语音识别实验
此实验采用STM32核心板+ LD3320模块,通过初始化LD3320并写入待识别关键词,对麦克风说出相应关键词,实现实训平台上的流水灯相应变化的效果。
LD3320 是一颗基于非特定人语音识别 (SI-ASR:Speaker-Independent Automatic Speech Recognition)技术的语音识别/声控芯片。提供了真正的单芯片语音识别解决方案。
LD3320 芯片上集成了高精度的 A/D 和 D/A 接口,不再需要外接辅助的Flash 和 RAM,即可以实现语音识别/声控/人机对话功能。并且,识别的关键词语列表是可以动态编辑的。
主要特色功能:
- 非特定人语音识别技术:不需要用户进行录音训练。
- 可动态编辑的识别关键词语列表:只需要把识别的关键词语以字符串的形式传送进芯片,即可以在下次识别中立即生效。
- 真正单芯片解决方案:不需要任何外接的辅助 Flash 和 RAM,真正降低系统成本。
- 内置高精度 A/D和D/A通道:不需要外接 AD 芯片,只需要把麦克风接在芯片的AD 引脚上;可以播放声音文件,并提供 550mW 的内置放大器。
- 高准确度和实用的语音识别效果。
- 支持用户自由编辑 50 条关键词语条:在同一时刻,最多在 50 条关键词语中进行识别,终端用户可以根据场景需要,随时编辑和更新这 50 条关键词语的内容。
程序代码
1、 LD3320创建语音识别任务,完成关键词的设置。
void LD3320_Task(void)
{
uint8_t i=0;
uint8_t LD_ASR_Candi_Num,LD_ASR_EXTI_IFO; //从中断代码拿过来的
char buf[20];
uint8_t j=1;
//测试读取寄存器
printf("LD3320_Task...\r\n");
ETH_CS_H();
VS_CS_H();
LD_CS_K_H() ; //关掉底板上的LD3320 实训平台对比测试
LD_WriteReg(0x29,0) ; /*关闭中断*/
LD_WriteReg(0x02,0) ;
//1 空闲状态;2 识别成功状态;3 识别失败状态。
while(1)
{
switch(process)
{
case 0: /*ld3320处于空闲状态*/
i++;
process=LD_Run();
if(i==4)
{
printf("语音识别模块内部故障,请检查硬件连接 \r\n");
return;
}
break;
case 1: /*ld3320语音准备OK*/
if(flag) /*中断判断*/ //判断识别是否成功
{
switch(direct) /*对结果执行相关操作*/
{
case 1: /*命令“流水灯”*/
printf(" 流水灯 指令识别成功\r\n");
break;
case 2: /*命令“闪烁”*/
printf(" 闪烁 指令识别成功\r\n");
break;
case 3: /*命令“按键触发”*/
printf(" 开灯/点灯 指令识别成功\r\n");
break;
case 4: /*命令“全灭”*/
printf(" 全灭 指令识别成功\r\n");
break;
default:
break;
}
process=flag=0;
}
break;
case 2: /*ld3320语音识别失败*/
i=0;
if(flag) /*中断判断*/
{
printf("未识别到有效信息或没有声音\r\n");
process=flag=0;
}
break;
default:
break;
}
if((process==1)&&(LD_ReadReg(0xB2)==0x21) && (LD_ReadReg(0xbf)==0x35))
{
printf("进入判断 原中断处理 \r\n");
flag=1; //!!!!!!
LD_ASR_Candi_Num = LD_ReadReg(0xba);
if(LD_ASR_Candi_Num>0 && LD_ASR_Candi_Num<=4)
{
direct = LD_ReadReg(0xc5);
process=1; //识别成功
printf("接收到的语音信息 %d \r\n",direct );
}else
process=2; //识别失败
/*完成一次语音识别后重新配置寄存器*/
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
}
LD_Test();
}
}
音乐播放器实验
单片机首先挂载FATS文件系统,接着在加载指定路径下的音频文件,最终通过VS1053解码并输出音频。VS1053采用SPI协议传输音频数据。但其还有两种不同的工作模式一种是串行数据接口的串行协议(SDI),一种是串行命令接口的串行协议(SCI)。所以片选有两个XCS and XDCS。
SCI 串行总线命令接口包含了一个指字节、一个地址字节和一个 16 位的数据字。读写操作可以读写单个寄存器,在 SCK 的上升沿读出数据位,所以主机必须在下降沿刷新数据SCI 的字节数据总是高位在前低位在后的。第一个字节指令字节, 只有 2 个指令,也就是读和写,读为0X03,写为 0X02。
对于SCI的读时序,是向 VS1053 读取数据,通过先拉低 XCS,然后发送读指令(0X03),再发送一个地址,最后,我们在 SO 线(VS_MISO)上就可以读到输出的数据了。而同时SI(VS_MOSI)上的数据将被忽略。
对于SCI的写时序,与读时序一样都是先发指令,再发地址。不过写时序中,我们的指令是写指令(0X02),并且数据是通过 SI 写入 VS1053的, SO 则一直维持低电平。在这两个图中,DREQ 信号上都产生了一个短暂的低脉冲,也就是执行时间。我们在写入和读出 VS1053 的数据之后,它需要一些时间来处理内部的事情,这段时间,是不允许外部打断的,所以,我们在 SCI 操作之前,最好判断一下DREQ 是否为高电平,如果不是,则等待 DREQ 变为高。
程序代码
这里我们仅对主函数进行展示:
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
// KEY_Init(); //初始化按键
LCD_Init(); //初始化LCD
// W25QXX_Init(); //初始化W25Q128
VS_Init(); //初始化VS1053
my_mem_init(SRAMIN); //初始化内部内存池
exfuns_init(); //为fatfs相关变量申请内存
// f_mount(fs[0],"0:",1); //挂载SD卡
// f_mount(fs[1],"1:",1); //挂载FLASH.
POINT_COLOR=RED;
// while(font_init()) //检查字库
// {
// LCD_ShowString(30,50,200,16,16,"Font Error!");
// delay_ms(200);
// LCD_Fill(30,50,240,66,WHITE);//清除显示
// }
while(SD_Init()) //检测SD卡
{
LCD_ShowString(30,70,200,16,16,"SD Card Failed!");
delay_ms(200);
LCD_Fill(30,70,200+30,70+16,WHITE);
delay_ms(200);
}
LCD_ShowString(30,70,200,16,16,"SD Card OK");
Show_Str(30,50,200,16,"战舰 STM32实训平台",16,0);
Show_Str(30,70,200,16,"音乐播放器实验",16,0);
Show_Str(30,90,200,16,"正点原子@ALIENTEK",16,0);
Show_Str(30,110,200,16,"2015年1月20日",16,0);
Show_Str(30,130,200,16,"KEY0:NEXT KEY2:PREV",16,0);
Show_Str(30,150,200,16,"KEY_UP:VOL+ KEY1:VOL-",16,0);
while(1)
{
LED1=0;
Show_Str(30,170,200,16,"存储器测试...",16,0);
printf("Ram Test:0X%04X\r\n",VS_Ram_Test());//打印RAM测试结果
Show_Str(30,170,200,16,"正弦波测试...",16,0);
VS_Sine_Test();
Show_Str(30,170,200,16,"<<音乐播放器>>",16,0);
LED1=1;
mp3_play();
}
}