14.FM Radio Receiver Module
Arduino กับ FM Radio Receiver Module (RDA5807SS)
อุปกรณ์
บอร์ด Arduino
FM Radio Receiver Module RDA5807SS
LCD
เครื่องมือ
Arduino-1.0.3
ความสามารถ
Arduino ทำหน้าที่เป็น ตัวควบคุม ให้ภาครับ FM ทำงาน
แสดงค่าความดังและสถานีได้ทาง LCD
วงจร
คู่มือของ FM Module ดูได้จาก เอกสารแนบ
ตัวอย่างโปรแกรมแก้ไขมาจาก http://pastebin.com/KEyfK0dd
โปรแกรมนี้ยังไม่ต้องต่อ LCD แต่ใช้การสั่งงานผ่านทาง Serial Monitor
เมื่อรันโปรแกรมที่ Serial Monitor จะเป็นดังนี้
คำสั่งสำหรับสั่งงานดูได้จาก หน้าต่าง Serial Monitor
เช่น + หรือ - เป็นการปรับคลื่น และ เครื่องหมาย > หรือ < ปรับความดังเสียง
โปรแกรม
// i2c fm parallax part 27984
// bs2 and spin code available
// device has 2 I2C address, ending in 0, no addresses required Ahhhh
// write configregs 5x2 read status 2x2
// have to enable tune to set channel
#include <Wire.h>
#include <stdint.h>
#include <string.h>
// SDA pin is Analog4 module pin 1 internal pullup ok
// SCL pin is Analog5 module pin 2
// grnd to pin 10 v3.3-5v to pin 9
// device ID
#define SLAVE_ID 0x20 >> 1
#define CONFIG_WORDS 5
#define STATUS_WORDS 4
static uint16_t Config0[CONFIG_WORDS] = {0xD001, 0, 0x0400, 0x86D3, 0x4000};
static uint16_t Config[CONFIG_WORDS], Status[STATUS_WORDS];
// config 0 register 02
#define DHIZ 15
#define DMUTE 14
#define MONO 13
#define BASS 12
#define CLK32_INPUT_ENB 10
#define SEEK 8
#define CLK_MODE 4
#define SOFT_RESET 1
#define ENABLE 0
#define CLK_MODE_MASK (7 << CLK_MODE)
#define SEEK_MASK (3 << SEEK)
#define SEEK_UP (3 << SEEK)
#define SEEK_DOWN (1 << SEEK)
// config 1 register 03
#define CHAN 6
#define TUNE 4
#define BAND 2
#define SPACE 0
#define CHAN_MASK (0xff << CHAN)
#define BAND_MASK ( 3 << BAND)
#define SPACE_MASK ( 3 << SPACE)
// config 2 register 04
#define STCEIN 14
#define DE 11
#define I2S_ENABLED 6
#define GPIO3 4
#define GPIO2 2
#define GPIO1 0
#define GPIO3_MASK ( 3 << GPIO3)
#define GPIO2_MASK ( 3 << GPIO2)
#define GPIO1_MASK ( 3 << GPIO1)
// config 3 register 05
#define INT_MODE 15
#define SEEKTH 8
#define LNA_PORT_SEL 6
#define LNA_ICSEL_BIT 4
#define VOLUME 0
#define SEEKTH_MASK (0x7f << SEEKTH)
#define LNA_PORT_MASK (2 << LNA_PORT_SEL)
#define LNA_ICSEL_MASK (2 << LNA_ICSEL_BIT)
#define VOLUME_MASK (0x0f << VOLUME)
// status regs
// status 0 register 0a
#define STC 14
#define SF 13
#define ST 10
#define READCHAN 0
#define READCHAN_MASK (0xff << READCHAN)
// status 1 register 0b
#define RSS 9
#define FM_TRUE 8
#define FM_READY 7
#define RSS_MASK (0x7f << RSS)
// assume band 0 760 for other spacing .1 MHz
#define MAX_PRESETS 10
#define MAX_FREQ 1080
#define MIN_FREQ 870
#define MAX_SST 127
#define MAX_VOL 15
uint16_t fm_vol=1, fm_chan = 975; // channel spacing 100KHz
uint16_t fm_rss, fm_readchan,fm_sst=6,fm_st,fm_true,fm_ready,fm_stc,fm_sf;
uint16_t fm_seek, fm_presets[MAX_PRESETS] = {919,975}, fm_presetnext=2;;
bool seeking;
void setup()
{
int channel;
Wire.begin(); // connect I2C
Serial.begin(9600);
delay(5);
Serial.println("FM Demo");
fm_reset();
printConfig();
printPresets();
delay(100);
getStatus();
printStatus();
}
void loop()
{
uint8_t c;
bool update;
Serial.println();
Serial.println("Freq +/- Vol >/< Seek u/d Preset 0-9 AddPreset A Reset R SST x/y");
Serial.println(" Enter command character:");
while(!Serial.available()) delay(1);
c = Serial.read();
Serial.println((char)c);
update = false;
switch(c) {
case '+':
update = chan_update(fm_chan+1);
break;
case '-':
update = chan_update(fm_chan-1);
break;
case '>':
update = vol_update(fm_vol+1);
break;
case '<':
update = vol_update(fm_vol-1);
break;
case 'u':
Config[0] &= ~SEEK_MASK;
Config[0] |= SEEK_UP;
seeking = update = true;
break;
case 'd':
Config[0] &= ~SEEK_MASK;
Config[0] |= SEEK_DOWN;
seeking = update = true;
break;
case 'x':
update = sst_update(fm_sst+1);
break;
case 'y':
update = sst_update(fm_sst-1);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
chan_update(fm_presets[c - '0']);
update = true;
break;
case 'A':
add_preset();
break;
case 'R':
fm_reset();
update = true;
break;
case '?':
getStatus();
printConfig();
printStatus();
printPresets();
break;
default:
break;
}
if (update || seeking) {
setConfig();
delay(800); // let seek complete ... spin on flags?
getStatus();
if (seeking && fm_stc) {
seek_disable();
chan_update(fm_seek + MIN_FREQ);
setConfig();
}
tune_disable();
printConfig();
printStatus();
}
}
// config updates
void fm_reset() {
seeking = false;
fm_vol = 1;
fm_chan = 975;
fm_sst = 6;
memcpy(Config,Config0,CONFIG_WORDS * sizeof(uint16_t));
Config[1] &= ~CHAN_MASK;
Config[1] |= (fm_chan - MIN_FREQ) << CHAN;
Config[3] &= ~VOLUME_MASK;
Config[3] |= fm_vol << VOLUME;
tune_enable();
setConfig();
tune_disable();
}
void tune_enable() {
Config[1] |= (1 << TUNE);
}
void tune_disable() {
Config[1] &= ~(1 << TUNE);
}
void seek_disable() {
seeking = false;
Config[0] &= ~SEEK_MASK; // turn off seek
}
bool vol_update(int val) {
if (val < 0 || val > MAX_VOL) return false;
fm_vol = val;
Config[3] &= ~VOLUME_MASK;
Config[3] |= fm_vol << VOLUME;
return true;
}
bool chan_update(int val) {
if (val < MIN_FREQ || val > MAX_FREQ) return false;
fm_chan = val;
Config[1] &= ~CHAN_MASK;
Config[1] |= (fm_chan - MIN_FREQ) << CHAN;
tune_enable();
return true;
}
bool sst_update(int val) {
if (val < 0 || val > MAX_SST) return false;
fm_sst = val;
Config[3] &= ~SEEKTH_MASK;
Config[3] |= fm_sst << SEEKTH;
return true;
}
void add_preset() {
if (fm_presetnext >= MAX_PRESETS) return;
fm_presets[fm_presetnext++] = fm_chan;
printPresets();
}
// Set configuration register
void setConfig()
{
int i;
Wire.beginTransmission(SLAVE_ID);
for(i=0; i< CONFIG_WORDS;i++) {
Wire.write((int)Config[i]>>8);
Wire.write((int)(Config[i] & 0xff));
}
Wire.endTransmission();
}
void getStatus()
{
int i;
Wire.requestFrom(SLAVE_ID, STATUS_WORDS*2);
for(i=0; i< STATUS_WORDS;i++) {
Status[i] = Wire.read();
Status[i] = Status[i]<<8 | Wire.read();
}
fm_seek = Status[0] & READCHAN_MASK;
fm_stc = Status[0] >> STC & 1;
fm_sf = Status[0] >> SF & 1;
fm_st = Status[0] >> ST & 1;
fm_rss = (Status[1] & RSS_MASK) >> RSS;
fm_true = Status[1] >> FM_TRUE & 1;
fm_ready = Status[1] >> FM_READY & 1;
}
void printConfig() {
int chan;
char str[128];
sprintf(str,"config %04x %04x %04x %04x",Config[0],Config[1],Config[2],Config[3]);
Serial.println(str);
chan = ((Config[1] & CHAN_MASK) >> CHAN ) + MIN_FREQ;
sprintf(str," fm channel %d.%d volume %d ss %d sst %d",
chan/10,chan%10,fm_vol,fm_rss,fm_sst);
Serial.println(str);
}
void printStatus() {
int chan;
char str[128];
sprintf(str,"status %04x %04x",Status[0],Status[1]);
Serial.println(str);
chan = fm_seek + MIN_FREQ;
if(seeking) Serial.print("seeking ... ");
sprintf(str," seek channel %d.%d ss %d stereo %d complete %d fail %d %d %d",
chan/10,chan%10,fm_rss,fm_st,fm_stc,fm_sf,fm_true,fm_ready);
Serial.println(str);
}
void printPresets() {
int chan,i;
char str[128];
Serial.print("Presets: ");
for (i=0;i<fm_presetnext;i++) {
chan = fm_presets[i];
sprintf(str,"%d.%d ",chan/10,chan%10);
Serial.print(str);
}
Serial.println();
}
#define SID (0x22 >> 1)
void i2cdump(uint8_t addr, int n)
{
int i;
uint16_t buff[8];
char str[128];
Serial.print(addr,HEX); Serial.println(" dump");
Wire.beginTransmission(SID);
Wire.write(addr); // start addr
Wire.endTransmission();
Wire.requestFrom(SID, n*2);
for(i=0; i< n;i++) {
buff[i] = Wire.read();
buff[i] = buff[i]<<8 | Wire.read();
sprintf(str,"%04x ",buff[i]);
Serial.print(str);
}
Serial.println();
}
แบบที่ 2 แสดงค่าความถี่ออกทาง LCD
อ้างอิง
https://sites.google.com/site/eplearn/microcontroller/fm_tunner
http://pastebin.com/KEyfK0dd