基于Arduino的LD3320语音识别模块设计详解

文章目录

    • 基于Arduino的LD3320语音识别模块设计详解
  • 前言
  • 一、LD3320驱动编写
    • step 1.0 使用Arduino的SPI库,通过硬件SPI和LD3320通讯,读写寄存器
    • setp 1.1 访问LD3320的三个指定寄存器,检查硬件连接的可靠性
    • setp 1.2 进行驱动程序的编写,驱动LD3320进行语音识别
  • 二、第二部分 用模拟SPI编写LD3320的驱动程序
    • 模拟SPI通讯程序例程
  • 三、IIC修改命令词

前言

本文章为记录本人的学习过程,最终目的是设计一款IIC通讯方式的语音识别模块,该模块的主要功能,就是识别程序中设定的指令词,并返回识别结果,指令词和对应的返回编号可在程序中任意修改,不需要去给语音识别模块烧录固件,支持命令词的动态编辑。
模块硬件包含一块单片机芯片,一块LD3320芯片,以及外围电路。PCB工程已开源,网上到处都有。
基础功能:
1.动态编辑命令词,不需要烧录模块的固件
2.识别成功后返回对应结果
文章将会记录我从零开始的调试步骤以及遇到的问题,还有解决问题的详细思路。
接下来我们开始。
工程已上传(PCB工程+模块固件+Demo),有需要的可以先下载,链接挂在末尾

一、LD3320驱动编写

根据ICroute官方文档所写,想要驱动LD3320进行语音识别,可以使用软硬并口通讯方式对LD3320的寄存器进行读写从而驱动LD3320,也可以使用软硬SPI串行通讯方式对LD3320的寄存器进行读写,也可以驱动LD3320。需要注意的是,模拟并口驱动方式官方并不推荐,不仅速度慢,也会造成通讯不稳定等情况。推荐使用硬件SPI进行驱动,如果MCU没有SPI的硬件接口,也可以使用普通I/O口模拟SPI进行通讯,较为稳定。
回到正题,我手头正好有一块网上买的LD3320模块,是不带单片机的那种,板子上只有LD3320的那种。

直接先拿Arduino UNO开发板和这款LD3320进行原理测试,Let’s go。
直接用杜邦线,按如下方式连接:

5V – VCC
GND – GND
MISO – D12
MOSI – D11
SCK – D13
NSS – D4
RST – D9
IRQ – D2
WR – GND

官方文档所说,LD3320的电压为3V3,通讯引脚耐压也是3V3,超过3V3会使模块使用不稳定,但是在使用Arduino的实际测试中,未使用电压转换模块,反应良好。千万别学我,最好还是用3V3该转压还是得转请注意,引脚电平可以超过3v3,但是!电源只能是3v3
本部分我分为三小步来完成:

step 1.0 使用Arduino的SPI库,通过硬件SPI和LD3320通讯,读写寄存器
setp 1.1 访问LD3320的三个指定寄存器,检查硬件连接的可靠性
setp 1.2 进行驱动程序的编写,驱动LD3320进行语音识别

step 1.0 使用Arduino的SPI库,通过硬件SPI和LD3320通讯,读写寄存器

这一步的主要目的,是确定和LD3320能否进行正常的通讯,众所周知,SPI是一种串行通讯方式,需要至少连接五根线,为什么是五而不是四,因为要公地。
【SCK】 》》同步主机产生的数据传输的时钟脉冲。
【MOSI】 》》用于向外设发送数据的线,主机从这个引脚发送,从机从这个引脚接收。
【MISO】《《用于向主设备发送数据的线,主机从这个引脚接收,从机从这个引脚发送。
【CS】 》》片选信号,主机控制这个引脚来开启和禁用从机,低电平使能。
【GND】 祖传公地。
好了,SPI相关的知识我们就了解这么多,我们只需要知道他是全双工串行通讯,还有这些引脚是干啥的就可以了。继续下一步。

我们要和LD3320进行通讯,首先要让LD3320工作,我们需要先复位芯片,激活内部DSP。
只需要将LD3320芯片的47脚【RSTB*】发一个低电平,就可以复位LD3320到初始状态。然后需要激活DSP,就需要对片选【CS】做一次拉低再拉高的操作。

复位LD3320激活内部dsp的子函数

