Решение... Советы... Windows 10

Что такое прерывание в микроконтроллере. ______________________________ Прерывание ___________________________

Системы прерываний - важная часть любой управляющей системы.

От ее работы во многом зависит то, насколько эффективно микропроцессорная система выполняет свои функции. Общая структура системы пре рываний МК-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, сохраненного там в момент вызова обработчика прерывания, и логику приоритетов прерываний.

Сегодня будем разбирать понятие прерывания и как его использовать. Естественно не обойдется без учебной программы, но на этот раз моргать светодиодами не будем. Хорош уже. Сделаем подобие дверного звонка.

Задача: заставить микроконтроллер по нажатию кнопки издавать звуковой сигнал.
Схема для нашего примера . Файлы проекта .

Создаем в старом workspace проект ring.
Задаем настройки проекта для конфигурации Release:

Выбираем тип микроконтроллера.
General Options > Target > Processor configuration
У меня это ATmega8535.

Разрешаем использование имен битов определенных в хидер файле
В General Options > System ставим галочку Enable bit definitions in I/O-Include files
До сих пор мы не пользовались именами битов, но сегодня они нам понадобятся.

Меняем тип выходного файла.
Linker > Output.
B поле Output file cтавим галочку Override default и заменяем расширение d90 на hex
В поле Format выбираем Other и в выпадающем меню Output format выбираем тип файла intel-standart

Сохраняем проект и workspace.

______________________________ Прерывание ___________________________

Представьте себе ситуацию. Вы сидите на работе и корпите над очередной микроконтроллерной програмулиной. Подходит к вам начальник и говорит: “Слушай, Паш, нам осциллографы в отдел закупили - Tektronix, четырехканальные. Помоги Васе притащить их”. Вы думаете: ”Ну, е-мое, только мысль поперла.. и на тебе”. А начальник так смотрит на вас, а глаза у него такие добрые, такие добрые. Как тут ему откажешь. Ну, вы все бросаете и идете с другом за осциллографами. Притащили. Отчитались. И снова сели за свою программу. Вот примерно так и выглядит механизм прерывания.

Довольно просто, но есть ряд принципиальных моментов.
Во-первых:
- вы делали свою работу
- параллельно кто-то покупал осциллографы
- по наступлению события «осциллографы закупили» - вы прерываете выполнение своей работы
- некоторое время вы занимаетесь другой работой – тащите осциллографы
- потом вы возвращаетесь на рабочее место и продолжаете делать свою работу с того места, на котором остановились

Во-вторых:
- вы вполне могли бы послать начальника и никуда не идти
- уйдя за осциллографами, вы могли задержаться там надолго, а то и вовсе не вернуться
- вернувшись на рабочее место, вы могли бы уже позабыть свои гениальные идеи

Все это очень похоже на то, что происходит в микроконтроллере. Микроконтроллеры AVR имеют в своем составе целую тучу периферийных устройств (таймеры/счетчики, аналого-цифровой преобразователь, аналоговый компаратор, асинхронный приемопередатчик…и т.д). Мощь микроконтроллера в том, что все эти устройства могут работать параллельно и независимо друг от друга, а также параллельно выполняемой программе. Каждое периферийное устройство может вызывать прерывание по наступлению определенного события. Прерывание будет происходить только в том случае, если оно разрешено. Разрешение прерываний устанавливается для каждого устройства отдельно. Помимо этого есть флаг глобального разрешения/запрещения всех прерываний – это I флаг в регистре SREG. При возникновении прерывания микроконтроллер сохраняет содержимое счетчика команд PC в стеке, то есть запоминает место, на котором его прервали. Загружает в счетчик команд адрес соответствующего вектора прерывания и переходит на этот адрес. Попадает на команду безусловного перехода по которой переходит на подпрограмму обработки прерывания. Запрещает прерывания сбросом флага I, выполняет подпрограмму. Выполнив подпрограмму обработки прерывания, микроконтроллер разрешает прерывания, устанавливая флаг I, и восстанавливает содержимое счетчика команд, то есть возвращается на то же место программы, на котором его прервали.

По идее, обработчик прерывания не должен повреждать содержимое регистров микроконтроллера, потому что они могут содержать данные программы выполняемой в тот момент. Для этого в начале подпрограммы обработки прерывания содержимое регистров микроконтроллера сохраняют в стеке, а в конце подпрограммы восстанавливают. Таким образом, выйдя из прерывания, микроконтроллер сможет продолжить выполнение программы, как ни в чем не бывало. Программируя на ассемблере, сохранение регистров прописывает сам программист, на Си – это делает компилятор.

