Вектор прерывания atmega8 avr studio. Прерывания - Изучаем AVR - Каталог статей - Микроконтроллеры - это просто! _____________________ Cинтаксис функции прерывания _____________________
Первым делом о том что такое прерывание.
Прерывание (interrupt) - это своеобразная функция, которая будет выполнена при поступлении сигнала на какой нибудь вход контроллера.
При работе в AVR Studio прерывания создаются при помощи макросов ISR()
, SIGNAL()
и INTERRUPT()
. Они помечают некоторую функцию как обработчик прерывания. Их различие в том, что INTERRUPT()
и ISR()
определяют функцию обработчик для случая, когда разрешено общее прерывание (обработчик может быть прерван), а SIGNAL()
для случая когда общее прерывание запрещено.
На этом покончим с теорией и перейдём к практике (хотя теории ещё будет ниже).
Соберём в ISIS такую схему:
Как вы уже наверное догадались мы напишем прерывание (которое генерируется кнопкой) которое будет зажигать и тушить диод.
Итак, откройте студию и создайте стандартный проект.
Для использования прерываний включим заголовочный файл:
#include
Условимся, что прерывание (физически) не будет включать выключать питание на ноге контроллера (как это делается я уже рассматривал), а всего лишь будет изменять флаг. При определённых значениях которого и будет включаться и выключаться диод.
Зададим этот флаг глобально:
Int num = 1;
Теперь объявим прерывание:
ISR(SIG_INTERRUPT1){ if (num == 1) num = 0; else num = 1; }
Как видите в скобках макроса указан так называемый вектор прерывания. Этот вектор указывает компилятору для какого входа будет сгенерировано прерывание. Для INT1 - это SIG_INTERRUPT1. Для АЦП (ADC) например это - SIG_ADC. (весь перечень отлично описан в книге "Шпак Ю.А. Программирование на языке Си для AVR и PIC микроконтроллеров".)
Теперь перейдём к функции main нашей "программы".
Нам необходимо разрешить прерывания в целом и для INT1 в частности:
Sei(); // в целом
GIMSK |= (1< Когда это сделано нужно настроить поведение прерывания. Оно может быть сгенерировано по разному. Думаю как перевести это вы и так поймёте. MCUCR = (0< Теперь установим весь порт С как выход: DDRC = 0xff; // порт С - выход
Ну а это уже должно быть понятно: While (1){
if (num == 1)
PORTC |= 1; // включаем первый выход С
else
PORTC &= ~1; // выключаем первый выход С
_delay_ms(100); // ждём 100мс
}
Ждать не обязательно. Тем более что это уменьшает быстродействие. Но мне так хочется.
#define F_CPU 8000000UL // 8MHz
#include Компилируем hex и собираем схему в Proteus. Наслаждаемся работой прерывания при изменении положения кнопки. Для чего нужны внешние прерывания
Прерывание — это событие по которому прерывается исполнение основного кода программы (например функции main) и управление передаётся функции обработчику прерывания. Соответственно внешние прерывания — это некие внешние события прерывающие исполнение основного кода программы. Внешние прерывания позволяют получить быструю, гарантированную реакцию на внешние события. По этому наиболее частое применение внешних прерываний это реализация счетчиков импульсов, измерение частоты или длительности импульсов, программная реализация uart, one-wire, i2с, spi, а так-же обработка сигналов от внешних периферийных устройств. Для того что бы микроконтроллер узнал о внешних событиях используются дискретные входы INT0 INT1 и т.д. Дискретные означает что они работают с логическими уровнями: 0 и 1. Внешние прерывания можно разделить на два типа: Срабатывание внешнего прерывания может быть настроено на низкий или высокий логический уровень. Например, если прерывание настроено на низкий логический уровень, то оно возникает когда на входе INT напряжение равно нулю. Если же прерывание настроено на высокий уровень, то оно возникает когда на входе логическая 1. Прерывание по переднему фронту или, как иногда говорят, нарастанию сигнала, возникает когда происходит изменение уровня сигнала на входе INT с 0 на 1. Прерывание по заднему фронту (спаду сигнала), возникает при изменении уровня сигнала на входе INT с 1 на 0. Внешние прерывания в avr atmega8
настраиваются при помощи бит ISCxx
регистра MCUCR
. Зависимость условия срабатывания внешнего прерывания INT0 от бит ISC0x регистра MCUCR в avr atmega8
Для внешнего прерывания INT1
, настройка производиться так же, только используются биты ISC11
ISC10
. Пример
настройки внешнего прерывания для avr atmega8:
//сбрасываем все биты ISCxx
MCUCR &= ~((1< Для того что бы внешние прерывания заработали их надо разрешить, установив в 1 соответствующие биты в регистре GICR
. Бит INT0
отвечает за разрешение/запрещение внешнего прерывания INT0
, а бит INT1
, соответственно за внешне прерывание INT1
. Так же необходимо что бы был выставлен флаг глобального разрешения прерываний. Пример кода разрешающего внешнее прерывание INT0 для avr atmega8:
//разрешаем внешнее прерывание INT0
GICR |= (1< В качестве примера приведу программу счетчика импульсов. Программа подсчитывает количество импульсов на входе INT0, и раз в секунду выводит результат подсчета в uart. #include Частенько бывает, что микросхемка должна работать-работать себе спокойненько, а на какое-то событие бросать все дела и выполнять что-то иное. А потом - снова возвращаться к первоначальному делу... Это как в часах, например, - они показывают время до тех пор, пока не настанет время будильника. И вроде как никаких внешних воздействий - нажатия там кнопки, ресета - а микросхема сама переключается. Это и можно реализовать с помощью прерываний - сигналов, сообщающих процессору о наступлении какого-либо события. Вот пример из бытовой жизни - сидите Вы на кухне, пьете чай с малиновым вареньем и вкусняшками неприменно, и ждете гостей. А как узнать, что кто-то пришел? Тут два варианта: либо мы каждые пять минут будем отвлекаться от варенья, в смысле, чая и бегать проверять, а не стоит ли кто за дверью, либо купить дверной звонок и спокойненько ждать на нагретом месте, пока кто-нибудь в него не позвонит. Так вот, когда гость звонит - это событие. Соответственно, мы прерываемся и кидаемся к двери. Итак, у микросхемы есть прерывания. И не одно. Прерывания делятся на внешние - такие срабатывают при определённом напряжении на некоторых выводах микросхемы (INT0, INT1 и также иногда целый порт PCINT) - и внутренние - при переполнении счётчика, срабатывании сторжевого таймера, при использовании USART, при прерывании аналогового компаратора, АЦП и прочей периферии. Соответственно, возникает проблема приоритета. Это как мы все также сидим и пьем чай, но звонят нам уже не только в дверь, но и по телефону... И ведь не разорвешься, что-то нужно сделать первым. Поэтому в даташите есть таблица векторов прерываний. Чем меньше номер прерывания, тем более оно приоритетно. Здесь получается несколько тонкостей... Вот произошло событие - пошел запрос на прерывание, то есть выставляется так называемый "флаг запроса на прерывание". Если все хорошо, прерывание разрешено, то жизнь прекрасна и происходит его обработка. А вот если прерывание запрещено - например, уже происходит обработка более приоритетного прерывания - тогда этот флаг запроса так и остается висеть до момента разрешения прерываний. После этого чип проверяет регистр запроса в порядке приоритета, и если есть флаг - обрабатывает его. НО! Получается, что даже если прерывание обрабатывается, не факт, что событие, которое его вызвало, ещё живо... Это как позвонили в дверь и по телефону одновременно, Вы ответили по телефону, а гости уже решили, что никого дома нету и ушли. И вроде как событие - звонок в дверь - было, а за дверью никого нет. Ещё проблема - что пока обрабатывается другое прерывание и флаг запроса уже поднят, событие может произойти ещё несколько раз. Ответили на звонок по телефону, открываем дверь - а там уже целая куча гостей! Страшно? Страшно... Ещё одна особенность использования прерываний - да и не только прерываний: реентерабельность (или повторная входимость). Реентерабельная программа - та, которую могут вызвать несколько пользователей (или процессов), и при этом как минимум не возникнет ошибка, а как максимум - не будет потери вычислений - например, другому пользователю не придется выполнять код снова. Иными словами, если на кухне во то время, пока Вы встречаете гостей, никто не утащит себе вкусняшки, то значит все реентерабельно) В общем, серезная штука - если её не учитывать, можно долго мучится с "а чего же она не работает?!". Нужно её учитывать, например, если обрабатываются несколько прерываний, и каждое изменяет какую-то глобальную переменную... Обычно прерывания НЕ реентерабильны. То есть, в момент работы прерывания нельзя повторно вызвать это же прерывание.. Именно для защиты от повторного вхождения в обработчик прерывания автоматически запрещаются в момент его обработки (если вам захотелось разрешить прерывания в процедуре обработки прерываний, надо десять, двадцать раз подумать, прежде чем сделать такой опрометчивый шаг). Рассмотрим работу с внешними прерываниями: нам нужно, во-первых, настроить, по какому событию будет происходить прерывание, а, во-вторых, разрешить микросхеме вообще обрабатывать это самое прерывание. За первое в микросхеме ATmega8 отвечает регистр MCUCR - биты ISC11-ISC10, отвечающие за INT1, и ISC01-ISC00, отвечающие за INT0. Таблица 1. Определение событий для генерации прерывания по INT1 Соответственно, с INT0 аналогично. А теперь остается разрешить прерывания по нужному нам выводу - в регистре GIGR есть биты INT0 и INT1; поставить на нужный "1" - и внешнее прерывание разрешено! Но ещё рано радоваться - помимо внешних прерываний надо разрешить прерывания вообще - ставим крайний левый бит I регистра SREG в "1". Это же можно сделать и ассемблерной командой: asm sei; Рассмотрим простой примерчик: на ножку INT0 (D.2) микросхемы ATmega8 присоединена кнопка (к ножке и на ноль); нажимаем - возникает прерывание и включается светодиодик на выводе B.0. Светодиод, соответственно, подключен к ножке и на единицу:
//программа для ATmega8 при нажатии на кнопку на выводе INT0 (D.2) - присоединена к 0 -
//включает по внешнему прерыванию светодиодик на выводе B.0 - присоединён к 1
//переопределяем типы
typedef unsigned char byte;
sbit ddrButton at ddD2_bit; //кнопка генерации
sbit pinButton at pinD2_bit;
sbit portButton at portD2_bit;
sbit ddrLight at ddB0_bit; //вывод для светодиода, на выход с подтяжкой, включается 0 по кнопке
sbit portLight at portB0_bit;
byte flagButton = 0; //флаг нажатия кнопки; нажата - 1
void INT0_interrupt() org IVT_ADDR_INT0 //нужно написать как минимум пустую функцию -
//потому что компилятор сам не создает. Иначе не работает
{
flagButton = 1;
}
//обработка нажатия кнопки - с учётом дребезга
void buttonLight()
{
if(flagButton) //если нажата кнопка
{
portLight = 0; //включаем светодиод
delay_ms(500);
portLight = 1; //выключаем светодиод
flagButton = 0;
}
}
void main()
{
//инициализация всех используемых портов
ddrB = 0;
portB = 0;
ddrD = 0;
portD = 0;
//инициализация кнопки - на вход с подтяжкой
portButton = 1;
ddrButton = 0;
//инициализация светодиодика, которая включается по 0 и нажатию кнопки - на выход и в 1
portLight = 1;
ddrLight = 1;
//настраиваем внешние прерывания
MCUCR.ISC00 = 0; //прерывание генерируется по логическому 0 на INT0
MCUCR.ISC01 = 0;
GICR.INT0 = 1; //разрешаем внешнее прерывание INT0
asm sei;//SREG.B7 = 1; //разрешаем прерывания в принципе (бит I); команды аналогичны
while(1)
{
buttonLight();
}
}
Немного о синтаксисе. Функция прерывания написана так: void имя_функции() org IVT_ADDR_INT0. Ключевое слово org указывает, что дальше будет идти адрес прерывания из даташита. У нас же есть название прерывания из библиотечки: набираем IVT и и дальше нажимаем Ctrl + Пробел (люблю я такие вещички ˆˆ). Ещё вместо слова org можно использовать iv, судя по справке компилятора. Ещё маленькое замечание: во-первых, прерывание никогда не должно быть громоздким - несколько строк и все. Это связано с тем, что во время обработки прерывания микросхема не может отвлечься на что-либо иное, азначит, если у нас прерываний несколько, то можно пропустить наступление какого-нибудь события. А ещё может оказаться так, что обработка прерывания нам вообще не нужна - например, достаточно, что схема вышла из спящего режима. Но в этом случае все равно надо писать функцию прерывания, пусть даже пустую - так называемую "заглушку". В принципе, некоторые компиляторы автоматически пишут пустые функции для каждого прерывания, но это не наш случай - приходится делать ручками. Системы
прерываний - важная часть любой управляющей
системы. От ее работы
во многом зависит то, насколько эффективно
микропроцессорная система выполняет
свои функции. Общая структура системы
пре рываний МК-51 представлена на рис.
14.3. Микроконтроллеры
семейства МК-51 обеспечивают поддержку
пяти источников прерываний: * двух внешних
прерываний, поступающих по входам INT0
и INT1 (линии порта Р3:Р3.2 и
Р3.3 соответственно); * двух
прерываний от таймеров/счетчиков Т/С0
и Т/С1; *
прерываниеотпоследовательногопорта. Запросы на
прерывание фиксируются в регистрах
специальных функций микроконтроллера:
флаги IE0, IE1,
TF0, TF1
запросов на прерывание от INT0,
INT1, T/C0
и T/C1
содержатся в регистре управления TCON
(табл. 14.4), а флаги RI и TI
запросов на прерывание от последовательного
порта - в регистре SCON
управления последовательным портом. Таблица 14.4.
Формат регистра TCON 0 IT0 Настройка
вида прерывания INT0 1 IE0 Флаг
запроса прерывания INT0 2 IT1 Настройка
вида прерывания INT1 3 IE1 Флаг
запроса прерывания INT1 4 TR0 Включение
в работу таймера/счетчика 0 5 TF0 Флаг
переполнения (запрос прерывания)таймера/счетчика
0 6 TR1 Включение
в работу таймера/счетчика 1 7 TF1 Флаг
переполнения (запрос прерывания)таймера/счетчика
1 Флаги TF0 и TF1 устанавливаются
аппаратно при переполнении соответствующего
таймера/счетчика (точнее, при
переходе T/Cx из состояния "все
единицы" в состояние "все нули"). Флаги IE0 и
IE1 устанавливаются аппаратно от внешних
прерываний IT0 и IT1 соответственно. Внешний
запрос может вызвать установку флага
либо при низком уровне сигнала на
соответствующем входе, либо при
переключении этого сигнала с высокого
уровня на низкий (с частотой, не превышающей
половины частоты внешней синхронизации
МК). Настройка
на тип запроса осуществляется программной
установкой бит IT0 и IT1 в регистре управления
TCON. Установка ITx = 0 настраивает систему
прерывания на запрос по низкому уровню
сигнала, ITx = 1 - запрос на прерывание по
спаду сигнала. Флаги TI и RI
устанавливаются аппаратно схемой
последовательного интерфейса после
окончания передачи или после окончания
приема соответственно. Все указанные
флаги запросов на прерывание программно
доступны для установки и сброса.
Программная установка флага запроса
на прерывание приводит к такой же реакции
микроконтроллера, что и аппаратная
установка того же самого флага. Флаги TF0
и TF1 сбрасываются аппаратно
при передаче управления программе
обработки соответствующего прерывания. Сброс флагов
IEx выполняется аппаратно
при обслуживании прерывания только в
том случае, если прерывание было настроено
на восприятие спада сигнала INTx.
Если прерывание было настроено на
восприятие уровня сигнала запроса, то
сброс флага IEx должна
выполнять программа обслуживания
прерывания, воздействуя на источник
прерывания для снятия им запроса. Флаги TI
и RI сбрасываются только
программным путем. Каждый вид
прерывания индивидуально разрешается
или запрещается установкой или сбросом
соответствующих разрядов регистра
разрешения прерывания IE.
Этот регистр содержит также и бит общего
запрещения всех прерываний. ФорматрегистраIE
приведен в табл. 14.5. Таблица
14.5. Назначение разрядов регистра IE
Позиция
в регистре
Мнемоника
бита
Функция
Запрет
прерывания от всех источников Не
используется Не
используется Запрет
прерывания от последовательного
порта
Запрет
прерывания от таймера/счетчика T/C1 Запрет
прерывания от внешнего источника INT1 Запрет
прерывания от таймера/счетчика T/C0 Запрет
прерывания от внешнего источника INT0 Каждому виду
прерывания может быть программно
присвоен один из двух возможных
приоритетов: 0 - низший или 1 - высший. Настройка
приоритетов осуществляется установкой
или сбросом соответствующего бита
регистра приоритетов прерываний IP.
Формат этого регистра приведен в табл.
14.6. При одновременном
поступлении запросов прерывания от
источников, имеющих различные приоритеты,
сначала обрабатывается запрос от более
приоритетного источника. В случае
одновременного поступления нескольких
запросов на прерывания с одинаковым
приоритетом порядок их обработки
определяется аппаратными
средствами микроконтроллера и не
может быть изменен программно. Этот
порядок соответствует последовательности
опроса флагов запросов прерываний,
имеющей следующий вид: IT0
-> TF0 -> IT1 -> TF1 -> (RI, TI) Таблица 14.6.
Назначение разрядов регистра IP Позиция в
регистре Мнемоника бита Функция 7 - Не
используется 6 - Не
используется 5 - Не
используется 4 PS Приоритет
прерыванияот последовательного порта 3 PT1 Приоритет
прерывания от таймера/счетчика T/C1 2 PX1 Приоритет
прерыванияот внешнего источника INT1 1 PT0 Приоритет
прерывания от таймера/счетчика T/C0 0 PX0 Приоритет
прерыванияот внешнего источника INT0 Аппаратно
реализуемый вызов обработчика
прерываний состоит из следующих
действий: * сохранение
значения программного счетчика в стеке; Точки входа
вобработчик прерывания для каждого
источника прерываний аппаратно
зафиксированы. Их значения приведены
в табл. 14.7. Таблица
14.7. Адреса точек входа в обработчики
прерываний
Источник
прерывания
Адреса
точек входа в обработчики прерываний
Внешнее
прерывания(ITO
) Таймер-счетчик(TFO) Внешнее
прерывания(IT1) Таймер-счетчик(TF1) Последовательный
порт(R1 или T1) По указанному
адресу должна размещаться первая
команда обработчика прерывания. Как
правило, такой командой является
команда безусловного перехода в
то место программы, где фактически
располагается обработчик. При переходе
на подпрограмму обработки прерывания
автоматически независимо от состояния
регистра IE запрещаются все прерывания,
которые имеют уровень приоритета, равный
уровню приоритета обслуживаемого
прерывания, - то есть вложенные прерывания
с равным уровнем приоритета запрещены.
Таким образом, низкоприоритетное
прерывание (имеющее "0" в соответствующем
разряде регистра IP) может прерываться
высокоприоритетным (имеющим "1" в
соответствующем разряде регистра IP),
но не низкоприоритетным. Обслуживание
высокоприоритетного прерывания не
может быть прервано другим источником. Возврат из
обработчика прерываний осуществляется
с помощью команды RETI, которая
восстанавливает из стека значение
программного счетчика PC, сохраненного
там в момент вызова обработчика
прерывания, и логику приоритетов
прерываний. Что такое прерывания в микроконтроллере?
Это когда микроконтроллер вынужден реагировать на какое-то событие. Ну вот, к примеру, как обыкновенный будильник: спокойно тикает себе в углу, никого не трогает и вообще все про него забыли... Но вдруг в какое-то определенное время он начинает звонить. Вот пример из бытовой жизни - сидите Вы на кухне, пьете чай с малиновым вареньем и ждете гостей. А как узнать, что кто-то пришел? Тут два варианта: либо мы каждые пять минут будем отвлекаться от варенья, (в смысле чая) и бегать проверять, а не стоит ли кто за дверью, либо купить дверной звонок и спокойненько ждать на нагретом месте, пока кто-нибудь в него не позвонит. Так вот, когда гость звонит - это событие. Соответственно, мы прерываемся и кидаемся к двери. Итак, у микросхемы есть прерывания
. И не одно. Прерывания делятся на внешние - такие срабатывают при определённом напряжении на некоторых выводах микросхемы (INT0, INT1 и также иногда целый порт PCINT) - и внутренние - при переполнении счётчика, срабатывании сторжевого таймера, при использовании USART, при прерывании аналогового компаратора, АЦП и прочей периферии. Соответственно, возникает проблема приоритета. Это как мы все также сидим и пьем чай, но звонят нам уже не только в дверь, но и по телефону... И ведь не разорвешься, что-то нужно сделать первым. Поэтому в даташите есть таблица векторов прерываний. Чем меньше номер прерывания, тем более оно приоритетно. Здесь получается несколько тонкостей... Вот произошло событие - пошел запрос на прерывание, то есть выставляется так называемый "флаг запроса на прерывание". Если все хорошо, прерывание разрешено, то жизнь прекрасна и происходит его обработка. А вот если прерывание запрещено - например, уже происходит обработка более приоритетного прерывания - тогда этот флаг запроса так и остается висеть до момента разрешения прерываний. После этого чип проверяет регистр запроса в порядке приоритета, и если есть флаг - обрабатывает его. НО! Получается, что даже если прерывание обрабатывается, не факт, что событие, которое его вызвало, ещё живо... Это как позвонили в дверь и по телефону одновременно, Вы ответили по телефону, а гости уже решили, что никого дома нету и ушли. И вроде как событие - звонок в дверь - было, а за дверью никого нет. Ещё проблема - что пока обрабатывается другое прерывание и флаг запроса уже поднят, событие может произойти ещё несколько раз. Ответили на звонок по телефону, открываем дверь - а там уже целая куча гостей! Страшно? Страшно... Ещё одна особенность использования прерываний - да и не только прерываний: реентерабельность (или повторная входимость). Реентерабельная программа - та, которую могут вызвать несколько пользователей (или процессов), и при этом как минимум не возникнет ошибка, а как максимум - не будет потери вычислений - например, другому пользователю не придется выполнять код снова. Иными словами, если на кухне во то время, пока Вы встречаете гостей, никто не утащит себе вкусняшки, то значит все реентерабельно) В общем, серезная штука - если её не учитывать, можно долго мучится с "а чего же она не работает?!". Нужно её учитывать, например, если обрабатываются несколько прерываний, и каждое изменяет какую-то глобальную переменную... Обычно прерывания НЕ реентерабильны. То есть, в момент работы прерывания нельзя повторно вызвать это-же прерывание.. Именно для защиты от повторного вхождения в обработчик прерывания автоматически запрещаются в момент его обработки. (если вам захотелось разрешить прерывания в процедуре обработки прерываний, надо десять, двадцать раз подумать прежде чем сделать такой опрометчивый шаг.) Рассмотрим работу с внешними прерываниями: нам нужно, во-первых, настроить, по какому событию будет происходить прерывание, а, во-вторых, разрешить микросхеме вообще обрабатывать это самое прерывание. За первое в микросхеме ATmega8 отвечает регистр MCUCR - биты ISC11-ISC10, отвечающие за INT1, и ISC01-ISC00, отвечающие за INT0. Соответственно, с INT0 аналогично. А теперь остается разрешить прерывания по нужному нам выводу - в регистре GIGR есть биты INT0 и INT1; поставить на нужный "1" - и внешнее прерывание разрешено! Но ещё рано радоваться - помимо внешних прерываний надо разрешить прерывания вообще - ставим крайний левый бит I регистра SREG в "1". Это же можно сделать и ассемблерной командой: asm sei; Рассмотрим простой примерчик: на ножку INT0 (D.2) микросхемы ATmega8 присоединена кнопка (к ножке и на ноль); нажимаем - возникает прерывание и включается светодиодик на выводе B.0. Светодиод, соответственно, подключен к ножке и на единицу: Немного о синтаксисе. Функция прерывания написана так: void имя_функции() org IVT_ADDR_INT0. Ключевое слово org указывает, что дальше будет идти адрес прерывания из даташита. У нас же есть название прерывания из библиотечки: набираем IVT и и дальше нажимаем Ctrl + Пробел (люблю я такие вещички ˆˆ). Ещё вместо слова org можно использовать iv, судя по справке компилятора. Ещё маленькое замечание: во-первых, прерывание никогда не должно быть громоздким - несколько строк и все. Это связано с тем, что во время обработки прерывания микросхема не может отвлечься на что-либо иное, азначит, если у нас прерываний несколько, то можно пропустить наступление какого-нибудь события. А ещё может оказаться так, что обработка прерывания нам вообще не нужна - например, достаточно, что схема вышла из спящего режима. Но в этом случае все равно надо писать функцию прерывания, пусть даже пустую - так называемую "заглушку". В принципе, некоторые компиляторы автоматически пишут пустые функции для каждого прерывания, но это не наш случай - приходится делать ручками.
Скачиваем datasheet (ссылка есть при создании проекта) и находим в разделе прерывания (interrupt) такую таблицу:
Установим состояние генерации прерывания при каждом "логическом изменении на INT1".
Программа целиком: Принцип работы внешних прерываний в AVR
0 — это отсутствие напряжения на входе
1 — наличие на входе напряжения, которое равно напряжению питания микроконтроллера.Внешние прерывания по уровню
При работе с прерываниями по уровню надо помнить, что пока на входе INT соответствующий уровень, прерывание будет возникать постоянно. Т.е. если возникло прерывание, например по низкому уровню и программа его обработала, но если при выходе из обработчика прерывания на входе остается низкий уровень, то прерывание сработает еще раз, и опять будет вызван обработчик прерывания, и так будет продолжаться до тех пор пока на входе не появится высокий уровень. Что бы этого не происходило нужно в обработчике запрещать данный вид прерываний, или перенастраивать его на другой уровень.Внешние прерывание по фронту
Так же возможно настроить прерывание что бы оно реагировало на любое изменение на входе INT т.е. оно будет возникать и по переднему и по заднему фронту. Настройка внешних прерываний в AVR
//сбрасываем все биты ISCxx
MCUCR &
amp;=
~( (1
&
lt;&
lt;
ISC11)
|
(1
&
lt;&
lt;
ISC10)
|
(1
&
lt;&
lt;
ISC01)
|
(1
&
lt;&
lt;
ISC00)
)
MCUCR |=
(1
&
lt;&
lt;
ISC01)
|
(1
&
lt;&
lt;
ISC00)
;
Разрешение внешних прерываний в avr atmega
Пример использования внешних прерываний в AVR atmega
#include