detachInterrupt() not working?!

Hi everyone,
I am having a bit of a problem with detachInterrupt() and I have no idea why.

I have a code where I am “simulating” a rotary encoder but I also use it as a feedback.
I have 2 mosfets which I use to pull-down the two phases of the rotary encoder and I also read those two phases with other 2 inputs and I am using an interrupt to read the encoder pulses.

My intetion was to:
attachInterrupt()
//Get the “feedback” from the encoder//
detachInterrupt
//Simulate the encoder how I need to//

But the interrupt still fires and I am getting a feedback even when I don’t want to.

I am completely lost.
If there is any reason for why it does this than I would love to hear it!

Thanks a lot!
Tomas

Don’t use detachInterrupt(), you almost never need it, and its a complete pitfall for the
unwary - call attachInterrupt() in setup() and leave it there.

@ T-workshop

Do you think it might help if you posted your sketch ?

The easier you make it to read and copy the code the more likely it is that you will get help

Please follow the advice given in the link below when posting code

1 Like

I am not sure what do you mean

Well post your code then - easier to explain how to change it if we can see it.

1 Like

@ T-workshop
I see that you decided not to follow the advice to use code tags. Auto format the code in the IDE then right click and choose Copy for forum then paste here

I wanted to spare your eyes from my low-level code but I completely understand that it is better to see it. I am gonna upload the code I have in front of me right now so pardon the comments in Czech and the lack of them. The void loop() is “split in two” by selector switch. Now I am talking about the while(TIG == true) The main problem is that for some reason the variable “MaxAmps” is being decremented by the ISR “Encoder” even when I don’t want it to. It’s being decremented everytime the program goes into the while(digitalRead(Led) == LOW && digitalRead(HF) == LOW) Once again sorry for the mess below :frowning:

#include <Wire.h>

//Hodnoty
#define MaxA 190 //Maximální proud svářečky
#define MinA 10 //Minimální proud svářečky
#define PulseW 2000 //Šířka pulsu v mikrosekundách
#define DebounceEnc 50 //Debounce čas v ms pro enkodér
#define DebounceCal 50 //Debounce čas v ms pro kalibraci
#define UpdateInterval 600000 //Čas, po kterém se bude aktualizovat hodnota v EEPROM
#define Hystereze 2 //Hystereze

//Vstupy
#define EncA 2 //Vstup enkodér A
#define EncB 4 //Vstup enkodér B
#define Led A0 //Vstup stavu LED pro nastavování proudu
#define HF 3 //Vstup zapalování oblouku
#define Cal 8 //Vstup kalibračního panelového spínače
#define Syn 9 //Vstup panelového spínače módu synchronizace minima
#define Mod 5 //Vstup nastavení módu MMA/TIG
#define Pot A6 //Vstup potenciometru dálkového ovládání

//Výstupy
#define OutA A2 //Výstup enkodér A
#define OutB A3 //Výstup enkodér B
#define OutG A1 //Výstup pro odpojení reference enkodéru (GND)
#define OutHF 10 //Výstup pro zapálení oblouku
#define LedCal 6 //Led u spínače kalibrace
#define LedSyn 7 //Led u spínače synchronizace

//Hodnoty EEPROM
#define Address 0x50 //Adresa EEPROM
#define AddressON 0 //Adresa počtu zapnutí (přeteče na 50)
#define AddressA 1 //Adresa nastavené hodnoty proudu pro TIG
#define AddressTIGMaxMSB 2 //Adresa maximální hodnoty z potenciometru pro mód TIG
#define AddressTIGMaxLSB 3
#define AddressTIGMinMSB 4 //Adresa minimální hodnoty z potenciometru pro mód TIG
#define AddressTIGMinLSB 5
#define AddressMMAMaxMSB 6 //Adresa maximální hodnoty z potenciometru pro mód MMA
#define AddressMMAMaxLSB 7
#define AddressMMAMinMSB 8 //Adresa minimální hodnoty z potenciometru pro mód MMA
#define AddressMMAMinLSB 9




