RDA5807 with OLED RDS problem

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.

I miss the link to the used libtaries. The Tiny4kOLED library I found is written for an ATtiny and a 128x32 display. Which one are you using?

Is your RDS system using only ASCII characters?

Actually I am new to Arduino I don't know about ASCII characters. I tested above sketch with my 128x64 OLED its shows frequency, RSSI, and volume data. but It couldn't decode RDS data properly. After I tested this sketch but same problem.

#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#include <RDA5807.h>
#include <Wire.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

#define I2C_ADDRESS 0x3C

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);
SSD1306AsciiAvrI2c oled;
void setup() {
  Serial.begin(9600);
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
  oled.setFont(Adafruit5x7);
  oled.set1X();

  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(9480); // 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);
Serial.println();
}

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();
  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("               ");
  oled.setCursor(0, 6);
  oled.print(stationName);
  Serial.print("St Name : ");
  Serial.print(stationName);
  delay(1000);
}

void showRDSTime()
{
  if (strcmp(bufferRdsTime, rdsTime) == 0)
    return;
  //printValue(10, 7, bufferRdsTime, rdsTime, 4);
  //String v3 = String(rdsTime);
    oled.setCursor(0, 7);
  oled.print("               ");
  oled.setCursor(0, 7);
  oled.print(rdsTime);
  Serial.print("  Time :");
  Serial.println(rdsTime);
  delay(1000);
}


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);
      Serial.print(*pOld);
      Serial.print("     ");
      // Writes new value

      oled.setCursor(c, line);
      oled.print(*pNew);
      Serial.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);
    Serial.print(*pOld);
    pOld++;
    c += space;
  }

  // Is there anything else to print?

  while (*pNew)
  {

    oled.print(*pNew);
    Serial.print(*pNew);
    pNew++;
    c += space;
  }

  // Save the current content to be tested next time
  strcpy(oldValue, newValue);
}


I m stuck with this problem. Please help to fix it.

ASCII characters are limited to the characters the English language uses. You seem to live in a world where more than that basic set is needed to show the local language.

The version of the library I found doesn't support the 128x64 OLED. In the new code you're using even another library but you still failed to post a link to the version you're using!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.