Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Эрни Каспер Программирование на языке Ассемблер...doc
Скачиваний:
120
Добавлен:
09.11.2019
Размер:
954.88 Кб
Скачать

7.6.Программирование ввода и вывода информации для пользователя

В большинстве изделий, управляемых микроконтроллерами, при обмене информацией с пользователем используются кнопки или клавиши для ввода и светодиодные индикаторы для вывода. В некоторых случаях для оповещения пользователя о каком-либо событии используется также звуковой сигнал. Включение или выключение звукового сигнализатора производится одной командой и посему программируется очень просто. Вывод более сложных звуковых сигналов (например, одноголосных мелодий) является любопытной, но не актуальной задачей и не рассмат­ривается в этой книге. Перейдем к более поучительному примеру про­граммирования ввода информации в микроконтроллер при помощи кнопок и вывода информации из микроконтроллера при помощи отдель­ных светодиодов и цифровых индикаторов на светодиодах.

Рассмотрим устройство с 5 группами светодиодов для вывода (4 цифровых индикатора и 5 отдельных светодиодов) и с 10 кнопками для ввода информации. Отведем по одному байту ОЗУ для каждого из кана­лов ввода и вывода информации:

.RSECT

klvO: .DS 1 ; для ввода с кнопки О

klvl: .DS 1 ; для ввода с кнопки 1

klv2: .DS 1 ; для ввода с кнопки 2

klv3: .DS 1 ; для ввода с кнопки 3

klv4: .DS 1 ; для ввода с кнопки 4

klv5: .DS 1 ; для ввода с кнопки 5

klv6: .DS 1 ; для ввода с кнопки 6

klv7: .DS 1 ; для ввода с кнопки 7

klv8: .DS 1 ; для ввода с кнопки 8

klv9: .DS 1 ; для ввода с кнопки 9

indO: .DS 1 ; для вывода на индикатор О

indl: .DS 1 ; для вывода на индикатор 1

ind2: .DS 1 ; для вывода на индикатор 2

ind3: .DS 1 ; для вывода на индикатор 3

ind4: .DS 1 ; для вывода на индикатор 4

Эти ячейки предназначены для связи программ ввода и вывода с програм­мами, решающими внутренние задачи. В принципе для ввода с кнопок можно было бы отвести по 1 бит памяти. Но в некоторых случаях бывает необходимо определить не только нажатое или отпущенное состояние кнопки, но и переход из одного состояния в другое. В этом случае для ввода с кнопок нужно отвести по 2 бит памяти. Если же в программе необходимо учитывать и длительность нажатого состояния, то приходится использовать еще по несколько битов на кнопку. Для вывода на цифро­вые индикаторы требуется по 1 байт памяти (7 бит на сегменты и 1 на десятичную точку).

В приведенном примере для осуществления параллельного обмена потребовалось бы 43 вывода (10 на кнопки, 28 на 4 цифровых индикато­ра, каждый из которых содержит по 7 сегментов, и 5 на светодиоды). В микроконтроллере имеется только 4 порта по 8 разрядов, к тому же многие из них приходится использовать для других целей. Поэтому используется последовательно-параллельный режим ввода/вывода. Это означает поочередный опрос групп кнопок и зажигание индикаторов. Притом пользователю должно казаться, что опрос всех кнопок и вывод на все индикаторы происходят одновременно. Инерция зрительного воспри­ятия позволяет зажигать индикаторы поочередно. При выборе частоты сканирования нужно исходить из того, что каждый из индикаторов дол­жен включаться не менее 50 раз в секунду. Следовательно для обслужи­вания 5 индикаторов необходимо использовать прерывания с частотой 250 Гц (период прерываний 4000 мкс). Минимальная длительность нажа­тия кнопки составляет около 0,1 с, поэтому частота опроса кнопок 50 Гц является достаточной.