void LD_reset()//对LD3320复位  对47脚发送低电平 然后反转片选一次 激活DSP:
{digitalWrite(RSTB, HIGH);delay(1);digitalWrite(RSTB, LOW);delay(1);digitalWrite(RSTB, HIGH);delay(1);cSLow();delay(1);cSHigh();delay(1);//writeReg(0xb9, 0x00);  //寄存器 0xB9  当前添加识别语句的字符串长度   初始化时写入0x00
}

激活DSP之后,就可以进行LD3320的寄存器读写了,我们使用的是SPI串行方式,根据官方的文档描述,SPI的通讯参数需要设置如下:
SPI没有官方标准,所以要好好看芯片的datasheet

在Arduino的setup里对SPI参数进行设置

void setup() {......SPI.setClockDivider(SPI_CLOCK_DIV16);  //16分频SPI.setDataMode(SPI_MODE2);  //时钟极性CPOL 1   时钟相位CPHA  0SPI.setBitOrder(MSBFIRST);  //高位在前......
}

接下来写一个用于读寄存器的程序,根据官方文档描述,要读寄存器,需要先发送0x05,然后再发送十六进制的寄存器地址,然后再读取芯片返回过来的十六进制数据。

读寄存器的子函数

unsigned char LD_readReg(unsigned char address)
{unsigned char result;//局部变量 保存读取的数据cSLow();   //片选使能 低电平有效delay(10);SPI.transfer(0x05);SPI.transfer(address);  //发送 寄存器地址result = SPI.transfer(0x00);  //读取数据cSHigh();  //片选去使能return (result);   //返回数据
}

接下来写一个用于写寄存器的程序,根据官方文档描述,要写取寄存器,需要先发送0x04,然后再发送十六进制的寄存器地址,最后发送十六进制数据。

写寄存器的子函数

void LD_writeReg(unsigned char address, unsigned char value)
{cSLow();//片选使能delay(10);SPI.transfer(0x04);//发送0x04  是写入模式SPI.transfer(address);  //发送 寄存器地址SPI.transfer(value);  //发送 数据cSHigh();//片选去使能
}

接下来,进行对LD3320寄存器的读写测试。
如果,我们先向可读写的寄存器写入某个数值,再读出来,用来检查寄存器读写是否正常。
每次先向一个寄存器写,再读出来,内容是完全正确,但是在接下来的语音识别操作中,发现LD3320芯片并不会鸟你,这是为什么呢,因为可能你的数据存在SPI的总线上,但是没有Touch到寄存器里面
所以我建议读写寄存器的序列如下:

对寄存器写入再读取的操作顺序

void setup() {......LD_reset();//先复位激活LD3320delay(1);LD_readReg(0x06);//读取一次0X06寄存器delay(1);LD_writeReg(0x35, 0x33);//对寄存器0x35写入0x33LD_writeReg(0x1b, 0x55);//对寄存器0x1b写入0x55LD_writeReg(0xb3, 0xaa);//对寄存器0xb3写入0xaaSerial.print(LD_readReg(0x35),HEX); Serial.print(" ");//读取并打印寄存器0x35的值Serial.print(LD_readReg(0x1b),HEX); Serial.print(" ");//读取并打印寄存器0x1b的值Serial.print(LD_readReg(0xb3),HEX); Serial.println(" ");//读取并打印寄存器0xb3的值
}

就是向 3 个寄存器先依次写数据,再依次读数据出来。作为比较。
这样可以有效地验证读写寄存器是否正常。
如果结果是 33 55 aa 那么恭喜你,读写寄存器正常,可以进行下一步操作了。
这一步基本不会出错,如果出错了,请详细比对SPI的参数设置
step1.0 完整代码,在工程文档中,有需要的直接下载即可

setp 1.1 访问LD3320的三个指定寄存器,检查硬件连接的可靠性

既然已经可以正常读写LD3320的寄存器了,那为了保证LD3320稳定工作,再来检查一下硬件之间连接的可靠性。
我们在复位LD3320之后,读取寄存器0x06两次,再读取寄存器0x35和0xb3,将值打印出来。

访问三个指定寄存器的操作

