Interrupt question - attach / detach

I am trying to use an interrupt for a safety switch on a motor with a winch. The line on the winch goes up to a certain level and down. That upper level is calibrated with a function that turns the winch until a metal disk acts as a button and triggers to stop then backs down a bit and that is the callibrated level. This is done without an interrupt. But now can that same switch act as an interrupt while the loop is going? So basically after callibration is done and then the loop function does it's going up and down. But now I want to use an interrupt just in case the winch motor screws up and goes too high and triggers that disk again it would stop the motor? I tried to detach the interrupt when callibration function is working and then attach an interrupt when the calibration is done but then arduino just hangs and nothing happens. Can you only attach an interrupt in SETUP? and not in a function?

Raf, can you post your code, it may help to clarify what your code is doing.
FWIW, my inclination would be to keep the handler attached but check whatever tells the software that the calibration is completed to see if it should actually do anything or not.

//----------------------------------------------------------------------------------
// MOTORS 
//pins for motor 1
int mode1 = 9;
int phase1 = 8;
int enable1 = 11;

//pins for motor2
int mode2 = 7;
int phase2 = 6;
int enable2 = 10;

// determines the 4 static positions of both motors
int motor1Position = 1;                
int motor2Position = 1;

//for determining the motor state during interrupt
int motor1Dir = 3;                     
int motor2Dir = 3;
//motorDir = O  Stable
//motorDir = 1  Forward (Up)
//motorDir = 2  Backwards (Down)

int motor1Limit = 4;   //1 lowest 4 highest
int motor2Limit = 4;
//motorLimit = 0 In-between
//motorLimit = 1 Top
//motorLimit = 2 Bottom

//----------------------------------------------------------------------------------
//COUNTERS
int counter1Pin = 4;                  // digital button for rotation counter 1 for motor 1 
int counter2Pin = 5;                  // digital button for rotation counter 2 for motor 2
int counter1=0;                       // counter for column 1 that counts between column positions
int counter2=0;                       // counter for column 2 that counts between column positions
int counterALL1=0;                    // overall counter for column1
int counterALL2=0;                    // overall counter for column2
int counter1PinVal=0;                   // the current reading from the counter 1 input pin
int counter2PinVal=0;                   // the current reading from the counter 1 input pin
int previousCounter1PinVal = LOW;     // the previous reading from the counter 1 input pin
int previousCounter2PinVal = LOW;     // the previous reading from the counter 2 input pin
long counter1time = 0;                // the last time the output pin was toggled
long counter2time = 0;                // the last time the output pin was toggled
long debounce = 6000;                 // the debounce time, increase if the output flickers

//----------------------------------------------------------------------------------
// CALIBRATION 
int clibrationSwitch1=0;                //calibration and interrupt switch for column 1 (interrupt 0)
int clibrationSwitch2=0;                //calibration and interrupt switch for column 2 (interrupt 1)
int clibrationSwitchPin1 = 2;         //digital pin for switch for column 1
int clibrationSwitchPin2 = 3;         //digital pin for switch for column 2

int initialCalibration1 = 0;           
int initialCalibration2 = 0;

int calibrated1 = 0;
int calibrated2 = 0;

