Radio Frequency Rotary Encoder Control problem

Hi. I'm trying to change the frequency of my TEA5767 FM radio using a Rotary Encoder. The problem is that when I rotate the encoder, the frequency increases, and if I rotate the encoder in the opposite direction, the frequency increases. If I try to use an interrupt to check the Rotary Encoder, the frequency does not change. If I rotate the encoder, and if I try to upload the sketch again, the IDE sometimes "freezes" and it's stuck on "Uploading".

This is the sketch I wrote:

#include <LiquidCrystal.h>
#include <Wire.h>
#include <TEA5767N.h>
const int CL = 7;
int CLlast;
const int DT = 11;
float prevFreq;
const int rs = 4, en = 5, d4 = 6, d5 = 13, d6 = 8, d7 = 9;
//LCD Symbols (Custom)
byte stereo[] = {
  B00000,
  B10001,
  B10001,
  B11011,
  B11011,
  B10001,
  B10001,
  B00000
};

byte mono[] = {
  B00010,
  B00110,
  B01110,
  B11110,
  B11110,
  B01110,
  B00110,
  B00010
};
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
TEA5767N radio = TEA5767N();
void setup() {
  pinMode(DT, INPUT);
  pinMode(CL, INPUT);
  CLlast = digitalRead(CL);
  lcd.begin(16, 4);
  lcd.createChar(0, stereo);
  lcd.createChar(1, mono);
  welcomeScreen();
  radio.setStandByOff();
  radio.selectFrequency(87.7);
  prevFreq = radio.readFrequencyInMHz();
  radioScreen(radio.readFrequencyInMHz(), radio.isStereo(), radio.getSignalLevel());
}

void loop() {
  if(prevFreq != radio.readFrequencyInMHz()){
    radioScreen(radio.readFrequencyInMHz(), radio.isStereo(), radio.getSignalLevel());
    prevFreq = radio.readFrequencyInMHz();
  }
  int clval = digitalRead(CL);
  if(clval != CLlast){
    if(digitalRead(DT) != clval){
      next();
    } else {
      prev();
    }
  }
  CLlast = clval;
  delay(150);
}

void welcomeScreen(){
  lcd.clear();
  lcd.home();
  lcd.print("VokRadio v1-BETA");
  lcd.setCursor(0, 1);
  lcd.print("Starting . . .");
  delay(1000);
  lcd.clear();
}

void radioScreen(float freq, bool stereoState, int signalLvl){
  lcd.clear();
  lcd.home();
  lcd.print(String(freq));
  lcd.print("MHz | ");
  if(stereoState){
    lcd.setCursor(15, 0);
    lcd.write(byte(0));
  } else {
    lcd.setCursor(15, 0);
    lcd.write(byte(1));
  }
  lcd.setCursor(0, 1);
  lcd.print("SQ: " + String(signalLvl));
}
void next(){
  if(radio.readFrequencyInMHz() <= 78){
      return;
  } else {
    prevFreq = radio.readFrequencyInMHz() - 0.1f;
    radio.selectFrequency(radio.readFrequencyInMHz() - 0.1f);
    delay(5);
  }
}
void prev(){
  if(radio.readFrequencyInMHz() >= 108){
      return;
    } else {
      prevFreq = radio.readFrequencyInMHz() + 0.1f;
      radio.selectFrequency(radio.readFrequencyInMHz() + 0.1f);
      delay(5);  
    }
}

Interrupt version:

#include <LiquidCrystal.h>
#include <Wire.h>
#include <TEA5767N.h>
const int CL = 7;
int CLlast;
const int DT = 11;
float prevFreq;
const int rs = 4, en = 5, d4 = 6, d5 = 13, d6 = 8, d7 = 9;
//LCD Symbols (Custom)
byte stereo[] = {
  B00000,
  B10001,
  B10001,
  B11011,
  B11011,
  B10001,
  B10001,
  B00000
};

