广播发烧网欢迎您!
广播发烧网
广播发烧友网站
数码时代Digital Era
网络收音机

ESP32-S2 变身两栖收音机:Wi-Fi 网络与 FM 空中频道自由切换!

作者:电子森林 日期:2025-08-23 人气:1509 添加:5BCL.com 


“这个暑假,我用 ESP32-S2 搭建了一台独一无二的“网络 + FM 双模”收音机:它既能通过 Wi-Fi 寻访线上 HLS 协议电台,也可捕捉传统 88–108 MHz 的 FM 广播;OLED 实时显示,按键实现静音与模式切换。一路摸索 ESP-IDF、ADF、LVGL、SSD1306 等框架,虽说技术小白上手版本,但成果满满。跟我一起,回味电波魅力,拥抱 DIY 乐趣!”

01 )

项目简介

基本功能:

  • 可以连接WiFi收听HLS协议的网络电台节

  • 收听空中的FM电台88MHz~108MHz

  • OLED0.96寸显示

  • 四个独立按键控制两种模式,切换节目,静音。

项目环境:

  • ESP-IDF v4.2:乐鑫ESP系列的基本开发环境,借鉴了sntp例程。

  • ESP-ADF v2.3:乐鑫的音频开发框架,主要借鉴了pipeline_living_stream和pipeline_play_mp3_with_dac_or_pwm这两个例程。

  • ESP-IOT-SOLUTION:Iot设备驱动和解决方案。使用SSD1306库,里面的7.5版本的LVGL已经被我用8.1的替换,并且修改一处SSD1306驱动程序的错误(LVGL仓库中的:ssd1306水平终止范围错误 #103)以及使用iot_button库,因为这个驱动可以识别按钮单击、双击、长按等功能。

  • LVGL v8.1:嵌入式GUI库,替换ESP-IOT-SOLUTION中的v7.5的LVGL。

  • ESP-IDF-LIB v0.8.1:基于IDF开发的一些常用芯片的库(项目中使用RDA5807M的库)。

  • MCU_Font_Release:用于生成LVGL使用的自定义字体来显示中文。

硬件:

  • ESP32-S2-MINI-1:ESP32-S2-FH4的芯片,320K的DRAM,无PSRAM。

  • FM模块:RDA5807M

02 

如何使用

关于环境配置,需要自己按照官方教程配置IDF和ADF环境,其他的iot-solution以及LVGL以及在项目里。下面是用的VS Code的esp-idf插件作为开发环境。

1.1 克隆项目

git clone https://github.com/DaMiBear/ESP32S2_Network-Radio_FM-Radio.git

1.2 选择设备

VS Code打开项目文件夹后,F1输入如下命令,选择根据你的设备选择,项目中使用的是ESP32S2。

1.3 配置

点击如下图标,进行设置

Serial flasher config

Flash size改为4MB

Partition Table

更改为如下设置,默认的factory大小只有1M是不够的,要改为3M

Audio HAL

选择ESP32-S2-Kaluga-1,这个选项是属于ADF里的,ADF里大多数程序都是按照官方提供的那些开发板来的,官方开发板中的S2是有2MB的PSRAM的,这里主要是为了产生一些宏定义防止编译出错,具体初始化的程序是我们自己写的。

play_living_stream Configuration

输入自己WiFi的名称和密码。如果有中文,就在sdkconfig这个文件中修改,注意在sdkconfig文件中修改只限于WiFi名称和密码,其他的值大部分会在编译的时候重新覆盖。

Compiler options

为了节省内存,这里选择.

因为ADF的play_living_stream程序非常占内存,再加上FreeRTOS和LVGL,如果是默认设置,320K的内存是肯定不够的,所以要更改一些配置来节省内存。

ESP32S2-specific

选择240MHz

Wi-Fi

与IRAM有关的都去掉,要不然代码会直接放入内存中,虽然可以加快速度,但是内存是真的不够用。

LCD Drivers

勾选SSD1306

LVGL configuration

勾选LVGL minimal configuration

Color settings

选择1:1

Memory settings

设置为6,默认的大小为32,就是32K,这样就会产生一个大小为32K的全局变量,这个才是内存占用的罪魁祸首。一开始没发现这一点,导致加入LVGL程序后,内存根本不够用。这里设置为6可以不报错,试过5或者更小,但在运行过程中会出错。

Feature configuration - Others

勾选Enable float in built-in (v)snprintf functions来支持浮点数显示

Font usage - Enable built-in fonts

选用Enable Montserrat 20和Enable UNSCII 8 (Perfect monospace font),因为项目中使用的LVGL内置字体就这两个,还有一个为了支持中文显示的自定义字体。

下面的Select theme default title font默认格式选择UNSCII 8。这里LVGL里面的Kconfig文件中,比如我们选择的是UNSCII 8那就会产生一个CONFIG_LV_FONT_DEFAULT_UNSCII_8的宏定义,之后根据lv_conf_kconfig.h文件的#elif defined会定义

/* file:lv_conf_kconfig.h */
#elif defined CONFIG_LV_FONT_DEFAULT_UNSCII_8
#define CONFIG_LV_THEME_DEFAULT_FONT         &lv_font_unscii_8

随后会根据lv_conf_internal.h文件中下面部分代码,但是代码中使用的是CONFIG_LV_FONT_DEFAULT,而不是CONFIG_LV_THEME_DEFAULT_FONT,因为CONFIG_LV_FONT_DEFAULT没有定义,那这样设置默认字体是没效果的。所以我把CONFIG_LV_FONT_DEFAULT改为了CONFIG_LV_THEME_DEFAULT_FONT,这样就可以改变默认字体了,当然这肯定不是最好的办法。

/* file:lv_conf_internal.h */
/*Always set a default font*/
#ifndef LV_FONT_DEFAULT
ifdef CONFIG_LV_FONT_DEFAULT // 更改为了CONFIG_LV_THEME_DEFAULT_FONT
#   define LV_FONT_DEFAULT CONFIG_LV_FONT_DEFAULT // 更改为了CONFIG_LV_THEME_DEFAULT_FONT
else
#   define LV_FONT_DEFAULT &lv_font_montserrat_8
endif
#endif

后面的LVGL选项自己根据情况勾选就行。

1.4 编译下载

点击左下角图小,分辨是编译、下载、监视,第四个是三个功能合为一个按键。

03 )

