hiro yamamoto works

マイコンハード、ソフトを作ったりしています。
お家や現場のお困りごと解決に!
内容利用は自己責任でお願いします。

bluetoothで音声を送る(I2S DAC PCM5102Aで音を出す)

2024-07-28 17:35:24 | bluetooth-Audio

書きかけの投稿です。
今回の内容は、ESP32-ROOM-32EとPCM5102A I2S DACを使った、
bluetooth音声出力デバイスについてです。


ネタとなったお困りごと:
音声を数百メートル離れた場所へ送りたい。とのこと
どんな方法があるのか?
・Wi-Fiに載せて送る
・bluetoothで送る
・他

"到達距離"は
Wi-Fiの方が伸びそう(?)
bluetoothでもmeshで伸ばすことができる(?)
XIAO ESP32C3,ESP32S3を使えば、外部アンテナで可能性あり。
"音声を送る"は
Wi-Fiでは難しそう(個人の感想です)
bluetoothでは簡単そう("ESP32-A2DP"ライブラリを使った作例が公開されている)

わくわくでプロジェクトをスタートしました。

わかったこと
目論んでいたESP32S3,C3ですが、コンパイルエラーとなりました。
ESP32-A2DP関係を調べてみると"・・・esp32-c3 has no support for classic BT"とか
"・・・ s3 support Bluetooth classic?・・・only the ESP32 will be supporting classic BT"とか
出てきます。現時点(?)では難しいようです。
ESP32-WROOM-32Eの秋月ボードでテスト開始します。

bluetooth受信〜音声出力(sink側)から始めました。
Amazonで"PCM5102 DAC デコーダ モジュール I2S インターフェイス"を購入
動作確認がとれました。

接続図
DAC右側端子シルク印刷がSOKとなっていますがSCKの間違いですね
LCKはLRCKです。

ArduinoIDEの準備は
GitHubで"ESP32-A2DP"ライブラリを探して、ZIPファイルをダウンロードしてインストールします。
スケッチは・・・

サンプルスケッチだけでは・・・
そのまま使える作例はネットを探すと見つかると思います。
当ブログでのスケッチ紹介は、理解できてからにしたいと思います。
と思ったのですが、ESP32-A2DPライブラリの中で、すぐ使える
サンプルスケッチがわかりましたのでご報告します。

このサンプルスケッチが使えました。
スケッチ例 ESP32-A2DP/examples/legacy-api/bt_music_receiver_simple
defaultの設定で動いていると推定します。
"BluetoothA2DPOutput.cpp"に記述されているやつがそうかな?



つづく


赤外線リモコンをWi-Fiで中継する(deep-sleepを組み込む)

2024-07-17 15:26:34 | 赤外線リモコン

この投稿は書きかけです。
スケッチは参考程度に見てください。
動作時の電流を測定したので載せておきます。
待機時約84mA 赤外線受信Wi-Fi送信時ピーク約120mA sleep時約0.62mA


ポイント
 赤外リモコン中継送信機の消費電力削減のために、
 ESP32のDeep-sleep Modeを組み込みました。
 XIAO ESP32C3でフィードバックLED点灯を断念し代用LEDをGPIO2に接続
 #define LED_BUILTINでピン指定しても点きません。XIAO ESP32S3ではデフォルトのままでチカチカしてました。

タイトルでは"Wi-Fiで"と表現していますが、正しくは"ESP-NOW"です。
だれでもイメージしやすいように"Wi-Fiで"と表現しています。

SONY製レコーダーのリモコンモード変更設定可能台数不足解決、
同室複数SONY製テレビの赤外線リモコン操作での問題解決に役立ちます。
Tip
SONY新型テレビリモコン(一部機種)は、電源ボタンのみ赤外線で、
以外はbluetooth接続との情報です。
テレビ側設定でbluetoothをOFFで赤外線操作になるが
"googleアシスタント"はbluetooth接続要とのこと。
ちなみにbluetooth接続は、キッチンだと電子レンジの影響が出る可能性があります。


XIAO ESP32C3を使用しました。
Wakeupスイッチ・・・D1(GPIO3)とGND間にプッシュスイッチを接続
状態表示LED・・・D2(GPIO4)と3.3V間に抵抗とLEDを直列接続(抵抗は仮に1K点灯がわかれば良い)
IR_RECEIVE_PIN ・・・D8(GPIO8)
FEEDBACK LED代用・・・D0(GPIO2)をdigitalWrite()で(ESP32C3用)
D0(GPIO2)と3.3V間に抵抗とLEDを直列接続(抵抗は仮に1K点灯がわかれば良い)

