AVR Урок 42. EXINT или внешние прерывания



 

Урок 42

EXINT или внешние прерывания

 

Вот наконец-то и настало время нам попробовать поработать с внешними прерываниям. Данный урок, во-первых, был очень востребован, хотя он и кажется на первый взгляд несложным. Очень много было просьб и я не мог не откликнуться. Во-вторых, мы сейчас работаем с модулем LAN ENC28J60, у которго имеется выход, по которому мы можем получить прерывания по окончании определённых операций, которые я и хотел обработать. Также, если у меня получится, я хотел этим поделиться и с вами, но без первоначального представления о внешних прерываниях в контроллере AVR это понять, я считаю, будет, мягко говоря, нелегко. Вот поэтому и созрел данный урок.

Так как я случайно залочил свой контроллер ATMega328, расположенный на недорогой плате, то работать мы будем с платой Arduino UNO.

Нет, не пугайтесь, мы не будем работать со средой программирования Arduino IDE, мы также будем работать с тем же самым Atmel Studio, только Arduino мы будем использовать в качестве отладочной платы и будем его программировать через разъём ISP.

Так что вы можете использовать по-прежнему любые отладочные платы. Но если вдруг кто-то решит использовать так же, как и я, Arduino UNO или любую другую Arduino, то предупреждаю заранее — после этого уже работать с ней Вы не сможете через стандартную среду программирования — Arduino IDE, так как загрузчик мы в случае прошивания через ISP затираем. Но это не смертельно, так как его можно будет впоследствии восстановить. Правда это занятие не из лёгких, но если есть интерес к восстановлению загрузчиков Arduino после их затирания программированием через ISP, то я могу по этому поводу написать статью и дать видеоурок.

Вообщем, пока не приедут платы более мелкие, я буду свои уроки писать с применением Arduino UNO, также и с модулем LAN я также буду работать с той же платой.

Также чем оказался хорош Arduino, что к нему не требуется переходник TTL-USB, так как он там уже прекрасно аппаратно реализован. Причём, мало того, мы через штатный USB-разъём Arduino не только будем пользоваться USART-ом, но и питать наш Arduino будем через него же.

В качестве программатора мы также будем использоваь дешёвый USBASP. Так как он у меня с переключателем пиания 3,3В/5В, то убрав с него совсем перемычку, мы вообще отключим питание с программатора на плату и будем через ISP исключительно только программировать нашу плату.

Так как на плате Arduino находится 6-контактный разъём ISP, то будем использовать стандартный ISP-переходник

 

image10

 

После подключения программатора к плате мы получим вот такую картину

 

image11

 

Подключим раъём USB к компьютеру — теперь у нас есть готовый выход USART на ПК, а также и питание

 

image12

 

Вернёмся к нашим прерываниям. Внешние прерывания — это такие прерывания, которые обрабатываются вследствие возникновения некоторых событий на определённой ножке порта микроконтроллера. Таких событий существует несколько. Прерывания у контроллера AVR могут срабатывать как по уровню, так и по фронту. По уровню они срабатывают, когда будет замечен определённый логический уровень. То есть, если будет настроено срабатывание по уровню логической единицы, то если данный уровень будет оставаться на ножке внешнего прерывания, то прерывание будет срабатыать циклично, пока не установится другой логический уровень. А по фронту — когда будет замечен переход из одного логического состояния в другое. Фронт, как известно бывает восходящий или нисходящий. Говорят ещё вместо восходящего просто фронт, а вместо нисходящего — спад. Также ещё называют передний и задний фронт. Вообщем — это кому как удобно.

Ножек для отслеживания внешних прерываний у контроллера существует две — INT0 и INT1. Первая ножка совпадает с ножкой порта PD2, а вторая — с PD3

 

image00

Теперь немного по аппаратной организации внешних прерываний. Вышеуказанные ножки назначены по умолчанию, но их можно и менять. Для этого есть в контроллере определённые регистры. Но данная тема сегодня рассматриваться не будет, мы будем работать именно с ножками вышеуказанными, поэтому и регистры мы рассмотрим только нужные нам.

 

 

Первый регистр — это регистр управления типом обрабатываемого события — EICRA

 

image03

 

Пара битов ICS01 и ICS00 управляет типом событий на ножке INT0, а вторая — ICS11 и ICS10INT1

Вот зависимость типов событий от включения битов ICS01 и ICS00

 

image04

 

А это для ICS11 и ICS10

 

image05

 

Соответственно получим мы следющую зависимость:

00 — Низкий уровень на ножке,

01 — Любое изменение на ножке,

10 — нисходящий фронт на ножке,

11 — восходящий фронт на ножке.

Второй регистр — это регистр включения ножки прерываний EIMSK

 

image01

 

В данном регистре существует всего два бита, разрешающих прерывания на соответствующих ножках — INT1 и INT0. Биты так и называются, поэтому не перепутаем.

Третий регистр — регистр флагов EIFR, устанавливаемых и сбрасываемых при определённых событиях

 

image02

 

Напрямую мы к данному регистру не обращаемся, так как работать будем с функцией-обработчиком.

