Прерывание микроконтроллеров AVR это специальный сигнал который говорит нам о том что произошло какое либо событие. К примеру если у нас переполнился счетчик у таймера, или аналого-цифровой преобразователь (АЦП) завершил свое преобразование, или на внешнем выводе МК появилось напряжение. Все это примеры некоторых прерываний, при наступлении такого события у нас прерывается выполнение последовательности команд, и управление передается обработчику прерываний, т. е. начинается выполнение другой последовательности команд. После выполнения команд прерывания управление передается в прерванный код.
Большим плюсом микроконтроллеров AVR это то что все они имеют по умолчанию большое количество прерываний. Используя прерывания можно мониторить множество параллельных процессов, таким образом это можно назвать многозадачностью когда у нас параллельно выполняется несколько процессов.
Ниже представлена таблица возможных прерываний микроконтроллера ATmega16.
№ | Адрес | Источник | Описание прерывания |
---|---|---|---|
2 | $0004 | INT1 | Внешнее прерывание 1 |
3 | $0006 | TIMER2 COMP | Совпадение таймера/счетчика Т2 |
4 | $0008 | TIMER2 OVF | Переполнение таймера/счетчика Т2 |
5 | $000A | TIMER1 CAPT | Захват таймера/счетчика Т1 |
6 | $000C | TIMER1 COMPA | Совпадение «А» таймера/счетчика Т1 |
7 | $000E | TIMER1 COMPB | Совпадение «В» таймера/счетчика Т1 |
8 | $0010 | TIMER1OVF | Переполнение таймера/счетчика Т1 |
9 | $0012 | TIMER0OVF | Переполнение таймера/счетчика Т0 |
10 | $0014 | SPI, STC | Передача по SPI завершена |
11 | $0016 | USART,RXC | USART, прием завершен |
12 | $0018 | USART,UDRE | Регистр данных USART пуст |
13 | $001A | USART,TXC | USART, передача завершена |
14 | $001C | ADC | Преобразование АЦП завершено |
15 | $001E | EE_RDY | EEPROM, готово |
16 | $0020 | ANA_COMP | Аналоговый компаратор |
17 | $0022 | TWI | Прерывание от модуля TWI |
18 | $0024 | INT2 | Внешнее прерывание 2 |
19 | $0026 | TIMER0 COMP | Совпадение таймера/счетчика Т0 |
20 | $0028 | SPM_RDY | Готовность SPM |
Давайте рассмотрим внешние прерывание, у микроконтроллера ATmega16 есть 3 внешних прерывания:
- INT0;
- INT1;
- INT2;
Эти прерывания привязан к ножкам PD2,PD3, и PB2. Настроить эти прерывания на другие вывод нельзя, нужно использовать только эти.
Для того чтобы включить или выключить нужный нам вывод на работу по внешнему прерыванию, нам нужно настроить управляющий регистр GICR.
Для того чтобы разрешить прерывание на соответствующем выводе нужно установить состояние битов INT1, INT0, INT2.
После того как мы разрешили нужное нам внешнее прерывание нам нужно выставить флаг глобального разрешения прерывания, настройка осуществляется в регистре SREG. Если мы этого не сделаем то вообще ничего работать не будет.
Внешнее прерывание может случиться при наступлении следующего условия:
- низкое значение уровня на выводах INT0, INT1;
- любое изменение логического уровня на выводах INT0, INT1;
- в случае спадающего фронта сигнала на выводах INT0, INT1, INT2;
- в случае нарастающего фронта сигнала на выводах INT0, INT1, INT2;
Для понимания низкого, высокого, нарастающего и спадающего фронта сигнала вот вам картинка.
Установка прерывания на определенное условие срабатывание производится путем настройки регистра MCUCR для INT0 и INT1 и MCUCRS для INT2.
Для того чтобы нам настроить прерывания INT0 на определенное условие срабатывание нам нужно записать следующие значения в управляющие разряды ISC01, ISC00.
Настройки INT1 осуществляется аналогичным образом, только управляющие разряды ISC11, ISC10.
С прерыванием INT2 дела обстоят несколько иначе, для его настройки можно использовать только один бит — ISC2 который находиться в регистре MCUCS
Нужно помнить, что в случае смены значения бита ISC2 может произойти прерывание INT2. Для того чтобы этого не случилось, следует осуществить изменение бита ISC2 следующим образом:
запретить внешнее прерывание > изменить значение бита ISC2 > произвести сброс флага прерывания (INTF2) > и далее опять разрешить прерывание INT2.
Идентификация или регистрация фронта сигнала на выводах INT0/INT1 происходит синхронно, т. е. синхронно с сигналом тактового генератора. Наименьшее значение продолжительности входного сигнала, которое обеспечит генерацию прерывания равно значение периода тактового сигнала генератора МК.
Внешние прерывания INT0 и INT1 настроенные на срабатывание по минимальному уровню, обрабатываются асинхронно. Для того чтобы прерывание произошло, нужно чтобы уровень удерживался до завершения текущей команды. Если прерывание произошло а уровень еще держится, то прерывание будет произведено еще раз.
Обнаружение перепадов сигнала на выводе INT2 также происходит асинхронно. При это наименьшее значение длительности импульса, при которой гарантированно произойдет прерывание равно 50 нс. Внешние прерывание которые обнаруживаются асинхронно, можно использовать для того чтобы выводить МК из «спящего» режима — 6 состояний МК при котором у нас пониженное энергопотребление.
Помимо перечисленных выше регистров нам также понадобиться статусный регистр GIFR. В данном статусном регистре имеются флаги которые автоматически устанавливаются в случае формирования запроса на внешнее прерывание. Т.е. флаги сбрасываются аппаратно, когда вызывается обработчик прерывания. Их также можно сбросить программно, записав в данные регистр «1». Сброс регистра осуществляется перезаписью регистра GIFR,а не операцией «или».
Пример:
- неправильно: GIFR |= (1<<INTFO);
- правильно: GIFR = (1<<INTF0).
Давайте рассмотрим пример при котором мы опрашиваем состояние тактовой кнопки при помощи внешнего прерывания.
#include "lcd_lib.h"
#define PIN_INT0 PD2
volatile unsigned char flagInt0 = 0;
int main( void )
{
LCD_Init();
//настраиваем вывод на вход
DDRD &= ~(1<<PIN_INT0);
//включаем подтягивающий резистор
PORTD |= (1<<PIN_INT0);
//разрешаем внешнее прерывание на int0
GICR |= (1<<INT0);
//настраиваем условие прерывания
MCUCR |= (1<<ISC01)|(0<<ISC00);
__enable_interrupt();
while(1){
if (flagInt0){
LCD_Goto(0,0);
LCD_SendString("on ");
flagInt0 = 0;
__delay_cycles(16000000);
LCD_Goto(0,0);
LCD_SendString("off");
}
}
return 0;
}
//внешнее прерывание. обработчик.
#pragma vector=INT0_vect
__interrupt void int0(void)
{
unsigned char i = 0;
unsigned char count = 0;
while(i < 16){ if ((PIND & PIN_INT0) == 0) count++; i++; } if (count > 10) flagInt0 = 1;
}
Первыми строками в методе main мы производим инициализацию дисплея, далее устанавливаем PD2 на вход и подтягиваем резистор.
В начале функции main мы инициализируем дисплей, настраиваем вывод PD2 на вход и включаем подтягивающий резистор. Разрешаем внешнее прерывание INT0 и задаем условие его генерации – по спадающему фронту. Далее устанавливается флаг глобального разрешения прерываний, и программа бесконечно выполняет цикл while, в теле которого происходит опрос программного флага.
Если флаг установлен, то на дисплей выводится строка “On” и флаг сбрасывается. А после секундной задержки на дисплей выводится строка “Off”. Если флаг не установлен, то ничего не происходит.
Вывод PD2 подтянут с помощью внутреннего резистора к плюсу питания. Пока кнопка не нажата на выводе присутствует напряжение логической единицы. Когда кнопка нажимается, потенциал вывода PD2 становится равен напряжению логического нуля.
Обнаружив перепад сигнала, микроконтроллер вызывает обработчик внешнего прерывания, в теле которого происходит многократный опрос вывода PD2. Если в течение этой процедуры уровень сигнала все еще остается низким, о чем свидетельствует значение счетчика, — взводится флаг. Далее обработчик прерывания заканчивает свою работу, и программа возвращается в основной цикл.
Похожие записи
Практически все современные микроконтроллеры имеют на своем борту 3 вида памяти: Виды памяти микроконтроллеров память программ FLASH; оперативная память (ОЗУ) SRAM (Static RAM); ...
Это простая схема двойного светодиодного мигающего сигнала. В качестве базовой схемы нестабильного мультивибратора используется таймер NE 555. Светодиоды включаются по очереди, частоту...
Представленная схема полицейской мигалки на микроконтроллере и светодиодах может работать в 16 различных режимах. Режим выбирается при помощи одной кнопки, и собрана на микроконтроллере...
Последовательный интерфейс I2C (также его обозначается как IIC) довольно популярный последовательный интерфейс. Свою популярность он получил за неплохую скорость передачи информации. В...
Последовательный периферийный интерфейс SPI (Serial Peripheral Interface) — последовательный стандарт передачи данных. Предназначен для сопряжения микроконтроллеров и периферийных устройств. SPI...
В это примере подключим и научимся обрабатывать события нажатия кнопок при помощи микроконтроллера AVR. Другими словами мониторить состояние кнопок, и при каких либо изменениях делать что...
Прерывание микроконтроллеров AVR
Подскажите что значит запись такового вида DDRD &= ~(1<<PIN_INT0)?
"Подскажите что значит запись такового вида DDRD &= ~(1<<PIN_INT0)?"
Эта запись значит, что бит "PIN_INT0" выставляется в 0, сам бит "PIN_INT0" это бит "PD2", просто он для удобства переименован через #define.
Если бит нужно в 1 выставить, то запись была бы, DDRD |= (1<<PIN_INT0)?