语音交互(第一篇)_ 呼唤STM32让舵机转动和停止

嵌入式之路,贵在日常点滴

                                                                ---阿杰在线送代码

目录

一、 LD3320模块介绍(类似于耳朵)

1、简介

2、 有三个工作模式

3、板上管脚资源

二、MP3模块(类似于嘴巴)

1、简介

2、板上管脚资源 

3、 MP3模块播放的指令和格式

三、LD3320和MP3之间的对话 

四、功能实现 


一、 LD3320模块介绍(类似于耳朵)

1、简介

LD3320是一颗基于非特定人语音识别(SI-ASR:Speaker-Independent Automatic Speech Recognition)技术的语音识别芯片,或者说是语音声控芯片。 

非特定人语音识别是什么

通俗点讲就是不用针对指定发音人的识别技术,这种语音识别技术不分年龄、性别,只要发音人说的是相同的语言就可以识别。再说得简单点,就是说只要是拼音可以拼出的发音,都是可以输入芯片进行识别的。

这个语音识别模块它不是智能的,不是说我们问它什么它就可以回答什么,它不像我们手机上的语音助手比如小爱或者Siri那样,能跟我们对答如流。这个模块能识别的内容,是需要我们提前设定好的,我们把要识别的关键词语列好,然后把这些关键词语以字符的形式传送到 LD3320 内部,这样才可以对用户说出的关键词语进行识别,而且在同一时刻,它最多是在50条关键词语中进行识别。

2、 有三个工作模式

1、普通模式:不同的工作模式可以通过程序编程来实现

2、口令模式:模块工作时,我们先要说出一个一级口令,比如“芝麻开门”,模块在识别到正确的一级口令后才进行下一级的识别

3、按键触发模式:模块工作时,我们在进行语音识别之前,需要先按一下按键,接下来才能进行下一步的识别

(不同的工作模式可以通过程序编程来实现)

这三个模式我觉得口令模式比较实用,本实验,我用的就是口令模式。

3、板上管脚资源

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第1张图片

如上图中这个语音识别模块的图片,红色框框中的引脚就是我们可以用的IO,竖着那一排由下而上标着P10~P17有八个,横着那一排从左往右是P34、P33,P23~P27,P41,也有8个,这样我们可以用的IO口就有16个啦,这16个IO口可以用来控制继电器,LED,或者接单片机的IO口。 

上图中,最左边由下而上标着5V,GND,TX,RX的四个引脚就是用来给模块下载程序的地方,串口就在这里了。我们通过串口给其它模块或者单片机发数据也是从这里接。 

二、MP3模块(类似于嘴巴)

1、简介

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第2张图片模块型号名称是MP3-TF-16P,别看它体积不大,功能可是很强大的。简单来说,它就是一个音乐播放器,可以用来播放U盘、TF卡、NOR FLASH里的MP3、WAV、WMA格式的音频文件,同时它也可以作为电脑的声卡,用来播放电脑的声音。它也可以作为读卡器,通过USB连接电脑后就可以更新TF卡里的内容,用来更新文件。 

这个小东西能用来放音乐,放广播,它不仅支持通过按键来选曲、调音量,还可以通过单片机来操作,这也就是说,我们可以通过编程,通过串口来发指令,指定它什么时候放哪首歌曲,放多大的音量,中途插不插播广告等,根本不用我们动手,程序上就解决了。 

2、板上管脚资源 

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第3张图片

一共有16个脚,左上角为第一个脚,是模块的电源输入引脚,输入电压范围是3.3-5V,建议用5V供电。

第一个脚是VCC,接5V电

第二个脚是RX,是UART 串行数据输入。

第三个脚是TX,是UART 串行数据输出

第四个脚是DAC_R,是音频输出右声道,可驱动耳机或者输出音频信号给功放。

第五个脚是DAC_L,是音频输出左声道。

第六个脚是SPK2,是接小喇叭+的,可以驱动小于3W的喇叭

第七个脚是GND,接电源负极

