2

Desired behaviour:

  1. Go to IDLE sleep mode.
  2. When PB2 (blue trace) goes low wake up and give a 10 ms HIGH on PB1 pulling a pull-up low (yellow trace on Figure 1).
  3. Go to 1.

What I get:

Oscilloscope view.

Figure 1. (1) The input triggers, (2) the CPU wakes from sleep, (3) the CPU goes back to sleep and wakes up repeatedly until (9) the input goes high again.

I want one 10 ms low pulse and then go back to sleep until the next negative going edge on PB2 regardless of how long PB2 is held low.

Even though I set MCUCR to falling edge of INT0 the device seems to wake repeatedly when PB2 is held low. My code below attempts to solve this by switching to rising edge interrupt if the input is low and falling edge interrupt if the input is high. The result is shown in Figure 1.

void setup(){
  ADCSRA &= ~_BV(ADEN);               // ADC off. ADC not used.
  pinMode(reedPin, INPUT);
}

void loop(){
  system_sleep();                     // Go straigth to sleep.
  // ---- System woken up by interrupt. ---------
  if (!digitalRead(reedPin)) {        // Check that input is low.
    pinMode(outPin, OUTPUT);          // Enable output.
    digitalWrite(outPin, HIGH);       // Pull motor sensor input low by MOSFET.
    delay(pulseTime);                 // Pulse time.
    digitalWrite(outPin, LOW);        // Pulse off.
  }  
}

// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
  MCUCR |= _BV(ISC01);                    // Required for both rising and falling edge interrupt.
  if(digitalRead(reedPin)) {              // Input is high so set interrupt for detecting low.
    MCUCR &= ~_BV(ISC00);                 // Clear MCUCR bit 0 for falling edge interrupt.
  } else {                                // Input is low so set interrupt for detecting high.
    MCUCR |= _BV(ISC00);                  // Set MCUCR bit 0 for rising edge interrupt.
  }
  GIMSK |= _BV(INT0);                     // Enable Pin Change Interrupts
  set_sleep_mode(SLEEP_MODE_IDLE);        // Leaves the clock running for elapsedMillis.
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sei();                                  // Enable interrupts
  sleep_cpu();                            // sleep
  // ZZZZZZZZZZZzzzzzzzzzzz .......
  // ------- CPU is now asleep and awaiting interrupt. ----------------------
  cli();                                  // Disable interrupts on wake up.
  sleep_disable();                        // Clear SE bit.
}

ISR(INT0_vect){                           // Wake up.
  GIMSK = 0;                              // Disable external interrupts. (Only need one to wake up.)
}

Can anyone guide me through this?

Many thanks.

4

1 Answer 1

1

The Arduino core configures a timer to deliver a periodic interrupt. This interrupt is used to implement millis(), delay(), etc. Your code assumes the external interrupt is the only one the microcontroller can receive. I guess the timer interrupts may be the cause of the observed behavior.

I suggest configuring the interrupt for falling edges and leaving it always on. The ISR can take care of starting the pulse, and setting a flag to let the main loop know the pulse is active. The main loop can then stop the pulse when it has been on for long enough:

volatile bool pulse_active;     // whether the pulse is on
volatile uint32_t pulse_start;  // time when it started

ISR(INT0_vect) {
    // Start the pulse.
    digitalWrite(outPin, HIGH);
    pulse_active = true;
    pulse_start = millis();
}

void loop() {
    // End the pulse if it's time to do so.
    if (pulse_active && millis() - pulse_start >= pulseTime) {
        digitalWrite(outPin, LOW);
        pulse_active = false;
    }

    // Take a little nap.
    sleep_mode();
}

Note that the little nap in the code above can be interrupted by either the external interrupt or the timer interrupt.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.