ざっくり説明
 IRremote、ESP32 ESPNow、ESP32 DeepSleep各exampleから
 Seeed Studio wiki のXIAO ESP32C3 Getting Started のスケッチから
 必要な部分を使用させていただきました。
DeepSleep組込前スケッチはこちらの記事を見てください
 
 赤外線受信していないときsleep用カウンタを加算、
 赤外線受信し"protocol == SONY"でカウンタクリア
 カウント値が連続100,000,000回(仮)を超えたときに
 "esp_deep_sleep_start()"でsleepする。
 D1(GPIO3)プッシュスイッチでWeakup
 電源表示LED 動作中点滅、sleep中消灯
 ESP32C3でのFEEDBACK LED代用として
 D0(GPIO2)をdigitalWrite()で点消灯している。

参考スケッチ
(XIAO ESP32S3では手直し必要、間違いや抜けがあるかも)

//オリジナル部分を省略して主に追加した部分を記述
#define IR_RECEIVE_PIN 8
#define ledPin 4 //sleep中 点滅LED
uint32_t sleepTime_RepeatCount = 0;
uint32_t detectionCount = 100000000; //delay(1)へ変更に伴う

//ESP-NOW Masterは赤外線リモコンを受信してESP-NOW Slaveへ送る
typedef struct struct_IRSendData {
  char IR_protocol[10];//"SONY"の文字が入れば良い
  uint16_t IR_address;
  uint16_t IR_command;
  uint8_t IR_repeat;
  uint8_t IR_bit;
} struct_IRSendData;
struct_IRSendData IRSendData;
 
uint8_t irSendRepeatCount = 0;
uint32_t LastSendMillis = 0;

bool ledState = LOW; // sleep中 点滅LED
uint32_t blinkPreviousMillis = 0; // sleep中 点滅LED
const uint16_t blinkInterval = 1000; // sleep中 点滅LED
#include <IRremote.hpp>//"<"と">"は半角に直す
//中略
//以降はsetup()の中
//pinMode(LED_BUILTIN, OUTPUT);//XIAO ESP32S3
  pinMode(ledPin, OUTPUT);//LED スリープ中消灯 動作中点滅する
  pinMode(2, OUTPUT);//GPIO2(D0)//ESP32C3でFEEDBACK LED代用
  digitalWrite(2, HIGH);//ESP32C3でFEEDBACK LED代用起動時点灯するので消しておくため
//LED 3.3V to ANODE ,GPIO2 to CATHODE
/*参考 esp_err_t esp_deep_sleep_enable_gpio_wakeup(uint64_t gpio_pin_mask,
    esp_deepsleep_gpio_wake_up_mode_t mode)*/
//wakeup設定部
  esp_deep_sleep_enable_gpio_wakeup(BIT(D1), ESP_GPIO_WAKEUP_GPIO_LOW);
  //mode -- Select logic function used to determine wakeup condition:
  //ESP_GPIO_WAKEUP_GPIO_LOW: wake up when the gpio turn to low.
  //ESP_GPIO_WAKEUP_GPIO_HIGH: wake up when the gpio turn to high.
  /*ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORSはデフォルト有効
    プルアップ、ダウン抵抗指定不要 外部で行う時は
    ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS オプションを無効にとあったが
    設定方法は見つからんかった*/
//中略
  
  IrReceiver.begin(IR_RECEIVE_PIN)//XIAO ESP32C3の時
  //IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);//XIAO ESP32S3
  
