Rotary encoder response too slow

hi all,

I would like to add rotary encoder to control 7 segment display brightness on my clock project.

I have the code ready and everything works great when i have just one display and encoder, without any other code. The problem is when i try to add this code to existing clock project that has much more code than this test. Its almost not responsive at all, when i try to reduce brightness it does so after 10 seconds or so…

test code that works is below

#define CLK_PIN  2
#define DATA_PIN 3
#define YLED A1
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"


Adafruit_7segment disp = Adafruit_7segment();

////////////////////////////////////////////////////
void setup() {
   pinMode(CLK_PIN,INPUT);
   pinMode(DATA_PIN,INPUT);
   pinMode(YLED,OUTPUT);
   disp.begin(0x74);
}

////////////////////////////////////////////////////
void loop() {
   

    static int state=0,counter=0;

    state=(state<<1) | digitalRead(CLK_PIN) | 0xe000;

    if (state==0xf000){
       state=0x0000;
       if(digitalRead(DATA_PIN))
         counter--;
       else
         counter++;
       if (counter>15) {(counter = 15);}
       if (counter<0) {(counter = 0);}
        
       disp.print(counter);
       disp.writeDisplay();
       disp.setBrightness(counter);
    
    }
}

As as see it, i would need to use interrupt pins, but not sure how the code should look like in that case. Any help would be highly appreciated. I am using MEGA board.

Manythanks,
Alek

elcrni:
The problem is when i try to add this code to existing clock project that has much more code than this test. Its almost not responsive at all,

I think you are saying that the encoder is unresponsive when you incorporate it into the bigger program. That suggests that the problem is caused by the bigger program so you need to post that in your next Reply.

...R

Thanks Robin, here is the big code:

#include <TimeLib.h>
#include <DCF77.h>
#include <Wire.h>
#include <Adafruit_LEDBackpack.h>
#include <Adafruit_GFX.h>
#include <RTClib.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>


#define DCF77PIN 2              // Connection pin to DCF 77 device
#define DCF_INTERRUPT 0        // Interrupt number associated with pin
#define PIN_LED 22             // LED signalin that the DCF77 signal has been aquired
#define PIN_LED2 23            // LED (red) signaling loss of signal. Trigers every hour at :00 to update the signal status
#define PIN_LED_monday 24      // LED on if monday
#define PIN_LED_tuesday 25     // LED on if tuesday
#define PIN_LED_RTC_online 26  // Led on if RTC is online and battery OK
#define PIN_LED_RTC_offline 27 // Led on if RTC is offline or battery dead
#define CLK_PIN  18
#define DATA_PIN 19
#define YLED A1
#define SEALEVELPRESSURE_HPA (1013.25)


Adafruit_BME280 bme;
RTC_DS3231 rtc;



int _hours;
int _minutes;
int _seconds;
int _days;
int _months;
int _years;
int WeekDay =0;
int DOW;             // day of week 


float _temp; 
int roundtemp;

float _pressure; 
int roundpressure;

float _humidity; 
int roundhumidity;

int tensofdegrees, singledegrees, millidegrees;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

int singlehours, singleminutes, tensofhours, tensofminutes, tensofseconds, singleseconds, singledays, tensofdays, months, tensofmonths, years, tensofyears, hundredsofyears, thousandsofyears; 
unsigned long lastupdate = now();
unsigned long currenttime = now();

int update = 0;

Adafruit_7segment display1 = Adafruit_7segment();
Adafruit_7segment display2 = Adafruit_7segment();
Adafruit_7segment display3 = Adafruit_7segment();
Adafruit_7segment display4 = Adafruit_7segment();
Adafruit_7segment display5 = Adafruit_7segment();
Adafruit_7segment display6 = Adafruit_7segment();
Adafruit_7segment display7 = Adafruit_7segment();


DCF77 DCF = DCF77(DCF77PIN,DCF_INTERRUPT); // "false" is used for ELV DCF77 receivers as they have inverted signal
//=======================================================================================================================================================
// SETUP
//=======================================================================================================================================================

