Events management (Part 1)
Managing events in an (hopefully) intelligent manner is the primary objective for designing a microcontroller based application. I am opening this endless topic in order to compare the various solutions apllicable to the management of events.
As a starter, we will only use one input line and one output led. Next exemple illustrates the most basic application. For the sake of code readability, the status reading and the related action are written in separate routines. The loop() routine will sequencially read the status and store it in a global variable in the readState() routine, while the writeState() routine will read this variable and turn the control led accordingly.
#define PIN_PUSHBUTTON PIND2 #define LED_PIN PINB5 byte pushButtonState = 0x00; // Ground true void setup(void) { // Setup input pin DDRD &= ~(1 << PIN_PUSHBUTTON); // Bias input pin PORTD |= (1 << PIN_PUSHBUTTON); // Set led pin as output DDRB |= (1 << LED_PIN); // Functions blinkLed(5, 200); } void loop(void) { // Read push button state and turn led on or off accordingly readState(); // read pushbutton state writeState(); // write pushbutton state on led output // Do something else here delay(10); } void readState(void) { // Read pushbutton state (Ground true) pushButtonState = ((~PIND >> PIN_PUSHBUTTON) & 0x01); } void writeState() { // Write pushbutton state on led output if (pushButtonState) PORTB |= (1 << LED_PIN); // Turn led on else PORTB &= ~(1 << LED_PIN); // Turn led off } void blinkLed(int nbrBlinks, int intervals){ // Blink status led for (int i = 0; i < (nbrBlinks * 2); i++) { PORTB ^= (1 << LED_PIN); // toggle status led delay (intervals); } }
Problem is that the additional code in the loop() routine may last varaiable time, so that the pushbutton status is read on an undefined time basis (may be too fast or too slow).
A first approach would be to trigger the read and write routines at constant time intervals. This is done using the millis() function:
#define PIN_PUSHBUTTON PIND2 #define LED_PIN PINB5 byte pushButtonState = 0x00; // Ground true long interval = 100; long lastTime = 0; void setup(void) { // Setup input pin DDRD &= ~(1 << PIN_PUSHBUTTON); // Bias input pin PORTD |= (1 << PIN_PUSHBUTTON); // Set led pin as output DDRB |= (1 << LED_PIN); // Set global variable lastTime = millis(); // Functions blinkLed(5, 200); } void loop(void) { long now = millis(); if ((now - lastTime) >= interval) { // Read push button state and turn led on or off accordingly readState(); // read pushbutton state writeState(); // write pushbutton state on led output lastTime = now; // record time at which last event management occured } // Do something else here delay(10); } void readState(void) { // Read pushbutton state (Ground true) pushButtonState = ((~PIND >> PIN_PUSHBUTTON) & 0x01); } void writeState() { // Write pushbutton state on led output if (pushButtonState) PORTB |= (1 << LED_PIN); // Turn led on else PORTB &= ~(1 << LED_PIN); // Turn led off } void blinkLed(int nbrBlinks, int intervals){ // Blink status led for (int i = 0; i < (nbrBlinks * 2); i++) { PORTB ^= (1 << LED_PIN); // toggle status led delay (intervals); } }
Problem now is that we cannot track changes during the interval period of time. The answer to this is “external interrupts” that we will discuss in a next post