第八个脚是SPK1,是接小喇叭-的

第九个脚是IO1,是触发口,默认上一曲(长按音量-)。

第十个脚也是GND。

第十一个脚是IO2,也是触发口,默认下一曲(长按音量+)。

第十二个脚是ADKEY1,AD口1,当触发时是第一段(长按循环第一段)。

第十三个脚是ADKEY2,AD口2,当触发时是第五段(长按循环第五段)。

第十四个脚是USB+,USB+ DP,接U盘或插电脑的USB口。

第十五个脚是USB-,USB- DM,接U盘或插电脑的USB口。

最后一个是BUSY引脚,它是播放指示,有音频播放时是输出低电平,没有音频播放时是输出高电平。

串口接线电路图:

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第4张图片 

3、 MP3模块播放的指令和格式

指定播放一个MP3文件的指令是这样的:7E FF 06 03 00 00 01 FE F7 EF 

--》03 00 00 01这四个字节,代表的就是指定播放第一首歌曲,不需要信息反馈

从语音模块(LD3320)通过串口给MP3模块发这一串东西,MP3模块收到后就知道这是要播放第几个MP3文件 

7E 是起始位,固定不变的,都要有它

FF 这是这个模块的版本信息,也是固定不变的

06 指的是从上一字节开始,到后面的字节个数,也就是说,从FF开始,到06 03 00 00 01为止,一共有六个字节 

03 在这里,指的是指定曲目播放,也是固定不变的

00 在这里指的是不需要反馈信息。如果是01,就是要反馈信息,这里的反馈信息指的是MP3播放模块反馈给语音识别模块的信息

00 01 这里指的是歌曲序号,00是数据高字节,01是数据低字节,低字节01在这里表示的就是播放第一首歌曲

FE和F7指的是累加和校验,是用来给数据查错的

最后一位EF是结束位,当接收到这一位,就说明整个数据发送完毕了

-》设置那么复杂的指令是为了提高数据传输时的准确性

三、LD3320和MP3之间的对话 

思路:对于命令的传输我们通过串口来发送,当语音识别模块(LD3320)识别到我们的命令后,让它通过串口给这个MP3模块发送一串指令,这MP3模块接收到指令后,就播放相对应的MP3文件,这样不就实现了系统对我们的应答了嘛。 

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第5张图片

比如我设置这个语音识别模块的一级口令为“阿杰在线送代码”,我叫一声“阿杰在线送代码”,语音识别模块识别成功后就给MP3模块发送一个指令,指定播放一个MP3文件,而这个文件的内容是“主人,我在”,这样就完成了一个交互的过程。

好,先把硬件连接好,来个简单的电路图: 

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第6张图片左边这个是语音识别模块,右边的是MP3模块,它们电源正极和地都需要接,这个不用说,然后就是数据的传输了,通过串口来,它们的RX和TX交叉来接,RX接TX,TX接RX,这就完成了,很简单。 

四、功能实现 

通过语音识别模块(LD3320)识别想要执行的动作,MP3给出回应开始执行动作。 

实现:

一级指令:科技之城

MP3:主人,我在

二级指令:转动舵机

MP3:好的,开始转动舵机 (此时STM32读取LD3320给出的高低电平状态来开始执行动作)

一级指令:科技之城

MP3:主人,我在

二级指令:恢复原位

MP3:好的,恢复原位 (此时STM32读取LD3320给出的高低电平状态来开始执行动作)

程序我们直接利用商家给的初始化程序,我们去做修改即可。

需要修改的地方

语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第7张图片语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第8张图片语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第9张图片语音交互(第一篇)_ 呼唤STM32让舵机转动和停止_第10张图片废话不说上代码

*LDChips.c

