Arduino FM Radio

There are a few FM receiver modules that are available. We used an FM module that is based on the RDA5807M chip and unlike some of the other chips this one supports volume control. To keep our project compact we used the Arduino Nano, but we tested the UNO and Mega and they both worked well.

fmradio

There are a lot of options on how to control your FM radio. We liked the idea of using an old TV remote because this allowed us to change the volume and radio stations anywhere in the room. For this project we used:

• an I2C FM receiver module ($13)
• any Arduino module that has SDA and SCL pins
• an IR receiver ($5)
• a small bread board and some jumpers

The FM receiver module works on the I2C bus that connects to the SDA and SCL pins. Depending on which IR chip you use the wiring will vary slight. The key thing is to connect the data pin correctly. For our example we used pin 11.

circuit2

FM Module

When we first starting working this project there was no Arduino FM library available, so we started to by talking directly with the I2C bus. However now an Arduino FM library is available.

The RDA5807M chip [3] on the FM receiver module has a number of register addresses that we needed to write to. The key ones were:

  • REGISTER 2 – Initialize the chip (0xC003)
  • REGISTER 2 – Enable radio communications (0xC00D)
  • REGISTER 3 – Set the frequency
  • REGISTER 5 – Set the volume

We needed to pause between initializing and enabling radio communications. Setting the radio frequency is done by offsetting the frequency from the minimum range (870) and then splitting the value into high and low bytes.

The volume on register 5 is adjusted between a value of 0, the lowest, and 15 or 0xF the highest. There are other options on register 5 so our code changed the value from 0x84D0 to 0x84DF.

The Arduino modules uses the wire.h library to read and write to I2C devices. To write to a register the important commands are:

  • Wire.beginTransmission
  • Wire.write
  • Wire.endTransmission

An example using these commands would be:


//This is an example of setting the volume to 1
//This sets up communications to a device
Wire.beginTransmission(0x11); // 0x11 is the RDA5807M chip
Wire.write(0x05); // address 0x05 is where you want to write to
Wire.write(0x84); // write 0x84 to the first byte of address 0x05
Wire.write(0xD1); // write 0xD1 to the second byte of address 0x05
Wire.endTransmission(); // finish the write

We made a simple radio test program (Listing 1) that set up the radio to a local frequency at volume 1.


#include <Wire.h>

int freq;
int freqB;
byte freqH, freqL;

void setup()
{
Wire.begin();

// Initialize the RDA5807M chip

Wire.beginTransmission(0x11); // Device address is 0x11
Wire.write(0x02); // Register address 0x02
Wire.write(0xC0); Wire.write(0x03); // Initialize the settings
Wire.endTransmission(); // stop condition
delay(500); // wait 500ms

Wire.beginTransmission(0x11); // Device address is 0x11
Wire.write(0x02); // Register address 0x02
Wire.write(0xC0); Wire.write(0x0D); // Setup the radio for communications
Wire.endTransmission();
delay(500);

// Define an FM station to listen to

freq = 1079; // 107.9 MHz our local FM station
freqB = freq - 870; // chip needs to have freq offset from lowest freq (870)
freqH = freqB>>2; // you need to break the offset freq into 2 parts (hi/low)
freqL = (freqB&3)<<6; // Shift channel selection for matching register 0x03

Wire.beginTransmission(0x11);
Wire.write(0x03);
Wire.write(freqH); // write High freq byte
Wire.write(freqL + 0x10); // write Low freq byte
Wire.endTransmission();

// The volume is from 0-F and its the first bytes, leave all the bytes (0x84D0 - 0x84DF)

Wire.beginTransmission(0x11);
Wire.write(0x05);
Wire.write(0x84); Wire.write(0xD1); // set volume to 1
Wire.endTransmission();
}

void loop()
{

}

Finding TV Remote Codes

We used a small program to find the IR (Infrared) codes from our TV remote. For our program we used the volume up, volume down, channel up and channel down keys. Different TV remotes will have different codes so you will have to find the codes that work with your remote.


/*
IR TEST PROGRAM

PINOUTS:

LEFT = DATA PIN
MIDDLE = GND
RIGHT = 3.3 volts

*/
#include <IRremote.h>

