基于嵌入式单片机的 STM32F103系列的 《语音识别模块HBR640》

        语音识别模块HBR640

        就近需要做一个有关语音交互的小项目,这个年代挺好,不用自己写识别算法,直接用芯片就好了大笑,于是乎上网找芯片去了。网友们都说快速开发而且要求不高的话用LD3320芯片还可以,不仅便宜,识别词条多,还集成了小型功放电路由于语音播放。可以满足要求。但是我的识别量比较少在100个左右,用不了LD3320那么多识别词条,所以想另寻他法。

        贴一些LD3320的资料偷笑

(ld3320资料网址 1. http://blog.chinaunix.net/xmlrpc.php?id=4358363&r=blog/article&uid=29270628

                                       2.http://blog.sina.com.cn/s/blog_52e8baa40101nik6.html    )

        后面在淘宝上寻找,找到了hbr640模块,芯片国产,便宜。。。。。优点是配备上位机,修改添加识别词条简单,还可以分识别组,单片机只需要遵守串口协议就可以读出结果或者播放语音了。控制方便,识别率挺高,词条刚好100个,正合我意。

        下面贴图:

*实物图

*上位机

*串口协议(部分)

    缺点:1.上位机没有集成语音生成WAV音频文件功能,需要第三方软件完成。睡觉

    我在使用过程中,发现官方给的STM32F4的开发历程,太过涉及道芯片本身特定库函数的调用了,注释较少,变量和宏定义太多,程序实现有些繁琐(当然我也知道商业化都这样,方便版本升级嘛,但是我用得就不是很舒服了委屈)。后面由于工程紧急,且要使用与官方历程不同的芯片实现适应性功能裁剪,没有时间先理解官方繁琐的变量和宏定义变换,再一一对应自己所用芯片就的相同功能一一修改。大哭

     所以自己照着不是很复杂的通信协议写了一个模块历程。我曾经在网上搜索这个模块,发现根本没有它的资料,所以我就写了一个命令集齐全的,且对本身芯片型号控制资源依赖少的程序模块出来和大家分享。希望减少大家因为更换芯片所需要增加的开发时间。和降低官方工程的开发难度,希望能够帮助到使用这个模块的人!大笑生气

.c文件

#include "sys.h" 
#include "hbr640.h"
#include "usart2.h"
#include "delay.h" /*改:芯片延时函数*/

unsigned char RX_data_count=0;
unsigned char Recognition_flag_count=0;
unsigned char 	Recognition_data[3]; 
unsigned char 	USART2_RX_data[3]; // 储存接收的3个数据
unsigned char  RX_data_flag=0;  // 接收3个数据成功标志

/*********************************************************************************
函数名称:hbr640_init
函数功能:初始化hbr640
入口参数:BaudRate  hbr640所用到的串口的波特率值
返回值:1 模块存在初始化成功  0 没有检测到模块初始化失败
*********************************************************************************/
unsigned char hbr640_init(unsigned int BaudRate) // 默认为115200 需要设置请在语音命令生成软件设置
{

	USART2_Init(BaudRate); /*改:芯片串口初始化*/
	SendData(0xA0,0xA0,0xA0); // 初始化语音模块命令
	if( ReadData(0x50,0x50,0x20,1) ) // 检查hbr640是否存在,芯片版本号是不是0x20(没个模块的版本号不同,请注意修改)
	{
//		Microphone_Sensitivity(0x2F,0x0C);
//		Noise_Limit(0x16,0x1c);
		Volume_Config(0x03);
		if(Recognition_Group(0x01,0x00))
		{
			Continuous_Recognition(1);
			Recognition_flag=1; // 初始化完成,开启识别结果储存
		}
		
		return 1;
	}
	return 0;
}	

/*********************************************************************************
函数名称:USART_DO
函数功能:放在串口接收成功的中断里
入口参数:无
返回值:无
*********************************************************************************/

void USART_DO(void)
{
	unsigned char key=1;
	if(!RX_data_flag) // 1.命令集的返回值收集,用于判断所发命令是否有效
	{
		if(RX_data_count<3) 
			USART2_RX_data[RX_data_count++] = USART_ReceiveData(USART2); /*改:芯片获取串口数据*/
		if(RX_data_count==3) 
		{
		  RX_data_count=0;
		  RX_data_flag=1;
		}
		key=0;
	}
	
	if(Recognition_flag==1 && key) // 2.用于与命令集返回值区分开来,单独接储存收识别的结果 
	{
		if(Recognition_flag_count<3)
			Recognition_data[Recognition_flag_count++] = USART_ReceiveData(USART2); /*改:芯片获取串口数据*/
		if(Recognition_flag_count==3) 
		{
			Recognition_flag=10;
			Recognition_flag_count=0;
		}
	}
}

/*********************************************************************************
函数名称:ReadData
函数功能: mode=1		接收hbr640传回的三组数据并与入口进行比对校验
			    mode=2	 将接收数据暂存入RxDataTemp数组中
入口参数:date1 date2 date3 说明书的接收命令集 
				  mode=1	用于接收命令不变的情况
					mode=2  用于接收命令变的情况
返回值:1 与入口参数相同  0 与入口参数不同  
*********************************************************************************/
unsigned char RxDataTemp[3]={0,0,0};
unsigned char ReadData(unsigned char date1,unsigned char date2,unsigned char date3,unsigned char mode)
{
	u32 sum=0;
	while(!RX_data_flag) //  等待模块回应
	{
		sum++;
		if(sum>80000) break;
	}
	if(mode==1)
	{
		if( sum<80000 && USART2_RX_data[0]==date1 &&  USART2_RX_data[1]==date2 && USART2_RX_data[2]==date3 )
		{
//			printf("->%d %d %d",USART2_RX_data[0],USART2_RX_data[1],USART2_RX_data[2]);
			USART2_RX_data[0]=0;
			USART2_RX_data[1]=0;
			USART2_RX_data[2]=0;
			return 1;
		}
	}
	else if(mode==2)
	{
//		printf("->%d %d %d ",USART2_RX_data[0],USART2_RX_data[1],USART2_RX_data[2]);
		if(sum<80000)
		{
			RxDataTemp[0]=USART2_RX_data[0];
			RxDataTemp[1]=USART2_RX_data[1];
			RxDataTemp[2]=USART2_RX_data[2];
			USART2_RX_data[0]=0;
			USART2_RX_data[1]=0;
			USART2_RX_data[2]=0;
			return 1;
		}
	}
	USART2_RX_data[0]=0;
	USART2_RX_data[1]=0;
	USART2_RX_data[2]=0;
	return 0;
}

/*********************************************************************************
函数名称:SendData
函数功能:date1 date2 date3 分别向hbr640发送一个字节的命令信息
入口参数:date1 date2 date3 都表示8位的1个字节数据
返回值:无
*********************************************************************************/
void SendData(unsigned char date1,unsigned char date2,unsigned char date3)//发送单个字节
{
	delay_us(50);
	USART_SendData(USART2,date1);
	while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
	delay_us(50);
	USART_SendData(USART2,date2);
	while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
	delay_us(50);
	USART_SendData(USART2,date3);
	while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
	RX_data_flag=0;
}

/*********************************************************************************
函数名称:Microphone_Sensitivity
函数功能:设置hbr640的麦克风灵敏度强度级数
入口参数:Strength_Series_Low 麦克风灵敏度下限  
				 Strength_Series_Hight 麦克风灵敏度上限
返回值:无
*********************************************************************************/
void Microphone_Sensitivity(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight)
{
	if( Strength_Series_Low!=0x2F && Strength_Series_Hight!=0X0B ) //  Strength_Series_Low=0x2F  Strength_Series_Hight=0X0B 是默认值
	{
		if(Strength_Series_Low>0x3F) Strength_Series_Low=0x3F; // 麦克风灵敏度下限范围0x00 至 0x3f   (十进制是0~77)
		if(Strength_Series_Hight>0x0f) Strength_Series_Hight=0x0F; // 麦克风灵敏度上限范围0x00 至 0x0f   (十进制是0~15)
		SendData(0xA1,Strength_Series_Low,Strength_Series_Hight);
	}
}

/*********************************************************************************
函数名称:Noise_Limit
函数功能:设置hbr640的麦克风噪声门限设置
入口参数:Strength_Series_Low 麦克风噪声下限  
				 Strength_Series_Hight 麦克风噪声上限
返回值:无
*********************************************************************************/
void Noise_Limit(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight)
{
//  Strength_Series_Low=0x16  Strength_Series_Hight=0X19 是默认值
	if( Strength_Series_Low!=0x16 && Strength_Series_Hight!=0X19 ) //  Strength_Series_Low=0x16  Strength_Series_Hight=0X19 是默认值
	{
		if(Strength_Series_Low>0x28) Strength_Series_Low=0x28;// 麦克风噪声下限范围0x16 至 0x28   (十进制是22~40)
		else if(Strength_Series_Low<0x16) Strength_Series_Low=0x16;
		if(Strength_Series_Hight>0x30) Strength_Series_Hight=0x30; // 麦克风噪声上限范围0x19 至 0x30   (十进制是25~48)
		else if(Strength_Series_Hight<0x19) Strength_Series_Hight=0x19;
		SendData(0xA2,Strength_Series_Low,Strength_Series_Hight);
	}
}

/*********************************************************************************
函数名称:Recognition_Group
函数功能:设置需要识别的语音组
入口参数:Strength_Series_Hight(0x**)  Strength_Series_Low(0x**) 组成 0xHHLL 的识别组数序号
返回值:1 设置成功  0 设置失败
*********************************************************************************/
unsigned char Recognition_Group(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight) // 0xHHLL 为需要设定识别的组数序号
{
  if(Strength_Series_Low<0x01) Strength_Series_Low=0x01; // 默认是第一组
	if(Strength_Series_Hight>0x64) Strength_Series_Hight=0x64; // hbr640的识别组数范围0x01 至 0x64   (十进制是1~100)
	SendData(0xA9,Strength_Series_Low,Strength_Series_Hight);
	ReadData(0,0,0,2);
//	printf("->%d %d %d ",RxDataTemp[0],RxDataTemp[1],RxDataTemp[2]);
	if( RxDataTemp[0]==0x59 && RxDataTemp[1]==Strength_Series_Low && RxDataTemp[2]==Strength_Series_Hight )
		return 1;
	return 0;
}

/*********************************************************************************
函数名称:Some_working_640
函数功能:在Once_Recognition或Continuous_Recognition之一的mode2调用它,
					起到循环接收640数据的作用
入口参数:无
返回值:无
*********************************************************************************/
void Some_working_640(void)
{
		if(Recognition_data[0]==0x79 && Recognition_data[1]==0x01 && Recognition_data[2]==0x00) // 检测语音播放是否结束
		{
			Play_Voice_flag=0;
			Continuous_Recognition(1);
		}
//		Candidate_Result();
}

/*********************************************************************************
函数名称:Once_Recognition
函数功能:启动一次识别模式,并且设置识别处理的最大时间
入口参数:Recognition_Time 设置识别最大时间
					mode=1 初始化 mode=2 循环检测识别结果
返回值:!0 设置成功,并返回该组语音的识别结果的序号  0 设置失败
*********************************************************************************/
unsigned int Once_Recognition(unsigned char Recognition_Time,unsigned char mode) // 0x00(不超时)秒内进行识别
{
	unsigned int result=0;
	if(mode==1)	SendData(0xAA,Recognition_Time,0x00);
	if(mode==2)
	{
		if(Recognition_flag==10)
		{
//		Some_working_640();
			if(RxDataTemp[0]==0x5a)
			{
				if(  (Recognition_data[1]==0xff && Recognition_data[2]==0xff) || (Recognition_data[1]==0xff && Recognition_data[2]==0x7f)  ) // 0x7fff表示超时 0xffff表示有语音输入但无正确结果
				{
					Recognition_data[0]=0;
					Recognition_data[1]=0;
					Recognition_data[2]=0;
					Recognition_flag=1;
					return 0;
				}
				result=Recognition_data[1]+(Recognition_data[2]<<2)+1;
				Recognition_data[0]=0;
				Recognition_data[1]=0;
				Recognition_data[2]=0;
				Recognition_flag=1;
				return result;
			}
		}
	}
	return 0;
}

/*********************************************************************************
函数名称:Continuous_Recognition
函数功能:启动连续识别模式
入口参数:mode=1 初始化 mode=2 循环检测识别结果
返回值:!0 设置成功,并返回该组语音的识别结果的序号  0 设置失败
*********************************************************************************/
unsigned char Recognition_flag=0;
unsigned int Continuous_Recognition(unsigned char mode)
{
	unsigned int result=0;
	if(mode==1)
	{
		delay_us(50);
		USART_SendData(USART2,0xAB);
		while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
		delay_us(50);
		USART_SendData(USART2,0xAB);
		while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
		delay_us(50);
		USART_SendData(USART2,0x00);
		while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
	}
	if(mode==2)
	{
		if(Recognition_flag==10)
		{
//				printf("-》%d %d %d ",Recognition_data[0],Recognition_data[1],Recognition_data[2]);
			Some_working_640();
			if( Recognition_data[0]==0x5b && Recognition_data[1]==0xff && Recognition_data[2]==0xff ) // 0xffff表示有语音输入但无正确结果
			{
				Recognition_data[0]=0;
				Recognition_data[1]=0;
				Recognition_data[2]=0;
				Recognition_flag=1;
				return 0;
			}
			if( Recognition_data[0]==0x5b )
			{
				result=Recognition_data[1]+(Recognition_data[2]<<2)+1;
				Recognition_data[0]=0;
				Recognition_data[1]=0;
				Recognition_data[2]=0;
				Recognition_flag=1;
				return result;
			}
		}
	}
	Recognition_data[0]=0;
	Recognition_data[1]=0;
	Recognition_data[2]=0;
	Recognition_flag=1;
	return 0;
}

/*********************************************************************************
函数名称:Exit_Recognition
函数功能:退出识别,等待命令
入口参数:无
返回值:无
*********************************************************************************/
void Exit_Recognition(void)
{
	Recognition_flag=0;
	SendData(0xAC,0xAC,0x00);	
}

/*********************************************************************************
函数名称:hbr640_Sleep
函数功能:进入休眠模式
入口参数:mode=1 进入休眠   mode=2 解除休眠
返回值:1 设置成功  0 设置失败
*********************************************************************************/
unsigned char hbr640_Sleep(unsigned char mode)
{
	if(mode==1)
		SendData(0xAE,0xAE,0x00);	// 返回0x5e正常
	if(mode==2)
	{
		delay_us(50);
		USART_SendData(USART2,0xA0);
		while( (USART2->SR&0X40)==0 );//等待前面的数据发送完成
		return 1;
	}	
	return 0;
}

/*********************************************************************************
函数名称:Continuous_Recognition
函数功能:提取候选结果
入口参数:result(0至7级)其值越小优先级越高,识别相似度越高
					mode=1 初始化 mode=2 循环检测识别结果
返回值:!0 设置成功,并返回该组语音的识别候选结果的序号  0 设置失败
*********************************************************************************/
unsigned int Candidate_Result(unsigned char result,unsigned char mode) 
{
	if(mode==1)
	{
		if(result>7) result=7;
		SendData(0xAF,result,0x00);	
	}
	if(mode==2)
		if( RxDataTemp[0]==0x5f )
		{
			if( (RxDataTemp[1]==0xff && RxDataTemp[2]==0xff) ) // 0xffff表示有语音输入但无正确结果
				return 0;
			return RxDataTemp[1]+(RxDataTemp[2]<<2)+1;
		}
	return 0;
}

/*********************************************************************************
函数名称:Play_Voice
函数功能:设置播放语音,并设置播放语音的组序号
入口参数:Strength_Series_Hight(0x**)  Strength_Series_Low(0x**) 组成 0xHHLL 来设定播放的组数序号
返回值:无
*********************************************************************************/
unsigned char Play_Voice_flag=0; // 播放结束标记
void Play_Voice(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight) // 0xHHLL 为需要设定播放的组数序号
{
	if(!Play_Voice_flag)
	{
		SendData(0xC8,Strength_Series_Low,Strength_Series_Hight);	
		if( RxDataTemp[0]==0x78 && RxDataTemp[1]==0x01 && RxDataTemp[2]==0x00 ) Play_Voice_flag=1;
	}	
}

/*********************************************************************************
函数名称:Play_Voice_Stop
函数功能:设置停止播放语音
入口参数:无
返回值:无
*********************************************************************************/
void Play_Voice_Stop(void)
{
	SendData(0xC9,0x00,0x00);
}

/*********************************************************************************
函数名称:Volume_Config
函数功能:设置播放语音的音量
入口参数:Voice_Series 设置播放语音的音量大小
返回值:无
*********************************************************************************/
void Volume_Config(unsigned char Voice_Series) // 调节音量的氛围是 0x00~0x0F (十进制是1~15)
{
	if(Voice_Series>0x0F) Voice_Series=0x0F;
	SendData(0xCA,Voice_Series,0x00);
}

.h文件

#ifndef __HBR640_H
#define __HBR640_H

extern unsigned char 	USART2_RX_data[3];
extern unsigned char 	RxDataTemp[3];
extern unsigned char  RX_data_flag;
extern unsigned char  Play_Voice_flag;
extern unsigned char  Recognition_flag;

unsigned char hbr640_init(unsigned int BaudRate); // 使用串口的波特率设置
void SendData(unsigned char date1,unsigned char date2,unsigned char date3);
unsigned char ReadData(unsigned char date1,unsigned char date2,unsigned char date3,unsigned char mode);
void Noise_Limit(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight);
void Microphone_Sensitivity(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight);
unsigned char Recognition_Group(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight);
unsigned int Once_Recognition(unsigned char Recognition_Time,unsigned char mode);
unsigned int Continuous_Recognition(unsigned char mode);
void Exit_Recognition(void);
unsigned char hbr640_Sleep(unsigned char mode);
unsigned int Candidate_Result(unsigned char result,unsigned char mode);
void Play_Voice(unsigned int Strength_Series_Low,unsigned int Strength_Series_Hight);
void Play_Voice_Stop(void);
void Volume_Config(unsigned char Voice_Series);
void Some_working_640(void);

#endif

        经测试,可用!但是由于水平有限,会有一定BUG还请各位博友指正大笑

下面贴出STM32F103系列的工程标准例程 ,识别词条与语音回答序号如上面的 “上位机”附图所示。

点击打开链接

https://download.csdn.net/download/weixin_41094315/10374276

不是打广告,不是推销,有兴趣者进入,淘宝链接

https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-9961989370.2.45cf4617mpWawz&id=564698348853

       谢谢观文!大笑

猜你喜欢

转载自blog.csdn.net/weixin_41094315/article/details/80083202