トップページへ    電子工作の目次へ
    FM ラジオ自作

IC の入手
 
2019 年秋、古河アマチュア無線クラブ のお仲間からFM ラジオ用 IC RDA5807M と制御プログラムを書き込んだ PIC12F1501 を分けてもらいラジオの組み立て配線をしました。

RDA5807M は 小さな基盤の上に32.768KHz 水晶発振子と共に組み込まれています。
DIP IC のようなピンは無く、側面に2mm ピッチで配線用クボミが付いた構造です。

ラジオというと周波数変換とか中間周波数増幅、検波などのラインがすぐ頭に浮かびますがこのラジオはそのような構造ではありません。でも近隣の放送局は良く聞こえます。

RDA5807M の基板は下の写真の通りで、概略 12mm x 12mm の大きさです。

 
 

下の写真右、RDA5807M を基板に乗せ脚ピンを付けました。
2mm ピッチで扱いずらいです。  左は PIC12F1501 です。
 

試 作

 ブレッドボード上に配線を展開、完成させました。
ところが音が全く出ません。RDA9807M をピンへ取り付けたハンダ付け不良でした。

ラジオとして動かすためのソフトウエアは PIC12F1501 に書き込まれているので配線するだけで製作完了しました。 ソフトウエアはインターネット上に公開されている「from Metal Woods」さんのアッセンブラ・プログラムです。

RDA5807M の英文データシート(Rev 1.8-Aug.2014)はインターネット上に公開されています。
ヘッドフォンのケーブルをアンテナ代わりにする方法が提示されていたので、コイルを自作し試してみました。
ヘッドフォンンは32Ωのものを使いました。 RDA5807M の出力にうまく合うようです。

下の写真は組み立て配線が完了したものです。

 
回路図を下に示します。 ヘッドフォンのケーブルがアンテナになります。


2号機の製作

自分流のプログラムを作ってみようと思い開発基盤を組み立てました。
PIC12LF1822 を使いプログラムはCコンパイラを使うことにしました。

PIC12LF1822 は和文データシートが入手できたことと、I2C シリアル通信プログラムが容易なMSSP(Master Synchronous Serial Port)モジュールがあるので使いやすいと思いました。

ただこの PIC はピンの数が少ないのでプログラム書込みや I2C 用ピンと共用する部分があるのでプログラム書込みとラジオとして使用するためには切換スイッチが必要になりました。

I2C の回路はプルアップしなければなりませんが、プログラム書込み用の ICD 3 は内部でプルダウンされているのです。

2号機は配線がアフロヘアーみたいにならないよう配慮しました。写真の通り、すっきりしています。

上の写真左から

  ・3.3V 電源コンセントと電源表示 LED
  ・LCD 表示器 AQM0802A 8文字 x 2行表示
  ・ラジオ用 IC RDA5807M と同調コイル
  ・低消費電力型 PIC12LF1822
  ・3.3V 400mW シングル・パワーアンプ BU7150NUV
  ・ステレオ・ヘッドフォンジャック(ヘッドフォン使用時はバワーアンプ入力配線を外す)

PICの回路部分は穴あき基盤上に組み立てました。将来他への転用が出来そうです。

音量調節は押ボタンスイッチで15段階に変更できます。

放送局の周波数をバンクに切換計算するのに机上の手間は要りません。
周波数を替えればプログラム上で計算が行はれます。

上はブレッドボードで仕上げた回路図です。
 
 
 アンテナコイルを作りました。約 82.5MHz あたりで共振しています。

 
PIC12LF1822 は基板から着脱しないでプログラムの書込みと作動テストができます。
プログラムの追加・変更の際は便利です。

FM 放送受信中は ICD 3 を外さないとノイズが多いようです。


 RD5807M のチップアドレス

I2C でスレーブ(RDA5807M) のレジスタにデータを書き込むためにはスレーブのチップアドレスが必要です。
RDA5807M の英文資料 Control Interface ではチップアドレスは 0010000b と書いてあります。
この値に I2C マスター(PIC)からの送信を指定する「0」を末尾に追加し
   0010000b (0x10)  は 00100000b (0x20) として I2C で送信設定することになります。

この 0x20 を使ってプログラムを書きましたが RDA5807M は動作しませんでした。

