详细测试流程如下:
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
#include "config.h"
引入头文件,该头文件里面包含宏定义和其他头文件,以及条件编译
- 使用typedef自定义数据类型名称【精确宽度有符号整数类型和精确宽度无符号整数类型】
- 宏定义0和1分别为使能(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
6、default
以上两种情况
将程序运行状态设为LD_ASR_NONE(进行下一次识别)
打开程序工程,在 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;
}
#define DATE_A 10
#define DATE_B 30
打开程序,在 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 //广州
打开程序,在 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.....*/
}
}
打开程序文件即打开源程序–>OBJ 文件夹里面后缀为 .hex 的文件
注意勾选“复位脚用作I/O口”
先将语音模块那边的 GND 那根线拔下,然后点击 下载/编程 按钮,接着再把 GND 插上,这是软件底部将有进度条显示,会提示下载完成。STC芯片是冷启动,必须断电重新连接才能下载。
阅读该博文完成串口通信的配置:树莓派——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;
}