interrupt with "if" function - dont work

I am designing a code for audio test equipment.
I am using a rotary encoder with push button function.

I would like the rotary encoder to be able to work with 2 different counting limits.

  1. Counting 3 to 6 for a menu function – this function also “more” an indicator on the display
  2. Counting 100 to 400 for a DAC / VCA function

Both functions works, but not together.
I am trying to use a volatile flag to tell the interrupt to change between the two functions.
But this doesn’t work.

Code-18-3-4-RotaryEncoder-OLED-Button-Interrupt.ino (4.11 KB)

I would not have any of that oled.nnn code called by an ISR - it will be far too slow.

I suggest you don't call the function ChangeValue() from ISR (PCINT2_vect) but rather change the ISR code to update the count directly. There is no reason why you could not have a simple IF statement inside the ISR. I think this should work

ISR (PCINT2_vect){                                             // Encoder control
  byte a = PIND>>EncoderA & 1; 
  byte b = PIND>>EncoderB & 1;
  byte changeVal;
  if (a != a0){
    a0 = a;
    if (b != c0){
 c0 = b;
 changeVal = (a == b);
 }
 if (func == HIGH) {
 Count = max(min((Count + (changeVal ? 1 : -1)), 400), 100);
 }
 else {
 Count = max(min((Count + (Up ? 1 : -1)), 6), 3);
 }
 newEncoderVal = true;
  }
}

Then in loop you can call a function that prints stuff to the Oled if newEncoderVal == true

...R

Robin2 - Thanks for a fast reply / help I have implemented your suggestion. I can get the chooise when starting the sketch.

Still the shift function after 1. push button action do not work. Or the rotary coder stops the first counting (limits) but dont start the second counting (limits)

This code is the code not activating the rotary coder interrupt:

void Impedance(){ func = HIGH; // dont work !!! oled.clear(); oled.setFont(ClassicX8x8); oled.setCursor(30, 0); oled.print("Impedance"); oled.setCursor(40, 1); oled.print("T E S T");

while(digitalRead(2)== LOW); }

classic: Robin2 - Thanks for a fast reply / help I have implemented your suggestion.

Post the complete latest version of your program.

Suppose the option is chosen which allows a count up to 400 and the actual value is (say) 231 what should happen if the option is changed to set the max at 6?

...R

Thank you for helping - Robin2!

This is the full sketch.

A small remark - the sketch is “a step” on the way to the final design.
But I need to see this part working before I continue.

Code-18-3-4-RotaryEncoder-OLED-Button-Interrupt.ino (4.11 KB)

The code attached to Reply #4 seems to be the same as in the Original Post.

And for short programs please just include the code in your Reply using the code button . Many people (not me) read the Forum on a Tablet and can't download attachments.

...R

Sorry...

/*  Sketch - based on:
 *  Bounce-Free Rotary Encoder for the Arduino Uno - see http://www.technoblogy.com/show?1YHJ
 *  David Johnson-Davies - www.technoblogy.com
 *  Arduino Uno Code
*******************************************************************************************************/

#include "SSD1306Ascii.h"          // OLED
#include "SSD1306AsciiAvrI2c.h"    // OLED
#include "Classic8x8.h"            // OLED
#include "ClassicX8x16.h"          // OLED
#include "ClassicX8x8.h"           // OLED

SSD1306AsciiAvrI2c oled;           // OLED
#define I2C_ADDRESS 0x3C           // OLED

const int LED = 8;                                                
const int EncoderA = 4;            
const int EncoderB = 5;
const int EncoderAInt = PCINT20;            

volatile int a0;
volatile int c0;
volatile int Count = 250;

volatile int func = LOW;           // intended to be the variable for switching between the rotary modes
//-------------------------------------------------------------------------------------------------------                                
ISR (PCINT2_vect){                                             // Encoder control
  byte a = PIND>>EncoderA & 1; 
  byte b = PIND>>EncoderB & 1;
  byte changeVal;
  if (a != a0){
    a0 = a;
    if (b != c0){
 c0 = b;
 changeVal = (a == b);
 }
 if (func == HIGH) {
 Count = max(min((Count + (changeVal ? 1 : -1)), 400), 100);
 }
 else {
 Count = max(min((Count + (changeVal ? 1 : -1)), 6), 3);
 }
 //newEncoderVal = true;
  }
}

