When it's better to be out of the loop
Unlike timer interrupts, external interrupts are triggered by external events. For example, when a button is pushed or you receive a pulse from a rotary encoder. However, just like the timer interrupts, you don’t need to keep polling the GPIO pins for a change.
The Arduino UNO has 2 external interrupt pins. In this example, we’ll attach our pushbutton to one of them and use it to reset our sweepers. First, well add a "reset()" function to our sweeper class. The reset() function sets the position to 0 and immediately positions the servo there:
void reset() { pos = 0; servo.write(pos); increment = abs(increment); }
Next, we'll add a call to AttachInterrupt() to connect the external interrupt with our handler code.
On the UNO, Interrupt 0 is associated with digital pin 2. We tell it to look for the "FALLING" edge of the signal on that pin. When the button is pressed, the signal "falls" from HIGH to LOW and the "Reset" interrupt handler is called.
pinMode(2, INPUT_PULLUP); attachInterrupt(0, Reset, FALLING);
And here is the "Reset" Interrupt Handler. It just calls the sweeper reset functions:
void Reset() { sweeper1.reset(); sweeper2.reset(); }
Now, whenever you press the button, the servos stop what they are doing and immediatey seek to the zero position.
#include <Servo.h> class Flasher { // Class Member Variables // These are initialized at startup int ledPin; // the number of the LED pin long OnTime; // milliseconds of on-time long OffTime; // milliseconds of off-time // These maintain the current state volatile int ledState; // ledState used to set the LED volatile unsigned long previousMillis; // will store last time LED was updated // Constructor - creates a Flasher // and initializes the member variables and state public: Flasher(int pin, long on, long off) { ledPin = pin; pinMode(ledPin, OUTPUT); OnTime = on; OffTime = off; ledState = LOW; previousMillis = 0; } void Update(unsigned long currentMillis) { if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime)) { ledState = LOW; // Turn it off previousMillis = currentMillis; // Remember the time digitalWrite(ledPin, ledState); // Update the actual LED } else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime)) { ledState = HIGH; // turn it on previousMillis = currentMillis; // Remember the time digitalWrite(ledPin, ledState); // Update the actual LED } } }; class Sweeper { Servo servo; // the servo int updateInterval; // interval between updates volatile int pos; // current servo position volatile unsigned long lastUpdate; // last update of position volatile int increment; // increment to move for each interval public: Sweeper(int interval) { updateInterval = interval; increment = 1; } void Attach(int pin) { servo.attach(pin); } void Detach() { servo.detach(); } void reset() { pos = 0; servo.write(pos); increment = abs(increment); } void Update(unsigned long currentMillis) { if((currentMillis - lastUpdate) > updateInterval) // time to update { lastUpdate = currentMillis; pos += increment; servo.write(pos); if ((pos >= 180) || (pos <= 0)) // end of sweep { // reverse direction increment = -increment; } } } }; Flasher led1(11, 123, 400); Flasher led2(12, 350, 350); Flasher led3(13, 200, 222); Sweeper sweeper1(25); Sweeper sweeper2(35); void setup() { sweeper1.Attach(9); sweeper2.Attach(10); // Timer0 is already used for millis() - we'll just interrupt somewhere // in the middle and call the "Compare A" function below OCR0A = 0xAF; TIMSK0 |= _BV(OCIE0A); pinMode(2, INPUT_PULLUP); attachInterrupt(0, Reset, FALLING); } void Reset() { sweeper1.reset(); sweeper2.reset(); } // Interrupt is called once a millisecond, SIGNAL(TIMER0_COMPA_vect) { unsigned long currentMillis = millis(); sweeper1.Update(currentMillis); //if(digitalRead(2) == HIGH) { sweeper2.Update(currentMillis); led1.Update(currentMillis); } led2.Update(currentMillis); led3.Update(currentMillis); } void loop() { }
Page last edited March 08, 2024
Text editor powered by tinymce.