系列文章目录
文章目录
- 系列文章目录
- 前言
- 1 JQ6500简介
- 2 基本参数说明
- 2.1 硬件参数
- 2.2 模块管脚说明
- 3 控制方式
- 3.1 通信格式
- 3.2 通信指令
- 4 硬件设计
- 5 软件设计
- 5.1 main.c
- 5.2 board_config
- 5.2.1board_config.h
- 5.2.2 board_config.c
- 5.3 module_config
- 5.3.1 module_config.h
- 5.3.2 module_config.c
- 5.4 jq6500
- 5.4.1 jq6500.h
- 5.4.2 jq6500.c
- 总结
前言
本节介绍下JQ6500语音播报模块的使用,基于的单片机是STM32F103RCT6。主要完成以下功能:
1、制作一个JQ6500驱动程序
2、通过按键进行切换上一曲、下一曲;增加音量,减小音量
1 JQ6500简介
JQ6500 是一个提供串口的MP3芯片,完美的集成了MP3、WMV的硬解码。同时软件支持TF卡驱动,支持电脑直接更新spi flash的内容,支持FAT16、FAT32文件系统。通过简单的串口指令即可完成播放指定的音乐,以及如何播放音乐等功能,无需繁琐的底层操作,使用方便,稳定可靠是此款产品的最大特点。另外该芯片也是深度定制的产品,专为固定语音播放领域开发的低成本解决方案。
2 基本参数说明
2.1 硬件参数
2.2 模块管脚说明
3 控制方式
3.1 通信格式
支持异步串口通讯模式,通过串口接受上位机发送的命令
通讯标准:9600 bps
数据位 :8
校验位 :none
流控制 :none
例如,如果我们指定播放,就需要发送:7E 04 03 00 01 EF,红色代表第几首, 01表示
第一首,02表示第二首… 即从01开始计算;
数据长度为4 ,这4个字节分别是[04 03 00 01] 。不计算起始、结束。
组合播放:
连续发送【7E 04 03 00 01 EF】【7E 04 03 00 02 EF】【7E 04 03 00 03 EF】,则连续播放第一首、第二首、第三首,最多可以十首组合,播放完停止
3.2 通信指令
例如,下一曲,发送:7E 02 01 EF
例如,上一曲,发送:7E 02 02 EF
例如,播放, 发送:7E 02 0D EF
4 硬件设计
JQ6500与STM32F103RCT6接线图:
JQ6500 | STM32F103RCT6 |
---|---|
K1 | PC5 |
BUSY | PA5 |
TX | PC11 |
RX | PC10 |
DC-5V | VCC5 |
GND | GND |
JQ6500与喇叭接线图:
JQ6500 | 喇叭 |
---|---|
SPK- | 喇叭- |
SPK+ | 喇叭+ |
5 软件设计
5.1 main.c
#include "board_config.h"#include "board_test.h"#include "module_config.h"/************************************************JQ6500语音模块驱动实验现象:淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************//************************************* 全局变量 *******************************************************//************************************* 本地函数 *******************************************************//*
************************************************************
* 函数名称: main
*
* 函数功能:
*
* 入口参数: 无
*
* 返回参数: 0
*
* 说明:
************************************************************
*/
int main(void)
{// 初始化所有外设BOARD_InitAll();// 初始化所有模块MODULE_InitAll();UsartPrintf(USART_DEBUG,"这是JQ6500驱动实验\r\n");while (1) {BOARD_TestAll();}
}
5.2 board_config
5.2.1board_config.h
/*** @file board_config.h* @brief 板级配置头文件,定义外设对象及初始化函数* @author 胜磊电子* @date 未定义* @version 1.0* @copyright 淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3<br>* 咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014<br>* 哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click*/
#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H#include "led.h"
#include "beep.h"
#include "usart.h"
#include "key.h"
#include "delay.h"/*** @brief 调试打印使用的USART外设*/
#define USART_DEBUG USART1 // 调试打印所使用的串口组/*** @brief USART1接收缓冲区大小定义*/
#define USART1_RX_BUFFER_SIZE 512 // 接收缓冲区配置/*** @brief USART1发送缓冲区大小定义*/
#define USART1_TX_BUFFER_SIZE 512 // 发送缓冲区配置/*** @brief UART4接收缓冲区大小定义*/
#define UART4_RX_BUFFER_SIZE 512 // 接收缓冲区配置/*** @brief UART4发送缓冲区大小定义*/
#define UART4_TX_BUFFER_SIZE 512 // 发送缓冲区配置
/*** @brief 按键中断处理函数声明*/
#define KEYUP_IRQHandler EXTI0_IRQHandler
#define KEY012_IRQHandler EXTI9_5_IRQHandler// 导出LED对象供外部使用
extern LED_TypeDef BOARD_LED1; /**< 板载LED1对象 */
extern LED_TypeDef BOARD_LED2; /**< 板载LED2对象 */// 导出蜂鸣器对象供外部使用
extern Beep_TypeDef BOARD_BEEP; /**< 板载蜂鸣器对象 */// 导出串口对象供外部使用
extern USART_HandleTypeDef huart1; /**< USART1句柄对象 */
extern USART_InitParams usart1_params; /**< USART1初始化参数对象 */extern USART_HandleTypeDef huart4; /**< USART1句柄对象 */
extern USART_InitParams usart4_params; /**< USART1初始化参数对象 */// 按键配置 - 可在board_config.c中修改
extern Key_InitTypeDef BOARD_KEYS[];
extern const uint8_t BOARD_KEYS_NUM;/*** @brief 板级所有外设初始化函数* @details 初始化板上所有外设(LED、蜂鸣器、USART等)* @return 无*/
void BOARD_InitAll(void);#endif /* BOARD_CONFIG_H */
5.2.2 board_config.c
/*** @file board_config.c* @brief 板级配置实现文件,初始化板上所有外设* @author 胜磊电子* @date 未定义* @version 1.0* @copyright 淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3<br>* 咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014<br>* 哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click*/
#include "board_config.h"/************************************* 外设对象定义 *******************************************************//** * @brief 板载LED1对象* @details 对应引脚为PB0*/
LED_TypeDef BOARD_LED1; /**< 板载LED1(PB0) *//** * @brief 板载LED2对象* @details 对应引脚为PB1*/
LED_TypeDef BOARD_LED2; /**< 板载LED2(PB1) *//** * @brief 板载蜂鸣器对象* @details 对应引脚为PB8*/
Beep_TypeDef BOARD_BEEP; /**< 板载蜂鸣器(PB8) *//** * @brief USART1句柄对象* @details 初始化接收/发送缓冲区、缓冲区大小及状态标志*/
USART_HandleTypeDef huart1 = {.rx_buffer = (uint8_t[USART1_RX_BUFFER_SIZE]){0}, ///< 接收缓冲区(大小由USART1_RX_BUFFER_SIZE定义).rx_buffer_size = USART1_RX_BUFFER_SIZE, ///< 接收缓冲区大小.rx_len = 0, ///< 初始接收长度为0.rx_complete = 0, ///< 初始接收完成标志为0.tx_buffer = (uint8_t[USART1_TX_BUFFER_SIZE]){0}, ///< 发送缓冲区(大小由USART1_TX_BUFFER_SIZE定义).tx_complete = 1 ///< 初始发送完成标志为1(空闲状态)
};/** * @brief USART1初始化参数* @details 配置USART1的硬件信息、中断使能及优先级*/
USART_InitParams usart1_params = {.usart = USART1,.rcc_apb_periph_usart = RCC_APB2Periph_USART1,.rcc_apb_periph_gpio = RCC_APB2Periph_GPIOA,.gpio_port = GPIOA,.gpio_pin_tx = GPIO_Pin_9,.gpio_pin_rx = GPIO_Pin_10,.enable_rxne_interrupt = 1, // 使能RXNE中断.enable_idle_interrupt = 1, // 使能IDLE中断.enable_tc_interrupt = 0, // 禁用TC中断.nvic_irq_channel = USART1_IRQn,.nvic_preemption_priority = 1,.nvic_sub_priority = 1
};/** * @brief UART4句柄对象* @details 初始化接收/发送缓冲区、缓冲区大小及状态标志*/
USART_HandleTypeDef huart4 = {.rx_buffer = (uint8_t[UART4_RX_BUFFER_SIZE]){0}, ///< 接收缓冲区(大小由USART1_RX_BUFFER_SIZE定义).rx_buffer_size = UART4_RX_BUFFER_SIZE, ///< 接收缓冲区大小.rx_len = 0, ///< 初始接收长度为0.rx_complete = 0, ///< 初始接收完成标志为0.tx_buffer = (uint8_t[UART4_TX_BUFFER_SIZE]){0}, ///< 发送缓冲区(大小由USART1_TX_BUFFER_SIZE定义).tx_complete = 1 ///< 初始发送完成标志为1(空闲状态)
};/** * @brief USART1初始化参数* @details 配置USART1的硬件信息、中断使能及优先级*/
USART_InitParams usart4_params = {.usart = UART4,.rcc_apb_periph_usart = RCC_APB1Periph_UART4,.rcc_apb_periph_gpio = RCC_APB2Periph_GPIOC,.gpio_port = GPIOC,.gpio_pin_tx = GPIO_Pin_10,.gpio_pin_rx = GPIO_Pin_11,.enable_rxne_interrupt = 0, // 使能RXNE中断.enable_idle_interrupt = 0, // 使能IDLE中断.enable_tc_interrupt = 0, // 禁用TC中断.nvic_irq_channel = UART4_IRQn,.nvic_preemption_priority = 1,.nvic_sub_priority = 1
};/** * @brief 开发板按键配置数组* @details 定义了开发板上4个按键的配置参数,包括GPIO、中断设置等*/
Key_InitTypeDef BOARD_KEYS[] = {{RCC_APB2Periph_GPIOA, /**< GPIO时钟使能:GPIOA */GPIOA, /**< GPIO端口:GPIOA */GPIO_Pin_0, /**< 引脚:PA0 */GPIO_PortSourceGPIOA, /**< 端口源:GPIOA */GPIO_PinSource0, /**< 引脚源:Pin0 */EXTI_Line0, /**< 外部中断线:Line0 */EXTI0_IRQn, /**< 中断号:EXTI0_IRQn */2, /**< 抢占优先级:2 */1, /**< 子优先级:1 */EXTI_Trigger_Rising, /**< 触发方式:上升沿触发 */GPIO_Mode_IPD /**< GPIO模式:下拉输入 */},{RCC_APB2Periph_GPIOC, /**< GPIO时钟使能:GPIOC */GPIOC, /**< GPIO端口:GPIOC */GPIO_Pin_5, /**< 引脚:PC5 */GPIO_PortSourceGPIOC, /**< 端口源:GPIOC */GPIO_PinSource5, /**< 引脚源:Pin5 */EXTI_Line5, /**< 外部中断线:Line5 */EXTI9_5_IRQn, /**< 中断号:EXTI9_5_IRQn */2, /**< 抢占优先级:2 */2, /**< 子优先级:2 */EXTI_Trigger_Falling, /**< 触发方式:下降沿触发 */GPIO_Mode_IPU /**< GPIO模式:上拉输入 */},{RCC_APB2Periph_GPIOC, /**< GPIO时钟使能:GPIOC */GPIOC, /**< GPIO端口:GPIOC */GPIO_Pin_6, /**< 引脚:PC6 */GPIO_PortSourceGPIOC, /**< 端口源:GPIOC */GPIO_PinSource6, /**< 引脚源:Pin6 */EXTI_Line6, /**< 外部中断线:Line6 */EXTI9_5_IRQn, /**< 中断号:EXTI9_5_IRQn */2, /**< 抢占优先级:2 */2, /**< 子优先级:2 */EXTI_Trigger_Falling, /**< 触发方式:下降沿触发 */GPIO_Mode_IPU /**< GPIO模式:上拉输入 */},{RCC_APB2Periph_GPIOC, /**< GPIO时钟使能:GPIOC */GPIOC, /**< GPIO端口:GPIOC */GPIO_Pin_7, /**< 引脚:PC7 */GPIO_PortSourceGPIOC, /**< 端口源:GPIOC */GPIO_PinSource7, /**< 引脚源:Pin7 */EXTI_Line7, /**< 外部中断线:Line7 */EXTI9_5_IRQn, /**< 中断号:EXTI9_5_IRQn */2, /**< 抢占优先级:2 */2, /**< 子优先级:2 */EXTI_Trigger_Falling, /**< 触发方式:下降沿触发 */GPIO_Mode_IPU /**< GPIO模式:上拉输入 */}
};/** * @brief 按键数量常量* @details 计算并存储按键配置数组的元素个数*/
const uint8_t BOARD_KEYS_NUM = sizeof(BOARD_KEYS) / sizeof(BOARD_KEYS[0]);/************************************* 外设初始化函数 *******************************************************//*** @brief 初始化板载LED* @details 初始化BOARD_LED1(PB0)和BOARD_LED2(PB1)对应的GPIO引脚* @return 无*/
static void BOARD_InitLEDs(void) {// 初始化LED1 (PB0)LED_Init(&BOARD_LED1, GPIOB, GPIO_Pin_0);// 初始化LED2 (PB1)LED_Init(&BOARD_LED2, GPIOB, GPIO_Pin_1);
}/*** @brief 初始化板载蜂鸣器* @details 初始化BOARD_BEEP(PB8)对应的GPIO引脚* @return 无*/
static void BOARD_InitBeep(void) {// 初始化蜂鸣器 (PB8)Beep_Init(&BOARD_BEEP, GPIOB, GPIO_Pin_8);
}/*** @brief 初始化板载USART* @details 初始化USART1,设置波特率为115200* @return 无*/
static void BOARD_InitUSART(void) {// 初始化USART1,波特率为115200Usart_Init(&huart1, &usart1_params, 115200);// 初始化USART4,波特率为9600Usart_Init(&huart4, &usart4_params, 9600);
}/*** @brief 初始化开发板按键* @details 配置开发板上按键的GPIO和中断参数,使其可以触发中断* @return 无*/
static void BOARD_InitKeys(void) {Key_Init(BOARD_KEYS, BOARD_KEYS_NUM);
}/*** @brief 初始化延时模块* @details 配置系统时钟,选择指定的定时器作为延时基准* @param timer 选择的定时器编号 (如 1 表示 TIM2)* @return 无*/
static void BOARD_InitDelay(uint8_t timer) {// 初始化延时模块,选择 TIM2 作为延时定时器Delay_Init(timer);
}/************************************* 全局初始化函数 *******************************************************//*** @brief 初始化板上所有外设* @details 配置NVIC优先级分组,依次初始化LED、蜂鸣器和USART外设* @return 无* @note NVIC优先级分组配置为2(2位抢占优先级,2位子优先级)*/
void BOARD_InitAll(void) {// 配置中断优先级分组为2(2位抢占优先级,2位子优先级)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 初始化LEDBOARD_InitLEDs(); // 初始化蜂鸣器BOARD_InitBeep(); // 初始化USARTBOARD_InitUSART(); // 初始化按键BOARD_InitKeys(); // 使用 TIM2 作为延时定时器BOARD_InitDelay(1);
}
5.3 module_config
5.3.1 module_config.h
/*** @file module_config.h* @brief 模块配置实现文件,初始化所有模块* @author 胜磊电子* @date 未定义* @version 1.0* @copyright 淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3<br>* 咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014<br>* 哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click*/#ifndef MODULE_CONFIG_H
#define MODULE_CONFIG_H#include "usart.h"
#include "jq6500.h"// 模块初始化函数
void MODULE_InitAll(void);#endif /* MODULE_CONFIG_H */
5.3.2 module_config.c
/*** @file module_config.h* @brief 模块配置实现文件,初始化所有模块* @author 胜磊电子* @date 未定义* @version 1.0* @copyright 淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3<br>* 咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014<br>* 哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click*/#include "module_config.h"/*** @brief 初始化 MODULE_InitJQ6500 语音模块* @details 该函数用于初始化 MODULE_InitJQ6500 语音模块* @note 无* @return 无*/
static void MODULE_InitJQ6500(void) {JQ6500_Init(UART4);
}void MODULE_InitAll(void) {MODULE_InitJQ6500(); //液晶屏初始化
}
5.4 jq6500
5.4.1 jq6500.h
#ifndef JQ6500_H
#define JQ6500_H#include "system_config.h" // 根据实际使用的MCU型号修改/*** @brief 初始化JQ6500语音模块* @param USARTx 串口外设指针 (如USART1, USART2等)*/
void JQ6500_Init(USART_TypeDef* USARTx);/*** @brief 播放*/
void JQ6500_Play(void);/*** @brief 暂停*/
void JQ6500_Pause(void);/*** @brief 停止*/
void JQ6500_Stop(void);/*** @brief 上一曲*/
void JQ6500_Previous(void);/*** @brief 下一曲*/
void JQ6500_Next(void);/*** @brief 音量加*/
void JQ6500_VolumeUp(void);/*** @brief 音量减*/
void JQ6500_VolumeDown(void);/*** @brief 设置音量* @param volume 音量值(0-30)*/
void JQ6500_SetVolume(uint8_t volume);/*** @brief 指定曲目播放* @param track 曲目编号*/
void JQ6500_PlayTrack(uint16_t track);/*** @brief 单曲循环开关* @param enable 1-开启 0-关闭*/
void JQ6500_SingleLoop(uint8_t enable);/*** @brief 循环播放*/
void JQ6500_CyclePlay(void);/*** @brief 随机播放*/
void JQ6500_RandomPlay(void);/*** @brief 开启EQ模式* @param eq 0-正常 1-流行 2-摇滚 3-古典 4-爵士 5-贝斯*/
void JQ6500_SetEQ(uint8_t eq);#endif /* JQ6500_H */
5.4.2 jq6500.c
/*** @file jq6500.c* @brief JQ6500语音模块驱动实现* @author * @date * @version 1.0*/#include "jq6500.h"
#include "stm32f10x_usart.h" // 根据实际使用的MCU型号修改// 静态变量存储当前使用的串口外设
static USART_TypeDef* jq6500_usart = NULL;// JQ6500指令帧格式定义
#define JQ6500_FRAME_HEADER 0x7E // 帧头
#define JQ6500_FRAME_TAIL 0xEF // 帧尾
#define JQ6500_FRAME_VERSION 0x02 // 版本号/*** @brief 向JQ6500发送单字节指令* @param cmd 指令字节*/
static void JQ6500_SendCmd(uint8_t cmd) {if (jq6500_usart == NULL) return;uint8_t frame[4] = {JQ6500_FRAME_HEADER,JQ6500_FRAME_VERSION,cmd,JQ6500_FRAME_TAIL};// 使用标准库函数发送数据for (uint8_t i = 0; i < 4; i++) {USART_SendData(jq6500_usart, frame[i]);// 等待发送完成while (USART_GetFlagStatus(jq6500_usart, USART_FLAG_TXE) == RESET);}
}/*** @brief 向JQ6500发送数据* @param data 数据缓冲区* @param len 数据长度*/
static void JQ6500_SendData(uint8_t* data, uint16_t len) {if (jq6500_usart == NULL || data == NULL || len == 0) return;for (uint16_t i = 0; i < len; i++) {USART_SendData(jq6500_usart, data[i]);// 等待发送完成while (USART_GetFlagStatus(jq6500_usart, USART_FLAG_TXE) == RESET);}
}/*** @brief 初始化JQ6500语音模块* @param USARTx 串口外设指针*/
void JQ6500_Init(USART_TypeDef* USARTx) {jq6500_usart = USARTx;// 确保串口已在外部初始化完成(波特率、数据位等)
}/*** @brief 播放*/
void JQ6500_Play(void) {JQ6500_SendCmd(0x01);
}/*** @brief 暂停*/
void JQ6500_Pause(void) {JQ6500_SendCmd(0x02);
}/*** @brief 停止*/
void JQ6500_Stop(void) {JQ6500_SendCmd(0x04);
}/*** @brief 上一曲*/
void JQ6500_Previous(void) {JQ6500_SendCmd(0x02);
}/*** @brief 下一曲*/
void JQ6500_Next(void) {JQ6500_SendCmd(0x01); // 发送7E 02 06 EF
}/*** @brief 音量加*/
void JQ6500_VolumeUp(void) {JQ6500_SendCmd(0x0B);
}/*** @brief 音量减*/
void JQ6500_VolumeDown(void) {JQ6500_SendCmd(0x0C);
}/*** @brief 设置音量* @param volume 音量值(0-30)*/
void JQ6500_SetVolume(uint8_t volume) {if (volume > 30) volume = 30; // 音量范围限制uint8_t frame[5] = {JQ6500_FRAME_HEADER,JQ6500_FRAME_VERSION,0x13,volume,JQ6500_FRAME_TAIL};JQ6500_SendData(frame, 5);
}/*** @brief 指定曲目播放* @param track 曲目编号*/
void JQ6500_PlayTrack(uint16_t track) {uint8_t frame[6] = {JQ6500_FRAME_HEADER,JQ6500_FRAME_VERSION,0x07,(uint8_t)(track >> 8), // 曲目高8位(uint8_t)(track & 0xFF), // 曲目低8位JQ6500_FRAME_TAIL};JQ6500_SendData(frame, 6);
}/*** @brief 单曲循环开关* @param enable 1-开启 0-关闭*/
void JQ6500_SingleLoop(uint8_t enable) {uint8_t frame[5] = {JQ6500_FRAME_HEADER,JQ6500_FRAME_VERSION,0x19,enable ? 0x01 : 0x00,JQ6500_FRAME_TAIL};JQ6500_SendData(frame, 5);
}/*** @brief 循环播放*/
void JQ6500_CyclePlay(void) {JQ6500_SendCmd(0x11);
}/*** @brief 随机播放*/
void JQ6500_RandomPlay(void) {JQ6500_SendCmd(0x18);
}/*** @brief 开启EQ模式* @param eq 0-正常 1-流行 2-摇滚 3-古典 4-爵士 5-贝斯*/
void JQ6500_SetEQ(uint8_t eq) {if (eq > 5) eq = 0; // EQ模式范围限制uint8_t frame[5] = {JQ6500_FRAME_HEADER,JQ6500_FRAME_VERSION,0x1A,eq,JQ6500_FRAME_TAIL};JQ6500_SendData(frame, 5);
}
总结
以上,就是JQ6500的使用。