_______________________________________________________________

Теперь поговорим о таймере. ATmega8535 имеет на борту три таймера/счетчика - два восьмиразрядных (T0, T2) и один шестнадцатиразрядный (T1). Мы будем использовать восьмиразрядный таймер/счетчик T0. В состав этого таймера входят три регистра - регистр управления TCCR0, счетный регистр TCNT0 и регистр сравнения OCR0. Когда таймер запущен, счетный регистр TCNT0 увеличивает свое значение на единицу на каждый перепад тактового сигнала. Частота тактового сигнала выбирается из нескольких возможных значений в регистре управления TCCR0. Также с помощью этого регистра устанавливается режим работы таймера. Таймер T0 может вызвать прерывание по наступлению события “переполнение” – это когда переполняется счетный регистр TCNT0 и по наступлению события “совпадение” – это когда значение счетного регистра TCNT0 становится равным значению регистра сравнения OCR0. Флаги разрешающие эти прерывания находятся в регистре TIMSK.
Мы настроим таймер/счетчик Т0 так, чтобы он вызывал прерывание по событию “совпадение” с частотой 5 кГц. В функции обработчике будем инвертировать состояние вывода микроконтроллера, к которому подключен пьезодинамик. Таким образом, частота пищания пьезика будет равна 2,5 кГц. (Подключен именно пьезодинамик! Не перепутайте. У пьезодинамика сопротивление зависит от частоты и на 2,5 КГц оно обычно еденицы Ком, поэтому его можно подключать к выводу микроконтроллера напрямую, без ограничительного резистора).

Теперь о программе. Построчно писать программу уже не получится, поэтому я сразу приведу ее текст. Ниже мы последовательно разберем все ее строки, и все станет понятно. Макросы я намеренно не стал использовать, программа маленькая, не хочется ее загромождать.

