本文主角是硬禾学堂的“2022寒假在家练”esp32s2收音机板,其采用的乐鑫esp32系列的新品S2作为主控,配备oled屏幕、麦克风输入、喇叭、USB接口、收音机模块,红外接收,硬件条件相当优良,可拓展功能很多,可玩性非常高。本文重点介绍在Arduino环境下用用LGFX驱动SSD1306oled屏幕,完成了传统收音机功能、电子钟、天气预报等功能,程序流畅度高,可以满足日常使用,供大家借鉴参考。
(一)LGFX驱动SSD1306oled屏幕
SSD1306oled是一款使用非常广泛的显示屏,基本大家接触的第一款屏幕就是它,对于它的驱动有很多丰富案例。因为esp32s2也提供很多操作平台,可以用micropython、circuitpython、sdk、idf、Arduino,选择困难症都来了。Circuitpython 代码简单,但在国内不甚流行。sdk和idf 用C++,代码功力要求高。Arduino 对野生创客还是挺友好的,因为基友多,可学习(ctl+c)的资源比较多,陷入了这样的舒适区,还没有跳脱。选定了Arduino 后,又面临用什么库来驱动这个屏幕,现成可用的有U8g2,Adafruit_GFX,U8g2这个库早前有简单接触过,代码风格有点古董,好像是70年代的产物,Adafruit_GFX还不错,和S2完美兼容,日常需求都满足了,就是中文支持不太好,但如果没有更好选择就是它了。还有其他的选择吗?Adafruit_GFX的升级版TFT_eSPI,支持主流的TFT屏幕,没看上低端的oled。TFT_eSPI的升级版lovyanGFX,貌似能支持所有屏幕,这个库的主战场也是TFT类的彩屏,ssd1306编译的时候看到有支持,但是没有现成的用例,在查看库类文件时,看到了个用户定制文件,可以根据实际需求设置屏幕参数来完成驱动,但是文件内容是日文的,不是那么有友好,需要逐条翻译。根据前面使用LovyanGFX的经验和反复几次试验,最终完成了用LovyanGFX驱动ssd1306oled。LovyanGFX库功能相当强大,开发图形界面的应用和游戏都可以应付,还有随手可得的汉字支持(无需制作字库),如果有强迫症需要完美的字体显示也可以自己制作字库,也是可以支持,这些特性都非常棒,灵活性非常高,为后面收音及界面显示提供了极大的便利。ESP32_2S_SD1306在后面附件可以获取,非常好用,不容错过。
(二)收音机功能实现
在LovyanGFX的加持下,完成了收音机初始化的界面及播放界面的动画设计。使得耗时较长初始化界面不再是毫无交互的漫长的黑暗等待。设计了个海螺状螺旋logo,播放过程会旋转,增加了播放收音时的趣味性,因此也给收音机起了个文艺名字叫FunRadio(泛调频),收音的核心功能由“RDA5807.h”提供,能力和时间不允许自己造轮子,主要工作在根据使用习惯完成收音机的一般功能。在播放界面可以实现换台,音量大小及声音开关的操作,播放收音可以在任何界面进行,例如时钟界面收音也是正常播放的,如果不想播放按下按键4就可以进入静音模式。可以清晰的接收本地多个电台,全天候不停播放,可以接上外置音响,效果也是杠杠滴。具体实现可以参考的附件代码。
功能演示
(三)时钟界面
联网后获取时间信息然后利用LovyanGFX的图层技术(sprite)完成了一个电子时钟界面。从自带的字库里精心挑选了一款适合显示时间的字体“Orbitron_Light”,显示没有残影,很有电子表的风范,使得这块板子不单纯的是一块学习用的开发板,可以成为日常生活的一个实用的装备,随手可得的24小时不间断的音乐,天气状况查询。
void showTime(void)
{
if (!getLocalTime(&timeinfo)) //获取时间
{
Serial.println("Failed to obtain time");
return;
}
spr.fillScreen(0);
spr.setFont(&fonts::TomThumb);
spr.setCursor(5, 5);
spr.setTextSize(1.5);
//spr.print(&timeinfo, "%Y/%m/%d"); //年月日
spr.print(&timeinfo, "%F");
spr.setFont(&fonts::Orbitron_Light_24);
spr.setTextSize(0.95);
spr.setCursor(5, 25);
spr.setTextDatum(CC_DATUM);
//spr.print(String(timeinfo.tm_hour)+":"+String(timeinfo.tm_min));
spr.print(&timeinfo, "%H:%M:%S"); // 时分秒。
spr.setFont(&fonts::efontCN_12_b);
spr.setCursor(15, 45);
spr.setTextSize(1.5);
spr.setTextDatum(TC_DATUM);
spr.print(weekDays[timeinfo.tm_wday]);
spr.setCursor(70, 45);
spr.print(liveData.weather);
//spr.print(String(timeinfo.tm_year));
// spr.setCursor(30, 50);
// spr.print(ipaddress.c_str());
}
天气预报
Esp32的强大联网功能早已为人所知,加上天气预报作业在近来几期的活动都有很多同学都做过,所以难度也不是特别大了。这里有一点工作就是选一个好点的天气预报信息的源。信息全面的站点要收费,免费站点的甚至连注册都不用,但是信息量就比较简单,只有温度和天气。最后选择注册了高德地图提供的天气信息,有天气、温度、湿度、风力和风向,3万条/天,我有没有看错,肯定用不完,何况天气也不是分分秒秒地更新,间隔5-10分钟更新一次已很好。这里的参考了wio_terminal活动大神的作业,使用了一个结构体来接收ArduinoJson解析的天气数据,数据处理起来更美观方便,值得学习(借用)。
void showWeather(void)
{
spr.setFont(&fonts::efontCN_16_b);
spr.fillScreen(0);
spr.setTextSize(1);
spr.setCursor(5, 2);
spr.print(liveData.city);
spr.setCursor(75, 2);
//spr.printf(/*"天气:%s",*/ liveData.weather);
spr.print(/*"天气:%s",*/ liveData.weather);
spr.drawFastHLine(2,25,120,TFT_WHITE);
spr.setFont(&fonts::efontCN_12_b);
spr.setCursor(2, 30);
spr.printf("温度%s℃", liveData.temperature);
spr.setCursor(65, 30);
spr.printf("湿度:%s%%", liveData.humidity);
spr.setCursor(2, 50);
spr.printf("风力:%s", liveData.windpower);
spr.setCursor(65, 50);
spr.printf("风向:%s", liveData.winddirection);
spr.setTextSize(1);
Serial.println(liveData.reporttime);
}
屏保小程序
这个是为了增加趣味性,做个泡泡屏保程序,如果觉得播放界面和天气预报界面比较枯燥也可以切换的这里来,我也时常切换到这里来,被这些按各自运行轨迹的小球迷倒了:)。虽然只有黑白色,运行起来也是毫不含糊,以后还可以移植些颜色不敏感的游戏。
void showCircles(void)
{
static long start = millis();
if (millis() - start >= 50) //控制刷新时间,不然太快了,非阻塞更新
{
spr.fillScreen(TFT_BLACK);
for (int i = 0; i < circlesNumber; i++)
{
//spr.fillCircle(circles[i].x,circles[i].y,circles[i].r,TFT_BLACK);
circles[i].x += circles[i].dx;
circles[i].y += circles[i].dy;
if ((circles[i].x <= circles[i].r) | (circles[i].x >= 128 - circles[i].r))
circles[i].dx *= -1;
if ((circles[i].y <= circles[i].r) | (circles[i].y >= 64 - circles[i].r))
circles[i].dy *= -1;
spr.drawCircle(circles[i].x, circles[i].y, circles[i].r, circles[i].color);
}
start = millis();
}
}
心得总结
我觉得本作业最大的贡献是完成了基于esp32S2使用LovyanGFX对SD1306的支持,为收音机板的图形驱动增加了一个选项,屏幕成功驱动后,后面所有工作变动非常轻松和水到渠成。项目内容包括时钟、收音、天气预报板块,内容较多,功能还算齐全,作为办公桌旁或床头的一个摆件都不失礼。略有不足的地方是没有实现流媒体音乐的播放,里面有我喜欢的HitFM,从前面大家的经验看来是要用espressif adf才能完成流媒体的播放,期待在不久的将来可以实现这个功能,但至少完成了很久以前的一个小小梦想---自己做一台收音机(硬禾帮我实现的“)。
祝大家新年进步,学业有成!
下一回合见!