TTS 真人發音 SYN6288 模塊
通常合成語音技術被稱作 TTS (Text To Speech),這樣的功能在報站,排隊叫號等等場合有著廣泛的應用。最近我入手了一個SYN6288的TTS模塊,價格50元送喇叭。
具體的說明可以在晶元手冊中找到,對於我們來說,最直接的用法就是播放語音。推薦剛拿到模塊的時候使用USB串口直接對模塊發送下面的數據可以測試是否正常。
從上面也能看出,命令的構成。需要特別注意的是命令參數指定了文本的編碼方式,對於 Windows來說默認通常都是Unicode。另外就是最後用於校驗的值,這是對每一個byte 異或運算獲得的。計算方式是: buffer[0]+ buffer[1]+…+ buffer[n]。
我們還需要了解的是 Arduino 中的漢字使用的是UTF8編碼 (因為 IDE 是 Unicode),例如:用下面的代碼輸出「宇音天下」。
char buffer[]="宇音天下";
void setup() {
Serial1.begin(9600);
Serial.begin(9600);
}
void loop() {
for (int i=0;i<sizeof(buffer);i++) {
Serial.print(buffer[i]&0xFF,HEX);
Serial.print(
);
}
Serial.println(
);delay(15000);
}
結果如下:
E5 AE 87 E9 9F B3 E5 A4 A9 E4 B8 8B 0
其中「宇」UTF8編碼:E5AE87,「音」UTF8編碼:E99FB3…..最後還有一個表示結尾的0【參考1】。
然後這個地方就讓人暈掉了,為什麼資料中給出來的 Unicode 是2Bytes一個漢字而上面給出來的是3個bytes?
終於我在【參考2】找到了答案,原來 Unicode規定了編碼方式,但是沒有規定如何存儲,比如:高位在前還是在後,具體要存儲多長。所以具體落地實現有UTF8 UTF16 等等。對於我們這個情況,Arduino Java 使用的是UTF8,但是模塊需要你以Unicode的編號通知它。接下來的問題就是,我有UTF8,如何轉化為 Unicode?
先說Unicode轉UTF8, 有下面這樣的表格
Unicode符號範圍 | UTF-8編碼方式
(十六進位) | (二進位)
----------------------+---------------------------------------------
00000000-0000 007F | 0xxxxxxx
00000080-0000 07FF | 110xxxxx 10xxxxxx
00000800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
00010000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
還是以漢字嚴為例,演示如何實現 UTF-8 編碼。
嚴的 Unicode 是4E25(100111000100101),根據上表,可以發現4E25處在第三行的範圍內(00000800 - 0000 FFFF),因此嚴的 UTF-8 編碼需要三個位元組,即格式是1110xxxx 10xxxxxx10xxxxxx。然後,從嚴的最後一個二進位位開始,依次從後向前填入格式中的x,多出的位補0。這樣就得到了,嚴的UTF-8 編碼是1110010010111000 10100101,轉換成十六進位就是E4B8A5。
上面的資料依然來自【參考2】。
然後我們要嘗試將E5AE87 轉換為 Unicode:
首先,E5AE87 寫成二進位就是下面這樣
根據上面的表格,切分一下(我們已經知道一個漢字是3 Bytes,所以直接使用第三行)
就是說上面紅色框中的對我們來說是多餘的,去掉之後我們只剩下下面的數值
這就是 5B87, 網頁上查到的也是這樣:
接下來的問題就是:為什麼上面給出來的0x5B87 而資料給出來的是0x8BED,對於這個問題我還真沒有找到答案,0x8BED是「語」的 Unicode。只能猜測一下,要麼是寫手冊的不小心犯錯,畢竟發出來聲音沒人聽的出來這兩個字的差別;要麼就是故意設計成這樣。
因此,簡單起見,我們可以直接計算要輸出的字元,將Arduino 定義的字元串每三個bytes一組,掐頭重新拼接成2個bytes。『
//要輸出的字元串
char buffer[]="宇音天下";
//實際漢字長度
#define BSIZE (sizeof(buffer)/3)
//存放轉化後的漢字 Unicode值
char character[BSIZE * 2];
void setup() {
Serial1.begin(9600);
Serial.begin(9600);
delay(3000);
}
void loop() {
//首先輸出一次Arduino
原始字元串UTF8 的值for (int i
=0;i<BSIZE*3;i++) {Serial.print(buffer[i]&0xFF,HEX);
Serial.print(
);}
Serial.println( );
//將 UTF8 轉化為
Unicodefor (int i
=0;i<BSIZE;i=i+1) {
character[i*2]=((buffer[i*3]&0xF)<<4)+((buffer[i*3+1]>>2)&0xF);
character[i*2+1]=((buffer[i*3+1]&0x3)<<6)+(buffer[i*3+2]&0x3F);
Serial.print(character[i*2]&0xFF,HEX);
Serial.print(
);Serial.print(character[i*2+1]&0xFF,HEX);
Serial.print(
);}
Serial.println( );
delay(15000);
}
實驗結果就是:
接下來在上面代碼的基礎上繼續修改,集成直接串口發送
//要輸出的字元串
char buffer[]="宇音天下";
//實際漢字長度
#define BSIZE (sizeof(buffer)/3)
//存放轉化後的漢字 Unicode值
char character[BSIZE * 2];
//根據字元串計算計算出來的送到串口的值
char output[BSIZE*2+6];
void setup() {
Serial1.begin(9600);
Serial.begin(9600);
delay(5000);
}
void loop() {
//首先輸出一次Arduino
原始字元串UTF8 的值for (int i
=0;i<BSIZE*3;i++) {Serial.print(buffer[i]&0xFF,HEX);
Serial.print(
);}
Serial.println( );
//將 UTF8 轉化為
Unicodefor (int i =0;i<BSIZE;i=i+1)
{character[i*2]=((buffer[i*3]&0xF)<<4)+((buffer[i*3+1]>>2)&0xF);
character[i*2+1]=((buffer[i*3+1]&0x3)<<6)+(buffer[i*3+2]&0x3F);
Serial.print(character[i*2]&0xFF,HEX);
Serial.print(
);Serial.print(character[i*2+1]&0xFF,HEX);
Serial.print(
);}
Serial.println("");
output[0]=0xFD;
output[1]=(BSIZE*2+3)>>8;
output[2]=((BSIZE*2+3)&0xFF);
output[3]=0x01;
output[4]=0x03;
//把字元串定義搬過去
for (int
i=0;i<BSIZE*2;i++) {output[i+5]=character[i];
}
//計算一個校驗和
output[BSIZE*2+5]=output[0];
for (int
i=1;i<BSIZE*2+5;i++) {output[BSIZE*2+5]=output[BSIZE*2+5] ^ output[i];
}
for (int i
=0;i<BSIZE*2+6;i++) {Serial.print(output[i]&0xFF,HEX);
Serial.print(
);Serial1.write(output[i]);
}
Serial.println( );
delay(15000);
}
運行結果
工作的視頻
https://www.zhihu.com/video/934887313406849024從上面可以看到,Arduino中是有機會將指定定義的中文字元串轉換後發送出去的。但是更多時候,我們直接定義每一個字元對應的Unicode即可,雖然不是很直觀,但是在編碼上會省很多力氣。
特別提一下:模塊上面有耳機插孔,我插入了一個沒有聲音,並且晶元迅速發熱,懷疑是兼容性上的問題。如果有朋友需要用耳機或者功放,需要特別注意一下(我懷疑是耳機插頭什麼地方導致短路)。
參考:
1. http://www.qqxiuzi.cn/bianma/Unicode-UTF.phpUnicode和UTF編碼轉換
2. http://www.ruanyifeng.com/blog/2 ... code_and_utf-8.html
推薦閱讀:
※生物黑客學院 第一課 第二部分——Arduino&焊接
※Arduino有什麼炫酷的作品?
※如何給第三方模塊自定義Mixly圖形塊
※做一個智能花草照料花盆(五) 麵包板
※【圖形化學習 Arduino】(三)串口通信
TAG:Arduino |