单片机语音模块JQ8900

您所在的位置:网站首页 焊接USB接口新手教程 单片机语音模块JQ8900

单片机语音模块JQ8900

2024-07-10 10:09| 来源: 网络整理| 查看: 265

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

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) //[email protected] { 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; //È¡³öʮ룬ºó¼ÓÈë0x30 CRC_data = CRC_data + Buffer[i]; i++; Buffer[i] = *DATA%10+0x30; //È¥³ý¸÷룬ºó¼ÓÈë0x30 CRC_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 UART1_SendByte(*DAT); DAT++; } } unsigned char i; for(i=0; i UART1_SendByte(*DAT); DAT++; } } 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}; //²¥·ÅµÚÊ®¶þÊ× 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); } 您可能感兴趣的内容: 使用STM32F103C8T6硬件IIC驱动OLED显示屏 使用STM32F103模拟SPI控制0.96寸OLED显示屏(6针/7针)的方法详解 STM32F103硬件SPI控制0.96寸OLED显示屏(6针/7针)详解 使用STM32实现0.96寸4针OLED屏模块的功能 从零开始:使用正点原子F103精英板和CubeIDE的Hal库进行LCD驱动移植


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3