Прерывание микроконтроллеров AVR  это специальный сигнал который говорит нам о том что произошло какое либо событие. К примеру если у нас переполнился счетчик у таймера, или аналого-цифровой преобразователь (АЦП) завершил свое преобразование, или на внешнем выводе МК появилось напряжение. Все это примеры некоторых прерываний, при наступлении такого события у нас прерывается выполнение последовательности команд, и управление передается обработчику прерываний, т. е. начинается выполнение другой последовательности команд. После выполнения команд прерывания управление передается в прерванный код.

Большим плюсом микроконтроллеров AVR это то что все они имеют по умолчанию большое количество прерываний. Используя прерывания можно мониторить множество параллельных процессов, таким образом это можно назвать многозадачностью когда у нас параллельно выполняется несколько процессов.

Ниже представлена таблица возможных прерываний микроконтроллера ATmega16.

 

Адрес

Источник

Описание прерывания

1

$0002

INT0

Внешнее прерывание 0

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. Если мы этого не сделаем то вообще ничего работать не будет.
Внешнее прерывание может случиться при наступлении следующего условия:
  1. низкое значение уровня на выводах INT0, INT1;
  2. любое изменение логического уровня на выводах INT0, INT1;
  3. в случае спадающего фронта сигнала на выводах INT0, INT1, INT2;
  4. в случае нарастающего фронта сигнала на выводах INT0, INT1, INT2; 
 
 
Для понимания низкого, высокого, нарастающего и спадающего фронта сигнала вот вам картинка.
 Для установки прерывания на определенное условие срабатывание нужно настроить регистры MCUCR для INT0 и INT1 и MCUCRS для INT2.
Регистр MCUCR для настройки условия срабатывания INT0 и INT1
Регистр MCUCSR для настройки условия срабатывания INT2
 
Для того чтобы нам настроить прерывания INT0 на определенное условие срабатывание нам нужно записать следующие значения в управляющие разряды ISC01, ISC00.
 
Настройки INT1 осуществляется аналогичным образом, только управляющие разряды ISC11, ISC10. 
С прерыванием INT2 дела обстоят несколько иначе, для его настройки можно использовать только один бит - ISC2 который находиться в регистре MCUCS
Бит - ISC2 который регистра MCUCS
Нужно помнить, что в случае смены значения бита ISC2 может произойти прерывание INT2. Для того чтобы этого не случилось, следует осуществить изменение бита ISC2 следующим образом:
запретить внешнее прерывание > изменить значение бита ISC2 > произвести сброс флага прерывания (INTF2) > и далее опять разрешить прерывание INT2.
 
Идентификация или регистрация фронта сигнала на выводах INT0/INT1 происходит синхронно, т. е. синхронно с сигналом тактового генератора. Наименьшее значение продолжительности входного сигнала, которое обеспечит генерацию прерывания равно значение периода тактового сигнала генератора МК.
Внешние прерывания INT0 и INT1 настроенные на срабатывание по минимальному уровню, обрабатываются асинхронно. Для того чтобы прерывание произошло, нужно чтобы уровень удерживался до завершения текущей команды. Если прерывание произошло а уровень еще держится, то прерывание будет произведено еще раз.
Обнаружение перепадов сигнала на выводе INT2 также происходит асинхронно. При это наименьшее значение длительности импульса,  при которой гарантированно произойдет прерывание равно 50 нс.
Внешние прерывание которые обнаруживаются асинхронно, можно использовать для того чтобы выводить МК из "спящего" режима - 6 состояний МК при котором у нас пониженное энергопотребление.
Помимо перечисленных выше регистров нам также понадобиться статусный регистр GIFR. В данном статусном регистре имеются флаги которые автоматически устанавливаются в случае формирования запроса на внешнее прерывание. Т.е. флаги сбрасываются аппаратно, когда вызывается обработчик прерывания. Их также можно сбросить программно, записав в данные регистр "1".  Сброс регистра осуществляется перезаписью регистра GIFR,а не операцией "или".
Пример:
  • неправильно: GIFR |= (1<<INTFO);
  • правильно: GIFR = (1<<INTF0). 

Cтатусный регистр GIFR

Давайте рассмотрим пример при котором мы опрашиваем состояние тактовой кнопки при помощи внешнего прерывания.

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


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

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


Защитный код
Обновить