单片机语音模块JQ8900-16P的几种触发方式与源码配置

news/2024/11/16 22:57:33/

我先来讲一下这个模块方便在什么地方:
(我没有做广告哈,有一说一)

1,有SPI-flash,USB的接口直接连电脑显示U盘,替换音频很方便

2,默认情况下有IO口按键触发,很方便播放指定的曲目,说白了你把那个接口用手捏着就可以播放,方便吧;

3,IO口的触发的功能还可以自定义

4,支持单线串口,与双线串口通讯(UART)

还有一个原因就是引脚是焊接好的,对于新手而言,焊接排针还是有点点难度的

端口定义与参数

请添加图片描述
请添加图片描述

和单片机或者说是串口助手连线的时候,TX,RX交替连接。VPP是一线串口的引脚

接的喇叭功放要求2W,8欧以下,电源端最高不可以超过5.2V。

配置方式

1,IO口触发播放

2,双线串口

3,单线串口

1,IO口触发播放

请添加图片描述
请添加图片描述

注意音频文件命名与端口触发对照表;

当然端口也可以复用:

按照配置软件配置就行,主要是要实现在端口上的开始/暂停,上一曲/下一曲,这些操作

请添加图片描述

2,双线串口

这种方式也是我们最常用的一种方式,通过TX,RX与单片机通讯,接受单片机串口发送过来的指令进行事先通讯约定的操作:

重点关注的部分我已经用红线标明了:

请添加图片描述

一定一定注意这个和校验,每次修改指令的时候都要将校验码(SM)修改一遍,不然发送指令可能无响应。

请添加图片描述

详细的其他指令:
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

​ 看到这里你大概明白怎么操作了吧,就是调用串口发送函数将这些十六进制指令都发送到单片机,那么为了方便,我们一般呢将一个指令用数组的形式储存起来,然后调用由串口通讯单字节发送函数封装的指定字节发送函数就行。然后还有就是可以调用资料里面的串口软件直接生成相关指令,但是我一点那个软件就卡退。所以这里还是将每一条指令手编的。

我将常用的指令封装成数组,供大家参考:

(复制到keil5里面显示注释,这里md文档用utf-8显示的是乱码)

u8 code Mode0[] = {0xAA, 0x18, 0x01, 0x00, 0xC3};//Ñ­»·²¥·Åģʽ
u8 code Mode1[] = {0xAA, 0x18, 0x01, 0x01, 0xC4};
u8 code Mode2[] = {0xAA, 0x18, 0x01, 0x02, 0xC5};
u8 code Mode3[] = {0xAA, 0x18, 0x01, 0x03, 0xC6};
u8 code Mode4[] = {0xAA, 0x18, 0x01, 0x04, 0xC7};
u8 code Mode5[] = {0xAA, 0x18, 0x01, 0x05, 0xC8};
u8 code Mode6[] = {0xAA, 0x18, 0x01, 0x06, 0xC9};
u8 code Mode7[] = {0xAA, 0x18, 0x01, 0x07, 0xCA};u8 code PrevFile[] = {0xAA, 0x05, 0x00, 0xAF};//ÉÏÒ»Ê×
u8 code NextFile[] = {0xAA, 0x06, 0x00, 0xB0};//ÏÂÒ»Ê×
u8 code Play[] = {0xAA, 0x02, 0x00, 0xAC};    //²¥·Å
u8 code Stop[] = {0xAA, 0x04, 0x00, 0xAE};    //Í£Ö¹
u8 code Pause[] = {0xAA, 0x03, 0x00, 0xAD};    //Í£Ö¹
u8 code Path[] = {0xAA, 0x08, 0x10, 0x02, 0x2F, 0xB9, 0xE3, 0xB8, 0xE6, 0x2A, 0x2F, 0xD0, 0xA1, 0xC3, 0xD7, 0x2A, 0x4D, 0x50, 0x33, 0x8B, }; // flash   /¹ã¸æ*/СÃ×*MP3
u8 code Voiceup[] = {0xAA, 0x14, 0x00, 0xBE};  //ÒôÁ¿Ôö
u8 code Voicedown[] = {0xAA, 0x15, 0x00, 0xBF};//ÒôÁ¿¼õu8 code Play1[] = {0xAA, 0x07, 0x02, 0x00, 0x01, 0xB4}; //Ö¸¶¨²¥·ÅµÚ1Ê×
u8 code Play2[] = {0xAA, 0x07, 0x02, 0x00, 0x02, 0xB5}; //Ö¸¶¨²¥·ÅµÚ2Ê×
u8 code Play3[] = {0xAA, 0x07, 0x02, 0x00, 0x03, 0xB6}; //Ö¸¶¨²¥·ÅµÚ3Ê×
u8 code Play4[] = {0xAA, 0x07, 0x02, 0x00, 0x04, 0xB7}; //Ö¸¶¨²¥·ÅµÚ4Ê×
u8 code Play5[] = {0xAA, 0x07, 0x02, 0x00, 0x05, 0xB8}; //Ö¸¶¨²¥·ÅµÚ5Ê×
u8 code Play6[] = {0xAA, 0x07, 0x02, 0x00, 0x06, 0xB9}; //Ö¸¶¨²¥·ÅµÚ6Ê×
u8 code Play7[] = {0xAA, 0x07, 0x02, 0x00, 0x07, 0xBA}; //Ö¸¶¨²¥·ÅµÚ7Ê×
u8 code Play8[] = {0xAA, 0x07, 0x02, 0x00, 0x08, 0xBB}; //Ö¸¶¨²¥·ÅµÚ8Ê×
u8 code Play9[] = {0xAA, 0x07, 0x02, 0x00, 0x09, 0xBC}; //Ö¸¶¨²¥·ÅµÚ9Ê×u8 code Combine[] = {0xAA, 0x1B, 0x04, 0x30, 0x31 ,0X30 ,0X32 ,0x8C}; //×éºÏ²¥·ÅZHÎļþ¼ÐϵÄ01£¬02Îļþ

