Микроконтроллеры. Прерывания. СИ++

Векторы прерываний в Atmega8

Адрес Источник прерывания Описание
0x0000 RESET Сигнал сброса
0x0001 INT0 Внешний запрос на прерывание по входу INT0
0x0002 INT1 Внешний запрос на прерывание по входу INT1
0x0003 T/C1 Захват по таймеру T/C1
0x0004 T/C1 Совпадение с регистром сравнения A таймера T/C1
0x0005 T/C1 Совпадение с регистром сравнения B таймера T/C1
0x0006 T/C1 Переполнение счётчика T/C1
0x0007 T/C0 Переполнение счётчика T/C0
0x0008 SPI Передача данных по интерфейсу SPI завершена
0x0009 UART Приём данных приёмопередптчиком UART завершен
0x000A UART Регистр данных UART пуст
0x000B UART Передача данных приёмопередптчиком UART завершена
0x000C ANA_COMP Прерывание от аналогового компаратора

Управления прерываниями

За управление прерываниями в ATmega8 отвечают 4 регистра: GIMSK (он же GICR), GIFRTIMSK, TIFR:

Регистр GIMSK (GICR) - управление прерываниями по внешним сигналам на входах INT0, INT1

7 6 5 4 3 2 1 0 Описание
INT1 INT0  -  -    -     -    -   -  
1 прерывания по входу INT0 разрешён
1 прерывания по входу INT1 разрешён

Регистр GIFR - управление всеми внешними прерываниями в Atmega8

7 6 5 4 3 2 1 0 Описание
INTF1 INTF0  -  -    -     -    -   -  
1
1

Регистр TIMSK управление прерываниями от таймеров/счётчиков в Atmega8

7 6 5 4 3 2 1 0 Описание
OCIE2 TOIE2 TICIE1   OCIE1A   OCIE1B  TOIE1    TOIE0
1 прерывание по переполнению TCNT0. Си: TIMSK|=(1<<TOIE0);
1 прерывание по переполнению TCNT1. Си: TIMSK|=(1<<TOIE1);
1 прерывание при совпадении регистра сравнения OCR1B с содержимым счётчика TCNT1
1 прерывание при совпадении регистра сравнения OCR1A с содержимым счётчика TCNT1
1 прерывание при выполнении условия захвата
1 прерывание по переполнению TCNT2. Си: TIMSK|=(1<<TOIE2);
1 прерывание при совпадении регистра сравнения OCR2 с содержимым счётчика TCNT2

TIFR - регистр флагов. Когда какое-то прерывание срабатывает, то выскакивает флаг, что есть прерывание. Этот флаг сбрасывается аппаратно, когда программа уходит по вектору. Если прерывания запрещены, то флаг так и будет стоять до тех пор пока прерывания не разрешат и программа не уйдет на прерывание. Чтобы этого не произошло флаг можно сбросить вручную. Для этого в регистре TIFR в него нужно записать 1, например: TIFR = (1<<TOV0); // не ИЛИ, а присвоение!

7 6 5 4 3 2 1 0 Описание
TOV1 OCF1A  OCF1B  -    ICF1     -    TOV0   -  
1 переполнение TCNT0
1 TCNT1 равно OCR1
1 произошло совпадение регистра сравнения B с содержимым счётчика T/C1
1 произошло совпадение регистра сравнения A с содержимым счётчика T/C1
1 переполнение TCNT1

Флаги сбрасывается при соответствующем прерывании или при присвоении логической 1

Прерывания работают только тогда, когда в регистре состояния SREG разрешены общие прерывания.

Прерывания по внешним событиям
  например INT0, INT1, INT2 для Atmega16
  INT0 (ножка PD2), INT1 (ножка PD3), и PCINT0...7 (все ножки порта B) для ATtiny2313. Смотреть DataSheet для каждого МК

ISR(INT0_vect){...} // INT0 вектор (прерывание по внешнему событию INT0)
ISR(PCINT0_vect){...} // PCINT0 вектор (прерывание для 0-го порта B)
ISR(PCINT2_vect){...} // PCINT2 вектор (прерывание для 2-го порта B)
ISR(TIMER_OVF_vect){...} // вектор при переполнении таймер-счётчика
ISR(TIMER_COMP_vect){...} // вектор при совпадении таймер-счётчика
Пример с внешними прерываниями:
# define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h> //подключаем прерывания
#include <util/delay.h>
ISR(INT0_vect){
	PORTD |=(1<<0);  // RD0 определяем в 1 (зажигаем)
	_delay_ms(1000); // пауза
	PORTD &=~(1<<0);  // RD0 определяем в 0 (тушим)
}
int main(void){
	DDRD |=(1<<0); // RD0 на выход
	PORTD &=~(1<<0); // RD0 определяем в 0
	DDRD |=(1<<2); // RD2 на вход (кнопка)
	PORTD |=(1<<2); // RD2 определяем в 1, т.к. кнопка по низкому уровню срабатывает
	GIMSK |=(1<<INT0); //разрешаем прерывание INT0
	//MCUCR &=~((1<<ISC01)|(1<<ISC00)); //по нижнему уровню на INT0
	//MCUCR |=(1<<ISC00); //по любому изменению на INT0
	//MCUCR |=(1<<ISC01); //по заднему фронту на INT0
	MCUCR |=(1<<ISC01)|(1<<ISC00); //по переднему фронту на INT0
	asm("sei"); // или SREG |=(1<<SREG_I); //разрешим прерывания глобально //asm("cli");// запрет прерывания
	while(1){
		asm("nop");
	}
}
При выполнении наших функций, чтоб не было глюков прописываем запрет на выполнение прерывания, пока выполняется наша фуyкция:
NashaFunkciya(){
  asm("cli");// запрет прерывания
  ... команды
  asm("sei");// разрешаем прерывания
}