小型FMラジオの作成

無線

AQM1602Y LCDモジュールとRDA5870M DSPラジオモジュールを使って、小型FMラジオを作ってみました。
タバコより少し大きいくらいの大きさで、個人的には気に入ってます!
電源にUSB給電を採用していますが、消費電力が少ないため、一部のモバイルバッテリーでは少し時間が経過すると電源の供給が止まります。ACアダプタ式のUSB充電器などを使うと良いと思います。(PCからの給電はやめてください。)

注意:この動画により作成したものの、動作を保証するものではありません。また、製作中、完成品の動作中の事故などについて、当方は責任を負いかねます。自己責任でお願い致します。

ケース

ケースには、タカチ電機工業さんの、KC型小型アルミケースKC3-8-10BB(外寸:75x30x100mm、内寸:57.8x24x94.5mm)を使いました。ボディー部にアルミ押出材を使用し、パネル部にABS樹脂が使用されており、加工しやすく、高級感もあります。

binary comment
Amazon.co.jp

制御部

制御用のマイコンには、Arduino Pro Mini 328 3.3V 8MHzを使いました。SparkFunが製造したものを、SWITCH SCIENCEさんから購入できます。リードピンを半田付けして使います。

画像に alt 属性が指定されていません。ファイル名: IMG_5875.jpg画像に alt 属性が指定されていません。ファイル名: IMG_5880.jpg

I2C用のSDA、SCL端子は本体内にあるので、被覆線などで別に配線する必要があります。配線を半田付けする際は、近くにATmega328Pの足など面付け部品があるので、半田を盛りすぎないなど注意が必要です。

FMラジオモジュール

FMラジオモジュールには、Aitendoさんの「★5807★FMラジオモジュール [M5807MB]」を使いました。このモジュールは、DSPラジオチップRDA5807Mを搭載しており、I2Cインターフェイスで容易に制御できます。Arduinoのライブラリも充実していることから、使いやすいモジュールです。結構高感度で、簡単なアンテナを付けるだけで、良好に受信できます。そして、何といっても安価です!
受信周波数範囲:50〜115MHz、動作電源:2.7〜3.6V

モジュールのピンのピッチが2mmなので、ラジオモジュールDIP化基板を使ってDIP化します。ピンの取り出しがストレートのタイプ(P-2.0-D10B)と、90°変化するタイプ(P-2.0-D10A)があります。今回使ったものは、90°変化するタイプです。少し古いバージョンだったため、6番ピンがプリント配線されておらず、ジャンパー線で接続して使っています。

画像に alt 属性が指定されていません。ファイル名: IMG_5871.jpg画像に alt 属性が指定されていません。ファイル名: IMG_5877.jpg

RDA5807Mラジオモジュールのピン配置などは、AitendoさんのHPをご覧ください。
RDA5807Mラジオモジュールは、Amazonからも購入できます。

Ren He FMラジオモジュール RDA5807M RRD-102V2.0 ステレオ DC 2.7-3.6V 5個 収納ボックス付き
【商品説明】 このFMステレオ無線モジュールは、高感度、低電力です。 内蔵ノイズ除去、ソフトミュート、低音ブースト回路設計。 ワイヤレスオーディオとワイヤレスステレオヘッドセットの機能。 GPSナビゲーション、テレビ放送システムと他のワイヤレスFMラジオ。 ハイエンドゲームやワイヤレスオーディオ電子玩具。 携帯電話、イ...

表示部

表示部には、バックライト付きのLCDモジュール「AQM1602Y-NLW-FBW」を使いました。秋月電子通商さんから購入できます。AQM-1602Yシリーズには、バックライトの有無、バックライト・文字の色でいくつかの種類があります。今回使ったものは、白色文字、黒色バックライトのタイプで、ケースが黒なので、文字が浮かび上がる感じで気に入ってます。
ドライバICにST7032iが使われており、I2CインターフェイスでArduinoのライブラリが使えます。

このモジュールを使うためには、3個のコンデンサと、バックライト用の抵抗が必要になります。ケースに収める事を考慮し、LCDモジュールの後ろ側に基板がくるように細工しました。部品の配置、配線は、こんな感じです。

(上から見た図です。104:0.1μFセラミックコンデンサ、105:1μFセラミックコンデンサ)

LCDモジュールのリードピン(9本)は基板の裏側で半田付けし、バックライト用の端子は基板の上側からリード線を差し込み、端子および基板の裏面を半田付けします。

画像に alt 属性が指定されていません。ファイル名: IMG_5850.jpg
リードピンの配線(上の配線図とは左右反転してます)
画像に alt 属性が指定されていません。ファイル名: IMG_5852.jpg
バックライト用配線

アンプ