void setup() 
{
  Wire.begin();
  DCF.Start();
  Serial.begin(9600);
  pinMode(DCF77PIN, INPUT);
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_LED2, OUTPUT);
  pinMode(PIN_LED_monday, OUTPUT);
  pinMode(PIN_LED_tuesday, OUTPUT);
  pinMode(PIN_LED_RTC_online, OUTPUT);
  pinMode(PIN_LED_RTC_offline, OUTPUT);


  pinMode(CLK_PIN,INPUT);
  pinMode(DATA_PIN,INPUT);
  pinMode(YLED,OUTPUT);

  display1.begin(0x70);
  display2.begin(0x71);
  display3.begin(0x72);
  display4.begin(0x73);
  display5.begin(0x74);
  display6.begin(0x75);
  display7.begin(0x77);

  
  rtc.begin();
  if (! rtc.begin()) {
    Serial.println("RTC is NOT running.");
    } else {
    Serial.println("RTC is running.");
    DateTime now = rtc.now();
    setTime(now.unixtime());  //Set system clock from ds3231 once.
    }


    if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

}


//=======================================================================================================================================================
// LOOP
//=======================================================================================================================================================


void loop() 
{

time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
  if (DCFtime!=0)
  {
    Serial.print("DCF77 signal received and time updated! - @ ");
    Serial.print(tensofhours);
    Serial.print(singlehours);
    Serial.print(":");
    Serial.print(tensofminutes);
    Serial.print(singleminutes);
    Serial.print(":");
    Serial.print(tensofseconds);
    Serial.print(singleseconds);
    Serial.println();
    setTime(DCFtime);
    rtc.adjust(DCFtime);  //Set ds3231 from DCF
    lastupdate = now();
    currenttime = now();
    digitalWrite(PIN_LED, HIGH); // turns on LED that shows signal has been received and clock updated
    update = 1;
    }

  
  


dcf_status();    
show_displays();
//encoder_brightness();
}


//==============================================================================
// DCF STATUS Check
//
// This turns the DCF UPDATED LED off every hour
//==============================================================================


void dcf_status() {

if(minute() == 0) { update = 0; } //check every hour (at xx:00 minutes) to start a new cycle, it only resets the LEDs to update signal status
  if (update ==0)                          // when the dcf77 signal is not established yet
  {
   digitalWrite(PIN_LED2, HIGH);
   digitalWrite(PIN_LED, LOW);
  }

  if (update ==1)
  {
   digitalWrite(PIN_LED2, LOW);  // LED2 (red) turns off when signal is successfully received
 
  }

}




//==============================================================================
// SHOW DISPLAYS
//==============================================================================

void show_displays(){


// Day Of The Week LEDs
    
     if (DOW == 2) {
     digitalWrite(PIN_LED_monday, HIGH); //monday
     } else {
      digitalWrite(PIN_LED_monday, LOW); //monday
     }
     if (DOW == 3) {
     digitalWrite(PIN_LED_tuesday, HIGH); //tuesday
     } else {
      digitalWrite(PIN_LED_tuesday, LOW); //monday
     }


// if RTC is disconnected a red LED will turn on, otherwise yellow LED is on.

    if (! rtc.begin()) {
    digitalWrite(PIN_LED_RTC_offline, HIGH);
    digitalWrite(PIN_LED_RTC_online, LOW);
    } else {
    digitalWrite(PIN_LED_RTC_offline, LOW);
    digitalWrite(PIN_LED_RTC_online, HIGH);
    }



//=============================
// DATE & TIME
//=============================
    

  DateTime now = rtc.now();
 
  _hours = now.hour();
  _minutes = now.minute();
  _seconds = now.second();
  _days = now.day();
  _months = now.month();
  _years = now.year();
  DOW = now.dayOfTheWeek();
 

  // define time and date
  singlehours = _hours % 10;
  tensofhours = _hours / 10;
 
  singleminutes = _minutes % 10;
  tensofminutes = _minutes / 10;
 
  singleseconds = _seconds % 10;
  tensofseconds = _seconds / 10;

  singledays = _days % 10;
  tensofdays = _days / 10;

  months = _months % 10;
  tensofmonths = _months / 10;

  years = _years % 10;
  tensofyears = (_years /10)%10;
  hundredsofyears = (_years /100)%10;
  thousandsofyears = (_years /1000)%10;

  
  // define each digit - 0 is the first left, 2 is decimal dots.
  
  display1.writeDigitNum(0, tensofhours);
  display1.writeDigitNum(1, singlehours);
  display1.writeDigitNum(3, tensofminutes);
  display1.writeDigitNum(4, singleminutes);
  display1.drawColon(true);
  display1.writeDisplay();
 

}