串口通讯函数

/************************************************************************
¹¦ÄÜÃèÊö£º ´®¿Ú·¢ËÍ×Ö·û´®Êý¾Ý
Èë¿Ú²ÎÊý£º 	*DAT£º×Ö·û´®Ö¸Õë
·µ »Ø Öµ£º none
ÆäËû˵Ã÷£º API ¹©ÍⲿʹÓã¬Ö±¹Û£¡
**************************************************************************/
void UART1_SendString(u8 *DAT,u8 Len)
{while(Len--){UART1_SendByte(*DAT);DAT++;}
}
/********************************************************************
¹¦ÄÜÃèÊö£º ´®¿Ú·¢ËÍ×Ö½ÚÊý¾Ý
Èë¿Ú²ÎÊý£º 	*DAT£º×Ö·û´®Ö¸Õë
·µ »Ø Öµ£º none
ÆäËû˵Ã÷£º API ¹©ÍⲿʹÓã¬Ö±¹Û£¡
********************************************************************/
void UART1_SendByte(u8 value)
{ES=0; //¹Ø±Õ´®¿ÚÖжÏTI=0; //Çå·¢ËÍÍê±ÏÖжÏÇëÇó±ê־λSBUF=value; //·¢ËÍwhile(TI==0); //µÈ´ý·¢ËÍÍê±ÏTI=0; //Çå·¢ËÍÍê±ÏÖжÏÇëÇó±ê־λES=1; //ÔÊÐí´®¿ÚÖжÏ
}

串口初始化函数(11.0592MHz的晶振,9600波特率)

void UartInit(void)		//9600bps@11.0592MHz
{PCON &= 0x7F;		//²¨ÌØÂʲ»±¶ËÙSCON = 0x50;		//8λÊý¾Ý,¿É±ä²¨ÌØÂÊTMOD &= 0x0F;		//Çå³ý¶¨Ê±Æ÷1ģʽλTMOD |= 0x20;		//É趨¶¨Ê±Æ÷1Ϊ8λ×Ô¶¯ÖØ×°·½Ê½TL1 = 0xFD;		//É趨¶¨Ê±³õÖµTH1 = 0xFD;		//É趨¶¨Ê±Æ÷ÖØ×°ÖµET1 = 0;		//½ûÖ¹¶¨Ê±Æ÷1ÖжÏTR1 = 1;		//Æô¶¯¶¨Ê±Æ÷1
}

另外想插一个便捷控制组合播放的函数:(指令代号1B)

如果按之前的配置方法,那么需要将我们需要组合播放的曲目名换成高低位的十六进制表示,但是因为组合播放要求是mp3文件放在名为“ZH”的文件夹下,而且曲目名只能是两个字节,例如说01,02这样子。

配置方法也很简单就是将十位数字+0x30作为高位,将个位数字+0x30作为低位数字。