void setup() {......LD_reset();//先复位激活LD3320delay(1);Serial.print(LD_readReg(0x06),HEX); Serial.print(" "); //读取并打印寄存器0x06的值Serial.print(LD_readReg(0x06),HEX); Serial.print(" "); //读取并打印寄存器0x06的值Serial.print(LD_readReg(0x35),HEX); Serial.print(" "); //读取并打印寄存器0x35的值Serial.print(LD_readReg(0xb3),HEX); Serial.println(" ");//读取并打印寄存器0xb3的值}

如果打印出来的值,是 87 87 80 FF 或者 00 87 80 FF 则正常。不要把LD3320断电,复位Arduino UNO ,多读取几次,看看值是否稳定,如果稳定,则连接非常稳定。就可以进行语音识别的操作了。

setp 1.2 进行驱动程序的编写,驱动LD3320进行语音识别

现在我们进行完整驱动的编写。首先,先介绍驱动LD3320进行语音识别的流程。
ASR初始化→写入识别列表→开始识别→准备好中断函数→打开中断
然后每次识别到语音,无论是否识别到命令词,就会触发中断,运行你准备好的中断函数,正常情况是只运行一次就结束了,但是你可以在中断函数中添加ASR初始化→开始识别,继续进行下一轮识别,达到循环识别的目的。
接下来,我们按照流程来编写驱动程序。先贴两张寄存器地址的图表。

通用初始化函数,直接抄作业就可以了,都是官方例程,唯一需要注意的,就是晶振频率相关的四个变量

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, PLL_11);//和晶振频率有关,注意调整LD_writeReg(0x1e, 0x00);LD_writeReg(0x19, PLL_ASR_19);//和晶振频率有关,注意调整LD_writeReg(0x1b, PLL_ASR_1B);//和晶振频率有关,注意调整LD_writeReg(0x1d, 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);
}

ASR初始化函数,一样的,抄作业就完事了,没什么需要注意的

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

接下来,写入识别列表,也就是把自定义的命令词写入到LD3320里面。需要注意的是,我们在写入识别列表之前,要先读取0xB2寄存器的值,查看芯片的状态是否正常,如果不正常,则需要先复位一次芯片,再重新初始化,再写入。为什么会出现不正常的情况,主要原因,是电压和电流不稳定造成的。

检查0xB2寄存器的函数,返回1则正常,返回0失败

