当前位置: 首页 > article >正文

STM32控制JQ8400语音播报模块

时间记录:2024/2/7

一、JQ8400引脚介绍

标示说明
ONE LINE一线操作引脚
BUSY忙信号引脚,正在播放语音时输出高电平
RX串口两线操作接收引脚
TX串口两线操作发送引脚
GND电源地引脚
DC-5V电源引脚,3.3-5V
DAC-RDAC输出右声道引脚
DAC-LDAC输出左声道引脚
SPK-喇叭-引脚
SPK+喇叭+引脚

二、一线操作

(1)时序图
1线时序图
(2)时序分析
2.2.1 总线拉低2ms以上产生引导码
2.2.2 发送数据“1”,高电平大于1200us,低电平大于400us,高低电平时间比例3:1
2.2.3 发送数据“0”,高电平大于400us,低电平大于1200us,高低电平时间比例1:3
2.2.4 发送一字节指令和数据时低位先发
(3)控制指令

指令(HEX)功能说明
00数字0数字0-9可以用于需要数字的功能,比如选曲、设置音量、设置EQ、设置循环模式、设置通道、设置插播曲目先发数字后发功能指令。
01数字0
02数字2
03数字3
04数字4
05数字5
06数字6
07数字7
08数字8
09数字9
0A清零数字清除发送的数字
0B选曲确认配合数字实现
0C设置音量0-30
0D设置EQ
0E设置循环模式
0F设置通道
10设置插播曲目
11播放单字节控制指令,仅需发送一个控制指令即可。
12暂停
13停止
14上一曲
15下一曲
16上一目录
17下一目录
18选择SD卡
19选择U盘
1A选择FLASH
1B系统睡眠
(4)注意点
  • 音频文件命名需要为5位数字,该5位数字即为曲目号,例如00001.mp3
  • 音频文件需要放置在根目录下
  • 引导码延时要大于2ms,建议使用4ms
  • 高低电平时间比例在2-5都可以识别到
  • 发送两个字节,中间空闲状态建议维持10ms以上
  • 三、二线串口操作

    (1)串口波特率9600,音频文件命名无要求,复制的顺序即播放的曲目号
    (2)常用的几个命令介绍,其余命令可通过查看操作手册设置

  • 设置音量:AA 13 01 音量0-30 SM校验和
  • 播放指定曲目:AA 07 02 曲目高 曲目低 SM校验和
  • 停止播放:AA 04 00 AE
  • 设置循环模式:AA 18 01 循环模式 SM校验和
  • 四、示例代码

    (1)头文件

    #ifndef __JQ8400_H__
    #define __JQ8400_H__
    #include "stm32f10x.h"
    #include "delay.h"
    #include "sys.h"
    
    #define ONELINERCC      RCC_APB2Periph_GPIOB
    #define ONELINEGPIO     GPIOB
    #define ONELINEPIN      GPIO_Pin_5
    #define ONELINE         PBout(5)
    
    void vJq8400Init(u8 mode);//初始化,0:ONELINE操作,1串口操作
    void vOnelineVolume(int vol);//设置音量
    void vOnelinePlay(int cnt,u8 loop);//播放音频,最大999
    void vOnelinePause(u8 mode);//暂停/继续
    void vOnelineStop(void);//停止
    void vUartVolume(u8 vol);//设置音量
    void vUartPlay(int cnt,u8 loop);//播放音频,最大999
    void vUartStop(void);//停止
    
    #endif
    
    

    (2)源文件

    #include "jq8400.h"
    
    void vJq8400Init(u8 mode)
    {
        if(mode==0){//ONELINE操作
            //初始化时钟配置端口
            RCC_APB2PeriphClockCmd(ONELINERCC,ENABLE);
            
            GPIO_InitTypeDef GPIO_InitStruct;
            GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_InitStruct.GPIO_Pin = ONELINEPIN;
            GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_Init(ONELINEGPIO,&GPIO_InitStruct);
            
            Delay_Init();
        }else if(mode==1){//串口操作
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        
            GPIO_InitTypeDef GPIO_InitStruct;
            GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
            GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//发送数据端口,复用推挽输出
            GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
            GPIO_Init(GPIOA,&GPIO_InitStruct);
            
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
            
            USART_InitTypeDef USART_InitStruct;
            USART_InitStruct.USART_BaudRate = 9600;//波特率
            USART_InitStruct.USART_Mode = USART_Mode_Tx;//模式,发模式
            USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据位长度,8位
            USART_InitStruct.USART_Parity = USART_Parity_No;//校验位
            USART_InitStruct.USART_StopBits = USART_StopBits_1;//一位停止位
            USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
            USART_Init(USART1,&USART_InitStruct);
            
            USART_Cmd(USART1,ENABLE);
        }
    }
    
    static void vJq8400SendByte(u8 dataOrCmd)
    {
        ONELINE=1;
        Delay_Ms(5);//两个字节发送之间的延时
        
        //发送引导码,大于2ms,建议为4ms
        ONELINE=0;
        Delay_Ms(4);
        
        for(u8 i=0;i<8;i++){//发送数据
            ONELINE=1;
            if(dataOrCmd&0x01){//最低位为1,发送位1,高低电平时间3:1表示发送1,脉冲比例基数2-5都可以识别
                Delay_Us(1200);
                ONELINE=0;
                Delay_Us(400);
            }else{//发送位0
                Delay_Us(400);
                ONELINE=0;
                Delay_Us(1200);
            }
            dataOrCmd >>= 1;
        }
        
        ONELINE=1;
        Delay_Ms(5);//恢复空闲状态
    }
    
    static void vUartSendByte(u8 data)
    {
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//0表示数据还未转移到移位寄存器,1表示数据已经移动到移位寄存器可以发送数据
        USART_SendData(USART1,data);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);//1表示发送完成
    }
    
    void vOnelineVolume(int vol)
    {
        vJq8400SendByte(0x0A);//清除数字
        vJq8400SendByte(vol/10);//设置音量
        vJq8400SendByte(vol%10);
        vJq8400SendByte(0x0C);//设置音量
    }
    
    void vOnelinePlay(int cnt,u8 loop)
    {
        vJq8400SendByte(0x0A);//清除数字
        vJq8400SendByte(cnt/100);//设置数字
        vJq8400SendByte(cnt/10%10);
        vJq8400SendByte(cnt%10);
        vJq8400SendByte(0x0B);//确认选曲
        
        vJq8400SendByte(0x0A);//清除数字
        vJq8400SendByte(loop);//设置数字
        vJq8400SendByte(0x0E);//设置循环模式,0:倒序循环播放音频文件,1:循环播放当前曲目,2:播放1次,3:循环随机播放音频文件
        
        vJq8400SendByte(0x11);//播放选曲
    }
    
    void vOnelinePause(u8 mode)
    {
        if(mode==0)
            vJq8400SendByte(0x12);
        else if(mode==1)
            vJq8400SendByte(0x11);
    }
    
    void vOnelineStop(void)
    {
        vJq8400SendByte(0x13);
    }
    
    void vUartVolume(u8 vol)
    {
        vUartSendByte(0xAA);
        vUartSendByte(0x13);
        vUartSendByte(0x01);
        vUartSendByte(vol);
        vUartSendByte((0xAA+0x13+0x01+vol));//SM校验和
    }
    
    void vUartPlay(int cnt,u8 loop)
    {
        //设置循环模式
        vUartSendByte(0xAA);
        vUartSendByte(0x18);
        vUartSendByte(0x01);
        if(loop==0){
            vUartSendByte(0x02);
            vUartSendByte(0xC5);
        }else if(loop==1){
            vUartSendByte(0x01);
            vUartSendByte(0xC4);
        }
        
        //播放曲目
        vUartSendByte(0xAA);
        vUartSendByte(0x07);
        vUartSendByte(0x02);
        vUartSendByte(cnt/255);
        vUartSendByte(cnt%255);
        vUartSendByte((0xAA+0x07+0x02+cnt));//SM校验和
    }
    
    void vUartStop(void)
    {
        vUartSendByte(0xAA);
        vUartSendByte(0x04);
        vUartSendByte(0x00);
        vUartSendByte(0xAE);
    }
    
    

