Векторы прерываний в 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), GIFR, TIMSK, 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");// разрешаем прерывания
}