イヤホンで聞く仕様であればRDA5807Mの出力で十分ですが、小型のスピーカーを鳴らしたかったのでアンプ回路を入れることにしました。ネットの記事を見ると賛否両論あるようですが、単電源で2回路入りのNJM2073Dを使いました。RDA5807の出力が結構あるので、アンプの入力に半抵抗を入れて音量を調節できるようにしました。アンプの回路は、データシートに記載のある標準的なものです。

後述するスピーカーのとおり音質はあまり期待できないので、コンデンサの種類などはこだわっていません。

部品配置、配線

47mm×72mmのユニバーサル基板に部品を配置し、配線しました。RDA5807Mラジオモジュールのアンテナ(基板中央・上部にある赤線)には、適当なアンテナラインを接続します。(受信環境が悪い場所では、ケースにアンテナ端子を設けて、外部アンテナを接続することを検討してください。)私は、4.7μHのインダクタを基板上に取付け、15cm程度の被覆線を付けケース内に収めています。

ロータリーエンコーダーとの接続は、エンコーダー出力のうち両側の2本をArduinoの2番ピンと3番ピンへ、エンコーダーの接点出力の片方をArduinoの4番ピンへ、もう一方の接点出力とエンコーダー出力の中央をGNDへ接続します。

I2CのSDA、SCLは、Arduinoからの配線を図中のそれぞれの配線と接続します。

外部電源は、プラスを赤丸、マイナスを黒丸へ供給しました。USB給電としているので、5Vが供給される前提です。ArduinoとLCDには、外部電源がそのまま供給されるので、USB以外の電源を使用する際は、電圧が5V以上にならないよう気を付ける必要があります。

スピーカーとの接続は、両側の端子とそれぞれのスピーカーのプラス、中の2本の端子とそれぞれのスピーカーのマイナスと接続します。コネクタを使ったので、取り外しが楽です。

基板表面(青線は裏面配線、赤線は表面配線、緑線は裏面被覆配線)
基板裏面(青線は裏面配線、緑線は裏面被覆配線)
画像に alt 属性が指定されていません。ファイル名: IMG_5895.jpg
アンテナ用のインダクタ、スピーカー出力用のソケットは未装着です。
画像に alt 属性が指定されていません。ファイル名: IMG_5896.jpg

電源

電源は、USB給電としました。秋月電子通商さんから電源供給用のキットが発売されているので、これを使うと便利です。ケースの背面パネルに3mm程度の穴を二つあけ、USBコネクタが入る様にやすりなどで形を成形します。実際にUSBコネクタに給電し、テスターなどでプラス極とマイナス極を確認しておきます。

画像に alt 属性が指定されていません。ファイル名: DSC_0038.jpg画像に alt 属性が指定されていません。ファイル名: DSC_0042.jpg

モバイルバッテリーを使いたかったのですが、消費電力が少ないため少し時間が経過すると電源の供給が止まるものがあります。ACアダプタータイプの充電器などから、電源を供給すると良いと思います。パソコンのUSB端子と接続すると、パソコン本体に影響を与える場合があるので止めた方が賢明です。
小型の充電池と制御回路を内蔵することで、充電式のポータブルラジオに改造できると思います。

Amazon.co.jp

組み立て

正面パネルに、LCDモジュール、ロータリーエンコーダー、電源スイッチを取り付けます。
LCDモジュールの高さが25.47mmあるため、正面パネルの内側(高さ24mm)を少し削る必要があります。正面パネルの窓ですが、LCDモジュールの大きさに合わせて開けても良いのですが、今回は表示部分だけが見える大きさで窓を開けました。

画像に alt 属性が指定されていません。ファイル名: FP-1.jpg
カッターなどで、地道に削ってください。

ドリルを使って穴をぐるっと開け、開いた窓をやすりで仕上げました
画像に alt 属性が指定されていません。ファイル名: IMG_5912.jpg画像に alt 属性が指定されていません。ファイル名: IMG_5913.jpg

次に、電源スイッチ、ロータリーエンコーダーを取り付けます。電源スイッチは、手元に3接点2回路のものしかなかったので、プラス極、マイナス極とも配線しました。ロータリーエンコーダーは、あらかじめ基板から配線しておいた方が良いと思います。正面パネルの取付け穴は、現物合わせでそれぞれが干渉しないように開けました。ロータリーエンコーダーにはつまみを付けるので、この分も考慮しました。

画像に alt 属性が指定されていません。ファイル名: DSC_0044.jpg画像に alt 属性が指定されていません。ファイル名: IMG_5925.jpg

次に、基板をケースに固定します。アルミケースなので、裏面の配線と接触してショートする可能性もあることから、塩ビ板などの絶縁体を裏面に張り付け絶縁しました。強力な両面テープが市販されているので、固定にはこれを使いました。

