
In this project, we will use the RDA5807M FM receiver to listen to some local radio stations using an Arduino. Moreover, we will also display the current radio station on an OLED screen.
What is an RDA5807M FM Receiver?
The RDA5807M is a simple stereo radio chip that supports worldwide FM bands from 50MHz to 115MHz. It has a fully integrated synthesizer, (intermediate frequency (IF) selectivity, RDS/RBDS, and an MPX decoder.

The RDA5807M FM receiver.
This chip has a powerful low-IF digital audio processor, which means that you can directly listen to the audio via headphones. If you wish to connect it to bigger speakers, however, you might need an audio amplifier circuit. I will be using a simple portable speaker with a built-in audio amplifier for this project. Now let’s get started!
Required Hardware
- Arduino UNO (or any other)
- RDA5807M
- I2C OLED Display
- Radio or TV Antenna
RDA5807M Pinout

RDA5807M pinout
Required Software
Wiring Up the Hardware
Connect the radio receiver (RDA5807M) with the Arduino UNO as shown below.

Connecting the Arduino UNO, RDA5807M, and headphone jack.
You can use a one-foot, single-strand wire as an antenna or a TV/radio antenna for this receiver. Rout (right audio out) and Lout (left audio out) of the RDA5807M module can be connected via a 3.5mm audio jack female connector. For this purpose, you can make an aux cable as I did in the picture below.

Another view of connecting the UNO, FM receiver, and audio jack.
Using a breadboard, connect the OLED as shown below and connect the three buttons in series using 10-kiloohm resistors. The buttons are connected to analog pin A0 of the Arduino. The OLED display and FM receiver module share the same SDA and SCL lines with the Arduino.

Adding the pushbuttons and OLED screen to the build.
Once all of the hardware is wired up, here is what your build should look like:

All of the hardware connected.

The build connected to the speaker.
Uploading the Source Code
After double-checking all of the connections, upload the source code by copy-pasting and uploading the code below into Arduino IDE.
#include <EEPROM.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
//#include <TFT_ILI9163C.h>
#include <Adafruit_SSD1306.h>
#include <RDA5807M.h>
#include <RDSParser.h>
#include <radio.h>
//extern const uint8_t icon_radio[];
//extern const uint8_t icon_volume[];
RDA5807M radio; ///< Create an instance of a RDA5807 chip radio
#define DEBUG 0
#define OLED_RESET 4
Adafruit_SSD1306 tft(OLED_RESET);
RDSParser rds;
enum RADIO_STATE {
STATE_PARSECOMMAND, ///< waiting for a new command character.
STATE_PARSEINT, ///< waiting for digits for the parameter.
STATE_EXEC ///< executing the command.
};
RADIO_STATE state; ///< The state variable is used for parsing input characters.
const int entrada = A0;
int entradaV = 0;
int menu;
#define MAXmenu 3
int menux;
#define MAXmenux 3
static char* menuS[]= {" ","MANUAL TUNE","VOLUME ","AUTO TUNE","INFO "};
int volumen, volumenOld=7;
int frecuencia,frecuenciaOld;
int signal_level;
unsigned int z,z1;
byte xfrecu,xfrecuOld;
unsigned int estado[6];
unsigned long time,time1,time2,time3;
char buffer[30];
unsigned int RDS[4];
char seg_RDS[8];
char seg_RDS1[64];
char indexRDS1;
char hora,minuto,grupo,versio;
unsigned long julian;
int mezcla;
//radio.debugEnable();
void RDS_process(uint16_t block1, uint16_t block2, uint16_t block3, uint16_t block4) {
rds.processData(block1, block2, block3, block4);
}
void setup()
{
Wire.begin();
//Serial.begin(9600);
Serial.begin(57600);
tft.begin(SSD1306_SWITCHCAPVCC, 0x3C);
radio.init();
radio.debugEnable();
tft.display();
delay(20);
// Clear the buffer.
tft.clearDisplay();
// read value of last frequency
frecuencia = EEPROM.read(201);
volumen = EEPROM.read(202);
if (volumen < 0) volumen = 0;
if (volumen >15) volumen = 15;
if (frecuencia <0) frecuencia = 0;
if (frecuencia >210) frecuencia = 210;
tft.setRotation(0);
tft.setTextColor(WHITE);
tft.setCursor(95,0);
// tft.print("Nivel semnal :");
tft.print(signal_level);tft.display();
tft.print("/15 ");
// draw an antenna
tft.drawLine(103, 9, 103, 13, WHITE);
tft.drawCircle(103,9,2,WHITE);
WriteReg(0x02,0xC00d); // write 0xC00d into Reg.2 ( soft reset, enable,RDS, )
WriteReg(0x05,0x84d8); // write ,0x84d8 into Reg.3
time3=time2=time1=time = millis();
menu=3;
canal(frecuencia);
// clearRDS;
state = STATE_PARSECOMMAND;
// setup the information chain for RDS data.
radio.attachReceiveRDS(RDS_process);
rds.attachServicenNameCallback(tftServiceName);
// rds.attachTimeCallback(tftTime);
}
/*
void tftTime(uint8_t hour, uint8_t minute) {
tft.setCursor(60, 100);
tft.setTextSize(2);
tft.setTextColor(GREENYELLOW, BLACK);
if (hour < 10) tft.print('0');
if (hour > 30) tft.print(' ');
tft.print(hour);
tft.print(':');
if (minute < 10) tft.print('0');
tft.println(minute);
tft.setTextColor(GREENYELLOW, BLACK);
} // tftTime()
*/
void tftServiceName(char *name)
{
size_t len = strlen(name);
tft.setCursor(0, 25);
tft.setTextSize(1.5);
tft.setTextColor(WHITE, BLACK);
tft.print(name);tft.setTextColor(WHITE, BLACK); tft.display();
while (len < 8) {
tft.print(' ');tft.setTextColor(WHITE, BLACK); tft.display();
len++;
} // while
} // tftServiceName()
void loop() {
int newPos;
unsigned long now = millis();
// static unsigned long nextFreqTime = 0;
static unsigned long nextRadioInfoTime = 0;
char c;
entradaV = analogRead(entrada);
#if DEBUG
Serial.print("sensor = " ); Serial.println(entradaV);delay(50);
#endif
// Boton menu
if(entradaV>500 && entradaV<524)
{
Serial.print(entradaV);
menu++;
if(menu>MAXmenu)menu=1;
Visualizar();
#if DEBUG
Serial.print("menu = " ); Serial.println(menu);
#endif
while(1020>analogRead(entrada))delay(5);
}
// Boton derecho
if( entradaV<50)
{
Serial.print(entradaV);
menux++;
if(menux>MAXmenux)menux=MAXmenux;
#if DEBUG
Serial.print("menux = " ); Serial.println(menux);
#endif
switch(menu)
{
case 1:
frecuencia++;
if(frecuencia>210)frecuencia=210; // верхняя граница частот
delay(130);
break;
case 2:
volumen++;
if(volumen>15)volumen=15;
while(1020>analogRead(entrada))delay(5);
break;
case 3:
busqueda(0);
while(1020>analogRead(entrada))delay(5);
break;
case 4:
// LcdClear();
tft.clearDisplay();
// visualPI();
delay(3000);
// LcdClear();
tft.clearDisplay();
frecuenciaOld=-1;
break;
}
}
// Boton izquierdo
if( entradaV<700 && entradaV>660)
//if( entradaV<700 && entradaV>660)
{
Serial.print(entradaV);
menux--;
if(menux<1)menux=1;
#if DEBUG
Serial.print("menux = " ); Serial.println(menux);
#endif
switch(menu)
{
case 1:
frecuencia--;
if(frecuencia<0)frecuencia=0;
delay(130);
break;
case 2:
volumen--;
if(volumen<0)volumen=0;
while(1020>analogRead(entrada))delay(5);
break;
case 3:
busqueda(1);
while(1020>analogRead(entrada))delay(5);
break;
case 4:
// LcdClear();
tft.clearDisplay();
//tft.print(frecuencia);
//visualPTY();
delay(3000);
// LcdClear();
tft.clearDisplay();
frecuenciaOld=-1;
break;
}
}
if( millis()-time2>50)
{
ReadEstado();
time1 = millis();
//RDS
if ((estado[0] & 0x8000)!=0) {get_RDS();}
}
if( millis()-time3>500)
{
time3 = millis();
Visualizar();
}
if( frecuencia!=frecuenciaOld)
{
frecuenciaOld=frecuencia;
z=870+frecuencia;
EEPROM.write(201,frecuencia);
#if DEBUG
Serial.print("Frecuencia = " ); Serial.println(frecuencia);
#endif
sprintf(buffer,"%04d ",z);
// tft.drawBitmap(80, 2, icon_volume, 24, 10, WHITE);
//tft.display();
tft.setCursor(0,0);
tft.setTextSize(2);
tft.setTextColor(WHITE, BLACK);
for(z=0;z<5;z++)
{
if (z==0) {
if (frecuencia < 130) tft.print(" ");
else tft.print(buffer[0]);tft.setTextColor(WHITE, BLACK);
}
if(z==3) tft.print(",");tft.setTextColor(WHITE, BLACK);
if (z>0) tft.print(buffer[z]);tft.setTextColor(WHITE, BLACK);
}
// LcdString("MHz");
tft.setCursor(65,5);
tft.setTextSize(1);
tft.setTextColor(WHITE, BLACK);
tft.print("MHz");
tft.setTextColor(WHITE, BLACK);
tft.display();
canal(frecuencia);
// clearRDS();
}
//Cambio de volumen
if(volumen!=volumenOld)
{
volumenOld=volumen;
sprintf(buffer,"Volum %02d",volumen); tft.setCursor(62,25); tft.setTextSize(1); tft.setTextColor(WHITE, BLACK); tft.print(buffer);tft.print(" ");
tft.display();tft.print("/15");
WriteReg(5, 0x84D0 | volumen);
EEPROM.write(202,volumen);
}
// check for RDS data
radio.checkRDS();
}
void busqueda(byte direc)
{
byte i;
if(!direc) WriteReg(0x02,0xC30d); else WriteReg(0x02,0xC10d);
for(i=0;i<10;i++)
{
delay(200);
ReadEstado();
if(estado[0]&0x4000)
{
//Serial.println("Emisora encontrada");
frecuencia=estado[0] & 0x03ff;
break;
}
}
}
void Visualizar(void)
{
// tft.setCursor(3, 13); tft.setTextSize(2); tft.setTextColor(WHITE, BLACK); tft.print("FM");
// tft.setCursor(27, 20); tft.setTextSize(1); tft.setTextColor(WHITE, BLACK); tft.print("RDA5807-");
sprintf(buffer,"%s",menuS[menu]); tft.setCursor(5,17); tft.setTextSize(1); tft.setTextColor(WHITE,BLACK); tft.print(buffer);
//Detectar señal stereo
tft.display();
tft.setCursor(85,15);
tft.setTextColor(BLACK, WHITE);
if((estado[0] & 0x0400)==0) tft.print(""); else tft.setTextColor(BLACK, WHITE); tft.print("Stereo"); tft.setTextColor(BLACK, WHITE);
tft.display();
//Señal
// z=estado[1]>>10; sprintf(buffer,"S-%02d",z); tft.setCursor(58,0); tft.setTextColor(WHITE, BLACK); tft.print(buffer); tft.setCursor(25,0);tft.setTextColor(WHITE, BLACK);tft.print("Canal");
sprintf(buffer,"Volum %02d",volumen); tft.setCursor(62,25);tft.setTextSize(1); tft.setTextColor(WHITE, BLACK); tft.print(buffer); //DUBLARE AFISARE VOLUM
tft.display();tft.print("/15");
frecuencia=estado[0] & 0x03ff;
}
void canal( int canal)
{
byte numeroH,numeroL;
numeroH= canal>>2;
numeroL = ((canal&3)<<6 | 0x10);
Wire.beginTransmission(0x11);
Wire.write(0x03);
Wire.write(numeroH); // write frequency into bits 15:6, set tune bit
Wire.write(numeroL);
Wire.endTransmission();
}
//________________________
//RDA5807_adrr=0x11;
// I2C-Address RDA Chip for random Access
void WriteReg(byte reg,unsigned int valor)
{
Wire.beginTransmission(0x11);
Wire.write(reg); Wire.write(valor >> 8); Wire.write(valor & 0xFF);
Wire.endTransmission();
//delay(50);
}
//RDA5807_adrs=0x10;
// I2C-Address RDA Chip for sequential Access
int ReadEstado()
{
Wire.requestFrom(0x10, 12);
for (int i=0; i<6; i++) { estado[i] = 256*Wire.read ()+Wire.read(); }
Wire.endTransmission();
}
//READ RDS Direccion 0x11 for random access
void ReadW()
{
// Wire.beginTransmission(0x11); // Device 0x11 for random access
// Wire.write(0x0C); // Start at Register 0x0C
// Wire.endTransmission(0); // restart condition
// Wire.requestFrom(0x11,8, 1); // Retransmit device address with READ, followed by 8 bytes
// for (int i=0; i<4; i++) {RDS[i]=256*Wire.read()+Wire.read();} // Read Data into Array of Unsigned Ints
// Wire.endTransmission();
}
void get_RDS()
{
/* int i;
ReadW();
grupo=(RDS[1]>>12)&0xf;
if(RDS[1]&0x0800) versio=1; else versio=0; //Version A=0 Version B=1
if(versio==0)
{
#if DEBUG
sprintf(buffer,"Version=%d Grupo=%02d ",versio,grupo); Serial.print(buffer);
#endif
switch(grupo)
{
case 0:
#if DEBUG
Serial.print("_RDS0__");
#endif
i=(RDS[1] & 3) <<1;
seg_RDS[i]=(RDS[3]>>8);
seg_RDS[i+1]=(RDS[3]&0xFF);
//tft.setCursor(20,100);tft.setTextColor(BLUE, BLACK);
for (i=0;i<8;i++)
{
#if DEBUG
Serial.write(seg_RDS[i]);
#endif
// if(seg_RDS[i]>31 && seg_RDS[i]<128)
// tft.print(seg_RDS[i]);
// else
// tft.setTextColor(BLUE, BLACK);
//tft.clearScreen();
}
#if DEBUG
Serial.println("---");
#endif
break;
case 2:
i=(RDS[1] & 15) <<2;
seg_RDS1[i]=(RDS[2]>>8);
seg_RDS1[i+1]=(RDS[2]&0xFF);
seg_RDS1[i+2]=(RDS[3]>>8);
seg_RDS1[i+3]=(RDS[3]&0xFF);
#if DEBUG
Serial.println("_RADIOTEXTO_");
for (i=0;i<32;i++) Serial.write(seg_RDS1[i]);
Serial.println("-TXT-");
#endif
break;
case 4:
i=RDS[3]& 0x003f;
minuto=(RDS[3]>>6)& 0x003f;
hora=(RDS[3]>>12)& 0x000f;
if(RDS[2]&1) hora+=16;
hora+=i;
z=RDS[2]>>1;
julian=z;
if(RDS[1]&1) julian+=32768;
if(RDS[1]&2) julian+=65536;
#if DEBUG
Serial.print("_DATE_");
Serial.print(" Juliano=");Serial.print(julian);
// sprintf(buffer," %02d:%02d ",hora,minuto); tft.setCursor(50,110); tft.setTextColor(CYAN, BLACK); tft.print(buffer);
Serial.println(buffer);
#endif
break;
default:
#if DEBUG
Serial.println("__");
#endif
;
}
}
*/ }
Now, tune in to the popular radio stations in your area by clicking the right button. You will be able to see the current FM band on the OLED screen. By default, the receiver will be set to auto-tune.
If the quality of the audio is low, you can also try adjusting your antenna to get a better signal.

Playing a local radio station!