http://www.kler.cn/a/234881.html

相关文章:

  • 关于使用拓扑排序算法实现解析勾稽关系优先级的研究和实现
  • Qwen文章阅读笔记
  • C++ OpenGL学习笔记(2、绘制橙色三角形绘制、绿色随时间变化的三角形绘制)
  • ubuntu22.04编译安装Opencv4.8.0+Opencv-contrib4.8.0教程
  • Word图片嵌入格式不正确的解决办法
  • 【活动邀请·深圳】深圳COC社区 深圳 AWS UG 2024 re:Invent re:Cap
  • JavaScript 设计模式之外观模式
  • CSS盒子的概念
  • 《UE5_C++多人TPS完整教程》学习笔记8 ——《P9 访问 Steam(Acessing Steam)》
  • 2021年通信工程师初级 实务 真题
  • 刘谦春晚魔术的数学原理
  • 【开源】SpringBoot框架开发个人健康管理系统
  • 介绍 HTTPS 中间人攻击
  • 26.篮球练习
  • Android编程权威指南(第四版)- 第 4 章 UI状态的保存与恢复
  • 【WPF.NET开发】优化性能:其他建议
  • fast.ai 机器学习笔记(三)
  • 【开源】JAVA+Vue.js实现森林火灾预警系统
  • Rhino.Inside带材质将Revit模型bake到Rhino
  • 使用 FFmpeg 将视频转换为 GIF 动画的技巧
  • kafka教程
  • JavaWeb后端开发(第一期):Maven基础、Maven的安装配置、如何创建maven项目模块、maven的生命周期
  • 链表:反转链表
  • Flask 入门7:使用 Flask-Moment 本地化日期和时间
  • [ai笔记1] 借着“ai春晚”开个场
  • 第三百一十五回