目录
(资料分享见文末)
一、模块介绍
MP3-TF-16P是一款提供串口控制的音频播放模块,内部集成音频解码、TF卡文件系统、DAC输出和功率放大。使用时,单片机只需要通过UART发送指令,就可以完成指定歌曲播放、暂停、上一曲/下一曲、音量调节、循环播放和广告插播等功能。

以下是模块的参数:
|------|--------------------------|
| 型号 | MP3-TF-16P/DFPlayer Mini |
| 工作电压 | DC 3.3~5V |
| 通信接口 | UART串口 |
| 存储介质 | TF卡 |
| 音频格式 | MP3、WAV |
| 典型用途 | 语音提示、报警播报、音乐播放 |
| 开发特点 | 指令控制,不需要单片机解码音频 |
二、模块原理
1.原理图

MP3播放器模块的本质是一个"音频文件播放系统"。TF卡或U盘中的压缩音频文件先被模块读取,再由内部DSP完成硬解码,随后通过DAC转换成模拟音频信号。若使用喇叭输出,模拟信号再经过板载8002功放放大,最终驱动小功率喇叭发声。
以下是引脚描述:

|----|--------|---------|
| 编号 | 引脚 | 描述 |
| 1 | VCC | 3.3-5V |
| 2 | RX | 串行数据输入 |
| 3 | TX | 串行数据输出 |
| 4 | DAC_R | 音频输出右声道 |
| 5 | DAC_L | 音频输出左声道 |
| 6 | SPK2 | 喇叭+ |
| 7 | GND | 地 |
| 8 | SPK1 | 喇叭- |
| 9 | IO1 | 触发口1 |
| 10 | GND | 地 |
| 11 | IO2 | 触发口2 |
| 12 | ADKEY1 | AD口1 |
| 13 | ADKEY2 | AD口2 |
| 14 | USB+ | USB+DP |
| 15 | USB- | USB-DM |
| 16 | BUSY | 播放提示 |

三、模块控制方式
MP3播放模块支持三类控制方式:串口控制、IO触发和AD按键。实际嵌入式项目中,最常用的是UART串口控制,因为它能实现最完整的播放控制和状态查询。

四、串口通信协议
模块默认串口波特率为9600bps,TTL电平。完整指令帧由起始位、版本、长度、命令、反馈位、参数、校验和、结束位组成。工程中建议使用带校验的完整指令,提高通信稳定性。
播放第1首:
7E FF 06 03 00 00 01 FE F7 EF
常用串口指令:
下表列出STM32项目中最常用的控制指令。发送时只需要改变CMD和参数DH/DL,再重新计算校验和。

