语音模块开发——YS-LDV7 语音识别模块

文章目录

  • 硬件模块化开发定义
  • 模块参数
  • 模块结构介绍
  • 串口连接图
  • 验货测试方法
  • 语音模块源码阅读
    • 文件结构
    • 分析代码(从main.c函数出发)
  • 识别语句的修改
    • 1.添加关键词和识别码
    • 2.定义识别码
    • 3.修改处理函数
  • LDV7语音识别模块程序下载方法
  • 基于树莓派和YS-LDV7语音识别模块声控灯的实现

硬件模块化开发定义

  • 硬件自带的芯片能完成所需的功能,只需要了解输入和输出即可操作硬件完成指定的功能

模块参数

  • 型号:YS-LDV7
  • 名称:一体化语音识别模块
  • 规格:43*29.7MM
  • 供电电压:5V (内部工作电压 3.3V)
  • 待机电流:30MA
  • 识别时电流:45MA
  • IO 口输出:高电平为 3.3V
  • 通信方式:串口通信(5V TTL 电平,不可直接接 RS232、RS485)
  • 单片机参数:型号–>STC11L08XE 、flash–>8k、SRAM–>1280、eeprom–>32k
  • 识别词条个数:50 句
  • 工作温度:-20 至 60℃

模块结构介绍

  • 本模块实际原理为 1 片 STC11 单片机+1 片 LD3320 组合形成的一款语音识别模块,语音识别部分已写好驱动程序,用于只需要对 STC 单片机进行编程加入自己的识别语句和控制程序即可,语音识别部分无需理会和做编程处理。对此用户只需要在提供的源程序基础上做单片机的编程应用即可,本模块具备 1 个 5V TTL 串口和 16 个单片机 IO 口的引出,可与外部单片机进行通信交互信息亦可控制继电器等设备

串口连接图

  • 本模块的串口如下图所示,从下至上的 5 根针分别为 GND、RXD、TXD、5V、3.3V,其中 RXD 和 TXD 为实际内部单片机的串口接收和发射端口,故与外部串口设备连接时要注意 RXD 接 TXD 的交叉接法。3.3V 的口为输出口,可用于外部设备的供电利用,一般未用上直接忽略不用即可。下图为本店提供的 USB 转 TTL 与语音模块的连接方法,如与其他单片机或者其他设备的连接时注意串口电平需要为 5V,与语音模块电平一致,如电平不一致可加入串口电平转换模块否则将导致通信异常甚至损坏设备端口。

语音模块开发——YS-LDV7 语音识别模块_第1张图片

验货测试方法