一時はもうやめようかと思いましたが完成したハードウエアが机の上から睨んでいます。
ネット上をいろいろ調べたらやはりお困りの方が居るようでした。

RDA5807M にはデータシートに書かれていない隠れチップタアドレス 0x11 が有るのを知りました。
I2C でマスターから送信する場合は 0010001b の末尾に「0」を付けるようになっています。
値は左1ビットシフト +0 で 00100010b (0x22) となります。

チップアドレス 0x20 を使う場合はプログラムを次のように各レジスタの番号順にデータを記述送信します。各レジスタの番号は送信しません。

i2cStart(); // 送信開始
i2cTxData(0x20); // Chipアドレス
RDA5807M_Write(0xD001); // 02 レジスタ
RDA5807M_Write(0x1058); // 03 レジスタ
RDA5807M_Write(0x0000); // 04 レジスタ
RDA5807M_Write(0x0000); // 05 レジスタ
i2cStop(); // 送信終了

一般的には下記のように各レジスタにデータを書き込む使い方が多いのです。
この場合、チップアドレス 0x22 は各レジスタ番号とそのレジスタに入れるデータ等を一緒に記述します。

i2cStart(); // 送信開始
RDA5807M_Write(0x22, 0x02, 0xD001); // クロック設定
RDA5807M_Write(0x22, 0x03, 0x1058); // NHK 東京 FM
RDA5807M_Write(0x22, 0x04, 0x0000); // AFC 有効
RDA5807M_Write(0x22, 0x05, 0x888F); // 音量最大
i2cStop(); // 送信終了

RDA5807M のレジスタは 06, 07, 08 - - - と多くあるのですが 02 - - 05 までのレジスタにデータを書き込めばラジオとして機能するようです。

余談ですが使用した LCD 表示器 AQM0802A は 表示されているチップアドレス 0x7C がマスタからの送信する値になっているので、そのまま I2C 送信プログラムへ書き込みができます。


FM ラジオ試作プログラム

Cプログラムをホームページビルダーで表示しました。
プログラム中のインデントが無くなり コマンド と //コメント が密着した状態になっています。
HTML の <pre> --- </pre> で改修しようとしましたが PDF を掲載しました。
                                  2020.5.11、同 5.31 本文改訂

プログラム・ファイル (PDF)

 /*******************************************************************
RDA5807M - PIC12LF1822  FM ラジオ
DSPRX0C_RDA01.C  April 26, 2020 by JA1HHF
受信周波数:FM 76.0 --- 108.0 MHz
MPLAB XC8 C Compiler v2.10 & ICD 3
*******************************************************************/

// ********************* 受信機能設定 ********************************
#define SWs (PORTA|0b11000110) // SW 4ケの状態
#define VolDn !PORTAbits.RA5 // SW 音量 下げる
#define VolUp !PORTAbits.RA4 // SW 音量 上げる
#define stationDn !PORTAbits.RA3 // SW 選局 下向き
#define stationUp !PORTAbits.RA0 // SW 選局 上向き
// RA2 = I2C SDA
// RA1 = I2C SCL

// ********************* 使用 PIC (PIC12LF1822) **********************
#include <xc.h>

// ******************* コンフィグレーション *****************************
// CONFIG1
#pragma config FOSC = INTOSC // 内蔵オシレータ選択
#pragma config WDTE = OFF // ウヲッチドグ無効
#pragma config PWRTE = OFF // パワーアップタイマ無効
#pragma config MCLRE = OFF // MCLR ピンはデジタル入出力
#pragma config CP = OFF // コードプロテクト無効
#pragma config CPD = OFF // データメモリの保護は無効
#pragma config BOREN = ON // ブラウナウトリセット無効
#pragma config CLKOUTEN = OFF // クロックアウト機能無効
#pragma config IESO = OFF // 内部/外部スイッチオーバモード無効
#pragma config FCMEN = OFF // クロック監視無効
// CONFIG2
#pragma config WRT = OFF // プログラムメモリ書込保護 OFF
#pragma config PLLEN = OFF // PLL x 4 無効
#pragma config STVREN = ON // スタックオーバリセット有効
#pragma config BORV = LO // ブラウンアウト電圧 LOW
#pragma config LVP = OFF // 低電圧プログラミング無効

// ******************* 定 義 *****************************************
#define _XTAL_FREQ 4000000 // PICの内部発振周波数 4MHz に設定
#define CONTRAST 0x28 // Vcc = 3.3V の LCD コントラスト設定

