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

Векторы прерываний в 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 - регистр флагов в Atmega8

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

Прерывания работают только тогда, когда в регистре состояния SREG разрешены общие прерывания (бит 7 = 1). В случае наступления прерывания этот бит автоматически сбрасывается в 0, блокируя выполнение последующих прерываний.

Прерывания по внешним событиям
  например 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<<6); //разрешаем прерывание INT0 (6-ой бит регистра прерываний GIMSK)
    //GIMSK |=(1<<7); //разрешаем прерывание INT1 (7-ой бит регистра прерываний GIMSK)
    //GIMSK |=(1<<INT0); //можно так записать регистр маски прерываний   
    //MCUCR=0b00001111; // int by rising front - прерывание сработает при 1->0, т.е. ISC01=11; ISC00=11;
    //MCUCR=0b00001010; // int by falling front - прерывание сработает при 0->1, т.е. ISC01=10; ISC00=10;
    MCUCR &=~((1<<ISC01)|(1<<ISC00)); //по нижнему уровню
    asm("sei"); // разрешаем прерывания глобально
    while(1){
      asm("nop");
   }
}
При выполнении наших функций, чтоб не было глюков прописываем запрет на выполнение прерывания, пока выполняется наша фуyкция:
NashaFunkciya(){
  asm("cli");// запрет прерывания
  ... команды
  asm("sei");// разрешаем прерывания
}