int RECV_PIN = 11;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
Serial.println("Setup Complete");
}

void loop()
{
if (irrecv.decode(&results))
{
Serial.println(results.value, HEX);
irrecv.resume(); // Receive the next value
delay(500);

}
}

ircode

When our IR test program was running we used the Arduino monitor window to show us the different key codes. We manually recorded these codes and used them in our final project.

Using a TV Remote

Our goal was to use a TV remote to change the FM station and to adjust the volume. There are a lot of websites you can use to find nearby radio stations. A good website for this is: http://radio-locator.com.

Our final program  used a number of predefined FM stations that would change with channel up and channel down on the TV remote. The remote’s volume up and down would change the radio’s volume. Remember to change the IR codes to match your TV remote, and the FM stations for your area.


// RDA5807M Radio controlled with a TV Remote
//
#include <Wire.h>
#include <IRremote.h>

int RECV_PIN = 11; //Connect the IR data pin in 11
IRrecv irrecv(RECV_PIN);
decode_results results;

int volume = 0; // start with the volume low
int channellist[]= {999,1029,1021,1079}; // Define some radio stations
int maxc = 4; // Define the number of radio stations used
int channel = 2; // Start with a favorite station

void setup()
{
Wire.begin();

Serial.begin(9600);

irrecv.enableIRIn(); // Start the receiver

radio_init();
setfreq(channellist[channel]);
setvolume(volume);

}
void loop() {
if (irrecv.decode(&results)) {

switch (results.value) {
case 0xE0E0E01F:
Serial.println("vol up");
if (volume < 15) {
volume++;
setvolume(volume);
}
break;
case 0xE0E0D02F:
Serial.println("vol down");
if (volume > 0) {
volume--;
setvolume(volume);
}
break;
case 0xE0E048B7:
Serial.println("chan up");
if (channel < maxc) {
channel++;
setfreq(channellist[channel]);
}
break;
case 0xE0E008F7:
Serial.println("chan down");
if (channel > 0) {
channel--;
setfreq(channellist[channel]);
}
break;
default:
Serial.println(results.value, HEX);
}
irrecv.resume(); // Receive the next value
}
delay(100);
}
//===============================
void setvolume(int thevolume)
{
byte volbyte;

volbyte = thevolume + 0xD0;
Wire.beginTransmission(0x11);
Wire.write(0x05);
Wire.write(0x84); Wire.write(volbyte);
Wire.endTransmission();
delay(500);
}
//===============================
void setfreq(int thefreq)
{
int freqB;
byte freqH, freqL;

freqB = thefreq - 870;
freqH = freqB >> 2;
freqL = (freqB & 3) <<6;

Wire.beginTransmission(0x11);
Wire.write(0x03);
Wire.write(freqH); // write frequency into bits 15:6, set tune bit
Wire.write(freqL + 0x10);
Wire.endTransmission();
delay(500);
}
//================================
void radio_init()
{
Wire.beginTransmission(0x11); // Device address 0x11 (random access)
Wire.write(0x02); // Register address 0x02
Wire.write(0xC0); Wire.write(0x03); // Initialize the settings
Wire.endTransmission();
delay(500); // wait 500ms to finalize setup

Wire.beginTransmission(0x11); // Device address 0x11 (random access)
Wire.write(0x02);
Wire.write(0xC0); Wire.write(0x0D); // Setup radio settings
Wire.endTransmission();
delay(500); // wait 500ms to finalize settings
}

Packaging our Project

We wanted to make our radio project portable, so we came up with two ideas. The first idea was to put all the electronics into a plastic container. For this we used a soap dish ($1) that we drilled three holes in. The first two holes were for the power and speaker cords. The last hole was for the IR receiver. To power our project we used a solar charger ($10), so we could listen to music outside.

soapdish1

Our second idea was to place the electronics inside the pocket of a cooler bag. It is important to have the IR receiver poking out of the pocket.

coolerbag

There are also some fun projects where you could use LCD Keyboard Shields or Touchscreens.

lcd

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s