byte mono[] = {
  B00010,
  B00110,
  B01110,
  B11110,
  B11110,
  B01110,
  B00110,
  B00010
};
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
TEA5767N radio = TEA5767N();
void setup() {
  pinMode(DT, INPUT);
  pinMode(CL, INPUT);
  CLlast = digitalRead(CL);
  attachInterrupt(digitalPinToInterrupt(CL), isr0, CHANGE);
  lcd.begin(16, 4);
  lcd.createChar(0, stereo);
  lcd.createChar(1, mono);
  welcomeScreen();
  radio.setStandByOff();
  radio.selectFrequency(87.7);
  prevFreq = radio.readFrequencyInMHz();
  radioScreen(radio.readFrequencyInMHz(), radio.isStereo(), radio.getSignalLevel());
}

void loop() {
  if(prevFreq != radio.readFrequencyInMHz()){
    radioScreen(radio.readFrequencyInMHz(), radio.isStereo(), radio.getSignalLevel());
    prevFreq = radio.readFrequencyInMHz();
  }
  delay(1000);
}

void welcomeScreen(){
  lcd.clear();
  lcd.home();
  lcd.print("VokRadio v1-BETA");
  lcd.setCursor(0, 1);
  lcd.print("Starting . . .");
  delay(1000);
  lcd.clear();
}

void radioScreen(float freq, bool stereoState, int signalLvl){
  lcd.clear();
  lcd.home();
  lcd.print(String(freq));
  lcd.print("MHz | ");
  if(stereoState){
    lcd.setCursor(15, 0);
    lcd.write(byte(0));
  } else {
    lcd.setCursor(15, 0);
    lcd.write(byte(1));
  }
  lcd.setCursor(0, 1);
  lcd.print("SQ: " + String(signalLvl));
}
void next(){
  if(radio.readFrequencyInMHz() <= 78){
      return;
  } else {
    prevFreq = radio.readFrequencyInMHz() - 0.1f;
    radio.selectFrequency(radio.readFrequencyInMHz() - 0.1f);
    delay(5);
  }
}
void prev(){
  if(radio.readFrequencyInMHz() >= 108){
      return;
    } else {
      prevFreq = radio.readFrequencyInMHz() + 0.1f;
      radio.selectFrequency(radio.readFrequencyInMHz() + 0.1f);
      delay(5);  
    }
}

void isr0(){
  int clval = digitalRead(CL);
  if(clval != CLlast){
    if(digitalRead(DT) != clval){
      next();
      Serial.println("up");
    } else {
      prev();
      Serial.println("down");
    }
  }
  CLlast = clval;
  delay(800);
}

If I try to use my Rotary Encoder using this simple sketch:

const int CL = 2;
int CLlast;
const int DT = 23;
void setup() {
  Serial.begin(9600);
  pinMode(DT, INPUT);
  pinMode(CL, INPUT);
  CLlast = digitalRead(CL);
  attachInterrupt(digitalPinToInterrupt(CL), isr0, CHANGE);
}

void loop() {
  
  
}

void isr0(){
  int clval = digitalRead(CL);
  if(clval != CLlast){
    if(digitalRead(DT) != clval){
      Serial.println ("clockwise");
    } else {
      Serial.println("counterclockwise");
    }
  }
  CLlast = clval;
  delay(800);
}

it works perfectly.

Post your program code here. I am not wandering off to some other website to look for it.

You should not have Serial.print() statements inside an ISR. An ISR should be written so that it completes as quickly as possible. Do the printing in loop()

...R

Sorry, I updated the post. The code is now there.

Looking at your first program ...

You have lots of functions in your program (which is good) so I can't understand why you don't have a specific function to read the encoder. Then you could print the values to see what the program is getting from the encoder. Your symptoms sound as if you are not detecting the direction of the encoder properly. Why not write a short program that does nothing but read the encoder and show the values on the Serial Monitor?

And rather than use the encoder to control the volume directly I would use the encoder to increment or decrement an Arduino variable and I would update the volume when that variable changes. Separating things like that makes debugging much easier.

Looking at your second program ...

Your ISR is a dog's breakfast (and that's being polite :slight_smile: ). Your ISR should do nothing but increment or decrement a variable - the absolute minimum that you can get away with.

...R

What Arduino are you using? Which encoder? How is it wired?

What happens with the interrupt version if you put it on the same pin as the simple interrupt version which works.