语音识别芯片LD3320驱动程序

    1、芯片复位

复位就是对LD3320芯片的第47腿(RSTB*)发送低电平,然后需要对片选CS做一次拉低→拉  高的操作,以激活内部DSP。按照以下顺序:

void LD_reset()

{

RSTB=1;delay(1);RSTB=0;delay(1);RSTB=1;delay(1);

CSB=0;delay(1);CSB=1;delay(1);

}

delay(1)是为了更稳定地工作。 初始化一般在程序的开始进行,如果有时芯片的反应不太正常,也可用这个方法恢复芯片初始状态。

(1)通用初始化

按照以下序列设置寄存器。

void LD_Init_Common()

{

bMp3Play=0;

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);

/*PLL setting*/

LD_WriteReg(0x11,LD_PLL_11);

if(nLD_Mode==LD_MODE_MP3)

{

LD_WriteReg(0x1E,0x00);

//!!注意,下面三个寄存器,会随晶振频率变化而设置不同

//!!注意,请根据使用的晶振频率修改参考程序中的CLK_IN

LD_WriteReg(0x19,LD_PLL_MP3_19);

LD_WriteReg(0x1B,LD_PLL_MP3_1B);

LD_WriteReg(0x1D,LD_PLL_MP3_1D);

}

else

{

LD_WriteReg(0x1E,0x00);

//!!注意,下面三个寄存器,会随晶振频率变化而设置不同

//!!注意,请根据使用的晶振频率修改参考程序中的CLK_IN

LD_WriteReg(0x19,LD_PLL_ASR_19);

LD_WriteReg(0x1B,LD_PLL_ASR_1B);

LD_WriteReg(0x1D,LD_PLL_ASR_1D);

}

LD_WriteReg(0xCD,0x04);LD_WriteReg(0x17,0x4c);delay(5);

LD_WriteReg(0xB9,0x00);LD_WriteReg(0xCF,0x4f);

LD_WriteReg(0x6F,0xFF);

}

(2)语音识别用初始化

按照以下序列设置寄存器。

void LD_Init_ASR()

{

nLD_Mode=LD_MODE_ASR_RUN;

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,0x00);LD_WriteReg(0x42,0x08);

LD_WriteReg(0x44,0x00);LD_WriteReg(0x46,0x08);delay(1);

}

(3)写入识别列表

列表的规则是:每个识别条目对应一个特定的编号(1个字节),不同的识别条目的编号可以相同,而且不用连续。本芯片最多支持50个识别条目,每个识别条目是标准普通话的汉语拼音(小写),每2个字(汉语拼音)之间用一个空格间隔。下面是一个简单的例子:

编号可以相同,可以不连续,但是数值要小于256(00H~FFH)。例子中的“北京”和“首都”对应同一编号,说这两个词会有相同的结果返回。简单流程图如下:

代码如下:

#define CODE_DEFAULT 0

#define CODE_BEIJING 1

#define CODE_SHANGHAI 3

#define CODE_TIANJIN 7

#define CODE_CHONGQING 8

先介绍一个读取0xB2寄存器的函数,如果在以后的ASR命令函数前不能够读取到正确Idle状态,说明芯片内部可能出错了。当使用的电源电压/电流出现不稳定有较大波动时,有小概率会出现这种情况。出现这种情况时,建议Reset LD3320芯片,重新启动设置芯片。

// Return 1: success.

uint8 LD_Check_ASRBusyFlag_b2()

{

uint8 j;uint8 flag=0;

for(j=0;j<10;j++)

{

if(LD_ReadReg(0xb2)= 0x21)

{flag=1;break;}

delay(10);

}

return flag;

}

// Return 1: success.

uint8 LD_AsrAddFixed()

