LD3320语音识别模块:LDV7模块使用详解

 
LD3320是非特定人(不用针对指定人)语音识别芯片,即语音声控芯片。最多可以识别50条预先内置的指令。
 
工作模式:
LD3320(LDV7)语音模块可以工作在以下三种模式:
普通模式:直接说话,模块直接识别;
按键模式:按键触发开始ASR进程;
口令模式:需要一级唤醒词(口令);
推荐使用口令模式,这样避免嘈杂环境下误动作。
 
应用场景:
1、家居智能控制
2、智能小车DIY设计
3、毕业设计创新功能
4、个人DIY设计
5、语音控制嵌入式产品设计
 
 
 
 
 
我购买的LDV7语音识别模块,内置单片机,LD3320语音识别芯片的驱动是靠模块上自带的STC11L08单片机驱动的,我们可以修改模块自带工程的Demo程序,修改里面的关键词,然后将识别的结果通过串口打印出来,我们使用另外一个MCU与该模块进行串口通信,解析收到的串口指令,进而做响应的指令动作。
 
例如
我们说口令:当前时间(dang qian shi jian)
》》 模块识别之后,串口输出:PrintCom("{\"VoiceCommandCode\":2}");
》》 MCU接收串口信息之后,对该串口指令进行解析(可以使用cJSON解析此字符串);
》》 然后通过TTS文字转语音模块播放当前时间,即完成本次语音识别控制过程。
 
 
识别原理:
就是你说一句话,然后模块用拼音去和你的发音做比较,在关键词中找出哪些预设值的词语与发音的接近程度大于多少的(假定50%),然后再从一堆大于(50% )里面输出一个最接近的。
 
这里就会造成一个问题,容易造成误识别太多。
如果你只有一个关键词:时间
然后你说了一句:‘时刻’,他识别到‘时’这个发音,所以有50% 以上的相似,但是候选词中没有‘时刻’这个比他更接近的关键词,所以他就会输出‘时间’的结果。这样子他就是错误了。
如果你设置一些拟声词,有可能随随便便就触发了。
 
解决方案:
在设定好要识别的关键词语后,为了进一步降低误识别率,可以再添加一些其他的任意词汇进识别列表,用来吸收错误识别,从而达到降低误识别率的目的。我们把这样一些关键词语称之为“垃圾关键词语”。
 
比如,某个应用场景中,需要识别的关键词语是 4 条,“前进”,“后退”,“开门”,“关门”。在把这 4 个关键词语设置进 LD3320 后,可以再另外设置10~30个词语进LD3320,比如“前门”,“后门”,“阿阿阿”,“呜 呜”等等。 所以最好把一些拟声词或者容易混淆的词语设置为垃圾关键词,即,识别后不进行输出。
 
只有识别结果是 4 个关键词语之内的,才认为识别有效。如果识别结果是 “垃圾关键词语”,则说明是其他的声音导致的误识别,产品应该重新开始一次识别过程。 这样,可以非常有效地降低误识别率。极大地提高终端用户的主观使用体验。
 
移植过程:
 
1、向LD模块中添加关键词
 
 
 
 
/************************************************************************
功能描述: 向LD模块添加关键词
入口参数: none
返 回 值: flag:1->添加成功
其他说明: 用户修改.
                     1、根据如下格式添加拼音关键词,同时注意修改sRecog 和pCode 数组的长度
                     和对应变了k的循环次数设置。拼音串和识别码是一一对应的。
                     2、开发者可以学习"语音识别芯片LD3320高阶秘籍.pdf"中
           关于垃圾词语吸收错误的用法,来提供识别效果。
                     3、”duo gong neng bao shi“ 为口令,故在每次识别时,必须先发一级口令“多功能报时”
**************************************************************************/
uint8 LD_AsrAddFixed()
{
    uint8 k, flag;
    uint8 nAsrAddLength;
    #define DATE_A 8   /*数组二维数值*/
    #define DATE_B 21        /*数组一维数值*/
    uint8 code sRecog[DATE_A][DATE_B] = {
                             "duo gong neng bao shi",\        
                             "xian zai ji dian le",\
                             "dang qian shi jian",\
                             "xian zai shi ke",\
                             "bao shi",\
                             "dang qian wen du",\
                             "dang qian shi du",\
                             "wen shi du duo shao"
                        };    /*添加关键词,用户修改*/


    uint8 code pCode[DATE_A] = {
                                    CODE_CMD,\
                                    CODE_XZJDL,\
                                    CODE_DQSJ,\
                                    CODE_XZSK,\
                                    CODE_BS,\
                                    CODE_DQWD,\
                                    CODE_DQSD,\
                                    CODE_WSDDS
                                 };    /*添加识别码,用户修改*/    
    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;
}
 