uint8 LD_AsrAddFixed()
{	
    ...
    #define DATE_A 9   /*数组二维数值*/
	#define DATE_B 24		/*数组一维数值*/
	uint8 code sRecog[DATE_A][DATE_B] = {
														"ke ji zhi cheng",\		
														"kai shi shao shui",\
														"guan bi shao shuii",\
														"kai shi pao cha",\
														"hui shou di yi ge bei zi",\
													    "kai shi xi cha bei",\
														"zhuan dong duo ji",\
														"hui fu yuan wei",\
														"yin lue"
										};	/*添加关键词,用户修改*/
	uint8 code pCode[DATE_A] = {
															CODE_CMD,\
															CODE_KSSS,\
															CODE_GBSS,\
															CODE_KSPC,\
															CODE_HSDYGBZ,\
															CODE_KSXCB,\														
															CODE_ZDDJ,\
															CODE_HFYW,\
															CODE_YL
							  };	/*添加识别码,用户修改*/	
    ....
}
*LDChips.h

//识别码客户修改处 
#define CODE_CMD  0x00   //该命令码0x00用户不可进行修改。
#define CODE_GBSS	0x01		//开始烧水
#define CODE_KSSS	0x02		//关闭烧水
#define CODE_KSPC 0x04			//开始泡茶
#define CODE_HSDYGBZ 0x05		//回收第一个杯子
#define CODE_KSXCB 0x06			//开始洗茶杯
#define CODE_ZDDJ 0x07			//转动电机
#define CODE_HFYW 0x08			//恢复原位
#define CODE_YL 	0x09			//音乐
*usart.c
//直接在MP3的串口调试移植,需要修改一点东西

#include "config.h"
#define FOSC 22118400L      //System frequency
uint32_t baud=9600;           //UART baudrate
unsigned char Send_buf[20];				/*指针溢出了*/
/************************************************************************
函 数 名: 串口初始化
功能描述: STC10L08XE 单片机串口初始化函数
返回函数: none
其他说明: none
**************************************************************************/
void UartIni(void)
{
    SCON = 0x50;            //8-bit variable UART
    TMOD = 0x20;            //Set Timer1 as 8-bit auto reload mode
    TH1 = TL1 = -(FOSC/12/32/baud); //Set auto-reload vaule
    TR1 = 1;                //Timer1 start run
    ES = 1;                 //Enable UART interrupt
    EA = 1;                 //Open master interrupt switch
}
/***********************************************************
* 名    称: 
* 功    能: 
* 入口参数: 无 
* 出口参数:无
* 说    明: 					 
**********************************************************/
void Uart_Isr() interrupt 4 using 1
{	
	if(RI)
	{	
		  
	}

}
/************************************************************************
功能描述: 	串口发送一字节数据
入口参数:	DAT:带发送的数据
返 回 值: 	none
其他说明:	none
**************************************************************************/
void Uart_PutByte(uint8_t DAT)
{
	ES  =  0;
	TI=0;
	SBUF = DAT;
	while(TI==0);
	TI=0;
	ES = 1;
}
/************************************************************************
功能描述: 串口发送字符串数据
入口参数: 	*DAT:字符串指针
返 回 值: none
其他说明: API 供外部使用,直观!
**************************************************************************/
void PrintCom(uint8_t *DAT)
{
	while(*DAT)
	{
	 	Uart_PutByte(*DAT++);
	}	
}

void SendCmd(int len) 
{ 
	int a = 0;
	Uart_PutByte(0x7E); //起始
	for(a=0; a>8); 
	*(Str+a+1) = (unsigned char)(xorsum & 0x00ff); 
} 
void Uart_SendCMD(unsigned char CMD ,unsigned char feedback ,int dat) 
{ 
	Send_buf[0] = 0xff; //保留字节 
	Send_buf[1] = 0x06; //长度
	Send_buf[2] = CMD; //控制指令
	Send_buf[3] = feedback;//是否需要反馈
	Send_buf[4] = (unsigned char )((dat >> 8)&0xFF);//datah 
	Send_buf[5] = (unsigned char )(dat&0xFF); //datal 
	DoSum(Send_buf,6); //校验
	SendCmd(8); //发送此帧数据
}
*main.c

