Skip to content

Instantly share code, notes, and snippets.

@Wollw
Created April 14, 2012 00:17
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Wollw/2381139 to your computer and use it in GitHub Desktop.
Save Wollw/2381139 to your computer and use it in GitHub Desktop.
AVR Timer Interrupt Examples
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
/*
* A global flag used to communicate between the Interrupt Service Routine
* and the main program. It has to be declared volatile or the compiler
* might optimize it out.
*/
volatile bool update = false;
/*
* The interrupt service routine. This is run whenever the interrupt
* "TIMER1_OVF_vect" is triggered. This is an interrupt that the ATmega328P
* triggers whenever Timer 1 overflows past its maximum value. It sets
* the update flag to "true" to tell the main program that it needs to
* do something.
*/
ISR(TIMER1_OVF_vect) {
update = true;
}
int main(void) {
// Set PORTB pins as output, but off
DDRB = 0xFF;
PORTB = 0x00;
// Turn on timer with no prescaler on the clock for fastest
// triggering of the interrupt service routine.
TCCR1B |= _BV(CS10);
TIMSK1 |= _BV(TOIE1);
// Turn interrupts on.
sei();
for(;;) {
// This turns interrupts off for the code inside it. Probably
// not needed here but it's good to know about.
ATOMIC_BLOCK(ATOMIC_FORCEON) {
// If the ISR has indicated we need to update the state
// then run this block.
if (update) {
// Toggle the pins on PORTB on/off.
PORTB ^= 0xFF; // Toggle the pins on/off
/*
* We reset the update flag to false to indicate that
* we are done. This ensures that this block will not
* be executed until update is set to true again, which
* is only done by the interrupt service routine.
*/
update = false;
}
}
}
}
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <stdbool.h>
#include <util/delay.h>
/*
* Struct to hold the old and new pin states;
*/
volatile struct {
uint8_t d_old;
uint8_t d;
} pins;
/*
* Change the current pin state to the old pin state and read the new pin
* state.
*/
ISR(TIMER1_OVF_vect) {
pins.d_old = pins.d;
pins.d = PIND;
}
int main(void) {
DDRB = 0x01;
PORTD = 0x04; // pullup on PD2
// Turn on timer with no prescaler on the clock for fastest
// triggering of the interrupt service routine.
TCCR1B |= _BV(CS10);
TIMSK1 |= _BV(TOIE1);
// Turn interrupts on.
sei();
for(;;) {
ATOMIC_BLOCK(ATOMIC_FORCEON) {
// Toggle pin state on low edge (pull-up on PD2 means the pin is active low)
if ( !(pins.d & _BV(PD2)) && (pins.d_old & _BV(PD2)) ) {
PORTB ^= _BV(PB0);
_delay_ms(10);
}
}
}
}
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <stdbool.h>
#include <util/delay.h>
/*
* Struct to hold the old and new pin states;
*/
volatile struct {
uint8_t b_old;
uint8_t b;
} pins;
/*
* Change the current pin state to the old pin state and read the new pin
* state.
*/
ISR(TIM0_OVF_vect) {
pins.b_old = pins.b;
pins.b = PINB;
}
int main(void) {
DDRB = 0b011110; // PB1 through PB4 as outputs
PORTB = 0b000001; // pullup on PB0 as an input
// Turn on timer with no prescaler on the clock for fastest
// triggering of the interrupt service routine.
TCCR0B |= _BV(CS00);
TIMSK |= _BV(TOIE0);
// Turn interrupts on.
sei();
for(;;) {
ATOMIC_BLOCK(ATOMIC_FORCEON) {
// Toggle pin state on low edge (pull-up on PB0 means the pin is active low)
if ( !(pins.b & _BV(PB0)) && (pins.b_old & _BV(PB0)) ) {
if (PORTB & _BV(PB1))
PORTB &= ~_BV(PB1);
else
PORTB |= _BV(PB1);
_delay_ms(10);
}
}
}
}
@kaanaksit
Copy link

Thank you very much this piece of code help me understand the concept.

@vicvicvar
Copy link

Like!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment