В данном занятии мы попробуем реализовать механизм реакции контроллера на внешние воздействия.
Для этого существует такое понятие как внешние прерывания (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, остальные на выход
1 2 3 4 |
void main() { TRISB=0XF1; PORTB=0X00; |
Включим обработку восходящих фронтов по внешнему прерыванию
1 2 |
PORTB=0X00; INTEDG = 1; //rising edge |
Очистим флаг прерывания, разрешим внешние прерывания, а также разрешим прерывания от периферии (хотя они по идее не обязательны, но пусть будут), а также глобальные прерывания
1 2 3 4 5 |
INTEDG = 1; //rising edge INTF = 0; INTE = 1; PEIE = 1; GIE = 1; |
Изменим имя глобальной переменной и обнулим её значение
unsigned char fl=0;
Обработчик прерываний у нас уже есть, поменяем там обрабатываемый флаг
if (INTF)
{
INTF=0;
Срабатывать светодиод будет теперь по изменению флага, который у нас хранится в переменной fl. Мы будем то включать светодиод, то выключать
INTF=0;
if(!fl)
Поменяем контрольный светодиод на другой в «истинном» теле, а также включим флаг
if (!fl)
{
PORTB |= 0X02;
fl=1;
}
Аналогичные действия произведём и с «ложным» телом
else
{
PORTB &= ~0X02;
fl=0;
}
Соберём код проекта, и понажимаем на кнопку
Светодиод будет менять своё состояние в тот момент, когда мы будем кнопку отжимать, так как именно при отжатой кнопке у нас высокое состояние (она не притянута к земле).
Закомментируем настройку бита и в другой строчке настроим его на срабатывание по спаду
1 2 |
//INTEDG = 1; //rising edge INTEDG = 0; //falling edge |
Ещё раз соберём код и прошьём контроллер, и состояние светодиода будет меняться в момент нажатия на кнопку.
Раз уж мы так быстро управились, то давайте поиграем с другим типом прерывания — по изменению состоянию на ножках 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
Смотреть ВИДЕОУРОК (нажмите на картинку)
Чудесные уроки! Спасибо.
Сделайте урок по выводу мелодии mid файла на пищалку.
Спасибо за оценку!
Для воспроизведения файла mid нужен не просто аудиоцап, а полноправный кодек с банком инструментом. Ну или очень мощный процессор, который сможет подбрасывать звуки из виртуальных банков (как минимум Pentium 3), так как миди-файлы — это файлы командные и они несут информацию только о том, какой звук в данный момент звучит, также информация о темпе и сколько долей звучит данный звук, также о громкости, затухании. Но вот беда, самих звуков там нет, только их коды по системе General MIDI.
А функции воспроизведения звука типа MikroC ?
Здравствуйте, получается на pic контроллерах нету векторов прерывания, котые бы функцию обработчик типа «ISR (tim_vect)», как на АВР вызывали?