STM32F103C8T6 × HAL库 × UART串口通信
DFPlayer Mini MP3 Player 模块的工作原理、核心功能与引脚定义
DFPlayer Mini MP3 Player 是一款紧凑型串口控制音频解码模块,内部集成了 MCU 控制器和 MP3 解码芯片。模块通过 TF 卡(支持 FAT16/FAT32 文件系统,最大 32GB)存储 MP3/WAV 音频文件。
主控 STM32 通过 UART 串口(9600bps, 8N1)向模块发送 8 字节指令帧,模块接收后解析命令并执行播放、暂停、切歌、音量调节等操作。
解码后的音频通过内置 24-bit DAC 输出,可直接驱动 3W 以下扬声器(SPK1/SPK2),也可通过 DAC_L/DAC_R 接外部功放或耳机。模块还提供 BUSY 引脚指示播放状态。
除串口模式外,模块还支持 I/O 按键模式(短按切歌、长按调音量)和 AD 按键模式(通过 AD 端口分压电阻触发不同曲目),实现独立运行。
| 命令码 | 功能 |
|---|---|
| 0x01 | 下一首 |
| 0x02 | 上一首 |
| 0x0D | 播放/恢复 |
| 0x0E | 暂停 |
MCU通过UART发送指令帧,控制播放、暂停、切歌、音量调节等全部功能
支持I/O按键模式和AD按键模式,无需MCU即可通过物理按键独立运行
SPK1/SPK2差分输出可直接驱动3W以下8Ω喇叭,无需外部功放电路
支持FAT16/FAT32文件系统,最大32GB TF卡,支持100个文件夹每文件夹255首
| 引脚号 | 名称 | 功能 | STM32连接 |
|---|---|---|---|
| 1 | VCC | 电源正极 (3.3~5V DC,建议5V) | 建议5V |
| 2 | RX | UART串口接收 | PA2 (USART2_TX) |
| 3 | TX | UART串口发送 | PA3 (USART2_RX) |
| 4 | DAC_L | 左声道音频输出 | 接功放/耳机 |
| 5 | DAC_R | 右声道音频输出 | 接功放/耳机 |
| 6 | SPK2 | 扬声器负极 | 接喇叭- |
| 7 | GND | 电源地 | GND |
| 8 | SPK1 | 扬声器正极 | 接喇叭+ |
| 9 | IO1 | 触发端口1 (短按上一曲/长按音量-) | - |
| 10 | GND | 地 | GND |
| 11 | IO2 | 触发端口2 (短按下一曲/长按音量+) | - |
| 12 | ADKEY1 | AD按键1 (触发播放第1首) | - |
| 13 | ADKEY2 | AD按键2 (触发播放第5首) | - |
| 14 | USB+ | USB正极 | - |
| 15 | USB- | USB负极 | - |
| 16 | BUSY | 播放状态指示 (低=播放中) | - |
DFPlayer Mini MP3 Player 模块多角度实物展示
DFPlayer Mini MP3 Player 模块原理图与PCB封装展示
STM32F103C8T6 HAL库源代码逐模块分析
void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 8MHz x 9 = 72MHz if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) Error_Handler(); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB = 72MHz RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // APB1 = 36MHz RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2 = 72MHz if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) Error_Handler(); }
void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /* K1(PA4) K2(PA5) K3(PA6) — 上拉输入 */ GPIO_InitStruct.Pin = K1_Pin | K2_Pin | K3_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(K1_GPIO_Port, &GPIO_InitStruct); }
UART_HandleTypeDef huart2; void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 9600; // DFPlayer标准波特率 huart2.Init.WordLength = UART_WORDLENGTH_8B; // 8位数据 huart2.Init.StopBits = UART_STOPBITS_1; // 1停止位 huart2.Init.Parity = UART_PARITY_NONE; // 无校验 huart2.Init.Mode = UART_MODE_TX_RX; // 收发模式 huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控 huart2.Init.OverSampling= UART_OVERSAMPLING_16; if(HAL_UART_Init(&huart2) != HAL_OK) Error_Handler(); } /* USART2 GPIO: PA2=TX(复用推挽), PA3=RX(浮空输入) */ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { if(uartHandle->Instance == USART2) { __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // PA2 → USART2_TX (复用推挽输出) GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // PA3 → USART2_RX (输入) GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART2_IRQn); } }
MP3_Send() 函数封装了 DFPlayer Mini 的串口命令发送逻辑。使用 u2_printf 宏通过 USART2 发送 8 字节指令帧。
uint8_t USART2_TX_BUF[200]; #define u2_printf(...) HAL_UART_Transmit(&huart2, USART2_TX_BUF, \ sprintf((char *)USART2_TX_BUF, __VA_ARGS__), 0xffff) /* * 发送8字节MP3指令帧 * CMD: 0x01=下一首 0x02=上一首 0x0D=播放 0x0E=暂停 */ void MP3_Send(uint8_t CMD) { u2_printf("%c%c%c%c%c%c%c%c", 0x7E, 0xFF, 0x06, CMD, 0x00, 0x00, 0x00, 0xEF); }
int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); OLED_Init(); while (1) { /* —— 按键检测 —— */ if(HAL_GPIO_ReadPin(K1_GPIO_Port, K1_Pin) && HAL_GPIO_ReadPin(K2_GPIO_Port, K2_Pin) && HAL_GPIO_ReadPin(K3_GPIO_Port, K3_Pin)) flag_Key = 0; // 所有按键松开,复位消抖标志 if(!HAL_GPIO_ReadPin(K1_GPIO_Port, K1_Pin) && !flag_Key) // 上一首 { MP3_Send(0x02); (song == 0) ? (song = 5) : (song--); Flag_Play = 1; flag_Key = 1; } if(!HAL_GPIO_ReadPin(K2_GPIO_Port, K2_Pin) && !flag_Key) // 下一首 { MP3_Send(0x01); (song == 5) ? (song = 0) : (song++); Flag_Play = 1; flag_Key = 1; } if(!HAL_GPIO_ReadPin(K3_GPIO_Port, K3_Pin) && !flag_Key) // 播放/暂停 { if(Flag_Play == 0) { Flag_Play = 1; MP3_Send(0x0D); } // 播放 else { Flag_Play = 0; MP3_Send(0x0E); } // 暂停 flag_Key = 1; } /* —— OLED屏幕显示(50ms刷新) —— */ if(HAL_GetTick() - Time_Now >= 50) { OLED_Clear(); switch(song) // 显示歌名 { case 0: OLED_CenterPrintf(12, "枫"); break; case 1: OLED_CenterPrintf(12, "蒲公英的约定"); break; case 2: OLED_CenterPrintf(12, "富士山下"); break; case 3: OLED_CenterPrintf(12, "瞬"); break; case 4: OLED_CenterPrintf(12, "唯一"); break; case 5: OLED_CenterPrintf(12, "特别的人"); break; } if(Flag_Play == 0) OLED_CenterPrintf(36, "暂停"); else OLED_CenterPrintf(36, "播放"); OLED_Update(); Time_Now = HAL_GetTick(); } } }
| song 值 | 歌曲名称 | 按键操作 | MP3命令 |
|---|---|---|---|
| 0 | 枫 | - | - |
| 1 | 蒲公英的约定 | K2 下一首 | 0x01 |
| 2 | 富士山下 | K2 下一首 | 0x01 |
| 3 | 瞬 | K2 下一首 | 0x01 |
| 4 | 唯一 | K2 下一首 | 0x01 |
| 5 | 特别的人 | K2 下一首 | 0x01 |
| 0←5 | 循环切换 | K1 上一首 | 0x02 |
| - | 切换状态 | K3 播放/暂停 | 0x0D / 0x0E |
#define SCL_Port GPIOB #define SCL_Pin GPIO_PIN_15 #define SDA_Port GPIOB #define SDA_Pin GPIO_PIN_14 /* 字体大小参数 */ #define OLED_8X16 8 // 8x16像素字体 #define OLED_6X8 6 // 6x8像素字体 void OLED_Init(void); void OLED_Clear(void); void OLED_Update(void); void OLED_CenterPrintf(int16_t Y, char *format, ...);
STM32主程序执行流程,包含 while(1) 主循环
模拟 STM32 + DFPlayer Mini MP3 Player 的完整工作流程
点击 K1/K2/K3 按钮模拟物理按键,观察 UART 数据帧传输、OLED 屏幕更新和扬声器音频输出状态。点击"自动演示"可自动循环展示完整流程。
DFPlayer模块:模拟实物芯片MH3002,16引脚封装,通过UART接收指令
BUSY LED:播放时常亮红色,暂停时熄灭
扬声器:播放时显示声波扩散动画,暂停时停止
UART数据流:逐字节高亮显示8字节指令帧的传输过程
OLED显示屏:实时显示歌曲名称和播放/暂停状态