PIC Урок 28. External Interrupt (внешние прерывания)



В данном занятии мы попробуем реализовать механизм реакции контроллера на внешние воздействия.

Для этого существует такое понятие как внешние прерывания (External Interrupt). Внешние прерывания — это такие прерывания, которые обрабатываются вследствие возникновения некоторых событий на определённой ножке порта микроконтроллера. Данных событий контроллер PIC16 умеет обрабатывать два вида. Первый — это изменение состояния ножки с низкого уровня на высокий (фронт), второй — изменение состояния ножки с высокого на низкий. Ножка, на которой отслеживаются данные события у микроконтроллера PIC16 одна — это RB0. Посмотрим расположение данной ножки на нашем контроллере PIC16F877A, с которым мы сегодня продолжим работать

 

 

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

Также существует ещё один вид внешних прерываний — это изменение состояния на любой ножке из диапазона RB4:RB7, про этот вид мы поговорим чуть позже.

Регистр настроек для внешних прерываний — это INTCON. Правда там присутствуют и некоторые другие настройки, мало того, мы с данным регистром уже давно дружим. Поэтому рассмотрим мы только биты, которые нужны будут нам именно в данном уроке.

Вот этот регистр

 

 

Рассмотрим интересующие нас биты.

 

INTE (RB0/INT External Interrupt Enable bit): Разрешение внешнего прерывания

1 — прерывание разрешено

2 — прерывание запрещено

RBIE (RB Port Change Interrupt Enable bit): Разрешение внешнего прерывания по изменению сигнала на входах RB7:RB4

1 — прерывание разрешено

2 — прерывание запрещено

INTF (RB0/INT External Interrupt Flag bit): Флаг внешнего прерывания RB0/INT

1 — прерывание произошло (должен быть очищен программно)

2 — прерывание не происходило

RBIF (RB0/INT External Interrupt Flag bit): Флаг прерывания по изменению сигнала на входах RB7:RB4

1 — изменение уровня на одном из входов зафиксировано (должен быть очищен программно)

2 — прерывание не происходило

 

Также нам потребуется бит регистра OPTION_REG — INTEDG, который задаёт обрабатываемое событие изменения сигнала на ножке — фронт или спад

 

 

Если бит установлен, то обрабатываем фронт, если нет — то спад.

Попробуем поработать над данной темой теперь и на практике.

 

 

Схема у нас та же — плата от WaveShare на контроллере PIC16F877A.

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

 

 

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

Подключим нашу кнопку

 

 

Перемычки, отвечающие за подключение к порту 8 светодиодов, оставим в замкнутом состоянии только для RB3, RB2 и RB1, а остальные повесим на один контакт, чтобы не потерялись

 

 

Подключим также программатор, который подключим к ПК с помощью кабеля USB.

 

 

Проект возьмём из урока 26 по модулю компараторов с именем COMP_AN и дадим ему имя EXTI01.

Питаться наша плата будет от программатора, поэтому мы откроем наш проект в MPLAB X, сделаем его главным, зайдём в настройки и убедимся, что контроллер будет получать питание от программатора.

В файле main.h изменим частоту тактирования, так как она у нас, начиная с прошлого занятия 16 МГц

 

#define _XTAL_FREQ 16000000

 

Перейдём в файл main.c, удалим подключение библиотеки для работы со строками, которая нам не нужна

 

#include «string.h»

 

В функции main() код тела до бесконечного цикла удалим, а в бесконечном цикле исправим мигание на другую ножку — на ножку RB2

 

while(1)

{

PORTB |= 0X04;

__delay_ms(105);

PORTB &= ~0X04;

__delay_ms(105);

}

 

Проинициализируем ножки порта B, включив на вход ножки RB7:RB4 и ножку RB0, остальные на выход

 

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

 

 

Очистим флаг прерывания, разрешим внешние прерывания, а также разрешим прерывания от периферии (хотя они по идее не обязательны, но пусть будут), а также глобальные прерывания

 

 

Изменим имя глобальной переменной и обнулим её значение

 

unsigned char fl=0;

 

Обработчик прерываний у нас уже есть, поменяем там обрабатываемый флаг

 

if (INTF)

{

  INTF=0;

 

Срабатывать светодиод будет теперь по изменению флага, который у нас хранится в переменной fl. Мы будем то включать светодиод, то выключать

 

INTF=0;

if(!fl)

 

Поменяем контрольный светодиод на другой в «истинном» теле, а также включим флаг

 

if (!fl)

{

  PORTB |= 0X02;

  fl=1;

}

 

Аналогичные действия произведём и с «ложным» телом

 

else

{

  PORTB &= ~0X02;

  fl=0;

}

 

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

 

 

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

Закомментируем настройку бита и в другой строчке настроим его на срабатывание по спаду

 

 

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

Раз уж мы так быстро управились, то давайте поиграем с другим типом прерывания — по изменению состоянию на ножках RB7:RB4. На ножках RB7 и RB6 почему-то данное изменение не чувствуется, возможно потому, что эти ножки подключены к программатору, а ножки RB5 и RB4 чувствуются нормально.

В функции main() закомментируем строку с настройкой фронта/спада, она нам не нужна

 

//INTEDG = 0; //falling edge

 

Изменим наименование флага и бита, разрешающего прерывания

 

RBIF = 0;

RBIE = 1;

 

Также изменим наименование флага и в обработчике прерываний

 

if (RBIF)

{

RBIF=0;

 

Соберём код, прошьём контроллер. Теперь светодиод будет реагировать и на нажатие и на отжатие кнопки, так как флаг олицетворяет именно изменение состояния (любое изменение).

Если переключить контакт кнопки на RB5, то всё будет также работать. Отследить, какая именно кнопка вызвала изменение, можно в обработчике, записывая состояние ножек порта в переменную и при следующем входе в функцию сравнивать их.

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

 

Всем спасибо за внимание!

 

 

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

Исходный код

 

 

 

Купить программатор (неоригинальный) можно здесь: PICKit3

Купить программатор (оригинальный) можно здесь: PICKit3 original

 

 

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

 

PIC External Interrupt Внешние прерывания

4 комментария на “PIC Урок 28. External Interrupt (внешние прерывания)
  1. Валерий:

    Чудесные уроки! Спасибо.
    Сделайте урок по выводу мелодии mid файла на пищалку.

    • Спасибо за оценку!
      Для воспроизведения файла mid нужен не просто аудиоцап, а полноправный кодек с банком инструментом. Ну или очень мощный процессор, который сможет подбрасывать звуки из виртуальных банков (как минимум Pentium 3), так как миди-файлы — это файлы командные и они несут информацию только о том, какой звук в данный момент звучит, также информация о темпе и сколько долей звучит данный звук, также о громкости, затухании. Но вот беда, самих звуков там нет, только их коды по системе General MIDI.

  2. Анатолий:

    Здравствуйте, получается на pic контроллерах нету векторов прерывания, котые бы функцию обработчик типа «ISR (tim_vect)», как на АВР вызывали?

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

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

*