/*
void ChangeValue (bool Up){                                   // Called when rotary encoder value changes
  if(func == HIGH){
  Count = max(min((Count + (Up ? 1 : -1)), 400), 100);}       // VCA control --- max = 400 / min = 100

  if(func == LOW){
  Count = max(min((Count + (Up ? 1 : -1)), 6), 3);            // Menu control --- max = 6 / min = 3         

  for(int i = 3; i < 7; i++){oled.setCursor(1, i); oled.print(" ");} 
  oled.setCursor(1, Count); oled.print(">");}  
}                    
ISR (PCINT2_vect){                                             // Encoder control
  int a = PIND>>EncoderA & 1; 
  int b = PIND>>EncoderB & 1;  
  if (a != a0){                  
    a0 = a;
    if (b != c0){c0 = b;ChangeValue(a == b);}
  }
}
*/
//--- Setup ----------------------------------------------------------------------------------------------
void setup() {
  pinMode(LED, OUTPUT);
  pinMode(EncoderA, INPUT_PULLUP);
  pinMode(EncoderB, INPUT_PULLUP);

  PCMSK2 = 1<");


  //while(1);
}  
//-------------------------------------------------------------------------------------------------------
void Menu(){
  oled.setFont(ClassicX8x8);
  oled.setCursor(10, 3); oled.print("Impdance");
  oled.setCursor(10, 4); oled.print("SPL Level");
  oled.setCursor(10, 5); oled.print("Distortion");
  oled.setCursor(10, 6); oled.print("Response");  
}
void toggle(){                                                    // Called when push function is activated
  switch(Count){                                                 
    case 3: Impedance();break;
    case 4: dB();break;
    case 5: Distortion();break;
    case 6: Response();break;
  }
}
//------------------------------------------------------------------------------------------------------
void Impedance(){
  func = HIGH;                                                   // dont work !!!
  oled.clear();
  oled.setFont(ClassicX8x8);
  oled.setCursor(30, 0); oled.print("Impedance");
  oled.setCursor(40, 1); oled.print("T E S T");

  while(digitalRead(2)== LOW); 
}
void dB(){
  oled.setCursor(0, 2); oled.print("SPL");
}
void Distortion(){
  oled.setCursor(0, 2); oled.print("Dist");
}
void Response(){
  oled.setCursor(0, 2); oled.print("Resp");
}
//--- E N D ---------------------------------------------------------------------------------------------
Suppose the option is chosen which allows a count up to 400 and the actual value is (say) 231 what should happen if the option is changed to set the max at 6?

The functionality I am looking for is:

A small meny with only 4 steps. I set the counter for the same munbering as the display line ID. 3 to 6. Everytime I call the meny I request this functionality.

