По некоторым слабо зависящим от меня причинам не мог участвовать в жизни нашего города. Вы наверное уже и не надеялись на продолжение моих статей... Приношу вам свои глубочайшие извинения! И обещаю закончить свой курс!
Сегодня мы продолжим тему взаимодействия МК с внешним миром.
В предыдущей статье я рассказал о способах подключения внешних органов управления к МК. Теперь пришло время заставить наш контроллер на них реагировать.
Начнем с простейшей схемы с двумя кнопками:
Список всех частей:
Грызём микроконтроллеры. Урок 1. Моргаем 8-ю светодиодами. CodeVision, Proteus, ISIS
Грызём микроконтроллеры. Урок 2. CodeVision и С
Грызём микроконтроллеры. Урок 3. Циклы, прерывания и массивы
Грызём микроконтроллеры. Урок 4. Мерим температуру или напряжение
Грызём микроконтроллеры. Урок 5. Кодовый замок
Грызём микроконтроллеры. Урок 6. Прошиваем МК
Грызём микроконтроллеры. Урок 7. Подключение к МК кнопок, клавиатуры, энкодера
Грызём микроконтроллеры. Урок 8. Программирование кнопок, клавиатуры, энкодера
Грызём микроконтроллеры. Урок 9. Клавиатура вглубину
Поставим себе следующую задачу: При нажатии на кнопку BTN1 светодиод должен загораться, а при нажатии на кнопку BTN2 - гаснуть.
Задача простейшая, но, как ни странно, имеет минимум ТРИ способа реализации!
Исключён фрагмент. Полный вариант доступен меценатам и полноправным членам сообщества.
Какой алгоритм использовать в своей конструкции, это дело выбора каждого и зависит от решаемых задач. Но рассмотреть каждый из них считаю своим долгом.
Способ 1.
Создаем проект, генерируем и сохраняем его:
Исключён фрагмент. Полный вариант доступен меценатам и полноправным членам сообщества.
Обратите внимание на третий рисунок. Я специально выделил строку желтым цветом, т.к. в ней отключена внутренняя подтяжка бита №3, т.к. при отпущенной кнопке на этом выводе должен быть лог. "0", который обеспечивается внешним резистором PullDown.
В начале нашей программы ( например после строки #include"mega8.h" ) добавим строки
#define LED PORTB.0
#define BTN1 PIND.2
#define BTN2 PIND.3
Строки эти никак не повлияют на работоспособность нашего алгоритма, зато сделают его более наглядным и позволят не изменяя самой программы подключить кнопки или светодиод к другим выводам МК.
Далее, используя эти обозначения, в основной цикл программы впишем следующее:
if(BTN1==0)LED=1;
if(BTN2==1)LED=0;
Теперь, каждый раз, когда выполнение программы будет доходить до этих строк (а т.к. они у нас единственные, то просто будут выполняться по очереди), сначала будет проверяться состояние кнопки BTN1, и если она нажата (т.е., вход соединен с общим проводом) то на входе, к которому она подключена, будут логический "0". В этом случае условие BTN1==0 истинно, и выполняется код, расположенный за скобками (выходу LED присваивается значение "1"), что приводит к загоранию светодиода. То же самое происходит далее с кнопкой BTN2, с той лишь разницей, что если она нажата, светодиод тухнет.
Компилируем программу и проверяем ее в ISIS. Радуемся первым результатам.
Способ 2.
Создаем новый проект:
Исключён фрагмент. Полный вариант доступен меценатам и полноправным членам сообщества.
При указанной частоте входного сигнала для таймера (0,977 kHz) период его переполнения, а соответственно и срабатывания его прерывания будет равен примерно 261 мс., т.е., кнопки будут опрашиваться ~3,83 раза в секунду.
Теперь, как и в предыдущем примере вписываем в начало программы
#define LED PORTB.0
#define BTN1 PIND.2
#define BTN2 PIND.3
А в обработчик прерывания Timer 0 overflow вписываем
if(BTN1==0)LED=1;
if(BTN2==1)LED=0;
Эффект будет тот же самый, что и в предыдущем примере, с одним лишь различием - кнопки будут опрашиваться через равные промежутки времени.
Компилируем, проверяем в ISIS. Снова поражаемся результату своих трудов.
Способ 3.
И опять создаем проект...
Исключён фрагмент. Полный вариант доступен меценатам и полноправным членам сообщества.
На последней картинке вы видите установку параметров внешних прерываний.
Напомню, что:
Low level - срабатывание прерывания при низком уровне (лог "0") на входе INTх
Any change - срабатывание прерывания при любом изменении на входе INTх
Falling edge - срабатывание прерывания при переходе от "1" к "0" (т.н. задний фронт импульса) на входе INTх
Rising edge - срабатывание прерывания при переходе от "0" к "1" (т.н. передний фронт импульса) на входе INTх
Почему я выбрал именно такие параметры попробуйте разобраться сами
Теперь, изменим своей привычке и в начале программы напишем только
#define LED PORTB.0
Кнопки описывать теперь нет никакой необходимости
Далее, в прерывании External Interrupt 0 пишем
LED=1;
А в External Interrupt 1
LED=0;
Пояснение: при нажатии кнопки BTN1 срабатывает прерывание, в котором всего одна строчка "LED=1;", которая и включает светодиод. А при нажатии на BTN2 выполняется строчка "LED=0;", соответственно выключая светодиод.
С одиночными кнопками разобрались. Пора переходить к чему-то посложнее
Соблюдая последовательность предыдущей статьи, разберем взаимодействие с валкодером. Если кто-то не помнит принцип его действия, советую освежить свою память, прочитав ту самую статью: Микроконтроллеры. Связь с внешним миром. Клавиатура.
Самый удобный способ взаимодействия с валкодером - подключение одного из его сигнальных выводов ко входу внешнего прерывания. Именно его я и предлагаю рассмотреть.
К сожалению, в ISIS нет модели валкодера, а проверить программку виртуально хотелось бы, поэтому представим его двумя кнопками, в соответствии с принципом работы:
Исключён фрагмент. Полный вариант доступен меценатам и полноправным членам сообщества.
Предположим, что общий контакт COM валкодера мы подключим к общему проводу, тогда при нажатии кнопки LEFT, лог. "0" появится только на выводе A, а при нажатии кнопки RIGHT, благодаря диоду, лог. "0" будет на обоих выводах (A и B). Таким образом, вывод A в этой схеме будет "тактовым" (т.к. на нем появляется сигнал при нажатии на любую кнопку), а вывод B - "сигнальным" (уровень на нем определяет направление).
Теперь составим схему нашего будущего устройства:
Для простоты схемы я использовал семисегментный индикатор со встроенным дешифратором, на который будет выводиться число от 0 до F (в шестнадцатичной системе счисления). Представление валкодера описанной ранее схемой накладывает некоторые ограничения, из-за которых ко входу внешнего прерывания нужно подключать именно вывод A. При использовании реального валкодера таких ограничений нет. Его выводы A и B можно спокойно менять местами, при этом изменится только кодирование направления (т.е., если раньше было "влево", то станет "вправо" и наоборот ).
Итак, со схемой разобрались, теперь по ней и будем писать программу.
Создаем проект, указывая PORTB - все выходы, PORTD - все входы с подтяжкой. А на вкладке внешних прерываний выберем только INT1 и установим его "по заднему фронту" (картинок больше не будет - разбирайтесь по предыдущим примерам ).
Создали? Вот и отлично!
Далее создадим глобальную переменную для счетчика counter (глобальной она будет, если определить ее вне функции в начале кода программы).
char counter=0;
И там же сопоставим вход МК, к которому подключен вывод B валкодера с константой DIRECTION
#define DIRECTION PIND.4
Теперь в основном цикле будем записывать значение переменной counter в порт B:
PORTB=counter;
Почему именно в основном цикле? Да потому, что мне так захотелось
Хотя есть и еще причины, например, если в прерывании написать слишком большой код, то это может затормозить выполнение основной программы, т.к. МК в каждый момент времени может обрабатывать только одно прерывание, другие прерывания будут ожидать окончания обработки текущего. А если обработки ожидает прерывание, которое сообщает об отключении питания устройства и нужно сохранит данные в EEPROM? Это прерывание может так и не дождаться своей очереди, так что делайте выводы.
А теперь самое интересное - обработка сигналов от валкодера.
Прерывание INT0 срабатывает при нажатии любой кнопки (вращении валкодера в любую сторону), а направление определяется состоянием второго, т.е. "сигнального" вывода.
Значит, если DIRECTION - "1", крутим влево, а если "0" - крутим вправо.
Так и запишем в функции обработки прерывания:
if(DIRECTION==1)counter--;
else counter++;
И, по уже сложившейся традиции, компилируем и проверяем
Думаю на сегодня впечатлений достаточно. Остальные способы рассмотрим в следующей статье.
Все исходники и схемы можете взять тут: 🎁keys2.rar 209.42 Kb ⇣ 229
Хотя я настоятельно рекомендую попробовать сделать всё самому с нуля!
С уважением, Владимир
Камрад, рассмотри датагорские рекомендации
🌼 Полезные и проверенные железяки, можно брать
Опробовано в лаборатории редакции или читателями.