One interrupt works, other doesn't

I am trying to figure out how to use interrupts. This code

// general constants
// interrupt pin
const int changePin = 13;
// pin to sense change
const int sensorPin = 2;
// debug switch
const bool DEBUG = true;

// forward declarations
// interrupt service routine 1
void displayMicros();
// interrupt service routine 2
void displayMillis();


/*==========================================*/


void setup()
{
    // start Serial
    Serial.begin(9600);

    // tell 'em who we are, man
    Serial.println("     usingInterrupts.ino");
    Serial.println();

    // initialize pins
    pinMode(changePin, OUTPUT);
    pinMode(sensorPin, INPUT);


    // hook up the interrupts
    attachInterrupt(digitalPinToInterrupt(sensorPin), 
        displayMicros, RISING);
    attachInterrupt(digitalPinToInterrupt(sensorPin),
        displayMillis, FALLING);
}  //  end setup()


/*==========================================*/


void loop()
{
    digitalWrite(changePin, HIGH);
    delay(2000);
    digitalWrite(changePin, LOW);
    delay(2000);
    Serial.println();
}  //  end loop()


/*==========================================*/


// interrupt service routine 1
void displayMicros()
{
    Serial.print("micros() = ");
    Serial.println(micros());
}  // end displayMicros()


// interrupt service routine 2
void displayMillis()
{
    Serial.print("millis() = ");
    Serial.println(millis());
}  //  end displayMillis()

gives this output

Opening port
Port open
     usingInterrupts.ino

millis() = 1999

millis() = 5999

millis() = 10000

millis() = 14001

millis() = 18000

My circuitry is a UNO with a jumper from D13 to D2.

Why does millis() work okay but micros() not?

Thanks

You can not (or should not) ever use Serial communications in an ISR. Also there are no interrupts on pin 13. You really need to start reading the documentation.

I think it's a safe bet that you can't set one pin to trigger on both FALLING and RISING. You set it to trigger on RISING and then overrode/replaced that with FALLING which is why only the millis() are printed. If you want to catch both rising and falling, you should use one attach function with CHANGE and then determine whether the pin was high or low when the interrupt occurs.

Pete

aarg:
You can not (or should not) ever use Serial communications in an ISR.

I can’t find that warning in the Arduino Reference. Where did they hide it?

aarg:
Also there are no interrupts on pin 13. You really need to start reading the documentation.

I didn’t set an interrupt on pin 13. I found this in the Arduino Reference
InterruptsToUse-640x271.png

so I set the interrupts to pin 2 (hence the aforementioned jumper).

Well, the Arduino documentation links to Nick Gammon's documentation, which says in part,

Don't do serial prints

Thanks Pete

el_supremo: I think it's a safe bet that you can't set one pin to trigger on both FALLING and RISING.

Ah Ha! One pin - one interrupt.

el_supremo: If you want to do catch both rising and falling, you should use one attach function with CHANGE and then determine whether the pin was high or low when the interrupt occurs.

// constants
// interrupt pin
const int changePin = 13;
// pin to sense change
const int sensorPin = 2;


// forward declarations
// interrupt service routine
void actOnPinChange();


/*==========================================*/


void setup()
{
    // start Serial
    Serial.begin(9600);

    // tell 'em who we are, man
    Serial.println("     usingInterrupts.ino");
    Serial.println();

    // initialize pins
    pinMode(changePin, OUTPUT);
    pinMode(sensorPin, INPUT);


    // hook up the interrupts

    attachInterrupt(digitalPinToInterrupt(sensorPin),
        actOnPinChange, CHANGE);
}  //  end setup()


/*==========================================*/


void loop()
{
    digitalWrite(changePin, HIGH);
    delay(2000);
    digitalWrite(changePin, LOW);
    delay(2000);
    Serial.println();
}  //  end loop()


/*==========================================*/


// interrupt service routine 
void actOnPinChange()
{
    if (digitalRead(sensorPin) == HIGH)
    {
        Serial.print("micros() = ");
        Serial.println(micros());
    }
    else
    {
        Serial.print("millis() = ");
        Serial.println(millis());
    }
}  // end actOnPinChange()

gives

