单片机语音模块JQ8900
我先来讲一下这个模块方便在什么地方:(我没有做广告哈,有一说一)
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显示的是乱码)
u8codeMode0[]={0xAA,0x18,0x01,0x00,0xC3};//Ñ»·²¥·Åģʽu8codeMode1[]={0xAA,0x18,0x01,0x01,0xC4};u8codeMode2[]={0xAA,0x18,0x01,0x02,0xC5};u8codeMode3[]={0xAA,0x18,0x01,0x03,0xC6};u8codeMode4[]={0xAA,0x18,0x01,0x04,0xC7};u8codeMode5[]={0xAA,0x18,0x01,0x05,0xC8};u8codeMode6[]={0xAA,0x18,0x01,0x06,0xC9};u8codeMode7[]={0xAA,0x18,0x01,0x07,0xCA};u8codePrevFile[]={0xAA,0x05,0x00,0xAF};//ÉÏÒ»Ê×u8codeNextFile[]={0xAA,0x06,0x00,0xB0};//ÏÂÒ»Ê×u8codePlay[]={0xAA,0x02,0x00,0xAC};//²¥·Åu8codeStop[]={0xAA,0x04,0x00,0xAE};//Í£Ö¹u8codePause[]={0xAA,0x03,0x00,0xAD};//Í£Ö¹u8codePath[]={0xAA,0x08,0x10,0x02,0x2F,0xB9,0xE3,0xB8,0xE6,0x2A,0x2F,0xD0,0xA1,0xC3,0xD7,0x2A,0x4D,0x50,0x33,0x8B,};//flash/¹ã¸æ*/СÃ×*MP3u8codeVoiceup[]={0xAA,0x14,0x00,0xBE};//ÒôÁ¿Ôöu8codeVoicedown[]={0xAA,0x15,0x00,0xBF};//ÒôÁ¿¼õu8codePlay1[]={0xAA,0x07,0x02,0x00,0x01,0xB4};//Ö¸¶¨²¥·ÅµÚ1Ê×u8codePlay2[]={0xAA,0x07,0x02,0x00,0x02,0xB5};//Ö¸¶¨²¥·ÅµÚ2Ê×u8codePlay3[]={0xAA,0x07,0x02,0x00,0x03,0xB6};//Ö¸¶¨²¥·ÅµÚ3Ê×u8codePlay4[]={0xAA,0x07,0x02,0x00,0x04,0xB7};//Ö¸¶¨²¥·ÅµÚ4Ê×u8codePlay5[]={0xAA,0x07,0x02,0x00,0x05,0xB8};//Ö¸¶¨²¥·ÅµÚ5Ê×u8codePlay6[]={0xAA,0x07,0x02,0x00,0x06,0xB9};//Ö¸¶¨²¥·ÅµÚ6Ê×u8codePlay7[]={0xAA,0x07,0x02,0x00,0x07,0xBA};//Ö¸¶¨²¥·ÅµÚ7Ê×u8codePlay8[]={0xAA,0x07,0x02,0x00,0x08,0xBB};//Ö¸¶¨²¥·ÅµÚ8Ê×u8codePlay9[]={0xAA,0x07,0x02,0x00,0x09,0xBC};//Ö¸¶¨²¥·ÅµÚ9Ê×u8codeCombine[]={0xAA,0x1B,0x04,0x30,0x31,0X30,0X32,0x8C};//×éºÏ²¥·ÅZHÎļþ¼ÐϵÄ01£¬02Îļþ串口通讯函数
/************************************************************************¹¦ÄÜÃèÊö£º´®¿Ú·¢ËÍ×Ö·û´®Êý¾ÝÈë¿Ú²ÎÊý£º*DAT£º×Ö·û´®Ö¸Õë·µ»ØÖµ£ºnoneÆäËû˵Ã÷£ºAPI¹©ÍⲿʹÓã¬Ö±¹Û£¡**************************************************************************/voidUART1_SendString(u8*DAT,u8Len){while(Len--){UART1_SendByte(*DAT);DAT++;}}/********************************************************************¹¦ÄÜÃèÊö£º´®¿Ú·¢ËÍ×Ö½ÚÊý¾ÝÈë¿Ú²ÎÊý£º*DAT£º×Ö·û´®Ö¸Õë·µ»ØÖµ£ºnoneÆäËû˵Ã÷£ºAPI¹©ÍⲿʹÓã¬Ö±¹Û£¡********************************************************************/voidUART1_SendByte(u8value){ES=0;//¹Ø±Õ´®¿ÚÖжÏTI=0;//Çå·¢ËÍÍê±ÏÖжÏÇëÇó±ê־λSBUF=value;//·¢ËÍwhile(TI==0);//µÈ´ý·¢ËÍÍê±ÏTI=0;//Çå·¢ËÍÍê±ÏÖжÏÇëÇó±ê־λES=1;//ÔÊÐí´®¿ÚÖжÏ}串口初始化函数(11.0592MHz的晶振,9600波特率)
voidUartInit(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的数组代码,用串口发送字节依次发送即可。
u8codeCombine[]={0xAA,0x1B,0x04,0x30,0x31,0X30,0X32,0x8C};但是每次都要重新编写数组的话不免有些复杂:下面这个函数就是替代了将十位数字+0x30作为高位,将个位数字+0x30作为低位数字,这个操作。
同样的如果我们要组合播放01,02,那么只需要向函数穿入数组i[1,2]就行,数组长度Len传入2。
/************************************************************************¹¦ÄÜÃèÊö£º×éºÏ²¥±¨º¯ÊýÈë¿Ú²ÎÊý£º*DAT£º×Ö·û´®Ö¸Õë,Len×Ö·û´®³¤¶È·µ»ØÖµ£ºnoneÆäËû˵Ã÷£º½«ÐèÒª²¥±¨µÄÎļþÃû·ÅÈëÊý×éÖÐ×÷ΪÐβμ´¿É**************************************************************************/voidJQ_8x00_ZuHeBoFang(u8*DATA,u8Len){u16CRC_data=0,i=3;u8Buffer[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);}下面我想补充一个知识点:
就是我在编写串口连续发送函数的时候:
voidUART1_SendString(u8*DAT,u8Len){while(Len--){UART1_SendByte(*DAT);DAT++;}}每次传入的数组还要数有几个元素,再将Len传入函数。是在是复杂。而且这个函数最大的缺点是,如果你数数,数少了。那么不会报错,而且芯片也没有反应。但是多了是没有问题的。
我第一想到构造的函数是这样的:进行数组大小次发送,每次发送完了以后数组的地址+1;
voidUART1_SendData(u8*DAT){unsignedchari;for(i=0;iunsignedchari;for(i=0;i0x0a,0x00,0x00,0x0c};u8codeVoice10[]={0x0a,0x01,0x00,0x0c};u8Voice20[]={0x0a,0x02,0x00,0x0c};//ÉϵçºóĬÈÏ20u8codeVoice30[]={0x0a,0x03,0x00,0x0c};//²¥·Åu8codePlay[]={0x11};u8codePause[]={0x12};u8codeStop[]={0x13};u8codeNext[]={0x15};u8codePrevious[]={0x14};u8codePlay1[]={0x0a,0x01,0x0b};//²¥·ÅµÚÒ»Ê×u8codePlay2[]={0x0a,0x02,0x0b};//²¥·ÅµÚ¶þÊ×u8codePlay3[]={0x0a,0x03,0x0b};//²¥·ÅµÚÈýÊ×u8codePlay11[]={0x0a,0x01,0x01,0x0b};//²¥·ÅµÚʮһÊ×u8codePlay12[]={0x0a,0x01,0x02,0x0b};//²¥·ÅµÚÊ®¶þÊ×时序函数和简单封装的连续发送函数:
/*****************************************************************************º¯ÊýÃû:Delay1us¹¦ÄÜÃèÊö:1΢ÃëÑÓʱº¯ÊýÊäÈë²ÎÊý:intTÊä³ö²ÎÊý:ÎÞ·µ»ØÖµ:µ÷Óú¯Êý:±»µ÷º¯Êý:*****************************************************************************/voidDelay1us(intT){T=T-70;do{;}while(T--);}/*****************************************************************************º¯ÊýÃû:SendData¹¦ÄÜÃèÊö:Ò»Ïß´®¿Ú·¢Ëͺ¯ÊýÊäÈë²ÎÊý:u16NÊä³ö²ÎÊý:ÎÞ*****************************************************************************/voidSendData(u8addr){u8i;EA=0;/*·¢ËÍʱ¹ØµôÖжϣ¬·ÀÖ¹ÖжÏÓ°ÏìʱÐò*/sda=1;/*¿ªÊ¼À¸ã*/Delay1us(1000);sda=0;/*¿ªÊ¼Òýµ¼Âë*/Delay1us(2200);/*´Ë´¦ÑÓʱ×îÉÙÒª´óÓÚ2ms£¬´Ë²ÎÊýÑÓʱΪ310ms*/for(i=0;iDelay1us(500);sda=0;Delay1us(210);}else/*1£º3±íʾÊý¾Ýλ0,ÿ¸öλÓÃÁ½¸öÂö³å±íʾ*/{Delay1us(210);sda=0;Delay1us(500);}addr>>=1;}sda=1;EA=1;}/************************************************************************¹¦ÄÜÃèÊö£ºµ¥Ïß·¢ËÍÒ»´®Êý¾ÝÈë¿Ú²ÎÊý£º*DAT£º×Ö·û´®Ö¸Õë·µ»ØÖµ£ºnoneÆäËû˵Ã÷£ºAPI¹©ÍⲿʹÓã¬Ö±¹Û£¡**************************************************************************/voidSendDataString(u8*DAT,u8Len){while(Len--){SendData(*DAT);DAT++;}}单线通信的音量只能设置一个事先确定好的值,没有连续递增或者递减功能,所以我封装了一个函数:音量增大,音量减小函数:
u8Voice20[]={0x0a,0x02,0x00,0x0c};//ÉϵçºóĬÈÏ20voidVoiceup(void)//Ôö´óÉùÒô{if(Voice20[2]==0x09){Voice20[2]=0x00;Voice20[1]++;}else{Voice20[2]++;};SendDataString(Voice20,4);}voidVoicedown(void)//¼õСÉùÒô{if(Voice20[2]==0x00){Voice20[2]=0x09;Voice20[1]--;}else{Voice20[2]--;}SendDataString(Voice20,4);}