五、程序设计
1.使用STM32F103C8T6控制MP3模块进行音乐播放、切换、调节音量等
2.将当前状态音量等在OLED上显示
|----------|------|
| MP3_RX | PA2 |
| MP3_TX | PA3 |
| OLED_SCL | PB8 |
| OLED_SDA | PB9 |
| 调试 | 串口1 |
| 按键1 | PB12 |
| 按键2 | PB13 |
| 按键3 | PB14 |
| 按键4 | PB15 |
main.c文件
cpp
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "key.h"
#include "usart2.h"
#include "TIM2.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : MP3播放器模块实验
* 版本 : V1.0
* 日期 : 2026.7.28
* MCU : STM32F103C8T6
* 接口 : 串口2
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
#define KEY_1 1
#define KEY_2 2
#define KEY_3 3
#define KEY_4 4
uint8_t play_flag = 0;
uint8_t volume = 15;
uint8_t volume_update=0;
int main(void)
{
SystemInit();
delay_init(72);
Key_Init();
USART1_Config();
USART2_Config();
OLED_Init();
MP3_SendCmd(0x06,volume,0);
OLED_Clear();
delay_ms(1000);
TIM2_Init(72-1,1000-1);
OLED_ShowNum(48,16,volume,2,16,1);
while(1)
{
if(play_flag)
{ //播放中
OLED_ShowChinese(0,0,0,16,1);
OLED_ShowChinese(16,0,1,16,1);
OLED_ShowChinese(32,0,4,16,1);
}
else{ //暂停中
OLED_ShowChinese(0,0,2,16,1);
OLED_ShowChinese(16,0,3,16,1);
OLED_ShowChinese(32,0,4,16,1);
} //音量:
OLED_ShowChinese(0,16,5,16,1);
OLED_ShowChinese(16,16,6,16,1);
OLED_ShowChar(32,16,':',16,1);
if(volume_update)
{
OLED_ShowNum(48,16,volume,2,16,1);
volume_update=0;
}
if(KeyNum)
{
switch(KeyNum)
{
case KEY_1:
if(play_flag==0)
{
play_flag=1;
MP3_SendCmd(0x0D,0,0);//播放
}
else
{
play_flag=0;
MP3_SendCmd(0x0E,0,0);//暂停
}
break;
case KEY_2:
{
if(volume >= 30)
{
volume = 0;
}
else
{
volume++;
}
MP3_SendCmd(0x06,volume,0);//设置音量
delay_ms(200);
volume_update=1;
}
break;
case KEY_3:
MP3_SendCmd(0x01,0,0);//下一曲
break;
case KEY_4:
MP3_SendCmd(0x02,0,0);//上一曲
break;
}
KeyNum=0;
}
}
}
usart2.h文件
cpp
#ifndef __USART2_H
#define __USART2_H
#include "stm32f10x.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : MP3播放器模块实验
* 版本 : V1.0
* 日期 : 2026.7.28
* MCU : STM32F103C8T6
* 接口 : 串口2
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
void USART2_Config(void);
void USART2_SendByte(uint8_t data);
void USART2_SendArray(uint8_t *buf,uint16_t len);
void MP3_SendCmd(uint8_t cmd,uint16_t param,uint8_t feedback);
#endif
usart2.c文件
cpp
#include "usart2.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : MP3播放器模块实验
* 版本 : V1.0
* 日期 : 2026.7.28
* MCU : STM32F103C8T6
* 接口 : 串口2
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
/**
* @brief USART2初始化
* @note
* TX: PA2
* RX: PA3
* 波特率:9600
*/
void USART2_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//开启GPIOA、AFIO、USART2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
USART_DeInit(USART2);
//USART2_TX PA2 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//USART2_RX PA3 浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//USART参数配置
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_Init(USART2,&USART_InitStructure);
//使能USART2
USART_Cmd(USART2,ENABLE);
}
/**
* @brief USART2发送一个字节
*/
void USART2_SendByte(uint8_t data)
{
//等待发送缓冲空
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
//写入数据
USART_SendData(USART2,data);
//等待发送完成
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
}
/**
* @brief USART2发送数组
*/
void USART2_SendArray(uint8_t *buf,uint16_t len)
{
uint16_t i;
for(i=0;i<len;i++)
{
//逐个发送:
USART2_SendByte(buf[i]);
}
}
/**
* @brief MP3发送控制指令
*
* 数据格式:
*
* 7E FF 06 CMD FEEDBACK PARAM_H PARAM_L CHK_H CHK_L EF
*
*/
void MP3_SendCmd(uint8_t cmd,uint16_t param,uint8_t feedback)
{
uint8_t buf[10];//创建10字节数组
uint16_t checksum;
uint16_t sum;
uint8_t i;
buf[0]=0x7E;//帧头
buf[1]=0xFF;//版本
buf[2]=0x06;//长度
buf[3]=cmd; //功能
buf[4]=feedback;//反馈
buf[5]=param>>8;//参数高8位
buf[6]=param;//参数低8位
sum=0;
//计算校验
for(i=1;i<=6;i++)
{
sum+=buf[i];
}
checksum=0-sum;
buf[7]=checksum>>8;
buf[8]=checksum;
buf[9]=0xEF;
USART2_SendArray(buf,10);
}
六、实验效果
