> 技术文档 > 基于单片机与BY8301-16P 语音模块间的串口通信,实现播放指定音频_by8301语音模块

基于单片机与BY8301-16P 语音模块间的串口通信,实现播放指定音频_by8301语音模块


基于单片机与BY8301-16P 语音模块间的串口通信,实现播放指定音频

一、串口语音模块

这里我们使用的具体型号是:CH32V307VCT6开发板和BY8301-16P 语音模块。

以下是BY8301-16P语音模块的一些主要特点:

  • 高品质音频播放: 支持MP3和WAV两种主流音频格式解码,提供高品质的声音输出。具有24位DAC输出,支持90dB的动态范围和85dB的信噪比(SNR)。
  • 内置存储介质: 内置SPI-FLASH作为存储介质,通常有4MB(32Mbit)或更大的容量,最大可支持16M Byte容量的SPI FLASH(例如GD25Q128)。
  • 方便的音频更新: 配有Micro USB接口,无需上位机软件,可以直接通过数据线连接电脑(支持XP和WIN7系统)自由更换FLASH中的音频内容,操作简便。
  • 集成功放: 模块内置3W功放,可以直接驱动3W/4Ω或2W/8Ω的喇叭,方便使用,无需额外添加功放电路。
  • 多种控制方式:
    • IO口触发播放: 支持21段语音一对一触发播放,通过3个IO口(A、B、C)配合3.3K电阻接地或不接,可以选择8种硬件触发模式,应用广泛。
    • UART异步串口控制: 内置标准UART异步串口接口(3.3V TTL电平),可以通过串口命令进行播放、暂停、上下曲、音量加减、选曲播放、广告插播等操作。这使得它可以通过单片机、电脑串口等进行灵活控制。
    • 内置记忆功能: 支持音量、曲目、EQ(均衡器)掉电记忆功能。
  • 小巧封装: 采用标准的2.54mm间距DIP16封装,体积小巧,方便集成到各种产品中。
  • 宽电压供电: 工作电压范围为3.6V-5V,推荐值4.2V。

模块引脚原理图:

在这里插入图片描述

引脚编号 引脚名称 功能描述 1 SPK2 喇叭输出2(直接连接喇叭的一个引脚,与SPK1组成差分输出) 2 SPK1 喇叭输出1(直接连接喇叭的另一个引脚,与SPK2组成差分输出) 3 DACL 左声道音频数据输入(通常用于连接外部DAC,如果模块内置DAC则可能不常用) 4 DACR 右声道音频数据输入(通常用于连接外部DAC,如果模块内置DAC则可能不常用) 5 PLAY_LED 播放指示灯,停止常亮,播放闪烁(输出高电平,LED 负极接地) 6 VCC 电源输入(模块的工作电压,通常为3.6V-5V) 7 TX 串口发送信号(UART异步串口的发送端,用于向外部设备发送数据) 8 RX 串口接收信号(UART异步串口的接收端,用于接收外部设备发送的数据) 9 BUSY 系统忙碌信号(当模块正在播放音频时,此引脚会输出特定的电平状态,指示模块处于忙碌状态) 10 IO6 通用输入输出6(可配置为输入或输出,用于触发播放、模式选择或其他自定义功能) 11 IO5 通用输入输出5(可配置为输入或输出,用于触发播放、模式选择或其他自定义功能) 12 IO4 通用输入输出4(可配置为输入或输出,用于触发播放、模式选择或其他自定义功能) 13 IO3 通用输入输出3(可配置为输入或输出,用于触发播放、模式选择或其他自定义功能) 14 IO2 通用输入输出2(可配置为输入或输出,用于触发播放、模式选择或其他自定义功能) 15 IO1 通用输入输出1(可配置为输入或输出,用于触发播放、模式选择或其他自定义功能) 16 GND 地线(电源的负极,与VCC共同为模块供电)

二、基础知识

1、引脚连接

BY8301-16P语音模块采用标准的UART异步串口接口(3.3V TTL电平)进行通信。这里我们使用CH32的串口三进行串口通信:

BY8301-16P 语音模块引脚 CH32 微控制器引脚/功能 功能描述 SPK1 单声道无源喇叭 连接喇叭的一个引脚,与SPK2共同驱动喇叭发声。 SPK2 单声道无源喇叭 连接喇叭的另一个引脚,与SPK1共同驱动喇叭发声。 VCC CH32 3.3V 输出 为BY8301-16P模块提供3.3V电源。 GND CH32 GND 输出 BY8301-16P模块的接地端。 RX CH32 PB10 BY8301-16P模块的串口接收引脚,连接到CH32的PB10,用于接收CH32发送的控制命令。

2、通信协议

  • 数据格式:通信数据格式为1个起始位、8个数据位、无奇偶校验位和1个停止位。
  • 控制功能:通过串口命令,可以实现播放、暂停、上下曲切换、音量调节等多种操作。

