KL36和LD3320结合的语音识别系统
前言
在网上买的LD3320一般都是STM32或者STC或者Arduino的,没有比较冷门的板子,比如飞思卡尔的M+系列或者KL系列,但是我学的又是这些冷门的板子,所以进行了移植,现在算是移植成功了,移植过程遇到了许多问题,来分享一下
两个板子之间的通信原理
首先我们要知道他的通信原理,就是一句话,通过读或者写LD33320的寄存器来进行对控制,具体的寄存器可以查看LD3320的开发手册,读和写寄存器有两种方式,我们常用的就是用SPI通信,所以刚一开始遇到的问题就是不能正常读取寄存器,通过查找问题发现,是SPI通信的问题。
SPI通信遇到的问题
1.读取寄存器的值为0
首先我们要理解SPI通信的原理,具体的通信机制可以上网查,我这里最后理解的是,在接受数据的时候,主不能没事干,只充当一个接收者,也要发送数据,才能接收到数据,因为KL36板子的spi提供的驱动函数把发送函数和接收函数是分开的,所以当初一直读取寄存器为0,头疼了几天,最后把两个函数结合起来,在读取寄存器函数里面也要发送0x00过去,就能正常读取到寄存器的值了。要注意的是要把CPOL=0,CPHA=1
根本不用进入到SPI中断拿返回值(KDS提供的中断都会统一写在isr.c文件)
当初也一直以为中断拿返回值卡了很久
static uint_8 spi_send_byte(uint_8 No,uint_8 data)
{
SPI_MemMapPtr baseadd=SPI_baseadd(No);
while(!(SPI_S_REG(baseadd)&SPI_S_SPTEF_MASK));//等待发送缓冲区空闲
SPI_DL_REG(baseadd)=data;//数据寄存器接收数据
while(!(SPI_S_REG(baseadd)& SPI_S_SPRF_MASK)); //检测SPI是否收到了数据。
return SPI_DL_REG(baseadd);
}
unsigned char LD_ReadReg( unsigned char address )
{
uint_8 i;
gpio_set(WR, 0);
gpio_set(GEC_22, 0);
spi_send_byte(SPIB,0x05); // 发送 0x05
spi_send_byte(SPIB,address); // 发送 address
i=spi_send_byte(SPIB,0x00);
gpio_set(GEC_22, 1);
return i;
}
关于初始化的配置遇到的问题
我们要对一些引脚进行初始化,这些也是我遇到的一些问题
1 初始化了SPIB之后,执行不下去
KL36提供了两组SPI,当我想使用SPIB进行通信时,发现程序执行不下去了,但是当我把两组都初始化之后,就能正常执行下去了,所以应该是要把全部的SPI都进行初始化,才能使用,不知道是不是所有的单片机都是这样。
解决方法:把两组SPI都进行初始化
gpio_init(GEC_31,0,0); //设置SS为输入
spi_init(SPIA,1,6000,0,0); //初始化SPI0为主机
spi_init(SPIB,1,1500,0,1); //初始化SPI1为主机
gpio_init(GEC_22,1,0); //设置SS为输入 连LD的CS
2 不能将CS片选信号进行控制,就是输出高电平还是低电平
我们知道,SPI通信有一根线是CS片选信号,对LD3320进行通信的时候,要求CS片选信号是低电平,但是我们利用get获取引脚电平或者软件模拟的时候,发现CS引脚总是高电平,就算是用函数输出低电平还是一样,经过研究发现,改引脚在SPI_init的时候,把引脚设置为了输入,所以才总是高电平,控制不了,但是要求是低电平
解决方法:在SPI初始化之后,再将引脚复用为GPIO,输出,就可以对引脚进行输出高低电平的控制了
运行的时候遇到的问题
在能正常读取寄存器之后,以为就能很快进行语音的控制了,但是又遇到了一大堆问题,卡了好几天
1 不能多次循环识别,烧录进去之后只能执行一次
这个的问题就是不能回到主函数执行循环体,当时以为是LD3320不能多次产生中断,或者是以为退出不了中断处理程序,因此还加了恩智浦的讨论群,后来发现其实不是这样,这个模块是只要有声音,就会产生中断,多次试验后发现,是自己写的中断出问题了
解决方法:直接在中断里面写开发手册写好的中断,然后自己在关外部中断开外部中断
void GPIOB_Handler(void)
{
ProcessInt0();
gpio_clear_int(IRQ);
gpio_reverse(LIGHT_RED);
ENABLE_INTERRUPTS;
}
2 中断处理函数得到LD3320当前状态后,不能将LD_ASR_FOUNDOK返回值给主函数,case到然后执行处理函数
这个问题其实是和上面的那个问题结合起来的,所以当时不知道是哪里出了问题,明明产生中断了并且识别成功有正确返回值了,但是回到主函数之后就是不能被case到LD_ASR_FOUNDOK,就非常纳闷,正常的流程就应该获取结果然后进行引脚操作,后来参考了别人的程序,
解决方法:执行函数是在switch和while之前插入一个执行函数,就能进入到LD_ASR_FOUNDOK里面并且能循环执行了,非常奇怪,然后自己写了一个
接口函数
}//switch
control(nAsrRes);//这里插入
}//while
static void control(uint_8 Coad_val)
{
switch(Coad_val)
{
case 1:
gpio_set(LIGHT_GREEN, LIGHT_ON);
break;
case 3:
gpio_set(LIGHT_GREEN, LIGHT_OFF);
break;
default:
break;
}
}
识别不准确的问题
能识别之后,发现,识别非常的不准确,添加垃圾词之后,勉强能准确那么一点,但是有时候甚至开灯识别到关灯,这个的话后期经过调整语音监测点寄存器应该能好点,或者说,这个芯片就是识别的这么不准确,那就没办法了