内容介绍
内容介绍
1 项目介绍
- 系统能够自动连接WiFi,获取准确的当前时间(年、月、日、时、分、秒)
- 可以通过WiFi接收和播放网络上的电台,并通过按键进行选台
- 也可以通过FM模块接收和播放空中的电台,并通过按键进行调频
- 在OLED显示屏上显示网络电台的节目名字和FM信号的频率、音频质量等信息
2 硬件介绍
- 核心控制器采用乐鑫公司的ESP32-S2-Mini-1模块:通用型Wi-Fi MCU模组,4MB SPI flash,ESP32-S2-FH4芯片,工作频率高达 240 MHz
- FM模块:RDA5807M
3 软件环境
- Arduino
- arduino-esp32 v2.0.0: Arduino平台的ESP32开发库
- u8g2: Arduino使用I2C或SPI控制屏幕的库
- RDA5807: Arduino使用I2C控制收音机模块的库
- VS code
- esp-idf v4.3:乐鑫ESP系列的基本开发环境
- esp-adf v2.3:乐鑫的音频开发框架
4 实现思路
上电后进行WiFi连接和显示的初始化,在连接WiFi时加载一个Audio Loading…界面,然后,进行时间校准,连接网络电台、FM电台的任务。首先会自动播放第一个网络电台,先获取m3u8文件后,对文件中的aac音频地址进行下载、解码、播放;使用RDA5807库函数来接收FM电台、改变频率、获取音频质量。通过按键1可以在网络电台和FM电台之间切换, 通过按键2、3实现FM电台调频和网络电台的换台。
用LVGL创建2个屏幕,一个用来显示网络电台的信息、另一个显示FM电台的信息。网络电台显示的有:IP地址、节目名称、当前时间。FM电台显示的有:频率、RSSI、当前时间,通过按键进行切换。
5 主要代码
- 上电: 进行屏幕, FM, WIFI等功能的初始化
/* ssd1306 LVGL初始化 */
SSD1306_init();
/* 加载动画显示 */
my_lvgl_load_anim();
wifi_connect();
// xTaskCreate(state_task, "state_task", 2048, NULL, 15, NULL);
xTaskCreate(time_task, "time_task", 1024*2, NULL, 10, NULL);
/* HLS初始化 */
play_living_stream_start();
/* 独立按键初始化 */
board_button_init();
/* FM模块rda5807初始化 */
rda5807m_app_init();
/* APP_GUI绘制 */
my_lvgl_app();
- 时间校对并显示,时间信息储存在timeinfo中
time(&now); // 更新当前时间
localtime_r(&now, &timeinfo);
setenv("TZ", "CST-8", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
if (data_time_label1 != NULL && data_time_label2 != NULL && timeinfo.tm_year > (2022-1900)) // 大于2022-1900是因为有时ntp更新时间太慢,tm_year是与1900时间差
{
lv_label_set_text(data_time_label1, strftime_buf);//显示年月日
lv_label_set_text(data_time_label2, strftime_buf);//显示时分秒
}
ESP_LOGI(TAG, "The current date/time in Harbin is: %s", strftime_buf);
- WiFi连接
void wifi_connect()
{
ESP_LOGI(TAG, "[ * ] Start and wait for Wi-Fi network");
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
set = esp_periph_set_init(&periph_cfg);
periph_wifi_cfg_t wifi_cfg = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
};
esp_periph_handle_t wifi_handle = periph_wifi_init(&wifi_cfg);
esp_periph_start(set, wifi_handle);
periph_wifi_wait_for_connected(wifi_handle, portMAX_DELAY);
}
- 设置FM电台的频率,频率值储存在rda5807m_current_fre中
rda5807m_set_frequency_khz(&rda5807m_dev, rda5807m_current_fre);
- 连接网络电台,通过url地址可以获取m3u8文件,对文件中的aac音频地址进行下载、解码、播放
static int _http_stream_event_handle(http_stream_event_msg_t *msg)
{
if (msg->event_id == HTTP_STREAM_RESOLVE_ALL_TRACKS) {
return ESP_OK;
}
if (msg->event_id == HTTP_STREAM_FINISH_TRACK) {
return http_stream_next_track(msg->el);
}
if (msg->event_id == HTTP_STREAM_FINISH_PLAYLIST) {
return http_stream_fetch_again(msg->el);
}
return ESP_OK;
}
static void living_stream_task()
{
while (1) {
audio_event_iface_msg_t msg;
esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
continue;
}
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT
&& msg.source == (void *) aac_decoder
&& msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) {
audio_element_info_t music_info = {0};
audio_element_getinfo(aac_decoder, &music_info);
ESP_LOGI(TAG, "[ * ] Receive music info from aac decoder, sample_rates=%d, bits=%d, ch=%d",
music_info.sample_rates, music_info.bits, music_info.channels);
updata_radio_info_label(music_info);
audio_element_setinfo(output_stream_writer, &music_info);
// i2s_stream_set_clk(output_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
pwm_stream_set_clk(output_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
continue;
}
/* restart stream when the first pipeline element (http_stream_reader in this case) receives stop event (caused by reading errors) */
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT
&& msg.source == (void *) http_stream_reader
&& msg.cmd == AEL_MSG_CMD_REPORT_STATUS && (int) msg.data == AEL_STATUS_ERROR_OPEN) {
ESP_LOGW(TAG, "[ * ] Restart stream");
audio_pipeline_stop(pipeline);
audio_pipeline_wait_for_stop(pipeline);
audio_element_reset_state(aac_decoder);
audio_element_reset_state(output_stream_writer);
audio_pipeline_reset_ringbuffer(pipeline);
audio_pipeline_reset_items_state(pipeline);
audio_pipeline_run(pipeline);
continue;
}
}
- 电台信息储存在HLS_list数组中
HLS_INFO_t HLS_list[MAX_HLS_URL_NUM] = {
{.hls_url = "http://open.ls.qingting.fm/live/20210755/64k.m3u8?format=aac", .program_name = "星河音乐"}, // 星河音乐
{.hls_url = "http://open.ls.qingting.fm/live/20210756/64k.m3u8?format=aac", .program_name = "天籁古典"}, // 天籁古典
{.hls_url = "http://open.ls.qingting.fm/live/1007/64k.m3u8?format=aac", .program_name = "CRI HIT FM"}, // CRI HIT FM
{.hls_url = "http://open.ls.qingting.fm/live/386/64k.m3u8?format=aac", .program_name = "中国之声"}, // 中国之声
{.hls_url = "http://open.ls.qingting.fm/live/4985/64k.m3u8?format=aac", .program_name = "CNR中国交通广播"}, // CNR中国交通广播
{.hls_url = "http://open.ls.qingting.fm/live/1005/64k.m3u8?forma t=aac", .program_name = "CRI环球资讯"}, // CRI环球资讯
{.hls_url = "http://open.ls.qingting.fm/live/387/64k.m3u8?format=aac", .program_name = "CNR经济之声"}, // CNR经济之声
};
- 最后,设计FM电台、网络电台界面,将信息显示出来。要显示一段文字,首先要通过lv_label_create()函数创建对象,通过lv_obj_align()函数排列文本,然后通过lv_label_set_text()函数打印文本,lv_obj_set_pos()可以用来设置文本位置,lv_obj_set_style_text_font()可以设置字体。
static void internet_radio_scr_create()
{
my_scr1 = lv_obj_create(NULL); //创建屏幕
/* 设置布局 */
//lv_obj_set_layout(my_scr1, LV_LAYOUT_FLEX);
lv_obj_set_flex_flow(my_scr1, LV_FLEX_FLOW_COLUMN);
static lv_style_t row_container_style;
lv_style_init(&row_container_style);
lv_style_set_pad_row(&row_container_style, 0); // 改变元素间距
lv_obj_add_style(my_scr1, &row_container_style, 0);
/*
* 创建label
*/
/* 节目名称 */
radio_label = lv_label_create(my_scr1);
//lv_obj_set_pos(radio_label, 0, 9);
lv_obj_set_width(radio_label, 128);
lv_label_set_long_mode(radio_label, LV_LABEL_LONG_SCROLL); // 来回滑动显示
lv_obj_set_style_text_font(radio_label, &lv_font_myfont_8, 0); // 设置支持中文字体
lv_label_set_text_fmt(radio_label, "%s", HLS_list[0].program_name);
/* IP地址 */
lv_obj_t* ip_address_label = lv_label_create(my_scr1); // 从当前活动屏幕创建
lv_obj_set_pos(ip_address_label, 0, 0);
lv_obj_set_size(ip_address_label, 128, 8);
lv_label_set_text(ip_address_label, "IP:172.20.10.2");
/* 地址 */
radio_info_label = lv_label_create(my_scr1);
lv_obj_set_width(radio_info_label, 128);
// lv_label_set_long_mode(radio_info_label, LV_LABEL_LONG_SCROLL); // 来回滑动显示
/* 当前日期时间 */
data_time_label1 = lv_label_create(my_scr1);
lv_obj_set_width(data_time_label1, 128);
// lv_label_set_long_mode(data_time_label1, LV_LABEL_LONG_SCROLL);
// get_current_time(current_time, sizeof(current_time));
lv_label_set_text(data_time_label1, "updating time...");
lv_group_add_obj(g, radio_label); // 控制的对象添加到组中
lv_obj_add_event_cb(radio_label, radio_label_event_cb, LV_EVENT_KEY, NULL); // 添加事件
}
static void FM_radio_scr_create()
{
my_scr2 = lv_obj_create(NULL); //创建屏幕
/* 设置布局 */
//lv_obj_set_layout(lv_scr_act(), LV_LAYOUT_FLEX);
lv_obj_set_flex_flow(my_scr2, LV_FLEX_FLOW_COLUMN);
static lv_style_t row_container_style;
lv_style_init(&row_container_style);
lv_style_set_pad_row(&row_container_style, 0); // 改变元素间距
lv_obj_add_style(my_scr2, &row_container_style, 0);
/* 当前频段 */
fre_label = lv_label_create(my_scr2);
lv_obj_set_style_text_font(fre_label, &lv_font_montserrat_20, 0);
lv_label_set_text_fmt(fre_label, "%.1fMHz", ((float)rda5807m_current_fre/1000));
lv_group_add_obj(g, fre_label); // 添加到组中
lv_obj_add_event_cb(fre_label, fre_label_event_cb, LV_EVENT_KEY, NULL); // 配置事件
/* 当前信号RSSI */
rssi_label = lv_label_create(my_scr2);
lv_obj_set_style_text_font(rssi_label, &lv_font_montserrat_20, 0);
lv_label_set_text(rssi_label, "RSSI:0");
/* 当前日期时间 */
data_time_label2 = lv_label_create(my_scr2);
lv_obj_set_width(data_time_label2, 128);
//lv_obj_set_pos(data_time_label2, 0, 50);
lv_label_set_text(data_time_label2, "updating time...");
}
5 功能展示
- 加载界面:
- FM电台界面
- 网络电台界面
6 遇到的问题及解决方法
- 刚开始选择了Arduino开发环境,配置了ESP32S2器件,添加了u8g2、RDA5807等库,实现了连接WiFi、校准时间、收听FM电台的功能,但是实现网络电台时遇到了瓶颈,于是转战VsCode。
- 用了很多时间配置VsCode环境,需要安装esp-idf、idf tools、esp-adf等,借鉴了例程,最后成功编译,烧录。
软硬件
元器件
ESP32-S2-MINI-1
2.4GHz WiFi (802.11 b/g/n) 模组, 内置ESP32S2系列芯片,Xtensa® 单核32位LX7微处理器, 内置芯片叠封4MB flash,可叠封2MB PSRAM, 37个GPIO,丰富的外设, 板载PCB天线或外部天线连接器
附件下载
附件-百度网盘地址.txt
团队介绍
评论
0 / 100
查看更多
猜你喜欢
2021暑假一起练-用ESP32S2做了网络收音机/FM收音机电子森林暑假一起练项目。ESP32S2实现网络收音机/FM收音机的功能,WIFI接收网络电台或者RDA5807M接收空中电台。以及在这两种模式间切换。基于ESP-IDF,ESP-ADF,ESP-IOT-SOLUTION,LVGL等库
DamingBear
4709
基于ESP32-S2的网络收音机&FM收音机这是一款使用乐鑫ESP32-S2制作的网络收音机和FM收音机,基于ESP-IDF框架。网络收音机可以收听蜻蜓FM的电台,FM收音机可以收听频段87MHz到108MHz的电台,另外该收音机具有自动校时功能。
大伟和他的小伙伴们
7466
用ESP32-S2-MINI-1模块实现的网络\FM收音机本项目基于ESP32-S2-MINI-1模块,在esp-idf开发工具和esp-adf框架的基础上,实现了网络\FM收音机。
月影沫晨
2269