Текст
                    Белов А.В.
Конструирование устройств на микроконтроллерах. —
СПб.: Наука и Техника, 2005. — 256 с.: ил.
ISBN 5-94387-155-1
Серия «Радиолюбитель»
Перед вами новая книга по микропроцессорам. Эта книга задумана, как следующий этап для тех, кто прочитал «Самоучитель по микропроцессорной технике» этого же автора [I]. Настоящая книга призвана продемонстрировать основные приемы проектирования конкретных микропроцессорных узлов. Формат книги — это учебник в примерах. Набор конкретных, проверенных в работе схемных и программных решений может очень пригодиться в разработке самого широкого спектра микропроцессорных устройств.
В книге рассматриваются примеры проектирования некоторых периферийных узлов для широкораспространенного микроконтроллера АТ89С2051. Все приведенные в книге схемы — это практические схемы с номиналами, обозначениями выводов и советами по их применению. Большинство схем взято из реальных конструкций, разработанных автором и проверенных в работе. При разработке своих собственных конструкций читатель может использовать приведенные в книге схемы и программы, составляя из них свою собственную схему, как из элементов конструктора.
Книга предназначена для широкого круга читателей-радиолюбителей, как начинающих, так и более опытных, конструирующих устройства на микроконтроллерах. Может быть полезна студентам технических институтов и университетов.
9795943 871152 >
ISBN 5-94387-155-1
Контактные телефоны издательства (812) 567-70-25, 567-70-26 (044) 516-38-66, 559-27-40
Официальный сайт: www nit com.ru
©Белов А.В.
© Наука и Техника (оригинал-макет), 2005
ООО «Наука и Техника»
Лицензия №000350 от 23 декабря 1999 года.
198097 г Санкт-Петербург ул Маршала Говорова д 29
Подписано в печать 10 09 2004 Формат 60x88 1/16
Бумага газетная. Печать офсетная. Объем 16 п л
Тираж 5000 экз. Заказ № 922
Отпечатано с готовых диапозитивов в ОАО «Техническая книга»
190005. Санкт-Петербург, Измайловский пр., 29
СОДЕРЖАНИЕ
Содержание .........................................   3
Введение	.5
Глава 1. Традиционные периферийные устройства................. 7
1.1	Общие сведения.......	  7
1.2	. Кнопки и датчики ...	...	. . 9
1.3	. Световые индикаторные устройства................26
1.4	. Комбинированные устройства......................50
1	5. Исполнительные устройства.	  60
Глава 2. Другие варианты схем ввода/вывода....................63
2	1 Общие сведения............................ ... 63
2.2	Пример построения ЦАП .........................   64
2.3	. Система аналогового ввода. .................... 68
2.4	. Жидкокристаллический дисплей....................77
2	5. Подключение ЖКИ дисплея к микроконтроллеру....	85
2	6 Управляющая программа для ЖКИ модуля	86
Глава 3. Работа с l2C шиной.................................. 98
3	1 Общие сведения.................................. 98
3.2	Основные характеристики lzC шины................ 101
3.3	. Схема построения 12С интерфейса............... 103
3.4	. Протокол 12С шины..............................105
3.5	Микросхемы EEPROM с 12С интерфейсом............. 113
3	6. Программная реализация 12С интерфейса	129
3.7	. Примеры программ для работы с флэш-памятью.... 149
Глава4. Работа с шиной MicroLAN .............................161
4.1.	Общие сведения................................. 161
4.2.	Новый класс микросхем — iButton.................168
4.3.	1-Wire микросхемы в традиционном исполнении.....171
4
4.4.	Схемная реализация 1-Wire интерфейса........... 175
4.5.	Синхронизация и побитная передача информации.... 178
4.6	Сброс и обнаружение присутствия на линии........ 182
4.7.	Система команд протокола 1 -Wire............... 184
4.8.	Структура ID кода............................... 192
4.9	Интегральные датчики температуры................. 194
4	10 Внутренняя архитектура микросхемы DS18B20.....196
4.11.	Схема подключения микросхемы DS18B20.......... 207
4	12 Программная реализация 1-Wire интерфейса......209
4.13.	Чтение кода ПЗУ микросхемы DS18B20	 219
4.14.	Подпрограмма чтения температуры................227
4.15.	Вывод температуры на индикатор.................237
4	16 Программа подсчета контрольной суммы .........244
Заключение...........................................255
Список литературы	 255
Список ссылок в Интернет.............................255
Введение
Итак, перед вами очередная книга по микропроцессорам. Эта книга задумана, как следующий этап для тех, кто прочитал «Самоучитель по микропроцессорной технике» [1]. «Самоучитель» давал обшие понятия о микропроцессорах, начиная с самых азов. Там вес начиналось с элементов цифровой логики и заканчивалось устройством микропроцессора и микропроцессорной системы. Настоящая же книга призвана продемонстрировать основные приемы проектирования конкретных микропроцессорных узлов. Формат книги — это учебник в примерах. Как известно, самый эффективный метод обучения — это обучение на примерах. Однако, если вы не относитесь к разряду начинающих и хорошо представляете себе что такое микропроцессор и микроконтроллер, наша книга поможет вам в совершенствовании своих знании. Набор конкретных, проверенных в работе схемных и программных решений может очень пригодиться в разработке самого широкого спектра микропроцессорных устройств.
Книга называется «Разработка периферийных устройств для микроконтроллеров». Почему же объектом вашего внимания я решил выбрать именно периферийные устройства? Ответ прост. Современные микроконтроллеры достигли такого уровня интеграции, что представляют собой универсальные микросхемы, содержащие все основные элементы микропроцессорной системы: память, порты ввода/вывода, систему прерываний, таймеры и многое другое. Единственные элементы, которые еще пока остаются за пределами микросхемы — это кварцевый резонатор и несколько элементов, предназначенных для начального сброса при включении питания. Современная тенденция развития микропроцессорной техники направлена на то, что и эти внешние элементы все чаще встраиваются внутрь микроконтроллера. Таким образом, микроконтроллер является самодостаточной системой. Простейшие задачи он может решать без дополнительных внешних элементов (не считая нескольких описанных выше навесных элементов, предусмотренных его типовой схемой включения). На рынке уже появились простые микропроцессорные устройства, собранные всего на одной микросхеме микроконтроллера. Например, целый набор телефонных приставок, выполненных в телефонной розетке. Несмотря на свою миниатюр
6
Введение
ность, такие приставки выполняют довольно серьезные функции. В простейшем случае они могут блокировать несанкционированное использование вашей телефонной линии, или блокировать междугородние звонки, производимые без вашего ведома. Высшим пилотажем можно считать мини-АТС в телефонной розетке, позволяющее двум абонентам пользоваться одной телефонной линией без опасения, что сосед будет слушать ваши разговоры.
Однако, в большинстве случаев, для решения практических задач без подключения внешних элементов нс обойтись. К микроконтроллеру необходимо подключать внешние датчики, кнопки управления, различные исполняющие и индикаторные устройства. Все эти устройства и принято называть периферийными. В большинстве случаев, процесс конструирования микропроцессорной системы сводится к разработке периферийных устройств. Под этим понимается разработка схемы, а также разработка управляющей программы. Именно в умении грамотно и рационально подключить периферийные устройства и состоит искусство схемотехники.
В настоящей книге я постарался охватить все возможные виды периферийных устройств, применяемых в микропроцессорной технике. Весь материал книги — это набор конкретных примеров. К каждому примеру прилагается принципиальная схема, а также пример управляющей программы. Все схемы и программы, приведенные в книге, сопровождаются подробным описанием. При подборе примеров предпочтение отдавалось простым схемным решениям. Именно таким принципом нужно руководствоваться при разработке реальных микропроцессорных устройств. Нс нужно искусственно усложнять схему. Основным правилом должно быть: если заданных характеристик можно достичь при помощи более простого схемного решения, нужно применить именно его. В то же время, из всех возможных вариантов построения схемы нужно уметь выбрать такой, который будет оптимален с точки зрения программной реализации.
Все приведенные в книге схемы — это практические схемы с номиналами, обозначениями выводов и советами по их применению. Большинство схем взято из реальных конструкций, разработанных автором и проверенных в работе. При разработке своих собственных конструкций читатель может использовать приведенные в книге схемы и программы, составляя из них свою собственную схему, как из элементов конструктора.
Глава 1
Традиционные
периферийные устройства
1.1. Общие сведения
В первой главе я решил объединить такие обычные и широкораспространенные элементы микропроцессорных систем, как кнопки, контактные датчики, а также простейшие световые индикаторы. Практически ни одно микропроцессорное устройство не может обойтись без элементов подобного рода. Однако, прежде чем перейти к раскрытию заявленной темы, я хотел бы договориться о некоторых общих моментах.
Все примеры, приведенные в данной книге, основаны на применении одного и того же микроконтроллера. Как и в предыдущей книге, в качестве базового контроллера, я решил выбрать микросхему АТ89С2051 фирмы Atmel. Несмотря на то, что фирма Atmcl уже давно делает упор на новое поколение микроконтроллеров (серия AVR), микроконтроллер АТ89С2051 тоже довольно широко применяется. И не случайно, так как эта микросхема имеет еще достаточно большой потенциал. Параметры микросхемы позволяют создавать широкий спектр современных электронных устройств, находящих свое применение в самых разных областях микропроцессорной техники. Главным преимуществом выбора именно этой микросхемы является ее широкая доступность и приемлемая цена. Настоящая книга рассчитана на читателей, которые знакомы с архитектурой и системой команд микроконтроллера АТ89С2051. Остальных я хочу отослать к «Самоучителю...» 11], где дано подробное описание этой микросхемы. Применение одной микросхемы во всех примерах позволило достичь определенной преемственности. Многие примеры являются продолжением предыдущих. Кроме того, при разработке всех примеров я старался обеспечить их
8
Традиционные периферийные устройства
взаимную совместимость. Это значит, что разные примеры почти всегда можно легко совместить в одной общей схеме.
Рис. 1.1. Типовая схема включения микроконтроллера АТ89С2051
Теперь немного о типовой схеме включения микроконтроллера АТ89С2051. Эта схема приведена на рис. 1.1. Элементы Rl, С1 составляют цепь начального сброса микроконтроллера. Она служит для перевода в исходное состояние всех внутренних систем микроконтроллера сразу после включения питания. Кварцевый резонатор Z1 определяет частоту встроенного тактового генератора микроконтроллера. Этот генератор предназначен для синхронизации всех внутренних процессов микроконтроллера. Микросхема АТ89С2051 допускает выбирать частоту кварцевого резонатора до 24 МГц. Нижний предел частоты не ограничивается. Конденсаторы С2 и СЗ — это согласующие элементы для кварца. Конкретная частота кварца выбирается исходя из требуемого быстродействия и некоторых других соображений, о которых мы поговорим дальше. Но наличие кварца вовсе не обязательно. Микроконтроллер АТ89С2051 допускает применение в качестве времязадающей цепи резонансного контура, и даже подключение внешнего тактового генератора. Однако такие методы получения тактовой частоты менее предпочтительны и в настоящей книге не рассматриваются.
Кнопки и датчики
9
На схеме рис. 1.1 не показаны цепи питания микросхемы. В цифровой схемотехнике не принято показывать цепи питания, чтобы ни загромождать схему. В нашем случае напряжение питания (+5 В) подается на вывод 20, общий провод — вывод 10.
Оставшиеся выводы микроконтроллера представляют собой два порта ввода/вывода, которые получили обозначение Р1 и РЗ. Именно к этим двум портам и подключаются периферийные устройства. Описанная выше типовая схема включения не является единственно возможной. Однако это самый приемлемый вариант. Мы возьмем ее за основу для всех последующих примеров. Далее мы будем опускать все цепи, относящиеся к типовой схеме включения. Однако вы должны помнить, что на самом деле во всех дальнейших примерах микроконтроллер всегда включен но своей типовой схеме (см. рис. 1.1).
Ну и, наконец, немного о приведенных в книге программах. Все программы написаны автором на языке ассемблера для микроконтроллера АТ89С2051 (Cross-Assembler 8051, Version 1.2h). Подробно этот язык и инструментальные программы для трансляции и отладки прикладного программного обеспечения описаны в |1]. Каждый пример программы для удобства его восприятия выделен при помощи рамки. В левой части этой рамки на сером фоне помещены условные номера строк программы. Номера строк введены для удобства. В реальном тексте программы на языке ассемблера таких номеров нет. Вы должны понимать, что текст программы — эго то, что находится внутри рамки. Исходные тексты всех программных примеров из этой книги вы можете найти в электронном виде на сайте [8W] (см. ссылку в конце книги).
На этом изложение предварительной информации можно считать законченным. Теперь приступим к основному повествованию.
1.2. Кнопки и датчики
Практически ни одно микропроцессорное устройство не обходится без кнопок и простейших датчиков на основе обычных контактов. При помощи этого вида периферийных элементов в микропроцессорное устройство поступает различная информация, которая используется для изменения алгоритма работы программы.
10	Традиционные периферийные устройства
Примером может служить датчик поворота. Допустим, наша микропроцессорная система должна управлять поворотом некоего поворотного устройства. Для отслеживания реального угла поворота нам понадобится датчик, при помощи которого микроконтроллер сможет определить этот угол. Самый простой способ построения такого датчика — это механические контакты, связанные с поворачиваемым устройством. Проще всего на валу устройства укрепить постоянный магнит, а на неподвижной ее части расположить геркон. При вращении вала укрепленный на нем магнит будет проходить рядом с герконом и вызывать срабатывание его контактов.
Схема подключения такого датчика к микроконтроллеру приведена на рис. 1.2. Датчик представляет собой свободно разомкнутые контакты геркона. В приведенном примере датчик подключен к линии Р1.0 порта Р1 микроконтроллера. Через этот вход микропроцессор производит считывание состояния датчика. Однако с таким же успехом подобную схему можно подключить и к любой другой линии любого из двух портов микроконтроллера (см. рис 1.1).
Рис. 1.2. Простая схема подключения датчика на основе геркона
Принцип работы схемы, приведенной на рис. 1.2, очень простой. В исходном состоянии контакты датчика разомкнуты. На вход микроконтроллера через резистор R1 подается напряжение от источника питания +5 В. Микросхема воспринимает это напряжение как сигнал логической единицы. При срабатывании датчика контакты замыкаются и соединяют вывод микроконтроллера с общим проводом. В результате напряжение на входе Р1.0 падает до нуля. Теперь микросхема воспринимает входной уровень сигнала как логический ноль. Резистор R1 при этом служит токоограничиваю
Кнопки и датчики	11
щим элементом, предотвращая короткое замыкание между шиной питания и общим проводом. Наличие резистора Rl обязательно лишь в том случае, если датчик подключается к линии Р1.0 или Pl.l. Остальные линии имеют свои внутренние резисторы нагрузки, которые могут с успехом заменить внешний резистор.
Теперь рассмотрим пример программы для обслуживания нашего датчика. Посмотрите на листинг 1.1. Здесь приведен фрагмент программы, которая постоянно опрашивает датчик и в зависимости от его состояния запускает одну из двух специальных процедур.
Листинг 1.1
	Программа обработки сигнала с датчика			
1	ml.	mov	p1.0,C1	Записываем 1 в соответствующий разряд порта
2		mov	c.pl.O	Читаем состояние датчика в битовый аккумулятор
3			m2	Если контакты датчика разомкнуты перейти к m2
4		ail	piod	Вызов процедуры обработки нажатия контакта
5		imp	I	Возврат к началу (следующий цикл считывания)
6	m2:	call	proc2	Вызов процедуры обработки размыкания контакта
7		jmp	ml	Возврат к началу (следующий цикл считывания)
Как легко видеть из текста программы, первое, что делает программа — записывает в линию Р1.0 сигнал логической единицы (строка 1). Это необходимо для того, чтобы данная линия могла работать на ввод информации (подробнее о правилах работы с портом смотри в [1]). Следующая команда считывает бит информации, поступающей от датчика, и помещает ее в регистр признака переноса (строка 2). В микропроцессорной технике принято ячейку признака переноса обозначать как CY. Ячейка CY часто используется как аккумулятор для битовых операций. Если в момент считывания сигнала контакты датчика были разомкнуты, то в ячейке CY окажется логическая единица. Если контакты замкнуты, то там будет логический ноль. Оператор условного перехода jc осуществляет оценку содержимого CY (строка 3). Если в CY логический ноль, то управление передастся на метку m2, и выполняется команда call ргос2 (строка 6). В противном случае передача управления не происходит и выполняется команда call prod (строка 4). Оператор call — это вызов подпрограммы. Поэтому, в зависимости от состояния датчика вызывается одна из двух подпрограмм: prod или
12	Традиционные периферийные устройства
ргос2. Тексты самих подпрограмм здесь не показаны. Это могут быть два разных алгоритма работы вашей системы, которые будут переключаться при срабатывании датчика.
Схема, приведенная на рис. 1.2, универсальна и широко применяется как для подключения простейших контактных датчиков, так и для подключения различных кнопок управления. Любое реальное микропроцессорное устройство редко обходится без кнопок управления. При помощи таких кнопок могут переключаться режимы работы вашего устройства. Например, кнопки «Пуск» и «Стоп» могут быть использованы для запуска и останова любого процесса. Если вам нужно иметь несколько кнопок управления, вы можете подключить их к разным входам микроконтроллера. При этом будут одновременно работать несколько кнопок. Если количество кнопок не слишком велико, то данный способ их включения — самый рациональный. Однако, если требуется большое количество управляющих кнопок, то вам просто может не хватить имеющихся выводов. В этом случае нс обойтись без матрицы клавиш. На рис. 1.3 приведена схема подключения клавиатуры из 32 клавиш путем составления из них матрицы.
Рис. 1.3. Схема подключения клавиатуры в виде матрицы клавиш
Кнопки и датчики
13
Напоминаю, что цепи сброса и цепи, связанные с кварцевым резонатором, на этой схеме, как и в большинстве последующих примеров, условно не показаны. Как видно из схемы, для подключения тридцати двух клавиш используется всего лишь 12 выводов. В данном конкретном случае порт Р1 работает как порт ввода. Четыре младшие разряда порта РЗ работают на вывод. Возможен и обратный вариант (Р1 на вывод, РЗ на ввод). Но мы выбрали тот вариант, который наиболее рационален с точки зрения удобства составления программы. Давайте рассмотрим подробнее принцип работы схемы.
В исходном состоянии на выводы Р-З.О...РЗ.З подается сигнал логической единицы. На все выводы порта Pl (Pl 0...Р1.7) также поданы единицы. Но во втором случае единицы поданы для того, чтобы обеспечить возможность работы линий в режиме ввода. Контроллер периодически опрашивает состояние клавиш путем изменения сигналов на выходах РЗ.О...РЗ.З и считывания сигнала из порта Р1. В случае обнаружения замыкания контактов одной из клавиш, программа выполняет закрепленные за этой клавишей действия. В случае, если при опросе клавиатуры обнаружится несколько одновременно нажатых клавиш, это считается ошибкой и никаких действий не выполняется. Если ни одна клавиша не нажата, никаких действий также нс выполняется. Такой алгоритм используется в большинстве современных клавиатур.
Каким же образом осуществляется опрос клавиш? Процедура опроса клавиш поочередно переводит одну из линий РЗ.О...РЗ.З в нулевое состояние. Сначала в нулевое состояние переводится линия РЗ.О. Сразу после этого контроллер производит чтение числа из порта Р1. Если ни одна из клавиш нс нажата, то все разряды считанного числа будут равны единице (считанное число будет равно 0FFH). Если хотя бы одна из клавиш К1...К8 окажется нажатой, то число, прочитанное из порта Р1, будет отличаться от значения 0FFH. Предположим, что мы нажали клавишу К1. Тогда сигнал логического нуля с выхода РЗ.О поступит на вход Р1.0 и младший разряд считанного числа окажется равным нулю. В этом случае процессор из порта Р1 прочитает 0FEH. Нажатие любых других клавиш этой вертикали (К2...К8) приведет к обнулению других разрядов считываемого числа. В результате для разных комбинаций клавиш мы получим разные коды.
Аналогичным образом микроконтроллер опрашивает остальные вертикали клавиш. То есть, на следующем этапе, процессор вы
14
Традиционные периферийные устройства
ставляет ноль на линию Р3.1, а линию РЗ.О возвращает в единичное состояние. После этого считанное из порта Pl число будет определять состояние клавиш К9...К16. Затем ноль выставляется на линию Р3.2 и проверяется состояние клавиш К17...К24. И в заключение ноль выставляется на линию РЗ.З и проверяется состояние клавиш К25...К32. Анализируя полученные при этом коды можно вычислить номер нажатой клавиши.
Посмотрим, как это делается. Для обслуживания клавиатуры, изображенной на рис. 1.3, была разработана процедура klav, текст которой вы можете видеть в листинге 1.2. Это всего лишь один из возможных вариантов реализации подобной процедуры. Процедура оформлена в виде отдельной подпрограммы, к которой при необходимости обращается основная программа микроконтроллера. При каждом обращении подпрограмма klav производит однократное сканирование всей клавиатуры и возвращает код нажатой клавиши. Возвращаемый код помещается в аккумулятор (то есть регистр а). Если в момент сканирования клавиатуры ни одна клавиша не была нажата, то возвращаемый код состояния будет равен нулю. Если нажато сразу несколько клавиш, программа также возвращает ноль. И только в том случае, если нажата всего одна клавиша, то возвращаемый подпрограммой код будет равен номеру этой клавиши. Описанный выше алгоритм является стандартным для клавиатуры, состоящей из матрицы клавиш.
Итак, рассмотрим подробнее текст процедуры klav. Процедура состоит из основной подпрограммы и нескольких вспомогательных. Кроме того, листинг 1.2 содержит текст описания констант и переменных, необходимых для работы всех этих подпрограмм. Текст описаний занимает строки 1...8. Оператор $mod2051 (строка 1) — это стандартный оператор присоединения библиотечного файла. Он обязательно должен присутствовать в начале любой программы, написанной на данной версии ассемблера. Подробнее о действии этого оператора и о порядке применения библиотечных файлов смотрите в [1]. В строках 2...8 происходит определение необходимых констант и резервирование ячеек памяти. На самом деле в реальной программе и констант, и ячеек памяти будет гораздо больше. В приведенном примере показаны лишь те операции, которые необходимы для работы процедуры klav. В строках 2...5 программы определяется четыре константы. Это коды, соответствующие четырем банкам регистров РОН. Такой блок определения банков будет широко применяться во многих
Кнопки и датчики
15
примерах, приведенных далее в нашей книге. В данном конкретном случае используется лишь один банк регистров. Поэтому нам понадобится лишь одна константа: ЬапкЗ.
Строки 6...8 — это блок резервирования ячеек памяти. И опять мы приводим лишь строки необходимые для работы процедуры klav. В реальной программе этот блок будет дополнен операторами, которые зарезервируют ячейки и для других целей. В нашем случае в оперативной памяти микроконтроллера по адресу 20Н резервируется одна ячейка, для буфера порта РЗ (строка 8). Эта ячейка получает название p3buf. Что же это за буфер и зачем он нужен? Для того, чтобы это понять, взгляните еше раз на схему подключения клавиатуры (рис. 1.3). Как видно из схемы, для подключения клавиатуры мы использовали почти все информационные выводы микросхемы Но микропроцессорное устройство, содержащее только одну клавиатуру, не имеет никакого смысла. Недостаточно просто вводить информацию. Нужно, чтобы наше устройство еще чем-нибудь управляло. Иначе, зачем клавиатура? Но это не беда! У нас еще остается три старших разряда порта РЗ (Р3.4, Р3.5 и Р3.7). Не густо, но в некоторых случаях этого вполне достаточно. Чтобы использовать эти три линии, нам придется обеспечить независимое управление старшими и младшими разрядами порта РЗ. Изменяя информацию на линиях РЗ.О...РЗ.З в процессе опроса клавиатуры, нельзя допустить, чтобы изменились сигналы на выводах Р3.4, Р3.5, Р3.7
Есть несколько способов раздельного управления старшими и младшими разрядами одного и того же порта. Можно применять битовые операции и управлять по очереди каждым отдельным разрядом. Однако, в нашем случае удобнее применять метод буфера порта. Этот метод состоит в том, что код, предназначенный для вывода в порт, хранится в специальной ячейке памяти, служащей буфером. Перед тем как вывести код непосредственно в порт, его значение вычисляется в буфере. Значениями младших разрядов управляет одна подпрограмма (в нашем случае подпрограмма klav), а значениями старших — другая.
После изменения своей части буфера любой из этих подпрограмм, производится вывод буфера в порт. В результате такой технологии «не свои» биты порта остаются без изменений. Подробнее об использовании буфера мы еще поговорим. А сейчас продолжим изучение листинга 1.2 далее, по порядку.
16
Традиционные периферийные устройства
В строках 9, I0 показаны операторы, которые должны предшествовать тексту основной программы. После текста основной программы располагается наша процедура опроса клавиатуры Текст процедуры занимает строки 12...29. Основная программа может вызывать процедуру klav каждый раз, когда это потребуется. Выполнение подпрограммы начинается с команды сохранения регистра psw в стеке (строка 12) Сразу за этим в этот регистр записывается константа ЬапкЗ (строка 13). Это приводит к переключению на третий банк РОН В конце процедуры, непосредственно перед выходом (строка 28), состояние регистра psw восстанавливается. В результате восстанавливается тот банк регистров, который действовал до вызова подпрограммы. Таким образом, наша процедура использует для своей работы свой собственный банк регистров (третий).
При написании программ рекомендуется по возможности распределить все банки регистров между крупными процедурами. Например, банк 3 закрепить за процедурой ввода с клавиатуры. Банк 2 для процедуры вывода на индикатор и так далее. Банк О обычно используют для основной программы В результате такого распределения регистров снижается опасность того, что вызванная процедура случайно изменит содержимое ячейки, где уже хранится важная информация, что может нарушить ход выполнения других процедур.
Листинг 1.2
1	5mod2051
;-------------------- Определение констант
2	bankO	EOU	00000000В	:	Коды банков памяти
3	bankl	EQU	00001000В
4	bank2	EOU	00010000В
5	ЬапкЗ	EQU	00011000В
------------------- Резервирование ячеек памяти
6	DSEG
ORG 20Н	Начинаем резервирование с адреса 20Н
8	p3buf:	OS 1	Буфер порта рЗ
----------- Начало программного кода
9	CSEG
10	ORG	ООН	Начинаем программный код с адреса ООН
11		
В этом месте вы должны поместить основной текст вашей программы
Кнопки и датчики
17
	.шшшштшшшмтшешш			
	:ии	Подпрограмма опроса клавиатуры tit		
	.Вйв#Вй#вйВв#«##вС#в«в»вйЛй#вВв«#ВВ#»вВв			
12	klav:	push	psw	Сохранение регистра флагов в стеке
13		mov	psw,#bank3	Переключение на Банк 3 регистров РОН
14		mov	p1,#0FFH	Перевод Р1 0-Р1.7 в единичное состояние
15		call	clrb	Перевод РЗ.О-РЗ.З в единичное состояние
16		mov	rO.SO	Очистка буф. ра кода клавиши
17		mov	r1,#4	Инициализация счетчика столбцов
18		mov	r2.COFEH	Код сканирование первого столбца
19	kll:	call	set!)	;	Вывод кода в лсрт РЗ
20		mov	a.p1	Считывание состояния клавиатуры
21		cjne	a.«0FFH.kl3	Если клавиша нажата, переходим к к13
			 Переход к	следующему столбцу	
22	К12	mov	a,r2	Извлечение к-да
23		Г1	a	Сдвиг
24		mov	г2,а	Записать назад в буфер
25		djnz	r1,kl1	Команда цикла опроса столбцов
			 Окончание	процедуры опроса клавиатуры	
М	klfin	call	cl rU	;	Перевод в исходное состояние порта РЗ
27		mov	a.rO	Запись в аккумулятор кода клавиши
28		pop	psw	Восстановление регистра флагов
29		ret		Выход из подпрограммы
			 Нахождение номера клавиши в		строке
30	kl3:	mov	r3,#1	Инициализация счетчика строк
31	kl4:	setb	С	Обнуление признака переноса
32		Г ГС	a	Сдвиг входного кода
33		jnc	kl5	Если нашли разряд, равный нулю перейти  к!6
34		inc	r3	Итерация счетчика строк
35		jmp	k!4	Переход к началу цикла счета строк
36	kl5:	cjne	a,B0FFH.kl6	Если еще есть хоть один ноль, перейти к к16
37		mov	a.rO	Не найдена ли уже другая нажатая 'чопка
38		jnz	k!6	Если да то перейти к к16
			 Вычисление номера клавиши		
39		mov	a. 44	Запись константы в аккумулятор
40		clr	(:	Очистка признака переноса
41		subb	a, r i	Вычисление номера столбца
42		rl	a	Три оператора сдвига (умножение на 8)
43		rl	a	
44		rl	a	
45		add	a,r3	Прибавление номера строки
46		mov	rO.a	Записываем в буфер
47		jmp	k!2	Продолжаем поиск по остальным столбцам
48	k!6:	mov	rO.KO	Возвратить ноль
49		jmp	klfin	Перейти на конец процедуры
			 Сброс разрядов стс.'йцов		
50	clrll:	mov	a,p3buf	Считывание содержимого буфера порта РЗ
51		orl	a.cOFH	Перевод разрядов РЗ.О-РЗ.З в единичное гост
52		mov	p3buf,a	Запись результата назад в буфер
53		mov	p3,p3buf	;	Вывод содержимого буфера в порт РЗ
18
Традиционные периферийные устройства
ret
55
56
57
58
59
60
setU:
Вывод столбцов
mov	a,p3buf
orl	a.oOFH
anl	a,r2
mov	p3buf,a
mov	p3,p3buf
ret
, Считывание содержимого буфера порта РЗ , Перевод разрядов РЗ.О-РЗ.З в единицу : Вывод в РЗ.О-РЗ.З кода сканирования : Запись результата назад в буфер ; Вывод содержимого буфера в порт РЗ
Сюда вы можете поместить другие подпрограммы
end
Однако продолжим описание подпрограммы опроса клавиатуры. В строках 14 и 15 происходит инициализация всех линий, связанных с клавиатурой. Сначала в порт PI выводится код 0FFH (строка 14), что переводит все выходы в единичное состояние. Теперь порт Р1 готов работать на ввод. В строке 15 производится вызов подпрограммы clrU (начальная установка управляющих выходов). Текст подпрограммы clrU занимает строки 50. .54. Она, как и подпрограмма setU, предназначена для реализации принципа раздельного управления разрядами порта РЗ.
Подпрограмма clrU производит установку разрядов РЗ.О...РЗ.З в единичное состояние. Для этого она сначала извлекает содержимое буфера p3buf (строка 50), устанавливает младшие разряды в единицу (строка 51), сохраняет результат обратно в буфере (строка 52), а затем выводит тот же результат в порт РЗ (строка 53). Таким образом, значения всех старших разрядов порта РЗ остается таким, каким его установили другие подпрограммы.
После установки линий порта в исходное состояние начинается цикл опроса клавиатуры. Перед началом цикла производится его подготовка. Сначала очищается регистр гО, который используется как буфер для хранения промежуточного значения кода нажатой клавиши (строка 16). В строке 17 происходит инициализация регистра г1, который используется как счетчик столбцов. В нашей схеме четыре столбца клавиш, поэтому в г1 помещается начальное значение, равное четырем.
Кнопки и датчики
19
Еще один регистр г2 используется для хранения кода, который в процессе сканирования мы будем подавать на разряды РЗ О...РЗ.З Это такой код, когда один из разрядов равен нулю, остальные единице. В первом цикле опроса нам нужно подать ноль на линию РЗ.О и единицу на линии P3.1...P3.3. В двоичном виде это будет выглядеть следующим образом: 111 II ИОВ В шестнадцатеричном виде это будет 0FEH. Именно это значение помещается в регистр г2 (строка 18). В дальнейшем, для перехода к следующему столбцу клавиатуры, мы будем сдвигать содержимое регистра г2 влево Таким образом, ноль из младшего разряда будет перемешаться но очереди во все последующие, и мы получим коды для опроса каждого из столбцов.
Сразу после команд инициализации начинается главный цикл сканирования Тело цикла составляют строки 19...25. Цикл начинается с вызова вспомогательной подпрограммы setU. Эта подпрограмма производит вывод четырех младших разрядов регистра г2 в порт РЗ, не затрагивая при этом четыре старших разряда. Для выполнения этих действий тоже используется буфер p3buf. Сначала значение буфера извлекается в аккумулятор (строка 55). Затем производится установка старших разрядов в единицу (строка 56)
Теперь, когда старое значение этих разрядов сброшено, можно производить операцию объединения. В строке 57 производится операция «И» между содержимым аккумулятора и содержимым регистра г2. В результате таких вычислений мы получаем в аккумуляторе число, четыре младшие разряда которого равны младшим разрядам регистра г2, а старшие разряды остались без изменения. Это число мы, во-первых, записываем обратно в буфер (строка 58), а во-вторых, выводим в порт РЗ (строка 59).
Итак, сигнал опроса ряда установлен. Теперь программа производит считывание порта Р1 (строка 20). Если в опрашиваемом столбце ни одна клавиша не нажата, то считанное таким образом число будет равно 0FFH. Если же хотя бы одна клавиша окажется нажатой, то считанное число будет отличаться от 0FFH. В строке 21 происходит проверка считанного числа. Если клавиша нажата, то управление передается по метке к13. Здесь определяется номер строки клавиатуры, где произошло замыкание клавиши. Если замыканий не обнаружено, то эта часть алгоритма пропускается и программа продолжает опрос столбцов. Для перехода к следующему
20
Традиционные периферийные устройства
столбцу производится сдвиг кода в регистре г2 (строки 22...24). Оператор djnz в строке 25 — последний оператор в цикле опроса столбцов клавиатуры. Он уменьшает содержимое регистра г1 на единицу и обеспечивает переход в начало цикла (метка к!1), если содержимое регистра не достигло нуля. Таким образом, опрашиваются все четыре столбца. Когда все столбцы опрошены, цикл завершается. Программа выходит на финишную прямую. Младшие разряды порта РЗ переводятся в исходное состояние (строка 26). Код нажатой клавиши помещается в аккумулятор (строка 27). Восстанавливается регистр psw (строка 28), и, наконец, происходит выход из подпрограммы klav (строка 29).
В процессе описания подпрограммы мы пропустили одну ее часть. Ту часть, где происходит вычисление кода нажатой клавиши. Вернемся и рассмотрим ее подробнее. Вычисление кода нажатой клавиши начинается с метки kl3 и занимает строки с 30 по 49. Как вы помните, в это место программа переходит, если при опросе очередного столбца считанный из порта Р1 код не равен 0FFH. Этот код мы будем называть кодом столбца. Если код столбца не равен 0FFH, то тут возможны два варианта. Первый вариант — в опрашиваемом столбце нажата всего одна клавиша.
Второй вариант — в одном столбце нажато сразу несколько клавиш. Если нажатых клавиш несколько, дальнейший перебор клавиш не имеет смысла. Программа должна завершиться досрочно и возвратить ноль в аккумуляторе. Если на данном этапе обнаружится всего одна нажатая клавиша, то заканчивать перебор еще рано. В этом столбце одна, а в других? Это мы узнаем в процессе дальнейшей проверки. А сейчас нам нужно вычислить номер нажатой клавиши, записать его в буфер кода клавиатуры (регистр г0) и продолжить процесс опроса клавиатуры.
В дальнейшем содержимое регистра г0 можно использовать для проверки факта одновременного нажатия двух клавиш в разных столбцах. Обнаружив нажатую клавишу, нужно сразу проверить г0. Если содержимое этого регистра не равно нулю, то нажатая клавиша не’единственная.
Посмотрим теперь как это делается на практике. Для начала рассмотрим процесс определения номера строки, где нажата клавиша. Этот номер определяется путем многократного сдвига кода столбца. Сдвиг выполняется при помощи оператора ггс (строка 32). Сдвиг
Кнопки и датчики
21
происходит до тех пор, пока ноль от нажатой клавиши не достигнет ячейки CY. Количество циклов сдвига, которые потребуются для этого и равно номеру строки, где произошло нажатие клавиши. Если в столбце была нажата лишь одна клавиша, то после всех этих циклов сдвига во всех оставшихся разрядах аккумулятора останутся лишь единицы То есть код в аккумуляторе будет равен 0FFH. Если это не так, то это значит, что в одном столбце нажато сразу несколько клавиш.
Рассмотрим, как происходит весь этот процесс в программе. Перед тем как начинать сдвигать аккумулятор, признак переноса устанавливается в единицу (строка 31). Если там оставить ноль, то при сдвиге он попадет в аккумулятор и сделает невозможным обнаружение лишних нажатий. Тело цикла сдвига занимает строки 31 ..35. Перед началом цикла устанавливается начальное значение для счетчика строк (строка 30). В качестве счетчика используется регистр гЗ. После каждого сдвига проверяется значение ячейки CY (строка 33). Как только признак окажется равным нулю, оператор jnc, находящийся в этой строке, передаст управление по метке к15 и цикл на этом завершится.
Подсчет строк производится в строке 34. После каждого цикла сдвига счетчик строк увеличивается на единицу. В строке 35 расположен оператор, организующий замыкание цикла. Это оператор безусловного перехода. В другом случае применение оператора безусловного перехода могло бы привести к образованию бесконечного цикла и зависанию программы. Но в нашем случае применение этого оператора вполне оправдано. Так как точно известно, что, как минимум, один из разрядов сдвигаемого числа обязательно будет равен нулю. Если это было бы нс так, то управление вообще бы не перешло в эту часть программы. Предварительная проверка содержимого аккумулятора производится в строке 21.
После завершения всех циклов сдвига в регистре гЗ будет находиться номер строки, где обнаружено нажатие клавиши. Но прежде чем записывать его в буфер (гО), нужно произвести две проверки для выявления двойного нажатия. Сначала проверяется содержимое аккумулятора (строка 36). После сдвига там должно быть 0FFH. Если это не так, то управление передается по метке к!6, где производится досрочное завершение подпрограммы с нулевым результатом.
22
Традиционные периферийные устройства
Следующая проверка — это проверка буфера клавиатуры. Если там не ноль, то это значит, что в одном из предыдущих столбцов уже была обнаружена нажатая клавиша. Для проверки содержимое гО помешается в аккумулятор (строка 37). Затем, в строке 38, оно проверяется на равенство нулю. Для этого используется оператор jnz. Если аккумулятор не равен нулю, то управление также передается по метке к16 и подпрограмма завершается с нулевым результатом.
Если подпрограмма провела все описанные выше проверки и определила, что мы имеем дело с единственной нажатой клавишей, она должна вычислить код этой клавиши и записать его в гО. Вычисление кода происходит в строках 39...47. Код вычисляется по простой формуле: номер столбца умножается на восемь и к полученному результату прибавляется номер строки. Номера столбца в чистом виде у нас нет. Однако в регистре г1 содержится счетчик циклов опроса столбцов. Он содержит обратную величину. В самом начале его значение равно четырем. После опроса каждого очередного столбца содержимое счетчика уменьшается на единицу.
Очевидно, что текущий номер столбца легко найти, если содержимое регистра г1 вычесть из четырех. Это арифметическое действие выполняется в строках 39...4L Сначала в аккумулятор помешается значение, равное 4 (строка 39). Для вычитания используется оператор subb (строка 41). Оператор subb производит вычитание с учетом признака переноса. Поэтому в строке 40 признак переноса обнуляется. После выполнения команды subb мы получим номер столбца, который будет находиться в аккумуляторе. Далее номер столбца умножается на 8. Для этого используется метод тройного сдвига (строки 42...44). Каждый сдвиг двоичного числа вправо эквивалентен операции умножения на 2. После трех сдвигов содержимое аккумулятора увеличится в восемь раз.
Далее к полученному числу прибавляется номер строки (строка 45). Вычисленный таким образом номер нажатой клавиши записывается в буфер клавиатуры — регистр гО (строка 46). На этом завершается процесс вычисления кода нажатой клавиши, но не заканчивается процесс сканирования клавиатуры. Для продолжения этого процесса управление передается по метке kl2 (строка 47).
Описанную только что схему (рис. L3) можно усовершенствовать. Добавив всего один дешифратор, мы можем сэкономить две линии порта РЗ. Схема клавиатуры с дешифратором приведена на
Кнопки и датчики
23
рис. 1.4. В этой схеме для выбора одного из четырех столбцов клавиатуры используется дешифратор DD2 типа К555ИД4. В такой схеме для сканирования столбцов микроконтроллер должен подавать на выходы РЗ.О и Р3.1 двухразрядный двоичный код, равный номеру столбца. Код поступает на входы АО и А1 дешифратора. В результате один из его выходов (тот, номер которого соответствует поступившему коду) примет нулевое значение. На остальных же выходах будет единица. Так, при коде 00В на входе дешифратора выход Q0 (вывод 9) принимает нулевое значение. При коде 01В — ноль будет на выходе Q1. И так далее. Таким образом, микроконтроллер может перебирать все четыре столбца, используя всего два разряда. В остальном алгоритм работы новой схемы ничем не отличается от предыдущей (рис. 1.3).
В связи с изменением схемы немного изменится и программа. Изменения коснулись лишь процедуры опроса столбцов. Теперь код будет формироваться другим способом. В остальном новый вариант программы будет почти полностью совпадать с предыдущим вариантом. Новый текст программы опроса клавиатуры приведен в листинге 1.3. Для удобства все строки в новом тексте программы имеют ту же самую нумерацию, как и в первом ее варианте (см. листинг 1.2). Сравнить эти два варианта программы нс составит особого труда.
Ниже приведен список всех изменений.
1.	Упростилась основная часть процедуры (строки 17...25 листинга 1.3). Регистр г2 нам теперь не понадобится. Нам уже не нужно заниматься сдвигом кода выбора строки. Достаточно только подать номер столбца на линии РЗ.О и Р3.1.
2:	Изменились обе подпрограммы раздельного управления разрядами порта РЗ: clrU и setU. Теперь они должны работать не с четырьмя, а всего с двумя разрядами. Однако текст подпрограмм практически тот же. Отличается только значение маски в операции «И» (сравните строки 51 и 56 обоих вариантов программы).
3.	В связи с изменением способа подсчета номера столбца, изменилась процедура вычисления кода нажатой клавиши. Теперь регистр г1 содержит номер столбца в прямом виде. Поэтому команды, производящие вычисление номера столбца, убираются (см. строки 39...41).
24
Традиционные периферийные устройства
Рис. 1.4. Второй вариант подключения матрицы клавиш
Листинг 1.3
1	$mod2051
,------------------- Определение констант
2	ЬапкО	ECU	00000000В Кодь банков памяти
3	banki	ECU	0001000В
4	оапк2	ECU	00010000В
5	ЬапкЗ	ECU	00011000В
---- Резервирование ячеек памяти
6	DSEG
ORG 20Н	Начинаем резервирование с адреса 20Н
8	p3buf DS 1	Буфер порта рЗ
.---------- Начало прел раммною кода
Кнопки и датчики
25
9
10
11
12
13
14
1
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3
3
32
33
4
35
36
37
3
39
40
41
42
4
44
45
CSEG
0RG ООН	Начинаем программный код с адреса ООН
В этом месте вы должны поместить основной текст Bat"? "эограммы
ORG 20Н	Продолжаем программный . адрса 20Н
; л#########»############################
,И Подпрограмма опроса клавиатуры ##
			
klav:	push mov mov call mov mov	psw psw,#bank3 pl.ftOFFH clrU rO, #0 r1,#0	Сохранение регистра флагов в стеке Переключение на Ба к 3 регистров РОН Перевод Р1.0-Р1.7 в единичное состояние Перевод РЗ.О. РЗ 1 в единичное состояние Очистка буфера кода клавиши Инициализация счетчика столбцов
kl1:	call mov cjne	setU a,p1 a,#0FFH.kl3	Вывод кода в порт РЗ Считывание состояния клавиатуры Если клавиша нажо’1"’. ”трс?хс/,им к >.. у
kl2:		 Переход inc mov cjne	к следующему столбцу n	Увеличение счст-.и: а стот.б ов на а.П	Извлекаем в а дла правя/».' а #4к11	Если значение счет иж э < . а [Щвяо 4. продолжаем цикп (лег- хсд на кН)	
			клавиатуры Перевод в исходное состояние порта РЗ
klfin:	call	clrU	
	mov pop ret	а, гО psw	Запись в аккумулятор кода клавиши Восстановление регистра флагов Выход из программы
			в строке Инициализация счетчи i строк Обнуление признака переноса Сдвиг входного ч/да
kl3: kl4:	mov	r3,	#1 setb	c rrc	a		
kl5:	jnc inc jmp cjne mov jnz	kl5 гЗ kl4 a,#0FFH,kl6 а, rO kl6	Если нашли разряд, равны.: нулю, переи1.' • .5 Итерация счетчика строк Переход к началу цинга счета отрок Если еще есть хоть один ноль перейти и к!6 Не найдена ли уже другая нажатая кнопк. Если да, то перейти к |;’,Е
		 Вычисление номера клавиши mov	а.г1 rl	a rl	a rl	a add	a.r3		Запись номера столбца в аккумулятор операции вычитания, находившиеся ранее на этом месте убраны Три оператора сдвига (умножение на 8) Прибавлена номера строки
26
Традиционные периферийные устройства
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
к16
end
ClrU:
setU:
mov	rO.a	Записываем в буфер
jmp	kl2	Продолжаем поиск по остальным столбцам
mov	rO.trO	. Возвратить ноль
jmp	klfin	Перейти на конец процедуры
- Сброс	разрядов etc бцов	
mov	a.p3buf	Считывание содержимого буфера порта РЗ
orl	а,400000011В	, Перевод разрядов РЗ.О. РЗ 1 в единицу
mov	рЗЬиГ.а	Запись результата назад в буфер
mov	p3,p3buf	; Вывод содержимого буфера в порт РЗ
ret		
— Вывод	столбцов	
mov	а. рЗЬиГ	Считывание содержимого буфера порта РЗ
orl	а.400000011В	. Перевод разрядов РЗ.О, Р3.1 в единицу
anl	а,г2	Вывод в РЗ.О, Р3.1 кода сканирования
mov	рЗЬиГ а	Запись результата назад в буфер
mov	рЗ.рЗЬиГ	Вывод содержимого буфера в порт РЗ
ret
. Сюда вы можете поместить другие подпрограммы
Приведенные на рис. 1.3 и 1.4 схемы с успехом могут быть использованы для подключения большого количества простых контактных датчиков. Однако при таком подключении датчиков возникнет ряд ограничений. Главное из них — быстродействие. Если подключаемые таким образом датчики должны отслеживать быстроизменяющиеся процессы, матричная схема включения не сможет обеспечить надежную их работу. Связано это с тем, что опрос датчиков производится последовательно, поэтому обнаружение факта срабатывания датчика может быть надежным только в том случае, если минимальное время, в течение которого датчик находится в замкнутом состоянии, в несколько раз больше, чем время опроса всей матрицы клавиш.
1.3. Световые индикаторные устройства
Практически любое микропроцессорное устройство содержит элементы световой индикации. В качестве световых индикаторов
Световые индикаторные устройства	27
в настоящее время чаще всего применяются светодиоды. На рынке имеется огромный выбор светодиодов, самых разных видов и размеров. Легко можно купить светодиоды повышенной яркости, мигающие, двух- и даже трехцветные. Светодиоды выделяются среди других светоизлучательных элементов благодаря особой экономичности и долговечности.
В микропроцессорных устройствах световые индикаторы могут служить для отображения различных режимов работы: предупреждать о критических ситуациях, отражать ход приема управляющих сигналов. Подключить одиночный светодиодный индикатор к микропроцессору очень просто. На рис. 1.5 приведена схема подключения светодиода непосредственно к выводу порта процессора АТ89С2051.
Все выходные каскады микроконтроллера имеют достаточную нагрузочную способность для того, чтобы выдержать подключение одного светодиодного индикатора. Тут имеется в виду светодиод среднего и миниатюрного размера с током потребления в рабочем режиме не больше 20 мА. Если вы желаете подключить по такой схеме несколько светодиодов на несколько разных выходов микроконтроллера, то суммарный ток, проходящий через все эти выходы, не должен превышать 80 мА.
Рис. 1.5. Простейшая схема подключения светодиодного < индикатора
Рис. 1.6. Схема подключения светодиода посредством электронного ключа
Если нужно подключить индикатор большого размера или повышенной яркости, который потребует большего рабочего тока, придется применить буферный элемент. Одним из вариантов буферного
28
Традиционные периферийные устройства
элемента является электронный ключ. Схема подключения светодиода при помощи электронного ключа приведена на рис. 1.6.
Основой электронного ключа служит транзистор VT1. Резистор R1 — токоограничивающий в цепи базы. Резистор R2 служит для надежного запирания ключа при нулевом сигнале на выходе РЗ.О. Резистор R3 ограничивает рабочий ток светодиода. Его номинал может изменяться в зависимости от типа применяемого светодиода. Если в качестве VT1 использовать транзистор КТ315, схема способна обеспечивать рабочий ток светодиода до 250 мА.
Кроме максимально допустимого тока нагрузки, обе приведенные выше схемы отличаются способом управления. Схема, изображенная на рис. 1.5, с инверсным способом управления. Для того, чтобы зажечь светодиод, нужно подать на выход РЗ.О низкий логический уровень. Схема, изображенная на рис. 1.6, обеспечивает прямое управление. Для того, чтобы зажечь светодиод, включенный по этой схеме, на выход РЗ.О нужно подать сигнал логической единицы.
С программной точки зрения управление светодиодом, включенным по любой из двух вышеприведенных схем, не представляет никаких трудностей. Например, для того, чтобы установить линию РЗ.О в единичное состояние, процессор должен просто выполнить команду:
setb РЗ.О перевод бита РЗ 0 в единичное состояние
При этом в первом случае (рис. 1.5) светодиод потухнет, а во втором (рис. 1.6) — загорится. Для сброса сигнала в нулевое состояние достаточно подать команду:
clr РЗ 0 перевод бита РЗ.О в нулевое состояние
Для тех же целей можно использовать команды вывода в порт:
mov	РЗ.#1 перевод бита РЗ.О в единичное состояние
mov	РЗ.йО	 перевод бита РЗ.О в нулевое состояние
Однако в этом случае одновременно устанавливаются значения всех восьми разрядов порта РЗ. Иногда именно это и требуется.
Световые индикаторные устройства
29
Кроме одиночных световых индикаторов в микропроцессорных устройствах часто применяют знакосинтезируюшие матрицы, которые еще называют цифровыми индикаторами. Простейшим примером цифрового индикатора может служить так называемый ссмисегмснтный индикатор. Вам наверняка хорошо знаком та кой тип индикаторов. Он широко применяется в самых разных устройствах цифровой техники: от калькулятора, до электронных часов. Семисегментный индикатор представляет собой матрицу из семи светодиодов продолговатой формы, размешенных таким образом, чтобы, зажигая их в разных сочетаниях, можно было бы отобразить любую десятичную цифру (имеются в виду арабские цифры от 0 до 9). Кроме семи основных сегментов индикатор чаше всего дополняют восьмым маленьким сегментом, который предназначен для отображения десятичной точки (запятой). Расположив в рад несколько таких индикаторов, можно отображать любое десятичное число с плавающей запятой.
На рис. 1.7 изображен внешний вид семисегментного индикатора. В цифровой технике принято каждый сегмент индикатора обозначать буквой латинского алфавита так, как это показано на рисунке.
Рис. 1.7. Семисегментный цифровой индикатор
Такой индикатор обычно выполняется в виде отдельного самостоятельного компонента и имеет 9 выводов По внутренней схеме включения семисегментные индикаторы подразделяются на индикаторы с общим анодом и индикаторы с общим катодом.
30
Традиционные периферийные устройства
Схемы обоих видов индикаторов приведены на рис. 1.8 и рис. 1.9, соответственно. В первом случае на общий провод подается плюс источника питания, а во втором — минус Иногда семисегментный индикатор имеет К) выводов (общий вывод дублируется). Каждый из восьми светодиодов семисегментного индикатора можно подключать к выводам микропроцессора по любой из двух схем, приведенных в начале этого раздела (рис. 1.5 или рис. 1.6). Например, индикатор с общим анодом можно включить так, как показано на рис 1.10. В этой схеме использовано непосредственное подключение к выходам микропроцессора
Рис. 1.8. Схема индикатора с общим анодом
Рис. 1.9. Схема индикатора с общим катодом
Так же, как и для отдельных светодиодов, существует широкая гамма различных модификаций семисегментных индикаторов. Они отличаются друг от друга размерами, цветом свечения, яркостью, расположением выводов Сущест вуют двухцветные семисегментные индикаторы, многоразрядные матрицы и так далее. Применение простейших цифровых светодиодных индикаторов — самый недорогой способ заставить ваше микропроцессорное устройство отображать цифры.
Рис. 1.10. Подключение семисегментного индикатора
Световые индикаторные устройства
31
Итак, со схемой, надеюсь, все понятно. Теперь давайте посмотрим, как происходит управление семисегментным индикатором на программном уровне- Пример обслуживающей процедуры для индикатора, включенного согласно рис. 1.10, приведен в листинге 1.4.
Процедура представляет собой подпрограмму prind, занимающую строки 8...19. Для работы подпрограммы необходимо зарезервировать в битовой области памяти микроконтроллера одну ячейку для хранения одного бита информации. Подпрограмма использует эту ячейку в качестве буфера десятичной точки. В строках I...6 листинга показан фрагмент начала программного кода, в который, в частности, включены псевдооператоры, резервирующие такую ячейку под буфер точки (строки 2...4). Буферу присваивается метка bufT.
Оператор ORG 20Н (строка 7) принудительно устанавливает адрес начала подпрограммы prind равным 20Н. Это не обязательный оператор и приведен просто для примера.
Листинг 1.4
Программа вывода на семисегментный индикатор
1	$mod2051
;------------------- Резервирование ячеек
2	BSEG	. Команда перехода к битовому сегменту
3	ORG 0	, Начинаем с начала сегмента
4	bufT:	DBIT 1	; Буфер десятичной точки
------------ Начало программного кода
5	CSEG	; Команда перехода к программному сегмен,у
б	ORG ОН	. Начинаем с начала сегмента
; В этом месте вы должны поместить основной текст вашей программы
7	ORG 20Н	: Продолжаем с адреса 20Н
;и Вывод на семисегментный индикатор п
8	prind:	push psw	: Сохранение регистра PSW в стеке
32
Традиционные периферийные устройства
5	push	DPH	Сохранение регистра DPTR в стеке (стари )
10	push	DPL	(млады половина)
11	mov	DPTR «zg	Загрузка начала таблицы знакогенератора
12	move	a,@a+DPTR	, Считывание кода цифры в аккумулятор
13	mov	c.bufT	Считывание буфера точки
14	mov	acc 7,c	Запись значения точки в старший разряд
15	mov	p1, a	; Вывод полученного кода в порт Р1
16	pop	DPI	; Восстановление регистра DPTR (младш.)
17	pop	DPH	. (стары, половина)
18	pop	psw	; Восстановление регистра psw
19	ret		; Выход из подпрограммы
	Сюда вы можете	поместить другие	подпрограммы.
20	ORG	0700H	: Программа продолжается с адреса 700Н
		—		 Знакогенератор
21	zg:	OB	11000000В	Символ 0
22	OB	11111001В	Символ 1
23	OB	10100100В	Символ 2
24	DB	10110000В	Символ 3
25	DB	10011001В	Символ 4
26	DB	10010010В	Символ 5
27	OB	10000010В	Символ 6
28	DB	11111000В	Символ 7
29	OB	10000000В	Символ 8
30	DB	10010000В	Символ 9
31	end		
Теперь перейдем к описанию принципа работы подпрограммы prind. Основная программа вызывает процедуру prind каждый раз, когда нужно вывести какую-либо новую цифру на индикатор. При этом в процедуру передаются два параметра: код цифры и состояние десятичной точки. Код цифры передается через аккумулятор, а состояние десятичной точки через буфер bufT. Говоря проще, основная программа сначала помешает код цифры в аккумулятор. Чтобы высветить «О», в аккумулятор помещается код ООН. Чтобы высветить «1», туда помещается 01Н. И так далее. Затем основная программа устанавливает значение буфера bufT. Если точка должна гореть, в буфер помещается единица. В противном случае, туда помещают ноль. И только после этого вызывается подпрограмма prind. Текст, производящий все эти действия, мы не приводим. Надеюсь, все и так ясно.
Световые индикаторные устройства
33
Теперь займемся самой подпрограммой (см. листинг 1.4). Посмотрите на ее текст. Большую часть текста занимают операторы, которые сохраняют в стеке, а затем восстанавливают содержимое регистров psw и DPTR. Именно эти два регистра в строках 11...15 подвергаются изменению. Строки 8... 10 — это команды сохранения регистров, а строки 16... 18 — команды восстановления. Сохранение и восстановление регистров рекомендуется всегда использовать в любых универсальных подпрограммах. Его применение гарантирует, что вызываемая подпрограмма оставит неизменным содержимое всех регистров и тем самым не нарушит работу других подпрограмм.
Алгоритм работы подпрограммы prind очень прост. Он сводится к перекодировке. Подпрограмма получает код числа, которое нужно вывести на индикатор. Получив код, подпрограмма должна записать в порт индикатора (порт Р1) другой код, который включит нужные светодиоды и отключит ненужные. В результате семисегментный индикатор должен высветить требуемую цифру. Для перекодировки используется таблица символов. Таблица символов — это цепочка кодов в программной памяти микроконтроллера, соответствующих выводимым символам. Таблица создается в программной памяти при помощи операторов DB.
Фрагмент программы, создающей таблицу символов, вы можете видеть в строках 20...30. Для наглядности, коды, записываемые в таблицу, приведены в двоичном виде. Таблица начинается с адреса 700Н, что определяется псевдооператором OGR в строке 20. Вы можете выбрать любой другой адрес. Началу таблицы присваивается метка zg. В первую ячейку таблицы записывается код, соответствующий символу «0». Во вторую — код символа «1». Где же взять эти коды? Их легко определить! Нужно внимательно посмотреть на схему (рис. 1.10) и представить значение каждого разряда. В этом вам также поможет рис. 1.7. Например, для того, чтобы высветить на индикаторе символ нуля, нужно включить сегменты a, b, с, d, е и f. Сегмент g нужно выключить. В соответствии со схемой на рис. 1.10 код на выходе порта Р1 при этом должен быть равен 11000000В (для зажигания сегмента на выход соответствующего разряда нужно подать ноль). Таким же образом определяются и остальные коды таблицы.
Основная часть программы работает следующим образом: сначала в регистр DPTR помещается адрес начала таблицы (строка 11), за-
2 Зак. 922
34
Традиционные периферийные устройства
тем извлекается код из таблицы. Для этого используется оператор move (строка 12). Этот оператор извлекает байт данных из программной памяти и помешает его в аккумулятор. Адрес ячейки, из которой извлекается байт, находится как сумма содержимого регистра DPTR и содержимого аккумулятора. До начала операции move в аккумуляторе находится код символа. В результате, после выполнения команды move в аккумуляторе оказывается тот элемент таблицы символов, порядковый номер которого равен коду символа. Далее к полученному коду добавляется значение десятичной точки (сегмент 11). При этом в качестве промежуточного хранилища используется ячейка признака переноса CY. Значение точки извлекается из буфера bufT (строка 13). А затем помещается в седьмой разряд аккумулятора (строка 14). Полученный таким образом код выводится в порт Р1 (строка 15). Этот код поступает на индикатор, на котором и высвечивается требуемый символ.
Для отображения цифровых данных одного цифрового индикатора обычно недостаточно. В таких случаях к микроконтроллеру подключают сразу несколько таких индикаторов. Однако, из-за отсутствия достаточного количества выводов у процессора приходится применять специальные ухищрения. На рис. 1. 11 изображена типичная схема подключения четырех семисегментных индикаторов к микроконтроллеру. Как видно из рисунка, индикаторы, включенные по такой схеме, не могут работать все одновременно. Если их включить одновременно, то все они будут отображать одно и то же. Схема, изображенная на рис. 1. 11, предназначена для работы индикаторов в режиме динамической индикации
Режим динамической индикации часто применяется для многоразрядных цифровых индикаторов. Он состоит в том, что разряды индикатора работают не одновременно, а по очереди. Переключение разрядов происходит с большой скоростью Если скорость переключения разрядов достаточно велика, то человеческий глаз не замечает того, что разряды горят по очереди. Мерцания сливаются в статическую картинку, и человек видит цифры одновременно во всех разрядах. Подобный эффект используется в кино и в телевидении. Там, сменяющиеся с большой скоростью кадры сливаются в одно непрерывное изображение. Ученые давно определили тот предел скорости смены кадров, при которой глаз человека уже не различает дискретности. Этот предел равен 24 кадрам в секунду. Если кадры на экране менять с этой скоростью, то они сливаются в плавно движущееся изображение. Однако для глаза такое
Световые индикаторные устройства
35
изображение не будет комфортным. Мы не увидим дерганья при смене кадров, но просмотру будет мешать неприятное мерцание. Эффект мерцания возникает от того, что в промежутках между кадрами экран темный, а в момент отображения кадра экран ярко освещен. Глаз способен воспринимать такое изменение общей яркости и это мерцание неприятно для зрения. Для того, чтобы мерцание было незаметно, частота смены яркости экрана должна быть, как минимум, в два раза выше. То есть должна быть не менее 48 Гц. В кино это достигается введением дополнительного затемнения экрана посреди каждого кадра. В телевидении для устранения этого эффекта придумана чересстрочная развертка. Каждый кадр выводится в два приема: сначала нечетные строки, а затем — четные.
Работа цифрового индикатора в режиме динамической индикации очень напоминает смену кадров в кино или телевидении. В каждый момент времени работает только один разряд. И каждый разряд показывает свою цифру. Разряды включаются по очереди, начиная с первого и заканчивая последним. Затем все начинается сначала. Такой способ работы индикатора имеет только одно преимущество: он позволяет экономить выводы микропроцессора и количество управляющих элементов (ключей). Представьте, что мы решили бы подключить четыре семисегментных индикатора в обычном статическом режиме. То есть, каждый из них подключен по схеме, изображенной на рис. 1.10. Тогда нам потребовалось бы 32 линии ввода/вывода или четыре порта. А если понадобится подключить более мощные индикаторы, которые не смогут работать без применения управляющих ключей, то нам понадобится собрать еще и 32 схемы, подобные той, которая изображена на рис. 1.6.
А теперь взгляните на рис. 1.11. Выводы одноименных сегментов всех разрядов индикатора объединены вместе и подключены к порту Р1 микроконтроллера. При этом линия Р1.0 управляет сегментом «а» каждого индикатора, линия Р1.1 — сегментом «Ь». И так далее. Возможность поочередного выбора сегментов обеспечивается при помощи дешифратора DD2 и четырех транзисторных ключей VTI...VT4. На вход дешифратора поступает управляющие сигналы с выводов РЗ 0 и Р3.1. Подавая на эти выходы код номера разряда (от 00В до 11В), микроконтроллер может включать соответствующий разряд. При этом все остальные разряды окажутся выключены.
Работает схема очень просто. Специальная программа, реализующая работу динамической индикации, постоянно перебирает разряды
36
Традиционные периферийные устройства
индикатора и выводит на каждый из индикаторов соответствующий символ. Такая программа должна работать в фоновом режиме, независимо от остальных программ, выполняемых процессором. Это достигается применением режима прерываний по таймеру. При переборе разрядов индикатора микроконтроллер сначала подает номер очередного разряда на выходы РЗ.О, Р3.1. Затем, на всех выходах порта Р1 устанавливается код, соответствующий выводимому символу. Символ появляется на соответствующем индикаторе. Затем отрабатывается задержка по времени. Назовем ее периодом смены разрядов (tcvip). По истечении времени tcvip микроконтроллер производит смену индицируемого разряда. Для этого он сначала подает код нового разряда на линии РЗ.О, Р3.1. А затем выводит в порт Р1 код, соответствующий символу, который в этом новом разряде должен отобразиться. Время между моментами переключения разрядов должно быть всегда одинаковым и равным tCMp. Иначе свечение разрядов получится неравномерным по яркости.
Рассмотрим теперь один из вариантов управляющей программы, предназначенной для работы с описанной выше схемой (см. листинг 1.5). В качестве примера используется упрошенная программа электронных часов, использующая индикаторы для отображения текущего времени. Для того, чтобы обеспечить работу динамической индикации в фоновом режиме, программа использует систему прерываний. По этой причине программа состоит из двух частей: модуля инициализации (строки 32...44) и процедуры обработки прерывания dind (строки 45...98). Программа инициализации выполняется один раз, сразу после включения питания. Она настраивает один из внутренних таймеров микроконтроллера таким образом, чтобы тот непрерывно, с периодом, равным tCMP, вызывал процедуру обработки прерывания (dind). Затем микроконтроллер переходит к выполнению основной программы (в листинге не показана). В случае электронных часов основная программа может сводиться к периодическому сравнению текущего времени с временем срабатывания будильника и включению исполнительного механизма при их совпадении. Кроме того, нужно выполнять команды по установке времени, включению и выключению будильника и т.п. Для этого схему придется дополнить клавиатурой.
В то время, когда процессор занят выполнением основной программы, работает запущенный вначале внутренний таймер. Он отсчитывает промежуток времени, равный tCMP. Отсчитав этот промежуток времени, таймер вызывает прерывание основной про
Световые индикаторные устройства	37
граммы и вызов процедуры dind. Процедура производит смену разрядов индикации и возвращает управление основной программе. При этом происходит перезапуск таймера, и отсчет времени возобновляется. Отсчитав следующий период, таймер снова вызывает процедуру обработки прерывания. И так продолжается постоянно, пока включено питание.
Рис. 1.11. Схема включения четырех семисегментных индикаторов с динамической индикацией
Рассмотрим подробнее работу процедуры dind При первом вызове она подает на выходы РЗ.О, Р3.1 код 00В и включает, таким образом, индикатор HL1. Через порт Р1 программа высвечивает на
38
Традиционные периферийные устройства
индикаторе значение десятков часов. В таком состоянии индикатор остается вплоть до следующего момента срабатывания таймера. При очередном вызове процедуры dind она изменяет код на выходах РЗ.О, РЗ. 1 и он становится равным 01В. Включается индикатор HL2. Затем процедура изменяет информацию на выходах порта Р1 и на индикатор выводится значение единиц часов. При следующем вызове процедуры dind она таким же образом включит индикатор HL3 и выведет на него значение десятков минут. А при четвертом срабатывании на индикатор HL4 будет выведено значение единиц минут. Однако, работа таймера продолжается. Осчитав очередной период времени, равный tCMl„ таймер снова вызовет процедуру dind. На этот раз счетчик разрядов будет сброшен в ноль и программа снова включит индикатор HLI. Таким образом, этот процесс выполняется непрерывно, и через равные промежутки времени происходит переключение индицируемых разрядов.
Важный этап при разработке подобной программы — определение коэффициента деления для нашего таймера. Как уже было сказано выше, оптимальной частотой смены «кадра» для динамически изменяющегося изображения является величина 48 Гц. Округлим эту величину и выберем частоту смены изображения для динамической индикации 50 Гц. Одним «кадром» в нашем случае можно считать поочередное включение всех четырех разрядов индикатора. Поэтому частота переключения разрядов будет равна 50 х 4 = 200 Гц Наш таймер должен формировать сигналы прерывания именно с этой частотой. Теперь нам необходимо найти коэффициент пересчета таймера. Прежде, чем это сделать, нам нужно разобраться, как он работает. Интегрированные таймеры микросхемы АТ89С2051 имеют несколько режимов работы. Используем для динамической индикации таймер ТО. Для нашего случая таймер удобно перевести в режим подсчета внутренних тактовых импульсов. Внутренние тактовые импульсы формируются из сигнала тактового генератора микроконтроллера путем деления его частоты на 12 (подробнее см. в [1]). Таймер производит подсчет этих импульсов. Причем подсчет ведется в прямом направлении. Это значит, что при поступлении каждого очередного импульса содержимое регистра ТО увеличивается на единицу. При достижении максимального значения таймер переполняется. Если система прерываний включена, то сигнал переполнения таймера произведет вызов прерывания. Для того, чтобы таймер сформировал нужную нам задержку по времени, при его запуске в регистр ТО нужно записать некоторое начальное
Световые индикаторные устройства
39
значение. При этом задержка по времени будет определяться количеством импульсов, которое должно поступить на вход таймера прежде, чем он переполнится. После того как таймер сработает и вызовет процедуру обработки прерывания, эта процедура должна перезапустить таймер, то есть снова записать в регистр ТО коэффициент пересчета. Итак, коэффициент пересчета таймера напрямую определяется его начальным значением, записываемым в регистр таймера перед началом его работы.
Для того, чтобы найти необходимое нам начальное значение, сначала определим требуемый коэффициент пересчета таймера. Для этого нужно выбрать частоту кварцевого генератора. Напомним, что кварц подключается по схеме, приведенной на рис. 1.1. Микросхема АТ89С2051 допускает подключение кварцевого резонатора с частотой резонанса до 24 МГц. В данном случае на частоту кварца нет строгих ограничений. Все же желательно выбирать ее повыше. Для простоты расчетов выберем кварц с частотой 12 МГц. При этом на вход таймера будут поступать импульсы с частотой 12/12 = 1 МГц (10б Гц). Учитывая, что частота смены разрядов динамической индикации должна быть равна 200 Гц, коэффициент пересчета нашего таймера должен быть равен 106/200 = 5000. Теперь можно найти начальное значение для записи в регистр таймера. Этот регистр содержит 16 двоичных разрядов, а значит, максимальное значение регистра, при котором происходит его переполнение равно 0FFFFH. В десятичном формате это число равно 65535. Отсюда находим начальное значение: 65535 - 5000 = 60535. Это значение мы и будем использовать в нашей программе.
Теперь приступим к детальному изучению текста программы динамической индикации. Посмотрите на листинг 1.5. Приведенный фрагмент программы под названием «Часы» не только реализует процедуру динамической индикации текущего времени, но и реализует «ход» часов. Для реализации функции «хода» используется то же самое прерывание, которое реализует режим динамической индикации.
В начале листинга (строки 1...18) показано, как определяются переменные и резервируются ячейки для всех последующих процедур. С некоторыми элементами этой части программы мы уже знакомы. Например, мы уже встречались с определением констант для выбора банков РОН (строки 2...5) и с резервированием буфера для десятичной точки bufT (строка 9). В строке 6 определяется константа ktdi.
40
Традиционные периферийные устройства
которая используется при инициализации таймера. Константе присваивается вычисленное выше значение: 60535. Зарезервированные ячейки timsec, timdop и tim используются при подсчете текущего времени. Ячейку nomR использует процедура динамической индикации для хранения номера текущего индицируемого разряда.
Листинг 1.5
Программа «Часы»
1	$mod2051			
		—	— Определение констант	
2	bankO	EOU	оооооооов	: Коды банков памяти
3	bankl	EOU	00001000В	
4	bank2	EOU	00010000В	
5	ЬапкЗ	EOU	00011000В	
6	kt di	EOU	60535	Начальное значение для таймера
	—		- Резервирование	ячеек
7		BSEG		В битовой области памяти
8		ORG	0	
9	bufT:	OBIT	1	Буфер десятичной точки
10		DSEG		В обычной памяти данных
11		ORG	25Н	
12	timsec:	OS	1	Счетчик секунд (/60)
13		ORG	зон	
14	timdop:	OS	1	Дополнительный счетчик (/200)
15	tim:	DS	4	Основной счетчик времени
16	nomfi:	OS	1	Номер текущего разряда
17		ORG	60Н	начало стека
18	stack.	DS	20Н	глубина стека
				
			Начало программного кода	в#	
	ШШШтШВДШтШШШттШИИИИШШИ			
19		CSEG		
20		ORG	ООООН	к процедуре инициализации
21		jmp	init	после включения/сброса
22		ORG	0003Н	переопределение вектора
23		reti		внешнего прерывания 0
24		ORG	ооовн	переопределение вектора
25		jmp	dnind	прерывания по таймеру 0
26		ORG	0013Н	переопределение вектора
27		reti		внешнего прерывания 1
28		ORG	001ВН	переопределение вектора
29		reti		прерывания по таймеру 1
Световые индикаторные устройства
41
30 31	ORG reti	0023H	вектор прерывания по последовательному каналу
		Инициализация	
32	ORG	0030H	
33	Init;	mov	sp, If (stack-1)	Установка вершины стека
34	mov	rim.#0	Обнуление разрядов
35	mov	tim+1, flO	счетчика времени
36	mov	tim+2. #0	
37	mov	tim+3 tO	
38	mov	nomR.uO	
		Программирование таймера	
J9	mov	THOD.#000000016	Выбор режима работы таймеров
40	mov	THO,«(high ktdi)	Период срабатывания прерывания
41	mov	TLO #(low ktdi)	
42	mov	IE #100000106	Наска прерываний
43	mov	IP. #000000106	Установка приоритетов
44	mov	TOON,#000100006	Разрешение счета таймеров
main:
В этом месте вы должны поместить основной текст вашей программы
.S#####################################################
	.##	Обработка прерывания от таймера		##
	#########################«#########################«#и			
45	dnind:	push	ACC	
46		push	PSW	
47		mov	PSW.#bank1	Выбор банка 1
48		mov	THO. «(high ktdi)	Период срабатывания прерываний
49		mov	TIC, «(low ktdi)	
		—		 бывод на индикатор	
50		mov	a.nomR	Вывод номера разряда
51		rrc	Q	
52		mov	рЗ.О.с	Младший бит
53		rrc	a	
54		mov	p3.1,c	Следующий бит
				Вывод точки
55		mov	a.nomR	
56		cjne	a,#1.dn1	Проверка номера разряда
57		mov	c,timsec 0	Мерцание точки
53		jmp	dn2	
59	dnl:	setb	c	Точку выключаем
60	dn2:	mov	bufT.c	Помещаем результат в буфер гички
				Вывод символа
61		aod	a, «tin'	Вычисляем адрес в буфере
62		mov	rO.a	
42
Традиционные периферийные устройства
63	mov		a.grO	Чтение кода символа из буфера
64		call	print)	вывод на индикатор
65		inc	nomR	Увеличение номера текущего разряда
66		mov	a.nomR	
67		cjne	1, #4, t)n3	, Это последний разряд?
68	dn3:	mov	notnR, #0	; Если да, то перейти на первый
		—		Делитель на 200
69		inc	timdop	
'0		mov	a.timdop	
71		cjne	a, #200,dniF	
72		mov	timdop,#0	Счет секунд
73		inc	timsec	
74		mov	a.timsec	
75		cjne	a #60 dniF	
76	-		mov	timsec,#0	— Счет основного таймера
77		inc	tim+3	Единицы минут
78		mov	a nm+3	
79		cjne	a,#10.dniF	
80		mov	tim+3. #0	
81		inc	tim+2	Десятки минут
82		mov	a,tim+2	
83		cjne	a.#6,dniF	
84		mov	tim+2,#0	
85		inc	tim+1	Единицы часов
86		mov	a,tim+1	
87		cjne	a,#4,dn4	
88		mov	a,tiro	
89		cjne	a,#2.dniF	
90		mov	tim,#0	
91		mov	tim+1. #0	
92		jmp	dniF	
93	dn4:	cjne	a,#10 dniF	
94		mov	tim+1. #0	
95		inc	tim	Десятки часов
	dniF'.	—	— Завершающие команды	
96		pop	PSW	
97		pop	ACC	
98		reti		
Сюда должна быть помещена подпрограмма print) (см. Листинг 1 4)
Сюда же вы можете поместить другие подпрограммы
end
Световые индикаторные устройства	43
В строках 19 ..31 находится новый для нас программный модуль Такой модуль обычно включается в любую программу для микроконтроллера АТ89С2051. Его назначение — переопределение векторов прерывания. Что же такое, эти векторы прерывания? И зачем их переопределять? Как известно, микросхема АТ89С2051 имеет пять встроенных источников прерываний. За каждым из этих источников в программной памяти закреплен свой фиксированный адрес. Ниже перечислены все эти особые адреса.
0003Н — прерывание от внешнего входа INTO;
000BH — прерывание по переполнению таймера ТО;
001ЗН — прерывание от внешнего входа INT1;
001ВН — прерывание по переполнению таймера Т1;
0023Н — прерывание по последовательному каналу.
Особые адреса используются при вызове процедуры обработки прерывания. Например, в нашем случае будет использоваться прерывание по переполнению таймера ТО. Как только регистр таймера переполнится, сработает система прерывания. Она приостановит выполнение основной программы и передаст управление по адресу 000BH. По этому адресу нужно расположить команду безусловного перехода. В нашем случае — это команда jmp dnind (строка 25 программы). Повинуясь этой команде, процессор выполнит переход по метке dnind, где и находится процедура обработки прерывания.
Особые адреса, закрепленные за каждым видом прерывания, называются векторами прерываний. А применение команды перехода называется переопределением вектора прерывания В нашей программе переопределение требует лишь один вектор прерывания. Остальные прерывания не используются. Однако, я настоятельно рекомендую поставить на каждый из неиспользуемых векторов своеобразную программную «заглушку». «Заглушка» представляет собой всего одну команду. Это команда выхода из подпрограммы обработки прерывания (reti). Наличие «заглушек» минимизирует отрицательные последствия в том случае, если вы допустите программную ошибку. Если в результате ошибки произойдет случайный вызов ненужного нам прерывания, то ничего страшного не произойдет. Вызванное по ошибке прерывание сразу же и завершится.
44
Традиционные периферийные устройства
Адрес 0000Н тоже можно считать особым Именно с этого адреса всегда начинается выполнение программы после включения питания или сразу после сброса. Тут нам тоже придется поставить команду безусловного перехода для того, чтобы «перепрыгнуть» область специальных адресов. В нашем случае осуществляется переход по метке init (см. строку 21). Программный модуль init — это начало основной программы. Он начинается с адреса ЗОН и служит для инициализации всех необходимых переменных и настройки режимов работы микроконтроллера.
Инициализация переменных начинается с установки вершины программного стека (строка 33). Затем происходит присвоение нулевого значения всем разрядам основного счетчика времени (строки 34...37). В результате, после включения отсчет времени начинается с нуля. Нулевое значение присваивается также и указателю текущего индицируемого разряда nomR (строка 38). Поэтому процесс динамической индикации начинается с разряда номер ноль (индикатор HL1 на рис. 1.11). На этом инициализация переменных заканчивается
Следующий этап — настройка режимов работы. Настройкой режимов занимается программный модуль, расположенный в строках 39...44. Модуль служит для программирования таймера и настройки системы прерываний. Начинается настройка с выбора режима работы таймера. Для этого в регистр TMOD записывается код 00000001В. Этот код переводит таймер ТО в режим подсчета внутренних импульсов. Затем в таймер записывается начальное значение ktdi, которое мы вычисляли в начале этого раздела. Регистр таймера ТО имеет шестнадцать разрядов. Однако запись всех шестнадцати разрядов одновременно система команд микроконтроллера не предусматривает. Для чтения и записи информации регистр ТО разделен на две половинки. Старшая половинка регистра ТО называется ТНО. Младшая половинка — TLO Запись константы производится в два приема. Сначала старшие 8 бит константы записываются в регистр ТНО (строка 40). Затем младшие 8 бит записываются в регистр TLO (строка 41). Для определения значений старшей и младшей частей константы используются псевдооператоры high и low.
В строке 42 определяется маска прерываний. Маска — это число, которое записывается в регистр IE микроконтроллера. Каждый бит этого числа разрешает или запрещает работу одного из внутренних источников прерываний микроконтроллера. В нашем случае значе
Световые индикаторные устройства
45
ние маски равно 10000010В. Единица в старшем разряде разрешает работу всей системы прерываний. Единица в предпоследнем разряде разрешает прерывание от таймера ТО.
В строке 43 происходит установка приоритетов. Число, записанное в регистр 1Р микроконтроллера, определяет приоритет обслуживания прерываний в том случае, если два или больше прерываний были вызваны одновременно. Каждый бит этого числа определяет приоритет одного из видов прерываний. В нашем случае используется только один источник прерываний. Поэтому установка приоритетов нс имеет никакого смысла. Однако, на всякий случай, для прерывания от таймера установлен высокий приоритет.
Заканчивается процесс настройки режимов работы программированием регистра TCON. Регистр TCON служит для оперативного управления таймерами. В строке 44 в него записывается код, разрешающий работу таймера ТО. Сразу после этой команды таймер ТО начнет отсчет времени. Одновременно продолжится выполнение основной программы (метка main). Текст программы main вы можете написать самостоятельно. Если это вызывает затруднения, обратитесь в Интернет, на специальный сайт [8W], созданный для поддержки этой книги. Там вы найдете полную версию программы «Часы». Подробнее о системе прерываний микроконтроллера АТ89С2051 вы можете посмотреть в [1].
Теперь перейдем к процедуре dnind. Текст процедуры начинается со строки 45 и заканчивается строкой 98. Строки 45, 46 — это сохранение рабочих регистров в стеке. Строка 47 — выбор банка РОН. Выбирается банк номер один. Этот банк мы будем использовать исключительно для процедуры динамической индикации. Основной текст процедуры начинается с перезапуска таймера ТО. Для перезапуска в регистр таймера записывается его начальное значение (строки 48, 49). Сразу после перезапуска таймер начнет формирование следующего временного интервала. А выполнение процедуры обработки прерывания тем временем продолжается. Следующее ее действие — вывод на индикатор текущего разряда. Номер текущего разряда находится в ячейке nomR. Для вывода разряда программа выполняет следующие действия: подаст номер разряда на входы дешифратора DD2, затем записывает в порт Р1 код, зажигающий на индикаторе нужную цифру.
Вывод на дешифратор номера текущего разряда происходит в строках 50...54. Для управления дешифратором используется все
46
Традиционные периферийные устройства
го две линии (РЗ.О и Р3.1). Поэтому нам не нужно выводить все число. Достаточно вывести два младших бита. Для передачи битов используется метод сдвига. Сначала номер текущего разряда помещается в аккумулятор (строка 50). Затем производится сдвиг вправо содержимого аккумулятора через признак переноса (строка 51). В результате, младший бит кода окажется в ячейке CY. В строке 52 этот бит выводится в линию РЗ.О. Далее производится следующий сдвиг (строка 53). Затем второй бит выводится в линию Р3.1 (строка 54). Таким образом, два младших бита номера текущего разряда из nomR поступают на адресные входы дешифратора DD2. В результате на вывод общего анода выбранного индикатора поступает напряжение +5 В от источника питания.
Теперь можно приступать к высвечиванию цифры. Для вывода цифр использована подпрограмма prind (см. листинг 1.4). Она подходит нам без каких-либо изменений. Перед вызовом подпрограммы prind необходимо поместить в аккумулятор код выводимого символа, а в буфер bufT — состояние десятичной точки. В программе «Часы» индикатор должен отображать текущее время. Значение времени находится в буфере tim. Буфер занимает четыре ячейки памяти. В каждой ячейке находится значение своего разряда времени.
Ячейка с адресом tim — хранит десятки часов;
Ячейка с адресом tim+1 — единицы часов;
Ячейка с адресом tim+2 — десятки минут;
Ячейка с адресом tim+З — единицы минут.
Нам нужно просто извлечь число из соответствующей ячейки буфера tim и вывести его на индикатор. Однако прежде нам нужно позаботиться о выводе на индикатор десятичной точки. Точку удобно поставить между изображением часов и минут, то есть в разряде номер 1 (индикатор HL2). Как принято в электронных часах, заставим точку мигать с периодом в одну секунду. Для создания эффекта мигающей точки воспользуемся ячейкой tims-ес. Она используется в программе для подсчета секунд. Процесс подсчета секунд будет описан чуть позже. Сейчас нам достаточно знать, что младший бит ячейки timsec каждую секунду изменяет свое значение. Этот факт и используется для создания эффекта мигания точки.
Световые индикаторные устройства
47
Управления свечением десятичной точки происходит в строках 55...60. Сначала проверяется значение переменной nomR (номер текущего разряда). Мигание точки разрешается только в разряде номер один. Для проверки этого условия номер разряда из буфера nomR помещается в аккумулятор (строка 55). Затем он проверяется на равенство единице (строка 56). Если код не равен единице, то управление передается по метке dn1 и в буфер bufT записывается сигнал выключения точки (строки 59, 60). Если номер текущего разряда равен единице, то перехода не происходит и выполняется алгоритм мерцающей точки. Для этого в буфер bufT просто помещается значение младшего бита ячейки timsec (строки 57, 58, а затем 60). В результате в течение первой секунды точка горит, в течение последующей не горит. И так далее.
Разобравшись с выводом точки, переходим к коду символа. Мы должны извлечь код символа из соответствующей ячейки буфера tim и поместить его в аккумулятор. Фрагмент программы, извлекающей нужный код из буфера, занимает строки 6!.. 63. Начинается этот фрагмент с вычисления адреса ячейки, из которой будем извлекать код. Для этого, к адресу начала буфера tim прибавляется код текущего индицируемого разряда (nomR). Так как значение nomR уже находится в аккумуляторе, программа просто прибавляет к нему константу, равную tim (строка 61). Знак # перед именем буфера tim означает, что в качестве второго слагаемого команды add выступает не содержимое ячейки с адресом tim, а сам этот адрес. Далее полученная сумма отправляется в регистр гО (строка 62). Регистр гО используется для извлечения кода из буфера tim в режиме косвенной адресации (строка 63). Теперь, когда код символа получен, можно вызывать подпрограмму prind, что и делается в строке 64.
После того, как очередная цифра высветилась на индикаторе, программа приступает к вычислению нового значения ячейки nomR. Это нужно для того, чтобы при следующем вызове процедуры dnind она выводила уже другой разряд индикатора. Сначала содержимое ячейки nomR увеличивается на единицу (строка 65). Затем проверяется, не последний ли это разряд. Для проверки содержимое nomR помешается в аккумулятор (строка 66). Далее программа проверяет, не равно ли полученное число четырем (строка 67). Если равно, то в ячейку nomR записывается ноль (строка 68). В результате, код номера разряда меняется от 0 до 3, а затем все опять начинается с нуля.
48
Традиционные периферийные устройства
Дальнейшие операции уже не связаны с динамической индикацией. Со строки 69 начинается подсчет текущего времени. Способ подсчета времени основан на том, что процедура dnind вызывается через строго фиксированные промежутки времени. Частота вызова процедуры постоянна и равна 200 Гц. Счетчик текущего времени удобно реализовать путем подсчета количества вызовов подпрограммы. Посмотрите на строки 69...72 листинга. В них реализован программный делитель на 200. Рассмотрим как он работает. При каждом вызове процедуры прерывания dnind программа сначала выполняет описанные выше команды динамической индикации и, в конце концов, доходит до строки 69. Здесь и организован подсчет количества вызовов. Для этого оператор inc увеличивает на единицу содержимое ячейки timdop (строка 69).
При каждом вызове процедуры происходит лишь однократное увеличение этого счетчика. Затем, в строках 70 и 71 происходит проверка нового значения. Если значение счетчика еще не достигло 200, то все остальные команды нс выполняются и управление сразу передается в конец процедуры по метке dniF (строка 71). В результате 199 вызовов подпрограммы будут лишь увеличивать содержимое счетчика. И лишь двухсотый вызов не вызовет этого перехода. Содержимое счетчика timdop обнуляется (строка 72) и управление передастся к строке 73. Таким образом, строка 73 будет выполняться только один раз за 200 вызовов процедуры dnind. То есть один раз в секунду! Как видите, очень легко программным путем мы реализовали делитель на 200 и получили на его выходе секундные импульсы. Такой принцип лежит в основе всех остальных делителей. Секунды делятся до минут. А дальше похожим способом ведется подсчет всех четырех разрядов текущего времени.
Программа подсчета секунд занимает строки 73...76. Коэффициент деления этого программного счетчика равен 60. Для хранения результата используется ячейка timsec. Как используется младший разряд этой ячейки для организации эффекта мигания десятичной точки, мы уже видели.
Строки 77...80 занимает счетчик единиц минут. Его коэффициент деления равен 10, а для хранения результата используется последняя ячейка буфера tim, адрес которой равен tim+З. Содержимое этой ячейки в процессе динамической индикации выводится на индикатор HL1. Счетчик, организованный в строках 81...84, служит для подсчета десятков минут. Его коэффициент деления равен 6
Световые индикаторные устройства	49
и результат хранится в ячейке с адресом tim+2. Содержимое этой ячейки выводится на индикатор HL2.
В строках 85...95 организован самый сложный счетчик — счетчик на 24. Он состоит, во-первых, из счетчика единиц часов, который имеет коэффициент деления равный 10. Результат подсчета хранится в ячейке с адресом tim+1 и выводится на индикатор HL3. С ним жестко связан счетчик десятков часов. Подсчетом десятков часов занимается всего одна строка программы (строка 95). Результат подсчета хранится по адресу tim и выводится на индикатор HL4. Оба этих счетчика охвачены общей процедурой сравнения, которая сбрасывает значение обоих счетчиков в ноль при достижении ими значения, соответствующего 24 часам. Проверка на 24 производится в строках 86...89. В строках 90, 91 производится обнуление обоих счетчиков при достижении значения 24. В строке 93 производится проверка счетчика единиц часов. При достижении этим счетчиком значения 10 происходит его обнуление (в строке 94) и вызов строки 95, где десятки часов увеличиваются на единицу.
В результате работы всех этих программных счетчиков содержи мое четырех ячеек буфера tim постоянно меняется и отображает текущее время. Процедура динамической индикации выводит это время на индикатор.
Мы рассмотрели пример использования схемы динамической индикации для реализации простейших электронных часов. Однако четыре разряда для такой схемы далеко не предел. Схему, изображенную на рис. 1.1 (, легко усовершенствовать, добавив туда новые разряды. Небольшое изменение в схеме включения дешифратора DD2 позволяет легко расширить количество разрядов динамической индикации до восьми. Новая схема включения дешифратора приведена на рис. 1.12.
DD2
К555ИД4
Рис. 1.12. Включение дешифратора по полной схеме
50
Традиционные периферийные устройства
В новой схеме используются уже три младших разряда порта РЗ. В результате мы получим возможность увеличить число индикаторов до восьми. Нужно только предусмотреть еще четыре транзисторных ключа, подключенных к остальным выходам дешифратора. Предлагаю читателю самому разобраться, как будет выглядеть полная схема динамической индикации для восьмиразрядного индикатора и попробовать изменить программу так, чтобы она оказалась пригодной для этого случая.
1.4. Комбинированные устройства
В предыдущих разделах мы рассмотрели основные приемы подключения к микроконтроллеру управляющих клавиш и элементов индикации. На практике чаще всего клавиатура и индикация объединяются в одну общую схему. На рис. 1.13 приведен пример подобной схемы. Если вы посмотрите на этот рисунок внимательно, то увидите, что он представляет собой симбиоз рис. 1.4 (матричное включения клавиатуры) и рис. 1.11 (схема с динамической индикацией). Правда, количество клавиш, по сравнению с прототипом, уменьшено вдвое, а количество разрядов индикатора, наоборот, увеличено до шести. Благодаря тому, что клавиатура и индикаторы подключены к разным выходам дешифратора DD2, микроконтроллер может раздельно управлять индикацией и производить опрос клавиатуры.
В связи с тем, что две схемы объединились в одну, пришлось ввести несколько разделяющих диодов: VD1...VD&. Эти диоды предотвращают появление помех для индикации в случае одновременного нажатия двух или более клавиш. Что это за помехи, и как они возникают? Представим себе, что диоды VDI...VD8 отсутствуют и заменены перемычками. Допустим, пользователь нажал и удерживает одновременно клавиши К1 и К2. Это приведет к замыканию сегментов а и b во всех разрядах индикатора. В результате они не будут зажигаться раздельно. Установка диодов устраняет эту проблему При одновременном замыкании клавиш К1 и К2 один из двух диодов (VD1 или VD2) всегда будет закрыт.
Как же совместить динамическую индикацию и опрос клавиатуры? Да очень просто! Необходимо выполнять эти два алгоритма в
Комбинированные устройства
51
разные моменты времени. Опрос клавиатуры должен происходить в промежутке времени между сменами разрядов в процессе динамической индикации.
Процедура для обслуживания схемы, изображенной на рис. 1.I3, называется dnindl. Текст этой процедуры, а также всего необходимого для ее работы, приведен на листинге 1.6. Она представляет собой результат объединения двух программ. За основу взята процедура динамической индикации программы «Часы» (листинг 1.5). Из нее удалено все, что касается подсчета времени. Вместо этого в процедуру встроена функция опроса клавиатуры. В основу функции легла подпрограмма klav (см. листинг 1.3). Процедура dnindl — это такая же процедура обработки прерывания, как и dnind (см. листинг 1.5). Она также, периодически, вызывается при помощи таймера.
Рис. 1.13. Комбинированная схема клавиатуры и индикации
52 Традиционные периферийные устройства
При каждом вызове процедура dnindl сначала опрашивает клавиатуру и записывает код нажатой клавиши в специальный буфер KodK. И лишь затем производится смена индицируемого разряда для обеспечения эффекта динамической индикации. Таким образом, опрос клавиатуры происходит синхронно с работой схемы динамической индикации. Совмещение процедур — это оптимальное решение, так как для опроса клавиш и для вывода на индикатор используются одни и тс же элементы схемы.
Теперь разберем подробнее текст программы (листинг 1.6). Так как за основу была взята программа динамической индикации из предыдущего примера, мы остановимся только на отличиях новой программы от предыдущей. В строках 1... 18 происходит определение констант и переменных. Эта часть повторяется почти без изменений. Но есть и отличия. Константа ktdi, определяющая время задержки таймера, теперь имеет другое значение. Это связано с тем, что в новой схеме уже не четыре, а шесть разрядов индикатора. Для того, чтобы частота смены «кадров» динамической индикации оставалась равной 50 Гц, нужно частоту смены разрядов выбрать равной 50x6 = 300 Гц. Кварцевый генератор мы оставим прежний (12 МГц). Поэтому частота сигнала, поступающего на вход таймера, как и прежде, будет равна 106 Гц. Отсюда найдем новый коэффициент пересчета таймера: 106/300 = 3333,33... Округлим до 3000. Осталось найти начальное значение таймера (ktdi). Оно будет равно: 65535 — 3000 = 62535. Присвоение значения константе ktdi происходит в строке 6 программы.
Следующее отличие нового варианта программы от старого — отсутствие буфера tim. Вместо него появился другой буфер, под названием but (см. строку 14). Этот буфер занимает уже 6 ячеек памяти. Буфер but имеет то же назначение, что и буфер tim. В нем хранятся коды символов, которые будут выводиться на индикатор Если в предыдущем примере в буфере хранилось значение текущего времени, то в новой программе в буфер может быть записана любая величина. Например, такой индикатор может использоваться в цифровом измерительном приборе. Тогда на наш индикатор будет выводиться результат измерения.
Еще один новый элемент — однобайтовый буфер kodK (строка 16). Он предназначен для хранения кода нажатой клавиши. Буфер понадобился для передачи кода из процедуры обработки прерывания в основную программу. Процедура обработки прерывания dnindl
Комбинированные устройства
53
работает сама по себе в фоновом режиме. При этом она постоянно опрашивает клавиатуру и определяет код нажатой клавиши. Выполнение основной программы происходит своим чередом, независимо от прерываний. Поэтому процедура dnindl помещает код нажатой клавиши в буфер kodK. А основная программа считывает его оттуда при необходимости для того, чтобы отреагировать на нажатия клавиш.
И, наконец, еще один новый буфер regT (см. строку 12). Шесть младших бит буфера regT используются для хранения состояния десятичных точек всех шести разрядов индикатора. Эту информацию использует процедура dnindl при выводе цифр на индикатор. Управляя отдельными битами этого буфера, можно включать и выключать любую точку на индикаторе. Для буфера regT выбран адрес 21Н. Ячейка, расположенная по этому адресу, допускает раздельное управление каждым своим битом.
Листинг 1.6
Программа обслуживания комбинированной схемы (рис 113)
1	$mod2051
;------------------ Определение констант
2	bankO	EOU	00000000В Коды банков	памяти
3	bank!	EQU	00001000В
4	bank2	EQU	00010000В
5	ЬапкЗ	EOU	00011000В
6	ktdi	EQU	62535
			—	— Резервирование
7		BSEG	
8		ORG	0
9	bufT-	OBIT	1
10		DSEG	
11		ORG	21H
12	regT:	DS	1
13		ORG	ЗОН
14	but:	DS	6
15	nomA:	DS	1
16	kodK:	DS	1
17		ORG	бон
18	stack	DS	20H
Коэффициент пересчета таймера ячеек памяти
В битовой обп.лти лам ти
Буфер десятичной тс .ки
В обычной памяти данных
Регистр всех десятичных точек
Буфер экрана
Номер текущего разряда
Буфер для кода клавиатуры
начало стека глубина стека
54
Традиционные периферийные устройства
.тшшшшшшштшшшшшшшшшмм
:##	Начало программного кода	ttit
;я««««#««#яя#««4«#«««#««««я#««###«#ш##««###««#«#««««##««в
19 20 21	CSEG ORG jmp	0000H init	к процедуре инициализации после включения/сброса
22	ORG	0003H	переопределение вектора
23	reti		внешнего прерывания 0
24	ORG	OOOBH	переопредели „и вектора
25	jmp	dnind	прерывания по таймеру 0
26	ORG	0013H	переопределение вектора
27	retl		внешнего прерывания 1
28	ORG	001BH	переопределение вектора
29	reti		прерывания по таймеру 1
30	ORG	0023H	вектор прерывания по
31	reti		последовательному каналу
		-- Инициализация	
32	ORG	0030H	
33	init:	mov	sp.«(stack-1)	Установка вершины стека
34	mov	rO.Sbuf	Цикл обнуления буфера экрана
35	mov	rl. «6	
36	ini1:	mov	₽r0,«0	
37	inc	rO	
38	djnz	r1,inil	
39	mov	nomR,«0	Инициализация счетчика разрядов
	• 		Программирование таймера	
40	mov	THOO, «00000001В	Выбор режима работы таймеров
41	mov	ТПО,«(high ktdi)	Период срабатывания прерывания
42	mov	TL0,«(low ktdi)	
43	mov	IE, Я10000010В	Наска прерываний
44	mov	IP,#00000010B	Установка приоритетов
45	mov	TCON.BOOOIOOOOB	Разрешение счета таймеров
main:
Сюда вы должны поместить текст основной программы
46
««####«#«#«««#«««##««##«««#«#«#«#««#«««#««««#««#«#««««
;«« Обработка прерывания от таймера	tti
:«#«Ш««««««##««###«««««««Ш##««###«««Й#«Й«««««####«# dnind!:	push ACC
Комбинированные устройства
55
47 48 49	push push push		DPH DPI PSW	
50		mov	PSW,#bank1	Выбор банка 1
51		mov	THO,#(high ktdi)	Период срабатывания прерываний
52		mov	FLO, ft(low ktdi)	
				UlipUL MldDHdlypU			-	-------	
53		mov	p1 #OFFH	Перевод Р1 J-P1.7 в единичное состояние
54		call	clrU	Перевод РЗ.О-РЗ.З в единичное состояние
55		mov	rO, #0	Очистка буфера кода клавиши
56		mov	H HO	Инициализация счетчика столбцов
57	кН.	mov	a.rl	Вычисление выводимого кода
58		add	a. 46	
59		call	setU	Вывод кода в порт РЗ
60		mov	a, p1	Считывание состояния клавиатуры
61		cjne	a,#0FFH.kl3	Если клавиша нажата, переходим к к13
	—		 Переход к следующему столбцу		
62	к12-	inc	r1	Увеличение счетчика столбцов на единицу
63		mov	a.rl	Извлекаем в а для проверки
64		cjne	a,«2,kl1	Если значение счетчика еще не равно 2,
				продолжаем цикл (переход на кН)
	•			 Окончание процедуры опроса		клавиатуры
65	klfin:	call	clrU	Перевод в исходное состояние порта РЗ
66		mov	kodK, rO	Запись в буфер кода клавиши
				
?7		mov	a.nomR	Вывод номера разряда
68		call	setU	
69		mov	rO.nomR	Вывод значения очередной точки
70		inc	rO	в буфер деситичной точки t.ufT
71		mov	a.regT	
72	dnl:	rrc	0	
73		djnz	rO,dn1	
74		mov	bufT.c	
75		mov	a.nomR	Вывод очередной цифры
76		add	a.Hbuf	на индикатор
77		mov	rO a	
78		mov	a.PrO	
79		call	prind	К процедуре из Листинга 1 4
60		inc	nomR	Инкремент номер- разряда
81		mov	a, nomR	
82		cjne	a,#6,dn3	Проверка - не последний ли разряд
83		mov	nomR, ItO	Если последний, начинаем с"двла
				 Завершающие команды	
84	dn3'	pop	PSW	;	Восстановление регистрон из стека
56
Традиционные периферийные устройства
85	POP	DPI
86	pop	DPH
87	pop	ACC
88	reti	
========== Вспомогательные процедуры ===•
Нахождение номера клавиши в строке
89	М3'	mov	r3.Hl	Инициализация счетчика строк
90	k!4:	setb	c	Обнуление признака переноса
91		rrc	a	Сдвиг входного кода
92		jnc	kl5	Если нашли разряд, равный 0 перейти к к15
93		inc	r3	Итерация счетчика строк
94		jmp	kl4	Переход к началу цикла счета строк
95	k!5:	cjne	a,#0FFH,kl6	Если еще есть хоть один 0, перейти к к16
96		mov	a,rO	Не найдена ли уже другая нажатая кнопка
97		jnz	kl6	Если да. то перейти к к16
			 Вычисление номера клавиши		
98		mov	a. r1	Запись номера столбца в аккумулятор
				операции вычитания, находившиеся
				ранее на этом месте, убраны
99		rl	a	Три оператора сдвига (умножение на В)
100		rl	A	
101		rl	a	
102		add	a.r3	Прибавление номера строки
103		mov	rO.a	Записываем в буфер
104		jmp	kl2	. Продолжаем поиск по остальным столбцам
105	k!6:	mov	rO 80	Возвратить ноль
106		jmp	klfin	Перейти на конец процедуры
			 Сброс	разрядов столбцов	
107	clrl):	clr	рЗ.О	Сброс побитно
108		clr	p3.1	
109		clr	рЗ 2	
110		ret		
			 Вывод столбцов		
111	setl)	rrc	a	Перенос сдвигом в ячейку с
112		mov	рЗ.О,с	Вывод в порт
113		rrc	а	Сдвиг еще на один разряд
114		mov	р3.1.с	Вывод в порт
115		rrc	а	Последний (третий) разряд
11G		mov	р3.2.с	Вывод в порт
117		ret		
118
119
:ттпт!штшш1шшпшшп
,#« Подпрограмма опроса клавиатуры йй
klav:	mov a.kodK	, Просто извлечь код клавиши из буфера
ret
Комбинированные устройства
57
Сюда вы можете поместить другие подпрограммы.
в том числе и таблицу символов
120
,end
В строках 19...31 происходит переопределение векторов прерываний. Здесь нет никаких отличий от предыдущего примера.
В строках 32.. 39 находятся команды инициализации Выполняемая ими функция полностью совпадает с предыдущим примером. Однако ячеек, подлежащих обнулению, теперь стало больше. Поэтому теперь, для этой цели, разумнее организовать программный цикл. Цикл занимает строки 34 38 Смысл его в том, чтобы поместить во все ячейки буфера buf нулевой код. Регистр г1 используется как параметр цикла, а регистр гО как указатель буфера. Инициализация этих переменных происходит в строках 34, 35 Тело цикла занимает строки 36...38. В строке 36 в очередную ячейку буфера записывается ноль. Далее значение указателя буфера увеличивается на единицу (строка 37). Заканчивается тело цикла оператором djnz (строка 38).
Остальная часть модуля инициализации (строки 40...45) не изменилась.
Процедура dnindl переделана из dnind. Текст процедуры занимает строки 46...88 Теперь в начало процедуры добавлен модуль опроса клавиатуры (строки 53 ..66) Модуль динамической индикации переместился в конец (строки 67...83). Кроме этих двух основных модулей процедура включает несколько дополнительных подпрограмм (см. строки 89..117). Они используются для опроса клавиатуры В качестве модуля опроса клавиатуры выступает немного переделанная подпрограмма klav (см. листинг 1.3). Алгоритм работы этой подпрограммы подробно описан в разделе 1 2 Модуль динамической индикации тоже не написан с нуля. Он почти полностью повторяет аналогичный модуль в процедуре dnind. Не будем повторять полное описание этих модулей. Ограничимся описанием только тех участкам кода, которые подверглись изменениям. Описание различий ведется по тексту листинга 1.6.
58
Традиционные периферийные устройства
Модуль опроса клавиатуры. Главное отличие новой клавиатуры — уменьшение количества клавиш. У нас теперь не четыре, а только два столбца. Поэтому меняется параметр цикла опроса столбцов (строка 64). Второе отличие в том, что наши столбцы клавиш теперь подключены нс к первым, а к последним выводам дешифратора DD2 (см. рис. 1.13). Поэтому для опроса наших двух столбцов на вход дешифратора DD2 через линии Р3.0...Р3.2 нужно подавать коды 6 (для первого столбца) или 7 (для второго). В связи с этим нам нужно осуществлять пересчет кодов. Перед выводом в порт значение кода просто увеличивается на 6 (строки 57, 58).
Часть вспомогательных процедур (строки 89... 106) не изменились. Но процедуры, предназначенные для работы с портом РЗ, полностью переработаны. В новой программе пришлось применить другой способ раздельного доступа к линиям порта РЗ. Раньше мы использовали метод буфера. Теперь пришлось применить непосредственное управление разрядами. Связано это с тем, что такой способ уже использует программа динамической индикации. Зачем применять два способа? Рассмотрим по порядку новые версии старых процедур.
Подпрограмма начальной установки clrU (строки 107...НО) состоит из трех команд, которые по очереди обнуляют каждый из трех разрядов порта РЗ. Подпрограмма setU (строки 111...117) в новой программе используется не только при опросе клавиатуры, но и в процедуре динамической индикации. Для новой версии подпрограммы setU код, предназначенный для вывода, предварительно должен быть помещен в аккумулятор. Вывод кода происходит методом сдвига. Для извлечения каждого из трех младших разрядов код в аккумуляторе сдвигается вправо через CY. После каждого сдвига попавший в СУ бит посылается в соответствующий разряд порта РЗ.
И, наконец, последнее отличие новой версии модуля опроса клавиатуры от старой: полученный в результате опроса код состояния клавиатуры записывается не в аккумулятор, как раньше, а в буфер kodK (см. строку 66).
Модуль динамической индикации. Первое отличие новой версии модуля от старой состоит в том, что для вывода информации в три младшие разряда порта РЗ используется уже известная нам процедура setU. Вызов этой процедуры происходит в строках 67, 68.
Комбинированные устройства
59
Следующее отличие связано с новым способом вывода десятичной точки. Как уже говорилось, для управления точками в программу введен буфер bufT. Шесть его младших разрядов соответствуют шести точкам на индикаторе. Младший разряд буфера (bufT.O) управляет точкой на индикаторе HL1. Разряд bufT.5 управляет точкой на HL5. Управление инверсное. Это значит, что для зажигания точки в соответствующий разряд записывается ноль. Чтобы потушить точку, туда нужно записать единицу.
Для реализации алгоритма управления десятичными точками введен специальный программный модуль. Текст модуля занимает строки 69...74. Этот модуль извлекает из буфера regT содержимое нужного бита и записывает его в буфер bufT перед тем, как вызвать подпрограмму prind. Для извлечения бита организуется цикл. В цикле сдвигается содержимое буфера regT до тех пор, пока нужный бит не окажется в CY. В качестве параметра цикла используется регистр гО. В него нужно записать требуемое количество циклов сдвига. Оно получается увеличением на единицу номера текущего разряда (см. строки 69, 70). В результате, для нулевого разряда будет выполнен один сдвиг. Для первого разряда — два сдвига и так далее. В строке 71 в аккумулятор помещается содержимое буфера regT. И начинается сдвиг. Тело цикла составляют строки 72, 73. Фактически оно состоит из одного оператора ггс. По окончании всех циклов найденное значение помещается в буфер bufT (строка 74). Буфер bufT используется в дальнейшем при выводе символа на индикатор.
Начиная со строки 75 модуль динамической индикации работает так же, как и в первом варианте программы. Есть только два небольших отличия:
1. Теперь мы используем буфер buf вместо буфера tim (строка 76).
2. Новый буфер занимает шесть ячеек памяти, поэтому параметр цикла в строке 82 будет равен шести.
60
Традиционные периферийные устройства
1.5. Исполнительные устройства
Практически ни одна микропроцессорная система не может обойтись без таких элементов, как исполнительные устройства. В конце концов, главное назначение любой системы — это управление каким-либо внешним механизмом. Это могут быть электромоторы, нагреватели, электромагнитные клапаны и так далее. Поэтому, кроме датчиков, кнопок управления и элементов индикации к микроконтроллеру обязательно придется подключать и исполнительные устройства. Для управления внешними устройствами используются те же самые порты ввода/вывода микроконтроллера. Естественно, в данном случае они работают на вывод. Сигналы с любой из линий любого порта легко могут быть использованы для включения и выключения внешнего устройства. Необходимо лишь усилить управляющий сигнал по мощности до необходимого уровня. Для этого применяются различные согласующие схемы. Выбор схемы зависит от типа исполнительного устройства. А точнее, от его рабочего напряжения и тока.
В простейшем случае можно применить уже знакомый нам транзисторный ключ (см. рис. 1.14). При использовании транзистора КТ315Г можно управлять внешними цепями с током потребления до 100 мА и напряжением UIIIIT до 15 В. Транзистор допускает и большие напряжения, однако повышение напряжения возможно при снижении тока.
Рис. 1.14. Простейший транзисторный ключ
Для управления цепями с большим током управления нужно применить более мощный транзистор или целую транзисторную сборку. При выборе транзистора не забывайте, что максимально
Исполнительные устройства
61
допустимый ток нагрузки для любого из выходов микроконтроллера не должен превышать величины 20 мА. При составлении программы нужно не забывать, что любой транзисторный ключ инвертирует сигнал. Если на выходе Р1.0 (см. рис. 1.14) установить единичный уровень, ключ открывается и нагрузка подключается к источнику питания. При нулевом уровне на том же выходе ключ закрывается и нагрузка отключается.
Если исполнительный механизм, которым должна управлять наша микропроцессорная система, питается от сети переменного тока 220 В, нужно применять схему управления с гальванической развязкой. Один из возможных вариантов — релейная схема управления. Типичный вариант релейной схемы управления приведен на рис. 1.15. На схеме мы видим уже знакомый нам электронный ключ, в нагрузку которому включено электромагнитное реле К1. Микропроцессор при помощи ключа может включать и выключать электромагнитное реле. Контакты реле, в свою очередь, управляют нагрузкой. Такая схема обеспечивает коммутацию достаточно больших напряжений и токов.
Рис. 1.15. Релейное исполнительное устройство
Гальваническая развязка между всеми цепями микропроцессорной системы и силовыми сетями 220 В обеспечивает безопасность работы с этой схемой. Диод VD1 предназначен для зашиты элементов схемы от напряжения ЭДС самоиндукции, возникающего в катушке К1 в момент закрывания ключа VT1. При выборе электромагнитного реле необходимо обращать внимание на следующие параметры. Во-первых, напряжение срабатывания реле. В нашем случае оно должно быть равно 12 В. Во-вторых, максимально допустимый
62
Традиционные периферийные устройства
коммутируемый ток и максимально допустимое напряжение для исполнительных контактов реле. Они должны соответствовать реальным значениям тока и напряжения в цепи нагрузки. Современные реле импортного производства обычно имеют маркировку на своем корпусе, где указаны все основные параметры.
Как известно, недостатком электромагнитных реле является их недолговечность, связанная с подгоранием и быстрым изнашиванием его контактов. А также акустические шумы в процессе его работы. На рис. 1.16 показана схема устройства согласования без использования электромагнитных реле. Здесь в качестве управляющего элемента используется симистор VS1. Для обеспечения гальванической развязки между силовой и управляющей цепями используется оптодинистор U1. Светодиод HL1 служит для индикации срабатывания ключа. Симистор ТС106-10 рассчитан на ток до 10 А. Промышленность выпускает несколько классов таких симисторов. Они различаются по максимально допустимому рабочему напряжению. Для работы в цепях с напряжением до 220 В рекомендуется применять симисторы 4-го класса. Не забудьте снабдить симистор небольшим радиатором (5... 10 см2).
С программной точки зрения, управление исполнительными механизмами ничем не отличается от управления единичными светодиодными индикаторами (см. схему на рис. 1.6). Поэтому останавливаться подробнее на программной части вопроса мы не будем. На сайте [lw] вы можете найти несколько практических схем, где используются различные способы управления исполнительными устройствами.
Рис. 1.16. Исполнительное устройство на основе симистора
Глава 2
с D
Другие варианты
схем ввода/вывода
2.1.	Общие сведения
В предыдущей главе мы рассмотрели основные принципы построения простейших периферийных устройств для микроконтроллеров с использованием традиционного набора элементов Однако возможности современной схемотехники этим далеко не ограничиваются. В настоящей главе я объединил несколько примеров построения систем ввода и вывода информации, которые можно отнести к нестандартным решениям.
Первый вопрос, который просто необходимо затронуть для полного раскрытия заявленной темы — вопрос ввода и вывода аналоговой информации. Как известно, микропроцессорным устройствам иногда приходится работать в условиях, когда часть информации представлена в аналоговом виде. Допустим, микропроцессор должен контролировать показания прибора, который выдает результаты измерения в виде пропорционально изменяющегося напряжения. Либо второй случай: микропроцессор должен управлять исполнительным механизмом, а для этого требуется плавно изменять управляющее напряжение. Для таких случаев применяются цифро-аналоговые или аналого-цифровые преобразователи (сокращенно ЦАП и АЦП). Вообще, тема аналого-цифрового и цифро-аналогового преобразования — это большая самостоятельная тема. Можно собрать АЦП или ЦАП и на отдельных микросхемах малой степени интеграции. Однако, современная промышленность выпускает большую гамму специализированных микросхем. Наконец, существуют микроконтроллеры со встроенным АЦП или ЦАП. В настоящей главе мы остановимся на трех несложных схемах, Удачно использующих возможности микроконтроллера AT89C205L Это очень упрощенные схемы, обладающие невысокой точностью преобразования. Однако они послужат прекрасным примером.
64
Другие варианты схем ввода/вывода
иллюстрирующим принципы цифро-аналогового и аналого-цифрового преобразования.
В конце настоящей главы затронута еще одна интересная тема. Там приведен пример использования современной элементной базы для создания цифрового жидкокристаллического дисплея.
2.2.	Пример построения ЦАП
Описываемый ниже цифро-аналоговый преобразователь был разработан как вспомогательный, для применения в качестве составной части многоканального АЦП, схему которого мы рассмотрим в следующем разделе. Однако он вполне может служить самостоятельным устройством для преобразования цифровой информации в аналоговую форму. Точность преобразования этой схемы невелика. Преобразователь позволяет сформировать аналоговый сигнал, имеющий всего 256 градаций уровня. Однако, в некоторых случаях этого может оказаться вполне достаточно. Представьте, например, микропроцессорную систему управления преобразователем напряжения. Подобный ЦАП с успехом может использоваться Д1я формирования синусоидального напряжения, которое затем можно усилить по мощности, подать на вход трансформатора и получить на выходе напряжение 220 В 50 Гц практически идеальной синусоидальной формы.
Схема цифро-аналогового преобразователя приведена на рис. 2.1 Он представляет собой матрицу резисторов R3...R10. Через каждый из этих резисторов на выход преобразователя поступает сигнал с одного из выходов буферного регистра DD2. Номиналы резисторов подобраны по принципу удвоения. Сопротивление резистора R9 в два раза больше, чем сопротивление R10. Сопротивление R8 еще в два раза больше. И так далее. Из стандартного пятипроцентного ряда специально подобраны такие номиналы, чтобы получился ряд значений, в котором каждое последующее в два раза больше предыдущего. В связи с тем, что главным критерием была простота и низкая стоимость, решено было отказаться от прецизионных радиоэлементов и более совершенных схемных решений. Для минимизации влияния нагрузки на точность преобразования используется эмиттерный повторитель (VT1, R11).
Посмотрим, как работает такая схема. Процессор DD1 просто записывает число, предназначенное для преобразования в аналоговый
Пример построения ЦАП
65
сигнал, в буферный регистр DD2. В тот же момент то же число появляется на выходах этого регистра в виде восьми битов двоичного кода. В соответствии со значениями разрядов этого кода, на каждом из выходов DD2 установится одно их двух возможных выходных напряжений. Напряжение на выходе может быть либо равно нулю (низкий логический уровень), либо практически равно напряжению питания (высокий логический уровень). Через соответствующие резисторы матрицы эти напряжения поступят на вход эмиттерного повторителя. Результирующее напряжение сложится из всех этих сигналов. Однако вес каждого из сигналов в общей сумме будет разный. Младший разряд (Q1) будет иметь самый маленький вес. Разряд Q2 будет иметь вес в два раза больший. И так далее. В результате уровень сигнала на выходе схемы будет прямо пропорционален значению двоичного числа, записанного в регистр DD2. При изменении этого числа от ООН до FFH напряжение на выходе преобразователя будет изменяться в пределах от 0 до 5 вольт. Преобразователь способен выдавать 256 дискретных уровней напряжения. Шаг между соседними уровнями будет равен 5/256 = 0,0195 (где-то около 20 мВ).
Это в идеале В реальной схеме диапазон изменения выходного напряжения будет меньше из-за падения напряжения на переходе база-эмиттер Несколько улучшить параметры такого ЦАП можно путем исключения эмиттерного повторителя, но только в случае, если нагрузка высокоомная.
Для управления регистром DD2 используется порт Р1 микроконтроллера (передача данных) и линия Р3.4 (сигнал записи). Рези-
3 Зак. 922
66
Другие варианты схем ввода/вывода
сторы RI и R2 установлены для обеспечения нормальной работы выходов Р1.0 и Р1.1. Эти выходы не имеют внутренних резисторов нагрузки, поэтому они требуют применения внешней нагрузки. Приведенную схему ЦАП можно было бы еше больше упростить Например, можно обойтись и без микросхемы DD2, подключив матрицу резисторов непосредственно к порту Р1. Можно также отказаться от эмиттерного повторителя. Но отказ от эмиттерного повторителя еще более снизит точность преобразования. А отказ от промежуточного регистра приведет к резкому ограничению функциональных возможностей всей схемы. Так как сделает невозможным одновременное применение порта Р1 для нескольких разных целей. Как еще можно использовать порт Р1 мы увидим уже в следующем разделе Но прежде нам предстоит рассмотреть пример управляющей программы, предназначенной для работы со схемой (рис. 2 1)
Для обслуживания схемы была разработана специальная процедура pDAP (см. листинг 2.1). Для работы этой процедуры предварительно нужно определить только один параметр — описать линию управления внешнего порта. Эта линия получает имя EDS (см. строку 6) и служит для передачи на вход С микросхемы DD2 сигнала записи. Текст процедуры pDAP занимает строки 7... 15. Основная программа вызывает процедуру pDAP каждый раз, когда нужно изменить код в регистре DD2. Новый код передается в процедуру через аккумулятор.
Листинг 2 1
Прэ’Минз обг..-', •  > |нс.> . » чы ЦАП
1	Sm<xI2051			
			Определение	
2	ba..kO	EQU	OOOOOOWB	Кед»	анпти
3	bank1	EQU	ООО:.'"DOB	
4	bank2	EOU	00010000B	
5	ЬапкЗ	EQU	00011000B	
6	EDS	BIT	P3 4	Выход включения д-»и^»лтог«
Сюда вы должны погостить модрь иниии  «ации
И гекст основном гл, раммы
Пример построения ЦАП
67

Подпрограмма ЦАП
8
9
10
11
12
13
14
15
Выводимый КОД в А
pDAP:	push psw
mov	psw.nbankl	;	Выбор	банка 1	памяти
setb EDS	Установка выхода управления
mov	р1,а	:	Вывод	кода в регистр ЦАП
Clr	EDS
setb	EDS
mov	pl.ftOFFH
pop ret
psw
Сюда вы можете поместить другие подпрограммы.
16 end
Мы пропускаем описание команд сохранения и восстановления регистра psw (строки 7 и 14), а также команду выбора банка РОН (строка 8). Основной текст процедуры занимает всего пять строк (строки 9 ..13). Работа процедуры начинается с исходного значения на выходе EDS (строка 9). На этом выходе устанавливается единичное значение. Эта единица поступает на вход С регистра DD2. Затем код из аккумулятора записывается в порт Р1 (строка 10). С выходов порта он поступает на входы D1...D8 микросхемы DD2. Теперь осталось только подать импульс записи Отрицательный импульс на выходе EDS формируется в строках 11 и 12 подпрограммы. Импульс поступает на вход С регистра DD2 и вызывает запись в него кода, присутствующего на его входах.
В заключение процедура переводит все выходы порта Р1 в единичное состояние (строка 13). Такой прием делает процедуру универсальной. Перевод всех выходов в единичное состояние позволяет использовать их на ввод.
68
Другие варианты схем ввода-вывода
2.3.	Система аналогового ввода
Итак, мы узнали один из способов, при помоши которого можно преобразовывать код в напряжение. Теперь мы займемся обратным преобразованием. И здесь нам поможет уже знакомая схема ЦАП. Оказывается, любой ЦАП легко превратить в АЦП. Для этого нужен только компаратор напряжения и специальная программа. Блок-схема такого АЦП приведена на рис. 2.2. Принцип его работы достаточно прост. Он основан на измерении напряжения на одном из входов компаратора путем подбора напряжения на другом его входе. На этот второй вход компаратора подастся напряжение с выхода ЦАП. Выход компаратора тоже подключен к микроконтроллеру. Для того, чтобы измерить величину входного напряжения, нужна специальная измерительная программа. Действуя по этой программе, микропроцессор изменяет напряжение на выходе ЦАП от нуля до максимума, при этом постоянно контролируя уровень сигнала на выходе компаратора. Как только напряжение на выходе ЦАП превысит входное напряжение, сигнал на выходе компаратора переключится с единицы на ноль. Обнаружив перепад, микроконтроллер прекращает перебор кодов. Последнее значение кода, засланное в ЦАП перед тем, как сработал компаратор и есть цифровой эквивалент измеряемого напряжения.
Рис. 2.2. Блок-схема построения АЦП
Описанная ниже схема (см. рис. 2.3) работает именно по такому принципу Однако это нс просто отдельный АЦП. Применение аналогового коммутатора позволяет превратить один прсобразо-
Система аналогового ввода
69
ватель в целую систему аналогового ввода. Система аналогового ввода позволяет вводить информацию в микропроцессорное устройство путем плавного поворота рукоятки на передней панели. Представьте себе, что вы решили создать систему управления отоплением в индивидуальном жилом доме. Причем температура в каждом помещении дома должна регулироваться индивидуально. Для оперативной регулировки температуры в каждом помещении установлен регулятор. Находясь в комнате, можно повернуть регулятор в ту или иную сторону и сделать теплее или холоднее. В данном случае регулятор предпочтительнее, чем кнопки «Больше» и «Меньше». Во-первых, крутить ручку удобнее. Во-вторых, отпадает потребность в цифровом индикаторе уровня нагрева. В случае с кнопками без него нс обойтись.
Можно придумать множество других применений для системы аналогового ввода. Но вернемся к схеме устройства. Микросхемы АТ89С2051 уже содержат встроенный компаратор. Это упрощает нашу задачу. Очень удобно использовать этот компаратор для построения АЦП. Входы встроенного компаратора совмещены с выводами Р1.0, Р1.1. Именно по этой причине в выходных схемах разрядов Р1.0 и Р1.1 отсутствуют внутренние резисторы нагрузки. Выход встроенного компаратора подключен к входу Р3.6, который не выводится на внешние выводы микросхемы и может работать только с компаратором. Цифро-аналоговый преобразователь, аналогичный приведенному на рис. 2.1, построен на основе регистра DD4, резистивной матрицы R11...R18 и эмиттерного повторителя VT1, R19 (см. рис. 2.3).
При подключении ЦАП к микроконтроллеру возникает одна небольшая проблема. Два вывода — Р1.0 и Р1.1 — необходимо использовать сразу двумя способами. Во-первых, они должны работать, как младшие разряды порта Р1 при записи кода в регистр DD4. Те же самые выводы должны работать, как входы компаратора в процессе ввода аналогового сигнала. К счастью, эта проблема легко разрешима. Для решения этой задачи применяется метод динамической коммутации выводов. Для коммутации выводов применена микросхема К561КТЗ (DD3 на рис. 2.3). Она содержит четыре управляемых электронных ключа на основе КМОП транзисторов. Такой ключ действует нс хуже, чем электромагнитное реле. При подаче управляющего сигнала на вход Е ключа он замыкается, и выводы X и К оказываются замкнутыми между собой. Причем ток по цепи Х-К может течь как в прямом, так и в обратном на
70
Другие варианты схем ввода-вывода
правлении. При снятии управляющего напряжения выводы Хи К размыкаются. В описываемой схеме для коммутации выводов Р1.0 и Р1.1 используются три ключа микросхемы DD3.
Кроме простых аналоговых ключей в схеме используется более сложное переключающее устройство — аналоговый коммутатор. Микросхема аналогового коммутатора DD1 (К561КП2) имеет восемь аналоговых входов, обозначенных как ХО, XI, ...XI. Любой из аналоговых входов может быть подключен к единственному аналоговому выходу коммутатора, обозначенному буквой К. Для этого микросхема коммутатора содержит восемь аналоговых ключей, аналогичных тем, что применяются в микросхеме К561КТЗ. Управление этими ключами осуществляет внутренняя логика микросхемы, использующая для этого сигналы на входах А, В, С и ОЕ. Одновременно может быть включен только один ключ коммутатора. Для подключения одного из входов (Х0...Х7) на выход коммутатора на входы А, В и С нужно подать адрес этого входа. Затем на вход ОЕ нужно подать сигнал разрешения. Разрешающим сигналом для инверсного входа ОЕ будет логический ноль. Если на вход ОЕ подать сигнал логической единицы, то все ключи микросхемы будут закрытыми.
При помощи коммутатора DD1 к входу нашего АЦП может быть подключен движок любого из переменных резисторов R1...R8. Эти резисторы используются как регулируемые делители напряжения для ввода аналоговой информации. Микроконтроллер опрашивает все резисторы по очереди и считывает величину напряжения на выходе каждого из них. Затем он использует эти величины в процессе реализации основного алгоритма.
Для управления схемой коммутации используются выходы Р3.0...Р3.2 микроконтроллера. Они служат для подачи адреса на входы А, В, С коммутатора. Выход РЗ.З служит для управления всей схемой коммутации.
Рассмотрим работу системы коммутации и всей схемы аналогового ввода в режиме измерения величины входного сигнала. Сначала микропроцессор устанавливает на выходе РЗ.З уровень логической единицы. Коммутатор DD1 закрывается. Закрывается также и ключ DD3.3 благодаря тому, что элемент D5 инвертирует управляющий сигнал. В то же время ключи DD3.1 и DD3.2 открываются. В результате выводы 12 и 13 микроконтроллера подключаются к выводам 1 и 2 регистра DD4, а аналоговые сигналы от них отключа
Система аналогового ввода
71
ются. Такой режим работы схемы коммутации назовем цифровым режимом. В цифровом режиме микроконтроллер записывает в регистр DD4 код, предназначенный для цифро-аналогового преобразования. Код запоминается в регистре и соответствующий ему аналоговый сигнал поступает на выход эмиттерного повторителя
Закончив работу в цифровом режиме, микроконтроллер устанавливает на выходе РЗ.З логический ноль. Ключи DD3.1 и DD3.2 закрываются и отключают выводы I2 и I3 микроконтроллера от цифровых цепей. Одновременно открывается коммутатор DD1 и ключ DD3.3. На вход компаратора (вывод I2 микросхемы DD2) поступает аналоговый сигнал с одного из резисторов R1...R8. А на второй вход компаратора (вывод 13 микросхемы DD2) поступает напряжение с эмиттерного повторителя. Этот режим работы схемы мы будем называть аналоговым режимом. В аналоговом режиме два напряжения, поступившие на входы компаратора, сравниваются между собой. Микроконтроллер считывает результат сравнения через линию Р3.6. Если микроконтроллер обнаружит на выходе компаратора логическую единицу, то процесс измерения продолжится. Система снова перейдет в цифровой режим, запишет новое значение кода в регистр ЦАП (DD4), а затем перейдет в аналоговый режим и снова проверит сигнал на выходе компаратора.
Микропроцессор многократно повторяет описанный выше цикл сравнения. При этом он каждый раз увеличивает значение кода, засылаемого в регистр DD4. Так продолжается до тех пор, пока единичный уровень на выходе компаратора не сменится на нулевой. Два резистора R9 и RIO — это нагрузка для линий Р1.0 и Pl.l. Они подключаются к выводам 12 и 13 микроконтроллера посредством ключей DD3.1 и DD3.2 только в цифровом режиме работы схемы коммутации. В аналоговом режиме ключи DD3.1 и DD3.2 закрываются и резисторы не мешают работе компаратора.
В качестве датчиков сигнала для аналогового ввода наряду с переменными резисторами можно применять и другие источники аналогового сигнала. Например, терморезисторы, аналоговые датчики давления, влажности и т.п. Необходимо лишь согласовагь диапазон изменения напряжения на выходе датчика с входным диапазоном нашего АЦП. Для того, чтобы полностью использовать диапазон АЦП, напряжение на его входе должно изменяться в пределах от 0 до +5 В. Для согласования диапазонов не обойтись без специального согласующего устройства. Например, в случае
72
Другие варианты схем ввода-вывода
Рис. 2.3. Схема многоканального аналогового ввода
Система аналогового ввода 73
использования тсрморезистора согласующее устройство должно преобразовывать уровень снимаемого напряжения таким образом, чтобы при изменении температуры в пределах заданного диапазона напряжение на входе АЦП изменялось от нуля до 5 В. Описание электронного термометра, в котором применена подобная схема, вы можете найти в [3].
Для работы со схемой аналогового ввода была разработана специальная процедура pADP (см. листинг 2.2). Процедура считывает величину напряжения с одного из восьми аналоговых входов и помещает ее в аккумулятор. Номер входа, на котором необходимо прочитать величину напряжения, передастся в процедуру через регистр Ь. Вначале определяются все основные переменные. В строке 6 определяется имя для линии EDS. Как и в предыдущем примере, эта линия служит для управления процессом записи кода в регистр ЦАП. Линия RGS (см. строку 7) служит для управления схемой коммутации.
Листинг 2.2
, Программа обслуживания схемы АЦП
1
$mod2051
2
3
4
6
bankO bankl bank2 ЬапкЗ
Определение констант
ЕОЬ	000000008
EOU	00001000В
EQ0	000100008
EOU	00011000В
Коды банков памяти
EDS	BIT	Р3.4
RGS	BIT	РЗ.З
Выход сигнала записи в DD4 Выход переключения цепей
Сюда вы должны поместить модуль инициализации и текст основной программы

Подпрограмма АЦП
Ввод: в регистре В - номер канала АЦП Вывод, в регистре А • введг^.'Сс число
8
9
pADP:
push mov
psw
psw, 11 bankl
, Выбор Santa 1 памяти
74
Другие варианты схем ввода-вывода
К) и 12
13
141
15 16
17
18
19
20
21
22
23
24
25
26
ntev	a.b	Вкяю'Ргие нужною мныа
orl	а,#11111000В
то.'	Г-З.а
Ши»	<1. #0
Вывод кода в регистр ЦАП
sett.	RGS
ncirf	p1,r0
ci г	EDS
setb	EDS
p1,«0FFH
Чцнис состовнит компаратора clr	RGS
Mil	I'.p
Jt2	. Если еще не cpef, ’ал
inc	rO
cjne	rO,#OFFH,sc1
nCv	а,го	Запись ретугьтата в аккумумгор
"SW
V. 28 29 30 31 .12 33 34 35
1гл
id:
— Ввод с мяпамтсо» пак 5, #20 nnv	а,80
nnv	с.рЗ 6
iidCc	а,#0
1 i	г5.1р1
clr	с.
и.аь	1 #10
ср!	с
ret
Сюда вы мойен' i кинсль „ругие подпрограммы
<Ь I
1
। nd
Текст процедуры pADP занимает строки 8..35. В строках 8 и 25 происходит сохранение и восстановление регистра psw в стеке, а в строке 9 переключение банка РОН. Основная часть процедуры начинается со строки 10 и заканчивается строкой 24. Первая операция, которую выполняет процедура pADP — установка на адресных входах коммутатора адреса выбранного канала. Адрес подается на выходы Р3.0...Р3.2. Информация будет выводиться сразу во все разряды порта РЗ, поэтому сначала нужно позаботиться о
Система аналогового ввода
75
том, чтобы не нарушить работу остальных, не нужных нам выходов. Для этого код выбранного канала из регистра b помещается в аккумулятор (строка 10).
Затем все старшие разряды принудительно устанавливаются в единицу (строка 11). Для этой операции используется операция «ИЛИ». Затем полученное число выводится в порт РЗ (строка 12). В данном случае такой способ раздельного управления разрядами порта является наиболее рациональным, так как он автоматически устанавливает единичный уровень на выходах РЗ.З, Р3.4 и Р3.6. Это переводит схему в исходное состояние. Единица на выходе РЗ.З переведет схему в цифровой режим. Единица на выходе Р3.4 обеспечит корректную работу регистра DD4 в режиме ожидания. И наконец, единица на входе Р3.6 обеспечит нормальную работу компаратора (возможность работы входа Р3.6 режиме ввода). Единичный уровень на двух неиспользуемых выходах Р3.5 и Р3.7 обычно тоже вполне допустим.
После выдачи сигнала на адресные входы коммутатора, процедура приступает к циклу измерения уровня сигнала. В этом цикле на регистр ЦАП (DD4) нужно последовательно подавать возрастающие коды, начиная с нуля и до максимально возможного значения. Тело цикла занимает строки 14. .23. В качестве счетчика кода используется регистр гО Перед началом цикла (строка 13) в этот регистр записывается исходное значение (ноль).
Цикл начинается с установки единичного значения на выходе RGS (строка 14), что переводит схему в цифровой режим работы (если она еще не в цифровом режиме). Затем текущее значение кода из регистра гО выводится в порт Р1 (строка 15). После чего формируется отрицательный импульс записи на выходе EDS (строки 16, 17). В результате очередное значение кода записывается в регистр DD4 и на выходе ЦАП появляется соответствующее ему напряжение. После этого система переключается в аналоговый режим работы, для чего на выход RGS подается сигнал логического нуля (строка 19). Аналоговые сигналы поступают на оба входа компаратора, и на его выходе устанавливается результат их сравнения. В строке 20 управление передается вспомогательной подпрограмме inp, которая считывает сигнал с выхода компаратора. Вызов подпрограммы производится в строке 20. Подпрограмма специально создана для фильтрации помех на входе АЦП. Она производит многократное чтение сигнала с выхода компаратора и усреднение полученного результата. Окончательное значение сигнала компаратора подпро
76
Другие варианты схем ввода-вывода
грамма inp возвращает через ячейку CY. Признак переноса будет содержать единицу, если напряжение на входе АЦП больше напряжения на выходе ЦАП, и ноль — в противном случае.
В строке 21 производится оценка этого значения. Если сигнал на выходе компаратора ноль, то произойдет передача управления по метке sc2 и цикл подбора завершится. Если же там единица, то цикл подбора продолжается дальше. В строке 22 происходит увеличение содержимого регистра гО на единицу. Далее, происходит проверка: не достигло ли значение регистра максимально возможного значения (0FFH). Если максимально возможное значение достигнуто, то это означает, что напряжение на входе АЦП больше пяти волы и подбор также следует прекратить. Проверка достижения конца диапазона происходит в строке 23. Если конец диапазона не достигнут, управление передастся по метке sc1 в начало цикла. Если конец достигнут, то управление плавно переходит к строке 24. Сюда же, как мы видели раньше, передается управление при обнаружении нуля на выходе компаратора (см. строку 21). В строке 24 полученный в результате измерения код помешается в аккумулятор. Затем процедура pADP завершается.
Теперь посмотрим, как работает вспомогательная подпрограмма inp. Текст этой подпрограммы занимает строки 27...35. Назначение подпрограммы — фильтрация помех, которые неизбежно будут присутствовать в измеряемом сигнале. Наличие помех может привести к неправильному определению момента срабатывания компаратора. Конечно, отфильтровать помехи можно аппаратными средствами. Например, можно зашунтировать каждый из восьми аналоговых входов коммутатора DD1 конденсатором в 5...Ю микрофарад. Однако фильтрация помех на программном уровне тоже не помешает. В основу алгоритма программной фильтрации положен принцип усреднения результата. Для реализации этого принципа программа производит двадцатикратное чтение сигнала с выхода компаратора и производит суммирование полученных значений. Затем проверяется результат. Если полученная таким образом сумма окажется больше десяти (большинство считанных значений равно единице), то в качестве выходного значения программа возвращает единицу Если полученная сумма окажется меньше десяти, то подпрограмма возвращает ноль.
Для многократного считывания и суммирования результата организуется цикл. Тело цикла занимает строки 29...31. В качестве
Жидкокристаллический дисплей
77
параметра цикла используется регистр г5. В строке 27 в этот регистр записывается начальное значение. Аккумулятор используется для накопления суммы, поэтому в строке 28 он обнуляется. Цикл начинается с команды чтения сигнала из компаратора (строка 29). Полученное значение записывается в ячейку признака переноса CY Затем оно прибавляется к текущему значению аккумулятора. Для этого применяется команда adde (строка 30). Оператор adde производит сложение содержимого аккумулятора с константой!, учитывая при этом значение признака переноса.
В нашем случае величина константы равна нулю. Поэтому в результате сложения к значению аккумулятора добавляется значение признака переноса. Таким образом, происходит накопление суммы прочитанных битов. По завершении цикла полученная сумма сравнивается с числом 10. К сожалению, в системе команд микроконтроллера АТ89С2051 отсутствует команда сравнения. Ее приходится заменять вычитанием. В строке 33 производится это вычитание. Для того, чтобы на результат вычитания не влияло содержимое ячейки CY, она предварительно обнуляется (строка 32). После вычитания значение признака переноса устанавливается следующим образом. Если сумма в аккумуляторе окажется больше или равна десяти, то значение CY будет равно нулю. В противном случае CY будет равен единице. Как видите, результат получился обратный тому, что нам нужен. Поэтому в строке 34 перед выходом из подпрограммы содержимое ячейки CY инвертируется.
На этом я хочу закончить рассказ о методах преобразования аналогового сигнала и перейти к совершенно новой и не менее интересной теме.
2.4.	Жидкокристаллический дисплей
В первой главе этой книги мы узнали, как построить цифровой дисплей на основе светодиодных семисегментных индикаторов. Однако дисплеи, построенные на основе светодиодных индикаторов, обладают рядом недостатков. Во-первых, это относительно большой уровень потребляемой мощности. А во-вторых, низкая контрастность изображения в условиях прямых солнечных лучей. В настоящее время имеется альтернативный вариант — использо
78
Другие варианты схем ввода-вывода
вание жидкокристаллических индикаторов (ЖКИ). В английской литературе для таких индикаторов существует свое сокращение — LCD. Производители электронного оборудования предлагают широчайший выбор готовых индикаторных панелей. Начиная с простых однострочных дисплеев и заканчивая большими графическими дисплеями, позволяющими одновременно отображать большое количество информации
Обычно ЖКИ дисплей имеет встроенный контроллер управления. Миниатюрные жидкокристаллические дисплеи очень удобно применять в микропроцессорных системах Они информативны, потребляют маленький ток от источника питания. И, наконец, готовые ЖКИ панели промышленного производства очень красиво выглядят на передней панели любого микропроцессорного устройства. Все ЖКИ дисплеи подразделяются на два больших класса: цифровые семисегментные дисплеи и алфавитно-цифровые знакосинтезирующие. Первый класс индикаторов содержит одну или несколько строк, состоящих из семисегментных разрядов. По расположению сегментов такие дисплеи похожи на уже знакомые нам светодиодные. В знакосинтезирующих индикаторах каждый из разрядов представляет собой матрицу точек, в которой могут отображаться не только цифры, но и буквы, а также любые другие символы. Эти индикаторы более дорогие по сравнению с семисег-ментными, но зато они гораздо более информативны.
В литературе вы уже могли встречать описание различных конструкций с использованием готовых ЖКИ индикаторов. Например, в [2] приведена схема и описание цифрового термометра на основе ЖКИ модуля АС161В. Мы же в качестве примера возьмем ЖКИ модуль типа МТ-10Т7-7 российской фирмы МЭЛТ. Внешний вид этого модуля показан на рис. 2.4.
Основные характеристики модуля МТ- 10Т7-7:
Тип индикатора....................цифровой семисегментный;
Количество строк..................I;
Количество разрядов...............10;
Напряжение питания................минимальное	+3	В;
максимальное +5 В;
Ток потребления...................30 мкА;
Способ регулировки контрастности..ручной (внешний резистор);
Количество выводов................12;
Габаритные размеры................66x31,5x9,5	мм.
Жидкокристаллический дисплей
79
Рис. 2.4. Жидкокристаллический дисплей МТ- 10Т7-7
Модуль МТ-10Т7-7 — это недорогой, достаточно распространенный однострочный индикатор, содержащий десять семисегментных разрядов для вывода цифровой информации. Выводы модуля выполнены в виде контактных площадок на печатной плате с отверстиями для пайки проводов. Назначение выводов модуля показано в табл. 2.1.
Назначение выводов ЖКИ модуля МТ- 10Т7-7
Таблица 2 1
Номер вывода	Название цепи	Назначение
1	АО	Вход выбора «адрес/данные»
2	WR2	Инверсный вход синхронизации записи
3	WR1	Прямой вход синхронизации записи
4	DB3	Разряд 3
5	DB2	Разряд 2
		Шина данных/адреса
6	DB1	Разряд 1
7	DB0	Разряд 0
8	GND	Общий провод
9	V0	Вход управления контрастностью
10	+Е	Питание модуля
11	+L	Не используется
12	-L	Не используется
Как видно из рис. 2.4, ЖКИ модуль МТ-10Т7-7 представляет собой печатную плату из стеклотекстолита, на которой установлена БИС специализированного контроллера в бескорпусном исполнении, а также ЖК панель. Модуль можег отображать 10 знакомест.
80
Другие варианты схем ввода-вывода
Каждое знакоместо — это семисегментный цифровой индикатор с точкой. Расположение и наименование сегментов в каждом разряде индикатора аналогично светодиодному индикатору (см. рис. 1.7). Функциональная схема модуля МТ-10Т7-7 показана на рис. 2.5.
Система управления построена таким образом, что каждый сегмент каждого разряда может быть включен или выключен независимо от всех остальных сегментов. Специализированный контроллер содержит десять восьмиразрядных регистров хранения информации (SG1...SG10). Каждый регистр управляет одним разрядом ЖКИ (см. табл. 2.2). Одиннадцатый регистр — это регистр блокировки. Он используется для хранения признака временной блокировки работы модуля. Каждый из регистров SG1...SG10 разделен на две тетрады. То есть на два полурегистра по 4 разряда в каждом. Они обозначены на функциональной схеме буквами Н (старший) и L (младший).
Рис. 2.5. Функциональная схема дисплея МТ-1ОТ7-7
Адреса регистров ЖКИ модуля
Таблица 2.2
№ знакоместа	1	2	3	4	5	6	7	8	9	10	-
Наименование регистра	SG1	SG2	SG3	SG4	SG5	SG6	SG7	SG8	SG9	SG10	Блокировка
Адрес (HEX)	00	01	02	03	04	05	06	07	08	09	0F
Жидкокристаллический дисплей
81
Разделение управляющих регистров на полурегистры необходимо для уменьшения количества управляющих выводов. Модуль имеет всего четыре входа для записи данных (DB0...DB3) и три входа управления. Входы DB0...DB3 используются как для ввода данных, так и для ввода адреса. Для переключения режимов «Адрес/дан-ные» служит вход АО. Если на этот вход подать низкий логический уровень, то сигналы на входах DB0...DB3 будут интерпретироваться как адрес. Если на входе АО высокий уровень, то входы DB0...DB3 используются для ввода данных. Входы WR1 и WR2 — это входы разрешения записи. Первый из них — прямой, второй — инверсный. Запись данных или адреса происходит только в том случае, если уровень сигнала на входе WR1 равен единице, а уровень сигнала на входе WR2 при этом равен нулю. Наличие двух входов управления записью позволяет упростить схему в случае параллельного включения нескольких модулей. Если модуль только один, удобно вывод WR2 напрямую соединить с общим проводом, а процессом записи управлять при помощи входа WR1.
Рассмотрим теперь логику управления ЖКИ модулем МТ-ЮТ7-7. Диаграмма сигналов на входах модуля в процессе записи приведена на рис. 2.6. Этот рисунок будет иллюстрировать описание управляющего алгоритма. Допустим, что нам нужно высветить какой-либо символ в первом (самом левом) разряде индикатора. Для управления этим разрядом служит регистр SG1 (см. табл. 2.2). Поэтому нам нужно записать в регистр SGI некий код, который соответствует высвечиваемому символу. Для этого сначала нужно передать в модуль адрес этого регистра.
Процесс передачи адреса происходит следующим образом: прежде всего на входы DB0...DB3 подается значение адреса (для регистра SG1 адрес равен ООН). Затем на входе АО необходимо установить низкий логический уровень. Завершается процесс записи адреса коротким положительным импульсом на входе WR1 (при условии, что на входе WR2 ноль). По переднему фронту этого импульса значение адреса записывается во внутренний регистр адреса модуля. Теперь, когда адрес нужного регистра записан, можно приступить к записи в этот регистр кода символа. Код записывается в два приема. Сначала записывается младший полубайт, затем старший. Полубайты записываются один за другим.
Система управления модуля автоматически помещает первый из полученных полубайтов в младшую часть регистра (SGl(L)), а второй полубайт в старшую его часть (SGl(H)). Запись данных происходит точно так
82
Другие варианты схем ввода-вывода
же, как и запись адреса. Однако, на входе АО теперь должен присутствовать сигнал логической единицы. Сначала на входы DB0...DB3 подается младший полубайт. Положительный импульс на входе WR1 записывает информацию в модуль. Затем на входы DB0...DB3 подается старший полубайт. Следующий единичный импульс на входе WR1 записывает и его. После записи обоих полубайтов значение адреса во внутреннем регистре адреса ЖКИ модуля автоматически увеличивается на единицу. Это позволяет записывать коды символов в несколько регистров подряд, без дополнительных операций по записи адреса. Этот режим, как и режим однократной записи, наглядно показан на рис. 2.6.
Рис. 2.6. Временные характеристики процесса записи управляющих сигналов
Теперь разберемся с тем, какие коды нужно записывать в регистры модуля для того, чтобы высветить на индикаторе тот или иной символ. Как уже говорилось, каждому разряду любого из регистров SGx соответствует свой сегмент семисегментного индикатора. В таблице на рис. 2.7 показано соответствие разрядов регистра и сегментов индикатора. Высокий логический уровень включает соответствующий сегмент, а низкий уровень его выключает. На рис. 2.7 показаны коды, которые нужно записывать в регистр SGx для того, чтобы высветить тот или иной символ.
Как видно из рисунка, на семиссгментном индикаторе можно высвечивать нс только символы цифр от «О» до «9», но и другие знаки и даже некоторые буквы. В наш пример дополнительно включены символы латинского алфавита от «А» до «F», символ градуса («°»), минус, а также буквы «г» и «о». Символы латинского алфавита используются для отображения на индикаторе чисел в шестнадцатеричной форме. Знак минус и символ градуса можно использовать для индикации температуры. Буквы «г» и «о» используются для вывода на индикатор слова «Error» (ошибка). Возможности по отображению букв у семисегментного индикатора ограничены. Так пришлось буквы
Жидкокристаллический дисплей	83
«Ь», «d», «г» и «о» сделать строчными, а остальные буквы заглавными. Это немного затрудняет читаемость при отображении цифр в шестнадцатеричном формате. Но к этому легко привыкнуть.
И, наконец, еще один символ, который приведен в таблице на рис. 2.7 — это символ пробела. Пробел — это когда не один из сегментов не светится. Символ пробела удобно выводить на индикатор в том случае, когда между двумя цифрами на экране должен быть промежуток.
Разряд	Cer-мент	Символы										
		A	b	c	d	E	F		0	-	r	0
DBO(L)	g	1	1	0	1	1	1	0	1	0	0	0
DB1(L)	e	1	1	1	1	1	t	0	0	0	0	1
DB2(L)	d	0	1	1	1	1	0	0	1	0	0	0
DB3(L)	a	1	0	1	0	1	1	0	0	0	0	0
DBO(H)	h	0	0	0	0	0	0	0	1	0	0	0
DB1(H)	b	1	0	0	1	0	0	0	0	0	0	1
OB2(H)	c	1	1	0	1	0	0	0	0	0	1	1
OB3(H)	f	1	1	1	0	1	1	0	1	1	1	1
Рис. 2.7. Схема соответствия разрядов регистра и сегментов индикатора
Каким же образом определяются коды, приведенные на рис. 2.7? Это делается очень просто. Достаточно посмотреть на изображение семисегментного индикатора в правой верхней части рисунка и представить себе, какие из сегментов индикатора должны быть включены, а какие выключены для отображения того или иного символа. Затем нужно проставить в строке, соответствующей каж
84
Другие варианты схем ввода-вывода
дому из сегментов ноль либо единицу. Ноль, если сегмент должен быть выключен, а единицу, если включен. Сегмент «11» (десятичная точка) будем считать пока выключенным.
Как будут выглядеть описанные выше символы и как кодируется каждый из них видно из табл. 2.3. В графе SG(L) этой таблицы приводится младший полубайт кода символа. В графе SG(H) — старший полубайт. Это те же самые значения, которые мы уже видели на рис. 2.7. В графе HEX представлен уже полный код символа в шестнадцатеричном виде. Полный код получается путем объединения обоих полубайтов (SG(H) и SG(L)).
Аппаратная кодировка символов для ЖКИ модуля	Таблица 2.3
Изображение	SG(H)	SG(L)	HEX	Изображение	SG(H)	SG(L)	HEX
п и	1110	1110	ОЕЕН	Я	1110	1011	ОЕВН
1 1	0110	0000	060Н	О	1100	0111	0С7Н
р	0010	1111	02FH	г L	1000	1110	08ЕН
3	оно	1101	06DH	Г1	0110	0111	067Н
ч	1110	0001	0Е1Н	Е	1000	1111	08FH
S	1100	1101	0CDH	F	1000	1011	08ВН
8	1100	1111	0CFH	О	1010	1001	0А9Н
"1 1	0110	1000	068Н	-	0000	0001	001Н
8	1110	1111	0EFH	г	0000	0011	ООЗН
п □	1110	1101	0EDH	О	0100	0111	047Н
Подключение ЖКИ дисплея к микроконтроллеру	85
И последнее, о чем нужно сказать в этом разделе, так это о регистре блокировки. Этот регистр не разделен на два полурегистра. Напротив, он имеет всего один действующий бит. Этот бит соответствует входу DB0. При записи нуля в разряд DB0 регистра блокировки, работа модуля блокируется. Запись во все остальные регистры модуля становится невозможной. Режим блокировки действует на 30 циклов записи. То есть, если в этом режиме пытаться все же записывать информацию, то после 30 попыток режим блокировки автоматически снимается. Если режим блокировки нужно снять раньше, то нужно просто записать единицу в разряд DB0 регистра блокировки.
2.5.	Подключение ЖКИ дисплея к микроконтроллеру
Подключать ЖКИ модуль МТ-10Т7-7 к микроконтроллеру очень просто. Учитывая, что вход WR2 мы напрямую подключаем к общему проводу, для управления модулем потребуется всего 6 линий. Одна из возможных схем подключения изображена на рис. 2.8. В этой схеме для управления ЖКИ модулем используется порт Р1 микроконтроллера. В качестве шины данных/адреса (DB0...DB3) используются четыре младших разряда порта.
Рис. 2.8. Пример схемы подключения ЖКИ модуля к микроконтроллеру
86
Другие варианты схем ввода-вывода
Для управления входами АО и WR1 можно было бы использовать любые два из остальных выводов порта. В данной схеме для управления входом АО используется линия PI.6, а для управления входом WR1 — линия Р1.4. Выбор именно этих линий обусловлен исключительно соображениями удобства разводки печатной платы. Удобство при разводке особенно важно в случае применения плоского кабеля, где запутывать провода нежелательно. Резисторы R1 и R2 выполняют роль нагрузки для линий Р1.0 и PI.1 микроконтроллера. Резистор R3 служит для регулировки контрастности изображения. Каждый конкретный экземпляр ЖКИ модуля требует подстройки контрастности. Контрастность выставляется таким образом, чтобы включенные сегменты были видны максимально ярко, но при этом сегменты, которые должны быть отключены, на индикаторе не просматривались.
2.6.	Управляющая программа для ЖКИ модуля
В этом разделе мы рассмотрим целый пакет подпрограмм, предназначенный для работы с ЖКИ модулем МТ-10Т7-7, включенным по схеме, изображенной на рис. 2.8. Пакет состоит из четырех подпрограмм (см. листинг 2.3). Все подпрограммы пакета тесно взаимосвязаны между собой. Применять эти подпрограммы необходимо только вместе в составе пакета, так как некоторые из них не будут работать самостоятельно.
Но сначала небольшая вступительная часть. Как и в случае со светодиодным дисплеем (см. раздел 1.3), в нашем примере все отображаемые символы кодируются двумя разными способами. С одним видом кодировки мы познакомились при составлении табл. 2.3. В этой таблице приведены коды, которые нужно (в два приема) выдавать на индикатор для того, чтобы высветить необходимый нам символ. Такой набор кодов можно назвать аппаратной кодировкой. От нее никуда не денешься: она заложена в конструкцию ЖКИ модуля.
Однако использовать такой способ кодирования в программе неудобно. Значение кода не связано с функцией высвечиваемого знака. С такими кодами затруднительно производить логические
Управляющая программа для ЖКИ модуле
87
операции и различные вычисления. Учитывая то, что модуль МТ-10Т7-7 в основном ориентирован на вывод чисел, было бы гораздо удобнее, чтобы код символа по возможности совпадал с его значением. Такая кодировка приведена в табл. 2.4. Символу «О» присвоен код ноль (ООН). Символу «1» — код единица (01Н) и так далее. Так как буквы латинского алфавита A, b, С, d, Е и F предназначены для отображения шестнадцатеричных чисел, то им присвоены коды с 10 по 15. Для остальных символов выбор кодов может быть любым. Поэтому коды этих символов продолжают начатую последовательность. Такой способ кодировки мы будем называть естественной кодировкой.
В процессе вывода символа на индикатор производится перекодировка. Как и в случае со светодиодным индикатором для перекодировки используется специальная таблица символов. В листинге 2.3 таблица занимает строки 59...79. Естественно, в нашем случае таблица содержит уже другие значения. Если точнее, таблица содержит коды символов в аппаратной их кодировке, а порядок расположения их в таблице соответствует естественной кодировке.
Естественная кодировка символов	Таблица 2.4
Символ	Код	Символ	Код	Символ	Код
п IJ	С	1 1	7	с	14
I 1	1	8	8	f	15
“1 L	2	5	9	Пробел	16
3 J	3	О 11	10	о	17
и 1	4	L и	11	-	18
5	5	г L	12	г	19
ь	6	IJ	13	о	20
Теперь перейдем к рассмотрению текста подпрограмм. Пакет состоит из четырех подпрограмм. Подпрограммы вывода символа на экран prehr, подпрограммы установки начальных значений eres.
88
Другие варианты схем ввода-вывода
подпрограммы очистки экрана eclr и подпрограммы установки курсора ecur. Для нормальной работы всех подпрограмм пакета в самом начале программы нужно описать два управляющих сигнала: сигнала АО и сигнала WR1. Указанные символьные имена закрепляются за линиями PI.4 и Р1.6. (см. листинг 2.3, строки 6 и 7).
Начинать изучение пакета подпрограмм удобнее с подпрограммы начального сброса eres. Эта подпрограмма, в паре с подпрограммой eclr, переводит все внутренние регистры ЖКИ модуля в исходное состояние. Такая операция должна обязательно выполняться в самом начале работы, сразу после включения питания. Дело в том, что ЖКИ модуль МТ-10Т7-7 не имеет собственной схемы начального сброса. После подачи напряжения питания во всех его внутренних регистрах устанавливаются случайные значения. Установить начальные значения можно только программным путем. Причем начинать нужно с записи единичного уровня в триггер блокировки (снять блокировку). Кроме этого, подпрограмма eres производит начальную установку курсора. Это не тот курсор, который мы видим на экране компьютера в виде мигающей черточки. Этот курсор никак нс обнаруживает себя на экране. Под курсором здесь понимается текущее значение адреса, то есть адрес регистра, куда будет выводиться очередной символ (см. табл. 2.2). Этот адрес хранится внутри ЖКИ модуля в специальном регистре адреса. Подпрограмма eres перемещает курсор в начальную, самую левую, позицию (устанавливает текущий адрес равным ООН).
Текст подпрограммы eres занимает в листинге строки 36...45. В строках 36...41 выполняется установка значения триггера блокировки. Делается это в следующем порядке: сначала текущий адрес модуля устанавливается равным адресу триггера блокировки. Для записи адреса выполняются строки 36...38. В строке 36 в порт PI записывается код 0FH. Этот код одновременно определяет и значение адреса (четыре младшие разряды), и значение управляющих сигналов (Р1.4 и Р1.6). Адрес поступает на входы DB0...DB3 модуля. Оба управляющих сигнала принимают нулевое значение. Ноль с линии Р1.6 поступает на вход АО модуля и переводит его в режим записи адреса. Затем формируется положительный импульс на входе WR1 (строки 37 и 38), который вызывает запись адреса. В результате «курсор» устанавливается на триггер защиты. Теперь в триггер защиты осталось записать нужное значение. Запись единичного значения в триггер происходит в строках 39...41. В строке 39 в порт Р1 записывается число, подготавливающее схему к вводу
Управляющая программа для ЖКИ модуле
89
данных. Единица в младшем разряде этого числа предназначена для записи в триггер защиты. Единица в шестом разряде поступает в разряд PL6, а значит, и на вход АО и переводит ЖКИ модуль в режим приема данных. Отрицательный импульс (строки 40. 41) завершает процесс записи.
В строках 42...44 происходит начальная установка курсора. В про цсссе начальной установки адрес курсора должен установиться в ноль. Для этого в порт Р1 записывается код ООН (строка 42). Он подготавливает режим записи адреса. Все разряды этого кода равны нулю. Четыре младших разряда поступят на входы DB0...DB3. Нулевой сигнал на выходе Р1.6 переводит схему в режим записи адреса. Завершается запись положительным импульсом на входе WR1 (строки 43, 44). Оператор ret (строка 45) завершает всю подпрограмму.
Подпрограмма очистки экрана eclr предназначена для полного «стирания» информации с индикатора. Она вызывает отключение всех сегментов во всех разрядах индикатора. Подпрограмму очистки экрана удобно вызывать каждый раз перед выводом на индикатор нового изображения. Такой прием гарантирует отсутствие на экране лишних символов, оставшихся от предыдущего изображения. Текст программы занимает строки 46...52. Начинается подпрограмма очистки экрана с вызова рассмотренной выше процедуры начального сброса (строка 46). Вызов начального сброса в подпрограмме очистки экрана повышает устойчивость всей системы к случайным сбоям в результате внешних помех. После окончания начального сброса курсор указывает на самый первый разряд индикатора. Поэтому, нам вообще больше не потребуется установка адреса.
Для очистки экрана нам остается только перейти в режим ввода данных и записать во все разряды индикатора ООН в режиме группового ввода. Такой код вызовет выключение всех сегментов каждого разряда. Код каждого разряда должен передаваться в два приема. Но значения обоих полубайтов в нашем случае равны нулю. Поэтому мы должны подать на входы DB0...DB3 полубайт, имеющий нулевое значение и 20 раз повторить положительный импульс записи на входе WR1. Этим и занимается остальная часть подпрограммы eclr. Для подготовки этой операции в порт Р1 помещается код 01000000В (строка 47). Единица в шестом разряде этого числа поступает на вход АО и переводит модуль в режим приема данных. Четыре младших разряда равны нулю и поступают на входы DB0...DB3.
90 Другие варианты схем ввода-вывода
Далее организуется цикл, который формирует двадцать импульсов записи на входе WR1. Тело цикла занимает строки 49...51. В качестве параметра цикла используется регистр гО. В строке 48 ему присваивается начальное значение. Тело цикла содержит лишь пару команд, которые формируют положительный импульс записи (строки 49, 50). Оператор организации цикла (строка 51) обеспечивает его двадцатикратное повторение. Сразу по окончании цикла подпрограмма eclr завершается (строка 52).
Подпрограмма установки курсора ecur позволяет устанавливать курсор в любую позицию экрана. Это существенно облегчает вывод символов в том случае, когда нужно вывести надпись посередине зкрана или переписать только один символ в уже имеющейся надписи. Требуемое положение курсора передается подпрограмме в качестве параметра через аккумулятор. Текст подпрограммы приведен в строках 53...57. Как видим — это самая простая подпрограмма из всех подпрограмм пакета. Сначала в переданном коде принудительно обнуляются четыре старших бита (строка 53). Затем, полученный таким образом код записывается в порт Р1 (строка 54) В результате на управляющих входах АО и WR1 установятся нулевые уровни, а на входах DB0...DB3 код, соответствующий новому положению курсора. Положительный импульс на входе WR1 (строки 55, -56) записывает новый адрес курсора в ЖКИ модуль. В строке 57 подпрограмма ecur завершается.
Листинг 2.3
Па. . . -. 	• КИ ; з МТ-10Т7-7
.......... ипоецележе чокган!
Ljh .-.-.г.-и	ri
ЕОУ	ИИ11ХЮ8
ЕОЬ	Кй1000Ьв
EQu	ЭДИ100М
BIT	Р1 6	Адрес,'Данъг
BIT	Р1 4	Запись

МВ
ОРЗ ийн	ыека
D3 2JH ; гл,г ина стека
Управляющая программа для ЖКИ модуле
91
Сюда вы должны поместить модрь инкдцализаиии и текст основной программы
:########################################«##«##
	,## Под ограмма	ВЫ-	.. V- 1/j M i i‘	ШИ fin
	;#################################«############		
11	prcnr	pysn	LrL	toxpai «'>'!  p ।дон в iiih’
12	push	DPH	
13	push	к	
14		DPTP Its	. Начало габлид. cxMSuiiDB
15	MV	c.kc 7	бодантем з-ачеиго точки
16	cl г	ace 7	Сбцвсываем значение бита
17	INJVK	a Ad+DPTR	. Пс -аем выводимый »г-г,
18	MV	act 4,c	 Вс.	-.ем	-»• ? точки
19	wov	S.a	.... -чем его в b
20	ДЛ1	a #CFH	Отд^ -.зм нладь’й Г.	, 5..И'
21	mov	p1,a	Выводим его на .-мди.-ни»
22	setb	AO	Вил режима вывела дачка<
23	sett.	WR1	Им'	дОПМСИ
24	wl	WR1	
25	MV	a.b	Востанавливаем выводимый код
26	?#ap	a	Меняем т«гргат
27	anl	j,#OFH	О'дмлд-ч съ.г.лх полубайт
28	IDIJV	p1,a	Выводим С". । 1 индикатор
29	set*)	AO	Вкл №»>иа амведа оамых
J0	Mjtb	WR1	Инг ,	. '.’си
31	clr	WR1	
32	pop	b	Вс-, -ановле- * риги . -
33	pop	DPH	
34	pop	DPL	
35	ret		
-,«»1аяввиаип#»11««аа«яий«й»»й«4»йй«««йи#»«
;ИП	Сброс ЖКИ модуля ни
,##ШШШ######ШШ»Ш#ШШШ«
3	erw	mov	pl.BOFH	* Ззсилжм адрес реглета блошфсйи*
37		setb	WR1	
38		clr	WR1	
39		mov	p1, #010000016	~V3blB?£M КОД снятия
40		setb	WR1	
41		cP	WR1	
42		mov	p1,#0	, уста lefi'WjfM	ч. 'kitMai пгг.
43		setb	WR1	
44		clr	WR1	
45		>et		
92
Другие варианты схем ввода-вывода
:#««####в###в#####ввв##вв####в########в
,ВВ	Очистка экрана	ft#
#ВВ#В##в«####ВВ##В#В#В##ВВ#ВВ#В######В
46	eclr:	call	eres	Сброс экрана
47		mov	pt #010000006	Установка управляющего кода
48		mov	r0,#20	. Инициализация счетчика разрядов
49	сП	setb	WR1	Импульс записи
50		clr	WR1	
51		djnz	rO.cll	; Оператор цикла
52		ret		
###############В##############В8#В#####В#Й
;tttt	Установка курсора	«в
: ВВВ88ЙЙЙ8Й##ВВЙЙ8Й#ЙВЙ##Й88ЙЙ8ЙЙЙЙЙ8#В88ЙЙ
53	есиг:	ап1	a, #0FH	Отделяем биты адреса
54		mov	pl. a	Устанавливаем адрес на первый разряд
55		setb	WR1	
56		clr	WR1	
57		ret		
. Сюда вы можете поместить другие подпрограммы.
Й##88##ВВ8ЙЙ#ЙЙ#8###В##8В8#####8##8#888####Й
Таблица символов
.ввввввввввввввввввввввввввавввваввввввавввва
58		ORG	0600H	
59	ts	06	OEEH	;0
60		06	060H	1
61		06	02FH	;2
62		06	06DH	;3
63		06	0E1H	.4
64		06	OCDH	,5
65		06	OCFH	;6
66		06	068H	;7
67		06	OEFH	;8
68		06	OEDH	:9
69		06	0E6H	:A (10)
70		06	0C7H	;b (11)
71		OB	08EH	.c (12)
72		OB	067H	d (13)
Управляющая программа для ЖКИ модуле
93
73	ОВ	O8FH	,Е (14)
74	ОВ	08ВН	;F (15)
75	ОВ	COCH	(16)
76	ОВ	ОА9Н	(17)
77	ОВ	001Н	(18)
78	ОВ	оозн	г (19)
79	ОВ	047Н	,о (20)
80	end		Конец программы
И последняя подпрограмма пакета — prchr Она предназначена для вывода символа на экран. Текст подпрограммы занимает строки 11 ..35. Код символа (в естественной кодировке, см. табл. 2.4) передастся в подпрограмму через аккумулятор. Подпрограмма производит вывод символа на экран ЖКИ индикатора в текущую позицию курсора. После того, как символ будет выведен, позиция курсора автоматически перемещается на один разряд вправо
Кроме задачи по выводу символа, подпрограмма решает и еще одну: управляет отображением десятичной точки. Информация о значении десятичной точки также передается через аккумулятор. Для этого используется самый старший бит аккумулятора. По сути, для передачи кода символа используются разряды 0...6 аккумулятора. А седьмой, самый старший разряд, передает значение десятичной точки. Если этот разряд равен единице — точка «зажигается», если нулю — точка «погашена».
В аналогичной программе для светодиодных индикаторов (ли стинг 1.4), используется другой способ управления точками Применив новый способ решения старой задачи, я хотел показать, что все приведенные в книге программы нс догма, а всего лишь пример одного из вариантов решения поставленной задачи.
В начале работы подпрограмма prchr сохраняет в стеке регистры b и DPTR (строки 11... 13). Регистр DPTR сохраняется в два приема. Сначала его младшая часть — DPL (строка 11), а затем старшая — DPH (строка 12). Сохранение регистра b происходит в строке 13.
Основная часть подпрограммы начинается с перекодировки символов. Для этого в регистр DPTR записывается адрес начала таблицы символов (строка 14). Далее от входного кода отделяется признак, передающий информацию о десятичной точке. Значение этого признака извлекается из старшего бита аккумулятора и временно по
94
Другие варианты схем ввода-вывода
мешается в ячейку CY (строка 15). Затем старший бит аккумулятора обнуляется (строка 16), чтобы не мешал процессу перекодировки Теперь все готово для перекодировки. В аккумуляторе находится естественный код символа.
В регистре DPTR адрес начала таблицы символов. Для того, чтобы получить аппаратный код того же символа, достаточно просто извлечь из таблицы символов код по адресу a+DPTR, что и происходит в строке 17 программы. Полученный код тоже помещается в аккумулятор. Теперь можно приступать к его выводу в текущий разряд ЖКИ модуля. Но предварительно нужно учесть значение десятичной точки. Это значение у нас пока хранится в ячейке CY. В строке 18 бит из ячейки CY помещается в четвертый разряд аккумулятора. Именно этот разряд в аппаратном коде символа отвечает за десятичную точку (см рис. 2.7 и табл. 2.3).
Последний этап — вывод кода в ЖКИ модуль. Для этого код сначала нужно разделить на две тетрады и вывести эти тетрады по очереди. Сначала копия полученного кода сохраняется в регистре b (строка 19). Затем при помощи маски 0FH выделяется младшая тетрада (строка 20). Применение маски обнуляет старшие разряды аккумулятора, оставляя четыре младших разряда без изменения. В строке 21 значение аккумулятора записывается в порт Р1. Младшая тетрада появляется на входах DB0...DB1 ЖКИ модуля Следующая команда (строка 22) устанавливает единичное значение на входе АО. В результате модуль переходит в режим записи данных. Короткий положительный импульс на входе WR1, сформированный в строках 23 и 24 программы, записывает младшую тетраду.
Следующий этап — вычисление старшей тетрады. Сначала код, временно хранящийся в регистре Ь, снова помещается в аккумулятор (строка 25). Оператор swap в строке 26 меняет между собой старшую и младшую тетрады. Ненужные разряды аккумулятора обнуляются (строка 27). В результате этих действий в младших разрядах аккумулятора оказывается нужная нам старшая тетрада. Запись старшей тетрады в ЖКИ модуль происходит аналогично записи младшей (см. строки 27. .31)
Сразу после записи второй тетрады изображение символа появится в текущем разряде индикатора, а положение «курсора» переместится в следующую позицию. Напомню, что перемещение курсора происходит автоматически. Это свойство системы управления самого ЖКИ модуля.
Управляющая программа для ЖКИ модуле
95
Описанный выше пакет подпрограмм позволяет выводить на индикатор любые символы в любом месте экрана. Это могут быть как цифры, так и некоторые служебные надписи. Для вывода надписей удобно использовать специальную подпрограмму. Пример такой подпрограммы приведен в листинге 2.4. Она называется prstr и предназначена для вывода на индикатор целого слова, состоящего из любых букв и знаков.
Для того, чтобы лучше понять, зачем нужна подпрограмма prstr, на том же листинге приведен еще один пример: это универсальная подпрограмма индикации ошибки prErr. Ее назначение — просто вывести посередине экрана сообщение, состоящее из слова «Error» и цифры, означающей номер ошибки. Подпрограмма prErr для вывода на экран слова «Error» использует подпрограмму вывода сообщений prstr Рассмотрим принцип работы обеих подпрограмм по порядку Начнем с подпрограммы prstr. Это универсальная процедура для вывода на индикатор слов, состоящих из любых допустимых символов Слово, предназначенное для вывода на индикатор при помощи подпрограммы prstr, нужно предварительно поместить в программную память микроконтроллера в виде цепочки байтов. Такая цепочка называется сообщением. Каждый байт сообщения — это код одного из символов нашего слова в естественной кодировке. Коды должны располагаться в таком же порядке, как символы располагаются слове. В конце цепочки нужно добавить еще один байт, имеющий нулевое значение. Он будет служить признаком окончания слова.
В листинге 2.4, таким образом описано слово «Error» (строка 21) Для того, чтобы вывести это сообщение на индикатор, нужно поместить адрес начала этого сообщения в регистр DPTR, а затем вызвать подпрограмму prstr. Она считывает из программной памяти коды символов, начиная с адреса, записанного в DPTR, и последовательно выводит соответствующие им символы на индикатор. Для вывода символов используется описанная в предыдущем примере подпрограмма prehr (см. листинг 2.3). Завершается процесс вывода символов тогда, когда очередной код окажется равным нулю.
Листинг 2.4
шштшшштшшштшптт11шт
.tilt Подпр грамма вывода сообиггмя на экран tttt
1 prstr push psw	Сохранение регис-ад psw
srev psw #bank3	Включаем б?н« 3
96
Другие варианты схем ввода-вывода
3	ps1:	mov	a.#0	
4		move	a.@a+OPTR	Полуи । .1 :и . "лив га
5		cjne	a.BC,ps2	Если ЭТО ИВ «ОСМвгий ВъвМИИ
6		pop	psw	Завершен^.? пр-г  чины
7		ret		
8	ps2:	call	prehr	Виас . М	Hl 34.UH
9		inc	DPTR	»йвпн‘1йвб®м хня^ние
10		jmp	pst	
	в11#вввв#вв#11в#в##ввв##вввввв#в##ввв#вввввввввв#вв#ввв1г			
	:В«		Вывод сообщения об ошибке	#в
	.вввв#ввввйв#й#ввв#й11В11вв11#в##ввв#в#ввйввввв11ввввввв#вв			
11	ргЕгг	push	асе	
12		call	eclr	очистить
13		mov	а, В2	, . в । ию 2
14		call	есиг	
15		mov	DPTR.Bserr	Вывес.и	-Error-
16		call	prstr	
17		pop	асе	
18		call	prehr	Ьо1ВО,п. f-.йц. :
19		ret		
				 I_,uo6ll) :‘НИЯ	
20		ORG	0680Н	
21	serr	OB	14,19.19.20.19.0	Error
Текст подпрограммы prstr занимает строки I ...10. Подпрограмма начинается с сохранения регистра psw в стеке и включения банка 3 РОН (строки 1, 2). Затем начинается цикл вывода сообщения Этот цикл не похож на циклы, с которыми мы до сих пор имели дело. До сих пор для организации цикла мы использовали оператор djnz. В цикле вывода сообщений этот оператор не используется. Цикл завершается только в том случае, если в процессе вывода сообщения встретится нулевой байт. Рассмотрим, как это происходит. Сразу после вызова подпрограммы в регистре DPTR находится адрес начала сообщения.
Цикл начинается с извлечения первого байта этого сообщения. Сначала в аккумулятор записывается нулевое смещение (строка 3). Затем, при помощи оператора move a,@a+DPTR из программной памяти извлекается очередной байт (строка 4). Затем значение этого байта проверяется на равенство нулю (строка 5). Если считанный код равен нулю, то подпрограмма завершается (строки 6, 7). Если код не равен нулю, то управление передается по метке ps2 и цикл продолжается. В строке 8 вызывается подпрограмма prehr, которая
Управляющая программа для ЖКИ модуле
97
печатает символ, соответствующий извлеченному байту. В строке 9 содержимое регистра DPTR увеличивается на единицу.
Затем управление передается в начало цикла (безусловный переход в строке 10). Цикл повторяется. Причем извлекается уже следующий байт сообщения. Для корректной работы подпрограммы prstr нужно не забывать ставить ноль в конце сообщения. Иначе подпрограмма будет выводить на экран все последующие коды до тех пор, пока ей случайно не встретится в памяти нулевой кол. В результате вы получите на экране полный хаос.
Текст подпрограммы prErr занимает строки 11... 19. При вызове подпрограммы в качестве параметра ей передается номер ошибки. Передача параметра происходит через аккумулятор. Подпрограмма начинается с команды сохранения содержимого аккумулятора в стеке (строка 11). В данном случае стек используется нс так, как мы привыкли. Просто в данном случае удобно использовать стек для временного хранения параметра. В конце подпрограммы мы извлечем из стека номер ошибки и выведем его на экран. Но сначала нам нужно очистить экран ЖКИ модуля и вывести слово «Error». Вызов подпрограммы очистки экрана производится в строке 12. Затем производится установка курсора в позицию номер два (третий символ слева). Это нужно для того, чтобы надпись оказалась в центре экрана. Для установки курсора в аккумулятор помещается номер позиции (строка 13), и вызывается подпрограмма есиг (строка 14). Затем в регистр DPTR помещается адрес начала сообщения (строка 15) и вызывается подпрограмма prstr (строка 16). На экране появляется слово «Error». При выводе каждого символа сообщения курсор автоматически перемещается Поэтому, после вывода всего сообщения, курсор будет указывать на следующую после слова позицию. Нам осталось вывести номер ошибки. Этот номер у нас находится в стеке. В строке 17 он извлекается из стека. А затем посылается на экран (строка 18). После чего подпрограмма prErr завершается (строка 19).
Аналогичным образом можно вывести на индикатор любую допустимую надпись, цифровые данные, а также то и другое вперемешку. В конце книги мы еще вернемся к нашему ЖКИ индикатору. Там описана схема цифрового термометра, которая использует индикатор для вывода температуры. Но сначала я хочу осветить большую интересную тему — подключение к микроконтроллеру периферийных устройств при помощи последовательных шин передачи данных.
4 Зак 922
3.1.	Общие сведения
В предыдущих главах мы рассмотрели основные способы подключения периферийных устройств, из разряда традиционных приемов. Описанные при этом схемы — это системы с параллельной передачей информации. Главный недостаток параллельного способа передачи информации — в них задействовано слишком большое количество выводов микроконтроллера. Можно, конечно, применить другой микроконтроллер. Например, микросхема АТ89С51 имеет четыре порта ввода/вывода. Существуют приемы расширения количества линий. Однако все эти приемы усложняют конструкцию. Как следствие, увеличивается время разработки системы, уменьшается ее надежность.
Современная микроэлектроника предлагает новые способы решения этих задач. В распоряжении современного разработчика существуют микросхемы, которые способны обмениваться информацией с любым микроконтроллером при помощи последовательной шины передачи данных. Устройство и логика работы таких шин может быть самая разная. В настоящей книге я хотел бы рассказать о двух самых популярных стандартах последовательных линий связи.
И начать я хочу с детища фирмы Philips, которое называется PC шина. Многим, кто имеет дело с микроэлектроникой, хорошо знакомо это оригинальное наименование. Название шины происходит от сокращения ПС, что расшифровывается, как «Inter 1С». Сокращение «1С» — это известное сокращение, которое расшифровывается как «интегральная схема». Поэтому «Inter 1С bus» расшифровывается примерно так: «межмикросхемная шина». Для большей наглядности сокращение ПС решено было записывать
Общие сведения	99
как ВС, Это довольно известный прием. Название «ВС» хорошо прижилось в микроэлектронике и известно всему миру.
Правда, не всегда возможна запись двойки с использованием верхнего индекса, поэтому в некоторых электронных документах можно встретить другой способ написания этого названия: I2C. Фирма Philips даже разработала официальную эмблему для ВС шины (см. рис. 3.1). Каждый, кто использует в своих разработках эту технологию, обязан поместить эту эмблему на одной из внешних панелей разрабатываемого устройства.
Рис. 3.1. Официальная эмблема PC шины
ВС шина была разработана около двадцати лет назад, и была задумана как средство передачи сигналов управления на различные микросхемы сложных электронных устройств. Например, современные телевизионные приемники широко используют наборы специализированных микросхем с цифровым управлением. Каждая микросхема служит основой целого блока. Существуют микросхемы радиоканала, декодера цветности, выходных видеоусилителей, системы синхронизации и другие. При этом сами микросхемы — это аналоговые устройства, осуществляющие преобразование сигналов традиционным способом. Однако, для уменьшения количества выводов и упрощения схемы соединений все регулировки внутренних параметров этих микросхем производятся при помощи цифровой системы управления, основанной на применении ПС шины.
Управляющие сигналы вырабатываются центральным процессором телевизора и передаются посредством ПС шины на все остальные элементы схемы. Процессор может изменять в процессе работы любые параметры в любом блоке телевизора. Таким образом, происходит регулировка яркости, контраста, насыщенности, громкости и т.д. Таким же образом происходит переключение и настройка телевизионных каналов, выбор телевизионного стандарта (PAL, SECAM, NTSC) и так далее. Подобная система управления при
100
Работа с l2C шиной
меняется и в других областях электронной техники. Например, в радиоприемниках, магнитолах, системах измерения и в промышленном оборудовании.
Первую спецификацию на PC шину (версии 1.0) фирма Philips выпустила в 1992 году. А к 1998 году PC шина стала фактическим мировым стандартом, который теперь применяется более чем в 1000 различных видов микросхем и лицензия на ее использование куплена более чем 70 компаниями. Спецификация на шину много раз дорабатывалась. Последний опубликованный стандарт на шину PC имеет номер версии 2.1.
Основные преимущества PC шины — это простота ее аппаратной реализации. Шина представляет собой двухпроводную линию, на которую параллельно подключаются все управляемые ею микросхемы. При этом нет никаких особенных требований к самим проводникам, составляющим шину. Устройства, подключаемые к шине, должны иметь специальный PC интерфейс, который аппаратным путем реализует всю логику работы шины. Существует также возможность программной реализации PC интерфейса. В этом случае в качестве элементов, подключаемых к шине, выступают микроконтроллеры.
Технология передачи информации при помощи PC шины позволяет решать огромный спектр задач. Однако, исходя из темы нашей книги, нас будет интересовать только следующий аспект: подключение периферийных устройств к микроконтроллеру. Среди 150 видов микросхем производства фирмы Philips, имеющих PC интерфейс, и более 1000 видов микросхем других производителей мы можем ндйти практически все типы знакомых нам периферийных устройств, которые с успехом можно использовать при разработке любой микропроцессорной системы. Вот только краткий перечень этих устройств: аналого-цифровые и цифро-аналоговые преобразователи, контроллеры ЖКИ и светодиодных дисплеев, универбальныс порты ввода/вывода, преобразователи температуры и напряжения, микросхемы энергонезависимой памяти (EEPROM), контроллеры DIP переключателей и многое другое. Нужно только выбрать одну или несколько микросхем с нужными нам функциями и подсоединить к микроконтроллеру посредством 12С шины. Для присоединения всех этих устройств нам потребуется задействовать всего две линии ввода/вывода микроконтроллера.
Основные характеристики 12С шины
101
3.2.	Основные характеристики 12С шины
PC — это двухпроводная, двунаправленная шина, с Последовательной передачей данных. В стандартном режиме работы (Standard mode) шина может адресовать до 128 подключенных к ней устройств. Длина шины и количество подключаемых к ней устройств ограничены максимально допустимой суммарной электрической емкостью всех се элементов. Значение этой емкости нс должно превышать 400 пФ. Скорость передачи информации в стандартном режиме составляет 100 Кбит/с.
Последняя модификация шины (версия 2.1) предусматривает несколько дополнительных режимов работы:
Ускоренный режим (Fast mode) позволяет передавать данные со скоростью 400 Кбит/с.
Режим повышенной скорости (High-speed mode или HS-mode) разработан для современных высокоскоростных систем. Скорость передачи информации (bit rate) составляет 3,4 Мбит/с.
Режим 10-битной адресации позволяет адресовать до 1024 устройств на PC шине.
Все дополнительные режимы совместимы сверху вниз. Это значит, что микросхемы, поддерживающие один или несколько дополнительных режимов, без труда будут работать и в стандартном режиме.
В настоящей книге мы остановимся только на стандартном режиме работы PC шины с семибитовой адресацией. Если мы ставим перед собой задачу — просто подключить периферийное устройство к микропроцессору, то стандартного режима работы для этого будет вполне достаточно. Поэтому все, что вы прочтете далее в этой книге, относится только к стандартному режиму. Если вы желаете изучить работу шины в полном объеме, можете обратиться к официальной спецификации PC стандарта. Ее вы можете найти в Интернете на сайте фирмы Philips по адресу http://www.scmico-nductors.phiIips.com/acrobat/literature/9398/39340011 .pdf.
Итак, рассмотрим электрическую схему шины (см. рис. 3.2). Шина состоит из линии передачи данных (SDA) и линии синхронизации (SCL). Все PC устройства подключаются к обеим линиям шины параллельно. Кроме двух сигнальных проводников, все подклю
102
Работа с l2C шиной
чаемые к шине устройства должны иметь один общий провод (минус источника питания). Кроме того, на каждое из устройств необходимо подать напряжение питания. Источник питания не обязательно должен быть общим, однако в пределах одной шины все напряжения питания должны быть одинаковыми.
Рис. 3.2. Подсоединение микросхем к PC шине
Устройства, подключаемые к PC шине, по своему назначению делятся на ведущие (Master) и ведомые (Slave). Это известная терминология. Буквальная расшифровка терминов Master и Slave означает — «хозяин» и «раб». В русскоязычной литературе пользуются и теми и другими названиями. Для правильной работы, как минимум, одно из подключенных к шине устройств должно быть ведущим. Ведущее устройство берет на себя все управление шиной. Оно вырабатывает тактовые импульсы на шине синхронизации (SCL), а также инициирует сеансы передачи информации. Информация может передаваться как от ведущего устройства к ведомому, так и в обратном направлении. В обоих случаях процесс передачи информации управляется ведущим устройством. В зависимости от направления передачи информации, как Master, так и Slave устройство в разные моменты времени могут выступать в качестве передатчика (Transmitter), либо в качестве приемника (Receiver). Если информация передается от Master к Slave то Master-устройство выступает как передатчик, a Slave — как приемник. При передаче информации от Slave к Master, уже Master станет приемником, a Slave, соответственно, передатчиком
Каждое Slave-устройства, подключенное к PC шине, имеет свой уникальный адрес. Ведущее (Master) устройство имеет возможность обратиться к любому из ведомых, используя для выбора нужного
Схема построения 12С интерфейса
103
устройства его адрес. В стандартном режиме для адреса используется 7 бит информации.
В качестве ведущего (Maser) устройства чаще всего выступает микроконтроллер. Причем для этой цели подойдет практически любой существующий тип микроконтроллеров. Протокол обмена по PC шине реализуется обычно программным путем. Примеры таких программ будут подробно описаны в конце этой главы. Для подключения микроконтроллера к проводникам PC шины обычно используются любые две линии любого порта ввода/вывода микроконтроллера. Существуют микроконтроллеры, в которых PC интерфейс реализован аппаратным путем. Однако они имеют большую стоимость и применяются значительно реже. В качестве ведомых (Slave) устройств обычно используют специализированные микросхемы, имеющие встроенный PC интерфейс.
Шина PC допускает наличие на шине нескольких Master-устройств. Для этого в протоколе шины предусмотрена процедура синхронизации ведущих устройств между собой (Synchronization) и арбитражная процедура (Arbitration). Однако в задачи книги нс входит описание подобного режима.
3.3.	Схема построения !2С интерфейса
На рис. 3.3 показана принципиальная электрическая схема шины PC. На схеме условно показаны два устройства, подключенные к линиям SDA и SCL шины. Остальные устройства подключаются точно также. С электрической точки зрения линии SDA и SLC построены одинаково. Причем каждый из двух выводов PC интерфейса любой микросхемы должен быть и входом и выходом. Для правильной работы шины все выходные каскады должны быть построены по схеме с открытым коллектором, как это показано на рис. 3.3. Общие нагрузочные резисторы (RH), один для линии SDA и один для SLC, могут быть установлены в любом месте. Но чаше всего эти резисторы ставятся рядом с ведущим устройством. Через каждый из таких резисторов на линию поступает напряжение питания от источника VDD.
Такое схемное построение шины позволяет не только легко менять направление передачи данных, но и решать задачи захвата/отпу
104
Работа с PC шиной
скания шины, передачи сигнала подтверждения и т.д. В исходном состоянии на выходах всех микросхем, подключенных к PC шине, должны быть установлены сигналы логической единицы (транзисторы выходных каскадов всех микросхем закрыты). Это позволяет всем устройствам, подключенным к шине, находиться в режиме чтения.
Рис. 3.3. Принципиальная электрическая схема PC шины
Теперь допустим, что устройство 1 начинает процесс передачи информации. В этом случае устройство 1 выступает в качестве передатчика. Остальные устройства будут выполнять роль приемников. При этом в передатчике происходят следующие процессы.Сигнал данных и сигнал синхронизации поступают на соответствующие выходные каскады PC интерфейса. Оба сигнала представляют собой последовательность импульсов. Эти импульсы открывают транзисторы выходных каскадов. Когда транзистор открывается, он «подсаживает» соответствующую линию PC шины. Напряжение на «подсаженной» линии близко к нулю. При «отпущенной» линии (транзистор закрыт) напряжение близко к напряжению питания.
Переданные таким образом сигналы данных и синхронизации поступают на входы всех остальных микросхем, работающих в режиме приема. Каждый приемник считывает переданный сигнал и оценивает его содержание. Кроме полезных данных в передаваемый сигнал заложен адрес устройства, для которого эти данные
Протокол 12С шины
105
предназначены. Если передаваемый адрес совпадет с индивидуальным адресом одной из микросхем-приемников, то эта микросхема примет и обработает передаваемые данные. Остальные микросхемы их проигнорируют. Это общий принцип работы PC шины. Теперь рассмотрим, каким образом происходит передача информации.
Информация по PC шине передастся побайтно. Каждый байт передается последовательно, бит за битом. В конце байта формируется контрольный бит. При этом передача каждого бита по шине SDA сопровождается передачей синхроимпульса по шине SCL. Приемник побитно читает сигнал с шины SDA, используя сигнал на шине SCL для синхронизации. После передачи восьми битов данных передатчик запрашивает сигнал подтверждения от приемника. Для этого он «отпускает» шину SDA и передает импульс синхронизации по шине SCL. В ответ на этот импульс, приемник должен сам «подсадить» шину SDA. Передатчик считывает сигнал на шине. Если подтверждение получено, он продолжает передачу. Если нет, передача приостанавливается. Таким образом, схема шины позволяет легко изменять направление передачи информации в процессе одного сеанса обмена. В следующем разделе мы изучим этот вопрос подробнее.
В заключение этого раздела хотел бы сделать небольшое уточнение. На рис. 3.3 показан вариант построения PC интерфейса, где в выходных каскадах применены биполярные транзисторы. Это лишь один из возможных вариантов. С таким же успехом можно использовать и полевые транзисторы. Более того, в настоящее время именно так и поступают большинство производителей микросхем с PC интерфейсом.
3.4.	Протокол !2С шины
В предыдущем разделе мы рассмотрели электрическую схему PC шины. Такой принцип построения схем последовательного канала часто используется в самых различных устройствах последовательной передачи информации. Для того, чтобы приведенная на рис. 3.3 схема могла считаться PC шиной, необходимо, чтобы во всех входящих в нее микросхемах была реализована определенная логика работы. Набор правил, определяющий логику взаимодсйст-
106
Работа с l2C шиной
вия всех элементов PC шины, и называется протоколом PC шины. Полное описание протокола содержится в документе, который называется «Спецификация PC шины» (The PC-bus specification). Найти это описание вы всегда можете на сайте фирмы Philips [5WJ-В данном разделе мы подробно рассмотрим все особенности протокола PC шины в стандартном режиме работы (Standard Mode).
Взаимодействие на уровне электрических сигналов
Как уже говорилось ранее, PC шина рассчитана на передачу данных в виде байтов. Каждый байт передается по шине последовательно, бит за битом. Сигнал данных передается по линии SDA. Передача каждого бита синхронизируется одним импульсом на линии SCL. Этот процесс (см. рис. 3.4) происходит следующим образом. Устройство-передатчик выставляет на шине SDA уровень, соответствующий очередному передаваемому биту (0 или I). В тот момент, когда завершатся все переходные процессы и уровень сигнала на линии данных примет требуемое значение, на линии синхронизации (SCL) появляется положительный импульс, который и служит для устройства-приемника сигналом, разрешающим чтение бита.
SDA
SCL
1 Момент
। смены
1 уровня
1 на линии
। данных
Момент стробирования. Сигнал на линии данных не изменяется
Рис. 3.4. Процесс передачи битов
Спецификация сигналов требует, чтобы в процессе передачи битов сигнал на линии SDA изменялся только в тот момент, когда уровень сигнала на линии SCL равен нулю, как это показано на рис. 3.4. Однако есть два особых случая, когда сигнал на линии
Протокол PC шины	107
SDA изменяется как раз в момент, когда на линии SCL единица. Это происходит при формировании «СТАРТ-условия» (START condition) и «СТОП-условия» (STOP condition). На рис. 3.5 наглядно показано как формируются эти условия.
Рис. 3.5. Стартовое и стоповое условия
СТАРТ-условие — это отрицательный перепад (с единицы в ноль) на линии SDA при единичном уровне на линии SCL. СТОП-усло-вие — это положительный перепад (от нуля к единице) на линии SDA при единице на линии SCL. В фирменной спецификации PC протокола эти условия принято обозначать буквами S и Р, как показано на рис. 3.5. СТАРТ и СТОП условия используются для синхронизации пакетов. Передача информации по PC шине всегда начинается со СТАРТ-условия и заканчивается СТОП-условием. В середине пакета допускается производить повторный СТАРТ СТАРТ-условие также используется для правильного разделения передаваемых битов на байты. Сразу после СТАРТ-условия передача байта всегда начинается сначала.
Обратимся к рис. 3.6. На нем показан процесс передачи байта по шине PC. Диаграмма, изображенная на рисунке одинаково справедлива как для случая записи данных из ведущего устройства в ведомое, так и для случая чтения данных ведущим устройством из ведомого. Начнем описание этого процесса с первого из вариантов.
Итак, посмотрим, как происходит передача информации от ведущего устройства к ведомому. Очевидно, что при этом ведущее устройство выступает в качестве передатчика, а ведомое в качестве приемника. Для лучшего понимания происходящих процессов сигнал на линии SDA на рис, 3.6 условно изображен в виде двух разных сигналов: выходные данные передатчика и выходные дан
108
Работа с l2C шиной
ные приемника. На самом деле эти два сигнала присутствуют на линии одновременно. Они объединены между собой благодаря эффекту схемного «ИЛИ», который образуется при параллельном включении нескольких каскадов с открытым коллектором (стоком). Разделение одного сигнала на два позволяет легче понять, какое из двух устройств вызвало «подсаживание» линии в тот или иной момент времени.
Стартовое условие
Синхроимпульс бита подтверждения
Рис. 3.6. Передача данных
Процесс передачи данных всегда начинается со СТАРТ-условия. После чего начинается побитная передача первого байта. Сразу после первого передается второй и так далее. Каждый байт передается за 9 тактов сигнала синхронизации. За восемь первых тактов передаются восемь информационных битов, составляющих байт. Девятый такт используется для сигнала подтверждения. Передача байта производится старшим битом вперед. То есть, вначале передастся бит 7, а в конце бит 0. Передача битов производится, таким образом, как показано на рис. 3.4. Затем ведущее устройство «отпускает» линию SDA и формирует на линии SCL еще один импульс синхронизации. Если приемник работает нормально, и успел принять все восемь битов от передатчика, то, получив девятый импульс по линии SCL, он должен сформировать на линии SDA сигнал подтверждения. А именно, он должен перевести линию в ноль (см. рис. 3.6). Приемник проверяет уровень на линии SDA. Если там ноль, то процесс передачи продолжается. Если единица, то программа приступает к процедуре обработки ошибки.
Протокол PC шины
109
Теперь рассмотрим случай, когда ведущее устройство должно прочитать данные из ведомого. Этот процесс очень похож на предыдущий. Только теперь ведомое устройство является передатчиком, а ведущее — приемником. Несмотря на то, что ведущее устройство выступает в роли приемника, именно оно, как и прежде, занимается формированием СТАРТ и СТОП условий, а также импульсов синхронизации. Процесс считывания данных начинается с того, что ведущее устройство вырабатывает СТАРТ-условис. Сразу после этого ведущее устройство начинает процесс считывания первого байта. Для этого оно вырабатывает импульсы синхронизации на линии SCL.
Ведомое устройство считывает эти импульсы и на каждый из них выдает на линию SDA очередной бит передаваемого байта. Данные передаются старшим битом вперед. После передачи восьми битов данных ведомое устройство ожидает от ведущего сигнал подтверждения. Ведущее устройство передает сигнал подтверждения в девятом такте.
Если чтение байта прошло нормально, то сигнал подтверждения будет равен нулю. Если произошла ошибка, то сигнал подтверждения равен единице. Ведущее устройство выставляет этот сигнал на шине SDA и затем формирует синхроимпульс на линии синхронизации (SCL). При нормальном завершении процесса считывания байта ведущее устройство сразу же приступает к считыванию следующего байта.
Рассмотрим теперь логику работы ПС шины при передаче пакета данных. Процесс передачи пакета показан на рис. 3.7. Как видно из рисунка, процесс передачи цепочки байтов начинается со СТАРТ-условия и заканчивается СТОП-условисм. Промежуток между S и Р условиями называется посылкой. Кроме того, НС протокол допускает применение повторного СТАРТ-условия. Повторное СТАРТ-условие формируется в середине посылки и ничем не отличается от обычного. После повторного СТАРТ-условия мастер может изменить параметры передачи данных, например, может быть назначен другой адрес ведомого устройства или поменяться направление передачи информации. На временных диаграммах повторное СТАРТ-условие обозначается, как Sr.
На рис. 3.7 показана часть посылки между СТАРТ-условием п СТОП-условием, или между двумя СТАРТ-условиями, при передаче информации от ведущего устройства (Master) к ведомому
110
Работа с l2C шиной
(Slave). Сразу после СТАРТ-условия происходит передача восьми бит информации (первый байт). Затем, на девятом такте, Master получает сигнал подтверждения от Slave.
Рис. 3.7. Структура одной посылки при передаче данных
Реальные устройства после приема байта требуют некоторого времени для обработки полученных данных. Поэтому в PC протоколе предусмотрен механизм передачи сигнала готовности. Сигнал готовности передается от Slave устройства к Master устройству через линию синхронизации (SCL). Получив байт и выдав в линию сигнал подтверждения, Slave устройство «подсаживает» линию SCL и удерживает се в этом состоянии до тех пор, пока не окончит обработку принятого байта. Master устройство ожидает, пока линия SCL будет «отпущена», и все это время не начинает процесс передачи следующего байта. Аналогичным образом передаются и все остальные байты посылки.
Механизм передачи сигнала готовности действует и в случае, когда происходит чтение данных из Slave устройства. Ведущему устройству также может потребоваться время для обработки принятого байта. В этом случае оно просто задерживает очередной синхроимпульс до тех пор, пока обработка байта не закончится.
Таковы основные принципы работы 12С шины на уровне электрических сигналов. На этом этапе пока не понятно, каким образом происходит выбор режима записи, либо режима чтения. А также нс понятно, каким образом происходит передача адреса Slave устройства. Все эти процессы происходят на более высоком уровне протокола — на логическом уровне. Изучением этого уровня мы сейчас и займемся.
Протокол PC шины	111
Логический уровень протокола 12С шины
Принципы работы протокола 12С шины на логическом уровне иллюстрирует рис. 3.8. Каждый бит, передаваемый по PC шине, изображен на рисунке в виде квадратика. Серыми квадратиками изображены биты, передаваемые Master устройством, а светлыми квадратиками — биты, передаваемые Slave устройством. Все условные обозначения приведены в нижней части рисунка.
Передача данных
В Адо»;улройогм JQ. -бИИглвиад  В	~~ Й»|
^-Ст Мл-^ ^Ст	Мл-^ { ^СТ	Мл^ J
Прием данных
Jo| Байт данных Байт данных [Д'Д ^-Ст.....Мл-^ д ^-Ст-	- -Мл-^ £ ^Ст -	Мл^
SCL
I ~ Приемник f	stu	|
Master	Slave
I	SCL	|
~ .^Передатчик
Лоредвтмпс
ПрмаМНМК
SDA
Условные обозначения
Ст — старший бит Мл — младший бит
S — СТАРТ-условие А — подтверждение
Р — СТОП-условив JC— не подтверждение
R — признак чтения
W — признак записи
Рис. 3.8. Диаграмма процессов передачи и приема данных
Верхняя диаграмма изображает процесс передачи данных от Master к Slave (запись данных). Процесс начинается с того, что Master формирует СТАРТ-условие (на рисунке обозначено символом «S»). Затем Master выдаст на шину первый байт (восемь бит информации). Первые семь бит этого байта — это адрес Slave устройства, на которое Master желает передать данные. Восьмой бит называется битом выбора режима и определяет направление передачи информации. Если этот бит равен нулю, то это значит, что Master начинает передачу данных, если единице, то прием.
Как видите, в данном случае бит равен нулю. По этой причине бит выбора режима помечен символом «W» (от английского слова Write — запись). Все Slave устройства, подключенные к шине, получив СТАРТ-условие. принимают первый байт и сравнивают заключенный в нем адрес со своим собственным адресом. Только для одного из Slave устройств условие равенства адресов будет выполнено. Именно это устройство и продолжит дальнейшую работу на шине. Остальные Slave устройства переходят в режим ожидания. Все они будут ждать следующего СТАРТ-условия на шине, после которого они опять выполнят проверку адреса.
Устройство, адрес которого совпал, сначала завершает процедуру приема байта. Для этого оно вырабатывает сигнал подтверждения,
112
Работа с l2C шиной
обозначенное на диаграмме как «А». Получив подтверждение, Master продолжает передачу байтов. Но теперь это уже байты данных, предназначенные для записи в выбранное Slave устройство. Передача каждого байта происходит уже знакомым нам образом. Восемь бит данных, а затем сигнал подтверждения. Таким образом, происходит передача любого количества байтов. Для завершения процесса передачи Master вырабатывает СТОП-условие (обозначено на диаграмме символом «Р»).
Нижняя диаграмма на рис. 3.8 иллюстрирует процесс приема данных. Прием данных начинается так же, как и передача Сначала Master вырабатывает СТАРТ-условие. Затем передает на линию служебный байт. Старшие 7 бит служебного байта, как и в предыдущем случае, означают адрес Slave устройства, из которого Master желает получить данные. Последний (младший) бит теперь равен единице. Это означает, что Master устройство начинает операцию чтения. Поэтому бит выбора режима обозначен на диаграмме символом «R» (от английского слова Read — чтение). Служебный байт, как и в предыдущем случае, принимается всеми устройствами, подключенными к PC шине. И только одно из них останется в активном состоянии.
Выбранное устройство вырабатывает сигнал подтверждения (А), а затем переходит в режим передачи. В этом режиме выбранное устройство один за другим передает байты данных, используя сигналы на линии SCL для синхронизации. В свою очередь, Master устройство принимает эти байты и выдает сигнал подтверждения после каждого из них. В этом режиме работы сигнал подтверждения используется для выхода из режима передачи. Пока сигнал подтверждения равен нулю, передача продолжается. При получении последнего байта посылки Master устанавливает сигнал подтверждения в единицу. В результате Slave устройство прекращает дальнейшую передачу данных. Завершается весь процесс формированием СТОП-условия. В правой части рис. 3.8 схематически показано направление передачи информации по обеим линиям 12С шины в разных режимах работы.
Итак, мы теперь получили представление о принципах организации протокола передачи информации посредством двухпроводной PC шины. Очевидно, что при создании электронных устройств с применением этой шины необходимо обязательно соблюдать условие, чтобы на одну шину были подключены устройства с разными индивидуальными адресами. Как же определяются адреса для Slave
Микросхемы EEPROM с 1гС интерфейсом
113
устройств с PC интерфейсом? Иногда PC адрес микросхемы просто жестко зашит в нее при изготовлении. В этом случае сам производитель микросхем должен позаботиться, чтобы адреса разных микросхем, предназначенных для применения в одной и той же общей схеме, были бы различными. Если адрес микросхемы жестко зашит в нее при изготовлении, то он обязательно должен быть указан в прилагаемой документации. Например, микросхема TDA8844 (однокристальный телевизор фирмы Philips), описанная в [4], имеет PC адрес для записи 10001010 (или 138 в десятичном представлении). Для чтения, соответственно, адрес будет равен 10001011 (139 десятичное). В данном случае под адресом подразумевается значение всего служебного байта, вместе с битом «чтение/запись».
В других случаях в микросхему зашита лишь часть адреса. А остальная часть адреса определяется при помощи специальных адресных входов, на которые подаются разные комбинации напряжения. Микросхемы энергонезависимой памяти, которые будут описаны далее в этой главе — пример именно таких устройств, у которых часть адреса фиксирована, а другая часть определяется при помощи адресных входов.
3.5.	Микросхемы EEPROM с 12С интерфейсом
Хорошим примером применения PC шины являются микросхемы энергонезависимой памяти. Такие микросхемы имеют и второе название: Flesh-память (флэш-память). Что же такое флэш-память? Задача надежного сохранения информации после выключения электропитания давно стояла перед разработчиками. Микросхемы памяти с момента своего появления делились на оперативные запоминающие устройства (ОЗУ) и постоянные запоминающие устройства (ПЗУ). ОЗУ — это такое устройство, информацию в котором можно оперативно изменять. Однако при выключении питания она нс сохраняется. В ПЗУ информация хранится даже после выключения питания.
Однако в первых моделях ПЗУ информация записывалась однократно, в процессе изготовления. Позже появились технологии, позволяющие «перепрошивать» ПЗУ. Но этот процесс был до
114
Работа с l2C шиной
вольно длительным и требовал извлечения микросхемы из устройства, где она использовалась и подключения к специальному программатору.
Долго не удавалось разработать технологию, позволяющую оперативно изменять информацию в ПЗУ. Наконец была изобретена технология ПЗУ с электрическим стиранием информации (репро-граммируемые ПЗУ). В английской транскрипции такие микросхемы называются EEPROM. Именно эти устройства и получили второе название: флэш-память. В современных микросхемах флэш-памяти время стирания информации составляет 5...Ю мс. Это намного медленнее, чем процесс записи в ОЗУ, однако для устройств долговременного хранения данных вполне приемлемо. Количество циклов записи/стирания для флэш-памяти ограничено, однако на сегодняшний день эта цифра достигает миллиона.
Микросхемы флэш-памяти широко применяются в микропроцессорной технике. Например, память программ микроконтроллера АТ89С2051 использует технологию флэш-памяти. Существует также широкая номенклатура различных микросхем автономной флэш-памяти. Такие микросхемы для связи с микроконтроллером могут использовать самые различные виды интерфейса. Есть микросхемы, использующие параллельный способ подключения. Однако нас в данном случае будут интересовать микросхемы флэш-памяти с PC интерфейсом. Такие микросхемы получили широкое применение в современной электронной аппаратуре. В [I| описана схема позиционера спутниковой антенны, который использует микросхему флэш-памяти с PC интерфейсом для хранения информации о направлении антенны при ее наведении на разные спутники.
Ведущим разработчиком микросхем флэш-памяти по праву можно считать фирму Atmcl. Она выпускает целую серию микросхем энергонезависимой памяти с PC интерфейсом. Эта серия получила название АТ24Схх. Здесь хх — это две или даже три цифры, которые обозначают номер модели микросхемы. Обычно он соответствует объему памяти микросхемы, выраженному в килобитах. В табл. 3.1 приведены основные характеристики микросхем этой серии.
Родоначальником серии можно считать микросхему АТ24С01. По сравнению с другими микросхемами, эта микросхема имеет самую простую внутреннюю структуру. Микросхема содержит всего 128 ячеек памяти, каждая из которых может хранить один байт информации. Объем памяти в килобитах будет равен 128 * 8 = 1024.
Микросхемы EEPROM с 12С интерфейсом
115
Что соответствует I Кбит. Для нас привычнее отсчитывать объем памяти в байтах и килобайтах. Поэтому в табл. 3.1 приведены оба варианта. При подключении микросхемы АТ24С01 к ПС шине она одна выступает в качестве 128 Slave, устройств. Каждая ячейка памяти — свое отдельное устройство. По этой причине на одной шине может одновременно присутствовать только одна микросхема типа АТ24С01. То есть процессор просто соединяется с микросхемой при помощи двух проводников, к каждому из которых нужно не забыть подключить сопротивление нагрузки. Микроконтроллер при этом, естественно, является Master.
Для того, чтобы записать байт данных в ячейку памяти с адресом N, микроконтроллер должен выполнить стандартную процедуру передачи информации по PC шине от Master к Slave. При этом Slave будет иметь адрес N. Передачу данных в этом режиме в точности отображает диаграмма, приведенная на рис. 3.8. Следует заметить, что запись во флэш-память — это относительно медленный процесс. Для микросхемы АТ24С01 время записи может достигать Ю мс.
Для того, чтобы ни задерживать работу шины, микросхема АТ24С01 имеет специальную буферную память. В режиме записи информация она сначала попадает в буферное ОЗУ. При этом скорость передачи информации равна 100 Кбит/с. А в некоторых режимах она может быть увеличена до 400 Кбит/с. Сразу после того, как Maser сформирует СТОП-условие, микросхема памяти перейдет в режим переноса информации из буфера непосредственно во флэш-память. До тех пор, пока этот процесс нс закончится, микросхема АТ24С01 не выдаст сигнал готовности.
Большое время записи информации обусловлено особенностями EEPROM технологии. Прежде чем записать новое значение в любой из ячеек памяти, система управления микросхемы должна произвести операцию по электрическому стиранию предыдущей информации. Это сложный процесс, связанный со структурными изменениями в материале подложки.
Если нужно записать несколько ячеек подряд, не обязательно обращаться к каждой из них отдельно. Для этого в микросхеме предусмотрен страничный способ записи. При страничной записи Master в одном сеансе передает по PC шине не один, а несколько байт. В качестве Slave адреса он указывает адрес первой ячейки памяти, с которой и будет начинаться запись. В результате дан
116
Работа с l2C шиной
ные будут записаны последовательно в несколько ячеек. После записи каждого очередного байта текущий адрес, хранящийся в специальном внутреннем регистре микросхемы памяти, автоматически увеличивается на единицу. Однако изменяются только два младших разряда адреса. Пять старших разрядов остаются без изменения. Поэтому длина страницы в режиме страничной записи для микросхемы АТ24С01 равна четырем. Это значит, что максимальное количество байтов, которые можно передать за один сеанс — четыре байта.
Вся память микросхемы, таким образом, разделена на 32 страницы по 4 байта в каждой. Программа управляющего микроконтроллера должна учитывать эту особенность. Важно понять, что при страничном способе записи, за один прием можно переписать не более четырех байтов. Причем все они всегда будут находиться в пределах одной страницы. Если вы неправильно составите программу, и ваш микроконтроллер за один раз попытается записать в микросхему памяти цепочку байт, которая выходит за пределы страницы, то, дойдя до конца страницы, запись начнется с ее начала.
Например, для передачи блока из четырех байтов необходимо обязательно начинать запись с первого байта одной из страниц. Если вы все же решили начинать со второго байта страницы, то безболезненно передать можно будет только три байта. И так далее. Сама микросхема АТ24С01 не выполняет никаких проверок для обнаружения неправильного использования страниц памяти.
Вы спросите: зачем же такие сложности? Дело в том, что стирать каждую ячейку в отдельности дело довольно сложное и дорогое. Поэтому производится стирание сразу нескольких ячеек. Эти несколько ячеек и составляют страницу памяти. Даже если вы переписываете не всю страницу, а лишь ее часть, все равно соответствующая часть электрически стираемой памяти очищается. Содержимое всех остальных ячеек (которые не надо переписывать) предварительно сохраняется в буферной памяти. Затем, после окончания процесса стирания, все байты, составляющие страницу, записываются назад. При этом нужные байтгы получают новое значение, а в остальных остается старое.
Другие микросхемы из серии АТ24Схх также имеют страничную организацию памяти. В табл. 3.1 в графе 3 показаны данные о структуре страниц для каждого типа микросхем!.
Микросхемы EEPROM с 12С интерфейсом
117
Семейство микросхем АТ24Схх фирмы Atmel	Таблица 3.1
Максим, адресуе-	Мал ИС1МИ lt> (байтов)	со	со см		см	см	СМ	см	I X9i I	см со	|	64К	1	|	64К	|	со см	Г 256К	1	|	256К	|		СО см	|	64К	|
, го го «= 2 го о. о Ь;	битов		•	г-	СО	СО	со	со	СО	см	СО		tn	СО	СО		Г	14(15) |
О £ S eg го	байтов	tn	1 нет	—	--	—	—	—	—	см	см	см	см	см	см		—	СМ
	о	сП	СЕ	R/W	R/W	S tx	АА/Н	* се	АА/Ь	5 се	СЕ	R/W	СЕ	СЕ	АА/Ь		R/W	R/W
байта	--			§	§	р	р	р	р	S	О <с	§	§	§	р		*	§
О о	см	со	амят		5		CL	ЕЁ	К	5		5	5	5	5		*	<г
VO ф *	со	см	с:	см <1	см	см <1	СМ <Г	см	см	см с	СМ <	о	о	о	о			о
гслу:			Ф СК	о	о	о	о	о	О	о	О	о	о	о	о		о	о
EHld(	LD	О	эсует	—	—	—	—	—	5	—	—	—	—	—	—		—	—
е	СО	о	Адр(	о	о	о	о	о	СМ	о	о	о	<=>	о	о		о	о
	г-	со		—	--	—	--	—	--	--	—	—	—	—	--			—
Входы установки	адреса	Г-	Г ^н		| АО, А1.А2 |	I АО. А1.А2 I	I А1.А2 I	см	1		1	I АО, А1, А2 I	см <С §	Izv'iv'ov ]	1 АО, А1 |	I АО. А1 |	| АО, А1 I			ф X	| АО, А1
О £П ЬкГ . го «ч 2	па шине	со	—	СО	СО	’е	см	—	СО	СО	со				см		—	
изация 1ЯТИ	Байт на страницу	Ш	•е	со	со	со	со	со	со	см со	см со	S	S	см	I 9S2 I		—	S
OpraHi паь,	Страниц	-st	СМ	со	см со	см со	S	СО см	I 256	СО см	1 256 J	со tn см	см tn	I 512	СМ ш		СО см	| 256
памяти	байтов	со	СО см	СО см	со tn см	L512		см	см		со	со	32К |	I 64К I	128К |		со см	16К
Объем	битов	см			см		СО	1 16К |	СО	см со	I 64К |	со см	| 256К |	| 512К |	2			| 128К
Тип микро-	Ё г и $	—	| АТ24С01 |	| АТ24С01А |	| АТ24С02 |	1 АТ24С04 |	со о О см	I АТ24С16 I	| АТ24С164 |	см со о см <£	1 АТ24С64 |	| АТ24С128 |	| АТ24С256 |	| АТ24С512]	| АТ24С1024 |		| АТ24С21 ‘ |	| AT24CS128" |
Имеет дополнительный последовательный канал чтения данных.
Имеет дополнительную область для хранения идентификационных данных. ’ Биты не используются
118
Работа с PC шиной
В режиме чтения страничные ограничения отсутствуют. Процесс чтения для микросхемы АТ24С01 полностью описывается соответствующей диаграммой на рис. 3.8. Причем адрес Slave устройства, передаваемый в первом (служебном) байте посылки, соответствует адресу той ячейки памяти, с которой начинается процесс чтения. Микроконтроллер может читать как один байт за сеанс, так и любое количество байтов подряд. Максимальное количество прочитанных байтов равно полному объему используемой памяти. Для микросхемы АТ24С01 эта величина будет равна 128 байтам. Если попытаться за один раз прочитать большее количество байтов, то микросхема выдаст все содержимое своей памяти, а затем начнет выдавать его сначала.
Микросхема АТ24С01 в настоящее время используется очень редко. Объема памяти в 128 ячеек для современных электронных приборов совершенно недостаточно. Однако используемый способ адресации ячеек не позволяет увеличить их количество. Чтобы не изменять уже сложившийся протокол для ЕС шины и получить возможность для адресации большого количества ячеек памяти, фирма Atmel разработала несколько вариантов расширения этого протокола. Все эти расширения полностью совместимы с основным стандартом снизу вверх. Это означает, что все дополнения не затрагивают основных правил, описанных в разделе 3.4. Новые правила лишь дополняют старые. Расширенных протоколов всего два. Оба они предусматривают введение дополнительных служебных байтов. В первом варианте добавляется только один дополнительный служебный байт. С применением такого протокола появилась возможность адресовать до 2 Кбайт памяти. Фирма /\tmel первоначально выпустила целую линейку микросхем, использующих этот протокол: АТ24С01А, АТ24С02, АТ24С04, АТ24С08, АТ24С16. Основные характеристики этих микросхем вы можете видеть в табл. 3.1.
Первая микросхема этой линейки — АТ24С01А. Объем ее памяти не отличается от объема памяти микросхемы АТ24С01 и тоже равен 128 байтам. Объем памяти каждой последующей модели описываемой линейки в два раза больше предыдущего (см. табл. 3.1). Адресация ячеек памяти происходит совершенно не так как в микросхеме АТ24С01. Главное отличие нового способа адресации — возможность подключения нескольких микросхем памяти на одну ЕС шину. Первый служебный байт ЕС протокола предназначается для выбора одной из нескольких, подключенных к шине микросхем. Для того, чтобы каждому конкретному экзем-
Микросхемы EEPROM с 12С интерфейсом
119
пляру микросхемы АТ24С01А можно было бы присвоить свой индивидуальный адрес, она имеет специальные входы адреса: АО, Al, А2. Эти входы предназначены для задания трех младших разрядов адреса микросхемы. Для задания адреса каждый из этих входов нужно подсоединить либо к общему проводу, либо к напряжению питания (Vpp). Если разряд должен быть равен нулю, то его подсоединяют к общему проводу. Если единице — к питанию. Четыре старших разряда адреса фиксированы. Их значение всегда равно ЮЮВ. Структура основного служебного байта, в который заложен Slave адрес микросхемы, приведена в табл. 3.1 (столбцы 8...15). Очевидно, что при таком способе адресации на одной PC шине могут одновременно работать до восьми микросхем памяти.
RST
— XL1
5 „
XI2
P3.0
— P3.2
II
P3.3
P3.4
P3.5
АО SDA
2
2
Al SCL
Al SCL
Al SCL
CPU
Al SCL
12
3
Р1.0
А2 WP
A2 WP
13
P1.1
14
S£L
P12
P1.3
P1.4
SDA
WP
15
DOI
AT89C2051
DD4 AD SDA
DD2 AD SDA
DO5 AD SOA
16
PI.5
SDA
SDA
Al SCL
SCL
SCLF---
SCL ----
DD2..DD9
P1.7
AT24C01A
WP
DD9
AO SDA
-ЧА2 WP|
2
3
Рис. 3.9. Схема подключения EEPROM типа AT24C01A к микропроцессору АТ69С2051
На рис. 3.9 показана схема подключения микросхем АТ24С01А к микроконтроллеру АТ89С2051. Суммарный объем памяти при подключении микросхем АТ24С01А по такой схеме составляет 1 Кбайт. Это максимально возможный объем памяти при использовании именно этого вида микросхем. Максимально возможный объем памяти для других видов микросхем приведен в столбце 18 табл. 3.1. При помощи перемычек на входах АО, Al, А2 каждой из микросхем памяти присваиваются свой индивидуальный адрес. В табл. 3.2 приведены адреса всех микросхем, изображенных на рис. 3.9. Адрес каждой микросхемы приведен в двоичном и шестнадцатеричном видах.
120
Работа с l2C шиной
Адреса микросхем памяти, включенных по схеме на рис. 3.9 Таблица 3.2
Микросхема		DD2	DD3	DD4	DD5	DD6	DD7	DD8	DD9
Адрес	BIN	1010000В	1010001В	1010010В	1010011В	1010100В	1010101В	1010110В	1010111В
	HEX	50H	51Н	52Н	53Н	54Н	55Н	56Н	57Н
Служебный байт	BIN	10100000В	10100010В	10100100В	10100110В	10101000В	10101010В	10101100В	10101110В
в режиме записей	HEX	ОАОН	0А2Н	0А4Н	0А6Н	0А8Н	ОААН	ОАСН	ОАЕН
Для адресации ячеек памяти внутри каждой микросхемы применяется дополнительный служебный байт. С точки зрения стандартного протокола — это первый байт данных. Однако для микросхемы памяти этот байт имеет смысл адреса ячейки памяти. Диаграмма, поясняющая принципы работы расширенного PC протокола с одним дополнительным байтом, приведена на рис. 3.10. Если вы посмотрите внимательнее на рисунок, вы без труда поймете эти принципы. Описываемый протокол используют все микросхемы описываемой линейки. Микросхема АТ24С01А содержит всего 128 ячеек памяти. Для их адресации достаточно лишь семи разрядов. Поэтому старший разряд дополнительного служебного байта в этой микросхеме не используется. Микроконтроллер может устанавливать в этом разряде любое значение. На выбор ячейки памяти это не повлияет. В табл. 3.1 в столбцах 16 и 17 приведено количество дополнительных служебных байтов для разных видов микросхем, а также количество задействованных разрядов.
Адрес ячейки, передаваемый в дополнительном служебном байте, запоминается в специальном внутреннем регистре микросхемы памяти. При записи последовательности из нескольких байтов, после каждого очередного байта этот адрес автоматически увеличивается на единицу. Значение адреса после записи последнего байта цепочки сохраняется во внутреннем регистре микросхемы памяти до тех пор, пока он нс будет переписан новой командой записи. Этот адрес называется текущим адресом. Сохранение текущего адреса позволяет в любой момент продолжить прерванный процесс чтения памяти. Процесс чтения всегда начинается с текущего адреса. После чтения каждого очередного байта текущий адрес также увеличивается. Если перед началом сеанса чтения требуется изменить текущий адрес, нужно просто произвести запись адреса. Режим записи адреса отличается от обычного режима записи только тем, что на запись передается только один дополнительный служебный байт. Этот процесс изображен на рис. 3.10 на диаграмме «Чтение данных, начиная с заданного адреса».
Микросхемы EEPROM с 12С интерфейсом
121
§
со
со
о
ф а
со
со о в со
Рис. 3.10. Однобайтовый способ адресации ячеек памяти EEPROM
122
Работа с l2C шиной
Микросхема АТ24С02 отличается от микросхемы АТ24С01А лишь увеличенным вдвое объемом памяти (256 байт). В связи с этим, для адресации ячеек памяти эта микросхема использует все восемь разрядов дополнительного служебного байта. Микросхемы АТ24С02 можно подключать к микроконтроллеру по схеме, изображенной на рис. 3.9, без каких-либо изменений Суммарный объем памяти при этом увеличится до 2 Кбайт.
Микросхема АТ24С04 имеет объем памяти 512 байт. Для адресации такого количества ячеек одного байта адреса недостаточно. Несмотря на это, микросхема также использует протокол, изображенный на рис. 3.10. Для того, чтобы это стало возможным, память микросхемы разделена на два банка по 256 байт. Каждый из этих банков выступает как отдельное Slave устройство на PC шине. Для выбора одного из банков используется младший бит адреса в основном служебном байте. В табл. 3.1 формат основного служебного байта расшифровывается в столбцах 8... 15. Бит, определяющий один из банков памяти, обозначен там как Р0. В то же время у микросхемы АТ24С04 отсутствует вход АО. Соответствующая ножка микросхемы просто не задействована. В результате одна микросхема АТ24С04, при подключении ее к FC шине, заменяет две микросхемы АТ24С02. Одновременно, на одну шину могут быть подключено не более четырех микросхем типа АТ24С02. Однако, микроконтроллер, как и прежде, «увидит» на шине те же восемь Slave устройств. Поэтому максимальный объем памяти при применении микросхем АТ24С02 останется равным 2 Кбайтам. Сократится лишь количество корпусов.
Микросхема АТ24С08 позволяет еще вдвое сократить количество корпусов. Объем памяти этой микросхемы равен 1024 байтам. Теперь эта память разбита на четыре банка, каждый их которых выступает, как отдельное Slave устройство Для адресации этих банков используется уже два младших разряда основного служебного байта. В табл. 3.1 они обозначены как ВО и Р1. Микросхема АТ24С08 имеет лишь один адресный вход (А2). Входы АО и А1 не используются. Одновременно на одну шину могут быть подключены только две такие микросхемы. Максимальный объем памяти опять не изменился и равен 2 Кбайта.
Микросхема АТ24С16 — последняя микросхема из этой серии. Она заменяет все восемь микросхем типа АТ24С02. Она имеет 2048 ячеек памяти, разбитых на восемь банков. Для адресации банков используются все три младших разряда основного служебного
Микросхемы EEPROM с 12С интерфейсом
123
байта (РО, Р1 и Р2 — см. табл. 3.1). Микросхема вообще не имеет внешних входов установки адреса (таких, как АО, А1 и А2). На одной PC шине может присутствовать только одна такая микросхема. Максимальный объем памяти опять равен 2 Кбайта.
Все описанные выше микросхемы (01 А, 02, 04, 08 и 16) имеют страничную организацию памяти. Размер и количество страниц каждой такой микросхемы приведены в табл. 3.1 (столбцы 4 и 5). При записи информации в любую из этих микросхем необходимо придерживаться правил работы со страницами. Эти правила мы подробно рассматривали при описании микросхемы АТ24С01.
Еще одна особенность микросхем 24С01А, 02, 04, 08, 16 — наличие режима защиты от перезаписи. Этот режим позволяет использовать микросхемы в качестве ПЗУ для хранения данных, нс подлежащих изменению. Для перевода микросхем в защищенный режим используется специальный вывод WP (Write Protect). Если зашита от записи нс нужна, то вход WP подключается к общему проводу (см. рис. 3.9). Включенная таким образом микросхема работает во всех режимах. Микроконтроллер может свободно записывать в нее любые данные. Если затем вход WP любой из микросхем подсоединить к источнику питания (Vpp), то она перейдет в защищенный режим работы. В этом режиме часть ячеек (или все ячейки) памяти микросхемы становятся недоступными для записи. Фирма Atmel специально выпустила дополнительные модификации микросхем 24С02А, 04А, 08А и 16А, которые отличаются от своих аналогов (без буквы) только способом защиты памяти. В табл. 3.3 приведены способы защиты для всех типов микросхем.
Способы защиты памяти при помощи входа WP	Таблица 3.3
Микросхема	Способ защиты	Микросхема	Способ защиты
АТ24С01	Нет защиты	АТ24С32	Верхний квадрант (1/4)
АТ24С01А	Вся память	АТ24С32А	Вся память
АТ24С02	Вся память	АТ24С64	Верхний квадрант (1/4)
АТ24С02А	Верхняя половина	АТ24С64А	Вся память
АТ24С04	Вся память	АТ24С128	Вся память
АТ24С04А	Верхняя половина	АТ24С256	Вся память
АТ24С08	Нет защиты	АТ24С512	Вся память
АТ24С08А	Вся память	АТ24С1024	Вся память
АТ24С16	Верхняя половина	АТ24С164	Вся память
АТ24С16А	Вся память	AT24CS128	Вся память
124
Работа с l2C шиной
Еще один вид микросхем использует описанный выше (см. рис. 3.10) расширенный протокол с одним дополнительным служебным байтом. Это микросхема АТ24С164. Микросхема в некотором смысле является аналогом АТ24С16. Она тоже имеет объем памяти 2048 байт, разбитый на восемь банков по 256 байтов. Однако у этой микросхемы задействованы входы установки адреса (АО, Al, А2). Это единственная микросхема из всех микросхем серии АТ24Схх, у которой старшая часть адреса не равна ЮЮВ. Фиксированная часть адреса сокращена до одного бита (см. табл. 3.1). В результате, такая микросхема выступает на PC шине как восемь Slave устройств. Причем на шину одновременно можно подключать восемь таких микросхем. В результате структура адреса, заложенного в основной служебный байт, следующая.
Старший бит всегда равен единице. Три следующих бита определяют номер микросхемы. Последние три бита адреса определяют номер банка памяти внутри выбранной микросхемы. Если подключить все восемь микросхем на шину, то с точки зрения процессора на шине будут присутствовать 64 Slave устройства, имеющих по 256 ячеек памяти каждое. Логика обмена данными по PC шине для микросхемы АТ24С164 полностью соответствует логике работы с микросхемой АТ24С16. Увеличивается только количество используемых Slave адресов. Их диапазон теперь простирается от 40Н до 7FH. Максимальный суммарный объем памяти в случае применения микросхем типа АТ24С164 составляет 16 Кбайт.
Дальнейшее развитие микросхем флэш-памяти привело к созданию следующей модификации PC протокола. Для адресации еще больших объемов памяти был разработан протокол с двумя дополнительными служебными байтами. Диаграмма работы такого протокола приведена на рис. 3.11. Как можно видеть из диаграммы, логика работы такого протокола аналогична предыдущему случаю (см. рис. 3.10). Два дополнительных служебных байта содержат адрес ячейки памяти. Сначала передается старший байт адреса, а затем младший. Служебные байты передаются только в режиме записи. Содержащийся в них адрес запоминается в специальном регистре микросхемы памяти и называется текущим адресом. При записи последовательности из нескольких байтов, текущий адрес автоматически увеличивается после каждого байта. Режим записи иллюстрируют две верхние диаграммы на рис. 3.11.
Процесс чтения иллюстрируют две нижние диаграммы на рис. 3.11. При чтении блока из нескольких байтов текущий адрес автоматы-
Микросхемы EEPROM с 12С интерфейсом
125
чески увеличивается после каждого байта. Для того, чтобы начать чтение с заранее заданного адреса, сначала нужно установить новое значение текущего адреса. В этом случае процесс чтения начинается с перезаписи адреса. При перезаписи адреса в микросхему памяти передаются лишь два дополнительных служебных байта.
Фирмой Atmel разработана целая линейка микросхем, использующих новый протокол. В нее вошли такие микросхемы, как АТ24С32, АТ24С64, AT24CI28, АТ24С256, АТ24С512, АТ24С1024. Рассмотрим их по порядку.
Микросхема АТ24С32 имеет объем памяти 4096 байт. Они выступают одним общим массивом и не разбиваются на банки. Для адресации такого количества ячеек используется 12 разрядов адреса. В двух дополнительных служебных байтах содержится 16 разрядов адреса. Поэтому 4 старших разряда не используются. В столбцах 16 и 17 табл. 3.1 указано число разрядов адреса для каждой из микросхем. Неиспользуемые разряды могут принимать любые значения. На процесс выбора ячейки это не влияет.
В микросхеме АТ24С32 задействованы входы АО, А1 и А2. Благодаря чему на одну PC шину можно одновременно подключить до восьми таких микросхем. Суммарный объем памяти при этом будет равен 32 Кбайтам.
Микросхема АТ24С64 отличается от АТ24С32 только вдвое большим объемом памяти. Для адресации этой памяти используются уже 13 разрядов адреса. Других особенностей микросхема не имеет.
Следующие три микросхемы (АТ24С128, АТ24С256, АТ24С512) по своей внутренней структуре максимально приближены к микросхемам АТ24С32/64. Они имеют объем памяти 16, 32 и 64 Килобайт, соответственно. Для адресации этой памяти используется соответственно, 14, 15 и 16 разрядов. Отличительной особенностью этих трех микросхем является то, что в них не задействован вход А2. В связи с этим на одну PC шину может быть одновременно подключено не более четырех микросхем одного из этих типов.
Последняя микросхема из этой линейки АТ24С1024 отличается от остальных тем, что 128 Кбайт се памяти разбито на два банка по 64 Кбайт каждый. Вход АО у этой микросхемы не задействован. Поэтому на одну PC шину одновременно могут быть подключены только две такие микросхемы. Каждая из них выступает как два Slave устройства. Суммарный объем памяти для такой микросхе-
126
Работа с 12С шиной
I* Е
|о|<-<

Запись одного байта
Ю
CQ
W Q. <
% X

CQ
U О а 3
н О
5 ф
х х
§
►-
Я
аз
Ф
CQ О ф а 5
а
3 и
Рис. 3.11. Двухбайтовый способ адресации ячеек памяти EEPROM
Микросхемы EEPROM с 12С интерфейсом
127
мы равен 256 Кбайт. Точно такой суммарный объем обеспечивает микросхема АТ24С512. Правда, для этого нужно подключить на шину четыре таких микросхемы.
Вся описанная линейка микросхем АТ24С(32... 1024) также имеет страничную организацию памяти. Правила работы со страницами точно такие же, как и для микросхем АТ24С(02...16).
Особняком стоят две микросхемы специального назначения (АТ-24С21 и AT24CS128). Микросхема АТ24С21 имеет специальный дополнительный последовательный канал для считывания информации. Дополнительный канал использует специальный дополнительный вход VCLK и работает по упрощенному протоколу. Информация считывается сразу из всей памяти, бит за битом, начиная с самого первого байта. В процессе считывания информации на вход VCLK подаются тактовые импульсы. Считываемые биты снимаются с выхода SDA. Дополнительный канал предназначен только для чтения данных. Микросхема не использует ни одного из входов выбора адреса АО, Al, А2 и при подключении к микроконтроллеру должна быть единственной микросхемой на шине. В связи с тем, что данная микросхема предназначена для специальных применений, мы не будем подробно останавливаться на ее описании. В случае необходимости вы можете найти полное описание микросхемы на сайте фирмы Atmel |3WJ-
Микросхема AT24CS128 является аналогом микросхемы АТ24С128. Она отличается от прототипа тем, что имеет специальную область памяти, которая может работать в режиме одноразовой записи. В документации он называется «One-time Programmable» или OTP. Дополнительная область памяти имеет объем в 256 байт. Она расположена в верхней части адресного пространства, сразу после основной памяти. Пока режим ОТР не включен дополнительная память работает как обычная. После включения ОТР режима единожды записанная туда информация не может быть изменена. Она может быть только прочитана.
Но главное назначение этой области — она может служить в качестве ключа. Для этого микросхема имеет режим проверки. В режиме проверки выполняется запись информации в ОТР область памяти. Запись не изменяет содержимое ОТР памяти Однако, в том случае, если «записываемые» данные в точности повторяют
128
Работа с PC шиной
данные в памяти, то при «записи» каждого байта микросхема выдает сигнал подтверждения Такой сигнал возникает в том случае, если «запись» прошла удачно. Если «записываемые» данные отличаются от данных ключа, то подтверждения не будет.
Для включения режима ОРТ на 12С шину, к которой подключена данная микросхема, необходимо подать следующую последовательность сигналов:
S 1010 1100 11хх хххх хххх хххх хххх хххх Р
Микросхемы серии АТ24Схх выпускаются в корпусах разных видов. Используются такие типы корпусов, как PDIP, SOIC, TSSOP, МАР, SOT23. Каждая микросхема обычно имеет 8 выводов. Типовое назначение выводов приведено в табл 3.4.
Типовое назначение выводов микросхем памяти	Таблица 3.4
Вывод	Символ	Назначение
1	АО	Входы предустановки адреса
2	А1	
3	А2	
4	GND	Общий провод
5	SDA	Линия данных
6	SCL	Линия синхронизации
7	WP	Вход защиты от записи
8	Vpp	Напряжение питания
Напряжение питания микросхем серии АТ24Схх может изменяться в довольно широких пределах. Верхний предел питания обычно равен 5,5 В. Нижний предел бывает разный. Для каждого типа микросхем существует две или три модификации, различающиеся нижним пределом напряжений. На корпусе микросхемы обычно указывается нижний предел. Однако некоторые виды микросхем отличаются нестандартным питанием. Поэтому при покупке микросхемы обязательно проверяйте ее параметры по справочнику. Максимально допустимая скорость передачи информации при разных режимах питания может быть разной. Основные скоростные характеристики микросхем приведены в табл. 3.5.
Програмная реализация 12С интерфейса
129
Таблица 3 5
Скоростные характеристики микросхем
Тип микросхемы	Быстродействие при разных напряжениях питания. (Кбит/с)			
	1,8 В	2.5 В	2,7 В	5В
АТ24С01	100	100	100	400
АТ24С01А, 02. 04,16	100	100	100	400
АТ24С02А,04А, 06А	100	100	100	400
АТ24С21	-	100	-	100
АТ24С16А	100	400	400	400
АТ24С164	100	100	100	400
АТ24С32,64	100	100	100	400
АТ24С32А	100	400	400	400
АТ24С64А	400	400	400	400
АТ24С128, 256	100	400	400	1000
АТ24С512	100	-	400	1000
АТ24С1024	-	-	400	1000
AT24CS128	100	-	400	1000
3.6.	Программная реализация 12С интерфейса
В предыдущем разделе мы подробно рассмотрели протоколы для всех режимов работы микросхем флэш-памяти серии АТ24Схх, В настоящей главе нам предстоит познакомиться с примерами программ, реализующих эти протоколы. Фирма Atmel очень ответственно подходит к вопросу технической поддержки своей продукции. На сайте фирмы ([3W]) постоянно публикуются типовые образцы программ, которые она рекомендует применять для разных случаев применения микросхем своего производства. Существует также и набор подпрограмм, специально разработанных для работы с микросхемами АТ24Схх серии. Вполне естественно, что существует несколько вариантов таких программ, написанных для разных типов микроконтроллеров Мы рассмотрим типовой пакет подпрограмм для работы с микросхемами флэш-памяти, имеющими PC интерфейс. Этот вариант программ разработан фирмой Atmel специально для микроконтроллера АТ89С2051. В свое время эти программы были скачаны автором с сайта Atmel и адаптированы под ту версию ассемблера, на которой написаны все программные
5 Зах 922
130
Работа с l2C шиной
примеры, приведенные в настоящей книге. Применение программ, рекомендованных изготовителем микросхем, гарантирует надежность и качество работы. Приведенные ниже подпрограммы опробованы на практике. Именно эти подпрограммы используются, например, для записи информации во внешнюю флэш-память позиционера спутниковой антенны, описанного в [1].
Описываемая ниже версия подпрограмм рассчитана на работу с микросхемами, которые используют протокол с двумя дополнительными служебными байтами В графическом виде этот протокол изображен на рис. 3.11. Однако все подпрограммы можно легко адаптировать для протокола с одним служебным байтом (см. рис. 3.10). Как это сделать, я расскажу в конце раздела. В качестве примера к микроконтроллеру мы будем подключать микросхемы АТ24С64. Схема включения микросхем в этом случае будет точно такая, как изображена на рис. 3.9. Для того, чтобы применить эти подпрограммы для других типов микросхем, достаточно лишь изменить некоторые константы.
В процессе реализации протокола необходимо отрабатывать различные временные интервалы. В приведенных примерах подпрограмм все временные интервалы формируются программным путем. Чаще всего, для формирования задержки программа выполняет несколько «пустых» команд. Время задержки при этом будет зависеть от количества пустых операторов и от частоты кварцевого резонатора. При разработке подпрограмм предполагалось, что кварцевый резонатор должен иметь резонансную частоту 12 МГц.
Для удобства изучения все подпрограммы пакета были условно разбиты на несколько групп. В каждой такой группе собрано несколько подпрограмм сходного назначения. Мы будем изучать группы подпрограмм в порядке их значимости. А начнем мы с того, что посмотрим, какие переменные и константы нужно определить в самом начале программы для нормальной работы всего пакета. Для этого обратимся к листингу 3.1. Он представляет собой начальную часть основной программы.
В строках 2...6 определяются значения нескольких констант, используемых в дальнейшем при работе с флэш-памятью. Значения большинства из этих констант зависят от характеристик применяемой микросхемы памяти. Константа FADDR описывает фиксированную часть Slave адреса. Фиксированная часть — это четыре старших разряда основного служебного байта. Их значение, как мы
Програмная реализация 12С интерфейса
131
помним, всегда равно 10ЮВ (или ОАН), Поэтому значение самой константы FADDR будет равно 10100000В или (ОАОН). Константа FADDR представляет собой значение служебного байта, в котором установлена только фиксированная часть адреса, а остальные биты равны нулю. Константа PADDR определяет изменяемую часть адреса. Если быть точным, константа PADDR — это номер микросхемы памяти. В зависимости от того, к какой из восьми микросхем мы хотим обратиться, эта константа может принимать значение от О до 7 В нашем случае номер микросхемы равен нулю. На схеме рис. 3.9 эта микросхема обозначена как DD2. Это та самая микросхема, у которой на все три адресных входа (АО, Al, А2) подан сигнал логического нуля. Для вычисления изменяемой части адреса три младших бита константы PADDR сдвигают влево на один шаг. Как это делается, мы увидим дальше.
Константа SIZE хранит объем памяти используемой микросхемы Константа PSIZE — это размер одной страницы памяти. И, наконец, константа FILL — это код для заполнения. Этот код используется в процедуре заполнения всех ячеек памяти одной и той же величиной. А также в процедуре проверки правильности заполнения.
Всем константам присвоены значения, соответствующие характеристикам выбранной микросхемы флэш-памяти (АТ24С64). Для того, чтобы адаптировать пакет подпрограмм для работы с другим типом микросхем, достаточно просто поменять значения соответствующих констант.
В строках 7... И происходит определение переменных программы. Каждой переменной ставится в соответствие один из регистров. Именно в этом регистре и будет храниться значение соответствующей переменной. Подробно об использовании каждой переменной мы узнаем чуть позже. Сейчас же мы приведем лишь общее назначение каждой из них. Регистр гО будет использоваться как счетчик-указатель текущей ячейки в буфере данных (строка 7). Буфер используется как временное хранилище данных в процессе приема каждой страницы. Регистр г1 будет использоваться в качестве счетчика принятых байтов. Этот же регистр, в другом случае, будет служить в качестве буфера данных (строки 8, 9). Регистры г2 и гЗ используются для хранения текущего адреса считываемой памяти (строки 10, II). В регистре г2 хранится младшая часть адреса, а в регистре гЗ — старшая.
132
Работа с l2C шиной
В строках 12 и 13 определяются разряды порта Р1, которые будут использоваться в качестве линий SCL и SDA. В строках 14... 16 резервируется память под буфер страницы. Буфер начинается с адреса 40Н и имеет длину, равную PSIZE И в заключение, определяется адрес начала и глубина стека (строки 17, 18).
Листинг 3.1
				
	Определение констант и переменных			и инициализация программы
1	Smod2051			
2	FADDR	EOU	OAOH	Фиксированная часть адреса
3	PADDR	EOU	0	Номер микросхемы <м.б. от 0 до 7)
4	SIZE	EOU	2000H	Размер памяти АТ24С64 (в байтах)
5	PSIZE	EOU	32	Размер страницы АТ24С64 (в байтах)
6	Fill	EOU	55H	Пример величины заполнения
	Определение	регистров.		
7	index	EQU	rO	указатель буфера
8	koun!	EQU	H	регистр счетчика байтов
9	zdata	EQU	r1	регистр данных
1С	addr lo	EOU	r2	2х байтовый регистр адреса
11	addrhi	EOU	r3	
	Подключение шин		микроконтроллера	к последовательной шине АТ24Схх
1	SCL	BIT	p12	линия синхронизации
13	SDA	BIT	pl.3	линия данных
и		DSEG		
15		ORG	40H	
16	buffer:	DS	PSIZE	буфер данных чтения/записи
17		ORG	60H	начало стека
18	stack.	DS	20H	глубина стека
	.штттттшттштшттшшттт!!			
			Начало программного кода	#tf	
				
19		CSEG		
20		ORG	ООООН	к процедуре инициализации
21		imp	on_reset	после включения/сброса
22		ORG	0003H	переопределение вектора
23		reri		; внешнего прерывания 0
24		ORG	OOOBH	; переопределение вектора
Програмная реализация PC интерфейса
133
25
26
27
28
29
30 :i1
ген		, прерывания по таймеру 0
ORG	0013H	переопределение вектора
reti		внешнего прерывания 1
ORG	001BH	переопределение вектора
reti		прерывания по таймеру 1
ORG	OO23H	вектор прерывания по
reti		последовательному каналу
Инициализация программы
ORG	0080Н
USING	О
on_reset mov sp.#(stack-1)	установка вершины стека
, Инициализация линий последовательного канала АТ24Схх
setb	SDA	Запись высокого уровня
setb	SCL	Запись высокого уровня
Далее идет основной текст программы
Строки 19 .31 — это переопределение векторов прерываний. Наши подпрограммы не используют прерывания, поэтому все специальные адреса закрываются «заглушкой» (командой reti). Если какое-либо прерывание потребуется для основной программы, его можно определить так, как это сделано, например, в программе, приведенной в листинге 1.5 (см. главу 1). Использование прерываний нс мешает работе с 12С шиной, если перед началом любой операции с шиной будет стоять команда запрета прерывания. По окончании работы с шиной не забудьте поставить команду разрешения прерывания. По адресу 0000Н (см. строки 20, 21 программы) находится команда безусловного перехода на начало основной программы (по метке on_reset) Приведены также первые строки этой программы (строки 34...36). Начинается она с команды инициализации стека (строка 34). Затем обе линии PC шины (SCL и SDA) переводятся в исходное (единичное) состояние (строки 35, 36).
Итак, мы определили все основные константы и переменные В реальной программе вы добавите сюда свои команды для определения констант и объявите дополнительные переменные. Мы же пойдем дальше. Теперь пора начинать рассмотрение подпрограмм
134
Работа с l2C шиной
пакета. Начнем мы с блока подпрограмм самого низкого уровня. И первая подпрограмма из этого блока называется start. Она предназначена для формирования СТАРТ условия на PC шине.
Посмотрите на листинг 3.2. Там приведен текст этой подпрограммы. Подпрограмма start не получает и не возвращает данных. Однако, перед тем, как приступить непосредственно к процедуре формирования СТАРТ-условия, она проверяет состояние линий SDA и SCL. Если хотя бы одна из линий занята (сигнал равен нулю), СТАРТ-условие не формируется, а процедура возвращает сигнал ошибки.
Принцип работы программы предельно прост. Сначала линии SDA и SCL переводятся в единичное состояние (строки I и 2). Затем, в строках 3 и 4 происходит проверка уровня сигналов на этих линиях. Если один из проверяемых битов окажется равным нулю, то произойдет переход по метке х40 (к строке 15). Здесь происходит формирование сигнала ошибки. Информация об ошибке возвращается в ячейке признака переноса (CY). В случае ошибки CY устанавливается в единицу. Если в процессе проверки линий выяснилось, что все нормально и обе они «отпущены», начинается формирование СТАРТ-условия (строки 5... 12). Для этого переводятся в ноль сначала линия SDA (строка 6), а затем линия SCL (строка 12). Между этими двумя событиями нужно обеспечить небольшую задержку по времени. Для формирования необходимой задержки применяется пустой оператор пор. Команда пор означает «нет операции». Встретив эту команду, микроконтроллер не выполняет никаких действий. Однако каждая такая команда занимает один машинный цикл. Несколько операторов пор, поставленных друг за другом, формируют требуемую задержку. После окончания процесса формирования СТАРТ-условия, программа обнуляет признак переноса (строка 13) и завершается.
Листинг 3.2
Формирование СТАРТ условия
1	start' setb SDA
2	setb SCL
: Проверка доступности шины
3	job SDA.xAO
Установка линий в исходное состояние
; переход если линия SDA занята
Програмная реализация 12С интерфейса
135
4	job	SCL x40	переход ecrj линий SCL занята
5	пор		предварительная задержка
6	clr	SM	в ноль линию дам|-ыи
7	г ,г>		. задержка
8	ОСО		
9	пор		
10	пор		
11	imp		
12	clr	SCL	в ноль линию синхронизации
13	clr	c	очисти фл".га ошибки
14	jmp	x41	
15	х40'	setb		уст •пркз флаг' ошибки
16	х41	re1		
Процедура формирования СТОП-условия (см. листинг 3.3) еще проще. Процедура называется stop. Она не производит никаких проверок, а просто формирует нужную последовательность фронтов и спадов Сначала обнуляется линия SDA (строка I). Затем линия SCL переводится в единичное состояние (строка 4). И, наконец, SDA снова переводится в единичное состояние (строка Ю). Вес временные интервалы, как и в предыдущем случае, формируются при помощи операторов пор.
Листинг 3.3
Формирование СТОП условия
1 2
3
4
5 6
7 8
9
10
11
stop- lr SDA псу? пор setb SCL пор пор пор пор пор setb SDA ret
в '.'.ont линию данных
зацзржка SCL перед установи? гднчых
в единицу линию синхронизации здегша
в единицу линию данных
Следующая подпрограмма предназначена для формирования сигнала подтверждения. Сигнал подтверждения используется в девятом такте передачи байта для подтверждения правильности приема.
136	Работа с l2C шиной
Процедура называется АСК (см. листинг 3.4). Эта процедура не получает и не возвращает данных, и не производит никаких проверок. Она лишь формирует нужную последовательность сигналов. Сначала линия SDA переводится в ноль (строка 1), а затем на линии SCL формируется один положительный тактовый импульс (строки 4 .9) Все задержки и в этом случае формируются при помощи команды пор.
Листинг 3.4
Формирование сигнала подтверждения
1
2
3
4
5
6
7
8
9
10
АСК:	clr SDA
пор пор setb SCL
пор пор пор пор clr SCL
ret
АСК бит
задержка SCL перед уст данных
начало тактового импульса
задержка
конец тактового импульса
Отдельная подпрограмма служит для формирования сигнала не-подтверждения. Подпрограмма называется NAK. Микроконтроллер вызывает эту подпрограмму вместо подпрограммы ASK в том случае, когда произошла ошибка приема или для того, чтобы прервать процесс чтения цепочки байтов. Текст процедуры приведен в листинге 3.5. От процедуры АСК она отличается только тем, что на линии SDA устанавливается не нулевой, а единичный уровень (см. строку 1).
Листинг 3.5
Формирование сигнала неподтверждения
1 NAK:	setb SDA ; ND АСК бит
Програмная реализация |2С интерфейса	137
	пор	задержка SCL перед уст данных
3	пор	
4	setb SCL	начало тактового импульса
5	пор	задержка
6	пор	
7	пор	
8	пор	
9	clr	SCL	конец тактового импульса
10	ret	
Теперь перейдем к блоку подпрограмм более высокого уровня. И первая такая подпрограмма — это процедура записи байта в Slave устройство по PC шине. Эта процедура называется shout. Текст процедуры приведен в листинге 3.6 Байт, предназначенный для записи по PC шине, передастся подпрограмме в качестве параметра через аккумулятор. Ячейка признака переноса CY используется в качестве флага ошибки. В случае нормального завершения операции CY содержит логический ноль. Если при записи байта произойдет ошибка, то CY будет равен единице.
Посмотрим на текст подпрограммы. Регистр Ь используется в ней в качестве счетчика битов. В связи с этим, в начале подпрограммы содержимое этого регистра сохраняется в стеке (строка I). В конце подпрограммы содержимое Ь восстанавливается (строка 23). Для последовательной передачи восьми битов в программе организуется цикл. Тело цикла составляют строки 3...12. Перед началом цикла в регистр b записывается начальное значение (строка 2).
В теле цикла происходит извлечение каждого очередного бита данных и передача его по PC шине. Для побитного извлечения данных используется оператор rlc. Этот оператор вызывает циклический сдвиг содержимого аккумулятора через признак переноса CY. В первой строке тела цикла (строка 3) этот оператор сдвигает передаваемый байт на один бит влево и значение очередного бита оказывается в ячейке CY. Далее, полученный бит передается по PC шине (строки 4. II). В строке 4 передаваемый бит выводится на линию SDA. В строках 6...Н на линии SCL формируется синхроимпульс. В строке 12 находится оператор организации цикла. Он передает управление на начало цикла (по метке х42), до тех пор, пока содержимое счетчика битов (регистра Ь) не достигнет нуля.
138
Работа с lzC шиной
Листинг 3.6
	Побитная передача байта, старшим битом вперед			
1	shout	push	i)	
2		mov	b #8	счетчик битов
3	х42’	rlc	a	поместить бит в CY
4		mov	SDA.i	вывод бита
5		пор		задержка SCL перед установкой дан ix
6		setb	SCL	начало тактового импульса
7		nop		задержка
8		nop		
9		nop		
10		nop		
11		clr	SCL	завершение тактового импульса
12		djnz	b.x42	спедуюшии бит
13		setb	SDA	освобождение SDA г ст АСК
14		nop		задержка перед SCL и АСК
1)		nop		
16		etb	SCL	• надо tjktobo о имг, ьса АСК
17		nop		задгржкд
18		nap		
19		nop		
20		nop		
21		mov	c.SDA	получение Пр а АСК
22		dr	SCL	окончание тактового импульса АСК
23		pop	b	
24		rei		
После передачи восьми битов данных подпрограмма проверяет сигнал готовности, который вырабатывает микросхема памяти в случае нормального завершения операции. Проверка сигнала готовности производится в строках 13...22. Прежде всего, программа освобождает линию SDA (строка 13), устанавливая на выходе единичное значение. Затем, программа формирует тактовый импульс на линии SCL (строки 14...22). Перед самым окончанием тактового импульса в строке 21 программа читает уровень сигнала с линии SDA и помещает его в ячейку CY. Полученный таким образом сигнал готовности и используется в качестве признака ошибки. По сути, это и есть сигнал ошибки. Именно поэтому он был помещен в CY. Поэтому подпрограмма просто завершается. Обратите внимание, что и в этом случае все необходимые задержки формируются при помощи команды пор
Програмная реализация PC интерфейса	139
Процедура shin принимает один байт по PC шине. Текст процедуры приведен в листинге 3.7. Никаких данных процедуре shin передавать не требуется. Зато сама процедура возвращает принятый байт в аккумуляторе. Как и в предыдущем случае, регистр b использует ся в качестве счетчика битов. Поэтому в начале процедуры его содержимое сохраняется в стеке (строка 2). В строке 3 счетчику битов присваивается начальное значение. Для приема восьми битов данных и объединения их в один байт организуется цикл. Тело цикла составляют строки 4 ..13. Перед началом цикла программа «отпускает» линию данных (строка I). В теле цикла формируется тактовый импульс на линии SCL. Фронт импульса формируется в строке 7, а спад в строке 12. Перед самым окончанием тактового импульса происходит считывание значения очередного бита (строка Ю). Затем значение бита помешается на свое место в аккумулятор путем сдвига содержимого аккумулятора на один бит влево (строка II). После восьми таких сдвигов в аккумуляторе окажется принятый байт. В строке 13 находится оператор цикла, который передает управление в начало цикла. Такой переход выполняется до тех пор, пока не будут приняты все восемь битов. Передача сигнала подтверждения происходит за пределами подпрограммы shin. Перед выходом из подпрограммы производится восстановление содержимого регистра b из стека.
Листинг 3 7
•; Побитный прием байта, старшим битом вперед
1	shin:	setb	SOA
2		push	b
3		mov	b #8
4	х43:	nop	
5		пор	
6		nop	
7		setb	SCI
8		nop	
9		nop	
10		mov	c.SDA
11		rlc	a
12		clr	SCL
13		djnz	Ь.хАЗ
14		pop	b
15		ret	
использовать SDA как вход
счетчик битов
задержка
начало тактового импульса задержка
получение бита
сборка битов в байт
окончание тактового импульса следующий бит
140
Работа с PC шиной
Приведенные выше две подпрограммы (shout и shin) не имеют самостоятельного значения. Это просто вспомогательные подпрограммы, которые используются в других процедурах более высокого уровня наряду с подпрограммами start, stop, ASK и NAK Как раз эти процедуры следующего, более высокого уровня, мы сейчас и рассмотрим.
И первая из этих процедур называется write_byte. Текст процедуры приведен в листинге 3.8. Это законченная процедура, реализующая алгоритм записи одного байта данных в произвольную ячейку заранее заданной микросхемы памяти. Адрес Slave устройства, в которое будет записываться байт информации, состоит из двух частей. Эти части адреса поступают в описываемую процедуру по-разному. Фиксированная часть адреса определяется константой FADDR. Изменяемая часть адреса передается в процедуру через аккумулятор.
Причем передается нс сама младшая часть адреса, а номер вызываемой микросхемы. Для микросхемы DD2 (см. рис. 3.9) этот номер будет равен нулю. Для микросхемы DD3 — единице. И так далее. Подпрограмма использует обе половинки Slave адреса при формировании основного служебного байта. Для процесса записи мало выбрать одну из микросхем. Для выбранной микросхемы нужно указать адрес ячейки памяти, куда будет записываться информация. Адрес ячейки памяти внутри выбранной микросхемы передается в подпрограмму посредством двух переменных.
Переменная addrhi содержит старшую часть этого адреса, а переменная addrjo — младшую его часть. Значение, предназначенное для записи, содержится в переменной zdata. Каждая из этих трех переменных представляет собой регистр общего назначения, где и хранится соответствующая величина (см. листинг 3.1).
Процедура write byte также устанавливает признак ошибки. Для передачи признака ошибки используется ячейка CY. Если в процессе записи произойдет ошибка, в CY записывается единица.
Теперь разберем подробнее текст процедуры write_byte (см. листинг 3.8). Начинается процедура с формирования СТАРТ-условия (строка 1). В случае ошибки (линия занята) процедура start возвращает единицу в ячейке CY В строке 2 это значение проверяется. Если CY равно единице, то управление передается по метке х49 и подпрограмма write byte завершается Причем признак ошибки так и остается в ячейке CY.
Програмная реализация PC интерфейса
141
Листинг 3 8
Процедура записи одного байта по произвольному адр< ,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
write_byte‘ call start jc	x49
rl	a
orl	a,#FADDR
clr	acc 0
call	shout
jc	x48
mov	a,addr_hl
call	shout
jc	x48
mov	a,addrjo
call	shout
jc	/48
mov	a.zdata
call	shout
jc	x48
clr	c
x48:	call	stop
x49:	ret
формирование СТАРТ условия выход, если пин» гедостипна
изменяемый адрес (биты 3:1) "Убавление фиксированного адреса установка признака «записо» передача служебного байта выход, если ошибка
передача старшего банта адреса
выход если ошиб*
передала младшего байта адрес-
выход, если оибка
данные в аккумулятор передача данных выход если ошибка
очистка фгаго ошибки
Если ошибки нет, то передача байта продолжается. В строках 3...5 происходит формирование основного служебного байта. Сначала номер выбранной микросхемы, переданный в подпрограмму через аккумулятор, сдвигается вправо на один бит. В результате три значащих бита этого номера оказываются на своих местах в будушсм служебном байте (см. рис. 3.11), где они определяют изменяемую часть адреса Slave устройства. Далее, в строке 4 к изменяемой части добавляется фиксированная часть адреса. Слияние двух частей адреса производится при помощи оператора orl, который реализует функцию «ИЛИ» между двумя частями адреса. И в заключение, в полученном значении служебного байта младший бит сбрасывается в ноль. Как вы помните, младший бит служебного байта определяет вид выполняемой операции. Нулевое значение этого бита соответствует операции записи. Сформированный таким образом служебный байт выводится в PC шину Для вывода байта используется подпрограмма shout (строка 6). В строке 7
142
Работа с PC шиной
проверяется значение флага ошибки. В случае ошибки управление передается по метке х48, где программа завершается. Если ошибки нет, процесс записи продолжается.
После передачи первого служебного байта, таким же образом передаются и два дополнительных. Передача дополнительного служебного байта, содержащего старшую часть адреса ячейки памяти, производится в строках 8...Ю программы. Служебный байт, содержащий младшую часть адреса, передается в строках 11... 13. После передачи каждого вспомогательного байта производится проверка признака ошибки. В случае ошибки управление передается все к той же метке х48. В строках 14...J6 точно таким же образом передастся байт данных. В случае нормального завершения всех этих операций очищается флаг ошибки (строка I7), после чего в строке 18 происходит формирование СТОП-условия. В строке 19 процедура write byte завершается.
Процедура readcurrent производит чтение одного байта из произвольной микросхемы памяти по текущему адресу. Напомню, что текущий адрес хранится в самой микросхеме памяти. Поэтому каждая микросхема будет иметь свой собственный текущий адрес. Текст процедуры приведен в листинге 3.9. Начинается процедура с формирования СТАРТ-условия (строка I). В строке 2 происходит проверка признака ошибки. В случае обнаружения ошибки управление передается в конец процедуры по метке х45. В строках 3...5 происходит формирование основного служебного байта.
От предыдущего примера данный процесс отличается только тем, что в данном случае младший бит служебного байта устанавливается в единицу (см. строку 5). Эта единица определяет режим чтения. Сформированный служебный байт передается по шине (строка 6). Строка 7 — оценка признака ошибки. В строке 8 вызывается процедура чтения байта данных. Процедура shout читает восемь бит данных, а затем при помощи процедуры NAK производится вывод сигнала неготовности. Этот сигнал необходим для того, чтобы микросхема памяти после передачи одного байта вышла из режима передачи (см. на рис. З.Н диаграмму «Чтение данных с текущего адреса»).
И в завершение процедура read current сбрасывает признак ошибки (строка Ю), вырабатывает сигнал СТОП (строка II) и заканчивает свою работу (строка 12).
Програмная реализация 12С интерфейса
143
Листинг 3 9
 Процедура чтения одного байта по текущему адресу
read.current.
1		tall	start
2		К	x45
3		rl	a
4		orl	a.UFADDB
5		setb	acc 9
6		ull	shout
7		JC	<44
8		call	shin
9		call	NAK
10		clr	c
11	х44:	call	stop
12	х45:	ret	
формигэвание СТАРТ условия выход если шика недоступиа
изменяемый адрес (биты 3:1) добавить фиксирова' до адрес устамлвка типа i . !,ии ( чтсни ) перчмича служебк ? Файта
еыхад 8C! >' "ЖГГГкЛ
получение байта данных пере-дзча сигнала неготовности
очистка флага ошибки формирование СТОП успивия
Процедура read random (см. листинг 3.10) тоже читает один байт из произвольной микросхемы памяти. Однако в данном случае чтение байта производится не по текущему, а по произвольному адресу. Такой процесс фактически состоит из двух процедур: процедуры записи нового текущего адреса и процедуры чтения байта по текущему адресу. Две эти процедуры составляют одно целое потому, что в конце первой из них отсутствует СТОП-условие. Адрес ячейки памяти, из которой нужно прочитать байт информации, передается в процедуру через ячейки addr_hi и addrjo. Номер микросхемы памяти передается в процедуру через аккумулятор. Начинается процедура с сохранения в стеке содержимого регистра b (строка 1). Этот регистр нам понадобится для временного хранения содержимого аккумулятора. Команда, помещающая содержимое аккумулятора в регистр Ь, находится в строке 2. Затем начинается процедура определения нового текущего адреса. Эту процедуру можно назвать «Ложной записью», так как выполняется она так же, как процедура записи, за исключением последнего этапа — записи данных. Процедура «Ложной записи» занимает строки 3...15. В строках 3. 4 происходит формирование СТАРТ-условия. В строках 5...9 формируется
144
Работа с l2C шиной
и выдается на линию основной служебный байт. В строках 10... 15 в линию передаются два дополнительных служебных байта. На этом процедура «Ложной записи» заканчивается. После окончания «Ложной записи» новый текущий адрес будет установлен.
После этого начинается процедура чтение байта. Для этого из регистра b извлекается номер микросхемы памяти и помещается в аккумулятор (строка 16). Затем просто вызывает процедуру read current (строка 17). Процедура read_current самостоятельно формирует значение основного служебного байта. Кроме того, она сама формирует как СТАРТ, так и СТОП условия. Поэтому сразу после се окончания управление передается по метке х47, где процедура read_random заканчивается. Строка 19 включена в программу для того, чтобы правильно завершать операцию в случае досрочного выхода из-за ошибки.
Листинг 3.10
			
	 Процедура чтения одного	байта no произвольному адресу	
1	read_random push	0	сохранить регистр в стеке
2	mov	b,a	сохранение копии аккумулятора
	Посылка команды ложной	записи для установки начального адреса	
3	call	start	формирование СТАРТ условия
4	JC	х47	выход, если шина не доступна
5	rl	а	изменяемый адрес (биты 3'1)
6	orl	a,«FADDR	добавить фиксированный адрес
7	clr	асс.О	установка типа операции («запись»)
8	call	shout	передача служебного байта
S	jc	х46	выход, если ошибка
10	mov	a.addr hi	передача старшего байта адреса
11	call	shout	
12	jc	х46	выход, если ошибка
13	mov	a.addr lo	передача младшего байта адреса
14	call	shout	
15	JC	x46	выход, если ошибка
	Вызов функции чтения no	текущему адресу	
16	mov	a.b	. получить адрес микросхемы памяти
17	call	read_current	чтение с текущего адреса	
18	jmp	x47	переход на конец процедуры
19	x46:	cuil	stop	формирование СТОП условия
Програмная реализация PC интерфейса
145
20	х47'	pop	b	восстановить регистр и, •
21	ret
Итак, мы рассмотрели несколько простейших случаев, когда нужно прочитать либо записать всего один байт информации. Приведенные подпрограммы легко можно доработать таким образом, чтобы они могли читать либо записывать целую цепочку байтов Сделать это можно двумя способами. Можно просто повторять много раз процедуру чтения/записи одного байта. А можно применить групповой режим, когда целый блок данных читается/записывается за один прием. Мы рассмотрим оба варианта. Во всех случаях для временного хранения прочитанного блока информации применяется специальный буфер, который в программе так и называется: buffer (см. листинг 3.1, строка 16). Размер этого буфера всегда равен PSIZE. то есть размеру страницы микросхемы памяти. В целях экономии памяти микроконтроллера тот же буфер используется и в режиме чтения.
Процедура записи блока информации в произвольную область памяти называется write_block. Текст процедуры приведен в листинге 3.11. Процедура записывает блок информации из буфера в микросхему памяти. Причем адрес ячейки флэш-памяти, с которой будет начинаться запись — это тот адрес, который хранится в переменных addr_hi и addrjo. Длина записываемого блока должна быть записана в переменную kount Номер микросхемы передается через аккумулятор. Подпрограмма write_block является развитием подпрограммы write_byte (см. листинг 3.8).
Для того, чтобы подпрограмма смогла записывать блок информации, в ней организован цикл передачи байтов. Тело цикла занимает строки 15...19. В строке 14 происходит инициализация переменной index. Переменная index предназначена для хранения адреса текущего передаваемого байта. Поэтому в качестве начального значения туда записывается адрес начала буфера.
В строке 1 происходит вызов процедуры формирования СТАРТ-условия. В строках 2...7 происходит формирование и вывод основного служебного байта. Затем на шину выводятся два дополнительных служебных байта. Эти два байта служат для адресации ячейки памяти. В строках 8... 10 происходит вывод старшего байта адреса, а в строках 11. .13 — выводится младший байт адреса. По-
146
Работа с l2C шиной
еле этого начинается цикл вывода блока информации из буфера. Тело цикла составляют строки 15...19. В строке 15 содержимое ячейки памяти, адрес которой хранится в index, помещается в аккумулятор. Затем происходит передача этого байта по ВС шине (строка 16). В строке 17 происходит проверка флага ошибки. В случае обнаружения ошибки, управление передается по метке х37. Если ошибки не было, то в строке 18 содержимое ячейки index увеличивается на единицу. Оператор цикла (строка 19) уменьшает счетчик цикла (kount) на единицу и, если после этого значение kount не достигнет нуля, передает управление на начало цикла (к метке х36).
По завершении цикла, в микросхему памяти будет записано нужное количество байт. Если цикл записи блока информации завершен успешно, то признак ошибки сбрасывается в ноль (строка 20). Перед окончанием процедуры write_block программа формирует СТОП-условие (строка 21).
Листинг 3 11
			
	Запись одной	страницы памяти Споком	
	write_block:		
1	call	start	формирование СТАРТ условия
2	jc	x38	выход, если шина недоступна
3	rl	a	изменяемый адрес (биты 3:1)
4	orl	a.nFADDR	добавление фиксированного адреса
5	clr	acc.O	определение типа операции (-запись»)
6	call	shout	посылка служебного байта
7	jc	x37	выход, если ошибка
8	mov	a.addr hi	передача старшего байта адреса
9	call	shout	
10	jc	x37	выход, если ошибка
11	mov	a.addr lo	передача младшего байта адреса
12	call	shout	
13	jc	x37	:	выход, если ошибка
14	mov	index.ll buffer	указатель буфера
1э	x36:	mov	a. ? index	очередной байт в аккумулятор
Програмная реализация 12С интерфейса
147
16		call	shout	передача байта
17		jc	x37	выход, если ошибка
18		inc	index	продвижение указателя буфера
19		djnz	kount,x36	следующий байт
20		clr	c	очистка Inara ошибки
21	Х37:	call	stop	формирование СТОЛ условия
22	х38:	ret		
Подпрограмма read_block предназначена для чтения блока информации из флэш-памяти и размещения этой информации в буфере. Текст подпрограммы приведен в листинге 3.12. Адрес считываемо го блока хранится в переменных addr_hi и addrjo. Длина блока должна быть записана в переменной kount. Номер микросхемы передается через аккумулятор. Процедура read_block является развитием процедуры read_random (см. листинг 3.10). Для того, чтобы программа могла считывать целый блок информации, организован цикл чтения данных.
Тело цикла занимает строки 22...29 Перед началом цикла переменной index присваивается начальное значение — адрес начала буфера (строка 21). Команды чтения байта включены в тело цикла. Сначала из флэш-памяти извлекается очередной байт (строка 22). Затем он записывается в буфер (строка 23). В строке 24 производится проверка счетчика байтов. Если байт не последний, то после его приема в линию передается сигнал АСК (строка 27), переменная index увеличивается на единицу (строка 28) и цикл продолжается (строка 29). Если же прочитан последний байт, то в линию передается сигнал NAK (строка 25), и управление передается на конец процедуры (по метке хЗЗ).
В остальном процедура read_block почти полностью соответствует процедуре read_random. Имеется еще только одно различие. Основной служебный байт, будучи один раз вычислен в строках 3, 4, не вычисляется вторично. Он записывается в переменную index (строка 5), которая используется в этом случае как временное хранилище информации. Затем, после окончания процедуры «Ложной записи», в строке 17 это значение извлекается из временного хранилища и используется при инициализации процесса чтения.
148
Работа с FC шиной
Листинг 3.12
Чтение одной страницы данных блоком
read_block:
Посылка команды ложной записи для адресации первого байта
1 2	call К		start x35	. формирование СТАРТ условия , выход, если команда не опознана
3		rl	a	изменяемый адрес (биты 3:1)
4		ОГ1	a, II FADDR	добавление фиксированного адреса
5		mov	index,a	сохранение служебного байта
6		clr	acc 0	определение типа операции («запись»)
7		call	shout	передача основного служебного байта
8		jc	x34	выход, если ошибка
9		mov	a,addr_hi	передача старшего байта адреса
10		call	shout	
11		jc	x34	выход, если ошибка
12		mov	a.addr.lo	, передача младшего байта адреса
13		call	shout	
14		jc	x34	выход, если ошибка
		; Передана команды чтения и		прием данных
15		call	start	формирование повторного СТАРТ условия
16		jc	x34	выход, если шина недоступна
17		mov	a. index	получение служебного байта
18		setb	acc.O	, определение типа операции ("чтение»)
19		call	shout	; передача нового служебного байта
20		jc	x34	 выход, если ошибка
21		mov	index, II buffer	. инициализация указателя буфера
22	х31	call	shin	. чтение байта данных
23		mov	(sindex.a	сохранения данных в буфере
24		cjne	kount.#1,x32	переход, если не последний байт
25		call	NAK	если последний байт
26		jmp	хЗЗ	, переход в конец процедуры
27	х32:	call	ACK	сигнал подтверждения
28		inc	index	продвижение указателя буфера
29		djnz	kount,x31	следующий байт
30	хЗЗ:	clr	c	очистка флага ошибки
31	х34:	call	stop	формирование СТОП условия
32	л35:	ret		
Примеры программ для работы с флэш-памятью
149
Итак, мы имеем все необходимые процедуры для того, чтобы организовать процесс обмена данными с любой микросхемой флэш-памяти по PC шине, поддерживающей протокол с двумя дополнительными служебными байтами. Этим условиям удовлетворяют микросхемы АТ24С32/64/128/256/512/1024. Однако все эти процедуры легко переделать так, чтобы они работали с другим, более простым протоколом, предусматривающим только один дополнительный служебный байт. Такой протокол применяется в микросхемах АТ24С01А/02/02А/04/04А/08/08А/16/16А. Для того, чтобы любую из описанных выше подпрограмм переделать на упрощенный протокол, нужно исключить из текста подпрограммы команды, передающие на PC шину содержимое переменной addrhi. Например, в процедуре write_byte (см. листинг 3.8) нужно исключить строки 8, 9 и 10. В процедуре read_random (см. листинг 3.10) нужно исключить строки 10, 11 и 12 и так далее. Переменную addr_hi в этом случае вообще можно не определять, исключив строку И в модуле определения переменных (листинг 3.1).
Для работы с микросхемами АТ24С01/164/21/S128 нужна более глубокая переделка всех процедур. В данной книге этот вопрос не рассматривается. Предлагаю самостоятельно модифицировать тексты всех подпрограмм, используя для этого данные из табл. 3.1.
3.7. Примеры программ для работы с флэш-памятью
В заключение этой главы приведу несколько примеров подпрограмм, иллюстрирующих использование описанных выше процедур обмена данными с микросхемами флэш-памяти. Для иллюстрации процесса записи информации в микросхему флэш-памяти приведу два варианта подпрограммы заполнения всех ячеек одним и тем же фиксированным кодом. В первом варианте программы будет применен побайтовый способ записи, а во втором случае запись будет производиться постранично. В качестве кода для заполнения памяти будет использовано значение константы FILL (см. листинг 3.1. строка 6).
Первая из этих подпрограмм называется byte_fi!L Текст этой подпрограммы приведен в листинге 3.13. Основу подпрограммы
150
Работа с PC шиной
составляет цикл записи байтов. Тело этого цикла начинается со строки 3 и заканчивается строкой 15. Перед началом цикла производится инициализация двух переменных. Во-первых, в переменную zdata записывается значение байта, которым мы будем заполнять всю память (стока 1). Во-вторых, в регистр DPTR, который используется в программе в качестве указателя адреса, записывается начальное значение (строка 2). Так как мы собираемся заполнять константой всю память микросхемы, то начальный адрес у нас будет равен нулю.
Листинг 3.13
Заполнение всех ячеек памяти одной и той же величиной
(побайтовый способ записи)
.Записывается одна ячейка за один раз (страничный режим не используется)
.Единица в СУ означает ошибку в процессе записи
.Изменяет содержимое Б DPTR. ХВАТА. ADDF._HI:ADDR LO
byte_fil1
1	mov		zdata,«FILL	установка байта заполнения
2		mov	DPTR.fiO	инициализация указателя адреса
3	x51.	mov	addr lo.DPL	установка адреса
4		mov	addrjii.DPH	
5		mov	b,«120	подготовка счетчика
6	x52	mov	a It PADDR	Номер микросхемы памяти
7		call	wnte_byte	попытка записи
8		jnc	x53	перейти если запись удалась
3		djnz	b, x52	повторить попытку записи
10		setb	c	установка флага истечения времени
11		jmp	x54	выход
12	x53:	inc	DPTR	увеличить указатель адреса
13		mov	a.DPL	проверить младший байт
14		cjne	a.#(low size),x51	 перейти если не последний
15		mov	a. DPH	• проверить старший байт
16		cjne	a,#(high size).x51	перейти если не последний
17		clr	c	, очистка флага ошибки
18	x54:	ret		
Примеры программ для работы с флэш-памятью
151
В начале цикла записи значение младшей (DPL) части адреса записывается в переменную addrlo (строка 3), а значение старшей (DPH) части адреса записывается в переменную addrhi (строка 4). Затем осталось только вызвать процедуру write_byte, которая записывает один байт по текущему адресу. Однако в подобных программах нельзя просто взять и записать байты данных во все ячейки памяти. Необходимо учитывать то, что после получения СТОП-условия в микросхеме флэш-памяти начинается относительно длительный процесс обработки информации. Длительность этого процесса для разных микросхем разная. В технических условиях оговорена только максимальная величина этой длительности (10 мс). Пока длится эта обработка, запись очередного байта невозможна. На любую попытку записи микросхема флэш-памяти ответит сигналом неготовности. Для того, чтобы точно отследить момент окончания процесса обработки, применяется метод многократной записи. Этот метод состоит в том, что программа производит множество попыток записи байта до тех пор, пока очередная попытка не окончится успехом. Однако, для того, чтобы, в случае дефекта микросхемы памяти этот цикл не продолжался вечно, в программе ограничено максимальное число попыток. В нашем примере максимальное количество попыток выбрано равным 120. В самую первую ячейку информация будет записана с первой попытки. Но уже для второй ячейки придется сделать множество дополнительных попыток Если микросхема исправна, то количество дополнительных попыток не должно превысить 120. В противном случае программа совершит 120 попыток и закончится досрочно. При этом она установит флаг ошибки.
Рассмотрим теперь подробнее, как в процедуре byte_fill реализован алгоритм многократной записи. Текст программы, выполняющей многократную запись, занимает строки 5.9. Строки 6...9 — это тело цикла, который выполняет 120 попыток записи. В качестве счетчика попыток используется регистр Ь. В строке 5 происходит инициализация счетчика. Выполнение цикла начинается с того, что в аккумулятор помещает номер микросхемы памяти, с которой мы собираемся работать (строка 6). Затем происходит вызов процедуры writebyte (строка 7). Процедура производит попытку записи байта из ячейки zdata во флэш-память. По завершении попытки записи производится проверка флага ошибки (строка 8). Если попытка окончилась удачно и не возвратила ошибки, то управление передается по метке х53, и дальнейшие попытки за
152
Работа с PC шиной
писи прекращаются. В том случае, если байт еще не записан, цикл продолжается. Оператор организации цикла (строка 9) обеспечивает 120 повторений цикла записи. Если число попыток еще не исчерпано, он передает управление на начало цикла. Когда же все 120 попыток окончатся неудачей, выполняются строки 10 и 11 программы. В строке 10 устанавливается флаг ошибки, а в строке 11 происходит безусловный переход на конец подпрограммы.
В строках 12... 15 расположена та часть программы, которая выполняется в случае успешного завершения одной из попыток записи. В этих строках текущий адрес, находящийся в регистре DPTR, увеличивается на единицу (строка 12). Затем проверяется, не превысил ли новый полученный адрес размера заполняемой памяти. Если нет, то управление передается на начало большого цикла записи по метке х51. В противном случае выполнение подпрограммы byte_fill завершается. На этот раз он завершается успешно Для проверки условия конца памяти текущий адрес сравнивается с величиной, хранящейся в переменной size. И адрес, и константа size представляют собой шестнадцатиразрядные двоичные коды. Поэтому проверка условия происходит в два этапа. Сначала младшая часть адреса сравнивается с младшей частью кода size. Для этого в строке 13 содержимое регистра DPL передается в аккумулятор. В строке 14 содержимое аккумулятора сравнивается с младшей половиной константы size. В случае несовпадения управление сразу передается в начало большого цикла по метке х51. Если младшие части адреса совпали, сравнение продолжается. В строках 15 и 16 сравниваются старшие части двух значений. В случае несовпадения старших частей управление также перелается по метке х51. Если же обе части адреса совпадают, то программа очищает флаг ошибки (строка 17) и завершает свою работу (строка 18).
Второй вариант подпрограммы, выполняющий заполнение всех ячеек памяти одним и тем же кодом, называется page fill. Текст нового варианта программы приведен в листинге 3.14. Новая программа применяет страничный способ записи информации. Для записи одной страницы информации описываемая подпрограмма использует процедуру write_block (см. листинг 3.11). Процедура write_block записывает блок информации из буфера во флэш-память. Поэтому перед тем как начинать заполнение флэш-памяти, необходимо записать во все ячейки буфера код заполнения FILL. Для заполнения буфера предназначена часть подпрограммы, занимающая строки 1...5. Для записи байтов организован специальный
Примеры программ для работы с флэш-памятью	153
цикл. Тело цикла составляют строки 3...5. В качестве параметра цикла используется регистр Ь.
Перед началом цикла в этот регистр записывается размер буфера (строка I). Кроме того, указателю адреса index присваивается его начальное значение (строка 2). Цикл заполнения состоит всего из двух операторов. В строке 3 константа FILL записывается в очередную ячейку буфера. В строке 4 адрес текущей ячейки буфера index увеличивается на единицу. По окончании цикла заполнения все ячейки буфера содержат значение FILL. После того, как буфер будет заполнен, можно приступать к основному циклу записи.
Запись информации в память производится целыми страницами. Регистр DPTR используется для хранения начального адреса текущей записываемой страницы. Перед началом цикла записи в DPTR помещается адрес самой первой страницы памяти, с которой и должно начинаться заполнение (строка 6). Этот адрес в нашем случае тоже будет равен нулю.
Листинг 3.14
Заполнение всех ячеек памяти одной и той хе величиной
(страничный способ записи)
Запись одной страницы за один раз.
Единица в CY означает ошибку в процессе записи
Изменяет А, В. DPTR. KOUNT, INDEX, ADDR_HI.ADDR.LO
page.fiii
	. Первоначальное заполнение			буфера
1		mov	b.KPSIZE	байт на страницу
2		mov	index, 4t buffer	указатель буфера
3	Х61	mov	©index,«FILL	занести байт заполнения в буфер
4		inc	index	увеличение значения указателя
5		djnz	b,x61	следующий байт
6		mov	DPTR, KO	инициализация указателя адреса
Копирование буфера в страницу памяти за один раз
7	х62:	mov	addr.lo, DPL	, установка адреса
8		flOV	addr.hi.DPH	
154
Работа с l2C шиной
9	mov	kount,SPSIZE	байт на страницу
10	mov	b.#120	счетчик попыток
11	хбЗ:	mov	a.«PADDR	номер микросхемы памяти
12	call	write_block	попытка записи
13	jnc	x64	переход, если запись ОК
14	djnz	Ь.хбЗ	нова? попытка
15	setb	c	установка флага ошибки ожид"
16	jmp	x66 Добавление размера страницы		выход к указателю адреса
17	x64:	mov	a,DPI	получение младшего байта
18	add	a. UPSIZE	добавление размера страницы
19	mov	DPI, a	запись младшего байта
20	jnc	x65	переход, если старший байт не изменился
21	inc	DPH	увеличение старшего байта проверка младшего байта
22	x65:	cjne	a,«(LOW SIZE).x62	переход, если не последний
23	mov	a.DPH	, проверка старшего байта
24	cjne	a «(HIGH SIZE),x62	переход если не последний
25 26	clr x66:	ret	c	очистка флага переполнения
Большой цикл заполнения памяти занимает строки 7. .24 программы. Начинается большой цикл с инициализации переменных addrjo, addr_hi и kount. Эти переменные будут использоваться процедурой write_block для записи очередного блока информации. При записи блока также используется метод многократной записи, позволяющий учитывать время обработки информации микросхемой флэш-памяти. При страничном способе записи, каждая страница записывается с максимальной скоростью. После записи каждого очередного байта не требуется ожидания сигнала готовности. Зато после того как вся страница записана, начинается ее обработка. Обработка страницы данных займет то же самое время, что и обработка одного байта Все время, пока идет обработка, микросхема флэш-памяти игнорирует новые попытки записи и возвращает сигнал неготовности.
Цикл многократной записи очередного блока информации занимает строки 10... 16. Структура этого цикла практически полностью повторяет цикл записи байта из предыдущего примера. Различие только в том, что цикл вызывает процедуру write_block вместо процедуры write_byte.
После того, как очередная страница записана, в строках 17...21 производится вычисление начального адреса для следующей страницы.
Примеры программ для работы с флэш-памятью
155
Для этого к содержимому регистра DPTR прибавляется значение константы PSIZE (размер страницы). Так как в системе команд микроконтроллера АТ89С2051 отсутствует команда сложения двух шестнадцатеричных чисел, операция сложения выполняется в несколько приемов. Сначала в аккумулятор помещается младшая половина регистра DPTR (строка 17). Затем происходит сложение содержимого аккумулятора с константой PSIZE (строка 18).
Полученная сумма помещается обратно в младшую половинку DPTR (строка 19). Если в результате сложения будет установлен признак переноса (CY), он должен быть учтен в старшей части регистра DPTR. Для этого в строке 20 проверяется значение CY. Ели переноса нет, то управление передается по метке х65 и строка 21 подпрограммы не выполняется. Если же перенос есть и его нужно учитывать, то оператор inc в строке 21 увеличивает на единицу значение старшего байта регистра DPTR.
В строках 22...25 производится проверка условия достижения конца записываемой памяти. Так как содержимое младшего разряда текущего адреса уже находится в аккумуляторе, программа сразу начинает проверку (строка 22). В случае если младшая часть текущего адреса равна младшей части константы size вызывается и проверяется старшая часть адреса (строки 23, 24). Если заполнение памяти не окончено, управление перелается на начало цикла по метке х62. Если заполнение памяти окончено, то подпрограмма очищает флаг ошибки (строка 25) и завершает свою работу (строка 26).
Следующие два примера демонстрируют применение процедур чтения информации из микросхем флэш-памяти. Предлагаемые под программы выполняют проверку содержимого всех ячеек памяти. Предполагается, что во всех ячейках памяти записан код FILL. Если это окажется не так, то необходимо возвратить признак ошибки. Первая из подпрограмм, реализующих этот алгоритм, называется ver-ify_byte_fill. Она использует для чтения информации из флэш-памяти побайтовый метод. Для чтения самого первого байта используется процедура readrandom. Все последующие байты читаются при помощи процедуры read_current. Подпрограмма устанавливает флаг ошибки в двух случаях. Во-первых, если процесс чтения памяти на любом своем этапе закончился неудачей. И во-вторых, если хотя бы один считанный байт оказался не равным значению константы FILL
Текст подпрограммы verify_byte_fill приведен в листинге 3 15. Рассмотрим подробнее принцип работы программы. Начинается
156
Работа с l2C шиной
подпрограмма с инициализации переменных addrjo, addr_hi. Эти переменные будут использоваться процедурами read_random и read current для чтения информации из микросхемы памяти. После инициализации переменных программа приступает к чтению первого байта из флэш-памяти Для чтения первого байта последовательности используется метод многократного считывания. Многократное считывание необходимо потому, что непосредственно перед самой операцией чтения могла выполняться операция записи. В этом случае микросхема флэш-памяти будет еще находиться в процессе обработки полученной информации, и будет не готова выполнять какие-либо другие операции.
Режим многократного чтения позволяет дождаться готовности микросхемы флэш-памяти. Операция многократного чтения выполнена по уже знакомому нам алгоритму. Команды, выполняющие многократное чтение, расположены в строках 4...9. Если микросхема памяти исправна, то при очередной попытке, первый байт последовательности будет прочитан Остальные байты будут читаться уже с первой попытки.
После того, как прочитан очередной байт, сразу выполняется его проверка. В строке 10 значение прочитанного байта сравнивается с константой FILL. В случае несовпадения этих двух величин управление передается по метке х86, где происходит установка флага ошибки и завершение всей операции сравнения.
Если все прошло нормально и первый считанный байт содержит значение FILL, процесс сравнения продолжается. Так как текущий адрес для микросхемы флэш-памяти уже установлен в процессе чтения первого байта, для чтения остальных байтов удобнее воспользоваться процедурой read_current. Режим многократного считывания здесь уже не понадобится, так как при чтении данных микросхема флэш-памяти выдает информацию без задержки. Поэтому для чтения всех остальных байтов из микросхемы памяти организован простой цикл чтения Каждый прочитанный байт тут же проверяется на равенство значению FILL.
Тело цикла составляют строки 12. .20 программы. В строке 13 вызывается процедура read_current. Для правильной работы этой процедуры в аккумулятор записывается номер выбираемой микросхемы (строка 12). В строке 14 происходит проверка ошибки чтения. Если чтение прошло без ошибок, в строке 15 прочитанный только что байт сравнивается с константой FILL. В случае если
Примеры программ для работы с флэш-памятью
157
прочитанный байт отличается от FILL, управление передается по метке х86, где устанавливается флаг ошибки. В случае любой ошибки дальнейший процесс считывания и проверки памяти прекращается. Если же при считывании очередного байта никаких ошибок не было обнаружено, то программа увеличивает текущий адрес памяти в регистре DPTR (строка 16) и выполняет уже знакомую нам процедуру проверки вновь полученного адреса (см. строки 17...20). Если новый полученный адрес в регистре DPTR еще меньше максимального значения, управление передается на начало цикла по метке х83. Если проверены уже все ячейки памяти и значение в регистре DPTR превысило значения константы size, то цикл проверки завершается. В этом случае, сначала сбрасывается флаг ошибки (строка 21). А затем завершается вся подпрограмма (строка 22).
Листинг 3.15
Проверка, всех ячеек памяти на равенство величине заполнения (побайтовый способ чтения)
verify_byte_fill:
1 2 3	mov mov mov	DPTR, «0 addr_lo,DPL addr_hi,DPH	инициализация указателя адреса/счетчика установка адреса
4	mov	b,#120	счетчик числа попыток
5	x81:	mov	a, «PADDR	Номер микросхемы памяти
6	call	read_random	попытка чтения
7	jnc	x82	переход, если чтение ОК
8	djnz	b,x81	повторная попытка
9	Jmp	x86	установка флага ошибки и выход
10	x82:	cjne	a.«FILL. x86	. переход если ошибка сравнения
11	jmp	x85	 оставить прежний адрес
12	x83:	mov	a, «PADDR	; Номер микросхемы в аккумулятор
13	call	read_curreni	. чтение байта с текущего адреса
14	jc	x87 '	, переход, если ошибка чтения
15	cjne	a,«FILL, x86	; переход, если ошибка сравнения
16	x85:	inc	DPTR	, новый адрес
17	mov	a.DPL	проверка младшего байта
18	cjne	a,«(LOW SIZE),x83	переход, если не последний
19	mov	a,OPR	проверка старшего байта
20	cjne	a,«(HIGH SIZE),x83	, переход, если не последний
21	clr	c	очистка флага ошибки
22	jmp	x87	. выход
158
Работа с PC шиной
23	хВ6:	setb	с	установка флага ошибки
24	х87:	ret
И, наконец, последний пример работы с микросхемами флэш-памяти: вторая версия подпрограммы проверки памяти. Эта версия называется verify_page_fill. Новая версия подпрограммы использует страничный метод при считывании информации из микросхемы флэш-памяти. Каждую прочитанную станицу памяти подпрограмма предварительно записывает в буфер. Затем информация, находящаяся в буфере побайтно сравнивается с константой FILL. При возникновении ошибки в процессе чтения, либо в том случае, когда хотя бы один из считанных байтов окажется не равным константе FILL, программа прекращает процесс проверки и возвращает признак ошибки.
Текст подпрограммы verify_page_fill приведен в листинге 3.16. Основную часть подпрограммы составляют уже хорошо знакомые нам фрагменты. Во-первых, это большой цикл постраничного чтения. Цикл начинается в строке 2 и заканчивается в строке 24. В строках 1...4 происходит инициализация основных переменных. Причем присвоение начального адреса регистру DPTR происходит вне основного цикла программы, а присвоение значений переменным addrjo, addr_hi и kount производится каждый раз в начале очередного цикла
В строках 5... 11 производится многократное чтение блока информации из текущей страницы памяти. В случае отсутствия ошибки в процессе чтения блока программа переходит к проверке прочитанной информации. Текст процедуры проверки приводится в строках 12... 16 программы. Основой этой процедуры является цикл проверки Тело цикла занимает строки 14... 16. В качестве параметра цикла используется регистр b В строке 12 параметру цикла присваивается начальное значение. В строке 13 происходит инициализация указателя адреса буфера (переменная index). Первая операция цикла проверки (строка 14) предназначена для сравнения очередного байта из буфера с константой FILL В случае неравенства этих двух величин управление передается в конец подпрограммы по метке х73 Дальнейшая работа подпрограммы, таким образом, прекращается. Если содержимое байта равно FILL,
Примеры программ для работы с флэш-памятью
159
значение переменной index увеличивается на единицу, и цикл проверки продолжается.
После проверки всего буфера программа увеличивает адрес в регистре DPTR на величину, равную размеру страницы. В результате при следующем проходе программы по большому циклу проверки она будет считывать уже новую страницу памяти. Увеличение адреса в DPTR производится в строках 17 и 21 программы. Это уже знакомая нам процедура сложения двух шестнадцатиразрядных двоичных чисел. Далее, в строках 22...24 производится проверка значения адреса. Если программа нс достигло конца проверяемого диапазона, управление передается на начало цикла по метке х71. В противном случае подпрограмма verify_page_fill завершается, предварительно сбросив в ноль признак ошибки (строки 25, 26).
Листинг 3 16
Проверка, всех ячеек памяти на равенство величине заполнения
(страничный способ чтения)
verlfy_page_fill
	Копирование страницы памяти в буфер			
1		mov	DPTR. no	инициализация указателя адр&сэ
2	х71:	mov	addrJo.DPL	установка адреса
3		mov	addr_hi,DPH	
4		mov	kount, UPSIZE	байт на страницу
5		mov	b,«120	, счгтчик попыток
6	х72:	mov	a, «PADDR	номер микросхемы памяти
7		call	read_block	попытка чтения
8		jnc	x74 '	переход, если чтение ОК
9		djnz	b,x72	новая попытка
10	х73:	setb	c	установка флага ошибки
11		jmp	x77	выход
		Проверка содержания буфера		
12	х74:	mov	b.fiPSIZE	байт на страницу
13		mov	index,«buffer	указатель буфера
14	х75:	cjne	gindex.«FILL, x73	переход при ошибке сравнения
15		inc	index	, передвижение указания
16		djnz	b,x75	следующей байт
160
Работа с lzC шиной
	Добавление размера страницы		к указателю адреса
17	mov	a.DPL	получение младшего байта
16	add	a.UPSIZE	добавление размера страницы
19	mov	DPL.a	: запись младшего байта
20	jnc	x76	переход, если старший байт не изменился
21	inc	DPH	увеличение старшего байта
22	x76' cjne	a.«(LOW SIZE).x71	переход если младший байт не последний
23	mov	a, DPH	проверка старшего байта
24	cjne	a,«(HIGH SIZE),x71	переход, если не последний
25	clr	Q	очистка флага ошибки
26	x77:	ret		
На этом мы заканчиваем изучение PC шины. Используя приведенные выше примеры подпрограмм, вы можете самостоятельно организовать программный интерфейс с любой микросхемой флэш-памяти, а также с другими микросхемами, использующими PC технологию. А теперь, я бы хотел перейти к описанию еще одной интересной разработки в области последовательной передачи информации. Это оригинальная шина, позволяющая обмениваться данными и даже получать электропитание всего по одному проводу.
с шиной MicroLAN
4.1. Общие сведения
В предыдущей главе мы познакомились с двухпроводной шиной для последовательной передачи данных PC. Эта шина хорошо подходит для передачи сигналов управления между микросхемами, расположенными на одной и той же плате. В крайнем случае, PC шину можно применить в пределах одного блока. Максимальная протяженность PC шины не может превышать Ю м. Однако перед разработчиками микропроцессорных устройств часто ставится более сложная задача: соединить микросхемы, находящиеся на более значительных расстояниях друг от друга. В частности, автору этой книги пришлось разрабатывать систему управления индивидуальной гелиоустановкой.
По техническому заданию система управления должна была собирать информацию от шести различных термодатчиков, находящихся в разных местах индивидуального дома. Один датчик устанавливался на гелиоколлекторе, который располагался на крыше дома. Остальные устанавливались в разных точках отопительной системы, но тоже на значительных расстояниях друг от друга. Задача легко решилась путем применения однопроводной шины l-Wire, объединившей все датчики разрабатываемой системы в единую сеть. Такая сеть специально разработана для подобных применений и имеет название MicroLAN.
Шина l-Wire является основой сетей MicroLAN и разработана в конце 90-х годов фирмой Dallas Semiconductor. В настоящее время фирма Dallas Semiconductor является дочерним предприятием фирмы MAXIM. Микросхемы и комплектующие фирмы MAXIM широко известны разработчикам электронных устройств. Логотип
6 Зак 922
162
Работа с шиной MicroLAN
этой фирмы приведен на рис. 4.1. Создавая шину MicroLAN, фирма Dallas Semiconductor поставила перед собой, казалось бы, неразрешимую задачу. Идея состояла в том, чтобы соединить между собой множество различных микросхем, расположенных на значительном расстоянии друг от друга, используя при этом всего один сигнальный провод. Разумеется, кроме сигнального провода для замыкания цепи обязательно должен быть и обратный так называемый «общий провод». Все микросхемы должны подключаться к такой двухпроводной шине параллельно. И вот по этой линии, состоящей всего из двух проводников от одной микросхемы к другой, должна передаваться информация, как в прямом, так и в обратном направлении. Кроме того, в случае необходимости, по той же однопроводной шине решено было осуществлять питание всех подключенных к ней микросхем. Сама постановка такой задачи уже была достаточно дерзкой. Фирма Dallas Semiconductor блестяще справилась с этой задачей. Шина 1-Wire и основанные на ней сети MicroLAN давно с успехом применяются в электронной технике.
/И/1Х1УИ
Рис. 4.1. Логотип фирмы Dallas Semiconductor
Ниже приведены основные характеристики этой шины:
♦	Максимальная протяженность шины до 300 м.
♦	Скорость передачи информации 16,3 Кбит/с.
♦	Максимальное количество адресуемых элементов на шине 256
♦	Уровни напряжений на шине соответствуют стандартным КМОП/ТТЛ уровням.
♦	Напряжение питания компонентов сети 2,8...6 В.
♦	Для соединения элементов сети может применяться обычный телефонный кабель или витая пара.
Существуют и модификации шины 1-Wire. Например, отдельные виды микросхем поддерживают скоростной режим работы шины (Overdrive). В этом режиме скорость передачи информации равна 142 Кбит/с. Однако такие микросхемы могут работать только на
Общие сведения
163
шине малой протяженности и при условии, когда уровень внешних электрических помех сведен к минимуму.
Шина Micro LAN, так же как и 12С шина, построена по технологии Master/Slave. На шине должно быть хотя бы одно ведущее устройство (Master). Все остальные устройства должны быть ведомыми (Slave) Ведущее устройство инициирует все процессы передачи информации в пределах шины. Master может прочитать данные из любого Slave устройства или записать их туда. Передача информации от одного Slave к другому напрямую невозможна. Для того, чтобы Master мог обращаться к любому из ведомых устройств по шине, каждое ведомое устройство содержит в себе индивидуальный код (ID-код). Этот код заносится в специальную область микросхемы при помощи лазера. Фирма-изготовитель гарантирует, что этот код никогда не повторится и все когда-либо изготовленные микросхемы, содержащие 1-Wire интерфейс, всегда будут иметь разные коды.
Еще одним полезным свойством шины является возможность автоматического обнаружения факта подключения новых компонентов. Протокол I-Wire включает в себя специальную команду поиска, при помощи которой ведущее устройство (Master) может осуществлять автоматический поиск ведомых устройств. В процессе поиска Master определяет ID коды для всех подключенных к сети микросхем. Поиск происходит путем постепенного отсеивания несуществующих адресов. Поэтому для того, чтобы найти все устройства, подключенные к шине (их еще называют узлами сети), требуется довольно значительное время. Средняя скорость поиска элементов в сети MicroLAN составляет примерно 75 узлов в секунду.
При разработке протокола 1-Wire большое внимание было уделено надежности работы сети. Изначально было поставлено условие — работа должна происходить в условиях плохих контактов. Кроме того, допускается подключение и отключение ведомых элементов прямо в процессе работы. Для обеспечения надежной и устойчивой работы всех элементов в сети MicroLAN используется механизм двухэтапной записи информации с применением промежуточной, так называемой «блокнотной памяти». А также методы контроля целостности передаваемой информации методом контрольных сумм. В свое время об этом мы поговорим подробнее.
Идеальным применением для сети MicroLAN является система телеметрии и автоматики в производственных или бытовых помещениях. Представьте себе, что в некоем здании по всем по-
164
Работа с шиной MicroLAN
мешениям в разных местах установлены миниатюрные датчики температуры, влажности, освещенности и др. Все они соединены между собой одной двухпроводной линией и подключены к единому управляющему устройству (см. рис. 4.2). Этим устройством может быть персональный компьютер, снабженный специальной программой, либо специально разработанный блок на основе микроконтроллера. Кроме того, по всем помещениям рассредоточены миниатюрные исполнительные устройства. Они могут включать и выключать обогреватели, осветительные приборы, вентиляторы, электрические замки на дверях, зуммеры, механизмы открывания штор и любые другие, электрические и неэлектрические приборы, расположенные в разных помещениях вашего дома.
Все исполнительные механизмы также подключаются к той же самой двухпроводной шине. Конечно, тс устройства, которые требуют значительной мощности для своего питания, не могут получать его по шине 1-Wire. Они должны иметь свои автономные источники питания. Те же микросхемы, которые потребляют незначительную мощность (например, различные датчики), с успехом могут получать питание от той же двухпроводной линии, через которую происходит обмен информацией. Управляющее устройство объединяет все подключенные к ней элементы. Оно должно содержать программу для централизованного управления всей этой системой. В рамках сети MicroLAN можно организовать глобальную систему управления всеми бытовыми устройствами и механизмами в вашем доме, или системами комфорта и жизнеобеспечения на любом предприятии.
При разработке сетей MicroLAN фирма Dallas Semiconductor по заботилась о том, чтобы обеспечить самый широкий набор вариантов ее построения. Например, в качестве Master устройства может выступать как специализированный контроллер MicroLAN, так и персональный компьютер, а также любой универсальный микроконтроллер, работающий на тактовых частотах превышающих 1,8 МГц. Для согласования шины MicroLAN с компьютером фирма Dallas Semiconductor разработала специальные микросхемы — преобразователи интерфейса. Такие устройства могут подключаться как к LPT порту компьютера, так и к любому его СОМ порту и работать в качестве моста, согласующего порты компьютера с шиной 1-Wire. Существует даже вариант реализации 1-Wire интерфейса непосредственно на выводах СОМ порта, без применения дополнительных элементов. Этот способ возможен только в том случае, если в вашем компьютере для реализации
Общие сведения
165
последовательного СОМ интерфейса используется микросхема Intel 8250. Протокол l-Wire в этом случае реализуется программным путем. Соответствующую программу можно найти на сайте фирмы Dallas Semiconductor [6W].
Рис. 4.2. Топология сети MicroLAN
Иногда при построении сети MicroLAN использование топологии, состоящей всего из одной 1-Wire шины, оказывается недостаточно. Ограничения могут быть вызваны слишком большой суммарной емкостью или большим суммарным током потребления всех подключенных к шине устройств. Специально для таких случаев в стандарте сетей MicroLAN предусмотрена возможность ветвления. Для ветвления шины 1-Wire применяется специальные микросхемы — управляемые разветвители. Разветвитель управляется по той же самой l-Wire шине, которую он же и коммутирует. На рис. 4.3 показана схема подключения дополнительной ветви сети при помощи микросхемы разветвителя типа DS2409. Встроенный 1-Wire интерфейс принимает команды из сети и управляет
166
Работа с шиной MicroLAN
электронным коммутатором К и схемой управления (Упр). По команде из ведущего устройства шина «ответвление» может быть подключена или отключена от основной шины. Если ответвление подключено к основной шине, то эти две шины представляют собой одно целое.
Команды, посланные ведущим устройством, распространяются на все ведомые устройства, подключенные к обеим ветвям. Когда шина-ответвление отключается от основной шины, она подключается к специальной управляющей схеме внутри микросхемы DS2409- Управляющая схема способна по команде от ведущего устройства передавать информацию в шину «ответвление», выступая в роли управляемого Master устройства для дополнительной шины. При таком методе управления прямое соединение двух этих шин отсутствует. Однако передача сигналов возможна, хотя алгоритм управления при этом усложняется.
Итак, микросхема-разветвитель позволяет сделать в любом месте однопроводной шины управляемое ответвление. Шина может содержать любое количество ответвлений. При этом структура сети будет напоминать дерево (см. рис. 4.4). Древовидная структура позволяет включать различные ветви сети по мере надобности. Остальные ветви временно отключаются и не создают дополнительной нагрузки.
Рис. 4.3. Ответвление сети
Как можно было убедиться из всего вышесказанного, шина MicroLAN имеет огромные возможности и большие перспективы. Однако тема данной книги, если помните — подключение периферийных
Общие сведении
167
устройств к микроконтроллеру. l-Wire интерфейс прекрасно подходит для этой цели. Микроконтроллер AT89C205I позволяет легко, программным путем реализовать l-Wire интерфейс на любой из своих линий ввода/вывода.
Рис. 4.4. Древовидная структура
Долгое время шина MicroLAN не получала широкого распространения из-за того, что номенклатура микросхем, оснащенных l-Wire интерфейсом, была не слишком велика. Однако в последнее время фирма Dallas Semiconductor разработала множество новых типов микросхем. Для того, чтобы вы могли почувствовать весь диапазон возможностей этой технологии, приведем краткий обзор производимых в настоящее время l-Wire совместимых микросхем. Все микросхемы с l-Wire интерфейсом можно разделить на две большие группы:
I. Микросхемы, предназначенные для монтажа при помощи пайки.
2. Микросхемы в специальном, мобильном исполнении, получившие название iButton.
Мы обязательно рассмотрим обе эти категории микросхем. Однако начать я хочу с совершенно необычного вида микросхем — микросхем нового класса, получивших название iButton.
168
Работа с шиной MicroLAN
4.2.	Новый класс микросхем — iButton
Фирма Dallas Semiconductor по праву гордится тем, что является изобретателем нового вида микросхем Этот вид микросхем даже получил специальное название — iButton, которое также является зарегистрированной торговой маркой. На рис. 4.5 показан логотип торговой марки iButton. Фирма Dallas Semiconductor даже создала специальный сайт в Интернете, полностью посвященный микросхемам iButton (см. ссылку [7W] в конце книги).
Рис. 4.5. Торговая марка iButton
Что же представляют собой эти микросхемы? Главная их особенность — новое конструктивное решение. Корпус этих микросхем имеет форму таблетки (см. рис. 4.6). До сих пор в подобных корпусах выпускались только миниатюрные источники питания. Новый корпус для микросхем получил название MicroCan. Корпус выпускается в двух модификациях, которые отличаются друг от друга по толщине. На рис. 4.8 приведены основные размеры микросхем в корпусе MicroCan. Диаметр корпуса для обеих модификаций одинаковый и равен 16,25 мм. Толщина корпуса L для модификации F3 равна 3,1 мм, а для модификации F5 — 5,8 мм. В одних моделях микросхем в корпусе размещается лишь кремниевая пластина (см. рис. 4.7). В других же, кроме кремниевой пластины, может находиться миниатюрный литиевый источник питания, и даже кварцевый резонатор.
Микросхема, заключенная в такой корпус, всегда имеет только два вывода — это верхняя и нижняя обкладки корпуса. Такая микросхема не предназначена для пайки. Для подключения микросхем в корпусе MicroCan используются специальные адаптеры. Микросхема в любой момент легко вставляется в адаптер и извлекается из него. Металлический корпус микросхемы делает ее исключительно прочной и надежной в эксплуатации. Микросхема выдерживает
Новый класс микросхем — IButton	169
удар в 0,5 кг, падение на пол с высоты до 1,5 метра. Допустимый диапазон температур для микросхем iButton: от —40 до +85°С,
Рис. 4.6. Микросхемы iButton
Рис. 4.7. Микросхема изнутри
Какие же функции могут выполнять микросхемы iButton? Оказывается можно придумать множество применений микросхемам, имеющим всего два вывода. Перечислим все по порядку.
Элементы контроля доступа. Такая микросхема не содержит ничего, кроме своего собственного уникального 64-разрядного ID кода. Применяются они как ключ. Разработано множество систем с использованием микросхем iButton в качестве ключа. Существуют дверные замки, имеющие вместо замочной скважины гнездо для подключения микросхемы. Системы защиты компьютерных программ для подключения микросхем iButton используют специальные кабели. Такой кабель подключается к LPT или СОМ порту компьютера. На втором конце такого кабеля имеется одно или два гнезда для подключения ключевой микросхемы. Специально раз
170
Работа с шиной MicroLAN
работанные программы проверяют наличие микросхемы в разъеме и соответствие ее внутреннего кода коду владельца программы. При несовпадении кодов доступ к программе блокируется.
Микросхемы памяти. Существует несколько видов таких микросхем. Это однократно записываемая память (EPROM), многократно записываемая память с электрическим стиранием (EEPROM), а также энергонезависимое ОЗУ со встроенным источником питания (NV RAM). Память может использоваться для хранения и переноса с компьютера на компьютер любой информации: изображений, музыки, текстовой информации. Кроме того, существует специальный вид защищенной памяти, которая используется в качестве электронного кошелька, для мелких сумм. Существует также память, защищенная паролем.
Цифровой термометр. Служит для измерения температуры в цифровом виде. Измеренную информацию можно считывать по l-Wire интерфейсу. К цифровому термометру мы еще вернемся в конце этой главы и рассмотрим этот вопрос очень подробно.
Часы, календари реального времени. Содержат в себе миниатюрный источник питания и микросхему, выполняющую непрерывный подсчет времени. Считывание и установка этого времени возможна только при помощи 1-Wire интерфейса. Кроме задачи подсчета времени в микросхеме реализован календарь, секундомер, измеритель времени наработки подключенного к контактам микросхемы внешнего устройства и др. Кроме самостоятельных таймеров производятся и комбинированные устройства. Первый такой гибрид — таймер, совмещенный с энергонезависимым ОЗУ. Такое совмещение позволяет ограничить доступ к хранящейся в ОЗУ микросхемы информации в определенные моменты времени. Например, можно реализовать ключ доступа к компьютерной программе, который будет срабатывать только в заранее установленное вами время суток.
Самый интересный вариант применения таймера — это устройство термохрон (Thermochron). Термохрон содержит часы реального времени, энергонезависимое ОЗУ и датчик температуры. Микросхема измеряет температуру через заданные промежутки времени, а результаты измерений записывает в свое энергонезависимое ОЗУ. Параметры процесса измерения могут быть предварительно запрограммированы при помощи 1-Wire интерфейса. Через тот же интерфейс в любой момент могут быть считаны результаты из
1 -Wire микросхемы в традиционном исполнении
171
мерений. Таблетки термохрона можно поместить внутри упаковки любого товара, и они будут автоматически контролировать температурный режим хранения товара на протяжении всего времени транспортировки. Получатель может подключить такую таблетку к компьютеру. Специальная программа считает записанную туда информацию и отобразит ее на экране. В случае несоблюдения температурного режима при транспортировке товара фирма-изготовитель может легко предъявить претензии к транспортной компании, осуществляющей перевозку грузов. На сайте (Button ([7W]) в качестве примера приведен случай вложения таблетки термохрона в упаковку со свежемороженой рыбой.
Криптопроцессор. Эта микросхема содержит встроенный микроконтроллер, совместимый с системой команд процессора 8051, защищенные часы реального времени, быстродействующий модульный ускоритель возведения в степень больших целых чисел длиной до I024 бита, ПЗУ (64 Кб) с предварительно зашитой управляющей программой, энергонезависимое ОЗУ (NVRAM) объемом в 6 Кб для хранения важных данных. Криптопроцессор предназначен для шифрования информации. Прибор обеспечивает аппаратное выполнение таких криптографических операций, как быстродействующее шифрование передаваемых данных с открытым 1024 битным ключом и защита сообщений от просмотра.
Более полную информацию по использованию микросхем iButt-оп вы можете найти на официальном сайте, посвященном этой технологии |7WJ. Мы же перейдем к описанию микросхем в более привычном для нас исполнении: в корпусе, предназначенном для монтажа при помощи пайки.
4.3.	1 -Wire микросхемы в традиционном исполнении
Наряду с микросхемами iButton в корпусе MicroCan фирма Dallas Semiconductor выпускает большой набор микросхем в корпусах традиционного вида (см. рис. 4.9). По функциональному назначению среди микросхем в традиционном исполнении можно
172
Работа с шиной MicroLAN
найти аналоги почти всех микросхем, выполненных по технологии iButton. Так в традиционном корпусе можно найти микросхемы памяти (EPROM, EEPROM, NVRAM), часы реального времени, измерители температуры. Однако имеются и другие типы микросхем, которые невозможно выполнить по технологии iButton. Рассмотрим их по порядку.
АЦП (аналого-цифровой преобразователь). Типичный представитель — четырехканальный АЦП типа DS2450. Эти микросхемы удобно применять для считывания информации с различных датчиков, выдающих сигнал в аналоговой форме. Например, датчик освещенности, влажности, давления и т.д.
Цифровой потенциометр. Это специальный прибор, имитирующий работу обычного потенциометра. Управление «движком» потенциометра осуществляется посредством l-Wire интерфейса. Функциональная схема одного из вариантов прибора изображена на рис. 4.10. Такую микросхему удобно применять для цифрового управления аналоговыми устройствами. Например, такие потенциометры вполне можно было бы применить в качестве программно управляемых регуляторов громкости, баланса и тембра в современном аудиокомплексе. С таким же успехом можно было бы осуществлять все оперативные регулировки в телевизоре. При этом блок управления телевизора можно будет выполнить на микроконтроллере, а управляющие сигналы ко всем элементам будут передаваться по шине l-Wire.
жшшш
DS 2404
ШПППГЛ!
Рис. 4.9. Микросхемы для монтажа пайкой
1-Wire микросхемы в традиционном исполнении
173
Рис. 4.10. Управляемый переменный резистор
Счетчик внешних импульсов. Пример такого счетчика — микросхема DS2423. Кроме двухканального счетчика внешних импульсов она имеет встроенную буферную память. Микросхема предназначена для обслуживания различных датчиков, выдают сигнал в импульсном виде. Например, датчик количества оборотов, выходной сигнал с расходомеров-вертушек, емкостные датчики влажности, включенные в задающие цепи управляемых генераторов импульсов, счетчики уровня радиации, преобразователи напряжения в частоту и т.д.
Универсальный транзисторный ключ. Содержит не только ключ для переключения внешних цепей, но и имеет возможность контролировать напряжение в переключаемой сети. Например, микросхема DS2407 содержит два таких ключа. Транзисторный ключ может использоваться для включения индикаторов и различных исполнительных механизмов (после усиления по мощности). Благодаря встроенной схеме контроля уровня те же самые микросхемы могут осуществлять считывание сигнала с дискретных датчиков. То есть с таких датчиков, которые выдают сигналы вида Да/Нет (датчики положения, прохода, присутствия, пожарной и охранной сигнализации и т.д.).
Управляемые разветвители сети. С этим видом устройств мы уже знакомы (см. раздел 4.I). Однако приведенная в этом разделе функциональная схема разветвителя (см. рис. 4.3) немного упрощена. На самом деле микросхема DS2409 имеет два управляемых электронных коммутатора, позволяющих создать сразу два ответвления. Они называются MAIN (основное) и AUX (дополнительное). Кроме того, микросхема содержит электронный ключ для управления сигнальным светодиодом. Допускается независимое
174
Работа с шиной MicroLAN
управление посредством l-Wire интерфейса как любым из двух сетевых ответвлений, так и ключом для светодиодного индикатора.
Мониторинг элементов питания. Это специализированные микросхемы, осуществляющие непрерывный контроль режимов работы аккумуляторных батарей. Такая микросхема встраивается в аккумулятор и производит непрерывный контроль режима его разрядки. Она измеряет ток разрядки через заданные промежутки времени и записывает результаты измерений в свою внутреннюю память. Когда приходит время заряжать аккумулятор, он подключается к специальному зарядному устройству. Это устройство считывает информацию, записанную во внутреннюю память микросхемы, и использует ее для определения оптимального режима зарядки.
Датчики температуры. Датчики температуры, пожалуй, самый применяемый тип микросхем с l-Wire интерфейсом. Выпускается множество модификаций датчиков температуры в корпусах, предназначенных для монтажа пайкой. Например, датчик DS18B20 выпускается в двух модификациях. В корпусе SOIC (8 выводов) и в корпусе ТО-92 (см. рис. 4.II). Такие датчики очень удобно использовать для измерения температуры в различных местах помещений, разбросанных на большой площади.
Рис. 4.11. Интегральные датчики температуры с 1-Wire интерфейсом
Кроме перечисленных выше приборов, управляемых посредством l-Wire интерфейса, фирма Dallas Semiconductor выпускает большой ассортимент вспомогательных микросхем для облегчения согласования сетей MicroLAN с самыми различными устройствами. Например, микросхема DS2404 — это двухпортовая статическая память. Считывание и запись памяти в этой микросхеме может
Схемная реализация 1-Wire интерфейса
175
осуществляться как по 1-Wire интерфейсу, так и со стороны подчиненного последовательного интерфейса, управляемого микропроцессором. Такая микросхема может служить «мостиком» между системами различных типов. Микросхема DS14I0E — адаптер параллельного порта. Он позволяет подключать шину MicroLAN к параллельному порту компьютера. Микросхемы DS9097E и DS909-7U — это адаптеры последовательных портов (СОМ). Микросхема DS2490 — адаптер порта USB.
Я перечислил далеко не все виды микросхем, рассчитанных на технологию сетей MicroLAN. К тому же их список постоянно пополняется. Для более полной информации рекомендую обратиться на сайт [6W|. А мы приступим к рассмотрению принципов работы 1-Wire интерфейса.
4.4.	Схемная реализация 1 -Wire интерфейса
Для начала рассмотрим принципиальную электрическую схему, реализующую l-Wire интерфейс. Схема соединения ведущего и ведомого устройств посредством однопроводной шины приведена на рис. 4.12. На том же рисунке показаны особенности схемной реализации выходных каскадов ведущего и ведомого устройств. Как видно из рисунка, в схеме 1-Wire интерфейса, так же как и в интерфейсе для PC шины, используются выходные каскады с открытым коллектором (стоком) и обшей нагрузкой R„ для всех элементов сети. В спецификации для 1-Wire интерфейса специально оговаривается, что резистор R„ должен находиться в непосредственной близости от ведущего устройства.
Биполярный транзистор в выходном каскаде ведущего устройства показан условно. С неменьшим (а скорее большим) успехом можно применять микросхемы, у которых выходные каскады построены по КМОП технологии. Ведомые устройства обычно целиком построены на КМОП транзисторах. В режиме ожидания все выходные транзисторы закрыты. На шине присутствует напряжение логической единицы. Информация по шине передается при помощи отрицательных импульсов. Любое устройство, подключенное к шине, как ведущее, так и ведомое, может создавать
176
Работа с шиной MicroLAN
отрицательные импульсы и тем самым передавать информацию. Однако ведомое устройство начинает процесс передачи только под управлением ведущего
Рис. 4.12. Электрическая схема сети MicroLAN
Подробнее этот процесс мы рассмотрим в следующем разделе. А пока обратите внимание на дополнительные элементы в составе ведомого устройства (см. рис. 4.12). Во первых, это встроенный источник тока (обозначенный двумя пересекающимися окружностями). Этот источник создает внутреннюю утечку на входе 1-Wire интерфейса. Смысл этой утечки — создать нулевой уровень сигнала на внутренних элементах ведомого устройства при его отключении от шины 1-Wire. Когда соединение будет восстановлено, внутренняя логика ведомой микросхемы обнаруживает перепад напряжения с нуля на единицу. Сразу после получения такого сигнала ведомая микросхема должна выдать на шину 1-Wire сигнал присутствия. Каким образом выдается этот сигнал, мы увидим чуть позже. Обнаружив сигнал присутствия на линии связи, ведущее устройство может провести процедуру обнаружения новых устройств. Таким образом, шина 1-Wire позволяет легко подключать и отключать различные устройства, не нарушая при этом ее работу.
Еще один дополнительный элемент, который присутствует только в схеме интерфейса ведомого устройства — это цепь паразитного
Схемная реализация 1-Wire интерфейса
177
питания. Эта цепь состоит из накопительного конденсатор (Сцдк), токоограничивающего резистора (Rorp) и выпрямительного диода (Овып)- Все эти элементы используются в режиме паразитного питания. Каждая микросхема, рассчитанная на работу с l-Wire интерфейсом, имеет два режима питания. Первый режим — обычный. В этом режиме питание подается на специальный вывод микросхемы. Такой вывод обычно имеется у всех микросхем, кроме микросхем серии iButton.
Независимо от наличия вывода питания любая микросхема может питаться непосредственно от информационной шины. Этот способ получения электроэнергии называется «паразитным питанием». В процессе работы на шине всегда присутствует импульсный сигнал. В те моменты, когда напряжение на шине равно единице, выпрямительный диод открывается и накопительный конденсатор заряжается через токоограничивающий резистор. Емкость конденсатора невелика (примерно 800 пФ). Однако и ток потребления КМОП микросхемы тоже очень мал. Поэтому заряда конденсатора хватает для обеспечения питания микросхемы в промежутках между импульсами.
Однако режим паразитного питания применим далеко не во всех случаях. Некоторые операции невозможно выполнить при сверхмалом потреблении энергии. Например, процесс преобразования температуры в код требует полноценного, а не паразитного питания. На этот случай 1-Wire протокол предусматривает третий, специальный режим питания. Такой режим питания используется только совместно с режимом паразитного питания. Основная идея — подавать полноценное питание на ту же самую шину, по которой передается информация в те моменты времени, когда ведомая микросхема выполняет особо энергоемкие операции. При этом, пока на шине присутствует полноценное питание, передача информации невозможна. Подробнее об этом режиме питания мы поговорим, когда будем рассматривать принцип работы микросхемы электронного термометра.
Несколько устройств, включенных по схеме, изображенной на рис. 4.14, это еще не 1-Wire шина. Для того, чтобы она стала таковой, каждое из подключенных устройств должно содержать специальное управляющее устройство, реализующее протокол шины. Именно протокол определяет все правила передачи информации. Поэтому мы приступаем к изучению протокола.
178
Работа с шиной MicroLAN
4.5.	Синхронизация и побитная передача информации
Как и в случае PC шины, протокол l-Wire имеет несколько разных уровней. Самый низкий уровень описывает, каким образом передаются отдельные биты. Как уже говорилось выше, l-Wire протокол предусматривает двухсторонний обмен информации. При этом все операции на шине производятся исключительно под управлением Master устройства. Master может выполнять операции двух видов: записывать информацию в Slave устройство или считывать информацию из него. Информация передастся побайтно, в последовательном виде, бит за битом, начиная с младшего бита. В любом из этих двух случаев, для передачи информации Master устройство вырабатывает на шине тактовые импульсы. Для этого оно периодически «подсаживает» шину при помощи выходного транзистора своего l-Wire интерфейса (см. рис. 4.12). Полезная информация передается путем изменения длительности этих импульсов. Причем при записи информации длительностью импульсов управляет исключительно Master устройство.
В режиме чтения начинает формирование импульса Master устройство, но Slave устройство может продлевать длительность любого импульса, «подсаживая» в свою очередь сигнал на линии в нужный момент. На рис. 4.13 изображены две временные диаграммы. Верхняя диаграмма иллюстрирует режим записи двух разных битов информации, а нижняя — режим чтения. Участки диаграммы, где линия «отпущена» и уровень сигнала на линии определяется лишь резистором RH, изображены на диаграмме при помощи тонких линий. Участки, где один из элементов сети «подсаживает» линию, изображены при помощи широких линий. Рассмотрим подробнее два режима работы сети.
Запись бита. В исходном состоянии все Slave устройства, подключенные к шине, находятся в режиме ожидания. Линия «отпущена». То есть выходные транзисторы всех элементов шины закрыты, и напряжение на шине определяется резистором нагрузи (RH на рис. 4.12). Для того, чтобы записать данные в одно из Slave устройств, Maser начинает формировать отрицательные синхроимпульсы (верхняя диаграмма на рис. 4.13). На каждый передаваемый бит формируется один импульс. Импульсы передаются путем «подсаживания» линии до нуля. Для передачи каждого бита выделяется промежуток времени
Синхронизация и побитная передача информации	179
стандартной длительности. Этот промежуток получил название «слот» (Slot). Если значение передаваемого бита равно 0, то Master вырабатывает «длинный» импульс. Его длина равна длительности слота. Для передачи единичного бита Master вырабатывает «короткий» импульс, который, по сути, является чистым синхроимпульсом. Оставшаяся часть слота должна быть заполнена единичным сигналом. Между двумя слотами обязательно должен быть небольшой промежуток, во время которого уровень сигнала на шине тоже равен единице.
Условные обозначения ммта Шину подсаживает "Master*	Шину подсаживает "Slave*
----- Шина свободна. Напряжение определяется резистором Ru
Рис. 4.13. Упрощенная диаграмма процесса записи и чтения одного бита
Slave устройство в этом режиме только принимает сигнал. Для этого оно постоянно находится в режиме ожидания. Обнаружив начало синхроимпульса, Slave устройство начинает процесс приема бита информации. Передний фронт этого импульса служит Slave устройству началом отсчета. Выдержав паузу, равную длительности синхроимпульса, Slave устройство считывает уровень сигнала на линии. Если в этот момент времени уровень сигнала на линии равен нулю, значит и передаваемый бит равен нулю. Если же сигнал будет равен единице, то и бит равен единице. Протокол шины l-Wire жестко определяет только длительность слота. Интервал между слотами имеет ограничение только на минимальное свое значение. Максимальное значение интервала между слотами не-ограничено. Таким образом, может легко регулироваться скорость передачи данных от своего максимального значения (16,3 Кбит/с) практически до нуля.
180
Работа с шиной MicroLAN
Чтение бита. Процесс чтения бита (нижняя диаграмма на рис. 4.13) очень похож на процесс записи. Отличие его в том, что при чтении Master вырабатывает только синхроимпульсы (короткой длительности). Обнаружив синхроимпульс, Slave устройство должно удлинить или не удлинять этот синхроимпульс в пределах слота. Если очередной считываемый бит равен нулю, то синхроимпульс удлиняется. Если единице, удлинения не происходит.
Для иллюстрации этого процесса на рис. 4.13 участки временной диаграммы, где линию «подсаживает» Master устройство, изображены черным цветом. Участки, которые «подсаживает» Slave устройство изображены серым цветом. Master-устройство считывает эту информацию. Для этого оно контролирует уровень сигнала внутри слота сразу после синхроимпульса.
Временные параметры. Для надежной работы однопроводного интерфейса необходимо, чтобы в процессе передачи информации всеми элементами сети строго соблюдались временные параметры. Каждая микросхема, подключенная к сети, самостоятельно вырабатывает все необходимые для ее работы интервалы времени. Для ведущего устройства в сети эти требования более жесткие, чем для ведомых. Это связано с тем, что в качестве ведущего устройства обычно выступает микроконтроллер. Любой микроконтроллер способен с высокой точностью отрабатывать любые временные интервалы, благодаря использованию кварцевого резонатора. Ведомые же микросхемы обычно выполнены в микроминиатюрном корпусе. Временные параметры 1-Wire интерфейса таких микросхем формируются обычно параметрическими методами, без помощи кварца.
На рис. 4.14 приведены временные параметры протокола 1-Wire в различных режимах работы. Как видно из рисунка, величина слота для передачи одного бита информации (Тх) должна лежать в пределах от 60 до 120 мкс. Длительность синхроимпульса равна 1 мкс. Ведомое устройство, обнаружив на шине передний фронт синхроимпульса, должно сформировать задержку минимум в 15 мкс, и затем произвести проверку сигнала на шине. Допустимый разброс времени задержки для разных экземпляров микросхем лежит в пределах от 15 до 60 мкс. Этот диапазон показан на рисунке в виде области, обозначенной как «Зона проверки уровня Slave».
Минимальная величина интервала между слотами (TREC) равна 1 мкс. Максимальная, как уже говорилось, нсограничена.
Синхронизация и побитная передача информации
181
В режиме записи нулевого бита Master вырабатывает только синхроимпульсы, длительность которых равна I мкс. Если читаемый бит равен нулю, Slave устройство продлевает длительность синхроимпульса. Минимальная длительность продленного импульса составляет 15 мкс. Для этого временного интервала тоже допускается довольно значительный разброс. В пределах этого разброса длительность удлиненного импульса может вырасти еше на 45 мкс. Если читаемый бит равен единице, удлинения синхроимпульса не происходит. Для того, чтобы правильно оценить значение читаемого байта, Master устройство должно прочитать уровень сигнала на шине сразу после окончания синхроимпульса, но не позднее, чем через 15 мкс. Зона проверки уровня для Master устройства в режиме чтения значительно уже аналогичной зоны для Slave устройства в режиме записи.
Условные обозначения
Шину подсаживает "Master”
ммммп Шину подсаживает "Slave”
Шинй свободна. Напряжение определяется резистором RH
Рис. 4.14. Временные характеристики протокола 1-Wire
182
Работа с шиной MicroLAN
4.6.	Сброс и обнаружение присутствия на линии
В предыдущем разделе мы узнали, как происходит чтение и запись отдельных битов. Возникает вопрос, как происходит их разделение на байты. Байты формируются путем подсчета битов. Байты передаются младшим битом вперед. Первые восемь битов — это первый байт. Следующие восемь битов — второй байт. И так далее. Начало же всей этой цепочки определяется сигналом сброса. Любой цикл обмена данными в сети MicroLAN начинается с импульса сброса. Импульс сброса — это сверхдлинный отрицательный импульс на шине 1-Wire, вырабатываемый ведущим устройством.
Временная диаграмма, иллюстрирующая процесс формирования импульса сброса, приведена на рис. 4.15. С импульсом сброса тесно связан еще один служебный сигнал — сигнал присутствия на шине. Сигнал присутствия вырабатывает каждое Slave устройство сразу после окончания действия импульса сброса. Master устройство должно проконтролировать наличие этого импульса. Если импульса присутствия нет, то это значит, что на линии нет ни одного Slave устройства.
Кроме инициации импульсов присутствия импульс сброса переводит в исходное состояние всю систему. Любые незаконченные процессы на линии моментально завершаются, и отсчет битов начинается сначала. Временные характеристики сигнала сброса и сигнала присутствия на линии приведены на рис. 4.15. Длительность импульса сброса должна быть нс менее 480 мкс. Процесс передачи информации по линии может начинаться нс раньше, чем через 480 мкс после окончания действия импульса сброса. В этом временном интервале и ожидается появление сигнала присутствия. Для этого после окончания импульса сброса Master «отпускает» линию и ждет сигнала от Slave устройств.
Каждое Slave устройство, обнаружив импульс сброса, выдерживает паузу в 15...60 мкс, а затем «подсаживает» линию. Длительность импульса присутствия составляет 60...240 мкс. Сигналы присутствия от всех Slave устройств сливаются в один общий импульс. Ведущее устройство проверяет наличие нулевого уровня на линии в средине этого интервала. Если сигнал обнаружен, то это значит, что на линии имеется хотя бы одно нормально работающее
Сброс и обнаружение присутствия на линии
183
Slave устройство и Мастер может продолжать работу в сети. Если сигнал не обнаружится, то микропроцессор перейдет к обработке этой ситуации. Обычно в этом случае он выдаст сигнал ошибки (зуммер, светодиод, надпись на дисплее и т.д.).
Условные обозначения
Шину подсаживвет"Mester” им—1 Шину подсаживает “Sieve" ------ Шина свободна. Напряжение определяется резистором RH
Рис. 4.15. Временная диаграмма процесса начального сброса
Итак, мы познакомились с самым низким уровнем протокола l-Wirc, и знаем, как передается информация на уровне отдельных битов. Теперь перейдем к следующему уровню. Этот уровень определяет, каким же образом Master устройство управляет направлением передачи информации по шине, и как передается информация на уровне байтов. Для этого в сети MicroLAN существует такое понятие, как команды. Master посылает команды, а все Slave устройства их выполняют. Любая операция в сети MicroLAN начинается с команды. Команда представляет собой один байт информации.
Каждая команда имеет свой собственный код. Для того, чтобы понять, как работает механизм передачи команд, рассмотрим, как выполняется команда «Чтение ПЗУ» (Read ROM). Под ПЗУ понимается специальная область памяти микросхемы, где при помощи лазера записан ее индивидуальный код (ID-код). Команда «Чтение ПЗУ» позволяет микроконтроллеру (Master устройству) прочитать этот код. На рис. 4 16 приведена временная диаграмма сигнала, возникающего
184
Работа с шиной MicroLAN
на линии 1-Wirc в процессе выполнения команды «Чтение ПЗУ» (для удобства восприятия все импульсы внутри пакетов условно показаны одной длительности). Следует заметить, что команда «Чтение ПЗУ», в отличие от всех остальных команд, может корректно выполняться только в том случае, когда на шине имеется одно Master и одно Slave устройство. Почему это так, мы узнаем позже.
Выполнение команды начинается с импульса сброса. Затем Slave устройство вырабатывает, a Master проверяет сигнал присутствия на линии. Если сигнал на месте, Master выдаст на линию код команды «Чтение ПЗУ» (ЗЗН). Код выдается в режиме записи. Получив этот код, Slave микросхема переключается в режим выдачи информации. В этом режиме Master читает из Slave микросхемы 64 бита (8 байт), составляющие ее ID код. Последние восемь битов ID кода — это контрольная сумма. Она вычисляется по специальному алгоритму из его первых 56 битов. Микропроцессор проверяет контрольную сумму и в случае несоответствия повторяет процедуру «Чтение ПЗУ».
Команда «Чтение ПЗУ» далеко не единственная в протоколе 1-Wire шины. Существует целая система команд, позволяющая гибко управлять процессами обмена информации по шине. Настало время перейти к подробному изучению всех этих команд.
4.7.	Система команд протокола 1 -Wire
В предыдущих разделах мы рассмотрели работу сети MicroLAN на нескольких разных уровнях. Каждый из этих уровней имеет свое название. Первые два уровня мы изучили в предыдущем разделе. Определяются они следующим образом:
Система команд протокола 1-Wire
185
Физический уровень. Это схемное решение шины, уровни напряжений, взаимодействие элементов сети на уровне электрических сигналов.
Уровень связи. Это правила формирования сигнала сброса, синхронизация и способ передачи битов информации в обоих направлениях.
Эти два уровня определяются физическими особенностями сети MicroLAN. Однако при описании протокола принято выделять еще два уровня, которые, напротив, связаны с логикой работы протокола. Это, так называемые, сетевой и транспортный уровни. Любая шина l-Wire всегда находится на одном из этих уровней. Причем, сразу после сигнала сброса шина переходит на сетевой уровень. И лишь отработав команду сетевого уровня, шина переходит на транспортный. Команды сетевого уровня служат для адресации Slave микросхем. Это команды вида «Выбрать микросхему такую-то». Команды транспортного уровня служат для непосредственной передачи информации. Это команды типа «записать», «прочитать». Рассмотрим оба этих уровня подробнее.
Сетевой уровень. На этом уровне происходит адресация элементов на однопроводной шине. Находясь на этом уровне, все Slave устройства ожидают одну из команд адресации. Такая команда должна выбрать одно или несколько устройств, с которыми Master будет работать на транспортном уровне. Все команды сетевого уровня приведены в табл. 4.1.
Команды сетевого уровня	Таблица 4.1
Код	Команда	Описание
ЗЗН	Чтение ПЗУ	Чтение индивидуального кода ведомой микросхемы из специального ПЗУ (см. рис. 4.16)
OFH	Чтение ПЗУ	То же самое, но для микросхемы DS1990A (в этой микросхеме используется немного другая система команд)
55Н	Совпадение ПЗУ	Поиск и активизация элемента с заданным кодом. Остальные элементы переходят в пассивный режим
ОССН	Пропуск ПЗУ	Пропуск команды выбора устройства. Применяется, если нужно работать сразу со всеми устройствами, или оно всего одно
OFOH	Поиск ПЗУ	Команда, позволяющая осуществлять поиск элементов, подключенных к шине. Одновременно с поиском происходит определение их индивидуальных номеров
186
Работа с шиной MicroLAN
Как видно из таблицы, коды одной и той же команды для некоторых видов микросхем могут отличаться друг от друга. Так, команда «Чтение ПЗУ» (Read ROM) почти для всех типов микросхем имеет код ЗЗН, а для микросхемы DS1990A этот код равен 0FH. Принцип работы команды «Чтение ПЗУ» мы уже рассмотрели в предыдущем разделе. Master сначала передает код операции, а затем читает 64 разряда ID кода.
Команда «Совпадение ПЗУ» (Match ROM) работает по-другому. Master передает на шину код операции, а затем передает еще 64 разряда, представляющих собой ID код адресуемой микросхемы. Получив всю эту информацию, все Slave микросхемы, подключенные к шине, переходят на транспортный уровень. Причем одна из этих микросхем, у которой коды совпали, останется в активном режиме и будет принимать команды транспортного уровня. Остальные перейдут в пассивный режим и будут ожидать очередного сигнала начального сброса.
Очевидно, что перед тем, как применить команду «Совпадение ПЗУ», программист должен знать ID коды всех Slave микросхем, подключенных к однопроводной шине. Единственный способ узнать эти коды — по очереди подключить все эти микросхемы к микроконтроллеру, и при помощи специальной вспомогательной программы прочитать ID код каждой микросхемы, используя команду «Чтение ПЗУ».
Команда «Пропуск ПЗУ» (Skip ROM) позволяет перейти на транспортный уровень и при этом оставить активными все Slave микросхемы. Для выполнения этой команды Master просто передает в шину код ОССН. И сразу после этого все элементы шины перейдут на транспортный уровень. Команда «Пропуск ПЗУ» используется в двух случаях. Либо на линии присутствует всего одно Slave устройство и выбор адреса не требуется. Либо нужно подать команду транспортного уровня сразу на все элементы сети. Такой режим применяется, например, когда на все микросхемы датчиков температуры нужно одновременно подать команду «Начало преобразования температуры в код».
Команда «Поиск ПЗУ» (Search ROM) позволяет, при любом количестве элементов, подключенных к шине, адресовать всего один из них, не зная заранее его ID кода. Алгоритм этой команды составлен таким образом, что в процессе ее выполнения становится известен ID код одной из ведомых микросхем. Повторяя команду «Поиск
Система команд протокола 1-Wire
187
ПЗУ» несколько раз подряд, можно обнаружить все подключенные к шине Slave устройства и определить их ID коды Причем, если к шине подключены N разных Slave устройств, то для того чтобы найти их все, достаточно применить команду «Поиск ПЗУ» только N раз. Причем алгоритм всегда позволяет узнать, есть ли еще ненайденные устройства на шине. Как же работает эта удивительная команда? Рассмотрим подробно все этапы выполнения команды «Поиск ПЗУ».
♦ Сначала ведущее устройство выдает на шину код операции (0F0H) и переключается в режим приема. Но принимает оно в данном случае всего два бита информации.
♦ Получив команду, каждое ведомое устройство передает эти два бита. Они представляют собой значение младшего разряда ID кода конкретной микросхемы в прямом и инверсном виде. Сначала передается прямое, а затем инверсное значение разряда. Все микросхемы, подключенные к шине, передают своп биты одновременно. Поэтому ведущее устройство принимает результирующее значение этих двух битов. Представим себе ситуацию, что первый бит ID кодов всех Slave микросхем окажется одинаковым и равным нулю. В этом случае, все микросхемы выдадут код 01 (двоичное). Если первый бит 1D кода у всех микросхем окажется равным единице, то значение двух принятых битов будет 10 (двоичное). И, наконец, в том случае, если первый бит ID кода хотя бы у одной из микросхем будет отличаться от того же бита у других, на линии возникнет конфликт. Разные микросхемы будут выдавать разные коды. Одни 01, другие 10. Так как однопроводная шина обладает эффектом схемного «И», значение пары битов, принятых в этом случае Master устройством будет равно 00. Таким образом, на этом этапе выполнения команды «Поиск ПЗУ» можно получить следующую информацию:
1. Мы можем определить, имеет ли младший разряд ID кода одинаковое значение для всех микросхем, подключенных к I-Wire шине или нет.
2. Если младший разряд для всех микросхем одинаковый, мы можем точно узнать его значение.
♦ Следующий этап — сепарация. Master выдает на шину всего один бит, при помощи которого он производит отбор Slave микросхем.
188
Работа с шиной MicroLAN
Если Master выдаст на шину единицу, то все элементы, у которых младший разряд кода равен нулю, отключаются. Остаются только те элементы с единицей в младшем разряде. Если Master выдаст ноль, то на шине остаются микросхемы с младшим разрядом, равным нулю. Сепарацию нужно производить таким образом, чтобы на шине всегда оставались активные устройства. Так, если на предыдущем этапе Master получил два бита, значение которых равно 01, то он должен выдать на шину бит равный нулю. Если два полученных бита были равны Ю, то ответный бит должен быть единичным. Особый случай — значение битов 00. Здесь алгоритм допускает любые варианты. Передаваемый бит может быть равен как нулю, так и единице. В любом случае часть микросхем отключится, а часть останется в работе. Во всех трех перечисленных выше случаях на шине останутся активными элементы, для которых нам теперь точно известно значение одного из разрядов ID кода. Кроме того, точно известно, что на шине имеется хотя бы одна такая микросхема.
♦	На следующем этапе вся шина переходит к проверке следующего разряда ID кода. Для этого Master опять читает, а все Slave выдают новую пару битов. Теперь эти биты представляют прямое и инверсное значения нового разряда. После чтения пары битов происходит очередной этап сепарации.
♦	Так, этап за этапом, происходит оценка всех 64 разрядов ID кода. В случае разницы в кодах, происходит выбор одного из вариантов и отсеивание остальных. Выполнение команды «Поиск ПЗУ» заканчивается после того, как таким образом будут оценены все 64 разряда. В результате на шине останется всего одно активное Slave устройство, а микроконтроллер будет точно «знать» се ID код. Дальше вся шина переходит на транспортный уровень.
Операцию «Поиск ПЗУ» можно повторять множество раз. При этом поиск новых ID кодов нужно вести с учетом уже найденных. Найденные ранее варианты ID кода в процессе поиска нужно исключать. Таким образом, можно найти ID коды для всех устройств подключенных к вашей шине. Адреса запоминаются в памяти микроконтроллера и в дальнейшем, для обращения к каждому элементу сети, используется команда «Совпадение ПЗУ».
Система команд протокола 1-Wire
189
Дополнительные команды сетевого уровня
В некоторых видах микросхем встречается еще несколько дополнительных команд сетевого уровня. Например, микросхема DS1994 имеет встроенный таймер, который способен вырабатывать специальный сигнал прерывания в заданный момент времени. Сигнал прерывания передастся все по той же одной единственной однопроводной шине.
Сигнал прерывания представляет собой отрицательный импульс большой длительности (960...3840 мкс). Если на шине присутствует несколько микросхем DS1994, то, обнаружив сигнал прерывания, микропроцессор должен еще определить, какая из этих микросхем является его источником. Для этого предусмотрена специальная команда «Поиск прерывания» (Search Interrupt). Код этой команды — ОЕСН. Команда «Поиск прерывания» работает точно так же как команда «Поиск ПЗУ», но поиск происходит только среди тех микросхем, которые вызвали прерывание. Остальные микросхемы сразу отключаются.
Подобная команда существует и в микросхемах других видов. Например, в серии микросхем DS18S20, DSI8B20, DS1822. Эти микросхемы представляют собой электронные измерители температуры. Все они содержат два специальных регистра, при помощи которых можно задавать верхний и нижний пределы изменения температуры. При выходе температуры за установленные пределы микросхема термодатчика не вырабатывает на шине сигнал прерывания, как микросхема DS1994. Однако в составе ее команд также имеется команда «Поиск Прерывания», при помощи которой микроконтроллер всегда может быстро отобрать из всех микросхем только те, которые требуют немедленной обработки.
Транспортный уровень. Все микросхемы сети MicroLAN переходят на этот уровень после любой команды сетевого уровня. Набор команд транспортного уровня для разных микросхем несколько отличается один от другого. Примеры команд транспортного уровня для разных типов микросхем приведены в табл. 4.2. Основные команды транспортного уровня — это команды «Запись памяти» и «Чтение памяти». Все микросхемы, используюшие l-Wirc интерфейс, по внутренней архитектуре представляют собой несколько
190
Работа с шиной MicroLAN
ячеек памяти. Обычно это набор регистров, через который осуществляется обмен данными. Через одни регистры микропроцессор может записывать в микросхему коды, определяющие режим ее работы. Через другие он может считывать различные величины. Например, температуру, результат цифро-аналогового преобразования и так далее.
В качестве примера команды транспортного уровня рассмотрим команду «Чтение памяти». На рис. 4.17 приведена временная диаграмма выполнения команды «Чтение памяти». Для адресации микросхемы в приведенном примере использована команда сетевого уровня — «Совпадение ПЗУ». Как видно из рисунка, выполнение команды начинается с импульса сброса. Далее, все ведомые устройства вырабатывают сигнал присутствия на линии. Но пока это только сетевой уровень.
Выдержав положенную паузу, ведущее устройство выдает на линию команду «Совпадение ПЗУ». Команда состоит из восьми бит кода операции и 64-битного ID кода. Получив эту команду, все ведомые микросхемы переходят на транспортный уровень. Но только одна из них останется активной. Остальные перейдут в пассивный режим ожидания.
Далее, ведущее устройство передает на шину команду «Чтение памяти» (8 бит). Получив эту команду, выбранная нами ведомая микросхема переходит в режим выдачи данных. Ведущее же устройство читает эти данные из ведомой микросхемы. Объем считываемых данных зависит от типа применяемой микросхемы. Чаще всего он равен 8 байтам (64 бит) и обязательно содержит контрольную сумму в последних восьми битах.
После того, как все данные приняты, выполнение команды можно считать законченным. Для того, чтобы выполнить следующую команду, нужно все начинать с начала. То есть с импульса начального сброса.
Если вы сравните команды сетевого и команды транспортного уровней (табл. 4.1 и 4.2), то можете заметить, что для команд разного уровня могут применяться одинаковые коды. Однако это не вызывает никаких затруднений, так как каждая из категорий команд действует на своем уровне.
Система команд протокола 1-Wire
191
Примеры команд транспортного уровня
Таблица 4.2
Микросхема	Код	Команда
DS1994 (4096-битная перезаписываемая энергонезависимая память)	OFH	Запись в блокнотную память
	ОААН	Чтение блокнотной памяти
	55Н	Копирование блокнотной памяти
	ОГОН	Чтение основной памяти
DS2417 Часы реального времени	66Н	Чтение времени
	99Н	Запись времени
DS2450 4-канальный АЦП	ОААН	Чтение из памяти результатов преобразования напряжения
	55Н	Запись в память управляющих команд
DS18S2O/DS18B2O/DS1822 Электронные датчики температуры	44Н	Запуск процесса конвертирования температуры в код
	4ЕН	Запись в блокнотную память (пределов регулирования температуры)
	ОВЕН	Чтение блокнотной памяти
	48Н	Копирование блокнотной памяти в специальные ячейки внутренней EfPROM
	0В8Н	Чтение информации из EEPROM в блокнотную память
	0В4Н	Чтение информации о режиме питания
Импульс сброса Импульс присутствия
\	1	Не в масштабе
Следующий импульс сброса
/
8 бит: команда “Совпадение ПЗУ"
8 бит: команда "Чтение памяти”
Рис. 4.17. Формат команды 1 -Wire протокола
Итак, мы узнали все основные принципы построения протокола передачи информации с использованием однопроводной последовательной шины сети MicroLAN. Далее мы еще рассмотрим, как эта шина применяется на практике. Но прежде, чем перейти к более конкретным примерам, я должен остановиться на одном небольшом, но очень важном вопросе. Практически с самого начала этой главы мы постоянно упоминали ID коды. Между тем, ID код — это не просто набор цифр. Он тоже имеет определенную структуру.
192
Работа с шиной MicroLAN
4.8.	Структура ID кода
Структура индивидуального кода, записанного в специальное ПЗУ любой микросхемы, поддерживающей однОпроводный интерфейс l-Wire, условно изображена на рис. 4.18. Код состоит из трех основных элементов:
Младший разряд Вбит
Групповой код
48 бит Уникальный номер
8 бит
Контрольная сумма CRC
Старший разряд
Рис. 4.18. Структура индивидуального кода микросхемы 1-Wire
Первые 8 бит, начиная с младшего разряда — это групповой код микросхемы. Групповой код однозначно определяет ее вид. Примеры группового кода для разных видов микросхем приведены в табл. 4.3. Следующие 48 бит — это уникальный серийный номер микросхемы. Последние 8 бит — это контрольная сумма (CRC) младших 56 бит.
Групповые коды некоторых видов микросхем	Таблица 4.3
Вид микросхемы	Описание	Групповой код
DS18S20	Электронный термометр	ЮН
DS18B20	Электронный термометр	28Н
DS18B22	Электронный термометр	22Н
DS1992	Энергонезависимая память	08Н
DS1993	Энергонезависимая память	06Н
DS1994	Энергонезависимая память	04Н
DS2401	Кремневый серийный номер	01Н
DS2417	Таймер реального времени	27Н
OS2450	4-канальный АЦП	20Н
DS2890	Электронный переменный резистор	2СН
Структура ID кода	193
Контрольная сумма, или циклически избыточный код (Cyclic Redundancy Check — CRC), формируется при помощи специального полиномного генератора, состоящего из регистра сдвига и трех логических элементов XOR, реализующих функцию «Исключающее ИЛИ». Функциональная схема такого генератора показана на рис. 4.19. Такая схема реализует многочлен Xs+X5+X4+1. Биты (Р7...Р0) регистра сдвига перед началом вычисления устанавливаются в ноль. Затем, на вход схемы последовательно подаются 56 младших разрядов ID кода. При подаче каждого очередного разряда информация в сдвиговом регистре полиномного генератора сдвигается на один шаг в направлении, показанном стрелками. При этом в разряд Р7 регистра попадет результат операции XOR между значением очередного бита на входе всей схемы и значением разряда РО. Значения разрядов РЗ и Р2 также являются результатом операции XOR, которую выполняют остальные два элемента. После 56 циклов такого сдвига в разрядах Р7...Р0 полиномного генератора будет находиться искомая контрольная сумма. Точно такое значение будут иметь последние 8 бит исходного ID кода. Если содержимое регистра полиномного генератора и последних восьми байтов ID кода совпали, то это значит, что при передаче кода по сети ошибок не произошло.
Вход
Рис. 4.19. Функциональная схема полиномного генератора
Если при вычислении контрольной суммы через полиномный генератор пропустить не 56, а все 64 разряда ID кода, то в результате мы должны получить в регистре генератора код ООН. То есть все разряды регистра (Р7...Р0) должны быть равными нулю. Это второй способ проверки контрольной суммы.
В микросхемах 1-Wire периферии полиномный генератор выполнен аппаратным способом. Там действительно имеется сдвиговый регистр и три элемента «Исключающее ИЛИ». Если ведущее устройство выполнено на основе микроконтроллера, то подсчет контрольной суммы организуется программным путем. Для этого существует специальная подпрограмма, выполняющая те же действия, что и схема, изображенная на рис. 4.19. Пример такой программы приведен в разделе 4.16 нашей книги.
7 Зак. 922
194
Работа с шиной MicroLAN
4.9.	Интегральные датчики температуры
До конца понять принципы работы любого последовательного протокола можно только на конкретном примере. Для PC шины в качестве такого примера мы выбрали микросхемы флэш-памяти. Это было абсолютно оправдано, так как для PC шины — это самое удачное применение. Теперь нам нужно выбрать столь же удачный пример для однопроводной шины. Безусловно, самое удачное применение шины — подключение к микроконтроллеру микросхем измерителей температуры. Фирма Dallas Semiconductor выпускает целый набор таких микросхем. Самый первый интегральный термодатчик с 1-Wire интерфейсом назывался DS1820. Эта оригинальная микросхема сразу после своего появления приобрела популярность у разработчиков электронной аппаратуры. Микросхема была помещена в пластмассовый корпус, напоминающий по размерам и форме миниатюрный транзистор. Однако в процессе ее проектирования была допущена одна досадная ошибка. Ошибка приводила к тому, что термодатчик в отдельных случаях давал неверный результат.
Правда эта ошибка легко исправлялась путем несложной дополнительной программной обработки на стороне микроконтроллера. Поэтому, несмотря на ошибку, микросхема продолжала широко применяться. Фирма Dallas Semiconductor быстро исправила досадную ошибку. Однако существующую микросхему переделывать не стала для обеспечения совместимости с массой электронных устройств, разработанных к тому времени на ее основе. Фирма просто выпустила новую микросхему, уже без дефекта, и назвала ее DSI8S20. Новая микросхема имеет более миниатюрный корпус и является полным функциональным аналогом DS1820, но ее внутренняя микропрограмма не содержит никаких ошибок.
Термодатчики DS1820 и DS18S20 имеют рабочий диапазон температур от —55°С до +125°С. Максимальное время преобразования температуры в код 750 мс. Результаты измерения считываются по 1-Wire интерфейсу из специальных внутренних регистров микросхемы в виде девятиразрядого двоичного кода. Девять двоичных разрядов представляют собой значение температуры в дополнительном коде, измеренную с шагом в 0,5°С. Точность измерения
Интегральные датчики температуры
195
температуры различна в различных точках рабочего диапазона. На отрезке -10°С...+85°С точность измерения равна ±0,5°С.
Чем ближе к краю диапазона, тем точность измерения меньше. На самых краях она составляет всего ±2°С. Преобразователь температуры в код, применяемый в микросхем DS1820 и DSI8S20, способен выдавать значение температуры с большим количеством отсчетов (более мелким шагом). Промежуточные значения просто вычисляются. Для этого в обеих микросхемах предусмотрены два специальных регистра. В первом из них хранится число оставшихся отсчетов, а во втором — число отсчетов на один градус. Используя содержимое этих регистров, можно рассчитать значение температуры с разрешением в 0,01...0,05°С. Тут следует заметить, что повышение дискретности не ведет к увеличению точности измерения температуры, а лишь улучшает плавность регулировочных характеристик.
Более совершенная микросхема DS18B20 не требует никаких дополнительных вычислений. Высокая дискретность достигается увеличением количества разрядов результирующего кода. Причем в микросхеме имеется возможность изменения количества разрядов выходного регистра. По умолчанию выходной регистр имеет 9 разрядов. Изменяя содержимое регистра конфигурации, микроконтроллер может увеличить количество разрядов до 12. Точность измерения температуры в диапазоне —1О...+85°С составляет ±0,5°С. На выходе микросхемы DS18B20 мы получаем прямой код, значение которого равно величине измеряемой температуры. В 9-разрядном режиме значение измеряемой температуры выдается с дискретностью в 0,5°С. В двенадцатиразрядном режиме количество отсчетов повышается в восемь раз. Максимальное время преобразования для микросхемы DS18B20 также зависит от выбранного количества разрядов. Для 12-разрядного режима работы оно равно 750 мс.
В настоящее время микросхема DS18B20 — это самый распространенный вид микросхем подобного назначения. Однако фирма Dallas Semiconductor выпускает и другие модификации электронных термометров. Микросхема DS1822 — более дешевый вариант DS18B20. По функциональным возможностям они являются полными аналогами. Однако DS1822, имеет меньшую точность измерения температуры. В диапазоне — 10°С...+85"С точность измерения составляет всего ±2°С. А на краях еще хуже. Зато она дешевле своего аналога.
196
Работа с шиной MicroLAN
Выпускаются также варианты всех вышеперечисленных микросхем, предназначенные для работы исключительно в режиме паразитного питания. Они получили название DS18S20-PAR, DS18B20-PAR, DS1822-PAR Эти микросхемы внешне ничем не отличаются от своих аналогов. Однако вывод питания у них не задействован. Существуют и другие, экзотические модификации датчиков температуры Например, микросхема DS18B20X — аналог микросхемы DS18B20, выполненный в специальном микроминиатюрном без-выводном корпусе.
Очевидно, что для нашего примера удобнее всего выбрать микросхему DS18B20, так как остальные варианты либо устарели, либо могут считаться ее модификациями. Поэтому рассмотрим подробнее именно эту микросхему.
4.10.	Внутренняя архитектура микросхемы DS18B20
Микросхема DS18B20 выпускается в двух модификациях. Они отличаются исключительно конструкцией корпуса. На рис. 4.20 приведен внешний вид обеих модификаций микросхемы. Основной вариант микросхемы выполнен в миниатюрном пластмассовом корпусе типа ТО-92. Второй вариант заключен в планарный восьмивыводной, миниатюрный корпус типа SOIC. Для того, чтобы различать эти два варианта исполнения, второй вариант получил обозначение DS18B20Z. Микросхема имеет всего три задействованных вывода: DQ — вход/выход данных (-Wire интерфейса; VDD — вывод внешнего питания; GND — общий провод. Расположение выводов показано на рис. 4.20.
Внутренняя структура микросхемы DS18B20 приведена на рис. 4.21. Сигнал с шины DQ и напряжение с внешнего вывода питания (VDD) прежде всего поступают на схему паразитного питания. Принцип работы паразитного питания мы уже рассматривали в разделе 4 4 настоящей главы. Однако в схеме паразитного питания имеется еще один дополнительный элемент, о котором не говорилось ранее. Это датчик наличия питания. Датчик представляет собой пороговый элемент, на который поступает напряжение питания от внешнего источника. Датчик вырабатывает логический
Внутренняя архитектура микросхемы DS18B20
197
сигнал, поступающий в схему управления. В результате микросхема получает возможность автоматически определять режим своего питания. Микроконтроллер, работающий в качестве Master устройства на той же шине, имеет возможность запросить у всех подключенных к ней датчиков информацию о режиме питания и соответствующим образом скорректировать алгоритм своей работы. Как это делается на практике, мы еще увидим.
DQ — вывод 1 -Wire GNO — общий провод NC — вывод не используется
1 2 3
(Вид снизу)
DS1BB20 в корпусе ТО-92
Рис. 4.20. Внешний вид микросхем DS18B20 в двух разных исполнениях
VPU
Рис. 4.21. Внутренняя структура микросхемы DS18B20
198
Работа с шиной MicroLAN
Сигнал DQ, обеспечив напряжением схему паразитного питания, поступает на l-Wire порт, который служит аппаратной частью однопроводного интерфейса. Данные, полученные при помощи этого интерфейса, поступают в блокнотную память. Блокнотная память предназначена для временного хранения информации от датчика температуры и трех специальных регистров: регистра верхнего предела (Ttl), регистра нижнего предела (TL) и регистра конфигурации. Все три специальных регистра представляют собой три ячейки флэш-памяти (EEPROM).
С блокнотной памятью также связан генератор контрольной суммы. Этот генератор автоматически вычисляет контрольную сумму всех регистров блокнотной памяти. При считывании информации из блокнотной памяти контрольная сумма также читается и служит для проверки правильности прочитанной информации. Применение блокнотной памяти позволяет повысить надежность передачи информации. Информация никогда не записывается непосредственно в ячейки флэш-памяти (регистры Тн и TL и регистр конфигурации). Предварительно она помещается в блокнотную память. Затем микроконтроллер читает ее оттуда и проверяет контрольную сумму. Если результат проверки положительный, микроконтроллер подает по шине специальную команду «Копирование блокнотной памяти в ЕЕ PROM».
Посредством 1-Wire интерфейса можно также прочитать содержимое 64-битного ПЗУ, в котором хранится ID код микросхемы. Последние восемь битов ID кода представляют собой контрольную сумму первых ее 56 битов. Алгоритм составления контрольной суммы в обоих случаях одинаковый (см. раздел 4.8).
Структура памяти микросхемы DS18B20 приведена на рис. 4.22. Память состоит из восьми регистров блокнотной памяти и трех регистров EEPROM. Операции записи и чтения блокнотной памяти выполняются для всех ее регистров одновременно. При записи все восемь регистров блокнотной памяти записываются одним блоком из восьми байт. Точно также одним блоком происходит и считывание информации. На рис. 4.22 для каждого регистра обозначена его позиция внутри передаваемого блока (байт 0, байт 1 и так далее).
Два самых младших регистра (байт 0 и байт 1) содержат результат преобразования температуры в код. Следующие три регистра служат для промежуточного хранения информации для регистров
Внутренняя архитектура микросхемы DS18B20
199
флэш-памяти. В регистр Тн записывается верхний предел температуры. В регистр TL — нижний. Эти регистры используют для проверки факта выхода величины измеренной температуры за границы установленного диапазона. Микроконтроллер способен быстро отыскать в сети MicroLAN все термодатчики, у которых не соблюдается это условие. Если вам не нужен механизм ограничения температуры, то регистры Тн и TL можно использовать как дополнительные ячейки энергонезависимой памяти и хранить в них любые данные. Например, туда можно записать код места положения конкретного датчика. Регистр конфигурации служит для переключения количества разрядов измерителя температуры.
Блокнотная память
Байт О
Байт 1
Байт 2 БайтЗ Байт 4
Байт 5
Байт 6
Байт 7 БайтВ
* — эти регистры при включении питания восстанавливают свое значение из БЕРНОМ
Рис. 4.22. Структура памяти микросхемы DS18B20
Все три описанные выше регистра (байт 2, байт 3, байт 4) имеют механизм автоматического восстановления. При включении питания в них автоматически копируется информация из соответствующих регистров EEPROM. В регистр температуры после включения питания помещается код 0550Н (старший байт 05Н, младший байт 50Н), что соответствует температуре 85°С.
Оставшиеся три регистра блокнотной памяти (байт 5, байт 6 и байт 7) в микросхеме DS18S20 не используются. Они зарезервированы для будущих се модификаций. При чтении все три неиспользуемых регистра возвращают код 0FFH (единицы во всех
200
Работа с шиной MicroLAN
разрядах). Последний, восьмой регистр блокнотной памяти — это регистр генератора контрольной суммы.
Теперь рассмотрим по порядку формат каждого из описанных выше регистров. Формат регистра температуры приведен на рис. 4.23.
	Бит?	Бит 6	Бит 5	Бит 4	БитЗ	Бит 2	Бит 1	БитО
Младший байт	23	2г	2’	2°	2 1	2’2	23	2-4	|
	Бит 15	Бит 14	Бит 13	Бит 12	Бит 11	Бит 10	Бит 9	Бит 8
Старший байт	S	S	S	S	S	26	г5	2"
Рис. 4.23. Структура регистра температуры
Как уже говорилось, после окончания процесса преобразования эти регистры содержат прямое значение величины измеренной температуры в двоичном виде. Регистр температуры — это два регистра блокнотной памяти. На рис. 4.23 показан вес каждого разряда регистра. Биты с 11-го по 15-й (обозначенные буквой S) содержат одно и то же значение. Оно равно знаку записанного числа (0 — плюс, 1 — минус). Положительные значения температуры записываются в прямом коде, а отрицательные — в дополнительном. Дополнительный код широко используется в вычислительной технике для записи отрицательных чисел. •
Для того, чтобы перевести двоичное число в дополнительный код, нужно инвертировать его, а затем прибавить единицу. Подробнее о правилах и приемах двоичной арифметики вы можете почитать на сайте «Цифровые микросхемы и микропроцессоры» [ lw].
Для того чтобы понять, каким образом измеряемая температура записывается в виде кода, посмотрите на табл. 4.4. В этой таблице приведено несколько примеров преобразования температуры в код. В двенадцатиразрядном режиме работы микросхемы задействованы все значащие биты регистра температуры от бита 0 до бита 11. При понижении разрядности младшие биты отключаются. В девятиразрядном режиме работают биты с 3 по 11. Отключенные биты всегда имеют нулевое значение (для отрицательных чисел — единичное).
Внутренняя архитектура микросхемы DS18B20
201
Преобразование температуры в код	Таблица 4 4
Температура	Выходной код	
	В двоичном виде	В шестнадцатеричном виде
+125'С	00000111 1101 0000	07DOH
+85"С	0000 0101 0101 0000	0550h
+25.0625‘С	00000001 1001 0001	019111
+10.125Г	0000 000010100010	00A2h
+0.5'С	0000000000001000	0008h
(УС	0000 000000000000	OOOOh
-0.5‘С	1111 1111 1111 1000	FFF8h
-10.125'С	1111 11110101 1110	FF5Eh
-25.0625’С	1111 1110 01101111	FE6Fh
-55'С	1111 1100 1001 0000	FC90h
Теперь рассмотрим формат регистров Тн и TL. На рис. 4.24 он представлен в графическом виде. Как видно из рисунка, эти регистры имеют всего по восемь разрядов. Причем старший разряд — это знак числа. Поэтому верхний и нижний пределы температуры могут устанавливаться лишь с шагом в I градус. Для записи положительных и отрицательных чисел в регистрах Тн и TL также используются прямой и дополнительный коды.
Бит 7	Бите	Бит 5	Бит 4	БитЗ	Бит 2	Бит t	БитО
s	26	2®	24	2Э	22	2*	2°
Рис. 4.24. Формат регистров Тц и TL
Последний регистр, формат которого мы должны рассмотреть, это регистр конфигурации. Формат регистра приведен на рис. 4.25. Для изменения конфигурации используются только два разряда этого регистра — бит 5 и бит 6. Значения остальных битов показаны на рисунке. В табл. 4.5 представлены все четыре режима, которые можно установить при помощи регистра конфигурации. Номер режима определяется разрядами R0 и RI. При отключении лишних разрядов уменьшается точность измерения температуры, но одновременно уменьшается и время, необходимое для преобразования температуры в код. В табл. 4.5 для каждого из режимов работы приведено максимальное значение времени преобразования.
202
Работа с шиной MicroLAN
Бит 7	Бит 6	Бит 5	Бит 4	БитЗ	Бит 2	Бит 1	БитО
0	R1	R0	1	1	1	1	1
Рис. 4.25. Формат регистра конфигурации
Выбор количества разрядов	Таблица 4.5
R1	R0	Разрядность преобразования	Максимальное время преобразования	
0	0	9	93,75 мс	tconv/8
0	1	10	187,5 мс	Uv/4
1	0	11	375 мс	tconv/2
1	1	12	750 мс	tconv
Теперь перейдем к рассмотрению системы команд 1-Wire интерфейса микросхемы DS18B20. Практически со всеми командами мы уже знакомы. Полный список команд приведен в табл. 4.6. Все команды сетевого уровня подробно были описаны в разделе 4.7. Поэтому подробнее мы остановимся лишь на командах транспортного уровня.
Система команд микросхемы DS18B20	Таблица 4 6
Команда	Описание
Команды сетевого уровня	
OFOH	Поиск ПЗУ
ЗЗН	Чтение ПЗУ
55Н	Совпадение ПЗУ
ОССН	Пропуск ПЗУ
ОЕСН	Поиск прерывания
Команды транспортного уровня	
4ЕН	Запись блокнотной памяти
ОВЕН	Чтение блокнотной памяти
0В4Н	Чтение режима питания
0В8Н	Чтение из EEPROM в блокнотную память
48Н	Копирование блокнотной памяти в EEPROM
44Н	Запуск процесса преобразования
Внутренняя архитектура микросхемы DS18B20
203
Команда «Запись блокнотной памяти» (Write Scratchpad).
При выполнении этой команды, микроконтроллер выдает на шину следующие сигналы:
♦	Сигнал начального сброса;
♦	Одну из команд сетевого уровня;
♦	Код операции «Запись блокнотной памяти» (4ЕН);
♦	Восемь байт для записи во все восемь регистров этой памяти. Причем восьмой, последний байт должен быть равен контрольной сумме первых семи байтов. Микросхема DS18B20 принимает все эти данные и записывает в регистры памяти.
Команда «Чтение блокнотной памяти» (Read Scratchpad).
При выполнении этой команды микроконтроллер производит следующие действия:
♦	Выдает на шину сигнал начального сброса;
♦	Выдает одну из команд сетевого уровня;
♦	Выдает код операции «Чтение блокнотной памяти» (ОВЕН);
♦	Считывает восемь байт данных из блокнотной памяти.
Последний байт — контрольная сумма.
Команда «Чтение режима питания» (Read Power Supply).
Команда позволяет микроконтроллеру запросить у микросхемы термодатчика информацию о его режиме питания (внешнее или паразитное). Для выполнения команды микроконтроллер выполняет следующие действия:
♦	Выдает на шину сигнал начального сброса;
♦	Выдает одну из команд сетевого уровня;
♦	Выдает код операции «Чтение режима питания» (0В4Н);
♦	Читает один бит информации, который выдает микросхема DS18B20.
Если микросхема работает в режиме паразитного питания, то она в ответ на команду «Чтение режима питания» выдаст бит равный нулю. Если используется внешнее питание, то ответный бит будет равен единице.
204
Работа с шиной MicroLAN
Команда «Заполнение блокнотной памяти» (Recall Е2).
Команда служит для переноса информации из EEPROM в блокнотную память. Для выполнения этой команды микроконтроллер производит следующие действия:
♦	Выдает на шину сигнал начального сброса;
♦	Выдает одну из команд сетевого уровня;
♦	Выдает код операции «Заполнение блокнотной памяти» (0В8Н).
Сразу после получения этой команды содержимое EEPROM копируется в блокнотную память. Эта команда выполняется автоматически каждый раз после включения питания.
Две оставшиеся команды транспортного уровня отличаются от всех остальных команд тем, что для своего исполнения они требуют значительно большего количества энергии от источника питания Первая из этих команд вызывает запись информации в регистры встроенной EEPROM памяти, а вторая запускает процесс преобразования температуры в код. В момент выполнения любой из этих операций нельзя использовать режим паразитного питания. В этом случае нужно либо включить микросхему в режим внешнего питания, либо воспользоваться третьим вариантом: подачей полноценного питания по той же линии, по которой происходит передача информации. Ниже приведены две возможные схемы включения термодатчиков, предназначенные для работы в разных режимах питания.
Рис. 4.26. Схема включения термодатчика в режиме внешнего питания
На рис. 4.26 показана схема включения микросхем DS18B20 в режиме внешнего питания. Внешнее питание подается на каждую такую микросхему через вывод VDD. Если термодатчик находится на значительном удалении от микроконтроллера, то применение
Внутренняя архитектура микросхемы DS18B2O	205
такой схемы включения не очень желательно, так как для питания датчика придется прокладывать еще один (третий) провод.
Второй вариант включения микросхем DS18B20 изображен на рис. 4.27. В такой схеме реализованы два режима питания. Для переключения режимов используется управляемый электронный ключ К1. Ключ управляется от микроконтроллера, для чего используется отдельная линия ввода/вывода. Такая схема позволяет переключать режимы питания программным путем. Основной режим работы для схемы, изображенной на рис. 4.27 — это режим паразитного питания. В этом режиме ключ К1 закрыт и напряжение на шине определяется резистором нагрузки R1, что позволяет передавать информацию по шине, используя 1-Wire протокол.
В нужный момент ключ К1 открывается и на шину поступает полноценное питание от источника VP1J. Питание поступает только на время выполнения одной из энергоемких команд. Пока ключ К1 открыт, информационный обмен по шине невозможен. Микроконтроллер выдерживает шину в таком состоянии необходимое время, а затем закрывает ключ К1. Шина возвращается в обычный режим работы и снова обретает возможность передачи данных. Для того, чтобы микросхема DS18B20 правильно работала в режиме паразитного питания, нужно соединить между собой выводы VDD и GND и подключить оба этих вывода к общему проводу, как показано на рисунке
Рис. 4.27. Схема включения термодатчика в режиме паразитного питания
Теперь рассмотрим, как выполняются две оставшиеся команды транспортного уровня: «Копирование блокнотной памяти»(и «Запуск процесса преобразования». Формат обеих команд практически одинаковый. Микроконтроллер просто подает команду и ожидает, пока закончится ее выполнение. А вот процедура ожидания зависит
206
Работа с шиной MicroLAN
от схемы включения термодатчика. Для каждой из двух описанных выше схем (см. рис. 4.26 и 4.27) ожидание выполняется по-разному. Рассмотрим обе команды подробнее.
Команда «Копирование блокнотной памяти» (Copy Scratchpad)
Для выполнения этой команды микроконтроллер производит следующие действия:
♦	Выдает на шину сигнал начального сброса;
♦	Выдает одну из команд сетевого уровня;
♦	Выдает код операции «Копирование блокнотной памяти» (48 Н);
♦	Выполняет процедуру ожидания конца операции.
В результате выполнения этой команды содержимое блокнотной памяти копируется в EEPROM.
Команда «Запуск процесса преобразования» (Convert Т)
Для выполнения этой команды микроконтроллер производит следующие действия:
♦	Выдает на шину сигнал начального сброса;
♦	Выдает одну из команд сетевого уровня;
♦	Выдает код операции «Запуск процесса преобразования» (44Н);
♦	Выполняет процедуру ожидания конца операции.
В результате выполнения этой команды измеренная температура преобразуется в код. Полученный код помешается в соответствующий регистр микросхемы DS18B20.
Если все термодатчики включены по схеме с внешним питанием (рис. 4.26), то длительность процедуры ожидания определяется сигналом готовности. Сигнал готовности формируется следующим образом. Как только микросхема термодатчика начинает выполнять одну из двух энергоемких команд, она «подсаживает» 1 - Wire шину. Микроконтроллер проверяет уровень сигнала на шине. Обнаружив нулевой сигнал, он переходит в режим ожидания Режим ожидания продолжается до тех пор, пока все микросхемы термодатчиков не закончат выполнение операции и не отпустят шину.
Если термодатчики включены по схеме, изображенной на рис. 4.27, то процедура ожидания представляет собой фиксированный по
Схема подключения микросхемы DS18B20
207
длительности временной интервал, в течение которого микроконтроллер удерживает ключ К! во включенном состоянии и больше не производит никаких операций на шине Интервал ожидания формируется микроконтроллером и должен быть заведомо большим, чем максимально возможное время выполнения операции. Например, максимальное время выполнения процедуры преобразования температуры для микросхемы DS18B20 равно 750 мс. Длительность временного интервала ожидания должна быть больше. Ее можно выбрать равной I секунде
Программа, реализующая команды l-Wire интерфейса, обычно делается универсальной, рассчитанной для любой схемы включения термодатчиков. Такая программа автоматически проверяет режим питания микросхем и в зависимости от полученного результата изменяет алгоритм процедуры ожидания. Проверка производится при помощи команды «Чтение режима питания» (0В4Н) В конце этой главы будет приведен пример такой универсальной программы.
4.11.	Схема подключения микросхемы DS18B20
В качестве примера применения датчика температуры рассмотрим схему электронного термометра. Схема термометра приведена на рис. 4.28. Термометр предназначен для работы с двумя датчиков температуры типа DS18B20. Датчики работают в режиме паразитного питания с возможностью получения полноценного питания по шине данных. Для индикации температуры используется ЖКИ модуль, подробно описанный в главе 2. На рис. 4.28 показана полная схема прибора, включая вспомогательные цепи и цепи питания. При желании схему можно использовать для самостоятельной сборки термометра.
Роль однопроводной шины выполняет линия Р3.1 микроконтроллера. Резистор R2 — это нагрузочный резистор шины. В связи с тем, что на шине работают всего две микросхемы термодатчиков, номинал этого резистора увеличен до Ю кОм (рекомендованное значение 4,7 кОм). Электронный ключ для переключения режима питания собран на элементах VTl, R3, R4 и R5. Микроконтроллер управляет ключом при помощи линии РЗ.О. Резистор R5 служит для
208
Работа с шиной MicroLAN
ограничения тока базы транзистора VT1. Резистор R4 введен для надежного закрывания транзистора. Резистор R3 — страховочный. Он служит для ограничения тока при коротком замыкании в цепи датчика. Для большей надежности можно поставить предохранитель в цепи датчика. Выбирайте предохранитель с минимально возможным значением по току.
Рис. 4.28. Схема электронного термометра
Индикатор HG1 включен точно таким же образом, как на схеме, приведенной рис. 2.8. Поэтому все программные процедуры, описанные в разделе 2.6, можно без изменений использовать в программе для термометра. Для управления режимами работы термометра в схему введена миниклавиатура, состоящая всего из трех кнопок (SI, S2 и S3). Схема включения кнопок аналогична схеме, приведенной на рис. 1.2. Установка добавочных резисторов для такой схемы необязательна. Их с успехом заменяют внутренние резисторы микроконтроллера.
Схема, приведенная на рис. 4.28, пригодна не только для измерения температуры. Ту же самую схему удобно применить для чтения 1D кодов любых микросхем, оснащенных 1-Wire интерфейсом.
Программная реализация 1-Wire интерфейса
209
Достаточно лишь заменить управляющую программу и термометр превратится в детектор кодов. Единственное отличие этих двух вариантов использования схемы состоит в том, что при чтении ID кодов все 1-Wire микросхемы нужно подключать по очереди. Подключение нескольких микросхем одновременно не допускается.
DD1
3
2 DS18B20	—
Рис. 4.29. Два варианта подключения датчиков
В режиме термометра, наоборот, к схеме можно подключать любое количество микросхем-термодатчиков. Однако мы ограничимся всего двумя. На рис. 4.29 приведены две схемы подключения датчиков. На рис. 4.29.0 приводится схема подключения одной микросхемы DS18B20 для определения ее ID кода. Термодатчик включен по схеме с внешним питанием. На схеме 4.29.6 показано подключение двух датчиков для измерения температуры. На этот раз термолатчики работают в режиме паразитного питания.
4.12.	Программная реализация 1-Wire интерфейса
Весь комплекс программ для реализации l-Wire протокола подразделяется на несколько разных уровней. К самому низкому уровню можно отнести элементарные процедуры формирования отдельных импульсов и временных интервалов (слотов) на шипе. Следующий уровень — это процедуры чтения и записи отдельного байта и отдельного бита информации. В данном разделе рассматриваются подпрограммы этих двух начальных уровней. Подпрограммы рас
210
Работа с шиной MicroLAN
считаны для работы со схемой, показанной на рис. 4.28. Пакет подпрограмм самого низкого уровня приведен на листинге 4.1.
Прежде, чем перейти к подробному описанию подпрограмм, рассмотрим некоторые общие особенности. Все операции низкого уровня (сигнал начального сброса, запись и чтение временного слота) предполагают формирование различных временных интервалов. Длительность этих интервалов для разных операций может составлять от 1 до 700 мкс. Из опыта реализации PC шины мы уже знаем, что такие относительно небольшие интервалы времени удобнее формировать программным путем. В простейшем случае микроконтроллер просто выполняет несколько пустых операций пор.
Как уже говорилось, команда пор не выполняет абсолютно никаких действий. В то же время, ее выполнение занимает один машинный цикл микроконтроллера. При тактовой частоте, равной 16 МГц, длительность машинного цикла будет чуть меньше одной микросекунды. А точнее эта величина равна 12/16 = 0,75 мкс. В микросхеме АТ89С2051 частота тактового генератора делится на 12. Для формирования небольших временных интервалов достаточно нескольких операторов пор, поставленных подряд друг за другом. Для более длительных интервалов применяется пустой цикл. Цикл просто выполняет несколько пустых операторов определенное число раз. В приведенных ниже подпрограммах широко используются оба способа формирования временных интервалов. В качестве счетчика цикла используется специальная ячейка памяти, обозначенная в программе, как LoopCnt. Строка программы, резервирующая ячейку с этим именем, выглядит следующим образом:
LoopCnr OS 1	Счетчик задержки
Эту строку нужно поместить в начале программы, среди других подобных операторов. Кроме того, для формирования временных интервалов специально создана небольшая подпрограмма, которая называется Dely. В листинге 4.1 она занимает строки 45...47. Как видно из текста подпрограммы, она представляет собой два оператора пор и завершается командой выхода из подпрограммы. Такая подпрограмма обеспечивает задержку, примерно равную 4,5 мкс. Подпрограмму Delay удобно использовать при формировании от
Программная реализация 1-Wire интерфейса
211
носительно больших задержек по времени, включая вызов этой подпрограммы в тело пустого цикла.
Еще два параметра, которые необходимо определить в начале программы — это две линии, составляющие l-Wire интерфейс:
tempIO	BIT	Р3.1	Линия 1-Wire порта
tempV	BIT	РЗО	Выход управления режимом питания
Теперь приступим к изучению отдельных подпрограмм нашего пакета. В листинге 4.1 приведены подпрограммы самого низкого уровня. Первая из этих подпрограмм называется resLAN. Она предназначена для формирования импульса начального сброса. Эта же подпрограмма производит проверку наличия сигнала присутствия на линии. Подпрограмма способна обнаруживать два вида ошибок: обрыв линии и короткое замыкание. В случае воз никновения ошибки подпрограмма возвращает код ошибки через аккумулятор.
Начинается подпрограмма resLAN с формирования импульса начального сброса (строки 1...5, листинг 4.1). Процесс формирования начинается с того, что программа «подсаживает» линию (строка 1). Затем формируется задержка длительностью 700 мкс (строки 2...4). После чего линия «отпускается» (строка 5). Для формирования задержки используется метод пустого цикла. Тело цикла занимает строки 3 и 4. В строке 2 параметру цикла присваивается начальное значение. В данном случае это значение равняется 116. Именно столько раз в цикле вызывается подпрограмма Dely.
После формирования импульса начального сброса программа приступает к проверке сигнала присутствия на линии. Для этого она формирует задержку в 65 мкс, а затем проверяет значение сигнала на линии. Если нет обрыва на линии и сигнал присутствия сформирован нормально, то именно в этот момент времени уровень сигнала на линии должен быть равен нулю. Задержка в 65 мкс формируется в строках 6...8. Программная конструкция, формирующая эту задержку — копия аналогичного фрагмента, формирующего в начале подпрограммы задержку в 700 мкс. Проверка состояния линии происходит в строке 9. Если уровень сигнала на линии tempIO равен нулю, то это значит, что ошибки не обнаружено. Управление передается по метке rst3 и строки 10, 11 не
212
Работа с шиной MicroLAN
выполняются. Если уровень сигнала на линии равен единице, то выполняются строки 10 и 11. В строке 10 в аккумулятор помещается код ошибки «обрыв на линии», а в строке И подпрограмма досрочно завершается.
Если все же произошел переход к метке rst3 (ошибка не обнаружена), подпрограмма формирует задержку в 500 мкс (строки 12.. 14) и снова проверяет уровень сигнала на линии (строки 15... 17). Задержка в 500 мкс необходима для правильного завершения процесса начального сброса (см. рис. 4.15). По истечении этого промежутка времени сигнал присутствия должен уже закончиться и уровень сигнала на линии должен быть равен единице. Если это не так, то это значит, что линия просто закорочена. В таком случае выполняются строки 16 и 17, где в аккумулятор записывается код ошибки 2 («короткое замыкание») и программа досрочно завершается. Если короткого замыкания не обнаружено, то управление передается по метке rst5 и подпрограмма завершается нормальным образом. В этом случае, перед завершением подпрограммы в аккумулятор помещается нулевой код (строка 18). Ноль — это код отсутствия ошибки.
Листинг 4.1
,тшштшшш#шшшимиишш8й
;И Набор подпрограмм низкого уровня н
для реализации 1-Wire протокола	ЦП
: «ояявйййявввйяййййвйййййяийййвйийоююююййя
Подпрограмма формирования сигнала начального сброса
1	resLAN:	clr	tempIO	'закорачиваем' линию tempIO
2		mov	LocpCnt,#1l6	Задержка 700 мкс
3	rst1	call	Delay	
4		djnz	LoopCnt.rstl	
5		setb	tempIO	'отпускаем'линию tempIO
6		mov	LoopCnt. #11	Задержка 65 мкс
7	rst2:	call	Delay	
8		djnz	L'jopCnt. rst2	
Программная реализация 1-Wire интерфейса
213
9	jnb	tempIO, rst3	, Проверка сигнала присутствия
10	mov	a.Bl	; Код ошибки «Нет датчика.
11	ret		
12	rst3:	mov	LoopCnt, #83	. Задержка 500 мкс
13	rst4:	call	Delay	
14	djnz	LoopCnt, rst4	
15	jb	tempIO, rst5	. Если на пинии 1 переход
16	mov	a #2	Код ошибки «КЗ В ЛИНИИ'
17	ret		
1В	rst5	mov	a #0	Код нормального завершения
19	ret		
Подпрограмма чтение слота
результат чтения (1 бит) возвращается через признак переноса
20	mrslot	clr	tempIO	. Заксрзтиго <«нию
21		nop		
22		nop		
23		setb	tempIO	Отпустить линию
24		mov	LoopCnt, #2	Задержка 13 мкс
25	ms!2	acall	Delay	
26		djnz	LoopCnt,bs!2	
27		mov	C.tempIO	Прочитать и сохранить бит
26		mov	LoopCnt.#16	. Задержка 60 мкс
29	msll:	acall	Delay	
30		djnz	LoopCnt,msll	
31		ret		
Подпрограмма записи О' в слот
32	mwlow:	clr	tempIO	Закоротить линию
33		mov	LoopCnt,#19	Задержка 80 мкс
34	mwlT	acall	Delay	
35		djnz	LoopCnt.niwH	
36		setb	tempIO	Отпустить линию
37		ret		
214
Работа с шиной MicroLAN
Подпрограмма записи Т в слот
38	mwhi’	clr	tempIO	Закоротить линию
39		acall	Delay	, Задержка 4.5 мкс
40		setb	tempIO	, Отпустить линию
41		mov	LoopCnt, В18	Задержка 75 мкс
42	лмМ	acall	Delay	
43		djnz	LoopCnt.mwhl	
44		ret		
Процедура задержки 4.5 мкс (при тактовой частоте 16 МГц)
45
46
47
Delay.
пор пор ret
Следующие три подпрограммы, представленные в листинге 4.1, предназначены для работы с временным слотом. Все они определяют длительность слота. При этом они выполняют чтение информации из слота или запись в слот информации. В графическом виде эти процессы показаны на рис. 4.14. Итак, рассмотрим работу всех этих трех подпрограмм по порядку.
Подпрограмма mrslot (чтение слота) служит для чтения одного бита информации из ведомого устройства. Подпрограмма возвращает прочитанный бит через CY (признак переноса). На рис. 4.14 этот процесс обозначен как «Чтение 0» и «Чтение 1». Текст подпрограммы mrslot приведен в строках 20...31 (листинг 4.1). Сначала подпрограмма формирует синхроимпульс. Для этого она «подсаживает» линию (строка 20), формирует задержку в 1 мкс (два оператора пор в строках 21, 22), а затем линию отпускает (строка 23). После окончания синхроимпульса формируется задержка в 13 мкс (строки 24...26) и считывается уровень сигнала на линии (строка 27). Прочитанный бит помешается в CY. Это и есть результат чтения слота. Однако на этом выполнение подпрограммы не завершается.
Прежде чем выйти из подпрограммы, необходимо закончить формирование длительности слота. Если вы помните, общая
Программная реализация 1-Wire интерфейса
215
длительность слота должна лежать в пределах 60... 120 мкс. Для попадания времени выполнения нашей подпрограммы в этот диапазон в строках 28...30 формируется задержка в 60 мкс. И лишь после этого подпрограмма завершается.
Две простенькие подпрограммы выполняют запись слота. Программа mwlow записывает в слот нулевое значение. В графическом виде эта операция представлена на рис. 4.14 под заголовком «Запись 0». Текст подпрограммы уместился всего в шесть строк (строки 32.. 37). Действие подпрограммы сводится к формированию в пределах слота отрицательного импульса длительностью 80 мкс.
Подпрограмма mwhi чуть сложнее. Она выполняет запись в слот единичного значения. На рис. 4.14 эта операция озаглавлена «Запись 1». Действие подпрограммы начинается с формирования синхроимпульса длительностью 4,5 мкс (строки 38...40). Для формирования такой длительности производится однократное обращение к подпрограмме Delay. После завершения синхроимпульса формируется задержка 75 мкс. Эта задержка доводит длительность слота до стандартной величины.
Описанный выше набор подпрограмм низкого уровня никогда нс используется самостоятельно. Эти простые подпрограммы предназначены для совместного использования с подпрограммами более высокого уровня. На этом уровне работа ведется с отдельными битами и байтами. Пакет подпрограмм следующего уровня приведен на листинге 4.2. Этот пакет включает в себя четыре подпрограммы. Первая из этих подпрограмм называется wr8LAN. Подпрограмма выполняет операцию записи байта в ведомое устройство. Байт, предназначенный для записи, передается в подпрограмму через аккумулятор. Текст подпрограммы занимает строки 1...11 (см. листинг 4.2).
Сразу обращаю ваше внимание на то, что строки 2 и 10 «закомментированы». То есть в начале каждой из этих строк стоит знак «точка с запятой». Весь текст после символа «точка с запятой» превращается в комментарий. В результате при трансляции программы эти строки будут пропущены. Их как бы не существует. Такой прием часто используется в программировании для того, чтобы временно отключать некоторые строки программы. Причем при таком способе «удаления» строк их можно в любой момент снова включить. «Закомментирование» применяется в том случае, когда нужно создать гибкую программу, которую легко адапти
216
Работа с шиной MicroLAN
ровать для разных случаев. В нашем случае закомментированные строки — это команды отключения и последующего включения режима прерываний. Две закомментированные строки нужно включить в текст программы (убрать символ «;») если в вашей системе используется механизм прерываний и не включать, если прерываний вы не используете. Подробнее о том, зачем это делается, я расскажу в конце этого раздела. А сейчас рассмотрим основной текст подпрограммы wr8LAN.
Основной текст подпрограммы занимает строки 3 9. Подпрограмма выводит содержимое байта, полученного через аккумулятор, бит за битом в режиме записи. Именно поэтому описываемая подпрограмма представляет собой, по сути, цикл для передачи битов. Тело цикла занимает строки 4 .9. Регистр г1 используется в качестве параметра цикла. В строке 3 ему присваивается начальное значение. Начальное значение равно восьми (по числу битов в байте). Выполнение цикла начинается с команды извлечения очередного бита (строка 4). Для этого содержимое аккумулятора сдвигается вправо при помощи команды ггс. Действие этой команды приводит к тому, что очередной бит оказывается в ячейке признака переноса CY.
Затем программа оценивает значение этого бита (строка 5). Если он равен единице, вызывается подпрограмма записи единицы в слот mwhi (строка 8). В противном случае вызывается подпрограмма mwlow для записи в слот нуля (строка 6). После выполнения одной из этих программ управление передается по метке wb3 (строка 9). В этой строке находится команда организации цикла. Она передает управление на начало цикла, если это не последний бит, и завершает цикл, если бит последний.
Подпрограмма wrILAN предназначена для передачи по шине одного бита в режиме записи. Эта подпрограмма очень похожа на wr8LAN. Отличие только в отсутствии цикла. Текст подпрограммы занимает строки 12.. 20. Строки 13 и 19 закомментированы. Их назначение такое же, как и в предыдущем случае Бит информации, предназначенный для передачи по шине 1-Wire, передается в подпрограмму через ячейку CY. В строке 14 оценивается значение бита, переданного подпрограмме через CY. В зависимости от значения этого бита выполняется либо подпрограмма mwhi (строка 17), либо mwlow (строка 15).
Программная реализация 1-Wire интерфейса
217
Листинг 4.2
,t>t>	Пакет подпрограмм для работы	М
;М	с интерфейсом 1-Wire	й#
йй«ййй«ййй»йЯЯ»ЙИЙ1»ВМйЯй1»йййй»й11ПЯЯ»##йийй»Я#П»Я»аИЙЯ
Подпрограмма записи байта
1	wr8LAN:			
2		clr	EA	Запрет прерывания
3		mov	R1,»8	, Инициализация счетчика разрядов
4	wb1	г ГС	A	 Младший бит в с'
5		Jc	wb2	Если текущий бит = 0
6		call	mwlow	запись 0 в слот
7		jmp	wb3	
8	wb2:	call	mwhi	запись 1 в слот
9	wb3:	djnz	R1,wb1	, Продолжать если не последний
10		setb	EA	, Разрешение прерывания
11		ret		
Подпрограмма записи бита
12	wrILAN			
13		clr	EA	, Запрет прерывания
14		jc	wb4	. Если бит - 0
15		call	mwlow	, запись 0 в спот
16		jmp	wb5	; Разрешение прерывания
17	wb4	call	mwhi	запись 1 в слот
18	wb5.			
19		setb	EA	Разрешение прерывания
20		ret		
Подпрограмма чтения байта
21	rd8LAN			
22		clr	ЕА	. Запрет прерывания
23		mov	R1.B8	Счетчик количества битов
24	гЫ:	call	mrslot	Чтение очередного бита
25		ггс	А	Сдвиг битов младшим разрядом вперед
218
Работа с шиной MicroLAN
djnz setb ret
R1 rb1
EA
Продолжать, если не последний Разрешение прерывания
Подпрограмма чтения бита
29
30
31
32
33
rdlLAN:
clr	EA
call	mrslot
setb	EA
ret
Запрет прерывания
; Разрешение прерывания
Подпрограмма rd8LAN предназначена для чтения одного байта по шине 1-Wire. Текст подпрограммы занимает строки 21...28 (см. листинг 4.2). Программа возвращает прочитанный байт в аккумулятор. И в этой подпрограмме имеются закомментированные строки (22 и 27). Основная же часть подпрограммы — это цикл ввода битов. Тело цикла занимает строки 24...26. В качестве параметра цикла используется регистр г1. В строке 23 ему присваивается начальное значение Первая команда, выполняемая в теле цикла — вызов подпрограммы чтения слота (строка 24). Она помещает прочитанный бит в ячейку CY Затем бит помещается в аккумулятор методом сдвига (строка 25) Сдвиг производится при помощи команды rrc После каждого такого сдвига в аккумулятор «вдвигается» очередной прочитанный бит После восьми циклов сдвига аккумулятор будет содержать полноценный прочитанный байт. Оператор djnz (строка 26) служит для организации всего этого цикла.
Подпрограмма rdlLAN предназначена для чтения одного бита из линии 1-Wire. Это самая простая подпрограмма из всего пакета. Все, что она делает — вызывает подпрограмму чтения слота mrslot (строка 31). Кроме этого, она содержит еще две закомментированные строки (30 и 32).
В заключение мне осталось только рассказать, зачем нужны закомментированные строки и когда нужно их «включать», убирая символ комментария «;». Как вы могли заметить, эти строки стоят в начале и в конце каждой из четырех подпрограмм, приведенных в листинге 4.2. Если все эти строки «раскомментировать», то строка в начале каждой подпрограммы отключит систему прерываний, а строка в конце подпрограммы включит ее вновь Отключение и
Чтение кода ПЗУ микросхемы DS18B20
219
включение системы прерываний производится при помощи регистра маски прерываний IE. Каждый из разрядов этого регистра может включать и выключать один из источников прерываний микроконтроллера АТ89С2051. Старший бит этого регистра включает и выключает сразу всю систему прерываний. Этот бит имеет свое специальное обозначение — ЕА.
Для чего же отключать прерывания? Прерывания отключаются для того, чтобы они не мешали при формировании временных интервалов. Временные интервалы в наших подпрограммах формируются программным путем Поэтому любая задержка определяется количеством пустых операций, выполняемых специально для этой цели. Однако, если не запретить работу системы прерываний, то процедура обработки одного из запросов может легко «вклиниться» в цикл формирования задержки. При этом время задержки резко увеличится и работа 1-Wire протокола нарушится. Если вы решили использовать в своем устройстве 1 -Wire интерфейс, но не собираетесь использовать систему прерываний, то закомментированные строки нужно оставить закомментированными. Если наряду с 1-Wire протоколом в своем устройстве вы будете использовать прерывания, то признак комментария во всех этих строках нужно убрать. Подробнее о системе прерываний можно прочитать в [1].
4.13.	Чтение кода ПЗУ микросхемы DS18B20
Итак, мы имеем все необходимые подпрограммы для работы с 1-Wire интерфейсом. Пора переходить к практике их применения. Удобнее всего начинать с примера выполнения команды «Чтение ПЗУ». Тем более, что такая команда нам понадобится в первую очередь. Для того, чтобы наша программа могла обращаться к любому из двух подключенных к шине датчиков температуры, нам нужно сначала узнать ID коды каждого из них. Для этой цели и была создана специальная подпрограмма kodROM. Ее текст приведен в листинге 4.3 Подпрограмма рассчитана на работу с каждым датчиком по отдельности. Датчики должны подключаться к 1-Wire шине по схеме, изображенной на рис. 4.29.а. Подпрограмма kodROM читает из микросхемы-датчика 64-разрядный ID код и
220
Работа с шиной MicroLAN
помещает его в специальный буфер. Место для этого буфера нужно зарезервировать в ОЗУ микроконтроллера в начале текста основной программы. Ниже приведена строка программы, резервирующая восемь байт для буфера. Для обращения к этому буферу программа использует метку bufLAN.
bufLAN. OS 8	Буффер для приема данных из MicroLAN
Подпрограмма kodROM широко использует описанные ранее низкоуровневые процедуры (см. листинг 4.2). Кроме того, для индикации ошибок подпрограмма обращается к процедуре ргЕгг, описанной в главе 2 (см. листинг 2.4). Текст подпрограммы состоит всего из 16 строк (см. листинг 4.3). Начинается программа с сохранения регистра psw и включения второго банка РОН (строки 1, 2). Затем выполняется процедура начального сброса (строка 3). После ее завершения проверяется содержимое аккумулятора на наличие кода ошибки (строка 4). Если процедура начального сброса обнаружила ошибку на линии, то содержимое аккумулятора не будет равно нулю. В таком случае управление передается по метке кгЗ, где происходит вызов подпрограммы индикации ошибки. Код ошибки, который находится в аккумуляторе, автоматически передается в процедуру ргЕгг и высвечивается на экране индикатора.
Если в процессе начального сброса ошибок не обнаружено, то управление переходит к строке 5. В строках 5 и 6 происходит передача на линию команды «Чтение ПЗУ». Сначала код команды (ЗЗН) записывается в аккумулятор (строка 5), а затем он передается на линию при помощи подпрограммы wr8LAN (строка 6). Сразу после этого начинается цикл чтения байтов ID кода. Тело цикла составляют строки 9... 12. Регистр г2 используется в качестве параметра цикла, а регистр гО — в качестве указателя буфера.
В строках 7, 8 этим двум переменным присваиваются начальные значения. Выполнение цикла начинается с команды чтения очередного байта (строка 9). В строке 10 прочитанное значение записывается в буфер. При записи используется регистр гО в режиме косвенной адресации. В строке 11 содержимое гО увеличивается на единицу. В результате очередной прочитанный байт будет записан в свою ячейку буфера. Завершается цикл оператором djnz (строка 12), который обеспечивает нужное число проходов (восемь). После того как приняты все восемь байтов, цикл прекращается.
Чтение кода ПЗУ микросхемы DS18B20
221
И после восстановления регистра psw (строка I3) подпрограмма kodROM завершается.
Листинг 4 3
,М	Чтение кода ПЗУ в буфер	ПК
1 2	kodROM:	push mov	psw psw,Bbank2	Выбор банка 2 памяти
3	kr1:	call	reslAN	Сброс
4		cjne	а.ИО.кгЗ	Еспи ошибка
5		mov	a S33H	Команда «Чтение ПЗУ-
6		call	wr81AN	Передаем команду
7		mov	r0, «bufLAN	Инициализация цикла чтения да-ных
8		mov	r2 «8	
9	kr2:	call	rd8LAN	Чтение очередного байта
10		mov	@rO,a	Запись его в буфер
11		inc	r0	Увеличение указателя буфера
12		djnz	r2,kr2	Оператор цикла
13		pop	psw	
14		ret		
15	кгЗ:	call	ргЕгг	Печать кода ошибки
16		jmp	kr1	
Итак, мы научились читать ID код любой микросхемы и записывать его в память микроконтроллера. Теперь нужно показать этот код на экране ЖКИ. Иначе как же мы его увидим? В главе 2 был описан пакет подпрограмм для вывода информации на ЖКИ индикатор. Однако этот пакет нам не совсем подходит. Дело в том, что восемь байтов ID кода удобнее всего выводить на индикатор в шестнадцатеричном виде. В пакете подпрограмм, описанном в разделе 2.6, отсутствует процедура вывода числа в шестнадцатеричном виде. Сейчас мы восполним этот пробел.
Текст такой подпрограммы приведен в листинге 4.4. Она называется prhex. Код, предназначенный для вывода на экран в шестнадцатеричном виде, передается в подпрограмму через аккумулятор Для преобразования переданного кода в шестнадцатеричный вид, его сначала нужно разделить на две тетрады, а затем вывести на индикатор каждую из них в виде соответствующего символа.
222
Работа с шиной MicroLAN
В результате, шестнадцатеричное значение байта займет на экране два разряда.
Программа prhex использует банк регистров номер 3. Если опустить команду выбора банка, а также команды сохранения и восстановления регистров, то текст основной части подпрограммы занимает строки 3...9. Перед тем как начинать процесс отделения старшей тетрады, содержимое аккумулятора сохраняется в регистре г7 (строка 3). Это содержимое нам еще понадобится для нахождения младшей тетрады. Старшая тетрада находится методом наложения маски. Сначала обе тетрады меняются местами (команда swap в строке 4). Затем, в строке 5 накладывается маска. Код маски 0FH. В результате мы получаем число, у которого четыре старших разряда равны нулю, а четыре младших разряда соответствуют старшей тетраде исходного кода. В строке 6 символ, соответствующий старшей тетраде, выводится на экран.
Следующий этап — вывод младшей тетрады. Для ее вычисления исходный код, временно хранящийся в регистре г7, снова помещается в аккумулятор (строка 7). В строке 8 на исходный код накладывается маска. В строке 9 полученное таким образом значение младшей тетрады выводится на экран.
Результат действия подпрограммы prhex — два символа на экране индикатора. Причем каждый из этих двух символов может принимать значение от «О» до «F». А вместе они представляют собой шестнадцатеричное представление выводимого байта.
Листинг 4.4
		Вывод	байта в HEX виде	
1	prhex:	push	psw	 Сохранение регистра psw
2		mov	psw, ii ЬапкЗ	Включаем банк 3
3		mov	r7,a	Сохраняем копию байта
4		swap	a	
5		anl	а, КОЕН	Выделение старшего полубайта
6		call	prehr	Вывод его на экран
I		mov	a.r7	Восстановление байта
8		anl	a.KOFH	Выделение младшего полубайта
9		call	prehr	. Вывод его на экран
Чтение кода ПЗУ микросхемы DS18B20
223
pop psw
Восстанавливаем psw
Подпрограмма ввода с клавиатуры
12
13
14
15
16
17
18
19
20
inkl:
setb	k!1
setb	k!2
setb	k!3
mov	a,p3
rr	a
rr	a
anl	a,#000001116
xrl	а.йОООООШВ
Установка 1 на линиях клавиатуры
Считывание порта рЗ
Обнуление лишних разрядов Инвергирование
Теперь нам нужно создать программу, которая бы выводила на индикатор все восемь байт ID кода из буфера. Однако каждый байт займет два разряда индикатора. Для вывода 8 байтов нам потребуется I6 разрядов. Но индикатор МТ-10Т7-7 имеет всего 10 разрядов. Поэтому за один раз вывести все восемь байт кода невозможно. Придется выводить ID код в два приема. Сначала первые четыре байта, а затем оставшиеся четыре. И тут нам придется использовать клавиатуру. Нам понадобится всего одна клавиша. Нажимая эту клавишу, мы будем переключать режим вывода
Для обслуживания простейшей трехкнопочной клавиатуры (см. рис. 4.28) была разработана специальная упрощенная подпрограмма inkl (см. листинг 4.4). Подпрограмма опрашивает все три кнопки и возвращает в аккумуляторе код состояния клавиатуры. Если ни одна кнопка не нажата, подпрограмма возвращает код, равный нулю. Каждая нажатая кнопка устанавливает в единицу один из трех младших битов в возвращаемом коде. Нулевой бит отвечает за состояние кнопки S3. Бит номер один — за состояние S2, а бит номер два — за кнопку S1. Для своей работы подпрограмма inkl использует три новых константы Определение этих констант в начале программы должно выглядеть следующим образом:
k!1	BIT	Р3.2	Клавиша 1
kl2	BIT	РЗ.З	Клавиша 2
k!3	BIT Р3.4	, Клавин#1. 3
224
Работа с шиной MicroLAN
Текст подпрограммы ink! занимает строки 12...20. Программа начинается с перевода всех трех линий, к которым подключена клавиатура в единичное состояние (строки 12...14). Таким образом, все три линии получают возможность работать на ввод информации. Затем производится чтение сигнала с клавиатуры. Для этого сначала содержимое порта рЗ помещается в аккумулятор (строка 15). Затем код сдвигается вправо на два разряда (строки 16, 17). Таким образом, информация, отражающая состояние кнопок, окажется в трех младших битах аккумулятора.
Следующий этап — наложение маски (строка 18). После этой операции обнуляются все биты, кроме трех младших, и в аккумуляторе останется лишь информация о состоянии клавиатуры. Но она будет иметь неудобное для нас значение. Если все три кнопки отпущены, код окажется равным 00000111В. Для того, чтобы привести этот код к удобному виду, программа инвертирует три младших разряда аккумулятора (строка 19). Для инвертирования используется операция «Исключающее ИЛИ». Подробнее о логических функциях вы можете узнать из [1].
После инвертирования в аккумуляторе полностью сформируется код состояния клавиатуры. В строке 20 подпрограмма ink! завершается.
Листинг 4.5
,## Подпрограмма чтения и вывода на экран m
ПЗУ микросхемы DS18B2O	ИН
.шшшшшшштшштшшшмш
1		call	eclr	Стирание экрана
2	ini:	call	kodROM	, Чтение ПЗУ в буфер
3		call	inkl	; Ввод состояния клавиатуры
4		cjne	a,#100B,in2	; Проверка кода состояния клавиатуры
5		mov	r1,BbufLAN+4	, Если нажата S1 выводим первые 4 байта
6		mov	а.вОВН	; Выводим символ «Ь»
7		jmp	in3	
8	in2:	mov	r1, sbufLAN	 Выводим последние 4 байта
9		mov	а.йОАН	; Выводим символ «А»
10	1пЗ:	call	prchr	
11		mov	a.«18	; Вывод тире
12		call	prchr	
13		mov	г0,й4	; Цикл вывода байтов
14	in4:	mov	a.@r1	
15		call	prHEX	; Вывод очередного байта
Чтение кода ПЗУ микросхемы DS18B20	225
16	inc	r1	Увеличение указателя буфера на 1
17	djnz	r0,in4	
18	mov	a, HO	; Установка курсора в начальную позицию
19	call	ecur	
20	jmp	in1	
Итак, все вспомогательные подпрограммы получены. Теперь можно приступать к созданию программы, которая будет читать ID код из микросхемы термодатчика и выводить его на индикатор в шестнадцатеричном виде. Текст такой программы приведен в листинге 4.5. Перед тем как вывести что-либо на экран, подпрограмма проверяет состояние клавиатуры и выясняет, нажата ли кнопка S1. Если кнопка не нажата, то подпрограмма выводит на экран первые четыре байта из буфера bufLAN в шестнадцатеричном виде. Если кнопка S1 нажата, то выводятся последние четыре байта. Кроме этого, на экран выводится код режима Режимы обозначаются буквами «А» или «Ь». Пример изображения, которое вы увидите на экране, приведен на рис. 4.30. В примере показано, как будет выглядеть на экране код 28В8564В000000С5Н. На рис. 4.30.а показан режим, когда кнопка S1 не нажата, а на рис. 4.30.6 — кнопка S1 нажата.
а)
Рис. 4.30. Отображение ID кода на индикаторе
б)
Рассмотрим подробнее текст подпрограммы. В первой строке подпрограммы вызывается процедура eclr, которая очищает экран индикатора. Процедура eclr, как и другие процедуры для работы с ЖКИ модулем, были описаны в разделе 2.6 (см. листинг 2.3). После того как экран будет очищен, вызывается подпрограмма
8 Зак. 922
226
Работа с шиной MicroLAN
kodROM (строка 2), которая читает все восемь байт ID кода и помещает их в буфер bufLAN. Далее, начинается процесс вывода полученного кода на экран. Для начала проверяется состояние клавиатуры (строки 3 и 4). Сначала вызывается подпрограмма inkl. Код, возвращенный подпрограммой inkl, оценивается в строке 4. Если кнопка S1 нажата, то этот код должен быть равен 100В. По результатам оценки выполняются либо строки 5, 6 (режим «Ь»), либо строки 8, 9 (режим «А»), И та, и другая пара строк делает одно и то же — подготавливает информацию для вывода на экран. Подготовка состоит в том, что в аккумулятор помещается код режима, а в регистр Н помещается адрес той ячейки буфера, с которой будет начинаться вывод четырех байтов ID кода.
После выполнения подготовительных операций управление переходит к строке 10. Здесь вызывается подпрограмма prchr, которая выводит на индикатор код режима, который к тому времени уже находится в аккумуляторе. Далее, в строках И и 12 на индикатор выводится тире. Код символа «тире» равен 18 (см. табл. 2.4). В строках 13 ..17 организован цикл вывода четырех байтов ID кода. Адрес первого байта уже записан в регистр г1. В качестве параметра цикла используется регистр гО. В строке 13 ему присваивается начальное значение. Тело цикла занимает строки 14 ..17. В строке 14 значение очередного байта извлекается из буфера и помещается в аккумулятор. В строке 15 это значение выводится на экран в шестнадцатеричном виде. В строке 16 значение указателя буфера увеличивается на единицу. Завершает тело цикла оператор djnz (строка 17).
После того как на экран будут выведены все четыре байта, цикл завершается. Программа переходит к своей последней стадии. Она устанавливает курсор в начальную позицию (строки 18 и 19). А затем управление передается в самое начало (по метке in1). После этого весь процесс чтения и вывода кода на индикатор повторяется снова. Программа так и работает, непрерывно выполняя все эти операции, все время, пока включено питание. Не выполняется только строка I (операция очистки экрана). Она заменена командами установки курсора (строки 18, 19). Это сделано не случайно. Если включить программу очистки экрана в большой цикл программы, то мы ничего не увидим на экране. Время выполнения процедуры codROM намного больше, чем время выполнения всех операций с ЖКИ дисплеем вместе взятых. Поэтому, если каждый раз в начале большого цикла программы будет очищаться экран,
Подпрограмма чтения температуры	227
то пока не завершится выполнение подпрограммы codROM, он так и будет оставаться чистым. А изображение будет появляться на короткое мгновение. Поэтому оно будет казаться очень блеклым. Причем настолько, что его можно и не разглядеть.
В случае, если при считывании ID кода подпрограмма codROM обнаружит ошибку, то управление перейдет к подпрограмме ргЕгг Программа ргЕгг описана в разделе 2.6 (см. листинг 2 4). Код ошибки высветится на экране. Как это выглядит, показано на рис. 4.31.
Рис. 4.31. Отображение на индикаторе кода ошибки
4.14.	Подпрограмма чтения температуры
Итак, мы научились читать ID код. Пора приступать к чтению температуры. Задача чтения температуры подразделяется на два этапа: запуск процесса преобразования температуры в код и считывание полученных значений из соответствующего регистра микросхемы DS18B20. Для каждого из этапов мы создадим свою специальную подпрограмму. Подпрограмма, которая будет выдавать команду запуска на преобразование, должна автоматически определять режим питания микросхемы и в зависимости от этого корректировать алгоритм своей работы
Все описанные в данном разделе подпрограммы рассчитаны на работу со схемой, изображенной на рис. 4.28. При этом к схеме
228
Работа с шиной MicroLAN
должно быть подключено два термодатчика. Схема подключения термодатчиков приведена на рис. 4.29.6. Тексты обеих подпрограмм, обеспечивающих процесс измерения температуры, приведен в листинге 4.6. Эти подпрограммы, так же как и любые другие, требуют определения различных констант и переменных. Часть определений нам уже знакомо и использовалось ранее. Другие определения вводятся впервые.
В листинге 4.6 приведен текст начальной части основной программы, где приведены все определения, необходимые для работы электронного термометра (см. рис. 4.28). Сюда включены определения не только для подпрограмм чтения температуры, но и для подпрограмм, которые будут выводить полученный результат на индикатор. Эти подпрограммы мы будем рассматривать в следующем разделе.
Листинг 4.6
1	$mod2051			
2	SNOPAGING			
	.			— Определение констант	
3	bankO	EQU	OOOOOOOOB	Кош банков памяти
4	bankl	EQU	00001000В	
5	bank2	EQU	00010000В	
6	ЬапкЗ	EQU	00011000В	
7	АО	BIT	Р1.6	Адрес/Данные
8	WR1	BIT	Р1.4	Выбор индикатора
9	tempIO	BIT	РЗ 1	; 1-Wlre порт
10	teiapV	BIT	РЗ.О	; Порт управления режимом питания 1-Wire
11	кН	BIT	РЗ 2	Клавиша 1
12	k!2	BIT	РЗ.З	. Клавиша 2
13	k!3	BIT	Р3.4	: Клавиша 3
	—		Резервирование	ячеек
14		BSEG	АТ 0	
15	fpit:	OBIT	1	, Флаг вида питания датчиков
16		DSEG		
17		ORG	ЗОН	
18	LoopCnt:	PS	1	: Счетчик задержки
19	bufLAN:	PS	8	Буфер для приема данных из NicroLAN
20		ORG	60Н	 начало стека
21	stack:	PS	20Н	глубина стека
	.			Переопределение	векторов прерываний
22		CSEG		
23		ORG	0000Н	; к процедуре инициализации
Подпрограмма чтения температуры
229
24	jmp	main	после включения/сброса
25	ORG	0003H	переопределение вектора
26	reti		внешнего прерывания 0
27	ORG	OOOBH	переопределение вектора
28	reti		прерывания по таймеру 0
29	ORG	0013H	переопределение вектора
30	reti		внешнего прерывания 1
31	ORG	001BH	переопределение вектора
32	reti		прерывания по таймеру 1
33	ORG	OO23H	вектор прерывания по
34	reti		, последовательному канапу
Кратко пройдемся по листингу 4.6. Строки 1 и 2 — это системные команды. Команда $mod2051 служит для подсоединения библиотеки стандартных определений для микропроцессора АТ89С2051. Подробнее об этом смотрите в [I]. Строка 2 — это команда транслятору, чтобы он не разбивал листинг, генерируемый при трансляции на страницы. Если для вас это не существенно, исключите эту строку из программы. В строках 3...6 происходит определение констант для переключения банков РОН. Далее, в строках 7...I3 определяется имя для каждой из линий порта рЗ микроконтроллера. Имя дано в соответствии с выполняемой функцией. Выходы АО и WR1 служат для управления режимами работы ЖКИ модуля. Выводы tempIO и tempV — это два вывода, которые используются для реализации l-Wire интерфейса. Выводы кН, к!2, к!3 — это три входа от клавиатуры. Каждый вход соответствует своей клавише. Все эти определения нам уже знакомы и повторяются тут лишь для того, чтобы вы могли увидеть полный текст определений, необходимых именно для этой программы.
В строках 14...21 происходит резервирование памяти. В строке 15 резервируется один бит в битовом пространстве памяти микроконтроллера. Эта ячейка будет использоваться для хранения режима питания микросхем-термодатчиков. Если используется паразитное питание, в эту ячейку запишется нулевое значение. При внешнем питании в ячейке будет единица.
В строке 18 резервируется одна ячейка под счетчик LoopCnt. Этот счетчик, как вы помните, используется при формировании временных интервалов. В строке 19 резервируются восемь ячеек под буфер bufLAN. А в строках 20, 21 определяются параметры стека.
230
Работа с шиной MicroLAN
Заканчивается листинг 4.6 строками, в которых переопределяются векторы прерываний (строки 22...34).
Теперь обратимся к листингу 4.7. Он содержит текст двух подпрограмм для измерения температуры. Первая из них называется sttmp. Она предназначена для передачи по шине команды «Запуск процесса преобразования». 'Запуск процесса преобразования производится одновременно в обеих микросхемах термодатчиков. Для этого, в качестве команды сетевого уровня, используется команда «Пропустить ПЗУ». Применение этой команды ведет к тому, что подпрограмма sttmp без всяких изменений может работать с любым количеством термодатчиков. Сколько бы датчиков не было, все они запустятся в режим преобразования.
Листинг 4.7
	x*«Aw*ft*********«**i>***	00,000 0	*0***t,*»*»0*to
	Запуск процесса	измерения температуры **	
	***********************	*************	*»»**»o***o*»»*t
1	sttmp:	push	psw	
2	mov	psw,#bank2	Выбор банка 2 памяти
			— Запрос режима питания
3	stm1:	call	resLAN	 Сброс
4	cjne	a,#0,stm6	Если ошибка переход
5	mov	a. HOOCH	Пропустить ПЗУ
6	call	wr8LAN	
7	mov	3.B0B4H	Проверка вида питания
8	call	wr8LAN	
9	call	rdlLAN	Считывание ответа
10	mov	fpit.c	Установка флага
	===================		— Запуск процесса преобразования
11	call	resLAN	; Сброс
12	cjne	a,#0,stm6	Если ошибка переход
13	mov	a,#OCCH	Пропустить ПЗУ
14	call	wr8LAN	
15	mov	a.#44H	Запуск преобразования
16	call	wr8LAN	
17	jb	fpit,stm4	Выбор варианта ожидания
		 Ожидание в режиме		питания по пинии
18	setb	tempIO	«Отпустить» линию 1-Wire
19	clr	tempV	, Включить питание на пинию
20	mov	r0,#255	, Далее цикл ожидания
21	stm2:	mov	LoopCnt.#255	
22	stm3:	call	Delay	
23	call	Delay	
Подпрограмма чтения температуры
231
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
call Delay
	djnz djnz setb jmp	LoopCnt stm3 r0,stm2 teropV stm5
		 Ожидание	в режиме внешнего питания
stm4:	call jnc	rdlLAN	Запрос об окончании преобразования stm4	Если не готово/ повторить
sttri5:	pop ret	psw	Выход из подпрограммы
stm6:	call jmp	ргЕгг	Если ошибка, печать stm1	Перейти в начало
;**	Чтение температуры		* *
************	***********	***********************	*********
, Входные параметры		acc - номер канала	
Выходные	параметры	- температура	
	в bufLAN - младший байт		
	в bufLAN+1 - старший байт		
rdtmp:	push	psw	
	mov	psw,#bank2	; Выбор банка 2 памяти
rtm1:	mov	Ь,й8	: Вычисление смещения
	mul	ab	; для адреса ПЗУ
	mov	r7,a	; Временно сохранить в г7
			 Начальный сброс	
	call	resLAN	; Вызов процедуры сброса
	cjne	a,#0,rtni2	. Еспи ошибка
			 Выбор ПЗУ	
	mov	а, #55Н	, Выдать команду
	call	wr8LAN	
	mov	Ь,г7	, Восстановить смещение
	mov	DPTR.Bpzu	Начальный адрес кодов ПЗУ
	mov	г6,й8	Счетчик байтов
szul:	mov	а,Ь	Текущее смещение
	move	a,@a+DPTR	Извлечь очередной байт
	call	wr8LAN	Выдать на линию
	inc	b	Увеличить смещение на 1
	djnz	r6,szu1	Продолжить цикл, если не последний
			 Чтение ОЗУ (только регистр температуры)	
	mov	а, «ОВЕН	Выдать команду
	call	wr8LAN	
	call	rd8LAN	Чтение младшего байта
	mov	bufLAN, а	Запись в буфер
232
Работа с шиной MicroLAN
56		call	rd8LAN	Чтение старшего байта
57		mov	bufLAN+1.a	Запись в буфер
58		pop	psw	Завершение подпрограммы
59		ret		
60	rtm2:	call	ргЕгг	Если ошибка вывести ее на экран
61		jmp	rtm1	Перейти в начало
62	pzu.			
63	pzuO.	DB	28H,0B8H.56H,4BH 0.0.0.0C5H	Коды ПЗУ датчиков
64	pzut	DB	28H,6FH,5CH,4BH,0,0,0.39H	
Текст подпрограммы занимает строки 1...34. Подпрограмма использует банк номер 2. Сохранение в стеке регистра psw и переключение банков происходит в строках I и 2. Основной текст подпрограммы sttmp подразделяется на две части. Первая часть (строки 3...10) выполняет запрос режима питания термодатчиков. Вторая часть (строки И...30) реализует команду запуска режима преобразования.
Запрос режима питания начинается с процедуры начального сброса (строка 3). В строке 4 происходит обработка ошибки, которая может быть обнаружена подпрограммой resLAN. Затем в линию выдается команда сетевого уровня «Пропустить ПЗУ» (строки 5, 6). Код этой команды ОССИ. После команды сетевого уровня следует команда транспортного уровня «Чтение режима питания» с кодом 0В4Н (строки 7, 8). В строке 9 производится чтение одного бита информации. Этот бит выдают все микросхемы, получившие команду запроса. Если микросхемы находятся в режиме паразитного питания, они выдают нулевой бит. В режиме внешнего питания — единичный. В строке 10 полученная информация записывается в ячейку fpit.
Далее, подпрограмма переходит к формированию следующей команды. Процесс снова начинается с процедуры начального сброса (строка 11). Снова контролируется код ошибки (строка 12). Затем формируется команда сетевого уровня «Пропустить ПЗУ» (строки 13, 14). Команда транспортного уровня («Запуск процесса преобразования») формируется в строках 15, 16. Ее код 044Н. Получив эту команду, все термодатчики переходят в режим преобразования температуры, а программа переходит в режим ожидания. Алгоритм работы в этом режиме зависит от используемого режима питания. Поэтому в строке 17 анализируется значение флага fpit. И в зависимости от его значения выбирается один из способов обработки
Подпрограмма чтения температуры
233
этого режима. Если используется паразитное питание (значение fpit равно нулю), то выполняется фрагмент программы, занимающий строки 18...28. Если используется режим внешнего питания и значение флага fpit равно единице, то управление передается по метке stm4 и выполняются строки 29, 30. Заканчивается подпрограмма в обоих случаях строками 31, 32.
Рассмотрим оба режима отработки периода ожидания по порядку. В случае паразитного питания перед началом режима ожидания программа должна открыть ключ VT1 (см. рис. 4.28), чтобы подать полноценное питание на линию данных. Но прежде чем открыть этот ключ, в строке 18 в линию tempIO записывается единица. Это предохранительная мера. Если одновременно открыть ключ VT1 и перевести линию tempIO (р3.1) в нулевое состояние, то произойдет короткое замыкание через открытый транзистор VT1 и выходной транзистор линии р3.1. А это может привести к выходу из строя микроконтроллера. Команда в строке 18 дает дополнительную гарантию от такого исхода событий. Открывание ключа производится при помощи команды clr tempV в строке 19.
В строках 20...26 формируется задержка по времени длительностью 750 мс. Это максимальное время, которое может занимать процесс преобразования. Используемые ранее программные методы формирования временных интервалов в данном случае не подходят. Такое большое значение времени задержки можно реализовать только в том случае, если применить для ее формирования два вложенных цикла. Первый цикл в качестве параметра использует регистр гО. В строке 20 ему присваивается начальное значение. Оператор, организующий этот цикл, расположен в строке 26. Внутри этого первого цикла находится второй. В качестве параметра он использует ячейку LoopCnt. В строке 21 и этому параметру присваивается начальное значение. Обратите внимание, что для каждого из двух вложенных циклов выбрано максимально возможное количество проходов — 255. Оператор djnz для внутреннего цикла находится в строке 25. В теле внутреннего цикла три раза вызывается подпрограмма Dely. Так как каждая программа Dely дает задержку в 4,5 мкс, общая задержка одного прохода внутреннего цикла будет равна 4,5 х 3 = 13,5 мкс. Общая же задержка будет равна 13,5 * 255 * 255 = 877837,5 мкс.
После окончания процесса формирования задержки ключ VT1 закрывается. Команда, закрывающая ключ, находится в строке 27.
234
Работа с шиной MicroLAN
В случае применения внешнего питания процедура ожидания занимает всего две строки. Это строки 29 и 30 программы. Эти две строки реализуют цикл ожидания сигнала готовности. Сигнал готовности формируют микросхемы термодатчики в момент, когда они закончат процесс преобразования температуры в код. В строке 29 происходит чтение бита информации. А в строке 30 его проверка. Если прочитанный бит равен нулю, то управление передается по метке stm4 и цикл чтения продолжается. Процесс чтения и проверки продолжается до тех пор, пока очередной раз не будет получена единица.
Строки 33, 34 содержат команды обработки ошибок. В случае возникновения ошибки управление передается к строке 33. Здесь вызывается подпрограмма prErr, которая выводит сообщение об ошибке на экран. Затем управление передастся по метке stm1 на начало подпрограммы, и процесс передачи команды запуска на преобразование повторяется.
Вторая подпрограмма, приведенная в листинге 4.7 — это подпрограмма чтения температуры. Она называется rdtmp. Подпрограмма производит считывание температуры с одно из датчиков Для того, чтобы отличать датчики друг от друга, каждому из них присваивается свой порядковый номер. Например, датчик, установленный в помещении, получил номер 0. Датчик, установленный на улице — номер 1. Для того, чтобы подпрограмма rdtmp могла обращаться к каждому датчику по отдельности, она должна использовать для обращения к датчикам их ID коды.
Эти ID коды помещаются в программную память микроконтроллера в виде небольшой таблицы. Пример такой таблицы приведен в листинге 4.7 строки 62...64. Начало таблицы имеет метку pzu. Коды датчиков в таблице нужно располагать в порядке присвоенных им номеров. В строке 63 в таблицу записывается код датчика номер 0. В строке 64 — код датчика номер 1. Каждый код занимает восемь ячеек в памяти микроконтроллера. Так как в нашу таблицу мы поместили только два ID кода, подпрограмма rdtmp работает только с двумя датчиками. Однако на самом деле подпрограмма rdtmp тоже вполне универсальная. Она легко может работать с любым количеством датчиков. Достаточно лишь дополнить таблицу pzu и приписать ID коды новых датчиков в конец таблицы.
Текст подпрограммы rdtmp занимает строки 35...61. Номер термодатчика передастся в подпрограмму через аккумулятор. Подпро
Подпрограмма чтения температуры
235
грамма работает по упрошенному алгоритму. Она не считывает все внутренние регистры микросхемы DS18B20 и не проверяет контрольную сумму. Для нашего случая, когда используются всего 2 датчика и длина линии минимальна, такой способ вполне допустим. Собранный образец электронного термометра, в котором использовалась такая программа, работал очень устойчиво без единого сбоя. Подпрограмма возвращает значение измеренной температуры в виде двух байт, записанных в две старшие ячейки буфера bufLAN. Младший байт регистра температуры записывается по адресу bufLAN, а старший — по адресу bufLAN+1.
Начинается подпрограмма rdtmp традиционно, с команды сохранения регистра psw (строка 35). Далее включается банк номер два (строка 36). В строках 37...39 вычисляется величина смещения, которая будет использоваться далее для нахождения ID кода конкретного датчика в таблице pzu. Так как ID код любого датчика занимает 8 ячеек в таблице, то для вычисления смещения нужно умножить номер датчика на 8. Это смешение в нужный момент будет добавляться к адресу pzu для того, чтобы получить адрес первой ячейки ID кода. Для вычисления величины смещения множитель (число 8) помещается в регистр b (строка 37). Так как номер датчика уже находится в аккумуляторе, для вычисления смещения остается лишь выполнить команду mul (умножение). Эта команда находится в строке 38. После выполнения команды mul в аккумуляторе остается величина смещения. В строке 39 найденное смешение помещается в регистр г7 для временного хранения.
Данный способ вычисления адреса первой ячейки в таблице ограничивает допустимое количество термодатчиков. Датчиков не может быть больше 32. При большем количестве датчиков величина смещения получится большей, чем 255 и для ее хранения нам нс хватит одного регистра. Но и 32 датчика — это достаточно много
После того как найдено смещение, подпрограмма может начинать выполнение своей главной задачи: чтение регистров блокнотной памяти термодатчика. Начинается этот процесс с вызова процедуры начального сброса (строка 40). В строке 41 проверяется признак ошибки. В строках, 42...51 происходит вывод команды сетевого уровня «Выбор ПЗУ». Сначала (строки 42, 43) в линию выдастся код этой команды (055Н). Сразу после кода команды необходимо выдать восемь байт ID кода. Тут нам и понадобится вычисленное ранее смещение. В строке 44 величина смещения помещается в регистр Ь. Для того, чтобы выдать все 8 байт ID кода, организу
236
Работа с шиной MicroLAN
ется цикл. Тело цикла занимает строки 47...51. В строках 45 и 46 происходит подготовка начальных значений. В качестве параметра цикла используется регистр гб. Начальное значение параметру цикла присваивается в строке 46.
Кроме того, в регистр DPTR помещается адрес начала таблицы ID кодов (строка 45). В теле цикла происходит поочередное извлечение всех восьми байтов ID кода и передача этих кодов на шину 1-Wire. Для этого сначала текущая величина смещения помещается в аккумулятор (строка 47). Затем, используя величину смешения в аккумуляторе и базовый адрес в регистре DPTR, оператор move извлекает из таблицы очередной байт ID кода (строка 48). Извлеченный байт также помещается в аккумулятор. В строке 49 содержимое аккумулятора выводится на шину. Затем значение смещения в регистре b увеличивается на единицу (строка 50). Если это не последний байт, то оператор djnz в строке 51 передает управление по метке szu1 и цикл повторяется. Так как величина смещения увеличилась на единицу, при очередном проходе будет передаваться уже следующий байт ID кода.
После того как будут переданы все 8 байтов, интерфейсы всех датчиков перейдут на транспортный уровень. При этом на шине останется только один активный датчик температуры. Второй перейдет в неактивный режим. Далее, программа перейдет к формированию команды «Чтение блокнотной памяти». Формирование этой команды происходит в строках 52...57. Сначала, в строках 52 и 53, в линию выдается код операции (ОВЕН). Затем начинается процесс чтения регистров термодатчика. Как уже говорилось ранее, в данной подпрограмме процесс чтения регистров выполняется неполностью. Читаются только два первых регистра. Именно они и содержат значение температуры. Протокол 1-Wire допускает такой режим работы. В строках 54 и 55 читается первый байт значения температуры и помещается в ячейку памяти с адресом bufLAN. В строках 56, 57 читается второй байт и помещается в ячейку с адресом bufLAN+1. На этом подпрограмма rdtmp завершает свою работу. Перед выходом из подпрограммы восстанавливается содержимое регистра psw (строка 58).
В строках 60, 61 помещены команды обработки ошибки. Алгоритм обработки ошибки такой же, какой мы видели при рассмотрении подпрограммы sttmp (см. строки 33, 34).
Вывод температуры на индикатор 237
4.15.	Вывод температуры на индикатор
Итак, значение температуры прочитано и хранится в ОЗУ микроконтроллера в виде двух байтов информации. Теперь осталось ее только вывести на индикатор. Тут возникает следующая проблема: в ОЗУ микроконтроллера температура записана в двоичном виде. Перед нами стоит задача: перевести это значение из двоичной системы в десятичную. И лишь затем вывести его на экран. Для того, чтобы решить эту задачу, внимательнее присмотримся к формату регистра температуры. Для этого вернемся к табл. 4.4. Изучив эту таблицу, вы можете обнаружить следующее:
1.	Температура записывается в виде шестнадцатиразрядного двоичного числа, у которого только одиннадцать младших разрядов являются значащими.
2.	Отрицательные значения температуры записываются в дополнительном коде.
3.	Вес одной единицы этого числа равен одной шестнадцатой градуса.
Последний вывод, который можно сделать, рассматривая табл. 4.4 — число, хранящее значение измеренной температуры, имеет четкую структуру. Эта структура в графическом виде показана на рис. 4.32. Именно в структуре кода и заложен ключ к составлению самого простого алгоритма преобразования значения температуры в десятичную форму.
Р9 Р8
Целая часть
Младший байт
Р7	Р6	Р5	Р4	РЗ	Р2	Р1	РО
Дробная I часть ~1
Рис. 4.32. Формат регистров температуры
Рассмотрим подробнее рис. 4.32. На нем изображены два байта, которые вместе составляют шестнадцатиразрядное двоичное число. Все 16 разрядов этого числа легко разбиваются на три диапазона. Разряды с Р15 по Р12 всегда содержат одно и то же значение, равное знаку числа. Разряды с Р11 по Р4 можно представить как целую часть числа. Вес младшего разряда этого диапазона равен
238
Работа с шиной MicroLAN
одному градусу. Разряды P0...P3 — это дробная часть числа. Вес любого из этих разрядов меньше одного градуса. Вы можете возразить, что разряд Pl I тоже содержит знак числа. Но его все же удобно включить в диапазон, относящийся к целой части. Во-первых, при переводе из двоичной в десятичную систему, знак числа нс помеха. А во-вторых, такое разделение легче выполнить программным путем. Достаточно лишь разделить каждый байт на две тетрады и склеить их в нужном порядке.
Итак, способ перевода в десятичную систему напрашивается сам собой. Нужно выделить из полученного кода диапазон разрядов, соответствующий целой части числа, перевести сначала его в десятичную форму и вывести на экран. После последнего знака целой части числа нужно не забыть поставить десятичную точку. Затем в десятичную форму переводится дробная часть числа и тоже выводится на экран после запятой. При этом нужно учесть знак числа. В конце выведенного таким образом числа нужно поместить надпись «°C».
Для двоично-десятичного преобразования удобно использовать команду целочисленного деления div. Микроконтроллер АТ89С2051 — один из немногих контроллеров этого класса, который имеет в системе команд такую команду. Для того, чтобы осуществить двоично-десятичное преобразование целой части числа, нужно выполнить целочисленное деление исходного числа на 10. После такой операции аккумулятор будет содержать частное, а регистр b — остаток от деления. Частное будет соответствовать количеству десятков, а остаток — количеству единиц в десятичном представлении числа.
Затем можно просто вывести на экран два этих числа. Сначала содержимое аккумулятора, а затем содержимое регистра Ь. В результате, на экране мы получим изображение целой части значения температуры в десятичном виде. Такой простой метод преобразования будет правильно работать только в том случае, если целая часть числа не превышает значения 99. При большем значении температуры в старшем разряде полученного десятичного числа будут появляться буквы: частное от деления будет больше 10. Применение упрошенной программы снизит диапазон измерения термометра. Теперь он будет равен (—55...+99)°С. Однако для электронного бытового термометра такой диапазон вполне допустим.
Вывод температуры на индикатор	239
Для вывода на индикацию дробной части температуры нужно проделать немного более сложные вычисления. Сначала нужно выделить четыре бита, составляющие дробную часть в виде отдельного числа. Затем нужно умножить это число на 16 (вес единицы дробной части числа равен 1/16 градуса). А затем полученный результат нужно поделить на 10. Тогда целая часть полученного таким образом числа будет равна десятым долям градуса. Остаток от деления в этом случае мы учитывать не будем.
Для реализации описанного алгоритма разработана подпрограмма primp (см. листинг 4.8). Подпрограмма prtmp читает два байта температуры из буфера bufLAN и выводит это значение на экран в десятичном виде. Текст подпрограммы prtmp занимает строки 17...53. Начинается подпрограмма с оценки знака числа. Для этого старший байт температуры помещается в аккумулятор (строка 17). Затем проверяется значение старшего бита аккумулятора (строка 18). Если он равен единице — температура отрицательная. Если нулю — положительная.
Листинг 4.8
;вййййввйввйййвввйввййвявйввййвййвйяяйййвйявявййй
ИИ	Основная программа	во
1	main:	call	eclr	Стирание экрана
2	ini:	mov	a.«2	Установка курсора
3		call	ecur	
4		call	sttmp	Запуск процесса преобразования
5		call	inkl	Чтение клавиатуры
6		cjne	a,#100B,in2	, Если нажата переход
7		mov	а.йО	Если не нажата датчик 0
8		jmp	in3	
9	in2:	mov	a.#1	Датчик 1
10	1пЗ:	call	rdtmp	Чтение температуры
11		call	prtmp	Вывод температуры на индикатор
12		mov	а.й17	Вывод символа -градус»
13		call	prehr	
14		mov	а.йОСН	Вывод буквы «С» (Цельсия)
15		call	prehr	
16		jmp	ini	: Возврат в начало
Вывод темпеватуры на экран
240
Работа с шиной MicroLAN
17	prtmp	mov	a.bufLAN+1	Читаем старший байт
18		jnb	acc 7,prt1	Проверка знака если «плюс» - переход
19		mov	a,#18	Вывод минуса
20		call	prchr	
			—	Пересчет отрицательного числа
21		mov	a, bufLAN	; Читаем младший байт
22		cpl	a	Инвертируем
23		add	a,#l	Увеличиваем на единицу
24		mov	bufLAN. a	Записываем назад
25		mov	a,buflAN+1	Читаем старший байт
26		cpl	a	Инвертируем
27		adde	а.йО	Складываем с учетом переноса
28		mov	buflAN+1,a	Записываем назад
29		imp	prt2	
30	prt1:	mov	a #16	Вывод пробела
31		call	prchr	
						Вычисление целой части
32	prt2:	mov	a,bufLAN+1	, Считываем старший байт
33		swap	a	. Обмен тетрад
34		anl	a,#01OH	: Получили старший полубайт
35		mov	r5.a	; Временно записываем в г5
36		mov	a.bufLAH	, Считываем младший байт
37		swap	a	 Обмен тетрад
38		anl	a,#OFH	; Получили младший полубайт
39		add	a.r5	Складываем полубайты
40		mov	b.eW	: Деление на 10
41		div	ab	
42		call	prchr	; Вывод десятков
43		mov	a.b	, Берем остаток от деления
44		setb	acc.7	, Включить точку
45		call	prchr	; Вывод единиц
						Вычисляем десятые
46		mov	a.bufLAN	; Читаем младший байт
47		anl	а, НОРМ	Выделяем младшие разряды
48		mov	b,#10	Умножаем на 10
49		mul	ab	
50		mov	b.#16	Делим на 16
51		div	ab	
52		call	prchr	Вывод десятых
53		ret		
В случае отрицательной температуры выполняются блок операций по обработке отрицательных чисел (строки 19...29). Начинается этот блок с вывода на экран символа «минус» (строки 19, 20). Затем температура переводится из дополнительного кода в прямой. В результате этой операции значение температуры становится положительным, но не изменяется по абсолютной величине. Для перевода числа из дополнительной кодировки в прямую его нужно проинвертировать, а затем к нему прибавить единицу. Для шестнадцатиразрядного числа перевод выполняется в два этапа.
Вывод температуры на индикатор
241
Сначала в аккумулятор вызывается младший байт числа (строка 21). Он инвертируется (строка 22) и увеличивается на единицу (строка 23). Полученный результат записывается на место (строка 24). Затем в аккумулятор вызывается старший байт числа (строка 25). Инвертируется (строка 26). Затем программа должна учесть перенос, который мог возникнуть на первом этапе преобразования. Команда сложения результата с нулевым байтом (строка 27) позволяет учесть бит переноса. Полученное значение старшего байта также записывается на свое место (строка 28).
Если температура изначально была положительной, то описанные выше преобразования не выполняются. После строки 18 управление сразу передается по метке prt1. В этом месте выполняются две команды, которые выводят на экран символ пробела (строки 30, 31). Символ пробела выводится вместо минуса и означает плюс.
После всех описанных выше операций, как в случае отрицательной, так и is случае положительной температуры, управление передается к метке prt2. К этому моменту в буфере bufLAN находится положительное значение температуры, а на индикатор уже выведен минус, если это необходимо. Далее программа переходит к следующему этапу — выводу на экран целой части числа. Для этого сначала из нужного диапазона формируется значение целой части. Это происходит в строках 32...39 программы. Сначала в аккумулятор вызывается старший байт температуры (строка 32). Затем меняются местами обе его тетрады (строка 33). При помощи маски от полученного числа отделяются четыре старших бита (строка 34). И все это временно сохраняется в регистре г5 (строка 35). Затем вызывается младший байт температуры (строка 36). Две его тетрады тоже меняются местами (строка 37). Далее, при помощи маски отделяются младшие четыре бита (строка 38). В заключение, две полученные половины целой части числа объединяются при помощи оператора сложения (строка 39).
В строках 40, 41 производится операция двоично-десятичного перевода целой части числа. Для этого в регистр b помещается делитель (строка 40). А затем производится деление (строка 41). Теперь нам осталось только вывести результат на индикатор. Сначала выводятся десятки градусов, которые находятся в аккумуляторе (см. строку 42). А затем единицы градусов, которые находятся в регистре b (см. строки 43...45). При этом программа устанавливает признак вывода десятичной точки (строка 44). Признак передается через
242
Работа с шиной MicroLAN
старший бит аккумулятора (см. описание подпрограммы prchr в разделе 2.6).
Сразу после вывода целой части числа начинается вывод дробной его части (строки 46...52). Сначала в аккумулятор помещается младший байт температуры (строка 46). При помощи маски от него отделяются четыре младших разряда (строка 47). Далее, полученное число умножается на 10 (строки 48, 49). А затем делится на 16 (строки 50, 51). Полученное значение десятых долей градуса выводится на индикатор (строка 52). На этом работа подпрограммы prtmp завершается.
Теперь нам осталось объединить все описанные выше подпрограммы и создать наконец программу электронного термометра. Текст этой программы также приведен в листинге 4.8. Он занимает строки 1...16. Программа рассчитана на работу с двумя датчиками. Датчики переключаются при помощи кнопки S1. При отпущенной кнопке на экран выводится температура, измеренная датчиком номер 0. При нажатой кнопке S1 на экран выводится температура датчика номер 1. Начинается программа с очистки индикатора (строка 1). Затем производится установка курсора в позицию номер два (строки 2, 3). Вывод температуры на экран начинается со второй позиции для того, чтобы надпись оказалась посередине экрана. Далее (в строке 4) происходит вызов подпрограммы sttmp, которая запускает процесс преобразования для всех датчиков. Подпрограмма завершается только после окончания этого процесса. Затем вызывается подпрограмма inkl (строка 5), которая считывает состояние клавиатуры. После получения кода состояния клавиатуры проверяется условие нажатия кнопки S1 (строка 6). По результатам проверки в аккумулятор заносится код одного из датчиков. Если кнопка не нажата, то в аккумулятор записывается код 0 (строка 7). Если нажата, то в аккумулятор помещается единица (строка 9).
После того как номер датчика занесен в аккумулятор, вызывается подпрограмма чтения температуры (строка 10). Подпрограмма читает температуру, помещает ее значение в буфер but LAN. После этого вызывается подпрограмма prtmp (строка 11), которая выводит значение температуры на экран. И в заключение на экран выводится надпись «°C». Сначала выводится символ градуса (строки 12, 13), а затем символ «С» (строки 14, 15). Программа измерения температуры, так же как и программа считывания ID
Вывод температуры на индикатор
243
кодов (листинг 4.5), зациклена. В строке 16 находится оператор безусловного перехода, который передает управление на самое начало. Зацикливание программы создает эффект непрерывного измерения температуры. Все изменения температуры тут же отображаются на индикаторе.
Итак, пройдя все этапы разработки, мы получили полный текст программы цифрового термометра. При желании, вы можете самостоятельно собрать схему, изображенную на рис. 4.28. Если вы объедините в единый текст все фрагменты программы, приведенные в этой книге, затем оттранслируете полученный полный текст и «зашьете» его в программную память микроконтроллера, то получите работающий электронный термометр, который будет измерять температуру, как в вашей квартире, так и на улице. Если у вас возникнет проблема при составлении полного текста программы, вы можете скачать его из Интернет. На специальном сайте, посвященном этой книге [8wL находится не только полный текст программы электронного термометра, но и тексты всех программных примеров из этой книги. Кроме того, на сайте вы найдете готовый оттранслированный вариант программы термометра и еще много разных полезных программ.
Внешний вид опытного образца электронного термометра показан на рис. 4.33.
Рис. 4.33. Внешний вид электронного термометра
244
Работа с шиной MicroLAN
4.16. Программа подсчета контрольной суммы
В предыдущем разделе мы рассмотрели упрощенный вариант считывания информации с датчиков температуры, без проверки контрольной суммы. Для простого домашнего термометра этот вариант вполне подходит. Но в условиях значительного удаления датчика от микроконтроллера и особенно в случае повышенного уровня помех, упрощенный вариант программы будет работать неустойчиво. Поэтому, в данном разделе я хотел бы рассмотреть вопрос, как программным путем рассчитать, а затем сверить контрольную сумму. Для того, чтобы рассчитать контрольную сумму, нам уже недостаточно будет двух байтов.
Нам придется считывать из термодатчика все восемь регистров блокнотной памяти. Значения этих регистров мы будем размещать все в том же буфере bufLAN. Новая версия подпрограммы rdtmp приведена в листинге 4.9. Текст подпрограммы практически полностью повторяет текст первого ее варианта, приведенного в листинге 4.7. Отличие только в последних строках. Вместо строк, где читаются два байта блокнотной памяти (строки 34, 57, листинг 4.7), в новом варианте подпрограммы применен цикл считывания байтов (строки 18...25, листинг 4.9).
Тело цикла занимает строки 22...25. В строках 18, 19 производится инициализация этого цикла Регистр гО используется в качестве указателя буфера, а регистр г1 — в качестве параметра цикла. В строках 20, 21 на шину выдается команда «Чтение блокнотной памяти». В первой строке цикла производится чтение очередного байта (строка 22). В строке 23 прочитанный байт записывается в буфер bufLAN. В строке 28 значение указателя буфера увеличивается на единицу. Оператор djnz (строка 25) обеспечивает повторение цикла для всех восьми байтов.
После того, как все восемь байтов прочитаны и записаны в буфер, вызывается подпрограмма расчета контрольной суммы cmpCRC (строка 26). Эта подпрограмма будет описана чуть позже. Подпрограмма cmpCRC рассчитывает и сверяет значение контрольной суммы, используя информацию из буфера bufLAN. По результатам работы подпрограмма возвращает код ошибки в аккумуляторе. Если контрольная сумма не сошлась, код в аккумуляторе будет равен трем (ошибка номер 3). Если ошибки не обнаружено, то в
Программа подсчета контрольной суммы
245
аккумуляторе будет ноль. Ошибка контрольной суммы обрабатывается точно таким же образом, как и остальные виды ошибок. На экране высвечивается «ЕггогЗ», а программа начинает процесс считывания температуры сначала.
Листинг 4.9
	****•«**>********************»************************			
			Чтение Температуры	
	г**		второй вариант	**
	: Входные параметре		в асе - номер канала	
	; Выходные	параметры - в bufLAN 8 байтов		считанного кода
1	rdtmp:	push	psw	
2		mov	psw,#bank2	Выбор банка 2 памяти
3	rtm1:	mov	b.#8	Вычисление смещения
4		mul	ab	для адреса ПЗУ
5		mov	г7,а	Временно сохранить в г7
			Начальный сброс	
6		call	resLAN	;	Вызов процедуры сброса
7		cjne	a,#0,rtm2	Если ошибка
			Выбор ПЗУ	
8		mov	а.#55Н	Выдать команду
9		call	wr8LAN	
10		mov	Ь.г7	Восстановить смещение
11		mov	г6.#8	Счетчик байтов
12		mov	DPTR.flpzul	Начальный адрес кодов ПЗУ
13	szu1:	mov	a.b	Текущее смещение
14		move	a,@a+DPTR	Извлечь очередной байт
15		call	wr8LAN	Выдать на линию
16		inc	b	Увеличить смешение на 1
17		djnz	r6,szu1	Продолжить цикл, если не последний
				Чтение ОЗУ	
18		mov	rO, AbufLAN	Инициализация указателя буфера
19		mov	r1,A8	Инициализация счетчика байтов
20		mov	a.AOBEH	Выдать команду
21		call	wr8LAN	
22	szu2:	call	rdSLAN	Чтение младшего байта
23		mov	@rO,a	Запись в буфер
24		inc	rO	Увеличение указателя буфера
25		djnz	r1,szu2	
			Проверка контрольной	суммы
26		call	cmpCRC	:	Вызов процедуры проверки КС
27		cjne	a.#0rtm2	;	Если ошибка
246
Работа с шиной MicroLAN
28 29	POP ret		psw	Завершение подпрограммы
30	rtm2'.	call	prErr	Если ошибка вывести ее на экран
31		jmp	rtm1	Перейти в начало
32	pzu1:	DB	28H.0B8H,56H.4BH,D,O,O,0C5H	; Коды ПЗУ датчиков	
33	pzu2:	DB	28H.6FH.5CH.4BH.0.0.0.39H	
Теперь посмотрим, как работает подпрограмма расчета контрольной суммы. Для начала вспомним алгоритм. Схематически алгоритм вычисления контрольной суммы приведен на рис. 4.19. Как мы можем увидеть из этого рисунка, алгоритм основывается на операции сдвига и трех операциях «Исключающего ИЛИ» (XOR). Нам придется организовать обе эти операции программным путем. В системе команд микроконтроллера АТ80С2051 имеются команды, позволяющие выполнить обе эти операции. Однако решение задачи «в лоб» не всегда рационально.
Для задачи подсчета контрольной суммы существуют приемы, позволяющие максимально упростить программу. Для того, чтобы понять сущность этих приемов, вспомним сначала некоторые свойства двоичной функции «Исключающее ИЛИ». На рис. 4.34 приведена таблица истинности для этой функции. Внимательно посмотрев на эту таблицу, вы можете легко заметить интересную особенность.
Х1	Х2	Y
0	0	0
0	1	1
1	0	1
1	1	0
Рис. 4.34. Таблица истинности логической функции XOR
Функция «Исключающее ИЛИ» может использоваться в качестве управляемого инвертора. Представим себе, что вход XI — это вход данных, а вход Х2 — управляющий. Если на управляющем входе Х2 установлен нулевой уровень, то сигнал на выходе Y повторяет сигнал на входе XI. Если же на управляющий вход Х2 подать логическую единицу, то уровень сигнала на выходе
Программа подсчета контрольной суммы
247
Y будет инверсным по отношению к сигналу на входе XI. Это свойство широко используется в вычислительной технике и в программировании. Используется он и в описываемой подпрограмме проверки контрольной суммы. Ниже приводятся два варианта подпрограммы. Оба варианта абсолютно равнозначны и любой из них может использоваться в подпрограмме rdtmp, текст которой приведен в листинге 4.9.
Текст первого варианта подпрограммы cmpCRC приведен в листинге 4.10. Этот вариант сначала вычисляет контрольную сумму первых семи ячеек буфера bufLAN. Затем он сравнивает вычисленное значение с содержимым последней, восьмой ячейкой буфера. Если обе величины окажутся равными, подпрограмма возвращает ноль в аккумуляторе. Если контрольная сумма не сойдется, подпрограмма возвращает код ошибки. Код ошибки в данном случае равен 3.
Для правильной работы подпрограммы нам потребуется зарезервировать еще одну ячейку в ОЗУ микроконтроллера. Эта ячейка будет использоваться подпрограммой для хранения промежуточного результата при подсчете контрольной суммы. Две дополнительные строки, резервирующие такую ячейку, выглядят следующим образом:
ORG 21Н
buTCRC:	DS 1	. Бу^эр контрольной суммы
Адрес 21Н выбран неслучайно. Для правильной работы подпрограммы нам потребуется как прямой доступ к этой ячейке памяти, так и доступ к отдельным ее битам. Не все ячейки ОЗУ имеют такую возможность. Двойной доступ допускают ячейки с адреса 20Н по адрес 2FH (подробнее об этом смотри в [1|). Однако ячейка с адресом 20Н уже занята. Ее младший бит используется в качестве флага fpit. Поэтому выбрана следующая по счету не-задействованная ячейка.
Для вычисления контрольной суммы семи первых ячеек буфера мы должны представить содержимое всех этих ячеек в виде единой последовательности из 56 битов. Затем мы должны побитно «вдвигать» эти данные в буфер контрольной суммы bufCRC, одновременно производя три операции «Исключающего ИЛИ» в соответствующих разрядах (см. схему алгоритма на рис. 4.19). Та
248
Работа с шиной MicroLAN
ких циклов сдвига должно быть ровно 56 (по числу проверяемых битов). Если действовать строго по алгоритму, изображенному на рис. 4.19, то мы должны на каждом шаге расчета контрольной суммы одновременно сдвигать содержимое буфера и на ходу производить операции XOR. Однако эту операцию удобно разделить на два отдельных действия. Сначала вычислить все операции XOR, поместив результат операций в те же самые разряды. А затем произвести сдвиг. В результате, для того чтобы реализовать один цикл вычисления контрольной суммы, мы должны выполнить четыре этапа. В графическом виде все этапы изображены на рис. 4.35.
♦ На первом этапе нужно произвести сдвиг битов в буфере bufLAN таким образом, чтобы самый младший бит оказался в ячейке CY. Здесь буфер представляется в виде непрерывного 56-битного регистра.
Первый этап ___________________________bufLAN_________________________
8 разрядов (CRC) |	56 разрядов (7 байт)
Направление сдвига bufCRC_____________________________
|Р7|рб| Р5|Р4|РЗ|Р2|Р1 |рр] |с7|-
Второй этап
Третий этап.
Четвертый этап Ьит
теряется
bufCRC
|Р7|Р6|Р5|Р4|РЗ|Р2|Р1
Направление сдвига
Рис. 4.35. Этапы одного цикла вычисления контрольной суммы
Программа подсчета контрольной суммы
249
♦ На втором этапе нужно произвести операцию XOR между полученным на предыдущем этапе битом и младшим разрядом буфера bufCRC. Тем самым будет реализована первая из операций XOR алгоритма (самый правый по рис. 4.19, сразу на входе алгоритма). Результат операции XOR удобно сохранить в CY
♦ На третьем этапе мы можем произвести сразу две оставшихся операции XOR одновременно. Вот тут нам и пригодится удивительное свойство оператора «Исключающее ИЛИ». Обе оставшиеся операции XOR в схеме алгоритма получают на один из своих входов только что вычисленный нами бит, который пока находится в CY. Если значение этого бита равно нулю, то обе интересующие нас операции XOR должны превратиться в повторители и пропустить через себя сигнал без изменения. Если в CY находится единица, то оба оператора XOR должны проинвертировать входной сигнал. Для имитации работы в режиме повторителей можно просто не производить никаких действий, тогда значение разрядов не изменится. Если нам необходимо проинвертировать эти два разряда, то мы должны сначала сформировать константу, равную ООО11ОООВ. А затем произвести операцию «Исключающее ИЛИ» между содержимым буфера bufCRC и этой константой. В результате значение двух разрядов проинвертируется.
♦ На последнем этапе нужно просто сдвинуть содержимое буфера на один разряд вправо. На этом один цикл расчета контрольной суммы будет завершен.
Если произвести 56 описанных выше циклов, то в конце операции в буфере bufCRC сформируется значение контрольной суммы. Текст подпрограммы cmpCRC, реализующей описанный выше алгоритм, приведен в листинге 4.Ю. Начинается подпрограмма с обнуления буфера bufCRC (строка I). Обнулить буфер перед началом вычислений нужно обязательно. Это тоже требование алгоритма. Далее, в строках 3...1I, начинается цикл подсчета контрольной суммы. В качестве параметра цикла используется регистр г2. В строке 2 ему присваивается начальное значение — 56. Тело цикла занимает строки 3...11. В начале цикла (строка 3) вызывается специальная подпрограмма, которая производит сдвиг первых семи ячеек (56 бит) буфера bufLAN. Специальная подпрограмма используется потому, что сдвигать нам надо не одну, а сразу семь ячеек. Описание
250
Работа с шиной MicroLAN
подпрограммы сдвига будет приведено чуть позже. В результате работы этой подпрограммы информация в буфере bufLAN сдвигается на один бит вправо, а самый младший бит оказывается в ячейке CY. На этом завершается первый этап (см. рис. 4.35).
Затем программа приступает ко второму этапу. На этом этапе она должна выполнить функцию XOR между двумя битами информации. В системе команд микроконтроллера АТ89С2051 отсутствует операция «Исключающее ИЛИ» для отдельных битов. Поэтому она заменяется несколькими командами, приводящими к аналогичному результату. Тут мы опять вспомним, что операция «Исключающее ИЛИ» — это управляемый инвертор. Управляемая инверсия реализуется в строках 4 и 5 программы. В качестве бита управления служит содержимое ячейки CY. В качестве инвертируемого бита — младший бит буфера bufCRC. В строке 4 оценивается значение ячейки CY. Если это значение равно нулю, то происходит переход по метке срг2 и инверсии не производится. Если признак переноса равен единице, то младший бит буфера bufCRC инвертируется (строка 5).
Дальше программа переходит к третьему этапу. Для этого извлекается содержимое буфера bufCRC и помешается в аккумулятор (строка 6). Далее производится проверка значения младшего разряда буфера bufCRC (строка 7). Если младший разряд равен единице, то нужно произвести операцию «Исключающее ИЛИ» аккумулятора с константой 00011000В. Если младший бит буфера bufCRC равен нулю, то никаких больше действий на этом этапе выполнять не нужно. Операция «Исключающее ИЛИ» между содержимым аккумулятора и константой 00011000В выполняется в строке 8.
Листинг 4.10
HiiititiioeBiifiititiiijilWHiitiilfHttifiitititttfiititMHiiltiitim
#11	Проверка контрольной суммы Н
:И	Вариант 1	Вй
1	cmpCRC:	mov bufCRC.#0	Обнуление буфера КС
2	mov г2,#56	Инициализация счетчика сдвигов
3	eprt call rr56	, Сдвиг 56 разрядов в буфере
Программа подсчета контрольной суммы
251
4		jnc	cpr2	Проверка очередного бита
5		cpl	bufCRC.O	Если он равен единице, инвертируем
6	срг2:	mov	a,bufCRC	Читаем содержимое буфера КС
7		jnb	bufCRC.О.сргЗ	Проверка младшего бита
8		xrl	а,«00011000В	Если он равен единице делаем XOR
У	сргЗ.	rr	a	. Сдвиг
ю		mov	bufCRC a	Помещаем назад в буфер
и		djnz	r2,cpr1	Оператор икта
12		clr	c	Сб; ' Лризм«а переноса
13		mov	a,buflAN+7	Из- .-.иние КС из буфера bufLAN
14		subb	a,bufCRC	Вычитание из него рассчитанной КС
15		jz	cpr4	Проверка результата
16		mov	a,#3	Если не ноль - ошибка номер три
17	срг4:			
18		ret		
			 Сдвиг	7	6vt>.r i вj	один бит впргьо
19	гг56.	mov	rO.tft. ILAN+6	Инициалимцая yoyr^ii буфера
20		mov	r1,#7	Инициализздия счетчика байтов
21		mov	a, bufLAN	Извлечение первого байта
22		rrc	a	засылка в CY младшего бита
23	гг1:	mov	a,@rO	Извлечение очередного числа
24		rrc	a	Сдвиг
25		mov	@rO,a	Ззлись назад
26		dec	rO	Итерация счетчика байтов
27		djnz	r1.rd	. v7.&|bTi)P ЦИК7.О
28		ret		
Последний этап — это сдвиг содержимого аккумулятора. Исходный код после предыдущего этапа уже находится в аккумуляторе. Сдвиг выполняется оператором гг в строке 9 программы. После сдвига аккумулятор будет содержать промежуточное значение контрольной суммы. Это значение помешается назад, в буфер bufCRC (строка 10).
После того как все четыре этапа закончены, нужно повторить их еще и еще раз. Всего должно быть 56 циклов. Оператор djnz (строка 11) возвращает управление в начало цикла (метка срг1) до тех пор, пока не будут обработаны все 56 битов информации.
По завершении процесса вычисления контрольной суммы ее окончательное значение будет находиться в буфере bufCRC. Несмотря на то, что в процессе подсчета контрольной суммы содержимое буфера bufLAN постоянно сдвигалось, после окончания всех 56 циклов сдвига оно восстановится (сдвиг происходит по кругу). В результате там снова будут находиться те же самые исходные значения, которые были считаны из микросхемы термодатчика.
252
Работа с шиной MicroLAN
Теперь рассмотрим подробнее работу подпрограммы, которая производит сдвиг 56 разрядов буфера bufLAN. Она вызывается по ссылке гг56. Расположение всех 56 разрядов в буфере и направление сдвига информации изображены на рис. 4.36. Для того чтобы осуществить такой сдвиг, содержимое каждой из семи ячеек буфера bufLAN поочередно вызывается в аккумулятор. В аккумуляторе содержимое очередной ячейки сдвигается вправо, при помощи команды rrc (сдвиг вправо через признак переноса). Затем результат сдвига записывается обратно в ту же ячейку, откуда был прочитан. Ячейка признака переноса CY используется для передачи сдвигаемого бита из одной обрабатываемой ячейки в другую. При этом бит, из младшего разряда предыдущей ячейки попадает в старший разряд последующей. Для того чтобы обеспечить правильную передачу битов от одной сдвигаемой ячейки в другую, нужно начинать обработку ячеек с самой последней ячейки последовательности (bufLAN+б). После завершения всей процедуры сдвига в CY оказывается самый младший бит всей последовательности (РО).
Текст подпрограммы гг56 занимает строки 19...28 (см. листинг 4.10). Для последовательного перебора всех семи ячеек буфера в подпрограмме организован цикл. В качестве счетчика цикла используется регистр И. В строке 20 ему присваивается начальное значение. В качестве указателя текущей ячейки используется регистр гО. В строке 19 в него записывается адрес ячейки, с которой будет начинаться обработка.
Следующие две строки содержат команды, которые помещают в CY содержимое бита РО (см. рис. 4.35). Эта операция нужна для соблюдения условия цикличности (сдвиг по кругу). Для извлечения содержимого разряда РО в аккумулятор помещается содержимое самой первой ячейки буфера с адресом bufLAN (строка 21). Затем младший бит аккумулятора отправляется в CY. Это действие выполняется при помощи операции сдвига rrc (строка 22). После этого сразу начинается цикл сдвига.
Тело цикла составляют строки 23...27. В строке 23 очередной байт извлекается из буфера. В строке 24 происходит его сдвиг на один бит вправо. В строке 25 результат помещается обратно в ячейку, откуда он был взят. В строке 26 содержимое указателя буфера уменьшается на единицу. Оператор цикла в строке 27 обеспечивает повторение цикла сдвига для всех семи ячеек буфера. В строке 28 подпрограмма гг56 завершается.
Программа подсчета контрольной суммы
253
BufLAN
BufLAN+1
BufLAN+2
BufLAN+3
BufLAN+4
BufLAN+5
BufLAN+6
Направление сдвига
Рис. 4.36 Схема сдвига битов в буфере bufLAN
Описанную только что программу можно немного сократить. Для этого можно использовать одно любопытное свойство алгоритма расчета контрольной суммы. Если вычислить контрольную сумму не семи, а всех восьми ячеек буфера, то результат вычисления будет равен нулю. Но это только в том случае, если все восемь байтов были считаны без ошибок. В случае любой ошибки результат будет отличен от нуля. Немного изменив программу, можно реализовать и этот новый способ проверки контрольной суммы. При этом мы экономим на операции сравнения. Новый, более оптимальный вариант подпрограммы cmpCRC приведен в листинге 4.11. В результате такой оптимизации текст программы уменьшился на три строчки, а результирующий код подпрограммы стал короче на целых 5 байт.
254
Заключение
Листинг 4.11
	;################################################
	.##	Проверка контрольной суммы	И ;##	Вариант 2	П
	:«#»###############»#######«#####################
1	cmpCRC:	mov	BufCRC, #0	Обнуление буфера КС
2	mov	г2,#64	Инициализация счетчика сдвигов
3	сргГ	call rr64	Сдвиг 64 разрядов в буфере
4	jnc	срг2	Проверка очередного бита
5	cpl	bufCRC.0	Если он равен единице, инвертируем
6	срг2.	mov	a, bufCRC	Читаем содержимое буфера КС
7	jnb	bufCRC.О.сргЗ	Проверка младшего бита
8	xrl	а,#000110006	Если он равен единице делаем XDR
9	сргЗ:	гг	а	Сдвиг
10	mov	bufCRC,а	Помещаем назад в буфер
11	djnz	г2,срг1	Оператор цикла
12	jz	срг4	. Проверка результата
13 14 15	mov	а.#3	, Если не ноль - ошибка номер три срг4: ret
		 Сдвиг 8 ячеек буфера на один бит вправо
16	гг64:	mov	rO. #bufLAW+7	; Инициализация указателя буфера
17	mov	г1 #8	Инициализация счетчика байтов
18	mov	a.bufLAN	; Извлечение первого байта
19	ггс	а	, засылка в CY младшего бита
20	гг1:	mov	а,@гО	; Извлечение очередного числа
21	ггс	а	Сдвиг
22	mov	@г0,а	, Запись назад
23	dec	гО	; Итерация счетчика байтов
24 25	djnz r1,rr1	: Оператор цикла ret
Заключение 255
Заключение
Уважаемый читатель! На этом я закачиваю свою вторую книгу, посвященную микропроцессорам. В этой книге я постарался раскрыть все наиболее применимые способы построения периферийных устройств. Мне очень интересно ваше мнение. Жду ваших отзывов, как по обычной, так и по электронной почте. Что понравилось, что не понравилось. Может что-то непонятно. Я всегда готов помочь советом. Извините, но отвечать я смогу только в электронном виде. Существует еще несколько тем, не вошедших в книгу. Например, такая интересная тема, как подключение микроконтроллера к компьютеру при помощи последовательного (СОМ) порта. Напишите, нужно ли включать эту тему в последующих изданиях.
С уважением, Белов Александр Владимирович
Адрес для писем: Украина, АР Крым, г. Симферополь, ул. Русская, д. 194. Электронный адрес: belov@selma.crimea.ua
За более точными координатами обращайтесь на мой персональный сайт http://avbelov.by.ru
Список литературы
1.	Белов А. В., «Самоучитель по микропроцессорной технике». Наука и Техни! -Санкт-Петербург, 2003 г.
2.	В. Трошков. Термометр на DS1B21 и PIC-Контроллере// Радио N* 5. 2002 г с 20. 21.
3.	С. Семилетников. Домашняя метеостанция// Радио. № 9, 2002 г. с 35. 37.
4 Б. Хохлов. Видеопроцессоры серии TDA88xx// Радио. № 3, 2000 г с. 6 ..8
Список	ссылок в	Интернет
1и	http://digitchip.by.rij...	Сайт	«Цифровые микросхемы и
микропроцессоры»
2М	http://microprocessor.by.ru..	Сайт	«Микропроцессоры»
Зк	http://www.atmel.com	Сайт	фирмы Atmel
http://www.atmel.ru..	Сайт	фирмы Atmel (русское
представительство)
4К http://www.philips.com.	Сайт фирмы Philips
5И http://www.semiconductors.philips.com .Сайт фирмы Philips (радиоэлементы)
6И	http://www.maxim-ic.com...	.	Сайт фирмы MAXIM
7W	http //www.ibutton.com..	.	Сайт, посвященный	микросхемам	iButton
http://www.ibutton.ru.	..	Сайт, посвященный	микросхемам	iButtcj.
(русский)
8ц http://book.microprocessor.by.ru........Сайт «Книги по микропроцессора;»'”