基于语音识别的微博签到系统
作者:Catherine
語音識別與簽到系統
近年來,語音識別在語音導航,室內設備控制。人際對話等方面得到了廣泛的應用。
我們在今年第1期雜志《為設備加入社交網絡功能》中,實現了W5500EVB自己發微博功能。試想假設我們把語音識別與微博簽到結合起來,我們上班時,報上姓名。經識別后,攝像頭為我們拍張照片。傳到新浪微博,這樣既能得到我們簽到的時間,又能保證是本人簽到,可靠高效,同一時候朋友通過微博能了解到我們上班時的狀態,這樣是不是非常有意思呢?
今天要介紹的就是上面提到的,基于語音識別的微博簽到系統。我們用攝像頭ov2640拍照,LD3320做語音識別。然后W5500EVB把我們想說的話,以及照片發送到新浪微博。
基于語音識別的微博簽到系統設計
(1)???開發板基本情況
a)????????單片機:STM32F103RCT6,256K字節Flash。48K字節SRAM,2K字節EEPROM
b)???????以太網控制器:W5500,SPI接口與單片機相連
c)????????電源:USB供電
(2)???開發工具: IARfor ARM v5.41,這是我們project所使用的版本號。假設使用不同版本號的IAR。請對STM的庫稍作調整。
(3)???語音識別:LD3320語音識別模塊。
(4)???圖像生成:OV2640攝像頭。
(5)???其它
a)????????新浪微博username和password;如若沒有,就趕快給你的設備申請一個吧。
b)???????一根Mini接口的USB線,如圖1所看到的。
c)????????一根網線。
d)???????STM32芯片的串口程序燒錄工具,STM官方提供的程序名為:Flash Loader Demo。
圖1是系統實物圖。
圖1系統實物圖
首先,我們了解一下整個程序流程,流程圖由一個主流程圖(見圖2)和四個子流程圖(圖3,圖4,圖5。圖6)組成。在STM32及ov2640初始化完畢之后,將進行網絡參數配置,依據自己網絡的情況配置W5500的IP地址等網絡參數,確保W5500能連接外網。
然后配置LD3320語音模塊,語音模塊處于初始狀態,將進行寫入識別列表,啟動語音識別過程,當我們對著麥克風說話的時候,LD3320檢測到有語音輸入,LD3320將進入中斷,在中斷中將把我們說的內容與寄存器里的詞條比較,假設找到1-4個候選答案。返回“找到識別結果”狀態,假設沒有找到候選答案。返回“未找到識別結果”狀態。
在下一次循環中,LD3320假設是“找到識別結果”狀態。將拍攝照片及發送微博。假設是“未找到識別結果”狀態。將進入初始狀態。假設是“正在識別”或者“識別錯誤”將又一次檢查LD3320的狀態。各個子流程圖描寫敘述的比較詳盡。這里不再一一贅述。
對于拍攝照片子流程圖。我們須要了解jpg圖片的數據格式。圖片的前兩個字節是0xff,0xd8,最后兩個字節是0xff。0xd9,在中斷程序接收圖片數據的過程中,首先推斷數據是不是前兩個字節。假設是。保存數據,后面的數據是先保存。然后推斷是不是數據結尾。直到接收成功。
圖2系統主流程圖
?
圖3寫入識別列表函數流程圖 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖4啟動語音識別模式流程圖
?
圖5拍攝照片流程圖
圖6發送微博流程圖
以上四個子流程圖,已清晰地給大家展示語音識別微博簽到系統的整個工作流程。那么接下來就為大家揭開具體的制作過程。
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? SPI方式讀時序
圖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);???? //清除EXTI0線路掛起位
?if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_1)==0)return;//HREF管腳為低
?temp=(u8)((GPIOC->IDR)>>8 & 0x00ff);??? //讀取一個字節圖像數據
switch(jpg_flag)
?{
case 0:
????? if(temp==0xff)????????????????????? //圖像數據以0xff 0xd8開頭
????? {??
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;? //圖像數據以0xff0xd9結尾
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?4??? /*數組二維數值*/
#define DATE_B? 20???? /*數組一維數值*/
uint8?sRecog[DATE_A][DATE_B] = {
????????????????????????????????????????????????????????????????????? "wenjuan",\
????????????????????????????????????????????????????????????????????? "guocui",\
????????????????????????????????????????????????????????????????????? ?"jierui",\
????????????????????????????????????????????????????????????????????? ? "chenge"\
????????????????????????????????????????? ???????????????????? };??? /*加入關鍵詞*/
???????????????????????????????????? uint8? pCode[DATE_A] = {
????????????????????????????????????????????????????????????????????? CODE_wenjuan,\
????????????????????????????????????????????????????????????????????? CODE_guocui,\
????????????????????????????????????????????????????????????????????? CODE_jierui,\
????????????????????????????????????????????????????????????????????? CODE_chenge\
??????????????????????????????????????????????????????? };??? /*加入識別碼*/
flag = 1;
for (k=0; k<DATE_A; k++)
{???????????????????????????
if(LD_Check_ASRBusyFlag_b2() == 0)
?????????????????????????????? {
?????????????????????????????????? flag= 0;
?????????????????????????????????? break;
???????????????????????????????? }
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<DATE_B;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???? LD_WriteReg(0x35,MIC_VOL);? ?//ADC增益設置
2???? LD_WriteReg(0x1C,0x09);????? //ADC開關控制。寫09H為保留命令字。
3???? LD_WriteReg(0xBD,0x20);????? //初始化控制寄存器,寫入20H,保留命令字。
4?? LD_WriteReg(0x08, 0x01);???? //清除FIFO內容。第0位:寫入1→清除FIFO_DATA。
?????? LD3320_delay( 5);?
5???? LD_WriteReg(0x08,0x00);??????
?????? LD3320_delay( 5);
6???? if(LD_Check_ASRBusyFlag_b2()== 0)? //檢查b2寄存器是否為空暇
?????? {
????????????? return 0;
?????? }
?????? LD_WriteReg(0xB2,0xff);??
7?? LD_WriteReg(0x37, 0x06); //語音識別控制命令下發寄存器,寫06H:通知DSP開始識別語音。
?????? LD_WriteReg(0x37,0x06);
?????? LD3320_delay( 5);
8? LD_WriteReg(0x1C, 0x0b); // ADC開關控制寫0BH 麥克風輸入ADC通道可用
LD_WriteReg(0x29, 0x10); // 中斷同意(可讀寫)第4位:同步中斷同意,1表示同意;0表示不同意。
LD_WriteReg(0xBD, 0x00);?????????? // 初始化控制寄存器寫入00H。然后啟動;為ASR模塊。
?????? return 1;
}
第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? ucRegVal = LD_ReadReg(0x2B);? // 讀取中斷請求編號寄存器
2?? LD_WriteReg(0x29,0);? // 第2位:FIFO 中斷同意,1表示同意;0表示不同意。
第4位:同步中斷同意,1表示同意;0表示不同意。
3?? LD_WriteReg(0x02,0);? // FIFO中斷同意第0位:同意FIFO_DATA中斷;第2位:同意FIFO_EXT中斷。
4?? If((ucRegVal& 0x10)&&LD_ReadReg(0xb2)==0x21 &&LD_ReadReg(0xbf)==0x35)? ??????// 中斷請求編號寄存器0x2B第4位:讀取值為1表示語音識別有結果產生;MCU可清零。ASR過程中DSP忙閑狀態寄存器0xb2,讀取到0x21 表示閑,查詢到為閑狀態能夠進行下一步ASR動作。ASR狀態報告寄存器0xbf 讀到數值為0x35,能夠確定是一次語音識別流程正常結束.
???????????? {???
5????????????????? nAsrResCount= LD_ReadReg(0xba); //中斷輔助信息寄存器,當中的數值表示語音識別有幾個識別候選
6????????????????? if(nAsrResCount>0&&nAsrResCount<=4)
?????????????? {
nAsrStatus=LD_ASR_FOUNDOK;?????????????????????????
?????????????? }
else
?????????????? {
7nAsrStatus=LD_ASR_FOUNDZERO;
?????????????? }?????
}
else
{
8? nAsrStatus=LD_ASR_FOUNDZERO;??? //運行沒有識別
}
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*/
}
中斷處理函數的第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 表示閑,然后讀取語音識別狀態報告寄存器0xbf的值,讀到數值為0x35,能夠確定是一次語音識別流程正常結束,當這三個寄存器的數值不滿足以上要求的時候。返回“LD_ASR_FOUNDZERO”,表示未找到識別結果。當滿足以上要求時,第5行,讀取中斷輔助信息寄存器,當中的數值表示語音識別有幾個識別候選。當數值為1 – 4: 表示有N個識別候選,數值為0或者大于4表示沒有識別候選,當有識別候選的時候,返回“LD_ASR_FOUNDOK”。表示找到語音識別結果。
發送微博程序(摘至weibo.c)
unsigned char post_weibo_upload(char* weibo, uint8* pic,uint32 picLen)
{
unsigned char ret=0;
unsignedintlen=0;
1 ?if(socket(SOCK_WEIBO,Sn_MR_TCP,any_local_port++,0)!=1)? //to initialize a TCP socket
? {
printf("Socket initialization failed.\r\n");
return 0;
? }
else
? {
printf("Connect with Weibo server.\r\n");
2???ret=connect(SOCK_WEIBO,weibo_server_ip,80);???? ??//connect to the weibo server, default TCPport is 80
if(ret!=1)
??? {
printf("Connect Weibo server failed.\r\n");
return 0;
??? }
else
??? {
3while(getSn_SR(SOCK_WEIBO)!=SOCK_ESTABLISHED);? //wait for the TCP connection established!
printf("Connected with Weiboserver.\r\n");
4?? sprintf(post_data,"\r\n--%s\r\nContent-Disposition:form-data; name=\"id\"\r\n\r\n%s"\
"\r\n--%s\r\nContent-Disposition:form-data; name=\"pw\"\r\n\r\n%s"\
"\r\n--%s\r\nContent-Disposition:form-data; name=\"cmd\"\r\n\r\nupload"\
"\r\n--%s\r\nContent-Disposition:form-data; name=\"status\"\r\n\r\n%s"\
"\r\n--%s\r\nContent-Disposition:form-data; name=\"file\"; filename=\"pic.jpg\"\r\nContent-Type:application/octet-stream\r\n\r\n",(char*)BOUNDARY,(char*)WEIBO_ID,(char*)BOUNDARY,(char*)WEIBO_PWD,(char*)BOUNDARY,(char*)BOUNDARY,weibo,(char*)BOUNDARY);//"\r\n--%s--\r\n"
5?? sprintf(tmp_buf,"POST %sHTTP/1.1\r\nHost: %s\r\nUser-Agent: w5500\r\nContent-Type: multipart/form-data;boundary=%s\r\nConnection:close\r\nContent-Length:%d\r\n\r\n%s",(char*)HTTP_PATH,(char*)WEIBO_SERVER,(char*)BOUNDARY,strlen(post_data)+picLen+strlen((char*)BOUNDARY)+8,post_data);
6?? len=send(SOCK_WEIBO,(unsignedchar*)tmp_buf,strlen(tmp_buf)); //upload your weibo content
????? uint16 file_len=picLen;
???? uint16 send_len=0;
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);? // upload picture
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,"\r\n--%s--\r\n",(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);??//receive thereturn result from weibo server
11char*p=strstr(tmp_buf,(char*)"\r\n\r\n")+4;? ?//gethttp payload without http headerprintf("%s\r\n",p);
disconnect(SOCK_WEIBO);??//disconnect with weibo server
close(SOCK_WEIBO);???????//close the socket
return 1;????????????????//sucess! return 1
??????? }
? ????}
??? }
? }
}
發送微博函數的第1行,初始化一個socket。第2行,對server發出連接請求,第3行一直等待連接的建立。
與server建立連接后。第4。5行負責組建帶有微博內容和圖片長度的HTTP數據包,第6行負責發送微博內容,第7,8行發送圖片數據。第9行是讀取W5500接收到的數據長度,第10行從W5500的接收緩存中把接收到的數據讀到tmp_buf中。
因為接收到的數據包括了HTTP頭,第11行是把HTTP頭去掉,得到server的返回結果。server返回結果的類型請參看《為你的設備加入社交網絡功能》一文。
好了。代碼就這么多,趕快編譯燒到單片機里面吧,上電,對著麥克風說出一句已經寫到LD3320里的話,當相應的指示燈亮或者閃爍。說明已經識別成功,然后對著攝像頭微笑吧,這時攝像頭為我們拍張照片,上傳微博,然后看串口調試信息。假設收到“255:ok”,那就成功了,登錄到微博看看,寫進程序里的話以及自己的照片出如今微博上面。如圖11。
圖11系統發送微博效果圖
至此。我們的基于語音識別的微博簽到系統已經大功告成,你心動了嗎?趕快制作你自己的微博簽到系統吧。
歡迎與我們很多其它交流:wiznetbj@wiznet.co.kr
WIZnet官方站點: http://www.iwiznet.cn
WIZnet官方微博:http://weibo.com/wiznet2012
?
總結
以上是生活随笔為你收集整理的基于语音识别的微博签到系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js实现svg图形转存为图片下载[转]
- 下一篇: 解决问题Can’t connect to