Go Down

Topic: MEGA2560 and interrupts{SOLVED} (Read 141 times) previous topic - next topic

Steveiboy

Nov 21, 2020, 10:31 pm Last Edit: Nov 22, 2020, 10:24 am by Steveiboy
I was using an Uno with an rotary encoder and now want to add a second rotary encoder so I moved over to the Mega256 as this has 3 set's of interrupts pins (2,3,17,18,19,20,21), Pins 20,21 I'm using for the I2C part.


The code below worked on an Uno but only with rotary encoder implemented at the time using pins 2,3.
I think it may be something to do with this part, But I don't really understand if I need to change or alter this part  for the mega256, trying to get my head around it.
Code: [Select]
// Configure interrupt and enable for rotary encoder.
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();


This is my full code with 2 rotary encoders implemented but the values do not change when I rotate the knobs.
Rotary encoder 1 on pins 2,3 (same as the uno)and rotary encoder 2 on pins 18,19.
Code: [Select]
#include <Rotary.h>            //  Rotary encoder: https://github.com/brianlow/Rotary
#include <Wire.h>
#include <TimedAction.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7); //0x27 is the default address of the LCD with I2C bus module
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
Adafruit_MCP4725 dacB; // constructor
#include <Adafruit_ADS1015.h> //Include the libarary for 16Bit A/D converencoderValuester
#define  VOLTS_CHAN0 0 //channel 1 value
#define  VOLTS_CHAN1 1 //chanel2 value
#define stepPin1 18                    // Set 'Step' rotary encoder pins
#define stepPin2 19
int Amp_multiplier = 17;
Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
uint16_t err1; //ADC0 variable
uint16_t err2; //ADC1 variable
float Vmultiplier = 0.0001875F;  // used to convet readings this is calculated
float Vmultiplier1 = 0.0001875F; // used to convet readings this is calculated
float Vresults0; // Holds raw battery voltage value
float Vresults1; // Holds raw battery current value
float Voltage1 = 0.0;
float Voltage2 = 0.0;
int DAC8574_Ch2_Val = 0;
float r1 = 47000.0;
float r2 = 6200.0;
float Actual_volt = 0;
float Set_volt = 0;
Rotary Volts_Rotary = Rotary(2, 3);               // Rotary encoder for frequency connects to interrupt pins
Rotary Amps_Rotary = Rotary(stepPin1, stepPin2);              // Rotary encoder for frequency connects to interrupt pins

int selector = 0;
float Voltage3 = 0;
bool buttonPress = false;
bool inMenu = false;
long unsigned int Dac_volt_Chanel1 = 1157;         // Set initial Dac_volt_Chanel1uency.
long unsigned int Dac_Amp_Chanel1 = 0;
int stepPointer = 1;
unsigned long  Dac_multiplier = 0;
//String units = stepText[stepPointer];
//#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
const int numOfInputs = 2;
const int inputPins[numOfInputs] = {4, 17};
int inputState[numOfInputs];
int lastInputState[numOfInputs] = {LOW, LOW};
bool inputFlags[numOfInputs] = {LOW, LOW};
int inputCounters[numOfInputs];
long lastDebounceTime[numOfInputs] = {0, 0};
long debounceDelay = 50;
int output = 0;
void TimerService01();
TimedAction Timedact01 = TimedAction(80, TimerService01); // mS
void TimerService02();
TimedAction Timedact02 = TimedAction(250, TimerService02); // mS


void setup() {
  dacB.begin(0x62); // The I2C Address: Run the I2C Scanner if you're not sure
  ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  ads.begin();  //start the 16bit A/D converter
  for (int i = 0; i < numOfInputs; i++) {
    pinMode(inputPins[i], INPUT);
    digitalWrite(inputPins[i], HIGH); // pull-up 20k
  }
  //pinMode(stepPin1, INPUT_PULLUP);     // Pins for step rotary encoder on analogue pins A2, A3
  // pinMode(stepPin2, INPUT_PULLUP);
  // Configure interrupt and enable for rotary encoder.
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  //Set PCIE0 to enable PCMSK2 scan.
  sei();
  lcd.begin(20, 4);
  lcd.setBacklightPin(3, POSITIVE);                        // BL, BL_POL
  lcd.setBacklight(HIGH);                                  //set LCD backlight on
  lcd.clear();
}