//=============================
// ENCODER BRIGHTNESS
//=============================

void encoder_brightness(){

  static int state=0,counter=0;

    state=(state<<1) | digitalRead(CLK_PIN) | 0xe000;

    if (state==0xf000){
       state=0x0000;
       if(digitalRead(DATA_PIN))
         counter--;
       else
         counter++;
       if (counter>15) {(counter = 15);}
       if (counter<0) {(counter = 0);}
        
       //disp.print(counter);
       //disp.writeDisplay();
       display1.setBrightness(counter);
       display2.setBrightness(counter);
       display3.setBrightness(counter);
       display4.setBrightness(counter);
       display5.setBrightness(counter);
       display6.setBrightness(counter);
       display7.setBrightness(counter);
    }


}

Thanks,
Alek

I suspect the problem is that you are doing a lot of stuff on every iteration of loop() that probably only needs to be done once or twice per second - for example updating the time and the display. All that code takes time so that loop() is not repeating fast enough to read the encoder in a responsive way.

It would probably be a good idea to reorganise the code so it only updates things (say) 10 times per second and on each of those occasions it only does 25% of the work so it takes 400 millisecs to do get around to doing everything once. Of course the encoder won't be part of that - it should be updated as often as possible.

You could perhaps use an interrupt to detect the encoder pulses.Your program is already using the external interrupt on pin2 (assuming you are using an Uno) but if you just need a single pin for the encoder you could use interrupt1 which is on pin3. If you need to detect 2 encoder pins then you will need to use a pinChange interrupt which is a little more complicated.

I can't say whether interrupts alone would solve the brightness update speed problem because in part it will still depend on the speed at which loop() repeats.

...R

Thanks Robin,

Yes, i would need to slow the loop repeat but i do not want to use delay() and not so familiar with millis()
this also causes a problem with sensor reading on 7 segment displays, as they are updating way too fast, i would also like to slow this down as well but again, not to affect the clock.

I use MEGA so have more interrupt pins. As for encoder, not sure if i need to interrupt CLK pin only or DT as well?

Many thanks,
Alek

elcrni:
Yes, i would need to slow the loop repeat

That’s the opposite of what you need. You need to speed it up so it can attend to the encoder more frequently.

The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

…R

Ok, i have added this code:

void show_displays(){

if (second() != previousSecond)
  {

    previousSecond = second();

and then it runs displays, day of week, clock, sensors etc... Now the encoder works in real time BUT, my clock is now always one second behind... any idea how to remedy this?

Many thanks,
Alek

elcrni:
and then it runs displays, day of week, clock, sensors etc... Now the encoder works in real time BUT, my clock is now always one second behind... any idea how to remedy this?

You are not giving me much to go on. I don't think I would notice if a clock was 1 second wrong.

Have you tried updating at half-second intervals?

...R

no no, dont get me wrong, 1 second behind is OK, DCF77 keeps the clock in sync so i know it will be accurate, the thing here is a mild OCD and that one second just bothers me :slight_smile: not super important like something has to happen at exactly one second and on exactly accurate time. :slight_smile:

i have now redefined my loop() to look like this:

void loop() 
{

dcf_time_update();
tasksEverySecond();
tasksEveryMinute();
encoder_brightness();
}

then i call the clock, dcf... in "void tasksEverySecond()", sensors in EveryMinute etc.

If i could speed it up a bit more, like half second as you said, that would be great. How would the code for half a second look like?

Many thanks,
Alek

ok, i think i got it

unsigned long previousMillis = 0;
const long interval = 100;

So not half a second but 1/10th of a second, it works like a charm and i only 1/10th of a second behind now!

Many thanks,
Alek