Later when I call a function for a test setup using a DAC and a VCA, I would like to implement a manual volume control for the audio level of the test signal. This is the reason for the rotary coder to be able to use a steps between 100 and 400 (starting with the mid level of 250.

You have a line 116 that sets the variable func HIGH but I don't see an line that sets it LOW.

And I suspect the code would be easier to make sense of if the variable was called something like menuActivated rather than func. And if you use true and false rather than HIGH and LOW.

The compiler won't care, but code should be written for humans to understand.

...R

func is a lousy name for the variable that defines whether to constrain to 3 to 6 or 100 to 400.

HIGH or LOW are lousy values to determine which range to use.

You have NOT answered Robin2's question. If the interrupt has currently set the value of Count to 231, and the value in func changes to LOW, what should the interrupt handler do with the 231?

PaulS
I dear - I am truly sorry.
I have answered Robin2’s question by the explanation of the functionality.

But to be more clear - the Count is not at 231! (It is at the default setting 250)

The interrupt should change the value of tehe setting between 100 and 400.

To Robin2,

I have changed according to your suggestions and I have also used different places for the change og the interrupt setting. With no luck. This is the full code according to you recommendations:

/*  Sketch - based on:
 *  Bounce-Free Rotary Encoder for the Arduino Uno - see http://www.technoblogy.com/show?1YHJ
 *  David Johnson-Davies - www.technoblogy.com
*******************************************************************************************************/

#include "SSD1306Ascii.h"          // OLED
#include "SSD1306AsciiAvrI2c.h"    // OLED
#include "Classic8x8.h"            // OLED
#include "ClassicX8x16.h"          // OLED
#include "ClassicX8x8.h"           // OLED

SSD1306AsciiAvrI2c oled;           // OLED
#define I2C_ADDRESS 0x3C           // OLED

const int LED = 8;                                                
const int EncoderA = 4;            
const int EncoderB = 5;
const int EncoderAInt = PCINT20;            

volatile int a0;
volatile int c0;
volatile int Count = 250;

volatile int menuActivated = true;           // intended to be the variable for switching between the rotary modes
//-------------------------------------------------------------------------------------------------------                                
ISR (PCINT2_vect){                                             // Encoder control
  byte a = PIND>>EncoderA & 1; 
  byte b = PIND>>EncoderB & 1;
  byte changeVal;
  if (a != a0){
    a0 = a;
    if (b != c0){
       c0 = b;
       changeVal = (a == b);
    }
    if (menuActivated == true) {
       Count = max(min((Count + (changeVal ? 1 : -1)), 6), 3);
    }
    else{
       Count = max(min((Count + (changeVal ? 1 : -1)), 400), 100);
    }
  //newEncoderVal = true;
  }
}

/*
void ChangeValue (bool Up){                                   // Called when rotary encoder value changes
  if(menuActivated == HIGH){
  Count = max(min((Count + (Up ? 1 : -1)), 400), 100);}       // VCA control --- max = 400 / min = 100

  if(menuActivated == LOW){
  Count = max(min((Count + (Up ? 1 : -1)), 6), 3);            // Menu control --- max = 6 / min = 3         

  for(int i = 3; i < 7; i++){oled.setCursor(1, i); oled.print(" ");} 
  oled.setCursor(1, Count); oled.print(">");}  
}                    
ISR (PCINT2_vect){                                             // Encoder control
  int a = PIND>>EncoderA & 1; 
  int b = PIND>>EncoderB & 1;  
  if (a != a0){                  
    a0 = a;
    if (b != c0){c0 = b;ChangeValue(a == b);}
  }
}
*/
//--- Setup ----------------------------------------------------------------------------------------------
void setup() {
  pinMode(LED, OUTPUT);
  pinMode(EncoderA, INPUT_PULLUP);
  pinMode(EncoderB, INPUT_PULLUP);

  PCMSK2 = 1<");


  //while(1);
}  
//-------------------------------------------------------------------------------------------------------
void Menu(){
  oled.setFont(ClassicX8x8);
  oled.setCursor(10, 3); oled.print("Impdance");
  oled.setCursor(10, 4); oled.print("SPL Level");
  oled.setCursor(10, 5); oled.print("Distortion");
  oled.setCursor(10, 6); oled.print("Response");  
}
void toggle(){                                                    // Called when push menuActivatedtion is activated
  switch(Count){                                                 
    case 3: Impedance();break;
    case 4: dB();break;
    case 5: Distortion();break;
    case 6: Response();break;
  }
}
//------------------------------------------------------------------------------------------------------
void Impedance(){
  menuActivated = false;                                                  
  oled.clear();
  oled.setFont(ClassicX8x8);
  oled.setCursor(30, 0); oled.print("Impedance");
  oled.setCursor(40, 1); oled.print("T E S T");
  oled.setCursor(0, 2); oled.print(Count);
  //while(digitalRead(2)== LOW); 
}
void dB(){
  oled.setCursor(0, 2); oled.print("SPL");
}
void Distortion(){
  oled.setCursor(0, 2); oled.print("Dist");
}
void Response(){
  oled.setCursor(0, 2); oled.print("Resp");
}
//--- E N D ---------------------------------------------------------------------------------------------

So far, all I've seen you write is that "this doesn't work". What does the code ACTUALLY do, and how does that differ from what you want? THAT is useful information. "This doesn't work" is useless information.

Perhaps you kindly look at #7, thats where I explain the functionality.

I don't understand why the line menuActivated = true; is not inside the Menu() function. It seems a bit late to be setting the value after the menu code is finished.

Also, I wonder if you need a clearer distinction between the situation where the menu is active and other activity. For example the loop() function only seems to call the Menu() function. When are the other functions called?

And I do agree with @PaulS that it is important to explain in detail what happens when you the program and what you want it to do that is different.

From Reply #10

But to be more clear - the Count is not at 231! (It is at the default setting 250)

If the purpose of one mode is to allow the count within the range 100 to 400 then why couldn't it be at 231 on some occasion?

...R

Robin2, I really appriciate your comments and help - thank you very much.

But if the explanations I have really tried to do is not enough - I think I am not able to do much better in a foreign languid. I realize I have to do better and continue on my own from here. You have really tried to help and also given me valuable help which I appreciate.

Best regards Frede Kristensen

There is a Scandinavian language section.

...R

PS. I wish I could do any language other than English as well as you do English.

Robin2,
Thank you very much.

I have now re-written part of the sketch and removed the section with interrupt controlled pushbutten function as a main change.
That solved the issue.
Everything works now and I can go on with the coding of the sketch.

Obs. I didnt know about the Scandinavien section - tks for this advise.