void getStep() {
  switch (stepPointer) {

    case 1:  Dac_multiplier = 1; break;
    case 2:  Dac_multiplier = 10; break;
    case 3:  Dac_multiplier = 50; break;
    case 4:  Dac_multiplier = 100; break;

  }
}


void loop() {


  setInputFlags();
  resolveInputFlags();
  Timedact01.check();
  Timedact02.check();
  DAC8574_Ch2_Val =  Dac_volt_Chanel1;
  dacB.setVoltage(DAC8574_Ch2_Val, false);
}

ISR(PCINT2_vect) {
  unsigned int result = Volts_Rotary.process();
  if (result) {
    if (result == DIR_CW) {
      if ((Dac_volt_Chanel1 + Dac_multiplier) <= 4095) Dac_volt_Chanel1 += Dac_multiplier;
    } else {
      if ((Dac_volt_Chanel1 - Dac_multiplier) >= 1157) Dac_volt_Chanel1 -= Dac_multiplier;
    }
    if (Dac_volt_Chanel1 <= 729)  Dac_volt_Chanel1 = 1157;
    if (Dac_volt_Chanel1 >= 4095) Dac_volt_Chanel1 = 4095;
  }

  unsigned int result1 = Amps_Rotary.process();
  if (result1) {
    if (result1 == DIR_CW) {
      if ((Dac_Amp_Chanel1 + Dac_multiplier) <= 4095) Dac_Amp_Chanel1 += Dac_multiplier;
    } else {
      if ((Dac_Amp_Chanel1 - Dac_multiplier) >= 1157) Dac_Amp_Chanel1 -= Dac_multiplier;
    }
    if (Dac_Amp_Chanel1 <= 729)  Dac_Amp_Chanel1 = 1157;
    if (Dac_Amp_Chanel1 >= 4095) Dac_Amp_Chanel1 = 4095;
  }

}
void TimerService01() {
  //#################################################################
  //#  Read both ADC channels                                       #
  //#################################################################

  //Read BAttery volatage
  err1 = ads.readADC_SingleEnded(VOLTS_CHAN0)  ;   // Ch.0 (3) 16bit
  Voltage1 = err1 * Vmultiplier ; //conert to float
  Actual_volt = Voltage1 / (r2 / (r1 + r2)); //convert to real time reading
  /*
    err2 = ads.readADC_SingleEnded(VOLTS_CHAN1)  ;   // Ch.1 (3) 16bit
    Voltage2 = err2 * Vmultiplier1 ;// Convert to actual input v
    Voltage3 = Voltage2 - 1.293; //set the reading to zero but show a minius
    Voltage2 = Voltage3 * 4.096; ///this is wherer I've tried differtn methods to set voltage to read saem as actual voltage
  */
  Voltage2 = map(Dac_volt_Chanel1, 1157, 4057, 0, 4057);
  Set_volt = Voltage2 * 4.993 / 1023 ;
}

void TimerService02() {
  //
  //  units = stepText[stepPointer];


  lcd.setCursor(0, 0);
  lcd.print("V Set = ");
  lcd.print(Set_volt, 2);
  lcd.print(" V");
  lcd.setCursor(0, 1);
  lcd.print("V ACT = ");
  if ( Actual_volt >= 6.5) {
    lcd.print(Actual_volt, 2);//DAC8574_Ch2_Val
  } else {
    lcd.print(Actual_volt, 3);//DAC8574_Ch2_Val
  }
  lcd.setCursor(0, 2);
  lcd.print("D ");
  lcd.print(DAC8574_Ch2_Val);//DAC8574_Ch2_Val
  lcd.print(" : ");
  lcd.print(stepPointer);
  lcd.print(" ;");
  lcd.print(Dac_multiplier);
  lcd.print("    ");
  lcd.setCursor(0, 3);
  lcd.print(Voltage2);//DAC8574_Ch2_Val DACSetSteps[i]
  lcd.print(" : ");
  lcd.print(Dac_Amp_Chanel1); //result stepPointer
  lcd.print("   ");
  // lcd.print();
}
void setInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    int reading = digitalRead(inputPins[i]);
    if (reading != lastInputState[i]) {
      lastDebounceTime[i] = millis();
    }
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
      if (reading != inputState[i]) {
        inputState[i] = reading;
        if (inputState[i] == HIGH) {
          inputFlags[i] = HIGH;
        }
      }
    }
    lastInputState[i] = reading;
  }
}

void resolveInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    if (inputFlags[i] == HIGH) {
      // Input Toggle Logic
      inputCounters[i]++;
      stepPointer = inputCounters[i];
      inputFlags[i] = LOW;
      getStep();
    }
    if (inputCounters[i] > 3) {
      inputCounters[i] = 0;
      stepPointer = 1;
    }
  }
}








UKHeliBob

Have you tried using attachInterrupt() ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

cattledog

Quote
Have you tried using attachInterrupt() ?
Yes. Using 18 and 19 for external interrupts instead of pin change interrupts is the way to go.

PCINT18 and PCINT19 are on Analog pins 10 and 11. There are no pin change interrupts on pins 18 and 19, just external ones. You need to be using a Mega data sheet and pin out for working at the register level.

Steveiboy

#3
Nov 21, 2020, 11:49 pm Last Edit: Nov 21, 2020, 11:49 pm by Steveiboy
Have you tried using attachInterrupt() ?
No I've not tried that way, If I remove the second encoder code part and and leave the first encoder in and upload to a uno it works perfectly, Up load the same code(only with 1 encoder) to the Mega it  does not work.

Catledog I will read the data sheet and try to understand how to set it, so the encoder works on pins 2,3,18,19

Steveiboy

#4
Nov 22, 2020, 12:10 am Last Edit: Nov 22, 2020, 12:18 am by Steveiboy
Update, I've got the encoder 2 working buy using this
Code: [Select]
// Configure interrupt and enable for rotary encoder.
  PCICR |= (1 << PCIE2 );
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();

 
And moved the encoder to pins A10,A11, I thought this part of code was for the inerrupt pins 2,3,18,19 and not A10,A11. I think I understand it a bit better now

But now I've moved encoder 2 to A10,A11which is working but not sure why encoder 1 still not working ?

Steve

cattledog

Quote
not sure why encoder 1 still not working ?
Code: [Select]
unsigned int result1 = Amps_Rotary.process();

I'm not certain if this is the cause of the problem with encoder 1, but the reading of the encoder1 is contained within the ISR triggered by the pins of encoder 2. If encoder 2 is not turning, encoder 1 will not be read.

I would try attachInterrupt() on pins 2 and 3, and move the .process() call to that ISR.

Steveiboy

I've changed to attachInterrupt() and moved the 2 encoders into there own routine and it now works.
Also along the way I've learned more about Interrupt's and how to use them and I know this part is causing the issue with the meaga, 

Code: [Select]
// Configure interrupt and enable for rotary encoder.
    PCICR |= (1 << PCIE2);
    PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
    sei();





StefanL38

I haven't read al the posts but for standard rotary-encoders attaching interrupts and counting up/down in the isr is sufficient. Why do you add this 
Code: [Select]
// Configure interrupt and enable for rotary encoder.[color=#222222][/color]
    PCICR |= (1 << PCIE2);[color=#222222][/color]
    PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);[color=#222222][/color]
    sei();


stuff to it?
best regards Stefan 
any newbee can apply the most professional habit right from the start:
 add only ONE thing at a time. Debug that ONE thing until that ONE thing works reliable - repeat.
Newbee: become a professional by following this rule.

UKHeliBob

Stefan - I am trying to track down what causes code posted in code tags sometimes causes color tags to be added.  How exactly did you copy and paste the code snippet and what environment (OS and browser) are you using ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

StefanL38

Stefan - I am trying to track down what causes code posted in code tags sometimes causes color tags to be added.  How exactly did you copy and paste the code snippet and what environment (OS and browser) are you using ?
I am using WIndows 10 pro. 
I created a code-section by clicking on <|> 
then I clicked select on steveiboy's code
pressed ctrl-c
clicked with mouse into my new created code-section
then pressed ctrl-v
I have my viewing-options adjusted to show the text WYSIWYG (bold as real bold colors as real colors etc.)
then clicked on post.
After that I clicked on modify to add something. But I'm not sure if the color-tags were already there
as browser I'm using vivaldi.
If you want me to copy & paste in a certain way post a description how I should do it
best regards Stefan 
any newbee can apply the most professional habit right from the start:
 add only ONE thing at a time. Debug that ONE thing until that ONE thing works reliable - repeat.
Newbee: become a professional by following this rule.

UKHeliBob

Thanks for the details.  My question was not a subtle way of suggesting that you did anything wrong.  There should be no need to copy/paste in any particular way 

I think that the problem may be the WYSISYG setting.  I will do some more tests
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Go Up