平台介绍:
本平台使用了乐鑫公司的ESP32-S2-Mini-1模块,ESP32-S2-MINI-1是一颗通用型Wi-Fi MCU模组,功能强大,具有丰富的外设接口,可用于可穿戴电子设备、智能家居等场景。ESP32-S2-MINI-1采用PCB板载天线,模组配置了4MB SPI flash,采用的是 ESP32-S2FN4 芯片。该芯片搭载了Xtensa32 位LX7 单核处理器,工作频率高达 240 MHz。用户可以关闭 CPU 的电源,利用低功耗协处理器监测外设的状态变化或某些模拟量是否超出阈值。ESP32-S2-FH4 还集成了丰富的外设接口。2.4 GHz WiFi (802.11 b/g/n) 模组,可叠封2 MB PSRAM,37 个GPIO,丰富的外设,板载PCB 天线或外部天线连接器。
OLED原理:
OLED(Organic Light-Emitting Diode),又称为有机电激光显示、有机发光半导体(Organic Electroluminescence Display,OLED)。OLED属于一种电流型的有机发光器件,是通过载流子的注入和复合而致发光的现象,发光强度与注入的电流成正比。OLED在电场的作用下,阳极产生的空穴和阴极产生的电子就会发生移动,分别向空穴传输层和电子传输层注入,迁移到发光层。当二者在发光层相遇时,产生能量激子,从而激发发光分子最终产生可见光。
基本功能:
- 可以连接WiFi,并且通过NTP获取网络时间
- 连接网络后可以播放音乐
- 收听并显示FM电台88MHZ~108MHZ
- 四个独立按键,切换模式,调节声音大小,切换FM频率
流程框图:
代码思路分析:
程序下载完成并且上电后向显示器缓冲区发送数据显示开机界面,然后连接wifi并返回本机IP,而后41、41管脚置于高阻,4按钮管脚置于高阻,同时获取网络时间并校准晶振、显示当前时间。至此,该程序初始化完毕,进入功能选择状态。
初始时模式参数置于1,即网络音乐播放模式,即将预设好的服务器地址、端口号、密码等数据以客户端形式发送至服务端,待服务端正确返回后显示连接成功。同时由DAC模块驱动扬声器。由于本人使用的网络服务器可以对音频来进行处理,因此客户端不需要任何音频处理模块。而后通过按下第一个按键,来实现计数器的模2累加操作。2为FM模式,即关闭WI-FI模块,调用rda5807的库,初始化收音模块,通过第二个按键和第三个按键来选择广播的频道(88MHZ~108MHZ),第四个按键来调节音量大小(有1~15级,可循环)。
代码分析:
- oled配置
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 36, /* data=*/ 35, /* cs=*/ 46, /* dc=*/ 33, /* reset=*/ 34); u8g2.begin();
- speaker配置
pinMode(41, OUTPUT); pinMode(42, OUTPUT);
- 模式选择函数
void selectDevice(uint8_t dev) { if(dev == 0) { digitalWrite(41, LOW); digitalWrite(42, LOW); } if(dev == 1) { digitalWrite(41, HIGH); digitalWrite(42, LOW); } if(dev == 2) { digitalWrite(41, HIGH); digitalWrite(42, HIGH); } }
- 按键配置
pinMode(KEY1, INPUT_PULLUP); //上拉输入 pinMode(KEY2, INPUT_PULLUP); pinMode(KEY3, INPUT_PULLUP); pinMode(KEY4, INPUT_PULLUP);
- 时间显示
//时间参数 uint8_t a=20; char str[64] = {0}; const char *ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 8 * 3600; const int daylightOffset_sec = 0; //显示函数 void printLocalTime() { /*时间显示*/ struct tm timeinfo; if (!getLocalTime(&timeinfo)) //bool getLocalTime(struct tm*info,uint32_t ms=5000) { //info是一个struct tm 结构体对象,用于接收当前时间 Serial.println("Failed to obtain time"); //ms为该操作超时时间,超时则返回false(一般不自己配置) return; } // Serial.println(&timeinfo, "%F %T %A"); // 格式化输出 u8g2.firstPage(); u8g2.clearBuffer(); //清除内部缓冲区 u8g2.setFontDirection(0); //设置字体方向 u8g2.setFont(u8g2_font_ncenB14_tr); //设置字体 u8g2.setCursor(4, 25); u8g2.print(&timeinfo, "%F"); u8g2.setCursor(4, 50); u8g2.print(&timeinfo, "%T"); u8g2.sendBuffer(); }
- WiFi参数及配置
//WIFI参数 const char *ssid = ""; //你的网络名称 const char *password = ""; //你的网络密码 //WIFI连接 WiFi.begin(ssid, password); //连接WIFI while (WiFi.status() != WL_CONNECTED) { delay(500); } Serial.println("WiFi connected!");
- FM收音机主体代码
//RDA5807初始化 RDA5807 rx; //主体代码 Wire.begin(ESP32_I2C_SDA, ESP32_I2C_SCL); //iic的使用 rx.setup(); //启用rda5807 rx.setVolume(14); //音量 delay(500); rx.setFrequency(9080); rx.setRDS(true);
- 网络音乐主体代码(数据流)
if (iswaitecho == false && (writep - readp) < 2) { client.write('n'); iswaitecho = true; } if (client.available()) { num = client.read(netbuf[writep % 20], 2048); if (writep == 0 && readp == 0) { flipper.attach_ms(0, onTimer); } iswaitecho = false; writep++; }
- 网络音乐播放函数
void onTimer(void) { if(readp<=writep) dacWrite(17, netbuf[readp % 20][m_offset++]); //播放一次声音 if (m_offset >= 2048) { m_offset = 0; readp++; //读取完成一个缓冲区 } }
- oled显示代码
void dispwellcom() { /*屏幕显示*/ u8g2.firstPage(); u8g2.clearBuffer(); //清除内部缓冲区 u8g2.setFontDirection(0); //设置字体方向 u8g2.setFont(u8g2_font_ncenB14_tr); //设置字体 u8g2.setCursor(4, 35); u8g2.print("WELLCOME"); u8g2.sendBuffer(); delay(5000); u8g2.clear(); } void connectedprint() { /*屏幕显示*/ u8g2.firstPage(); u8g2.clearBuffer(); //清除内部缓冲区 u8g2.setFontDirection(0); //设置字体方向 u8g2.setFont(u8g2_font_unifont_t_chinese2); //设置字体 u8g2.setCursor(10, 35); u8g2.print("WiFi connected!"); u8g2.sendBuffer(); delay(2000); } void printLocalTime() { /*时间显示*/ struct tm timeinfo; if (!getLocalTime(&timeinfo)) //bool getLocalTime(struct tm*info,uint32_t ms=5000) { Serial.println("Failed to obtain time"); return; } // Serial.println(&timeinfo, "%F %T %A"); // 格式化输出 u8g2.firstPage(); u8g2.clearBuffer(); //清除内部缓冲区 u8g2.setFontDirection(0); //设置字体方向 u8g2.setFont(u8g2_font_ncenB14_tr); //设置字体 u8g2.setCursor(4, 25); u8g2.print(&timeinfo, "%F"); u8g2.setCursor(4, 50); u8g2.print(&timeinfo, "%T"); u8g2.sendBuffer(); } void moshiprint(uint8_t moshi) { u8g2.firstPage(); u8g2.clearBuffer(); //清除内部缓冲区 u8g2.setFontDirection(0); //设置字体方向 u8g2.setFont(u8g2_font_ncenB14_tr); //设置字体 u8g2.setCursor(4, 35); if(moshi==1) { u8g2.print("FMradio"); } else if(moshi==2) { u8g2.print("Webmusic"); } u8g2.sendBuffer(); }
结果展示:
- Wifi连接
- 获取时间
- 网络音乐
- FM收音
心得体会:
我很高兴能够参加本次硬禾课堂寒假在家练活动,我收获颇多,第一次接触ESP32系列单片机,无从下手,搭建环境也走了很多弯路,但是有交流群里的帮助,也有老师的提示,我最终还是一步步的做出了属于自己的一份作品。经过本次活动,我对于编程和硬件的理解更加的深入,逻辑思维能力也有了提升。但是也还有一些不足之处,比如如何更好的在两种模式下丝滑的切换,如何改进音乐播放声音的质量,这些都是我仍需努力的。希望下次还能参加硬禾课堂的活动。