Samou4ka » 🐞 AVR.Начинающим » Внешние прерывания МК AVR

Внешние прерывания МК AVR

Что же такое прерывание? Прерывание это событие, при котором происходит приостановка основной программы и переход на выполнение подпрограммы прерывания. Чтобы узнать какие же есть прерывания в МК, откроем даташит микроконтроллера и нажмем на вкладку Interrupts и там в самом начале увидим таблицу векторов прерываний. Для МК mega8 она выглядит вот так.

В каждом векторе прерывания находится команда перехода с адресом начала подпрограммы прерывания. Любая программа начинается с Reset, в котором находится команда перехода к блоку инициализации. А дальше, каждое прерывание настроено на какое-то событие и при срабатывании этого события программа переходит к обработчику этого прерывания. Видно, что каждому прерыванию соответствует свой вектор прерывания. Чем выше адрес прерывания, тем ниже приоритет прерывания. Т.е. в очереди прерываний, прерывания с большим приоритетом будут выполняться раньше. Если началась обработка какого-нибудь прерывания, никакое другое не может быть вызвано, даже с большим приоритетом. Иначе получался бы рекурсивный вызов обработчиков прерываний и сложнее было бы отследить работу программы. При вызове обработчика любого прерывания бит глобального разрешения прерываний I регистра SREG (status register — регистр состояния) сбрасывается в «0»и только по завершении обработки прерывания снова устанавливается в «1» и разрешает начать обработку следующего прерывания в очереди. Чтобы установить ручками этот бит существует функция sei(), а чтобы сбросить — cli(). При запуске программы этот бит всегда сброшен и чтобы прерывания срабатывали его нужно установить (вызвать sei()).

Итак, в этой статье нас будут интересовать только внешние прерывания, т.е. те прерывания, которые возникают при изменении состояния определенных входом МК. Из таблицы векторов прерываний видно, что у МК ATmega8 таких прерываний 2 — INT0 и INT1 и их приоритет выше других прерываний. Жмем в даташите External Interrupts и обнаруживаем интересную вещь. Для настройки этих прерываний нужно воспользоваться регистрами MCUCR (MCU Control Register — регистр управления) и GICR (General Interrupt Control Register — общий регистр управления прерываниями). Рассмотрим их подробней.

MCUCR

Бит 1, 0 — ISC01, ISC00: Настройка условия срабатывания прерывания INT0 (таблица 1).

Бит 3, 2 — ISC11, ISC10: Настройка условия срабатывания прерывания INT1 (таблица 2)

Биты 4-7 относятся к управлению питанием и здесь рассматривать их не будем.

GICR

  • Бит 7 — INT1: Разрешает внешнее прерывание 1 («1» — разрешено, «0» — запрещено)
  • Бит 6 — INT0: Разрешает внешнее прерывание 0 («1» — разрешено, «0» — запрещено)

Также любое прерывание имеет свой флаг прерывания. Этот флаг устанавливается в «1» в момент, когда должно произойти прерывание, даже если прерывания глобально запрещены и соответствующая программа обработки прерывания не вызывается. Можно, например, внутри какого-нибудь обработчика прерывания по этому флагу проверять было ли какое-либо прерывание или нет. Флаги внешних прерываний являются 7-м и 6-м битом регистра GIFR. Флаги прерываний сбрасываются записью в них «1».

GIFR

  • Бит 7 — INTF1: Флаг внешнего прерывания 1.
  • Бит 6 — INTF0: Флаг внешнего прерывания 0.

Вот собственно и все, что нужно знать чтобы настроить внешние прерывания. Рассмотрим на примере, что нужно записать в регистры MCUCR и GICR, чтобы настроить внешние прерывания. Мы хотим настроить вызов обработчика прерывания INT1 при установлении «1» на входе INT1 (т.е. по переднему фронту импульса). Согласно таблице 2 нужно установить в «1» биты ISC11 и ISC10 регистра MCUCR, а по таблице 1 бит INT1 регистра GICR. Таким образом, MCUCR = 0b00001100 и GICR = 0b10000000.

Настроим внешние прерывания в WinAVR. Чтобы вызвать обработчик конкретного прерывания в WinAVR нужно воспользоваться макросом ISR и указать ему в качестве параметра вектор нужного прерывания. Откроем файл микроконтроллера mega8 — в папке с WinAVR по адресу \avr\include\avr\iom8.h и в нем найдем определения векторов прерывания. Внешнему прерыванию INT1 соответствует вектор INT1_vect. В блоке инициализации устанавливаем регистры MCUCR и GICR, после этого вызываем функцию sei(). Да, еще нужно подключить файл interrupt.h. В примере добавил переменную, которую будем инкрементировать при срабатывании внешнего прерывания — такой себе счетчик. Все это будет выглядеть вот так:

#include <iom8.h>
#include <avr/io.h>
#include <avr/interrupt.h>
//определяем биты регистров
#define ISC10 2
#define ISC11 3
#define INT1 7
unsigned char int1 = 0;
ISR(INT1_vect)
{
//обработка прерывания
        int1++;
}
//функция инициализация внешнего прерывания
void INTinit()
{
MCUCR = (1<<ISC10) | (1<<ISC11);//0b00001100
GICR = (1<<INT1);//0b10000000
}
int main()
{
        INTinit();//вызываем функцию инициализации прерывания
        sei();//устанавливаем бит глобального разрешения прерываний
while(1);
}

На этом собственно и все по поводу внешних прерываний.

Как вам статья? Ваша реакция:
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
Расскажите друзьям:
Оцените статью:

5 комментариев

  • «Дмитрий здравствуйте, респектище за статью !!!!!!!!

    Вот вы инициализировали только INT1

    void INTinit()

    {

    MCUCR = (1»

  • «/определяем биты регистров

    #define ISC10 2

    #define ISC11 3

    #define INT1 7

    Это лишнее, оно определено в соответствующем файле (для тини2313 — iotn2313.h) через io.h»

  • А если обработчик выполняет вычисления и возвращает значение, какая должна быть запись?

  • «А если обработчик выполняет вычисления и возвращает значение, какая должна быть запись?
    С основным телом программы обработчик общается через изменение глобальных переменных, которые следует объявлять как volatile:

    unsigned char volatile int1 = 0;
    Иначе, без объявления переменной как volatile, включенная оптимизация может удалить переменную как неиспользуемую явно в программе.»

  • Не рекурсивные вызовы, а в итоге выполнение самого приоритетного! Рекурсивные были бы, если бы даже приоритет не учитывался.

Оставить комментарий