﻿/*
         Live-Demonstration Interrupts on Atmel AVR
         Microcontroller: ATMEGA 16

Author:   Stefan Gänsler
Contact:  stefan.gaensler@tum.de
Date:     01.12.2011
Licence:  CC 3.0 by-nc-sa

All pagenumbers mark pages in the datasheet of ATMEGA 16
http://www.atmel.com/dyn/resources/prod_documents/doc2466.pdf

*/

#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>

uint8_t volatile i = 0;

int main(void)
{
	// set port B to 1 (STK500 user guide p.12)
	PORTB = 0xFF;

	// Data Direction Register
	// set port B as output
	DDRB = 0xFF;

	// CASE 1: use a timer to let LED blink
	// TimerCounter Control Register 1 B
	// set timer clock source, p.85 top
	TCCR0 |= (0<<CS02)|(0<<CS01)|(1<<CS00);

	// TimerCounter Control Register 0
	// set timer to CTC modus (count to OCR0), p.83 bottom
	TCCR0 |= (1<<WGM01);

	// Output Compare Register 0, p.85 middle
	// 3.81469726562 Hz ISR call with prescaler 1024
	OCR0 = 255;

	// TimerCounter Interrupt Mask
	// enable interrupt on compare match, p.85 bottom
	TIMSK |= (1<<OCIE0);


	// CASE 2: Interrupt on key press
	// MCU Control Register
	// Set Interrupt on falling edge on INT0 (Switch 2), p.69 top
	MCUCR |= (1<<ISC01)|(0<<ISC00);

	// Generic Interrupt Control Register
	// Enable Interrupt 0, p.69 bottom
	GICR |= (1<<INT0);


	// enable all interrupts - set SREG I bit, p.9 bottom
	// see p.45 for all interupt vectors
	sei();


	while(1)
	{

		// turn leds on on key press (first demo)
		PORTB = PIND;

		// LED 3 blink - bad implementation, main loop blocked during delay
		PORTB ^= 1<<3;
		_delay_ms(1000);

		// CASE 3 global variable
		// variable also used in ISR, so we need a volatile declaration
		if(i == 1)
			PORTB &= ~(1<<1);
		if(i == 0)
			PORTB |= (1<<1);

	}

}

// Interrupt Service Routines

// ISR for CASE 1
ISR(TIMER0_COMP_vect)
{
	PORTB ^= (1<<0);

	// CASE 3 edit a variable
	i ^= 1;
}

// ISR CASE 2
ISR(INT0_vect)
{
	PORTB ^= (1<<7);

	// don't do this, you will prevent your main program from working
	//_delay_ms(5000);

}