{

uint8 k, flag;

uint8 nAsrAddLength;

const char sRecog[5][13]={"bei jing","shou du","shang hai","tian jin", "chong qing"};

const uint8 pCode[5]={CODE_BEIJING,CODE_BEIJING,CODE_SHANGHAI,                                                                   CODE_TIANJIN,CODE_CHONGQING};

flag=1;

for(k=0;k<5;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<20;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;

}

(4)开始识别

设置几个相关的寄存器,就可以控制LD3320芯片开始语音识别。 值得注意:单片机程序中,一般会用一个全局变量控制当前状态,(例如:LD_ASR_RUNING状态或者LD_ASR_FOUNDOK状态),在编程时一定要把对该状态的设置放在正式LD3320芯片开始识别以前,例如下面例程中的语句nAsrStatus=LD_ASR_RUNING;便是设置控制变量。需要把这句语句放置在LD3320正式开始识别之前调用:

{

。。。

nAsrStatus=LD_ASR_RUNING;LD_AsrRun();

}

参考代码如下:

// Return 1: success.

uint8 LD_AsrRun()

{

nAsrStatus=LD_ASR_RUNING;

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(0xB2,0xff);

LD_WriteReg(0x37,0x06);delay(5);

LD_WriteReg(0x1C,0x0b);

LD_WriteReg(0x29,0x10);

LD_WriteReg(0xBD,0x00);

EX0=1;

return 1;

}

综上所述:语音识别的流程可以总结成如下的参考代码,可以以此为参考,根据使用流程进行合理的改动。

uint8 RunASR()

{

uint8 i=0;uint8 asrflag=0;

for(i=0;i<5;i++)

{

LD_Init_ASR();delay(100);

if(LD_AsrAddFixed()==0)

{LD_reset();delay(100);continue;}

delay(10);

if(LD_AsrRun()==0)

{LD_reset();delay(100);continue;}

asrflag=1;

break;

}

return asrflag;

}

对上述函数的调用参考代码:

文件main.c 函数main()

case LD_ASR_NONE:

{

nAsrStatus=LD_ASR_RUNING;

if (RunASR()==0)

{nAsrStatus=LD_ASR_ERROR;LED1=0;LED2=0;}

break;

}

(5)响应中断

如果麦克风采集到声音,不管是否识别出正常结果,都会产生一个中断信号。而中断程序要根据寄存器的值分析结果。

读取BA寄存器的值,可以知道有几个候选答案,而C5寄存器里的答案是得分最高、最可能正确的答案。

例如发音为“上海”并被成功识别(无其他候选),那么BA寄存器里的数值是1,而C5寄存器里的值是对应的编码3。

以下为简单流程图:

程序代码如下:

void ExtInt0Handler(void) interrupt 0 {ProcessInt0();}

void ProcessInt0()

{

uint8 nAsrResCount=0;EX0=0;ET0=0;

ucRegVal=LD_ReadReg(0x2B);

ucHighInt=LD_ReadReg(0x29);

LD_WriteReg(0x29,0);

ucLowInt=LD_ReadReg(0x02);

LD_WriteReg(0x02,0);

if(nLD_Mode==LD_MODE_ASR_RUN)

{

if((ucRegVal&0x10)&&LD_ReadReg(0xbf)==0x35&&LD_ReadReg(0xb2)==0x21)

{

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);

ET0=1;

return;

}

}

uint8 LD_GetResult() {return LD_ReadReg(0xc5);}

值得注意:获取识别结果 LD_ReadReg(0xba); 多少条候选识别结果,值1~4说明是有正确的识别结果。

4个候选结果的读取:根据0xba决定读取几个识别结果。

LD_ReadReg(0xc5);

LD_ReadReg(0xc7);

LD_ReadReg(0xc9);

LD_ReadReg(0xcb);

在目前的Demo程序中,只读取了最优候选。在其他使用场合,如果需要读取其他候选,用户可以自己编程实现。

3、声音播放

播放声音的操作顺序是:

MP3播放用初始化(包括通用初始化)→调节播放音量→开始播放声音, 并准备好中断响应函数,打开中断允许位。

(1)通用初始化

和语音识别部分一样,按指定序列设置寄存器。

(2)声音播放用初始化 请参照源代码设置寄存器。

void LD_Init_MP3()

{

nLD_Mode = LD_MODE_MP3;

LD_Init_Common();

LD_WriteReg(0xBD,0x02);

LD_WriteReg(0x17, 0x48); delay(10);

LD_WriteReg(0x85,0x52);

LD_WriteReg(0x8F,0x00);

LD_WriteReg(0x81,0x00);

LD_WriteReg(0x83,0x00);

LD_WriteReg(0x8E,0xff);

LD_WriteReg(0x8D,0xff); delay(1);

LD_WriteReg(0x87,0xff);

LD_WriteReg(0x89,0xff); delay(1);

LD_WriteReg(0x22,0x00);

LD_WriteReg(0x23,0x00);

LD_WriteReg(0x20,0xef);

LD_WriteReg(0x21,0x07);

LD_WriteReg(0x24, 0x77);

LD_WriteReg(0x25,0x03);

LD_WriteReg(0x26, 0xbb);

LD_WriteReg(0x27,0x01);

}

(3)调节播放音量

这里需要修改寄存器8E。 音量分为16级,用4位二进制表示,范围是0-15。 设置音量时,将(15-音量值) 设给寄存器8E的第2-5位。

源代码如下:

void LD_AdjustMIX2SPVolume(uint8 val)

{

uint8 ucTmp;

ucSPVol=val;

val=((15-val)&0x0f)<<2;

LD_WriteReg(0x8E,val|0xc3);

}

这个函数只调节喇叭(Speaker)的音量,和耳机等其他输出无关。而且实验板上只有喇叭连接了输出。

耳机音量是可以调节的,使用寄存器81(左耳音量)和83(右耳音量)。 2个寄存器都是只有第1-5位有效,共32级,而且这5位都为0(00000B)的时候是音量最大的,都为1(11111B)的时候音量最小。

(4)开始播放声音

开始播放位置清零(自定义变量Mp3Pos=0)

寄存器1B的第3位设为1(按位或0x08)

循环执行:

while(【播放条件】=true)

{

顺序将MP3数据放入寄存器01(每次一个字节);

Mp3Pos增加1

}

【播放条件】为下面条件都成立,有一个不满足就跳出循环:

读取寄存器06,第3位=0

Mp3Pos < MP3文件的总长度。

修改BA 、17等寄存器。(参照源代码)

开放中断允许。例如,EX0=1。

开始播放的简单流程图如下:

源代码如下:

void LD_play()

{

nMp3Pos=0;bMp3Play=1;

if(nMp3Pos>=nMp3Size)return ;

LD_ReloadMp3Data();

LD_WriteReg(0xBA,0x00);

LD_WriteReg(0x17,0x48);

LD_WriteReg(0x33,0x01);

LD_WriteReg(0x29,0x04);

LD_WriteReg(0x02,0x01);

LD_WriteReg(0x85,0x5A);

EX0=1;

}

void LD_ReloadMp3Data()

{

uint32 nCurMp3Pos;uint8 val;uint8 k;

nCurMp3Pos=nMp3StartPos+nMp3Pos;

FLASH_CS=1;FLASH_CLK=0;FLASH_CS=0;

IO_Send_Byte(W25P_FastReadData);                   /* read command */

IO_Send_Byte(((nCurMp3Pos&0xFFFFFF)>>16)); /* send 3 address bytes */

IO_Send_Byte(((nCurMp3Pos&0xFFFF)>>8));

IO_Send_Byte(nCurMp3Pos&0xFF);

IO_Send_Byte(0xFF);

ucStatus=LD_ReadReg(0x06);

while(!(ucStatus&MASK_FIFO_STATUS_AFULL)&&(nMp3Pos<nMp3Size))

{

val=0;

for(k=0;k<8;k++){FLASH_CLK=0;val<<=1;FLASH_CLK=1;val|=FLASH_DO;}

LD_WriteReg(0x01,val);nMp3Pos++;ucStatus=LD_ReadReg(0x06);

}

FLASH_CS=1;FLASH_CLK=0;

}

LD_ReloadMp3Data()函数的功能是送入数据,不同的硬件结构可能需要改写这一部分。例如有的系统可能使用大容量的RAM,取数据就会很方便。这里是根据串行FLASH存储器的接口写的函数,使用的是SPI协议。

(5)中断响应。

开始播放可以把声音数据的最初部分送入芯片,等到芯片播放这一段后会发出中断请求。而中断函数里会不断的送入数据,直到FIFO_DATA装满或声音数据结束。这一段程序和开始播放比较类似,都是通过LD_ReloadMp3Data()函数送入数据。

由于LD3320芯片只有一只管脚负责中断请求输出,所以一般情况下用一个中断响应函数处理2种中断。这里为了简明,将中断函数分开书写。

中断处理函数里,播放声音部分流程图如下:

要注意的是,寄存器操作2)和寄存器操作3) 并不会恢复寄存器02和29的内容。因为这时播放已经结束了,应该让02,29清零。 而数据重载结束后(达到了继续播放的条件),需要恢复寄存器02,29。 以便于继续出中断,连续播放。