byte ON = 0; //počítadlo zapnutí
volatile byte Amps = 0;  //Aktuální proud
volatile int MaxAmps = 0; //Maximum proudu
byte VarAmps = 0; //Nastavený proud
byte delta = 0; //Rozdíl nastavené a aktuální hodnoty - pro hysterezi
byte LSB = 0;
unsigned int MSB = 0;
unsigned int pot = 0; //hodnota analogového vstupu
unsigned int MIN = 1023; //minimální hodnota analogového vstupu
volatile unsigned int MAX = 0;  //maximální hodnota analogového vstup
unsigned long CalMillis = 0; //Hodnota millis() pro proces kalibrace
volatile unsigned long EncMillis = 0;  //Hodnota millis() pro enkodér
unsigned long UpdMillis = 0;  //Hodnota millis() pro update
unsigned long LastUpdMillis = 0;
unsigned long LastRegMillis = 0;
unsigned long RegMillis = 0;
bool TIG = false; //proměnná pro indikaci módu
bool MMA = false; //promenná pro indikaci módu
bool LastCalState = true; //Poslední hodnota HF vstupu pro proces kalibrace
bool regulation = false;  //Kontrolní bit pro úlohy v regulaci
volatile bool show = false; //Kontrolní bit pro signalizaci maximální hodnoty proudu
bool setzero = false; //Kontrolní bit "donulování"


void setup() {
  pinMode(EncA, INPUT);
  pinMode(EncB, INPUT);
  pinMode(Led, INPUT);
  pinMode(HF, INPUT_PULLUP);
  pinMode(Cal, INPUT_PULLUP);
  pinMode(Syn, INPUT_PULLUP);
  pinMode(Mod, INPUT);

  pinMode(OutA, OUTPUT);
  pinMode(OutB, OUTPUT);
  pinMode(OutG, OUTPUT);
  pinMode(OutHF, OUTPUT);
  pinMode(LedCal, OUTPUT);
  pinMode(LedSyn, OUTPUT);


  if (digitalRead(Mod) == LOW) {
    TIG = true;
    MMA = false;
  }
  else if (digitalRead(Mod) == HIGH) {
    TIG = false;
    MMA = true;
  }

  Wire.begin(); //Inicializace I2C

  ON = ReadEEPROM(AddressON);

  if (ON == 48) {
    ON = 0;
  }

  if (ON == 0) {
    ON++;
    Kalibrace();
  }

  else {
    ON++;
  }

  delay(5);
  WriteEEPROM(AddressON, ON);
  delay(5);

  Nulovani();

  MaxAmps = ReadEEPROM(AddressA);
  MaxAmps = 33;
}

void loop() {

  while (TIG == true) { //Mód TIG
    MSB = ReadEEPROM(AddressTIGMinMSB);
    LSB = ReadEEPROM(AddressTIGMinLSB);
    MSB = MSB << 8;
    MIN = MSB + LSB;
    MSB = ReadEEPROM(AddressTIGMaxMSB);
    LSB = ReadEEPROM(AddressTIGMaxLSB);
    MSB = MSB << 8;
    MAX = MSB + LSB;

    UpdMillis = millis();
    if (UpdMillis - LastUpdMillis > UpdateInterval) {
      UpdateEEPROM(AddressA, MaxAmps);
      LastUpdMillis = millis();
    }


    if (show == false) {
      ShowMax();
      show = true;
    }

    while (digitalRead(Led) == LOW && digitalRead(HF) == LOW) {
      regulation = true;
      if (setzero == false) {
        SetZero();
        setzero = true;
      }
      digitalWrite(OutHF, HIGH);
      digitalWrite(OutG, LOW);
      Regulace();
    }

    if (regulation == true) {
      digitalWrite(OutHF, LOW);
      digitalWrite(OutG, HIGH);
      show = false;
      regulation = false;
    }


    if (digitalRead(Cal) == LOW) {
      Kalibrace();
    }

  } //Konec módu TIG

  while (MMA == true) {
    detachInterrupt(digitalPinToInterrupt(EncA));
    MSB = ReadEEPROM(AddressMMAMinMSB);
    LSB = ReadEEPROM(AddressMMAMinLSB);
    MSB = MSB << 8;
    MIN = MSB + LSB;
    MSB = ReadEEPROM(AddressMMAMaxMSB);
    LSB = ReadEEPROM(AddressMMAMaxLSB);
    MSB = MSB << 8;
    MAX = MSB + LSB;
    MaxAmps = MaxA;



    while (digitalRead(Led) == LOW) {
      digitalWrite(OutG, LOW);
      Regulace();
    }

    if (digitalRead(Led) == HIGH) {
      digitalWrite(OutG, HIGH);
    }

    if (digitalRead(Cal) == LOW) {
      Kalibrace();
    }


  } //Konec módu MMA


}

