R2 Project Log – External Interrupts

I’ve done some playing, and worked out how to turn on the external interrupts on the atmega128 I am using for R2.

Code:

#define F_CPU 1000000UL
#include < avr/io.h>
#include < util/delay.h>
#include < avr/interrupt.h>

#include "r2.h"

int main(void) {
	// Activate all the LEDs, set their pins to output
	bit_set(LED_WHITE_L_DDR, LED_WHITE_L_BIT);
	bit_set(LED_WHITE_R_DDR, LED_WHITE_R_BIT);
	bit_set(LED_RED_L_DDR, LED_RED_L_BIT);
	bit_set(LED_RED_R_DDR, LED_RED_R_BIT);
	bit_set(LED_YELLOW_FL_DDR, LED_YELLOW_FL_BIT);
	bit_set(LED_YELLOW_FR_DDR, LED_YELLOW_FR_BIT);
	bit_set(LED_YELLOW_RL_DDR, LED_YELLOW_RL_BIT);
	bit_set(LED_YELLOW_RR_DDR, LED_YELLOW_RR_BIT);

	// enable internal pullup on PD0
	bit_set(PORTD, BIT(0));
	// enable external interrupts
	EIMSK = BIT(INT0) | BIT(INT1);
	// enable global interrupts
	sei();

	// turn on the white and red LEDs
	bit_set(LED_WHITE_L_PORT, LED_WHITE_L_BIT);
	bit_set(LED_WHITE_R_PORT, LED_WHITE_R_BIT);
	bit_set(LED_RED_L_PORT, LED_RED_L_BIT);
	bit_set(LED_RED_R_PORT, LED_RED_R_BIT);

	// loop forever
	while (1)
	{
		delayms(500);
	}
	return 0;
}

// delay for up to 65k milliseconds
void delayms(uint16_t millis)
{
	// loop, delaying 1ms each iteration
	while ( millis )
	{
		_delay_ms(1);
		millis--;
	}
}

// this catches the Interrupt sent from pin INT0
ISR(INT0_vect)
{
	//Turn everything off
	bit_clear(LED_WHITE_L_PORT, LED_WHITE_L_BIT);
	bit_clear(LED_WHITE_R_PORT, LED_WHITE_R_BIT);
	bit_clear(LED_RED_L_PORT, LED_RED_L_BIT);
	bit_clear(LED_RED_R_PORT, LED_RED_R_BIT);

	// loop forever, flashing our indicators.
	while(1)
	{
		bit_flip(LED_YELLOW_FL_PORT, LED_YELLOW_FL_BIT);
		bit_flip(LED_YELLOW_FR_PORT, LED_YELLOW_FR_BIT);
		bit_flip(LED_YELLOW_RL_PORT, LED_YELLOW_RL_BIT);
		bit_flip(LED_YELLOW_RR_PORT, LED_YELLOW_RR_BIT);
		delayms(500);
	}
}

Changing Trigger Mode:

By default, the interrupt triggers when the pin is brought low. If we want to change this behavior, we need to poke at the External Interrupt Control Registers, EICRA (for INT0 – INT3) and EICRB (for INT4 – INT7).

Each interrupt pin has 2 bits in the EICR Registers, ISCxO and ISCx1. This Gives 4 possible options for triggering:

  • 0 0: Default, Trigger when INTx is held low
  • 0 1: Not Used
  • 1 0: Trigger when INTx changes from 1 to 0
  • 1 1: Trigger when INTx changes from 0 to 1

So, to turn on INT1, and set it to trigger on a rising edge, we,d use the following code:

// enable external interrupt
EIMSK = BIT(INT0);
//  set the interrupt to trigger on a rising edge
EICRA |= BIT(ISC00) | BIT(ISC01);

Video: