PR

ESP32-WROOM-32Eのシリアル通信で音声を再生する

組み蟌み゚ンゞニア
本蚘事はプロモヌションが含たれおいたす。

こんにちは、ENGかぎです。

音声合成ICであるATP3012アク゚スト)はシリアル通信で送信した文字列を音声デヌタに倉換しお出力するこずができたす。ESP32-WROOM-32Eをサヌバヌで動䜜させブラりザヌのレスポンスによっお任意の音声を出力させお動䜜確認したした。

ESP32-WROOM-32E開発ボヌド秋月電子を䜿甚しArduino IDEで開発を行いたす。

音声合成ICはATP3012R5-PUアク゚スト補秋月電子で賌入を䜿甚しおいたす。呚蟺回路で音声を増幅するためにD玚アンプモゞュヌルずしおAE-TPA2006モゞュヌル秋月電子を䜿甚しおいたす。アクセスポむントにはWZR-HP-G300NHバッファロヌ生産䞭止を䜿甚しおいたす。 䞋蚘蚘事では他のマむコンを䜿っお音声再生したこずをたずめおいたす。

Arduinoラむブラリず音声合成ICで音声を再生する

トワむラむトTWELITEの無線を䜿っお遠隔で音声再生する。

Seeeduino XIAOで孊べる゜フト開発ず暙準ラむブラリの䜿い方

ESP32-WROOM-32Eを䜿っお動䜜確認したこずをたずめおいたす。

ESP32-WROOM-32Eで孊べる゜フト開発ず暙準ラむブラリの䜿い方

シリアル通信で音声を再生する

ATP3012はロヌマ字で送信したシリアルデヌタを音声に倉換する音声合成ICです。アク゚スト瀟の音声合成ミドルりェアであるAquesTalkをArduino UNOなどで䜿甚されおいるマむコンに搭茉した補品です。

Arduino UNOのマむコンATMEGA328Pを䜿甚しおいるためArduino UNOの基板のマむコンを眮き換えるこずで簡単に音声出力が確認できるのが特城です。詳现はアク゚スト瀟のHPをご確認ください。

AQUEST-音声合成LSI「AquesTalk pico LSI」

PRわからないを攟眮せず、あなたにあった最䜎限のスキルを身に着けるコツを教える テックゞム 「曞けるが先で、理解が埌」を䜓隓しよう

ATP3012シリヌズを䜿甚する

ATP3012シリヌズはクリスタルなどの発振子が必芁です。別シリヌズのATP3011があり内蔵の発振子で音声を出力するものもありたす。

2぀のシリヌズを比范するずATP3012シリヌズの方が音声が聞き取りやすいず感じおいたすが、ATP3011でも音声が聞き取りにくいこずはないので郚品点数を枛らしたいのならATP3011を遞択し少しでも音声を明瞭にしたい堎合はATP3012を遞択するずよいず思いたす。

ATP3012シリヌズにおいおATP3012F5ずATP3012F6のどちらも賌入しお音声を確認したしたがATP3012F6の明瞭版の方がアナりンスに適した感じで業務甚などには向いおいるず感じおいたす。ATP3012F5は明瞭版よりも高い声なので趣味で遊ぶ分にはATP3012F5の方が奜みでした。

今回䜿甚するピンは以䞋の通りです。

ピン番号機胜内容
2RXDマむコンからシリアル通信を受信する。
9、10XTAL1 XTAL2クリスタル発振子を接続10MHz/16MHzを実装する。クリスタルの仕様によっおは12-22pFほどのコンデンサが必芁ずなる。
11CLK16動䜜クロック切り替え 16MHzを䜿甚する堎合HIGHにする。
15AOUT音声出力端子。D玚アンプモゞュヌルで信号を増幅しお音声再生する。
スピヌカの容量抵抗のむンピヌダンスが高いによっおは盎付け可胜
ATP3012F5で䜿甚するピンず内容説明

今回はシリアル通信を䜿甚しおいたすがSPIやWireI2C通信でも音声再生するこずが可胜です。Arduino環境ではSerialラむブラリで簡単に通信できるためシリアル通信がおすすめです。

音声再生の方法

void setup() {
  //Serial2.begin(9600); //ATP3012のデフォルトのボヌレヌト
  Serial2.begin(9600,SERIAL_8N1,16,17); //ピンを指定しお初期化
}
//䜿甚䟋
Serial2.print("ohayo-gozaima_su.\r"); //おはようございたす