//setup()部分はここまで
loop(){
  digitalWrite(2, HIGH);//XIAO ESP32C3でFEEDBACK LEDの代用
  if (IrReceiver.decode()) { //赤外線
    if (IrReceiver.decodedIRData.protocol == SONY) {
       sleepTime_RepeatCount = 0;
       Serial.println("sleepTime_RepeatCount clear");
    //
   strcpy(IRSendData.IR_protocol, "SONY");
       IRSendData.IR_address = IrReceiver.decodedIRData.address;
       IRSendData.IR_command = IrReceiver.decodedIRData.command;
       IRSendData.IR_repeat = 2;//2で固定
       IRSendData.IR_bit = IrReceiver.decodedIRData.numberOfBits;
       
   //さっき送ったのと今送った時間差300mS以上のときにカウントをリセットする
      uint32_t SendMillis = millis();
      if (SendMillis - LastSendMillis >= 300) { //
        irSendRepeatCount = 0;
      }
      /*Serial.print("irSendRepeatCount = "); Serial.println(irSendRepeatCount);*/
      LastSendMillis = SendMillis;
      //リモコンボタン押し時間が長め(**mS超え)の時 1発目送って少し待って(**mS)2発目送る
      //以降は少ない待ち時間で繰り返し
      if (irSendRepeatCount == 0 || irSendRepeatCount >= 10) {
        sendData();//ESP-NOW
      }
        irSendRepeatCount++;//
    } else if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
      Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
    }
    IrReceiver.resume();
    //
    digitalWrite(2, LOW);//ESP32C3でFEEDBACK LED代用
  } else {
    //
    sleepTime_RepeatCount++;
    //Serial.print("sleepTime_RepeatCount = "); Serial.println(sleepTime_RepeatCount);
    delay(1); //修正して様子みる
    if (sleepTime_RepeatCount >= detectionCount) { //uint32_t detectionCount no-operation-detection count
      
      //Go to sleep now
      Serial.println("Going to sleep now");
      esp_deep_sleep_start();
    } //if (sleepTime_RepeatCount・・・
  } // } else {
  //スリープ中以外にLEDを点滅する
  uint32_t blinkCurrentMillis = millis();
  if (blinkCurrentMillis - blinkPreviousMillis >= blinkInterval) {
    blinkPreviousMillis = blinkCurrentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}//loop()


改善点が見つかればつづく


赤外線リモコンをWi-Fiで中継する(電池稼働のためにdeep-sleepを試す)

2024-07-14 17:20:50 | 赤外線リモコン

この投稿は書きかけです。
スケッチは参考程度に見てください。

ポイント
 赤外リモコン中継送信機の消費電力削減のために、
 ESP32のDeep-sleep Modeを組み込みテストします。
 無操作時は"deep-sleep"へ移行し、プッシュスイッチでwakeupします。

タイトルでは"Wi-Fiで"と表現していますが、正しくは"ESP-NOW"です。
だれでもイメージしやすいように"Wi-Fiで"と表現しています。

SONY製レコーダーのリモコンモード変更設定可能台数不足解決から
派生したプロジェクトです。
同室に複数設置されたSONY製テレビの赤外線リモコン操作で、
目的テレビ以外が反応してしまう問題解決に役立ちます。
Tip
SONY新型テレビは、赤外線は電源ボタンのみで、以外はbluetooth接続に
なっているとの情報です。テレビ側の設定でbluetoothをOFFにすると赤外線に
なりますが"googleアシスタント"が使えなくなるらしいです。
ちなみにbluetooth接続は、キッチンだと電子レンジの影響が出る可能性があります。


XIAO ESP32C3を使用しました。
Wakeupスイッチ・・・D1(GPIO3)とGND間にプッシュスイッチを接続
状態表示LED・・・D2(GPIO4)と3.3V間に抵抗とLEDを直列接続(抵抗は仮に1K点灯がわかれば良い)
IR_RECEIVE_PIN ・・・D8(GPIO8)
"IRremote"ライブラリの一部を合体し"デコード結果の
"リザルト ショート"をシリアルモニタへ表示
ざっくり説明
 Seeed Studio wiki のXIAO ESP32C3 Getting Started に
 紹介されているスケッチをベースにしています。
赤外線受信がなくcurrentMillis から previousMillisを引いた値が
小さくなったときカウンタを加算、大きくなった時カウンタをクリア
カウント値が連続50回(仮)を超えたときに"esp_deep_sleep_start()"
D1プッシュスイッチでWeakup
参考スケッチ

//オリジナル部分を省略して主に追加した部分を記述
#define IR_RECEIVE_PIN 8
uint32_t repeatCount = 0;
uint32_t previousMillis = 0;
#include <IRremote.hpp>//"<"と">"は半角に直す
//中略
//以降はsetup()の中へ追加
  /*参考 esp_err_t esp_deep_sleep_enable_gpio_wakeup(uint64_t gpio_pin_mask,
    esp_deepsleep_gpio_wake_up_mode_t mode)*/