下面是示例中配置的组合播放01,02的数组代码,用串口发送字节依次发送即可。

u8 code Combine[] = {0xAA, 0x1B, 0x04, 0x30, 0x31 ,0X30 ,0X32 ,0x8C};

但是每次都要重新编写数组的话不免有些复杂:下面这个函数就是替代了将十位数字+0x30作为高位,将个位数字+0x30作为低位数字,这个操作。

同样的如果我们要组合播放01,02,那么只需要向函数穿入数组 i[1,2] 就行,数组长度Len传入2。

/************************************************************************
¹¦ÄÜÃèÊö£º×éºÏ²¥±¨º¯Êý
Èë¿Ú²ÎÊý£º 	*DAT£º×Ö·û´®Ö¸Õë,Len×Ö·û´®³¤¶È
·µ »Ø Öµ£º none
ÆäËû˵Ã÷£º ½«ÐèÒª²¥±¨µÄÎļþÃû·ÅÈëÊý×éÖÐ×÷ΪÐβμ´¿É
**************************************************************************/
void  JQ_8x00_ZuHeBoFang(u8 *DATA,u8 Len)
{u16 CRC_data=0,i = 3;u8 Buffer[ZH_MAX] ={0xaa,0x1b};Buffer[2] = Len*2;			//¼ÆËãÊý¾Ý³¤¶È(ÿ¸öÇúÄ¿ÓɸßλÓëµÍλ¹¹³É£¬ËùÒÔ³ËÒÔ2)CRC_data = CRC_data + 0xaa + 0x1b + Buffer[2];while(Len--){Buffer[i] = *DATA/10+0x30;			//È¡³öʮ룬ºó¼ÓÈë0x30CRC_data = CRC_data + Buffer[i];i++;Buffer[i] = *DATA%10+0x30;			//È¥³ý¸÷룬ºó¼ÓÈë0x30CRC_data = CRC_data + Buffer[i];i++;DATA++;}Buffer[i] = CRC_data;//УÑéλUART1_SendString(Buffer,i+1);
}

下面我想补充一个知识点:

就是我在编写串口连续发送函数的时候:

void UART1_SendString(u8 *DAT,u8 Len)
{while(Len--){UART1_SendByte(*DAT);DAT++;}
}

每次传入的数组还要数有几个元素,再将Len传入函数。是在是复杂。而且这个函数最大的缺点是,如果你数数,数少了。那么不会报错,而且芯片也没有反应。但是多了是没有问题的。

我第一想到构造的函数是这样的:进行数组大小次发送,每次发送完了以后数组的地址+1;

void UART1_SendData(u8 *DAT)
{unsigned char i;for(i=0; i<sizeof(DAT); i++){UART1_SendByte(*DAT);DAT++;}
}

但是实际上,传递到函数的数组名是数组的首地址,用sizeof(DAT)并不能求出数组的长度,得到的是指针变量DAT的内存大小,依据操作系统不同而异。

详细如下:

请添加图片描述

所以我用的这个函数:

void UART1_SendData(u8 *DAT)
{unsigned char i;for(i=0; i<6; i++){UART1_SendByte(*DAT);DAT++;}
}

因为,常用的指令中,一般都是发送4个,5个,最多6个十六进制数据。而组合播放用之前封装的函数也足够了;

3,单线串口

​ 需要单片机在端口处依照严格的时序通过高低电平持续的时间来表示逻辑0和1,优点就不用多说了,对于51单片机而言,只有P3_1与P3_0处的一个串口。如果使用单线通讯可以将串口节省出来用作蓝牙模块的连接啊什么的。单线通讯的连线是1号引脚口VPP引出的,具体看之前的引脚示意图:

请添加图片描述

这个第三条的脉冲比例基数我没查到词条,但是就我理解的话:

如果脉冲比例基数为4的话,就是示例,即

高定平:低电平=4:1 表示1

高定平:低电平=1:4 表示0

也不知道说的对不对哈,欢迎指正

请添加图片描述请添加图片描述

控制说明的单字节控制就是只需要发送一个指令就行,适用的指令都有标注

然后多字节的话需要先用0x0a清空上次的数字,然后发送2个十六进制数据一个表示十位,一个表示个位。

例如:0x01,0x05表示的是十进制的15