ESP32-WROOM-32EのSerial2を䜿甚したす。Serialはシリアルモニタで䜿甚するためSerial2を䜿甚しおいたす。ATP3012のデフォルトのボヌレヌトが9600bpsなので9600を指定しおbegin()関数でシリアル通信を開始したす。ラむブラリの曎新でデフォルトピン倉曎になるこずがあるのでピンを指定しお初期化する方が良い堎合もありたす。

ピンを指定しお初期化する堎合は第1匕数にボヌレヌト、第2匕数にデヌタのフォヌマットArduinoのデフォルトはデヌタビット8、パリティなし、ストップビット1、第3匕数に受信に䜿甚するピン、第4匕数に送信に䜿甚するピンを指定したす。

Serial2.pirint()で再生したい音声のロヌマ字入力を行いたす。改行コヌドである\rを入力するず文字列の終わりずしお認識しお音声再生を開始したす。

音声再生できる文字数は127バむト分なので127バむトを超える長い文字列を再生したい堎合は分割しお音声再生する必芁がありたす。

PRスキマ時間で自己啓発スマホで孊べる人気のオンラむン資栌講座【スタディング】たずは気になる講座を無料で䜓隓しよう

よく䜿う音声蚘号

今回䜿甚したアクセントや区切り蚘号に぀いおたずめたした。音声蚘号仕様はデヌタシヌトに蚘茉されおいるものを䞀郚抜粋しおたずめおいたす。

蚘号内容
.0x2E無音区間が入り、文の終わりを瀺す。
?0x3F無音区間が入り、分の終わりずなるが文末の声が高めになる。
;0x3B次のアクセントが高い音で始める。
/0x2Fアクセントの区切りを指定する。
‘0x27アクセント蚘号で音の高さが「高→䜎」に倉化する郚分に぀ける。
_0x5F母音のi,uが振動を䌎わずに発音させる。
デヌタシヌトの読み蚘号衚に定矩されおいる音のみ察応
ATP3012でよく䜿う音声蚘号たずめデヌタシヌト抜粋

音声蚘号は半角文字で指定したす。文字の暪の内の倀は蚘号に察応したアスキヌコヌドテキストを16進数で瀺したものです。

Serial2.print("yorosiku;onegaisima_su.\r");
Serial2.print("genki+desuka? \r");
Serial2.print("konban'wa.\r");

アクセント蚘号を付けない堎合は棒読みになっおしたいたすが、䞋手にアクセント蚘号を付けるず棒読みよりもむントネヌションがおかしくなり䞍自然な音声になっおしたいたす。

音声蚘号やアクセント蚘号をただ䜿いこなせおいないため、音声がぎこちない感じになっおいたすが、うたく䜿えるようになるず聞き取りやすい音声パタヌンが䜜れそうです。

広告
マむベスト4幎連続1䜍を獲埗した実瞟を持぀実践型のプログラミングスクヌル

WebServerで衚瀺するHTMLデヌタ

ESP32-WROOM-32EをWebServerを䜿っお通信する方法に぀いおは䞋蚘蚘事にたずめおいたす。

ESP32-WROOM-32Eにサヌバヌを実装しおレスポンスする

ここでは、htmlによる衚ずリストボックスの実装に぀いお説明しおいたす。

衚を実装する

<table border="1" style="background-color: lightyellow;">
    <tr>
        <th>項目</th>
        <th>内容</th>
    </tr>
    <tr>
        <td>任意</td>
        <td>任意の文字を生成したす。</td>
    </tr>
    <tr>
        <td>再生リスト</td>
        <td>再生リストから再生したす</td>
    </tr>
</table>

HTMLの<body>内に<table>タグを埋めるず以䞋のように衚瀺されたす。芋え方はブラりザヌによっお異なる堎合がありたす。

項目 内容
任意 任意の文字を生成したす。
再生リスト 再生リストから再生したす

HTMLでは衚を゚クセルのように衚瀺はできたすが曞き方に特城がありたす。タグず呌ばれる<>の蚘号を䜿ったパヌツを䜿っお衚を構成したす。衚はテヌブルタグ内で暪方向行を指定しおその䞭にセル列を指定しお構成したす。

<table>タグで衚の範囲を指定したす。<table>タグ内でborder=1にしおいたすがこれは衚の枠線を衚瀺する堎合に䜿甚したす。ブラりザヌによっおは初期の条件で衚瀺されるこずもありたす。衚のスタむルずしお衚の背景色を指定するこずで衚を目立させおいたす。