画像に alt 属性が指定されていません。ファイル名: DSC_0033.jpg
画像に alt 属性が指定されていません。ファイル名: DSC_0034.jpg画像に alt 属性が指定されていません。ファイル名: DSC_0035.jpg

スピーカーは、天板に取付けました。スペースが限られるため、薄くて小さなものを使いました。音質は、少し犠牲になってもらいます。天板には、音が出るための穴をいくつか開けておきます。少しは音質の改善が図られるかと思い、塩ビの板でスペーサーを作って付けてあります。固定は、瞬間接着剤です。

画像に alt 属性が指定されていません。ファイル名: IMG_5920.jpg画像に alt 属性が指定されていません。ファイル名: IMG_5923.jpg
画像に alt 属性が指定されていません。ファイル名: DSC_0025.jpg画像に alt 属性が指定されていません。ファイル名: DSC_0029_1.jpg

Amazonで購入できる、こんなので良いかなと思います。

Amazon.co.jp

Arduinoにプログラムを書き込み、動作確認を行います。初期状態で周波数の変更ができます。ロータリーエンコーダーを押す毎に「登録放送局の選択:CH.**」、「音量の調整:Vol**」、「周波数の変更:FREQ」と変わります。音量の調整は、0~15まで選択できるので7くらいにセットして、実際に聞こえる音の大きさを基板上の半固定で調整しました。

調整が終わったら、部品、配線の干渉がないことを確認しながら、全体を組み立てます。

binary comment

プログラム

Arduinoのプログラムは、下のリストのとおりです。
〇RDA5807Mのライブラリは、Arduino IDEのライブラリマネージャーから、”Radio”を検索してインストールしました。Arduinoのリファレンスはこちら
〇ロータリーエンコーダーのライブラリは、こちらのサイトのものを使用させて頂きました。
〇LCDモジュール用のST7032ライブラリは、「オレ工房」さんのライブラリを使用させて頂きました。
必要に応じ、サイトからダウンロードしてお使いください。

22~33行目で放送名を、35行目でそれぞれの周波数を登録しています。お近くの放送局に書き換えて登録しておくと便利です。周波数は、MHzの値を100倍して指定します。(例:80.4MHz⇒8040)
今後、ArduinoのEEPROMに任意の放送局をメモリーできる機能を付けたいと思っています。

37行目のVOLの値は、電源投入時の音量です。

38行目のCHの値は、電源投入時の登録放送局の選択値です。

51行目の lcd.setContrast(0x0E);の値を変えると、LCDのコントラストを変えられます。

周波数の上限値、下限値をプログラムで制限していません。ラジオモジュールの仕様では、受信周波数範囲は50〜115MHzとありますので、プログラム次第では51MHz帯にFMでオンエアしているアマチュア無線局も聞こえるかもしれません。(8行目のFIX_BANDの値を変える必要があると思います。)

#include <Arduino.h>
#include <Wire.h>
#include <radio.h>
#include <RDA5807M.h>
#include <ST7032.h>
#include "Rotary.h"
// RDA5807M BAND
#define FIX_BAND RADIO_BAND_FMWORLD

// Enconder PINs
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3
#define ENCODER_SW    4
// Encoder control variables
volatile int encoderCount = 0;
// Encoder control
Rotary encoder = Rotary(ENCODER_PIN_A, ENCODER_PIN_B);

RDA5807M radio;
ST7032 lcd(0x3E);
// 登録放送局名
String STATION_NAME[11] = {"AIR-G           ",
                           "FM North Wave   ",
                           "NHK FM          ",
                           "STV Radio(FM)   ",
                           "HBC Radio(FM)   ",
                           "FM ENIWA        ",
                           "FM IRUKA        ",
                           "FM maple        ",
                           "FM HAMANASU     ",
                           "FM SHIROISHI    ",
                           "                "
                          };
// 登録放送局周波数 x100MHz
unsigned int STATION_FREQ[11] = { 8040, 8250, 8520, 9040, 9150, 7780, 8070, 7990, 7610, 8300, 0000};

int VOL = 1;
int CH = 4;     // 初期チャンネル設定
char  MODE = 0; // 0:freq, 2:ch, 3:vol
unsigned int FREQ = STATION_FREQ[CH];
String  MODE_NAME[3] = {"FREQ", "CH.", "Vol"};