Opening port
Port open
     usingInterrupts.ino

micros() = 308
millis() = 1999

micros() = 4000888
millis() = 6000

micros() = 8001656
millis() = 10001

micros() = 12002456
millis() = 14002

Thanks aarg

I had read ... you should not try to do debugging "prints" inside an ISR. The time taken to do those is likely to cause more problems than they solve on Gammon's page and decided that, in this program, the execution time if the ISR was irrelevant so I used it anyway.

However, I see that I missed Don't do serial prints (eg. Serial.println ("ISR entered"); ) Don't try to do serial reading.

Hmm. My last post on this thread shows that Serial does work in the ISR, but then again - that is all the ISR has to do and time taken is irrelevant. Let's assume that that wasn't the case and that it was imperative to return information somehow during the operation of the interrupt. How would I go about that?

vagulus: Hmm. My last post on this thread shows that Serial does work in the ISR, but then again - that is all the ISR has to do and time taken is irrelevant. Let's assume that that wasn't the case and that it was imperative to return information somehow during the operation of the interrupt. How would I go about that?

Return something during an interrupt? What kind of crazy talk is that? During an interrupt, the processor state including the address of the code that was running at the time the interrupt was triggered, is waiting on the stack. It's in deep freeze waiting for the ISR to complete.

You simply can not do what you are describing, no matter how imperative it is. If it is really imperative, then the application that you are designing has to be scrapped.

What you can do, is assign values to variables that will be read by the main code after the ISR completes. You have to follow rules for that, including declaring them volatile.

aarg:
Return something during an interrupt? What kind of crazy talk is that?

// constants
// button one
const int BUTTON_ONE_PIN = 2;
// button two
const int BUTTON_TWO_PIN = 3;
// debug switch
const bool DEBUG = true;


// global variables
// booleans changed by ISRs
volatile bool buttonOneHot = false, buttonTwoHot = false;


// the following variables are unsigned longs because the time,
//  measured in milliseconds, will quickly become a bigger number
//  than can be stored in an int.
// the last time the output pin was toggled
//unsigned long lastDebounceTime = 0;
// the debounce time; increase if the output flickers
//unsigned long debounceDelay = 50;


// forward declarations
// interrupt service routines
void buttonOnePressed();
void buttonTwoPressed();
// debounce delay
//void delayForDebounce(unsigned long lastDebounceTime);


/*==========================================*/


void setup()
{
 // start Serial
 Serial.begin(9600);

 // tell 'em who we are, man
 Serial.println("     buttonInterruptPassData.ino");
 Serial.println();

 // initialize pins and related debouncers
 // button one
 pinMode(BUTTON_ONE_PIN, INPUT);
 // button two
 pinMode(BUTTON_TWO_PIN, INPUT);

 // hook up the interrupts
 attachInterrupt(digitalPinToInterrupt(BUTTON_ONE_PIN),
 buttonOnePressed, FALLING);
 attachInterrupt(digitalPinToInterrupt(BUTTON_TWO_PIN),
 buttonTwoPressed, FALLING);
}  //  end setup()


   /*==========================================*/


void loop()
{
 // display data from ISRs
 if (buttonOneHot == true)
 {
 Serial.println("buttonOne has been pressed");
 buttonOneHot = false;
 }

 if (buttonTwoHot == true)
 {
 Serial.println("buttonTwo has been pressed");
 buttonTwoHot = false;
 }

 // show loop is running
 Serial.println("Loop is running");
 delay(2000);
}  //  end loop()


   /*==========================================*/


   // interrupt service routines
   /*
   You cannot attach more that one interrupt to any one pin, so, if
   you need two or more reactions they have to be on the basis of a
   decision made inside the ISR.
   Also, we are advised against using Serial inside an interrupt
   http://gammon.com.au/interrupts
   if we need to move information in and out we use 'volatile'
   variables.
   */
void buttonOnePressed()
{
 buttonOneHot = true;
}  // end buttonOnePressed()


void buttonTwoPressed()
{
 buttonTwoHot = true;
}  // end buttonTwoPressed()

works fine on this

TwoButtonsForInterrupts.png

passing information from the ISR to the mainline.