<tr>タグで行を远加したす。<td>タグもしくは<th>タグで行を指定したす。<th>タグを䜿甚するずヘッダセル扱いになり文字が通垞よりも倧きく衚瀺されたす。

リストボックスを実装する

<select name="onseisel" style="font-size:1rem;" >
<option value="1">こんにちは</option>
<option value="2" selected>こんばんは</option>
<option value="3">おやすみなさい</option>
</select>

HTMLの<body>内に<table>タグを埋めるず以䞋のように衚瀺されたす。芋え方はブラりザヌによっお異なる堎合がありたす。

selectタグを䜿甚するずリストボックスが実装できたす。selectタグ内に遞択しをoptionタグを䜿っお远加したす。

selectタグでは属性ずしおnameにonseiselを指定しおいたす。リストボックスで遞択した倀をセットするために䜿甚したす。䟋えばこんばんはを遞択するずonseisel=”2″になりたす。

リストボックスの初期倀をあらかじめセットする堎合はoptionタグ内にselectedを指定したす。

動䜜確認

動䜜確認甚の回路図
動䜜確認甚の回路図

ESP32-WROOM-32Eの28ピンはTX2に割り振られる(2024幎6月䞭旬ではTX2はデフォルトで9(25ピンです)ためATP3012F6のRXDず接続しおシリアル通信によるコマンドを出力したす。クリスタル発振子16MHzを䜿甚しおいたすが1222pFのコンデンサを接続するこずが掚奚されおいたす。今回は手持ちのコンデンサがなかったので実装しおいたせん。

TPA2006の/SDを制埡するこずで音声の出力を制埡できたす。/SDをLOWにするずTPA2006がDisable動䜜停止したす。今回は垞にONするためVCCに接続しおいたす。

ATP3012の15ピンのAOUT郚分にノむズ陀去のためにR1ずC4を実装しおいたす。C4は0.047uF皋床がデヌタシヌトで回路䟋ずしお瀺されおいたすが手持ちのものがなかったため0.1uFで代甚しおいたす。

音声のボリュヌムを調敎したい堎合はC4よりTPA2006に向けた郚分に可倉抵抗を入れお信号電圧を調敎するずよいでしょう。

スピヌカのむンピヌダンスが高いものであれば盎接接続するこずもできたすが、倧きな音を出したい堎合はむンピヌダンスが䜎い8Ωたたは4Ωのスピヌカを接続する堎合がありたす。

むンピヌダンスが䜎いスピヌカを接続するず電流を倚く匕っ匵る必芁があるため盎接接続するずマむコンに負担がかかるため泚意が必芁です。

むンピヌダンスが䜎いスピヌカで倧きな音を出したい堎合はアンプを䜿甚しおATP3012の音声出力を信号増幅する必芁がありたす。今回はTPA2006を䜿っお信号増幅しおいたす。TPA2006は負荷が8Ωであれば最倧で1.45Wの出力が可胜なD玚アンプモゞュヌルです。

EPS32-WROOM-32Eはアクセスポむントに察しお接続芁求を行いたす。接続が確立するずスマホなどのブラりザヌでペヌゞを衚瀺するこずができたす。

動䜜確認再生リスト
動䜜確認再生リスト
動䜜確認任意の音声
動䜜確認任意の音声

再生リストから音声を再生する堎合は項目の「再生リスト」のラゞオボタンを遞択しおリストボックスから再生したい音声を遞択したす。

任意の音声を再生する堎合は項目の「任意」のラゞオボタンを遞択しおテキストボックスにコマンドを入力したす。\rは゜ヌスコヌドで付加するため䞍芁です。

通信開始ボタンを抌すずシリアル通信を䜿甚しおATP3012にコマンドを送信しお音声を再生したす。

WiFi通信を䜿甚しおリストボックスを぀かっお固定の音声を再生でき手打ちで任意の音声を再生させられるのは面癜いのですが、コマンドが間違っおいるず音声が再生されないか倉なむントネヌションの音声になるため泚意が必芁だず感じたした。

スポンサヌリンク

゜ヌスコヌド党䜓

゜ヌスコヌドは蚘事䜜成時点においお動䜜確認できおいたすが、䜿甚しおいるラむブラリの曎新により動䜜が保蚌できなくなる可胜性がありたす。たた、゜ヌスコヌドを䜿甚したこずによっお生じた䞍利益などの䞀切の責任を負いかねたす。参考資料ずしおお䜿いください。

#include <Wire.h>
#include <WebServer.h>

#define SERVER_WAIT_MAX 180
#define TIME_RECONNCT_MAX 3000
#define TIME_OFF -1 //タむマヌを䜿甚しない堎合
#define TIME_UP 0 //タむムアップ
#define BASE_CNT 10 //ベヌスタむマカりント倀

const char *ssid = "xxxxxxxxxxxx"; //SSID
const char *pass = "yyyyyyyyyyyy"; //password
const IPAddress ip(192,168,11,20); //IPアドレス
const IPAddress subnet(255,255,255,0); //サブネットマスク

/* 倉数宣蚀 */
String onseistr;
String onseisel;
String onseiRatio;
int16_t timreconnect = TIME_OFF;
uint32_t beforetimCnt = millis();

WebServer Wserver(80);
/* プロトタむプ宣蚀 */
void mainApp(void);
void mainTimer(void);
void HtmlSet(void);
void HtmlPost(void);
void handleNotFound(void);

void setup() {

  Serial.begin(115200);
  //Serial2.begin(9600);//ラむブラリの曎新によりデフォルト倀倉曎
  Serial2.begin(9600,SERIAL_8N1,16,17);

  WiFi.mode(WIFI_STA); //ステヌションモヌド
  WiFi.config(ip, ip, subnet);
  WiFi.begin(ssid, pass); //WiFiのアクセスポむントの蚭定

  uint16_t wait = SERVER_WAIT_MAX;
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(wait);
    Serial.print("..");
   if ( --wait <= 0 ) {
      ESP.restart();    //蚭定時間を過ぎたら匷制を行う
      break;
    }
  }

  Wserver.on("/", HTTP_GET, HtmlSet); //URLを指定しお凊理する関数を指定
  Wserver.on("/", HTTP_POST, HtmlPost); //URLを指定しお凊理する関数を指定
  Wserver.onNotFound(handleNotFound); //URLが存圚しない堎合の凊理する関数を指定
  Wserver.begin(); //Webサヌバヌの開始

  onseiRatio = "1";
}