源代码是:

void ExtInt0Handler(void) interrupt 0{ProcessInt0();}

void ProcessInt0()

{

uint8 nAsrResCount=0;

EX0=0;ET0=0;

ucRegVal=LD_ReadReg(0x2B);

ucHighInt=LD_ReadReg(0x29);

ucLowInt=LD_ReadReg(0x02);

LD_WriteReg(0x29,0);

LD_WriteReg(0x02,0);

if(nLD_Mode==LD_MODE_MP3)

{

if(LD_ReadReg(0xBA)&CAUSE_MP3_SONG_END)

{

LD_WriteReg(0x2B,0);

LD_WriteReg(0xBA,0x00);

LD_WriteReg(0xBC,0x00);

bMp3Play=0;

LD_WriteReg(0x08,0x01);

LD_WriteReg(0x08,0x00);

LD_WriteReg(0x33,0x00);

return ;

}

if(nMp3Pos>=nMp3Size)

{

LD_WriteReg(0xBC,0x01);

LD_WriteReg(0x29,0x10);

EX0=1;

return;

}

LD_ReloadMp3Data();

LD_WriteReg(0x29,ucHighInt);

LD_WriteReg(0x02,ucLowInt) ;

EX0=1;

}

}

补充说明

1、此芯片的特色是兼有语音识别和MP3播放的两项功能,但是由于这两项功能会使用一些公用的资源,所以为了使芯片稳定地工作,在功能切换的时候,必须从最“通用初始化”开始,对芯片进行一系列的设置。

