Functions at same time getting stucked

Hello,

I am slowly getting better at coding, little by little, and I am now experimenting creating my own block of functions to make the coding more organized and properly done. Regardless of my effort in understanding how it works, reading all I can, I think I am clearly missing something...

I have a rotary encoder that I use both as a rotary encoder and as a push button (connecting all 5 pins) and an i2c display. The aim is to select a variable in an array with the rotary encoder, use the button to trigger different modes of the program and display everything on the i2c display.

The problem arise as I have 3 functions running in void loop() and the display one seems to be "predominant":

  1. readEncoder() to read the rotary encoder and save a counter based on the encoder position to select the variable in the array.
  2. readButton() to read the button states changes.
  3. displayInfo() to print all the information of the display.

This way, I correctly print the button state on the display but I cannot read the encoder (I've tried to with Serial.print to see if it was reading but not printing to the display, but it doesn't read at all).

The only way I found to make it work is to collapse readEncoder() and readButton() into one single function and recall displayInfo() within the same function but it doesn't seems the smartest way to approach the problem.

I haven't posted the code because it's very long and tedious but if you need it I'll post it next time.

Sorry for my poor knowledge and if I might have said some silly things, I'm trying my best.

Many many thanks,

Alessandro

There are rotary encoders and then there are other rotary encoders, and then there are even more rotary encoders. Which one, exactly, do you have?
Paul

I haven't posted the code because it's very long and tedious but if you need it I'll post it next time.

we can’t help without seeing that

Thank you very much for your help!

The rotary encoder I am using is an EC11, leftover from another project I did.

Here is the code, some clarification:
a) You'll see the code for the encoder is structured to manage various encoder, I am using only one for this project.
b) The double IF statement within encoder (to keep counter[0] within 0-25 range, as I need it for this project), could be probably be written better, outside encoder() but I had no time so far, still it works.
c) The whole sketch is divided into 3 tabs, that's the reason for the method declaration before void setup();.

The problem is that displayvisualization(); blocks my encoder reading.
I can't get why the encoder gets stucked and not the button.

Many thanks for your help!

Alessandro

MAIN TAB

// -----------------------------------------------------------------------------
// Libraries
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Display
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(128, 32, &Wire, OLED_RESET);

// -----------------------------------------------------------------------------
// Mode Buttons
const byte modeButton = A3;

// -----------------------------------------------------------------------------
// Clk & Data pins for each encoder
byte pinClk   [] = {A2};
byte pinData  [] = {A1};
#define N_ENC   sizeof(pinData)     // determine # of encoders

// -----------------------------------------------------------------------------
// Methods Declarations

int readModeButton();
void displayvisualization ();
int8_t read_rotary();
int encoder();

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

void setup() {
  
  pinMode(modeButton, INPUT_PULLUP);
  
  Serial.begin(9600);
  Serial.println("Test Begin");

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
  Serial.println(F("SSD1306 allocation failed"));
  for(;;); // Don't proceed, loop forever
  }

  // -----------------------------------------------------------------------------
  // Rotary Encoders Pin Set-up
  for (int i=0; i < N_ENC; i++){
  pinMode (pinData[i], INPUT_PULLUP);
  pinMode (pinClk[i], INPUT_PULLUP);
}
  
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void loop() {
  int mode = readModeButton(3);
  //Serial.print(mode);
  int a_counter = encoder(0);
  //Serial.print(a_counter);
  displayvisualization (mode, a_counter); // THIS BLOCK THE ROTARY ENCODER
}
// -----------------------------------------------------------------------------

TAB 1

// -----------------------------------------------------------------------------
// Read the SW Button of specific encoder
int readModeButton(int modeTotNumber){
  
  static byte modeCounter = 1;
  static byte modeNow;
  static byte modePrevious;

  uint32_t now = 0;
  int debounce_delay = 150;
    
  modeNow = digitalRead(modeButton);
  if ((millis()-now) > debounce_delay){
    if (modeNow == LOW && modePrevious == HIGH){
    if (modeCounter == modeTotNumber) modeCounter = 0;
    modeCounter += 1;
    Serial.println(modeCounter);
    modePrevious = modeNow;
    }
    else if (modeNow == HIGH && modePrevious == LOW){  
      modePrevious = modeNow;   
    }
    now = millis();
}
return modeCounter;
}

// -----------------------------------------------------------------------------
// Display Visualization
void displayvisualization (int mode, int a_counter) {
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setTextSize(1);
      display.setCursor(0, 0);
      display.print("Display TEST");
      display.setCursor(0, 8);
      display.print("MODE: "); display.print(mode);
      display.setCursor(0,16);
      display.print("A Counter "); display.print(a_counter);
      display.display();
  
}

TAB 2

// -----------------------------------------------------------------------------
// A vald CW or  CCW move returns 1, invalid returns 0.
int8_t read_rotary (int  & store, int  & prevNextCode, byte data, byte clk )
{
    static int8_t rot_enc_table[] = {
        0,1,1,0,   1,0,0,1,
        1,0,0,1,   0,1,1,0 };

    prevNextCode <<= 2;
    prevNextCode  |= data << 1;
    prevNextCode  |= clk;
    prevNextCode  &= 0x0F;

    // If valid then store as 16 bit data.
    if  (rot_enc_table [prevNextCode] ) {
        store <<= 4;
        store  |= prevNextCode;
        store  &= 0xFF;

        if (store == 0x2b) {
          return -1;
        }
        if (store == 0x17) {
          return 1;
        }
    }
    return 0;   // invalid input
}

