RDA5708M FMラジオ 2

今回はXAIO ESP32C6 SH1106 RDA5708M の構成で組んでみました。I2C で SH1106 RDA5708M を接続するだけで完成です。

コードも AI にお願い

#include <Arduino.h>
#include <Wire.h>
#include <radio.h>
#include <RDA5807.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <RotaryEncoder.h>

// OLEDの設定 (SH1103 128x64)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ロータリーエンコーダのピン設定
#define PIN_IN1 D7  // CLK
#define PIN_IN2 D6  // DT
#define PIN_PUSH D3 // SW

// ラジオとエンコーダのインスタンス作成
RDA5807 radio;
RotaryEncoder *encoder = nullptr;

// ラジオの各種変数
#define MAP_BAND RADIO_BAND_FMWORLD 
RADIO_FREQ currentFreq = 8130;     // 初期周波数 81.3 MHz
RADIO_FREQ minFreq = 7600;         // 最低周波数 76.0 MHz
RADIO_FREQ maxFreq = 10800;        // 最高周波数 108.0 MHz
int stepFreq = 10;                 // 周波数ステップ (0.1 MHz)

int currentVolume = 2;             // 初期音量 (0〜15)
const int maxVolume = 15;
const int minVolume = 0;

// モード管理用の定義
enum Mode {
  MODE_TUNE, // 周波数変更モード
  MODE_VOL   // 音量調整モード
};
Mode currentMode = MODE_TUNE; // 起動時は周波数モード

bool shouldUpdateDisplay = true;

// 割り込み処理関数(エンコーダの回転検知)
void IRAM_ATTR checkPosition() {
  encoder->tick();
}

// 画面描画関数
void updateDisplay() {
  display.clearDisplay();
  display.setTextColor(SH110X_WHITE);
  
  // 1. タイトルバー
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("XIAO ESP32C6 RADIO");
  display.drawLine(0, 12, 127, 12, SH110X_WHITE);
  
  // 2. 周波数表示エリア
  if (currentMode == MODE_TUNE) display.print(">"); else display.print(" ");
  display.setCursor(10, 22);
  display.setTextSize(2);
  display.print((float)currentFreq / 100.0, 1);
  display.setTextSize(1);
  display.print(" MHz");
  if (currentMode == MODE_TUNE) display.print(" [TUNE]");

  // 3. 音量表示エリア
  display.setCursor(10, 42);
  if (currentMode == MODE_VOL) display.print(">"); else display.print(" ");
  display.print(" VOL: ");
  display.print(currentVolume);
  // 音量をバーグラフで簡易表示
  display.drawRect(65, 43, 50, 7, SH110X_WHITE);
  display.fillRect(65, 43, map(currentVolume, 0, 15, 0, 50), 7, SH110X_WHITE);
  if (currentMode == MODE_VOL) {
    display.setCursor(110, 42);
    display.print("*");
  }

  // 4. 下部ステータス
  display.drawLine(0, 53, 127, 53, SH110X_WHITE);
  display.setCursor(0, 56);
  display.setTextSize(1);
  display.print("RSSI: "); display.print(radio.getRssi());
  if (radio.isStereo()) display.print("  STEREO");

  display.display();
}

void setup() {
  Serial.begin(115200);

  // OLEDの初期化
  if(!display.begin(0x3C, true)) { // アドレスは環境に合わせて調整してください
    Serial.println("OLED init failed");
    for(;;);
  }
  display.display();
  delay(1000);

  // 1. ピンモードの設定(内蔵プルアップを有効化)
  pinMode(PIN_IN1, INPUT_PULLUP);
  pinMode(PIN_IN2, INPUT_PULLUP);
  pinMode(PIN_PUSH, INPUT_PULLUP);

  // エンコーダのインスタンス作成
  encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);  // TWO03

  // 2. 割り込みの設定
  attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);

  // ラジオの初期化(環境に合わせて設定してください)
  Wire.begin();
  radio.setup();
  radio.setBand(MAP_BAND);
  radio.setFrequency(currentFreq);
  radio.setVolume(currentVolume);  

  //選局時のノイズを抑える
  radio.setSoftmute(true); 
}

void loop() {
  static int lastPosition = 0;
  static unsigned long lastPushTime = 0;

  // エンコーダの回転チェック
  encoder->tick(); 
  int newPosition = encoder->getPosition();

  if (newPosition != lastPosition) {
    int direction = newPosition - lastPosition;
    
    if (currentMode == MODE_TUNE) {
      // 周波数変更モード
      currentFreq += direction * stepFreq;
      if (currentFreq > maxFreq) currentFreq = maxFreq;
      if (currentFreq < minFreq) currentFreq = minFreq;
      radio.setFrequency(currentFreq);
    } else {
      // 音量調整モード
      currentVolume += direction;
      if (currentVolume > maxVolume) currentVolume = maxVolume;
      if (currentVolume < minVolume) currentVolume = minVolume;
      radio.setVolume(currentVolume);
    }
    
    lastPosition = newPosition;
    shouldUpdateDisplay = true;
  }

  // プッシュスイッチのチェック(チャタリング防止付き)
  if (digitalRead(PIN_PUSH) == LOW) {
    if (millis() - lastPushTime > 300) { // 300msのデバウンス
      // モード切り替え
      currentMode = (currentMode == MODE_TUNE) ? MODE_VOL : MODE_TUNE;
      shouldUpdateDisplay = true;
      lastPushTime = millis();
    }
  }

  // 画面の更新
  if (shouldUpdateDisplay) {
    updateDisplay();
    shouldUpdateDisplay = false;
  }
  
  delay(10); // 安定化のための僅かなウェイト
}

ESP32C3 ESP32C6 は小型なので活用できそうです。また RDA5708M も使いやすく感度もよさそうです。次は50MH FM に使えないかと AI に相談していますがどうも 25KHz ステップしか出来ないようです。

コメント