基于STM32(F103ZE的LD3320语音控制系统暑假快完了也什么成果,就打算做点东西来让这个暑假充实点。发现手头有一个LD3320语音模块,又刚学C#上位机,就想结合一个做一
基于STM32(f103ze )的LD3320声控系统暑假快结束了也没有什么收获,所以我打算做点什么来充实这个暑假。 我发现手头有LD3320语音模块,而且我刚学习了C#上位机,所以想做一个小项目。
因为是第一次写,所以请含有很多。
我的目的是对一个LED灯进行语音控制,有条件的话可以控制亮度并显示在LCD上,另外上位机也可以显示当前的状态并控制LED的状态。
材料STM32开发板(我使用的是正点原子的战舰V3 STM32F103ZET6。 大家也可以用自己的开发板做。 ) LD3320语音模块波本线)嗯,还需要电脑软件keil4或keil5。 因为下载的例行文件是keil4写的,所以手头的液晶屏的文件都是keil5战舰的,所以都用。
-VS2017
串行调试助手使用XCOME后开始。
我想去找关于制作过程http://www.Sina.com/LD3320的资料。
我先去淘宝找了这个模块,看了几家商家后找到了关于LD3320的资料。 完全。 附件地址3358 www.waveshare.net/wiki/LD 3320 _ board
我发现他有keil4写的程序,所以下载后找到了大头针地图
*虽然已经有图,但请注意VCC和GND绝对不要反向连接。 **
这样就连接了硬件部分。 接下来是程序和上位机-
得到硬件部分例行程序后,发现他的LED灯端口不一样,就改成了我们板上的LED
# define led1_ ping Pio _ pin _5# define led1_ gpio _ portgpiob # define led1_ gpio _ clk RCC _ AP B2 per iph _ gpiob # 看他已经写的命令是什么,有“流水灯”、“闪烁”、“按键触发”、“全灭”、“状态”几种,试试有没有用,确认串口配置是3333
设置波特率后,打开串口按重置按钮,对着模块用清晰的普通话说“流水灯”。 (虽然开始说了几次都没认出来,但我觉得有问题,慢慢澄清后成功率明显提高了。
图纸:
第一部分的尝试成功了。 接下来是修改代码,打开LCD,在LCD上显示当时的命令和状态。
然后将发送到上位机的串行数据,使上位功能能够识别并执行命令。
找了半天,战舰V3的LCD只有正点原子哥哥写了。 是用keil5写的,还是在sys的支持下(因为sys头文件在移植到keil4时有很多错误),只能写到5。 首先做一个项目,把源代码直接移植到5,运行后结果正常,再添加LCD的程序。 因为sys头文件包含delay、sys和usart,所以也会替换串行部分,并在主函数中添加头文件初始化等函数。
//标头文集# include ' delay.h ' # include ' sys.h '//在主函数下添加nvic _ prioritygroupconfig (nvic _ priority group _2) URT_init(115200; 而且,试试看,也很正常。
然后添加液晶屏程序
//添加头文件#include 'lcd.h' LCD_Init (; //将LCD_clear(white )添加到主函数中的POINT_COLOR=RED; LCD _ showstring (72,100,200,16,16,' Hello STM32!' ); 除了将它们添加到代码中外,还将lcd.c文件添加到工程项目中,以在道路上包含LCD文件夹
显示正常,我发现这样只会写英语,不会写汉字,所以添加了汉字显示
在lcd.c下输入voidLCD_showChinese(U16x,u16 y,u8 num,u8 size,u8 mode ) ) u8 size; u8 temp,t1,t; u16 y0=y; cize=(2* ) size/8 ) ) size%8)? 1:0 ) (* ) *(size/2 ); //得到的字体的1个字符占圆点点阵的字节数for(t=0; tcsize; t () if ) size==12 ) temp=chinese_12[num][t]; 1206字体elseif(size==16 ) temp=chinese_16[num][t]; 1608字体elseif(size==24 ) temp=chinese_24[num][t]; 调用2412字体else return; //没有字型银行for (t1=0; t18; t1 ) if(temp0x80 ) LCD_Fast_DrawPoint(x ) x,y,POINT_COLOR ); ELSEif(mode==0) LCD_Fast_DrawPoint(x ) x,y,BACK_COLOR ); temp=1; y; if () y-y0 )==size ) y=
y0;x++;break;}} } } //在lcd.h下添加void LCD_ShowChinese(u16 x,u16 y,u8 num,u8 size,u8 mode);//在指定位置显示一个汉字
因为用的时16*16大小的字体 所以在字库里添加字组时要添加到const unsigned char chinese_16[40][32]里。
接下来就是字体取模 我用这个PCtoLCD2002软件,配置好后,添加我们要用到的字体。
下边就是我们要的字组,复制到刚才说的数组里,在程序中添加 就OK了,还有好多汉字 我就不一一列举了,方法是一样的。 注意要把数字变大足以装下字组。
//主函数下添加 LCD_ShowChinese(29,40,5,16,1);//开LCD_ShowChinese(46,40,6,16,1);//始LCD_ShowChinese(63,40,7,16,1);//运LCD_ShowChinese(78,40,8,16,1);//行LCD_ShowChinese(95,40,9,16,1);//LLCD_ShowChinese(103,40,10,16,1);//DLCD_ShowChinese(111,40,11,16,1); //3LCD_ShowChinese(119,40,12,16,1);//3LCD_ShowChinese(127,40,13,16,1);//2LCD_ShowChinese(135,40,14,16,1);//0LCD_ShowChinese(143,40,15,16,1);//测LCD_ShowChinese(160,40,16,16,1);//试LCD_ShowChinese(177,40,17,16,1);//程LCD_ShowChinese(194,40,18,16,1);//序
这样就可以正常显示汉字了
然后找到LD3320.c文件下 语识别后要执行的部分 添加要显示的汉字 这样就做好了。注意:要在显示之前添加
LCD_ShowString(72,100,200,16,16," ");这样显示其下次的会把上次的覆盖掉,显示的就是新的内容。 试试
添加或修改口令
在LD3320.c里
//在LD_AsrAddFixed函数中sRecog[DATE_A][DATE_B]数组里加上你要说的口令的拼音 //比如第二个闪烁 uint8 sRecog[DATE_A][DATE_B] = { "liu shui deng",\"shan shuo",\"an jian chu fa",\"quan mie",\"zhuang tai"\};//和我的一样即可//在pCode[DATE_A]数组中添加指令,数组序号要对应比如上边第二个是闪烁,这个数组中就要相应闪烁的函数//比如第二个ssuint8 pCode[DATE_A] = { CODE_LSD,\CODE_SS,\CODE_AJCF,\CODE_QM,\CODE_JT\};//在Board_text函数中添加相应执行的函数//比如第二个Flicker_LED()static void Board_text(uint8 Code_Val){ switch(Code_Val) //¶Ô½á¹ûÖ´ÐÐÏà¹Ø²Ù×÷{case CODE_LSD: //ÃüÁî¡°Á÷Ë®µÆ¡±Glide_LED();break;case CODE_SS: //ÃüÁî¡°ÉÁ˸¡±Flicker_LED();break;case CODE_AJCF://ÃüÁî¡°°´¼ü´¥·¢¡±Key_LED();break;case CODE_QM://ÃüÁî¡°È«Ãð¡±Off_LED();break;case CODE_JT://ÃüÁ״̬¡±Jt_LED();break;default:break;}}//在下边添加相应函数所要执行的动作//Flicker_LED函数static void Flicker_LED(void){LED1_ON();LED2_ON();Delayms(0XFFF);LED1_OFF();LED2_OFF();Delayms(0XFFF);}
这样就添加了我们想要的命令了
完美!
接下来就是给上位机写好数据 我们用串口1。除了添加中断是否接收完成,还要添加们要用指令。
代码如下:
//在usart.c或者stm32f10x_it.c里添加void USART1_IRQHandler(void) //串口1中断服务程序{u8 Res;int i=0; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OSOSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收的数据必须是0x0d 0x0a结尾){Res =USART_ReceiveData(USART1);//读取接收到的数据if((USART_RX_STA&0x8000)==0)//接受未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000;//接收完成了if(USART_RX_STA&0x8000){if(strcmp(USART_RX_BUF,"全亮")==0){GPIO_ResetBits(GPIOE,GPIO_Pin_5);GPIO_ResetBits(GPIOB,GPIO_Pin_5);}if(strcmp(USART_RX_BUF,"第一个")==0){GPIO_ResetBits(GPIOE,GPIO_Pin_5);GPIO_SetBits(GPIOB,GPIO_Pin_5);}if(strcmp(USART_RX_BUF,"第二个")==0){GPIO_SetBits(GPIOE,GPIO_Pin_5);GPIO_ResetBits(GPIOB,GPIO_Pin_5);}if(strcmp(USART_RX_BUF,"全灭")==0){GPIO_SetBits(GPIOE,GPIO_Pin_5);GPIO_SetBits(GPIOB,GPIO_Pin_5);}USART_RX_STA=0x00000;for(i=0;i
(USART_REC_LEN-1))USART_RX_STA=0; //接收数据错误重新开始接收} }} }#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.OSIntExit(); #endif} #endif 软件部分 我要做一个能控制LED灯 并且可以显示当前LED状态的上位机
经过不断变化 最后设计的形象是这样的
在打开时自动扫描端口。
for (int i = 0; i <20; i++){ try { string str = "COM" + i; serialPort1.PortName = str; serialPort1.Open(); comboBox1.Items.Add(str); serialPort1.Close(); comboBox1.Text = str; } catch { }} 打开软件后自动监测COM口,然后波特率是115200点击连接,连接成功,连接按钮就会变成断开,连接失败就会弹出错误窗口。注意:如果在启动软件的时候没有把板子插上并打开,那么在打开软件的时候就不会有COM口,这是就需要通电板子并重新打开软件。
在连接之后就要监测LED当前状态,在keil5程序中,在监测到正确命令后,就会发送一个字符串printf("流水灯,指令识别成功")的提示,我们需要做的就是监测是否有”流水灯“字样的字符。我想在一个窗口显示接收到的数据,一个窗口显示目前的LED状态。遇到的问题就是serialPort1.ReadExisting();把接收代码里的字符串直接去识别的话是识别不成功的,如果去识别serialPort1.ReadLine();的话,可以成功识别,但是会造成显示窗口的卡死,为了解决这个问题,我又加了一个textbox控件,但是这个控件并不显示,只是拿到数据去做对比。这样就解决了这个问题。代码如下:
textBox2.Text=serialPort1.ReadExisting(); textBox1.AppendText(textBox2.Text); if (textBox2.Text.Contains("流")) textBox3.Text = "流水灯"; else if (textBox2.Text.Contains("闪")) textBox3.Text = "闪烁"; else if (textBox2.Text.Contains("按")) textBox3.Text = "按键触发"; else if (textBox2.Text.Contains("全")) textBox3.Text = "全灭"; else if (textBox2.Text.Contains("状")) textBox3.Text = "状态"; 这样就可以显示了。
附图:
:
最后就是控制LED 。因为程序一直在中断中运行,就需要不断给板子发命令,他才可以一直保持这种状态。这里我用一个定时器控件,当按键触发后,每隔很短的时间就给板子发送命令。代码如下:
private void button2_Click(object sender, EventArgs e){ if (button2.Text == "打开") try { button2.Text = "关闭"; timer1.Start(); } catch { } else { button2.Text = "打开"; timer1.Stop(); }}private void timer1_Tick(object sender, EventArgs e){ try { serialPort1.Write(comboBox3.Text + Environment + Environment.NewLine); textBox3.Text = comboBox3.Text; } catch { }} 成功了!这样这个项目就完成了!
最后附上完整的项目文件。自行下载。
https://download.csdn.net/download/weixin_42320020/16594044
还有很多不足的地方,希望大佬可以指正。也希望和爱好者交流学习。
第一次写,使用的很不熟练,写的不好希望不要介意。以后还会写。望多多交流学习。
禁止转载!!!
QQ:2039723308
VX:Shiboven