单片机与BY8301-16P语音模块串口通信详解:实现指定音频播放功能

基于单片机与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. 结构体定义

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

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

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

    6. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE);:使能USART3模块的时钟。USART3挂载在APB1总线上。
    7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);:使能GPIOB端口的时钟。USART3的引脚(PB10和PB11)位于GPIOB端口。
    8. 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的通信参数:

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

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

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

    16. USART_Cmd(USART3, ENABLE);:使能USART3模块,使其开始工作。
    17. 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语音模块,请看官方的使用说明书。
    

    作者:m0_74027440

    物联沃分享整理
    物联沃-IOTWORD物联网 » 单片机与BY8301-16P语音模块串口通信详解:实现指定音频播放功能

    发表回复