int main(void )
{
//настраиваем порты ввода-вывода
DDRD = (0<PORTD = (1<

//настраиваем таймер Т0
TCCR0 = (1< TCNT0 = 0;
OCR0 = 0xc8;

//разрешаем прерывания
__enable_interrupt();

//основной цикл программы – опрос кнопки
while (1){
if ((PIND & (1<TIMSK = (1<else
TIMSK = 0;
}
return 0;
}

//обработчик прерывания таймера Т0

__interrupt void Timer0CompVect(void )
{
PORTD ^= (1<}

Настройка портов

В нашей схеме к порту D подключена кнопка и пьезодинамик. Вывод, к которому подключена кнопка, нужно настроить на вход и включить подтягивающий резистор. Вывод, к которому подключен пьезодинамик, нужно настроить на выход.

DDRD = (0<PORTD = (1<

Настройка таймера

Режим работы таймера Т0 – СТС(сброс при совпадении), тактовый сигнал – clk/8. Отражаем это в регистре TCCR0

TCCR0 = (1<

Обнуляем на всякий случай счетный регистр TCNT0

В регистр сравнения OCR0 записываем 0xc8. Почему? Потому что я посчитал это на калькуляторе . Ну а на бумаге этот расчет выглядит так.
Тактовая частота микроконтроллера 8 МГц
Тактовый сигнал таймера равен 8000000 Гц/8 = 1000000 Гц.
Время одного такта таймера 1/1000000 = 1 мкс
Время одного такта нужной нам частоты 1/5000 Гц = 200 мкс
Сколько тактов таймера укладывается в 200 мкс? 200/1 = 200 тактов
200 в шестнадцатеричной системе = 0xс8

Подробное описание таймера T0 смотрите в документации на ATMega8535.

Таймер мы настроили, разрешаем общее прерывание, используя встроенную функцию.

__enable_interrupt();

Опрос кнопки

Когда кнопка не нажата, вывод микроконтроллера через внутренний подтягивающий резистор подключен к питанию, то есть на выводе присутствует единичка, когда кнопка нажата, вывод замкнут на землю, то есть на выводе ноль. Чтобы определить нажата ли кнопка, нужно считать содержимое регистра PIND и проверить значение нулевого бита (к PD0 подключена кнопка). Опрашивать кнопку будем в бесконечном цикле.

while (1)
{
if ((PIND & (1<//если кнопка нажата – микроконтроллер должен верещать
}
else {
//если нет - молчать как рыба
}
}

Не забывайте == это не оператор присваивания =.

Обработка нажатия/отпускания кнопки

По нажатию кнопки мы будем разрешать прерывание таймера T0, по отпусканию - запрещать. Для этого будем манипулировать битом OCIE0 регистра TIMSK

TIMSK = (1<// разрешаем прерывание таймера Т0 по событию совпадение

TIMSK = 0; //запрещаем прерывание

Поскольку мы используем всего один таймер, то нет нужды в установке или сбросе отдельных битов.

Функция прерывания

_____________________ Cинтаксис функции прерывания _____________________

Функция прерывания задается с помощью директивы #pragma vector= и служебного слова __interrupt. Функция должна иметь тип void и не должна принимать никаких параметров.

#pragma vector = Address
__interrupt void Name(void )
{
//здесь располагается наш код
}

Name – имя функции, выбираем на наше усмотрение
Address – адрес вектора прерывания, можно задавать числом, можно именами определенными в заголовочном файле микроконтроллера (iom8535.h – раздел Interrupt Vector Definitions)

______________________________________________________________

Для нашей задачи функция-обработчик прерывания выглядит так

#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void )
{
PORTD ^= (1<//инвертируем сигнал на выводе PD1
}

Ну вот собственно и все. Надеюсь все понятно.
В следующий статье заставим микроконтроллер играть мелодию.

Прерывание (interrupt) – событие, требующие немедленной реакции со стороны процессора. Реакция состоит в том, что процессор прерывает обработку текущей программы (прерываемой программы ) и переходит к выполнению некоторой другой программы (прерывающей программы ), специально предназначенной для данного события. По завершении этой программы процессор возвращается к выполнению прерванной программы.

Каждое событие, требующее прерывания, сопровождается сигналом прерывания , оповещающим об этом вычислительную машину, и называемым запросом прерывания .

Состояние программы представляет собой совокупность состояний всех запоминающих элементов в соответствующий момент времени (например, после выполнения последней команды). При возникновении прерывания микроконтроллер сохраняет в стеке содержимое счетчика команд и загружает в него адрес соответствующего вектора прерывания. Последней командой подпрограммы обработки прерывания должна быть команда, которая осуществляет возврат в основную программу и восстановление предварительно сохраненного счетчика команд. Во время выполнения обработчика прерывания некоторая информация может подвергнуться изменению. Поэтому при переходе к обработчику прерывания необходимо сохранить элементы, подвергающиеся изменению. Набор таких элементов представляет собой вектор состояния программы . При этом другая информация о состоянии ячеек памяти не существенна или может быть восстановлена программным путем.

Вектор начального состояния содержит всю необходимую информацию для начального запуска программы. Во многих случаях вектор начального состояния содержит только один элемент – начальный адрес запускаемой программы.

Вектор прерывания является вектором начального состояния прерывающей программы (обработчика) и содержит всю необходимую информацию для перехода к обработчику, в том числе его начальный адрес. Каждому типу прерываний соответствует свой вектор прерывания, который инициализирует выполнение соответствующего обработчика. Обычно векторы прерывания хранятся в специально выделенных фиксированных ячейках памяти с короткими адресами, представляющих собой таблицу векторов прерываний . Для перехода к соответствующей прерывающей программе процессор должен располагать вектором прерывания и адресом этого вектора. По этому адресу, как правило, находится команда безусловного перехода к подпрограмме обработки прерывания.

Как правило, управление запоминанием и возвратом возложено на обработчик прерывания. В этом случае обработчик состоит из трех частей – подготовительной (пролог ) и заключительной (эпилог ), обеспечивающих переключение программ, и собственно прерывающей программы, выполняющей затребованные запросом операции. Время реакции определяется как временной интервал от момента поступления запроса прерывания до начала выполнения прерывающей программы.


t p – время реакции системы на прерывание;
t з – время запоминания состояния прерываемой программы;
t ппр – время собственно прерывающей программы;
t в – время восстановления состояния прерванной программы

При наличии нескольких источников запросов должен быть установлен определенный порядок обслуживания поступающих запросов, называемый приоритетными соотношениями или дисциплиной обслуживания . Совокупность всех возможных типов прерывания процессора представляет собой систему прерывания микроконтроллера. Дисциплина обслуживания определяет, какой из нескольких запросов, поступивших одновременно, подлежит обработке в первую очередь, и имеет ли право данный запрос прерывать тот или иной обработчик прерывания.
В случае если во время обработки прерывания поступает запрос на прерывание с более высоким уровнем приоритета, управление передается обработчику прерывания более высокого приоритета, при этом работа обработчика прерывания с более низким уровнем приоритета приостанавливается. Возникает вложенность прерываний . Максимальное число программ, которые могут приостанавливать друг друга называется глубиной прерываний .

Если запрос прерывания окажется не обслуженным к моменту прихода нового запроса от того же источника (того же приоритета), то возникает насыщение системы прерываний . При этом часть запросов прерывания будет утрачена, что для нормальной работы микроконтроллера недопустимо.

Характеристиками системы прерывания являются:

  • общее количество запросов прерыванияколичество источников запросов прерывания;
  • тип представления прерывания – как правило, запрос прерывания представлен логическим уровнем сигнала;
  • приоритет прерывания – определяет очередность обработки каждого запроса прерывания, чем выше приоритет, тем меньше задержка в исполнении прерывающей программы для него;
  • время реакции – временной интервал между появлением запроса прерывания и началом выполнения прерывающей программы;
  • задержка прерывания – определяется суммарным временем на запоминание и восстановление программы;
  • глубина, обычно совпадает с числом уровней приоритетов в системе прерывания;
  • насыщение системы прерывания;
  • допустимые моменты прерывания программ (как правило, окончание выполнения следующей команды).

Маскирование прерываний используется для сообщения микроконтроллеру о необходимости реагировать на каждый тип прерывания или игнорировать его. Маска прерывания представляет двоичный код, разряды которого поставлены в соответствие источникам запроса прерываний. Единичный бит в двоичном коде сообщает микроконтроллеру о необходимости обработки прерываний такого типа. Нулевой бит напротив не позволяет микроконтроллеру переходить к обработке прерываний указанного типа.
Как правило, кроме маскирования прерываний, существует также бит глобального разрешения прерываний, нулевое значение которого отключает все обработчики прерываний (кроме аппаратного сброса и перехода к началу исполняемой программы).
Кроме двоичного кода маски прерываний существует также двоичный код флагов прерываний , который позволяет обработчику прерываний установить источник возникновения прерывания в случае если источников с указанным запросом в микроконтроллере несколько.

Что такое прерывания в микроконтроллере? Это когда микроконтроллер вынужден реагировать на какое-то событие. Ну вот, к примеру, как обыкновенный будильник: спокойно тикает себе в углу, никого не трогает и вообще все про него забыли... Но вдруг в какое-то определенное время он начинает звонить.

Вот пример из бытовой жизни - сидите Вы на кухне, пьете чай с малиновым вареньем и ждете гостей. А как узнать, что кто-то пришел? Тут два варианта: либо мы каждые пять минут будем отвлекаться от варенья, (в смысле чая) и бегать проверять, а не стоит ли кто за дверью, либо купить дверной звонок и спокойненько ждать на нагретом месте, пока кто-нибудь в него не позвонит.

Так вот, когда гость звонит - это событие. Соответственно, мы прерываемся и кидаемся к двери.

Итак, у микросхемы есть прерывания . И не одно. Прерывания делятся на внешние - такие срабатывают при определённом напряжении на некоторых выводах микросхемы (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, судя по справке компилятора.

Ещё маленькое замечание: во-первых, прерывание никогда не должно быть громоздким - несколько строк и все. Это связано с тем, что во время обработки прерывания микросхема не может отвлечься на что-либо иное, азначит, если у нас прерываний несколько, то можно пропустить наступление какого-нибудь события.

А ещё может оказаться так, что обработка прерывания нам вообще не нужна - например, достаточно, что схема вышла из спящего режима. Но в этом случае все равно надо писать функцию прерывания, пусть даже пустую - так называемую "заглушку". В принципе, некоторые компиляторы автоматически пишут пустые функции для каждого прерывания, но это не наш случай - приходится делать ручками.

Первым делом о том что такое прерывание.
Прерывание (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<

Когда это сделано нужно настроить поведение прерывания. Оно может быть сгенерировано по разному.
Скачиваем datasheet (ссылка есть при создании проекта) и находим в разделе прерывания (interrupt) такую таблицу:

Думаю как перевести это вы и так поймёте.
Установим состояние генерации прерывания при каждом "логическом изменении на INT1".

MCUCR = (0<

Теперь установим весь порт С как выход:

DDRC = 0xff; // порт С - выход

Ну а это уже должно быть понятно:

While (1){ if (num == 1) PORTC |= 1; // включаем первый выход С else PORTC &= ~1; // выключаем первый выход С _delay_ms(100); // ждём 100мс }

Ждать не обязательно. Тем более что это уменьшает быстродействие. Но мне так хочется.
Программа целиком:

#define F_CPU 8000000UL // 8MHz #include #include #include int num = 1; ISR(SIG_INTERRUPT1){ if (num == 1) num = 0; else num = 1; } int main (void){ sei(); GIMSK |= (1<

Компилируем hex и собираем схему в Proteus. Наслаждаемся работой прерывания при изменении положения кнопки.