// ******************* プロトタイピング *********************************
void RDA_Write(unsigned char, unsigned int); // RDA5807M 書込み用
void Freq_set(int); // 設定周波数
void RX_Disp(char); // 放送局名と周波数表示
void i2cTxData(char); // I2C 1文字保存書込送信用
void i2cintl(void); // I2C 初期設定用
void i2cLcdWrite(char, char, char); // LCD I2C 初期化
void LCD_dat(char); // LCD データ入力
void LCD_cmd(char); // LCD コマンド入力
void LCD_clr(void); // LCD クリヤ
void LCD_int(void); // LCD 初期化
void LCD_ROMstr(const char *str); // LCD 表示文字
void LCD_ROM2str(const char *str); // LCD 2行目表示文字

// ************* EEROM に設定する番号 *********************************
__EEPROM_DATA (0,15,0,0,0,0,0,0); //0番地:局、1番地:音量

// ******************* メインプログラム *********************************
void main() {
__delay_ms(100); // 起動遅延
signed char stn; // 受信局の番号 stn
signed char vol; // 音量段階 vol

// PIC の設定 --------------------------------------------------------
OSCCON = 0b01101010; // 内部クロック4MHz
PORTA = 0x00; // PortA クリヤ
TRISA = 0xFF; // PortA すべて入力
ANSELA = 0x00; // すべてデジタル
WPUA = 0x00; // 弱プルアップ OFF
IOCAN = 0b00111001; // スイッチ入力状態変化割込み
INTCONbits.IOCIE = 1; // 状態変化割り込有効

// I2C 初期化 ---------------------------------------------------------
SSP1CON1 = 0b00001000; // I2C Master modeにする
SSP1CON2 = 0x00; // PowerOn初期値にする
SSP1STAT = 0b10000000; // スルーレート制御は無効
SSP1ADD = 9; // クロックの設定 100k@4MHz
SSP1CON1bits.SSPEN = 1; // SDA と SCL 有効にする

// EEPROM 読出し -----------------------------------------------------
stn = eeprom_read(0); // 起動時受信局番号
vol = eeprom_read(1); // 起動時音量

// LCD 初期化 --------------------------------------------------------
LCD_int();

// RDA5807M 初期化 --------------------------------------------------
RDA_Write(0x02, 0x1001); // 音量ミュート
RDA_Write(0x03, 0x0008); // チューン無効
RDA_Write(0x04, 0x0000); // AFC 有効
RDA_Write(0x05, 0x8880 + vol); // 音量
RX_Disp(stn); // 受信設定とLCD 表示
__delay_ms(100); // 遅延
RDA_Write(0x02, 0xD001); // 音声
__delay_ms(100); // 遅延

// 選局と音量調節スイッチ操作 -------------------------------------------
while(1){
while(SWs == 0xFF); // SW が押されるのを待つ
__delay_ms(5); // チャタリング防止

// 受信局を変更 (上向き)------------------------------------
if(stationUp){
stn += 1; // 局番号変更 stn + 1
if(stn > 7)stn = 0; // 局番号を上向き変更
RX_Disp(stn); // 放送局選定とLCD表示
eeprom_write(0, stn); // EEPROM 0番地に stn 書込み
}

// 受信局を変更(下向き)-------------------------------------
if(stationDn){
stn -= 1; // 局番号変更 stn - 1
if(stn < 0)stn = 7; // 局番号を下向き変更
RX_Disp(stn); // 放送局選定とLCD表示
eeprom_write(0, stn); // EEPROM 0番地に stn 書込み
}

// 音量を大きくする (チップの機能は 15段階)-----------------------
if(VolUp){
vol += 1; // 音量を上げる vol + 1
if(vol > 15)vol = 15; // 上限の確認
RDA_Write(0x05,0x8880 + vol); // 音量をセット
eeprom_write(1, vol); // EEPROM 1番地にvol書込み
}

// 音量を小さくする ------------------------------------------
if(VolDn){
vol -= 1; // 音量を上げる vol - 1
if(vol < 0)vol = 0; // 下限の確認
RDA_Write(0x05,0x8880 + vol); // 音量をセット
eeprom_write(1, vol); // EEPROM 1番地にvol書込み
}
IOCAF = 0; // PORTA 状態変化割込み可
SLEEP(); // SW-ON 無ければスリープ
}
}
// ******************* メインプログラム終わり **************************

