Прерывание микроконтроллеров AVR

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

Биты управляющего регистра GICR

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

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

Внешнее прерывание может случиться при наступлении следующего условия:

  • низкое значение уровня на выводах INT0, INT1;
  • любое изменение логического уровня на выводах INT0, INT1;
  • в случае спадающего фронта сигнала на выводах INT0, INT1, INT2;
  • в случае нарастающего фронта сигнала на выводах INT0, INT1, INT2;

Для понимания низкого, высокого, нарастающего и спадающего фронта сигнала вот вам картинка.

Нарастающий и спадающий фронта сигнала

Установка прерывания на определенное условие срабатывание производится путем настройки регистра MCUCR для INT0 и INT1 и MCUCRS для INT2.

Биты регистра MCUCR

Биты регистра MCUCRS

Для того чтобы нам настроить прерывания INT0 на определенное условие срабатывание нам нужно записать следующие значения в управляющие разряды ISC01, ISC00.

Значения управляющих разрядов ISC01, ISC00

Настройки INT1 осуществляется аналогичным образом, только управляющие разряды ISC11, ISC10.
С прерыванием INT2 дела обстоят несколько иначе, для его настройки можно использовать только один бит — ISC2 который находиться в регистре MCUCS

ISC2

Нужно помнить, что в случае смены значения бита ISC2 может произойти прерывание INT2. Для того чтобы этого не случилось, следует осуществить изменение бита ISC2 следующим образом:
запретить внешнее прерывание > изменить значение бита ISC2 > произвести сброс флага прерывания (INTF2) > и далее опять разрешить прерывание INT2.

Идентификация или регистрация фронта сигнала на выводах INT0/INT1 происходит синхронно, т. е. синхронно с сигналом тактового генератора. Наименьшее значение продолжительности входного сигнала, которое обеспечит генерацию прерывания равно значение периода тактового сигнала генератора МК.

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

Обнаружение перепадов сигнала на выводе INT2 также происходит асинхронно. При это наименьшее значение длительности импульса,  при которой гарантированно произойдет прерывание равно 50 нс. Внешние прерывание которые обнаруживаются асинхронно, можно использовать для того чтобы выводить МК из «спящего» режима — 6 состояний МК при котором у нас пониженное энергопотребление.

Помимо перечисленных выше регистров нам также понадобиться статусный регистр GIFR. В данном статусном регистре имеются флаги которые автоматически устанавливаются в случае формирования запроса на внешнее прерывание. Т.е. флаги сбрасываются аппаратно, когда вызывается обработчик прерывания. Их также можно сбросить программно, записав в данные регистр «1».  Сброс регистра осуществляется перезаписью регистра GIFR,а не операцией «или».

Биты статусного регистра 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. Если в течение этой процедуры уровень сигнала все еще остается низким,  о чем свидетельствует значение счетчика, — взводится флаг. Далее обработчик прерывания заканчивает свою работу, и программа возвращается в основной цикл.

Автор
Staticvoid

Администратор сайта http://www.radiodetector.ru

Поделиться с друзьями:
Поделиться
Отправить
Класснуть
Линкануть
Запинить
Прерывание микроконтроллеров AVR
  • 2

Добавить комментарий