プッシュスイッチを押すとATP3011が決められた言葉をしゃべる(I2C通信)

[Arduinoで遊ぶ]

作成 : 2013/01/27

"サーバの実験室"の検索


プッシュスイッチを押すとATP3011が決められた言葉をしゃべる(I2C通信)

Arduino UNOとATP3011とでI2Cを使って通信をおこない、プッシュスイッチが押されたら決められた言葉をしゃべらせるようにします。

基本的な接続はATP3011 Datasheetの通りです。 動作モードを「コマンド入力モード(基本モード)」にするため、PMOD1(#14)とPMOD0(#15)を5Vに接続します。 通信モードを「I2C通信」にするため、SMOD1(#5)を5V、SMOD0(#4)をGNDに接続します。

ArduinoとATP3011 I2C通信 接続

しゃべらせたい言葉を変更するたびにスケッチをアップロードしなければならないので、実用性はあまりないです・・・

#include <Wire.h>

// ATP3011F4のI2Cアドレス(デフォルト値のまま)
#define ADDR 0x2E
// トリガにするピン
#define inPin 7

// ATP3011F4に送れるのは127byte+'\r'
#define MAX_BYTE 127
// WIREで1回に送れるのは32byte
#define MAX_WIRE_BYTE 32



// 最初に1回だけ実行
void setup() {
  // シリアル通信の転送レートを設定
  Serial.begin(9600);

  // I2Cを初期化
  Wire.begin();

  // デジタルピン#7を入力に設定
  pinMode(inPin, INPUT);
}



// 繰り返し実行
void loop() {

  // ATP3011に送るデータを格納する変数
  char sendStr[MAX_BYTE] = "ohayo- konnichiwa konnbannwa i-otenkide_sune";
  // ATP3011からのレスポンスを格納する変数
  char respStr[8];

  // デジタルピン#7が'HIGH'だったら実行
  if (digitalRead(inPin) == HIGH) {

    // atp3011_speak関数を呼んでデータを送信し、レスポンスをrespStrに格納
    atp3011_speak(sendStr, respStr);
  }
}


/*
 42 : '*'
 62 : '>'
 69 : 'E'
*/



// ATP3011にデータsendStrを送信して発声させ、レスポンスをrespStrに格納する
// 関数の戻り値は、レスポンスが'E'で始まるエラー系ならfalse、それ以外はtrueを返す
boolean atp3011_speak(char* sendStr, char* respStr) {

  // ATP3011にデータを送信する
  // ATP3011には127byteまで送信できるが、Wireでは32byteしか送信できないため、
  // 長いデータは32byteに分割して送る
  for (int w_loop = 0; w_loop < 4;w_loop++) {
    Wire.beginTransmission(ADDR);
    for (int s_idx = 0;s_idx < MAX_WIRE_BYTE;s_idx++) {
      // データの終わり'\0'がきたらループを抜ける
      if(sendStr[w_loop * MAX_WIRE_BYTE + s_idx] == '\0') {
        break;
      // データの終わり'\0'以外なら送信する(Wire.endTransmissionでまとめて送信される)
      } else {
        Wire.write(sendStr[w_loop * MAX_WIRE_BYTE + s_idx]);
      }
    }
    Wire.endTransmission();
  }
  // 最後に'\r'を送信して、発声を開始させる
  Wire.beginTransmission(ADDR);
  Wire.write('\r');
  Wire.endTransmission();

  Serial.print("Write message:"); Serial.println(sendStr);

  // ATP3011からのレスポンスを受け取る
  // BUSY('*')の間はループする
  do {
    // ATP3011へのポーリングは10ms間隔をあけること
    delay(10);

    // ATP3011から8byte読み取る
    // ATP3011からの最大レスポンス長は"Exxx>"で5byteになるはず
    Wire.requestFrom(ADDR,8);

   int r_idx=0;
    // ATP3011から読み取るデータがある間、ぐるぐる回る
    while (Wire.available()) {
      // ATP3011から1byte読み取る
      char c = Wire.read();
      // 読み取ったデータがBUSY'*'または'>'だったら、データをrespStrに格納してループを抜ける
      if (c == '*' ||  c == '>') {
        respStr[r_idx] = c;
        break;
      // 読み取ったデータがそれ以外だったら、データをrespStrに格納する
      } else {
        respStr[r_idx] = c;
        r_idx++;
      }
    }
    // respStrの最後に'\0'を付加して文字列の終わりを示す
    respStr[r_idx+1] = '\0';
  // レスポンスがBUSY"*"の間、ぐるぐる回る
  } while (!strcmp(respStr,"*"));

  Serial.print("Responce:"); Serial.println(respStr);

  // レスポンスがエラー"Exxx>"の場合はfalseを返す
  // レスポンスがエラー">"や"Vxx>の場合はtrueを返す
  if (respStr[0] == 'E') {
    return false;
  } else {
    return true;
  }
}

[Arduinoで遊ぶ]