Для прерывания с частотой 250 Гц в таймер-счетчик 0 нужно запи­сывать код F075H. Поочередное включение питания на 5 шин возможно посредством записи единиц в 5 различных битов порта, выбранного для этой цели. Но обычно это делается более экономным способом при помощи дешифратора. Дешифратор с 3 входами позволяет коммутиро­вать питание на 8 шинах, соответствующих кодам от 0 до 7, но мы будем использовать только коды от 0 до 4. Выберем для сканирования 3 млад­ших бита порта 2. Вывод кода для индикации будем осуществлять через порт 0 (8 бит). Каждую из этих же шин можно использовать для опроса пары кнопок, подключив одну группу кнопок с номерами от 0 до 4 к Р2.3,

а другую, с номерами от 5 до 9, к Р2.4. Таким образом для ввода и вывода информации, обеспечивающей общение с пользователем, занято только 13 из 32 выводов параллельных портов. Поскольку программирование прерывания при помощи таймера-счетчика было рассмотрено ранее, перейдем к программированию синхронизации задач ввода и вывода с переключением шин сканирования индикаторов и кнопок.

При сканировании будем осуществлять изменение адреса шины в нисходящем порядке (от 4 до 0). Поскольку запись числа 4 в ячейку scan производится с частотой 50 Гц, для получения частоты 10 Гц используется еще одна ячейка — sync, содержимое которой изменяется от 5 до 1. ; == ======следующие 3 команды выполняются с частотой 250 Гц

DEC scan ; уменьшение адреса шины

MOV A, scan ; для проверки адреса шины

JNB А.7, f250 ; переход по неотрицательному значению

;===следующие 4 команды выполняются с частотой 50 Гц

MOV scan, #4 ; запись максимального адреса шины

DEC sync ; изменение счетчика синхронизации

MOV A, sync ; для проверки счетчика

JNZ f250 ; переход до завершения интервала 0,1 с

;===команды до метки f250 выполняются с частотой 10 Гц

MOV sync, #5 ; обновление содержимого счетчика

; блок формирования кодов нажатия кнопок £250:

; блок вывода на индикаторы

; блок проверки нажатия кнопок

Приведенный фрагмент обеспечивает распределение времени таким образом, что блоки вывода на индикаторы и проверки нажатия кнопок выполняются 250 раз в секунду, а блок формирования кодов нажатия кнопок выполняется 10 раз в секунду.

Рассмотрим теперь программу вывода на индикаторы, предполагая, что в ячейках indO, indl, ind2, ind3 и ind4 находятся необходимые для вывода коды. Для смены кода на индикаторе нужно сначала погасить все сегменты (или светодиоды), включить следующую шину и зажечь те сегменты (или светодиоды), которые соответствуют включенной шине. Притом желательно по возможности уменьшить время между гашением одного индикатора и зажиганием другого. В приведенном примере пере­ключение вывода с одного индикатора на другой производится тремя последними командами. Предшествующие им команды обеспечивают формирование адреса шины для вывода на порт 2 и адреса для вывода содержимого ячейки на порт 0.

MOV A, scan ; чтение адреса шины

ADD A, #indO ; адрес ячейки для вывода на индикатор

MOV R0, А ; для косвенной адресации

MOV A, Р2 ; чтение порта для переключения шины

ANL A, #EOh ; выделение трех старших битов

ORL A, scan ; обновление адреса шины индикаторов

MOV Р0, 10 ; гашение светодиодов

MOV P2, А ; переключение шины

MOV Р0, @R0 ; вывод на индикатор

Следует обратить внимание на то, что вывод адреса шины на три младшие разряда порта 2 должен был бы производиться без изменения содержимого 5 старших разрядов этого порта. На самом деле 3 и 4 биты этого порта нужно установить в 0 для проверки нажатия кнопок.

В том же такте сканирования нужно проверить нажатие двух кнопок, присоединенных к включаемой шине. Здесь предполагается, что при нажатии кнопки сигнал с шины устанавливает соответствующий бит в 1. Если же кнопка отпущена, то импульс сканирования не проходит на вход порта 2. Запись нулей в биты 3 и 4 входного регистра порта нужна потому, что от предыдущего такта в них могли оказаться единицы. От момента переключения шины до опроса битов порта проходит время, затрачиваемое на выполнение 4 команд. Приводимая последовательность команд обес­печивает счет длительности нажатия в каждой из ячеек, отведенных для кнопок:

