I used following sketch to combination of my Arduino Nano, cheap RDA5807 and 128X64 OLED.
#include <Tiny4kOLED.h>
#include <RDA5807.h>
#include <Wire.h>
#include <SPI.h>
#include "Rotary.h"
// Enconder PINs
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3
// Buttons controllers
#define VOLUME_UP 4 // Volume Up
#define VOLUME_DOWN 5 // Volume Down
#define SWITCH_STEREO 6 // Select Mono or Stereo
#define SWITCH_RDS 7 // SDR ON or OFF
#define SEEK_FUNCTION 8 // SEEk
#define STEREO_LED 9
#define POLLING_TIME 2000
#define POLLING_RDS 80
char oldFreq[10];
char oldStereo[10];
char oldRssi[10];
char oldRdsStatus[10];
char oldRdsMsg[65];
bool bSt = true;
bool bRds = true;
bool bShow = false;
uint8_t seekDirection = 1; // 0 = Down; 1 = Up. This value is set by the last encoder direction.
long pollin_elapsed = millis();
char *rdsMsg;
char *stationName;
char *rdsTime;
char bufferStatioName[16];
char bufferRdsMsg[40];
char bufferRdsTime[20];
long stationNameElapsed = millis();
long polling_rds = millis();
long clear_fifo = millis();
// Encoder control variables
volatile int encoderCount = 0;
uint16_t currentFrequency;
RDA5807 rx;
Rotary encoder = Rotary(ENCODER_PIN_A, ENCODER_PIN_B);
void setup() {
Serial.begin(9600);
oled.begin(128, 64, sizeof(tiny4koled_init_128x64br), tiny4koled_init_128x64br);
oled.clear();
oled.on();
oled.setFont(FONT6X8);
pinMode(ENCODER_PIN_A, INPUT_PULLUP);
pinMode(ENCODER_PIN_B, INPUT_PULLUP);
// Push button pin
pinMode(VOLUME_UP, INPUT_PULLUP);
pinMode(VOLUME_DOWN, INPUT_PULLUP);
pinMode(SWITCH_STEREO, INPUT_PULLUP);
pinMode(SWITCH_RDS, INPUT_PULLUP);
pinMode(SEEK_FUNCTION, INPUT_PULLUP);
pinMode (STEREO_LED, OUTPUT);
// Encoder interrupt
attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), rotaryEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), rotaryEncoder, CHANGE);
rx.setup();
rx.setVolume(10);
rx.setMono(false); // Force stereo
rx.setRBDS(true); // set RDS and RBDS. See setRDS.
rx.setRDS(true);
rx.setRdsFifo(true);
rx.setFrequency(9450); // It is the frequency you want to select in MHz multiplied by 100.
rx.setSeekThreshold(50); // Sets RSSI Seek Threshold (0 to 127)
oled.clear();
showStatus();
}
void loop() {
if (encoderCount != 0)
{
if (encoderCount == 1) {
rx.setFrequencyDown();
seekDirection = RDA_SEEK_DOWN;
}
else {
rx.setFrequencyUp();
seekDirection = RDA_SEEK_UP;
}
bShow = true;
encoderCount = 0;
showFrequency();
}
if (digitalRead(VOLUME_UP) == LOW)
rx.setVolumeUp();
else if (digitalRead(VOLUME_DOWN) == LOW)
rx.setVolumeDown();
else if (digitalRead(SWITCH_STEREO) == LOW)
doStereo();
else if (digitalRead(SWITCH_RDS) == LOW)
doRds();
else if (digitalRead(SEEK_FUNCTION) == LOW)
doSeek();
if ( (millis() - pollin_elapsed) > POLLING_TIME ) {
showStatus();
if ( bShow ) clearRds();
pollin_elapsed = millis();
}
if ( (millis() - polling_rds) > POLLING_RDS) {
if ( bRds ) {
showRds();
}
polling_rds = millis();
}
delay(100);
}
void rotaryEncoder()
{ // rotary encoder events
uint8_t encoderStatus = encoder.process();
if (encoderStatus)
encoderCount = (encoderStatus == DIR_CW) ? 1 : -1;
}
/*
Shows frequency information on oled.
*/
void showFrequency()
{
oled.setFont(FONT8X16);
oled.setCursor(30, 0);
oled.print(" ");
oled.setCursor(30, 0);
oled.print(rx.getRealFrequency() / 100.0);
oled.setFont(FONT6X8);
oled.setCursor(98, 0);
oled.print("MHz");
}
/*
Show some basic information on display
*/
void showStatus()
{
oldFreq[0] = oldStereo[0] = oldRdsStatus[0] = oldRdsMsg[0] = 0;
showFrequency();
showStereoMono();
showRSSI();
}
/* *******************************
Shows RSSI status
*/
void showRSSI()
{
int rssi = rx.getRssi();
oled.setCursor(5, 2);
oled.print(" ");
oled.setCursor(5, 2);
oled.print(rssi);
int vol = rx.getVolume();
oled.setCursor(30, 2);
oled.print(" ");
oled.setCursor(30, 2);
oled.print(vol);
}
void showStereoMono() {
oled.setCursor(80, 2);
oled.print(" ");
oled.setCursor(80, 2);
oled.print((rx.isStereo()) ? "Stereo" : "Mono");
}
/*******************************
Process seek command.
The seek direction is based on the last encoder direction rotation.
*******************************/
void doSeek() {
rx.seek(RDA_SEEK_WRAP, seekDirection, showFrequency); // showFrequency will be called by the seek function during the process.
delay(200);
bShow = true;
showFrequency();
}
void doStereo() {
rx.setMono((bSt = !bSt));
bShow = true;
showStereoMono();
delay(100);
}
void doRds() {
rx.setRDS((bRds = !bRds));
showRds();
}
/*********************************************************
RDS Data
**********************************************************/
void showRds() {
oled.setCursor(0, 0);
oled.print(" ");
oled.setCursor(0, 0);
oled.print((bRds) ? "ON" : "OFF");
checkRDS();
}
void checkRDS()
{
// check if RDS currently synchronized; the information are A, B, C and D blocks; and no errors
if ( rx.hasRdsInfo() ) {
rdsMsg = rx.getRdsText2A();
stationName = rx.getRdsText0A();
rdsTime = rx.getRdsTime();
if (rdsMsg != NULL)
showRDSMsg();
if ((millis() - stationNameElapsed) > 1000)
{
if (stationName != NULL)
showRDSStation();
stationNameElapsed = millis();
}
if (rdsTime != NULL)
showRDSTime();
}
if ( (millis() - clear_fifo) > 10000 ) {
rx.clearRdsFifo();
clear_fifo = millis();
}
}
void showRDSMsg()
{
rdsMsg[32] = bufferRdsMsg[32] = '\0'; // Truncate the message to fit on oled. You can try scrolling
if (strcmp(bufferRdsMsg, rdsMsg) == 0)
return;
//printValue(10, 5, bufferRdsMsg, rdsMsg, 4);
delay(250);
}
/**
TODO: process RDS Dynamic PS or Scrolling PS
*/
void showRDSStation()
{
if (strncmp(bufferStatioName, stationName, 3) == 0)
return;
//printValue(10, 6, bufferStatioName, stationName, 4);
//String v2 = String(stationName);
oled.setCursor(0, 6);
oled.print(stationName);
// Serial.print("St Name : ");
//Serial.print(stationName);
delay(250);
}
void showRDSTime()
{
if (strcmp(bufferRdsTime, rdsTime) == 0)
return;
//printValue(10, 7, bufferRdsTime, rdsTime, 4);
oled.setCursor(0, 7);
oled.print(rdsTime);
// Serial.print(" Time :");
//Serial.println(rdsTime);
delay(100);
}
void clearRds() {
bShow = false;
}
void printValue(int col, int line, char *oldValue, char *newValue, uint8_t space)
{
int c = col;
char *pOld;
char *pNew;
pOld = oldValue;
pNew = newValue;
// prints just changed digits
while (*pOld && *pNew)
{
if (*pOld != *pNew)
{
// Erases olde value
oled.setCursor(c, line);
oled.print(" ");
oled.setCursor(c, line);
oled.print(*pOld);
// Writes new value
oled.setCursor(c, line);
oled.print(*pNew);
}
pOld++;
pNew++;
c += space;
}
// Is there anything else to erase?
while (*pOld)
{
oled.setCursor(c, line);
oled.print(" ");
oled.setCursor(c, line);
oled.print(*pOld);
pOld++;
c += space;
}
// Is there anything else to print?
while (*pNew)
{
oled.print(*pNew);
pNew++;
c += space;
}
// Save the current content to be tested next time
strcpy(oldValue, newValue);
}
My radio is working properly without RDS mode. but when its goes to RDS mode it couldn't decode RDS data in proper signal level. It gives some symbols ( ,@pp4 ,,, / ; ) in different commercial bands. But I know there is clear RDS data in my area (eg. Channel name / Local time data).
I want to make sure is any problem in my sketch or my module. I tried many examples from internet but unable to success. So hope your help to fix this problem. apologies for bad English because English is not my mother language.