2、用户执行函数 User_handle(nAsrRes); 处理语音识别结果
 
 
 
void  main(void)
{
    uint8 idata nAsrRes;
    uint8 i=0;
    Led_test();
    MCU_init();
    LD_Reset();
    UartIni(); /*串口初始化*/
    nAsrStatus = LD_ASR_NONE;        //    初始状态:没有在作ASR
    
    #ifdef TEST    
    PrintCom("一级口令:多功能报时\r\n"); /*text.....*/
    PrintCom("二级口令:1、现在几点了\r\n"); /*text.....*/
    PrintCom("    2、当前时间\r\n"); /*text.....*/
    PrintCom("    3、现在时刻\r\n"); /*text.....*/
    PrintCom("    4、报时\r\n"); /*text.....*/
    PrintCom("  5、当前温度\r\n"); /*text.....*/
    PrintCom("    6、当前湿度\r\n"); /*text.....*/
    PrintCom("    7、温湿度多少\r\n"); /*text.....*/
    #endif


    while(1)
    {
        switch(nAsrStatus)
        {
            case LD_ASR_RUNING:
            case LD_ASR_ERROR:        
                break;
            case LD_ASR_NONE:
            {
                nAsrStatus=LD_ASR_RUNING;
                if (RunASR()==0)    /*    启动一次ASR识别流程:ASR初始化,ASR添加关键词语,启动ASR运算*/
                {
                    nAsrStatus = LD_ASR_ERROR;
                }
                break;
            }
            case LD_ASR_FOUNDOK: /*    一次ASR识别流程结束,去取ASR识别结果*/
            {                
                nAsrRes = LD_GetResult();        /*获取结果*/
                User_handle(nAsrRes);            //用户执行函数
                nAsrStatus = LD_ASR_NONE;
                break;
            }
            case LD_ASR_FOUNDZERO:
            default:
            {
                nAsrStatus = LD_ASR_NONE;
                break;
            }
        }// switch                 
    }// while
}
 
3、根据不同结果,串口打印不同的指令
 
 
以JSON格式发送数据至串口,与语音识别模块相连的MCU接收此结果,然后对此字符串进行解析,进而得到当前识别的命令是什么,进而做相应的动作。
 
PrintCom("{\"VoiceCommandCode\":1}");


/***********************************************************
* 名    称:用户执行函数
* 功    能:识别成功后,执行动作可在此进行修改
* 入口参数: 无
* 出口参数:无
* 说    明:                      
**********************************************************/
void User_handle(uint8 dat)
{
     //UARTSendByte(dat);//串口识别码(十六进制)
         if(0==dat)
         {
              G0_flag=ENABLE;
            LED=0;
            PrintCom("{\"VoiceCommandCode\":0}");
            PrintCom("收到\r\n"); /*text.....*/
         }
         else if(ENABLE==G0_flag)
         {    
             G0_flag=DISABLE;
            LED=1;
            switch(dat)           /*对结果执行相关操作,客户可删除Printcom 串口输出语句替换为其他需要控制的代码*/
            {
              case CODE_XZJDL:            /*命令“测试”*/
                    PrintCom("{\"VoiceCommandCode\":1}");
                    PrintCom("“现在几点了”命令识别成功\r\n"); /*text.....*/
                    break;
                case CODE_DQSJ:
                    PrintCom("{\"VoiceCommandCode\":2}");
                    PrintCom("“当前时间”命令识别成功\r\n"); /*text.....*/
                    break;
                case CODE_XZSK:
                    PrintCom("{\"VoiceCommandCode\":3}");        
                    PrintCom("“现在时刻”命令识别成功\r\n"); /*text.....*/
                    break;
                case CODE_BS:
                    PrintCom("{\"VoiceCommandCode\":4}");            
                    PrintCom("“报时”命令识别成功\r\n"); /*text.....*/
                    break;
                case CODE_DQWD:
                    PrintCom("{\"VoiceCommandCode\":5}");        
                    PrintCom("“当前温度”命令识别成功\r\n"); /*text.....*/
                    break;
                case CODE_DQSD:
                    PrintCom("{\"VoiceCommandCode\":6}");        
                    PrintCom("“当前湿度”命令识别成功\r\n"); /*text.....*/
                    break;
                case CODE_WSDDS:
                    PrintCom("{\"VoiceCommandCode\":7}");        
                    PrintCom("“温湿度多少”命令识别成功\r\n"); /*text.....*/
                    break;                                                                                                            
                default:
                    PrintCom("{\"VoiceCommandCode\":-1}");
                    PrintCom("请重新识别发口令\r\n"); /*text.....*/
                    break;
            }    
        }    
        else     
        {
            PrintCom("{\"VoiceCommandCode\":-2}");
            PrintCom("请说出一级口令\r\n"); /*text.....*/    
        }
}
 
 
 