运行现象

从左到右四个按键功能依次是:网络电台/FM电台模式切换、切换至下一个节目/频段、切换至上一个节目/频段、禁用功放(静音)。

默认开机运行网络电台模式,该模式下,显示屏显示一些电台名称、时间等信息。FM电台模式下显示频段、RSSI、时间信息。


日志输出

WiFi的输出省略

I (439) cpu_start: Starting scheduler on PRO CPU.
I (441) gpio: GPIO[41]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (441) gpio: GPIO[42]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (461) spi_bus: SPI2 bus created
I(461) spi_bus: SPI2 bus device added, CS=38 Mode=0 Speed=20000000
I (661) lvgl_gui: GUI Run at esp32s2 Pinned to Core0
I (661) lvgl adapter: Alloc memory total size: 1024 Byte
I (661) lvgl_gui: Start to run LVGL
I (761) PLAY_LIVING_STREAM: [ * ] Start and wait for Wi-Fi network
I (771) wifi:wifi driver task: 3ffd68bc, prio:23, stack:6656, core=0
I (771) system_api: Base MAC address is notset
I (771) system_api: read default base MAC address from EFUSE
I (781) wifi:wifi firmware version: c7d0450
I (781) wifi:wifi certification version: v7.0
I (781) wifi:config NVS flash: enabled
I (781) wifi:config nano formating: disabled
··················································
W (1591) PERIPH_WIFI: WiFi Event cb, Unhandle event_base:WIFI_EVENT, event_id:4
I (1591) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (2461) esp_netif_handlers: sta ip: 192.168.123.100, mask: 255.255.255.0, gw: 192.168.123.1
I (2461) PERIPH_WIFI: Got ip:192.168.123.100
I (2461) GET_TIME: Initializing SNTP
I (2471) GET_TIME: Waiting for system time to be set... (1/10)
I (2471) PLAY_LIVING_STREAM: [1.0] Create audio pipeline for playback
I (2481) PLAY_LIVING_STREAM: [1.1] Create http stream to read data
I (2491) PLAY_LIVING_STREAM: [2.2] Create PWM stream to write data to codec chip
I (2501) PLAY_LIVING_STREAM: [2.3] Create aac decoder to decode aac file
I (2501) PLAY_LIVING_STREAM: [2.4] Register all elements to audio pipeline
I (2511) PLAY_LIVING_STREAM: [2.5] Link it together http_stream-->aac_decoder-->pwm_stream-->[codec_chip]
I (2521) AUDIO_PIPELINE: link el->rb, el:0x3ffdceac, tag:http, rb:0x3ffdfa98
I (2531) AUDIO_PIPELINE: link el->rb, el:0x3ffdf718, tag:aac, rb:0x3ffdfad4
I (2541) PLAY_LIVING_STREAM: [2.6] Set up  uri (http as http_stream, aac as aac decoder, anddefault output is i2s(changed to PWM))
I (2551) PLAY_LIVING_STREAM: [ 3 ] Set up  event listener
I (2551) PLAY_LIVING_STREAM: [3.1] Listening event from all elements of pipeline
I (2561) PLAY_LIVING_STREAM: [3.2] Listening event from peripherals
I (2571) PLAY_LIVING_STREAM: [ 4 ] Start audio_pipeline
I (2581) AUDIO_ELEMENT: [http-0x3ffdceac] Element task created
I (2581) AUDIO_ELEMENT: [aac-0x3ffdf718] Element task created
I (2591) AUDIO_ELEMENT: [output-0x3ffdf338] Element task created
I (2601) AUDIO_PIPELINE: Func:audio_pipeline_run, Line:359, MEM Total:87268 Bytes
I (2601) AUDIO_ELEMENT: [http] AEL_MSG_CMD_RESUME,state:1
I (2611) AUDIO_ELEMENT: [aac] AEL_MSG_CMD_RESUME,state:1
I (2621) AUDIO_ELEMENT: [output] AEL_MSG_CMD_RESUME,state:1
I (2621) AUDIO_PIPELINE: Pipeline started
I (2631) gpio: GPIO[1]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2641) board_button: Button[0] created
I (2641) gpio: GPIO[2]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2651) board_button: Button[1] created
I (2651) gpio: GPIO[3]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2661) board_button: Button[2] created
I (2671) gpio: GPIO[6]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2681) board_button: Button[3] created
I (2691) rda5807m: Device initialized
I (2691) rda5807m: Frequency: 102200 kHz
I (2701) HTTP_STREAM: total_bytes=789
I (2711) HTTP_STREAM: Live stream URI. Need to be fetched again!
I (2741) rda5807m: rda5807m_wait_and_finish_tune
I (2781) HTTP_STREAM: total_bytes=57780
I (2781) CODEC_ELEMENT_HELPER: The element is 0x3ffdf718. The reserve data 2 is 0x0.
I (2781) AAC_DECODER: a new song playing
I (2791) AAC_DECODER: this audio is RAW AAC
I (2821) PLAY_LIVING_STREAM: [ * ] Receive music info from aac decoder, sample_rates=24000, bits=16, ch=2
I (4251) GET_TIME: Notification of a time synchronization event
I (5471) main: The current date/time in Shanghai is: 2021-09-04      19:27:38
I (6471) main: The current date/time in Shanghai is: 2021-09-04      19:27:39
W (6801) HTTP_STREAM: No more data,errno:0, total_bytes:57780, rlen = 0
I (6801) AUDIO_ELEMENT: IN-[http] AEL_IO_DONE,0
I (6831) HTTP_STREAM: total_bytes=57848


板子运行现象


04 

改进点

  • SNTP校时任务可能会出现较长时间无法校时的情况,但还是会校时,只是时间较长。

  • WiFi输出日志中会出现W (1591) PERIPH_WIFI: WiFi Event cb, Unhandle event_base:WIFI_EVENT, event_id:4警告

  • 按键无响应,只遇到过一次

  • 网络电台切台过快程序会报错,目前只加延时简单处理


0
0
付款方式
×