2、当芯片长时间没有响应时,可能是应用程序的设置不合理或者是电源的电压/电流有比较大的波动造成。这时应使用芯片复位的功能(对芯片的RTSB*发送低电平),使芯片重新开始工作。

语音识别芯片LD3320介绍再续相关推荐

  1. 语音识别芯片LD3320介绍续

    语音识别芯片LD3320寄存器介绍 语音识别芯片LD3320寄存器大部分都是有读和写的功能,有的是接受数据的,有的是设置开关和状态的.寄存器的地址空间为8位,可能的值为00H到FFH.但除了本文档介绍 ...

  2. 语音识别芯片LD3320介绍

    语音识别芯片LD3320简介 LD3320 芯片是一款"语音识别"芯片,集成了语音识别处理器和一些外部电路,包括AD.DA 转换器.麦克风接口.声音输出接口等.LD3320不需要外 ...

  3. 基于WTK6900H语音识别芯片在智能语音识别晾衣架的应用设计方案介绍

    1.行业背景 对于经常做家务的人来说,洗衣服晾衣服是个体力活.传统的晾衣架要么是固定的高度,挂衣服拿衣服非常不方便,即便是升降的晾衣架,也要人手动操作,无疑增加了主妇的工作量. 而语音控制的智能升降晾 ...

  4. 晾衣架语音识别芯片应用设计方案介绍,唯创知音WTK6900H-24SS

    基于WTK6900H语音识别芯片在智能语音识别晾衣架的应用设计方案介绍 1.行业背景 对于经常做家务的人来说,洗衣服晾衣服是个体力活.传统的晾衣架要么是固定的高度,挂衣服拿衣服非常不方便,即便是升降的 ...

  5. 基于 STM32 的语音识别智能家居控制系统的设计(LD3320语音识别芯片+ESP8266 WIFI模块+DHT11温湿度采集+MQ系列 烟雾及可燃气体+蜂鸣器+步进电机模拟窗帘+OLED液晶显示+

    ## **基于 STM32 的语音识别智能家居控制系统的设计(LD3320语音识别芯片+ESP8266 WIFI模块(阿里云 或ONENET或局域网)+DHT11温湿度采集+MQ系列 烟雾及可燃气体+ ...

  6. 离线语音识别芯片-开发指南及芯片规格介绍

    ​   云知声(Unisound)作为行业内领先的人工智能企业,针对AI语音芯片各个不同的细分市场,共发布5款离线语音识别芯片,芯片及模块出货量已达百万级别.   下面介绍这5款芯片的各自特点:   ...

  7. 语音识别芯片模块LD3320到底甩了新唐ISD9160几条街

    时间:2018-11-02 12:26 来源:中国网 智能家居市场本地离线语音识别芯片的发展已为控制入口做了一个补充,在抛去了传统遥控器和手机APP之后,通过口令发送让家居环境达到舒适状态,让生活更便 ...

  8. 基于非特定人语音识别芯片的技术方案

    0 引言 随着高新技术在军事领域的广泛运用,武器装备逐步向高.精.尖方向发展.传统的军事训练由于训练时间长.训练费用高.训练空间窄,常常不能达到预期的训练效果,已不能满足现代军事训练的需要.为解决上述 ...

  9. ICRoute 语音识别芯片/声控芯片 用声音去沟通 LD332X系列语音识别芯片

    拼音串 + 51单片机 + LD3320 = 智能语音识别系统 ICRoute 推出LD332X非特定人语音识别芯片:只需要51MCU将关键词语拼音串,设置寄存器传入LD332X芯片,就可以完成语音识 ...

最新文章

  1. 8种方案解决重复提交问题
  2. 上市3年市值缩水9成,AI教育第一股流利说谋求私有化
  3. android自动创建桌面,Android应用启动后自动创建桌面快捷方式的实现方法
  4. ThreadPoolExecutor的execute源码分析
  5. win7建立wifi热点
  6. linux 定时执行kettle6,linux下使用crond定时执行kettle的job
  7. 5号字对应的数字字号_写好公文的几个数字口诀
  8. [转载] python+selenium定时爬取丁香园的新冠病毒每天的数据,并制作出类似的地图(部署到云服务器)
  9. 《Java高级Struts2》教学大纲(云计算) 版本号 编写人 版本描述 V1.0 目录 课程教学目标 5 (一)知识目标 5 (二)能力目标 6 (三)速度目标 6
  10. Mat转QImage
  11. sql服务器虚拟内存不足,SQL Server虚拟内存不足的解决方法
  12. 宽带通云解析结合用友致远A6使用方法
  13. 【JAVASE】IO系列 BufferedReader(超详细解析)
  14. raw格式(裸数据)格式文件读写
  15. 51.com新版上线 正式推出开放平台
  16. Java-设计模式之单例模式
  17. 苹果手机Charles设置未受信任的软件安装
  18. Delphi7企业原版_史上最经典的delphi 版本
  19. linux系统日志文件介绍
  20. LeetCode 316. Remove Duplicate Letters

热门文章

  1. java 定时任务只执行一次_Java执行定时任务
  2. IDEA集成SonarQube
  3. 服务器申请系统,政务云平台服务器申请
  4. 超级右键,让你的Mac电脑也能够鼠标右键新建文件!
  5. dubbo-源码环境搭建
  6. 将docker镜像推送到阿里云镜像仓库
  7. 【Python】OpenCV中的cv2.inpaint()函数
  8. 深圳码农买房记4:踩点篇
  9. fastadmin mysql字段类型为set 自动生成下拉框
  10. Mac 自带拼音输入法技巧