需要区分的是,我们之前说的第二种配置方式:双线串口的指定曲目播放的两个十六进制数据表示的要播放曲目编号的高8位和低8位,所以第二种方式一共可以播放65536首歌曲,这也是为什么第一首,第二首曲目的编号要定义成00001,00002的形式。

一线串口通讯示例:

请添加图片描述

依旧和双线通讯一样,我将单线通讯的常用函数代码做了一下封装方便大家直接调用:

常用指令集数组:

这里第4行将sda定义为P1^0接口,在diy的时候自己修改就行;

#define u8 unsigned char
#define u16 unsigned intsbit sda=P1^0;//½«µ¥Ïß½Ó¿Úsda¶¨ÒåΪP1^0
void Voiceup (void);
void Voicedown (void);
void Delay1us ( int T );
void SendData ( u8 addr );
void SendDataString(u8 *DAT,u8 Len);//ÒôÁ¿
u8 code Voice0[] = {0x0a,0x00,0x00,0x0c}; 
u8 code Voice10[] = {0x0a,0x01,0x00,0x0c}; 
u8 Voice20[] = {0x0a,0x02,0x00,0x0c}; //ÉϵçºóĬÈÏ20
u8 code Voice30[] = {0x0a,0x03,0x00,0x0c}; 
//²¥·Å
u8 code Play[] = {0x11};
u8 code Pause[] = {0x12};
u8 code Stop[] = {0x13};u8 code Next[] = {0x15};
u8 code Previous[] = {0x14};u8 code Play1[] = {0x0a,0x01,0x0b}; //²¥·ÅµÚÒ»Ê×
u8 code Play2[] = {0x0a,0x02,0x0b}; //²¥·ÅµÚ¶þÊ×
u8 code Play3[] = {0x0a,0x03,0x0b}; //²¥·ÅµÚÈýÊ×u8 code Play11[] = {0x0a,0x01,0x01,0x0b}; //²¥·ÅµÚʮһÊ×
u8 code Play12[] = {0x0a,0x01,0x02,0x0b}; //²¥·ÅµÚÊ®¶þÊ×

时序函数和简单封装的连续发送函数:

/*****************************************************************************º¯ Êý Ãû  : Delay1us¹¦ÄÜÃèÊö  : 1΢ÃëÑÓʱº¯ÊýÊäÈë²ÎÊý  : int TÊä³ö²ÎÊý  : ÎÞ·µ »Ø Öµ  :µ÷Óú¯Êý  :±»µ÷º¯Êý  :
*****************************************************************************/
void Delay1us ( int T )
{T = T - 70;do{;}while ( T-- );
}
/*****************************************************************************º¯ Êý Ãû  : SendData¹¦ÄÜÃèÊö  : Ò»Ïß´®¿Ú·¢Ëͺ¯ÊýÊäÈë²ÎÊý  : u16 NÊä³ö²ÎÊý  : ÎÞ
*****************************************************************************/
void SendData ( u8 addr )
{u8 i;EA = 0;/*·¢ËÍʱ¹ØµôÖжϣ¬·ÀÖ¹ÖжÏÓ°ÏìʱÐò  */sda = 1;/*¿ªÊ¼À­¸ã  */Delay1us ( 1000 );sda = 0;/*¿ªÊ¼Òýµ¼Âë*/Delay1us ( 2200 );/*´Ë´¦ÑÓʱ×îÉÙÒª´óÓÚ2ms£¬´Ë²ÎÊýÑÓʱΪ310ms  */for ( i = 0; i < 8; i++ ) /*×ܹ²8λÊý¾Ý  */{sda = 1;if ( addr & 0x01 ) /*3:1±íʾÊý¾Ýλ1,ÿ¸öλÓÃÁ½¸öÂö³å±íʾ  */{Delay1us ( 500 );sda = 0;Delay1us ( 210 );}else              /*1£º3±íʾÊý¾Ýλ0 ,ÿ¸öλÓÃÁ½¸öÂö³å±íʾ  */{Delay1us ( 210 );sda = 0;Delay1us ( 500 );}addr >>= 1;}sda = 1;EA = 1;
}/************************************************************************
¹¦ÄÜÃèÊö£º µ¥Ïß·¢ËÍÒ»´®Êý¾Ý
Èë¿Ú²ÎÊý£º 	*DAT£º×Ö·û´®Ö¸Õë
·µ »Ø Öµ£º none
ÆäËû˵Ã÷£º API ¹©ÍⲿʹÓã¬Ö±¹Û£¡
**************************************************************************/
void SendDataString(u8 *DAT,u8 Len)
{while(Len--){SendData(*DAT);DAT++;}
}

