基于語(yǔ)音識(shí)別的微博簽到系統(tǒng)
LD3320介紹
1 通過(guò)快速而穩(wěn)定的優(yōu)化算法,完成非特定人語(yǔ)音識(shí)別,識(shí)別準(zhǔn)確率95%。
2 不需要外接任何輔助的Flash芯片,RAM芯片和AD芯片,就可以完成語(yǔ)音識(shí)別功能。
3 每次識(shí)別最多可以設(shè)置50項(xiàng)候選識(shí)別句,每個(gè)識(shí)別句可以是單字,詞組或短句,長(zhǎng)度為不超過(guò)10個(gè)漢字或者79個(gè)字節(jié)的拼音串。識(shí)別句內(nèi)容還可以動(dòng)態(tài)編輯修改。
4 芯片內(nèi)部已經(jīng)準(zhǔn)備了16位A/D轉(zhuǎn)換器、16位D/A轉(zhuǎn)換器和功放電路,麥克風(fēng)、立體聲耳機(jī)和單聲道喇叭可以很方便地和芯片管腳連接。
5 支持并行和串行接口,串行方式可以簡(jiǎn)化與其他模塊的連接。
在本系統(tǒng)中采用的LD3320模塊如圖7,LD3320芯片外部已經(jīng)連接了麥克風(fēng),耳機(jī)接口,基本電路,只引出了我們需要的引腳。本系統(tǒng)采用串行方式,串行接口通過(guò)SPI協(xié)議和外部主CPU連接,首先要將MD接高電平,將SPIS接地,選定LD3320工作在串行模式,此時(shí)使用的管腳有:片選(SCS*)、SPI時(shí)鐘(SDCK)、SPI輸入(SDI)和SPI輸出(SDO),中斷引腳(INT),復(fù)位引腳(RST),時(shí)鐘引腳(CLK),通過(guò)SPI接口,配置LD3320的工作模式,讀取識(shí)別結(jié)果,圖8,圖9為SPI讀寫(xiě)時(shí)序。當(dāng)LD3320識(shí)別到有語(yǔ)音輸入,INT引腳將產(chǎn)生中斷,在中斷處理函數(shù)中,讀取識(shí)別結(jié)果,改變LD3320狀態(tài)。
圖7LD3320語(yǔ)音模塊
圖8
圖9 SPI方式寫(xiě)時(shí)序
在本系統(tǒng)中,OV2640輸出JPEG壓縮圖像格式。MCU與OV2640的通信采用串行與并行結(jié)合,OV2640帶有SCCB(Serial Camera Control Bus)雙線串行接口,MCU通過(guò)SCCB接口配置和讀取OV2640的信息;MCU通過(guò)并行總線的方式來(lái)接收OV2640的圖像數(shù)據(jù)。Y(2..9)為8位MSB(MostSignificant Bit,最高有效位模式)并行總線,SDIO、SCLK為SCCB接口,PCLK為像素時(shí)鐘輸出管腳(每個(gè)周期從并行總線上輸出一個(gè)像素),VSYNC為列同步輸出管腳(每幀圖像發(fā)生一次跳變),HERF為行參考輸出管腳(每個(gè)周期總線從并行總線上輸出一行圖像數(shù)據(jù))。系統(tǒng)的硬件電路連接簡(jiǎn)圖如圖10。
圖10系統(tǒng)硬件電路連接簡(jiǎn)圖
系統(tǒng)上電后,MCU配置OV2640的工作方式,初始化LD3320,然后檢查L(zhǎng)D3320的狀態(tài),當(dāng)LD3320的狀態(tài)是“找到識(shí)別結(jié)果”,開(kāi)啟OV2640中斷,在OV2640準(zhǔn)備好圖像后,VSYNC會(huì)被拉高一段時(shí)間,MCU通過(guò)PCLK上升沿中斷按字節(jié)接收?qǐng)D像數(shù)據(jù),接收數(shù)據(jù)完成,關(guān)閉OV2640中斷。然后向新浪微博發(fā)送已經(jīng)寫(xiě)進(jìn)程序里的自己想說(shuō)的話和接收到的圖片。接下來(lái)將對(duì)主要的程序塊做介紹。
程序介紹
在《為你的設(shè)備添加社交網(wǎng)絡(luò)功能》中,已經(jīng)詳細(xì)介紹了OV2640的初始化配置程序,本篇文章就不再贅述,圖像數(shù)據(jù)緩存程序與本文稍有不同,這里簡(jiǎn)單介紹圖像數(shù)據(jù)緩存程序。本文對(duì)LD3320的寫(xiě)入詞條列表,啟動(dòng)語(yǔ)音識(shí)別,中斷處理程序,發(fā)送微博程序做主要介紹。
圖像數(shù)據(jù)緩存程序(摘至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;
}
在中斷函數(shù)中通過(guò)以上程序即可正確讀取每一幀圖像的數(shù)據(jù)了。程序思想已經(jīng)在拍攝照片流程圖中體現(xiàn)。JPEGBuffer為一個(gè)全局的圖像緩存區(qū),在主函數(shù)中,檢測(cè)到緩存區(qū)數(shù)據(jù)準(zhǔn)備完畢后,就可以將圖像發(fā)送給新浪微博了。
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;
}
列表的規(guī)則是,每個(gè)識(shí)別條目對(duì)應(yīng)一個(gè)特定的編號(hào)(1個(gè)字節(jié)),不同的識(shí)別條目的編號(hào)可以相同,而且不用連續(xù)。本芯片最多支持50個(gè)識(shí)別條目,每個(gè)識(shí)別條目是標(biāo)準(zhǔn)普通話的漢語(yǔ)拼音(小寫(xiě)),每2個(gè)字(漢語(yǔ)拼音)之間用一個(gè)空格間隔。首先把識(shí)別條目的編號(hào)寫(xiě)入0xc1寄存器,其次,將字符串中的字符按順序?qū)懭爰拇嫫?x05,然后將字符串長(zhǎng)度寫(xiě)入寄存器0xB9,向寄存器0xB2寫(xiě)入0xFF,向寄存器0x37寫(xiě)入0x04,通知DSP要添加一項(xiàng)識(shí)別句。
LD3320啟動(dòng)語(yǔ)音識(shí)別程序(摘至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增益設(shè)置,或可以理解為麥克風(fēng)(MIC)音量??梢栽O(shè)置為00H-7FH。建議設(shè)置值為40H-55H:值越大代表MIC音量越大,識(shí)別啟動(dòng)越敏感,但可能帶來(lái)更多誤識(shí)別;值越小代表MIC音量越小,需要近距離說(shuō)話才能啟動(dòng)識(shí)別功能,好處是對(duì)遠(yuǎn)處的干擾語(yǔ)音沒(méi)有反應(yīng)。第6行檢查L(zhǎng)D3320是否為空閑狀態(tài),如果為空閑狀態(tài),在第7行向0x37寄存器寫(xiě)入0x06,通知DSP開(kāi)始語(yǔ)音識(shí)別。第8行,向寄存器0x1c寫(xiě)入0x0b,表示麥克風(fēng)輸入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);
}
中斷處理函數(shù)的第1行讀取中斷請(qǐng)求編號(hào)寄存器0x2B的值,第4位:讀取值為1表示語(yǔ)音識(shí)別有結(jié)果產(chǎn)生;MCU可清零。第2位:讀取值為1表示芯片內(nèi)部FIFO中斷發(fā)生。MP3播放時(shí)會(huì)產(chǎn)生中斷標(biāo)志請(qǐng)求外部MCU向FIFO_DATA中Reload數(shù)據(jù)。第3位:讀取值為1表示芯片內(nèi)部已經(jīng)出現(xiàn)錯(cuò)誤。值得注意的是:如果在中斷響應(yīng)時(shí)讀到這位為1,需要對(duì)芯片進(jìn)行重啟Reset,才可以繼續(xù)工作。第2,3行關(guān)閉LD3320的中斷。第4行,讀取中斷請(qǐng)求編號(hào)寄存器0x2B的值,當(dāng)?shù)?位讀取值為1表示語(yǔ)音識(shí)別有結(jié)果產(chǎn)生,其次讀取語(yǔ)音識(shí)別過(guò)程中DSP忙閑狀態(tài)寄存器0xb2,讀取到0x21
發(fā)送微博程序(摘至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;
}
發(fā)送微博函數(shù)的第1行,初始化一個(gè)socket,第2行,對(duì)服務(wù)器發(fā)出連接請(qǐng)求,第3行一直等待連接的建立。與服務(wù)器建立連接后,第4,5行負(fù)責(zé)組建帶有微博內(nèi)容和圖片長(zhǎng)度的HTTP數(shù)據(jù)包,第6行負(fù)責(zé)發(fā)送微博內(nèi)容,第7,8行發(fā)送圖片數(shù)據(jù)。第9行是讀取W5500接收到的數(shù)據(jù)長(zhǎng)度,第10行從W5500的接收緩存中把接收到的數(shù)據(jù)讀到tmp_buf中。由于接收到的數(shù)據(jù)包含了HTTP頭,第11行是把HTTP頭去掉,得到服務(wù)器的返回結(jié)果。服務(wù)器返回結(jié)果的類(lèi)型請(qǐng)參看《為你的設(shè)備添加社交網(wǎng)絡(luò)功能》一文。
好了,代碼就這么多,趕快編譯燒到單片機(jī)里面吧,上電,對(duì)著麥克風(fēng)說(shuō)出一句已經(jīng)寫(xiě)到LD3320里的話,當(dāng)對(duì)應(yīng)的指示燈亮或者閃爍,說(shuō)明已經(jīng)識(shí)別成功,然后對(duì)著攝像頭微笑吧,這時(shí)攝像頭為我們拍張照片,上傳微博,然后看串口調(diào)試信息,如果收到“255:ok”,那就成功了,登錄到微博看看,寫(xiě)進(jìn)程序里的話以及自己的照片出現(xiàn)在微博上面。如圖11。
圖11系統(tǒng)發(fā)送微博效果圖
至此,我們的基于語(yǔ)音識(shí)別的微博簽到系統(tǒng)已經(jīng)大功告成,你心動(dòng)了嗎?趕快制作你自己的微博簽到系統(tǒng)吧。
評(píng)論