详细测试流程如下:

  1. 首先在电脑上安装“USB 转 TTL 驱动”
  2. 根据以上串口连接图将 USB 转 TTL 模块与语音模块连接好
  3. 插入电脑 USB 口(注意不要加 USB 延长线直接插到主机的 USB 口)
  4. 打开“STC-ISP 下载软件”里面的串口助手,根据下图选择好各个选项(另外我们打开软件串口后,我们可以拔下 GND 再把 GND 插上,这样重新上电可以看到接收串口会打印出相关的识别口令。本模块在出厂前已经下载了口令模式版本的程序,收到货后可进行初步的测试。口令模式需要先按一级口令,识别成功后才能继续喊二级口令以此循环。内部默认的口令如下:
    一级口令:小杰
    二级口令:代码测试、开发板验证、开灯、关灯、北京、上海、广州
    语音模块开发——YS-LDV7 语音识别模块_第2张图片
  5. 以上步骤都准备好后,我们距离模块的麦克风 50cm 左右,以正常的发音速度和音量进行识别,第一句喊口令为:小杰 如识别正确,则模块 D1 指示灯将亮起,软件也将输出”收到”二字。 如没有任何反应可以尝试再次发音,注意手不要碰到模块的线路。可以夹住板边。

语音模块源码阅读

文件结构

main.c —— Main.c主函数、LED灯测试、单片机初始化、延时函数、
中断函数(调用LDChip.c中的中断函数)、
用户执行函数(对识别到的结果进行相应的串口输出)

config.h —— 包含的头文件

LDchip.c 、LDchip.h —— LD模块的复位、命令初始化、功能初始化
中断函数(当接收到音频信号,进入该函数,判断识别是否有结果)
运行识别流程(初始化、添加关键词、启动语音识别)
检测LD模块是否空闲、获取识别结果

Reg_Rw.c Reg_Rw.h —— 寄存器的读写操作

由于单片机内存空间有限且不怎么操作浮点数和负整数,一般用宏定义来操作

#define uint8 unsigned char
#define uint16 unsigned int
#define uint32 unsigned long

分析代码(从main.c函数出发)

#include "config.h"
引入头文件,该头文件里面包含宏定义和其他头文件,以及条件编译
- 使用typedef自定义数据类型名称【精确宽度有符号整数类型和精确宽度无符号整数类型】
- 宏定义01分别为使能(ENABLE)和不使能(DISABLE)
- 条件编译:#define TEST 测试命令,效果是在上电的时候在串口助手打印,
- 条件编译的定义如下:
#ifdef TEST  表示若有定义该宏则执行该范围代码,无该宏则不执行
#endif
uint8 idata nAsrStatus=0;	
nAsrStatus 用来在main主程序中表示程序运行的状态,从未识别,到正在识别,到识别结束有一个结果或无结果,到芯片内部出错等
通过switch条件判断语句去判断当前的状态,进入相应的函数体

函数的定义以及引脚定义:

void MCU_init(); 
void ProcessInt0(); //识别处理函数
void delay(unsigned long uldata);
void User_handle(uint8 dat);//用户执行操作函数
void Delay200ms();
void Led_test(void);//单片机工作指示
uint8_t G0_flag=DISABLE;//运行标志,ENABLE:运行。DISABLE:禁止运行 
sbit LED=P4^2;//信号指示灯

主函数程序入口:

Led_test()  LED灯测试(闪烁三次)
MCU_init()单片机初始化 (所有引脚电平拉高,开启中断)
LD_Reset() 复位(初始化)LD模块(单片机复位端口与片选端口与内置的LD模块相连)
UartIni()   串口初始化
nAsrStatus 表示程序运行的状态,初始化为0(使用宏LD_ASR_NONE来表示0),共有4种状态

while循环语句:

switch(nAsrStatus)判断程序运行状态
1. LD_ASR_RUNING 表示正在识别中
2. LD_ASR_ERROR  表示芯片内部出现错误
	以上两种情况不执行代码
3. LD_ASR_NONE   表示没有在识别
	执行代码:
		3.1 将nAsrStatus程序运行状态设为LD_ASR_RUNING
		
		3.2 RunASR() 启动一次识别流程(为初始化 添加关键词 启动运算)函数位于LDChip.c
			启动程序运行5次(防止由于硬件原因导致芯片工作不正常),continue是重头运行的意思,当asrflag=1;break循环
			3.2.1 LD_AsrStart();    初始化
				调用LD_Init_ASR();   将LD模块的ASR功能初始化,是根据LD3320时序图进行编写的代码
			
			3.2.2 LD_AsrAddFixed();  向LD模块添加关键词
				两个数组分别存放关键词和识别码,识别码的宏位于LDChip.h
				调用LD_CheckASRBusyFlag_b2()   判断LD模块是否空闲
				调用LD_WriteReg()  函数位于Reg_RW.c功能将内容写入寄存器中
			
			3.2.3 LD_AsrRun();    启动运算
				函数内部使用了中断,调用了main.c中的ExtInt0handler();【与LD模块连接的引脚发送中断】
					ExtInt0handler()调用了LDChip.c中的ProcessInt0();中断处理函数
						判断识别是否有结果,有结果将程序运行状态设为LD_ASR_FOUNDOK,
							      		  无结果设为LD_ASR_FOUNDZERO
	
			若添加关键词和启动运算出错则调用LD_Reset(); 功能为复位LD模块
4、LD_ASR_FOUNDOK     一次ASR识别流程结束,去取ASR识别结果
	4.1 调用main.c中的LD_GetResult();获取识别的结果
		将识别结果作为参数去调用了Reg_RW.c中的LD_ReadReg();读取寄存器返回识别码
	
	4.2 调用main.c中的User_handle(); 对识别的结果进行对应的操作
		GO_flag用于口令模式,必须说出一级口令,才能识别下一级
		switch判断数据,PrintCom串口输出相应的语句
		将程序运行状态设为LD_ASR_NONE(进行下一次识别)
5、LD_ASR_FOUNDZERO
6default
	以上两种情况
	将程序运行状态设为LD_ASR_NONE(进行下一次识别)

识别语句的修改

1.添加关键词和识别码

打开程序工程,在 LDChip.C 文件中找到 uint8 LD_AsrAddFixed() 函数,在该函数里面可以找到如下图所示内容:

/************************************************************************
功能描述: 向LD模块添加关键词
入口参数: none
返 回 值: flag:1->添加成功
其他说明: 用户修改.
					 1、根据如下格式添加拼音关键词,同时注意修改sRecog 和pCode 数组的长度
					 和对应变了k的循环置。拼音串和识别码是一一对应的。
					 2、开发者可以学习"语音识别芯片LD3320高阶秘籍.pdf"中
           关于垃圾词语吸收错误的用法,来提供识别效果。
					 3、”xiao jie “ 为口令,故在每次识别时,必须先发一级口令“小捷”
**************************************************************************/
uint8 LD_AsrAddFixed()
{
	uint8 k, flag;
	uint8 nAsrAddLength;
	#define DATE_A 50   /*数组二维数值*/
	#define DATE_B 70		/*数组一维数值*/
	uint8 code sRecog[DATE_A][DATE_B] = {
																				"xiao jie",\		
																				"kai fa ban yan zheng",\
																				 "dai ma ce shi",\
																				 "kai deng",\
																				 "guan deng",\
																				 "bei jing",\
																				 "shang hai",\
																				 "guang zhou"
																			};	/*添加关键词,用户修改*/
	uint8 code pCode[DATE_A] = {
															CODE_CMD,\
															CODE_KFBYZ,\
															CODE_DMCS,\
															CODE_KD,\
															CODE_GD,\
															CODE_BJ,\
															CODE_SH,\
															CODE_GZ
														 };	/*添加识别码,用户修改*/	
	flag = 1;
	for (k=0; k<DATE_A; k++)
	{
			
		if(LD_Check_ASRBusyFlag_b2() == 0)
		{
			flag = 0;
			break;
		}
		
		LD_WriteReg(0xc1, pCode[k] );
		LD_WriteReg(0xc3, 0 );
		LD_WriteReg(0x08, 0x04);
		delay(1);
		LD_WriteReg(0x08, 0x00);
		delay(1);

		for (nAsrAddLength=0; nAsrAddLength<DATE_B; nAsrAddLength++)
		{
			if (sRecog[k][nAsrAddLength] == 0)
				break;
			LD_WriteReg(0x5, sRecog[k][nAsrAddLength]);
		}
		LD_WriteReg(0xb9, nAsrAddLength);
		LD_WriteReg(0xb2, 0xff);
		LD_WriteReg(0x37, 0x04);
	}
    return flag;
}

  • 根据关键词的数量和长度修改宏定义 DATE_A 和 DATE_B ,例如您要添加10 个关键词,在这些关键词中最长的一句长度为 30,那么定义如下:
#define DATE_A 10
#define DATE_B 30
  • sRecog[ ][ ] 数组为关键词数组,添加内容为拼音输入方式,例如想添加“开灯”命令,则写入“kai deng”,每个汉字间的拼音用空格隔开。
  • pCode[ ] 数组为识别码数组,所添加的识别码为预先定义好的宏定义常量值,同时必须和关键词一一对应,如上图所示,“da ma ce shi”命令对应的识别码为 CODE_DMCS

2.定义识别码

打开程序,在 LDChip.h 文件中找到如下图所示:

//识别码客户修改处 
#define CODE_CMD  0x00   //该命令码0x00用户不可进行修改。
#define CODE_DMCS	0x01		//代码测试
#define CODE_KFBYZ	0x02	//开发板验证
#define CODE_KD 0x04			//开灯
#define CODE_GD 0x05			//关灯
#define CODE_BJ 0x16			//关灯
#define CODE_SH 0x17			//上海
#define CODE_GZ	0x2f			//广州	

  • 此处即为识别码的添加和修改,用户可以根据自己的需要和喜好任意定义识别码和宏名,但必须和前面所使用的识别码配对,否则会提示未定义错误。识别码的参数范围为 01-FF 随意选择,没有具体意义,只要不存在重复的即可。

3.修改处理函数

打开程序,在 main.c 文件中找到 void User_handle(uint8 dat)函数,在该函数中可以看到如下图所示内容:

void 	User_handle(uint8 dat)
{
     //UARTSendByte(dat);//串口识别码(十六进制)
		 if(0==dat)
		 {
		  	G0_flag=ENABLE;
			LED=0;
			PrintCom("收到\r\n"); /*text.....*/
		 }
		 else if(ENABLE==G0_flag)
		 {	
		 		G0_flag=DISABLE;
				LED=1;
			 switch(dat)		   /*对结果执行相关操作,客户可删除Printcom 串口输出语句替换为其他需要控制的代码*/
			  {
				  case CODE_DMCS:			/*命令“测试”*/
						PrintCom("“代码测试”命令识别成功\r\n"); /*text.....*/
													 break;
					case CODE_KFBYZ:	 /*命令“全开”*/
						PrintCom("“开发板验证”命令识别成功\r\n"); /*text.....*/
													 break;
					case CODE_KD:		/*命令“复位”*/				
						PrintCom("“开灯”命令识别成功\r\n"); /*text.....*/
													break;
					case CODE_GD:		/*命令“复位”*/				
						PrintCom("“关灯”命令识别成功\r\n"); /*text.....*/
													break;
					case CODE_BJ:		/*命令“复位”*/				
						PrintCom("“北京”命令识别成功\r\n"); /*text.....*/
													break;
					case CODE_SH:		/*命令“复位”*/				
						PrintCom("“上海”命令识别成功\r\n"); /*text.....*/
													break;
					case CODE_GZ:		/*命令“复位”*/				
						PrintCom("“广州”命令识别成功\r\n"); /*text.....*/
													break;																											
							default:PrintCom("请重新识别发口令\r\n"); /*text.....*/break;
				}	
			}	
			else 	
			{
				PrintCom("请说出一级口令\r\n"); /*text.....*/	
			}
}	 

  • 用户可以根据自己的使用情况在相对应的识别码后添加识别成功后的操作。那么在设备到某句话后就会执行相应的动作,实际上此段程序是判断识别到那个识别码然后执行相应的动作,属单片机的程序应用处理部分。

LDV7语音识别模块程序下载方法

  1. 打开“STC-ISP 下载软件”,根据下图的箭头指示选择好各个选项。
    语音模块开发——YS-LDV7 语音识别模块_第3张图片

  2. 打开程序文件即打开源程序–>OBJ 文件夹里面后缀为 .hex 的文件

  3. 注意勾选“复位脚用作I/O口”

  4. 先将语音模块那边的 GND 那根线拔下,然后点击 下载/编程 按钮,接着再把 GND 插上,这是软件底部将有进度条显示,会提示下载完成。STC芯片是冷启动,必须断电重新连接才能下载。

基于树莓派和YS-LDV7语音识别模块声控灯的实现

阅读该博文完成串口通信的配置:树莓派——wiringPi库详解

#include 
#include 
#include 
#include 
#include 

#define SWIT 26 //输出引脚

int main(){
        int fd;
        char cmd[32] = {'\0'};
        int nread;

        wiringPiSetup();
        fd = serialOpen("/dev/ttyAMA0", 9600);

        pinMode(SWIT, OUTPUT);
        digitalWrite(SWIT, HIGH);

		while(1){

                nread = read(fd, cmd, sizeof(cmd));

                if(strlen(cmd) == 0){
                        printf("chaosi\n");
                        continue;
                }
                if(strstr(cmd, "open") != NULL){
                        printf("open light\n");
                        digitalWrite(SWIT, LOW);
                }
                if(strstr(cmd, "close") != NULL){
                        printf("close light\n");
                        digitalWrite(SWIT, HIGH);
                }
                memset(cmd, '\0', sizeof(cmd)/sizeof(char));
        }

        return 0;
}

你可能感兴趣的:(语音识别,单片机,人工智能)