//次行参考にwakeup部(オリジナルのまま)
  esp_deep_sleep_enable_gpio_wakeup(BIT(D1), ESP_GPIO_WAKEUP_GPIO_LOW);
  //mode -- Select logic function used to determine wakeup condition:
  //ESP_GPIO_WAKEUP_GPIO_LOW: wake up when the gpio turn to low.
  //ESP_GPIO_WAKEUP_GPIO_HIGH: wake up when the gpio turn to high.
  /*ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORSはデフォルトで有効
    プルアップ、プルダウン抵抗の指定不要。外部プルアップ、プルダウンするときは、
     ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS オプションを無効にと書いてあった
     オプションの設定方法は見つけられなかった*/<
//中略
  pinMode(D2, OUTPUT); // D2(GPIO4)status check LED
  //pinMode(D3, INPUT_PULLUP);//test
  //D2 LED deep-sleepで消灯 3.3V to ANODE ,D2 to CATHODE
  digitalWrite(D2, LOW);
  IrReceiver.begin(IR_RECEIVE_PIN);
//setup()部分はここまで
//以降loop()中に追加
//中略
  if (IrReceiver.decode()) { //赤外線
     Serial.println(); // blank line between entries
    Serial.println(); // 2 blank lines between entries
    IrReceiver.printIRResultShort(&Serial);
    IrReceiver.resume();
  } else {
     //時間差**mS以下のとき
    uint32_t currentMillis = millis();
    //操作されない時current - previousの値は小さくなる
    //設定された時間(**mS)より小さい回数が連続し、指定した回数を超えた時
    if (currentMillis - previousMillis >= 300) {//仮に**mS=300
      //**mS以上のときカウントをクリア
      repeatCount = 0;
      Serial.println("repeatCount clear");
     } else {
      //**mS以上でない時(未満のとき)
      repeatCount++;
      Serial.print("repeatCount = "); Serial.println(repeatCount);
     }
    previousMillis = currentMillis;
    //**mS未満のカウントが**カウント以上ならsleep
    if (repeatCount >= 50) {//仮に**カウント=50 参 MAX uint32_t 4294967295
      //Go to sleep now
      Serial.println("Going to sleep now");
      esp_deep_sleep_start();
    }
  }
  delay(100);
}//loop()


deep-sleepへ移行

deep-sleep移行阻止

つづく


赤外線リモコンをWi-Fiで中継する(2号機テレビ用悩むチャタリング類似現象)

2024-07-06 20:14:19 | 赤外線リモコン

この投稿は書きかけです。
スケッチは参考程度に見てください。
SONY新型テレビのリモコンは、電源ボタンのみ赤外線で、
それ以外のボタンはデフォルトがbluetooth接続とのこと(赤外線にも設定可能)

ポイント
 赤外線リモコンWi-Fi中継テレビ用
 チャタリング類似現象の解決できたか?・・・できた

タイトルでは"Wi-Fiで"と表現していますが、正しくは"ESP-NOW"です。
だれでもイメージしやすいように"Wi-Fiで"と表現しています。

SONY製レコーダーのリモコンモード変更設定可能台数不足解決から
派生したプロジェクトです。
同室に複数設置されたSONY製テレビの赤外線リモコン操作で、
目的テレビ以外が反応してしまう問題解決に役立ちます。

テレビリモコンを中継してみて使いにくいことは
① 操作が遅れる
② 1回押しが2回押し(チャタリング的)になることがある
③ 準備OK・NG(中継可否)がわからない


①・・・赤外線受信してESP-NOW送信時に毎回再接続する。
起動時に接続して状態を維持する。・・・操作レスポンス向上
loop()の中に下記を見つけてsetup()の最後へ移動
  ScanForSlave();   if (slave.channel == CHANNEL) { /* check if slave channel is defined*/
    /* "slave" is defined. Add slave as peer if it has not been added already.*/
    // "slave"が定義されている スレーブがまだ追加されていなければピアとして追加する。
    bool isPaired = manageSlave();
    if (isPaired) {
      /* pair success or already paired Send data to device*/
      // ペアリング成功またはペアリング済み デバイスにデータを送信
      //sendData();//ここでは送らないのでコメントアウトしておく
    } else {
      Serial.println("Slave pair failed!");// スレーブペア失敗
      delay(3000); // 追加 
      ESP.restart(); // 追加スレーブペア失敗 3秒後再起動
    }
  } else {
    /*処理するスレーブが見つからない No slave found to process*/
    delay(3000); // 追加
    ESP.restart(); // 追加 スレーブが見つからない 3秒後再起動
  }

