一、模塊介紹
JR6001是一種語(yǔ)音播放模塊,具有以下特性:
1. 自帶USB接口,可以靈活地替換SPI-flash中的語(yǔ)音內(nèi)容,無(wú)需安裝主機(jī)電腦來(lái)替換傳統(tǒng)語(yǔ)音芯片的語(yǔ)音。SPI FLASH直接模擬為U盤(pán),就像復(fù)制U盤(pán)一樣,非常方便。任何計(jì)算機(jī)系統(tǒng)都可以支持它【7?source】。
2. 支持MP3、WAV高質(zhì)量音頻格式,聲音優(yōu)美。
3. 24位DAC輸出,動(dòng)態(tài)范圍支持90dB,信號(hào)比85dB。
4. 支持兩線串口控制,AD控制。
5. USB更新語(yǔ)音文件,無(wú)需安裝驅(qū)動(dòng)程序,無(wú)需安裝軟件,直接復(fù)制,快速方便。支持XP系統(tǒng),WIN7,WIN8,WIN10系統(tǒng)。
6. 支持上一首歌,下一首歌,播放,暫停,停止,選歌,和其他常見(jiàn)功能控制。 7. 支持自由組合播放。 8. 支持30級(jí)音量調(diào)整。
9. 支持周期號(hào)設(shè)置,更多應(yīng)用,更人性化。
10. 專(zhuān)用BUSY信號(hào)輸出指示。
11. 成熟的指令和指令分析使應(yīng)用更穩(wěn)定。
12. 專(zhuān)用支持主機(jī)電腦,快速使用,易于調(diào)試,命令自動(dòng)生成【8?source】。
關(guān)注微信公眾號(hào)--星之援工作室 發(fā)送關(guān)鍵字(JR6001)
????
使用的注意事項(xiàng)
1.只需要配置一個(gè)串口即可,波特率為9600
二、移植使用(資料代碼中沒(méi)有移植后的代碼,需要自行移植)
1.串口配置
usart2.c
因?yàn)槲覀兪褂玫腏R6001模塊是需要使用串口進(jìn)行通信控制(詳情可在獲取的資料中查看),我們只需要用到該串口的發(fā)送端口即可,不需要處理JR6001回傳的數(shù)據(jù),所以接收中斷中的數(shù)據(jù)處理可略過(guò) ~~?(引用GPS的串口配置)
#include "delay.h"
#include "usart2.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
char rxdatabufer;
u16 point1 = 0;
_SaveData Save_Data;
#if EN_USART2_RX // 如果使能了接收
// 串口1中斷服務(wù)程序
// 注意,讀取USARTx->SR能避免莫名其妙的錯(cuò)誤
char USART_RX2_BUF[USART2_REC_LEN]; // 接收緩沖,最大USART_REC_LEN個(gè)字節(jié).
// 接收狀態(tài)
// bit15, 接收完成標(biāo)志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字節(jié)數(shù)目
u16 USART2_RX_STA = 0; // 接收狀態(tài)標(biāo)記
void Usart2_Init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOB時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // 串口3時(shí)鐘使能
USART_DeInit(USART2); // 復(fù)位串口3
// USART3_TX PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PB10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復(fù)用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化PB10
// USART3_RX PB11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化PB11
USART_InitStructure.USART_BaudRate = bound; // 波特率一般設(shè)置為9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字長(zhǎng)為8位數(shù)據(jù)格式
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一個(gè)停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 無(wú)奇偶校驗(yàn)位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 無(wú)硬件數(shù)據(jù)流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收發(fā)模式
USART_Init(USART2, &USART_InitStructure); // 初始化串口 3
USART_Cmd(USART2, ENABLE); // 使能串口
// 使能接收中斷
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 開(kāi)啟中斷
// 設(shè)置中斷優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 搶占優(yōu)先級(jí)3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子優(yōu)先級(jí)3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
NVIC_Init(&NVIC_InitStructure); // 根據(jù)指定的參數(shù)初始化VIC寄存器
CLR_Buf(); // 清空緩存
}
void USART2_IRQHandler(void) // 串口1中斷服務(wù)程序
{
u8 Res;
#ifdef OS_TICKS_PER_SEC // 如果時(shí)鐘節(jié)拍數(shù)定義了,說(shuō)明要使用ucosII了.
OSIntEnter();
#endif
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
Res = USART_ReceiveData(USART2); //(USART1->DR); //讀取接收到的數(shù)據(jù)
if (Res == '$')
{
point1 = 0;
}
USART_RX2_BUF[point1++] = Res;
if (USART_RX2_BUF[0] == '$' && USART_RX2_BUF[4] == 'M' && USART_RX2_BUF[5] == 'C') // 確定是否收到"GPRMC/GNRMC"這一幀數(shù)據(jù)
{
if (Res == 'n')
{
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); // 清空
memcpy(Save_Data.GPS_Buffer, USART_RX2_BUF, point1); // 保存數(shù)據(jù)
Save_Data.isGetData = true;
point1 = 0;
memset(USART_RX2_BUF, 0, USART2_REC_LEN); // 清空
}
}
if (point1 >= USART2_REC_LEN)
{
point1 = USART2_REC_LEN;
}
}
#ifdef OS_TICKS_PER_SEC // 如果時(shí)鐘節(jié)拍數(shù)定義了,說(shuō)明要使用ucosII了.
OSIntExit();
#endif
}
u8 Hand(char *a) // 串口命令識(shí)別函數(shù)
{
if (strstr(USART_RX2_BUF, a) != NULL)
return 1;
else
return 0;
}
void CLR_Buf(void) // 串口緩存清理
{
memset(USART_RX2_BUF, 0, USART2_REC_LEN); // 清空
point1 = 0;
}
void clrStruct()
{
Save_Data.isGetData = false;
Save_Data.isParseData = false;
Save_Data.isUsefull = false;
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); // 清空
memset(Save_Data.UTCTime, 0, UTCTime_Length);
memset(Save_Data.latitude, 0, latitude_Length);
memset(Save_Data.N_S, 0, N_S_Length);
memset(Save_Data.longitude, 0, longitude_Length);
memset(Save_Data.E_W, 0, E_W_Length);
}
#endif
usart2.h
功能函數(shù)的定義(引用GPS的串口配置)
#ifndef __USART2_H
#define __USART2_H
#include "stdio.h"
#include "sys.h"
#include "string.h"
//V1.3修改說(shuō)明
//支持適應(yīng)不同頻率下的串口波特率設(shè)置.
//加入了對(duì)printf的支持
//增加了串口接收命令功能.
//修正了printf第一個(gè)字符丟失的bug
//V1.4修改說(shuō)明
//1,修改串口初始化IO的bug
//2,修改了USART_RX_STA,使得串口最大接收字節(jié)數(shù)為2的14次方
//3,增加了USART_REC_LEN,用于定義串口最大允許接收的字節(jié)數(shù)(不大于2的14次方)
//4,修改了EN_USART1_RX的使能方式
//V1.5修改說(shuō)明
//1,增加了對(duì)UCOSII的支持
#define USART2_REC_LEN 200 //定義最大接收字節(jié)數(shù) 200
#define EN_USART2_RX 1 //使能(1)/禁止(0)串口1接收
extern char USART_RX2_BUF[USART2_REC_LEN]; //接收緩沖,最大USART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符
extern u16 USART2_RX_STA; //接收狀態(tài)標(biāo)記
#define false 0
#define true 1
//定義數(shù)組長(zhǎng)度
#define GPS_Buffer_Length 80
#define UTCTime_Length 11
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2
typedef struct SaveData
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData; //是否獲取到GPS數(shù)據(jù)
char isParseData; //是否解析完成
char UTCTime[UTCTime_Length]; //UTC時(shí)間
char latitude[latitude_Length]; //緯度
char N_S[N_S_Length]; //N/S
char longitude[longitude_Length]; //經(jīng)度
char E_W[E_W_Length]; //E/W
char isUsefull; //定位信息是否有效
} _SaveData;
void Usart2_Init(u32 bound);
extern char rxdatabufer;
extern u16 point1;
extern _SaveData Save_Data;
void CLR_Buf(void);
u8 Hand(char *a);
void clrStruct(void);
#endif
2.JR6001的功能代碼編寫(xiě)
1. 配置完串口后,我們需要開(kāi)始編寫(xiě)我們的控制函數(shù),包括模塊的讀忙,發(fā)送相關(guān)的功能控制函數(shù)等基礎(chǔ)功能
JR6001.c
功能函數(shù)的編寫(xiě)
#include "JR6001.h"
#include "usart.h"
#include "delay.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
// 延時(shí)函數(shù)重定義 JR6001延時(shí)函數(shù)定義,用戶(hù)自行更改為自己的延時(shí)函數(shù)
#define JR6001_ms(ms) delay_ms(ms)
#define JR6001_us(us) delay_us(us)
void JR6001_Volumecontrol(u8 num);
void JR6001_Init(void)
{
// GPIO端口設(shè)置
GPIO_InitTypeDef GPIO_InitStructure;
#ifdef JR6001_BUSY // 查忙引腳配置
RCC_APB2PeriphClockCmd(JR6001_BUSY_GPIO_CLK, ENABLE); // 使能POR時(shí)鐘
GPIO_InitStructure.GPIO_Pin = JR6001_BUSY_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = JR6001_BUSY_GPIO_Mode;
GPIO_Init(JR6001_BUSY_GPIO_PORT, &GPIO_InitStructure);
#endif
JR6001_Volumecontrol(31); // 設(shè)置音量
JR6001_ms(100);
}
// 串口發(fā)送數(shù)據(jù)
void JR6001_SendCode(u8 *str, u8 busy)
{
u16 len, i;
len = strlen((char *)str);
printf("%sn", str);
if (busy == 1 && JR6001_BUSY_IO == 0)
{
for (i = 0; i <= len; i++) // 循環(huán)發(fā)送數(shù)據(jù)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
; // 循環(huán)發(fā)送,直到發(fā)送完畢
USART_SendData(USART2, str[i]);
}
}
else if (busy == 0)
{
for (i = 0; i <= len; i++) // 循環(huán)發(fā)送數(shù)據(jù)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
; // 循環(huán)發(fā)送,直到發(fā)送完畢
USART_SendData(USART2, str[i]);
}
}
JR6001_ms(10);
}
// 基礎(chǔ)指令發(fā)送
void JR6001_Instruction(u8 *str, u8 busy)
{
u8 JR6001_Buff[20];
sprintf((char *)JR6001_Buff, "%srn", str);
JR6001_SendCode(JR6001_Buff, busy);
}
// 曲目選擇
void JR6001_SongControl(u8 num, u8 busy)
{
u8 JR6001_Buff[20];
if (num < 10)
{
sprintf((char *)JR6001_Buff, "A7:0000%drn", num);
JR6001_SendCode(JR6001_Buff, busy);
}
else if (num < 100)
{
sprintf((char *)JR6001_Buff, "A7:000%drn", num);
JR6001_SendCode(JR6001_Buff, busy);
}
else
{
sprintf((char *)JR6001_Buff, "A7:00%drn", num);
JR6001_SendCode(JR6001_Buff, busy);
}
}
// 音量選擇
void JR6001_Volumecontrol(u8 num)
{
u8 JR6001_Buff[20];
sprintf((char *)JR6001_Buff, "AF:%drn", num);
JR6001_SendCode(JR6001_Buff, 0);
}
/*
JR6001_Init();
JR6001_SongControl(5,0);
*/
JR6001.h
功能函數(shù)的定義
#ifndef __JR6001_H
#define __JR6001_H
#include "sys.h"
// 查忙使能
#define JR6001_BUSY 0 // 0.失能 1.使能
// JR6001查忙引腳配置 高電平忙
#define JR6001_BUSY_GPIO_CLK RCC_APB2Periph_GPIOA
#define JR6001_BUSY_GPIO_PORT GPIOA
#define JR6001_BUSY_GPIO_PIN GPIO_Pin_6
#define JR6001_BUSY_GPIO_Mode GPIO_Mode_IPD
#define JR6001_BUSY_IO GPIO_ReadInputDataBit(JR6001_BUSY_GPIO_PORT, JR6001_BUSY_GPIO_PIN) // 讀取查忙引腳
// JR6001串口命令[播放 暫停 上一曲 下一曲 音量加 音量減]
#define Play "A2"
#define Suspend "A3"
#define On_Song "A5"
#define Next_Song "A6"
#define Volumeadd "B0"
#define Volumesub "B1"
void JR6001_Init(void);
// 串口發(fā)送數(shù)據(jù)
void JR6001_SendCode(u8 *str, u8 busy);
// 基礎(chǔ)指令發(fā)送
void JR6001_Instruction(u8 *str, u8 busy);
// 曲目選擇
void JR6001_SongControl(u8 num, u8 busy);
// 音量選擇
void JR6001_Volumecontrol(u8 num);
#endif
三、參考
【STM32】 JR6001語(yǔ)音播放https://blog.csdn.net/m0_56051805/article/details/125116764?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170200319216800184185082%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=170200319216800184185082&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-125116764-null-null.142^v96^pc_search_result_base7&utm_term=stm32JR6001&spm=1018.2226.3001.4187
完整代碼請(qǐng)關(guān)注衛(wèi)星公眾號(hào)進(jìn)行獲取和咨詢(xún)
聯(lián)系方式 微信號(hào):13648103287