無線ブログ集
メイン | 簡易ヘッドライン |
RDA5708Mモジュール50MHz受信器その1 (2024/2/27 7:23:16)
FMラジオの受信用として、とても安い価格のRDA5807Mモジュールをアマゾンで3個のものを注文し入手してあったので、試しにArduinoNANOで50MHzのFM受信機をスケッチし作製してみることにしました。
この価格でも安いですが、以前はこれよりもかなり安かったようです。
元々FMラジオ用として使用するものですが、データシートを確認してみると、レジスターアドレス03Hの2ビットめ3ビットめの2つのビットの設定でバンドセレクト(各国のFM周波数帯選択)ができるようになっています。下記のなかの11の設定で試してみるという方法で確認しました。結果から言うと、実際の受信できる周波数範囲はバンドセレクトの仕様とは異なり、受信感度も問題なく45.60MHzから119.60MHzと言う仕様よりも広範囲な受信周波数範囲で受信ができました。FMのインプットレンジが全部対応という事です。(仕様ではMIN:50MHzーMAX:115MHz)また、感度も50MHzではS/N=26dBで標準で1.4μV(EMF)という仕様の様です。びっくりです。
00:87-108MHz(US/Europe)
01:76-91MHz(Japan)
10:76-108MHz(World wide)
11:65-76MHz(East Europe) or
50-65MHz
このモジュールの取り付けピッチは2mmで通常の2.54mmのピッチに変換すると
ボードで使用できるので変換用に蛇の目基板を使い変換しています。時間をかけて半田ゴテをあててしまい、1個はモジュール側のメッキ部が取れて半田付けができなくなり失敗してしまいました。注意点として、早めの半田付のテクニックがいるかと思います。Hi!
ArduinoNANOを使いましたがArduinoUnoでも問題なく使用できます。
50MHz帯は51MHzからFMバンド帯なので起動時の周波数は51.00MHzに設定してあります。
ロータリーエンコーダ1クリックアップ時では、ステップ10KHzで、51.01MHzとなります。
今回のアマチュア無線バンドの50MHz帯の受信器の実験の参考にしたホームページは下記です。
面白いのは、レジスター60Hに書き込むとRDA5807Mで50MHzでも動かせるというものです。この隠しコマンドがあるということで、50MHz帯が受信できるように設定できるというものです。
他、スケッチのフレームとしてロータリーエンコーダ化も必要なので外国のアマチュア無線家 PU2CLR 局が作製してるデータを参考にしました。この局は他のDSPハード(SI4732)でSSB受信化できるライブラリを作った作者で、NETには数多くのDSPライブラリを使用した受信機の制作ページがありました。とても興味をそそる記事がたくさんあるようです。いつか試しにハードウェアを注文し確認してみたいと思います。ライブラリは基本的なもので改良、改変はOKとのことです。Hi! 今回はハードウェアはRDM5807なのでGithubに数多くデータを公開している中の、RDA5807_07_NANO_OLEDを参考に使用しました。また、表示DISPLAYは異なるものでしたので、手持ちのOLEDタイプのSD1306ASCiiのI2cタイプに変更してあります。
今回は単純にロータリーエンコーダーで周波数を10KHzステップで受信する機能のみです。ArduinoNANOにつなぐSWポートのD4、D5、D6、D14、D7の各ポートは設定のみです。スケッチはまだありません。(機能を付けてません。)ハード上追加できる機能としては上記のポートに対応してボリュームUP、ボリュームDOWN、オーディオMUTE、受信信号スキャン、オーディオBASSセットなどがあるのですが、他のハード用(ATtiny84)でしたので、今回の使用のハード用に下記のWireコマンドでソフトウェア設定する必要があります。機能追加するには、RDA5807Mのデータシートを確認しながらテストする必要があります。今後の検討課題としてあります。
Wire.beginTransmission(0x**);
Wire.write(0x**);
〜
Wire.endTransmission();
下記は50MHz帯のFM信号をロータリーエンコーダで10KHzステップで変えて受信するという機能のみのスケッチです。メインとなっているのは、アップダウンのスケッチ部です。
PU2CLR局が使用したハード(ATtiny84)がArduinoNANOと異なるのでスケッチで変えたところはレム化し、残してあります。また使用していない変数設定も一部アリます。Hi!
/*
Test and validation of RDA5807 on UNO/NANO or other ATMEGA328 based device.
It is FM receiver with
Nano and RDA5807 wireup
Wire up on Arduino UNO, Nano or Pro mini
| Device name | Device Pin / Description | Arduino Pin |
|-----------------------|-----------------------------------|------------ |
| OLED - I2C | | |
| | SDA | A4 |
| | SCLK | A5 |
| ----------------------|-----------------------------------|-------------|
| RDA5807 | | |
| | SDA/SDIO | A4 |
| | SCLK (Clock) | A5 |
| ----------------------| ----------------------------------|-------------|
| Buttons | | |
| | Volume Up | 4 |
| | Volume Down | 5 |
| | Mute | 6 |
| | Bass | 7 |
| | SEEK (encoder button) | D14/A0 |
| --------------------------| ------------------------------|-------------|
| Encoder | | |
| | A | 2 |
| | B | 3 |
By Ricardo Lima Caratti, 2020.
*/
#include "src/SSD1306AsciiAvrI2c.h"
#include "src/SSD1306Ascii.h"
SSD1306AsciiAvrI2c oled;
#define I2C_ADDRESS 0x3C //0x3C,0x3A
#define FIX_VOLUME 4
#include <Wire.h>
#include <TEA5767Radio.h>
TEA5767Radio rx;
//#include <Tiny4kOLED.h>
//#define RDA_FM_BAND_SPECIAL 3 //!< 65 –76 MHz(East Europe) or 50 - 65MHz(see bit 9 of gegister 0x07)
#include "Rotary.h"
// Please, check the ATtiny84 physical pins
#define VOLUME_UP 4
#define VOLUME_DOWN 5
#define AUDIO_MUTE 6
#define AUDIO_BASS 7
#define SEEK_STATION 14 // A0 = D14
// Enconder PINs
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3
bool bBass = false;
bool bMute = false;
volatile int encoderCount = 0;
int encorderCount = 0;
uint8_t seekDirection = 1; // 0 = Down; 1 = Up. This value is set by the last encoder direction.
long elapsedTimeEncoder = millis();
// Encoder control
Rotary encoder = Rotary(ENCODER_PIN_A, ENCODER_PIN_B);
unsigned char frequencyH=0;
unsigned char frequencyL=0;
unsigned int frequencyB;
double frequency=0;
double freq_available=0; //receivef
int b=0;
int c=0;
int d=0;
int e=0;
int f=0;
void setup()
{
pinMode(ENCODER_PIN_A, INPUT_PULLUP);
pinMode(ENCODER_PIN_B, INPUT_PULLUP);
// Push button pin
//#define VOLUME_UP 4
//#define VOLUME_DOWN 5
//#define AUDIO_MUTE 6
//#define AUDIO_BASS 7
#define SEEK_STATION 14 // A0 = D14
pinMode(VOLUME_UP, INPUT_PULLUP); //D4
pinMode(VOLUME_DOWN, INPUT_PULLUP); //D5
pinMode(AUDIO_MUTE, INPUT_PULLUP); //D6
pinMode(AUDIO_BASS, INPUT_PULLUP); //D7
pinMode(SEEK_STATION, INPUT_PULLUP); //D14
oled.begin(&Adafruit128x64,I2C_ADDRESS);
//oled.begin();
oled.clear();
//oled.on();
oled.setFont(Adafruit5x7);
// oled.setFont(FONT8X16);
oled.set2X();
oled.setCursor(0, 10);
oled.println("RDA5807OLED");
oled.setCursor(0,40);
oled.println("By PU2CLR ");
oled.setCursor(0,90);
oled.println("Modefy By");
oled.setCursor(0,140);
oled.println(" JL7GMN");
delay(3000);
oled.clear();
/*
Reads encoder via interrupt
Use Rotary.h and Rotary.cpp implementation to process encoder via interrupt
*/
// Encoder interrupt
attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), rotaryEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), rotaryEncoder, CHANGE);
// frequency initialize -------------------------------------------------
frequency=51.00; //starting frequency ABALABLE MIN 45.60MHz TO MAX 119.60MHz
frequencyB=4*(frequency*1000000+225000)/32768; //calculating PLL word
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;
delay(100);
//tune set to 0
Wire.beginTransmission(0X10); //continuous write
//no need to specify register
Wire.write(0X00); // 02h(HighByte02) DMUTE0
Wire.write(0X00); // 02l(LowByte02)
Wire.write(0X00); // 03h
Wire.write(0X00); // 03l TUNE0 ENABLE0
Wire.endTransmission();
Wire.beginTransmission(0x60); //writing TEA5767
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x00);// F0->10
Wire.write(0x00);
Wire.endTransmission();
/*
Wire.beginTransmission(0X11); //normal i2c
Wire.write(0X05); // specify register 05h
Wire.write(0X88); // 05h
Wire.write(0b10001000); // 05l VOLUMExxxx
Wire.endTransmission();
*/
//radio.setVolume(15);
//oled.setFont(Adafruit5x7);
oled.setFont(X11fixed7x14B);
oled.clear();
oled.setCursor(1, 0);
;
delay(10);
//----------------------------------------------------------
showStatus();
}
void rotaryEncoder()
{ // rotary encoder events
uint8_t encoderStatus = encoder.process();
if (encoderStatus)
encoderCount = (encoderStatus == DIR_CW) ? 1 : -1;
}
void showStatus()
{
;
oled.set2X();
oled.setCursor(0, 0);
oled.println("FM ");
oled.setCursor(0, 95);
oled.println(" ");
oled.setCursor(0, 95);
oled.set2X();
oled.print(frequency);
oled.setCursor(75, 75);
oled.println("MHz");
}
void loop()
{
oled.set1X();
// Check if the encoder has moved.
if (encoderCount != 0)
{
if (encoderCount == 1)
{
// seekDirection = RDA_SEEK_UP;
//frequency=(freq_available/1000000)+0.05; //f=receivef+0.05
frequency=(frequency+(freq_available/1000000)+0.01); //f=receivef+0.05
frequencyB=4*(frequency*1000000+225000)/32768+1;
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;
//tune set to 0
Wire.beginTransmission(0X10); //continuous write
//no need to specify register
Wire.write(0X00); // 02h(HighByte02) DMUTE0
Wire.write(0X00); // 02l(LowByte02)
Wire.write(0X00); // 03h
Wire.write(0X00); // 03l TUNE0 ENABLE0
Wire.endTransmission();
Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x00);//Wire.write(0x1F);
Wire.write(0x00);
//Wire.write(0x88); // 05h
//Wire.write(0x81); // 05l volulme001
Wire.endTransmission();
//////////////////////
b=100;
}
else
{
// seekDirection = RDA_SEEK_DOWN;
//frequency=(freq_available/1000000)-0.05; //f=receivef-0.05
frequency=(frequency+(freq_available/1000000)-0.01); //f=receivef-0.05
frequencyB=4*(frequency*1000000+225000)/32768+1;
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;
//tune set to 0
Wire.beginTransmission(0X10); //continuous write
//no need to specify register
Wire.write(0X00); // 02h(HighByte02) DMUTE0
Wire.write(0X00); // 02l(LowByte02)
Wire.write(0X00); // 03h
Wire.write(0X00); // 03l TUNE0 ENABLE0
Wire.endTransmission();
Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0x30);
Wire.write(0x00);//Wire.write(
// rx.setVolume(15);
//TEA5767Radio::setVolume(15);0x1F);
Wire.write(0x00);
//Wire.write(0x88); // 05h
//Wire.write(0x81); // 05l volulme001
Wire.endTransmission();
c=100;
}
showStatus();
encoderCount = 0;
}
else if (digitalRead(VOLUME_UP) == LOW) // D4
{;// rx.setVolumeUp();
}
else if (digitalRead(VOLUME_DOWN) == LOW) // D5
{;// rx.setVolumeDown();
}
else if (digitalRead(AUDIO_MUTE) == LOW) // D6
{;// rx.setMute(bMute = !bMute);
}
else if (digitalRead(SEEK_STATION) == LOW) //D14
{ ; // rx.seek(RDA_SEEK_WRAP, seekDirection, showStatus); // showFrequency will be called by the seek function during the process.
delay(200);
}
else if (digitalRead(AUDIO_BASS) == LOW) //D7
{;// rx.setBass(bBass = !bBass);
delay(50);
}
}
Test and validation of RDA5807 on UNO/NANO or other ATMEGA328 based device.
It is FM receiver with
Nano and RDA5807 wireup
Wire up on Arduino UNO, Nano or Pro mini
| Device name | Device Pin / Description | Arduino Pin |
|-----------------------|-----------------------------------|------------ |
| OLED - I2C | | |
| | SDA | A4 |
| | SCLK | A5 |
| ----------------------|-----------------------------------|-------------|
| RDA5807 | | |
| | SDA/SDIO | A4 |
| | SCLK (Clock) | A5 |
| ----------------------| ----------------------------------|-------------|
| Buttons | | |
| | Volume Up | 4 |
| | Volume Down | 5 |
| | Mute | 6 |
| | Bass | 7 |
| | SEEK (encoder button) | D14/A0 |
| --------------------------| ------------------------------|-------------|
| Encoder | | |
| | A | 2 |
| | B | 3 |
By Ricardo Lima Caratti, 2020.
*/
#include "src/SSD1306AsciiAvrI2c.h"
#include "src/SSD1306Ascii.h"
SSD1306AsciiAvrI2c oled;
#define I2C_ADDRESS 0x3C //0x3C,0x3A
#define FIX_VOLUME 4
#include <Wire.h>
#include <TEA5767Radio.h>
TEA5767Radio rx;
//#include <Tiny4kOLED.h>
//#define RDA_FM_BAND_SPECIAL 3 //!< 65 –76 MHz(East Europe) or 50 - 65MHz(see bit 9 of gegister 0x07)
#include "Rotary.h"
// Please, check the ATtiny84 physical pins
#define VOLUME_UP 4
#define VOLUME_DOWN 5
#define AUDIO_MUTE 6
#define AUDIO_BASS 7
#define SEEK_STATION 14 // A0 = D14
// Enconder PINs
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3
bool bBass = false;
bool bMute = false;
volatile int encoderCount = 0;
int encorderCount = 0;
uint8_t seekDirection = 1; // 0 = Down; 1 = Up. This value is set by the last encoder direction.
long elapsedTimeEncoder = millis();
// Encoder control
Rotary encoder = Rotary(ENCODER_PIN_A, ENCODER_PIN_B);
unsigned char frequencyH=0;
unsigned char frequencyL=0;
unsigned int frequencyB;
double frequency=0;
double freq_available=0; //receivef
int b=0;
int c=0;
int d=0;
int e=0;
int f=0;
void setup()
{
pinMode(ENCODER_PIN_A, INPUT_PULLUP);
pinMode(ENCODER_PIN_B, INPUT_PULLUP);
// Push button pin
//#define VOLUME_UP 4
//#define VOLUME_DOWN 5
//#define AUDIO_MUTE 6
//#define AUDIO_BASS 7
#define SEEK_STATION 14 // A0 = D14
pinMode(VOLUME_UP, INPUT_PULLUP); //D4
pinMode(VOLUME_DOWN, INPUT_PULLUP); //D5
pinMode(AUDIO_MUTE, INPUT_PULLUP); //D6
pinMode(AUDIO_BASS, INPUT_PULLUP); //D7
pinMode(SEEK_STATION, INPUT_PULLUP); //D14
oled.begin(&Adafruit128x64,I2C_ADDRESS);
//oled.begin();
oled.clear();
//oled.on();
oled.setFont(Adafruit5x7);
// oled.setFont(FONT8X16);
oled.set2X();
oled.setCursor(0, 10);
oled.println("RDA5807OLED");
oled.setCursor(0,40);
oled.println("By PU2CLR ");
oled.setCursor(0,90);
oled.println("Modefy By");
oled.setCursor(0,140);
oled.println(" JL7GMN");
delay(3000);
oled.clear();
/*
Reads encoder via interrupt
Use Rotary.h and Rotary.cpp implementation to process encoder via interrupt
*/
// Encoder interrupt
attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), rotaryEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), rotaryEncoder, CHANGE);
// frequency initialize -------------------------------------------------
frequency=51.00; //starting frequency ABALABLE MIN 45.60MHz TO MAX 119.60MHz
frequencyB=4*(frequency*1000000+225000)/32768; //calculating PLL word
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;
delay(100);
//tune set to 0
Wire.beginTransmission(0X10); //continuous write
//no need to specify register
Wire.write(0X00); // 02h(HighByte02) DMUTE0
Wire.write(0X00); // 02l(LowByte02)
Wire.write(0X00); // 03h
Wire.write(0X00); // 03l TUNE0 ENABLE0
Wire.endTransmission();
Wire.beginTransmission(0x60); //writing TEA5767
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x00);// F0->10
Wire.write(0x00);
Wire.endTransmission();
/*
Wire.beginTransmission(0X11); //normal i2c
Wire.write(0X05); // specify register 05h
Wire.write(0X88); // 05h
Wire.write(0b10001000); // 05l VOLUMExxxx
Wire.endTransmission();
*/
//radio.setVolume(15);
//oled.setFont(Adafruit5x7);
oled.setFont(X11fixed7x14B);
oled.clear();
oled.setCursor(1, 0);
;
delay(10);
//----------------------------------------------------------
showStatus();
}
void rotaryEncoder()
{ // rotary encoder events
uint8_t encoderStatus = encoder.process();
if (encoderStatus)
encoderCount = (encoderStatus == DIR_CW) ? 1 : -1;
}
void showStatus()
{
;
oled.set2X();
oled.setCursor(0, 0);
oled.println("FM ");
oled.setCursor(0, 95);
oled.println(" ");
oled.setCursor(0, 95);
oled.set2X();
oled.print(frequency);
oled.setCursor(75, 75);
oled.println("MHz");
}
void loop()
{
oled.set1X();
// Check if the encoder has moved.
if (encoderCount != 0)
{
if (encoderCount == 1)
{
// seekDirection = RDA_SEEK_UP;
//frequency=(freq_available/1000000)+0.05; //f=receivef+0.05
frequency=(frequency+(freq_available/1000000)+0.01); //f=receivef+0.05
frequencyB=4*(frequency*1000000+225000)/32768+1;
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;
//tune set to 0
Wire.beginTransmission(0X10); //continuous write
//no need to specify register
Wire.write(0X00); // 02h(HighByte02) DMUTE0
Wire.write(0X00); // 02l(LowByte02)
Wire.write(0X00); // 03h
Wire.write(0X00); // 03l TUNE0 ENABLE0
Wire.endTransmission();
Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x00);//Wire.write(0x1F);
Wire.write(0x00);
//Wire.write(0x88); // 05h
//Wire.write(0x81); // 05l volulme001
Wire.endTransmission();
//////////////////////
b=100;
}
else
{
// seekDirection = RDA_SEEK_DOWN;
//frequency=(freq_available/1000000)-0.05; //f=receivef-0.05
frequency=(frequency+(freq_available/1000000)-0.01); //f=receivef-0.05
frequencyB=4*(frequency*1000000+225000)/32768+1;
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;
//tune set to 0
Wire.beginTransmission(0X10); //continuous write
//no need to specify register
Wire.write(0X00); // 02h(HighByte02) DMUTE0
Wire.write(0X00); // 02l(LowByte02)
Wire.write(0X00); // 03h
Wire.write(0X00); // 03l TUNE0 ENABLE0
Wire.endTransmission();
Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0x30);
Wire.write(0x00);//Wire.write(
// rx.setVolume(15);
//TEA5767Radio::setVolume(15);0x1F);
Wire.write(0x00);
//Wire.write(0x88); // 05h
//Wire.write(0x81); // 05l volulme001
Wire.endTransmission();
c=100;
}
showStatus();
encoderCount = 0;
}
else if (digitalRead(VOLUME_UP) == LOW) // D4
{;// rx.setVolumeUp();
}
else if (digitalRead(VOLUME_DOWN) == LOW) // D5
{;// rx.setVolumeDown();
}
else if (digitalRead(AUDIO_MUTE) == LOW) // D6
{;// rx.setMute(bMute = !bMute);
}
else if (digitalRead(SEEK_STATION) == LOW) //D14
{ ; // rx.seek(RDA_SEEK_WRAP, seekDirection, showStatus); // showFrequency will be called by the seek function during the process.
delay(200);
}
else if (digitalRead(AUDIO_BASS) == LOW) //D7
{;// rx.setBass(bBass = !bBass);
delay(50);
}
}
上記のArduinoNANOスケッチで50MHz帯のFMが受信できました。
なおSSGで受信を確認してみたところ、FM受信は仕様上のチャンネルスペースの設定範囲が200KHz,100KHz,50KHz,25KHの中からの設定です。最低でも25KHz間隔です。なので見かけ上スケッチにて10KHz間隔で周波数表示対応できてはいますが選択したスペースで受信されているようです。やはりFM放送受信用ということでしょうか?
FM受信周波数にしてFMラジオとして使うのが一番無難なのかもしれません。Hi!
つづく?
execution time : 0.034 sec