void 	User_handle(uint8 dat)
{
     //UARTSendByte(dat);//串口识别码(十六进制)
		 if(0==dat)
		 {
		  	G0_flag=ENABLE;
//				PrintCom("“主人,我在”命令识别成功\r\n");
				LED=0;
				Uart_SendCMD(0x03,0x00,0x01);
		 }
		 else if(ENABLE==G0_flag)
		 {	
		 		G0_flag=DISABLE;
				LED=1;
			 switch(dat)		   /*对结果执行相关操作,客户修改*/
			  {
				 	case CODE_KSSS:	 /*命令“全开”*/
//		PrintCom("“好的 开始烧水”命令识别成功\r\n");//串口输出提示信息(可删除)
						Uart_SendCMD(0x03,0x00,0x02);
						
													 break;
					case CODE_GBSS:			/*命令“测试”*/
//		PrintCom("“好的 关闭烧水”命令识别成功\r\n"); //串口输出提示信息(可删除)
						Uart_SendCMD(0x03,0x00,0x03);
						
													 break;

					case CODE_KSPC:		/*命令“复位”*/				
//		PrintCom("“好的 开始泡茶”命令识别成功\r\n"); //串口输出提示信息(可删除)
						Uart_SendCMD(0x03,0x00,0x04);						
						PA3=1;//让PA3端口为高电平 
													break;
					case CODE_HSDYGBZ:		/*命令“复位”*/				
//		PrintCom("“好的 回收第一个杯子”命令识别成功\r\n"); //串口输出提示信息(可删除)
						Uart_SendCMD(0x03,0x00,0x05);					
						PA3=0;//让PA3端口为低电平
													break;
					case CODE_KSXCB:		/*命令“复位”*/				
//		PrintCom("“好的 开始洗茶杯”命令识别成功\r\n"); //串口输出提示信息(可删除)
						Uart_SendCMD(0x03,0x00,0x06);					
						PA4=1;//让PA4端口为高电平
													break;
					case CODE_ZDDJ:
						Uart_SendCMD(0x03,0x00,0x07);
						PA1=1;//让PA2端口为高电平
													break;
					case CODE_HFYW:
						Uart_SendCMD(0x03,0x00,0x08);
						PA1=0;//让PA1端口为高电平
													break;
					case CODE_YL:
						Uart_SendCMD(0x03,0x00,0x09);
													break;
																										
							default:
//		PrintCom("请重新识别发口令\r\n"); //串口输出提示信息(可删除)
													break;
				}	
			}	
			else 	
			{
//				PrintCom("请说出一级口令\r\n"); //串口输出提示信息(可删除)	
			}
}	 

上电后,你会发现MP3不给你回应,你可以尝试给MP3重新复位,即地拔掉再插上 

下面是STM32的代码 

 

//用来判断语音识别给的是高电平还是低电平来执行动作

#include "duoji.h"

void duoji_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义一个结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA 使能PC端口时钟 rcc.h-693
		
	
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPD;//PA15 设置成下拉输入
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
	GPIO_Init(GPIOA,&GPIO_InitStructure);//根据设定参数初始化GPIOE.5	

}

#define DUOJI GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)//读取 PA8 电平
main.c


		//舵机调试
		if(DUOJI == 1)	
		{
			TIM_SetCompare1(TIM3,75);//舵机90度		
			delay_ms(500);
			TIM_SetCompare1(TIM3,100);//舵机135度
			delay_ms(500);		
			TIM_SetCompare1(TIM3,125);//舵机180度
			delay_ms(500);		
			TIM_SetCompare1(TIM3,100);//舵机135度
			delay_ms(500);
			TIM_SetCompare1(TIM3,75);//舵机90度		
			delay_ms(500);
			TIM_SetCompare1(TIM3,50);//舵机45度	
			delay_ms(500);
			TIM_SetCompare1(TIM3,20);//舵机45度	
			delay_ms(500);
		}	
		else
		{
			TIM_SetCompare1(TIM3,75);//舵机90度		
			delay_ms(500);
		}	

你可能感兴趣的:(语音交互项目,c语言)