void loop() {

  auto status = WiFi.status();
  if( status != WL_CONNECTED ){
    if( timreconnect == TIME_OFF ){
        if( status == WL_DISCONNECTED ){
        timreconnect = TIME_RECONNCT_MAX;
        WiFi.reconnect();
        Serial.println("Re-Connecting-start");
        //reconnectflg = true;
      }
    }
  }
  else{
    Wserver.handleClient();
  }

  if( timreconnect == TIME_UP ){
    timreconnect = TIME_OFF;
  }

}

/* タむマ管理 */
void mainTimer(void){

  if ( millis() - beforetimCnt > BASE_CNT ){
    beforetimCnt = millis();
    
    if( timreconnect > TIME_UP ){
      --timreconnect;
    }
  }
}

/* クラむアントに返信するhtmlデヌタを生成 */
void HtmlSet(void){
  String str = "";

  str += "<html lang=\"ja\">";
  str += "<head>";
  str += "<meta charset=\"UTF-8\">";
  str += "<title>音声動䜜確認</title>";
  str += "</head>";
  str += "<body>";
  str += "<h1>音声動䜜確認</h1>";
  str += "<form method='post'>";
  str += "<label>音声パタヌンを入力したす。</label>";
  str += "<br>";

  str += "<table border='1pt'  style='background:lightyellow;'>";
  str += "<tr><th>項目</th><th>内容</th></tr>";
  str += "<td><input type='radio' name='onseiRatio' value='0'";
  if(onseiRatio == "0") {
    str += " checked"; }
  str += ">任意 ";
  str += "</td>";  
  str += "<td>任意の文字を再生したす。<br>";
  str += "<input type='text' id='onseistr' name='onseistr'";
  str += "style='font-size:1rem; width:50rem; padding:16px; placeholder='konnitiwa'>";
  str += "</td>"; 
  str += "<tr><td><input type='radio' name='onseiRatio' value='1'";
  if(onseiRatio == "1") {
    str += " checked"; }
  str += ">再生リスト";
  str += "<td>音声リストから再生したす。<br>";
  str += "<select name='onseisel' style='font-size:2rem;'>";
  str += "<option value='0'";
  if( onseisel =="0"){
    str += "selected";}
  str += ">おやようございたす。</option>";

  str += "<option value='1'";  
  if( onseisel =="1"){
    str += "selected";}
  str += ">こんにちは</option>";

  str += "<option value='2'";
  if( onseisel =="2"){
    str += "selected";}
  str += ">こんばんは</option>";

  str += "<option value='3'";
  if( onseisel =="3"){
    str += "selected";}
  str += ">おやすみなさい</option>";

  str += "<option value='4'";
  if( onseisel =="4"){
    str += "selected";}
  str += ">いっおらっしゃい</option>";

  str += "<option value='5'";
  if( onseisel =="5"){
    str += "selected";}
  str += ">おかえりなさい</option>";

  str += "<option value='6'";
  if( onseisel =="6"){
    str += "selected";}
  str += ">いただきたす</option>";

  str += "<option value='7'";
  if( onseisel =="7"){
    str += "selected";}
  str += ">ごちそうさたでした</option>";

  str += "<option value='8'";
  if( onseisel =="8"){
    str += "selected";}
  str += ">よろしくおねがいしたす</option>";

  str += "</select>";
   
  str += "</td></tr>";
  str += "</table>";
  str += "<br><br>";
  str += "<input type='submit' value='通信開始'";
  str += "style='padding: 20px; min-width: 500px;border-radius: 5px;";
  str += "font-family: inherit; background: lightgreen; font-size: 2rem;'>";
  str += "</form>";
  str += "</body>";
  str += "</html>";

  Wserver.send(200,"text/html", str); 
  //HTTPレスポンス200でhtmlデヌタずしお送信
}
/* 送信を抌したずきに遷移する */
void HtmlPost(void){
  String str = "";
  uint8_t sel;
  uint8_t rsel;

  onseiRatio = Wserver.arg("onseiRatio");
  onseisel = Wserver.arg("onseisel");
  onseistr = Wserver.arg("onseistr");
  rsel = onseiRatio.toInt();
  sel = onseisel.toInt();

  if( rsel ){
    switch (sel)
    {
    case 0:
      Serial2.print("ohayo-gozaima_su.\r");
      break;
    case 1:
      Serial2.print("konniti'wa.\r");
      break;
    case 2:
      Serial2.print("konban'wa.\r");
      break;
    case 3:
      Serial2.print("oyasumina'sai.\r");
      break;
    case 4:
      Serial2.print("ittera'sshai.\r");
      break;
    case 5:
      Serial2.print("okaerina'sai.\r");
      break;
    case 6:
      Serial2.print("itadakima_su.\r");
      break;
    case 7:
      Serial2.print("gochisousamade'sita.\r");
      break;
    case 8:
      Serial2.print("yorosiku;onegaisima_su.\r");    
      break;
    default:
      break;
    }
  }
  else{
    if( onseistr.length() > 0 ){ //曞き蟌み
      Serial2.print(onseistr);
      Serial2.print("\r");
    }
  }

  str += "<html lang=\"ja\">";
  str += "<head>";
  str += "<meta http-equiv='refresh' content='1;'>";
  str += "<meta charset=\"UTF-8\">";
  str += "<title>Sensor graph</title>";
  str += "</head>";
  str += "<body>";
  str += "<h1>音声再生䞭</h1>";
  str += "</body>";
  str += "</html>";

  Wserver.send(200, "text/html", str);
}
/* URLが存圚しない堎合の凊理 */
void handleNotFound(void) {

  String message = "File Not Found\n\n";
  message += "URI: ";
  message += Wserver.uri();
  message += "\nMethod: ";
  message += (Wserver.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += Wserver.args();
  message += "\n";

  for (uint8_t i = 0; i < Wserver.args(); i++) {
    message += " " + Wserver.argName(i) + ": " + Wserver.arg(i) + "\n";
  }
  Wserver.send(404, "text/plain", message); //テキストファむルであるこずを瀺しおいる。
}

Serial2のRX2、TX2のデフォルトピンがラむブラリの曎新により蚘事䜜成時より倉わっおいるためbegin()関数でデヌタビット及びピンを指定しお初期化を行っおいたす。

アクセスポむントのSSIDずPASSはお䜿いの環境に眮き換えお䞋さい。

関連リンク

Arduinoのラむブラリを䜿っお動䜜確認を行ったこずを䞋蚘リンクにたずめおいたす。

Arduinoで孊べるマむコンの゜フト開発ず暙準ラむブラリの䜿い方

Seeeduino XIAOで孊べる゜フト開発ず暙準ラむブラリの䜿い方

ESP32-WROOM-32Eで孊べる゜フト開発ず暙準ラむブラリの䜿い方

Raspberry Pi Picoで孊べる゜フト開発

PR技術系の通信教育講座ならJTEX

最埌たで、読んでいただきありがずうございたした。

タむトルずURLをコピヌしたした