②・・・リモコンからの赤外線が"リピート2"影響もあるのかな?
 "チャタリング的"改善の"接続維持"により、操作レスポンスが
 向上したのは良かったが、チャタリングは悪化
 ・・・赤外線受信回数をカウントして、送るタイミングを制御します。
 ボタンを押し続けた時はカウント0回(初回)と10回以上の時だけWi-Fi送信します。
 ボタンを離して300mS経過したらカウント値をリセットします。
 カウント0回と10回以上の時"?理由は
 テレビ付属リモコンをテレビに向けて"入力切換"押し続けてみるとわかります。
//中略
uint8_t repeatCount = 0;
uint32_t LastSendMillis = 0;
//中略
loop(){
   if (IrReceiver.decode()) {  // Grab an IR code
    if (IrReceiver.decodedIRData.protocol == SONY) {
    //さっき送ったのと今送った時間差300mS以上のときにカウントをリセットする
      uint32_t SendMillis = millis();
       if (SendMillis - LastSendMillis >= 300) { //
        repeatCount = 0;
      }
      strcpy(IRSendData.IR_protocol, "SONY");
      IRSendData.IR_address = IrReceiver.decodedIRData.address;
      IRSendData.IR_command = IrReceiver.decodedIRData.command;
      IRSendData.IR_repeat = 2;//2で固定
      IRSendData.IR_bit = IrReceiver.decodedIRData.numberOfBits;

      LastSendMillis = SendMillis;
       //リモコンボタン押し時間が長め(**mS超え)の時 1発目送って少し待って(**mS)2発目送る
      //以降は少ない待ち時間で繰り返し
      if (repeatCount == 0 || repeatCount >= 10) {
        sendData();//ESP-NOW送信
      }
       repeatCount++;//どこに入れたら良いか暫定
    } else if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
      Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
    }
    IrReceiver.resume();
  }
}//loop()

間違いがあるかもしれません。どんなことをやっているのか参考程度に見てください。
③・・・LED追加で表示(今後)
 ・・・ 中継できていない時は
 赤外線送信器側(Wi-Fi受信側)準備完了まで、赤外線受信側(Wi-Fi送信側)が
 待って接続を完了します。(再起動繰り返します)①のスケッチとダブります。
void InitESPNow() {
   WiFi.disconnect();
   if (esp_now_init() == ESP_OK) {
     Serial.println("ESPNow Init Success");
   } else {
     Serial.println("ESPNow Init Failed");
     // Retry InitESPNow, add a counte and then restart?
// InitESPNow();
     // or Simply Restart
     ESP.restart();
   }
}


もう少し伸びしろがあるのか?
つづく


赤外線リモコンをWi-Fiで中継する(2号機を作ってテレビ用改良点を探る)

2024-07-01 15:14:57 | 赤外線リモコン

この投稿は書きかけです。


ポイント
 赤外線LED3個用送信基板紹介してます。
 テレビ用にします。(?)

タイトルでは"Wi-Fiで"と表現していますが、正しくは"ESP-NOW"です。
だれでもイメージしやすいように"Wi-Fiで"と表現しています。

プロジェクトの経緯
1号機は、SONY製レコーダーの、リモコンモード変更設定可能台数不足という、
とてもニッチな"お困りごと"がきっかけででした。
"Wi-Fiで中継する"が他にもニッチ問題解決に役立つことに気づきました。
2号機製作は、主にテレビでの使用を目的とした動作検証と改良点探しです。
(1号機でも使いやすくなると思うので展開します。)

こんなことがありました。
部屋にテレビ視聴用と、パソコンモニタ用テレビ(どちらもSONY製)
それぞれ一人づつ使っていて、片方がリモコン操作すると両方反応して揉め事がおきます。
この中継使えばテレビ2台同室でも揉め事はおきないでしょう。

先ずは2号機の作成です。
赤外線受信(ESP-NOW Master)基板です。
秋月電子でなにか部品買ったときの空ケースに収納してみました。


赤外線送信(ESP-NOW Slave)基板です。赤外線LED2個(3個まで増設可)


赤外線受信(ESP-NOW Master)基板です。(1号機と同じ)


赤外線送信(ESP-NOW Slave)基板です。(赤外線LED3個用送信基板)

スケッチの改良ポイント
操作遅れる
1回押しが連続操作になってしまう
Master〜Slave接続できていない時のお知らせ表示と動作


つづく