//******** 受信周波数設定、局名と周波数を LCD に表示 ******************
void RX_Disp(char stn_num){
LCD_clr();

switch(stn_num){
case 0: Freq_set(7950);
LCD_ROMstr("NACK5"); LCD_ROM2str("79.5MHz"); break;
case 1: Freq_set(8000);
LCD_ROMstr("TOKYO-FM"); LCD_ROM2str("80.0MHz"); break;
case 2: Freq_set(8130);
LCD_ROMstr("J-WAVE"); LCD_ROM2str("81.3MHz"); break;
case 3: Freq_set(8250);
LCD_ROMstr("NHK-FM"); LCD_ROM2str("82.5MHz"); break;
case 4: Freq_set(8630);
LCD_ROMstr("FM-GUNMA"); LCD_ROM2str("86.3MHz"); break;
case 5: Freq_set(9050);
LCD_ROMstr("TBS-FM"); LCD_ROM2str("90.5MHz"); break;
case 6: Freq_set(9160);
LCD_ROMstr("BUNKA-FM"); LCD_ROM2str("91.6MHz"); break;
case 7: Freq_set(9300);
LCD_ROMstr("NIPPON"); LCD_ROM2str("93.0MHz"); break;
default: break;
}
}

// *************** I2C 関連の関数 **********************************
// I2C スタートコンディション ------------------------------------------
void i2cStart(){
SSP1IF = 0;
SSP1CON2bits.SEN = 1; // I2C スタート
while (SSP1IF == 0) {}
SSP1IF = 0;
}

// I2C ストップコンデション --------------------------------------------
void i2cStop(){
SSP1IF = 0;
SSP1CON2bits.PEN = 1; // I2C ストップ
while (SSP1IF == 0) {}
SSP1IF = 0;
}

// I2C で RDA5307M のレジスタに書込む --------------------------------
void RDA_Write(unsigned char add, unsigned int data) {
i2cStart(); // I2C スタート
i2cTxData(0x22); // Chipアドレス送信
i2cTxData(add); // RegAddress
i2cTxData(data >> 8); // Register data MSB
i2cTxData(data & 0xff); // Register data LSB
i2cStop(); // I2C ストップ
__delay_us(500);
}

// I2C で LCD のレジスタに書込む -------------------------------------
void i2cLcdWrite(char addr, char cont, char data){
i2cStart(); // I2C スタート
i2cTxData(addr); // アドレス送信
i2cTxData(cont); // 制御コード送信
i2cTxData(data); // データ送信
i2cStop(); // I2C ストップ
}

// I2C で SSP1BUF に1文字保存し送信終了を待つ -------------------------
void i2cTxData(char data){
PIR1bits.SSP1IF = 0; // 終了フラグクリア
SSP1BUF = data; // データセット
while(!PIR1bits.SSP1IF); // 送信終了待ち
}

//********* 新周波数設定 *******************************************
void Freq_set(int freq){
signed int reg_val;
reg_val=(freq - 7600)/10; // 受信チャンネル計算
RDA_Write(0x03, (reg_val << 6) + 0x18); // 計算値を書込む 
__delay_ms(100);
}

//********* LCD 関連 **********************************************
// 1文字表示 -------------------------------------------------\\---
void LCD_dat(char chr){
i2cLcdWrite(0x7C, 0x40, chr);
__delay_us(50); // 50μsec 遅延
}

// コマンド出力 -----------------------------------------------\\\---
void LCD_cmd(char cmd){
i2cLcdWrite(0x7C, 0x00, cmd);
if(cmd & 0xFC) // Clear と Home でない場合
__delay_us(50); // 50usec 遅延
else // Clear と Home の場合
__delay_ms(2); // 2msec 遅延
}

// 全消去 --------------------------------------------------------
void LCD_clr(void){
LCD_cmd(0x01); //Clearコマンド出力
}