3、命令结构

  • 格式:所有命令都遵循特定的十六进制格式:起始码、长度、操作码、参数1、参数2、校验和、结束码
  • 校验和:校验和通过异或(XOR)运算计算,用于确保数据传输的完整性。

4、主要控制命令

模块支持一系列控制命令,包括:

  • 播放 (0x01):启动音频播放。
  • 暂停 (0x02):暂停当前播放。
  • 音量调节 (0x05/0x06):增加或减小音量。
  • 曲目选择 (0x41):选择特定曲目进行播放。
  • 设备切换 (0x35):如果连接了多个设备,可以切换播放源。

5、查询命令

模块还允许您查询其状态:

  • 播放状态 (0x10):返回当前的播放状态(例如,正在播放、已暂停、已停止)。
  • 其他查询:您还可以查询当前的音量、均衡器模式以及文件夹中的歌曲数量。

6、重要注意事项

  • 命令间隔:发送连续命令时,确保每个命令之间至少有20毫秒的间隔。
  • 组合播放命令:对于组合播放命令,间隔应小于6毫秒。

三、通信程序

1、 Usart3_Init() 串口三初始化函数

配置CH32微控制器的USART3(通用同步/异步收发器3)进行串口通信。以下是代码的详细分解:

void Usart3_Init(){ //结构体定义 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //时钟使能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //GPIO 引脚配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); //USART3 参数配置 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_Mode_Rx; USART_Init(USART3, &USART_InitStructure); USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //中断配置 NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //使能 USART 和清除标志位 USART_Cmd(USART3, ENABLE); USART_ClearFlag(USART3,USART_FLAG_TC);//清空串口3的发送标志位}
  1. 结构体定义

    这里定义了三个结构体变量,分别用于配置:

    • GPIO_InitStructure:GPIO引脚。
    • USART_InitStructure:USART3模块。
    • NVIC_InitStructure:嵌套向量中断控制器,用于中断配置。
  2. 时钟使能

    这两行代码的作用是使能相关外设的时钟:

    • RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE);:使能USART3模块的时钟。USART3挂载在APB1总线上。
    • RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);:使能GPIOB端口的时钟。USART3的引脚(PB10和PB11)位于GPIOB端口。
  3. GPIO 引脚配置

    这段代码配置了GPIOB的PB10引脚用于USART3通信:

  • GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;:指定要配置的引脚是PB10。
  • GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;:设置引脚的输出速度为50MHz,这对于高速串口通信是常见的设置。
  • GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;:将引脚模式设置为复用推挽输出。对于USART,TX(发送)引脚通常需要配置为复用推挽输出。
  1. USART3 参数配置

    这段代码配置了USART3的通信参数:

    • USART_BaudRate = 9600;:设置波特率为9600bps。这是BY8301-16P语音模块的常用波特率。
    • USART_WordLength = USART_WordLength_8b;:设置数据字长为8位。
    • USART_StopBits = USART_StopBits_1;:设置停止位为1位。
    • USART_Parity = USART_Parity_No;:禁用奇偶校验。
    • USART_HardwareFlowControl = USART_HardwareFlowControl_None;:禁用硬件流控制。
    • USART_Mode = USART_Mode_Tx|USART_Mode_Rx;:使能USART3的发送和接收功能
  2. 中断配置

    这段代码配置了USART3的接收中断:

    • USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);:使能USART3的接收非空中断。这意味着当接收缓冲区有新的数据时,会触发中断。
    • NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;:指定中断通道为USART3的中断。
    • NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;:设置抢占优先级为1。
    • NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;:设置子优先级为1。
    • NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;:使能USART3中断。
    • NVIC_Init(&NVIC_InitStructure);:初始化NVIC
  3. 使能 USART 和清除标志位

    • USART_Cmd(USART3, ENABLE);:使能USART3模块,使其开始工作。
    • USART_ClearFlag(USART3,USART_FLAG_TC);:清除USART3的发送完成标志位。这通常在发送数据之前或发送数据后进行,以确保发送状态的正确性

2、 audio_proc():语音处理函数

通过USART3(串口3)向BY8301-16P语音模块发送命令,播放指定编号的音频文件。

