71歳の挑戦... PCM510xA-V3でネットラジオ　タクトスイッチ選局版（2025/01自家最新）

　以前も同様の投稿（ESP32でPCM510xA-V3を使う）をしました。しかしその後、PCM5102A 基板が突然息をしなくなりました。使い方が悪かったかも知れないので、このままではマズイと判断、同じ物を

http://nfj2019.livedoor.blog/archives/2601664.html
 
再度購入、見直して動作確認できた最新版を上げることにしました。
　ESP32ボード（ArduinoIDE2.3.2 上では、Heltec WiFi Kit 32）とは次のような接続に。

 |Heltec WiFi Kit 32|PCM5102A|
 |------|------|
 |  -   | GND |
 |  -   | MCLK |
 | 25   | BICK(BCK)  |
 | 27   | DATA(DOUT,DIN) |
 | 26   | LRCK(LCK)  |
 | GND  | GND | 
 |  -   | <ins> MUTE |
 | 5V   | VCC |

　新たな取組みとして、チャンネルを変更するためにタクトスイッチを利用しました。恥ずかしながら、これまでタクトスイッチを利用できずにいました。次の記事

https://deviceplus.jp/arduino/arduino_f06/

を参考にし、使えました。
　今回は回路のショートなどにも気を付けることにします。

    １．ESP32ボードは２列ピンメスソケットでユニバーサル基板に取り付けます。
    ２．ユニバーサル基板はESP32ボードとほぼ同じ大きさに切り詰めて使います。
    　ただし、２列ピンの外側にアクセスできるよう、またGNDを増設するために少し大きくします。
    ３．そうしたESP32ボードとPCM5102を、丁度良い大きさの百均の糸ようじケースの中に収めます。
    ４．左の写真の右下にあるようにケース側面にタクトスイッチを取り付けます。
    ５．Pin21番からタクトスイッチを介しGNDに繋がるようにジャンパー線をはんだ付けします。
    ６．スケッチの中であらかじめ Pin21番は「INPUT_PULLUP」で「HIGH」にしておく。
    ７．タクトスイッチを押したときだけGNDに繋がり、Pin21番は「LOW」になります。
    ８．ちょい押しでチャンネルアップ、１秒以上押しでチャンネルダウンとしました。

![Pcm5102A_v3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/5bb9a245-49ed-6860-a440-c941dba6babc.jpeg)

ArduinoIDE 2.3.2 上にて下のスケッチで動作します。チャンネル変化のためダブルコアにしてあります。コンパイルサイズが大きくなるようなので、

    Partition Scheme: "Huge APP (3MB ...)"

としておきます。

![NetRadio_Huge.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/701ffdcd-276b-c57a-33c7-e08f636ea141.jpeg)

ビルトインディスプレイ（ssd1306）に情報を表示できるように工夫しましたが、邪魔になれば「display」の箇所はカットしてください。

