[D0CT0RD ]
Главная » Статьи » Программирование AVR

4. Прерывания в микроконтроллере
Что такое прерывание? Прерывание - это событие, при котором происходит приостановка основной программы и переход на выполнение подпрограммы прерывания. Чтобы узнать какие же есть прерывания в МК, откроем даташит микроконтроллера и нажмем на вкладку Interrupts и там в самом начале увидим таблицу векторов прерываний. Для МК mega8 она выглядит вот так.
 
В каждом векторе прерывания находится команда перехода с адресом начала подпрограммы прерывания. Любая программа начинается с Reset, в котором находится команда перехода к блоку инициализации. А дальше, каждое прерывание настроено на какое-то событие и при срабатывании этого события программа переходит к обработчику этого прерывания. Видно, что каждому прерыванию соответствует свой вектор прерывания. Чем выше адрес прерывания, тем ниже приоритет прерывания. Т.е. в очереди прерываний, прерывания с большим приоритетом будут выполняться раньше. Если началась обработка какого-нибудь прерывания, никакое другое не может быть вызвано, даже с большим приоритетом. Иначе получался бы рекурсивный вызов обработчиков прерываний и сложнее было бы отследить работу программы. При вызове обработчика любого прерывания бит глобального разрешения прерываний I регистра SREG (status register - регистр состояния) сбрасывается в "0"и только по завершении обработки прерывания снова устанавливается в "1" и разрешает начать обработку следующего прерывания в очереди. Чтобы установить ручками этот бит существует функция sei(), а чтобы сбросить - cli(). При запуске программы этот бит всегда сброшен и чтобы прерывания срабатывали его нужно установить (вызвать sei()).
Итак, в этой статье нас будут интересовать только внешние прерывания, т.е. те прерывания, которые возникают при изменении состояния определенных входом МК. Из таблицы векторов прерываний видно, что у МК ATmega8 таких прерываний 2 - INT0 и INT1 и их приоритет выше других прерываний. Жмем в даташите External Interrupts и обнаруживаем интересную вещь. Для настройки этих прерываний нужно воспользоваться регистрами MCUCR (MCU Control Register - регистр управления) и GICR (General Interrupt Control Register - общий регистр управления прерываниями). Рассмотрим их подробней.
 
MCUCR
  • Бит 1, 0 - ISC01, ISC00: Настройка условия срабатывания прерывания INT0 (таблица 1).
  • Бит 3, 2 - ISC11, ISC10: Настройка условия срабатывания прерывания INT1 (таблица 2)
Биты 4-7 относятся к управлению питанием и здесь рассматривать их не будем.
 
GICR
  • Бит 7 - INT1: Разрешает внешнее прерывание 1 ("1" - разрешено, "0" - запрещено)
  • Бит 6 - INT0: Разрешает внешнее прерывание 0 ("1" - разрешено, "0" - запрещено)
Также любое прерывание имеет свой флаг прерывания. Этот флаг устанавливается в "1" в момент, когда должно произойти прерывание, даже если прерывания глобально запрещены и соответствующая программа обработки прерывания не вызывается. Можно, например, внутри какого-нибудь обработчика прерывания по этому флагу проверять было ли какое-либо прерывание или нет. Флаги внешних прерываний являются 7-м и 6-м битом регистра GIFR. Флаги прерыванийсбрасываются записью в них "1".
 
GIFR
  • Бит 7 - INTF1: Флаг внешнего прерывания 1.
  • Бит 6 - INTF0: Флаг внешнего прерывания 0.
Вот собственно и все, что нужно знать чтобы настроить внешние прерывания. Рассмотрим на примере, что нужно записать в регистры MCUCR и GICR, чтобы настроить внешние прерывания. Мы хотим настроить вызов обработчика прерывания INT1 при установлении "1" на входе INT1 (т.е. по переднему фронту импульса). Согласно таблице 2 нужно установить в "1" биты ISC11 и ISC10 регистра MCUCR, а по таблице 1 бит INT1 регистра GICR. Таким образом, MCUCR = 0b00001100 и GICR = 0b10000000.
Настроим внешние прерывания в WinAVR. Чтобы вызвать обработчик конкретного прерывания в WinAVR нужно воспользоваться макросом ISR и указать ему в качестве параметра вектор нужного прерывания. Откроем файл микроконтроллера mega8 - в папке с WinAVR по адресу \avr\include\avr\iom8.h и в  нем найдем определения векторов прерывания. Внешнему прерыванию INT1 соответствует вектор INT1_vect. В блоке инициализации устанавливаем регистры MCUCR и GICR, после этого вызываем функцию sei(). Да, еще нужно подключить файл interrupt.h. В примере добавил переменную, которую будем инкрементировать при срабатывании внешнего прерывания - такой себе счетчик. Все это будет выглядеть вот так:
 
#include <iom8.h>
#include <avr/io.h>
#include <avr/interrupt.h>
//определяем биты регистров
#define ISC10 2
#define ISC11 3
#define INT1 7
unsigned char int1 = 0;
ISR(INT1_vect)
{
//обработка прерывания
 int1++; 
}
//функция инициализация внешнего прерывания
void INTinit()
{
 MCUCR = (1<<ISC10) | (1<<ISC11);//0b00001100
 GICR = (1<<INT1);//0b10000000
}
int main()
{
 INTinit();//вызываем функцию инициализации прерывания
 sei();//устанавливаем бит глобального разрешения прерываний
while(1);
}
Категория: Программирование AVR | Добавил: 999 (28.03.2015)
Просмотров: 1507 | Теги: AVR, Микроконтроллеры, прерывания | Рейтинг: 0.0/0
Всего комментариев: 0
avatar