void audio_proc(uint8_t num){ // 定义一个包含串口发送命令的字节数组 uint8_t string[]={0x7E,0x05,0x41,0x00,num,0x05^0x41^0x00^num,0xEF}; uint8_t i = 0; // 循环计数器 for(i=0;i<7;i++) // 循环发送7个字节的命令 { USART_SendData(USART3, string[i]); // 发送当前字节 // 等待发送完成标志位被置位,确保当前字节发送完毕才发送下一个字节 while( USART_GetFlagStatus(USART3, USART_FLAG_TC)==0 ); }}
1. 、函数声明
  • void audio_proc(uint8_t num):
    • void: 表示函数没有返回值。
    • audio_proc: 函数名称,表示“音频处理”或“播放音频”。
    • uint8_t num: 函数接收一个名为 num 的无符号8位整数作为参数。这个 num 就是你想要播放的音频文件在模块内部的编号
2. 定义串口发送命令数组
  • uint8_t string[]={0x7E,0x05,0x41,0x00,num,0x05^0x41^0x00^num,0xEF};
    这行代码定义了一个字节数组 string,它包含了发送给BY8301-16P语音模块的串口命令。根据之前对BY8301-16P串口通信协议的了解,这是一个标准的**“选曲播放”**命令。让我们逐个分析这些字节:

    在这里插入图片描述
    在这里插入图片描述

    • 0x7E: 起始码 (Start Code)。所有命令的开始字节。
    • 0x05: 长度 (Length)。表示从“长度”到“校验码”之间的字节数。这里是 0x05,0x41, 0x00, num,0x05^0x41^0x00^num,共5个字节。所以实际长度是 5字节。
    • 0x41: 操作码 (Operation Code)。根据手册,0x41 是“选曲播放”命令的操作码。
    • 0x00: 参数1 (Parameter 1)。在选曲播放命令中,这个通常表示文件夹编号。0x00 通常代表根目录或不区分文件夹。
    • num: 参数2 (Parameter 2)。这就是传入函数的音频文件编号。例如,如果 num 是1,模块会播放编号为1的音频文件。
    • 0x05^0x41^0x00^num: 校验和 (Checksum)。这是从“长度”字节开始到“参数2”的所有字节的异或和。0x05(长度)^ 0x41(操作码)^ 0x00(参数1)^ num(参数2)。校验和用于验证数据传输的完整性。
    • 0xEF: 结束码 (End Code)。所有命令的结束字节。
3. 循环发送字节
  • uint8_t i = 0;:定义一个循环计数器 i,初始化为0。
  • for(i=0;i<7;i++): 这是一个 for 循环,将迭代7次。由于 string 数组有7个字节,这个循环会逐个发送 string 数组中的所有字节。
  • USART_SendData(USART3, string[i]);: 在每次循环中,这行代码将 string 数组中的当前字节 (string[i]) 发送给 USART3。
  • while( USART_GetFlagStatus(USART3, USART_FLAG_TC)==0 );: 这是一个阻塞等待循环。
    • USART_GetFlagStatus(USART3, USART_FLAG_TC): 这个函数用于检查 USART3 的 发送完成标志位 (Transmission Complete flag)。当 USART3 成功发送完一个字节的数据后,这个标志位会被置位。
    • ==0: 表示标志位没有被置位(即发送尚未完成)。
    • while(...): 只要 USART_FLAG_TC 标志位为0,程序就会一直停在这个 while 循环中,等待当前字节发送完毕。这样做的目的是确保每个字节都完全发送出去之后,才发送下一个字节,避免数据混乱或丢失。
4、总结作用:

audio_proc 函数的作用是:

  1. 根据传入的 num 值(音频文件编号),构造一个完整的BY8301-16P语音模块的“选曲播放”命令帧。
  2. 通过USART3(串口3)将这个命令帧中的每一个字节逐个发送出去。
  3. 在发送每个字节后,会等待直到该字节完全发送完成,才继续发送下一个字节,确保数据的正确传输。

简单来说,调用 audio_proc(5); 就会尝试让BY8301-16P语音模块播放编号为5的音频文件。

3、audio_volume():音量设置函数

在这里插入图片描述
其主要目的是通过USART3(串口3)向BY8301-16P语音模块发送命令,用于设置播放音量

void audio_volume(u8 volume){ // 定义一个包含串口发送命令的字节数组 u8 string[]={0x7e,0x04,0x31,volume,0x04^0x31^yinliang,0xef}; u8 i; // 循环计数器 for(i=0;i<6;i++) // 循环发送6个字节的命令 { USART_SendData(USART3,string[i]); // 发送当前字节 // 等待发送完成标志位被置位,确保当前字节发送完毕才发送下一个字节 while( USART_GetFlagStatus(USART3, USART_FLAG_TC)==0 ); }}

简单来说,调用 audio_volume(20); 就会尝试将BY8301-16P语音模块的音量设置为20(十六进制 0x14)。通常,音量范围是0到30(0x00到0x1E)。

USART_SendData(USART3,string[i]); // 发送当前字节
// 等待发送完成标志位被置位,确保当前字节发送完毕才发送下一个字节
while( USART_GetFlagStatus(USART3, USART_FLAG_TC)==0 );
}
}
简单来说,调用 audio_volume(20); 就会尝试将BY8301-16P语音模块的音量设置为20(十六进制 0x14)。通常,音量范围是0到30(0x00到0x1E)。

注意:如何把音频文件更新进BY8301-16P语音模块,请看官方的使用说明书。