MOV A, scan

ADD A, #klv0 ; адрес ячейки для 3-го бита порта 2

MOV R0, A

JNB P2.3, chl ; переход по не нажатой кнопке

INC @R0 ; счет тактов с нажатием

chl: ADD A, #5 ; адрес ячейки для 4-го бита порта 2

MOV R0, A

JNB P2.4, ch2 ; переход по не нажатой кнопке

INC @R0 ; счет тактов с нажатием

ch2: NOP ; для записи метки

Но этим счетом обработка содержимого ячеек для ввода не заканчивается. Необходимо поверять результаты подсчета и после этого стирать содер­жимое счетчиков.

Счет нажатий будем вести в течение 0,1 с, что соответствует посто­янной времени реакции человека. Для фильтрации ложных срабатываний кнопки будем считать кнопку нажатой, если за это время на счетчик прошло не менее 4 импульсов. Поскольку максимальное количество импульсов за 0,1 с равно 5, то для хранения этого числа достаточно 3 младших битов. Старшие биты отведем на хранение предыстории нажатия кнопки. Для этого нужно сдвигать содержимое ячейки на 1 разряд влево и записывать нули в три младших бита. Информация из 5 старших битов может использоваться внутренней программой для определения нажатия и отпускания кнопки или даже длительности нажатия в пределах 0,5 с. Формирование кодов нажатия кнопок осуществляется следующей программой:

MOV Rl, fl0 ; количество кнопок

MOV RO, #klv0 ; адрес массива ячеек для кнопок

ag: MOV A, @R0 ; чтение очередной ячейки для кнопок

RL A ; для формирования кода предыстории

ANL A, #F8h ; очистка младших битов для счета

MOV @R0, А ; обновление содержимого ячейки

INC R0 ; адрес ячейки для следующей кнопки

DJNZ R1, ag ; переход на начало цикла

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

В заключение отметим, что в ячейки, предназначенные для вывода на индикацию, должны записываться не числовые значения цифр, а коды, обеспечивающие зажигание нужных сегментов светодиодных индикаторов. Эти коды должны храниться в таблице, являющейся усеченным аналогом кодовых страниц компьютеров. Усечение связано с тем, что вместо матрицы хотя бы из 6x8 точек (6 байт) для каждого символа дисплея при использовании сегментных индикаторов достаточно хранить 1 байт для каждой цифры. Вообще-то индикаторы, состоящие из 7 сегментов, позво­ляют воспроизводить некоторое подобие букв. Но нам достаточно 10 цифр вместо 256 символов кодовой таблицы. Обычно выводы сегментов обозначаются строчными латинскими буквами. Букве "а" соответствует верхний (горизонтальный) сегмент, далее следуют в алфавитном порядке периферические сегменты по ходу часовой стрелки, а расположенный внутри горизонтальный сегмент обозначается буквой "g". Предполагая, что эти сегменты подключены в алфавитном порядке к битам от 0 до 6, получим следующую таблицу для случая включения сегментов единицей соответствующего бита:

dgts: .DB 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 07h, 7Fh, 6Fh

Программы, решающие внутренние задачи, должны записывать в ячейки для вывода информации коды, по которым программа вывода обеспечивает зажигание определенных светодиодов. Пусть ячейкам indO, indl, ind2 и ind3 соответствуют цифровые индикаторы разрядов единиц, десятков, сотен и тысяч, а ячейке ind4 — отдельные светодиоды. Обнов­лять содержимое ячеек для отображения десятичного числа нужно сразу же после преобразования двоичного числа в десятичное.

MOV DPTR, #dgts ; адрес таблицы с кодами десятичных цифр

MOV A, R3 ; количество тысяч

MOVC A, @A+DPTR

MOV ind3, А код ; цифры для тысяч

MOV A, R2 ; количество сотен

MOVC A, @A+DPTR

MOV ind2, А ; код цифры для сотен

MOV A, R1 ; количество десятков

MOVC A, @A+DPTR

MOV ind1, А ; код цифры для десятков

MOV A, RO ; количество единиц

MOVC A, @A+DPTR

MOV ind0, А ; код цифры для единиц

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