int ReadEEPROM(int address) { //čtení z EEPROM
  Wire.beginTransmission(Address);
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(Address, 1);
  if (Wire.available()) {
    int Read = Wire.read();
    return Read;
  }
  delay(5);
} //Konec ReadEEPROM

void WriteEEPROM(int address, int Write) { //zápis na EEPROM
  Wire.beginTransmission(Address);
  Wire.write(address);
  Wire.write(Write);
  Wire.endTransmission();
  delay(5);
} //Konec WriteEEPROM

void AmpsMinus() {
  digitalWrite(OutA, HIGH);
  delayMicroseconds(PulseW / 2);
  digitalWrite(OutB, HIGH);
  delayMicroseconds(PulseW / 2);
  digitalWrite(OutA, LOW);
  delayMicroseconds(PulseW / 2);
  digitalWrite(OutB, LOW);
  Amps--;
} //Konec AmpsMinus

void AmpsPlus() {
  digitalWrite(OutB, HIGH);
  delayMicroseconds(PulseW / 2);
  digitalWrite(OutA, HIGH);
  delayMicroseconds(PulseW / 2);
  digitalWrite(OutB, LOW);
  delayMicroseconds(PulseW / 2);
  digitalWrite(OutA, LOW);
  Amps++;
} //Konec AmpsPlus

void Kalibrace() {
  while (digitalRead(Cal) == HIGH) {
    digitalWrite(LedCal, HIGH);
    delay(250);
    digitalWrite(LedCal, LOW);
    delay(250);
  }
  digitalWrite(LedCal, HIGH);
  while (digitalRead(Cal) == LOW) {
    pot = analogRead(Pot);
    CalMillis = millis();

    if (digitalRead(HF) != LastCalState && TIG == true ) {
      long CurrCalMillis = millis();
      if (CurrCalMillis - CalMillis < DebounceCal) {
        MIN = pot;
        LastCalState = !LastCalState;
      }
    }

    if (pot > MAX) {
      MAX = pot;
    }
    if (pot < MIN && MMA == true) {
      MIN = pot;
    }
  }

  if (TIG == true) {
    MSB = MAX >> 8;
    LSB = MAX;
    WriteEEPROM(AddressTIGMaxMSB, MSB);
    WriteEEPROM(AddressTIGMaxLSB, LSB);
    MSB = MIN >> 8;
    LSB = MIN;
    WriteEEPROM(AddressTIGMinMSB, MSB);
    WriteEEPROM(AddressTIGMinLSB, LSB);
  }

  if (MMA == true) {
    MSB = MAX >> 8;
    LSB = MAX;
    WriteEEPROM(AddressMMAMaxMSB, MSB);
    WriteEEPROM(AddressMMAMaxLSB, LSB);
    MSB = MIN >> 8;
    LSB = MIN;
    WriteEEPROM(AddressMMAMinMSB, MSB);
    WriteEEPROM(AddressMMAMinLSB, LSB);
  }

  digitalWrite(LedCal, LOW);

} //Konec Kalibrace

