Учебный курс AVR. Использование внешних прерываний в AVR

Введение

  Микроконтроллер общается с внешним миром посредством портов ввода/вывода. Порт представляет собой совокупность выводов микроконтроллера объединенных в группу. Каждый вывод порта можно независимо от других выводов конфигурировать на вход или на выход. Также многие выводы микроконтроллеров AVR имеют альтернативные функции. Одна из таких функций – это прерывание по изменению состояния вывода, так называемое внешнее прерывание. Об этом прерывании мы сегодня и поговорим. 

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

   Для примера будем рассматривать микроконтроллер ATmega16. 
   У него три внешних прерывания - INT0, INT1 и INT2. Эти прерывания жестко «привязаны» к выводам PD2, PD3 и PB2 и переназначить их на другие выводы нельзя. 
   Когда используются внешние прерывания, выводы PD2, PD3 и PB2  конфигурируются на вход. Однако если они настроены на  выход, внешние прерывания тоже будут генерироваться при изменении их состояния, что позволяет реализовать программные прерывания. 

 
 
   Для разрешения или запрещения внешних прерываний предназначен управляющий  регистр GICR (General Interrupt Control Register).

 
   Установка битов INT1, INT0 или INT2 разрешает прерывания при возникновении события на соответствующем выводе микроконтроллера AVR, а сброс — запрещает.
 
   Естественно нужно установить еще и флаг глобального разрешения прерываний -  I, который расположен в регистре SREG. Без него вообще ни одно прерывание вызываться не будет.
 
Внешнее прерывание может происходить по одному из условий:
– по низкому уровню на выводах INT0, INT1, 
– по любому изменению логического уровня на выводах INT0, INT1
– по спадающему фронту сигнала на выводах INT0, INT1, INT2,
– по нарастающему фронту на выводах INT0, INT1, INT2.
 
Небольшая иллюстрация, чтобы уяснить разницу между фронтом и уровнем сигнала. 
 
 
   Условия генерации прерываний устанавливаются с помощью конфигурационных регистров. Для INT0, INT1 – это регистр MCUCR (MCU Control Register). Для INT2 – MCUCSR (MCU Control and Status Register)



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

 
   Для прерывания INT1 таблица выглядит аналогично, только управляющие разряды другие — это ISC11 и ISC10. 
 
   Прерывание INT2 может происходить только по фронтам сигнала, поэтому для установки условий используется всего один бит - это бит ISC2 регистра MCUCSR.
 


  Кстати, при смене значения бита ISC2 может быть сгенерировано прерывание INT2. Чтобы этого не происходило, нужно производить модификацию бита ISC2 так: запретить внешнее прерывание, поменять бит ISC2, сбросить флаг прерывания — INTF2 (смотри ниже) и опять разрешить прерывание INT2.
 
    Обнаружение фронтов сигналов на выводах INT0/INT1 осуществляется синхронно, то есть по сигналу тактового генератора. Минимальная длительность входного импульса, гарантирующая генерацию прерывания, составляет один период тактового сигнала микроконтроллера AVR.
    Внешние прерывания INT0/INT1 сконфигурированные на срабатывание по низкому уровню обрабатываются асинхронно. Для генерации прерывания, уровень должен удерживаться до окончания выполнения текущей команды. Если после обработки прерывания уровень еще удерживается, прерывание будет вызвано снова. 
    Обнаружение перепадов сигнала на выводе INT2 тоже осуществляется асинхронно. Минимальная длительность импульса, гарантирующая генерацию прерывания, составляет 50 нс.
    Внешние прерывания, обнаруживаемые асинхронно, могут быть использованы для пробуждения микроконтроллера, находящегося в любом из шести режимов пониженного энергопотребления. Об этом будет отдельный материал.  
 
   Последний регистр, имеющий отношение к внешним прерываниям, - это статусный регистр GIFR (General Interrupt Flag Register). В нем содержатся флаги, устанавливаемые в случае формирования запроса на внешнее прерывание. 
   Флаги сбрасываются аппаратно, когда вызывается обработчики прерываний. Также их можно сбросить программно, записав в регистр единицы. Причем сброс нужно производить перезаписью регистра GIFR, на не операцией побитового ИЛИ.

Неправильно: GIFR |= (1<<INTF1)    Правильно: GIFR = (1<<INTF1).   Почему? Читаем в статье про таймеры AVR.
 
 

Пример использования внешнего прерывания

   Рассмотрим простой пример использования внешнего прерывания — опрос тактовой кнопки.

Использование внешних прерываний в AVR
 
   

//***************************************************************************
//  Author(s)...: Pashgan    http://ChipEnable.Ru   
//  Target(s)...: mega16
//  Compiler....: IAR EWA 5.11A
//  Description.: Использование внешнего прерывания.
//  Data........:  14.09.2011
//***************************************************************************
#include <ioavr.h>
#include <intrinsics.h>
#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 на вход и включаем подтягивающий резистор. Разрешаем внешнее прерывание INT0 и задаем условие его генерации – по спадающему фронту. Далее устанавливается флаг глобального разрешения прерываний, и программа бесконечно выполняет цикл while, в теле которого происходит опрос программного флага. 
   Если флаг установлен, то на дисплей выводится строка “On” и флаг сбрасывается. А после секундной задержки на дисплей выводится строка “Off”. Если флаг не установлен, то ничего не происходит. 
   Вывод PD2 подтянут с помощью внутреннего резистора к плюсу питания. Пока кнопка не нажата на выводе присутствует напряжение логической единицы. Когда кнопка нажимается, потенциал вывода PD2 становится равен напряжению логического нуля.  
   Обнаружив перепад сигнала, микроконтроллер вызывает обработчик внешнего прерывания, в теле которого происходит многократный опрос вывода PD2. Если в течение этой процедуры уровень сигнала все еще остается низким,  о чем свидетельствует значение счетчика, - взводится флаг. Далее обработчик прерывания заканчивает свою работу, и программа возвращается в основной цикл. 

Файлы

У вас недостаточно прав для комментирования.