Теперь вроде что-то прояснилось по вопросу внешних прерываний.

Осталось дело за малым. Создать и прошить проект, который будет как-то наглядно демонстрировать работу внешних прерываний.

 

 

Запустим Atmel Studio 7, создадим проект с именем EXTI01, выберем контроллер ATmega328P, добавим в main.c функцию инициализации портов port_ini, в которой включим ножку светодиода на выход. Светодиод на плате располагается на ножке B6

 

//———————————————

void port_ini(void)

{

  //Включим ножку светодиода на выход

  DDRB |= 0b00100000;

}

//———————————————

 

Вызовем данную функцию в main()

 

//---------------------------------------------

int main(void)

{

  port_ini();

  while(1)

  {

  }

}

//---------------------------------------------

 

Подключим кнопку между ножкой PD2 (D2) и общим проводом

 

image13

 

Вернёмся в проект и напишем функцию инициализации внешних прерываний. Настроим нисходящий фронт, так как резистор для исключения неопределённого состояния на ножке мы можем подтянуть программно только к питанию и у нас в обычном состоянии на ножке будет логический 1

 

//---------------------------------------------

void int_ini(void)

{

  //включим прерывания INT0 по нисходящему фронту

  EICRA |= (1<<ISC01);

  //разрешим внешние прерывания INT0

  EIMSK |= (1<<INT0);

}

//---------------------------------------------

 

Вызовем данную функцию в main(), а также не забываем включить глобальные прерывания

 

port_ini();

int_ini();

sei();

 

Давайте ещё на всякий случай настроим данную ножку на вход и подтянем резистор к питанию. В данной ситуации лучше резистор подтянуть, так как может возникнуть неопределённое состояние. Для этого добавим соответствующий код в функцию port_ini

 

  DDRB |= 0b00100000;

  //Включим ножку INT0 (PD2) на вход

  DDRD &= ~(0b00000100);

  //Подтянем резистор на ножке INT0 (PD2) к питанию

  PORTD |= 0b00000100;

}

//---------------------------------------------

 

Также ещё нам необходимо добавить сам обработчик прерывания, в котором мы по возникновению настроенного события на ножке порта будем зажигать наш светодиод

 

//---------------------------------------------

ISR(INT0_vect)

{

  PORTB |= 0b00100000;

}

//---------------------------------------------

 

Соберём код, прошьём контроллер и попробуем нажать кнопку

 

image14

 

Как мы видим, светодиод у нас загорелся.

Теперь давайте попробуем также испытать и другую ножку — INT1.

Для этого сначала настроим данную ножку в port_ini()

 

//Включим ножки INT0 и INT1 (PD2 и PD3) на вход

DDRD &= ~(0b00001100);

//Подтянем резисторы на ножках INT0 и INT1 (PD2 и PD3) к питанию

PORTD |= 0b00001100;

 

Затем перенастроим прерывания с учётом данной ножки и в функции int_ini()

 

//включим прерывания INT0 и INT1 по нисходящему фронту

EICRA |= (1<<ISC11)|(1<<ISC01);

//разрешим внешнее прерывание INT0 и INT1

EIMSK |= (1<<INT1)|(1<<INT0);

 

А вот обработчик у данной ножки свой отдельный, поэтому добавим его и светодиод в нём будем гасить

 

//---------------------------------------------

ISR(INT1_vect)

{

  PORTB &= ~(0b00100000);

}

//---------------------------------------------

 

Теперь мы можем подключить ещё кнопку на ножку PD3 (D3), воторым проводм также подключив её к общему проводу, собрать код, прошить контроллер и понажимать кнопки и отследить результаты изменения уровней по светодиоду

 

image15

 

Теперь, если мы соберём код и прошьём контроллер, то первая кнопка будет у нас светодиод зажигать, а вторая тушить.

Казалось бы, что тут такого? А то, что происходит это уже независимо от хода самой программы, не в бесконечном цикле, когда во время там написанного обработчика по нажатию кнопки мы можем вообще не находиться и будет уже не ясно, обработается ли наше событие. Поэтому, изучив внешние прерывания, мы сделали большой шаг вперёд к независимости обработки тех или иных событий на ножках портов микроконтроллера. Конечно, учитывая наш уже теперь очень богатый опыт, нам было это проделать не очень тяжело.

 

 

Предыдущий урок Программирование МК AVR Следующий урок

 

 

Исходный код

 

 

Приобрести плату Arduino UNO R3 можно здесь.

Программатор (продавец надёжный) USBASP USBISP 2.0

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR EXINT или внешние прерывания

2 комментария на “AVR Урок 42. EXINT или внешние прерывания
  1. sergo80zxc:

    Не переназначаются ножки прерываний INT0, INT1. Они привязаны с своим пинам

  2. Иван:

    Здравствуйте! Вы можете написать статью про восстановление оригинального загрузчика Arduino?
    Знаю, что можно восстанавливать прошивку если на руках имеется еще одна плата со штатной прошивкой. Можно ли восстановить прошивку имея только программатор?

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*