系列文章目錄
文章目錄
- 系列文章目錄
- 前言
- 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的使用。