標籤:

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 轉化為

Unicode

for (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 轉化為

Unicode

for (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. qqxiuzi.cn/bianma/UnicoUnicode和UTF編碼轉換

2. http://www.ruanyifeng.com/blog/2 ... code_and_utf-8.html


推薦閱讀:

生物黑客學院 第一課 第二部分——Arduino&amp;焊接
Arduino有什麼炫酷的作品?
如何給第三方模塊自定義Mixly圖形塊
做一個智能花草照料花盆(五) 麵包板
【圖形化學習 Arduino】(三)串口通信

TAG:Arduino |