若该文为原创文章,转载请注明原文出处。
一、LD3320语音识别模块
LD3320语音模块有串口通信和SPI通信两种版本
SPI接口的就是把LD3320以及外围电路做成一个模块,需要外接单片机使用单片机可以是51、STM32、Arduino均提供例程。
串口通信的就是将一个51单片机(STC11L08XE)集成到语音模块上,将识别到的语音通过串口发送出来,可外接其他任意有串口的单片机或设配使用。并且模块有16路IO引出,可以单独使用。 两者的相同之处是词条在程序里都是拼音的形式,修改拼音即可修改词条。
这是使用的是串口方式。
二、硬件部分
1、stm32单片机系列: stm32f103RCT6最小系统
- stm32的TXD(PA9)、RXD(PA10)


三、软件部分
软件分为STC和STM32两部分
STC处理识别后串口输出给STM32, STM32解析串口数据执行相应控制。
1、STC代码
LD3320.c
#include "main.h"
extern unsigned char idata nAsrStatus;
extern void delay(unsigned long uldata);
unsigned char idata ucRegVal;
void ProcessInt0(void);
/************************************************************************
功能描述:复位LD模块
入口参数:none
返 回 值:none
其他说明:none
**************************************************************************/
void LD_Reset()
{
RSTB=1;
delay(5);
RSTB=0;
delay(5);
RSTB=1;
delay(5);
CSB=0;
delay(5);
CSB=1;
delay(5);
}
/************************************************************************
功能描述: LD模块命令初始化
入口参数: none
返 回 值: none
其他说明: 该函数为出厂配置,一般不需要修改;
**************************************************************************/
void LD_Init_Common()
{
LD_ReadReg(0x06);
LD_WriteReg(0x17, 0x35);
delay(10);
LD_ReadReg(0x06);
LD_WriteReg(0x89, 0x03);
delay(5);
LD_WriteReg(0xCF, 0x43);
delay(5);
LD_WriteReg(0xCB, 0x02);
LD_WriteReg(0x11, LD_PLL_11);
LD_WriteReg(0x1E,0x00);
LD_WriteReg(0x19, LD_PLL_ASR_19);
LD_WriteReg(0x1B, LD_PLL_ASR_1B);
LD_WriteReg(0x1D, LD_PLL_ASR_1D);
delay(10);
LD_WriteReg(0xCD, 0x04);
// LD_WriteReg(0x17, 0x4c);
delay(5);
LD_WriteReg(0xB9, 0x00);
LD_WriteReg(0xCF, 0x4F);
LD_WriteReg(0x6F, 0xFF);
}
/************************************************************************
功能描述:LD模块 ASR功能初始化
入口参数:none
返 回 值:none
其他说明:该函数为出厂配置,一般不需要修改;
**************************************************************************/
void LD_Init_ASR()
{
LD_Init_Common();
LD_WriteReg(0xBD,0x00);
LD_WriteReg(0x17,0x48);
delay(10);
LD_WriteReg(0x3C,0x80);
LD_WriteReg(0x3E,0x07);
LD_WriteReg(0x38,0xff);
LD_WriteReg(0x3A,0x07);
LD_WriteReg(0x40,0);
LD_WriteReg(0x42,8);
LD_WriteReg(0x44,0);
LD_WriteReg(0x46,8);
delay(1);
}
/************************************************************************
功能描述:中断处理函数
入口参数:none
返 回 值:none
其他说明:当LD模块接收到音频信号时,将进入该函数,
判断识别是否有结果,如果没有从新配置寄存器准备下一次的识别。
**************************************************************************/
void ProcessInt0(void)
{
unsigned char nAsrResCount=0;
EX0=0;
ucRegVal=LD_ReadReg(0x2B);
LD_WriteReg(0x29,0);
LD_WriteReg(0x02,0);
if((ucRegVal&0x10)&&LD_ReadReg(0xb2)==0x21&&LD_ReadReg(0xbf)==0x35) /*识别成功*/
{
nAsrResCount=LD_ReadReg(0xba);
if(nAsrResCount>0&&nAsrResCount<=4)
{
nAsrStatus=LD_ASR_FOUNDOK;
}
else
{
nAsrStatus=LD_ASR_FOUNDZERO;
}
} /*没有识别结果*/
else
{
nAsrStatus=LD_ASR_FOUNDZERO;
}
LD_WriteReg(0x2b,0);
LD_WriteReg(0x1C,0); //写0:ADC不可用
LD_WriteReg(0x29,0);
LD_WriteReg(0x02,0);
LD_WriteReg(0x2B,0);
LD_WriteReg(0xBA,0);
LD_WriteReg(0xBC,0);
LD_WriteReg(0x08,1); //清除FIFO_DATA
LD_WriteReg(0x08,0); //清除FIFO_DATA后再次写0
EX0=1;
}
/************************************************************************
功能描述:运行ASR识别流程
入口参数:none
返 回 值:asrflag:1->启动成功, 0--->启动失败
其他说明:识别顺序如下:
1、RunASR()函数实现了一次完整的ASR语音识别流程
2、LD_AsrStart()函数实现了ASR初始化
3、LD_AsrAddFixed()函数实现了添加关键词语到LD3320芯片中
4、LD_AsrRun()函数启动了一次ASR语音识别流程
任何一次ASR识别流程,都需要按照这个顺序,从初始化开始
**************************************************************************/
unsigned char RunASR(void)
{
unsigned char i=0;
unsigned char asrflag=0;
for(i=0;i<5;i++) //防止由于硬件原因导致LD3320芯片工作不正常,所以一共尝试5次启动ASR识别流程
{
LD_AsrStart();
delay(50);
if(LD_AsrAddFixed()==0)
{
LD_Reset(); //LD3320芯片内部出现不正常,立即重启LD3320芯片
delay(50); //并从初始化开始重新ASR识别流程
continue;
}
delay(10);
if(LD_AsrRun()== 0)
{
LD_Reset(); //LD3320芯片内部出现不正常,立即重启LD3320芯片
delay(50); //并从初始化开始重新ASR识别流程
continue;
}
asrflag=1;
break; //ASR流程启动成功,退出当前for循环。开始等待LD3320送出的中断信号
}
return asrflag;
}
/************************************************************************
功能描述:检测LD模块是否空闲
入口参数:none
返 回 值:flag:1-> 空闲
其他说明:none
**************************************************************************/
unsigned char LD_Check_ASRBusyFlag_b2()
{
unsigned char j;
unsigned char flag = 0;
for(j=0;j<10;j++)
{
if(LD_ReadReg(0xb2)==0x21)
{
flag=1;
break;
}
delay(10);
}
return flag;
}
/************************************************************************
功能描述:启动ASR
入口参数:none
返 回 值:none
其他说明:none
**************************************************************************/
void LD_AsrStart()
{
LD_Init_ASR();
}
/************************************************************************
功能描述:运行ASR
入口参数:none
返 回 值:1:启动成功
其他说明:none
**************************************************************************/
unsigned char LD_AsrRun()
{
EX0=0;
LD_WriteReg(0x35,MIC_VOL);
LD_WriteReg(0x1C,0x09);
LD_WriteReg(0xBD,0x20);
LD_WriteReg(0x08,0x01);
delay(1);
LD_WriteReg(0x08, 0x00);
delay(1);
if(LD_Check_ASRBusyFlag_b2()==0)
{
return 0;
}
// LD_WriteReg(0xB6,0xa); //识别时间 1S
// LD_WriteReg(0xB5,0x1E); //背景音段时间 300ms
// LD_WriteReg(0xB8,10); //结束时间
// LD_WriteReg(0x1C,0x07); //配置双通道音频信号做为输入信号
LD_WriteReg(0x1C,0x0b); //配置麦克风做为输入信号
LD_WriteReg(0xB2,0xff);
delay(1);
LD_WriteReg(0x37,0x06);
delay(1);
LD_WriteReg(0x37,0x06);
delay(5);
LD_WriteReg(0x29,0x10);
LD_WriteReg(0xBD,0x00);
EX0=1;
return 1;
}
/************************************************************************
功能描述:向LD模块添加关键词
入口参数:none
返 回 值:flag:1->添加成功
其他说明:用户修改.
1、根据如下格式添加拼音关键词,同时注意修改sRecog 和pCode 数组的长度和对应变了k的循环置。拼音串和识别码是一一对应的。
2、开发者可以学习"语音识别芯片LD3320高阶秘籍.pdf"中关于垃圾词语吸收错误的用法,来提供识别效果。
3、"xiao jie " 为口令,故在每次识别时,必须先发一级口令"小捷"
**************************************************************************/
unsigned char LD_AsrAddFixed()
{
unsigned char k, flag;
unsigned char nAsrAddLength;
#define DATE_A 50 /*数组二维数值*/
#define DATE_B 100 /*数组一维数值*/
unsigned char code sRecog[DATE_A][DATE_B]={
"pi pi",\
"ni hao",\
"ni shi shui",\
"ni de she ji chu zhong shi shen me",\
"ni shi na yi jie de",\
"ni zui da de te dian shi shen me",\
"ni he shou ji zhu shou you shen me qu bie",\
"ni wei lai xiang bian cheng shen me yang",\
"ni you ming zi ma",\
"ni you xin yang ma",\
"ni hai pa shen me",\
"ni gu du ma",\
"ni neng shou hu shen me",\
"ni shi ren lei de gong ju ma",\
"ni you meng xiang ma",\
"ni xi huan an jing hai shi re nao",\
"ni xi huan bai tian hai shi wan shang",\
"ni hui ti xing wo zuo shi ma",\
"ni neng an wei ren ma",\
"ni jue de ren lei fu za ma",\
"ni hui wang ji shi qing ma",\
"wo shi shui",\
"ni neng zuo shen me",\
"ni yon shen me xin pian",\
"ben she ji cai yon shen me fang an",\
"zhi chi yu yin huan xing ma",\
"shi bie fang shi shi zai xian hai shi li xian",\
"xi tong you na xie gong neng",\
"xie xie",\
"qi don xi tong",\
"xi tong xiang ying kuai ma",\
"dan pian ji shi shen me",\
"yu yin shi bie yuan li",\
"yu yin he cheng yuan li",\
"xia ci zai jian",\
"ju tou wang ming yue",\
"chuang qian ming yue guang",\
"chun mian bu jue xiao",\
"bai ri yi shan jin",\
"yu qiong qian li mu",\
"li li yuan shang cao"
}; /*添加关键词,用户修改*/
unsigned char code pCode[DATE_A]={
CODE_START,\
CODE_CMD1,\
CODE_CMD2,\
CODE_CMD3,\
CODE_CMD4,\
CODE_CMD5,\
CODE_CMD6,\
CODE_CMD7,\
CODE_CMD8,\
CODE_CMD9,\
CODE_CMD10,\
CODE_CMD11,\
CODE_CMD12,\
CODE_CMD13,\
CODE_CMD14,\
CODE_CMD15,\
CODE_CMD16,\
CODE_CMD17,\
CODE_CMD18,\
CODE_CMD19,\
CODE_CMD20,\
CODE_CMD21,\
CODE_CMD22,\
CODE_CMD23,\
CODE_CMD24,\
CODE_CMD25,\
CODE_CMD26,\
CODE_CMD27,\
CODE_CMD28,\
CODE_CMD29,\
CODE_CMD30,\
CODE_CMD31,\
CODE_CMD32,\
CODE_CMD33,\
CODE_CMD34,\
CODE_CMD35,\
CODE_CMD36,\
CODE_CMD37,\
CODE_CMD38,\
CODE_CMD39,\
CODE_CMD40,
}; /*添加识别码,用户修改*/
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;
}
/************************************************************************
功能描述:获取识别结果
入口参数:none
返 回 值:LD_ReadReg(0xc5 );读取内部寄存器返回识别码。
其他说明:none
**************************************************************************/
unsigned char LD_GetResult()
{
return LD_ReadReg(0xc5);
}
ld3320.h
#ifndef LD_CHIP_H
#define LD_CHIP_H
#define uint8 unsigned char
#define uint16 unsigned int
#define uint32 unsigned long
//以下五个状态定义用来记录程序是在运行ASR识别过程中的哪个状态
#define LD_ASR_NONE 0x00 /*表示没有在作ASR识别*/
#define LD_ASR_RUNING 0x01 /*表示LD3320正在作ASR识别中*/
#define LD_ASR_FOUNDOK 0x10 /*表示一次识别流程结束后,有一个识别结果*/
#define LD_ASR_FOUNDZERO 0x11 /*表示一次识别流程结束后,没有识别结果*/
#define LD_ASR_ERROR 0x31 /*表示一次识别流程中LD3320芯片内部出现不正确的状态*/
#define CLK_IN 22.1184 /*用户注意修改输入的晶振时钟大小*/
#define LD_PLL_11 (uint8)((CLK_IN/2.0)-1)
#define LD_PLL_MP3_19 0x0f
#define LD_PLL_MP3_1B 0x18
#define LD_PLL_MP3_1D (uint8)(((90.0*((LD_PLL_11)+1))/(CLK_IN))-1)
#define LD_PLL_ASR_19 (uint8)(CLK_IN*32.0/(LD_PLL_11+1)-0.51)
#define LD_PLL_ASR_1B 0x48
#define LD_PLL_ASR_1D 0x1f
//函数声明
void LD_Reset();
void LD_Init_Common();
void LD_Init_ASR();
uint8 RunASR(void);
void LD_AsrStart();
uint8 LD_AsrRun();
uint8 LD_AsrAddFixed();
uint8 LD_GetResult();
//识别码客户修改处
#define CODE_START 0
#define CODE_CMD1 1
#define CODE_CMD2 2
#define CODE_CMD3 3
#define CODE_CMD4 4
#define CODE_CMD5 5
#define CODE_CMD6 6
#define CODE_CMD7 7
#define CODE_CMD8 8
#define CODE_CMD9 9
#define CODE_CMD10 10
#define CODE_CMD11 11
#define CODE_CMD12 12
#define CODE_CMD13 13
#define CODE_CMD14 14
#define CODE_CMD15 15
#define CODE_CMD16 16
#define CODE_CMD17 17
#define CODE_CMD18 18
#define CODE_CMD19 19
#define CODE_CMD20 20
#define CODE_CMD21 21
#define CODE_CMD22 22
#define CODE_CMD23 23
#define CODE_CMD24 24
#define CODE_CMD25 25
#define CODE_CMD26 26
#define CODE_CMD27 27
#define CODE_CMD28 28
#define CODE_CMD29 29
#define CODE_CMD30 30
#define CODE_CMD31 31
#define CODE_CMD32 32
#define CODE_CMD33 33
#define CODE_CMD34 34
#define CODE_CMD35 35
#define CODE_CMD36 36
#define CODE_CMD37 37
#define CODE_CMD38 38
#define CODE_CMD39 39
#define CODE_CMD40 40
//数值越大越灵敏识别距离越远,但误识别率就越大, 根据自己的实际情况调节。
#define MIC_VOL 0x55 //咪头增益(灵敏度调节) 范围:00-7f
#endif
main.c
void main(void)
{
unsigned char idata nAsrRes;
unsigned char i=0;
Led_test(); //LED灯测试
MCU_init(); //单片机初始化
LD_Reset(); //LD3320复位
UartIni(); //串口初始化
nAsrStatus=LD_ASR_NONE; //初始状态:没有在作ASR
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;
}
}
}
}
/***********************************************************
* 名 称:用户执行函数
* 功 能:识别成功后,执行动作可在此进行修改
* 入口参数:无
* 出口参数:无
* 说 明:
**********************************************************/
void User_handle(uint8 dat)
{
switch(dat) /*对结果执行相关操作,客户修改*/
{
case CODE_START:
UARTSendByte('A');
LED=!LED;
break;
case CODE_CMD1:
UARTSendByte('B');
LED=!LED;
break;
case CODE_CMD2:
UARTSendByte('C');
LED=!LED;
break;
}
}
以上为STC的LD3320代码,提供了逻辑部分,只需要对应修改唤醒词和CMD
总结代码功能:
-
使用LD3320实现语音识别,通过单片机(STC10L08XE)控制。
-
关键词在LD_AsrAddFixed()中定义,包含几十条中文拼音串和对应的识别码。
-
识别成功后通过串口发送字符(A,B,C...)并翻转LED。
-
采用并行总线通信,Reg.c定义了寄存器读写。
-
主循环根据nAsrStatus状态机启动ASR流程,识别后获取结果。
烧写时要注意,软件需要更新到最新,不然烧写不了。使用TTL就可以烧写。

2、STM32F103C8T6代码
串口初始化
#include "LD3320.h"
u8 LD3320_RX_STA;//接收状态标记
u8 LD3320_RX_CMD;//计数标记
void LD3320_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
//USART2_TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2 NVIC配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_InitStructure.USART_BaudRate=9600;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
USART_Cmd(USART1,ENABLE);
}
void USART1_IRQHandler()
{
u8 res=0;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
{
res=USART_ReceiveData(USART1); //读取接收到的数据
if(LD3320_RX_STA==0)
{
LD3320_RX_CMD=res;
LD3320_RX_STA=1;
res=0;
}
}
USART_ClearFlag(USART1,USART_IT_RXNE);
}
主程序里接收处理cmd
if(LD3320_RX_STA == 1)
{
// 第一步:关串口中断(防止LD3320乱发数据干扰)
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
// 第二步:读取并保存指令
uint8_t cmd = LD3320_RX_CMD;
// 第三步:立刻清0
LD3320_RX_CMD = 0;
LD3320_RX_STA = 0;
// 第四步:处理指令
switch(cmd)
{
case 'A':
break;
}
}
以上就是LD3320和STM32通讯基本过程。
如有侵权,或需要完整代码,请及时联系博主。