// LCD 初期化 ----------------------------------------------------
void LCD_int(void){
__delay_ms(100);
LCD_cmd(0x38); // 8bit 2行 表示命令モード
LCD_cmd(0x39); // 8bit 2行 拡張命令モード
LCD_cmd(0x14); // OSC BIAS 設定1/5
// コントラスト設定
LCD_cmd(0x70 + (CONTRAST & 0x0F));
LCD_cmd(0x5C + (CONTRAST >> 4));
LCD_cmd(0x6B); // Ffollwer
__delay_ms(200);
LCD_cmd(0x38); // 表示命令モード
LCD_cmd(0x0C); // Display On
LCD_cmd(0x01); // Clear Display
}

// LCD Rom 文字列 1 行目出力 --------------------------------------
void LCD_ROMstr(const char *str){
while(*str) //文字列の終わり(00)まで継続
LCD_dat(*str++); //文字出力しポインタ+1
}

// LCD Rom 文字列 2 行目出力 --------------------------------------
void LCD_ROM2str(const char *str){
LCD_cmd(0xC0);
while(*str) //文字列の終わり(00)まで継続
LCD_dat(*str++); //文字出力しポインタ+1
}
// ******************* 全プログラムの終わり *************************

/* 付 記 */
/* [1] 周波数(バンク)の設定 **********
RDA5807M への受信周波数(バンク)書込み説明
関数 void Freq_set(int freq)で自動計算して書き込まれます。
放送局 NHK-FM 82.5 MHz の例
周波数を 10KHz 単位にすると 8250, 最低周波数は 7600 (76.0 MHz)
受信周波数バンク = (8250 - 7600)/10 = 65
10進数 65 を 2進数で表示すると   1000001
RDA5807M の 0x03 レジスタ 0x00000000 00000000 では
6 ビット左寄せした部分に計算した周波数バンクの値を入れるので
            0x00010000 01------ となります。
5--0 ビットには周波数帯などの値を入れます。
その値を  01100 に設定すると
0x03 レジスタに書込む値は 0x00010000 01001100 となります。
計算は全てプログラム内で自動的に行われる
*/

/* [2] PIC について **********
このプログラムでは PIC12LF1822 を使用していますが
プロジェクトを作る際 PIC12F1822 に変更することができます。
*/

/* [3] 音量調節 **************
RDA5807M の音量は 0--15 段階で調節できます。
音量は対数曲線的な変化で音量を上げていくとあまり変化を感じなせん。
*/

/* [4] 受信ノイズ ************
RDA5807M は 外部ノイズに弱い
LED 電気スタンドやインバータ電源など家電製品のそばで使うとノイズを拾うようです。
プログラム書込みに使用する ICD 3 はテスト受信時取り外した方がよいでしょう。
*/

/* [5] ソルダレスブレッドボード **********
大型ブレッドボード使用で電源取り入れ部より離れた個所に消費電流の
大きい AF アンプを使用すると音声のピークで LCD 等が点滅することあります。
電源回路に 1,000μF 程度の電解コンデンサを付けると解消できる場合があります。
*/
3号機の製作

ブレッドボードで組み立てて「動いた」で終わってしまう場合が多くあります。
別の工作をしたいため気分が次へ行ってしまうのでしょう。

今回は手持ちの部品を使ってプラケースに入れたFMラジオを作ってみました。
上の写真は3号機完成品の内部です。
プリアンプを内蔵しています。 LCD表示器はソケットから取り外した状態です。実際には下の写真の様になります。

構成はモノラルアンプ出力、音量調節は可変抵抗器による無段階調整です。
選局はロータリーエンコーダを使用しました。

上の写真は完成品、LCD表示器をセットしてプラケースのフタを取り付けたものです。
銘板はケースのフタの裏側に貼り付けたので剥がれたり汚れたりしません。

主仕様
受信周波数 76〜108 MHz
電源電圧  3.3 V

使用パーツ
プリアンプ : 2SK192A
RX IC    : RDA5807M
制御 IC   : PIC12LF1822 (プログラム自作)
AF Amp   : APM8012 (モノラル)
表示 LCD : AQM0802A (2行8文字)

FM局選択に使用したロータリーエンコーダ(ケース表面銘板:SEL)です。
少し古いタイプですがガッチリしています。 最近は小型のものが市販されているようです。
上は3号機の回路図を示します。
音量調節を直接VRで行うためPICのリセットピン MCLRを有効にすることができました。
 
3号機のプログラム(PDF)
 
履歴
2020.04.30 アップロード
2020.05.11 改訂
2020.05.13 1号機の写真取替
2020.08.19 3号機の製作追加 ・ 本文一部改訂