// -----------------------------------------------------------------------------
// Rotary Encoders

int encoder (int  idx ) {
    
    // allocate state variables for each encoder (i.e. N_ENC)
    static int  encState   [N_ENC] = {};
    static int  encInp     [N_ENC] = {};
    static long encPos     [N_ENC] = {};
    static long prevencPos [N_ENC] = {};
    static int res;
    
    res = read_rotary (encState [idx], encInp [idx],
                            digitalRead (pinData [idx]),
                            digitalRead (pinClk  [idx]) );
                            
    encPos [idx] += res;
    static int counter [N_ENC];

    if (res == -1) {
      if(idx == 0 && counter[0] > 0) {
        counter[0]--;
        Serial.println(counter[0]);
        } 
    }
    
    if (res == 1) {
       if(idx == 0 && counter[0] < 24) {
        counter[0]++;
        Serial.println(counter[0]);
        }
    }
    
    if (res)  {
        char s [80];
        sprintf (s, " %d: %02X %2d", idx, encState [idx], encPos [idx]);
        //Serial.println (s);
    }
    return counter[0];
}

No one...!? :frowning:

Ale_V:
No one...!? :frowning:

hey a bit of patience, you are asking for help from volunteers... You are not entitled to a 24/7 instant free support line or anything... It's not well regarded to bump your own thread just after a few hours. In the future wait at least 2 or 3 days if you don't get an answer and if you've not solved it in the mean time.

The problem is that displayvisualization(); blocks my encoder reading.

I'd say it's not blocking it but likely taking way too long to deal with the fast timing required by encoders and you are missing the encoder transitions (fronts) and thus getting incoherent behaviors. A button press is handled in "user time", likely hundreds of ms, so will be seen even if the display function is slow

To solve this:

  • make your displayvisualization() function go faster --> don't display anything if the data to display has not changed. a crude version could be this
void displayvisualization (int mode, int a_counter) {
  static int prev_mode = -10000;      // unlikely initial value
  static int prev_counter = -10000;   // unlikely initial value

  if ((mode != prev_mode) || (a_counter != prev_counter)) {
    // could be further optimized by not clearing the screen and only repainting the data fields that have changed
    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.print("Display TEST");
    display.setCursor(0, 8);
    display.print("MODE: "); display.print(mode);
    display.setCursor(0, 16);
    display.print("A Counter "); display.print(a_counter);
    display.display();
    mode = prev_mode;
    a_counter = prev_counter;
  }
}

you should further optimize this code ton only display what has really changed (the data not the labels) and not call clear()

PS: there are many warnings likely in the code you posted (handling signed and unsigned integers is one), fix those. The compiler is your friend.

hey a bit of patience, you are asking for help from volunteers... You are not entitled to a 24/7 instant free support line or anything... It's not well regarded to bump your own thread just after a few hours. In the future wait at least 2 or 3 days if you don't get an answer and if you've not solved it in the mean time.

Terrible sorry about that!
I didn't know the "timing etiquette", I just thought my post would have been so old that nobody would see it.
I won't do it again, thanks for the comment.

I'll try the modifications you suggested and let you know, thank you!

PS: there are many warnings likely in the code you posted (handling signed and unsigned integers is one), fix those. The compiler is your friend.

I didn't get this part, what do you mean?
I cannot use signed and unsigned integers together?

Thank you very much again for your precious help!

Ale

I didn't get this part, what do you mean?

in the IDE preferences, turn on compiler warnings.
When you compile you'll see some orange text. those are compilers warnings or errors. You need yo modify the code so that they go away.

for exemple when you do#define N_ENC  sizeof(pinData)    // determine # of encodersthe implicit type of N_ENC (when the macro will get replaced) is an unsigned long. So when you do   for (int i=0; i < N_ENC; i++){...you are comparing i which is a signed integer with N_ENC which is unsigned. You'll get a warning. The way to solve it since you likely won't have more than 255 encoders is to do   for (byte i=0; i < N_ENC; i++){and instead of a macro you could also use a constant const byte N_ENC =    sizeof pinData / sizeof pinData[0] ;    // determine # of encodersthat will help the compiler know what type you want to deal with.

I just thought my post would have been so old that nobody would see it.

Anyone who has already replied would find it in their 'Updated topics'

Anyone who has already replied would find it in their 'Updated topics'

Thank you, I did not know that!

in the IDE preferences, turn on compiler warnings.

Thank you, I did not know that as well!
I'll make the modifications you suggested!

    mode = prev_mode;
    a_counter = prev_counter;

I guess it was:

prev_mode = mode;
prev_counter = a_counter;

Like this i works perfectly, thank you very much!!!

I guess it was:

prev_mode = mode;

prev_counter = a_counter;



Like this i works perfectly, thank you very much!!!

good job, if I had given you the full working solution you would not have used your brain :slight_smile:

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