//----------------------------------------------------------------------------------
// SETUP
void setup() 
{ 
  pinMode (ledPin0, OUTPUT);     // sets the digital pin as output 
  
  pinMode (mode1, OUTPUT);     // sets the digital pin as output 
  pinMode (phase1, OUTPUT);    // sets the digital pin as output
  pinMode (enable1, OUTPUT);   // sets the digital pin as output 
  
  pinMode (mode2, OUTPUT);     // sets the digital pin as output 
  pinMode (phase2, OUTPUT);    // sets the digital pin as output
  pinMode (enable2, OUTPUT);   // sets the digital pin as output 
    
  pinMode(counter1Pin, INPUT);     
  pinMode(counter2Pin, INPUT); 

  pinMode(clibrationSwitchPin1, INPUT);
  pinMode(clibrationSwitchPin1, INPUT);

//----------------------------------------------------------------------------------
// LOOP
void loop() 
{ 
 
 while (calibrated1 == 0) {
    calibrate(); //calibratebothmotors
  } 

// this is just a dumb motor motion just for sorting out the code. 

 motor1QuarterDown();
 delay(500);
 motor1QuarterDown();
 delay(5000);
 
 motor1QuarterUp();
 delay(500);
 motor1QuarterUp();
 delay(5000);
}

//----------------------------------------------------------------------------------
// FUNCTIONS

void calibrate(){
  detachInterrupt(0);
  detachInterrupt(1);
  Serial.println("calibration mode");
  
  //initialCalibration1 = 0; 
  
  clibrationSwitch1 = digitalRead(clibrationSwitchPin1);               
    
  while(clibrationSwitch1 == LOW && initialCalibration1 == 0){
    motor1_up();
     clibrationSwitch1 = digitalRead(clibrationSwitchPin1);
      Serial.print("up");
  }
  
  if (clibrationSwitch1 == HIGH && initialCalibration1 != 3){                  // when the column has gone up to trigger
    motor1_stop();    
    initialCalibration1 = 1;                       // first initial calibration complete aka switch has been toggled
    Serial.println("contact");    
    delay(500);
    
    counter1=0;      
    counter1time = millis();
    debounce = 10;
    
   
    while (counter1 < 1 && counter1 >= 0 && initialCalibration1 == 1) {      
      motor1_down();   
      Serial.print("down");      
    } 
    counter1=0;
    counterALL1=0;
    debounce=6000;
    motor1Position = 4;    
    calibrated1 = 1;
    initialCalibration1 = 3;
    
    attachInterrupt(0, error, CHANGE);  // encoder pin on interrupt 0 - pin 2
    attachInterrupt(1, error, CHANGE);  // encoder pin on interrupt 0 - pin 3
    Serial.println("interrupts attached"); 
    
    
    
    Serial.println("calibration OK");    
  }


//----------------------------------------------------------------------------------
//
void error(){
 Serial.println ("*** ERROR *** ERROR *** ERROR *** ERROR *** ERROR *** ERROR *** ERROR *** ERROR *** ERROR *** ERROR ***");
  
  
  allStop();
  errorState = 1;
  
 
}
//----------------------------------------------------------------------------------
// 

void checkCounter1()
{
  counter1PinVal = digitalRead(counter1Pin);
   //Serial.print (counter1PinVal);
  if (counter1PinVal == HIGH && previousCounter1PinVal == LOW && millis() - counter1time > debounce) {    
    counter1 = counter1 + 1;
    motor1_stop();
   
   // if direction is needed this will count how rotations clockwise and counterclockwise
    if (motor1Dir == 2) 
      {  
      counterALL1 = counterALL1 + 1;         // going down
      //Serial.println ("c+");
      } 
    if (motor1Dir == 1)
      {
      counterALL1 = counterALL1 - 1;         // going up
      //Serial.println ("c-");
      }
      
  counter1time = millis(); 
  Serial.print ("c1="); Serial.println (counter1);  
  Serial.print ("cALL_1="); Serial.println (counterALL1);
  }
  
  previousCounter1PinVal = counter1PinVal;
  
}

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

void motor1_down() {
  
    motor1Dir = 1; 
    
    digitalWrite(mode1, 1);
    digitalWrite(phase1, 0); 
    digitalWrite(enable1, 1);
    checkCounter1();
  
}

void motor1_up() {
    motor1Dir = 2;   
    
    digitalWrite(mode1, 0); 
    digitalWrite(phase1, 1); 
    digitalWrite(enable1, 1);
    checkCounter1();
   
}

void motor1QuarterUp()
{
  if (motor1Position < 4) 
  {
    counter1time = millis();
    while (counter1 <= 4 && counter1 >= 0){
    
      motor1_up();
    }
    motor1_stop();
    motor1Position = motor1Position + 1;
    Serial.println("m1QU < 4");
    Serial.print("Motor 1 Position is "); Serial.println(motor1Position);
    Serial.print("Motor 2 Position is "); Serial.println(motor2Position);
    counter1=0;
  }
  else if (motor1Position == 4) {
    motor1_stop();
    motor1Position = 4;
    Serial.println("m1QU = 4");
    Serial.print("Motor 1 Position is "); Serial.println(motor1Position);
    Serial.print("Motor 2 Position is "); Serial.println(motor2Position);
  }
  
  else {
   // motor1_calibrate();
   Serial.println("m1QU error");
   Serial.print("Motor 1 Position is "); Serial.println(motor1Position);
   Serial.print("Motor 2 Position is "); Serial.println(motor2Position);
  }
}

void motor1QuarterDown() {
  if (motor1Position > 1) {
    counter1time = millis();
    while (counter1 <= 4 && counter1 >= 0) {
      
      motor1_down();
    }
    motor1_stop();
    motor1Position = motor1Position - 1;
    Serial.println("m1QD > 1");
    Serial.print("Motor 1 Position is "); Serial.println(motor1Position);
    Serial.print("Motor 2 Position is "); Serial.println(motor2Position);
    
    counter1=0;
  }
  
  
  else if (motor1Position == 1) {
    motor1_stop();
    motor1Position = 1;
    Serial.println("m1QD = 1");
   Serial.print("Motor 1 Position is "); Serial.println(motor1Position);
   Serial.print("Motor 2 Position is "); Serial.println(motor2Position);
  }
  
  else {
   // motor1_calibrate();
    Serial.println("m1QD error");
   Serial.print("Motor 1 Position is "); Serial.println(motor1Position);
   Serial.print("Motor 2 Position is "); Serial.println(motor2Position);
  }
}

This is just a part of the code...

The arduino compiles the full code fine. I'm not sure if I can use the attachinterrupt in a function or only in setup... but then why would they give you detachinterrrupt funcion?

I have sketches that attachInterrupt() in Setup(), dettachInterrupt() in Loop() and re-attachInterrupt later in Loop(), so that may not be your problem.

(Example - http://www.arduino.cc/playground/X10/ReceiveX10 lines 34,50,54)

Try it without any Serial.prints in the interrupt hander. Perhaps put in some code to turn on an LED so you can see when the handler is called. BTW, what code is in the allStop() function?

allStop() stops the DC motors

so this is the parts of that code that pertain to the interrupt...

  • - RJ11 pin 2 (RED) -> GND #define ZCROSS_PIN 2

volatile unsigned int ZCrossCnt = 0;

void setup() { attachInterrupt(0,Check_Rcvr,CHANGE);// (pin 2) trigger zero cross

void loop(){

detachInterrupt(0); // must detach interrupt before sending

attachInterrupt(0,Check_Rcvr,CHANGE);// re-attach interrupt }

Do I just need to #define that pin? What is volatile unsigned?

When you detach that interrupt can you still use it as a normal switch? That's my case I guess. Otherwise I'll need to use another pin for my calibrating and use pin2 as the interrupt.

My calibrating pin which just reads HIGH/LOW is digital pin2... that's what I want to use as an interrupt. But first I want to use that pin as a normal switch during the calibration so I can set the winch to the correct position, then after calibration is done, if the winch goes over that position, throw an error and either stop everything or recalibrate...

Sorry, didn't mean to confuse you. The link was just an example showing proof of what I was saying. ZCROSS has nothing to do with interrupts per sei.

I think 'mems' suggestion about removing Serial.print from your interrupt handler ("error()") is a very good one. Serial.print and delays do not play well in interrupt handlers (AKA ISR's)

To be honest I don't know for sure if you can use the same pin that the ISR trigger was on as a digitalRead if the interrupt is detached - but I'd be surprised if you couldn't.

I'd try mems suggestion and if that gets thing going you can use/try the switch thing. I think it will work. (You also have the option to connect the switch to 2 pins if necessary - as you said.)

Also note you set up the interrupt on CHANGE. This means the ISR is called when the switch goes from off to on and again when it goes from on to off. If that's what you want then OK if not look into the LOW, RISING and FALLING modes. http://arduino.cc/en/Reference/AttachInterrupt.

Again, sorry about the confusion. :-[

Do I just need to #define that pin?

http://arduino.cc/en/Reference/Define You can use #define for pins instead of a variable as long as the pin number will not be changed by the code when it's running - but it won't help or hurt you - it just saves a couple of bytes.

What is volatile unsigned?

http://arduino.cc/en/Reference/Volatile So it's a good idea to use volatile for vars that change in the ISR.

Looks like your going to make that little chip control something big! Good luck with your project.

allStop() stops the DC motors

Raf, I was asking what was in the function, not its purpose. can you post the code. Perhaps there is something in there that is related to the problem.

Aaagghh!! Scrolling finger hurts! It hurts!!

Please, when posting code, use the # button above you when you are typing.