音声合成LSI 「AquesTalk pico LSI」 (
ATP3010F4)は、UARTの他にI2CやSPIのインターフェースを持っています。
一方、Arduino側のUARTは、PCとの通信で既に使われているので、ArduinoとAquesTalk pico LSI間の通信には、I2CやSPIを利用するのが便利です。
今回は、I2Cを使ってAquesTalk pico LSIを動かす方法を示します。
(SPIを使う場合は
こちら)
配線
通信モードをI2CにするためSMOD0(4pin)をGNDに接続、
I2C通信のSCL(28pin)をArduinoのA5に、SDA(27pin)をA4に接続します。
また、このSCLとSDAは、4.7KΩ程度でプルアップ(VCCに接続)します。
サンプルスケッチこのスケッチは、予めプログラムに用意した複数のメッセージを順番に読み上げるものです。
注意点は、ArduinoのWireライブラリが1度に32byteまでしか送信できない制限があるようです(arduino-022)。
また、I2Cでは発声の完了が通知されないので、ポーリングで確認する必要があります。
そして、ATP3010F4の制限によりポーリングの間隔は10ms以上あけて行います。
実際の応用では、動的にメッセージの単語を入れ替えたり、さまざまな数値を読ませるのも良いと思います。
特に数値に関しては、単位(助数詞)を指定することで「一本、二本、三本」を「いっぽん、にほん、さんぼん」などと、読みやアクセントを正しく読む機能を持っていますので、是非ご利用ください。このあたりの詳しくは、
データシートの音声記号列仕様に書いてあります。
追記 2011/12/27 下記ソースはArduino 0023のもので、Arduino 1.0の場合は次のように変更してください。Wire.send() -> Wire.write()
Wire.recieve() -> Wire.read()
/////////////////////////////////
// aqtkpico_i2c - I2C通信で AquesTalk Pico LSIを操作するArdionoスケッチ
//
// by N.Yamazaki AQUEST Corp. <http://www.a-quest.com>
#include <Wire.h>
#define I2C_ADDR_PICO 0x2E // PicoのデフォルトのI2Cアドレス
// ローマ字音声記号列
// コマンドの最後のCR('¥r')を忘れずに
const char *TblKoe[] = {
"konnnichiwa¥r",
"yukkurisiteittene¥r",
"akuesuto-ku/pi'ko ba-jyonn <ALPHA =01a>.¥r",
"dennwaba'nngo-wa <NUM VAL=01-2345-6789>desu.¥r",
"<NUMK VAL=16 COUNTER=di>;<NUMK VAL=5 COUNTER=funn>/<NUMK VAL=35 COUNTER=byo->desu.¥r",
"#J¥r", // チャイム音J
"#K¥r", // チャイム音K
};
void setup()
{
Wire.begin(); // Arduino側をI2C Masterとして初期化
}
void loop()
{
for(int iMsg=0; iMsg<sizeof(TblKoe)/sizeof(char*); iMsg++){
Pico_WaitReady(); // Ready待ち
Pico_Synthe(TblKoe[iMsg]); // 発声コマンド送出
}
}
// Picoにコマンド送信
// 音声合成開始 引数に音声記号列を指定
void Pico_Synthe(const char *koe)
{
// Wireの制約で、一度に送れるのは32byteまで
// AquesTalk picoへは一度に128byteまで送れるので、
// Wire.beginTransmission()〜Wire.endTransmission()を複数回に分けて呼び出す
const char *p = koe;
for(;*p!=0;){
Wire.beginTransmission(I2C_ADDR_PICO);
// Wireの制約で、一度に送れるのは32byteまで
for(int i=0;i<32;i++){
Wire.send(*p++);
if(*p==0) break;
}
Wire.endTransmission(); // 実際はこのタイミングで送信される
}
}
// PicoがRedyになるのを待つ
// コマンドの受信可能な状態(音声合成の終了)を待つ
int Pico_WaitReady()
{
for(;;){
Wire.requestFrom(I2C_ADDR_PICO, 1);
if(Wire.available()>0){
byte c = Wire.receive();
if(c=='*' || c==0xFF) delay(10); // Busy応答は10msec以上待つ必要がある
else if(c=='>') break; // Ready応答
}
else { // NOACK または応答がなかった時
// Picoが動いていない可能性が高い
return 1; //ERR
}
}
return 0; // OK
}