void setup() {
  Wire.begin();
  // open the Serial port
  Serial.begin(57600);
  Serial.println("Radio...");
  delay(200);
  // Initialize LCD
  lcd.begin(16, 2);
  lcd.setContrast(0x0E);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("RDA5807 FM Radio");
  lcd.setCursor(0, 1);
  lcd.print("        Ver. 1.0");
  delay(3000);
  lcd.clear();

  // Initialize the Radio
  radio.init();
  radio.debugEnable();
  radio.setBand(FIX_BAND);
  radio.setFrequency(FREQ);
  radio.setVolume(VOL);
  radio.setMono(false);
  radio.setMute(false);

  lcd.setCursor(0, 1);
  lcd.print(MODE_NAME[MODE]);
  radio.setFrequency(FREQ);
  showFreq();

  // Encoder interrupt
  pinMode(ENCODER_PIN_A, INPUT_PULLUP);
  pinMode(ENCODER_PIN_B, INPUT_PULLUP);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), rotaryEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), rotaryEncoder, CHANGE);
} // setup

void loop() {
  char sw;

  while (1) {
    sw = digitalRead( ENCODER_SW );
    if ( sw == LOW ) {
      delay(200);
      MODE++;
      if ( MODE > 2 ) MODE = 0;
      lcd.setCursor(0, 1);
      lcd.print("     ");
      lcd.setCursor(0, 1);
      lcd.print(MODE_NAME[MODE]);
      if ( MODE == 1 ) showChannel();
      if ( MODE == 2 ) showVol();
    }

    if (encoderCount != 0) {
      switch (MODE) {
        // freq
        case 0:
          if (encoderCount == 1) {
            FREQ = FREQ + 10;
          }
          else {
            FREQ = FREQ - 10;
          }
          radio.setFrequency(FREQ);
          showFreq();
          encoderCount = 0;
          break;
        // ch
        case 1:
          if (encoderCount == 1) {
            CH = CH + (CH < 9);
          }
          else {
            CH = CH - (CH > 0 );
          }
          FREQ = STATION_FREQ[CH];
          radio.setFrequency(FREQ);
          showFreq();
          showChannel();
          encoderCount = 0;
          break;
        // Vol
        case 2:
          if (encoderCount == 1) {
            VOL = VOL + (VOL < 15);
          }
          else {
            VOL = VOL - (VOL > 0);
          }
          radio.setVolume(VOL);
          showVol();
          encoderCount = 0;
          break;

        default:
          break;
      }
    }
  }
} // loop

void showFreq() {
  int i;
  char  disp[17];
  char  freq[7];
  bool CH_FLG;

  for ( i = 0 ; i < 17 ; i++ ) {
    if ( i < 7 ) freq[i] = 0 ;
    disp[i] = 0;
  }

  sprintf(freq, "%5d", FREQ);
  freq[5] = freq[4];
  freq[4] = freq[3];
  freq[3] = '.';
  sprintf(disp, " %sMHz", freq);
  lcd.setCursor(6, 1);
  lcd.print(disp);
  CH_FLG = false;
  for ( i = 0 ; i < 10 ; i++ ) {
    if ( FREQ == STATION_FREQ[i] ) {
      CH = i;
      CH_FLG = true;
      break;
    }
  }
  lcd.setCursor(0, 0);
  if ( CH_FLG == true) {
    lcd.print(STATION_NAME[CH]);
  }
  else {
    lcd.print("                ");
  }
}

void showChannel() {
  int i;
  char  disp[17];
  char  ch_num[3];

  for ( i = 0 ; i < 17 ; i++ ) {
    if ( i < 3 ) ch_num[i] = 0;
    disp[i] = 0;
  }

  sprintf(ch_num, "%2d", CH + 1);
  lcd.setCursor(3, 1);
  lcd.print(ch_num);
  lcd.setCursor(0, 0);
  lcd.print(STATION_NAME[CH]);
}

void showVol() {
  int i;
  char  num_vol[3];

  for ( i = 0 ; i < 3 ; i++) num_vol[i] = 0;
  sprintf(num_vol, "%2d", VOL);
  lcd.setCursor(3, 1);
  lcd.print(num_vol);
}

void rotaryEncoder() {
  uint8_t encoderStatus = encoder.process();
  if (encoderStatus)
    encoderCount = (encoderStatus == DIR_CW) ? 1 : -1;
}
// End.

最後までご覧いただき、ありがとうございます。良かったら、この記事を参考にFMラジオを作ってみては如何でしょうか。自作のラジオから、放送局の音が聴こえたときの感動はなかなかのものです。

制作の過程はYouTubeにもアップしていますので、良かったらご覧ください。

ご質問などありましたら、こちらからお問い合わせください。可能な限り、お答えいたします。

コメント

  1. Farhad より:

    Wonderful! I made a copy of your FM radio and it works just fine. I made some changes to the code so it shows RSSI now + I had to change the LCD with a 16×2 one. Thank you so much. Keep creating new gadgets!

PAGE TOP