语音识别模块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
谢谢观文!
DY-SV17F模块驱动语音播放拥有多种驱动控制方式(不同的驱动方式需要自己另外做辅助电路进行选择,这也是该模块的缺陷之一,注意DY-SV17F仅具有语音播放功能不具有语音识别功能),本文仅介绍串口控制方式,每个模块售价在15元左右,可自定义语音播放内容,像U盘一样按照规定的命名顺序下载进去即可。支持32M储存(一条4个字的命令空间为28K大小),内部集成运放但需要自己外接小喇叭,可谓经济实惠 上图是块串口控制硬件连接图。
卖家提供上位机。可方便进行在线命令调试(上位机很稳定)。
/*********************************************************************************
函数名称:USART2_SendArray
函数功能:向语音模块发送一个字符数组的命令信息
入口参数:date 16位数组地址,length数组长度
返回值:无
*********************************************************************************/
void USART2_SendArray(unsigned char *date,unsigned char length)//发送字符数组
{
unsigned char i;
for(i=0;iSR&0X40)==0 );//等待前面的数据发送完成
}
}
/*********************************************************************************
函数名称:USART2_PlayVoice
函数功能:向语音模块发送一个字符数组的命令信息
入口参数:date 16位数组地址,length数组长度
返回值:无
*********************************************************************************/
unsigned char OpenVoice0[15]={0xAA, 0x08, 0x0B, 0x02, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2A, 0x4D, 0x50, 0x33, 0xD8}; //测试铃声
unsigned char OpenVoice1[15]={0xAA, 0x08, 0x0B, 0x02, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x31, 0x2A, 0x4D, 0x50, 0x33, 0xD9}; //工作时间已到
unsigned char OpenVoice2[15]={0xAA, 0x08, 0x0B, 0x02, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x32, 0x2A, 0x4D, 0x50, 0x33, 0xDA}; //休息时间已到
unsigned char OpenVoice3[15]={0xAA, 0x08, 0x0B, 0x02, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x33, 0x2A, 0x4D, 0x50, 0x33, 0xDB}; //工作时间不足30分钟
unsigned char OpenVoice4[15]={0xAA, 0x08, 0x0B, 0x02, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x34, 0x2A, 0x4D, 0x50, 0x33, 0xDC}; //欢迎使用
void USART2_PlayVoice(unsigned char num)
{
if(num==1)
{
USART2_SendArray(OpenVoice0,15);
}
else if(num==2)
{
USART2_SendArray(OpenVoice1,15);
}
else if(num==3)
{
USART2_SendArray(OpenVoice2,15);
}
else if(num==4)
{
USART2_SendArray(OpenVoice3,15);
}
else if(num==5)
{
USART2_SendArray(OpenVoice4,15);
}
}
/*
使用方式调用
USART2_PlayVoice(1);
delay_ms(500);
delay_ms(500);
即可播放00000.mp3的语音文件
*/
上面为模块 驱动代码。适用于文件存储类型如下图所示的00000.MP3至00003.MP3共4条语音播放命令。
如果想要添加更多条指令,可以在源代码上按照下图上位机生成的指令框内命令复制后创建新的数组即可(加多一个 else if和OpenVoiceX数组)。路径为\0000X.mp3 。
淘宝购买接口https://detail.tmall.com/item.htm?spm=a230r.1.14.6.47c53cf4yfE4cS&id=588218635743&cm_id=140105335569ed55e27b&abbucket=10如果觉得是推销可以自己上淘宝搜索。
如果觉得创建工程和资料下载麻烦的同学可以转到https://download.csdn.net/download/weixin_41094315/11328545进行下载。