单线通信的音量只能设置一个事先确定好的值,没有连续递增或者递减功能,所以我封装了一个函数:
音量增大,音量减小函数:

u8 Voice20[] = {0x0a,0x02,0x00,0x0c}; //ÉϵçºóĬÈÏ20
void Voiceup (void)//Ôö´óÉùÒô
{ if(Voice20[2]==0x09){Voice20[2]=0x00;Voice20[1]++;}else{Voice20[2]++;};SendDataString(Voice20,4);
}void Voicedown (void)//¼õСÉùÒô
{if(Voice20[2]==0x00){Voice20[2]=0x09;Voice20[1]--;}else{Voice20[2]--;}SendDataString(Voice20,4); 
}

http://www.ppmy.cn/news/249121.html

相关文章

JQ8900-16P语音模组硬件使用

资料阅读 1.模组特征 1. 支持 MP3 WAV 硬件解码1. 支持采样率(KHz):8/11.025/12/16/22.05/24/32/44.1/481. 多种控制模式:两线串口模式、一线串口控制、按键模式1. 支持上一曲&#xff0c;下一曲&#xff0c;播放、暂停、停止、选曲、等常用功能控制1. 支持播放曲目序号获取&…

JQ8900-16P语音模块(驱动及测试)

今天&#xff0c;给大家带来的是JQ8900语音模块&#xff0c;这是硬件图&#xff1a; VPP: 单线串口&#xff08;就是接收脉冲信号的引进&#xff09; BUSY: 播放指示灯 RX: 接收段 TX: 发送段 DC-5V: 5v供电 SPK-: 扬声器负极 SPK: 扬声器正极 IO1~IO7是触发输入口&…

EPSON RX8900SA/CE 时钟芯片开发笔记

文章资料来源&#xff1a;《Epson&#xff08;爱普生&#xff09; RX8900SA_RX8900CE实时时钟模块 应用手册》 一、模块简介 I2C总线接口实时时钟模块 RX8900 SA / CE 内置32.768 kHz DTCXO&#xff0c;稳定性高&#xff08;Digital Temperature Compensated Xtal(crystal) O…

【RT-Thread】高精度RTC rx8900 驱动软件包

文章目录 1 介绍1.1 支持功能1.2 目录结构1.3 许可证1.4 依赖 2 实现功能2.1 rx8900驱动描述2.2 rx8900读寄存器接口2.3 rx8900写寄存器接口2.4 RT-Thread设备虚拟文件接口2.5 片内温度获取接口2.6 rtc设备注册rx8900设备注册rx8900私有信息初始化 3 获取 rx8900 软件包4 使用 …

玩转黑莓8900,不信你不会。超级实用

的问题 &#xff08;有个别的游戏不能正常退出&#xff0c;我只好删除&#xff09; 2、刷机 刷机教程 大家按照网上的来做就ok 但是网上的刷机教程我搜索了好几个都是7系bb的教程。其实大同小异。都是 1、安装desktop 2、安装rom 3、到C:/Program Files/Common Files/R…

JQ8900语音模块组合播放

实现按下按键4播报当前时间实验 本次作业实践性较强&#xff0c;代码其实比较简单&#xff0c;在JQ8900压缩包中也有相应实例 &#xff0c;重点在于理解串口发送的相关知识 下面展示一些 关键函数的代码。这些代码直接使用即可&#xff0c;关键在于理解函数之间调用的返回结果…

Arduino Uno接JQ8900-16p语音播报模块

Arduino Uno接JQ8900-16p语音播报模块 前言 ​ 记录一个比较好用的语音播报模块JQ8900&#xff0c;这个模块成本低廉&#xff08;十几块就能买到&#xff09;&#xff0c;使用方便。 ​ 此外&#xff0c;这个模块还有以下优点&#xff1a; ​ ①搭载配套的软件可以支持文字…

常用模拟低通滤波器的设计——契比雪夫II型滤波器

常用模拟低通滤波器的设计——契比雪夫II型滤波器 切比雪夫 II 型滤波器的振幅平方函数为&#xff1a; 式中&#xff0c;为有效带通截止频率&#xff0c; 是与通带波纹有关的参量&#xff0c; 大&#xff0c;波纹大&#xff0c;&#xff1b; 为 N 阶契比雪夫多项式。 在 Matl…