void Nulovani() {
  detachInterrupt(digitalPinToInterrupt(EncA));
  digitalWrite(OutG, LOW);  //Odpojení panelového enkodéru
  while (digitalRead(Led) == HIGH) {
    delay(200);
  }
  for (int i = 0; i < (MaxA + MaxA); i++) {
    AmpsMinus();
  }
  MaxAmps = MinA;
  Amps = MinA;
  digitalWrite(OutG, HIGH);
  attachInterrupt(digitalPinToInterrupt(EncA), Encoder, FALLING);
} //Konec Nulovani

void ShowMax() {
  digitalWrite(OutG, LOW);
  detachInterrupt(digitalPinToInterrupt(EncA));
  while (Amps < MaxAmps) {
    AmpsPlus();
  }
  digitalWrite(OutG, HIGH);
  attachInterrupt(digitalPinToInterrupt(EncA), Encoder, FALLING);
} //Konec ShowMax

void SetZero() {
  detachInterrupt(digitalPinToInterrupt(EncA));
  digitalWrite(OutG, LOW);
  while (Amps > MinA) {
    AmpsMinus();
  }
  Amps = MinA;
  attachInterrupt(digitalPinToInterrupt(EncA), Encoder, FALLING);
} //Konec SetZero

void Regulace() {
  detachInterrupt(digitalPinToInterrupt(EncA));
  pot = analogRead(Pot);
  VarAmps = map(pot, MIN, MAX, MinA, MaxAmps);

  delta = VarAmps - Amps;

  if (abs(delta) >= Hystereze) {
    while (VarAmps > Amps) {
      AmpsPlus();
    }
    while (VarAmps < Amps) {
      AmpsMinus();
    }
  }

  else if (abs(delta) == 1) {
    RegMillis = millis();
    if ((RegMillis - LastRegMillis) > 100) {
      while (VarAmps > Amps) {
        AmpsPlus();
      }
      while (VarAmps < Amps) {
        AmpsMinus();
      }
    }
    LastRegMillis = RegMillis;
  }

  attachInterrupt(digitalPinToInterrupt(EncA), Encoder, FALLING);
} //Konec Regulace


void Encoder() {  //ISR pro enkodér
  long CurrEncMillis = millis();

  if ((CurrEncMillis - EncMillis) > DebounceEnc && digitalRead(Led) == LOW) {
    if (digitalRead(EncB) == LOW && MaxAmps < MaxA && regulation == false) {
      MaxAmps++;
    }

    if (digitalRead(EncB) == HIGH && MaxAmps > MinA && regulation == false) { //Odčítání
      MaxAmps--;
      digitalWrite(LedSyn, HIGH);
    }
  }

  EncMillis = millis();
}  //Konec Encoder

void UpdateEEPROM(int address, int Write) { //update EEPROM
  int Read = 0;
  Wire.beginTransmission(Address);
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(Address, 1);
  if (Wire.available()) {
    Read = Wire.read();
  }
  if (Read = ! Write) {
    Wire.beginTransmission(Address);
    Wire.write(address);
    Wire.write(Write);
    Wire.endTransmission();
  }
} //Konec UpdateEEPROM

regulation needs to be volatile. Lose all the detachInterrupt calls.

1 Like

Thanks, Iam definitely gonna try that! I
I though that variables need to be volatile only if the ISR changes their value.

Any variable used in both the ISR and the rest of the program need to be volatile, otherwise
there is no guarantee they are written to memory. You’re right in that if the ISR
doesn’t change the variable this is unlikely, but its possible if the main program
is in a loop and doesn’t flush that variable’s value.

I’ve since got it working by setting the interrupt flag register. I’ve read in another forum post that it is some kind of a bug in the software that even if you detach the interrupt it sets the flag and the ISR runs after you attach it.
So that is working but I have a problem that eventhough I am using “FALLING” trigger the interrupt triggers on clean (verified with oscilloscope) rising edge for some reason.

Its not a bug, its how the hardware works - you need to read the relevant bits of the datasheet and the code for attach/detachInterrupt and figure out what’s going to happen
(different on different processor types of course) - which is why its usually a great idea
not to be affected by any of this: don’t use detach!

1 Like