int LD_Check_ASRbusyFlag_b2()/**检查芯片状态**/
{for (int j = 0; j < 10; j++){if (LD_readReg(0xb2) == 0x21)//寄存器值0x21为空闲{return 1;}delay(10);}return 0;
}

如果检查寄存器结果是正常,那么就可以写入识别词了。

写入识别列表的函数,char *pass也可以用string pass代替

int LD_ASRAddFixed(char *pass, int num) /**添加命令词**/
{int i; //局部变量 用来循环写入识别字的数据,并记录字符的长度int flag;//返回添加成功或者失败flag = 1;for (int j = 0; j < 5; j++) {//这个循环没有任何意义if (LD_Check_ASRbusyFlag_b2() == 0) {flag = 0;break;//如果检查到不支持,则退出,并返回添加失败}LD_writeReg(0xc1, num);//添加命令的编号LD_writeReg(0xc3, 0);//识别字添加时写入0x00LD_writeReg(0x08, 0x04);//清除数据缓存器内容delay(1);LD_writeReg(0x08, 0x00);//清除后再次写入0x00delay(1);for (i = 0; i <80; i++)//为什么i<80,因为单个命令词最多支持80字节,最好只写入79字节{if (pass[i] == 0)break;//如果读取到空字符则退出循环写入LD_writeReg(0x5, pass[i]);///将识别字写入寄存器0x05}LD_writeReg(0xb9, i);//在0xb9寄存器写入当前字符长度LD_writeReg(0xb2, 0xff);LD_writeReg(0x37, 0x04);//在0x37寄存器写入 0x04通知DSP 我要写入一条识别词break;//写入完成,退出}return flag;//返回添加成功或者失败
}

接下来,就要启动识别了。

启动识别函数,照抄就行,这些变量都在程序头部进行宏定义

int LD_AsrRun()/**启动ASR**/
{LD_writeReg(0x35, MIC_VOL);//在0x35寄存器 写入识别灵敏度LD_writeReg(0xb3, speech_endpoint);//在0xb3寄存器 写入语音端点检测功能的灵敏度  0关闭 数值越小越灵敏LD_writeReg(0xb4, speech_start_time);//在0xb4寄存器 写入判断语句开始的时间LD_writeReg(0xb5, speech_end_time);//在0xb5寄存器 写入判断语句结束的时间LD_writeReg(0xb6, voice_max_length);//在0xb6寄存器 写入识别语句的最长长度LD_writeReg(0xb7, noise_time);//在0xb7寄存器 写入初始忽略掉的底噪时间LD_writeReg(0x1c, 0x09);//保留命令字LD_writeReg(0xbd, 0x20);//保留命令字LD_writeReg(0x08, 0x01);//清除缓存器delay( 1);LD_writeReg(0x08, 0x00);//再次写入00delay( 1);if (LD_Check_ASRbusyFlag_b2() == 0) //查看寄存器0xb2的值是否正常{return 0;//不正常返回0 ,启动失败}LD_writeReg(0xb2, 0xff);//更新寄存器0xb2的值LD_writeReg(0x37, 0x06);//通知dsp开始语音识别delay( 5 );LD_writeReg(0x1c, 0x0b);//选择声音输入方式,因为我用双极电容麦,直接写入0x0B,LD_writeReg(0x29, 0x10);//中断开启LD_writeReg(0xbd, 0x00);//启动ASR模块return 1;//成功
}

启动之后,我们准备好中断函数,用来响应LD3320发送的中断信号,查询返回值并启动下一轮识别。

中断响应函数

void LD_ASRget()/**中断执行程序**/
{/****以下程序对LD3320的运算结果进行分析,取其运算结果****/uint8_t Asr_Count = 0;LD_writeReg(0x29, 0) ;LD_writeReg(0x02, 0) ;if ((LD_readReg(0x2b) & 0x10) && LD_readReg(0xb2) == 0x21 && LD_readReg(0xbf) == 0x35){Asr_Count = LD_readReg(0xba); //读取有几个候选值if (Asr_Count > 0 && Asr_Count < 4){readnum = LD_readReg(0xc5); //得到最佳选项 如果你需要其他选项,可以去另外三个寄存器掏readflag = 1;}else {Serial.println("运算结果是无法识别");}LD_writeReg(0x2b, 0);LD_writeReg(0x1C, 0);}else {Serial.println("运算结果是无法识别");}/****以下程序对LD3320进行初始化,预备进行下一次识别****/LD_readReg(0x06);delay(10);LD_readReg(0x06);LD_writeReg(0x89, 0x03);delay(5);LD_writeReg(0xcf, 0x43);delay(5);LD_writeReg(0xcb, 0x02);LD_writeReg(0x11, PLL_11);LD_writeReg(0x1e, 0x00);LD_writeReg(0x19, PLL_ASR_19);LD_writeReg(0x1b, PLL_ASR_1B);LD_writeReg(0x1d, PLL_ASR_1D);delay(10);LD_writeReg(0xcd, 0x04);LD_writeReg(0x17, 0x4c);delay(5);LD_writeReg(0xcf, 0x4f);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);LD_writeReg(0x1c, 0x09);LD_writeReg(0xbd, 0x20);LD_writeReg(0x08, 0x01);delay( 1);LD_writeReg(0x08, 0x00);delay( 1);LD_writeReg(0xb2, 0xff);LD_writeReg(0x37, 0x06);delay( 5 );LD_writeReg(0x1c, 0x0b);LD_writeReg(0x29, 0x10);LD_writeReg(0xbd, 0x00);
}

把这个丢在LOOP里面循环运行

int LD_Read()
{if (readflag == 1){readflag = 0;return readnum;}return -1;
}

所有的子函数都准备完毕了,接下来,开始识别!
Let’s Go!!!

再来个运行语音识别的子函数,我保证是最后一个了

int RunASR()
{int asrflag = 0;for (int z = 0; z < 5; z++) {//循环尝试五轮LD_Init_ASR();//进行ASR初始化delay(100);//延时时间自己控制,可以改5msif (LD_ASRAddFixed("kai deng", 1) == 0) {//添加命令词kai deng,编号是1,注意,两个字的拼音用空格隔开LD_reset();                   //如果失败了,复位芯片delay(100);continue;                     //进行下一轮尝试}if (LD_ASRAddFixed("guan deng", 2) == 0) {//添加命令词guan deng,编号是2LD_reset();//如果失败了,复位芯片delay(100);continue;//进行下一轮尝试}if (LD_AsrRun() == 0) {//启动识别LD_reset();//如果失败了,复位芯片delay(100);continue;//进行下一轮尝试}asrflag = 1;//运行到这里了,说明上面的步骤都成功了break;//退出循环}return asrflag;//返回状态,成功或者失败
}

接下来调用RunASR()函数就可以启动语音识别了,当然你也可以这样写

if(RunASR()==0){Serial.println("ASR启动失败");
}
else Serial.println("ASR启动成功");

然后就可以愉快得尝试了。

二、第二部分 用模拟SPI编写LD3320的驱动程序

模拟SPI通讯程序例程

时隔不知多少日,我又来更新了~~~~~~~~~~
这部分内容来介绍一下模拟SPI通讯,为什么要这样做呢,因为部分的单片机没有硬件SPI的支持,只能通过普通引脚来模拟SPI,达到通讯的目的,不过这样实现的通讯,往往速度较硬件SPI慢的不止一点点,也不够稳定,只能说,勉强够用。
先附上时序图,其实和硬件SPI的时序一毛一样。


和常规的 SPI通讯一样,查看时序图可知这四个引脚的状态。CS引脚(片选引脚SCS),低电平有效,也就是说在开始通讯之前,要先将CS引脚置为低电平,结束通讯之后,将CS引脚置为高电平。CLK引脚(时钟信号引脚SDCK),在开始通讯之后,要送出稳定的时钟信号,下降沿有效,在CLK送出下降沿的时候,MOSI(SDI)或者MISO(SDO)线上的电平信号才被记录为一个位数据。
写寄存器的操作和之前一样,要先写入一个字节0x04(写入寄存器的指令,读出寄存器为0x05),再写入一个字节(地址的值),最后写入数据。如图所示的SDI线上的时序,分为了三个字节位置,分别是指令字节、地址字节、数据字节,每个四节各八位。众所周知,0b1111 1111是0xFF,写寄存器的图中指令字节是0b 0000 0100,也就是0x04,这是8421-BCD码的知识点,不会的同学自己百度哦。

废话不多说,直接上程序。

头部宏定义
nop根据单片机的运行周期自行调整,没有很严格的要求

#define nop 0.07
#define CS D4
#define SPI_MOSI_PIN  D11
#define SPI_SCK_PIN   D13
#define SPI_MISO_PIN  D12

模拟SPI写寄存器的部分程序
程序分成三个部分,分别为写入指令,写入地址,写入数据,三个流程结束,就成功完成了写寄存器的操作

void LD_writeReg(unsigned char address, unsigned char dataout)
{unsigned char i = 0;unsigned char Command = 0x04;//写寄存器的指令cSLow();//片选使能delayMicroseconds(nop * 3);//延时三个机器周期,如果通讯不正常,调整这里的延时时间可以解决问题//写入 指令for ( i = 0; i < 8; i++)//循环八次  循环结束就完整得写入了 Command {if ((Command & 0x80) == 0x80)//按位与 Command & 0b 1000 0000  判断最高位是否为1digitalWrite(SPI_MOSI_PIN, HIGH);//置为高elsedigitalWrite(SPI_MOSI_PIN, LOW);//置为低delayMicroseconds(nop * 3);//延时三个机器周期digitalWrite(SPI_SCK_PIN, LOW);//时钟信号拉低Command = (Command << 1);//将Command 左移一位 delayMicroseconds(nop * 3);//延时三个机器周期digitalWrite(SPI_SCK_PIN, HIGH);//时钟信号拉高}//写入 地址 (和写入指令的操作一样)for (i = 0; i < 8; i++){if ((address & 0x80) == 0x80)digitalWrite(SPI_MOSI_PIN, HIGH);elsedigitalWrite(SPI_MOSI_PIN, LOW);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, LOW);address = (address << 1);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, HIGH);}delayMicroseconds(nop * 3);//写入 数据(和写入指令的操作一样)for (i = 0; i < 8; i++){if ((dataout & 0x80) == 0x80)digitalWrite(SPI_MOSI_PIN, HIGH);elsedigitalWrite(SPI_MOSI_PIN, LOW);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, LOW);dataout = (dataout << 1);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, HIGH);}delayMicroseconds(nop * 3);//延时三个系统周期cSHigh();//片选去使能
}

模拟SPI读寄存器的部分程序
程序分成三个部分,分别为写入指令,写入地址,读取数据,三个流程结束,就成功完成了读寄存器的操作

unsigned char LD_readReg(unsigned char address)
{unsigned char i = 0;unsigned char datain = 0 ;//用于存储读取到字节完整数据unsigned char Temp = 0;//用于存储读取到的字节单个位的数据unsigned char Command = 0x05;//读寄存器的指令cSLow();//片选使能delayMicroseconds(nop * 3);//延时三个系统周期//写入 指令(和之前一样的操作,就不打备注了)for ( i = 0; i < 8; i++){if ((Command & 0x80) == 0x80)digitalWrite(SPI_MOSI_PIN, HIGH);elsedigitalWrite(SPI_MOSI_PIN, LOW);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, LOW);Command = (Command << 1);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, HIGH);}//写入 地址(和之前一样的操作,就不打备注了)for (i = 0; i < 8; i++){if ((address & 0x80) == 0x80)digitalWrite(SPI_MOSI_PIN, HIGH);elsedigitalWrite(SPI_MOSI_PIN, LOW);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, LOW);address = (address << 1);delayMicroseconds(nop * 3);digitalWrite(SPI_SCK_PIN, HIGH);}delayMicroseconds(nop * 3);//读取数据for (i = 0; i < 8; i++){datain = (datain << 1);//将datain 左移一位Temp = digitalRead(SPI_MISO_PIN);//读取到一位数据delayMicroseconds(nop * 3);//延时三个系统周期digitalWrite(SPI_SCK_PIN, LOW);//时钟信号拉低if (Temp == 1) {//如果Temp 为1datain |= 0x01;//或等于  将datain 的最低位变为1}delayMicroseconds(nop * 3);//延时三个系统周期digitalWrite(SPI_SCK_PIN, HIGH);//时钟信号拉高}delayMicroseconds(nop * 3);//延时三个系统周期cSHigh();//片选去使能return datain;//返回最后结果
}

这里给不懂 & 和 | 的同学稍微解释一下

& 在C语言里面是位与运算符,| 在C语言里面是位或运算符,例如:

int a=0x03;//0b 0000 0011
int b=0x02;//0b 0000 0010
int c,d;
c=a&b;
d=a|b;
//c的值为0x02  0&1=0  1&1=1  0&0=0
//d的值为0x03  0|1=1  1|1=1  0|0=0

&= 和 |= 的意思就是与等于和或等于,例如:
a&=b 的意思就是,先将a和b按位与,再将结果赋值给a
a|=b 的意思就是,先将a和b按位或,再将结果赋值给a

好了跑题了,回到正题,上述通过模拟SPI读写寄存器的操作就完成了,后面的驱动部分,按照第一部分硬件SPI驱动LD3320的方法移植过来就好了。
补充一点,驱动程序里面的外部中断响应操作不规范,正常情况下,读取到外部中断后,应该先关闭该外部中断,然后去执行一系列中断触发的程序,执行结束后重新打开该外部中断。建议修改。
文章结尾附上源码和PCB的下载链接
https://download.csdn.net/download/qq_40532525/85002112?spm=1001.2014.3001.5503

三、IIC修改命令词

原理很简单,就是通过自己拟定的代码命令,来操控语音识别模块的初始化等等进程,唯一需要注意的是,Arduino的IIC通讯缓存区只有32个字节,所以这边建议将命令词进行切割分块发送,最后发送一个自拟定的结束命令,通知模块我发送完了,你可以装载命令词了,具体方法查看例程3.1。例程2.3里面有切割字符串并载入到3320里面的例程。
祝大家玩的愉快,LD3320的内容就告一段落了。

基于Arduino IDE开发的LD3320语音识别模块相关推荐

  1. 基于Arduino IDE开发的ESP8266(ESP-12F)项目4 ——中断及高级输入输出

     本次写这篇文章是自己做一下学习记录,如有错误,还请大家斧正!!! 日后及时修正!感谢支持! 欢迎大家的关注        点赞        收藏        留言 目录 前言 一.新建工程 二. ...

  2. 基于Arduino IDE开发的ESP8266(ESP-12F)项目2 ——按键操作

     本次写这篇文章是自己做一下学习记录,如有错误,还请大家斧正!!! 日后及时修正!感谢支持! 欢迎大家的关注        点赞        收藏        留言 目录 前言 一.新建工程 二. ...

  3. 基于Arduino UNO开发板,超声波模块,直流电机,实现电机驱动

    这:是我的手机,一台能无线充电的华为Mate 30Pro 4G 这:是我的的无线充电器,(虽然速度低,毕竟店家送的) 这是我维持一年多的充电样子,为什么这么做呢......因为无线充电会发烫,毕竟无线 ...

  4. LD3320语音识别模块开发

    达者为先  师者之意 LD3320语音识别模块开发 1 LD3320语音识别模块基本参数 1.1 基本参数 1.2 识别原理 1.3 解决方案: 2 LD3320语音识别模块二次开发 2.1 源码修改 ...

  5. 基于FPGA的LD3320语音识别模块驱动设计

    一.设计要求 以FPGA为控制核心,接收语音控制信号和识别控制信息: 通过继电器完成对热水器.加湿器.空调等三个家用电器的控制: 二次升级要求:使用无线模块完成对热水器.加湿器.空调等三个家用电器的控 ...

  6. 单片机设计:基于stm32智能语音识别蓝牙音响(ld3320语音识别模块+mp3模块+喇叭+点阵屏+OLED+蓝牙+手机app)

    单片机设计:基于stm32智能语音识别蓝牙音响(ld3320语音识别模块+mp3模块+喇叭+点阵屏+OLED+蓝牙+手机app) 一.主要功能: 1.手机app播放内存卡的音乐.同时点阵屏随音乐进行跳 ...

  7. STM32F103C8T6 LD3320语音识别模块非特定识别人声 离线控制 智能家居 开发板

    STM32F103C8T6 LD3320语音识别模块非特定识别人声 离线控制 智能家居 开发板 STM32F103C8T6 LD3320语音识别模块非特定识别人声 离线控制 智能家居 开发板 测试单片 ...

  8. 基于Arduino Uno开发板制作音乐播放器

    基于Arduino Uno开发板制作音乐播放器 本文将基于Arduino开发板实现一个音乐播放器. 利用Arduino Uno读取sd卡模块中内存卡的音乐,传输信号到扬声器进行播放. 一.项目软硬件简 ...

  9. Arduino开发(二)_基于Arduino UNO开发板的RGB灯光控制方法

    Arduino开发(二)_基于Arduino UNO开发板的RGB灯光控制方法 首先,我们来看一下Arduino UNO开发板的具体引脚排列,如下图所示, 再了解一下三色RGB LED模块,如下图所示 ...

最新文章

  1. HarmonyOS Unknown HarmonyOS XML attribute
  2. 找取照片上的25个特征点,并保存结果
  3. 关于样式表setStyleSheet
  4. OpenCV中cornerSubPixel()亚像素求精原理
  5. Linux Shell脚本的10个有用的“面试问题和解答”
  6. MySQL多表数据记录查询详解
  7. 20.TCP/IP 详解卷1 --- TCP 的成块数据流
  8. UEFI引导修复教程
  9. C语言期末考试复习题(有答案)
  10. 这10个免费电子书网站合集赶紧收藏了!
  11. 通过shell命名和TexturePacker工具,将.pvr.ccz批量转换为png格式
  12. SQL窗口函数实现累加求功能
  13. Python绘制股票趋势图
  14. 计算机组网的有线传输媒介主要依赖,家庭无线局域网组建毕业论文
  15. 【转】Tomato-shibby无线中继(无线级联)
  16. python简单爬虫入门一_Python简单爬虫入门三
  17. 818品牌logo背后的故事
  18. ios6应用运行在ios7系统上
  19. 5天带你读完《Effective Java》(三)
  20. java面向对象编程基础

热门文章

  1. 25000linux集群源码,一文看懂 Redis5 搭建集群
  2. 为你的个人博客添加访客地图
  3. 英语音标,元音汇总(0基础学英语!必备!)
  4. USB ncm虚拟网卡
  5. c语言文字转语音代码,C语言实现将文字转为语音
  6. python之pyttsx3实现文字转语音播报
  7. MySQL数据查询之多表查询
  8. 计算机寸出,电脑显示器长31cm宽23cm是多少寸?
  9. 微擎添加绑定公众号,空白页或500错误,打不开
  10. 导游APP开发模板现源码