Events management (Part 2)

Part 1, 2, 3

In the previous attemps to capture a change in the state of an input line, we faced a timing problem. Interrupts will help us in this way. First we “attach” an interrupt to one one the two dedicated lines from Arduino (repectively PIND2 and PIND3 nammed after interrupt line 0 and 1): in the present case we tell Arduino that in case there is a change in the state of PIND2, the readState() routine shall be executed. As simple as this!

attachInterrupt(0, readState, CHANGE);

If we are interested in driving the output line as soon as a change occurs, we will add the writeState() at the end of the readState() routine just like this:

#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();
	attachInterrupt(0, readState, CHANGE);
	// Functions
	blinkLed(5, 200);
}

void loop(void) {
	// Do something else here
	delay(10);
}

void readState(void) {
// Read pushbutton state (Ground true)
  pushButtonState = ((~PIND >> PIN_PUSHBUTTON) & 0x01); 
	writeState(); // write pushbutton state on led output
}

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);
	}
}

In some cases, we will care about the change at a fixed interval. So that the writeState() routine will be inserted in the loop() routine:

void loop(void) {
	writeState(); // write pushbutton state on led output
	// Do something else here
	delay(10);
}

For the fun of making things more complex than necessary, we can program registers directly in order to get rid of the attachInterrupt() function:

#include 

#define PIN_PUSHBUTTON PIND2
#define LED_PIN PINB5
volatile 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);	
	// Attach interrupt
	EICRA = (1 << ISC00);	// Any logical change on INT0 generates an interrupt request.
	EIMSK = (1 << INT0); // Enable external interrupt on INT0
	// Set global variable
	lastTime = millis();
	// Functions
	blinkLed(5, 200);
}

void loop(void) {
	writeState(); // write pushbutton state on led output
	// Do something else here
	delay(10);
}

ISR(INT0_vect) {
// Former readState() routine
	// 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);
	}
}

There are only few changes: the #include declaration , the ISR(INT0_vect) routine which stands for “Intrerrupt Service Request” attached to INT0 vector (INT0 is physically identical to PIND2) and the the pushbuttonState is declared as volatile.

Warning: Care shall be taken to keep the code inside the ISR as short as possible. See reference documentation for more detailed information.

It may be a good time to remind that it is possible to enable or disable ALL interrupts by using respectively the sei(); and the cli(); functions. For selectively enabling or disabling external interrupts, use EIMSK |= (1 << INT0:1); and EIMSK &= ~(1 << INT0:1); instead.

OK, OK, well done, but I would like to attach external interrupts to other input lines, is it possible? Yes!

Next post on same subject

Leave a Reply

You must be logged in to post a comment.