完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
基于STM32(F103ZE)的LD3320语音控制系统
暑假快完了也什么成果,就打算做点东西来让这个暑假充实点。发现手头有一个LD3320语音模块,又刚学C#上位机,就想结合一个做一个小项目。 第一次写,多多包含。 我的目的是:可以语音控制一个LED灯 如果有条件就控制明亮度然后在LCD上显示出来,并且在上位机上也可以显示当前状态和控制LED状态。 材料 STM32开发板(我用的是正点原子的战舰V3 STM32F103ZET6大家也可以用自己的开发板做) LD3320语音模块 杜邦线 嗯 还需要电脑软件 keil4 或 keil5 因为下载的例程文件是keil4写的 而手头LCD屏的头文件都是keil5战舰的 所以两个都用到了 -VS2017 -串口调试助手 我用的是XCOME 然后就开始做了。 制作过程 硬件部分 想去找一些关于LD3320的资料。 我先去淘宝找了这个模块,发现有浏览了几家商家之后发现了资料关于LD3320的,很完整。 发现他有keil4已经写好的程序,我就下载下来,然后又找到引脚图 **虽然已经有图了,但是还要提醒下VCC和GND千万不要接反了!! ** 这样硬件部分就连接好了,接下来就是程序和上位机了- 程序部分 拿到例程后发现他的LED灯的端口不同,改成我们板子的LED #define LED1_PIN GPIO_Pin_5 #define LED1_GPIO_PORT GPIOB #define LED1_GPIO_CLK RCC_APB2Periph_GPIOB #define LED2_PIN GPIO_Pin_5 #define LED2_GPIO_PORT GPIOE #define LED2_GPIO_CLK RCC_APB2Periph_GPIOE 改之后,看他已经写的指令有哪些,有“流水灯”、“闪烁”、“按键触发”、“全灭”、“状态”这几个,试试管用不管 看串口部分配置是 115200 的波特率,打开串口调试工具。 设置好波特率之后打开串口 按复位键 对着模块用清晰的普通话讲“流水灯” (哈哈 开始说的几次都没识别出来 还以为有问题 慢点清晰后成功率明显提高了。 附图: 第一部分 尝试就成功了 接下来就是 修改代码 加上LCD 在LCD上也可以显示当时命令和状态。 还有就是把发送给上位机的串口数据做好 以便上位机能更好的识别命令和执行命令。 找了半天,战舰V3的LCD就只有正点原子哥写好的,是用keil5写的,还是在sys的支持下(因为sys头文件我在移植到keil4上时就有很多error),所以只能在5上写了。首先先创个工程把源代码原封不动的移植到5上,执行后结果正常,然后添加LCD的程序,因为sys头文件包含了delay、sys、usart所以串口部分也要替换掉,在主函数里添加头文件 初始化等函数; //添加头文集 #include "delay.h" #include "sys.h" //主函数下添加 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(); uart_init(115200); 然后试试,也正常。 接下来就是添加LCD程序 //添加头文件 #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下添加 void LCD_ShowChinese(u16 x,u16 y,u8 num,u8 size,u8 mode) { u8 csize; u8 temp,t1,t; u16 y0=y; csize=(2*(size/8+((size%8)?1:0))*(size/2)); //得到字体一个字符对应点阵集所占的字节数 for(t=0;t if(size==12)temp=chinese_12[num][t]; //调用1206字体 else if(size==16)temp=chinese_16[num][t]; //调用1608字体 else if(size==24)temp=chinese_24[num][t]; //调用2412字体 else return; //没有字体库 for(t1=0;t1<8;t1++) { if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR); else if(mode==0)LCD_Fast_DrawPoint(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); //L LCD_ShowChinese(103,40,10,16,1); //D LCD_ShowChinese(111,40,11,16,1); //3 LCD_ShowChinese(119,40,12,16,1); //3 LCD_ShowChinese(127,40,13,16,1); //2 LCD_ShowChinese(135,40,14,16,1); //0 LCD_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]数组中添加指令,数组序号要对应比如上边第二个是闪烁,这个数组中就要相应闪烁的函数 //比如第二个ss uint8 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为真,则需要支持OS OSIntEnter(); #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_RX_BUF=0; } } } else //还没收到0X0D { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(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 { } } 成功了!这样这个项目就完成了! 最后附上完整的项目文件。自行下载。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1792 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1626 浏览 1 评论
1094 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
732 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1682 浏览 2 评论
1943浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
740浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
577浏览 3评论
600浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
562浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 12:17 , Processed in 0.695832 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号