```c:NetRadio_2.ino
#include "Arduino.h"
#include "WiFi.h"
#include "Audio.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define I2S_DOUT 27  // 22 DIN
#define I2S_BCLK 25  // BCK
#define I2S_LRC  26  // LCK

#define OLED_SCL 15
#define OLED_SDA  4
#define OLED_RST 16
#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

#define intPin0 21  // Connecting GND makes
                    // channel++, channel--

String ssid = "Your SSID";
String password = "Your Password";

Audio audio;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);

uint8_t volume = 21;      // 0...21
uint8_t cur_station = 0;  // current station No.

#define EofRadios 10  // 0 - 10
String stations[] = {
  "WRTI_CLASSICAL https://playerservices.streamtheworld.com/api/livestream-redirect/WRTI_CLASSICAL.mp3",
  "WRTI_JAZZ https://playerservices.streamtheworld.com/api/livestream-redirect/WRTI_JAZZ.mp3",
  "relax.stream.publicradio.org/relax.mp3",  // Your Classical - Relax
  "ais-sa2.cdnstream1.com/b22139_128mp3",    // 101 SMOOTH JAZZ
  "smoothjazz.cdnstream1.com/2585_128.mp3",
  "avw.mdr.de/streams/284310-0_mp3_low.m3u",
  "www.radiomonique.nl/winamp_RM_64.pls",
  "ice1.somafm.com/illstreet-128-mp3",    // SomaFM / Illinois Street Lounge
  "ice1.somafm.com/secretagent-128-mp3",  // SomaFM / Secret Agent
  "ice1.somafm.com/seventies-128-mp3",    // SomaFM / Left Coast 70s
  "ice1.somafm.com/bootliquor-128-mp3"    // SomaFM / Boot Liquor
  //audio.connecttoFS(SD, "/test.wav");     // SD
};

TaskHandle_t thp[1];

void setup() {
  Serial.begin(115200);
  pinMode(intPin0, INPUT_PULLUP);
  pinMode(OLED_RST, OUTPUT);
  digitalWrite(OLED_RST, LOW);
  delay(20);
  digitalWrite(OLED_RST, HIGH);
  Wire.begin(OLED_SDA, OLED_SCL);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) {  // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ;  // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);

  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid.c_str(), password.c_str());
  while (WiFi.status() != WL_CONNECTED) delay(1500);
  Serial.println(F("WiFi start"));
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(volume);  // 0...21
  audio.connecttohost(stations[cur_station].c_str());
  //audio.connecttoFS(SD, "/test.wav");     // SD

  display.setCursor(0, 0);
  display.print("NetRADIO:No.");
  display.setCursor(72, 0);
  display.print("0");
  display.setCursor(0, 8);
  display.print(stations[cur_station].c_str());
  display.display();

  xTaskCreatePinnedToCore(Core0, "Core0", 4096 * 2, NULL, 3, &thp[0], 0);
  // if 4096, resetted by WDTimer in some cases.
}

void loop() {
  audio.loop();
}

void Core0(void *args) {
  while (1) {
    delay(1);
    if (digitalRead(intPin0) == LOW) {  // Once GND
      audio.stopSong();
      delay(1000);
      if (digitalRead(intPin0) == LOW) {  // Again GND
        cur_station--;
        if (cur_station >= 255) { cur_station = EofRadios; }
      } else {  // Once open, soon GND connected
        cur_station++;
        if (cur_station > EofRadios) { cur_station = 0; }
      }
      delay(1000);
      Serial.print(F("\n\rStation : "));
      Serial.print(cur_station);
      Serial.print(F(" > "));
      Serial.println(F(stations[cur_station].c_str()));
      audio.connecttohost(stations[cur_station].c_str());

      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("NetRADIO:No.");
      display.setCursor(72, 0);
      display.print(cur_station);
      display.setCursor(0, 8);
      display.print(stations[cur_station].c_str());

      display.display();
    }
  }
}

char BITRATE[6];

void audio_showstreamtitle(const char *info) {
  Serial.print(F("Title : "));
  Serial.println(info);

  display.clearDisplay();

  display.setCursor(0, 0);
  display.print("NetRADIO:No.");
  display.setCursor(72, 0);
  display.print(cur_station);

  display.setCursor(0, 8);
  display.print(stations[cur_station].c_str());

  display.setCursor(0, 8 * 6);
  display.print(info);

  display.setCursor(90, 0);
  display.print("       ");
  display.setCursor(90, 0);
  display.print(BITRATE);  // ?

  display.display();
}

void audio_bitrate(const char *info) {
  Serial.print(F("bitrate     "));
  Serial.println(info);

  strncpy(BITRATE, info, 6);

  display.setCursor(90, 0);
  display.print("       ");
  display.setCursor(90, 0);
  display.print(BITRATE);  // ?
  display.display();
}

// optional
void audio_info(const char *info) {
  Serial.print("info->Serial = ");
  Serial.println(info);
}
/*
void audio_id3data(const char *info){  //id3 metadata
  Serial.print("id3data     "); Serial.println(info);
}
void audio_eof_mp3(const char *info){  //end of file
  Serial.print("eof_mp3     "); Serial.println(info);
}
void audio_showstation(const char *info) {
  Serial.print("station     "); Serial.println(info);
}
void audio_commercial(const char *info){  //duration in sec
  Serial.print("commercial  "); Serial.println(info);
}
void audio_icyurl(const char *info){  //homepage
  Serial.print("icyurl      "); Serial.println(info);
}
void audio_lasthost(const char *info){  //stream URL played
  Serial.print("lasthost    "); Serial.println(info);
}
*/
```
　駄文を最後まで見ていただきありがとうございました。