基于语音识别的微博签到系统
LD3320介绍
1 通过快速而稳定的优化算法,完成非特定人语音识别,识别准确率95%。
2 不需要外接任何辅助的Flash芯片,RAM芯片和AD芯片,就可以完成语音识别功能。
3 每次识别最多可以设置50项候选识别句,每个识别句可以是单字,词组或短句,长度为不超过10个汉字或者79个字节的拼音串。识别句内容还可以动态编辑修改。
4 芯片内部已经准备了16位A/D转换器、16位D/A转换器和功放电路,麦克风、立体声耳机和单声道喇叭可以很方便地和芯片管脚连接。
5 支持并行和串行接口,串行方式可以简化与其他模块的连接。
在本系统中采用的LD3320模块如图7,LD3320芯片外部已经连接了麦克风,耳机接口,基本电路,只引出了我们需要的引脚。本系统采用串行方式,串行接口通过SPI协议和外部主CPU连接,首先要将MD接高电平,将SPIS接地,选定LD3320工作在串行模式,此时使用的管脚有:片选(SCS*)、SPI时钟(SDCK)、SPI输入(SDI)和SPI输出(SDO),中断引脚(INT),复位引脚(RST),时钟引脚(CLK),通过SPI接口,配置LD3320的工作模式,读取识别结果,图8,图9为SPI读写时序。当LD3320识别到有语音输入,INT引脚将产生中断,在中断处理函数中,读取识别结果,改变LD3320状态。
图7LD3320语音模块
图8
图9 SPI方式写时序
在本系统中,OV2640输出JPEG压缩图像格式。MCU与OV2640的通信采用串行与并行结合,OV2640带有SCCB(Serial Camera Control Bus)双线串行接口,MCU通过SCCB接口配置和读取OV2640的信息;MCU通过并行总线的方式来接收OV2640的图像数据。Y(2..9)为8位MSB(MostSignificant Bit,最高有效位模式)并行总线,SDIO、SCLK为SCCB接口,PCLK为像素时钟输出管脚(每个周期从并行总线上输出一个像素),VSYNC为列同步输出管脚(每帧图像发生一次跳变),HERF为行参考输出管脚(每个周期总线从并行总线上输出一行图像数据)。系统的硬件电路连接简图如图10。
图10系统硬件电路连接简图
系统上电后,MCU配置OV2640的工作方式,初始化LD3320,然后检查LD3320的状态,当LD3320的状态是“找到识别结果”,开启OV2640中断,在OV2640准备好图像后,VSYNC会被拉高一段时间,MCU通过PCLK上升沿中断按字节接收图像数据,接收数据完成,关闭OV2640中断。然后向新浪微博发送已经写进程序里的自己想说的话和接收到的图片。接下来将对主要的程序块做介绍。
程序介绍
在《为你的设备添加社交网络功能》中,已经详细介绍了OV2640的初始化配置程序,本篇文章就不再赘述,图像数据缓存程序与本文稍有不同,这里简单介绍图像数据缓存程序。本文对LD3320的写入词条列表,启动语音识别,中断处理程序,发送微博程序做主要介绍。
图像数据缓存程序(摘至stm32f10x_it.c):
void EXTI0_IRQHandler(void)
{
u8 temp;
EXTI_ClearITPendingBit(EXTI_Line0);
switch(jpg_flag)
case 0:
JPEGBuffer[0]=0xff;
jpg_flag=1;
break;
case 1:
if(temp==0xd8)
JPEGBuffer[1]=0xd8;
jpg_flag=2;
JPEGCnt=2;
else if(temp!=0xff)
jpg_flag=0;
break;
case 2:
JPEGBuffer[JPEGCnt++] =temp;
if(temp==0xff)jpg_flag=3;
break;
case 3:
JPEGBuffer[JPEGCnt++]=temp;
if(temp==0xd9)
jpg_flag=4;
else if(temp!=0xff)
jpg_flag=2;
break;
case 4:
break;
}
在中断函数中通过以上程序即可正确读取每一帧图像的数据了。程序思想已经在拍摄照片流程图中体现。JPEGBuffer为一个全局的图像缓存区,在主函数中,检测到缓存区数据准备完毕后,就可以将图像发送给新浪微博了。
LD3320添加词条程序(摘至LD3320_main.c)
uint8 LD_AsrAddFixed(void)
{
uint8 k, flag;
uint8nAsrAddLength;
#define DATE_A
#define DATE_B
uint8
flag = 1;
for (k=0; k
{
if(LD_Check_ASRBusyFlag_b2() == 0)
LD_WriteReg(0xc1, pCode[k] );
LD_WriteReg(0xc3, 0 );
LD_WriteReg(0x08, 0x04);
LD3320_delay(1);
LD_WriteReg(0x08, 0x00);
LD3320_delay(1);
for (nAsrAddLength=0; 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);
LD_WriteReg(0x37, 0x04);
}
return flag;
}
列表的规则是,每个识别条目对应一个特定的编号(1个字节),不同的识别条目的编号可以相同,而且不用连续。本芯片最多支持50个识别条目,每个识别条目是标准普通话的汉语拼音(小写),每2个字(汉语拼音)之间用一个空格间隔。首先把识别条目的编号写入0xc1寄存器,其次,将字符串中的字符按顺序写入寄存器0x05,然后将字符串长度写入寄存器0xB9,向寄存器0xB2写入0xFF,向寄存器0x37写入0x04,通知DSP要添加一项识别句。
LD3320启动语音识别程序(摘至LD3320_main.c)
uint8 LD_AsrRun(void)
{
1
2
3
4
5
6
7
8
LD_WriteReg(0x29, 0x10); //
LD_WriteReg(0xBD, 0x00);
}
第1行,ADC增益设置,或可以理解为麦克风(MIC)音量。可以设置为00H-7FH。建议设置值为40H-55H:值越大代表MIC音量越大,识别启动越敏感,但可能带来更多误识别;值越小代表MIC音量越小,需要近距离说话才能启动识别功能,好处是对远处的干扰语音没有反应。第6行检查LD3320是否为空闲状态,如果为空闲状态,在第7行向0x37寄存器写入0x06,通知DSP开始语音识别。第8行,向寄存器0x1c写入0x0b,表示麦克风输入ADC通道可用。
LD3320中断处理程序(摘至LDChip.c)
voidProcessInt0(void)
{
uint8nAsrResCount=0;
1
2
3
4
5
6
nAsrStatus=LD_ASR_FOUNDOK;
else
7nAsrStatus=LD_ASR_FOUNDZERO;
}
else
{
8
}
LD_WriteReg(0x2b,0);
LD_WriteReg(0x1C,0);
LD_WriteReg(0x29,0);
LD_WriteReg(0x02,0);
LD_WriteReg(0x2B,0);
LD_WriteReg(0xBA,0);
LD_WriteReg(0xBC,0);
LD_WriteReg(0x08,1);
LD_WriteReg(0x08,0);
}
中断处理函数的第1行读取中断请求编号寄存器0x2B的值,第4位:读取值为1表示语音识别有结果产生;MCU可清零。第2位:读取值为1表示芯片内部FIFO中断发生。MP3播放时会产生中断标志请求外部MCU向FIFO_DATA中Reload数据。第3位:读取值为1表示芯片内部已经出现错误。值得注意的是:如果在中断响应时读到这位为1,需要对芯片进行重启Reset,才可以继续工作。第2,3行关闭LD3320的中断。第4行,读取中断请求编号寄存器0x2B的值,当第4位读取值为1表示语音识别有结果产生,其次读取语音识别过程中DSP忙闲状态寄存器0xb2,读取到0x21
发送微博程序(摘至weibo.c)
unsigned char post_weibo_upload(char* weibo, uint8* pic,uint32 picLen)
{
unsigned char ret=0;
unsignedintlen=0;
1
printf("Socket initialization failed.");
return 0;
else
printf("Connect with Weibo server.");
2
if(ret!=1)
printf("Connect Weibo server failed.");
return 0;
else
3while(getSn_SR(SOCK_WEIBO)!=SOCK_ESTABLISHED);
printf("Connected with Weiboserver.");
4
"--%sContent-Disposition:form-data; name="pw"%s"
"--%sContent-Disposition:form-data; name="cmd"upload"
"--%sContent-Disposition:form-data; name="status"%s"
"--%sContent-Disposition:form-data; name="file"; filename="pic.jpg"Content-Type:application/octet-stream",(char*)BOUNDARY,(char*)WEIBO_ID,(char*)BOUNDARY,(char*)WEIBO_PWD,(char*)BOUNDARY,(char*)BOUNDARY,weibo,(char*)BOUNDARY);//"--%s--"
5
6
while(file_len)
if(file_len>PACKET_LEN)
if(getSn_SR(SOCK_WEIBO)!=SOCK_ESTABLISHED)
return 0;
7send(SOCK_WEIBO, (uint8*)(pic+send_len), PACKET_LEN);
send_len+=PACKET_LEN;
file_len-=PACKET_LEN;
else
8send(SOCK_WEIBO, (uint8*)(pic+send_len), file_len);// uploadpicture
send_len+=file_len;
file_len-=file_len;
sprintf(tmp_buf,"--%s--",(char*)BOUNDARY);
send(SOCK_WEIBO,(unsigned char*)tmp_buf,strlen(tmp_buf));
while(1)
9len=getSn_RX_RSR(SOCK_WEIBO);
if(len>0)
memset(tmp_buf,0x00,MAX_BUF_SIZE);
10len=recv(SOCK_WEIBO,(unsigned char*)tmp_buf, len);
11char*p=strstr(tmp_buf,(char*)"")+4;
disconnect(SOCK_WEIBO);
close(SOCK_WEIBO);
return 1;
}
发送微博函数的第1行,初始化一个socket,第2行,对服务器发出连接请求,第3行一直等待连接的建立。与服务器建立连接后,第4,5行负责组建带有微博内容和图片长度的HTTP数据包,第6行负责发送微博内容,第7,8行发送图片数据。第9行是读取W5500接收到的数据长度,第10行从W5500的接收缓存中把接收到的数据读到tmp_buf中。由于接收到的数据包含了HTTP头,第11行是把HTTP头去掉,得到服务器的返回结果。服务器返回结果的类型请参看《为你的设备添加社交网络功能》一文。
好了,代码就这么多,赶快编译烧到单片机里面吧,上电,对着麦克风说出一句已经写到LD3320里的话,当对应的指示灯亮或者闪烁,说明已经识别成功,然后对着摄像头微笑吧,这时摄像头为我们拍张照片,上传微博,然后看串口调试信息,如果收到“255:ok”,那就成功了,登录到微博看看,写进程序里的话以及自己的照片出现在微博上面。如图11。
图11系统发送微博效果图
至此,我们的基于语音识别的微博签到系统已经大功告成,你心动了吗?赶快制作你自己的微博签到系统吧。
评论