Системы прерываний - важная часть любой управляющей системы.
От ее работы во многом зависит то, насколько эффективно микропроцессорная система выполняет свои функции. Общая структура системы пре рываний МК-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, сохраненного там в момент вызова обработчика прерывания, и логику приоритетов прерываний.
Для чего нужны внешние прерывания
Прерывание — это событие по которому прерывается исполнение основного кода программы (например функции main) и управление передаётся функции обработчику прерывания. Соответственно внешние прерывания — это некие внешние события прерывающие исполнение основного кода программы.
Внешние прерывания позволяют получить быструю, гарантированную реакцию на внешние события. По этому наиболее частое применение внешних прерываний это реализация счетчиков импульсов, измерение частоты или длительности импульсов, программная реализация uart, one-wire, i2с, spi, а так-же обработка сигналов от внешних периферийных устройств.
Принцип работы внешних прерываний в AVR
Для того что бы микроконтроллер узнал о внешних событиях используются дискретные входы INT0 INT1 и т.д. Дискретные означает что они работают с логическими уровнями: 0 и 1.
0 — это отсутствие напряжения на входе
1 — наличие на входе напряжения, которое равно напряжению питания микроконтроллера.
Внешние прерывания можно разделить на два типа:
- внешние прерывания по уровню
- внешние прерывания по фронту
Внешние прерывания по уровню
Срабатывание внешнего прерывания может быть настроено на низкий или высокий логический уровень. Например, если прерывание настроено на низкий логический уровень, то оно возникает когда на входе INT напряжение равно нулю. Если же прерывание настроено на высокий уровень, то оно возникает когда на входе логическая 1.
При работе с прерываниями по уровню надо помнить, что пока на входе INT соответствующий уровень, прерывание будет возникать постоянно. Т.е. если возникло прерывание, например по низкому уровню и программа его обработала, но если при выходе из обработчика прерывания на входе остается низкий уровень, то прерывание сработает еще раз, и опять будет вызван обработчик прерывания, и так будет продолжаться до тех пор пока на входе не появится высокий уровень. Что бы этого не происходило нужно в обработчике запрещать данный вид прерываний, или перенастраивать его на другой уровень.
Внешние прерывание по фронту
Прерывание по переднему фронту или, как иногда говорят, нарастанию сигнала, возникает когда происходит изменение уровня сигнала на входе INT с 0 на 1. Прерывание по заднему фронту (спаду сигнала), возникает при изменении уровня сигнала на входе INT с 1 на 0.
Так же возможно настроить прерывание что бы оно реагировало на любое изменение на входе INT т.е. оно будет возникать и по переднему и по заднему фронту.
Настройка внешних прерываний в AVR
Внешние прерывания в avr atmega8 настраиваются при помощи бит ISCxx регистра MCUCR .
Зависимость условия срабатывания внешнего прерывания INT0 от бит ISC0x регистра MCUCR в avr atmega8
Для внешнего прерывания INT1 , настройка производиться так же, только используются биты ISC11 ISC10 .
Пример настройки внешнего прерывания для avr atmega8:
//сбрасываем все биты 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) ; |
//сбрасываем все биты ISCxx
MCUCR &= ~((1< Для того что бы внешние прерывания заработали их надо разрешить, установив в 1 соответствующие биты в регистре GICR
. Бит INT0
отвечает за разрешение/запрещение внешнего прерывания INT0
, а бит INT1
, соответственно за внешне прерывание INT1
. Так же необходимо что бы был выставлен флаг глобального разрешения прерываний. Пример кода разрешающего внешнее прерывание INT0 для avr atmega8:
//разрешаем внешнее прерывание INT0
GICR |= (1< В качестве примера приведу программу счетчика импульсов. Программа подсчитывает количество импульсов на входе INT0, и раз в секунду выводит результат подсчета в uart. #include Одним из преимуществ микроконтроллера ATmega8 является широкий диапазон различных прерываний. Прерывание
представляет собой событие, при наступлении которого выполнение основной программы приостанавливается и вызывается функция, обрабатывающая прерывание определённого типа. Прерывания делятся на внутренние и внешние. К источникам внутренних прерываний относятся встроенные модули микроконтроллера (таймеры, приёмопередатчик USART и т.д). Внешние прерывания возникают при поступлении внешних сигналов на выводы микроконтроллера (например сигналы на выводы RESET и INT). Характер сигналов, приводящих к возникновению прерывания задаётся в регистре управления MCUCR
, в частности в разрядах - ISC00 (бит 0) и ISC01 (бит 1) для входа INT 0; ISC10 (бит2) и ISC11 (бит3) для входа INT1. В микроконтроллере ATmega8 каждому прерыванию соответствует свой вектор прерывания
(адрес в начале области памяти программ, в которой хранится команда для перехода к заданной подпрограмме обработки прерывания). В mega8 все прерывания имеют одинаковый приоритет. В случае одновременного возникновения нескольких прерываний первым будет обрабатываться прерывание с меньшим номером вектора. Векторы прерываний в Atmega8
За управление прерываниями в ATmega8 отвечают 4 регистра: GIMSK
(он же GICR) - запрет/разрешение прерываний по сигналам на входах INT0, INT1 GIFR
- управление всеми внешними прерываниями TIMSK
, TIFR
- управление прерываниями от таймеров/счётчиков Регистр GIMSK(GICR) INTFx=1: произошло прерывание на входе INTx. При входе в подпрограмму обработки прерывания INTFx автоматически сбрасывается в сотояние лог. 0 Регистр TIMSK TOIE1=1
: прерывание по переполнению T/C1 разрешено OCIE1A=1
: прерывание при совпадении регистра сравнения A с содержимым счётчика T/C1 разрешено OCIE1B=1
: прерывание при совпадении регистра сравнения B с содержимым счётчика T/C1 разрешено TICIE=1
: разрешено прерывание при выполнении условия захвата TOIE0=1
: прерывание по переполнению T/C0 разрешено Регистр TIFR TOV1=1
: произошло переполнение T/C1 OCF1A=1
: произошло совпадение регистра сравнения A с содержимым счётчика T/C1 разрешено OCF1B=1
: произошло совпадение регистра сравнения B с содержимым счётчика T/C1 разрешено ICF=1
: выполнилось условия захвата TOV0=1
: произошло переполнение T/C0 При входе в подпрограмму обработки прерывания соответствующий прерыванию флаг регистра TIFR автоматически сбрасывается в сотояние лог. 0
Прерывания работают только тогда, когда в регистре состояния SREG разрешены общие прерывания (бит 7 = 1). В случае наступления прерывания этот бит автоматически сбрасывается в 0, блокируя выполнение последующих прерываний.
В данном примере вывод INT0 включён в режиме входа с подтяжкой. При замыкании вывода на землю при помощи кнопки на нём устанавливается лог.0 (фронт сигнала ниспадает с напряжения питания до 0) и срабатывает обработчик прерывания, включающий лампочку, подключённую к нулевому выводу порта B void lampON() interrupt void ext_int0_isr(void) DDRD.2=0; SREG|= (1 while(1) { На приведённом примере также видно, как задаются векторы прерываний в Code Vision AVR (interrupt void ext_int0_isr(void)). Аналогично задаются вектора прерываний и для других случаев: EXT_INT0 2 Сегодня будем разбирать понятие прерывания и как его использовать. Естественно не обойдется без учебной программы, но на этот раз моргать светодиодами не будем. Хорош уже. Сделаем подобие дверного звонка. Задача:
заставить микроконтроллер по нажатию кнопки издавать звуковой сигнал. Создаем в старом workspace проект ring. Выбираем тип микроконтроллера.
Разрешаем использование имен битов определенных в хидер файле
Меняем тип выходного файла.
Сохраняем проект и workspace.
Представьте себе ситуацию. Вы сидите на работе и корпите над очередной микроконтроллерной програмулиной. Подходит к вам начальник и говорит: “Слушай, Паш, нам осциллографы в отдел закупили - Tektronix, четырехканальные. Помоги Васе притащить их”. Вы думаете: ”Ну, е-мое, только мысль поперла.. и на тебе”. А начальник так смотрит на вас, а глаза у него такие добрые, такие добрые. Как тут ему откажешь. Ну, вы все бросаете и идете с другом за осциллографами. Притащили. Отчитались. И снова сели за свою программу. Вот примерно так и выглядит механизм прерывания. Довольно просто, но есть ряд принципиальных моментов. Во-вторых: Все это очень похоже на то, что происходит в микроконтроллере. Микроконтроллеры AVR имеют в своем составе целую тучу периферийных устройств (таймеры/счетчики, аналого-цифровой преобразователь, аналоговый компаратор, асинхронный приемопередатчик…и т.д). Мощь микроконтроллера в том, что все эти устройства могут работать параллельно и независимо друг от друга, а также параллельно выполняемой программе. Каждое периферийное устройство может вызывать прерывание по наступлению определенного события. Прерывание будет происходить только в том случае, если оно разрешено. Разрешение прерываний устанавливается для каждого устройства отдельно. Помимо этого есть флаг глобального разрешения/запрещения всех прерываний – это I флаг в регистре SREG. При возникновении прерывания микроконтроллер сохраняет содержимое счетчика команд PC в стеке, то есть запоминает место, на котором его прервали. Загружает в счетчик команд адрес соответствующего вектора прерывания и переходит на этот адрес. Попадает на команду безусловного перехода по которой переходит на подпрограмму обработки прерывания. Запрещает прерывания сбросом флага I, выполняет подпрограмму. Выполнив подпрограмму обработки прерывания, микроконтроллер разрешает прерывания, устанавливая флаг I, и восстанавливает содержимое счетчика команд, то есть возвращается на то же место программы, на котором его прервали. По идее, обработчик прерывания не должен повреждать содержимое регистров микроконтроллера, потому что они могут содержать данные программы выполняемой в тот момент. Для этого в начале подпрограммы обработки прерывания содержимое регистров микроконтроллера сохраняют в стеке, а в конце подпрограммы восстанавливают. Таким образом, выйдя из прерывания, микроконтроллер сможет продолжить выполнение программы, как ни в чем не бывало. Программируя на ассемблере, сохранение регистров прописывает сам программист, на Си – это делает компилятор. Теперь поговорим о таймере. ATmega8535 имеет на борту три таймера/счетчика - два восьмиразрядных (T0, T2) и один шестнадцатиразрядный (T1). Мы будем использовать восьмиразрядный таймер/счетчик T0. В состав этого таймера входят три регистра - регистр управления TCCR0, счетный регистр TCNT0 и регистр сравнения OCR0. Когда таймер запущен, счетный регистр TCNT0 увеличивает свое значение на единицу на каждый перепад тактового сигнала. Частота тактового сигнала выбирается из нескольких возможных значений в регистре управления TCCR0. Также с помощью этого регистра устанавливается режим работы таймера. Таймер T0 может вызвать прерывание по наступлению события “переполнение” – это когда переполняется счетный регистр TCNT0 и по наступлению события “совпадение” – это когда значение счетного регистра TCNT0 становится равным значению регистра сравнения OCR0. Флаги разрешающие эти прерывания находятся в регистре TIMSK. Теперь о программе. Построчно писать программу уже не получится, поэтому я сразу приведу ее текст. Ниже мы последовательно разберем все ее строки, и все станет понятно. Макросы я намеренно не стал использовать, программа маленькая, не хочется ее загромождать. int
main(void
) //настраиваем таймер Т0
//разрешаем прерывания
//основной цикл программы – опрос кнопки
//обработчик прерывания таймера Т0
Настройка портов
В нашей схеме к порту D подключена кнопка и пьезодинамик. Вывод, к которому подключена кнопка, нужно настроить на вход и включить подтягивающий резистор. Вывод, к которому подключен пьезодинамик, нужно настроить на выход. DDRD = (0< Настройка таймера
Режим работы таймера Т0 – СТС(сброс при совпадении), тактовый сигнал – clk/8. Отражаем это в регистре TCCR0 TCCR0 = (1< Обнуляем на всякий случай счетный регистр TCNT0 В регистр сравнения OCR0 записываем 0xc8. Почему? Потому что я посчитал это на калькуляторе
. Ну а на бумаге этот расчет выглядит так. Подробное описание таймера T0 смотрите в документации на ATMega8535. Таймер мы настроили, разрешаем общее прерывание, используя встроенную функцию. __enable_interrupt();
Опрос кнопки
Когда кнопка не нажата, вывод микроконтроллера через внутренний подтягивающий резистор подключен к питанию, то есть на выводе присутствует единичка, когда кнопка нажата, вывод замкнут на землю, то есть на выводе ноль. Чтобы определить нажата ли кнопка, нужно считать содержимое регистра PIND и проверить значение нулевого бита (к PD0 подключена кнопка). Опрашивать кнопку будем в бесконечном цикле. while
(1) Не забывайте == это не оператор присваивания =. Обработка нажатия/отпускания кнопки
По нажатию кнопки мы будем разрешать прерывание таймера T0, по отпусканию - запрещать. Для этого будем манипулировать битом OCIE0 регистра TIMSK TIMSK = (1< TIMSK = 0; //запрещаем прерывание
Поскольку мы используем всего один таймер, то нет нужды в установке или сбросе отдельных битов. Функция прерывания задается с помощью директивы #pragma
vector= и служебного слова __interrupt.
Функция должна иметь тип void и не должна принимать никаких параметров. #pragma
vector = Address Name
– имя функции, выбираем на наше усмотрение Для нашей задачи функция-обработчик прерывания выглядит так #pragma
vector = TIMER0_COMP_vect Ну вот собственно и все. Надеюсь все понятно. Стек представляет собой область памяти, которую ЦПУ использует для сохранения и восстановления адресов возврата из подпрограмм. Когда микропроцессор встречает одну из инструкций вызовов rcall/call/ecall/icall/eicall, то адрес следующего за ними слова в памяти программ аппаратно копируется в стек. В момент выхода из подпрограммы по команде ret адрес возврата восстанавливается из стека в программный счетчик. В моделях с объемом памяти программ 128 и 256 к/слов для сохранения PC в стеке потребуется 3 байта, для всех остальных – 2 байта. При сохранении каждого байта содержимое SP уменьшается на единицу, а при восстановлении, соответственно увеличивается. Рис.9 Расположение стека в памяти данных Программист должен самостоятельно определить местоположение стека в самом начале программы. С точки зрения максимальной его глубины, вершину стека нужно поместить в самом конце SRAM, как это показано на рис.9: Include "m8def.inc"
ldi temp,low(RAMEND) ;устанавливаем SP = RAMEND
out SPL,temp ;для ATmega8 SP = 0x045F
ldi temp,high(RAMEND)
out SPH,temp
Константа RAMEND из стандартного заголовочного файла m8def.inc имеет значение адреса последней ячейки SRAM. В диапазоне адресов SRAM между РВВ и текущим положением SP размещаются переменные прикладной программы. Поэтому очень важно предварительно оценить максимальный размер стека (глубину стека). Может случиться так, что вершина стека поднимется слишком высоко и начнет “затирать” пользовательские данные, а это одна из самых сложно-выявляемых ошибок! Стек AVR, помимо сохранения адресов возврата, имеет еще одно очень важное предназначение. Он позволяет сохранять любые данные специально предназначенными для этого командами push Rr (загрузка в стек) и pop Rd (выгрузка из стека). Каждый раз при выполнении push Rr содержимое Rr копируется в стек, после чего SP уменьшается на единицу. При выполнении pop Rr содержимое ячейки стека, на которую указывает SP, восстанавливается в Rr, а само значение SP инкрементируется. Стек подобного рода имеет организацию Last In First Out (Последний Вошел Первый Вышел): регистр, сохраненный последней командой push, будет восстановлен первой командой pop:
; SP Уровень стека после команды
push R16 ;сохраняем R16 0x045F R16 ? ?
push R17 ;сохраняем R17 0x045E R16 R17 ?
push R18 ;сохраняем R18 0x045D R16 R17 R18
̣̣̣̣̣̣̣̣
pop R18 ;восстанавливаем R18 0x045D R16 R17 ?
pop R17 ;восстанавливаем R17 0x045E R16 ? ?
pop R16 ;восстанавливаем R16 0x045F ? ? ?
Через стек очень просто можно обменять содержимое регистров местами:
; Обмен R16 <-> R17 SP Уровень стека после команды
push R16 ;сохраняем R16 0x045F R16 ?
push R17 ;сохраняем R17 0x045E R16 R17
pop R16 ;восстанавливаем R16 0x045E R16 ?
pop R17 ;восстанавливаем R17 0x045F ? ?
На рис.10 приведен небольшой фрагмент кода, в котором пошагово рассмотрен процесс изменения стека при входе и выходе из подпрограммы toggle и сохранении и восстановлении регистра R17. Это типичный пример, где могут понадобиться инструкции push/pop. Подпрограмма toggle использует РОН R17 в своих нуждах, но этот- же регистр может использоваться и в ходе основной программы. Поэтому, во избежание повреждения данных, R17 перед модификацией загружается в стек и восстанавливается из него перед командой ret.Разрешение внешних прерываний в avr atmega
Пример использования внешних прерываний в AVR atmega
#include
Адрес
Источник прерывания
Описание
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
Прерывание от аналогового компаратора
Управления прерываниями
7
6
5
4
3
2
1
0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-
7
6
5
4
3
2
1
0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-
{
PORTB.0=1;
DDRB.0=1;
}
{
lampON();
}
PORTD.2=1;
EXT_INT1 3
TIM2_COMP 4
TIM2_OVF 5
TIM1_CAPT 6
TIM1_COMPA 7
TIM1_COMPB 8
TIM1_OVF 9
TIM0_OVF 10
SPI_STC 11
USART_RXC 12
USART_DRE 13
USART_TXC 14
ADC_INT 15
EE_RDY 16
ANA_COMP 17
TWI 18
SPM_READY 19
Схема для нашего примера . Файлы проекта .
Задаем настройки проекта для конфигурации 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______________________________ Прерывание ___________________________
Во-первых:
- вы делали свою работу
- параллельно кто-то покупал осциллографы
- по наступлению события «осциллографы закупили» - вы прерываете выполнение своей работы
- некоторое время вы занимаетесь другой работой – тащите осциллографы
- потом вы возвращаетесь на рабочее место и продолжаете делать свою работу с того места, на котором остановились
- вы вполне могли бы послать начальника и никуда не идти
- уйдя за осциллографами, вы могли задержаться там надолго, а то и вовсе не вернуться
- вернувшись на рабочее место, вы могли бы уже позабыть свои гениальные идеи_______________________________________________________________
Мы настроим таймер/счетчик Т0 так, чтобы он вызывал прерывание по событию “совпадение” с частотой 5 кГц. В функции обработчике будем инвертировать состояние вывода микроконтроллера, к которому подключен пьезодинамик. Таким образом, частота пищания пьезика будет равна 2,5 кГц. (Подключен именно пьезодинамик! Не перепутайте. У пьезодинамика сопротивление зависит от частоты и на 2,5 КГц оно обычно еденицы Ком, поэтому его можно подключать к выводу микроконтроллера напрямую, без ограничительного резистора).
{
//настраиваем порты ввода-вывода
DDRD = (0<
TCCR0 = (1<
OCR0 = 0xc8;
__enable_interrupt();
while
(1){
if
((PIND & (1<
TIMSK = 0;
}
return
0;
}
__interrupt
void
Timer0CompVect(void
)
{
PORTD ^= (1<
Тактовая частота микроконтроллера 8 МГц
Тактовый сигнал таймера равен 8000000 Гц/8 = 1000000 Гц.
Время одного такта таймера 1/1000000 = 1 мкс
Время одного такта нужной нам частоты 1/5000 Гц = 200 мкс
Сколько тактов таймера укладывается в 200 мкс? 200/1 = 200 тактов
200 в шестнадцатеричной системе = 0xс8
{
if
((PIND & (1<
}
else
{
//если нет - молчать как рыба
}
}
Функция прерывания
_____________________ Cинтаксис функции прерывания
_____________________
__interrupt
void
Name(void
)
{
//здесь располагается наш код
}
Address
– адрес вектора прерывания, можно задавать числом, можно именами определенными в заголовочном файле микроконтроллера (iom8535.h – раздел Interrupt Vector Definitions)______________________________________________________________
__interrupt
void
Timer0CompVect(void
)
{
PORTD ^= (1<
}
В следующий статье заставим микроконтроллер играть мелодию.
Практически у всех микроконтроллеров AVR стек размещается в SRAM. Для адресации текущего элемента (вершины стека) используется указатель стека SP (Stack Pointer). Это однобайтовый РВВ SPL у моделей с объемом памяти данных до 256 б, или двухбайтовый SPH:SPL (SPH – старший байт, SPL – младший байт).
Рис.10 Пример работы стека