4、MCU根据指令不同,执行不同的动作
 
以JSON格式发送数据至串口,与语音识别模块相连的MCU接收此结果,然后对此字符串进行解析,进而得到当前识别的命令是什么,进而做相应的动作。
 
//LD3320
if(USART5_RX_STA&0x8000)
{
    uart5Len=USART5_RX_STA&0x3f;                                    //得到此次接收到的数据长度   
    
    //发送测试数据至串口1
    for(i=0;i<uart5Len;i++)    
    {  
        USART_SendData(USART1, USART5_RX_BUF[i]);                      //向串口 1 发送数据         
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);         //等待发送结束     
    }        


    receive_json = cJSON_Parse(USART5_RX_BUF);   //创建JSON解析对象,返回JSON格式是否正确
    if (!receive_json)
    {
        printf("JSON格式错误:%s \r\n", cJSON_GetErrorPtr()); //输出json格式错误信息
    }
    else
    {
        printf("JSON格式正确:%s \r\n",cJSON_Print(receive_json) );
        item_obj = receive_json->child; //获取name键对应的值的信息
        
        while(item_obj)
        {
            char * string = item_obj->string;
            
            if(!strcmp(string,"VoiceCommandCode"))
            {
                if(item_obj->valueint==0)
                {
                    printf("收到一级口令 智能报时 ... \r\n");    
                }
                else if(item_obj->valueint==1)
                {
                    printf("“现在几点了”命令识别成功 \r\n");
                    
                    m_nCurrentVoicePlayTimes++;
                    while(U5152_BSY){}
                    if(m_nCurrentVoicePlayTimes%2==0)
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m3]当前时间为%02d时%02d分%02d秒 \r\n",NowHour,NowMinute,NowSecond);
                    }
                    else
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m51]当前时间为%02d时%02d分%02d秒 \r\n",NowHour,NowMinute,NowSecond);
                    }                                
                    printf((char*)dtbuf);
                    XFS_FrameInfo((char*)dtbuf) ;
                    delay_ms(10);while(U5152_BSY){delay_ms(500);printf("while(U5152_BSY) \r\n");}
                }
                else if(item_obj->valueint==2)
                {
                    printf("“当前时间”命令识别成功\r\n");
                    
                    m_nCurrentVoicePlayTimes++;
                    while(U5152_BSY){}
                    if(m_nCurrentVoicePlayTimes%2==0)
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m3]当前时间为%02d时%02d分%02d秒 \r\n",NowHour,NowMinute,NowSecond);
                    }
                    else
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m51]当前时间为%02d时%02d分%02d秒 \r\n",NowHour,NowMinute,NowSecond);
                    }                                
                    printf((char*)dtbuf);
                    XFS_FrameInfo((char*)dtbuf) ;
                    delay_ms(10);while(U5152_BSY){delay_ms(500);printf("while(U5152_BSY) \r\n");}
                }
                else if(item_obj->valueint==3)
                {
                    printf("“现在时刻”命令识别成功\r\n");
                    
                    m_nCurrentVoicePlayTimes++;
                    while(U5152_BSY){}
                    if(m_nCurrentVoicePlayTimes%2==0)
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m3]当前时间为%02d时%02d分%02d秒 \r\n",NowHour,NowMinute,NowSecond);
                    }
                    else
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m51]当前时间为%02d时%02d分%02d秒 \r\n",NowHour,NowMinute,NowSecond);
                    }                                
                    printf((char*)dtbuf);
                    XFS_FrameInfo((char*)dtbuf) ;
                    delay_ms(10);while(U5152_BSY){delay_ms(500);printf("while(U5152_BSY) \r\n");}
                }
                else if(item_obj->valueint==4)
                {
                    printf("“关灯”命令识别成功\r\n");
                }
                else if(item_obj->valueint==5)
                {
                    printf("“当前温度”命令识别成功\r\n");
                    
                    m_nCurrentVoicePlayTimes++;
                    while(U5152_BSY){}
                    if(m_nCurrentVoicePlayTimes%2==0)
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m3]当前温度为%.1f摄氏度 \r\n",DHT11Temp);    
                    }
                    else
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m51]当前温度为%.1f摄氏度 \r\n",DHT11Temp);    
                    }                                
                    printf((char*)dtbuf);
                    XFS_FrameInfo((char*)dtbuf) ;
                    delay_ms(10);while(U5152_BSY){delay_ms(500);printf("while(U5152_BSY) \r\n");}
                }
                else if(item_obj->valueint==6)
                {
                    printf("“当前湿度”命令识别成功\r\n");
                    
                    m_nCurrentVoicePlayTimes++;
                    while(U5152_BSY){}
                    if(m_nCurrentVoicePlayTimes%2==0)
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m3]当前湿度为百分之%.1f \r\n",DHT11Hum);    
                    }
                    else
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m51]当前湿度为百分之%.1f \r\n",DHT11Hum);    
                    }                                
                    printf((char*)dtbuf);
                    XFS_FrameInfo((char*)dtbuf) ;
                    delay_ms(10);while(U5152_BSY){delay_ms(500);printf("while(U5152_BSY) \r\n");}
                }
                else if(item_obj->valueint==7)
                {
                    printf("“温湿度多少”命令识别成功\r\n");
                    
                    m_nCurrentVoicePlayTimes++;
                    while(U5152_BSY){}
                    if(m_nCurrentVoicePlayTimes%2==0)
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m3]温度为%.1f度,湿度为%.1f \r\n",DHT11Temp,DHT11Hum);    
                    }
                    else
                    {
                        sprintf((char*)dtbuf,"[v5][s5][m51]温度为%.1f度,湿度为%.1f \r\n",DHT11Temp,DHT11Hum);    
                    }                                
                    printf((char*)dtbuf);
                    XFS_FrameInfo((char*)dtbuf) ;
                    delay_ms(10);while(U5152_BSY){delay_ms(500);printf("while(U5152_BSY) \r\n");}
                }                        
            }
            
            item_obj = item_obj->next;
            
            printf("while(item_obj) \r\n");
        }
        
    }
    
    cJSON_Delete(receive_json);        
    
    USART5_RX_STA=0;   
    memset(USART5_RX_BUF, 0, sizeof(USART5_RX_BUF));                  //清空数组  
}
 
LDV7模块固件下载:
 
1、打开编译后的.hex文件
 
 
 
 
2、选对串口号,芯片型号后,选择“下载/编程”按钮,然后给STC单片机上电或者复位。
 
 
3、发出语音,测试语音识别结果
 
 
 
 
 
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":1}“现在几点了”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":2}“当前时间”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":3}“现在时刻”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":4}“报时”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":5}“当前温度”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":6}“当前湿度”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":7}“温湿度多少”命令识别成功
{"VoiceCommandCode":0}收到
{"VoiceCommandCode":7}“温湿度多少”命令识别成功

然后其他与LDV7模块相连的MCU只要解析接收到的串口数据即可。


喜欢请扫码关注微信公众号:程序员小哈

原创文章 6 获赞 1 访问量 761

猜你喜欢

转载自blog.csdn.net/rsd102/article/details/106126575