Текст
                    МИКГОКОПТГОППЕГП Н
Описание
внутреннего устройства
микропроцессоров
Разработка схем
на микроконтроллерах
Разработка и отладка программ
для микроконтроллеров
на языках Си и ассемблере
Александр Микушин


Александр Микушин оМНОНТРОППЕРПН Санкт-Петербург «БХВ-Петербург» 2006
УДК 681.3.06 ББК 32.973-04 М59 Микушин А. В. М59 Занимательно о микроконтроллерах. — СПб.: БХВ-Петербург, 2006. — 432 с: ил. ISBN 5-94157-571-8 Собраны материалы, затрагивающие различные аспекты проектирова- проектирования микропроцессорной техники: от сведений о простейших логических элементах до изложения принципов разработки микропроцессорных систем и достаточно сложных многомодульных программ для них. Из всего мно- многообразия микропроцессоров в качестве примера рассматриваются "клас- "классические", доступные и распространенные микроконтроллеры семейства MCS-51, поддерживаемые такими крупнейшими производителями, как Analog Devices и Texas Instruments. Большое внимание уделено построению структуры, принципам написания и отладке программ для микроконтрол- микроконтроллеров на языках Си и ассемблере. Приведены готовые шаблоны для напи- написания программ на ассемблере и показаны особенности применения языка Си для реализации конкретных устройств. При подготовке книги были ис- использованы материалы лекций по микропроцессорам, читаемых автором в течение ряда лет в Сибирском государственном университете телекоммуни- телекоммуникаций и информатики. Для широкого круга радиолюбителей и программистов УДК 681.3.06 ББК 32.973-04 Группа подготовки издания: Главный редактор Екатерина Кондукова Зам. главного редактора Игорь Шиишгин Зав. редакцией Григорий Добин Редактор Владимир Харитонов Компьютерная верстка Натальи Смирновой Корректор Наталия Першакова Дизайн обложки Елены Беляевой Зав. производством Николай Тверских Лицензия ИД № 02429 от 24.07.00. Подписано в печать 31.05.06. Формат 70x1001/ie. Печать офсетная. Усл. печ. л. 34,83. Тираж 3000 экз. Заказ № 328 "БХВ-Петербург", 194354, Санкт-Петербург, ул. Есенина, 5Б. Санитарно-эпидемиологическое заключение на продукцию № 77.99.02.953.Д.006421.11.04 от 11.11.2004 г. выдано Федеральной службой по надзору в сфере защиты прав потребителей и благополучия человека. Отпечатано с готовых диапозитивов в ГУП "Типография "Наука" 199034, Санкт-Петербург, 9 линия, 12 ISBN 5-94157-571-8 ©Микушин А. В., 2006 О Оформление, издательство "БХВ-Петербург", 2006
Оглавление Введение 1 Как пользоваться книгой 2 Глава 1. Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры 3 Классификация микропроцессоров 3 Универсальные процессоры 7 Микроконтроллеры 10 Сигнальные процессоры 12 Итак, подведем итоги 14 Глава 2. Цифровая техника 15 Простейшие логические элементы 16 Принципы реализации цифровых устройств по произвольной таблице истинности 20 Сумматоры 23 Дешифраторы 28 Мультиплексоры 31 Демультиплексоры 33 Шинные формирователи 34 Итак, подведем итоги 39 Глава 3. Запоминающие устройства 41 Постоянные запоминающие устройства 41 Триггеры 52 Регистры 56 Статические оперативные запоминающие устройства (ОЗУ) 60 Динамические оперативные запоминающие устройства (ОЗУ) 65 Итак, подведем итоги 71
IV Оглавление Глава 4. Принципы работы микропроцессора 73 Виды двоичных кодов 73 Беззнаковые двоичные коды 74 Прямые знаковые двоичные коды 74 Знаковые обратные двоичные коды 75 Знаковые дополнительные двоичные коды 76 Представление рациональных чисел в двоичном коде с фиксированной запятой 80 Представление рациональных чисел в двоичном коде с плавающей запятой 81 Представление десятичных чисел 84 Суммирование двоично-десятичных чисел 85 Представление текстовых данных в памяти процессора 86 Арифметико-логические устройства 86 Классификация микропроцессоров 91 Операционный блок микропроцессора 94 Блок микропрограммного управления 97 Команды микропроцессора 98 Микропрограммирование 101 Итак, подведем итоги 105 Глава 5. Принципы работы микропроцессорной системы 107 Системная шина 108 Адресное пространство микропроцессорного устройства 109 Способы расширения адресного пространства микропроцессора 112 Согласование быстродействия памяти и универсальных микропроцессоров 117 Подключение внешних устройств к микропроцессору 119 Принципы построения параллельного порта 123 Принципы построения последовательного порта 127 Синхронные последовательные порты 127 Асинхронные последовательные порты 131 Принципы построения таймеров 134 Итак, подведем итоги 138 Глава 6. Принципы работы микроконтроллеров 139 Семейство микроконтроллеров MCS-51 140 Архитектура микроконтроллеров MCS-51 142
Оглавление V Система команд микроконтроллеров MCS-51 147 Арифметические команды 148 Логические команды с байтовыми переменными 149 Команды пересылки данных 149 Битовые команды 150 Команды ветвления и передачи управления 151 Способы адресации операндов 154 Устройство параллельных портов микроконтроллеров MCS-51 156 Особенности построения памяти микроконтроллеров семейства MCS-51 164 Память программ микроконтроллеров MCS-51 165 Внешняя память данных микроконтроллеров MCS-51 167 Внутренняя память данных микроконтроллеров MCS-51 169 Регистры специальных функций 172 Внутренние таймеры микроконтроллера, особенности их применения 173 Режим 0 175 Режим 1 176 Режим 2 178 Режим 3 179 Управление таймерами/счетчиками 180 Использование таймера в качестве измерителя длительности импульсов 182 Использование таймера в качестве частотомера 183 Последовательный порт микроконтроллеров семейства MCS-51 185 Скорость приема/передачи информации через последовательный порт 187 Режим 0. Синхронный режим работы последовательного порта 189 Режим 1. Асинхронный 8-битовый режим 192 Режим 2. Асинхронный 9-битовый режим с фиксированной скоростью передачи 197 Режим 3. Асинхронный 9-битовый режим 199 Итак, подведем итоги 200 Глава 7. Принципы создания программ для микроконтроллеров 201 Языки программирования для микроконтроллеров 202 Виды программ-трансляторов 204 Виды компиляторов 205 Применение подпрограмм 206 Стек, его организация и структура 208
Оглавление Подпрограммы-процедуры и подпрограммы-функции 210 Применение комментариев 212 Структурное программирование 214 Линейная цепочка операторов 217 Условное выполнение операторов 220 Конструкция управления циклическим выполнением оператора с проверкой условия после тела цикла 225 Структурная конструкция циклического выполнения оператора с проверкой условия до тела цикла 228 Понятие многофайлового и многомодульного программирования 230 Многофайловые программы 231 Многомодульные программы 237 Программа-монитор 241 Использование таймера для организации параллельных программных потоков 258 Использование прерываний для ввода информации о кратковременных сигналах и событиях, наступающих в произвольный момент времени 261 Итак, подведем итоги 265 Глава 8. Язык программирования ASM-51 267 Исходный текст программы на языке программирования ASM-51 269 Символы языка ASM-51 271 Идентификаторы 272 Ключевые слова 273 Встроенные имена 274 Определяемые имена 274 Числа и литеральные строки 275 Директивы языка программирования ASM-51 277 Управляющие команды 283 Реализация подпрограмм на языке ASM-51 285 Реализация подпрограмм-процедур на языке ASM-51 285 Передача переменных-параметров в подпрограмму 286 Реализация подпрограмм-функций на языке ASM-51 289 Реализация подпрограмм обработки прерываний на языке ASM-51 290 Структурное программирование на языке ASM-51 293 Многомодульные программы 298 Использование сегментов в языке программирования ассемблер 301 Итак, подведем итоги 308
Оглавление VII Глава 9. Язык программирования С-51 309 Структура программ С-51 314 Элементы языка С-51 317 Используемые символы алфавита 317 Лексические единицы, разделители и использование пробелов 320 Идентификаторы 321 Ключевые слова 323 Константы 323 Использование комментариев в тексте программы 327 Типы данных языка программирования С-51 и их объявление 328 Категории типов данных 331 Целочисленный тип данных 332 Числа с плавающей запятой 333 Переменные перечислимого типа 333 Указатели 336 Указатели общего вида 337 Специализированные указатели 339 Массивы 340 Структуры 342 Битовые поля 344 Объединения (смеси) 345 Определение типов 346 Инициализация данных 347 Выражения 349 Операнды и операции 350 Преобразования типов при вычислении выражений 357 Операции унарного минуса, логического и поразрядного отрицания 358 Операции разадресации и вычисления адреса 359 Операция sizeof. 360 Мультипликативные операции 360 Аддитивные операции 361 Операции сдвига 363 Поразрядные операции 363 Логические операции 364 Операция последовательного вычисления 365 Условная операция 365 Операции инкремента и декремента 366 Простое присваивание 367
VIII Оглавление Составное присваивание 367 Приоритеты операций и порядок вычислений 368 Побочные эффекты 368 Преобразование типов 369 Операторы 372 Оператор-выражение 372 Пустой оператор 373 Составной оператор 373 Оператор // 374 Оператор switch 376 Оператор break 379 Оператор цикла/о/- 379 Оператор цикла while 381 Оператор цикла do-while 382 Оператор continue 383 Оператор возврата из функции return 383 Оператор безусловного перехода goto 384 Использование функций в языке программирования С-51 385 Определение и вызов функций 385 Итак, подведем итоги 393 Приложение. Справочные данные по системе команд микроконтроллера MCS-51 и кодировке символов 395 Литература 418 Предметный указатель 420
Введение Особенностью этой книги является то, что в одном месте собраны мате- материалы, затрагивающие различные аспекты проектирования микропро- микропроцессорной техники: от сведений о простейших логических элементах до изложения принципов разработки микропроцессорных систем и доста- достаточно сложных многомодульных программ для них. Такой подборки ма- материала не встречается ни в одной книге (за исключением достаточно старых изданий, опубликованных на заре появления микропроцессоров). Книга не рассчитана на подготовленных читателей, для которых все это — элементарные вещи. Однако, как показывает мой опыт, обычно люди, работающие в этой сфере, владеют какой-то одной из приведенных об- областей разработки микроконтроллерных устройств. И даже опытные программисты микропроцессоров, прекрасно знакомые с особенностями построения аппаратуры, часто не владеют основами программирования, хорошо известными их коллегам, пишущим программы для универсаль- универсальных компьютеров. Достаточно часто препятствием в освоении микропроцессорной техники становится непонимание того, как работает сам микропроцессор или микроконтроллер. В этой книге сделана попытка объяснить принципы устройства этих микросхем на рассмотрении примеров упрощенных ва- вариантов внутренней структуры. Только после этого происходит переход к обсуждению особенностей применения реально существующего семей- семейства микросхем. Почему в качестве примера выбрано семейство микроконтроллеров MCS-51? Да потому что оно наиболее распространено в мире. Даже на территории России производится несколько типов микросхем, выпол- выполненных по этой архитектуре. Это семейство стало классикой микрокон- микроконтроллеров. Разобраться с работой этих микросхем проще всего, а подоб- подобрать подходящую для конкретной задачи — тем более. Даже если один из многочисленных производителей микроконтроллеров семейства MCS- 51 прекратит их производство, то всегда найдутся десятки других, кото- которые с радостью предоставят вам свою продукцию, так что усилия, затра- затраченные на изучение предлагаемого материала, не пропадут даром. Еще одной важной особенностью данной книги является то, что в ней рассматриваются не только особенности разработки схем с использова- использованием микропроцессоров, но и принципы написания программ для этих микроконтроллеров. При этом большое внимание уделяется тому, что
Введение некоторые задачи элементарно решаются схемотехническими методами, но при этом требуют невероятных усилий при использовании для их ре- решения программных подходов. И наоборот, другие функции устройства элементарно решаются программными методами, но при попытке схем- схемной реализации требуют невероятных усилий от разработчика схемы. В книге максимальное внимание уделено принципам написания и отлад- отладке программ, требующих минимальных усилий от программиста. С са- самого начала уделяется большое внимание построению структуры про- программы, которая позволила бы увеличивать свою сложность по мере необходимости и не требовала бы переписывания заново при малейшем изменении исходного задания разрабатываемого устройства. Даются готовые шаблоны для написания программ на ассемблере. Это позволяет упростить программирование на ассемблере и приблизить по сложности к разработке программ на языках высокого уровня. Программирование на языке высокого уровня рассматривается на при- примере С-51. При этом большое внимание уделяется особенностям приме- применения этого языка программирования для реализации конкретных уст- устройств (а не вычислительных задач). Рассматриваются влияние выбора типов переменных и операторов этого языка на эффективность и размер конечной программы, т. е. вопросы, чрезвычайно важные для микропро- микропроцессорных устройств. Как пользоваться книгой Книга организована по принципу перехода от простого к сложному. Ос- Основной целью является преодоление порога, с которым сталкивается лю- любой разработчик или пользователь аппаратуры, построенной с примене- применением микропроцессорной техники. Материал начинается с рассмотрения простейших логических элементов, а заканчивается обсуждением особенностей разработки микропроцес- микропроцессорных систем и написания программ для микропроцессоров, применен- примененных в данной системе. В зависимости от уровня подготовки и интересов читателя можно про- пропускать отдельные главы, однако материал подобран так, что каждая последующая глава опирается на предыдущую. Более того, поскольку для понимания принципов работы микропроцессоров нужно знать все разделы цифровой схемотехники и основы программирования, то имеет смысл после прочтения последующих глав возвращаться к предыдущим. В результате те части материала, что, возможно, показались непонятны- непонятными при первом прочтении, при повторном обращении к ним могут ока- оказаться элементарными.
mw\ Глава 1 Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры Слово «микропроцессоры» у всех на слуху. Сигнальные процессоры из- известны меньшему кругу людей, однако и это понятие достаточно распро- распространено. Что же такое микроконтроллеры? Микроконтроллеры, как и остальные виды процессоров, в настоящее время выполняются в виде одной микросхемы. Микросхемы микроконтроллеров предназначены для управления различными объектами. В качестве таких объектов могут выступать радиостанции, приемники, сотовые телефоны, телевизоры и т. д. Обычно микроконтроллеры выполняются в виде готовых одно- однокристальных ЭВМ. Прежде чем заняться микроконтроллерами более подробно, рассмотрим, к какой области техники относятся микросхемы этого класса, и какой круг задач они решают. Классификация микропроцессоров Современные электронные устройства, в том числе и микроконтроллеры, выполняются на основе интегральных микросхем. Основные разновид- разновидности применяемых в настоящее время микросхем показаны на рис. 1.1. Все микросхемы разделяются на две большие группы: аналоговые и циф- цифровые. Преимущества и недостатки каждой из них известны. Аналоговые микросхемы характеризуются максимальным быстродействием при ма- малом потреблении энергии и сравнительно малой стабильностью пара- параметров. Цифровые микросхемы обладают прекрасной повторяемостью
4_ Глава 1 параметров, меньшей чувствительностью к воздействию помех. В по- последние годы, при применении цифровых микросхем для построения приемопередающих устройств, а также устройств обработки звука и изо- изображения удалось достигнуть большего по сравнению с аналоговой тех- техникой динамического диапазона. Эти преимущества и привели к быст- быстрому развитию цифровой техники в последние годы. Микросхемь Цифровые Микро- Микропроцессоры Универ- Универсальные Аналоговые Программируемые логические схемы Жесткая логика Микро- Микроконтроллеры Сигнальные Рис. 1.1. Место, занимаемое микропроцессорами среди микросхем По мере развития цифровых микросхем их быстродействие достигло впечатляющих результатов. Наиболее быстрые обладают временем пе- переключения порядка 3-5 не (серия микросхем 74ALS), а внутри кристал- кристалла микросхемы, где нет больших емкостей нагрузки, время переключения измеряется пикосекундами. Таким быстродействием обладают програм- программируемые логические интегральные схемы (ПЛИС) и заказные большие интегральные схемы (БИС). В этих микросхемах алгоритм решаемой за- задачи воплощен в их внутренней структуре. Часто для решаемой задачи не требуется такого быстродействия, каким обладают современные цифровые микросхемы. Однако за быстродейст- быстродействие приходится платить. Это выражается в следующем: ? быстродействующие микросхемы потребляют значительный ток, что ограничивает их сложность (уровень интеграции); ? для решения задачи приходится использовать много микросхем, что выливается в высокую стоимость и большие габариты устройства. Напомню основные характеристики различных видов цифровых микро- микросхем. Наибольшим быстродействием и наименьшей помехоустойчивостью об- обладали ЭСЛ-микросхемы (эмиттерно-связанная логика). Однако прин-
Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры 5 ципиальная особенность работы этих микросхем, заключающаяся в ра- работе входящих в их состав транзисторов в активном режиме, приводит к тому, что микросхемы такого типа обладают пониженной помехоустой- помехоустойчивостью. Это затрудняет построение микросхем, надежно реализующих достаточно сложные алгоритмы работы. В настоящее время ЭСЛ- микросхемы практически не применяются. Следующий вид цифровых микросхем — это ТТЛ (транзисторно- транзисторная логика). Современные ТТЛ-микросхемы обладают почти таким же быстродействием, как традиционная ЭСЛ. В связи с особенно- особенностями внутреннего устройства ТТЛ-микросхемы потребляемый ею ток питания не зависит от скорости переключения логических вентилей. И работая на пределе быстродействия, и переключаясь только несколь- несколько раз в секунду, микросхема потребляет одинаковый ток. Поэтому выпускается несколько различных серий ТТЛ-микросхем, обладающих различным быстродействием и, соответственно, различным током по- потребления. В современном мире наибольшее распространение получили КМОП- микросхемы, построенные на комплементарных транзисторах с изолиро- изолированным затвором. Их особенностью является то, что используется двух- двухтактная схема. В статическом состоянии, если один из двух последова- последовательно включенных транзисторов с разным типом проводимости открыт, то второй закрыт. Это означает, что ток через логический вентиль не протекает ни при формировании на выходе логической единицы, ни при формировании логического нуля. То есть в статическом состоянии через микросхему протекают только токи утечки транзисторов и из цепи пита- питания практически ничего не потребляется. Потребляемый ток возрастает только при увеличении скорости переключения логических КМОП- вентилей. На предельных скоростях работы КМОП-микросхемы ее по- потребление становится сравнимым с аналогичным параметром ТТЛ- микросхем и даже может превосходить его. Итак, задачу потребления минимального тока, обеспечивающего тре- требуемое в данный момент быстродействие, решает применение КМОП- микросхем (например, серий 1564, 74НС, 74АНС, универсальных микро- микропроцессоров AMD или PENTIUM). Именно поэтому в настоящее время преимущественное распространение получили КМОП-микросхемы. Задачу уменьшения стоимости и габаритов решают несколькими спосо- способами. Для жесткой логики — это разработка специализированных БИС. Их использование позволяет уменьшить габариты устройства, но стои- стоимость его снижается только при крупносерийном производстве, таком как производство радио- или телевизионной аппаратуры. Для среднего и малого объемов производства такое решение неприемлемо. Тем не менее,
_б __ Глава 1 для крупносерийного производства альтернативы этой технологии нет, так как при этом получается наименьшая стоимость микросхем. Еще одним решением уменьшения габаритов и стоимости устройства яв- является применение программируемых логических интегральных схем (ПЛИС). В этих микросхемах присутствуют как бы два слоя. Один слой — это набор цифровых модулей, способных решить практически любую задачу. Второй слой хранит структуру связей между модулями первого слоя. Эту структуру можно программировать, и тем самым менять схему устройства, а значит и решаемую микросхемой задачу. Это направление активно развивается в настоящее время, но оно не входит в рамки рас- рассмотрения данной книги. Третий способ решения задачи уменьшения габаритов и стоимости за- заключается в том, что можно заставить одно очень быстродействующее устройство со сложной внутренней структурой, допускающей реализа- реализацию большого числа элементарных операций, последовательно решать различные задачи. Этот подход воплощают микропроцессоры. В микро- микропроцессорах возможен обмен предельного быстродействия на сложность реализуемого в этой микросхеме устройства. Быстродействие микропро- микропроцессоров стараются максимально увеличить — это позволяет реализовы- вать все более сложные устройства в одном и том же объеме полупро- полупроводникового кристалла. Более того! В одном процессоре можно реализовать несколько устройств одновременно! Именно этот вариант решения задачи уменьшения габаритов и стоимости устройств и рас- рассматривается в предлагаемой вашему вниманию книге. В современном мире трудно найти область техники, где не применялись бы микропроцессоры. Они используются для вычислений, выполняют функции управления, обрабатывают звук и изображение. В зависимости от области применения микропроцессора варьируются требования к не- нему. Это накладывает отпечаток на его внутреннюю структуру. В настоя- настоящее время определилось три основных направления развития микропро- микропроцессоров, подразумевающих различную внутреннюю структуру этих устройств: ? универсальные микропроцессоры; ? микроконтроллеры; ? сигнальные микропроцессоры. Универсальные микропроцессоры служат для построения вычислитель- вычислительных машин. В них используются самые передовые решения, направлен- направленные на повышение быстродействия; при этом не обращают особого вни- внимания на габариты, стоимость и потребляемую энергию. Компьютеры не только работают у вас дома или в офисе, но и используются для управ-
Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры 7 ления системами или устройствами, обладающими большими габарита- габаритами и стоимостью. Для всех этих приложений массогабаритные и энерге- энергетические показатели не имеют особого значения. Микроконтроллеры. Для управления малогабаритными и дешевыми уст- устройствами используются однокристальные микроЭВМ, которые в на- настоящее время называют микроконтроллерами. В микроконтроллерах максимальное внимание уделяется именно уменьшению габаритов, стоимости и потребляемой энергии. Сигнальные процессоры. Еще один класс микропроцессоров решает за- задачи, которые традиционно выполняли аналоговые электронные уст- устройства. К сигнальным процессорам предъявляются специфические требования. От них требуются максимальное быстродействие и малые габариты, простая стыковка с аналого-цифровыми и цифроаналого- выми преобразователями, большая разрядность обрабатываемых дан- данных и небольшой набор математических операций, обязательно вклю- включающий операцию умножения-накопления и аппаратную организацию циклов. Рассмотрим более подробно каждую из упомянутых категорий микро- микропроцессоров. Универсальные процессоры Универсальные процессоры разрабатывают для применения в составе компьютеров, однако это не значит, что они могут использоваться толь- только для вычислений. Эти процессоры с успехом применяют для построе- построения игровых приставок, устройств коммутации в составе компьютерных сетей, а также в различных измерительных или медицинских приборах. Значимой составляющей стоимости любого устройства является разра- разработка и изготовление его схемы, и чем крупнее серийность изделия, тем меньшую часть в его стоимости занимает эта составляющая. В настоящее время серийность изготовления универсальных компьютеров достигла невероятных размеров. Поэтому возникает желание воспользоваться компьютером в качестве основы для изготовления различных устройств. При этом в состав их цены будет входить стоимость готового компьюте- компьютера, минимизированная за счет крупной серийности! Разработка и изго- изготовление элементов, функции которых будет выполнять универсальный компьютер, не потребуют затрат времени и денег! Разработка нового устройства сведется к созданию специализированной программы и эле- элементов, отсутствующих в универсальном компьютере.
8 Глава 1 Для управления автоматическими телефонными станциями, системами сотовой связи или кораблями часто используют универсальные компью- компьютеры. Обычно для построения такого типа устройств управления требу- требуются специфические модули сбора информации или вывода управляю- управляющих воздействий. Такие модули выполняют в виде отдельных блоков, подключаемых к компьютеру через один из стандартных портов, таких как LPT, USB или СОМ-порт. В тех случаях, когда нет жестких требова- требований к электромагнитной совместимости, дополнительные блоки могут выполняться в виде плат, подключаемых непосредственно к внутренним шинам компьютера. При этом не нужно изготавливать отдельные корпу- корпуса и блоки питания для дополнительных модулей, да и размеры нового устройства ограничиваются габаритами самого компьютера. Довольно часто для реализации нового прибора достаточно приобрести платы аналого-цифрового или цифроаналогового преобразователя или под- подключить плату согласования с телевизионной камерой и написать про- программу для этого прибора. шА Рис. 1.2. Примеры использования универсальных компьютеров для реализации различной аппаратуры По мере ужесточения требований к приборам готовый компьютер пере- перестает подходить для их реализации, но можно использовать отдельные блоки от компьютера, такие как материнские платы или платы аналого- цифровых преобразователей. Кроме того, существуют промышленные варианты материнских плат компьютеров, рассчитанные на работу в более
Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры 9 тяжелых условиях реального производства. Часто они имеют одноплат- одноплатное исполнение, что благоприятно сказывается на габаритах и энергопо- энергопотреблении. Пример такого одноплатного промышленного компьютера приведен на рис. 1.3. Рис. 1.3. Пример одноплатного встраиваемого компьютера В качестве примера устройств, для реализации которых использованы готовые одноплатные компьютеры, можно назвать приборы, выпускае- выпускаемые фирмой Rohde & Schwarz. На рис. 1.4 приведена фотография спек- троанализатора этой фирмы. |*? .... л ¦¦:¦. :¦ . ¦. ¦: ... . ¦ ::; .¦.;.. ..-. :-¦¦¦::' ¦ ¦¦: ¦ '.- :¦ . '.- ¦: ¦¦.¦ Рис. 1.4. Спектроанализатор фирмы Rohde & Schwarz
10 Глава 1 Микроконтроллеры Термин «контроллер» образовался от английского слова to control — управлять. Контроллеры можно реализовать на устройствах различно- различного принципа действия: от механических или оптических до электрон- электронных, аналоговых или цифровых элементов. Механические устройства управления (контроллеры) обладают низкой надежностью и высокой стоимостью по сравнению с электронными, поэтому в дальнейшем мы их рассматривать не будем. Электронные аналоговые устройства име- имеют недостаточно стабильные параметры и потому требуют периодиче- периодической подстройки и регулировки, что увеличивает стоимость их экс- эксплуатации. Поэтому такие устройства к настоящему времени стараются не использовать. Наиболее распространенными на сегодняшний день являются электронные устройства управления, построенные на основе цифровых микросхем. В зависимости от стоимости и габаритов устройства, которым требуется управлять, определяются и требования к контроллеру. Если объект управления занимает десятки квадратных метров, как, например, авто- автоматические телефонные станции, базовые станции сотовых систем связи или радиорелейные линии связи, то в качестве контроллеров можно ис- использовать универсальные компьютеры. Управление при этом можно осуществлять через их встроенные порты компьютера: LPT, COM, USB или ETHERNET. В оперативную память таких компьютеров при вклю- включении питания заносится управляющая программа, которая и превраща- превращает универсальный компьютер в контроллер. Использование универсального компьютера в качестве контроллера по- позволяет в кратчайшие сроки производить разработку новых систем свя- связи, легко их модернизировать (путем простой смены программы), а так- также использовать готовые, выпускаемые крупными сериями (а значит, дешевые) блоки. Однако контроллеры требуются не только для больших систем, но и для малогабаритных радиоэлектронных устройств, таких как радиоприем- радиоприемники, радиостанции, магнитофоны или сотовые телефонные аппараты. В малогабаритных устройствах предъявляются жесткие требования к стоимости, габаритам и температурному диапазону работы контролле- контроллеров. Этим требованиям не могут удовлетворить даже промышленные варианты универсального компьютера. Приходится вести разработку контроллеров на основе однокристальных ЭВМ, которые получили на- название микроконтроллеры.
Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры 11 Контроллеры требуются практически во всех предметах и устройствах, которые окружают нас. В качестве примера на рис. 1.5 показаны узлы автомобиля, в которых применяются микроконтроллеры. Автомобильная и носимая радиостанции, в которых тоже применяются однокристальные микроконтроллеры, показаны на рис. 1.6 и 1.7. ,. Внешние датчики с и с т е ••. a. i b t z о и а. с н о с тк Управ те кие tori ¦ ЕЙ . 11 p %j:i и апп «ip атг'р on Рис. 1.5. Узлы автомобиля, в которых применяются микроконтроллеры J I ™ J Рис. 1.6. Автомобильная радиостанция с применением микроконтроллеров Рис. 1.7. Носимая радиостанция с применением микроконтроллеров
12 Глава 1 Как выглядит носимая радиостанция внутри, показывает фотография, приведенная на рис. 1.8. Практически во всех узлах радиостанции ис- используются микроконтроллеры. Рис. 1.8. Печатная плата приемопередатчика носимой радиостанции Наиболее распространенными в настоящее время являются микрокон- микроконтроллеры семейства MCS-51. Они выпускаются рядом фирм — произво- производителей микросхем. Не менее распространенными в мире, но не в России являются микроконтроллеры фирмы Motorola. Это такие семейства 8- разрядных микроконтроллеров, как НС05, НС07, HCl l и многие другие. Пожалуй, не менее популярными являются микроконтроллеры AVR фирмы Atmel. Одно перечисление семейств микроконтроллеров может занять несколько страниц текста, поэтому ограничимся приведенным перечнем. Сигнальные процессоры Сигнальные процессоры, как следует из названия, предназначены для обработки сигналов. Важнейшей их задачей является реализация частот- частотной фильтрации входного сигнала. При реализации этого алгоритма требуется обеспечить максимальное быстродействие. Для данного класса
Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры 13 микропроцессоров потребление энергии часто не является определяю- определяющим требованием. Анализ алгоритмов цифровой обработки сигналов показывает, что ос- основной вклад в вычислительные затраты вносит умножение отсчетов входного сигнала на весовые коэффициенты. Поэтому основным блоком для сигнального процессора является аппаратный умножитель. Еще одной особенностью выполнения алгоритма фильтрации является возможная потеря точности при многократном суммировании результа- результатов перемножения. Поэтому обычно в сигнальных процессорах исполь- используются многоразрядные перемножители, сумматоры и соответствующие им многоразрядные регистры-аккумуляторы. Обычно разрядность таких сумматоров составляет сорок двоичных разрядов. При выполнении любого циклического алгоритма, а к этой категории, несомненно, относятся алгоритмы цифровой фильтрации, значительное время расходуется на организацию самого цикла. Требуется изменение счетчика циклов, проверка содержимого счетчика на равенство заданно- заданному значению, изменение содержимого указателей на текущий адрес па- памяти отсчетов сигнала цифрового фильтра и на текущий адрес памяти коэффициентов. Внутренняя структура сигнальных процессоров построена так, что все перечисленные задачи выполняются за один машинный такт. Это позво- позволяет значительно повысить алгоритмическое быстродействие сигналь- сигнальных процессоров. Именно наличие модулей умножения с накоплением вместе с аппаратной поддержкой циклического выполнения алгоритма позволяет отнести микропроцессор к классу сигнальных процессоров. Чрезвычайно важной для сигнального процессора является также воз- возможность легко соединяться с микросхемами аналого-цифровых (АЦП) и цифроаналоговых преобразователей (ЦАП). В ряде относительно де- дешевых сигнальных процессоров используются встроенные АЦП и ЦАП, но системы, построенные на таких микросхемах, обычно обладают сред- средними характеристиками. Первоначально сигнальные процессоры подключали модули АЦП или ЦАП через системную шину (такой подход сохраняется до сих пор для очень высоких скоростей обмена информацией), однако в дальнейшем наибольшее распространение получило подключение через универсаль- универсальный синхронный последовательный порт. Наличие параллельных пор- портов, в отличие от микроконтроллеров, не является обязательным для сигнальных процессоров.
14 Глава 1 Наиболее сильные позиции на рынке сигнальных процессоров в настоя- настоящее время занимают такие фирмы, как Analog Devices и Texas Instruments. Именно они предлагают в настоящее время наиболее производительные модели сигнальных процессоров. Не менее сильными являются позиции фирмы Motorola, но в нашей стране процессоры этого производителя менее распространены. Итак, подведем итоги Разнообразие микропроцессоров поражает, но все они построены по одинаковым принципам, которые будут рассмотрены в данной книге. При этом микропроцессоры будут рассматриваться на примере микро- микроконтроллеров. Причем микроконтроллеров очень распространенного в настоящее время семейства — MCS-51. Однако прежде чем начать под- подробное изучение принципов работы с микропроцессорами, рассмотрим основы работы цифровых систем, частью которых являются микропро- микропроцессоры.
moon Глава 2 Цифровая техника Итак, рассмотрев какие виды микропроцессоров бывают и для решения каких видов задач они применяются, можно приступить к решению во- вопроса — как же они устроены? Как уже говорилось, микропроцессорная техника является частью цифровой техники. Поэтому, не зная основ цифровой техники, невозможно понять, как работает микропроцессор. Начнем с самых элементарных вопросов: из каких элементов строятся цифровые схемы и как они устроены? Затем научимся реализовывать на основе этих простейших элементов цифровые устройства любой сложно- сложности. Следует отметить, что в данной книге вы не получите обзора всего разнообразия цифровых устройств. Будут рассмотрены только те цифро- цифровые устройства, которые используются непосредственно в микропроцес- микропроцессорной технике. В данной главе будут рассмотрены только сумматоры и устройства ком- коммутации цифровых сигналов. Однако, при необходимости, можно и ра- разобраться в оставшихся за рамками данной книги разделах цифровой техники, применив рассмотренные методы построения цифровых уст- устройств. Обычно любые устройства предназначены для преобразования входных сигналов в выходные. Свойства аналоговых схем описываются рядом общепринятых параметров (например, коэффициентом усиления и дина- динамическим диапазоном) и характеристик (амплитудно-частотные и фазо- частотные характеристики). Иначе обстоит дело с параметрами цифровых микросхем. Для идеализи- идеализированных цифровых устройств коэффициент усиления не нормируется — он реализуется достаточным для того, чтобы сигнал на выходе не затухал. И только! Логические уровни на входе и выходе цифровых микросхем одинаковы. Если логический элемент обладает запасом по коэффициенту усиления, то выходной сигнал просто ограничивается. Конкретное зна-
16 Глава 2 чение логических уровней зависит от напряжения питания цифровых микросхем и примененной схемотехники, но это не меняет принципов работы цифрового устройства. Цифровые схемы наиболее полно описываются таблицей истинности. Таблица истинности позволяет поставить выходные сигналы в соответ- соответствие входным сигналам. Обычно каждый из выходных сигналов цифро- цифрового устройства зависит от нескольких входных сигналов этого цифро- цифрового устройства. Поэтому в таблице истинности перечисляются все возможные комбинации входных сигналов и записывают соответствую- соответствующий каждой комбинации входных сигналов выходной сигнал. Достаточно часто одним и тем же комбинациям входных цифровых сиг- сигналов соответствуют несколько выходных сигналов. Тогда для всех вы- выходных сигналов записывается одна таблица истинности. Для простейших цифровых логических элементов таблица истинности состоит из одного выходного и одного или двух входных сигналов. Рас- Рассмотрим эти элементы. Простейшие логические элементы Любые цифровые устройства строятся на основе простейших логических элементов: «НЕ», «ИЛИ», «И». Самым простым логическим элементом является инвертор (элемент «НЕ»), который работает в соответствии с табл. 2.1. Он просто изменяет значение входного сигнала на прямо про- противоположное. В качестве инвертора можно использовать обычный транзисторный усилитель, построенный по схеме с общим эмиттером или общим истоком. Схемы, позволяющие реализовать функцию логиче- логического инвертирования, изображены на рис. 2.1. На рис. 2.1, а приведена схема инвертора на обычном биполярном транзисторе, а на рис. 2.1,6 приведена схема инвертора, выполненного на комплементарных МОП- транзисторах. Таблица 2.1. Таблица истинности логического инвертора Вход 0 1 Выход 1 0 Условное графическое обозначение инвертора на схемах не зависит от схемотехники, использованной для его реализации, оно приведено на
Цифровая техника 17 рис. 2.2. С этого момента инвертор будет изображаться исключительно в таком виде. +U, Рис. 2.1. Схемы, реализующие функцию логического инвертирования L Рис. 2.2. Условное графическое обозначение инвертора Следующий распространенный элемент цифровой техники реализует ло- логическую операцию «И», однако чаще всего в качестве готовых микро- микросхем существуют не отдельные схемы логического «И», а более сложные устройства, выполняющие одновременно две логические функции: «И» и «НЕ». Таблица истинности элемента, выполняющего логическую функ- функцию «2И-НЕ», приведена в табл. 2.2. Проще всего построить такой элемент на самых обыкновенных ключах, как это показано на рис. 2.3, а. В этой схеме ток будет протекать только в том случае, если оба ключа окажутся замкнутыми (будем считать, что такое их состояние достигается при управлении логической единицей). Это означает, что нулевой уровень на выходе схемы появится только при двух логических единицах на входе, т. е. приведенная схема реализует логическую функцию «2И-НЕ» (табл. 2.2). Точно таким же образом вы- выполняется элемент «2И-НЕ» и в микросхемах, построенных на КМОП- транзисторах, только в качестве ключа используется транзистор. Схема
18 Глава 2 логического элемента «2И-НЕ», выполненного на комплементарных МОП-транзисторах, приведена на рис. 2.3, б. Таблица 2.2. Таблица истинности схемы, выполняющей логическую функцию «2И-НЕ» Вход X 0 0 1 1 ВходУ 0 1 0 1 Выход 1 1 1 0 I п V 1 \ it' 1 * \ \ / _, +ип у \ Рис. 2.3. Принципиальные схемы цифровых элементов, реализующих логическую функцию «2И-НЕ» Условное графическое обозначение элемента, выполняющего логиче- логическую функцию «2И-НЕ», приведено на рис. 2.4, и с этого момента эле- элементы, выполняющие данную функцию, будут изображаться именно е таком виде. Это обозначение не зависит от конкретной схемы построе- построения цифрового элемента. Рис. 2.4. Условное графическое обозначение цифрового элемента, выполняющего логическую функцию «И-НЕ»
Цифровая техника 19 Точно так же, как редко можно встретить отдельный элемент логическо- логического «И», практически не производятся отдельные элементы логического «ИЛИ». Чаще встречаются элементы «2ИЛИ-НЕ», таблица истинности которых приведена в табл. 2.3. Таблица 2.3. Таблица истинности цифрового элемента, выполняющего логическую функцию «2ИЛИ-НЕ» Вход X 0 0 1 1 ВходУ 0 1 0 1 Выход 1 0 0 0 Как и в предыдущем случае, воспользуемся для реализации элемента «2ИЛИ-НЕ» ключами. На этот раз соединим ключи параллельно. Схема, реализующая таблицу истинности табл. 2.3, приведена на рис. 2.5, а. Схема логического элемента «2ИЛИ-НЕ», выполненного на КМОП- транзисторах, показана на рис. 2.5, б. Как видно из приведенных схем, уровень логического нуля появится на выходе любой из этих схем, как только любой из ключей будет замкнут, т. е. приведенные схемы реали- реализуют таблицу истинности табл. 2.3. I п +и \/ п I / \ \ ¦*- \ •* Рис. 2.5. Принципиальные схемы элемента, реализующего логическую функцию «2ИЛИ-НЕ» Так как один и тот же логический элемент может быть реализован раз личными способами, для его изображения на схемах используется специ- специальное условное графическое обозначение, приведенное на рис. 2.6.
20 Глава 2 Рис. 2.6. Условное графическое обозначение элемента, выполняющего логическую функцию «2ИЛИ-НЕ» Принципы реализации цифровых устройств по произвольной таблице истинности Любое цифровое устройство полностью описывается таблицей истинно- истинности. При построении сложных устройств с произвольной таблицей ис- истинности используется сочетание простейших элементов: «И» «ИЛИ» «НЕ». Если устройство имеет несколько выходов, то формирование сиг- сигнала для каждого из них анализируется отдельно и для каждого из них строится отдельная схема. Для реализации устройства можно воспользоваться как элементами «И», так и элементами «ИЛИ». В настоящее время наиболее распространены микросхемы, совместимые с ТТЛ, а в ТТЛ проще всего получить элемен- элементы «И», выходы которых объединены по функции «ИЛИ», поэтому рас- рассмотрим способ реализации произвольной таблицы истинности, осно- основанный на комбинации логических элементов «И-ИЛИ». Для реализации таблицы истинности при помощи логических элементов «И» достаточно рассмотреть только те ее строки, которые содержат ло- логические единицы в выходном сигнале. Строки, содержащие в выходном сигнале логический ноль, в построении схемы не участвуют. Каждая строка, содержащая в выходном сигнале логическую единицу, реализует- реализуется элементом логического «И» с количеством входов, совпадающим с количеством входных сигналов в таблице истинности. Таблица 2.4. Произвольная таблица истинности Входы InO 0 0 1п1 0 0 In2 0 0 In3 0 1 Выходы OutO 0 1 Out1 0 0
Цифровая техника 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 0 0 1 1 1 1 Входы 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 21 Таблица 2.4 (окончание) 0 0 0 0 1 0 0 0 0 0 1 0 0 0 Выходы 0 0 0 1 0 0 0 1 0 0 0 0 0 1 Входные сигналы, описанные в таблице истинности логической едини- единицей, подаются на вход этого элемента непосредственно, а входные сиг- сигналы, описанные в таблице истинности логическим нулем, подаются на вход этого же элемента «И» через инверторы. Объединение сигналов с выходов элементов «И», реализующих отдельные строки таблицы истинности, производится при помощи элемента логического «ИЛИ». Количество входов элемента «ИЛИ» определяется количеством строк таблицы истинности, в которых в выходном сигнале присутствует ло- логическая единица. Для сокращения количества инверторов имеет смысл выделить их в от- отдельный блок, который сразу сформирует сигналы, инверсные по отно- отношению к входным сигналам цифрового устройства. Теперь для реализа- реализации строки таблицы истинности достаточно соединить входы логического элемента «И» с соответствующими инвертированными и неинвертированными входными сигналами. Рассмотрим конкретный пример. Пусть необходимо реализовать устрой- устройство с таблицей истинности, приведенной в табл. 2.4. Для построения схемы, реализующей сигнал Outl, достаточно рассмотреть строки, выде- выделенные жирным шрифтом. Эти строки реализуются микросхемой D2 на
22 Глава 2 рис. 2.7. Каждая строка реализуется своим многовходовым элементом «И», затем выходы этих элементов объединяются по «ИЛИ». Количество входов элемента «И» однозначно определяется числом входных сигналов в таблице истинности. Количество этих элементов, а значит и входов в логическом элементе «ИЛИ», определяется количеством строк с единич- единичным сигналом на реализуемом выходе цифрового устройства. InO Inl In2 In3 Dl InO Inl In2 In3 1 о 1 к. 1J 1J 1 J >— S—н у 4 & & & 1 & & & 1 D2 ОиШ D3 Outl Рис. 2.7. Принципиальная схема устройства, реализующего таблицу истинности, приведенную в табл. 2.4 Для построения схемы, реализующей сигнал Out2, достаточно рассмотреть строки, выделенные курсивом. Соответствующая логическая функция реа- реализуется микросхемой D3. Принцип построения этой схемы такой же, как в примере, рассмотренном выше, и поэтому повторяться не будем. Обычно при построении цифровых устройств после реализации таблицы истинности производится минимизация схемы, но для упрощения изло- изложения материала в этой книге она выполняться не будет. Отказ от мини- минимизации оправдан еще и тем, что неминимизированные схемы обычно обладают максимальным быстродействием.
Цифровая техника 23 Сумматоры Важным элементом цифровых устройств, выполняющих арифметиче- арифметическую обработку цифровой информации, является сумматор. Построение двоичных сумматоров обычно начинается с сумматора по модулю 2. В табл. 2.5 приведена таблица истинности этого сумматора. Ее можно получить, исходя из правил суммирования в двоичной арифметике. Предполагается, что читатель знаком с основами двоичной арифметики. Более подробно операции над двоичными числами будут рассмотрены позднее. Таблица 2.5. Таблица истинности сумматора по модулю 2 ВходХ 0 0 1 1 ВходУ 0 1 0 1 Выход 0 1 1 0 В соответствии с принципами построения произвольной таблицы истин- истинности, рассмотренными в предыдущей главе, получим схему сумматора по модулю 2. Эта схема приведена на рис. 2.8. X Y X Y Out Рис. 2.8. Принципиальная схема устройства, реализующего таблицу истинности сумматора по модулю 2 Сумматор по модулю 2 (для двоичной арифметики его функцию реализу ет элемент исключающего «ИЛИ») изображается на схемах с использо ванием условного графического обозначения, показанного на рис. 2.9.
24 Глава 2 Рис. 2.9. Условное графическое обозначение элемента, выполняющего логическую функцию исключающего «ИЛИ» Сумматор по модулю 2 выполняет суммирование без учета переноса. В полном двоичном сумматоре его необходимо учитывать, поэтому тре- требуются элементы, позволяющие формировать перенос в следующий дво- двоичный разряд. Таблица истинности такого устройства, называемого по- полусумматором, приведена в табл. 2.6. Обратите внимание, что сигналы в приведенной таблице истинности расположены в порядке, принятом для схем, т. е. в соответствии с тем, что сигнал распространяется слева направо. В результате перенос, кото- который имеет двоичный вес, больший по сравнению с суммируемыми разря- разрядами, записан правее. В математике принят другой порядок разрядов числа. Старший разряд на бумаге записывается самым левым, а младший разряд записывается самым правым. В результате может возникнуть пу- путаница. Чтобы этого не произошло, приведу десятичный эквивалент ка- каждой строки таблицы истинности полусумматора (табл. 2.6). Первая строка получена из выражения 0 + 0 = Ом @(Ь). Вторая строка получена из выражения 0 + 1 = 1 ю @12>- Третья строка получена из вы- выражения 1 + 0 = 1 ю @12). Четвертая строка получена из выражения 1 + 1 = = 2io(lO2). Таблица 2.6. Таблица истинности полусумматора ВходА 0 0 1 1 Вход В 0 1 0 1 Выход S 0 1 1 0 Выход РО 0 0 0 1 В соответствии с принципами построения произвольной таблицы истин- истинности получим схему полусумматора. Она приведена на рис. 2.10. Услов- Условное графическое обозначение полусумматора показано на рис. 2.11. Полусумматор формирует перенос в следующий разряд, но Fie может учитывать перенос из предыдущего разряда, поэтому он и называется полусумматором.
Цифровая техника 25 А В А В D2 РО Рис. 2.10. Принципиальная схема цифрового устройства, реализующего таблицу истинности полусумматора А В HS РО Рис. 2.11. Условное графическое обозначение полусумматора Таблицу истинности полного двоичного одноразрядного сумматора (табл. 2.7) можно получить из правил суммирования двоичных чисел. В обозначении входов и выходов полного сумматора использовано сле- следующее правило: в качестве входов использованы одноразрядные двоич- двоичные числа А и В; сумма — это одноразрядное двоичное число S; перенос обозначен буквой Р; для обозначения входа переноса используется соче- сочетание букв PI (I — сокращение от английского слова input, вход); для обозначения выхода переноса используется сочетание букв РО (О — со- сокращение от английского слова output, выход). Таблица 2.7. Таблица истинности полного двоичного одноразрядного сумматора PI 0 0 0 0 А 0 0 1 1 в 0 1 0 1 S 0 1 1 0 РО 0 0 0 1 Математическое выражение 0 + 0 + 0 = 0ю @02) 0 + 0 + 1 = 1ю@12) 0 + 1+0 = 1ю@12) 0 + 1 + 1 =2юA02) 2 Зак. 328
26 Глава 2 Таблица 2.7 (окончание) PI 1 1 1 1 А 0 0 1 1 В 0 1 0 1 S 1 0 0 1 РО 0 1 1 1 Математическое выражение 1+0 + 0 = 1ю@12) 1+0+1 =2юA02) 1 + 1 +0 = 2юA02) 1 + 1 + 1 =3юA12) В соответствии с правилами построения принципиальной схемы по про- произвольной таблице истинности получим схему полного двоичного одно- одноразрядного сумматора. Она приведена на рис. 2.12. PI А В Dl PI А В 4 1J 1 L г г 4 ¦НММН ] & & & & D2 1 D3 & & & & 1 РО Рис. 2.12. Принципиальная схема цифрового устройства, реализующая функцию полного двоичного одноразрядного сумматора Ее можно минимизировать, но, как уже оговаривалось, минимизация в данной книге рассматриваться не будет. Условное графическое обо-
Цифровая техника 27 значение полного двоичного одноразрядного сумматора показано на рис. 2.13. pi А В SM РО Рис. 2.13. Условное графическое обозначение полного двоичного одноразрядного сумматора Для того чтобы получить многоразрядный сумматор, достаточно соеди- соединить входы и выходы переносов соответствующих двоичных разрядов. Схема реализации четырехразрядного сумматора на основе четырех од- одноразрядных приведена на рис. 2.14. PI- AO- BO- Al- Bl~ A2- B2- A3- B3- ¦NM L L PI A В PI манн A В PI A В PI A В SM SM SM SM о РО о РО О РО РО 1 1 1 so SI S2 S3 РО Рис. 2.14. Принципиальная схема многоразрядного двоичного сумматора Одноразрядные сумматоры практически никогда не использовались, т. к. почти сразу же были выпущены микросхемы многоразрядных суммато- сумматоров. Полный двоичный четырехразрядный сумматор изображается на
28 Глава 2 схемах с использованием условного графического обозначения, показан- показанного на рис. 2.15. Естественно, приведенная на рис. 2.14 схема не минимизирована, она служит лишь для пояснения принципа действия многоразрядного двоич- двоичного сумматора. В применяемых на практике схемах никогда не допус- допускают последовательного распространения переноса через все разряды многоразрядного сумматора. Для увеличения скорости работы двоично- двоичного сумматора используется отдельная схема формирования переносов для каждого двоичного разряда. Таблицу истинности для такой схемы легко получить из алгоритма суммирования двоичных чисел, а затем применить хорошо известные нам принципы построения цифрового уст- устройства по произвольной таблице истинности. PI АП А1 A3 A3 ВО В1 В2 ВЗ SM SO SI S2 S3 РО Рис. 2.15. Условное графическое обозначение полного двоичного многоразрядного сумматора На этом пока закончим обсуждение принципов работы сумматора, более сложные операции будут рассмотрены позднее, а пока для дальнейшего понимания принципов работы микропроцессора необходимо разобрать- разобраться, как осуществляется переключение двоичных чисел на входах и выходе сумматора. Эту операцию позволяют осуществить мультиплексоры и де- мультиплексоры, основной составной частью которых является дешиф- дешифратор. Именно это цифровое устройство мы рассмотрим в следующем разделе. Дешифраторы Дешифраторы позволяют преобразовывать n-разрядный двоичный код в унитарный код с числом разрядов не более 2". Преобразование произво-
Цифровая техника 29 дится по таблицам истинности, поэтому построение принципиальных схем дешифраторов не представляет трудностей. Для этого можно вос- воспользоваться рассмотренными ранее правилами построения цифрового устройства по произвольной таблице истинности. Рассмотрим пример построения дешифратора, который преобразует входной двоичный 4-разрядный двоичный код в унитарный 10-разряд- 10-разрядный код. Данное устройство называют дешифратором 4x10. Его таблица истинности приведена в табл. 2.8. Таблица 2.8. Таблица истинности дешифратора 4x10 Входы 8 0 0 0 0 0 0 0 0 1 1 4 0 0 0 0 1 1 1 1 0 0 2 0 0 1 1 0 0 1 1 0 0 1 0 1 0 1 0 1 0 1 0 1 Выходы 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 2 0 0 1 0 0 0 0 0 0 0 3 0 0 0 1 0 0 0 0 0 0 4 0 0 0 0 1 0 0 0 0 0 5 0 0 0 0 0 1 0 0 0 0 6 0 0 0 0 0 0 1 0 0 0 7 0 0 0 0 0 0 0 1 0 0 8 0 0 0 0 0 0 0 0 1 0 9 0 0 0 0 0 0 0 0 0 1 В соответствии с принципами построения цифрового устройства по про- произвольной таблице истинности, описанными в предыдущей главе, полу- получим схему дешифратора, реализующего таблицу истинности табл. 2.8. Эта схема приведена на рис. 2.16. Точно так же можно получить схему для любого другого дешифратора. Дешифраторы выпускаются в виде отдельных микросхем или использу- используются в составе других микросхем, таких как мультиплексоры или ПЗУ. Условное графическое обозначение дешифратора на схемах приведено на рис. 2.17. На этом рисунке показано обозначение дешифратора 4x10, принципиальная схема которого изображена на рис. 2.16.
30 Глава 2 8 * \ : 1 : i in 1J 1J 1 J L >— П • г : I ] i i & & & & & & & & & & 0 8 Рис. 2.16. Принципиальная схема дешифратора 4x10 АО А1 А2 A3 DC 0 1 2 3 4 5 6 7 8 9 Рис. 2.17. Условное графическое обозначение дешифратора 4x10
Цифровая техника 31 Мультиплексоры Мультиплексорами называются устройства, которые позволяют пода- подавать сигнал с одного из нескольких входов на один выход. В простейшем случае такую коммутацию можно осуществить при помощи ключей, изо- изображенных на схеме рис. 2.18. А В YA УВ УС Рис. 2.18. Коммутатор, собранный на ключах В цифровых устройствах нужно научиться управлять такими ключами цифровыми сигналами. Иными словами, мультиплексоры выполняют функцию ключа с электронным управлением цифровым сигналом. Простейшим ключом с электронным управлением является логический элемент «И». Рассмотрим его таблицу истинности. Один из входов логи- логического элемента «И» будем считать информационным, а другой вход — управляющим. Так как оба входа логического элемента «И» эквивалент- эквивалентны, то не важно, какой из них будет управляющим. Предположим, что вход X — управляющий, a Y — информационный. Для простоты рассу- рассуждений разделим таблицу истинности на две части в зависимости от уровня логического сигнала на управляющем входе X. Таблица 2.9. Таблица истинности логического элемента «И» ВходХ 0 0 1 1 ВходУ 0 1 I 0 1 Выход 0 0 0 1
32 Глава 2 По таблице истинности отчетливо видно, что пока на управляющий вход X подан нулевой логический уровень, сигнал, поданный на вход Y. на выход не проходит. При подаче на управляющий вход X логической единицы сигнал, поступающий на вход Y, появляется на выходе. То есть логический элемент «И» можно использовать в качестве электронного ключа. Остается только объединить выходы элементов «И». Это делается при помощи элемента «ИЛИ» точно так же, как и при построении схемы по произвольной таблице истинности. Такой вариант схемы коммутато- коммутатора приведен на рис. 2.19. в VA VB VC Out Рис. 2.19. Принципиальная схема коммутатора, построенного на элементах «И» Инф ормационные входы Адресные входы А & & О 1 DC О 1 2 3 Out Рис. 2.20. Принципиальная схема мультиплексора, управляемого двоичным кодом В схемах, приведенных на рис. 2.18 и 2.19, можно включать сразу не- несколько входов на один выход. Однако обычно это приводит к непред-
Цифровая техника 33 сказуемым последствиям. Кроме того, для управления таким коммутато- коммутатором требуется много входов, поэтому в состав мультиплексора обычно включают двоичный дешифратор, как показано на рис. 2.20. Это позво- позволяет управлять переключением информационных входов при помощи двоичных кодов, подаваемых на управляющие входы дешифратора. Ко- Количество информационных входов в таких схемах выбирают кратным степени числа два. Мультиплексор с двоичным управлением изображает- изображается на схемах как показано на рис. 2.21. хо XI Х2 хз АО А1 мих Рис. 2.21. Условное графическое обозначение мультиплексора Демультиплексоры Задача передачи сигнала с одного входа микросхемы на один из не- нескольких выходов называется демультиплексированием. Демультиплек- сор можно построить на основе точно таких же схем логического «И», как и при построении мультиплексора. In 0 1 0 1 DC 0 1 2 3 Out 0 Out 1 Out 2 Рис. 2.22. Принципиальная схема демультиплексора, управляемого двоичным кодом
34 Глава 2 Существенным отличием от мультиплексора является возможность объ- объединения нескольких входов в один без дополнительных элементов. Од- Однако для уменьшения входного тока демультиплексора на входе лучше поставить инвертор. Схема демультиплексора приведена на рис. 2.22. Для выбора конкретно- конкретного выхода демультиплексора, как и в мультиплексоре, используется дво- двоичный дешифратор. На схемах демультиплексор обычно изображается точно так же, как и дешифратор, условное графическое обозначение которого приведено на рис. 2.17. Единственное отличие в изображении схемы — это наличие дополнительного информационного входа V. Условное графическое обозначение демультиплексора приведено на рис. 2.23. V АО А1 А2 A3 DC 0 1 2 3 4 5 6 \j 7 8 9 Рис. 2.23. Условное графическое обозначение демультиплексора Шинные формирователи Мультиплексоры предназначены для выбора одного из нескольких сигналов в тех случаях, когда заранее известно их число. Часто это не- неизвестно. Более того, в ряде случаев количество микросхем, выходные сигналы которых выбираются мультиплексором, изменяется в процессе эксплуатации устройств. Наиболее яркий пример — это компьютеры, в которых в процессе эксплуатации изменяется объем оперативной памя- памяти, количество портов ввода-вывода, количество дисководов. В таких случаях невозможно для объединения нескольких выходов ключей, реализованных на элементах «И», воспользоваться логическим элемен- элементом «ИЛИ».
Цифровая техника 35 Тем не менее, необходимо иметь возможность передавать информацию с нескольких выходов на один или несколько входов. Этого достигают, выделяя один или несколько проводников, по которым информация мо- может передаваться в различных направлениях. Такая система проводников называется шиной. Для объединения нескольких выходов на один вход в случае, когда зара- заранее не известно, сколько микросхем нужно объединять, используется два способа: ? монтажное ИЛИ; ? шинные формирователи. Исторически первым вариантом объединения выходов нескольких мик- микросхем были схемы с открытым коллектором (монтажное «ИЛИ»). Схе- Схема монтажного «ИЛИ» приведена на рис. 2.24. I +ип R1 Микросхема №1 Микросхема №2 Микросхема I +U п R2 Рис. 2.24. Схема монтажного «ИЛИ» Монтажное «ИЛИ» позволяет объединять до 10 микросхем на один провод. Естественно, для того, чтобы микросхемы не мешали друг дру- другу, только одна из них должна выдавать информацию на линию шины. Остальные микросхемы в этот момент времени должны быть отключе- отключены от шины (т. е. выходной транзистор должен быть закрыт). Это обеспечивается внешней микросхемой управления, не показанной на данном рисунке. В качестве подобной микросхемы может служить обычный дешифратор. На схемах логические элементы с открытым коллектором обозначаются, как это показано на рис. 2.25.
36 Глава 2 Недостатком приведенной схемы объединения выходов нескольких мик- микросхем на один провод является низкая скорость передачи информации, обусловленная затянутым передним фронтом. Это обусловлено тем, что ток заряда паразитной емкости шины проходит через сопротивления R1 и R2, которые много больше сопротивления открытого транзистора, обеспечивающего разряд этой емкости. Величину сопротивления нагруз- нагрузки R1 и R2 невозможно снизить меньше некоторого предела, определяе- определяемого напряжением низкого уровня, который определяется в свою оче- очередь допустимым током через выходной транзистор. В результате заряд происходит заметно медленнее, чем разряд. Временные диаграммы на- напряжений на входе и выходе микросхемы с открытым коллектором при- приведена на рис. 2.26. Рис. 2.25. Условное графическое обозначение микросхемы с открытым коллектором на выходе Рис. 2.26. Временные диаграммы напряжений на входе и выходе микросхемы с открытым коллектором Обратите внимание, что нагрузочные сопротивления включены на обоих концах проводника, образующего шину. Это позволяет уменьшить от- отражения сигнала от ненагруженных концов линии передачи сигнала, об- образованной данным проводником. Сопротивления резисторов R1 и R2 должны быть равны волновому сопротивлению этой линии передачи.
Цифровая техника 37 Естественным решением проблемы затягивания переднего фронта сиг- сигнала было бы включение транзистора в верхнее плечо схемы, но при этом возникает проблема сквозных токов, из-за которой невозможно соединять выходы цифровых микросхем непосредственно, и решением которой как раз является использование микросхем с открытым кол- коллектором на выходе (монтажное «ИЛИ»). Причина возникновения сквозных токов поясняется на рис. 2.27. Показана ситуация, когда мик- микросхема № 2 пытается сформировать на выходе уровень логической единицы, а микросхема № 1 — уровень логического нуля. Буквами «3» и «О» для выходных транзисторов обозначены закрытое и открытое состояния соответственно. Микросхема №1 Микросхема №2 Рис. 2.27. Путь протекания сквозного тока /скв при непосредственном соединении выходов цифровых микросхем Эта проблема исчезает, если появляется возможность закрывать оба вы- выходных транзистора, как в верхнем, так и в нижнем плече выходного каскада. Если оба транзистора закрыты, то такое состояние выхода мик- микросхемы называется третьим состоянием или z-состоянием (высоко- омным состоянием). Возможность переводить выход в третье состояние появляется в специализированных микросхемах. Принципиальная схема выходного каскада микросхемы с тремя состояниями на выходе приведе- приведена на рис. 2.28. В этой схеме вводится дополнительный управляющий вход, который может запирать оба выходных транзистора. В приведенной схеме это осуществляется закорачиванием баз обоих транзисторов на общий про- провод при помощи многоколлекторного транзистора, на базу которого сигнал управления подается через резисторы R1 и R2.
38 Глава 2 Рис. 2.28. Принципиальная схема выходного каскада микросхемы с тремя состояниями на выходе На схемах логические элементы с тремя состояниями на выходе обозна- обозначаются, как это показано на рис. 2.29. Рис. 2.29. Условное графическое обозначение микросхемы с тремя состояниями на выходе Часто в микросхеме, содержащей несколько выходных каскадов с тремя состояниями, объединяют управляющие сигналы всех выходов в один провод. Такие микросхемы используются для подключения многораз- многоразрядных устройств к шине микропроцессора и поэтому называются шин- шинными формирователями. Шинные формирователи изображаются на схе- схемах так, как показано на рис. 2.30. 0 1 2 3 V V 0 1 2 3 Рис. 2.30. Условное графическое обозначение шинного формирователя
Цифровая техника 39 Итак, подведем итоги В данной главе были рассмотрены простейшие логические элементы, а также устройства суммирования двоичных сигналов и устройства, кото- которые позволят подавать на входы сумматора двоичные коды от различ- различных источников информации. Кроме того, рассмотрены устройства, по- позволяющие подавать результат суммирования к различным средствам запоминания двоичных кодов. Как будет показано в дальнейшем, любые, даже самые современные мощные микропроцессоры, из арифметических операций ничего, кроме суммирования, делать не умеют! Все их поражающие воображение вы- вычислительные возможности сводятся к способности с огромной скоро- скоростью суммировать двоичные числа. А теперь научимся работать с двоичными числами: суммировать их, вы- вычитать, работать со знаком и с дробными числами. Кроме того, пора бы научиться работать и с обычными текстами!
moon Глава 3 D Запоминающие устройства В предыдущей главе были рассмотрены основные виды микросхем, ис- используемых в цифровой технике. Однако мы собирались строить цифро- цифровые устройства на базе микропроцессорной техники. Пора обсудить, как устроены блоки, входящие в состав микропроцессоров. Одной из важнейших задач при построении универсальных устройств обработки информации является запоминание различных видов данных. Для выполнения этой функции были разработаны несколько видов мик- микросхем, отличающихся друг от друга. Отличие связано с требованиями, предъявляемыми к хранимым данным. Часть из них должна существо- существовать длительное время, часто до тех пор, пока существует устройство. Другая часть данных представляет интерес только в течение относитель- относительно короткого промежутка времени, в процессе работы устройства. В за- зависимости от этих требований различается и внутреннее устройство микросхем. Достаточно часто при длительном хранении данных требуется только операция считывания. При этом их можно записать в процессе изготов- изготовления устройства. Поэтому такие микросхемы получили название посто- постоянных запоминающих устройств. Так как в этих микросхемах произво- производится только одна операция, то и внутреннее устройство у них проще. Именно по этой причине начнем изучение внутренней структуры запо- запоминающих устройств с постоянных запоминающих устройств. Постоянные запоминающие устройства Очень часто в различных устройствах требуется хранение информации, которая не изменяется. Это программы в микроконтроллерах, начальные загрузчики и BIOS в компьютерах, таблицы коэффициентов цифровых
42 Глава 3 фильтров в сигнальных процессорах. Практически всегда эта информа- информация не требуется вся сразу, обычно требуется доступ к отдельным ее фрагментам. Простейшие устройства для запоминания постоянной информации мож- можно построить на мультиплексорах. Схема такого постоянного запоми- запоминающего устройства приведена на рис. 3.1; это устройство содержит во- восемь одноразрядных ячеек памяти. Запоминание конкретного бита в одноразрядной ячейке производится присоединением соответствующего входа мультиплексора к источнику питания (высокий уровень — запись единицы) или к общему проводу (низкий уровень — запись нуля). Выбор конкретной ячейки памяти осуществляется при помощи адресных входов А0-А2. В приведенной на рис. 3.1 схеме — это входы управления муль- мультиплексора. +U RD CS пр Адрес _ ячейки хо XI Х2 ХЗ Х4 Х5 Хб Х7 АО А1 А2 A3 MUX V Рис. 3.1. Схема постоянного запоминающего устройства, построенного на мультиплексоре Обычно информация на выходе ПЗУ не требуется постоянно. Она долж- должна быть предоставлена только по специальному запросу. Этот запрос формируется посредством сигнала чтения RD. Название этого сигнала расшифровывается как read (читать). Сигнал RD можно завести на внут- внутренний дешифратор мультиплексора, как это показано на рис. 3.1. То есть содержимое ячейки памяти появится на выходе ПЗУ только при ак- активном сигнале чтения RD. При всех других условиях выход микросхемы будет оставаться в высокоомном состоянии.
Запоминающие устройства 43 При построении устройств памяти обычно требуется иметь возможность расширения объема памяти. Это выполняется с помощью дополнитель- дополнительной микросхемы и дополнительной линии адресной шины. Кроме того, добавляется дешифратор адреса. Его нужно таким образом подключить к микросхемам памяти, чтобы он запрещал работу одной из микросхем памяти или разрешал работу другой в зависимости от адреса читаемой ячейки. Для подключения дополнительного дешифратора адреса служит еще один вход выбора кристалла CS (chip select — выбор кристалла). С точки зрения функционирования ПЗУ сигналы чтения RD и выбора кристалла CS не различаются, поэтому их можно объединить при помо- помощи логического элемента «2И». На схемах ПЗУ обозначается, как показано на рис. 3.2. На нем приве- приведено условное графическое обозначение, соответствующее схеме рис. 3.1. Надпись «ROM» в среднем поле является сокращением от английских слов read-only memory (память, доступная только для чтения). АО А1 А2 RD CS ROM V Y Рис. 3.2. Условное графическое обозначение постоянного запоминающего устройства Для того чтобы увеличить разрядность ячейки памяти ПЗУ, одноразряд- одноразрядные микросхемы можно объединять. При этом параллельно соединяются одноименные адресные входы и входы сигналов управления RD и CS, a информационные выходы остаются независимыми. Схема объединения одноразрядных ПЗУ для реализации многоразрядного запоминающего устройства с восемью 4-разрядными ячейками приведена на рис. 3.3, а условное графическое обозначение 8-разрядного ПЗУ с 1024 ячейками памяти — на рис. 3.4. Как видно из приведенной схемы, адресные входы схемы объединяются параллельно. При этом возрастает общий входной ток микросхем памя- памяти, протекающий по каждой линии адресной шины. Чтобы в результате не увеличивался входной ток запоминающего устройства, на адресных входах предусматривают усилители сигнала. В этом качестве можно использовать самые обыкновенные инверторы, как это показано на
44 Глава 3 рис. 3.3. Точно с такой же целью поставлены инверторы и на управляю- управляющих входах чтения RD и выбора кристалла CS. При этом активными становятся низкие уровни этих сигналов. RD CS АО А1 А2 RD CS ROM АО А1 А2 RD CS ROM АО А1 А2 RD CS ROM АО А1 А2 RD CS ROM V Y V Y V Y V Y DO Dl D2 D3 Рис. 3.3. Схема многоразрядного ПЗУ Масочные ПЗУ изображаются на схемах как показано на рис. 3.4. Ак- Активность низких уровней сигналов CS и RD обозначена кружками возле соответствующих управляющих входов. Запись информации в ПЗУ (микросхему, доступную только для чтения) производится при помощи последней операции изготовления микросхе- микросхемы — металлизации. Она выполняется при помощи маски, поэтому та- такие микросхемы получили название масочных запоминающих устройств. Еще одно отличие реальных микросхем от упрощенной модели, приве-
Запоминающие устройства 45 денной выше, — это использование для дешифрации адреса кроме муль- мультиплексора, еще и дешифратора. Рис. 3.4. Условное графическое обозначение многоразрядного постоянного запоминающего устройства Адрес строки АО А1 А2 Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 11111111 RD CS <= Запоминающая матрица (маска) Адрес столбца ХО XI Х2 ХЗ Х4 Х5 Хб Х7 АО А1 А2 A3 мих Рис. 3.5. Схема масочного постоянного запоминающего устройства с двухмерной матрицей запоминающих элементов
46_ Глава 3 Такое решение позволяет превратить одномерную запоминающую струк- структуру в двухмерную и тем самым существенно сократить объем схемы внутреннего дешифратора адреса. Реализация ПЗУ с двухмерной струк- структурой запоминающих элементов показана на рис. 3.5. Рассмотрим подробнее работу этого ПЗУ. В отличие от схемы, приве- приведенной на рис. 3.1, в данном случае не используется непосредственное соединение входов мультиплексора с общим проводом. Вместо этого подключение производится через резистор. В результате, если с выхода дешифратора не будет подан единичный уровень, то на входе мульти- мультиплексора будет присутствовать уровень логического нуля. Запись логи- логической единицы в ячейку ПЗУ производится соединением линий выхода дешифратора и входа мультиплексора в точке их пересечения. Если же в ячейку необходимо записать логический ноль, то соединение цепей не производится. Именно такая запоминающая структура получила назва- название «матрица». Приведенная на рис. 3.5 схема реализует одноразрядное ПЗУ с 64 одно- одноразрядными ячейками памяти. Рассмотрим, какая информация хранится в этом ПЗУ. При выборе нулевой ячейки памяти на адресные входы де- дешифратора будут поданы три младших разряда адреса, т. е. код 000. В результате единичный уровень появится на выходе Y0. На адресные входы мультиплексора будут поданы старшие три разряда адреса. В на- нашем примере они тоже равны нулю. В результате мультиплексор пере- передаст на выход сигнал со своего входа Х0. Так как на схеме эти цепи со- соединены между собой, то на выходе ПЗУ появится логическая единица. Теперь рассмотрим считывание восьмой ячейки памяти. Здесь, как и в предыдущем случае, младшие три разряда адреса равны 0. Поэтому де- дешифратор выдаст единицу на линию Y0. Мультиплексор же получит код 001, поэтому на выход будет подключен вход XI. Эти цепи между собой не соединены, поэтому на выход будет выдан уровень логического нуля. Для реализации многоразрядного ПЗУ необходимо использование не- нескольких матриц, подобных приведенной на рис. 3.5. Объединение мат- матриц производится согласно схеме рис. 3.3. Программирование масочного ПЗУ производится на заводе — изготови- изготовителе микросхем в процессе последнего этапа изготовления микросхе- микросхемы — металлизации. Масочные ПЗУ широко применяются при крупно- крупносерийном производстве, т. к. являются самым дешевым видом ПЗУ. Однако использование подобных ПЗУ очень неудобно для мелко- и среднесерийного производства, не говоря уже о стадии разработки уст- устройства, когда требуется многократная запись промежуточных вариан- вариантов программы. Для подобных вариантов применения были разработа- разработаны микросхемы, которые можно однократно программировать не на
Запоминающие устройства 47 заводе — изготовителе микросхем, а в специальных устройствах — про- программаторах. В этих микросхемах ПЗУ постоянное соединение провод- проводников в запоминающей матрице заменяется плавкими перемычками, из- изготовленными из поликристаллического кремния. Так как внутренняя схема такой микросхемы такая же, как у масочного ПЗУ, то для иллюст- иллюстрации внутреннего устройства этой схемы можно воспользоваться рис. 3.5, предполагая при этом, что во всех точках пересечения верти- вертикальных и горизонтальных проводников находятся плавкие поликрем- поликремниевые перемычки. При производстве микросхемы изготавливаются все перемычки, что эк- эквивалентно записи во все ячейки памяти логических единиц. В процессе программирования на выводы питания и выходы микросхемы подается повышенное напряжение или низкий потенциал. При этом если на выход микросхемы подается повышенное напряжение питания (логическая еди- единица), то через перемычку ток протекать не будет, и она останется непо- неповрежденной. Если же на выход микросхемы в режиме программирования подать низкий уровень напряжения (присоединить к общему проводу), то через перемычку будет протекать ток, который испарит ее, и при по- последующем считывании информации из этой ячейки будет считываться логический ноль. Микросхемы, работающие по такому принципу, называются (одно- (однократно) программируемыми ПЗУ (ППЗУ) и изображаются на схемах в виде условного графического обозначения, показанного на рис. 3.6. Надпись PROM в центральной части микросхемы является сокращением от английских слов programmable read-only memory (программируемая память, доступная только для чтения). В качестве примера таких ПЗУ можно назвать отечественные микросхемы 155РЕЗ, 556РТ4, 556РТ8. АО А1 А2 A3 А4 А5 А6 А7 А8 А9 >RD >CS PROM V 0 1 2 3 4 5 6 7 Рис. 3.6. Условное графическое обозначение однократно программируемого постоянного запоминающего устройства
48 Глава 3 Однократно программируемые ПЗУ оказались очень удобными при мел- мелко- и среднесерийном производстве, однако при разработке радиоэлек- радиоэлектронных устройств часто приходится менять записываемую в ПЗУ про- программу. ППЗУ невозможно использовать повторно, поэтому при необходимости изменить содержимое памяти, записанное ППЗУ прихо- приходится выкидывать, что естественно повышает стоимость разработки ап- аппаратуры. Для устранения этого недостатка был разработан еще один вид ПЗУ, содержимое которого могло бы стираться и программировать- программироваться многократно. Примером такого устройства является ПЗУ с ультрафиолетовым или электрическим стиранием, которое строится на основе матрицы запоми- запоминающих элементов, внутреннее устройство одного из которых приведено на рис. 3.7. пр о гр аммнрующий электрод плавающий затвор исток индуцир ов анныи канал сток Рис. 3.7. Запоминающий элемент ПЗУ с ультрафиолетовым и электрическим стиранием Ячейка представляет собой МОП-транзистор, в котором затвор выпол- выполняется из поликристаллического кремния. Затем в процессе изготовления микросхемы этот затвор окисляется и в результате он оказывается окру- окруженным оксидом кремния — диэлектриком с прекрасными изолирую- изолирующими свойствами. Из-за того, что затвор со всех сторон окружен диэлек- диэлектриком, он как бы плавает внутри диэлектрика, поэтому его называют плавающим затвором. В описанной ячейке при полностью стертом ПЗУ заряда в плавающем затворе нет, и поэтому транзистор ток не проводит. При программиро- программировании микросхемы на программирующий электрод, находящийся над плавающим затвором, подается высокое напряжение и в последнем за счет туннельного эффекта индуцируются заряды. После снятия програм-
Запоминающие устройства 49 мирующего напряжения на плавающем затворе индуцированный заряд сохраняется и, следовательно, транзистор остается в проводящем со- состоянии. Заряд на плавающем затворе может храниться десятки лет. Структурная схема постоянного запоминающего устройства не отлича- отличается от описанного ранее масочного ПЗУ. Единственное отличие — это использование описанной выше ячейки вместо плавкой поликремниевой перемычки. Такой вид ПЗУ в отечественной литературе получил назва- название «репрограммируемые ПЗУ» (РПЗУ). Стирание ранее записанной информации в репрограммируемых ПЗУ осуществляется ультрафиолетовым излучением. Для того чтобы оно могло беспрепятственно воздействовать на полупроводниковый кри- кристалл, в корпус микросхемы РПЗУ встраивается окошко из кварцевого стекла. При облучении микросхемы изолирующие свойства оксида крем- кремния теряются, накопленный заряд из плавающего затвора стекает в объ- объем полупроводника, и транзистор запоминающей ячейки переходит в за- закрытое состояние. Время стирания микросхемы колеблется в пределах 10-30 минут. АО А1 А2 A3 А4 А5 А6 А7 А8 А9 >WR RD CS EPROM V 0 1 2 3 4 5 6 7 Рис. 3.8. Условное графическое обозначение репрограммируемого постоянного запоминающего устройства Количество циклов записи-стирания микросхем РПЗУ составляет от 10 до 100 раз, после чего вследствие разрушающего действия ультрафиоле- ультрафиолетового излучения микросхема выходит из строя. В качестве примера та- таких микросхем можно назвать микросхемы 573-й серии российского производства, микросхемы серий 27сХХХ зарубежного производства.
Глава 3 В этих микросхемах чаще всего хранятся программы BIOS универсаль- универсальных компьютеров. Репрограммируемые ПЗУ изображаются на схемах в виде условного графического обозначения, показанного на рис. 3.8. Надпись «EPROM» в центральной части микросхемы является сокраще- сокращением от английских слов erasable programmable read-only memory (стираемая программируемая память, доступная только для чтения). Из-за дороговизны корпуса с кварцевым окошком, а также вследствие такого недостатка, как сравнительно малое количество циклов записи/ стирания, начали поиск способов стирания информации из РПЗУ элек- электрическим потенциалом. На этом пути встретилось много трудностей, которые к настоящему времени практически решены. Сейчас достаточно широко распространены микросхемы с электрическим стиранием ин- информации. В них используются такие же запоминающие ячейки, как и в РПЗУ, но они стираются электрическим потенциалом, поэтому количе- количество циклов записи/стирания для этих микросхем достигает 1 млн раз. Время стирания ячейки памяти в таких микросхемах уменьшается до 10 мс. В настоящее время наметилось два направления развития микро- микросхем РПЗУ: 1. ЭСРПЗУ — электрически стираемые ПЗУ. 2. Флэш-ПЗУ. Из-за сложности внутренней схемы управления запоминающими элемен- элементами электрически стираемые ПЗУ дороже и меньше по объему, но зато позволяют перезаписывать каждую ячейку памяти отдельно. В результа- результате эти микросхемы обладают максимальным количеством циклов записи/ стирания. Область применения электрически стираемых ПЗУ — хране- хранение данных, которые не должны разрушаться при выключении питания. К таким микросхемам относятся отечественные микросхемы 573РРЗ и зарубежные микросхемы серии 28сХХ. Электрически стираемые ПЗУ изображаются на схемах при помощи условного графического обозначе- обозначения, показанного на рис. 3.9. Надпись «EEPROM» в среднем поле рас- расшифровывается как electrically erasable programmable read-only memory — электрически стираемая программируемая память, доступная только для чтения. В последнее время наметилась тенденция уменьшения габаритов ЭСРПЗУ за счет сокращения количества внешних выводов микросхем. Для этого адрес и данные передаются в микросхему и из микросхемы в виде последовательного кода. При этом используются два вида последо- последовательных интерфейсов: SPI и I2C (микросхемы серий 93сХХ и 24сХХ соответственно). Зарубежной серии 24сХХ соответствует отечественная серия микросхем 558РРх.
Запоминающие устройства 51 Рис. 3.9. Условное графическое обозначение электрически стираемого постоянного запоминающего устройства АО А1 А2 A3 А4 А5 Аб А1 А8 А9 >WR RD CS FLASH V 0 1 2 3 4 5 6 7 Рис. 3.10. Условное графическое обозначение FLASH-памяти Микросхемы флэш-ПЗУ отличаются от ЭСРПЗУ тем, что производится стирание не каждой ячейки отдельно, а всей запоминающей матрицы, как это делалось в РПЗУ, или ее части (блока). Условное графическое обозначение FLASH-ПЗУ на схемах приведено на рис. 3.10. Использова- Использование блочного стирания позволяет уменьшить сложность внутреннего устройства управления микросхем, поэтому FLASH-ПЗУ предоставляют максимальный объем матрицы запоминающих элементов. Кроме того, эти микросхемы обладают значительно меньшей стоимостью по сравне-
52 Глава 3 нию с электрически стираемыми ПЗУ. В настоящее время FLASH-ПЗУ постепенно вытесняют все остальные виды постоянных запоминающих устройств за исключением электрически стираемых ПЗУ. Рассмотренные виды памяти позволяют хранить информацию практиче- практически неограниченно долго. Тем не менее, они не обладают максимальным быстродействием, поэтому, кроме постоянных запоминающих устройств, используются более быстродействующие микросхемы, теряющие свое содержимое при выключении питания. Эти микросхемы обладают боль- большим быстродействием по сравнению с ПЗУ и в них записывают резуль- результаты предварительных вычислений или информацию, нужную только в определенный момент времени. Например, набранный номер вызывае- вызываемого абонента в сотовом аппарате или выбранный номер телевизионной программы в телевизоре. Для хранения информации можно воспользоваться элементами, которые сохраняют напряжение на своем выходе до тех пор, пока подается пита- питание. Элементы, которые могут запоминать двоичные логические уровни, получили название «триггеры». Рассмотрим подробнее, как устроены подобные устройства. Триггеры Простейшая схема, позволяющая запоминать двоичную информацию, строится на основе простейших логических элементов «ИЛИ» или «И», описанных в главе 1. Такая схема, построенная на элементах «И», приве- приведена на рис. 3.11. Выход триггера Q можно установить в единичное со- состояние при подаче на его вход S (Set) логического нуля. Сбросить выход триггера Q в нулевое состояние можно, подав на его вход R (Reset) логи- логический ноль. Это состояние сохраняется до подачи очередного сигнала R или S либо до выключения напряжения питания схемы. Так как описанный триггер можно только устанавливать в единичное значение или сбрасывать в нулевое значение, он получил название RS-триггер. Такой триггер можно построить и на логических элементах «ИЛИ». Та- Такая схема приведена на рис. 3.12. Единственное отличие от схемы рис. 3.11 будет заключаться в том, что сброс и установка триггера осуще- осуществляются единичными логическими уровнями. Так как триггер при построении его на различных логических элементах работает одинаково, то его изображают на схемах тоже одинаково. Ус- Условное графическое обозначение RS-триггера приведено на рис. 3.13.
Запоминающие устройства 53 Рис. 3.11. Схема простейшего триггера на элементах «И» Входы R и S инверсные (активный уровень'О1) R Рис. 3.12. Схема простейшего триггера на элементах «ИЛИ» Входы R и S прямые (активный уровень '1') R Q Рис. 3.13. Условное графическое обозначение простейшего триггера Триггер позволяет запоминать логический сигнал, но при изменении сигнала на входе устройства может возникать переходный процесс (в цифровых схемах это явление называют гонками или состязаниями), в ходе которого сигнал на входе триггера может принимать случайные значения. Это может привести к ошибкам, для предотвращения которых запоминание входного сигнала должно происходить после окончания всех переходных процессов. То есть цифровые схемы требуют синхрони- синхронизации. Все переходные процессы в цифровой схеме должны закончиться до поступления синхросигнала, иначе цифровое устройство будет рабо- работать с ошибками. В синхронных цифровых схемах используются синхронные триггеры. Для построения такого триггера можно воспользоваться логическим элементом «И», ведь он может работать как электронный ключ (см. по-
54 Глава 3 строение мультиплексора на рис. 2.18). Схема синхронного RS-триггера приведена на рис. 3.14, а его условное графическое обозначение — на рис. 3.15. R— Рис. 3.14. Схема синхронного триггера на схемах «И» С R Q Рис. 3.15. Условное графическое обозначение синхронного триггера В дальнейшем именно это обозначение и будет использоваться на схемах более сложных запоминающих устройств. В приведенных схемах триггеров для записи логического нуля и логиче- логической единицы требуется подавать сигналы на разные входы, что не все- всегда удобно, поэтому для запоминания дискретной информации приме- применяются D-триггеры, имеющие один информационный вход. В D-триггере достаточно подать на вход D сигнал, который необходимо запомнить, и синхроимпульс — на вход синхронизации С. Схема такого триггера при- приведена на рис. 3.16, а условное графическое обозначение — на рис. 3.17. D С 5 С Q Рис. 3.16. Схема D-триггера со статическим управлением (защелки) Во всех приведенных схемах триггеров запоминание сигнала происходит по уровню синхросигнала, поэтому они называются D-триггерами со
Запоминающие устройства 55 статическим управлением, или триггерами-защелками. Легче всего объ- объяснить появление этого названия по временным диаграммам, приведен- приведенным на рис. 3.18. Как видно из рисунка, триггер-защелка хранит данные только при нулевом уровне на входе синхронизации С. Если же на этот вход подать активный высокий уровень, то напряжение на выходе триг- триггера будет повторять входной сигнал. Входное напряжение запоминается только в момент изменения уровня сигнала синхронизации С с высокого на низкий. Входные данные как бы «защелкиваются» в этот момент, от- отсюда и название — триггер-защелка. D Q Рис. 3.17. Условное графическое обозначение D-триггера со статическим управлением (защелки) iD С I LJL_! i— 1 i 1 i 1 предыдущее состояние i ¦ " i 1 i i "прозрачность ¦ - i 1 t t t "защелкнутый" входной сигнал Рис. 3.18. Временные диаграммы D-триггера со статическим управлением (защелки) В этой схеме переходный процесс входного информационного сигнала (D) может беспрепятственно проходить на выход триггера. Поэтому там, где важно избежать этого, необходимо сокращать длительность импуль- импульса синхронизации до минимума. Только в этом случае переходный про- процесс практически не сможет появиться на выходе триггера.
56 Глава 3 Чтобы преодолеть такое ограничение на длительность синхронизирую- синхронизирующего импульса, были разработаны триггеры, работающие по фронту синхросигнала. Схема такого триггера приведена на рис. 3.19, а его ус- условное графическое обозначение — на рис. 3.20. D С D Q D С Q -Q Рис. 3.19. Схема D-триггера с управлением по фронту D С тт Q Рис. 3.20. Условное графическое обозначение D-триггера с управлением по фронту Как видно из схемы D-триггера с управлением по фронту, приведенной на рис. 3.19, на ее выходе не могут появиться переходные процессы, т. к. если их пропускает первый триггер, то не пропустит второй, который в это время находится в режиме хранения. И наоборот, если второй триг- триггер пропускает сигнал со своего входа на выход, то первый триггер на- находится в режиме хранения и, значит, сигнал на входе второго триггера не может измениться. Из рис. 3.19 видно, что схема триггера с управлением по фронту сложнее, чем у триггера-защелки, а это означает, что D-триггер с управлением по фронту будет дороже, а его быстродействие — ниже, чем у триггера- защелки. Регистры Триггеры позволяют запоминать одноразрядное двоичное слово. Однако в ряде случаев требуется запоминать двоичные слова большей разрядно- разрядности. Это позволяют сделать регистры. Регистром называется последовательное или параллельное соединение любых устройств, будь то клавиши музыкального инструмента, набор
Запоминающие устройства 57 букв печатающей машинки или триггеры в цифровой технике. Регистры обычно строятся на основе D-триггеров. При этом для построения реги- регистров могут использоваться как D-триггеры с управлением по фронту, так и триггеры-защелки. При использовании для этого триггеров- защелок регистр называется регистром-защелкой. Параллельный регистр служит для запоминания многоразрядного двоичного слова. Количество триггеров, входящее в состав параллельного регистра определяет его разрядность. Схема четырехразрядного параллельного регистра, постро- построенного на D-триггерах, приведена на рис. 3.21, а его условное графиче- графическое обозначение — на рис. 3.22. DO Dl D2 — D3 D С D С D С D С Q -QO Q -Ql Q-Q2 Q-Q3 of Рис. 3.21. Схема 4-разрядного параллельного регистра DO Dl D2 D3 RG QO Ql Q2 Q3 Рис. 3.22. Условное графическое обозначение 4-разрядного параллельного регистра При записи информации в параллельный регистр все биты (двоичные разряды) записываются одновременно, поэтому входы синхронизации всех триггеров можно соединить параллельно. Кроме параллельных, в цифровой технике используются последователь- последовательные регистры. Последовательный регистр (регистр сдвига) обычно слу- 3 Зак 328
58 Глава 3 жит для преобразования последовательного кода в параллельный и на- наоборот. Схема регистра, осуществляющего преобразование последова- последовательного кода в параллельный, приведена на рис. 3.23, а его условное графическое обозначение — на рис. 3.24. DO D Q D Q D Q D Q QO Qi Q2 Q3 Рис. 3.23. Схема последовательного регистра DO RG QO Ql Q2 Q3 Рис. 3.24. Условное графическое обозначение последовательного регистра В схеме, приведенной на рис. 3.23, информация, поступившая на вход первого триггера сдвигового регистра DO, будет переписываться в сле- следующий триггер при поступлении очередного синхронизирующего им- импульса. Таким образом, после четырех тактовых импульсов на выходах сдвигового регистра окажется записанной информация, присутствовав- присутствовавшая на входе регистра в моменты поступления этих тактовых импульсов. Регистры сдвига выполняют обычно как универсальные последователь- последовательно-параллельные микросхемы, что позволяет преобразовывать двоич-
Запоминающие устройства 59 ный код из параллельной формы в последовательную. Это свойство уни- универсального последовательно-параллельного регистра используется, на- например, для реализации последовательного порта в микропроцессорной системе. Схема универсального последовательно-параллельного регист- регистра приведена на рис. 3.25, а его условное графическое обозначение — на рис. 3.26. DI DO D1 D2 D3 v - с & & D С Q D D С Q D Q QO Qi Q2 Q3 Рис. 3.25. Схема универсального последовательно-параллельного регистра DI DO DI D2 D3 V RG QO Ql Q2 Q3 Рис. 3.26. Условное графическое обозначение универсального последовательно-параллельного регистра Переключение регистра из параллельного режима в последовательный и наоборот осуществляется при помощи мультиплексора, построенного на
60 Глава 3 элементах 2И-2ИЛИ (рис. 3.25). В зависимости от управляющего сигнала V он подключает к входу каждого D-триггера либо выход предыдущего триггера, либо параллельный вход универсального регистра. При подаче на вход управления V логической единицы регистр будет работать как параллельный, а при подаче логического нуля — как последовательный. Если читателю покажется непонятной работа коммутатора, собранного на элементах 2И-2ИЛИ, то имеет смысл заново перечитать описание ра- работы мультиплексора в главе 2. Статические оперативные запоминающие устройства (ОЗУ) В радиоаппаратуре часто требуется хранение временной информации, значение которой не важно при включении устройства. Такую память можно было бы построить на микросхемах EEPROM- или FLASH-памя- ти, но, к сожалению, эти микросхемы дороги, характеризуются сравни- сравнительно малым количеством циклов перезаписи, а также чрезвычайно низким быстродействием при считывании и особенно при записи инфор- информации. Для хранения временной информации можно воспользоваться параллельными регистрами. Устройства памяти, в которых в качестве запоминающих ячеек исполь- используются параллельные регистры, называются статическими ОЗУ, т. к. ин- информация в них сохраняется все время, пока к микросхеме подключено питание. Кроме микросхем статических ОЗУ, существуют микросхемы динамических ОЗУ, где в качестве запоминающих ячеек используются конденсаторы. В отличие от микросхем статического ОЗУ, в микросхе- микросхемах динамического ОЗУ постоянно требуется регенерировать их содер- содержимое, иначе из-за разряда конденсаторов информация будет испорчена. Эти микросхемы будут рассмотрены позднее. Так как запоминаемые слова не нужны одновременно, то в ОЗУ можно воспользоваться механизмом адресации, который уже рассматривался ранее при объяснении принципов работы ПЗУ. В микросхемах статических ОЗУ присутствуют две операции: запись и чтение. Для их выполнения можно использовать различные шины дан- данных (как это делается в сигнальных процессорах), но чаще используется одна и та же шина. Это позволяет экономить выводы микросхем, под- подключаемых к этой шине, и легко осуществлять коммутацию сигналов между различными устройствами. Схема статического ОЗУ приведена на рис. 3.27. Вход и выход микросхе- микросхемы в этой схеме объединены при помощи шинного формирователя. Есте-
Запоминающие устройства 61 ственно, что схемы реальных ОЗУ будут иными, чем приведенная на этом рисунке. Тем не менее, она позволяет понять, как работает реальное ОЗУ статического типа. Условное графическое обозначение ОЗУ на схе- схемах приведено на рис. 3.28. WR - RD - Адресные входы CS - О 1 8 8 8 8 8 8 '8 8 О 1 DC О 1 2 3 D С D D D С RG RG RG RG Q 8 8 8 8 А В А В А В А В 8 8 8 8 8 Инф ормационные входы/выходы Рис. 3.27. Структурная схема ОЗУ 0А 1 2 3 4 5 б 7 8 9 >WR ЯШ \cs RAM D 0 1 2 3 4 5 б 7 Рис. 3.28. Условное графическое обозначение ОЗУ
62 Глава 3 На схеме рис. 3.27 для обозначения того, что используется инвертиро- инвертированный сигнал или сигнал с активным низким уровнем, над именем цепи проставляется черта. К сожалению, в обычном тексте затруднительно использовать такую же черту. Поэтому для обозначения таких сигналов в книге используется два способа: символ подчеркивания перед именем цепи (_WR) или символ # после имени (WR#). Сигнал записи WR# позволяет записать логические уровни, присутст- присутствующие на информационных входах, во внутреннюю ячейку ОЗУ. Сиг- Сигнал чтения RD# позволяет выдать содержимое внутренней ячейки памя- памяти на информационные выходы микросхемы. В приведенной на рис. 3.27 схеме невозможно одновременно производить операцию записи и чте- чтения, но это в большинстве случаев и не нужно. Схема на рис. 3.27 ориен- ориентирована на применение микропроцессорной системы с одной шиной, по которой в разные моменты времени будет осуществляться или запись, или чтение информации. Конкретная ячейка микросхемы, в которую будет записываться инфор- информация, выбирается при помощи двоичного кода — адреса ячейки. Объем памяти микросхемы зависит от количества ячеек, содержащихся в ней. Количество адресных выводов микросхемы ОЗУ однозначно определяет- определяется количеством находящихся в ней ячеек памяти. Исходя из этого, коли- количество ячеек памяти М в микросхеме можно определить по количеству адресных выводов N. Для этого необходимо возвести число 2 в степень, равную количеству адресных выводов микросхемы: Вывод выбора кристалла CS позволяет объединять несколько микросхем для увеличения объема памяти ОЗУ. Пример объединения четырех мик- микросхем ОЗУ с помощью дешифратора приведен на рис. 3.29. При этом общий объем памяти увеличивается в четыре раза. Статические ОЗУ требуют для своего построения большой площади кристалла, поэтому их емкость (количество запоминающих элементов) относительно невелика. Статические ОЗУ применяются для построения микроконтроллерных систем из-за простоты схемы запоминающих уст- устройств на их основе и возможности работать при сколь угодно больших длительностях управляющих сигналов, вплоть до статического режима. Это позволяет свободно выбирать тактовую частоту и упрощает проце- процедуру отладки микропроцессорной системы. Кроме того, статические ОЗУ применяются для построения кэш-памяти в универсальных компью- компьютерах, т. к. они обладают более высоким быстродействием по сравнению с динамическими ОЗУ.
Запоминающие устройства 63 Рис. 3.29. Схема ОЗУ, построенного на нескольких микросхемах памяти Временные диаграммы чтения данных из статического ОЗУ, такие же, как аналогичные диаграммы для рассмотренного ранее ПЗУ. Времен- Временные диаграммы записи в статическое ОЗУ и чтения из него приведены на рис. 3.30. D Запись Считывание Рис. 3.30. Временная диаграмма обращения к ОЗУ, принятая для схем, совместимых с микропроцессорами фирмы Intel
64 Глава 3 На рис. 3.30 стрелочками показана последовательность, в которой долж- должны формироваться управляющие сигналы. На этом рисунке RD — это сигнал чтения; WR — сигнал записи; А — сигналы шины адреса (так как отдельные биты в шине адреса могут принимать разные значения, то по- показаны пути перехода сигнала как в единичное, так и в нулевое состоя- состояние); DI — входная информация, предназначенная для записи в ячейку ОЗУ, расположенную по адресу Al; DO — выходная информация, счи- считанная из ячейки ОЗУ, расположенной по адресу А2. Временная диаграмма, приведенная на рис. 3.30, не единственная, при- применяемая для построения микропроцессорных систем. Она была предло- предложена фирмой Intel и получила широкое распространение. Для обраще- обращения к ОЗУ применяется и временная Диаграмма, предложенная фирмой Motorola. Эта временная диаграмма предполагает наличие постоянно присутствующего синхросигнала и сигнала, который определяет опера- операцию, которую необходимо выполнить (запись или чтение). R/Wj А D Запись Считывание t Рис. 3.31. Временная диаграмма обращения к ОЗУ, принятая для схем, совместимых с микропроцессорами фирмы Motorola Временная диаграмма микросхемы, работающей по описанному выше принципу, приведена на рис. 3.31. На этом рисунке стрелочками показа- показана последовательность, в которой должны формироваться управляющие сигналы, при этом R/W — сигнал выбора операции записи или чтения; DS — сигнал стробирования данных; А — сигналы адресной шины (так
Запоминающие устройства 65 как отдельные биты в шине адреса могут принимать разные значения, то показаны пути перехода сигнала как в единичное, так и в нулевое со- состояние); DI — входная информация, предназначенная для записи в ячейку ОЗУ, расположенную по адресу Al; DO — выходная информа- информация, считанная из ячейки ОЗУ, расположенной по адресу А2. Динамические оперативные запоминающие устройства (ОЗУ) Статические ОЗУ позволяют обеспечивать хранение записанной инфор- информации до тех пор, пока на микросхему подается питание. Однако запо- запоминающая ячейка статического ОЗУ занимает относительно большую площадь, поэтому для ОЗУ большого объема применяют более простую и потому компактную запоминающую ячейку — конденсатор. Естест- Естественно, что заряд на конденсаторе с течением времени уменьшается, по- поэтому его необходимо подзаряжать с периодом приблизительно Юме, называемым периодом регенерации. Подзарядка емкости производится при считывании ячейки памяти, поэтому для регенерации информации достаточно просто считать регенерируемую ячейку памяти. Схема запоминающего элемента динамического ОЗУ и его конструкция приведены на рис. 3.32. Рис. 3.32. Схема запоминающего элемента динамического ОЗУ и его конструкция При считывании заряда емкости необходимо учитывать, что линия счи- считывания имеет большую электрическую емкость, чем запоминающая ячейка. Графики, показывающие, как изменяется напряжение на линии считывания при выполнении операции чтения информации из запоми- запоминающей ячейки без использования схемы регенерации, приведены на рис. 3.33.
66 Глава 3 U лс 1 1 \_ AU! j Чтение 1 \l t p 1 t Чтение О t Рис. 3.33. Графики изменения напряжения на линии считывания при считывании информации с запоминающей ячейки Первоначально на линии записи/считывания присутствует половина на- напряжения питания микросхемы. При подключении к линии запи- записи/считывания запоминающей ячейки заряд, хранящийся в запоминаю- запоминающей ячейке, изменяет напряжение на линии на небольшую величину ДИ Теперь это напряжение необходимо восстановить до первоначального логического уровня. Если приращение напряжения AU было положи- положительным, то напряжение необходимо довести до напряжения питания микросхемы. Если приращение AU было отрицательным, то напряжение необходимо довести до потенциала общего провода. Для регенерации первоначального заряда, хранившегося в запоминаю- запоминающей ячейке, в схеме применяется RS-триггер, включенный между двумя линиями записи/считывания. Схема такого регенерирующего устройства приведена на рис. 3.34. Регенерация Линия 1 Линия 2 Рис. 3.34. Схема регенерирующего каскада Эта схема за счет положительной обратной связи восстанавливает пер воначальное значение напряжения, хранившегося в запоминающей ячей
Запоминающие устройства 67 ке. При этом на соседней линии считывания формируется противопо- противоположный сигнал, но т. к. она в данный момент никуда не подключена, то это неважно. То есть при считывании ячейки производится регенерация хранящегося в ней заряда. Для уменьшения времени регенерации микро- микросхема устроена так, что при считывании одной ячейки памяти в строке запоминающей матрицы регенерируется вся строка. Особенностью использования динамических ОЗУ является мультиплек- мультиплексирование шины адреса. Адрес строки и адрес столбца передаются по- поочередно. Адрес строки синхронизируется стробирующим сигналом RAS# (Row Address Strobe), а адрес столбца — сигналом CAS# (Column Address Strobe). Мультиплексирование адресов позволяет уменьшить ко- количество выводов микросхем ОЗУ, что очень важно для микросхем с большим объемом внутренней памяти, т. е. с большой разрядностью ад- адресной шины. Условное графическое обозначение микросхемы динами- динамического ОЗУ на схемах приведено на рис. 3.35, а временная диаграмма обращения к такой микросхеме — на рис. 3.36. АО Al А2 A3 А4 А5 А6 Al A8 A9 >R7W RAS |>CAS RAM D 0 1 2 3 4 5 6 7 Рис. 3.35. Условное графическое обозначение динамического ОЗУ Именно так долгое время велась работа с динамическими ОЗУ. Затем было замечено, что обычно обращение ведется к данным, лежащим в со- соседних ячейках памяти, поэтому не обязательно при считывании или записи каждый раз передавать адрес строки. Данные стали записывать или считывать блоками и адрес строки передавать только в начале бло- блока. При этом можно сократить общее время обращения к динамическому ОЗУ и тем самым увеличить быстродействие компьютера.
68 Глава 3 RASi CAS A R/Wi Запись Считывание Регенерация Рис. 3.36. Временная диаграмма обращения к динамическому ОЗУ Такое обращение к динамическому ОЗУ называется быстрым странич- страничным режимом доступа (FPM, Fast Page Mode). Длина считываемого бло- блока данных обычно равна четырем словам. Время доступа к памяти при- принято оценивать в тактах системной шины процессора. В обычном режиме доступа к памяти оно одинаково для всех слов. Поэтому цикл обращения к динамической памяти можно записать как 5-5-5-5. При ре- режиме быстрого страничного доступа цикл обращения к динамической памяти можно записать как 5-3-3-3, т. е. время обращения к первой ячей- ячейке не изменяется по сравнению с предыдущим случаем, а считывание по- последующих ячеек сокращается до трех тактов. При этом среднее время доступа к памяти сокращается почти в полтора раза. Временная диа- диаграмма режима FPM приведена на рис. 3.37. Еще одним способом увеличения быстродействия ОЗУ является приме- применение микросхем EDO (Extended Data Out — ОЗУ с расширенным выхо- выходом данных). В EDO ОЗУ усилители-регенераторы не сбрасываются по окончанию строба CAS#, поэтому времени для считывания данных в та- таком режиме больше. Теперь для того чтобы сохранить время считывания на прежнем уровне, можно увеличить тактовую частоту системной шины
Запоминающие устройства 69 и тем самым увеличить быстродействие компьютера. Для EDO ОЗУ цикл обращения к динамической памяти можно записать как 5-2-2-2. RASj \ Г CASj t RAVI t A t DI DI DI t Рис. 3.37. Временная диаграмма записи в динамическое ОЗУ в режиме FPM Следующим шагом в развитии схем динамического ОЗУ было примене- применение в составе ОЗУ счетчика столбцов. То есть при переходе адреса ячейки к следующему столбцу запоминающей матрицы адрес столбца инкремен- тируется (увеличивается) автоматически. Такое ОЗУ получило название BEDO (ОЗУ с пакетным доступом). В этом типе ОЗУ удалось достигнуть режима обращения к динамической памяти 5-1 -1 -1. В синхронном динамическом ОЗУ (SDRAM) увеличение быстродействия получается за счет применения конвейерной обработки сигнала. Как из- известно, при использовании конвейера можно разделить операцию счи- считывания или записи на отдельные подоперации, такие как выборка строк, выборка столбцов, считывание ячеек памяти, и производить эти операции одновременно. При этом пока на выход передается считанная ранее информация, производится дешифрация столбца для текущей ячейки памяти и производится дешифрация строки для следующей ячей- ячейки памяти. Этот процесс иллюстрируется рис. 3.38, а.
70 Глава 3 t CLK t CLK Рис. 3.38. Структурная схема конвейерной обработки данных Из приведенного рисунка видно, что, несмотря на увеличение времени доступа к ОЗУ при считывании одной ячейки памяти, при считывании нескольких соседних ячеек памяти общее быстродействие микросхем синхронного динамического ОЗУ возрастает. Для сравнения на рис. 3.38, б приведена структурная схема обычного динамического ОЗУ. Время за- задержки распространения сигнала /3 в этой схеме равно периоду тактово- тактового сигнала в шине обращения к ОЗУ и определяется по формуле: /з = tCT + tDC + *ЗМ, где 1ст — это время срабатывания счетчика адреса динамического ОЗУ; toe — это время распространения сигнала дешифратора адреса; /зм — это время появления сигнала на выходе запоминающей матрицы. Время задержки распространения сигнала в схеме синхронного динами- динамического ОЗУ можно определить по формуле: где /rg — это записи в параллельный регистр. Таким образом, время доступа к синхронному динамическому ОЗУ больше, чем к обычному динамическому ОЗУ. Однако период тактового сигнала можно значительно уменьшить, т. к. он будет определяться мак- максимальным из времен: 'обр = maX < 'rrl dc *
Запоминающие устройства 71 Поэтому, несмотря на то, что при обращении к одиночной ячейке па- памяти время доступа к SDRAM возрастает, при пакетном считывании последовательно расположенных байт общее время считывания оказы- оказывается значительно меньшим, т. к. все последующие данные на выходе ОЗУ будут появляться с периодом /Обр. Выигрыш при пакетной работе SDRAM может быть достаточно большим, т. к. при обращении к этому типу памяти допустимо устанавливать размер пакета данных равным 256 слов. На этом закончим рассмотрение различных видов памяти микропроцес- микропроцессорных устройств. Полученных знаний вполне достаточно для продол- продолжения изложения материала. Если же кому-либо захочется более под- подробно ознакомиться с устройствами запоминания информации, можно обратиться к специализированной литературе [1, 3, 5-7]. Итак, подведем итоги В данной главе были рассмотрены различные устройства хранения данных. Используя сумматоры, рассмотренные в предыдущей главе и запоминающие устройства, рассмотренные в этой главе, уже можно по- построить устройство обработки данных, входящее в состав любого мик- микропроцессора. А теперь научимся работать с двоичными числами: суммировать их, вы- вычитать, работать со знаком и с дробными числами. Кроме того, пора бы научиться работать и с обычными текстами!
шооп Глава 4 Принципы работы микропроцессора Теперь рассмотрены принципы работы основных узлов микропроцес- микропроцессорной системы, и можно перейти к изучению операционного блока микропроцессора. Он предназначен для выполнения команд, т. е. реали- реализует операции обработки данных. Однако прежде чем рассмотреть этот блок, давайте научимся представлять данные в двоичном виде и немного поучимся считать. Обратите внимание, что все примеры будут приведе- приведены в двоичном виде. Именно в такой форме выполняет обработку дан- данных цифровая аппаратура. Здесь не будет использоваться шестнадцате- ричная или восьмеричная форма записи двоичного кода. Эти формы записи двоичного числа удобны своею краткостью. Но для лучшего по- понимания принципов обработки данных удобней использовать двоичную запись. Виды двоичных кодов В микропроцессорах двоичные коды используются для представления любых обрабатываемых данных: чисел, текста, команд и т. д. При этом разрядность двоичных кодов может превышать разрядность внутренних регистров самого процессора и ячеек используемой памяти. В таком слу- случае длинный код может занимать несколько ячеек памяти и обрабаты- обрабатываться несколькими командами процессора. Подчеркнем, что все ячейки памяти, выделенные под многобайтное число, рассматриваются как одно число. Для представления числовых данных могут использоваться знаковые и беззнаковые коды. Для определенности примем разрядность процессора равной 8 битам, и в последующих примерах будем рассматривать именно такие числа.
74 Глава 4 Беззнаковые двоичные коды Первый вид двоичных кодов, который мы рассмотрим, используется для представления целых беззнаковых чисел. В нем каждый двоичный разряд представляет собой степень цифры 2. Формат 8-разрядного беззнакового двоичного кода приведен на рис. 4.1. 27 1 0 2б 1 0 25 1 0 24 1 • 0 23 1 • 0 22 1 0 21 1 0 2° 1 0 Максимально возможное число B55) Минимально возможное число @) Рис. 4.1. Формат 8-разрядного беззнакового двоичного кода При этом минимально возможное число, которое можно записать таким двоичным кодом, равно 0. Максимально возможное число, которое можно представить этим кодом, можно определить как М =2"- К где п — разрядность двоичного числа. Разрядность числа обычно выби- выбирают кратной разрядности микропроцессора. Эти два числа полностью определяют диапазон значений чисел, которые можно представить двоичным кодом. В случае двоичного 8-разрядного беззнакового двоичного кода целые числа, которые можно записать с его помощью, находятся в диапазоне от 0 до 255. Восьмиразрядное двоичное число обычно называют байтом. Для беззнакового двоичного 16-разрядного кода диапазон представляе- представляемых значений будет от 0 до 65535. В микропроцессорной системе, по- построенной на 8-разрядном процессоре, для хранения 16-разрядного числа используется две ячейки памяти, расположенные в соседних адресах. Для работы с числами, занимающими несколько ячеек памяти, используются специальные команды микропроцессора, позволяющие учитывать пере- перенос между младшими и старшими байтами. Прямые знаковые двоичные коды Второй вид двоичных кодов, который мы рассмотрим, — это прямые целые знаковые коды. В этих кодах старший разряд в слове используется для представления знака числа. В прямом знаковом коде нулем обозна- обозначается знак «+», а единицей - знак «-». В результате введения знакового
Принципы работы микропроцессора 75 разряда диапазон чисел, представляемых двоичным кодом, смещается в сторону отрицательных чисел. Формат 8-разрядного прямого знакового двоичного кода приведен на рис. 4.2. На рисунке приведено шесть раз- различных чисел, записанных в этом коде. Знак числа 26 25 24 23 22 21 2° 0 0 0 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 • ¦ 0 0 • 0 • ¦ 1 1 • 1 • 0 0 • 1 • 1 1 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 1 Максимально возможное число (+127) +10 +0 -0 -10 Минимально возможное число (-127) Рис. 4.2. Формат 8-разрядного прямого знакового двоичного кода Диапазон 8-разрядных целых чисел, которые можно записать, пользуясь таким кодом, простирается от -127 до +127. Для 16-разрядного числа этот диапазон составит от -32767 до +32767. В 8-разрядном процессоре для хранения такого числа используются две ячейки памяти, располо- расположенные в соседних адресах. Недостатком прямого знакового кода является то. что знаковый разряд и цифровые разряды приходится обрабатывать раздельно. Алгоритм программ, работающих с такими кодами, получается сложный. Для вы- выделения и изменения знакового разряда приходится применять механизм маскирования разрядов, что резко увеличивает размер программы и уменьшает ее быстродействие. Для того чтобы алгоритм обработки зна- знакового и цифровых разрядов не различался, были введены обратные двоичные коды. Знаковые обратные двоичные коды Обратные двоичные коды отличаются от прямых только тем, что от- отрицательные числа в них получаются инвертированием всех разрядов положительного числа. При этом обработка знакового и цифровых
76 Глава 4 разрядов не различается. Алгоритм работы с такими кодами резко упрощается. Тем не менее, при работе с обратными кодами требуется специальный алгоритм распознавания знака, вычисления абсолютного значения числа и восстановления знака результата числа. Кроме того, в прямом и об- обратном коде для представления числа 0 используются два разных кода, тогда, как известно, что число 0 положительное и отрицательным не мо- может быть никогда. Формат 8-разрядного обратного знакового двоичного кода приведен на рис. 4.3. На рисунке приведено шесть различных чисел, записанных в этом коде. Знак числа 26 25 24 23 22 21 2° 0 0 1 0 1 0 1 • 0 1 • 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 . . . 1 1 1 1 0 1 0 1 1 0 0 0 0 0 0 0 Максимально возможное число (+127) +10 +0 -0 -10 Минимально возможное число (-127) Рис. 4.3. Формат 8-разрядного обратного знакового двоичного кода Знаковые дополнительные двоичные коды От перечисленных недостатков свободны дополнительные коды. Они позволяют суммировать положительные и отрицательные числа, не ана- анализируя знаковый разряд, и при этом получать правильный результат. Все это становится возможным благодаря тому, что дополнительные числа являются естественным кольцом чисел, а не искусственным обра- образованием, как прямые и обратные коды. Кроме того, немаловажным яв- является то обстоятельство, что вычислять дополнение в двоичном коде чрезвычайно легко. Для этого достаточно к обратному коду добавить 1. Формат 8-разрядного дополнительного знакового двоичного кода при-
Принципы работы микропроцессора 77 веден на рис. 4.4. На рисунке приведено шесть различных чисел, запи санных в этом коде. Знак числа 26 25 24 23 22 21 2° 0 0 0 1 1 1 1 0 0 1 1 0 1 0 0 1 1 0 1 • 0 • 0 1 • 1 • 0 1 • 1 • 0 1 • 0 . 0 1 0 0 1 1 0 1 1 0 1 1 0 1 0 0 1 0 0 Максимально возможное число (+127) +10 +0 -1 -10 Минимально возможное число (-128) Рис. 4.4. Формат 8-разрядного дополнительного знакового двоичного кода Числа, которые можно представлять 8-разрядным дополнительным дво- двоичным кодом, находятся в диапазоне от -128 до +127. Для 16-разрядного кода этот диапазон будет от -32768 до +32767. В 8-разрядном процессоре для хранения 16-разрядного числа используются две ячейки памяти, рас- расположенные в соседних адресах. В обратных и дополнительных кодах наблюдается интересная особен- особенность, которая называется эффектом распространения знака: при преоб- преобразовании однобайтного числа в двухбайтное достаточно всем битам старшего байта присвоить значение знакового бита исходного байта. То есть для хранения знака числа можно использовать сколько угодно старших битов. При этом значение кода совершенно не изменяется. Эф- Эффект распространения знака используется при подключении таких уст- устройств, как АЦП или ЦАП, к микропроцессору если их разрядности не совпадают. Использование для представления знака числа двух битов предоставляет интересную возможность контролировать возникновение переполнения при выполнении арифметических операций. В качестве второго знаково- знакового бита используется флаг переноса С. Можно конечно использовать и большее количество знаковых битов, но это никаких дополнительных преимуществ не дает.
78 Глава 4 Рассмотрим несколько примеров работы с дополнительными двоичными кодами. 1. Просуммируем числа +12 и +5. Суммирование этих чисел в двоичном и десятичном представлении приведено на рис. 4.5. 00001100 12 00000101 <=> 5 000010001 17 Перенос Знак Рис. 4.5. Суммирование чисел +12 и +5 В этом примере видно, что в результате суммирования получается правильный результат. Это можно проконтролировать по флагу пе- переноса С, который совпадает со знаком результата (эффект распро- распространения знака действует). 2. Просуммируем два отрицательных числа -12 и -5. Суммирование этих чисел в двоичном и десятичном представлении приведено на рис. 4.6. 11110100 -12 11111011 <=> -5 111101111 -17 Перенос Знак Рис. 4.6. Суммирование чисел -12 и -5 В этом примере флаг переноса С тоже совпадает со знаком результата, т. е. переполнения не произошло и в этом случае. 3. Просуммируем положительное и отрицательное числа -12 и +5. Сум- Суммирование этих чисел в двоичном и десятичном представлении приве- приведено на рис. 4.7. В этом примере при суммировании положительного и отрицательного числа автоматически получается правильный знак результата. В дан- данном случае знак результата отрицательный. Флаг переноса совпадает со знаком результата, поэтому переполнения не было (мы можем убе-
Принципы работы микропроцессора 79 диться в этом непосредственными вычислениями на бумаге или на калькуляторе). 4. Просуммируем положительное и отрицательное числа +12 и -5. Сум- Суммирование этих чисел в двоичном и десятичном представлении приве- приведено на рис. 4.8. 11110100 -12 + + 00000101 <=> +5 111111001 -7 Перенос Знак Рис. 4.7. Суммирование чисел -12 и +5 00001100 +12 11111011 <=> -5 000000111 +7 '\ Перенос Знак Рис. 4.8. Суммирование чисел +12 и -5 В данном примере знак результата положительный. Флаг переноса совпадает со знаком результата, поэтому переполнения не было и в этом случае. 5. Просуммируем числа +100 и +31. Суммирование этих чисел в двоич- двоичном и десятичном представлении приведено на рис. 4.9. 01100100 +100 00011111 <=> +31 010000011 +131!! Перенос Знак Рис. 4.9. Суммирование чисел +100 и +31 В этом примере видно, что в результате суммирования произошло пе- переполнение 8-битовой переменной, т. к. в результате операции над по- положительными числами получился отрицательный результат. Если рас-
Глава 4 смотреть флаг переноса С, то он не совпадает со знаком результата. Эта ситуации является признаком переполнения результата и легко обнару- обнаруживается при помощи операции «исключающее ИЛИ» над старшим би- битом результата и флагом переноса С. Большинство процессоров осуще- осуществляют эту операцию аппаратно и помещают результат во флаг переполнения OV. 6. Просуммируем числа -100 и -31. Суммирование этих чисел в двоич- двоичном и десятичном представлении приведено на рис. 4.10. 10011100 -100 + 11100001 <=> -31 101111101 -131!! Перенос Знак Рис. 4.10. Суммирование чисел -100 и -31 В этом примере операции над отрицательными числами в результате суммирования произошло переполнение 8-битовой переменной, т. к. по- получился положительный результат. И в этом случае если рассмотреть флаг переноса С, то он не совпадает со знаком результата. Отличие от предыдущего случая только в комбинации этих битов. В примере 5 гово- говорят о переполнении результата (комбинация 01), а в примере 6 — об ан- антипереполнении результата (комбинация 10). Представление рациональных чисел в двоичном коде с фиксированной запятой Кроме целых чисел, часто требуется работать с рациональными числами. Как и в случае целых чисел, рациональные числа могут быть беззнако- беззнаковыми и знаковыми. Для двоичного представления знаковых рациональ- рациональных чисел могут быть использованы прямые, обратные и дополнитель- дополнительные коды. Принцип их построения точно такой же, как и в случае целых чисел. Рассмотрим, как можно записать рациональное число. Ранее, рассматри- рассматривая целые числа, мы предполагали, что в двоичном числе запятая, разде- разделяющая целую и дробную части, находится правее самого младшего раз- разряда. Но кто сказал, что она должна всегда находиться именно в этом
Принципы работы микропроцессора 81 месте? Мы можем договориться, что запятая, разделяющая целую и дробную части двоичного числа, находится слева от самого старшего разряда, и тогда в такой переменной можно будет записывать только дробные числа, меньшие 1,0ю. Формат 8-разрядного дробного беззнако- беззнакового двоичного кода приведен на рис. 4.11. На рисунке приведены два числа, записанных в этом коде. 21 1 0 2-2 1 0 2-3 1 0 2-4 1 • 0 2-5 1 • 0 2-е 1 0 2-' 1 0 2-8 1 0 Максимально возможное число @,9960938) Минимально возможное число @) Рис. 4.11. Формат 8-разрядного дробного беззнакового двоичного кода Или договоримся, что она находится точно посередине кода, и тогда мы сможем записывать числа, содержащие как целую, так и дробную части. Формат такого 8-разрядного беззнакового двоичного кода при- приведен на рис. 4.12. На рисунке приведены два числа, записанных в этом коде. 23 1 0 22 1 0 21 1 0 2° 1 • 0 2-1 1 • 0 22 1 0 2-3 1 0 2-4 1 0 Максимально возможное число A5,9375) Минимально возможное число @) Рис. 4.12. Формат 8-разрядного смешанного беззнакового двоичного кода Остальные виды двоичных кодов, используемых для представления чи- чисел с фиксированной запятой, рассматривать не будем. Они строятся точно так же, как и для целых чисел. Представление рациональных чисел в двоичном коде с плавающей запятой Часто приходится обрабатывать очень большие числа (например, рас- расстояние между звездами) или, наоборот, очень маленькие числа (на-
82 Глава 4 пример, размеры атомов или электронов). При таких вычислениях при- пришлось бы использовать числа с фиксированной запятой очень большой разрядности. В то же время нам не нужно знать расстояние между звез- звездами с точностью до миллиметра. Для вычислений с такими величинами числа с фиксированной запятой неэффективны. В десятичной арифметике в таких случаях число записывается в виде мантиссы, умноженной на 10 в степени, отображающей порядок числа, например: 2- 105; 1,6- Ю-38. В алгебре такое представление рациональных чисел называют стандарт- стандартным видом числа. В двоичной арифметике тоже используется похожая форма записи чисел — представление с плавающей запятой (часто также называемое представлением с плавающей точкой). А теперь рассмотрим промышленные стандарты, используемые для представления чисел с плавающей запятой в компьютерах. Существует стандарт ШЕЕ 754 для представления чисел с одинарной точностью (float) и с двойной точностью (double). Для записи числа в формате с плавающей запятой одинарной точности требуется 32-битовое слово. Для записи чисел с двойной точностью требуется 64-битовое слово. Ча- Чаще всего числа хранятся в нескольких соседних ячейках памяти процес- процессора. Форматы одинарной точности и удвоенной точности числа с пла- плавающей запятой приведены на рис. 4.13. 31 30 23 22 ... 0 S Е m 27 2° 2 2'23 63 62 52 51 ... 0 S Е m 2 2° 2'1 Рис. 4.13. Форматы чисел с плавающей запятой На рис. 4.13 над полями числа с плавающей запятой показан номер двоичного разряда, а внизу двоичный вес каждого разряда. При этом буквой S обозначен знак числа, 0 — это положительное число, 1 — от- отрицательное число, е обозначает смещенный порядок числа. Смещение требуется, чтобы не вводить в число еще один знак. Смещенный поря- порядок — всегда положительное число. В формате одинарной точности для порядка выделено 8 битов. Для смещенного порядка двойной точ-
Принципы работы микропроцессора 83 ности отводится 11 битов. Для формата одинарной точности принято смещение 127, а для формата двойной точности — 1023. В десятичной мантиссе числа стандартного вида старший разряд — это цифра от 1 до 9. Старший разряд двоичной мантиссы — всегда 1. Поэтому для хранения старшей единицы двоичной мантиссы не выделяется отдель- отдельный бит. Единица подразумевается, как и запятая, отделяющая дроб- дробную часть от целой. Кроме того, в формате чисел с плавающей точкой принято, что мантисса всегда больше 1. То есть значения мантиссы ле- лежат в диапазоне от 1 до 2. Рассмотрим несколько примеров. 1. Определить число с плавающей запятой, лежащее в четырех соседних байтах: 11000001 01001000 00000000 00000000. • Знаковый бит, равный 1, показывает, что число отрицательное. • Экспонента 10000010 в десятичном виде соответствует числу 130. Вычтя число 127 (смещение) из 130, получим число 3. • Теперь запишем мантиссу с учетом неявной единицы: 100 1000 0000 0000 0000 0000 1,1001 • И, наконец, определим десятичное число: 1100,12 = 12,5ю. 2. Определить число с плавающей запятой, лежащее в четырех соседних байтах: 11000011 00110100 00000000 00000000. • Знаковый бит, равный 1, показывает, что число отрицательное. • Экспонента 10000110 в десятичном виде соответствует числу 134. Вычтя число 127 из 134, получим число 7. • Теперь запишем мантиссу: 011 0100 0000 0000 0000 0000 1,01101. • И, наконец, определим десятичное число: 101 ЮЮО2 = 180ю. Для того чтобы записать ноль, достаточно записать в смещенный порядок число 000000002. Значение мантиссы при этом не имеет значения. Число, в котором все байты равны 0, тоже попадает в этот диапазон значений. Бесконечность соответствует смещенному порядку 1111111 Ь и мантиссе, равной 1,0. При этом существует минус бесконечность и плюс бесконеч- бесконечность (переполнение и антипереполнение), которые часто отображаются на экране монитора как +INF и -INF. При таком значении порядка все остальные комбинации битов в мантис- мантиссе (в том числе и все единицы) воспринимаются как не числа и отобра- отображаются на экране как NaN.
84 Глава 4 Представление десятичных чисел Иногда бывает удобно хранить числа в памяти процессора в десятичном виде (например, для вывода на экран дисплея или при финансовых рас- расчетах). Для представления таких чисел используются двоично-десятич- двоично-десятичные коды. Цифра одного десятичного разряда представляется при по- помощи четырех двоичных битов, называемых тетрадой. Иногда встреча- встречается название, пришедшее из англоязычной литературы, — нибл. При помощи четырех битов можно закодировать шестнадцать цифр. Лишние комбинации в двоично-десятичном коде являются запрещенными. Таб- Таблица соответствия двоично-десятичного кода и десятичных цифр приве- приведена в табл. 4.1. Таблица 4.1. Таблица соответствия двоично-десятичного кода и десятичных цифр Двоично-десятичный код 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 0 0 1 1 0 0 0 1 0 1 0 1 0 1 0 1 Десятичный код 0 1 2 3 4 5 6 7 8 9 Остальные комбинации двоичного кода в тетраде являются запрещен- запрещенными. Запишем пример двоично-десятичного кода: 1258 = 0001 0010 0101 1000 589 = 0000 0101 1000 1001 Достаточно часто в памяти процессора для хранения одной десятичной цифры выделяется одна ячейка памяти (8-, 16- или 32-разрядная). Это де- делается для повышения скорости работы программы. Для того чтобы от- отличить такое представление двоично-десятичного числа от стандартного, последнее называют упакованной формой двоично-десятичного числа.
Принципы работы микропроцессора 85 Суммирование двоично-десятичных чисел Суммирование двоично-десятичных чисел можно производить по пра- правилам обычной двоичной арифметики, а затем производить двоично- десятичную коррекцию, заключающуюсяся в проверке каждой тетрады на допустимость ее кода. Если в какой-либо тетраде обнаруживается запрещенная комбинация или был перенос в старшую тетраду, то это говорит о переполнении. В этом случае необходимо произвести двоич- двоично-десятичную коррекцию. Двоично-десятичная коррекция заключается в дополнительном суммировании числа 6 (число запрещенных комби- комбинаций) с тетрадой, в которой произошло переполнение. Приведем два примера использования двоично-десятичной коррекции. Просуммиру- Просуммируем десятичное число 18, записываемое в двоично-десятичном коде как 0001 1000 и десятичное число 13, двоично-десятичный код 0001 ООП. Ожидаемый результат 31. Запишем наши действия в столбик, как это показано на рис. 4.14. 0001 1000 0010 1011 0001 0011 =* 0000 0110 0010 1011 0011 0001 Рис. 4.14. Суммирование чисел 18 и 13 в двоично-десятичном коде В результате выполнения двоичного суммирования получим число 0010 1011 BBi6). To есть младшая тетрада содержит запрещенную комби- комбинацию. Это означает, что необходимо выполнить десятичную коррек- коррекцию. Прибавим к младшей тетраде код коррекции 6. Эта операция пока- показана на рис. 4.14 в столбике, записанном справа. В результате второго двоичного суммирования получаем результат 31. То есть именно то, что и ожидалось! Во втором примере просуммируем два десятичных числа 19, записывае- записываемых в двоично-десятичном коде как 0001 1001. Ожидаемый результат 38. Запишем наши действия в столбик, как это показано на рис. 4.15. В результате выполнения двоичного суммирования получим число 0011 0010 C2). В этом случае запрещенных комбинаций нет. Но зато был перенос в старшую тетраду, т. е. и в этом случае необходимо выполнить десятичную коррекцию. Прибавим к младшей тетраде код коррекции 6. Эта операция показана на рис. 4.15 в столбике, записанном справа. В ре-
86 Глава 4 зультате второго двоичного суммирования получаем результат 38. То есть именно то, что и ожидалось! Работа со старшей тетрадой ничем не отличается от работы с младшей тетрадой, рассмотренной в приведен- приведенных примерах. 0001 1001 0011 0010 + 0001 1001 => 0000 0110 0011 0010 0011 1000 Рис. 4.15. Суммирование двух чисел 19 в двоично-десятичном коде Представление текстовых данных в памяти процессора Для кодирования всех символов и букв достаточно восьми двоичных разрядов. Наиболее распространенными являются таблицы кодирования текста ASCII с национальными расширениями, применяемые в DOS (и которые можно использовать для записи текстов в микропроцессорах), и таблицы ANSI, применяемые в Windows. В этих двух группах таблиц первые 128 символов совпадают. В этой части таблицы содержатся сим- символы цифр, знаков препинания, латинские буквы верхнего и нижнего ре- регистров и управляющие символы. Национальные расширения символь- символьных таблиц и символы псевдографики содержатся в последних 128 кодах этих таблиц, поэтому кодировки русских текстов в DOS и Windows не совпадают. Таблица ASCII-символов приведена в Приложении. Арифметико-логические устройства Теперь после того как мы научились работать с двоичными кодами, можно перейти к устройствам, которые могут выполнять различные опе- операции над этими числами — суммировать, вычитать, увеличивать и уменьшать на единицу. При этом выбор выполняемой операции жела- желательно выполнять также при помощи двоичного кода. Такое устройство получило название арифметического устройства. Если же оно, кроме арифметических операций, выполняет еще и логические, то его называют арифметико-логическим устройством (АЛУ).
Принципы работы микропроцессора 87 Ранее были рассмотрены схемы, осуществляющие суммирование много- многоразрядных кодов. Однако часто требуется осуществлять не только сум- суммирование, но и вычитание двоичных кодов. Двоичные коды, при помощи которых можно записывать отрицательные числа, уже рассмат- рассматривались в предыдущих разделах. Там же было показано, что при использовании дополнительных кодов операцию вычитания двух поло- положительных чисел можно заменить операцией суммирования положи- положительного и отрицательного числа, при этом получение двоичного отри- отрицательного числа из положительного является элементарной операцией. Для этого необходимо проинвертировать число и прибавить к нему 1. Схема вычитателя числа А из числа В приведена на рис. 4.16, а схема вы- читателя числа В из числа А приведена на рис. 4.17. В этих схемах при- прибавление единицы к проинвертированному числу осуществляется пода- подачей уровня логической единицы на вход переноса сумматора PL Основным элементом этих двух схем является сумматор. Различаются они лишь местом включения инверторов. Рис. 4.16. Схема вычитателя числа А из числа В +U. п А0~ А1 - А2- АЗ- 80 - 81 - 82 — 83 — PI АО А1 А2 A3 БО В1 В2 ВЗ SM SO SI S2 S3 РО SO SI S2 S3 Рис. 4.17. Схема вычитателя числа В из числа А
88 Глава 4 Если же потребуется в процессе вычислений изменять арифметическую операцию, то в схему можно ввести коммутатор, который будет изменять ее внутреннюю структуру в зависимости от выполняемой арифметиче- арифметической операции. Такое устройство получило название арифметического устройства. Его структурная схема приведена на рис. 4.18. По ней легко получить принципиальную схему, поэтому для упрощения анализа все дальнейшие рассуждения будем производить по структурной схеме. Рис. 4.18. Структурная схема арифметического устройства В приведенной на рис. 4.18 схеме используются четырехвходовые муль- мультиплексоры, для управления каждым из которых достаточно двух битов. То есть для управления всей схемой в целом достаточно четырех сигна- сигналов управления. Попытаемся построить таблицу операций, которые бу- будет выполнять эта схема. На результат операции будет влиять входной сигнал переноса сумматора PI, поэтому его тоже включим в состав кода, управляющего схемой. Операции, которые выполняются арифметиче- арифметическим устройством в зависимости от кода, поданного на управляющие линии, приведены в табл. 4.2. Проанализируем эту таблицу. Если на все управляющие входы подать низкий потенциал, то к входу сумматора будут подключены коды А и В без инверсии. В этом случае будет производиться операция суммирова- суммирования. Эта ситуация ртображена первыми двумя строками (с номерами 0 и 1) таблицы выполняемых операций.
Принципы работы микропроцессора 89 Операция вычитания осуществляется строками 2, 3, 8 и 9. В этом случае один из операндов поступает на вход сумматора через блок инверторов. Единица, требуемая для получения дополнительного кода, подается на вход переноса сумматора PI. Таблица 4.2. Список команд арифметического устройства Номер строки 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Управляющий код КО 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 К1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 К2 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 КЗ 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 PI 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 Выполняемая операция S = A+ В S = А + В+1 S=B-A-1 S = B-A S = B-1 S = B S = B S = B+ 1 S=A-B-1 S = A-B S=-A-B-2 S=-B-A-1 S=-B-2 S=-B-1 S=-B-1 S = -B S = A-1 S = A S=-A-2 S=-A-1 S = -2 S=-1 S = -1 4 Зак 328
Глава 4 Таблица 4.2 (окончание) Номер строки 23 24 25 26 27 28 29 30 31 Управляющий код КО 1 1 1 1 1 1 1 1 1 К1 0 1 1 1 1 1 1 1 1 К2 1 0 0 0 0 1 1 1 1 КЗ 1 0 0 1 1 0 0 1 1 PI 1 0 1 0 1 0 1 0 1 Выполняемая операция s = o S = A S = A+ 1 S=-A-1 S = -A S = -1 S = 0 S = 0 S = +1 Часто используемой операцией является увеличение числа на единицу (инкрементирование) или уменьшение числа на единицу (декремен- тирование). Эти операции позволяют легко организовывать циклы в программе и переходить от предыдущего операнда к следующему. Они могут быть выполнены при помощи кодов, записанных в строках 4, 7, 16 и 25. Кроме того, схема арифметического устройства может просто переда- передавать на выход любой из входных кодов без изменения, что позволяет осуществлять копирование данных (суммирование с константой ноль) через это устройство без дополнительных схем коммутации. При небольшом изменении схемы такое устройство сможет осуществлять не только арифметические, но и логические операции. Для этого нужно ввести дополнительный коммутатор, который будет разрывать цепи пе- переноса между разрядами. Эта управляющая цепь обычно называется М. Подчеркнем основную особенность полученного устройства: выбор вида выполняемой операции при помощи кода, подаваемого на специальные выводы. Это дает возможность использовать одно и то же устройство для выполнения различных функций. Разработка такого устройства по- позволила обменивать большую скорость выполнения отдельных операций на сложность реализуемого алгоритма, что, в конце концов, привело к разработке микропроцессорных систем. Развитие этих систем изменило окружающий нас мир.
Принципы работы микропроцессора 91 Классификация микропроцессоров Прежде чем приступить к изучению внутреннего устройства микропро- микропроцессоров, рассмотрим основные их типы. По внутреннему устройству в настоящее время наметилось два направле- направления развития микропроцессоров: ? RISC-процессоры (процессоры с сокращенным набором команд); ? CISC-процессоры (процессоры с полным набором команд). В процессорах с полным набором команд используется уровень микро- микропрограммирования, обеспечивающий декодирование и выполнение команд микропроцессора. Команды микропрограмм называют микро- микрокомандами. В этих процессорах формат команды не зависит от аппара- аппаратуры процессора. На одной и той же аппаратуре при смене микропро- микропрограммы могут быть реализованы различные микропроцессоры. С другой стороны, смена аппаратуры никак не влияет на программное обеспечение микропроцессора. При разработке новых микросхем можно использовать аппаратурные решения, никак не связанные с предыдущей микросхемой. Главное, чтобы микропрограмма эмулировала эту микро- микросхему. То есть пользователь воспринимает новую микросхему как полный аналог старой. С его точки зрения у микропроцессора только увеличива- увеличивается производительность, снижается потребление энергии, уменьшаются габариты устройств. Определение микрокоманды и пример реализации микропрограммы бу- будут подробно рассмотрены ниже по тексту данной главы. Поэтому сей- сейчас эти понятия уточняться не будут. Неявным недостатком CISC-процессоров является то, что производители микросхем стараются увеличить количество команд, которые может вы- выполнять микропроцессор, тем самым увеличивая сложность микропро- микропрограммы и замедляя выполнение каждой команды. В RISC-процессорах декодирование и исполнение команды производятся аппаратно, поэтому количество команд ограничено минимальным набо- набором. В этих процессорах понятия команда и микрокоманда совпадают. Преимуществом этого типа процессоров является то, что команда может быть в принципе выполнена за один такт (не требуется выполнение мик- микропрограммы), однако для выполнения тех же действий, которые выпол- выполняет одиночная команда CISC-процессора, требуется выполнение неко- некоторой последовательности команд RISC-процессоров, иногда это после-
92 Глава 4 довательность довольно длинная. То есть выигрыш в быстродействии микропроцессора может быть сведен к нулю. В большинстве случаев быстродействие у RISC-процессоров выше, чем у CISC-процессоров. Тем не менее, при выборе процессора нужно прини- принимать в расчет все параметры в целом. Нужно учитывать, что тактовая частота RISC-процессора может оказаться значительно ниже, чем у CISC-процессора (особенно если в нем применяются специальные меры по повышению производительности), разрядность команды может ока- оказаться выше, чем у CISC-процессора (что чаще всего и бывает). В резуль- результате общий объем исполняемой программы для RISC-процессора, как правило, превышает объем подобной программы для CISC-процессора. Следующий признак классификации архитектур микропроцессоров — это система команд. По системе команд микропроцессоры отличаются огромным разнообразием, зависящим от фирмы-производителя. Тем не менее, можно определить две крайние архитектуры построения микро- микропроцессоров: аккумуляторные микропроцессоры; микропроцессоры с регистрами общего назначения. В микропроцессорах с регистрами общего назначения операнды матема- математических операций могут находиться в любом внутреннем регистре. В зависимости от типа операции команда может быть одноадресной, двухадресной или трехадресной. Принципиальным отличием аккумуляторных процессоров является то, что математические операции могут производиться только над одной особой ячейкой памяти, аккумулятором. Для того чтобы произвести операцию над произвольной ячейкой памяти, ее содержимое необходимо скопировать в аккумулятор, выполнить требуемую операцию, а затем скопировать полученный результат в произвольную ячейку памяти. В настоящее время в чистом виде не существует ни та, ни другая архитек- архитектуры. Все выпускаемые в настоящее время процессоры обладают систе- системой команд с признаками, как аккумуляторных процессоров, так и мик- микропроцессоров с регистрами общего назначения. Следующий признак, по которому классифицируются микропроцессо- микропроцессоры, — это способ работы с системной памятью. По способу работы с сис- системной памятью существует два основных принципа построения микро- микропроцессоров: гарвардская архитектура; архитектура фон Неймана.
Принципы работы микропроцессора 93 В гарвардской архитектуре принципиально различаются два вида памяти: ? память программ; ? память данных. В гарвардской архитектуре принципиально невозможно производить операцию записи в память программ, что исключает возможность слу- случайного разрушения управляющей программы в случае неправильных действий надданными. Кроме того, в ряде случаев для памяти программ и памяти данных выделяются отдельные шины обмена данными. Эти особенности определили области применения гарвардской архитектуры микропроцессоров. Она применяется в микроконтроллерах, где требует- требуется обеспечить высокую надежность работы аппаратуры. В сигнальных процессорах эта архитектура, кроме высокой надежности работы уст- устройств, позволяет обеспечить высокую скорость выполнения программы за счет одновременного считывания управляющих команд и обрабаты- обрабатываемых данных. Отличие архитектуры фон Неймана заключается в принципиальной воз- возможности работы над управляющими программами точно так же, как и над данными. Это позволяет производить загрузку и выгрузку управ- управляющих программ в произвольное место памяти процессора, которая в этой архитектуре не разделяется на память программ и память данных. Любой участок памяти может служить как памятью программ, так и па- памятью данных. Причем в разные моменты времени одна и та же область памяти может использоваться и как память программ, и как память дан- данных. Для того чтобы программа могла работать в произвольной области памяти, ее необходимо модифицировать перед загрузкой, т. е. работать с нею как с обычными данными. Эта особенность архитектуры позволяет наиболее гибко управлять работой микропроцессорной системы, но соз- создает принципиальную возможность искажения управляющей програм- программы, что понижает надежность работы аппаратуры. Архитектура фон Неймана используется в универсальных компьютерах и в некоторых ви- видах микроконтроллеров. В качестве примера реализации микропроцессора в. дальнейшем рас- рассмотрим устройство процессора с полным набором команд. При этом будет рассматриваться упрощенная модель процессора. Ядро CISC-микропроцессора состоит из двух основных частей: ? операционного блока; ? блока микропрограммного управления. Операционный блок (ОБ) предназначен для считывания команд из сис- системной памяти и выполнения считанных команд. Эти действия он осуще-
94 Глава 4 ствляет под управлением блока микропрограммного управления (БМУ), который формирует последовательность микрокоманд, необходимую для выполнения машинной команды. Микрокоманды меняются каждый раз после прихода импульса синхронизации микропроцессора. Операционный блок микропроцессора Основным принципом работы любого цифрового устройства с памятью, в том числе и микропроцессора, является наличие цепи синхронизации CLK. Синхросигнал, как и цепь питания, подводится к любому регистру цифрового устройства. Схема одного из вариантов операционного блока приведена на рис. 4.19. 8 8 8 О 11 12 MUX 8 + R0 R1 R7 АСС И РСН PCL 8 8 О 1 11 12 MUX 8 8 -f CONST AS А В ALU •б BS K,PI,M S 8 CLK 8 8 RAH 8 RAL —f 8 16 AB CR BUF 8 4- »• PSW DC ¦*-DB -4 RS Z,C,OV,N Рис. 4.19. Операционный блок В схеме, приведенной на рис. 4.19, явно просматривается, что отдельные биты микрокоманды (обозначены надписями внизу схемы) управляют различными элементами ОБ, поэтому их можно рассматривать незави- независимо друг от друга. Такие группы битов называются полями микро-
Принципы работы микропроцессора 95 команды. Кроме битов, управляющих арифметико-логическим устройст- устройством (АЛУ) и регистрами общего назначения (РОН), в микрокоманде есть биты, управляющие БМУ. Формат микрокоманды рассматриваемого процессора приведен на рис. 4.20. Результат выполнения микрокоманды записывается во внутренние регистры ОБ по сигналу синхронизации микропроцессора CLK. 6 битов 4 бита 4 бита 4 бита 8 битов 5 битов КОП (К, PI, М) Ист1 (AS) Ист 2 (BS) Прм (RS) CONST -Управление ОБ B6 бит) Условие перехода Адрес перехода -Управление БМУ Рис. 4.20. Формат микрокоманды процессора Попробуем реализовать аккумуляторный процессор с архитектурой фон Неймана. В этом случае потребуется более простая система команд. Что такое команды микропроцессора и как они реализуются, мы рассмотрим позднее. Для реализации аккумуляторного процессора необходимо один из реги- регистров ОБ выделить в качестве аккумулятора АСС. Для хранения и деко- декодирования выполняемой команды выделим 8-разрядный регистр, кото- который назовем RI. Для дальнейших рассуждений лучше иметь перед глазами временную диаграмму записи или чтения ОЗУ или чтения из ПЗУ. Можно восполь- воспользоваться временными диаграммами, приведенными на рис. 3.30 или 4.25. Для работы с микросхемами ОЗУ и ПЗУ, в которых может храниться программа, требуется специальный счетчик, который будет определять начальный адрес команд микропроцессора. Назовем это устройство про- программным счетчиком. Счетчик можно реализовать на любом регистре, подключенном к АЛУ. Для этого к содержимому регистра будем добав- добавлять длину команды и, тем самым, вычислять адрес следующей команды. Выход программного счетчика можно было бы подключить к внешним выводам микропроцессора, в состав которого входит рассматриваемый операционный блок. Однако кроме адресов команд нам потребуются ад- адреса данных, над которыми будет производиться работа. Поэтому выде- выделим отдельный регистр, в который мы будем записывать необходимый адрес. Выходы этого регистра подключим к внешним выводам микро- микропроцессора. Этот регистр назовем регистром адреса, а выводы, к кото- которым будут подключены выходы этого регистра, — шиной адреса.
96 Глава 4 Значения битов регистра адреса непосредственно определяют уровни сигналов на линиях шины адреса. Таким образом, в данной главе впер- впервые рассказано о записи двоичного кода в регистр для формирования логических сигналов на внешних выводах микросхемы. Этот метод ши- широко используется в микропроцессорной технике, и примеры его приме- применения будут часто встречаться в последующих главах. Определим необходимую разрядность шины адреса, а значит и разряд- разрядность регистра адреса и программного счетчика. Так как в качестве при- примера мы выбрали 8-разрядный микропроцессор, то и все регистры в этом процессоре восьмиразрядные. Максимальное беззнаковое число, которое можно записать в такой регистр, — 255, но для большинства программ такого объема памяти недостаточно. В приведенной на рис. 4.19 схеме для того, чтобы получить 16-разряд- 16-разрядный адрес используются два 8-разрядных регистра адреса, которые об- образуют 16-разрядную пару регистров. Теперь максимальное число, ко- которое можно записать в этих двух регистрах, будет 65535, что во мно- многих случаях достаточно для адресации программ и обрабатываемых ими данных. Для того чтобы различать регистры старшего и младшего байта регистра адреса, обозначим их как RA — старший байт и RA — младший байт. То же самое можно сказать и про программный счетчик. Он тоже должен быть 16-разрядным. И для него тоже выделим два 8-разрядных регистра. Для того чтобы различать регистры старшего и младшего байта про- программного счетчика, обозначим их как РСН — старший байт и PCL — младший байт. Это позволяет при помощи 8-разрядного АЛУ формиро- формировать 16-разрядный адрес очередной команды при помощи последова- последовательной работы с младшим и старшим байтом адреса. Для реализации операций чтения или записи ОЗУ, кроме адреса и собст- собственно данных, требуются еще сигналы управления. В простейшем случае это сигналы записи (WR) и чтения (RD). Для их формирования исполь- используем еще один регистр, выходы которого выведем за пределы микросхе- микросхемы микропроцессора. Назовем его регистром управления (CR). Для формирования необходимых сигналов достаточно записывать в опреде- определенный бит регистра логический 0 или 1. Определим формат регистра управления. Пусть бит 0 этого регистра будет сигналом записи, а бит 1 — сигналом чтения. Остальные биты этого регистра пока не важны. Если потребуются дополнительные сигналы управления системной шиной, то можно воспользоваться зарезервированными сейчас битами. Получен- Полученный формат регистра управления приведен на рис. 4.21.
Принципы работы микропроцессора 97 О RD WR Рис. 4.21. Формат регистра управления (CR) Блок микропрограммного управления В простейшем случае блок микропрограммного управления можно по- построить на счетчике с возможностью предварительной записи и ПЗУ. Структурная схема такого блока приведена на рис. 4.22. Рис. 4.22. Блок микропрограммного управления В этой схеме адрес очередной микрокоманды формирует двоичный счет- счетчик. Если требуется осуществить безусловный или условный переход, то новый адрес записывается из ПЗУ в этот счетчик, как в обычный парал- параллельный регистр, по сигналу параллельной записи V. Переход к следую- следующему адресу микрокоманды производится по сигналу синхронизации микропроцессора CLK. В приведенной схеме условный переход возможен по знаку результата операции, переносу, нулевому результату или переполнению. Следует заметить, что достаточно лишь флага N (знака числа) для реализации перехода по нескольким условиям: больше, меньше, больше или равно, меньше или равно. Содержимое ПЗУ блока микропрограммного управления называется микропрограммой. Именно эта микропрограмма и реализует конкрет- конкретный микропроцессор. При смене микропрограммы, в принципе, можно реализовать на одном и том же кристалле другой микропроцессор.
98 Глава 4 Команды микропроцессора Команды микропроцессора в отличие от микрокоманд разрабатываются независимо от аппаратуры микросхемы, поэтому их разрядность обычно кратна восьми разрядам. Команда микропроцессора содержит как ми- минимум код операции (КОП). Она может состоять только из кода опера- операции, когда не требуется указывать адрес операнда (операнды это данные, над которыми выполняется заданная операция), или может состоять из кода операции и адресов операндов или данных. Однобайтовые команды позволяют работать с внутренними программно доступными регистрами процессора. Многобайтные команды могут содержать адреса операндов, размещенных в ОЗУ или ПЗУ, или сами операнды (данные). Форматы команд очень сильно зависят от структуры процессора. Рассмотрим по- построение команд для 8-разрядного процессора, построенного по архи- архитектуре фон Неймана. Примеры форматов команд для такого процессора приведены на рис. 4.23. коп коп Данные КОП Адрес ст. Адрес мл. КОП Адрес ст. Адрес мл. Данные Однобайтовая команда Двухбайтовая команда Трехбайтовая команда Четырехбайтовая команда Рис. 4.23. Форматы различных команд микропроцессора Если для кода операции используется 8-разрядное число (байт), то при помощи этого числа можно закодировать 256 операций. В процессе раз- разработки системы команд для операции может быть назначен любой код. Система команд является важным признаком, характеризующим кон- конкретное семейство процессоров.
Принципы работы микропроцессора 99 При кодировании команд разработчик микропроцессора может назна- назначить любой операции любое число. Например, для операции сложения можно назначить код 1, для операции вычитания код 12 и т. д. Для вы- выполнения одной и той же операции над разными регистрами процессора назначаются разные коды команд. Поэтому для операции суммирования может потребоваться 8 чисел (команд). Например, 1 — просуммировать аккумулятор с регистром R0, 2 — просуммировать аккумулятор с реги- регистром R1, 3 — просуммировать аккумулятор с регистром R2 и т. д. Запоминать эти коды очень утомительно для человека. При программи- программировании в машинных кодах легко совершить ошибку и очень трудно найти ее, особенно если коды различаются только одним битом. Для со- сокращения объема записи вместо двоичного кода можно воспользоваться шестнадцатеричным, однако это не увеличивает удобочитаемости про- программы. Фрагмент шестнадцатеричного представления исполняемого кода программы для микропроцессора приведен на рис. 4.24. 75D7 0 012 07E812 0 02 612165 81216B9E4 FF121147BEFF0 5BFFF028 0 0AE4FF1211 3 07 92 912 01BA7F0112114 7BEFF05BFFF 02 8 0 0A7F0112113 0 7 92D12 01BA1217CF 12 0 0 0590 000 3Е4 93С0Е07 4 0193С0Е07 4 01С0Е0Е4С0Е07 4 0 8С0Е07В0 57А0 0 7 93 6 120 80 074FB2 581F58112107 4B2AFC2 98 Рис. 4.24. Фрагмент исполняемого кода микропроцессора Ну, как? Очень легко разобраться в такой последовательности чисел? Я думаю, не слишком. Чтобы уменьшить объем запоминаемой информа- информации и увеличить наглядность исходного текста программы, для каждой операции процессора придумывают мнемоническое обозначение. В качестве мнемонического обозначения операции обычно используют сокращения английских слов, образующих название этой операцию. На- Например, для операции копирования используется мнемоническое обо- обозначение MOV; для операции суммирования — ADD; для операции вы- вычитания — SUB; для операции умножения — MUL и т. д. Полная запись команды содержит мнемоническое обозначение операции и используемые этой операцией операнды, которые перечисляются через
100 Глава 4 запятую. При этом обычно операнд-приемник результата записывается первым, а операнд-источник операнда — вторым. Например: MOV R0, А /Скопировать содержимое регистра А в регистр R0 ADD A, R5 /Просуммировать содержимое регистров R5 и А, /результат поместить в регистр А Приведенные выше команды — однобайтовые, т. к. в них используются только внутренние регистры процессора. Если в команде используется константа в качестве операнда или указывается адрес операнда в памяти, то код команды будет занимать в памяти два или три байта. Например: MOV А, 1025 ; Скопировать содержимое ячейки памяти с адресом 1025 в ; регистр А ADD A, #110 ; Просуммировать содержимое регистра А с числом 110 Несмотря на то, что общий объем исходного текста программы увеличи- увеличивается, скорость написания и особенно отладки программ при примене- применении мнемонического обозначения команд возрастает. Кто сомневается, может попробовать разобраться в программе, приведенной на рис. 4.24. Теперь вместо одного текста программы в памяти компьютера или на бумаге придется хранить два варианта представления: один для челове- человека, в дальнейшем будем называть этот вариант исходным текстом про- программы; другой для микропроцессора, в дальнейшем будем называть этот вариант загрузочным модулем. Преобразование программы, записанной в мнемоническом виде, в ма- машинные коды является рутинной работой, которую можно поручить компьютерной программе. Язык программирования, в котором для обо- обозначения машинных команд используются мнемонические обозначения, называется ассемблером. Точно так же называют и программу или пакет программ, которые осуществляет трансляцию (преобразование) исход- исходного текста программы, написанной на языке программирования ас- ассемблер (исходный модуль), в машинные коды (загрузочный модуль). Теперь, когда мы рассмотрели все составные части микропроцессора: операционный блок, блок микропрограммного управления, — а также систему команд, можно, наконец, приступить к реализации самого мик- микропроцессора. Напомню, что архитектура микропроцессора реализуется микропрограммой и очень мало зависит от аппаратуры, для которой пишется эта микропрограмма. То есть, написав микропрограмму, мы тем самым построим микропроцессор с конкретной архитектурой. Микро- Микропрограмма состоит из сотен однотипных блоков, написанных для раз- различных команд микропроцессора, поэтому достаточно рассмотреть реа- реализацию нескольких типовых команд.
Принципы работы микропроцессора 101 Микропрограммирование Все действия микропроцессора и сигналы на его выводах определяются последовательностью микрокоманд, подаваемых на управляющие входы блока обработки сигналов. Эта последовательность микрокоманд назы- называется микропрограммой. При изучении принципов работы ОЗУ и ПЗУ приводились временные диаграммы, которые необходимо сформировать для того, чтобы запи- записать или прочитать необходимые данные. Выберем одну из этих времен- временных диаграмм (см. рис. 3.30). Любую временную диаграмму формирует микропроцессор. Устройство микросхемы, на примере которой мы будем рассматривать формирова- формирование необходимых сигналов, было проанализировано при обсуждении операционного блока. По его структурной схеме (см. рис. 4.19) можно определить формат микрокоманды, управляющей этим блоком. Он при- приведен на рис. 4.20. Для того чтобы разобраться в приводимых далее микропрограммах, же- желательно постоянно иметь перед собой временную диаграмму, формат микрокоманды и схему операционного блока. Работа любого цифрового устройства начинается с заранее заданных начальных условий. Эти начальные условия формируются специальным сигналом RESET (сброс), который вырабатывается после подачи пита- питания. Договоримся, что сигнал сброса микропроцессора будет записывать в регистр программного счетчика PC нулевое значение. Это условие справедливо не для всех процессоров. Например, IBM-совместимые про- процессоры при сбросе микросхемы записывают в программный счетчик значение FOOOOh, а процессоры фирмы Motorola заносят в него содержи- содержимое ячейки памяти с адресом FFFFh. Выполнение любой команды начинается со считывания ее кода из памя- памяти (ОЗУ или ПЗУ). Необходимые для этого микрокоманды подаются на входы управления ОБ из БМУ, как только снимается сигнал сброса. В случае однобайтной команды достаточно считать из системной памяти только код операции и выполнить задаваемые им действия. Временная диаграмма этого процесса приведена на рис. 4.25. Последовательность операций, которые необходимо выполнить микропрограмме, показана стрелочками. Для считывания следующей команды микропрограмма за- запускается заново (зацикливается).
102 Глава 4 Для того чтобы считать код операции из памяти, сначала необходимо адрес этой команды выставить на шине адреса. Этот адрес хранится в счетчике команд PC. После сигнала сброса микропроцессора в этом ре- регистре хранится нулевое значение. Скопируем его в регистр адреса RA, выходы которого подключены к шине адреса: Поля микрокоманды ОБ № Описание Константа Источник А Источник В Команда Приемник 1) PCH->RAH 11111111 1111 1010 00110 0 1100 2) PCL->RAL llllllll 1111 1011 001100 1101 RD А I Al D A2 КОП1 Считывание первой команды КОП 2 Считывание второй команды {; Рис. 4.25. Временные диаграммы сигналов считывания однобайтных команд из памяти Затем сформируем сигнал считывания. Для этого в регистр управления запишем константу 1111 1110. Поля микрокоманды ОБ № Описание Константа Источника Источник В Команда Приемник 3) const->CR 11111110 1111 1111 001100 1110 При этом на временной диаграмме, приведенной на рис. 4.25, сигнал чтения RD примет нулевое значение. Теперь можно считать число с ши- шины данных, а т. к. память в этот момент выдает на нее код операции, то мы считаем именно его. Запишем его в регистр команд и снимем сигнал чтения с системной шины.
Принципы работы микропроцессора 103 Для этого в регистр управления запишем константу 1111 1111. Поля микрокоманды ОБ № Описание Константа Источник А Источник В Команда Приемник 4) data->RI 11111111 1100 1111 110000 1001 5) const ->CR 11111111 1111 1111 00110 0 1110 Прежде, чем перейти к дальнейшему выполнению микропрограммы, увеличим содержимое счетчика команд на 1. Поля микрокоманды ОБ № Описание Константа Источника Источник В Команда Приемник 6)PCL+1->PCL 11111111 1011 1111 110010 1011 7) РСН+С -> РСН 1111 1111 1010 1111 110010 1010 После считывания команды ее необходимо декодировать. Это можно выполнить микропрограммным способом, проверяя каждый бит регистра команд, и осуществляя ветвление по результату проверки, или включить в состав блока микропрограммного управления аппаратный дешифра- дешифратор команд, который сможет осуществить переход микропрограммы на любую из 256 ветвей за один такт синхронизации микропроцессора. Вы- Выберем второй путь. Восьмым тактом микропрограмма направляется на одну из 256 ветвей, отвечающую за выполнение считанной команды. На- Например, если это была команда mov a,ro, to следующая микрокоманда будет выглядеть следующим образом: Поля микрокоманды ОБ № Описание Константа Источника Источник В Команда Приемник 9) R0 -> АСС 1111 1111 0000 1111 1100 0 0 1000 И т. к. в этом случае команда полностью выполнена, то счетчик микро- микрокоманд сбрасывается для выполнения следующей команды. Рассмотрим еще один пример. Пусть из системной памяти считывается команда безусловного перехода jmp 1234. Первые восемь микрокоманд совпадают для всех команд микропроцессора. Различие наступает, начи- начиная с девятой микрокоманды, которая зависит от выполняемой машинной команды. При выполнении команды безусловного перехода необходимо считать адрес новой команды, который записан в байтах, следующих за кодом операции.
104 Глава 4 Этот процесс аналогичен считыванию кода операции: Поля микрокоманды ОБ Константа Источник А Источник В Команда Приемник № Описание 9) РСН -> RAH 10) PCL->RAL 11) const ->CR 12) data->RI 1111 1111 1111 1111 1111 1110 1111 1111 1111 1111 13) const->CR 14) PCL+1 ->PCL 1111 1111 15) PCH+C->PCH 1111 1111 1111 1111 1111 1100 1111 1011 1010 1010 1011 1111 1111 1111 1111 1111 0011 ООП ООП 1100 ООП 1100 1100 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1100 1101 1110 1001 1110 1011 1010 Теперь считаем второй байт адреса перехода. № Описание 16) РСН-ЖАН 17) PCL-ЖАЬ 18) const ->CR 19) data-> РСН 20) const->CR 21) RI->PCL Поля микрокоманды ОБ Константа Источника Источник В Команда Приемник 1111 1111 1111 1111 1111 1111 1111 1111 1110 1111 1111 1111 1111 1111 1111 1100 1111 1001 1010 1011 1111 1111 1111 1111 ООП ООП ООП 1100 ООП 1100 0 0 0 0 0 1 0 0 0 0 0 0 1100 1101 1110 1110 1110 1001 RD А А2 A3 t I D 12 34 Считыв ание код а опер алии Считыв ание первого Считывание второго байта адреса байта адреса Рис. 4.26. Временная диаграмма выполнения команды jmp 1234
Принципы работы микропроцессора 105 В результате выполнения этой микропрограммы в программный счетчик будет загружен адрес, записанный во втором и третьем байтах команды безусловного перехода jmp 1234. Временная диаграмма, формируемая рассмотренной микропрограммой, приведена на рис. 4.26. По аналогии с рассмотренными примерами можно разработать другие микропрограммы, которые могут понадобиться в дальнейшем. Итак, подведем итоги На этом закончим рассмотрение внутреннего устройства и принципов работы микропроцессора. Полученных знаний достаточно для того, чтобы приступить к рассмотрению принципов работы систем, построен- построенных с использованием микропроцессора.
шооп Глава 5 Принципы работы микропроцессорной системы В предыдущей главе были рассмотрены принципы работы микропроцес- микропроцессора — универсального устройства, позволяющего выполнять различные виды операций. Как будет показано в следующих главах, с его помощью можно реализовывать цифровые устройства различного назначения. Однако мы пока не умеем использовать микропроцессор. В данной главе будут рассмотрены структурные схемы подключения к нему различных устройств. Структурные схемы приводятся с уровнем легализации, по- позволяющим легко превратить их в принципиальные схемы. В главе будут также рассмотрены основные методы расширения адрес- адресного пространства микропроцессорной системы и некоторые решения, позволяющие повысить ее быстродействие. Однако не следует забывать, что микропроцессор сам по себе никого не интересует. Это только инструмент решения задач управления какими- либо объектами или обработки сигналов. В данной ьчаве мы рассмотрим узлы микропроцессорной системы, позволяющие микропроцессору по- получать информацию извне и воздействовать на окружающую среду (в том числе и на человека). При решении задач управления или обработки сигналов очень важно, чтобы решения процессора были согласованы во времени с окружающими событиями. Поэтому будут рассмотрены узлы микропроцессорной системы, позволяющие организовывать взаимодей- взаимодействие с окружающей средой в реальном времени. Пожалуй, одним из самых значительных событий в развитии цифровой техники была разработка системной шины, позволяющей передавать информацию между различными блоками цифрового устройства. Имен- Именно с нее и начнем изложение материала.
108 Глава 5 Системная шина Системная шина предназначена для обмена информацией между микро- микропроцессором и любыми внутренними устройствами микропроцессорной системы (контроллера или компьютера). В качестве обязательных уст- устройств, которые входят в состав любой микропроцессорной системы, можно назвать ОЗУ, ПЗУ, таймер и порты ввода-вывода. Структурная схема простейшей микропроцессорной системы, включающей перечис- перечисленные устройства, приведена на рис. 5.1. Л6 ША ШД ШУ 16 i > 17, WR 8 А0...А12 DO .D7 Центральный процессор 16 RD WR 8 RD WR D0-D7 ОЗУ А0...А12 CS —о- А0..А12 А13 АИ А15 16 RD WR ¦8 -Л- RD WR D0 D7 ПЗУ АО ... А10 СЗ О- АО. All А12 А13 А14 А15 J .А10 i 1 16 RD WR ¦8 RD WR D0- D7 Порт ввода .Bx4 АО Al A2 A3 A4 A5 A6 A7 A8 A9 A10 All A12 A13 A14 A1S cs -о- O-1 .,,.,, Рис. 5.1. Структурная схема простейшей микропроцессорной системы В состав системной шины в зависимости от типа процессора входит одна или несколько шин адреса, одна или несколько шин данных и шина управления. Несколько шин данных и адреса применяются для увеличе- увеличения производительности системы и используются, как правило, в сиг- сигнальных процессорах. В универсальных процессорах и контроллерах обычно применяется одна шина адреса и одна шина данных даже при реализации гарвардской структуры. По шине данных информация передается либо к процессору, либо от процессора в зависимости от операции (записи или чтения), выполняе- выполняемой микропроцессором в данный момент. В любом случае все сигналы, необходимые для работы системной шины, формируются или опрашиваются микросхемой процессора, как это рас-
Принципы работы микропроцессорной системы 109 сматривалось при изучении операционного блока. То есть без микро- микропроцессора системная шина функционировать не может. Более того, ко- когда в микропроцессорной системе говорят об операции чтения, то пред- предполагается, что это микропроцессор читает данные. Если в этой системе говорят об операции записи, то запись данных осуществляет именно микропроцессор. Иногда, для увеличения скорости обработки информации, функции управления системной шины берет на себя отдельная микросхема (например, контроллер прямого доступа к памяти или сопроцессор), и тогда операции записи или чтения будет осуществлять именно эта мик- микросхема. В современных микроконтроллерах или сигнальных процессо- процессорах эти устройства могут находиться непосредственно в составе микро- микросхемы. Адресное пространство микропроцессорного устройства При подключении различных устройств к системной шине возникает во- вопрос — как различать эти устройства между собой? С этой целью ис- используют индивидуальный адрес для каждого устройства, подключенно- подключенного к системной шине микропроцессора. Так как адресация производится к каждой ячейке памяти устройства индивидуально, то возникает поня- понятие адресного пространства, занимаемого каждым устройством, и адрес- адресного пространства микропроцессорного устройства в целом. Адресное пространство микропроцессорного устройства изображается графически прямоугольником, одна из сторон которого соответствует разрядам адресуемой ячейки этого микропроцессора, а другая сторо- сторона — всему диапазону доступных адресов для этого же микропроцессора. Обычно в качестве минимально адресуемого элемента адресного про- пространства выбирается 8-разрядная ячейка (байт). Диапазон доступных адресов микропроцессора определяется разрядностью шины адреса. При этом минимальный номер ячейки памяти (адрес) будет равен 0, а макси- максимальный определяется из формулы: Для 16-разрядной шины это будет число 65535 F4 Кбайт). Адресное про- пространство этой шины приведено на рис. 5.2. Оно соответствует адресно- адресному пространству памяти микропроцессорной системы, изображенной на рис. 5.1.
110 Глава 5 Десятичный номер ячейки 64 К-1 1К 4 3 2 1 О Двоичный номер ячейки 1111111111111111 1111111111111110 1111111111111101 0000010000000001 0000010000000000 0000001111111111 0000000000000100 0000000000000011 0000000000000010 0000000000000001 0000000000000000 7 6 5 4 3 2 10 Номер бита в ячейке Рис. 5.2. Адресное пространство микропроцессора с 16-разрядной шиной адреса 64К-1 16К-1 8К 2К-1 0 Порт ввода-вывода Неиспользуемое адресное пространство ОЗУ Неиспользуемое адресное пространство ПЗУ 1111111111111111 Хххххххххххххххх 0011111111111111 001ХХХХХХХХХХХХХ 0010000000000000 ОООххххххххххххх 0000011111111111 ОООООххххххххххх 0000000000000000 Рис. 5.3. Распределение памяти микропроцессора с 16-разрядной шиной адреса Распределением памяти называют разбиение адресного пространства на несколько областей, каждая из которых выделена для размещения ячеек какого-либо определенного элемента системы: ОЗУ, ПЗУ или внешних устройств. Часто его изображают в форме рисунка. Распределение ад-
Принципы работы микропроцессорной системы 111 ресного пространства, соответствующее схеме, приведенной на рис. 5.1, изображено на рис. 5.3. Обычно адресное пространство распределяют одновременно с проекти- проектированием принципиальной схемы устройства (созданием дешифраторов адреса для каждого подключаемого к системной шине устройства). Нач- Начнем распределение адресного пространства с выделения диапазона адре- адресов для ПЗУ. Микропроцессоры после включения питания и выполнения процедуры сброса всегда начинают выполнение программы с определенного адреса, чаще всего нулевого. Однако есть и исключения. Например, процессоры, на основе которых строятся универсальные компьютеры IBM PC или Macintosh, стартуют не с нулевого адреса. Программа или се загрузчик должны храниться в памяти, которая не стирается при выключении пи- питания, т. е. в ПЗУ. Таким образом, адрес, записываемый в счетчик команд процессора после сброса, обязательно должен попадать в диапа- диапазон адресов, выделенных ПЗУ. Выберем для построения микропроцессорной системы микросхему ПЗУ объемом 2 Кбайт, как это показано на рис. 5.1. При построении опера- операционного блока мы договорились, что процессор после сброса начинает работу с нулевого адреса, поэтому разместим ПЗУ в адресном простран- пространстве, начиная с нулевого адреса. Для того чтобы нулевая ячейка ПЗУ оказалась расположенной по нулевому адресу адресного пространства микропроцессора, старшие разряды шины адреса E разрядов, начиная с разряда 11) должны быть равны 0. Так как в микросхеме ПЗУ уже имеются одиннадцать адресных выво- выводов, то при построении схемы необходимо дополнительно декодиро- декодировать старшие пять разрядов адреса (определить, чтобы они были равны 0). Это выполняется при помощи внешнего дешифратора адреса, кото- который в данном случае вырождается в 5-входовую схему «ИЛИ». При ис- использовании дешифратора адреса обращение микропроцессора за пре- пределы нижней области 2 Кбайт не приведет к чтению ячеек ПЗУ, т. к. на входе выбора кристалла CS уровень напряжения останется высоким (неактивным). Теперь подключим микросхему ОЗУ. Для примера выберем микросхему объемом 8 Кбайт. Выбор любой из ячеек этой микросхемы возможен при помощи 13-разрядного адреса, поэтому необходимо дополнительно де- декодировать сигналы трех старших линий 16-разрядной шины адреса. Так как начальные ячейки памяти адресного пространства уже заняты ПЗУ, то их использовать нельзя. Им соответствует значение старших разрядов адресной шины 000. Выберем для адресации ОЗУ комбинацию сигналов 001 и используем уже известные нам принципы построения схемы по
112 Глава 5 произвольной таблице истинности. Дешифратор адреса выродится в данном случае в 3-входовую схему «И-НЕ» с двумя инверторами на вхо- входе. Схема дешифратора адреса ОЗУ приведена на рис. 5.1. Этот дешиф- дешифратор адреса обеспечивает нулевой уровень сигнала на входе CS микро- микросхемы ОЗУ только при комбинации старших битов адреса 001. Обратите внимание: т. к. объем ПЗУ меньше объема ОЗУ, то между областями ад- адресов ПЗУ и ОЗУ образовалось пустое пространство неиспользуемых адресов памяти. Так как все микропроцессоры предназначены для обработки данных, по- поступающих извне, то в любой микропроцессорной системе должны при- присутствовать порты ввода-вывода. Будем считать, что порт ввода-вывода отображается в адресное пространство микропроцессорного устройства как одиночная ячейка памяти, поэтому можно выбрать любой свобод- свободный адрес. Проще всего построить дешифратор числа FFFFh. В этом случае он превращается в обычную 16-входовую схему «И-НЕ», поэтому и выберем данный адрес для размещения порта ввода-вывода. Способы расширения адресного пространства микропроцессора Известно, что размер адресного пространства определяется разрядно- разрядностью счетчика команд микропроцессора. Достаточно часто при развитии микропроцессорной системы возможности адресного пространства ис- исчерпываются. В таком случае приходится прибегать к методам расшире- расширения адресного пространства. Как уже говорилось, размер адресного пространства определяется коли- количеством адресных линий в составе адресной шины. Для увеличения ад- адресного пространства необходимо увеличить количество этих линий (добавить старшие разряды). Сигналы на этих проводниках ничем не от- отличаются от сигналов, используемых для управления внешними устрой- устройствами, поэтому для расширения адресного пространства микропроцес- микропроцессора можно воспользоваться параллельным портом. Внешние выводы параллельного порта можно использовать в качестве старших битов ад- адресной шины. Такой метод расширения адресного пространства называ- называется страничным методом адресации. Регистр данных параллельного порта при использовании его для расширения адресного пространства будет называться переключателем страниц, а сам параллельный порт — диспетчером памяти. Схема использования параллельного порта в каче- качестве переключателя страниц памяти приведена на рис. 5.4.
Ucc Uss U RST RESET XTAL2 XTAL1 RD CPU A/D0 1 2 3 4 5 6 7 ALE A 0 1 2 3 4 5 6 7 DO Dl D2 D3 D4 D5 D6 D7 DO Dl D2 D4 D5 D6 D7 1 2 3 4 5 6 7 Qo 1 2 3 4 5 6 7 АО Al A2 A4 A6 A7 A8 A9 A10 All A12 A13 A15 АО Al A2 A3 A4 A5 A6 A7 A8 A10 All ai: A9 A13 A14 A15 Dat Adr DO D3 D4 D5 D<5 D7 1 2 3 4 5 6 7 Qo 1 2 3 4 6 7 A16 A17 A18 A19 A20 A21 A22 A23 RD WR Рис. 5.4. Использование параллельного порта в качестве переключателя страниц памяти а: "С О) О\ о 3 о 3 3 о .с CD О О I о о с о CD о- со
114 Глава 5 При применении 8-разрядного параллельного порта в микропроцессор- микропроцессорной системе появились дополнительные восемь линий адреса. В резуль- результате адресное пространство микропроцессорной системы увеличилось до 16 Мбайт. Структура нового адресного пространства приведена на рис. 5.5, а принцип формирования нового адреса с использованием пере- переключателя страниц пояснен на рис. 5.6. Полный адрес Адрес внутри страницы FFFFFF FFOOOO 02FFFF 020000 01 FFFF 010000 OOFFFF 000000 FFFF 0000 FFFF 0000 FFFF 0000 FFFF 0000 Страница 255 • • • Страница 2 Страница 1 Страница 0 Адрес ячейки внутри страницы 1111111111111111 0000000000000000 1111111111111111 0000000000000000 1111111111111111 0000000000000000 1111111111111111 0000000000000000 Рис. 5.5. Структура страничного адресного пространства 0 15 0 Переключатель страниц Программный счетчик 23 -Сформированный адрес- 0 Рис. 5.6. Формирование адреса с использованием переключателя страниц Метод страничной адресации прост в реализации и при формировании адреса физической памяти не приводит к дополнительным временным задержкам. При использовании многозадачного режима работы процес- процессора для каждой активной задачи выделяется целая страница в систем- системной памяти микропроцессора. Если программный код задачи не занима- занимает полностью страницу, то в системной памяти процессора остается много неиспользуемых областей. Решить возникшую проблему позволя- позволяет метод сегментной организации памяти.
Принципы работы микропроцессорной системы 115 При использовании этого метода для расширения адресного пространст- пространства используется базовый регистр, относительно которого производится адресация команд или данных в программе. Разрядность базового реги- регистра обычно выбирают равной разрядности счетчика команд. В качестве базового регистра, как и при страничной организации памяти, можно использовать параллельный порт. Адресное пространство при использовании сегментного метода адреса- адресации и различном размере сегментов, приведено на рис. 5.7. Полный адрес FFFFF 17031 17030 0F030 0F028 0F010 0F005 00000 Адрес внутри сугмента 8000 0000 0018 0000 F005 0000 Неиспользуемое пространство Сегмент 2 . . . Сегмент 1 . . . Сегмент 0 Рис. 5.7. Пример адресного пространства с разделением на сегменты Для формирования физического адреса используется параллельный дво- двоичный сумматор. На входы этого сумматора подается содержимое базо- базового регистра и счетчика команд. Суммирование производится со сме- смещением кода базового регистра влево на несколько битов относительно содержимого счетчика команд (рис. 5.8). В результате максимальный размер сегмента определяется разрядностью программного счетчика, а максимальная неиспользуемая область памяти — смещением базового регистра относительно программного счетчика. Это связано с тем, что окна при сегментной организации памяти могут перекрываться, и если часть памяти в окне, выделенном для предыдущей программы, не используется, то следующее окно можно разместить, на- начиная с первой свободной ячейки памяти. Учитывая, что на рис. 5.8 ба-
116 Глава 5 зовый регистр смещен относительно программного счетчика на четыре разряда, минимальный шаг при размещении окон будет 24 = 16 байт. То есть в этом случае максимальная область неиспользуемой памяти между окнами будет равна 15 байтам. 15 15 0000 Программный счетчик + 0 Базовый регистр 0000 = Адрес = Программный счетчик + Базовый регистр*24 0 20 0 < Сформированный адрео > Рис. 5.8. Формирование адреса при сегментной адресации Количество одновременно используемых сегментов определяется количе- количеством базовых регистров. Сегменты могут перекрываться в адресном про- пространстве, и тем самым можно регулировать размер памяти, который отводится под каждый конкретный сегмент памяти. В компьютерах семей- семейства IBM PC имеются четыре базовых регистра, определяющих сегмент данных, сегмент программы, сегмент стека и дополнительный сегмент. Информацию в базовые регистры заносит операционная система при за- запуске программы и переключении между активными программами. Еще одним распространенным способом увеличения адресного про- пространства является применение окон. При использовании окон произво- производится расширение не всего адресного пространства, а только его части. Внутри адресного пространства выделяется некоторая область, которая называется окном. В это окно может отображаться часть другого адрес- адресного пространства. При использовании окон может быть применен как страничный, так и сегментный метод отображения адресного пространства в окно. При этом размер страницы, отображаемой в окно, не может превышать раз- размер самого окна. При использовании страничного метода отображения конкретная стра- страница дополнительного адресного пространства, отображаемая в окно основной памяти, определяется переключателем страниц. Переключа- Переключатель страниц строится по принципу, рассмотренному выше (см. схему на рис. 5.4).
Принципы работы микропроцессорной системы 117 При использовании сегментного метода конкретная область адресного пространства, которая будет отображаться в окно, определяется содер- содержимым базового регистра. Если разрядность адреса вспомогательного адресного пространства, отображаемого в окно основной памяти, сов- совпадает с разрядностью базового регистра, то любая область вспомога- вспомогательной памяти может быть отображена в основную память с точностью до байта. Принцип использования оконной адресации при отображении страниц дополнительной памяти в основное адресное пространство можно легко понять по рис. 5.9. Основная памать Дополнительная память Страница 255 Страница 2 Страница 1 Страница О Страница, которая видна в данный момент из основной памяти Рис. 5.9. Применение окна для расширения адресного пространства Оконная адресация часто используется при развитии микропроцессор- микропроцессорных семейств, когда размера областей памяти, отведенных для конкрет- конкретных задач в младших моделях семейства, не хватает для старших моде- моделей, а при этом нужно поддерживать аппаратную совместимость с младшими моделями семейства. В качестве примера можно привести микросхемы 181 с96 фирмы INTEL или TMS320c5410 фирмы Texas In- Instrument, где для расширения области регистров специальных функций используется оконная адресация. Согласование быстродействия памяти и универсальных микропроцессоров Универсальные микропроцессоры применяются в настольных или пор- портативных компьютерах, а также во встраиваемых системах, и в настоя-
118 Глава 5 щее время именно на них отрабатываются самые передовые решения по повышению быстродействия микросхем. Паразитные емкости печатной платы компьютера или другого устройст- устройства, в котором используется микропроцессор, не позволяют достигнуть предельного быстродействия, с которым может работать кристалл мик- микропроцессора. Кроме того, невозможно реализовать кварцевые резона- резонаторы на частоты, на которых работают современные микропроцессоры. Поэтому внутренняя и внешняя тактовая частота микропроцессора раз- различаются. Обычно внутренняя тактовая частота в несколько раз выше внешней. Умножение внешней тактовой частоты внутри кристалла процессора производится при помощи схемы фазовой автоподстройки частоты, по- поэтому для установления стабильной внутренней частоты микропроцес- микропроцессора требуется некоторое время, определяемое обычно десятками микро- микросекунд. Первым фактором, огранивающим быстродействие микропроцессор- микропроцессорной системы в целом, является то, что для увеличения доступной ем- емкости системной памяти компьютера используют микросхемы ОЗУ ди- динамического вида. Однако они обладают относительно невысоким бы- быстродействием. В результате возникает противоречие между высоким быстродействием микропроцессора и недостаточным быстродействием системной памяти, что ограничивает производительность микропро- микропроцессорной системы в целом. В качестве решения этой проблемы в современных компьютерах предла- предлагается использование кэш-памяти. Эта память с точки зрения програм- программиста никак не видна и общий объем системной памяти вследствие ее наличия не увеличивается. Кэш-память выполняется в виде статической памяти небольшого размера и высокого быстродействия. Она ставится как буфер между основной па- памятью и микропроцессором. Кэш-память располагается на материнской плате. Естественно, что при первом обращении к системной памяти быст- быстродействие снижается на задержку, вносимую копированием информации в кэш-память. Выигрыш в быстродействии достигается при повторном об- обращении к одному и тому же участку памяти. В этом случае обращение к основной памяти не требуется, т. к. в кэш-памяти уже хранится копия со- содержимого основной памяти. Учитывая, что выполнение программ обыч- обычно реализуется в виде циклов, когда один и тот же участок программного кода повторяется многократно, общее быстродействие системы в целом будет определяться быстродействием кэш-памяти. Всю логику работы с кэш-памятью выполняет контроллер памяти, входящий в набор микро- микросхем (chip set) материнской платы компьютера.
Принципы работы микропроцессорной системы 119 Рассмотренный выше метод увеличивает общее быстродействие систем- системной памяти, но только до значения тактовой частоты системной шины (внешняя тактовая частота микропроцессора). Согласовать внутреннее быстродействие микропроцессора и быстродействие системной шины позволяет использование внутренней кэш-памяти. Естественно, ее объем меньше, чем у кэш-памяти, расположенной на материнской плате ком- компьютера. При рассмотрении принципов работы цифровых микросхем мы узнали, что потребляемый микросхемой ток определяется быстродействием мик- микросхемы, поэтому внутренняя кэш-память в свою очередь разделяется на два уровня: первый уровень малого объема, но высокого быстродейст- быстродействия, совпадающего с внутренним быстродействием микропроцессора, и второй уровень, с большим объемом памяти, но с меньшим быстродей- быстродействием. Кэш-память, расположенную на материнской плате, называют, продолжая нумерацию, кэш-памятью третьего уровня. Подключение внешних устройств к микропроцессору Микропроцессорные системы часто используются для управления уст- устройствами, блоками или системами связи. При этом в качестве микро- микропроцессорного устройства может выступать универсальный компьютер или группа компьютеров, объединенных локальной или глобальной се- сетью (для больших и дорогих систем связи, таких как автоматические те- телефонные станции или коммутационные центры сотовых систем связи), или специализированное микропроцессорное устройство, в качестве ко- которого для дешевой и портативной аппаратуры чаще всего выступает однокристальный микроконтроллер. Внешними устройствами называются любые устройства, которыми управляет, от которых получает или которым передает информацию микропроцессор. В качестве внешних устройств может выступать прин- принтер или дисплей, клавиатура или модем, но для устройств связи в качест- качестве внешних устройств чаще выступают микросхемы приемников, пере- передатчиков (в том числе построенные на базе сигнальных процессоров), микросхемы синтезаторов частоты или постоянные запоминающие уст- устройства с электрическим стиранием. Согласование сигналов цифровых микросхем между собой не представ- представляет трудностей, т. к. практически все современные цифровые микросхе- микросхемы по входу и выходу согласованы с TTL-уровнями. Если же это не так, то для согласования нестандартных уровней с TTL-уровнями выпуска-
120 Глава 5 ются специальные микросхемы. Несколько иначе обстоит дело с индика- индикаторами и исполнительными устройствами. В качестве простейшего единичного индикатора рассмотрим светодиод- светодиодный индикатор. Схема его подключения показана на рис. 5.Ю. Транзи- Транзистор служит для увеличения тока, которым микропроцессор зажигает светодиодный индикатор. Кроме того, транзистор позволяет согласовать уровни выходного напряжения цифровых микросхем, к которым отно- относятся и микропроцессорные устройства, и напряжения, необходимого для работы светодиодного индикатора. Гальванической развязки тран- транзисторный ключ не обеспечивает. Светодиод питается постоянным то- током, поэтому для его работы требуется генератор тока, а не напряжения. В простейшем случае необходимый ток может обеспечить токоограни- токоограничивающии резистор R3. Если этот резистор не поставить, то ток по цепи индикатора может достигнуть недопустимой величины и светодиод или транзистор выйдут из строя. Микропро- Микропроцессорное устройство (порт вью од а) Рис. 5.10. Подключение одиночного светодиодного индикатора Простой светодиодный индикатор позволяет отображать двоичную ин- информацию, такую как состояние устройства (включено или выключено), наличие или отсутствие сигнала и т. д. Для отображения цифровой ин- информации используются 7-сегментные индикаторы. Подключение одно- одного сегмента такого индикатора не отличается от схемы, приведенной на рис. 5.Ю. Каждый сегмент представляет собой обычный светодиод. Практически так же выглядят схемы подключения индикаторов на газо- газоразрядных лампах и лампах накаливания к выходному порту микропро- микропроцессорной системы. Единственным отличием является то, что для лампы накаливания не нужен токоограничивающии резистор, ограничение тока обеспечивает внутреннее сопротивление самой лампы.
Принципы работы микропроцессорной системы 121 Несколько сложнее выглядит схема подключения внешних исполнитель- исполнительных электромеханических устройств. Чаще всего такие исполнительные устройства являются индуктивной нагрузкой. В качестве примера можно назвать такие устройства, как электромагнитное реле или электромаг- электромагнит. Схема, позволяющая работать на индуктивную нагрузку, приведена на рис. 5.11. Диод VD1 в этой схеме служит для ограничения напряжения импульсов эдс самоиндукции, которые могут вывести из строя силовой транзистор VT1. Микропро- Микропроцессорное устройство (порт вывода) VD1 R1 +U п К1 Г VT1 R2 Рис. 5.11. Подключение внешнего устройства с индуктивной нагрузкой При вводе информации из внешнего устройства возникают подобные проблемы. Источники дискретной информации могут иметь различную физическую природу. Они могут находиться на значительном расстоя- расстоянии от контроллера, иметь различное напряжение питания, но их данные должны быть безошибочно считаны управляющей программой микро- микропроцессорной системы. Практически всегда при работе с внешними дат- датчиками требуется гальваническая развязка датчиков и управляющей микропроцессорной системы. Для решения указанных проблем все датчики выполняются так, что с точки зрения электрической схемы представляют собой контакты, рабо- работающие на замыкание. Поэтому схемы подключения датчика и кнопки не различаются. Со стороны микропроцессорного устройства надо преоб- преобразовать замыкание/размыкание контактов в логические уровни, необ- необходимые для правильной работы микропроцессорного устройства. Эту функцию выполняет схема, приведенная на рис. 5.12. Иногда требуется вводить информацию с большого количества кнопок. В этом случае для уменьшения количества линий ввода-вывода использу- используется клавиатура, представляющая собой двухмерную матрицу кнопок, 5 Зак 328
122 Глава 5 организованных в ряды и колонки. Для подключения клавиатуры ис- используется два порта: ввода и вывода. Схема подключения клавиатуры приведена на рис. 5.13. Микропро- Микропроцессорное устройство (порт ввода) +U, ч/ П \ R Контакты датчика К1 кнопки Рис. 5.12. Подключение источника дискретной информации Микропро- Микропроцессорное устройство t О оЭ Л И Си О С И Си О С +ип> т VXTXTL I Rl I R2 rm R3 R4 Рис. 5.13. Подключение клавиатуры к микропроцессорному устройству Подключение клавиатуры отличается от схемы подключения одиночной кнопки тем, что потенциал общего провода на опрашиваемые кнопки подается не непосредственно, а через порт вывода. В каждый момент
Принципы работы микропроцессорной системы 123 времени сигнал логического 0 подается только на один столбец кнопок. Двоичные сигналы, присутствующие при этом на строках клавиатуры, считываются через порт ввода микропроцессорной системы. Временная диаграмма напряжений, присутствующих на порте вывода при выполне- выполнении программы опроса клавиатуры, приведена на рис. 5.14. и 1 i UJ U| 1 1 1 ' ' ' 1 1 1 i г~ I— " ¦ I 1 I 1 1 j | | t | | 1 1 1 1 ¦ | »•- , t | t »¦- t Рис. 5.14. Временная диаграмма напряжений на линиях порта вывода Принципы построения параллельного порта Параллельные порты предназначены для обмена многоразрядными дво- двоичными данными между микропроцессором и внешними устройствами. В качестве внешнего устройства может служить любой объект управле- управления или источник информации (различные кнопки, датчики, микросхемы приемников, синтезаторов частот, дополнительной памяти, исполни- исполнительные механизмы, двигатели, реле и т. д.). Иногда в качестве внешнего устройства может выступать другой компьютер или микропроцессор. Параллельные порты позволяют согласовывать низкую скорость работы внешнего устройства и высокую скорость работы системной шины мик- микропроцессора. С точки зрения внешнего устройства порт представляет собой обычный источник или приемник информации со стандартными
124 Глава 5 цифровыми логическими уровнями (обычно ТТЛ), а с точки зрения мик- микропроцессора — это ячейка памяти, куда можно записывать данные или где сама собой появляется информация. В зависимости от направления передачи данных параллельные порты называются портами ввода, пор- портами вывода или портами ввода-вывода информации. В качестве простейшего порта вывода может быть использован парал- параллельный регистр, т. к. он позволяет запоминать данные, выводимые мик- микропроцессором, и хранить их до тех пор, пока подается питание. Все это время сигналы с выходов этого параллельного регистра поступают на внешнее устройство. В порт вывода возможна только запись. Структур- Структурная схема порта вывода с использованием параллельного регистра при- приведена на рис. 5.15. Данные с системной шины микропроцессора записы- записываются в параллельный регистр по сигналу «WR». Выходы «Q» регистра могут быть использованы как источники логических уровней для управ- управления внешними устройствами. Этот регистр называется регистром дан- данных порта вывода. А0..А15 WR Дешифратор адреса Рис. 5.15. Структурная схема порта вывода Для отображения регистра параллельного порта вывода информации только в одну ячейку памяти адресного пространства микропроцессор- микропроцессорного устройства совместно с портом вывода всегда используется дешиф- дешифратор адреса. Разработка дешифратора адреса и вопросы выбора кон- конкретного адреса для параллельного порта обсуждались ранее при рассмотрении распределения адресного пространства микропроцессор- микропроцессорного устройства. В качестве порта ввода может быть использована схема с открытым кол- коллектором или с третьим (Z) состоянием. В настоящее время обычно ис- используются схемы с третьим состоянием. Микросхема, объединяющая несколько таких элементов, называется шинным формирователем. Из порта ввода возможно только чтение информации. Структурная схема
Принципы работы микропроцессорной системы 125 порта ввода приведена на рис. 5.16. Для построения порта ввода выход шинного формирователя подключается к внутренней шине данных, а на его вход подключаются сигналы, которые нужно ввести в микропроцес- микропроцессорную систему. Значение сигнала с внешнего вывода порта передается на шину данных (считывается) по управляющему сигналу «RD». А0..А15 RD Дешифратор адреса D0..D7 шинный формирователь QS Вх1..Вх4 J. ;. j. л Рис. 5.16. Структурная схема порта ввода Для отображения шинного формирователя порта ввода только в один адрес в пространстве адресов микропроцессорного устройства совместно с портом ввода используют дешифратор адреса. Выделяемый им адрес шинного формирователя порта ввода называют адресом регистра дан- данных порта ввода. Теперь обратите внимание, что из порта ввода возможно только чтение, а в порт вывода возможна только запись. Поэтому для портов ввода и вывода можно отводить один и тот же адрес в адресном пространстве микропроцессора. Порты выпускаются в качестве универсальных микросхем, но на заводе, где производятся эти микросхемы, неизвестно, сколько на самом деле потребуется линий ввода информации и сколько потребуется линий вы- вывода информации. Количество же выводов у микросхемы ограничено. Поэтому в одной универсальной микросхеме размещаются и порт ввода, и порт вывода информации. Настройку линий порта на ввод или вывод информации предоставляют конечному пользователю. Такие порты на- называются портами ввода-вывода информации. Структурная схема парал- параллельного порта ввода-вывода приведена на рис. 5.17. Для подключения портов ввода или портов вывода информации к внеш- внешним выводам микросхемы в схеме, приведенной на рис. 5.17, использует- используется коммутатор. Управляет этим коммутатором еще один (внутренний)
126 Глава 5 параллельный порт вывода, регистр данных которого называется реги- регистром управления параллельного порта ввода-вывода. Регистру управ- управления и регистрам данных порта ввода-вывода обычно назначаются со- соседние адреса. Следует отметить, что обычно то, что регистр управления подключается через внутренний параллельный порт, не указывается, и вся схема, сколько бы в ней ни присутствовало портов, называется пор- портом ввода-вывода. Л6 ША ШД ШУ 16 А0..А15 Дешифрат. адреса 2 8 16 D0..D7 Регистр управления С Q0..Q3 А0..А15 Дешифрат. адреса! WR 8 D0..D7 Регистр данных С Q0..Q3 RD 8 L-oJ D0..D7 ШИННЫЙ формироват CS Вх1..Вх4 Рис. 5.17. Структурная схема параллельного порта ввода-вывода. В некоторых микропроцессорах для портов ввода-вывода выделяется отдельное адресное пространство. В этом случае для записи в порт и для чтения из порта используются отдельные сигналы чтения и записи. Чаще всего они называются «IOWR#» и «IORD#». Параллельные порты, предназначенные для обмена данными между компьютерами, или компьютером и принтером, устроены несколько иначе. Основным отличием этого вида обмена является большой объем передаваемых данных: не один или даже несколько байтов информации, а длинные последовательности байтов, предаваемые через один и тот же параллельный порт. Дополнительно вводится специальный сигнал син- синхронизации CLK, который позволяет отличать один байт от другого. Для формирования такого сигнала можно воспользоваться вторым па- параллельным портом и получить его программным способом, но обычно этот сигнал формируется аппаратно из сигнала «WR#» при записи оче-
Принципы работы микропроцессорной системы 127 редного байта в параллельный порт вывода. Временная диаграмма об- обмена данными через параллельный порт приведена на рис. 5.18. CLK D D4 t Рис. 5.18. Временная диаграмма работы параллельного порта В данной книге приведены только основы работы параллельного порта. Кому интересно познакомиться более детально с особенностями работы параллельных портов, может обратиться к специализированной литера- литературе [14-17]. Принципы построения последовательного порта Последовательные порты предназначены для обмена информацией между микропроцессорами, а также между микропроцессорами и внешними уст- устройствами, если критично количество соединительных проводов. В на- настоящее время широко используются два вида последовательных портов: ? синхронные последовательные порты; ? асинхронные последовательные порты. Синхронные последовательные порты При рассмотрении работы параллельного порта в режиме обмена дан- данными с другим компьютером или принтером уже рассматривался режим последовательной передачи байтов. В последовательном порте режим последовательной передачи применяется не только к байтам, но и к от- отдельным битам внутри байта. В этом случае для передачи данных доста- достаточно только одного провода. Передаваемая и принимаемая информа-
128 Глава 5 ция обычно представляется в виде однобайтовых или многобайтовых слов. Вес каждого бита в слове различен, поэтому кроме битовой син- синхронизации, аналогичной байтовой синхронизации для параллельного порта, требуется кадровая синхронизация. Она позволяет однозначно определять номер каждого бита в передаваемом слове. Временная диа- диаграмма передачи кадра по синхронному последовательному порту при- приведена на рис. 5.19. CLK t ппппппппп FS t и Рис. 5.19. Временная диаграмма передачи одного кадра двоичной информации по последовательному порту Такая временная диаграмма характерна для синхронных последователь- последовательных портов, которые используются чаще всего в сигнальных процессо- процессорах для обмена информацией с кодеками речи, аналого-цифровыми и цифроаналоговыми преобразователями. На временной диаграмме пока- показаны два синхросигнала: тактовой синхронизации CLK и кадровой син- синхронизации FS. Кадровый синхросигнал формируется аппаратно из сиг- сигнала WR# при записи очередного байта в параллельный порт вывода. Полярность сигналов синхронизации зависит от конкретного типа при- применяемых микросхем, поэтому в большинстве последовательных портов возможна настройка полярности сигналов синхронизации. Упрощенная схема синхронного последовательного порта приведена на рис. 5.20. В состав последовательного порта входит универсальный по- последовательно-параллельный регистр, подключенный к системной шине. Он обеспечивает преобразования параллельного кода, поступающего с системной шины в последовательный. При обращении центрального
Принципы работы микропроцессорной системы 129 процессора к последовательному порту вырабатывается сигнал записи в последовательный порт WR#, который через дешифратор подается на вход параллельной записи V универсального регистра. Этот же сигнал используется в качестве кадрового синхросигнала FS. Тактовый синхро- синхросигнал CLK, вырабатываемый отдельным генератором, подается на вход последовательного сдвига С универсального регистра, входящего в со- состав порта. AQ..A15 WR Дешифратор адреса Ген. Рис. 5.20. Упрощенная схема синхронного последовательного порта RFS1' TFS1 ADSP-2101 SCLK1 DR1 DT1 SMODE RFS TFS SCLK AD7890 DATA OUT DATA IN Рис. 5.21. Схема подключения кодека к синхронному последовательному порту Количество передаваемых в одном кадре битов может меняться от вось- восьми до тридцати двух. В качестве примера использования синхронного последовательного порта на рис. 5.21 приведена схема подключения ана-
130 Глава 5 лого-цифрового преобразователя AD7890 фирмы Analog Devices к син- синхронному последовательному порту сигнального процессора ADSP-2101 той же фирмы. В синхронном последовательном порте информация передается непре- непрерывно, что, конечно, удобно для устройств с непрерывным потоком ин- информации, как, например, в кодеках речи. Но существуют устройства, к которым необходимо обращаться только периодически, как, например, синтезаторы частоты, микросхемы приемников, блоков цветности теле- телевизоров, микросхем памяти данных и многие другие устройства. В этих случаях используются другие виды синхронных последовательных пор- портов, такие как SPI и 12С. Временная диаграмма сигналов SPI-интерфейса приведена на рис. 5.22. 55 \ / SCLOCK. . я. \ / Ч / MISO sr 1Г / \ / MOSI \ / \ и. Рис. 5.22. Временная диаграмма SPI-интерфейса Основное отличие этого интерфейса от приведенного выше заключается в том, что сигнал тактовой синхронизации передается только в момент действия импульса кадровой синхронизации. Активный уровень сигнала кадровой синхронизации длится до окончания передачи последнего бита в передаваемом кадре. По одним и тем же линиям передачи данных: MISO (вход для главного, выход для ведомого); и MOSI (выход для главного, вход для ведомого), может передаваться информация к совер- совершенно различным микросхемам. Выбор среди микросхем, подключенных к одному и тому же порту, той, для которой предназначена информация, производится сигналом SS (выбор ведомого). В SPI-интерфейсе в прием- приемнике не требуется счетчик тактовых импульсов. Запись принятой инфор- информации в параллельный регистр данных производится по окончанию кад- кадрового импульса.
Принципы работы микропроцессорной системы 131 Если в устройстве используется много микросхем, то в SPI-интерфейсе количество линий выбора ведомого становится значительным, поэтому в таких случаях используется еще один вид синхронного последовательно- последовательного интерфейса: 12С. Временная диаграмма этого интерфейса приведена на рис. 5.23. В PC-интерфейсе прием и передача данных, а также передача адреса микросхемы и адреса регистра внутри микросхемы, к которому осуществляется обращение, производятся по одной и той же линии дан- данных SDA. Для подключения к этой линии используются микросхемы с открытым коллектором. Нагрузкой для всех микросхем, подключенных к линии SDA, служит внешний резистор. Естественно, что скорость пе- передачи данных по такому интерфейсу будет ниже, чем в случае SPI. Адрес микросхемы Ответ микросхемы Данные SDA SCL Start Рис. 5.23. Временная диаграмма 12С-интерфейса Сигнал тактовой синхронизации в 12С-шине передается по линии SCL. Начало работы с микросхемой обозначается особой комбинацией сигна- сигналов SDA и SCL (переход 0-1 SDA при высоком уровне SCL), которая на- называется условием старта. Эта же комбинация одновременно осуществ- осуществляет кадровую синхронизацию. Завершение работы с микросхемой обозначается еще одной комбинацией сигналов SDA и SCL — переходом 0-1 SDA при высоком уровне SCL. В качестве примера микросхем, ис- использующих интерфейс 12С, можно назвать микросхемы EEPROM серии 24сХХ. Асинхронные последовательные порты Рассмотренные синхронные последовательные порты позволяют достиг- достигнуть больших скоростей передачи данных, но линия, по которой ведется передача синхросигнала, практически не несет информации. Такой сиг- сигнал можно было бы сформировать и на приемном конце линии передачи, если заранее договориться о скорости передачи.
132 Глава 5 В настоящее время используются стандартные скорости передачи, крат- кратные скорости 1200 бит/с. При этом масштабирование может проводиться как в сторону увеличения скорости обмена, так и в сторону уменьшения скорости обмена двоичной информацией. Например, стандартной скоро- скоростью передачи последовательного порта будет скорость 2400 и 4800 бит/с. Стандартными же будут скорости обмена 600 и 300 бит/с. Проблема, возникающая при таком способе обмена данными, — это не- невозможность добиться от двух внутренних генераторов, осуществляющих синхронизацию передачи данных на приемном и передающем концах линии, одинаковой частоты и фазы генерируемых сигналов. Проблема решается принудительной синхронизацией тактового генератора на при- приемном конце при помощи особого условия начала асинхронной переда- передачи — стартового бита. Все время, пока не ведется передача информации, на линии присутствует стоп-сигнал единичного уровня. Перед началом передачи каждого байта передается старт-бит, сигнализирующий приемнику о начале посылки данных, за которым следуют информационные биты. Стартовый бит всегда передается нулевым уровнем с длительностью, как у информаци- информационных битов. Внутренний генератор синхронизации приемника использует счетчик- делитель опорной частоты, обнуляемый в момент приема начала старт- бита. Этот счетчик генерирует внутренние стробы, по которым приемник фиксирует последующие принимаемые биты. В идеале стробы распола- располагаются в середине битовых интервалов, что позволяет принимать данные и при незначительном рассогласовании скоростей приемника и передат- передатчика. Очевидно, что при передаче 8 битов данных, одного контрольного и одного стоп-бита предельно допустимое рассогласование скоростей, при котором данные будут распознаны верно, не может превышать 5%. В некоторых случаях после передачи битов данных может передаваться бит паритета (четности). Завершается передача данных стоп-сигналом. Минимальная длительность стопового сигнала должна быть 1,5 дли- длительности информационных битов, но обычно используют паузу между соседними пакетами данных, равную двум длительностям информацион- информационного бита. Временная диаграмма сигналов при асинхронной передаче данных при- приведена на рис. 5.24. START STOP BIT Рис. 5.24. Временная диаграмма сигналов при асинхронной передаче
Принципы работы микропроцессорной системы 133 Формат асинхронной посылки позволяет выявлять следующие возмож- возможные ошибки передачи: ? если принят перепад, сигнализирующий о начале посылки, а по стро- стробу старт-бита зафиксирован уровень логической единицы, то старт- бит считается ложным и приемник снова переходит в состояние ожи- ожидания. Об этой ошибке приемник может и не сообщать; ? если во время, отведенное под стоп-бит, обнаружен уровень логиче- логического нуля, то фиксируется ошибка стоп-бита; ? если применяется контроль четности, то после посылки битов данных передается контрольный бит. Он дополняет количество единичных битов данных до четного или нечетного в зависимости от принятого соглашения. Прием байта с неверным значением контрольного бита приводит к фиксации ошибки. Наиболее распространенным в настоящее время является последователь- последовательный асинхронный порт, работающий по стандарту RS-232. Временная диаграмма этого порта приведена на рис. 5.25. Используются уровни сигналов НОВ, что позволяет контролировать обрыв линии. Лог О О Старт- бит Пауза t Биты данных Стоп- бит Обрыв линии О 7 Лог1 Внутренние стробы Ч I 1 I 1 I 1 I 1 I 1 Возможно начало Т следующей передачи Рис. 5.25. Временная диаграмма сигналов интерфейса RS-232 Существует ряд международных стандартов на асинхронные последова- последовательные интерфейсы: RS-232C, RS-423A, RS-422A и RS-485. На рис. 5.26 приведены схемы соединения приемников и передатчиков, а также пока- показаны ограничения на длину линии (L) и максимальную скорость переда- передачи данных (V) по этим интерфейсам. Несимметричные линии интерфейсов RS-232C и RS-423A имеют самую низкую защищенность от синфазной помехи, хотя дифференциальный вход приемника RS-423A несколько смягчает ситуацию. Лучшие пара- параметры имеет двухточечный интерфейс RS-422A и его магистральный (шинный) аналог RS-485, работающие на симметричных линиях связи. В них для передачи каждого сигнала используются дифференциальные сигналы с отдельной (витой) парой проводов.
134 Глава 5 RS-232C L = 15 м V = 20 Кбит/с RS-423A L= 9m V=100K6kt/c 91m V= 10 Кбит/с 1200mV=1 Кбит/с RS-422A L L L 12 m V=10M6ht/c 120 m V=1M6ht/c 1200 m V= 100 Кбит/с RS-485 L=12m V=10M6ht/c L=120m V=lM6irr/c L= 1200 m V= 100 Кбит/с Рис. 5.26. Схемы соединения приемников и передатчиков различных стандартных асинхронных последовательных интерфейсов Последовательный асинхронный порт, работающий по стандартам RS- 232, RS-423A и RS-422A, позволяет соединять между собой только два устройства. Это связано с тем, что при параллельном соединении двух передатчиков их выходные каскады могут выйти из строя. В ряде случаев требуется объединить несколько устройств. Для того чтобы выходные каскады передатчиков последовательных портов не выходили из строя, необходимо применять специальные меры, которые обсуждались в пре- предыдущих главах. Эти меры реализованы в интерфейсе RS-485. Принципы построения таймеров Таймеры предназначены для формирования временных интервалов, по- позволяя микропроцессорной системе работать в режиме реального вре- времени. Таймеры представляют собой обычные цифровые счетчики, которые подсчитывают импульсы от высокостабильного генератора частоты. К системной шине микропроцессора таймеры подключаются при помо- помощи параллельных портов.
Принципы работы микропроцессорной системы 135 Генератор периодических импульсов, входящий в состав таймера, опре- определяет минимальный интервал времени, который может формировать таймер. Интервалы времени, задаваемые таймером, могут устанавли- устанавливаться только из дискретного набора допустимых интервалов времени. Их значения тоже определяются частотой задающего генератора. Раз- Разрядность цифрового счетчика, входящего в состав таймера, определяет максимальный интервал времени, который может формировать таймер. Обычно используются 16-разрядные таймеры, поэтому для их подключе- подключения к 8-разрядному процессору требуется два параллельных порта. Кро- Кроме того, таймером нужно управлять, для чего используется дополнитель- дополнительный порт. С его помощью таймер можно включать и выключать. Часто требуется определять, не возникало ли переполнение таймера. Факт пе- переполнения легко запомнить в дополнительном триггере, подключенном к выходу переноса счетчика таймера. Выходной сигнал этого триггера называется флагом переполнения таймера. Сигнал с выхода триггера (флаг) включения и выключения таймера и флаг переполнения таймера подключают к системной шине микропроцессора через дополнительный порт ввода-вывода. Структурная схема таймера, построенного по описанным выше принци- принципам, приведена на рис. 5.27. • * '16 4 t -8 ' Порт ввода вывода i i т t Ген. > -16 -8 • WR Порт ввода вывода j 1 Счётчик —*— 1 -16 -8 WR Порт ввода вывода j 1 Счётчик —*— Лб 'л - ША - шд - ШУ Фл nepei аг юлн. Младший байт Старший байт Рис. 5.27. Структурная схема таймера В зависимости от типа использованного цифрового счетчика таймеры бывают суммирующие (с суммирующим счетчиком) или вычитающие (с вычитающим счетчиком). Использование вычитающего счетчика позво-
136 Глава 5 ляет проще задавать интервалы времени. В этом случае записываемый в таймер код Codesuh будет соответствовать длительности временного ин- интервала Ttimcn вырабатываемого таймером: ' tuner ~~ ^Ou€sufjXI t,c,/p где Ткеп период импульсов внутреннего генератора. В случае использования суммирующего таймера код, записываемый в таймер для задания интервала времени Tlimcn определяется из другой формулы: 'timer ~~ (CsOdeimw — ^odesum)• Jк,.п. В этой формуле код Code,wn, который заносится в таймер, представляет собой дополнение кода интервала времени до максимального кода Codemax, который можно записать в таймер. Максимальный код Codem-лх опреде- определяется разрядностью таймера. В рассмотренном примере разрядность таймера равна 16. Это означает, что максимальный код равен Codemnx - = 216 = 65536. Достаточно часто применяются свободно бегущие суммирующие тайме- таймеры. Схема такого таймера приведена на рис. 5.28. Лб 1 '16 ¦ WR Порт ввода вывода с л -16 ¦ U WR i Порт ввода вывода j Ген. -*— -16 4 Г If WR i Порт ввода вывода J 1 Счётчик -16 * Л V WR - i Порт ввода вывода J Счётчик • Кодовый компаратор J I J RGL j RGH J ',8 -16 ',2 WR Порт ввода вывода 1 1 Флаг совпаден ША ШД ШУ Младший байт Старший байт Рис. 5.28. Структурная схема свободно бегущего таймера с модулем сравнения
Принципы работы микропроцессорной системы 137 Свободно бегущие таймеры используются как системные часы, задаю- задающие время внутри микропроцессорной системы. Для задания промежут- промежутков времени микропроцессор считывает значение текущего системного времени и суммирует с ним код задаваемого промежутка времени. Полу- Полученный результат записывается в регистр сравнения таймера. При сов- совпадении значений таймера и регистра сравнения устанавливается флаг совпадения. Значение этого флага можно определить программным опросом или воспользоваться механизмом прерывания работы процес- процессора. То есть работа со свободнобегущим таймером похожа на работу с обычным будильником, к которому мы привыкли в обычной жизни. Часто с одним свободно бегущим таймером работает несколько модулей сравнения. Это похоже на использование часов с несколькими будильни- будильниками. Кроме модулей сравнения, со свободно бегущим таймером работают модули захвата, которые позволяют аппаратно запоминать состояния внутренних счетчиков в момент какого-либо'внешнего события (как, на- например, фронта входного сигнала при измерении его периода) без уча- участия центрального процессора. Структурная схема свободно бегущего таймера с модулем захвата приведена на рис. 5.29. ,16 ША ШД ШУ л. 16 Г 1Г WR Порт ввода вывода Ген. 16 8 WR 16 WR 16 Порт ввода вывода Порт ввода вывода Счётчик Внешний вывод микросхемы Счетчик RGL RGH 8 WR 16 ¦8 Порт ввода WR Порт ввода Флаг захвата Младший байт Старший байт Рис. 5.29. Структурная схема свободно бегущего таймера с модулем захвата
138 Глава 5 Использование модулей захвата позволяет повысить точность измерения времени каких-либо событий, т. к. нее перестает влиять такой нестабиль- нестабильный параметр, как время реакции программы и она будет определяться только быстродействием цифровых микросхем свободно бегущего тай- таймера. Итак, подведем итоги В главе были рассмотрены схемы подключения к микропроцессору уст- устройств хранения, ввода и вывода данных. Кроме того, были рассмотре- рассмотрены основные методы расширения адресного пространства микропроцес- микропроцессорной системы и некоторые решения, позволяющие повысить ее быстродействие. Структурные схемы приведены с уровнем детализации, достаточным для превращения их в принципиальные схемы. Однако в настоящее время никто не разрабатывает схемы, подобные рас- рассмотренным в данной главе, ведь это стандартные схемы. Поэтому в на- настоящее время на мировом рынке представлено огромное количество го- готовых микросхем, построенных по рассмотренным принципам. Теперь можно перейти к изучению этих микросхем, представляющих собой уни- универсальные цифровые устройства.
moon Глава 6 Принципы работы микроконтроллеров В предыдущей главе мы познакомились с принципами построения мик- микропроцессорных систем. Однако цель нашей книги — научиться рабо- работать с микроконтроллерами, или как их раньше называли — однокри- однокристальными микроЭВМ. Внутри эти микросхемы устроены подобно микропроцессорной системе, пример которой мы рассматривали выше по тексту. Однако для каждого микроконтроллера есть индивидуальные отличия. Рассмотрим эти особенности на примере самого распростра- распространенного семейства микроконтроллеров. Напомню, что при изучении микропроцессорной техники необходимо иметь в виду две разных модели устройства — схемотехническую и про- программистскую. Под схемотехнической моделью подразумевается пере- перечень тех аппаратных средств (внутренних устройств), которые включены в состав микроконтроллера, и особенности их схемной реализации. В этой главе в основном будут рассматриваться схемотехнические осо- особенности использования выбранного семейства микроконтроллеров. Однако внутренние устройства микроконтроллеров нужно уметь исполь- использовать, ведь именно наличие таких устройств и характеризует современ- современные микросхемы. Поэтому там, где это необходимо, будут приведены участки программ, позволяющие настроить внутренние блоки микро- микроконтроллеров для работы с подключенными к этой микросхеме внешни- внешними устройствами. Если чтение программ вызовет определенные трудно- трудности, то можно почитать описание языка программирования, приведенное в последующих главах, а затем вернуться к этой главе. Очень важной характеристикой микропроцессорного устройства и мик- микроконтроллеров, как одного из представителей микропроцессоров, явля-
140 Глава 6 ется система команд. Поэтому в данной главе подробно рассматривают- рассматриваются команды и виды адресации, используемые в этих командах, для вы- выбранного семейства микроконтроллеров. Семейство микроконтроллеров MCS-51 В настоящее время среди всех 8-разрядных микроконтроллеров семейст- семейство MCS-51 является несомненным чемпионом по числу разновидностей и количеству компаний, выпускающих его модификации. Первый предста- представитель этого семейства — микроконтроллер 8051, выпущенный в 1980 г. на базе технологии п-МОП. Удачный набор периферийных устройств, возможность гибкого выбора внешней или внутренней программной памяти и приемлемая цена обес- обеспечили этому микроконтроллеру успех на рынке. С точки зрения техно- технологии микроконтроллер 8051 являлся для своего времени очень сложным изделием: в кристалле было использовано 128 тыс. транзисторов, что в 4 раза превышало количество транзисторов в 16-разрядном микропро- микропроцессоре 8086. Важную роль в достижении такой высокой популярности семейства 8051 сыграла открытая политика фирмы Intel, родоначальни- родоначальницы архитектуры, направленная на широкое распространение лицензий на ядро 8051 среди большого количества ведущих полупроводниковых компаний мира. В результате на сегодняшний день существует более 200 модификаций микроконтроллеров семейства 8051, выпускаемых почти двадцатью компаниями. Эти модификации включают в себя кристаллы с широчайшим спектром периферии: от простых 20-выводных устройств с одним таймером и 1К программной памяти до сложнейших 100-вывод- ных кристаллов с 10-разрядными АЦП, массивами таймеров-счетчиков, аппаратными 16-разрядными умножителями и 64К программной памяти на кристалле. Каждый год появляются все новые варианты представите- представителей этого семейства. Основными направлениями развития микрокон- микроконтроллеров являются: ? увеличение быстродействия (повышение тактовой частоты и перера- переработка архитектуры); ? снижение напряжения питания и потребления; ? увеличение объема ОЗУ и флэш-памяти на кристалле с возможностью внутрисхемного программирования; ? введение в состав периферии микроконтроллера сложных устройств типа системы управления приводами, CAN- и USB-интерфейсов и т. п.
Принципы работы микроконтроллеров 141 Очень важным направлением развития микроконтроллеров является производство микросхем в маленьких корпусах. Это позволяет осущест- осуществлять проектирование и производство малогабаритной аппаратуры. Микросхемы семейства MCS51 производятся рядом фирм различных стран мира, таких как Philips, Siemens, Intel, Atmel, Dallas, Temic, Oki, AMD, MHS, Gold Star, Winbond, Silicon Systems, и ряд других. Микро- Микроконтроллеры семейства MCS-51 выпускают и заводы бывшего СССР. Производство микроконтроллера 8051 осуидествляется в Киеве, Воронеже A816ВЕ31/51, 1830ВЕ31/51), Минске A834ВЕ31) и Новосибирске A850ВЕ31). В качестве примера в табл. 6.1 приведены названия нескольких микро- микросхем, производимых зарубежными фирмами, в табл. 6.2 приведены мик- микросхемы российского производства. Таблица 6.1. Микросхемы семейства MCS-51, производимые зарубежными фирмами Микроконтроллер АТ89сЮ51 АТ89с2051 80с51 80с31 8Хс52 АТ89с52 АТ89с8252 АТ89с55 8Хс54 8Хс58 8XC51FA 8XC51FB 8XC51FC 8XC51GB AduC834 ОЗУ 128 байт 128 байт 128 байт 128 байт 256 байт 256 байт 256 байт 256 байт 256 байт 256 байт 128 байт 256 байт 256 байт 256 байт 4 Кбайт ПЗУ 1 Кбайт 2 Кбайт 4 Кбайт - 8 Кбайт 8 Кбайт 8 Кбайт 20 Кбайт 16 Кбайт 32 Кбайт 8 Кбайт 16 Кбайт 32 Кбайт 8 Кбайт 64 Кбайт EEPROM — — — — — — 2 Кбайт — — — — — — — 2 Кбайт UART 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 SPI — — — — — — 1 — — — — — — 1 1 Таймеры 2 2 2 2 3 3 3 3 3 3 4 4 4 5 3 РСА — — — — — — — — — — 1 1 1 2 — АЦП комп. комп. — Юр 24 р
142 Глава 6 Примечание 1. Вместо символа X в названии микроконтроллера должны стоять символы: О — в микросхемах n-МОП без ПЗУ; 3 — в микросхемах n-МОП с ПЗУ; 7 — в микросхемах n-МОП с РПЗУ; Ос — в микросхемах КМОП без ПЗУ; Зс — в микросхемах КМОП с ПЗУ; 7с — в микросхемах КМОП с РПЗУ; 9с — в микросхемах КМОП с FLASH-памятью. 2. комп. — аналоговый компаратор. 3. Юр — количество разрядов во встроенном АЦП. Таблица 6.2. Микросхемы семейства MCS -51 российского производства Микроконтроллер КР1816ВЕ51 КР1816ВЕ751 КР1816ВЕ31 КР1830ВЕ51 КР1830ВЕ751 КР1830ВЕ31 ОЗУ 128 байт 128 байт 128 байт 128 байт 128 байт 128 байт ПЗУ 4 Кбайт — 4 Кбайт — — ППЗУ 4 Кбайт 4 Кбайт — Таймер 2 — — — — РСА — — — — — РСА1 — — — — АЦП — — — — — — Примечание Серия микросхем 1816 выполнена по n-МОП технологии. Серия микросхем 1830 выполнена по КМОП технологии. Архитектура микроконтроллеров MCS-51 Архитектура семейства MCS-51 в значительной мере предопределяет ее назначение — это построение компактных и дешевых цифровых уст- устройств. Все функции микроконтроллера реализуются с помощью единст- единственной микросхемы. В состав семейства MCS-51 входит ряд микросхем
Принципы работы микроконтроллеров 143 от самых простых микроконтроллеров до достаточно сложных. Микро- Микроконтроллеры семейства MCS-51 позволяют выполнять как задачи управ- управления различными устройствами, так и реализовывать простейшие алго- алгоритмы цифровой обработки сигналов. Все микросхемы чтого семейства работают с одной и той же системой команд. Большинство микросхем выполняется в одинаковых корпусах с совпадающей цоколевкой (схемой расположения выводов). Это позволяет использовать для разработанно- разработанного устройства микросхемы разных фирм-производителей (таких как Intel, Dallas, Atmel, Philips и т. д.) без переделки принципиальной схемы уст- устройства и программы. Структурная схема микроконтроллера представлена на рис. 6.1 и состоит из следующих основных функциональных узлов: ? блока управления; ? арифметико-логического блока; G блока таймеров/счетчиков; ? блока последовательного интерфейса и прерываний; П программного счетчика, памяти данных и памяти программ. Двусторонний обмен данными между элементами внутренней структуры микроконтроллера осуществляется с помощью внутренней 8-разрядной шины данных. По такой схеме построены практически все представители семейства MCS-51. Различные микросхемы этого семейства различаются толь- только регистрами специального назначения (в том числе и количеством портов). Система команд всех контроллеров семейства MCS-51 содержит 111 базовых команд длиной 1, 2 или 3 байта и не изменяется при перехо- переходе от одной микросхемы к другой. Это обеспечивает прекрасную перено- переносимость программ с одной микросхемы на другую. Рассмотрим подроб- подробнее назначение каждого блока. Блок управления и синхронизации предназначен для выработки синхро- синхронизирующих и управляющих сигналов, обеспечивающих координацию совместной работы блоков микроконтроллера во всех допустимых ре- режимах его работы. В состав блока управления входят: П устройство формирования временных интервалов; ? логика ввода-вывода; ? регистр команд; П регистр управления потреблением электроэнергии; ? дешифратор команд, логика управления микроконтроллером.
144 Глава 6 Р0.0-Р0.7 Р2.0-Р2.7 vfcc Vss - mm- mm- Дряйверы Портя 3 Дряйаеры портя 2 а. j— V L. P-, 00 о ц ¦D Зящепкд портя О EPROM УКЯЗЯТ9ЛЬ стекя SFRs. Тяймеры, PC/I, поспед. порты. PSEN-^1 AL§^R0a-<T EA/VPP —t RESET Упряв- лени^ и синхро- низяция ?« а» о а. ^ \ZL TMMI Р9ГИСТР ЯДр. EPROM А-А Прогряммный счетчик (PC) I XTAL1 П Зящепкд портя 1 Драйверы портя 1 XTAL2 J DPTR ЗйЩРПКА портя 3 Дряйьеры Портя 3 Р1.0-Р1.7 Р3.0-Р3.7 Рис. 6.1. Структурная схема микроконтроллера К1830ВЕ751 Устройство формирования временных интервалов предназначено для формирования и выдачи внутренних синхросигналов фаз, тактов и цик- циклов. Количество машинных циклов определяет продолжительность вы- выполнения команд. Практически все команды микроконтроллера выпол- выполняются за один или два машинных цикла, кроме команд умножения и деления, продолжительность выполнения которых составляет четыре машинных цикла. Обозначим частоту задающего генератора через Fr. Тогда длительность машинного цикла равна 12/ Fv или составляет 12 пе- периодов сигнала задающего генератора. Логика ввода-вывода предназна- предназначена для приема и выдачи сигналов, обеспечивающих обмен информаци- информацией с внешними устройствами через порты ввода-вывода РО-РЗ.
Принципы работы микроконтроллеров 145 Регистр команд предназначен для записи и хранения 8-разрядного кода операции выполняемой команды. С помощью дешифратора команд и логики управления микроконтроллера он преобразуется в микропро- микропрограмму выполнения заданной команды. Регистр управления потреблением (PCON) позволяет останавливать мик- микроконтроллер для уменьшения потребления электроэнергии и уменьше- уменьшения уровня помех. Еще большего уменьшения потребления электроэнер- электроэнергии и уменьшения помех можно добиться, остановив задающий генератор микроконтроллера при помощи переключения битов регистра управле- управления потреблением PCON. В вариантах микросхемы, изготовленных по технологии-п-МОП (серия 1816 или иностранных микросхем, в названии которых в середине отсутствует буква «с»), регистр управления потреб- потреблением PCON содержит только один бит, управляющий скоростью пере- передачи последовательного порта SMOD, а биты управления потреблением электроэнергии отсутствуют. Арифметико-логический блок (АЛБ) представляет собой параллельное 8- разрядное устройство, обеспечивающее выполнение арифметических и логических операций. АЛБ состоит из: G регистров временного хранения ТМР1 и ТМР2; G ПЗУ констант; G арифметико-логического устройства; ? дополнительного регистра (регистра В); G аккумулятора (АСС); G регистра состояния программ (PSW). Регистры временного хранения — это 8-разрядные регистры, предназна- предназначенные для приема и хранения операндов на время выполнения операций над ними. Регистры временного хранения программно не доступны, ими управляет только микропрограмма выполнения команд. ПЗУ констант обеспечивает выработку корректирующего кода при дво- двоично-десятичном представлении данных или кода маски при битовых операциях и констант. Арифметико-логическое устройство представляет собой схему комби- комбинационного типа с последовательным переносом, предназначенную для выполнения арифметических операций сложения, вычитания и логиче- логических операций «И», «ИЛИ», суммирования по модулю 2 и инвертиро- инвертирования. Регистр В — восьмиразрядный регистр, используемый во время операций умножения и деления. Для других инструкций он может рассматриваться как дополнительный регистр внутренней памяти микроконтроллера.
146 Глава 6 Аккумулятор — 8-разрядный регистр, предназначенный для приема и хранения результата, полученного при выполнении арифметико-логи- арифметико-логических операций или операций сдвига Блок последовательного интерфейса и прерываний предназначен для ор- организации последовательного ввода-вывода информации и организации прерываний выполнения программы. В состав этого блока входят: ? логика управления; ? регистр управления; ? буфер передатчика; ? буфер приемника; ? приемопередатчик последовательного порта; ? регистр приоритетов прерываний; ? регистр разрешения прерываний; ? логика обработки флагов прерываний. Счетчик команд предназначен для формирования текущего 16-разряд- 16-разрядного адреса внутренней или внешней памяти программ. В состав счетчи- счетчика команд входят 16-разрядный буфер счетчика команд, регистр счетчи- счетчика команд и схема инкремента (увеличения содержимого на 1). Память данных предназначена для временного хранения информации, используемой в процессе выполнения программы. Порты РО, PI, P2, РЗ являются квазидвунаправленными портами ввода- вывода и предназначены для обеспечения обмена информацией между микроконтроллером и внешними устройствами, образуя 32 линии ввода- вывода. Регистр состояния программы (PSW) предназначен для хранения инфор- информации о состоянии АЛУ при выполнении программы. Память программ предназначена для хранения программного кода и представляет собой постоянное запоминающее устройство (ПЗУ). В раз- разных микросхемах применяются масочные, стираемые ультрафиолетовым излучением или FLASH ПЗУ. Регистр указателя данных (DPTR) предназначен для формирования 16- разрядного адреса внешней памяти данных или памяти программ при считывании таблиц констант. Указатель стека (SP) представляет собой 8-разрядный регистр, предна- предназначенный для организации особой области памяти данных (стека), в ко- которой хранятся адреса возврата из подпрограмм, переменные и содер- содержимое внутренних регистров микроконтроллера (в том числе регистры PSW и аккумулятор).
Принципы работы микроконтроллеров 147 Система команд микроконтроллеров MCS-51 Ни один из видов микропроцессоров не может рассматриваться отдельно от системы команд. Не является исключением и семейство микрокон- микроконтроллеров MCS-51. Система команд микроконтроллеров этого семейства предоставляет большие возможности обработки данных, обеспечивает реализацию логических, арифметических операций, а также управление устройствами в режиме реального времени. В этой системе команд реализована побитная, потетрадная D бита), по- побайтовая (8 бит) и 16-разрядная обработка данных. Микросхемы семей- семейства MCS-51 — это 8-разрядные микропроцессоры, а это означает, что ПЗУ, ОЗУ, регистры специального назначения, АЛУ и внешние шины имеют байтовую организацию. Двухбайтовые данные используются только регистром-указателем (DTPR) и счетчиком команд (PC). В машинном коде команда занимает один, два или три байта в зависимо- зависимости от типа адресации. Команды выполняются за один, два или четыре (умножение и деление) машинных цикла. Запись команд в машинных кодах для человека неудобна. Кроме того, машинные команды, отличающиеся младшими битами или вторым байтом, выполняют одинаковые действия над разными ячейками памя- памяти. Поэтому для записи команд микропроцессоров была придумана система мнемонических обозначений. В записи команды микропроцес- микропроцессора сначала ставится мнемоническое обозначение кода операции, за- затем указывается ячейка памяти — приемник результата выполнения операции и, наконец, источник данных для выполнения операции. На- Например, в команде Е535 MOV A, 35h символы mov обозначают операцию копирования, второй операнд ль определяет, что данные необходимо взять из ячейки памяти с шетнадца- теричным адресом 3 5, а первый операнд л определяет, что результат не- необходимо поместить в регистр-аккумулятор. При этом старое значение регистра-аккумулятора будет стерто. Слева приведена машинная коман- команда микроконтроллера в шестнадцатеричной записи, соответств\ ющая находящейся справа мнемонической записи команды. Мнемоническое обозначение кода операции отделяется от операндов одним или несколькими символами пробела пли табуляции, а операнды отделяются друг от друга запятыми. При эюм между операндами допус-
148 Глава 6 тимо использование символов пробела или табуляции, которые могут потребоваться для более наглядной записи команды. Если операция требует для выполнения двух источников и одного при- приемника результата операции (например, команда сложения ADD или вычитания SUBB), то первый операнд является одновременно и источ- источником и приемником результата операции. Например, в команде 2535 ADD A, 35h символы add обозначают операцию сложения двух чисел, данные будут взяты из ячейки памяти с шестнадцатеричным адресом 35 и аккумулято- аккумулятора, а результат будет помещен в аккумулятор вместо старого значения этого регистра. В табл. Ш приведены мнемонические обозначения машинных команд, влияющих на значения флагов регистра слова состояния программы PSW, а в табл. П2 приведены обозначения и символы, используемые при описании команд микроконтроллеров семейства MCS-51. Команды микроконтроллера условно можно разбить на пять групп: ? арифметические команды; ? логические команды с байтовыми переменными; ? команды передачи данных; ? команды битового процессора; ? команды ветвления программ и передачи управления ОЭВМ. Арифметические команды В наборе команд микроконтроллера имеются следующие арифметиче- арифметические операции: ? сложение — add; ? сложение с учетом флага переноса — addc; ? вычитание с заемом из флага переноса — subb; ? инкрементирование (увеличение на 1) — inc; ? декрементирование (уменьшение на 1) — dec; ? десятичная коррекция — da; ? умножение — mul; ? деление — div.
Принципы работы микроконтроллеров 149 Действия производятся над целыми беззнаковыми 8-разрядными числа- числами. Арифметические операции в рассматриваемой системе команд могут быть выполнены только над содержимым регистра-аккумулятора. При операции умножения содержимое аккумулятора А умножается на содержимое регистра В, и результат размещается следующим образом: младший байт в регистре В, старший — в регистре А. В случае выполнения операции деления целое от деления помещается в аккумулятор А, остаток — в регистр В. Логические команды с байтовыми переменными Система команд рассматриваемого микроконтроллера позволяет реали- реализовать следующие логические операции: логическое «И» — anl; логическое «ИЛИ» — orl; исключающее «ИЛИ» — xrl. Логические операции могут выполняться только над аккумулятором или над портами ввода-вывода. Существуют логические операции, которые выполняются только на ак- аккумуляторе: сброс всех восьми разрядов А — clr a; инвертирование всех восьми разрядов А — cpl a; ? циклический сдвиг влево и вправо без учета флага переноса — rl аи rr а; циклический сдвиг влево и вправо с учетом флага переноса — rlc а и rrc а; обмен местами старшей и младшей тетрад внутри аккумулятора — SWAP A. Команды пересылки данных Как было рассмотрено ранее, арифметические и логические команды мо- могут быть выполнены только над содержимым регистра-аккумулято- регистра-аккумулятора, поэтому исключительное значение в системе команд приобретают команды пересылки данных. С помощью этих команд можно скопиро- скопировать содержимое любой ячейки памяти в регистр-аккумулятор или на-
150 Глава 6 оборот скопировать содержимое аккумулятора в любую ячейку памяти. Так как в микроконтроллере присутствуют три независимых области па- памяти, то для обращения к ним введены различные команды: копирование данных во внутреннем ОЗУ — mov; обмен данными аккумулятора с внутренним ОЗУ — хсн, хсно; копирование из внешней памяти данных — movx; копирование данных из памяти программ — movc. Рассмотрим несколько примеров использования команд пересылки данных. Любая из 256 ячеек внутреннего ОЗУ данных может быть выбрана с ис- использованием косвенно-регистровой адресации через регистры-указатели ro и ri (выбранного банка рабочих регистров): MOV A, @R0 /Скопировать число из ячейки памяти с адресом, /хранящимся в R0, в аккумулятор MOV @R1, А /Скопировать число из аккумулятора, в ячейку памяти с /адресом, хранящимся в R1 Команды пересылки между ячейками памяти, использующие прямую ад- адресацию, позволяют заносить содержимое порта в ячейку внутреннего ОЗУ или пересылать содержимое из одной ячейки внутреннего ОЗУ в другую без использования аккумулятора: MOV 15, 25 /Скопировать содержимое 25-ой ячейки в 15-ю ячейку Таблицы символов (кодов), записанные в ПЗУ программы, могут быть скопированы в аккумулятор с помощью команд передачи данных с кос- косвенной адресацией, например: MOVC A, @A+DPT/Скопировать символ в аккумулятор Ячейка адресного пространства 64-килобайтного внешнего ОЗУ также может быть выбрана с использованием косвенно-регистровой адресации через регистр-указатель данных dptr, например: MOVX A, QDPTR /Скопировать число из внешней ячейки памяти с адресом, /хранящимся в DPTR, в аккумулятор Содержимое аккумулятора может быть обменено с содержимым рабочих регистров выбранного банка, например: ХСН A, R0. Битовые команды Каждый бит из битового пространства внутренней памяти может быть установлен в 1. сброшен в 0 или инвертирован.
Принципы работы микроконтроллеров 757 Эти операции можно выполнить при помощи следующих команд: П установить бит (записать логическую единицу) — setb; ? сбросить бит (записать логический ноль) — clr; ? проинвертировать значение бита (изменить на противоположное) — cpl; lJ записать бит во флаг переноса или считать из флага переноса — mov. По значениям бита могут быть реализованы переходы: ? если бит установлен (содержит логическую 1) — jb; П если бит не установлен (содержит логический 0) — jnb; ? переход, если бит установлен со сбросом этого бита после выполнения команды (запись в этот бит 0) — jbc. Между любым битом из битового пространства внутренней памяти и флагом переноса могут быть произведены логические операции «И» или «ИЛИ». 3 «И» — ANL 3 «ИЛИ» — ORL Команды ветвления и передачи управления Команды ветвления позволяют реализовывать условные операторы и операторы циклов. В микроконтроллерах семейства MCS-51 доступны следующие команды: О безусловный переход: ljmp, ajmp, sjmp; ? вызов и возврат из подпрограммы: lcall, acall, ret, reti; О переход в зависимости от результата проверки содержимого аккуму- аккумулятора: JZ, JNZ, CJNE, JMP; ? переход в зависимости от значения флага переноса С: jc, jnc; О переход в зависимости от значения любого бита в битовом простран- пространстве: JB, JNB, JBC. Команды 16-разрядных безусловных переходов и вызовов подпрограмм позволяют осуществить переход в любую точку адресного пространства памяти программ объемом до 64 Кбайт. Примеры команд: LJMP Metka /Переход к команде, расположенной по адресу ;обозначенному меткой xMetka' LCALL Podprogramma ;Вызов подпрограммы по адресу, обозначенному меткой ; APodprogramma'
152 Глава 6 Команды II-разрядных переходов и вызовов подпрограмм позволяют сократить объем программы, но при этом обеспечивают переходы толь- только внутри сегмента программной памяти размером 2 Кбайт. Эти коман- команды принципиально могут приводить к необнаруживаемым транслятором ошибкам, когда программный модуль размещается на двух соседних двух килобайтовых сегментах памяти. AJMP Metka ACALL Podprogramma /•Переход к команде, расположенной по адресу, /•обозначенному меткой xMetka' ;Вызов подпрограммы по адресу, /обозначенному меткой ^Podprogramma' В системе команд микроконтроллеров семейства MCS-51 имеются команды условных и безусловных переходов относительно начального адреса следующей команды в пределах от (PQ-127 до (PQ+127. Приме- Примеры команд: /Переход к команде, расположенной по адресу, /•обозначенному меткой xMetka' ;Если на выводе 6 порта РЗ нулевой потенциал, ;то вызвать подпрограмму, обозначенную меткой ; хPodprogramma' ;Если в аккумуляторе содержится число 5, ;то вызвать подпрограмму, обозначенную меткой ; лPodprogramma' Команды условного перехода в зависимости от результата анализа со- содержимого аккумулятора или значения флага переноса С могут быть ис- использованы для реализации проверки различных условий. При этом со- содержимое не изменяется, т. е. если требуется произвести несколько проверок одной и той же переменной, то повторно заносить значение этой переменной в аккумулятор не нужно. Например: MOV А, 34 ;Если в переменной, хранящейся в ячейке внутренней JNB ACC_7, TstEQ5 ;памяти с адресом 34, число меньше нуля, CALL Podprogramma ;то вызвать подпрограмму, обозначенную меткой ; хPodprogramma' SJMP Metka JB P3.5, TstNxtUsl ACALL Podprogramma CJNE A, #5, TstNxtUsl ACALL Podprogramma TstEQ5 CJNE A,#5,TstLT5 CALL Podpr5 TstLT5 ;Если в переменной, хранящейся в ячейке внутренней ;памяти с адресом 34, занесено число 5, ;то вызвать подпрограмму, обозначенную меткой ; APodpr5'
Принципы работы микроконтроллеров 153 JNC TstGE5 CALL PodprLT5 :stGE5 ; JC TstNxtUsl CALL PodprGE5 TstGT5 ; CJNE A, #6,$ + 3 JC TstNxtUsl CALL PodprGT5 ;Если в переменной, хранящейся в ячейке внутренней /памяти с адресом 34, занесено число, меньшее 5, ;то вызвать подпрограмму, обозначенную меткой ; APodprLT5' , — — — — — — — — — — ав _ _ « « — — « — — — — — — — — — — — — — — — — — — — —¦• — — — — — — — — — — — — /Если в переменной, хранящейся в ячейке внутренней /памяти с адресом 34 занесено число, большее или ;равное 5, ;то вызвать подпрограмму, обозначенную меткой ; 'PodprGEb' ;Если в переменной, хранящейся в ячейке внутренней ;памяти с адресом 34, занесено число, большее 5, ;то вызвать подпрограмму, обозначенную меткой ; APodprGT5' JNC TstNxtUsl ;Если в переменной, хранящейся в ячейке внутренней /памяти 34, занесено число, меньшее или равное 5, CALL PodprLE5 ;то вызвать подпрограмму, обозначенную меткой ; APodprLE5' Косвенный переход jmp @a+dptr в системе команд микроконтроллеров семейства MCS-51 обеспечивает ветвление программы по содержимому аккумулятора А. Это позволяет реализовывать операцию перехода по заданному коду, эквивалентную оператору case в языке программирова- программирования Pascal, но намного быстрее (за два машинных цикла). Использование в этой команде указателя данных dptr позволяет размещать таблицу пе- переходов в любом месте памяти программ. Пример реализации команды выбора варианта: BeginOpCase: /Начало команды выбора вариантов MOV DPTR, #JMP_TBL /Задать начальный адрес таблицы адресов переходов MOV А, 33 ;В ячейке с адресом 33 хранится переменная, по /содержимому которой необходимо осуществить переход ;на обслуживающую программу CLR С RLC A JMP @A+DPTR /Осуществить арифметический сдвиг аккумулятора /вправо (умножить на 2) т.к. команды переходов /занимают два байта /Перейти к выполнению заданного в ячейке 33 кода 6 Зак. 328
154 Глава 6 /начало таблицы переходов по содержимому переменной в ячейке памяти 33 JMPJTBL: JMP CaseO /Перейти к выполнению кода по числу О JMP Casel ;Перейти к выполнению кода по числу 1 JMP EndCase ;Это число в ячейке 33 в список разрешенных не входит JMP EndCase ;Это число в ячейке 33 в список разрешенных не входит JMP Case4 /Перейти к выполнению кода по числу 4 Способы адресации операндов При определении способа адресации операндов в команде необходимо учитывать, что виды адресации для каждого операнда команды (источ- (источника или приемника) могут не совпадать. Неявная адресация. При неявной адресации регистр-источник или ре- регистр-приемник подразумевается в самом коде операции. Например: 03 RR А /Сдвинуть содержимое аккумулятора вправо D4 DA А /Произвести десятичную коррекцию результата суммирования Е8 MOV A, R0 ;В первом операнде использована неявная адресация, ;а во втором - регистровая Регистровая адресация используется для обращения к восьми рабочим регистрам выбранного банка рабочих регистров, а также для обращения к регистрам А, В, АВ (сдвоенному регистру), DPTR и к флагу переноса С. Номер регистра записывается в трех младших битах команды. На- Например: F8 MOV R0, А ;в первом операнде использована регистровая адресация, ;а во втором - неявная Прямая байтовая адресация используется для обращения к ячейкам внут- внутренней памяти (ОЗУ) данных (адреса 0:127) и к регистрам специального назначения (адреса 128 ... 256). Адрес ячейки памяти помещается во вто- второй байт команды. Например: Е520 MOV A, 20h ;во втором операнде использована прямая байтовая /адресация, а в первом - неявная 8D15 MOV 15h,R6 ;в первом операнде использована прямая байтовая /адресация, а во втором - регистровая Прямая битовая адресация используется для обращения к отдельно адре- адресуемым 128 битам, расположенным в ячейках с адресами 20Н—2FH, и к
Принципы работы микроконтроллеров 155 отдельно адресуемым битам регистров специального назначения. На- Например: D220 SETB 20h /использована прямая битовая адресация С215 CLR 15H ;использована прямая битовая адресация Косвенно-регистровая адресация используется для обращения к ячейкам внутреннего ОЗУ данных. В качестве регистров-указателей используются регистры RO, R1 выбранного банка регистров. Например: Еб MOV A,@R0 ;B первом операнде использована неявная адресация, ;а во втором — косвенно-регистровая F7 MOV @R1,A ;B первом операнде использована косвенно-регистровая /адресация, а во втором - неявная Косвенно-регистровая адресация используется также для обращения к внешней памяти данных. В этом случае с помощью регистров-указателей R0 и R1 (рабочего банка рабочих регистров) выбирается ячейка из блока 256 байт внешней памяти данных. Номер блока предварительно задается содержимым порта Р2. Е2 MOVX A,@R0 ;B первом операнде использована неявная адресация, ;а во втором - косвенно-регистровая F3 MOVX @R1,A ;B первом операнде использована косвенно-регистровая /адресация, а во втором - неявная Если в качестве регистра-указателя используется 16-разрядный указатель данных (dptr), to можно выбрать любую ячейку внешней памяти данных объемом до 64 Кбайт. (В некоторых моделях микроконтроллеров семей- семейства MSC-51 таким образом можно обращаться к внутренней памяти данных объемом более 256 байт). ЕО MOVX A,DPTR ;B первом операнде использована неявная адресация, ;а во втором - косвенно-регистровая FO MOVX DPTR,A ;B первом операнде использована косвенно-регистровая /адресация, а во втором - неявная Косвенно-регистровая адресация по сумме базового и индексного реги- регистров (содержимое аккумулятора А) упрощает просмотр таблиц, запи- записанных в памяти программ. Любой байт из таблицы может быть выбран по адресу, определяемому суммой содержимого dptr или рс и содержи- содержимого а, например: 83 MOVC A,0A+PC ;В первом операнде использована неявная адресация, ;а во втором - косвенно-регистровая 93 MOVC A,@A+DPTR ;B первом операнде использована неявная адресация, ;а во втором - косвенно-регистровая
156 Глава 6 Непосредственная адресация позволяет выбрать из адресного простран- пространства памяти программ константы, явно указанные в команде, например: 7414 MOV A, #14h ;B первом операнде использована неявная /адресация, а во втором - непосредственная 902048 MOV DPTR, #2048h ;B первом операнде использована неявная /адресация, а во втором - непосредственная Полный список команд микроконтроллеров семейства MCS-51, упоря- упорядоченный по коду команды, приведен в приложении, табл. ПЗ. Устройство параллельных портов микроконтроллеров MCS-51 Порты ввода-вывода Р0, PI, P2, РЗ являются квазидвунаправленными и обеспечивают обмен информацией между микроконтроллером и внеш- внешними устройствами, образуя 32 линии ввода-вывода. Каждый из портов содержит 8-разрядный регистр, имеющий байтовую и битовую адреса- адресацию для установки (запись логической 1) или сброса (запись логического 0) разрядов этого регистра с помощью программного обеспечения микро- микроконтроллера. Выходы этих регистров соединены с внешними выводами микросхемы. Все разряды параллельных портов устроены одинаково. Упрощенная схема одного разряда параллельного порта микроконтрол- микроконтроллера показана на рис. 6.2. Отличаются только выводы порта Р0, у кото- которых отсутствуют внутренние генераторы тока в верхней части схемы. Один разряд регистра-защелки порта представляет собой D-триггер, за- запись входных данных в который происходит по высокому уровню син- синхросигнала. На рис. 6.2 этот сигнал назван «запись в защелку». Сигнал с инвертирующего выхода триггера умощняется при помощи МОП- транзистора и поступает на внешний вывод микросхемы. Естественно, что внутреннее устройство порта намного сложнее приве- приведенного на рис. 6.2. Упрощение сделано для облегчения понимания ра- работы параллельных портов микроконтроллера. Желающие более под- подробно познакомиться с внутренним устройством параллельных портов микроконтроллера могут обратиться к техническому описанию конкрет- конкретной микросхемы. Внутренняя схема порта построена таким образом, чтобы максимально упростить подключение внешних устройств к микроконтроллеру. На- Например, умощняющий внешний транзистор может быть подключен не- непосредственно базой к выводу микроконтроллера без дополнительного
Принципы работы микроконтроллеров 157 токоограничивающего резистора, как показано на рис. 6.3. Это стано вится возможным благодаря внутреннему генератору тока. Чтение зящелки Внутр. шина Записьв защелку Чтение ВЫВОДИ т РХ.Х N UCC Внутренний генерятор токя РХ.Х ВЫВОД Рис. 6.2. Упрощенная схема одного бита параллельного порта Цепь Питание Питание Корпус Корпус Кокт +5В Ucc Uss U RST п Ucc Uss U Ublk XTAL2 XTAL1 RESET фЕА Ucci UCC2 Uss CPU +5В \у Рис. 6.3. Схема подключения светодиодных индикаторов к параллельному порту
158 Глава 6 Значение сигнала непосредственно с внешнего вывода порта считывается по сигналу «чтение вывода». Однако при выполнении операций с от- отдельными битами требуется считывать содержимое внутреннего регист- регистра-защелки порта. Если база биполярного транзистора непосредственно подключена к выводу порта, то считывание значения логической 1 с вы- вывода порта становится невозможным. Дело в том, что напряжение на р- n-переходе база-эмиттер транзистора не может превысить -0,7 В (для кремниевого транзистора). Такое напряжение однозначно будет воспри- воспринято цифровой схемой как логический ноль, поэтому при выполнении операций над отдельными битами параллельного порта считывание производится непосредственно с выхода регистра-защелки порта. При этом выход Q D-триггера подключается к внутренней шине (считыва- (считывается) по сигналу «чтение защелки». Чтение внешних выводов порта РЗ осуществляется командами: MOV А, РЗ /Скопировать состояние выводов порта РЗ в аккумулятор JB P3.4, Metka ;Если на выводе 4 порта РЗ логическая 1, то перейти на /метку Metka Чтение регистра-защелки осуществляется командами чтение-модифи- чтение-модификация-запись. Например: CPL РЗ. 1 ;Проинвертировать сигнал на выводе 1 порта РЗ ORL Р2, #56h /Установить единичный сигнал на выводах 1, 2, 4 и б порта Р2 ANL РЗ, #03h ;Установить нулевой сигнал на выводах 0 и 1 порта РЗ SETB РЗ. 1 ;Установить высокий потенциал на выводе 1 порта РЗ Порты микросхемы служат для управления внешними устройствами, подключенными к микроконтроллеру. Схема подключения простейших внешних устройств приведена на рис. 6.3. Он иллюстрирует особенности подключения светодиодных индикаторов к параллельным портам мик- микроконтроллера MCS-51. Присутствие в схеме порта выходного мощного транзистора позволяет подключать к выводам порта светодиодные индикаторы непосредствен- непосредственно, без усилителя мощности. Однако при этом необходимо следить за максимальной допустимой мощностью, рассеиваемой на микросхеме и отдельных выводах порта. Эквивалентная схема, на которой показан путь протекания выходного тока порта, приведена на рис. 6.4. Как видно из приведенной схемы именно выходной ток порта /о используется для зажигания светодиода. Для умощнения выводов порта можно применить транзисторный ключ, показанный также на рис. 6.3. Эта же схема используется при низко- низковольтном питании микроконтроллера. Напряжения 3,3 В недостаточно
Принципы работы микроконтроллеров 159 для получения стабильного и большого тока через светодиод. Обратите внимание, что база транзистора подключена непосредственно к выводу порта. Это стало возможным только благодаря использованию в схеме порта генератора тока в верхнем плече выходного каскада. +5В Внутренний генератор TOKaj о +5В ч/ R1 Внешний вывод микросхемы Рис. 6.4. Эквивалентная схема подключения светодиодного индикатора к параллельному порту Если выходного тока порта достаточно для открывания транзисторного ключа, то резистор R2 не используется. Этот резистор подключают для увеличения тока базы транзисторного ключа. На максимальное значение этого тока накладываются те же ограничения, что и для непосредствен- непосредственного подключения светодиодного индикатора к выводам порта. Рези- Резистор R3 рассчитывается исходя из допустимого тока через светодиод VD2. При возможности выбора напряжения питания для светодиодов лучше выбрать более высокое напряжение. Это позволит обеспечить бо- более равномерное свечение светодиодов, т. к. разброс параметров свето- светодиодов будет оказывать меньшее влияние на разброс значений токов, протекающих через них. Микроконтроллеры предназначены для управления внешними устройст- устройствами. Однако изменять напряжения на выводах параллельного порта микроконтроллера можно только при помощи программы, записанной в память программ. Какие напряжения необходимо подавать на выходы микросхемы, зависит от схемы подключения индикатора. В приведенной на рис. 6.3 схеме для зажигания светодиода VD1 в разряд 6 порта РО не- необходимо записать логический 0. Для зажигания светодиода VD2 необ- необходимо в разряд 7 порта Р2 записать логическую единицу, а для его га- гашения — логический ноль.
160 Глава 6 Чтобы изменять потенциалы на выводах микросхемы, можно воспользо- воспользоваться следующими командами с байтовой адресацией: 1. mov (пересылка), например: MOV Р1, #01110011Ь /Выдать на все восемь выводов Р1 число OlllOOlli MOV РЗ, А ;Выдать на все восемь выводов РЗ содержимое АСС 2. anl (логическое «И»), например: ANL Р1, #11110011b /выдать низкий потенциал на выводах Р1.2 и Р1.3 3. xrl (исключающее «ИЛИ»), например: XRL РЗ, #01000100Ь ;инвертировать состояние выводов РЗ.2 и РЗ . 6 4. orl (логическое «ИЛИ»), например: ORL Р1, #00001100b /выдать высокий потенциал на выводах Р1.2 и Р1. 3 Эти команды изменяют потенциал сразу на нескольких выводах порта. Для изменения потенциалов только на одном выводе микросхемы можно воспользоваться следующими командами с битовой адресацией: 1. mov (пересылка), например: MOV P1.2, С/выдать содержимое бита переноса через вывод 2 порта Р2 2. cpl (инверсия), например: CPL Р1.2 ;проинвертировать 2-й бит порта Р2 3. setb (установить бит), например: SETB Р2.3 ;выдать высокий потенциал на вывод 3 порта Р2 4. clr (сбросить бит), например: CLR Р2. 3 /выдать низкий потенциал на вывод 3 порта'Р2 При записи в разряд порта логического 0 выходной транзистор открыва- открывается и на выводе микросхемы появляется низкий потенциал, изменить который извне невозможно. Поэтому при опросе этого вывода порта микросхемы входная информация в этом случае всегда будет восприни- восприниматься как логический 0 независимо от состояния выходов внешних уст- устройств. Если в указанный разряд записать логическую 1, то выходной транзистор закрывается и на выводе микросхемы за счет генератора тока появляется высокий потенциал. Он может быть изменен извне на нулевой потенциал замыканием соответствующего вывода микросхемы на общий провод. В этом случае считываемое микроконтроллером значение бита будет соответствовать сигналу на выходе внешнего устройства. Поэтому перед тем как осуществить ввод информации по какому-либо выводу порта, соответствующий разряд необходимо настроить на ввод — запи- записать в него логическую единицу.
Принципы работы микроконтроллеров 161 По той же причине при настройке выводов порта на выполнение альтер- альтернативных функций в соответствующие разряды параллельного порта должны быть записаны логические I. Кроме работы в качестве обычных портов ввода-вывода внешние выво- выводы портов РО-РЗ могут выполнять ряд дополнительных (альтернатив- (альтернативных) функций. Порт РО может быть использован для организации части шины адреса и шины данных при работе микроконтроллера с внешней памятью данных или программ. При этом через него из микроконтроллера выводится младший байт адреса А0-А7, а также принимается в микроконтроллер или выдается из него байт данных. Во время чтения содержимого внеш- внешней памяти во все триггеры-защелки порта РО аппаратно записываются 1 (т. е. содержимое порта теряется). Кроме того, через порт РО передаются данные при программировании внутреннего ППЗУ, и читается содержи- содержимое внутренней памяти программ при работе с программатором. При сбросе микросхемы во все разряды порта РО записываются 1. У схе- схемы РО, в отличие от схем всех других портов, отсутствует внутренний ге- генератор тока. Поэтому при работе с этим портом приходится подклю- подключать внешние резисторы к плюсу источника питания. Формат и адрес порта РО приведены на рис. 6.5. На этом же рисунке при- приведены адреса отдельных битов порта РО в битовом пространстве. На рис. 6.6 приведена схема использования выводов портов РО и Р2 для под- подключения внешней памяти программ и внешней памяти данных. Адрес Ст. зн. порта разр. 080h Мл. зн. разр. A/D7 Р0.7 A/D6 Р0.6 A/D5 Р0.5 A/D4 Р0.4 A/D3 РО.З A/D2 Р0.2 A/D1 Р0.1 A/D0 РО.О РО 87h 86h 85h 84h 83h 82h 81 h 80h Рис. 6.5. Формат параллельного порта РО Порт Р1 может быть использован для чтения внутренней памяти про- программ или для передачи младшего байта адреса при программировании внутреннего РПЗУ. В младших моделях микроконтроллера семейства других альтернативных функций у порта Р1 нет. При сбросе микросхемы во все разряды порта записываются 1. Формат и адрес'порта Р1 приведены на рис. 6.7. На этом же рисунке при- приведены адреса отдельных битов порта Р1 в битовом пространстве.
О) Dl Ucc Uss U RST ФЁА RESET XTAL2 XTAL1 D2 CPU РО l 2 3 4 5 6 7 ALE P2 0 1 2 3 4 5 6 7 DO Dl _D2 D3 D4 1X5 D7 DO Dl D2 D3 D4 Pi D7 1 2 3 4 5 б 7 D3 Qo l 2 3 4 5 б 7 АО Al A2 A3 A4 Ai A6 A7 A8 A9 A10 All A12 A13 A14 Ali АО Al A2 A3 A4 Ai A6 A7 AS A9 A1O All A12 1 2 3 4 5 б 7 8 9 10 11 12 —6CS D4 ROM 1 2 3 4 5 6 7 DO Dl _D2 D3 D4 DJ D<5 D7 АО Al A3 A3 A4 A3 A6 A7 A8 AS A10 All A12 1 2 3 4 б 7 8 9 10 11 12 D5 RAM 1 2 3 4 б 7 DO Dl D2 D3 D4 D5 D6 D7 Рис. 6.6. Использование выводов портов РО и Р2 для подключения внешней памяти программ и внешней памяти данных Q) CD Q)
Принципы работы микроконтроллеров 163 Заметим, что этот порт в самых младших моделях микроконтроллеров альтернативных функций не имеет, а приведенные альтернативные функции относятся к микроконтроллерам с ядром MCS-52. Линии порта Р1 могут выполнять альтернативные функции только в том случае, если в соответствующие этим линиям разряды регистра записаны логические 1, иначе на линиях порта будет присутствовать логический 0 независимо от характера принимаемой или передаваемой информации. Адрес Ст. зн. Мл. зн. порта разр. разр. 090h I I I I I I I T2EX I T2 I P1 Р1.7 | Р1.6 | Р1.5 | Р1.4 | Р1.3 | Р1.2 I P1.1 | Р1.0 97h 96h 95h 94h 93h 92h 91 h 90h P1.0 T2 - внешний вход таймера/счетчика 2 P1.1 T2EX - вход управления перезагрузки/захвата таймера Рис. 6.7. Формат параллельного порта Р1 Порт Р2 может быть использован для передачи старшего байта адреса при программировании внутреннего ППЗУ и при чтении внутренней па- памяти программ. Через порт Р2 выводится старший байт адреса А8-А15 при работе с внешней памятью программ и внешней памятью данных (с 16-разрядным адресом). Во время доступа к внешней памяти содержимое регистра-защелки порта Р2 не изменяется. При сбросе микросхемы во все разряды порта записываются 1. Формат и адрес порта Р2 приведены на рис. 6.8. На рис. 6.6 приведена схема использования порта Р2 при под- подключении внешней памяти программ и внешней памяти данных. Адрес Ст. зн. порта разр. OAOh Мл. зн. разр. А15 Р2.7 А14 Р2.6 А13 Р2.5 А12 Р2.4 А11 Р2.3 А10 Р2.2 А9 Р2.1 А8 Р2.0 Р2 A7h A6h A5h A4h A3h A2h A1h AOh Рис. 6.8. Формат параллельного порта Р2 Порт РЗ. Каждая линия порта РЗ имеет индивидуальную альтернатив- альтернативную функцию, которая может быть задействована простым обращением к устройству, соединенному с выводом порта. Например, для того чтобы был выработан строб WR, достаточно обратиться с внешней памяти
164 Глава 6 командой movx @dptr, а или movx @R0f а. Линии порта РЗ могут выпол- выполнять альтернативные функции только в том случае, если в соответст- соответствующие этим линиям разряды регистра записаны логические I, иначе на линиях порта будет присутствовать логический 0 независимо от характе- характера принимаемой или передаваемой информации. При сбросе микросхемы во все разряды порта записываются 1. Формат и адрес порта РЗ приведе- приведены на рис. 6.9. Адрес Ст. зн. порта разр. OBOh Значение после сброса = 11111111В Мл. зн. разр. RD Р3.7 WR Р3.6 Т1 Р3.5 ТО Р3.4 INT1 РЗ.З INTO Р3.2 TxD Р3.1 RxD РЗ.О РЗ B7h РЗ.О RxD Р3.1 TxD Р3.2 INTO РЗ.З INT1 P3.4 IQ EZA II P3.6 WR P3.7 RQ B6h B5h B4h B3h B2h B1h BOh вход последовательного порта выход последовательного порта вход 0 внешнего запроса прерываний вход 1 внешнего запроса прерываний вход счетчика внешних событий О вход счетчика внешних событий 1 строб записи во внешнюю память данных строб чтения из внешней памяти данных Рис. 6.9. Формат параллельного порта РЗ Особенности построения памяти микроконтроллеров семейства MCS-51 Микроконтроллеры семейства MCS-51 построены по гарвардской архи- архитектуре. Это означает, что память данных и память программ в этих микросхемах разделены и имеют отдельные адресные пространства. В этих микроконтроллерах имеется три адресных пространства: памяти программ, внешней памяти данных и внутренней памяти. Такое построе- построение памяти позволяет удвоить доступное адресное пространство внеш- внешней памяти. Кроме того, построение памяти по гарвардской структуре позволяет в ряде случаев увеличить быстродействие микросхем. Для микроконтроллеров особенно важным является то обстоятельство, что не существует команд, способных осуществить запись данных в память программ и тем самым испортить управляющую программу.
Принципы работы микроконтроллеров 165 Схема подключения внешних микросхем памяти к микроконтроллерам семейства MCS-51 приведена на рис. 6.6. Регистр адреса D3 на этой схеме предназначен для запоминания младших восьми битов адреса, переда- передаваемых через шину данных/адреса, совмещенную с портом РО. Старшие 8 битов адреса передаются через шину адреса, совмещенную с портом Р2. Во время передачи адреса через порт РО микроконтроллер вырабатывает синхроимпульс на выводе ALE. Именно этот импульс позволяет запом- запомнить младший байт адреса в регистре D3 и тем самым организовать 16- разрядную шину адреса внешней памяти. При обращении к памяти данных и к памяти программ используются одни и те же шина адреса и шина данных, но разные управляющие сиг- сигналы. Для чтения памяти программ вырабатывается сигнал PSEN, а для чтения памяти данных — сигнал RD. Для записи информации в память данных вырабатывается сигнал WR. Именно эти управляющие сигналы и разделяют память микроконтроллера на память программ и память данных. То есть память программ доступна только для чтения, а память данных доступна и для чтения, и для записи любой информации, запи- записанной в двоичном коде. Память программ микроконтроллеров MCS-51 Память программ предназначена для хранения программ и имеет от- отдельное от памяти данных адресное пространство объемом 64 Кбайт, причем у некоторых микросхем (например, КР1816ВЕ51, КМ1819ВЕ751, КР1830ВЕ51) для хранения управляющих программ на кристалле микро- микроконтроллера расположено ПЗУ. Это ПЗУ отображается в область млад- младших адресов памяти программ. Поскольку выполнение программы после сброса микроконтроллера всегда начинается с нулевого адреса памяти программ, при включении питания начнет выполняться программа, за- записанная во внутреннем ПЗУ микроконтроллера. Микроконтроллеры, не имеющие внутреннего ПЗУ (например, КР1816ВЕ31 и КР1830ВЕ31), могут работать только с внешней микросхемой ПЗУ ем- емкостью до 64 Кбайт (при использовании портов PI и РЗ в качестве рас- расширителя адреса объем подключаемой ПЗУ может быть увеличен до I Гбайт). Микроконтроллеры семейства MCS-51 имеют внешний вывод ЕА, с по- помощью которого можно запретить работу внутренней памяти, для чего необходимо подать на вывод ЕА логический 0 (соединить этот вывод с общим проводом). При этом внутренняя память программ отключается
166 Глава 6 и, начиная с нулевого адреса, все обращения происходят к внешней па- памяти программ. Доступ к внешней памяти программ осуществляется в двух случаях: 1. При действии сигнала ЕА = 0 независимо от адреса обращения. 2. В любом случае, если программный счетчик (PC) содержит число большее, чем максимальный адрес внутренней памяти программ. Распределение памяти программ микроконтроллера КР1830ВЕ51 пред- представлено на рис. 6.Ю. На этом рисунке объем внутренней памяти приве- приведен для микроконтроллеров 1816ВЕ751. У других микросхем этого се- семейства он может оказаться другим, и соответственно будет иначе проходить граница между внутренней и внешней памятью программ. Количество доступных векторов прерываний тоже зависит от конкрет- конкретного типа микроконтроллера. 4095 35 0 65535 4096 Внешня* ч память программ Внутренняя память программ ЕА-1 Векторы прерывания OFFFFh 01000h Внешняя память программ ЕА-1 Векторы прерывания OFFFh 0023h OOOOh Рис. 6.10. Распределение памяти программ микроконтроллеров КР1830ВЕ751 Адреса векторов прерываний и соответствующие им аппаратные источ- источники прерываний для микроконтроллеров АТ89с52 приведены в табл. 6.3. Векторы прерываний и принципы работы с этими особыми ячейками памяти программ будут рассмотрены позднее. Таблица 6.3. Адреса векторов прерываний Адрес вектора прерывания оооон Флаги, вызывающие прерывание —— Источник прерывания Рестарт (сброс) контроллера RESET
Принципы работы микроконтроллеров 167 Таблица 6.3 (окончание) Адрес вектора прерывания 0003Н ооовн 0013Н 001ВН 0023Н 002ВН Флаги, вызывающие прерывание IE0 TF0 IE1 TF1 RI.TI TF2, EXF2 Источник прерывания Внешнее прерывание INTO Таймер 0 Внешнее прерывание INT1 Таймер 1 Последовательный порт Таймер 2 Сейчас разработано огромное количество микросхем, принадлежащих к этому семейству микросхем, у многих из них есть дополнительные векто- векторы прерываний. Для получения сведений об этих векторах прерываний необходимо обратиться к техническим описаниям соответствующих микроконтроллеров. Принципы работы с основными и с дополнитель- дополнительными векторами прерываний ничем не отличаются. Для чтения памяти программ используются команды с мнемоническим обозначением movc. Например: MOVC A, A+@DPTR ;Считать байт из памяти программ по адресу, вычисляемому ;как сумма содержимого регистров аккумулятора и DPTR MOVC А, А+@РС ;Считать байт из области памяти программ, начинающейся за ;данной командой Внешняя память данных микроконтроллеров MCS-51 Внешняя память данных предназначена для временного хранения ин- информации, используемой в процессе выполнения программы. Эта память физически должна быть подключена к микроконтроллеру при помощи схемы, изображенной на рис. 6.6. Максимальный объем этой памяти определяется регистром DPTR и составляет 64 Кбайт. Адресное простран- пространство памяти данных показано на рис. 6.11. Точно так же, как и в случае внешней памяти программ, объем доступной внешней памяти данных может быть увеличен за счет использования портов PI и РЗ до I Гбайт. Внешняя память данных для своей работы требует использования пор- портов РО, Р2 и РЗ. Это приводит к увеличению габаритов устройства, росту уровня помех и, в конечном итоге, удорожанию устройства в це-
168 Глава 6 лом. Поэтому в современных устройствах внешняя память обычно не используется. Однако в некоторых микроконтроллерах (таких как 87с550 фирмы Dallas или ADuC834 фирмы Analog Devices) команды обращения к внешней памяти используются для работы с дополнительной внутренней памятью большого объема. Для обращения к внешней памяти данных служат команды, использую- использующие 16-разрядный регистр адреса DPTR: MOVX A, 0DPTR /команда чтения MOVX @DPTR, А /команда записи Иногда для того, чтобы сохранить Р2 в качестве параллельного порта, для обращения к внешней памяти данных применяют команды, исполь- использующие 8-разрядные регистры адреса R0 или R1: MOVX A, @R0 /команды MOVX A, @R1 /чтения MOVX @R0, A MOVX @R1, A /команды ;записи 65535 OFFFFh 00100h OOOFF h OOOOOh Рис. 6.11. Адресное пространство внешней памяти данных В этом случае адресное пространство внешней памяти данных уменьша- уменьшается до размеров страницы 256 байт, как это показано на рис. 6.11. Отметим, что в качестве внешней памяти данных могут быть использо- использованы как микросхемы ОЗУ, так и микросхемы ПЗУ. В последнем случае
Принципы работы микроконтроллеров 169 соответствующая область памяти данных будет доступна только для чтения. Это необходимо учитывать при написании программы микро- микроконтроллера. Внутренняя память данных микроконтроллеров MCS-51 Несмотря на то, что внутренняя память данных имеет самое маленькое адресное пространство из рассматриваемых, оно устроено наиболее сложным образом. Распределение памяти данных микроконтроллеров серии MCS-51 приведено на рис. 6.12. Внутреннее ОЗУ данных предназначено для временного хранения ин- информации, используемой в процессе выполнения программы, и занимает 128 младших байтов, с адресами от OOOh до 07Fh для микроконтроллеров 8051, 8031, КР1816ВЕ31, КР1816ВЕ51, КР1816ВЕ751 КР1830ВЕ31, КР1830ВЕ51, КР1830ВЕ751 или 256 8-разрядных ячеек с адресами от OOOh до OFFh для всех остальных микроконтроллеров семейства. Регистры специальных функций занимают адреса внутренней памяти данных с 080h no OFFh. Так как адреса регистров специальных функций совпадают со старшими адресами внутреннего ОЗУ данных, то имеются особенности их использования. Система команд микроконтроллера позволяет обращаться к ячейкам внутренней памяти данных при помощи прямой и косвенно-регистровой адресации. Обращение к ячейкам памяти с адресами 0-127 @-7Fh) про- происходит с использованием любого из этих видов адресации и будет про- производить выборку одной и той же ячейки памяти. При обращении к ячейкам ОЗУ с адресами 128 @80h)-256 (OFFh) следует воспользоваться косвенно-регистровой адресацией. Учитывая, что работа со стеком ве- ведется при помощи косвенной адресации, а сам стек растет вверх, имеет смысл размещать в этой области памяти стек. Само понятие стека и осо- особенности его использования будут рассмотрены позднее. Если же требу- требуется обратиться к регистрам специальных функций, то нужно использо- использовать прямую адресацию. Например: MOV A, 80h /Скопировать сигналы с внешних выводов порта РО ;в аккумулятор MOV R0, #8Oh /Скопировать в аккумулятор содержимое MOV A, @R0 /ячейки внутреннего ОЗУ с адресом 80h
170 Глава 6 Десятичный адрес ячейки 255 128 127 48 47 32 31 25 24 16 15 08 07 00 Регистры специальных функций SFR (прямая адресация) ОЗУ (прямая и косвенная адресация) 127 126 125 124 | 123 122 121 Битовое пространство 7 6 5 4 I 3 2 1 RB3(PSW=18h) RB2(PSW=10h) RB1 (PSW=08h) RBO (PSW=00h) 120 4 0 R7'" RO1" R7" R0" R7' R01 R7 RO Шестнадцатеричный адрес ячейки ОЗУ (косвенная адресация) FFh 80h 7Fh 30h 2Fh Адрес оитовои ячеи1 памяти (флага) 20h <и 1Fh 18h 17h 10h OFh 08h 07h OOh Рис. 6.12. Адресное пространство внутренней памяти данных Регистры общего назначения позволяют писать самые эффективные программы. У микроконтроллеров семейства MCS-51 для программи- программирования доступны восемь регистров. Более того, в этом семействе микроконтроллеров есть четыре набора (банка) регистров с именами RB0-RB3. Для сравнения такие мощные процессоры, как «электроника- 79» и SPARC, обладают всего двумя наборами регистров. Банк регист- регистров состоит из восьми 8-разрядных регистров с именами RO, R1, ..., R7. Несколько банков регистров служат для организации независимой ра- работы нескольких параллельно выполняемых программных потоков. Переключение банков регистров производится при помощи двух осо- особых битов, входящих в состав регистра слова состояния программы PSW (биты RS0 и RSI). Если организация нескольких параллельных потоков обработки данных не нужна, то можно пользоваться только нулевым банком регистров, включающимся автоматически после пода- подачи питания и сброса микроконтроллера, остальные ячейки памяти ис- использовать как обычное ОЗУ. Все четыре банка регистров объединены с 32 младшими байтами внут- внутреннего ОЗУ данных (см. рис. 6.12). Так как физически регистры и
Принципы работы микроконтроллеров 171 ячейки внутреннего ОЗУ объединены, то команды программы могут обращаться к регистрам, используя или их имена R0-R7 (регистровая адресация): MOV A, R0 /Скопировать содержимое регистра R0 в аккумулятор MOV R7, А /Скопировать содержимое регистра R7 в аккумулятор или их адрес во внутренней памяти данных (прямая байтовая адресация): MOV А, 0 /Скопировать содержимое нулевой ячейки ОЗУ в аккумулятор MOV 7, А /Скопировать содержимое аккумулятора в седьмую ячейку ОЗУ Следующие после банков регистров 16 ячеек внутреннего ОЗУ данных (ад- (адреса 20H-2FH) образуют область памяти, к которой возможна как бай- байтовая, так и битовая адресация. В этих ячейках располагаются 128 про- программных флагов (битовых ячеек памяти). Обращение к отдельным би- битам этих ячеек возможно по их битовым адресам. Например, команды: SETB 15 /Запомнить во флаге 15 логическую единицу JB 15, Metka ;Если во флаге 15 записана логическая единица, то перейти ;по адресу Metka обращаются к флагу 15, расположенному в старшем бите байтовой ячей- ячейки памяти 21 h. Использование однобитовых ячеек памяти позволяет со- сократить необходимый для работы программы объем памяти данных, т. к. для хранения битовых переменных выделяется один бит в памяти данных, а не машинное слово, как это делается в универсальных микро- микропроцессорах (компьютерах). В битовой области сосредоточено только 128 флагов. Битовая адресация возможна также в области регистров специальных функций (см. табл. 6.4). Наиболее яркий пример использования битовой адресации в данной области — это обращение к отдельным выводам параллельных портов: CPL 92 ;Проинвертировать второй бит порта Р1 Выше адреса 128 @80h) располагаются регистры специальных функций, которые будут рассмотрены позже. Некоторые из регистров специаль- специальных функций допускают битовую адресацию к каждому из восьми своих битов. Оставшаяся область внутренней памяти данных используется как обычное ОЗУ, без особенностей. Следует отметить, что в современных микроконтроллерах данного се- семейства эту память следует рассматривать как встроенные 256 регистров сверхоперативного ОЗУ. Основной памятью постепенно становится внутренняя память микроконтроллера, доступная при помощи команд MOVX 0DPTR, А.
172 Глава 6 Регистры специальных функций Адреса внутренней памяти данных с 080h no OFFh используются регист- регистрами специальных функций. Они принадлежат дополнительным устрой- устройствам, расположенным на кристалле микроконтроллера, регистры кото- которых отображаются в адресное пространство внутренней памяти данных. В различных микросхемах семейства MCS-51 состав дополнительных устройств различается. Микроконтроллеры рассматриваемого семейства различаются между собой количеством параллельных портов, последо- последовательных портов, таймеров. Некоторые из регистров специальных функций с указанием их адресов в адресном пространстве SFR внутрен- внутреннего ОЗУ приведены в табл. 6.4. Таблица 6.4. Адреса регистров специальных функций во внутренней памяти данных и их значения после сброса F8 F0 Е8 ЕО D8 DO С8 СО В8 ВО А8 АО 98 90 80 В 00000000 АСС 00000000 PSW 00000000 T2CON 00000000 IE хооооооо ?3 11111111 ш 00000000 Р2 11111111 SCON 00000000 ?1 11111111 TCON 00000000 РО 11111111 Битовая адресация T2MOD 00000000 SADEN 00000000 SADDR 00000000 SBUF хххххххх TMOD 00000000 SP 00000111 RCAP2L 00000000 ты 00000000 DPL 00000000 RCAP2H 00000000 TL1 00000000 DPH 00000000 TL2 00000000 тно 00000000 ТН2 00000000 ТН1 00000000 PCON ооххоооо FF F7 EF Е7 DF D1 CF С7 BF В7 AF А8 9F 97 8F 87
Принципы работы микроконтроллеров 173 Примечание 1. Регистры, выделенные жирным подчеркнутым текстом, присутствуют во всех микросхемах семейства. 2. Регистры, выделенные жирным текстом, присутствуют в микросхемах с ядром 8052. 3. X — неопределенное состояние. Внутренние таймеры микроконтроллера, особенности их применения В базовых моделях семейства (ядро MCS-51) имеются два программи- программируемых 16-битных таймера/счетчика (Т/СО и Т/С1), которые могут быть использованы и как таймеры, и как счетчики внешних событий. Каждый из них состоит из двух 8-битных регистров ТНО (старший байт) и ТНО (младший байт) для таймера 0 или ТН1 (старший байт) и ТН1 (младший байт) для таймера 1. При переполнении таймеров производится запись логической единицы в дополнительный триггер (флаг) TF0 для таймера 0 nnnTFl для таймера 1. В старших моделях рассматриваемого семейства микроконтроллеров по- появляется еще один, причем более удобный, таймер Т2. Но рассмотрение принципов работы этого таймера не входит в задачу данной книги. В режиме таймера содержимое соответствующего таймера/счетчика ин- крементируется в каждом машинном цикле, т. е. через каждые 12 перио- периодов колебаний кварцевого резонатора. Таймер 0 и Таймер 1 могут работать в четырех режимах: ? режим 0: 13-битный таймер; ? режим 1: 16-битный таймер; ? режим 2: 8-битный таймер с автоматической перезагрузкой; ? режим 3: Таймер 0 как 2 раздельных 8-битных таймера. В режиме счетчика содержимое соответствующего таймера/счетчика ин- крементируется (увеличивается на единицу) под воздействием перехода из 1 в 0 внешнего входного сигнала, подаваемого на вывод микрокон- микроконтроллера ТО или Т1. Так как на распознавание периода требуются два машинных цикла, то максимальная частота подсчета входных сигналов
174 Глава 6 равна 1/24 частоты резонатора. На максимальную длительность периода входных сигналов ограничений нет. Для гарантированного обнаружения перехода уровень входного сигнала не должен изменяться как минимум в течение одного машинного цикла микроЭВМ. Кроме того, таймер 1 можно использовать для задания скорости обмена последовательного порта, работающего в режиме с настраиваемой ско- скоростью работы. Для управления режимами работы таймеров используется регистр TMOD (Timer — таймер, MODe — режим). Его формат приведен на рис. 6.13. Каждая тетрада регистра TMOD управляет своим таймером. Рассмотрим режимы работы внутренних таймеров более подробно. Адрес Ст. зн. разр. 89Н [GATE Значение после сброса = 00000000В Мл. зн. разр. С/Т М1 МО ¦Таймер 1 GATE М1 МО •Таймер О TMOD Символ Функция GATE Управление блокировкой. Когда установлен, Таймер/Счетчик 0 или 1 разрешен только тогда, когда на выводе INTO или INT1 высокий уровень и бит управления TR0 или TR1 установлен. Когда сброшен, Таймер/Счетчик 0 или 1 разрешается только тогда, когда бит управления TR0 или TR1 устанавливается СЛГ Бит выбора режима Таймера или Счетчика. Режим Таймера включается при СЛГ = 0 (синхронизация от внутренних импульсов синхронизации). Режим Счетчика включается при СЛГ = 1 (синхронизация от внешнего сигнала на выходе ТО и Т1) М1 МО Режим работы О 0 8-битный Таймер/Счетчик (ТНх), TLx как 5-битный предделитель 0 1 16-битный Таймер/Счетчик 1 0 8-битный автоперезагружаемый Таймер/Счетчик. ТНх содержит значение, которое загружается в TLx каждый раз, когда он переполняется 1 1 (Таймер 1). Таймер/Счетчик останавливается Рис. 6.13. Формат регистра выбора режимов таймеров (TMOD)
Принципы работы микроконтроллеров 175 Режим О В режиме 0 таймер работает как 13-битный счетчик, состоящий из 8 би- битов регистра ТНх и младших 5 битов регистра TLx. Заметим, что «х» в обозначении регистра заменяется на 0 или 1 в зависимости от номера таймера, которым мы управляем в данный момент. Состояния старших 3 битов регистров TLx в режиме 0 не определены и они игнорируются. Установка запускающего таймер флага TR0 или TR1 не очищает эти ре- регистры. Работе таймера 0 или таймера 1 в режиме 0 соответствует схема, приведенная для ТО на рис. 6.14. Флаг прерывания таймера TFx устанав- устанавливается (принимает значение логической 1) при изменении содержимого счетчика из состояния все 1 в состояние все 0, т. е. при переполнении. TL0 тно TF0 5 разрядов 8 разрядов От схемы «ям управления Рис. 6.14. Схема таймера ТО, работающего в режиме О Этот режим был введен для совместимости с устаревшим семейством микроконтроллеров MCS-48, чтобы облегчить перенос уже разработан- разработанных программ на новые процессоры, и поэтому в настоящее время не ис- используется. Тем не менее, в этом режиме можно обеспечить формирова- формирование одиночного интервала времени длительностью до 8096 мс при частоте задающего генератора 12 МГц. Обычно пользователя интересует не максимальный интервал времени, а некоторый конкретный временной промежуток. Для уменьшения интер- интервала времени в регистры таймера можно предварительно занести число и тем самым сформировать промежуток времени нужной длительности. Рассмотрим пример подготовки таймера ТО для формирования времен- временного интервала 5мс: /Настроить режим работы таймера MOV TMOD,#00000000Ь ;настроить таймеры ТО и Т1 на нулевой режим работы I I I I I I I I ||||||++ Перевести таймер ТО в 13-разрядный режим I I I I I I работы ; | | | | |+ Синхронизироваться от внутреннего генератора ; | | | | + Запретить управление таймером от ножки INTO
176 Глава 6 ; I I++ Перевести таймер Т1 в 13-разрядный режим ; || работы ; |+ Синхронизироваться от внутреннего генератора ; + Запретить управление таймером от вывода INT1 ;Настроить таймер на генерацию 5-миллисекундного интервала времени MOV TH0, #HIGH(-5000) ;Загрузить старший байт таймера MOV TLO, #LOW(-5000) ;Загрузить младший байт таймера В рассмотренном исходном тексте программы используется двоичное представление управляющей константы. Это позволяет показать каждый отдельный бит константы, тем более, что разные биты управляют раз- различными узлами таймера. Для того чтобы программа была более понят- понятной, в комментарии поясняется назначение отдельных битов константы. В исходном тексте программы, особенно при написании его под Windows, невозможно использовать символы псевдографики, поэтому для указания, к какому же из битов константы относится комментарий, используются символы «-» и «|». Для перехода от горизонтальной черты к вертикальной используется символ «+». В случае, когда для управления блоком таймера требуется несколько битов константы, в одной строке может быть использовано несколько символов «+». При настройке таймера требуется загрузить 16-битную константу в счет- счетчик таймера. Однако в системе команд микроконтроллера существуют только команды загрузки 8-битной константы. Для расщепления 16- битной константы на два отдельных байта в приведенном участке про- программы были использованы операторы выделения старшего и младшего байта HIGH и LOW соответственно. Эти функции присутствуют в боль- большинстве языков программирования ассемблера, предназначенных для микроконтроллеров MCS-51. Если же язык программирования не содер- содержит в своем составе подобные функции, то можно для выделения байтов воспользоваться операцией деления на 256: MOV TH0, #-5000/256 /Загрузить старший байт константы ;в старший байт таймера MOV TL0, #-E000-5000/256) /Загрузить младший байт константы ;в младший байт таймера Режим 1 В режиме I таймер работает как 16-разрядный счетчик. Этот режим по- похож на режим 0, за исключением того, что в регистрах таймера использу- использует все 16 битов. В этом режиме регистры ТНх и TLx также включены по-
TLO THO TFO Принципы работы микроконтроллеров 177 следовательно друг за другом. Работе таймера ТО или таймера Tl в ре- режиме I соответствует схема, приведенная на рис. 6.15. На этой схеме изо- изображен таймер ТО. 8 разрядов 8 разрядов От схемы ¦M0I управления Рис. 6.15. Схема таймера ТО, работающего в режиме 1 В этом режиме можно обеспечить формирование интервала времени длительностью до 65536 мкс при частоте задающего генератора 12 МГц. Рассмотрим пример использования таймера ТО для формирования вре- временного интервала 15мс. /Настроить режим работы таймера MOV TMOD,#00000001Ь /перевести таймер ТО в режим 1, а Т1 - в режим О ММ!I++ Перевести таймер ТО в 16-разрядный режим ММ 1+ Синхронизироваться от внутреннего генератора ||||+ Запретить управление таймером от вывода INTO I | ++ Перевести таймер Т1 в 13-разрядный режим |+ Синхронизироваться от внутреннего генератора + Запретить управление таймером от вывода INT1 г I I I /Настроить таймер на генерацию 15-миллисекундного интервала времени MOV THO, #HIGH(-15000) /Загрузить старший байт константы в старший байт / таймера MOV TLO, #LOW(-15000) /Загрузить младший байт константы в младший байт /таймера OjidanTimer: JNB TF0, OjidanTimer /Подождать пока не переполнится таймер В рассмотренном примере переполнение таймера произойдет через 15000 циклов процессора, т. е. при частоте тактового генератора микро- микроконтроллера, равной 12 МГц, через 15 мс. Программа будет постоянно проверять состояние флага переполнения таймера и, как только он уста- установится в единицу, перейдет к выполнению следующей команды. Это не самый лучший вариант использования таймера, но для иллюстрации его настройки для работы в режиме 1 вполне подходит.
178 Глава 6 Режимы 0 и I таймеров ТО и Tl предназначены для формирования оди- одиночного интервала времени. Если требуется формировать периодиче- периодическую последовательность интервалов времени, то надо обеспечить про- программную загрузку регистров ТНО и TL0 для задания нужного интервала времени, что для коротких интервалов времени может привести к значи- значительным затратам процессорного времени. Для формирования последовательности одинаковых интервалов времени используется режим работы таймера с перезагрузкой — режим 2. Режим 2 В режиме 2 регистр таймера TL0 работает как 8-битный суммирующий счетчик с автоматической перезагрузкой начального значения из регист- регистра ТНО. Переполнение счетчика TL0 не только устанавливает флаг TF0, но и снова загружает регистр TL0 содержимым ТНО. Перезагрузка тай- таймера не изменяет содержимое регистра ТНО. Для задания периода временных интервалов в регистр ТНО записывается отрицательное число. Работе таймера 0 или таймера 1 в режиме 2 соот- соответствует схема, приведенная на рис. 6.16. При этом первый период ко- колебания будет произвольным, но в большинстве случаев это не важно. Если же первый период колебания важен, то кроме регистра ТНО необ- необходимо программно устанавливать значение регистра ТН1. От схемы управления Рис. 6.16. Схема таймера ТО, работающего в режиме 2 Ниже приведен пример инициализации таймера в режиме 2 для генера- генерации прямоугольного колебания с частотой 10 кГц (период 100 мкс) и скважностью 2. /Настроить режим работы таймера MOV TMOD, #00000010Ь /перевести таймер ТО во режим 2, а Т1 в режим О I ! I
Принципы работы микроконтроллеров ; ММ!I++ Перевести таймер ТО в режим 8-разрядного ; МММ таймера с автозагрузкой ; ММ!+ Работа от внутреннего генератора ; ММ + Запретить управление таймером от вывода INTO I |++ Перевести таймер Т1 в 13-разрядный режим ; | + Работа от внутреннего генератора ; + Запретить управление таймером от вывода INT1 179 /Настроить таймер на генерацию 50-микросекундного интервала времени- MOV ТНО, #-50 ;Загрузить константу в старший байт таймера MOV TL0, #-50 /Загрузить константу в младший байт таймера OjidanTimer: JNB TFO, OjidanTimer /Подождать пока не переполнится таймер CPL P2.6 ;Проинвертировать сигнал на выводе 6 порта Р2 SJMP OjidanTimer ;Снова перейти к ожиданию окончания временного /интервала Режим 3 Таймер 1 при работе в режиме 3 просто хранит свое значение. Эффект такой же, как при сбросе бита TR1. Таймер 0 в режиме 3 представляет собой два раздельных 8-битных счетчика (регистры TL0 и ТНО). Регистр TL0 использует биты управления таймера 0: С/ТО, GATE0, TR0 и TF0. Регистр ТНО работает тоже в режиме отдельного таймера и использует биты TR1 и TF1 таймера 1. Логика работы таймера 0 в режиме 3 показа- показана на схеме, приведенной на рис. 6.17. От схемы управления TL0 TF0 Fr/12 ТНО TF1 Рис. 6.17. Логика работы таймера 0 в режиме 3
180 Глава 6 Работа таймера TL0 разрешена, если бит TR0 = I, а таймера ТНО — если 6htTR1 = I. Таймер I при работе таймера 0 в режиме 3 постоянно вклю- включен, т. к. он обычно при этом используется для синхронизации последо- последовательного порта и работает в первом или втором режимах работы. Этот режим работы позволяет реализовать два независимых таймера, если таймер I используется для работы последовательного порта. Но на- надо сказать, что на практике, особенно после появления таймера 2 в ядре MCS-52, режим 3 мало интересен. Управление таймерами/счетчиками Схема управления таймерами 0 и I идентична и для таймера ТО приведе- приведена на рис. 6.18. Для схемы управления таймером Т1 изменятся только номера управляющих битов (в их наименованиях 0 будет заменен на 1). В приведенной схеме заштрихованным прямоугольником обозначены внешние выводы микросхемы микроконтроллера. 12МГц 1мкС INT0 Х/////А к таймеру Рис. 6.18. Схема управления таймерами Из схемы видно, что таймер может включаться и выключаться битами TRx. Таким образом, можно уменьшать ток потребления микросхемы и уровень помех, создаваемый ею. Счетчики таймеров переключаются на высокой частоте, поэтому они могут потреблять до половины от общего тока потребления микроконтроллера. Следует отметить, что при вклю- включении и после сброса микроконтроллера работа таймеров запрещена. Есть возможность управлять работой таймера извне при помощи внеш- внешнего вывода ТО — для таймера ТО или Tl — для таймера Tl. Чтобы раз- разрешить передачу сигнала Тх, необходимо записать в бит GATEx логиче- логическую единицу (не забыв при этом разрешить работу таймера при помощи бита TRx).
Принципы работы микроконтроллеров 181 Кроме того, таймер может работать от внешнего генератора. Для этого в бит управления С/Т нужно записать логическую единицу. Биты включения таймеров TR0 и TR1 размещены в регистре управления таймерами TCON, а биты GATE и С/Т — в регистре режима таймеров TMOD. Название регистра TCON образовалось при соединении двух слов: Timer — таймер и CONtrol — управлять. Формат регистра TCON рассматривался ранее, а формат регистра TCON и описание его отдель- отдельных битов приведен на рис. 6.19. Адрес Ст. зн. разр. 88Н Мл. зн. разр. TF1 TCON.7 TR1 TCON.6 TF0 TCON.5 TR0 TCON.4 IE1 TCON.3 IT1 TCON.2 IE0 TCON.1 IT0 TCON.0 TCON 8Fh 8Eh 8Dh 8Ch 8Bh 8Ah 89h 88h Символ Функция TF1 Флаг переполнения таймера 1. Устанавливается аппаратно при переполнении Таймер/Счетчика 1. Сбрасывается аппаратно, когда процессор вызывает программу обслуживания прерывания TR1 Бит управления таймером 1. Устанавливается/сбрасывается программно для запуска/останова счетчика/таймера 1 TF0 Флаг переполнения таймера 0. Устанавливается аппаратно при переполнении Таймер/Счетчика 0. Сбрасывается аппаратно, когда процессор вызывает программу обслуживания прерывания TR1 Бит управления таймером 0. Устанавливается/сбрасывается программно для запуска/останова счетчика/таймера 0 IE1 Флаг прерывания 1. Устанавливается аппаратно, когда детектируется сигнал внешнего прерывания (перепад или активный уровень). Сбрасывается аппаратно в процессе прерывания только в том случае, если оно произошло по фронту IT1 Бит управления типом прерывания 1. Устанавливается/сбрасывается программно для определения типа прерывания 1 (по срезу/низким уровнем) IE0 Флаг прерывания 0. Устанавливается аппаратно, когда детектируется сигнал внешнего прерывания (перепад или активный уровень). Сбрасывается аппаратно в процессе прерывания только в том случае, если оно произошло по фронту IT0 Бит управления типом прерывания 0. Устанавливается/сбрасывается программно для определения типа прерывания 0 (по срезу/низким уровнем) Рис. 6.19. Формат регистра TCON
182 Глава 6 Кроме того, схема управления таймерами интересна тем, что позволяет использовать таймеры в качестве измерителей длительности импульсов и частотомеров. Рассмотрим эту возможность подробнее. Использование таймера в качестве измерителя длительности импульсов Известно, что измерение длительности импульса можно произвести, под- подсчитав импульсы эталонной частоты. Принцип измерения длительности импульсов иллюстрируется временной диаграммой, приведенной на рис. 6.20. Например, если за время длительности импульса на вход счет- счетчика таймера поступят 15 микросекундных импульсов, то длительность измеренного входного импульса равна 15 мкс. Измеряемый импульс /\ Опорный сигнал Подсчитываемые импульсы Рис. 6.20. Временная диаграмма измерения длительности импульсов Для измерения длительности импульса измеряемый сигнал подается на вывод микроконтроллера INTx, и в бит управления GATE записывается разрешающий сигнал логической единицы. Таймер/счетчик настраивает- настраивается в режим таймера записью в бит С/Тх логического нуля. Содержимое таймера перед измерением длительности импульса обнуляется. Ассемб- Ассемблерный текст процедуры измерения длительности импульса приведен в листинге 6.1. Листинг 6.1, Процедура измерения длительности импульса MOV TMOD,#00001001b ; М М М М ; I I I I I I++ Перевести таймер ТО в 16-разрядный режим ; I I I I |+ Работать от внутреннего генератора /ММ + Включать таймер от вывода микроконтроллера INTO
Принципы работы микроконтроллеров ; | | ++ Перевести таймер Т1 в 13-разрядный режим .[+ Работать от внутреннего генератора . + Запретить управление таймером от вывода INT1 183 MOV ТНО, #0 MOV TL0, #0 ;Обнулить старший байт таймера /Обнулить младший байт таймера SETB TR0 /Включить измеритель ширины импульса TstLogO: JNB INTO, TstLogO /Подождать начало импульса TstLogl: JNB INTO, TstLogl /Подождать конец импульса CLR TR0 /Отключить измеритель ширины импульса Если теперь на вход микроконтроллера INTO подать импульс с неизвест- неизвестной длительностью, то в регистрах ТНО и TL0 будет записана его дли- длительность в микросекундах. Использование таймера в качестве частотомера Известно, что измерение частоты можно произвести, подсчитав количе- количество периодов неизвестной частоты за единицу времени. Принцип изме- измерения частоты иллюстрируется рис. 6.21. Например, если за I мс на вход счетчика таймера поступят 15 импульсов, то измеренная частота равна 15 кГц. Эталонный импульс Измеряемый сигнал Подсчитываемые импульсы Рис. 6.21. Временная диаграмма измерения частоты
184 Глава 6 Измеряемый сигнал подается на вывод микроконтроллера Тх. Таймер/ счетчик настраивается в режим счетчика записью в бит С/Тх логической единицы. Содержимое таймера обнуляется. Таймер включается на строго определенный интервал времени. Этот интервал задается другим таймером. Пример исходного текста программы измерения частоты сигнала на вы- выводе микроконтроллера ТО приведен в листинге 6.2. Если теперь на вход микроконтроллера ТО подать сигнал с неизвестной час- частотой, то в регистрах ТНО и TL0 будет записана его частота в килогерцах. i.f*.*?9.f*.*At «ЛМ^^МЛ».^?/!» «Д?А,» »Af.A#» «Я.1ДМ1МДГ ^М» «At^Mf.M Г % Л • /MJ Ч Л ?#Л 9.J A,t А • ,1 Л » А *.Ч А • А Г Ч?*А».Ч**АГ • * t * Г ЧК*А»«Я«(АГ,Ч*.»А» «МЛ» * AtA» |Й|^|щ^^ сигнала' MOV TMOD,#00010101b ;!!::!!!! ;lllllI++ Перевести таймер ТО в 16-разрядный режим /* I I II 1+ Работать от сигнала на выводе ТО ; I I I I+ Запретить управление таймером от вывода INTO ; | |++ Перевести таймер Т1 в 16-разрядный режим ;|+ Работать от внутреннего генератора ;+ Запретить управление таймером от вывода INT1 MOV ТНО, #0 /Обнулить старший байт счетчика MOV TL0, #0 /Обнулить младший байт счетчика ; измерение вести в течение 1 мс MOV TH1, #HIGH(-1000) ;Загрузить старший байт константы в старший байт ;таймера MOV ТЫ, #LOW(-1000) /Загрузить младший байт константы в младший байт ;таймера MOV TCON,#01010000Ь /Включить частотомер ; I I I I I I I I ; | | | | | | |+ Прерывание от вывода INT1 возникает по фронту /MillI+ Сбросить запрос прерывания от вывода INT1 ;|||||+ Прерывание от вывода INT1 возникает по фронту ; I I I I+ Сбросить запрос прерывания от вывода INT1 /III + Включить таймер ТО ; | |+ Обнулить флаг таймера ТО ; | + Включить таймер Т1 .+ Обнулить флаг таймера Т1
Принципы работы микроконтроллеров 185 TstTimeOut: JNB TF1, TstTimeOut ;Если 1 мс прошла, MOV TCON, #00000000Ь ;то отключить частотомер ; II II II II ; I I I I I I I +—Прерывание от вывода INT1 возникает по фронту ; I I I I I I+ Сбросить запрос прерывания от вывода INT1 ;I I I I 1+ Прерывание от вывода INT1 возникает по фронту ; I I I I+ Сбросить запрос прерывания от вывода INT1 ; | | | + Отключить таймер ТО ; | | + Обнулить флаг таймера ТО ;| + Отключить таймер Т1 ;+ Обнулить флаг таймера Т1 Последовательный порт микроконтроллеров семейства MCS-51 Через универсальный последовательный порт микроконтроллера осуще- осуществляются прием и передача информации, представленной в последова- последовательном коде (младшими битами вперед). Наличие буферного регистра приемника позволяет совмещать операцию чтения ранее принятого бай- байта с приемом очередного. Но если к моменту окончания приема байта предыдущий не был считан из SBUF, то он будет потерян. Работой по- последовательного порта управляют три регистра: ? регистр управления/статуса приемопередатчика SCON; ? регистр управления мощностью PCON, бит SMOD; ? буферный регистр приемопередатчика SBUF. Последовательный порт может работать в четырех различных режимах: ? режим 0, синхронный; ? режим I, асинхронный 8-битовый обмен; ? режим 2, асинхронный 9-битовый обмен с фиксированной скоростью передачи; ? режим 3, асинхронный 9-битовый режим. Управление режимами работы приемопередатчика осуществляется через специальный регистр с символическим именем SCON. Он содержит не только управляющие биты, определяющие режим работы последова- последовательного порта, но и девятый бит принимаемых или передаваемых дан- 7 Зак 328
186 Глава 6 ных (RB8 и ТВ8) и биты прерывания приемника/передатчика (RI и TI). Формат регистра управления последовательным портом приведен на рис. 6.22. Адрес Ст. зн. разр. 98Н Мл. зн. разр. SM0 SCON.7 SM1 SCON.6 SM2 SCON.5 REN SCON.4 ТВ8 SCON.3 IT1 SCON.2 RB8 SCON.1 RI SCON.0 SCON 9Fh 9Eh 9Dh 9Ch 9Bh 9Ah 99h 98 h Наименование Позиция Назначение SMO SCON.7 Биты управления режимом работы приемопередатчика SM1 SCON.6 Устанавливаются/сбрасываются программно. См. примечание 1. SMO SM1 Режим работы приемопередатчика О 0 Сдвигающий регистр расширения ввода/вывода 8-битный приемопередатчик, изменяемая SM2 REN ТВ8 RB8 TI RI 1 1 SCON.5 SCON.4 SCON.3 SCON.2 SCON.1 SCON.0 скорость приема/передачи 9-битный приемопередатчик, фиксированная скорость приема/передачи 9-битный приемопередатчик, изменяемая скорость приема/передачи Бит управления режимом приемопередатчика. Устанавливается программно для запрета приема сообщения, в котором девятый бит имеет значение О Бит разрешения приема. Устанавливается/сбрасывается программно для разрешения/запрета приема последовательных данных Передача бита 8. Устанавливается/сбрасывается программно для задания девятого передаваемого бита в режиме 9-битового передатчика Прием бита 8. Устанавливается/сбрасывается аппаратно для фиксации девятого принимаемого бита в режиме 9-битового передатчика Флаг прерывания передатчика. Устанавливается аппаратно при окончании передачи байта. Сбрасывается программно после обслуживания прерывания Флаг прерывания приемника. Устанавливается аппаратно при приеме байта. Сбрасывается программно после обслуживания прерывания Рис. 6.22. Формат регистра управления последовательным портом
Принципы работы микроконтроллеров 187 Прикладная программа путем загрузки в старшие биты регистра SCON двухбитного кода задает режим работы приемопередатчика. Во всех че- четырех режимах передача инициализируется любой командой, в которой буферный регистр SBUF указан как получатель байта. Как уже отмеча- отмечалось, прием в режиме 0 осуществляется при условии, что RI = 0 и REN = 1, в остальных режимах — при условии, что REN = 1. В бите ТВ8 программно устанавливается значение девятого бита данных, который будет передан в режиме 2 или 3 в составе 9-битового поля дан- данных кадра передачи. В бите RB8 в этих режимах запоминается девятый принимаемый бит данных. В режиме 1 в бит RB8 заносится значение стоп-бита. В режиме 0 бит RB8 не используется. Флаг прерывания передатчика TI устанавливается аппаратно после пе- передачи стоп-бита во всех режимах. Подпрограмма, обслуживающая пре- прерывания или опрашивающая флаг, должна сбрасывать бит TI. Флаг прерывания приемника RI устанавливается аппаратно после прие- приема восьмого бита данных в режиме 0 и в середине периода приема стоп- бита в режимах 1, 2 и 3. Подпрограмма обслуживания прерывания долж- должна сбрасывать бит RI. Скорость приема/передачи информации через последовательный порт Скорость приема/передачи в различных режимах, задается различными способами. В режиме 0 частота передачи зависит только от резонансной частоты кварцевого резонатора/рез: /=/реэ/12. При этом за машинный цикл последовательный порт передает/прини- передает/принимает один бит информации. В режимах 1, 2 и 3 скорость приема/передачи зависит от значения управ- управляющего бита SMOD в регистре специальных функций PCON. Формат регистра управления питанием, в котором расположен бит управления скорости передачи, приведен на рис. 6.23. В режиме 2 частота приема/передачи определяется выражением Иными словами, при SMOD = 0 частота передачи равна 1/64 часто- частоты кварцевого резонатора/рез, а при SMOD = 1 частота передачи равна 1/32 частоты кварцевого резонатора/рез.
188 Глава 6 Адрес Ст. зн. разр. 87Н SMOD PCON.7 — PCON.6 — PCON.5 — PCON.4 Наименование Позиция Назначение SMOD PCON. 7 Удвс )енная GF1 PCON.3 CKODOCT GF0 PCON.2 ъ. Пои PD PCON.1 SMOD Мл. зн. разр. IDL PCON.0 = 1 СКО1 PCON GF1 GF0 PD IDL приема/передачи вдвое больше, чем при SMOD = 0. По сбросу SMOD = 0 PCON.6 Не используется PCON.5 Не используется PCON.4 Не используется PCON.3 фЛаги, специфицируемые пользователем PCON.2 (флаги общего назначения) PCON.1 Бит пониженной мощности. При PD = 1 микро-ЭВМ переходит в режим пониженной потребляемой мощност PCON.0 Бит холостого хода. При IDL = 1 микро-ЭВМ переходит в режим холостого хода Примечание При одновременной записи 1 в PD и IDL бит PD имеет преимущество. Сброс содержимого PCON выполняется путем загрузки в него кода 0XXX0000. Рис. 6.23. Формат регистра управления питанием В режимах 1 и 3 в формировании частоты приема/передачи, кроме управляющего бита SMOD, принимает участие таймер 1. При этом час- частота приема/передачи/зависит от частоты переполнения таймера 1 fm.m и определяется следующим образом: При использовании таймера 1 для тактирования последовательного пор- порта прерывания от этого таймера должны быть запрещены. Таймер может быть использован как в режиме 16-разрядного таймера, так и в режиме таймера с автозагрузкой. Обычно используется режим таймера с автоза- автозагрузкой (старшая тетрада регистра TMOD = 0010В). При этом скорость передачи последовательного порта определяется выражением: /= BSM0D х/рез)/C2 х 12 х B56 - 77/7)). Предельно низких скоростей приема и передачи по последовательному порту можно достичь при использовании таймера в режиме 1 (старший полубайт TMOD = 0001В). Перезагрузка 16-битного таймера должна
Принципы работы микроконтроллеров 189 осуществляться программным путем. При этом для того, чтобы можно было, кроме приема/передачи, выполнять дополнительные задачи, необ- необходимо использовать механизм обработки прерываний и для этого раз- разрешить прерывания от таймера I. Отметим, что для старших моделей семейства MCS-51 при использова- использовании для синхронизации последовательного порта таймеров 1 и 2 скоро- скорости приема и передачи информации по последовательному порту могут различаться. Режим 0. Синхронный режим работы последовательного порта В режиме 0 последовательный порт работает как обыкновенный сдвиго- сдвиговый регистр. Это позволяет использовать его для увеличения количества входов/выходов устройства. Использование сдвиговых регистров для этой цели показано на рис. 6.24 и 6.26. Передача через последовательный порт начинается с записи байта в регистр данных SBUF. Ucc Uss U RST RESET XTAL2 XTAL1 CPU RxD TxD ALE P2 1 2 3 4 5 6 7 DO RG Q0 Ql Q2 Q3 DO RG Q0 Ql Q2 Q3 Рис. 6.24. Схема подключения сдвиговых регистров к последовательному порту микроконтроллера для увеличения количества линий вывода устройства После завершения передачи аппаратно устанавливается флаг прерыва- прерывания передатчика TI. Временная диаграмма сигнала, вырабатываемого
190 Глава 6 последовательным портом микроконтроллера, при передаче восьми бит данных приведена на рис. 6.25. Прием байта через последовательный порт начинается после обнуления флага готовности приемника RI. Вре- Временная диаграмма приема входной информации последовательным пор- портом в режиме 0 приведена на рис. 6.27. Синхронный режим 0 задается записью комбинации 00 в биты SMO, SM1 регистра SCON. В этом режи- режиме информация передается/принимается через вывод входа приемника RxD, т. е. в этом режиме работы последовательный порт работает в сим- симплексном режиме. Через вывод TxD выдаются импульсы синхронизации, которые сопровождают каждый информационный бит. Скорость пере- передачи в этом режиме фиксирована и составляет FnnA2. Это означает, что при частоте задающего генератора 24 МГц обмен данными осуществля- осуществляется на скорости 2 Мбита/с. Номер команды |0|1|2|3|4|5|6|7|8| ale _ГLJ1J1J1ЛJ1JLЛJ1J1J1J1J1J1ГL^ TxD (CLK) RxD (DATA) Запись в SBUF П I \ _J^_rn_rL о X 1 X 2 X _rb_lL_n_lL_n з x 4 _X. 5 X 6 X 7 / Установка TI T Рис. 6.25. Временная диаграмма работы последовательного порта в режиме 0 после записи передаваемого байта в регистр данных SBUF Для осуществления передачи байта данных достаточно занести его в бу фер данных SBUF, как это показано в листинге 6.3. MOV SCON, #0 /Настроить последов, порт на передачу в режиме 0 MOV SBUF, A JNB TI, $ ;Передать содержимое аккум. по последовательному порту и ;подождать окончания передачи MOV SBUF, #5бН /Передать по последовательному порту число 56h и JNB TI, $ /подождать окончания передачи
Принципы работы микроконтроллеров 191 Ucc Uss и RST ФЕА RESET XTAL2 XTAL1 CPU RxD TxD ALE PSEN<>— P2 1 2 3 4 5 6 7 Ь DI DO Dl D2 D3 V RG Q3 DI DO Dl D2 D3 V RG Q3 Рис. 6.26. Использование режима 0 работы последовательного порта для увеличения количества линий ввода устройства Номер команды TxD (CLK) |0|1| |8| RxD (Входные данные) RI Обнуление RI Рис. 6.27. Временная диаграмма приема входной информации последовательным портом в нулевом режиме после обнуления флага готовности приемника RI Для осуществления приема байта данных достаточно настроить порт на прием в синхронном режиме (режим 0) и обнулить флаг приема RI, как это показано в примере программы, приведенной в листинге 6.4. Затем можно считывать принятый байт из регистра буфера данных SBUF.
192 Глава 6 /Настроить режим работы последовательного порта MOV SCON,#00010000b /настроить последов, порт на режим О ; I I I I I I I I ; I I I I I I I + Обнулить флаг приемника RI ; I I I I I I + Обнулить флаг передатчика TI ; II II 1+ Обнулить девятый бит приемника RB8 /III 1+ Обнулить девятый бит передатчика ТВ8 ; | | |+ Разрешить работу приемника .||+ g синхронном режиме не имеет значения ;++ Включить синхр. режим работы последов, порта ;Так как предыдущая команда обнулила флаг RI, с этого момента начинается /прием байта JNB RI, $ /Подождать окончания приема байта по последоват. MOV A, SBUF /порту и скопировать его в аккумулятор В настоящее время разработано огромное количество микросхем, управ- управление которыми осуществляется по синхронному последовательному порту. Это, например, синтезаторы частоты, микросхемы приемников, блоков цветности телевизоров, памяти. При этом микросхемы обычно реализуют синхронные протоколы обмена SPI или I2C. Последовательный порт микроконтроллеров семейства MCS-51, работающий в режиме О, позволяет осуществлять обмен с такими микросхемами при минималь- минимальных программно-аппаратных затратах. Справедливости ради необходи- необходимо отметить, что в современных микросхемах этого семейства присутст- присутствуют отдельные последовательные порты, работающие по протоколу SPI или I2C. В качестве примера такой микросхемы можно назвать микро- микроконтроллер ADuC834 фирмы Analog Devices. В таких микросхемах по- последовательный порт используется исключительно для связи с универ- универсальным компьютером через стандартный последовательный интерфейс RS232 или с любым другим микроконтроллером, обладающим асин- асинхронным последовательным портом. Режим 1. Асинхронный 8-битовый режим В режиме 1 последовательный порт работает в асинхронном режиме, принципы работы которого рассматривались ранее. Временная диа- диаграмма передаваемых через последовательный порт сигналов в асин-
Принципы работы микроконтроллеров 193 хронном последовательном режиме работы совпадает с временной диа- диаграммой, приведенной на рис. 5.24 Режим 1 задается записью комби- комбинации 01 в биты SM0 и SM1 регистра SCON. В асинхронном режиме информация передается через вывод выхода передатчика последователь- последовательного порта микроконтроллера TxD, а принимается через вывод входа приемника RxD, т. е. в этом режиме работы последовательный порт ра- работает в дуплексном режиме. Это означает, что передача и прием ин- информации могут вестись одновременно и независимо друг от друга. Ско- Скорость передачи в этом режиме задается при помощи таймера Т1. При работе в асинхронном режиме два микроконтроллера могут обме- обмениваться информацией между собой, используя минимум соединитель- соединительных проводов между блоками или даже отдельными устройствами. Единственное условие: скорости работы передающего и принимающего последовательных портов должны быть одинаковыми. Обычно исполь- используются стандартные скорости передачи, такие как 1200 бит/с, 2400 бит/с и т. д. Для получения таких скоростей передачи обычно используется кварцевый резонатор с частотой 11,0592 МГц. Значения констант, загру- загружаемых в таймер 1 для получения стандартных скоростей приема/передачи при использовании такого кварцевого резонатора, приведены в табл. 6.5. Таблица 6.5. Настройка таймера 1 для некоторых стандартных скоростей обмена через последовательный порт в режимах 1 и 3 Частота приема/передачи 62,2 кбит/с 19,2 кбит/с 9,6 кбит/с 4,8 кбит/с 2,4 кбит/с 1,2 кбит/с 110 бит/с Частота резонатора МГц 12 11,059 11,059 11,059 11,059 11,059 6 Таймер/счетчик 1 SMOD 1 1 0 0 0 0 0 с/т 0 0 0 0 0 0 0 Режим (М1, МО) 1,0 1,0 1,0 1,0 1,0 1,0 1,0 Перезагружаемое число 0FFH 0FDH 0FDH 0FAH 0F4H 0Е8Н 072Н В отличие от режима 0 в режиме 1 возможен обмен информацией между двумя микроконтроллерами, а не только между микроконтроллером и исполнительными микросхемами. Схема соединения двух микрокон-
194 Глава 6 троллеров между собой для обмена информацией приведена на рис. 6.28. Таким образом, может быть построена простейшая многопроцессорная система. Ucc Uss U RST ФЕА RESET XTAL2 XTAL1 CPU RxD TxD ALE PSEN6— P2 0 1 2 3 4 5 6 7 ФЁА RESET XTAL2 XTAL1 CPU RxD TxD ALE PSEN P2 0 1 2 3 4 5 6 7 Рис. 6.28. Схема обмена информацией между двумя микроконтроллерами через последовательные порты В режиме 1 для передачи байта через последовательный порт достаточно скопировать его в буфер данных SBUF. Единственное отличие заключа- заключается в том, что, кроме настройки регистра SCON, необходимо настроить таймер для задания скорости передачи информации по последователь- последовательному порту. Прием начинается только после обнаружения стартового бита. Пример программы, позволяющей осуществить прием информации по последовательному порту, приведен на листинге 6.5. Возможность работы в асинхронном режиме позволяет использовать последовательный порт для связи с универсальным компьютером через его последовательный СОМ-порт. К сожалению, уровни сигналов по- последовательного порта микроконтроллера не соответствуют специфи- спецификациям стандартного интерфейса RS232, используемого в СОМ-порте универсальных компьютеров, поэтому для подключения приходится
Принципы работы микроконтроллеров 195 дополнительно использовать специализированные микросхемы согла сования уровней. Эти же микросхемы обеспечивают защиту микрокон троллера от вывода из строя статическим потенциалом при подключе нии разъемов. тттшшшжжж ;НАСТРОЙКА ПОСЛЕДОВАТЕЛЬНОГО ПОРТА ;Настроить режим работы последовательного порта MOV SCON,#01110000b ;настроить последовательный порт на режим 1 ;I I I I I I I+ Обнулить флаг приемника RI ;I I I I I I+ Обнулить флаг передатчика TI ;I I I I I+ Обнулить девятый бит приемника RB8 ;I I I I+ Обнулить девятый бит передатчика ТВ8 ; I I I + Разрешить работу приемника ;||+ Проверять ошибку кадра (прием нулевого бита на ; | | месте стоп-бита) ;++ Включить асинхронный режим работы ;Настроить режим работы таймера Т1 ANL TMOD,#00001111Ь Подготовить таймер Т1 к настройке ;(таймер ТО не трогать!) ORL TMOD,#00100000Ь /перевести таймер Т1 в режим 2 ;I I I I ; (таймер ТО не трогать!) ; | | ++ Перевести таймер Т1 в режим автозагрузки ; | + Работа от внутреннего генератора ;+ Запретить управление таймером от вывода INT1 ;Настроить таймер на генерацию 3-микросекундного интервала времени- MOV ТНО, #0fdh ;Загрузить старший байт таймера MOV TLO, #0fdh ;Загрузить младший байт таймера SETB TR1 /Включить таймер 1
196 Глава 6 /РАБОТА С ПОСЛЕДОВАТЕЛЬНЫМ ПОРТОМ JNB RI, $ /Подождать окончания приема байта по последовательному MOV A, SBUF /порту и скопировать его в аккумулятор Обычно для обмена информацией используются только сигнальные це- цепи СОМ-порта компьютера. Тем не менее, оставшиеся буферы интер- интерфейсной микросхемы могут быть использованы для контроля питания микроконтроллерной схемы. Для этого сигнал запроса готовности уда- удаленного устройства от компьютера пропускается через интерфейсную микросхему. Затем этот же сигнал подается на вход подтверждения го- готовности удаленного устройства. Если на интерфейсную микросхему не будет подано питание, то сигнал подтверждения готовности не будет сформирован. Типовая схема подключения компьютера к последовательному порту микроконтроллеров семейства MCS-51 с применением интерфейсной микросхемы ADM3202 приведена на рис. 6.29. DD2 DD1 Ucc Uss U RST <>ЕА RESET XTAL2 XTAL1 CPU RxD TxD ALE PSEN- P2 1 2 3 4 5 6 7 DD3 R1OUT TUN R2OUT T2IN V- C2+ C2- RUN T1OUT R2IN T2OUT V+ C1+ Cl- Vcc GND цепь 8 6 KOHT TD RTS CTS DTR DSR DCD SG Рис. 6.29. Подключение последовательного порта микроконтроллеров семейства MCS-51 к СОМ-порту компьютера
Принципы работы микроконтроллеров 197 Использование последовательного порта компьютера позволяет не только управлять микроконтроллерным устройством, используя клавиа- клавиатуру компьютера, но и отображать внутреннюю информацию этого уст- устройства, используя дисплей компьютера. Это значительно расширяет возможности ввода и вывода информации в микроконтроллерных уст- устройствах. В последнее время дополнительно появилась возможность за- заносить программу во внутреннюю память программ наиболее современ- современных микроконтроллеров. Режим 2. Асинхронный 9-битовый режим с фиксированной скоростью передачи В этом режиме последовательный порт работает на фиксированной ско- скорости передачи, так же как в режиме 0. Скорость обмена определяется значением бита SMOD и при частоте кварцевого резонатора 12 МГц со- составляет 375 кбит/с. У современных микроконтроллеров, способных ра- работать с более высокой тактовой частотой, скорость обмена может пре- превышать 1 Мбит/с. Основной особенностью работы последовательного порта в этом режиме является передача девятого информационного бита, который может быть использован для контроля достоверности передаваемой информа- информации. Для вычисления четности передаваемого байта можно воспользо- воспользоваться аппаратным вычислителем, подключенным к аккумулятору мик- микроконтроллера А. Результат вычисления четности байта сохраняется в бите четности Р регистра PSW, откуда его можно скопировать в девятый информационный бит последовательного порта ТВ8, расположенный в регистре управления последовательным портом SCON. Еще большие возможности предоставляет 9-разрядный режим работы последовательного порта при реализации многопроцессорных систем. Параллельные порты микроконтроллеров семейства MCS-51 построе- построены по схеме с открытым стоком. Это позволяет объединять несколько выходов передатчиков в одну шину. Такое выполнение выходных кас- каскадов микросхем облегчает построение многопроцессорных систем. В многопроцессорной системе один процессор должен быть главным (master), остальные — подчиненными (slave). Естественно, команды главного процессора должны восприниматься подчиненными, поэтому выход передатчика главного процессора соединяется с входами прием- приемников подчиненных.
00 Ucc Uss и RST XTAL2 XTAL1 CPU RxD TxD ALE PSlN -o XTAL2 XTAL1 CPU RxD ALE PSEN ФЁА Hh RESET XTAL2 XTAL1 CPU RxD TxD ALE PSEN P2 1 2 3 4 5 6 7 ФЁА XTAL2 XTAL1 CPU RxD TxD ALE PSEN< 1 2 3 4 5 6 7 Рис. 6.30. Схема соединения нескольких микроконтроллеров между собой через последовательные порты, работающие в асинхронном режиме Q) СО Q)
Принципы работы микроконтроллеров 199 Выходы же передатчиков подчиненных процессоров объединяются и подключаются к входу приемника главного процессора. Схема примера многопроцессорной системы приведена на рис. 6.30. Команды главного процессора могут быть обращены к конкретному подчиненному процессору, поэтому в состав команд включается адрес подчиненного процессора. При работе в шине необходимо уметь отли- отличать адресную информацию от данных. Это можно осуществить при по- помощи девятого бита. Обычно при передаче адреса в девятый бит записы- записывают единицу, а при передаче данных и команд — ноль. Таким образом, микроконтроллер, даже подключившийся к шине позднее остальных, легко может осуществить синхронизацию с многопроцессорной шиной. Временная диаграмма работы многопроцессорной шины приведена на рис. 6.31. TxD "I Адрес 1 Команда Данные 1 Данные 2 п п Адрес 2 Команда Данные RxD (Подтверждение ¦команды (Подтверждение 'команды Время программной реакции Время программной реакции Рис. 6.31. Временная диаграмма работы многопроцессорной последовательной шины Настройка и работа с портом в режиме 2 никаких особенностей не имеет, поэтому можно воспользоваться примерами программ (см. листинги 6.3 и 6.4), приведенными для режима 0. Все особенности работы сосредото- сосредоточены на протокольном уровне, а это не входит в задачу рассмотрения последовательного порта. Режим 3. Асинхронный 9-битовый режим Работа последовательного порта в этом режиме не отличается от работы в режиме 2 за исключением скорости передачи. Скорость передачи по последовательному порту задается таймером 1, так же как и в режиме 1. Для построения программы можно воспользоваться примером, приве- приведенным для режима 1 (см. листинг 6.5), с учетом того, что в регистре SCON необходимо задать вместо режима 1 режим 3.
200 Глава 6 Итак, подведем итоги В главе было рассмотрено внутреннее устройство и система команд наи- наиболее распространенного семейства микроконтроллеров. При описании внутренних узлов этого семейства были приведены типовые фрагменты программ, иллюстрирующие работу с этими узлами. Там, где это необ- необходимо, были приведены фрагменты принципиальных схем устройств с использованием рассматриваемого микроконтроллера. Естественно, что в одной книге невозможно охватить все особенности применения микроконтроллеров. Тем более, что у каждого вида мик- микросхем, принадлежащего к этому семейству, имеются свои особенности. Тем не менее, были рассмотрены узлы, присутствующие во всех микро- микросхемах данного семейства. При необходимости полученные знания можно применить для того, чтобы разобраться и научиться управлять узлами микроконтроллеров, которые не были рассмотрены в данной книге. Даже для микросхем, которые только появятся на рынке через несколько лет. Однако уметь управлять отдельными узлами микроконтроллера еще не значит уметь писать программы. Точно так же как недостаточно иметь в наличии кирпичи, доски, окна и двери для того, чтобы построить дом. При написании программ используются специфические приемы, позво- позволяющие реализовывать законченные блоки аппаратуры и организовы- организовывать взаимодействие между ними. Там не менее, теперь можно перейти к изучению принципов написания программ для микроконтроллеров, реа- реализующих различные цифровые устройства. Именно этим мы и займемся в следующей главе.
шооп Глава 7 Принципы создания программ для микроконтроллеров В предыдущих главах были рассмотрены основы построения микропро- микропроцессорных систем, подробно описано внутреннее устройство самого рас- распространенного семейства микроконтроллеров — MCS-51. Однако од- одновременно выяснилось, что для разработки устройства на основе микроконтроллера создания одной только принципиальной схемы не- недостаточно. Кроме того, требуется разработать и занести во внутрен- внутреннюю память микроконтроллера программу. Именно она вместе с аппа- аппаратурой микроконтроллера и обеспечивает функционирование проек- проектируемого устройства. В предыдущей главе была рассмотрена система команд микроконтрол- микроконтроллера, но знания только системы команд недостаточно для создания про- программного обеспечения микропроцессорной системы. Нужны специаль- специальные программные средства, позволяющие облегчить процесс разработки программы. В настоящее время предлагаются инструментальные интег- интегрированные среды разработки программ. Микроконтроллеры предназначены для миниатюризации устройств управления, поэтому они интересны, прежде всего, для разработчиков различной аппаратуры. Однако обычно у этих специалистов отсутству- отсутствуют навыки программирования. В данной главе будут описаны основные принципы разработки программного обеспечения, причем основное внимание будет уделено особенностям построения программ для микро- микроконтроллеров. Основное внимание будет уделено методу структурного программирова- программирования, как наиболее подходящему для современного уровня развития мик- микроконтроллеров. Кроме того, мы остановимся на особенностях построения программ, реагирующих на сигналы, поступающие извне, рассмотрим программную реализацию блоков, которые ранее выполнялись аппарат- но, и взаимодействие программы с человеком.
202 Глава 7 Все современные программы пишутся на каких-либо языках программи- программирования, поэтому начнем главу с обзора существующих языков про- программирования и программ-трансляторов этих языков. Языки программирования для микроконтроллеров Программирование для микроконтроллеров, как и программирование для универсальных компьютеров, прошло большой путь развития — от использования машинных кодов до применения современных интегри- интегрированных сред, предоставляющих встроенный текстовый редактор, обеспечивающих трансляцию программ, их отладку и загрузку во внут- внутреннюю память микроконтроллеров. В настоящее время исходный текст программы пишется на каком-либо из языков программирования, отно- относящемся к одной из двух групп: ? языки программирования «низкого» уровня; ? языки программирования «высокого» уровня. Классификация языков программирования приведена на рис. 7.1. В язы- языках «низкого» уровня каждому оператору соответствует не более одной машинной команды. В их состав обязательно входит набор машинных команд каждого конкретного процессора. Языки программирования низкого уровня в настоящее время называются ассемблерами (старое на- название «автокоды»). Для каждого процессора существует своя группа ассемблеров. Ассемблеры для одного и того же процессора различаются между собой дополнительными возможностями, облегчающими про- программирование. Языки программирования «высокого» уровня позволяют заменять один оператор несколькими машинными командами. Это увеличивает произ- производительность труда программистов. Кроме того, языки «высокого» уровня позволяют писать программы, которые могут выполняться на различных микропроцессорах. (Естественно, что при этом необходимо использовать программы-трансляторы для соответствующего процессо- процессора.) В настоящее время для микроконтроллеров широко используются такие языки программирования высокого уровня, как С и PLM. О преимуществах и недостатках языков высокого и низкого уровней го- говорилось достаточно много. Выбор языка программирования зависит от состава аппаратуры, для которой пишется программа, наличия тех или
Принципы создания программ для микроконтроллеров 203 иных средств разработки программного обеспечения, а также от требуе- требуемого быстродействия всего программно-аппаратного комплекса в целом. В тех случаях, когда объем ОЗУ и ПЗУ мал (в районе нескольких килобай- килобайтов), альтернативы ассемблеру нет. Именно этот язык программирования позволяет получать самый короткий и самый быстродействующий код программы (при прочих равных условиях, т. к. испортить можно все!). Компиляторы Трансляторы Интерпретаторы Языки «высокого» уровня Рис. 7.1. Классификация языков программирования Языки программирования высокого уровня позволяют значительно со- сократить время создания программы, но при этом увеличивается ее раз- размер, поэтому использование такого языка программирования для мик- микропроцессорных систем требует достаточно большого объема памяти программ (несколько десятков килобайтов). Увеличение объема про- программы связано с несколькими факторами: 1. Язык программирования рассчитывается на все случаи жизни, поэто- поэтому в большинстве случаев человек мог бы написать программу коро- короче, исключив ненужные в данном конкретном случае проверки или защиты. 2. Если программист не знает, к чему приводит использование тех или других операторов языка программирования, то он может выбирать операторы, неоптимальные как с точки зрения длины машинного ко- кода программы, так и с точки зрения быстродействия программы. 3. Программист не использует подпрограммы там, где они могли бы со- сократить объем программы, т. к. на языке программирования высокого уровня это всего один или несколько операторов.
204 Глава 7 Первый из этих пунктов постепенно утрачивает свое значение с появле- появлением все более совершенных трансляторов. Третий пункт тоже решается тем же путем при применении различных видов оптимизаторов, входя- входящих в состав компилятора. Однако в большинстве случаев оптимизатор не может определить одинаковые действия, если они отличаются хотя бы одной командой. Кроме того, оптимизатор работает только в пределах одного программного модуля! Понятие программного модуля будет рас- рассмотрено позднее. Виды программ-трансляторов Процесс преобразования операторов исходного языка программирова- программирования в машинные коды микропроцессора называется трансляцией исход- исходного текста. В настоящее время ручная трансляция программ практически не используется. Трансляция производится специальными программами- трансляторами. Существуют два больших класса таких программ: компиляторы и интер- интерпретаторы. При использовании компиляторов весь исходный текст про- программы преобразуется в машинные коды, и именно эти коды записыва- записываются в память микропроцессора. При использовании интерпретатора в память микропроцессора записывается исходный текст программы, а трансляция производится при считывании очередного оператора. Есте- Естественно, что быстродействие интерпретаторов намного ниже, чем у ком- компиляторов, т. к., например, при использовании оператора в цикле он транслируется многократно. Применение интерпретатора может обеспечить выигрыш только в случае его разработки для языка программирования «высокого» уровня. В этом случае может быть сэкономлена внутренняя память программ, а также облегчен процесс отладки (при применении языка программирования BASIC) или облегчен перенос программ с одного типа процессора на другой (в случае использования языка программирования Java). При программировании на ассемблере применение интерпретатора при- приводит к проигрышу по всем параметрам, поэтому для языков програм- программирования низкого уровня применяются только программы-компиля- программы-компиляторы. Для программирования микроконтроллеров как на языке программиро- программирования «низкого» уровня, так и на языке программирования «высокого» уровня чаще используются компиляторы, поэтому рассмотрим подроб- подробнее виды этих трансляторов.
Принципы создания программ для микроконтроллеров 205 Виды компиляторов Программы-компиляторы бывают оценочные и профессиональные. Оценочные компиляторы позволяют написать простейшие программы для конкретного процессора и определить, подходит ли процессор для тех задач, которые предстоит решать в процессе разработки устройства. Конечно, если программа очень проста, то можно весь программный продукт выполнить на оценочном компиляторе. Оценочные компилято- компиляторы позволяют транслировать одиночный файл исходного текста про- программы. Иногда такие компиляторы позволяют включать в процесс трансляции содержимое отдельных файлов специальной директивой. В результате работы оценочного компилятора сразу получается испол- исполняемый или загрузочный модуль программы, поэтому такие компилято- компиляторы называются компиляторы с единой трансляцией. Профессиональные трансляторы позволяют производить компиляцию исходного текста программы по частям. Это позволяет значительно со- сократить время трансляции, т. к. нужно компилировать не весь текст про- программы, а только ту ее часть, которая менялась после предыдущей трансляции. Кроме того, каждый программный модуль может писать отдельный про- программист. Это позволяет сократить время написания программы. Даже в том случае, если программу пишет один человек, время написания про- программы сокращается за счет использования готовых отлаженных и от- оттранслированных программных модулей. При многомодульном программировании процесс получения исполняе- исполняемого кода программы разбивается на два этапа: компиляция исходного текста модулей (некоторых или всех) и связывание (компоновка) полу- полученных объектных файлов модулей в единую программу. Такой процесс получил название раздельная компиляция-компоновка. Оценочные компиляторы обычно предлагаются бесплатно фирмами — производителями микроконтроллеров. Профессиональные компиляторы разрабатываются и продаются незави- независимыми фирмами — разработчиками программного обеспечения. Для микроконтроллеров семейства MCS-51 получили известность продукты таких фирм, как FRANKLIN, IAR, KEIL и др. В состав современных профессиональных средств написания и отладки программ для микроконтроллеров обычно входят эмуляторы процессо- процессоров или отладочные платы, текстовый редактор, компиляторы языка вы- высокого уровня (чаще всего «С») и ассемблера, редактор связей (компо- (компоновщик) и загрузчик программы в отладочную плату. Все программы обычно объединены интегрированной средой разработки программного
206 Глава 7 проекта, которая позволяет поддерживать один или несколько про- программных проектов. Теперь, после того как были рассмотрены языки программирования для микроконтроллеров и программы-трансляторы, перейдем к рассмотре- рассмотрению основных принципов написания программ. Применение подпрограмм В программах часто приходится повторять одни и те же операторы (например, при реализации алгоритма работы с параллельным или по- последовательным портом). Было бы неплохо использовать один и тот же участок кода, вместо того, чтобы повторять одни и те же операторы не- несколько раз. Участок программы, к которому можно обращаться из различных мест программы для выполнения некоторых действий и последующего воз- возврата в место вызова, называется подпрограммой. Проблема, с которой приходится сталкиваться при многократном ис- использовании участков кодов, — как определить, в какое место памяти программ возвращаться после завершения подпрограммы. Обращение к подпрограмме производится из нескольких мест основной программы. Описанную ситуацию иллюстрирует рис. 7.2. На нем изображено адрес- адресное пространство микроконтроллера. Младшие адреса адресного про- пространства находятся в нижней части рисунка. Для того чтобы получить возможность возвращаться на команду, сле- следующую за вызовом подпрограммы, требуется запомнить ее адрес. Адрес возврата хранится в особых ячейках памяти данных. После выполнения подпрограммы необходимо осуществить переход к адресу, который за- записан в этих ячейках. Для обращения к подпрограмме и возврата из нее в систему команд мик- микропроцессоров вводят специальные команды. В микроконтроллерах се- семейства MCS-51 это команды lcall, acall для вызова подпрограммы и команда ret для возврата из подпрограммы. Команды вызова не только осуществляют передачу управления на указанный адрес, но и запомина- запоминают адрес команды, следующей за вызовом подпрограммы — адрес воз- возврата. Команда возврата из подпрограммы передает управление по адре- адресу возврата, которой был запомнен при вызове подпрограммы. Пример вызова подпрограммы и ее реализации на языке программиро- программирования ASM-51 приведен на листинге 7.1.
Принципы создания программ для микроконтроллеров 207 Внимание! Ни в коем случае нельзя попадать в подпрограмму любым спо- способом кроме команды вызова подпрограммы call! В противном случае команда возврата из подпрограммы передаст управление случайному адресу! По этому адресу могут быть расположены данные, которые в этом случае будут интерпретированы как программа, или обратиться к внешней памяти, откуда будут считываться случайные числа. Podpr call Podpr call Podpr Подпрограммы Основная программа Рис. 7.2. Вызов подпрограммы и возврат к выполнению основной программы ^Листинг 7Л< Пример вызова подпрограммы MOV А,#56 CALL PeredatByte * * • MOV A,#37 CALL PeredatByte .*****••**•**••*****•*•********************** /Подпрограмма передачи байта /через последовательный порт .**••••••••••****••*••*********•*•*****•********
208 Глава 7 PeredatByte: JB TI, $ ;Если предьщущий байт передан, MOV SBUF, G_Per ;то передать очередной байт RET В приведенном в листинге 7.1 примере перед подпрограммой обязательно должен быть бесконечный цикл. Иначе в подпрограмму можно попасть не через вызов подпрограммы, а при последовательном выполнении опе- операторов. Тогда команда ret передаст управление на случайный адрес. Это может привести к непредсказуемым последствиям. При особенно не- неблагоприятных обстоятельствах даже к выходу микропроцессорной сис- системы из строя. В программах, которые пишутся для микроконтроллеров, требуется обеспечить бесконечный цикл для того, чтобы программа ни- никогда не завершала свою работу. Если основная программа микрокон- микроконтроллера с бесконечным циклом будет располагаться до первой из под- подпрограмм, то приведенное условие будет выполняться автоматически. Очень часто возникает необходимость из одной подпрограммы обра- обращаться к другой подпрограмме. Такое обращение к подпрограмме назы- называется вложенным вызовом подпрограммы. Количество вложенных под- подпрограмм называется уровнем вложенности подпрограмм. Максимально допустимый уровень вложенности подпрограмм определяется количест- количеством ячеек памяти, предназначенных для хранения адресов возврата из подпрограмм. Стек, его организация и структура Адреса возврата из подпрограмм хранятся в области памяти, называе- называемой стеком. Логически доступ к этим ячейкам памяти организован так, чтобы считывание последнего записанного адреса возврата производи- производилось первым, а первого — последним. Логическая организация стека по- пояснена на рис. 7.3. Адресация ячеек стека осуществляется с использова- использованием специального регистра, называемого указателем стека, SP. Ячейка памяти, в которую в данный момент может быть записан адрес возврата из подпрограммы, называется вершиной стека. Ее адрес всегда хранится в указателе стека. Количество ячеек памяти, выделенных для стека, назы- называется глубиной стека. Последняя ячейка стека, в которую можно произ- производить запись, называется дном стека. Первоначально стек выполнялся аппаратно на отдельных ячейках памя- памяти, затем его стали размещать в обычной памяти данных микропроцес-
Принципы создания программ для микроконтроллеров 209 соров. Это позволило в каждом конкретном случае устанавливать необ- необходимую для программы глубину стека. Оставшуюся память можно ис- использовать для размещения глобальных и локальных переменных про- программы. Глубина стека устанавливается при помощи записи начального адреса вершины стека в регистр SP. Обычно глубина стека устанавлива- устанавливается один раз после включения питания в процедуре инициализации кон- контроллера. Указатель стека Вершина стека Глубина стека Дно стека Рис. 7.3. Организация стека в памяти данных микропроцессора Например, в микроконтроллерах семейства MCS-51 при занесении ин- информации в стек содержимое указателя стека увеличивается (стек растет вверх), поэтому стек размещается в самой верхней части памяти данных. Для того чтобы установить глубину стека 28 байт, необходимо вычесть из адреса максимальной ячейки внутренней памяти микроконтроллера глубину стека и записать полученное значение в указатель стека SP: DnoSteka EQU 127 ;для микроконтроллера АТ89с51 размер /внутренней памяти равен 128 байтам MOV SP, #DnoSteka-28 /Установить глубину стека 28 байт Кроме значения программного счетчика, часто требуется запоминать содержимое внутренних регистров и флагов процессора, локальных пе- переменных подпрограммы. Стек оказался удобным средством и для реше- решения этих задач. Сохранение локальных переменных в стеке позволило осуществлять вызов подпрограммы самой из себя (реализовывать рекур- рекурсивные алгоритмы). Для работы со стеком в систему команд микропро- микропроцессоров введены специальные команды. У микроконтроллеров семейст- семейства MCS-51 это команды push и pop. Их использование показано в листинге 7.2.
210 Глава 7 Г % ¦" v ¦• l Листинг 7.2. Пример использования команд работы со стеком " Podprogramma: PUSH PSW ;Сохранить содержимое PUSH ACC /используемых в PUSH RO ;подпрограмме регистров ;Текст подпрограммы POP R0 /Восстановить содержимое POP ACC /используемых в POP PSW /подпрограмме регистров ret /Вернуться из подпрограммы Подпрограммы-процедуры и подпрограммы-функции Подпрограммы предназначены для выполнения определенных действий над находящимися внутри микросхемы периферийными устройствами, внешними устройствами, подключенными к выводам микросхемы мик- микроконтроллера, или числами, хранящимися в его внутренней памяти. В любом случае, с точки зрения программы, операции производятся над переменными. Переменные могут быть локальными (доступными только из подпрограммы) или глобальными (доступными из любого места про- программы). Если подпрограмма осуществляет действия над глобальными перемен- переменными или выполняет определенный набор действий, то такая подпро- подпрограмма называется процедурой. Эта подпрограмма может осуществлять управление какими-то устройствами или осуществлять какие-либо вы- вычисления. Если производятся вычисления, то результат помещается в глобальную переменную для того, чтобы этим результатом могла вос- воспользоваться другая подпрограмма или основная программа. Пример фрагмента программы управления последовательным портом, написан- написанного на языке высокого уровня С-51, приведен в листинге 7.3.
Принципы создания программ для микроконтроллеров 211 шш&фш Шй?ШаШ&&шШ&&&$&аь* 'км iui' \*п fin &1*А ийлШ- fj 0E пой oBdirojrib н ым G_Per=56; PeredatByte(); //Занести передаваемое число в глобальную переменную //Передать это число G_Per=37; PeredatByte(); // Занести передаваемое число в глобальную переменную //Передать это число Подпрограмма передачи байта через последовательный порт void PeredatByte(void) (do;while(TI==0); //Если предыдущий байт передан, SBUF=G_Per; //то передать очередной байт Часто подпрограмма должна выполнять действия над каким-либо чис- числом, значение которого неизвестно в момент написания программы. Это число можно передать через глобальную переменную, как в приведенном выше примере подпрограммы. Однако намного удобнее использовать подпрограмму с параметрами. Параметры подпрограммы — это локальные переменные подпрограммы, начальные значения которым присваиваются в вызывающей программе или подпрограмме. В алгоритмическом языке С-51 параметры подпро- подпрограммы записываются в скобках после ее имени. Пример вызова такой подпрограммы представлен в листинге 7.4. PeredatByteE6); PeredatByteE7);
212 Глава 7 Подпрограмма передачи байта через последовательный порт void PeredatByte(char byte) {do;while(TI==0); //Если предьщущий байт передан, SBUF=byte; //то передать очередной байт Сравните с программой, использующей глобальные переменные (см. листинг 7.3). Как, по-вашему, какая из программ обладает большей на- наглядностью? В подпрограмму можно передавать и значительные объемы данных, например, строки или массивы данных: PeredatStroky("Напечатать строку"); Естественно, что в этом случае сама подпрограмма PeredatStroky долж- должна быть написана несколько иначе, чем в примерах на листингах 7.3 или 7.4. Здесь потребуется применение переменных-указателей, которые бу- будут рассмотрены позднее. Часто требуется передавать результат вычислений из подпрограммы в основную программу. Для этого можно воспользоваться подпрограм- подпрограммой-функцией. Подпрограмма-функция — это подпрограмма, которая возвращает вы- вычисленное значение. Пример использования подпрограммы-функции: Y=sin (x) ; Использование подпрограмм-функций позволяет приблизить текст про- программы к математической записи выражений, которые необходимо вы- вычислить, а также увеличивает наглядность программ и, в результате, по- повышает скорость написания и отладки программного обеспечения. Подпрограммы-функции обычно возвращают значения простых типов, таких как байт, слово или целое. Однако при помощи указателя можно возвращать и значения более сложных типов, таких как массивы пере- переменных, структуры или строки. Применение комментариев В текст программы, наряду с операторами языка программирования можно включать поясняющие комментарии, что служит улучшению наглядности программы и ее документированию. Комментарий может содержать любые печатные символы, а также пробелы и символы табу- табуляции.
Принципы создания программ для микроконтроллеров 213 Комментарии применяются, например, для того, чтобы поставить в со- соответствие элементу блок-схемы программы или неформального описа- описания алгоритма группу операторов языка программирования. Так как ал- алгоритм может быть написан с различной степенью детализации, это должно быть отображено при помощи комментариев. Комментарии для частей описания алгоритма с наибольшей степенью детализации обычно пишут справа от операторов, которые реализуют эту часть алгоритма. Более крупные блоки алгоритма отражаются комментариями, занимаю- занимающими в тексте программы отдельные строки. Эти комментарии, чтобы их легче было заметить, пишут буквами верхнего регистра. Один из та- таких блоков в листинге 7.5 выделен комментарием, названным коммента- комментарий алгоритма второго уровня. Еще более крупные блоки алгоритма вы- выделяют специальными символами, которые сразу бросаются в глаза. Пример использования комментариев приведен в листинге 7.5. Ч Л f .«.».« Л ».Ч » IHM . Листинг 7ф;Р#им^ • Комментарий алгоритма второго уровня /ПЕРЕДАТЬ ДВА ЧИСЛА ЧЕРЕЗ ПОСЛЕДОВАТЕЛЬНЫЙ ПОРТ Комментарий, поясняющий CALL PeredatByte /последовательный порт V несколько операторов MOV G_Per, #56 /Передать число 56 через ПОЯСНЯЮЩИЙ MOV G_Per, #37 /Передать число 37 через CALL PeredatByte /последовательный порт Конец блока алгоритма второго уровня .*********************+*+*************+*******+** /Подпрограмма передачи байта Так выделяются особо ^ важные блоки алгоритма /через последовательный порт " PeredatByte: JB TI,$ /Если предыдущий байт выдан, MOV SBUF,G_Per /то передать следующий RET Комментарий, поясняющий действие команды
214 Глава 7 В листинге 7.5 показан отрывок программы на языке ассемблера ASM- 51, для которого комментарии имеют наибольшее значение, но точно так же можно (и нужно) использовать комментарии и в исходных текстах программы на языке высокого уровня. При этом нужно помнить, что те фрагменты текста программы, которые абсолютно ясны в момент напи- написания, через месяц вызовут затруднения даже у программиста, написав- написавшего этот текст, не говоря уже о человеке, который видит его впервые. Программа читается, прежде всего, по комментариям и только потом, если она по каким-либо причинам не работает, проверяется на соответ- соответствие комментариям конкретных операторов языка программирования. Такой стиль написания программ позволяет значительно экономить время, т. к. не приходится повторно разбираться с уже написанными уча- участками кода при поиске ошибки программы. Структурное программирование Программирование для универсальных компьютеров начиналось с ис- использования машинных кодов, затем появились языки высокого уровня. Позже были развиты сначала принципы структурного программирова- программирования, а потом — объектно-ориентированное программирование. В на- настоящее время активно развивается визуальное программирование. Программирование для микроконтроллеров во многом повторяет тот же путь. Переход от этапа к этапу зависит от доступных внутренних ресур- ресурсов микроконтроллеров. Еще несколько лет назад использование языков высокого уровня при написании программ для микроконтроллеров было невозможно из-за малого объема внутренней памяти программ. (В деше- дешевых моделях микроконтроллеров эта ситуация сохраняется до сих пор.) В настоящее время с появлением микроконтроллеров и сигнальных про- процессоров с объемом внутренней памяти в несколько десятков килобайт появляется возможность использования методов структурного, а в неко- некоторых случаях и объектно-ориентированного проектирования. Применение структурного программирования позволяет увеличить ско- скорость написания программ и облегчить их отладку за счет сокращения количества доступных программных конструкций. Поэтому в начале се- семидесятых годов был разработан ряд языков высокого уровня, ориенти- ориентированных на структурное программирование. Это такие языки, как С, PASCAL, ADA. Однако не надо думать, что структурное программи- программирование возможно только на этих языках, для этого пригодны и такие языки, как ассемблер или FORTRAN, где не предусмотрено структурных операторов.
Принципы создания программ для микроконтроллеров 215 В настоящее время существуют два способа написания программ: снизу вверх и сверху вниз. При написании программы снизу вверх приступить к ее отладке невозможно, не завершив полностью разработку текста всей программы. При этом ошибка в написании (или понимании работы) крупных блоков программы приводит к тому, что даже правильно напи- написанные части программы приходится переделывать или выбрасывать полностью! Но наиболее неприятный момент заключается в том, что при таком методе программирования в программе содержится огромное ко- количество ошибок, каждая из которых может привести к неработоспособ- неработоспособности разрабатываемого устройства (мы помним, что в микроконтрол- микроконтроллерах именно программа во многом определяет работу устройства). И еще одна особенность написания и отладки программы для микрокон- микроконтроллеров и сигнальных процессоров. В отличие от универсальных ком- компьютеров никто не гарантирует, что правильно работает аппаратура! Возможна ситуация, что устройство не работает не из-за ошибки в про- программе, а из-за ошибки в схеме или ошибки монтажа! В процессе написа- написания и отладки программы для микроконтроллерного устройства произ- производится поиск ошибок не только в программном обеспечении, но и в схеме. При разработке программы сверху вниз на любом этапе она может быть оттранслирована и выполнена, при этом можно отследить выполнение всех фрагментов алгоритма, написанных к этому времени. Более того, разработку алгоритма можно объединить с его реализацией на языке программирования! Для этого можно воспользоваться подпрограммами. Выполняемое алгоритмическое действие обычно отображается в назва- названии подпрограммы. Это значительно повышает наглядность программы и тем самым скорость ее написания и отладки. Пример такого подхода показан в листинге 7.6. * • t • f ' ¦ , , , ¦ ¦. ....... . . . . [Листинг 7,§, Пример программы, в которой отдельным элементам алгоритма I соответствуют подпрограммы у**************************************** Подпрограмма чтения порта void ProchitatPort(void) {//Пока это только подпрограмма-заглушка! Подпрограмма включения индикатора
216 Глава 7 void Vklychitlndikator(void) {//Пока это только подпрограмма-заглушка! void main(void) {ProchitatPort (); //Прочитать порт Vklychitlndikator (); //Включить индикатор В листинге 7.6 текст программы практически не отличается от описания алгоритма. В начале процесса разработки программного обеспечения подпрограммы обычно еще не написаны. Для того чтобы можно было оттранслировать программу, можно воспользоваться механизмом за- заглушек. Подпрограмма-заглушка ничего не делает, но уже объявлена и имеет имя, совпадающее с тем действием, которое она должна будет в дальнейшем реализовать. Подпрограммы будут написаны позднее, когда уже будет отлажен верх- верхний уровень программы. При написании подпрограмм уже не нужно бу- будет заботиться о верхнем уровне, т. к. он уже к этому времени будет от- отлажен. Не потребуется также учитывать остальные подпрограммы, т. к. подпрограммы одного уровня не зависят друг от друга. Для улучшения восприятия текста программы, кроме «говорящих» на- названий подпрограмм широко используются «говорящие» имена пере- переменных. Особенно улучшается читаемость программы в том случае, если имена этих переменных связаны с аппаратурой микроконтроллерного устройства. Например, для микроконтроллера at89c5l можно назначить флагу за- завершения приема по последовательному порту ri имя BytePeredan. Тогда участок программы на языке программирования С-51, соответствующий ожиданию завершения приема байта последовательным портом, будет выглядеть следующим образом: if (BytePeredan) SBUF = SledujushchiyByte; При таком выборе имени переменной исходный текст программы прак- практически совпадает с фрагментом алгоритма, который этот участок про- программы реализует! В этом случае можно даже отказаться от применения комментария для пояснения фрагмента программы. Применение подпрограмм является не только средством структурирова- структурирования программы, но и существенно сокращает размер машинного кода, если подпрограммы многократно используются. Однако необходимо
Принципы создания программ для микроконтроллеров 217 отметить, что при использовании подпрограмм несколько уменьшается быстродействие устройства. В случае если для разрабатываемого устрой- устройства это недопустимо, вместо подпрограмм можно использовать макро- макросы, в названии которых точно так же будет отображаться выполняемое действие. Макрос, в отличие от подпрограммы, не передает управление в отдельную область памяти с последующим возвратом к следующему за вызовом подпрограммы оператору, а вызывает повторную подстановку одних и тех же команд столько раз, сколько в тексте программы встрети- встретилось имя макроса. Для образования макроса в программе на языке про- программирования С-51 достаточно объявить подпрограмму с префиксом inline. Основная идея структурного программирования заключаются в том, что существует только четыре структурных оператора. При использовании этих структурных операторов можно построить сколь угодно сложную программу. Линейная цепочка операторов Первая управляющая конструкция это линейная цепочка операторов. Она довольно часто используется, поскольку многие задачи могут быть раз- разбиты на несколько более простых последовательно выполняемых подза- подзадач. Однако такой подход достаточно очевиден и применялся с самого начала программирования. Недостаток прямого использования такого подхода — это то, что пока не написана вся программа целиком, ее нель- нельзя отлаживать. В результате отлаживаемая программа получается слож- сложной и в ней трудно найти ошибки. При использовании линейной цепочки операторов выполнение подзадач может быть поручено подпрограмме, в названии которой можно (и нуж- нужно) отразить подзадачу, которую должна решать эта подпрограмма. При этом вместо настоящих программ имеет смысл использовать подпро- подпрограммы-заглушки, принцип работы с которыми был рассмотрен ранее. Блок-схема стандартной структурной конструкции управления «линей- «линейная цепочка операторов» приведена на рис. 7.4. Поясним процесс преоб- преобразования этой блок-схемы в исходный текст программы. На момент написания алгоритма (и программы) верхнего уровня нам не известны детали их реализации, поэтому вместо настоящих подпро- подпрограмм, соответствующих элементам блок-схемы «Действие I» и «Дейст- «Действие 2», поставим подпрограммы-заглушки, которые ничего не делают! Однако в именах подпрограмм отразим те алгоритмические действия, которые они должны осуществлять в дальнейшем. Для отладки про- 8 Зак 328
218 Глава 7 граммы (и алгоритма) того уровня, который пишется в данный момент, неважно, что подпрограммы ничего не делают. Главное, что мы можем проверить, каков порядок вызовов подпрограмм, и соответствует ли он ожидаемому. На этом же этапе можно отладить взаимодействие между программами. I Действие 1 Действие 2 I | Рис. 7.4. Блок-схема конструкции управления «линейная цепочка операторов» Для этого мы можем произвести трансляцию программы и на отладчике проследить все действия программы. Возможность производить транс- трансляцию и отладку программы на любом этапе ее написания позволяет на- находить ошибки сразу же после написания оператора! Ведь если мы напи- написали только один оператор, то и совершить ошибку мы могли только в этом месте! То есть процесс поиска ошибки существенно упрощается. А ведь процесс написания программы на 90% состоит из поиска ошибок. После завершения отладки программы (и алгоритма!) текущего уровня можно перейти к написанию и отладке любой из подпрограмм, т. е. к превращению подпрограммы-заглушки в нормальную отлаженную про- программу. При этом очень важно заметить, что подпрограммы отлажива- отлаживаются независимо друг от друга, что значительно облегчает написание программы (да и чтение этой программы в дальнейшем). Пример использования подпрограмм-заглушек для реализации конст- конструкции управления «линейная цепочка операторов» на языке програм- программирования С-51 приведен в листинге 7.7, а на языке программирования ASM-51 — в листинге 7.8. Как видно из приведенного в листинге 7.7 исходного текста программы, для организации подпрограммы-заглушки на языке программирования С-51 достаточно определить подпрограмму, не помещая в ее тело ни од- одного оператора. При этом объявление подпрограммы-заглушки должно быть точно таким же, как у подпрограммы в готовой написанной и от- отлаженной программе.
Принципы создания программ для микроконтроллеров 219 «линейная цепочка операторов» /•••••••••••••••••••••••••••••••••••••••••••••• Определения подпрограмм •••••••••••••••••••••••••••••••••••••••••••••••у void Deistviel(void) {//Пока это только подпрограмма-заглушка! void Deistvie2(void) {//Пока это только подпрограмма-заглушка! /•*•••••••••••••••+•••••••••••••••••••••••*• Главная программа ••••••••••••••••••••••••••••••••••••••••••••у Deistviel();//Подпрограмма 1 Deistvie2();//Подпрограмма 2 На языке программирования ASM-51 имя подпрограммы совпадает с меткой в начале подпрограммы. Однако, в отличие от языков програм- программирования высокого уровня, для организации подпрограммы-заглушки один исполняемый оператор все-таки нужен. Это оператор возвращения из подпрограммы ret. И еще одно замечание. При программировании на языке ассемблера первый написанный оператор и выполняется первым. Для того чтобы исключить возможность случайного попадания в под- подпрограмму не по вызову подпрограммы, подпрограммы обычно распо- располагаются в конце исходного текста программы, за обязательным беско- бесконечным циклом основной программы. Иногда подпрограммы все же располагаются до основной программы, сразу за векторами прерывания, но в этом случае все подпрограммы обходятся при помощи команды без- безусловного перехода ljmp. управления «линейная цепочка операторов)» .••••••••••••••••••••••••••••••••••••••••••••••••it**** /Главная программа (с обязательным бесконечным циклом)
220 Глава 7 call Deistviel /Подпрограмма 1 call Deistvie2 /Подпрограмма 2 ;Определения подпрограмм r ;—Пока это только подпрограмма-заглушка! Deistviel: ret ;—Пока это только подпрограмма-заглушка! Deistvie2: ret Условное выполнение операторов Вторая конструкция управления называется условным выполнением опе- операторов. Достаточно часто одно или другое действие должно исполнять- исполняться в зависимости от определенного условия, которое зависит от резуль- результатов выполнения предыдущей части программы или от состояния (сигналов) внешних устройств. Блок-схема конструкции управления «условное выполнение операторов» приведена на рис. 7.5. Да Действие 1 I Нет | Действие 2 J Рис. 7.5. Блок-схема конструкции управления «условное выполнение операторов» Как видно из приведенной в листинге 7.9 программы на языке С-51, кон- конструкция условного выполнения операторов реализуется благодаря встроенным средствам самого языка С-51, т. к. он относится к структу-
Принципы создания программ для микроконтроллеров 221 рированным языкам программирования. В приведенном примере под- подпрограммы-заглушки использованы для отображения названий частей условного оператора. В структурированных языках программирования второе плечо услов- условного оператора записывается после зарезервированного слова «else». В случае необходимости использования в любом из плеч нескольких операторов применяется структурный оператор «линейная цепочка опе- операторов», реализация которого была описана ранее. Определения подпрограмм void Deistviel (void) {//Пока это только подпрограмма-заглушка! void Deistvie2(void) {//Пока это только подпрограмма-заглушка! Главная программа if(PrinjatByte)//Выражение Deistviel();//Реализация ветви 1 else Deistvie2();//Реализация ветви 2 Пример реализации конструкции управления «условное выполнение операторов» на языке программирования ASM-51 приведен в листин- листинге 7.10. Язык программирования ASM-51 не является структурирован- структурированным, поэтому для реализации конструкции условного выполнения опе- операторов приходится использовать несколько команд микропроцессора (операторов языка программирования ассемблер).
222 Глава 7 Для реализации блока «логическое выражение», изображенного на рис. 7.5 в виде ромба, можно использовать любую команду условного перехода, входящую в систему команд микропроцессора. При этом в простейшем случае логическое выражение сводится к анализу сигналов на выводах микроконтроллера или его внутренних флагов. Но в отличие от двумерной блок-схемы, память программ микропроцессора одномер- одномерна, т. е. все команды располагаются друг за другом. Для того чтобы вы- выполнялся только один из операторов («Действие 1» или «Действие 2»), необходимо после выполнения одного из них обойти другой. Это можно осуществить при помощи команды безусловного перехода. Размещение различных частей конструкции управления «условное вы- выполнение операторов» в памяти программ микропроцессора приведены на рис. 7.6. Направления возможных переходов при ее выполнении пока- показаны на этом же рисунке. При использовании такой конструкции будет выполнены только один из операторов. Какой — зависит от результатов выполнения условного выражения. Г .V V ! Листинг 7,10. Реализация конструкции управления «условное аолеЖ^^Ш ***************************************************************** ;Главная программа ; Условное выполнение операторов jb PrinjatByte,ElseUsl;Условное выражение Call Deistviel ;Реализация jmp EndUsl /первой ветви ElseUsl: Call Deistvie2 ;Реализация ветви 2 EndUsl:; ;Определения подпрограмм ;—Пока это только подпрограмма-заглушка! Deistviel:/Метка относится к следующему оператору ret
Принципы создания программ для микроконтроллеров 223 ;—Пока это только подпрограмма-заглушка! Deistvie2:;Метка относится к следующему оператору ret В листинге 7.10 проявляется еще одно полезное свойство подпрограмм. Команды условного перехода, используемые для реализации условного выражения, могут передавать управление на участок программы, от- отстоящий от них не более чем на 127 байтов. Однако для реализации алгоритма одной из ветвей может потребоваться большее количество команд. Выделение их в отдельную подпрограмму позволяет сократить необходимое расстояние условного перехода до трех байт (длины коман- команды вызова подпрограммы LCALL). Подпрограмма может быть разме- размещена в любом месте памяти программ микроконтроллера. Условный переход Deistviel Безусловный переход Deistvie2 Рис. 7.6. Размещение различных частей конструкции управления условным выполнением операторов в памяти программ микропроцессора Конструкция условного выполнения операторов может использоваться в неполном варианте, когда присутствует только один оператор. Для ее реализации не обязательно использовать команду безусловного перехо- перехода. Она легко реализуется одной командой условного перехода, входя- входящей в состав системы команд любого микропроцессора (а значит и языка программирования ассемблер для него). Однако если система команд микропроцессора неполная (например, есть команда проверки на равен- равенство, но нет проверки на неравенство), то для реализации противопо-
224 Глава 7 ложного оператора тоже может потребоваться команда безусловного перехода. Блок-схема и примеры реализации конструкции управления условным выполнением одного оператора на языках программирования С-51 и ASM-51 приведены на рис. 7.7 и в листингах 7.11 и 7.12. Каждый из ис- исходных текстов содержит очень подробные комментарии, поэтому до- дополнительные пояснения не понадобятся. Да Логическое выражение j Нет j Рис. 7.7. Блок-схема конструкции управления условным выполнением одного оператора шшшшжетшш11Ш Определения подпрограмм ••••••••••••••••••••••••••••••••••••••••• void Deistviel(void) {//Пока это только подпрограмма-заглушка! Главная программа ******************************************** if(PrinjatByte)//Условное выражение Deistviel(); //Реализация ветви
Принципы создания программ для микроконтроллеров 225 конструкции управления условным выполнением /Главная программа ;—конструкция управления условным выполнением одного оператора- jb PrinjatByte, EndUsl;Условное выражение call Operatorl ; Реализация ветви EndUsl:; ; Определения подпрограмм ;— Пока это только подпрограмма-заглушка! Operatorl:; Метка относится к следующему исполняемому оператору ret Конструкция управления циклическим выполнением оператора с проверкой условия после тела цикла Третья конструкция управления — это циклическое выполнение операто- оператора с проверкой условия после тела цикла. Оператор (или операторы), ко- который должен повторяться в процессе выполнения этой конструкции, называется телом цикла. В процессе выполнения этих операторов обыч- обычно модифицируется некоторая переменная, значение которой влияет на завершение цикла. Эта переменная получила название «параметр цикла». Отметим, что параметр цикла может изменяться и аппаратурой, под- подключенной к микроконтроллеру или входящей в его состав. Блок-схема конструкции управления циклическим выполнением опера- оператора с проверкой условия после тела цикла приведена на рис. 7.8. На- Напомню, что в качестве тела цикла можно использовать любую структур- структурную конструкцию, в том числе и еще один оператор цикла. На языках программирования высокого уровня такая конструкция вхо- входит в состав языка (оператор do ... while в языке программирования С или оператор repeat ... until в языке программирования PASCAL). При-
226 Глава 7 мер использования циклического выполнения оператора с проверкой условия после тела цикла на языке программирования С приведен в лис- тин- тинге 7.13. Обратите внимание, что в приведенном примере в качестве логи- логического выражения использована константа — единица. Это приводит к бесконечному циклу, эквивалентному безусловной передаче управления на начало тела цикла при помощи ассемблерной команды jmp. Тело цикла Логическое выражение Рис. 7.8. Блок-схема конструкции управления циклическим выполнением оператора с проверкой условия после тела цикла У**************************************** Определения подпрограмм ••••••••••••••••••••••••••••••••••••••••• void TeloCikla(void) {//Пока это только подпрограмма-заглушка! '••••^••••••••••••••••••••••••••••••••••*-**-*- Главная программа do TeloCikla();//Реализация тела цикла whileA);
Принципы создания программ для микроконтроллеров 227 Не сложнее реализуется эта структурная конструкция управления и на языке программирования ассемблер при помощи команды условного или безусловного (для организации бесконечного цикла) перехода. Реа- Реализация конструкции цикла с проверкой условия после тела цикла очень похожа на реализацию конструкции условного выполнения оператора. Отличие заключается в том, что передача управления в команде услов- условного перехода осуществляется не вперед, как при условном выполнении оператора, а назад, на начало цикла. В системе команд микроконтролле- микроконтроллеров семейства MCS-51 для реализации цикла с проверкой условия после тела цикла введена специальная команда - djnz. Она позволяет реализо- реализовать сразу два алгоритмических действия: вычитания единицы из пара- параметра цикла и проверку содержимого параметра цикла на равенство ну- нулю. Для обозначения начала тела цикла в программе на языке программирования ассемблер применяется метка. Пример реализации оператора цикла с проверкой условия после тела цикла на языке программирования ASM-51 приведен в листинге 7.14. В этом примере предполагается опрос бита завершения приема байта по- последовательным портом RI, который объявлен где-то в тексте програм- программы как переменная PrinjatByte. И$ации цикла с проверкой условия после тела цикла .••••••••••••••••••••••••••••••••••••••••••••• ;Главная программа Nachalo:;- конструкция управления циклическим выполнением оператора- call TeloCikla ;Реализация тела цикла jb PrinjatByte,Nachalo;Условное логическое выражение ;Определения подпрограмм ;—Пока это только подпрограмма-заглушка! -¦ TeloCikla: ret ;Оператор помечен предыдущей меткой
228 Глава 7 Структурная конструкция циклического выполнения оператора с проверкой условия до тела цикла Четвертая структурная конструкция управления — это цикл с проверкой условия до тела цикла. В отличие от предыдущего оператора тело цикла в этом операторе может ни разу не выполниться, если условие заверше- завершения цикла сразу же выполнено. Блок-схема цикла с проверкой условия до тела цикла приведена на рис. 7.9. Логическое выражение Рис. 7.9. Блок-схема структурной конструкции управления «циклическое выполнение оператора с проверкой условия до тела цикла» Конструкция цикла с проверкой условия до тела цикла может быть реа- реализована при помощи средств, входящих в состав языка программиро- программирования С-51, как впрочем и других языков, предназначенных для разра- разработки структурированных программ. Пример использования цикла с проверкой условия до тела цикла в про- программе, написанной на языке программирования С-51, приведен в лис- листинге 7.15. Как и в предыдущих случаях, для иллюстрации возможности повысить наглядность текста программы за счет использования пра- правильно выбранных названий подпрограмм функция, выполняемая в теле ЦИКЛа, названа TeloCikla. • АМ»,1М/М«)«МДМ &:;PP9jf$$J#^^ ******************************************** Определения подпрограмм ********************************************
Принципы создания программ для микроконтроллеров 229 void TeloCikla(void) {//Пока это только подпрограмма-заглушка! /******************************************* Главная программа I while (KnNaj) TeloCikla();//Реализация тела цикла Пример реализации цикла на языке программирования ASM-51 приве- приведен в листинге 7.16. Эту конструкцию, как и условное выполнение опера- операторов, невозможно реализовать при помощи одной машинной команды, поэтому реализуем его при помощи команд условного и безусловного перехода. На этот раз команда безусловного перехода помещается в ко- конец конструкции и осуществляет переход на команду проверки условия, т. е. на начало конструкции. Команда безусловного перехода sjmp пере- передает управление на начало цикла после выполнения его тела. Располо- Расположенная за командой безусловного перехода метка Koncykia обозначает команду, на которую передается управление, когда прекращается вы- выполнение цикла. использования цикла с проверкой условия ш йа языке программирования ASM-51 .******************************************************************** г /Главная программа .******************************************************************** Nachalo:; Оператор цикла jb KnNaj,KonCikla /Проверка условия завершения цикла Call TeloCikla ;Тело цикла sjmp Nachalo KonCikla:;
230 Глава 7 • к-к ;Определения подпрограмм ;—Пока это только подпрограмма-заглушка! -¦ TeloCikla: ret /Оператор помечен предыдущей меткой Понятие многофайлового и многомодульного программирования В процессе написания программ обычно накапливаются подпрограммы и фрагменты кода, которые можно использовать в нескольких програм- программах. Фрагменты исходного кода можно копировать из программы в про- программу при помощи текстового редактора, в котором вы пишете про- программы, однако это может привести к некоторым неудобствам. Прежде всего, разрастается текст программы, и в нем становится трудно ориен- ориентироваться при написании и редактировании программы. Кроме того, при обнаружении ошибок в отлаженном ранее участке кода или при пе- переходе к работе с другими устройствами (от светодиодного индикатора к жидкокристаллическому, от микросхемы АЦП одного типа к микро- микросхеме другого типа) приходится искать включенные ранее участки кода и заменять их новыми. Это трудоемкая работа, которая приводит к ошибкам и, в конечном сче- счете, замедляет написание и отладку программ. Но как же решить эту про- проблему? Намного удобнее использовать и хранить исходный текст про- программы в нескольких файлах, предоставляя работу по соединению этих файлов в единую программу транслятору. Обычно в один файл помеща- помещается участок кода, работающий с каким-либо конкретным устройством (жидкокристаллическим индикатором, последовательной микросхемой ПЗУ и т. д.) или отвечающий за определенную задачу (вывод цифровой и текстовой информации, помехоустойчивое кодирование, прием управ- управляющих сигналов). Использование готовых участков кодов позволяет собирать новые про- программы из готовых кусков как в детском конструкторе. Правда, не стоит надеяться, что эти куски будут так же легко соединяться!
Принципы создания программ для микроконтроллеров 231 Многофайловые программы Самым простым способом соединения нескольких файлов в одну про- программу является использование директивы включения текстового файла. В языке программирования ASM-51 это директива include. Точно так же, только буквами нижнего регистра записывается эта директива и в языке программирования С. При использовании директивы include в исходный текст программы до- добавляется содержимое включаемого файла, и только после этого произ- производится трансляция исходного текста в исполняемый код программы. Иными словами, содержимое главного файла программы и включаемых в него файлов объединяются препроцессором транслятора во временном файле, и только после этого производится трансляция полученного вре- временного файла в исполняемый код микроконтроллера. Пример исполь- использования директивы включения текстового файла в программе на языке программирования С-51 приведен в листинге 7.17. а языт С-51, использующей >. #include <global.h> /* Добавление файла определений переменных, связанных с выводами микросхемы*/ #include <reg51.h> /* Добавление файла описаний регистров специальных функций микроконтроллера */ #include <IO.h> /^Подключить файл с подпрограммами, осуществляющими ввод и вывод данных в микросхему микроконтроллера*/ ... /* Остальная часть программы */ В отдельные файлы выделяются, как правило, описания внутренних ре- регистров микроконтроллера и переменных, связанных с выводами микро- микросхемы микроконтроллера. Рассмотрим для примера содержимое вклю- включаемых файлов, имена которых использованы в примере, приведенном в листинге 7.17. Фрагменты исходных текстов этих файлов приведены в листингах 7.18 и 7.191. Содержимое файла IO.h является примером использования отдельного файла для хранения функций, осуществляющих ввод и вывод данных. Такое использование включаемых файлов позволяет разделить програм- программу по функциям. В результате новые программы можно собирать из та- 1 Листинги 7.18 и 7.19 являются фрагментами проектов, для трансляции которых исполь- использовался компилятор Keil-C. — Прим. ред.
232 Глава 7 ких файлов как из кирпичиков, используя готовые уже отлаженные под- подпрограммы. Таким образом, использование включаемых файлов резко упрощает программирование. void UART (void) interrupt 4 {register char tmp; if(RI) {RI=0; tmp=SBUF; *ptrBufUART++=tmp; } if(tmp==10) {msgRsvd=l; *ptrBufUART=O; return; /••••••••••••••••••••••••••••••••••••••••••••••••••• Подпрограмма преобразования тетрады в символ • •••••••••••••••••••••••••••••а-***** char Hex(char Nible) {Nible&=0x0f; if(Nible>=10)return(Nible+='7'); return(Nible+='0'); Подпрограмма преобразования слова управления устройством в строку, завершенную нулем •••••••••••••••••*••••*•*•**•••*••••*••************^ void LongToHex(char data *s,void data *Byte,unsigned char i) {unsigned char tmp; do{tmp=*(char data*)Byte;
Принципы создания программ для микроконтроллеров 233 Byte+=1; s++ =Hex(tmp>>4); *s++ =Hex(tmp); }while(--i!=O) ; *s =0; В файле REG51.h объявляются переменные, связанные с регистрами спе- специального назначения микроконтроллера 89с51. Они должны использо- использоваться в любой программе, работающей с микроконтроллером 89с51. Не имеет смысла повторять эти объявления в каждой программе — их мож- можно выделить в отдельный файл, что и сделано в приведенном в листин- листинге?.^ примере. Более того, файлы объявления регистров специальных функций для различных типов микроконтроллеров обычно поставляют- поставляются разработчиками компиляторов для исключения ошибок. /* REG51.H Файл объявления внутренних регистров для микроконтроллеров 80С51 и 80С31. */ /* BYTE Register */ sfr P0 = 0x80; sfr PI = 0x90; sfr P2 = OxAO; sfr P3 = OxBO; sfr PSW = OxDO; sfr ACC = OxEO; sfr В = OxFO; sfr SP = 0x81; sfr DPL = 0x82; sfr DPH = 0x83; sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A;
234 Глава 7 sfr ТЫ = 0х8В; sfr THO = 0х8С; sfr TH1 = 0x8D; sfr IE = 0xA8; sfr IP = 0xB8; sfr SCON = 0x98; sfr SBUF = 0x99; Файл объектного кода программы, который будет преобразован в ма- машинные коды микроконтроллера, формируется программой-транс- программой-транслятором в процессе обработки исходного текста программы. Как уже упоминалось ранее, прежде чем начать собственно преобразование ис- исходного текста программы, транслятор производит предварительную обработку программы, в процессе которой выполняются директивы ус- условной трансляции, включения содержимого дополнительных файлов и макроподстановок. Часто говорят, что перед трансляцией программы работает препроцессор. В результате этой предварительной обработки программы транслятор формирует временный файл. Например, в результате выполнения участ- участка программы, приведенного в листинге 7.17, будет сформирован вре- временный файл, содержание которого приведено в листинге 7.20. Именно этот файл и будет преобразован в машинные коды микроконтроллера, которые будут сохранены на жестком диске компьютера в виде загрузоч- загрузочного файла. Листинг 7,20. Временный файл, полученный в результате работь* препроцессора /* 10. Н void UART (void) interrupt 4 {register char tmp; if(RI) {RI=0; tmp=SBUF; *ptrBufUART++=tmp; } if(tmp==10)
Принципы создания программ для микроконтроллеров 235 {msgRsvd=l; *ptrBufUART=O; return; Подпрограмма преобразования тетрады в символ char Hex(char Nible) {Nible&=0x0f; if(Nible>=10)return(Nible+='71); return(Nible+='0'); /••••••*••••••••••••*•*•••••••••*••••••••*•••*••*•••*••**• Ar**^ Подпрограмма преобразования слова управления устройством в строку, завершенную нулем void LongToHex(char data *s, void data *Byte, unsigned char i) {unsigned char tmp; do{tmp=*(char data*)Byte; Byte+=1; *s++ =Hex (tmp»4) ; *s++ =Hex(tmp); }while(~i!=0) ; *s =0; i /•*•«.«.«.«. — ~ REG51.H Файл объявления внутренних регистров для микроконтроллеров 80С51 и 80С31. */ /* BYTE Register */ sfr P0 = 0x80; sfr PI = 0x90;
236 Глава 7 sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr sfr P2 P3 PSW = ACC = в = SP DPL = DPH = PCON = TCON = TMOD = TLO = TL1 = THO = TH1 = IE IP SCON = SBUF = OxAO; OxBO; OxDO; OxEO; OxFO; 0x81; 0x82 ; 0x83; 0x87 ; 0x88; 0x89; 0x8 A; 0x8B; 0x8C ; 0x8D; 0xA8; 0xB8; 0x98; 0x99; Подведем итоги. При многофайловом программировании: ? использование нескольких файлов позволяет разбить исходный текст программы на несколько частей, каждая из которых реализует свою независимую задачу; ? удобнее всего в отдельные файлы выносить подпрограммы, которые должны быть построены таким образом, чтобы их связь с основной программой была минимальной; ? разбираться с короткими файлами, реализующими одну или несколь- несколько связанных между собой функций, намного легче, чем работать с одним большим файлом; ? различные части программы могут быть написаны разными програм- программистами, которым намного легче работать со своей программой, оформленной в виде отдельного файла. Разбивать на несколько файлов можно не только программы, исходный код которых разработан на языках высокого уровня. Включение файлов можно использовать и в программах на языке ассемблера. В листинге 7.21 приведен пример использования включения файлов в программе на языке ASM-51.
Принципы создания программ для микроконтроллеров 237 $include (stdio.asm) ; включение Файла ; с функциями стандартного ввода-вывода $include (reg51.inc) ; включение Файла с описаниями ; регистров специальных функций микроконтроллера /Остальная часть программы В результате работы программы-транслятора, точно так же, как и в пре- предыдущем примере, будет сформирован временный файл, в который будет помещена информация из обоих включаемых файлов. И только затем будет осуществлена трансляция этого временного файла. С разбиением программы на несколько файлов связано понятие про- программного проекта. В состав программного проекта включают все фай- файлы, содержащие исходный текст программы. Обычно программный про- проект размещают в отдельном каталоге. Кроме исходных текстов программы, в состав проекта входит загрузоч- загрузочный файл, в который помещаются машинные коды микроконтроллера, полученные в результате трансляции программы. Очень часто они хра- хранятся в файле не непосредственно в двоичном виде, а в специальном формате, который позволяет исключить ошибочную запись неправиль- неправильного кода в микроконтроллер. Наибольшее распространение получил НЕХ-формат загрузочного файла. Еще один файл, который обычно включается в состав программного проек- проекта, — это файл листинга компилятора, в который помещается исходный текст программы, машинные коды в текстовом виде и сообщения об ошиб- ошибках. Этот файл облегчает поиск и исправление синтаксических ошибок.2 Многомодульные программы Разбиение исходного текста программы на несколько файлов делает его более понятным для программистов, участвующих в создании про- 2 Существует также точка зрения, согласно которой файл листинга не является при- принадлежностью программного проекта, поскольку он не нужен для компиляции и компоновки. Этот файл вырабатывается компилятором, если заданы соответствую- соответствующие командные опции, и служит для отладки, поскольку помогает показать соответ- соответствие между исходным кодом С-программы и командами машинного кода. В совре- современных отладчиках (например, C-SPY фирмы IAR) необходимое соответствие устанавливается самим отладчиком. — Прим. ред.
238 Глава 7 граммного продукта. Однако при использовании этих файлов при по- помощи директив включения остаются нерешенными еще несколько задач: ? программа-транслятор работает со всем исходным текстом целиком, ведь она соединяет все файлы перед трансляцией вместе. Поэтому время трансляции исходного текста программы получается значи- значительным. В то же самое время программа никогда не переписывается целиком. Обычно изменяется только небольшой участок программы. В связи с этим значительные затраты времени на компиляцию пред- представляются необоснованно большими; ? максимальное количество имен переменных и меток бывает ограниче- ограничено программой-транслятором и может быть исчерпано при написании исходного текста программы, если он достаточно велик; ? различные программисты, участвующие в создании программного продукта, могут назначать одинаковые имена для своих переменных и при попытке соединения таких файлов в единую программу обычно возникают проблемы. Все эти проблемы могут быть решены при раздельной трансляции про- программы. То есть было бы неплохо уметь транслировать каждый файл с исходным текстом части программы отдельно и соединять затем готовые оттранслированные участки в конечную программу. Компиляторы, которые позволяют транслировать отдельные участки программы, называются компиляторами с раздельной трансляцией. Часть программы, которая может быть отдельно оттранслирована, на- называется программным модулем. Оттранслированный программный мо- модуль сохраняется в виде отдельного файла в объектном формате, где, кроме машинных команд, сохраняется информация об именах перемен- переменных, адресах команд, требующих модификации при объединении моду- модулей в единую программу, и отладочная информация. Одновременно с объектным файлом может создаваться листинг этого модуля. Создание загрузочного файла программы при раздельной трансляции производится с использованием двух программ: транслятора исходного текста и редактора связей объектных файлов. Программа редактор связей позволяет объединять несколько объектных файлов в один исполняемый файл. Для этого имена всех объектных фай- файлов передаются в программу редактора связей в качестве параметров. Вот как выглядит вызов редактора связей из командной строки DOS для объединения трех модулей: rl51.exe progr.obj, modull.obj, modul2.obj
Принципы создания программ для микроконтроллеров 239 В результате работы редактора связей, вызванного при помощи приве- приведенной командной строки, будет создан исполняемый файл программы с именем progr. При использовании интегрированной среды программирования, входя- входящей в состав большинства современных инструментальных средств раз- разработки программного обеспечения микроконтроллеров, работа с ре- редактором связей значительно упрощается. Для объединения нескольких модулей в загрузочный файл достаточно создать программный проект, в который включены необходимые файлы с исходным кодом. На первый взгляд раздельная трансляция не должна вызывать каких- либо проблем. Однако это не так. В процессе компиляции исходного тек- текста программы транслятор, обрабатывая определения переменных, кон- констант и операторы, составляет таблицу ссылок. Если при втором про- просмотре исходного текста программы, во время которого формируется объектный модуль, транслятор обнаружит в выражении или операторе имя переменной или метки, отсутствующее в таблице, то будет сформи- сформировано сообщение об ошибке и объектный файл будет стерт с диска компьютера. Для того чтобы транслятор вместо формирования сообщения об ошибке записал в объектный файл информацию, необходимую для работы ре- редактора связей, нужно использовать специальные директивы ссылок на внешние (определенные в других модулях) переменные или метки. В язы- языке программирования ASM-51 эти директивы называются PUBLIC (общедоступные) и EXTRN (внешние). Для ссылки на переменную или метку из другого программного модуля служит директива EXTRN. В ней перечисляются через запятую метки и переменные, точное значение которых редактор связей должен получить из другого модуля и модифицировать все команды, в которых эти метки или переменные используются. Пример применения директивы EXTRN в программе на языке программирования ASM-51: EXTRN DATA (Buflnd, ERR) EXTRN CODE (Podprogr) Для того чтобы редактор связей мог осуществить связывание модулей в единую программу, переменные и метки, объявленные, по крайней мере, в одном из модулей как extrn, в другом модуле должны быть объявлены как доступные для всех модулей при помощи директивы public. Пример использования директивы public на языке программирования ASM-51: PUBLIC Buflnd, Parametr PUBLIC Podprogr, ?Podprogr?Byte Использование нескольких модулей при разработке программы увели- увеличивает скорость трансляции и, в конечном итоге, скорость написания
240 Глава 7 программы. Однако объявления переменных и имен подпрограмм внеш- внешних модулей загромождают исходный текст модуля. Кроме того, при ис- использовании чужих модулей трудно объявить переменные и подпро- подпрограммы без ошибок. Поэтому объявления переменных, констант и предварительные объявления подпрограмм хранят во включаемых фай- файлах, которые называются файлами-заголовками. Правилом хорошего тона считается при разработке программного модуля сразу же написать для него файл-заголовок, который может быть использован программи- программистами, работающими с вашим программным модулем. Из всего рассмотренного ранее понятно, что большую программу можно разделить на части. Остается открытым вопрос — как разделять единую программу на части, ведь это же цельный организм, который живет и развивается по мере разработки программы! Как найти часть програм- программы, наименьшим образом связанную с остальными частями? А искать особенно и не нужно! Ведь у нас уже есть такие части, которые связаны с остальной программой либо одним, либо несколькими заранее огово- оговоренными и неизменными параметрами! Это подпрограммы. Именно подпрограммы обычно выносят в отдельные модули. При этом стараются собрать в одном модуле подпрограммы, решающие подобные задачи. Например, в один модуль можно поместить подпрограммы, вы- вычисляющие математические функции, такие как синус, косинус, тангенс или котангенс. В другой модуль можно поместить подпрограммы, отве- отвечающие за ввод и вывод информации из вашего устройства. В третьем модуле собрать подпрограммы, осуществляющие кодирование и декоди- декодирование информации. Такое разделение программы на отдельные модули позволяет либо при- привлечь для написания программных модулей специалистов, хорошо раз- разбирающихся в данной области, либо решать поставленную задачу по частям. Если модули выделены правильно, то зависимости между от- отдельными частями программы получаются минимальными и изменения в одной из них минимально затрагивают другие или вовсе на них не влия- влияют. Многомодульность дает значительный выигрыш в скорости разра- разработки программы. Дополнительный выигрыш получится при написании следующих программ, т. к. в них вы сможете использовать готовые напи- написанные и отлаженные модули. Наиболее ярким примером использования модулей являются языки про- программирования высокого уровня, такие как С. Ведь никому не приходит в голову писать собственные программы вычисления синусов и косину- косинусов или функции ввода-вывода для этого языка! Используются готовые подпрограммы.
Принципы создания программ для микроконтроллеров 241 Программа-монитор Разработка программ для микропроцессоров происходит во многом иначе, чем для универсального компьютера. При выполнении програм- программы на универсальном компьютере ее запуск, взаимодействие с внутрен- внутренними и внешними устройствами или человеком берет на себя операцион- операционная система. Программа, написанная для микроконтроллера, должна решать все эти задачи самостоятельно. Программа универсального ком- компьютера когда-нибудь запускается и завершается. Программа, управ- управляющая микроконтроллером, запускается при включении устройства и не завершает свою работу, пока не будет выключено питание. Рассмотрим программу для микроконтроллера, которая будет выпол- выполнять поставленные задачи. Назовем эту программу «монитор», посколь- поскольку она «наблюдает» за использованием ресурсов системы. Схема алго- алгоритма программы-монитора приведена на рис. 7.10. После включения питания эта программа должна настроить микросхему микроконтролле- микроконтроллера для выполняемой разрабатываемым устройством задачи. Для этого она должна запрограммировать определенные выводы микросхемы мик- микроконтроллера на ввод или вывод информации, включить и настроить внутренние таймеры и т. д. Этот блок алгоритма программы-монитора называется инициализацией процессора. Инициализация микроконтрол- микроконтроллера выполняется только один раз. Повторно она может потребоваться только при сбоях в работе микроконтроллера. Устранение таких сбоев производится аппаратным сбросом микроконтроллера. Основная часть программы, реализующая алгоритм работы устройства, начинает выполняться после инициализации микроконтроллера. При этом необходимо понимать, что если в устройствах, не содержащих про- программно-управляемых компонентов, ввод, обработка и вывод информа- информации производятся различными аппаратными блоками, то при выполне- выполнении программы эти же действия производятся последовательно одним и тем же устройством — микропроцессором. Для выполнения каждой за- задачи обычно пишется отдельная подпрограмма. То есть при программ- программной реализации устройства подпрограмма выполняет те же функции, что и отдельный блок при схемотехнической реализации устройства. Точно так же, как и при аппаратной реализации различных блоков уст- устройства, необходимо, чтобы каждая подпрограмма решала свою кон- конкретную задачу. При написании программы очень часто возникает со- соблазн решать проблемы в месте их возникновения. В результате появляется огромное количество участков кода, занимающихся вводом информации, еще столько же участков, занимающихся управлением од-
242 Глава 7 ним и тем же устройством. Гораздо лучше, если вводом информации за- занимается одна подпрограмма, для управления устройством, подключен- подключенным к микроконтроллеру, служит другая подпрограмма, а общий алго- алгоритм работы устройства формирует третья подпрограмма. При этом нельзя допускать ситуации, когда подпрограмма ввода информации тут же пытается обработать полученные данные, и тем более начать управ- управление каким-либо устройством. ^ Включение питания^ г Инициализация г Сбор информации г Обработка > г Обработка ошибок Рис. 7.10. Схема алгоритма программы-монитора Для того чтобы работали все написанные подпрограммы, они включа- включаются в один бесконечный цикл. Это эквивалентно периодическому за- запуску аппаратных блоков. Соединению между блоками соответствует взаимодействие частей программы, осуществляемое при помощи гло- глобальных переменных. В этом же цикле обычно предусматривается блок обработки ошибок. Его предназначение сообщать оператору (пользо- (пользователю) о непредвиденной ситуации, такой как неправильный ввод с клавиатуры или неправильные данные, полученные от подключенного к микроконтроллеру устройства. Приведем пример реализации такого алгоритма работы программы. Для написания программы воспользуемся принципами структурного про- программирования, рассмотренными ранее. В этом случае для проверки правильности работы программы можно воспользоваться программами- заглушками. Исходный текст программы, реализующей алгоритм про- программы-монитора, схема которого показана на рис. 7.10, приведен в лис- листинге 7.22.
Принципы создания программ для микроконтроллеров 243 пгйиг 7,22, Пример реализации программы-монитора на языке С-51 / * Подпрограмма инициализации микроконтроллера * I void Init(void) { //По мере написания программы здесь будут добавляться операторы, //настраивающие элементы внутренней структуры микроконтроллера //на необходимый режим работы.} / * Подпрограмма опроса клавиатуры * / void Sborlnf (void) / -ic _ Подпрограмма обработки информации void Obrablnf (void) {//В этой подпрограмме обычно осуществляется переключение //режимов работы устройства} i ^ Подпрограмма обработки ошибок . * void ObrabOshib(void) {//В этой подпрограмме обычно осуществляется индикация //ошибочного ввода информации с клавиатуры} void main(void) {InitO; whileA) {Sborlnf() ; Obrablnf(); ObrabOshib();}
244 Глава 7 Как видно из приведенного текста, программа еще ничего не делает. Все будущие действия обозначены в именах подпрограмм-заглушек, однако эта программа уже может быть оттранслирована и запущена. В отладчи- отладчике можно проверить, что при включении устройства мы действительно попадаем в подпрограмму инициализации, а затем последовательно вы- вызываются подпрограммы сбора и обработки информации, а также под- подпрограмма обработки ошибок. При использовании нескольких подпрограмм встает проблема обмена информацией между ними. Как уже рассматривалось ранее, информация в подпрограмму может быть передана через параметры или через гло- глобальные переменные. При создании программы-монитора может потре- потребоваться передавать одну и ту же информацию нескольким подпрограм- подпрограммам (что аналогично параллельному соединению аппаратных блоков), поэтому в мониторе информация обычно передается через глобальные переменные, которые последовательно подвергаются обработке всеми подпрограммами, включенными в бесконечный цикл. Рассмотрим подробнее, как реализуется чтение информации с выводов микроконтроллера. Очень важно, чтобы сигналы со всех выводов считы- вались одновременно, иначе можно получить комбинации битов, не соот- соответствующие действительности. Иллюстрация такой ситуации приведена на рис. 7.11. В результате опроса сигналов в контроллер будет введен код 000, который никогда не присутствовал на выводах микросхемы! ж Опрос 1 Опрос 3 иг Опрос 2 \ Г Рис. 7.11. Пример неодновременного опроса сигналов на выводах микроконтроллера К сожалению, микроконтроллер может опрашивать порты только по- последовательно. Тем не менее, благодаря его высокому быстродействию можно обеспечить почти одновременное считывание информации со всех выводов микросхемы, поэтому вероятность возникновения ситуации, представленной на рис. 7.11, невысока.
Принципы создания программ для микроконтроллеров 245 В качестве примера рассмотрим ввод информации с 16-кнопочной кла- клавиатуры. Программа для микроконтроллера жестко зависит от принци- принципиальной схемы разрабатываемого устройства. Невозможно написать программу для микроконтроллерного устройства, не имея перед глазами его принципиальной схемы. Схема подключения клавиатуры к микро- микроконтроллеру приведена на рис. 7.12. D3 i—i +5В D2 Ucc Uss SW RST Цепь Питание Питание Общий Общий Конт п D1 Ucc Uss U Шых XTAL2 XTAL1 RESET бЕА Ucci UCC2 Uss CPU at89s51 0 1 2 3 4 5 6 7 ALE PSEN<6— P2 о 1 2 3 4 5 6 7 Рис. 7.12. Схема подключения клавиатуры к микроконтроллеру Рассмотрим только подпрограмму ввода информации, т. к. уже указыва- указывалось ранее, остальные части программы не должны зависеть от алгорит- алгоритма опроса кнопок клавиатуры. Они лишь должны использовать инфор- информацию, сформированную подпрограммой ввода информации. Объявим глобальную переменную skancode, в которой будем хранить зна- значения электрических сигналов на выводах микроконтроллера, подключен- подключенных к контактам клавиатуры. Переменная используется для формирования управляющих сигналов и считывания состояний контактов. Код, храня- хранящийся в этой переменной и отображающий значения электрических сигна- сигналов на выводах микроконтроллера, называется скан-кодом клавиатуры. Теперь собственно о программе. Если бы речь шла не о клавиатуре, то ввод информации свелся бы к простому копированию сигналов с внеш- внешних выводов порта в переменную командой MOV SkanCode, PI.
246 Глава 7 Но при вводе информации с клавиатуры необходимо осуществить ее сканирование, т. е. последовательный опрос колонок или столбцов кла- клавиатуры (по вашему желанию возможен любой из двух вариантов). Сначала определим, каким сигналом будем осуществлять сканирование. Для этого нужно вспомнить внутреннее устройство порта. Обратите внимание, что в качестве примера выбран микроконтроллер семейства MCS-51! При использовании других микроконтроллеров принципиаль- принципиальная схема и сигналы опроса могут оказаться другими! Путь протекания тока через замкнутую кнопку клавиатуры и элементы порта для микро- микроконтроллеров семейства MCS-51 показан на эквивалентной схеме двух разрядов порта Р1 (рис. 7.13). Внутренний генерятор токя Чтение выводя Закрыт КН Внутренний генерятор токя I КН Рис. 7.13. Эквивалентная схема цепи протекания тока через замкнутую кнопку клавиатуры Из приведенной на рис. 7.13 эквивалентной схемы видно, что для опроса колонки кнопок необходимо открыть нижний транзистор порта, под- подключенного к выбранной колонке. При этом нужно обеспечить запира- запирание транзисторов, подключенных к остальным колонкам кнопок. Это позволит исключить неоднозначность определения номера нажатой кнопки. Для открывания транзистора достаточно записать в соответст- соответствующий бит порта логический 0, а для запирания — логическую 1. В ре-
Принципы создания программ для микроконтроллеров 247 зультате коды опроса клавиатуры для схемы, приведенной на рис. 7.12, будут выглядеть следующим образом: ? код опроса первой колонки клавиатуры — liiionib; ? код опроса второй колонки клавиатуры — ишоиь; 3 код опроса третьей колонки клавиатуры — miiioib; ? код опроса четвертой колонки клавиатуры — иишоь. То есть для опроса состояния кнопок клавиатуры потребуется выдача на порт Р1, по крайней мере, четырех кодов. При этом следует отметить, что скан-код, считанный с клавиатуры, содержит намного больше ин- информации, чем просто номер замкнутого контакта. Например, при по- помощи скан-кода можно определить нажатие нескольких кнопок одно- одновременно, поэтому лучше хранить во внутренней памяти контроллера непосредственно скан-код, а не готовый номер кнопки. Пример подпро- подпрограммы опроса клавиатуры приведен в листинге 7.23. ь |W:X23, Подпрограмма опроса клавиатуры на языка С-51 Подпрограмма опроса клавиатуры / #define ScanColl 0xf7 //11110111b #define ScanCol2 Oxfb //11111011b #define ScanCol3 Oxfd //11111101b #define ScanCol4 Oxfe //11111110b void Sborlnf(void) {register char tmp; SkanCode=0xff; //Занести код отсутствия нажатой кнопки Pl=ScanColl; //Выдать код опроса кнопок в колонке 1 tmp=Pl; //прочитать состояние кнопок if(trap != ScanColl) //и если хоть одна кнопка в колонке нажата, SkanCode &= tmp; //то запомнить скан-код Pl=ScanCol2; //Выдать код опроса кнопок в колонке 2 tmp=Pl; //прочитать состояние кнопок if(tmp != ScanCol2) //и если хоть одна кнопка в колонке нажата, SkanCode &= tmp; //то запомнить скан-код
248 Глава 7 Pl=ScanCol3; //Выдать код опроса кнопок в колонке 3 tmp=Pl; //прочитать состояние кнопок if(tmp != ScanCol2) //и если хоть одна кнопка в колонке нажата, SkanCode &= tmp; //то запомнить скан-код Pl=ScanCol4; //Выдать код опроса кнопок в колонке 4 tmp=Pl; //прочитать состояние кнопок if(tmp != ScanCol2) //и если хоть одна кнопка в колонке нажата, SkanCode &= tmp; //то запомнить скан-код В результате работы этой подпрограммы нули появятся в битах, соот- соответствующих цепям колонок и строк клавиатуры, к которым подключе- подключены нажатые кнопки. Использование операции побитового умножения & позволяет определить не только нажатие одиночной кнопки клавиатуры, но и одновременное нажатие двух кнопок, а также некоторых комбина- комбинаций трех кнопок клавиатуры. Эта же подпрограмма может быть реализована и на языке программиро- программирования ассемблер. При этом она практически не будет отличаться от под- подпрограммы, приведенной выше (см. листинг 7.23). Пример реализации опроса клавиатуры на языке программирования ASM-51 приведен в лис- листинге 7.24. Vi V»V*b*4 vY*i4*4 public OprosKlaviat OprosCol_l equ 11110111b OprosCol_2 equ 11111011b OprosCol_3 equ 11111101b OprosCol_4 equ 11111110b _code segment code rseg _code /ПОДПРОГРАММА ОПРОСА КЛАВИАТУРЫ /Подпрограмма опроса клавиатуры сканирует клавиатуру 4x4 ;и возвращает в аккумуляторе полученный скан-код клавиатуры
Принципы создания программ для микроконтроллеров 249 OprosKlaviat: mov SkanCode,#FFh ;Занести код ненажатой кнопки mov AdrKlav,#OprosCol_l mov A,AdrKlav cjne A, #OprosCol__l,TstCol2 sjmp TstCol2 SetColl: anl A,SkanCode mov SkanCode,A TstCol2: mov AdrKlav,#OprosCol_2 mov A,AdrKlav cjne A,#OprosCol_2,SetCol2 sjmp TstCol3 SetCol2: anl A,SkanCode mov SkanCode,A TstCol3: mov AdrKlav,#OprosCol_3 mov A,AdrKlav cjne A,#OprosCol_3, SetCol3 sjmp TstCol4 SetCol3: anl A,SkanCode mov SkanCode,A TstCol4: mov AdrKlav,#OprosCol_4 mov A,AdrKlav cjne A,#OprosCol_4,SetCol4 sjmp EndOpros SetCol4: anl A,SkanCode mov SkanCode,A EndOpros: ret ;Выдать код опроса кнопок в колонке 1 /прочитать состояние кнопок ;и если хоть одна кнопка в колонке нажата ;(код опроса не совпадает со считанным), ;то запомнить ;скан-код ;Выдать код опроса кнопок в колонке 2 /прочитать состояние кнопок ;и если хоть одна кнопка ;в колонке нажата, ;то запомнить ;скан-код ;Выдать код опроса кнопок в колонке 3 ;прочитать состояние кнопок ;и если хоть одна кнопка ;в колонке нажата, ;то запомнить ;скан-код /Выдать код опроса кнопок в колонке 4 /прочитать состояние кнопок ;и если хоть одна кнопка ;в колонке нажата, ;то запомнить ;скан-код Интересной особенностью приведенной подпрограммы является исполь- использование команды sjmp, позволяющее превратить команду перехода по неравенству кодов cjne в команду перехода по равенству кодов. Осталь- 9 3ак 328
250 Глава 7 ные действия подробно пояснены комментариями и поэтому в дополни- дополнительных пояснениях не нуждаются. Следующая подпрограмма обработки данных может из скан-кодов сформировать последовательности (строки) кодов нажатых кнопок, ко- которые могут быть использованы как управляющие команды. Для хране- хранения этих последовательностей можно использовать массив символов (в языке программирования ассемблер это просто соседние ячейки памяти). При написании программы до сих пор считалось, что мы работаем с идеальными кнопками. Однако это не так. Обычно при нажатии и отпус- отпускании кнопки возникает переходный процесс, который называется дре- дребезгом контактов. Начинающие разработчики аппаратуры применяют различные методы борьбы с этим явлением — от применения специаль- специальных схемотехнических решений до повторного опроса кнопок в течение некоторого времени. Рассмотрим подробнее механизм возникновения явления дребезга кон- контактов. Его причиной является упругость самих контактов. При нажатии на кнопку или при срабатывании какого-либо датчика контакты испы- испытывают механическое импульсное воздействие. Обладая некоторой упру- упругостью и массой, они начинают совершать колебательное движение: один контакт ударяется о другой (замыкание) и снова отходит (размы- (размыкание). Колебательный процесс продолжается некоторое время. При этом количество замыканий и размыканий контактов случайно и зависит от механических свойств контактов и механической силы, воздействую- воздействующей на эти контакты. Обычно этот процесс длится от одной до восьми миллисекунд. Если мы будем опрашивать состояние контактов с периодом, превы- превышающим максимальную длительность дребезга, то даже не заметим, что они несколько раз замыкались или размыкались в промежутке между оп- опросами контактов. Для этого можно включить в основной цикл про- программу, которая будет обеспечивать выполнение цикла один раз за стро- строго определенное время. Пример временной диаграммы сигнала на контактах кнопки приведен на рис. 7.14. На временной оси этого рисунка моменты считывания сигна- сигналов показаны рисками. Внизу рисунка обозначены номера временных слотов. На приведенной временной диаграмме четко просматривается зона дребезга контактов. Для иллюстрации эффекта подавления дребезга контактов за счет ввода информации в строго определенные моменты времени на этой временной диаграмме выбран наихудший случай момента взятия отсчета. Этот мо- момент совпадает с зоной дребезга контактов. При этом на выводе порта микроконтроллера может быть считан сигнал логического нуля или ло-
Принципы создания программ для микроконтроллеров 251 гической единицы. Но даже в этом случае дополнительный импульс в считанном сигнале не возникает! В случае считывания в момент дребезга контактов логического нуля сигнал, введенный в микроконтроллер, бу- будет выглядеть как показано на рис. 7.14 сплошной линией, а в случае считывания логической единицы — пунктиром. Однако вне зависимости от того, какое значение сигнала мы считаем — нулевое или единичное, переход будет только один. Сигнал на контактах кнопки Сигнал, введенный в микроконтроллер 1 Рис. 7.14. Временные диаграммы напряжения на контактах кнопки и сигнала, введенного в микроконтроллер Дребезг контактов приводит только к неопределенности обнаружения момента нажатия кнопки, которая не превышает периода опроса клавиа- клавиатуры. Выберем это время. Так как мы уже определили, что время дребез- дребезга контактов не превышает 8 мс, то можно производить опрос портов, к которым подключены механические контакты, с периодом, который не- несколько больше, например, 10 мс. Это время и будет временем реакции системы. Но как обеспечить периодический опрос клавиатуры? Ведь программа в процессе выполнения может проходить по различным пу- путям в зависимости от состояния опрашиваемых контактов и содержимо- содержимого внутренних переменных микроконтроллера! В результате время вы- выполнения программы (тела рабочего цикла) будет случайным. Для того чтобы время прохождения программы по циклу было строго фиксиро- фиксированным, можно воспользоваться таймером. Таймер, являясь аппаратным элементом микроконтроллера, работает незайисимо от выполняемой программы, поэтому будет отсчитывать строго определенные промежутки времени. Если в конце выполнения цикла дожидаться срабатывания таймера, то время одного прохождения по циклу будет строго фиксированным. Единственное условие — макси- максимальное время прохождения рабочего участка тела цикла должно быть меньше Юме. Но ведь то же самое требуется и с точки зрения макси- максимального времени реакции системы. Если мы успеем несколько раз на- нажать на кнопки, а устройство не среагирует на эти нажатия, то что по- полезного можно сделать с его помощью? Если рабочая часть тела цикла
252 Глава 7 будет выполнена быстро, то ждать срабатывания таймера придется дол- долго. Если же проход по циклу будет выполняться долго, то после завер- завершения рабочей части цикла долго ждать срабатывания таймера не при- придется. Соотношение времени выполнения рабочей части цикла и ожидания срабатывания таймера приведено на рис. 7.15. Опрос выводов контроллера Выполнение рабочей части цикла Ожидание Рис. 7.15. Соотношение времени выполнения рабочей части цикла и ожидания срабатывания таймера Для организации периодического опроса клавиатуры требуется услож- усложнить подпрограмму инициализации. Теперь в ней требуется настроить таймер на выбранный период времени, а значит задать и его режим ра- работы. Выберем для задания равных промежутков времени таймер ТО. Он может обеспечить задание Ю-мс промежутка времени только в режиме 16-разрядного таймера. Подпрограмма инициализации микроконтрол- микроконтроллера, выполняющая настройку таймера, приведена в листинге. 7.25. Листинг 7.25, Подпрограмма инициализации микроконтроллера» выполняющая настройку таймера ТО на выработку 10-мс промежутков / "Ж* _ _ м_ м_ м_ м_ м_ м_ м_ м_ м_ м_ м_ _— _— м_ _— м_ _— м_ м_ 1ва_ 1ва_ _» 1ва_ м_ _» _» _» _» _» _» — — — — — — — — — — — — — — •— — •¦— — •¦— — •¦— — — Подпрограмма инициализации микроконтроллера */ void Init(void) {TMOD=0x01; //Настроить ТО на режим 16-разрядного таймера ТН0=(-10000)»8; //Занести старший байт числа -10000 ТЪ=-10000; //Занести младший байт числа -10000 TF=0; //Обнулить флаг переполнения таймера TR0=l; //Включить таймер
Принципы создания программ для микроконтроллеров 253 В приведенном примере предполагается, что микроконтроллер работает с частотой тактового генератора 12 МГц. В этом случае на вход таймера ТО будут поступать импульсы с периодом 1 мкс. Число, которое необхо- необходимо загружать в таймер, можно найти как отношение требуемого ин- интервала времени, Юме, и периода импульсов на входе таймера, 1 мкс. Так как таймер ТО суммирующий, то в регистры таймера будем загру- загружать отрицательное число с абсолютным значением, равным требуемому отношению. В приведенном участке программы (см. листинг 7.25) для выделения старшего байта из 16-разрядного числа использована функ- функция сдвига этого числа на 8 разрядов вправо. Теперь в тело основного цикла нужно включить участок программы, ко- который будет ожидать окончания работы таймера и только после этого приступать к выполнению следующего прохода по циклу. Это можно сделать при помощи команды, которая будет проверять флаг переполне- переполнения таймера TF0. Затем необходимо снова задать следующий интервал времени. Пример программы, в которой один проход по бесконечному циклу будет осуществляться один раз за 10 мс, приведен в листинге 7.26. Иными словами, программа, приведенная в листинге 7.26, реализует схе- схему, изображенную на рис. 7.16. В этой схеме есть три блока, синхронизи- синхронизированные от одного генератора, выполненного на внутреннем генерато- генераторе и таймере. Связям между блоками соответствует взаимодействие частей программы при помощи глобальных переменных, изображенных над линями со стрелочками. Порядок выполнения подпрограмм в цикле не важен, т. к. они только подготавливают данные для выдачи на выво- выводы микроконтроллера. Сигналы появятся на выводах микросхемы толь- только в следующем временном слоте, т. е. после завершения реакции систе- системы. Важны только связи между подпрограммами, а они осуществляются глобальными переменными. Исключение влияния порядка выполнения подпрограмм — важнейший принцип рассматриваемой системы. Время между моментами ввода и вывода сигналов как бы останавливается. И когда бы ни начиналось вы- выполнение подпрограмм, они завершают работу одновременно. Все это верно при условии, что цикл должен успеть завершиться до срабатыва- срабатывания таймера! Использование глобальных переменных для связи между подпрограмма- подпрограммами позволяет осуществлять не только последовательное, но и параллель- параллельное соединение аппаратных блоков, реализуемых программно. Пример такого соединения аппаратных блоков мы рассмотрим позднее.
254 Глава 7 char SkanCode; char Error; //Переменная, через которую будет передана информация //подпрограмме Obrablnf //Переменная, через которую будет передана информация //подпрограмме ObrabOshib void main(void) Unit () ; whileA) {Sborlnf(); Obrablnf(); ObrabOshib(); //Опросить кнопки, подключенные к микроконтроллеру do;while(TF==0); //Подождать, пока не истечет Юмс // подготовить таймер к следующему циклу TF=0; //Обнулить флаг переполнения таймера ТН0=(-10000)>>8; //Задать следующий интервал времени, ТЪ=-10000; //равный Юмс В программе, приведенной в листинге 7.26, процессор все время потреб- потребляет максимальный ток, определяемый тактовой частотой микрокон- микроконтроллера. Чем выше тактовая частота — тем больше ток. Максимальный ток потребляется даже при ожидании срабатывания таймера. В то же время в режиме ожидания микроконтроллер можно перевести в режим пониженного энергопотребления. Это делается записью соответствую- соответствующего бита в регистр SCON. Выйти из этого режима и продолжить вы- выполнение программы микроконтроллер сможет только по прерыванию от таймера. При включении питания все прерывания запрещены, поэтому следует разрешить прерывания от таймера. Это достаточно сделать только один раз после включения питания микроконтроллера, поэтому команды, разрешающие прерывания от таймера, нужно поместить в подпрограмму инициализации микроконтроллера. Ее новый вариант приведен в лис- листинге 7.27.
Принципы создания программ для микроконтроллеров 255 Ген. 1 МКС : 10000 Sborlnf ScanCode 10 мс Obrablnf Error ObrabOshib Рис. 7.16. Эквивалентная схема устройства, реализованного программой, приведенной в листинге 7.26 /¦ Подпрограмма инициализации микроконтроллера void Init(void) {TMOD=0x01; //Настроить таймер ТО на первый режим работы ТН0=(-10000)»8; //Занести старший байт числа -10000 TL=-10000; TR0=l; 1Е=A«7) | //Занести младший байт числа -10000 //Включить таймер //Разрешить прерывания (седьмой бит регистра IE) //Разрешить прерывания от таймера ТО //(первый бит регистра IE) В этой подпрограмме флаг переполнения таймера ТО не сбрасывается, т. к. после выполнения сброса микроконтроллера этот флаг и так содер- содержит нулевое значение. Разрешение прерываний осуществляется командой записи в регистр ie соответствующего числа. Для разрешения прерыва- прерываний от таймера ТО достаточно записать единицу в первый бит этого ре- регистра. Кроме того, для разрешения прерываний необходимо записать единицу в седьмой бит регистра ie, разрешающий или запрещающий все прерывания. Для тех, кто еще не привык считать в двоичной арифметике и легко пе- переводить двоичные числа в шестнадцатеричные и обратно, в этом при- примере приведен способ вычисления констант с помощью операции сдвига. Известно, что 2°=1. Тогда операция двоичного сдвига A«5) вычислит константу 25. Нам надо записать единицу в два бита. Необходимую кон-
256 Глава 7 станту можно образовать при помощи операции логического сложения «|». Не нужно пугаться довольно сложного выражения для вычисления константы, записываемой в ie. Оно вычисляется только один раз, на этапе трансляции программы в машинные коды микроконтроллера. В разраба- разрабатываемую программу будет помещен готовый результат вычислений. При выполнении программы значение константы уже известно. Еще одно преимущество приведенного способа записи констант — это возможность снабдить комментарием каждый бит константы, что повы- повышает наглядность программы, а значит — увеличивает скорость ее напи- написания и отладки. Теперь при переполнении таймера будут возникать прерывания, которые будут передавать управление программой на вектор прерывания. Нам пока ничего не нужно делать по прерыванию, но, тем не менее, подпро- подпрограмму обслуживания прерывания для того, чтобы вернуться из преры- прерывания в основную программу, необходимо написать. Пример такой под- подпрограммы на языке программирования С-51 приведен в листинге 7.28. \ Листинг 7,28. Подпрограмма обслуживания прерываний от таймера ТО \ Подпрограмма обслуживания прерываний от таймера ТО void PrerTO(void) interrupt 1 На то, что это подпрограмма обслуживания прерывания, указывает ключевое слово interrupt. Номеру прерывания i соответствует конкрет- конкретный адрес вектора прерывания, где будет размещаться переход на под- подпрограмму обслуживания прерывания. В приведенном примере это век- вектор прерывания от таймера ТО. Теперь все подготовительные операции выполнены, и можно осущест- осуществить режим пониженного потребления тока микроконтроллера. У мик- микроконтроллеров семейства MCS-51 есть два режима энергопотребления: остановка процессорного ядра и остановка задающего генератора. В нашем случае останавливать задающий генератор ни в коем случае нельзя, т. к. при этом остановится таймер, и микроконтроллер можно будет разбудить только при помощи аппаратного сброса. Остается толь- только режим остановки процессорного ядра.
Принципы создания программ для микроконтроллеров 257 Режимы пониженного энергопотребления задаются при помощи двух младших битов регистра pcon. Остановить процессорное ядро можно, записав в нулевой разряд этого регистра единицу. Для того чтобы не из- изменить содержимое остальных битов этого регистра, воспользуемся опе- операцией логического суммирования. Пример использования режима по- пониженного потребления тока для задания 10-мс интервалов времени между проходами по основному циклу программы показан в листин- листинге 7.29. Листинг 7*29. Основная функций программы, работающей один раз в 10 мс с пониженным потреблением тока ; ^ void main (void) {InitO ; while(l) {SborlnfO; //Опросить кнопки, подключенные к микроконтроллеру Obrablnf(); ObrabOshib(); PCON|=1; //Остановить процессорное ядро и //подождать, пока не истекут 10 мс // подготовить таймер к следующему циклу TF=0; //Обнулить флаг переполнения таймера ТН0=(-10000)»8; //Задать следующий интервал времени, TL=-10000; //равный 10 мс Хотелось бы сразу подчеркнуть, что описанная программа вызывает им- импульсные помехи с периодом 10 мс. Они распространяются по цепям пи- питания микроконтроллера. В ряде случаев этот фактор критичен и воз- возможно придется отказаться от режима понижения тока потребления в пользу варианта программы, приведенного в листинге 7.26. Если при этом микроконтроллер будет большую часть времени простаивать, то имеет смысл рассмотреть возможность уменьшения потребляемого тока за счет снижения тактовой частоты микроконтроллера. (Следует отме- отметить, что ряд современных микроконтроллеров, например, AduC824, по- позволяют регулировать частоту работы процессорного ядра непосредст- непосредственно в процессе работы.)
258 Глава 7 Достаточно часто программа, написанная для микроконтроллера, реа- реализует несколько режимов работы. Так как в каждый отдельный момент времени требуется только один режим работы, то для каждого из них можно использовать отдельную программу-монитор, вызываемую как подпрограмма из основной программы-монитора. Именно он должен осуществлять переключение между режимами. Поэтому завершение ра- работы любого из режимов должно осуществляться выходом из подпро- подпрограммы, реализующей этот режим. Использование таймера для организации параллельных программных потоков В рассмотренном примере все время процессора неограниченно принад- принадлежит одной программе-монитору. Это естественно, если время реакции любого алгоритмического блока, входящего в программу-монитор, оди- одинаково. Однако возможны задачи, когда на одном микроконтроллере реализуются алгоритмические блоки, время реакции которых на посту- поступающие от входных портов события должно быть различно. В таком случае используют разбиение времени микроконтроллера на временные слоты (интервалы). Это, как и в предыдущем случае, делается при помо- помощи таймера. Однако для реализации устройства используется несколько подпрограмм-мониторов. Кроме них в состав программы вводится еще один алгоритмический блок — диспетчер. Собственно говоря, этот блок уже присутствовал в предыдущем примере. Это программа, осуществ- осуществлявшая разбиение времени процессора на строго определенные интервалы. Пример функциональной схемы устройства, в котором требуется раз- различное время реакции на входное воздействие, приведен на рис. 7.17. Ген. 1 мкс : 10000 Диспетчер задач 10 мс :2 20 мс :6 60 мс I Монитор 1 Монитор 2 Рис. 7.17. Схема устройства, реализующая разное время реакции на входные воздействия
Принципы создания программ для микроконтроллеров 259 Можно было бы просто включить в основной монитор два различных счетчика и, анализируя их значения, вызывать соответствующие подпро- подпрограммы, но при этом возможна ситуация, когда общее время выполнения подпрограмм превысит значение временного слота монитора. Намного лучше заранее разбить время выполнения программы на временные сло- слоты и выделить для каждой подпрограммы различные слоты. Это позво- позволит отодвинуть выполнение некритичных по времени подпрограмм на более позднее время. Так реализуются параллельные программные потоки. На временной диаграмме рис. 7.18 общее время выполнения программы (максимальное допустимое время реакции системы) разбито на шесть временных слотов. При этом первый, третий и пятый временные слоты выделены для второго монитора, что обеспечивает время реакции уст- устройства /2, реализуемое этим монитором, не более 3,3 мс. Это будет один программный поток. Для первой подпрограммы-монитора с временем реакции на входное воздействие t\ выделен четвертый временной слот. Если времени одного слота для выполнения монитора 1 недостаточно, то есть еще два свобод- свободных временных слота. Подпрограмма-монитор 1 может быть разбита на три части, каждая из которых будет вызываться в своем временном сло- слоте. При этом максимальное время реакции на входное событие у мони- монитора 1 составит /i=10 мс. I* I I 1^ t2 1^ t2 I 1^ f2 1^ t2 1^ f2 I I Монитор 1 I I I I I , I Л I » I I I j L _|. Мониторг ' j " I | | I11! r I _ I j i i I i ij __L——-—— 1 i in h ^^П i Jr~\ м к I 'IN I I I I I nwuniiuuo I II I I ижидапис | ¦ Iwl^lw I w I w I ^ I I I 1 I I I 1 I I 1 1 1 > №слота 1 234561 2345f Рис. 7.18. Пример временной диаграммы работы микроконтроллера с двумя подпрограммами-мониторами Таким образом, в одном процессоре реализовано два программных по- потока с различным временем реакции на изменение сигналов на выводах микроконтроллера. В принципе, вместо ожидания срабатывания таймера
260 Глава 7 можно организовать еще один программный поток и разместить в этом потоке подпрограммы, время выполнения которых не является критиче- критическим для разрабатываемого устройства. Теперь рассмотрим, как можно реализовать приведенные выше прин- принципы организации программы на языке программирования С-51. Ис- Исходный текст программы приведен в листинге 7.30. Для нумерации сло- слотов, на которые разбивается время, используется глобальная переменная Nomsiot. Эта переменная используется как счетчик времен- временных слотов. Именно по ее значению вызывается одна из подпрограмм- мониторов. Подпрограмма инициализации микроконтроллера такая же, как в примере, приведенном в листинге 7.27, и поэтому сейчас рас- рассматриваться не будет. Листинг 7>3д* Пример реализации диспетчера программ с двумя программными мониторами char NomSlot=6; void main(void) {InitO; whileA) {if(NomSlot==6)Sborlnf(); //Если шестой слот, то опросить выводы контр. else if(NomSXot==5)Monit2();//Если пятый слот, то вызвать монитор 2 else if(NomSlot==4)Monitl();//Если четвертый слот, то вызвать монитор 1 else if(NomSlot==3)Monit2();//Если третий слот, то вызвать монитор 2 else if(NomSlot==l)Monit2();//Если первый слот, то вызвать монитор 2 if(—NomSlot==0)NomSlot=6;//Уменьшить номер слота, и если первый //слот уже выполнен, то перейти к шестому PCON|=1; //Остановить ядро и подождать, пока не истечет 1,67 мс // подготовить таймер к следующему циклу TF=0; //Обнулить флаг переполнения таймера ТН0=(-1666)»8; //Задать следующий интервал времени, равный 1,67 мс TL=-1666; //F слотов = 10 мс)
Принципы создания программ для микроконтроллеров 261 Использование прерываний для ввода информации о кратковременных сигналах и событиях, наступающих в произвольный момент времени Использование временных слотов позволяет реализовывать устройства с различными временами реакции. Однако размер временного слота не по- позволяет обрабатывать быстро текущие процессы. Часто сигнал на входе микроконтроллера длится в течение нескольких микросекунд. Для того чтобы не пропустить такой сигнал, время реакции системы должно быть в пределах нескольких команд микроконтроллера. Если сделать такой ма- маленький временной слот, то микроконтроллер будет постоянно переклю- переключаться с задачи на задачу, и ему некогда будет заниматься реализацией ос- основного алгоритма работы. В то же самое время временной интервал между приходом очередного сигнала на вход микроконтроллера может быть достаточно велик, т. е. время реакции системы даже для короткого сигнала может достигать единиц и даже десятков миллисекунд! Для решения возникшей проблемы в микроконтроллерах предусмотрен механизм прерываний основной программы. Разработчики микрокон- микроконтроллера предлагают аппаратный вызов подпрограмм при возникнове- возникновении какого-либо события. Это может быть изменение потенциала на особых выводах микроконтроллера (входах запроса прерывания), пере- переполнение таймеров, завершения передачи или приема байта через после- последовательный порт. В некоторых типах микроконтроллеров могут быть дополнительные источники прерываний. В предыдущих главах мы реализовывали ввод информации в начале ра- рабочего цикла программы-монитора. Тем самым мы обеспечивали ввод информации строго через равные интервалы времени. При этом предпо- предполагалось, что сигналы на выводах микроконтроллера меняются медлен- медленнее интервала опроса. Использование прерываний позволяет обрабаты- обрабатывать короткие сигналы или пакеты сигналов, приходящие в случайные моменты времени. Основное ограничение при использовании прерыва- прерываний — это то, что мы должны успеть запомнить полученную информа- информацию в глобальной переменной до поступления очередного запроса на прерывание. Наиболее ярким примером источника событий, наступающих в произ- произвольный момент времени, является последовательный порт. Обычно че- через него принимаются или передаются многобайтные команды или паке-
262 Глава 7 ты данных. Рассмотрим пример обмена микроконтроллера с универсаль- универсальным компьютером. Обычно для обмена используется последовательный порт компьютера (СОМ-порт). Схема согласования уровней сигналов последовательного порта микроконтроллера и СОМ-порта компьютера приведена на рис. 7.19. DD2 DD3 DD1 Ucc Uss U RST ОЁА RESET XTAL2 XTAL1 CPU RxD TxD ALE PSlR P2 1 2 3 4 5 6 7 R1OUT TUN R2OUT T2IN V- C2+ C2- 0 RUN T1OUT R2IN T2OUT V+ C1+ Cl- Vcc GND ~n± цепь 8 MOW. TD RD RTS CTS DTR DSR DCD SG Рис. 7.19. Схема согласования уровней сигналов последовательного порта микроконтроллера и СОМ-порта компьютера Прежде чем начать программирование обмена через последовательный порт, необходимо определить формат команд обмена с компьютером. Пусть обмен будет производиться ANSI-символами (их легче всего сформировать в любой терминальной программе на персональном ком- компьютере). Первый переданный символ будет рассматриваться как команда. При использовании в качестве команды заглавных и строчных букв латин- латинского алфавита будет доступно 56 команд. При желании можно добавить еще 64 команды, обозначаемые буквами русского алфавита. Следующие несколько символов составят поле данных. Обычно здесь используются цифры. Пусть у нас поле данных содержит четыре символа. В качестве завершения команды используем символ возврата каретки (ASCII-код «13»). Этот символ вводится при нажатии на клавишу <Enter>. Итак, подпрограмма ввода информации должна принять шесть 8-разряд- 8-разрядных символов и только после этого передать управление программе обра-
Принципы создания программ для микроконтроллеров 263 ботки информации. Естественно, что подпрограмма обработки информа- информации, которая входит в один из мониторов, не знает, когда будет завершен прием команды, поэтому введем однобитовую переменную (флаг) завер- завершения приема команды. Подпрограмма ввода информации будет записы- записывать в эту переменную единицу, а подпрограмма обработки команд после выполнения команды будет записывать в эту переменную ноль. Для того чтобы не пропустить ни одного байта, полученного через по- последовательный порт, оформим ввод информации как подпрограмму об- обработки прерывания. Для этого необходимо разрешить прерывания от последовательного порта при помощи подпрограммы инициализации микроконтроллера, приведенной в листинге 7.31. /¦ Подпрограмма инициализации микроконтроллера 7 void Init(void) {TMOD=0x20; ТН1=-3; TR1=1; SCON=A«6) | IE=A«7) //Настроить таймер 1 на режим работы с автозагрузкой //Настроить последовательный порт на скорость 9600 бит/с //Включить таймер 1 //Выбрать восьмибитовый асинхронный режим работы //Разрешить работу приемника //Разрешить прерывания (установить седьмой бит //регистра IE) //Разрешить прерывания от последовательного порта Если к микроконтроллеру не подключены кнопки или датчики, то про- процессорное время на временные интервалы можно не разделять, и микро- микроконтроллер будет находиться в режиме ожидания, пока подпрограмма ввода не примет через последовательный порт команду от персонального компьютера. В этом случае основная программа будет выглядеть так, как показано в листинге 7.32. ж bit cmPrinjata=0; void main(void)
264 Глава 7 {InitO; whileA) {PCON|=1; //Остановить процессорное ядро и подождать, //пока не будет принят очередной байт if(cmPrinjata) //Если прием команды завершен, {cmPrinjata=O; //то сбросить флаг приема команды Obrablnf(); //и выполнить команду. Теперь рассмотрим, как будет выполняться прием команды от компью- компьютера. В подпрограмме инициализации мы разрешили прерывания после приема байта через последовательный порт, поэтому прием команды бу- будет осуществляться в подпрограмме обработки прерывания. Листинг 7,33, Подпрограмма приема команд от персонального компьютера через последовательный порт /* Подпрограмма обслуживания прерываний от последовательного.порта char and[6]; char data* ptr=cmd-l; void PriemCmd (void) interrupt 4 (if(RI) //Если последовательный порт принял байт, {RI=0; //то обнулить флаг прерывания от приемника. ++ptr; //Перейти к следующему байту буфера команд *ptr=SBUF; //и запомнить в нем принятый байт if(*ptr==13) //Если принятый байт это символ конца строки, {cmPrinjata=l; //то установить флаг завершения приема команды ptr=cmd-l; //и подготовиться к приему очередной команды Для обмена данными с основной программой используется глобальная переменная буфера команд cmd и флаг завершения приема команды cmPrinjata. Выберем длину буфера команд равной максимальной длине команды — шесть байтов.
Принципы создания программ для микроконтроллеров 265 Первое действие этой подпрограммы — обнуление флага запроса преры- прерывания для того, чтобы разрешить дальнейшие прерывания от приемника последовательного порта. Затем принятый байт сохраняется в буфере команд. Для работы с буфером команд используется указатель, в кото- который при запуске программы занесен адрес первого байта буфера команд. При приеме очередного байта указатель переходит к следующему байту буфера команд. Использование указателя позволяет сделать подпро- подпрограмму обслуживания прерываниями максимально короткой, а это зна- значит, ее выполнение будет занимать минимальное время, что и требуется от любой подпрограммы обслуживания прерывания. Флаг завершения приема команды cmPrinjata устанавливается при об- обнаружении символа возврата каретки. Теперь необходимо подготовиться к приему следующей команды. Для этого в указатель ptr записывается адрес начального байта буфера обмена. Работа с другими источниками прерываний происходит так же, как в рассмотренном примере. Подпрограмма обслуживания прерывания долж- должна осуществить ввод или вывод информации, и не более того! Вся основ- основная обработка информации будет проводиться в главной программе. Это делается с целью не пропустить очередное прерывание. Итак, подведем итоги В главе были рассмотрены языки программирования, применяющиеся при разработке программ для микроконтроллеров. При этом были рас- рассмотрены преимущества и недостатки использования языков програм- программирования высокого и низкого уровней. Для полноты картины было описано, что такое подпрограммы, виды подпрограмм и как можно ими пользоваться. При этом основной акцент сделан на использовании под- подпрограмм для структурирования программ. Особое внимание в главе было уделено комментариям к программе и различным способам их ис- использования. Рассмотрено структурное программирование и примеры реализации структурных управляющих конструкций на различных язы- языках программирования. Особое внимание было уделено методу создания программ сверху вниз. Для этого был рассмотрен пример развития программы от построения програм- программы-прототипа до детализации, достаточной для реализации устройства. В главе были использованы некоторые интуитивно понятные конструк- конструкции языков программирования С и ASM-51. Однако для написания серь- серьезных программ требуются более глубокие знания по этим языкам про- программирования, поэтому в последующих главах мы остановимся на этих языках подробнее.
Ш0011 Глава 8 Язык программирования ASM-51 Язык программирования ASM-51 поддерживает модульное написание программ. Графическое изображение процесса разработки программы на языке программирования ASM-51 приведено на рис. 8.1. Тексто- Текстовый редактор c51.exe moduli.с Исходный текст прог- программы ~j moduli.1st moduli.obj mam Объектные модули modul2.asm asm51.exe J main rl51.exe modul2.obj _] modul2.lst Исполняе- Исполняемый модуль oh.exe main.hex main.m51 Внутри- Внутрисхемный эмулятор Программ- Программный симулятор Програм- Программатор Рис. 8.1. Схема процесса написания программы на языке программирования ASM-51 Файл, в котором хранится программа, написанная на языке ASM-51 (исходный текст программы), называется исходным модулем. Его можно создать, используя любой текстовый редактор. Для файла исходного текста программы принято использовать следующие расширения: asm, а51, srs, s51. Получить объектный модуль можно, указав имя исходного модуля про- программы в качестве параметра вызова программы-транслятора в DOS- строке или строке командного файла: asm51.exe modul.asm
268 Глава 8 Получить исполняемый модуль программы можно, указав все имена объектных модулей программы в качестве параметров вызова програм- программы-редактора связей в DOS-строке или строке командного файла: bl51.exe main.obj, modull.obj, modul2.obj Имя исполняемого модуля программы по умолчанию совпадает с име- именем первого объектного файла в списке параметров командной строки, используемой для запуска редактора связей. Исполняемый модуль про- программы записывается в файл с именем, но без расширения. Большинство программаторов не может работать с объектным форма- форматом исполняемого модуля программы, поэтому для загрузки машинного кода в микроконтроллер необходимо преобразовать объектный формат исполняемого модуля в общепринятый для программаторов НЕХ- формат. При таком преобразовании вся отладочная информация, содер- содержащаяся в исполняемом модуле, теряется. Машинный код процессора, записанный в НЕХ-формате, называется загрузочным модулем. Загрузочный модуль программы можно получить при помощи програм- программы-преобразователя oh.exe, передав ей при вызове в качестве параметра имя файла исполняемого модуля, например: oh.exe main Рис. 8.2. Пример системы отладки программного обеспечения для микроконтроллеров После того как программные модули успешно оттранслированы, разме- размещены по конкретным адресам и связаны между собой, для отладки про- программы можно воспользоваться внутрисхемным эмулятором. Это инст- инструментальное средство позволяет отображать переменные программы на дисплее персонального компьютера и оказывает значительную помощь
Язык программирования ASM-51 269 при отладке программ непосредственно на разрабатываемой аппаратуре. Необходимое для отладки программ оборудование показано на рис. 8.2. Отдельные участки программы могут быть отлажены и при помощи спе- специальных программ-отладчиков (симуляторов). Как эмуляторы, так и симуляторы предназначены для обнаружения ло- логических ошибок, содержащихся в исходном тексте программы, поэтому после обнаружения ошибки приходится исправлять исходный текст и заново транслировать его для получения исправленной версии испол- исполняемого или загрузочного модуля. Тем не менее, окончательная отладка программного обеспечения для разрабатываемого устройства производится только после записи загру- загрузочного модуля в память микроконтроллерной системы. Именно на этом этапе находятся и устраняются последние ошибки, допущенные при на- написании программы. Исходный текст программы на языке программирования ASM-51 Исходный текст программы представляет собой последовательность операторов языка программирования ASM-51, сгруппированных в сег- сегменты и оформленных в виде файла. Оператор — это базовая конструкция языка программирования, опреде- определяющая действия в программе. В языке программирования ASM-51 в од- одной строке может быть записан только один оператор! Максимальный допустимый размер строки — 255 символов. Признаком конца операто- оператора является символ «возврат каретки», который вводится в текст про- программы при нажатии на клавишу <Enter> в конце строки. Оператор языка программирования ASM-51 состоит из трех полей: <поле метки> <поле операции> <поле комментария> Любое из полей, в том числе и все поля, могут отсутствовать. Оператор, в котором все поля отсутствуют, называется пустым оператором. Он ис- используется для увеличения наглядности программы. Пример оператора, записанного на языке программирования ASM-51, приведен на рис. 8.3. Поле метки используется для записи меток. Метка представляет собой определяемое программистом имя, заканчивающееся двоеточием, и ис- используется для организации условных и безусловных переходов, а также для объявления переменных и констант. Если в операторе присутствует только метка, то она помечает ближай- ближайший следующий оператор, в котором присутствует инструкция процес-
270 Глава 8 сора или директива ассемблера. Использование оператора, содержащего только метку, может быть вызвано либо слишком большой длиной са- самой метки, либо необходимостью присвоить одному непустому операто- оператору нескольких меток. Наиболее яркий пример использования нескольких меток — это когда одна метка используется в качестве имени подпро- подпрограммы, а другая обозначает начало цикла. Пример использования опе- оператора, содержащего только метку, приведен в листинге 8.1. шпшшв PodprograinmaPeredachiDannyh: /Помечается следующий оператор CopyNxtByte: Mov R0, А Mov A, @R0 DJNZ RO, CopyNxtByte Поле операции используется для записи директивы языка или команды микроконтроллера. В последнем случае оно состоит из мнемонического обозначения команды и одного или нескольких операндов. При этом первый операнд всегда является приемником результата операции. Вто- Второй операнд всегда является источником данных для выполняемой опе- операции. Если в команде для выполнения операции требуется два источни- источника данных (например, операция суммирования), то первый операнд используется и в качестве источника и в качестве приемника данных. В качестве операндов могут использоваться адреса ячеек памяти, обо- обозначения регистров или метки операторов. Операнды отделяются друг от друга запятыми. Вместе с запятыми для увеличения читаемости про- программы допускается использование символов интервала (пробел или та- табуляция). Поле операции подробно показано на рис. 8.3. Поле метки Поле операции Поле комментария SumDig:^ApDA, #56^ (; Сложить содержи мое аккумулятора с числом 56 J Мнемоническое Первый Второй обозначение операнд операнд команды Рис. 8.3. Пример оператора, записанного на языке программирования ASM-51
Язык программирования ASM-51 271 Поле комментария начинается с символа «точка с запятой» (;) и может содержать любые ASCII- или ANSI-символы. Это поле используется для записи пояснений к программе. Оператор, в котором присутствует толь- только поле комментария, используется для увеличения наглядности про- программы. Примеры записи комментариев на языке программирования ASM-51 приведены в листинге. 8.2. т языке программирования ; ПОДПРОГРАММА ВЫЧИСЛЕНИЯ ФУНКЦИИ ; X + Y * Z Символы языка ASM-51 Символы исходной программы представляют собой подмножество таб- таблиц символов ASCII для DOS и ANSI для Windows. В исходном тексте программы, написанном на языке программирования ASM-51, могут быть использованы следующие символы: ? символы интервала; ? буквы; ? знаки; ? цифры. Символы интервала определяют один или несколько пробелов в предло- предложении исходного модуля. К этим символам относятся «пробел» и «табу- «табуляция». В качестве букв воспринимаются латинские буквы верхнего и нижнего регистра: А, В, С, D, E, F, G, H, I, J, К, L, М, N, О, Р, Q, R, S, T, U, V, W, X, Y, Z, а, Ь, с, d, e, f, g, h, i, j, k, 1, m, n, o, p, q, r, s, t, u, v, w, x, y, z. Кроме того, в качестве букв могут быть использованы символы вопроси- вопросительного знака (?) и подчеркивания (_). Ниже приведен перечень цифр: О, 1, 2, 3, 4, 5, б, 7, 8, 9.
272 Глава 8 Для записи шестнадцатеричных цифр дополнительно могут быть ис- использованы следующие символы: а, Ь, с, d, е, f, А, В, С, D, E, F. Наименования знаков и их обозначения приведены в табл. 8.1. Таблица 8.1. Наименования знаков и их обозначения Наименование Номер Знак денежной единицы Апостроф Круглая скобка левая Круглая скобка правая Звездочка Плюс Запятая Минус Обозначение # $ ? ( ) * + — Наименование Точка Дробная черта Двоеточие Точка с запятой Меньше Равно Больше Вопросительный знак Коммерческое эт Обозначение • / • • • / < = > 9 • 0 Знаки, комбинации знаков (<>, >=, <=), а также символы интервала явля- являются разделителями конструкций языка. До и после знака-разделителя в любой конструкции языка могут быть вставлены символы интервала. ASCII- или ANSI-символы, не входящие в перечень основных символов алфавита языка, считаются дополнительными. Они могут использовать- использоваться в комментариях для пояснений в исходном тексте программы, а также для определения символьных констант. Из символов формируются идентификаторы и числа. Идентификаторы Идентификатор — это символическое обозначение объекта программы. В качестве идентификатора может быть использована любая последова- последовательность букв и цифр. При этом в качестве буквы может быть использо- использована любая буква латинского алфавита, а также вопросительный знак (?) и знак «нижнее подчеркивание» (_). Идентификатор может начинаться только с буквы! Это позволяет отличать его от числа. В идентификато- идентификаторах язык программирования ASM-51 различает буквы верхнего и нижне- нижнего регистров.
Язык программирования ASM-51 273 Количество символов в идентификаторе ограничено только длиной строки B55 символов), но при этом транслятор языка программирования ASM-51 различает идентификаторы по первым 31 символам. Примеры записи идентификаторов: ADD5, FFFFH, ?, ALFA_1. В языке программирования ASM-51 имеются три категории идентифика- идентификаторов: 1. Ключевые слова. 2. Встроенные имена. 3. Определяемые имена. Ключевые слова Ключевое слово является определяющей частью оператора языка програм- программирования. Значения ключевых слов языка ASM-51 не могут быть изменены или переопределены в программном модуле каким-либо образом. Ключево- Ключевому слову не может быть назначено имя-синоним. Ключевые слова могут быть написаны буквами как верхнего, так и нижнего регистров. То есть клю- ключевое слово mov и ключевое слово mov полностью эквивалентны. В языке программирования ASM-51 имеются следующие категории клю- ключевых слов: ? инструкции; ? директивы; ? вспомогательные слова; ? операции. Инструкции по форме записи совпадают с мнемоническими обозначе- обозначениями команд микроконтроллеров семейства MCS-51 и совместно с опе- операндами составляют команды микроконтроллера. Список инструкций: ACALL, ADD, ADDC, AJMP, ANL, CALL, CJNE, CLR, CPL, DA, DEC, DIV, DJNZ, INC, JB, JBC, JC, JMP, JNB, JNC, JNZ, JZ, LCALL, LJMP, MOV, MOVC, MOVX, MUL, NOP, ORL, POP, PUSH, RET, RETI, RL, RLC, RR, RRC, SETB, SJMP, SUBB, SWAP, XCH, XCHD, XRL. Директивы совместно с вспомогательными словами определяют дейст- действия, которые должны быть выполнены ассемблером в процессе преобра- преобразования исходного текста программы в объектный код. В языке про- программирования ASM-51 используются: Директивы: BIT, BSEG, CODE, CSEG, DATA, DB, DBIT, DS, DSEG, DW, END, EQU, EXTRN, IDATA, ISEG, NAME, ORG, PUBLIC, RSEG, SEGMENT, SET, USING, XDATA, XSEG.
274 Вспомогательные слова: Глава 8 AT, BIT, BITADDRESSABLE, CODE, DATA, IDATA, INBLOCK, INPAGE, NUMBER, PAGE, UNIT, XDATA. Операции выполняются ассемблером в процессе вычисления выражений на этапе трансляции исходного текста программы для определения кон- конкретного числа, которое используется в команде. Перечень операций, использующихся языком программирования ASM-51: AND, EQ, GE, GT, HIGH, LE, LOW, LT, MOD, NE, NOT, OR, SHL, SHR, XOR. Встроенные имена Встроенные имена присвоены адресам регистров специальных функций, адресам флагов специальных функций AR0—AR7, рабочим регистрам RO—R7 текущего банка регистров, а также аккумулятору А и флагу пе- переноса С. Список встроенных имен приведен в табл. 8.2. Таблица 8.2. Встроенные имена Имя А RO—R7 ARO—AR7 DPTR PC С АВ Регистр Аккумулятор 8-разрядный рабочий регистр текущего банка рабочих регистров Адреса 8-разрядных рабочих регистров текущего банка рабочих регистров 16-разрядный регистр-указатель данных 16-разрядный счетчик команд Флаг переноса Регистровая пара, состоящая из аккумулятора А (старшая часть) и регистра В (младшая часть) Определяемые имена Определяемые имена объявляются пользователем. В языке программи- программирования ASM-51 имеются следующие категории определяемых иденти- идентификаторов: ? метки; ? внутренние и внешние переменные адресного типа; ? внутренние и внешние переменные числового типа; ? имена сегментов; ? названия программных модулей.
Язык программирования ASM-51 275 Числа и литеральные строки В языке программирования ASM-51 используются целые беззнаковые числа, представленные в двоичной, восьмеричной, десятичной и шестна- дцатеричной формах записи. Для определения основания системы счис- счисления используется суффикс (буква, следующая за числом): ? В определяет двоичное число (разрешенные цифры 0, 1); ? Q\O определяет восьмеричное число (разрешенные цифры 0, 1,2, 3, 4, 5, 6, 7); ? D определяет десятичное число (разрешенные цифры 0, 1,2, 3, 4, 5, 6, 7, 8, 9); ? Н определяет шестнадцатеричное число (разрешенные цифры 0, 1,2, 3,4,5,6,7,8,9,A,B,C,D,E,F). Для десятичного числа суффикс может отсутствовать. Количество сим- символов в числе ограничено размером строки, однако значение числа опре- определяется по модулю 216 (т. е. диапазон значений числа находится в преде- пределах от 0 до 65535). Примеры записи чисел: 011101b, 1011100B, 735Q, 45бо, 256, Ofah, 0CBH. Число всегда начинается с цифры. Это необходимо для того, чтобы от- отличать шестнадцатеричное число от идентификатора. Например: ? adch —идентификатор; ? ADCH — ЧИСЛО. Часто бывает удобно выполнить некоторые вычисления для того, чтобы получить число. При этом, если поместить в текст программы предвари- предварительно вычисленное на калькуляторе значение, то может возникнуть во- вопрос: откуда взялось это значение. Лучше ввести формулу расчета и сами значения непосредственно в исходный текст программы. Язык програм- программирования ASM-51 позволяет выполнять беззнаковые операции над чис- числами. В таких выражениях допустимо использовать следующие арифме- арифметические операции: ? + суммирование; ? - вычитание; ? * умножение; ? / деление; ? mod вычисление остатка от целочисленного деления.
276 Глава 8 В языке программирования ASM-51 также определена одноместная опе- операция изменения знака — «минус» (-). Для нее требуется только один операнд — тот, которому она предшествует. Часто требуется выполнять операции в определенном порядке, отли- отличающемся от принятого по умолчанию. Для изменения порядка выпол- выполнения операций можно воспользоваться скобками. Более того, использо- использование скобок в ряде случаев повышает наглядность программы и, тем самым, уменьшает время ее отладки. Кроме арифметических операций в выражениях допустимо использова- использование следующих логических операций: ? not побитовая инверсия операнда; ? and логическое «И»; ? or логическое «ИЛИ»; ? хог «исключающее ИЛИ» (суммирование по модулю два); ? функции выделения старшего «HIGH» и младшего «LOW» байта 16- разрядного числа. Пример использования выражений языка программирования ASM-51 для определения числовой константы приведен в листинге 8.3. Init: ; Настроить таймер ТО- mov TMOD,#00000001b ; || ++ Выбрать режим 16-разрядного таймера ; |+ Использовать внутреннюю синхронизацию . + Запретить управление таймером от ножки INTO mov THO, #HIGH(-(F_ZQ/12)*10) ;Выражение для определения mov TLO, #LOW(-(F_ZQ/12)*10) /константы setb TRO /Включить таймер О Часто операнд используется для представления символов на экране дис- дисплея. В этом случае для определения его значения удобнее воспользо- воспользоваться не числом, а литеральной константой.
Язык программирования ASM-51 277 Литеральная константа заключается в апострофы: •a1, 'W mov SBUF, #'Б' /Передать по последовательному порту ANSI код буквы ЛБ' Часто на экране дисплея приходится отображать не одну букву, а це- целые фразы. Их удобно запоминать в памяти программ, а затем переда- передавать на дисплей при помощи специальной подпрограммы. Для записи фраз в памяти программ можно воспользоваться литеральными стро- строками, для ввода которых в память программ удобно воспользоваться директивой db: Nadp: DB ^Ошибка в блоке 5' В этом случае каждый символ строки заменяется отдельным байтом и запоминается в ПЗУ памяти программ. Начало строки обязательно по- помечается при помощи метки. Для увеличения наглядности программы следует содержание надписи отобразить в имени использованной метки. Директивы языка программирования ASM-51 Любой ассемблер всегда включает в себя команды микроконтроллера, но ими не ограничивается набор операторов этого языка программирова- программирования. Дело в том, что нужно уметь управлять самим процессом трансля- трансляции программы. Первое, чем приходится по необходимости заниматься, если в программе используются только команды микроконтроллера, — это вручную рас- распределять память данных микроконтроллера. При таком распределении приходится помнить, какой вид данных находится в каждой конкретной ячейке памяти, и указывать значение адреса памяти в качестве операнда команд. При необходимости изменить местоположение данных в ячейках памяти приходится просматривать всю программу и изменять соответст- соответствующие команды. При чтении программы трудно отличить константы от переменных, ведь в командах они отличаются только видом адресации. Это приводит к увеличению времени написания программы, т. к. каждый раз приходится решать загадку: что же подразумевалось под конкретной цифрой — пе- переменная, константа или маска? Преодолеть эту трудность можно при помощи идентификаторов. Можно назначить какой-либо ячейке памяти идентификатор и работать с ним, как с переменной. Более того! При необходимости изменить адрес пере- переменной в памяти данных можно просто изменить значение идентифика- идентификатора, а не просматривать всю программу, каждый раз решая, является ли найденное число адресом переменной, маской или константой!
278 Глава 8 Директива equ позволяет назначать имена для констант и значения адре- адресов для переменных. При использовании этой директивы можно назна- назначить идентификатору переменной адрес в одном месте программы и пользоваться идентификатором этой переменной во всей программе. Правда, за использование идентификатора именно в качестве перемен- переменной отвечает программист. Если он попытается использовать адрес пе- переменной как константу, то транслятор не выдаст никакого сообщения об ошибке. Он спокойно оттранслирует оператор. При использовании назначения адресов переменных при помощи директивы equ изменение адреса при необходимости можно сделать в одном месте программы, а не просматривать всю программу, судорожно пытаясь вспомнить, где же еще была использована эта ячейка памяти. Все необходимые изменения в машинном коде программы сделает сам транслятор! Пример назначения имен переменных с использованием директивы equ приведен в листинге 8.4. FuncSet 8bit equ 0x20 equ 0x10 DispDat equ P0 ;Шина данных ЖКИ RDS equ Pl_2 ;Чтение команды ЖКИ RW equ Pl_l ;Сигнал выбора записи/чтения E equ Pl_0 ;Строб синхронизации ЖКИ mov DispDat,#(FuncSet or setb E clr E _8bit)/Выставить на шине данных ;команду установки функции ;и выдать стробирующий сигнал Как видно из приведенного примера, использование идентификаторов значительно повышает наглядность программы, т. к. в них отражается назначение соответствующих констант и переменных. При помощи директивы equ можно назначать не только переменные, но и константы. Как уже говорилось ранее, будет ли использован иденти- идентификатор как переменная или как константа, зависит от команд и видов адресации, которые использует программист. И даже если адрес пере- переменной и константа будут обладать одинаковым числовым значением, то лучше им назначить разные имена.
Язык программирования ASM-51 279 В приведенном в листинге 8.4 примере имена Funcset и _8bit являются константами, но это становится понятным только по использованию не- непосредственной адресации в команде mov. Один раз назначенный при помощи директивы equ идентификатор уже не может быть изменен, и при повторной попытке назначения точно такого же имени идентификатора транслятором будет выдано сообщение об ошибке. Директива set. Если требуется в различных местах программы назначать одному и тому же идентификатору различные значения, то нужно поль- пользоваться директивой set. Она используется точно так же, как директива equ, поэтому иллюстрировать это примером не будем. Константы, назначаемые директивами equ или set, могут быть исполь- использованы только в качестве операндов команд микроконтроллера. В то же время достаточно часто требуется работа с таблицей констант, такой как таблица перекодировки, таблицы элементарных функций или синдромы помехоустойчивых кодов. Такие константы используются не на этапе трансляции для формирования машинного кода инструкций, а при ис- исполнении программы. Они заносятся в память программ микроконтрол- микроконтроллера. Для помещения значений констант в память программ микрокон- микроконтроллера используются директивы аь и dw. Директива аь используется для занесения в память программ однобайт- однобайтных констант. Пример использования директивы аь приведен в листин- листинге 8.5. Decod: mov DPTR,#TabDecod move A,@A+DPTR ret TabDecod:;-abcdefg DB 01111110b /символ Л0' DB 00110000b /символ 4' DB 01101101b /символ Х2' DB 01111001b /символ Х3' DB 00110011b /символ Ч' DB 01011011b /символ Л5' DB 01011111b /символ Л6' Расположение сегментов в семисегментном индикаторе а
280 Глава 8 DB 01110000b /символ Л7' DB 01111111b ;символ *8f DB 01111011b /символ Х9' d В этом примере использована подпрограмма-функция, перекодирующая двоично-десятичное число в семисегментный код при помощи таблицы TabDecod. В эту функцию двоично-десятичный код передается через ак- аккумулятор и через этот же регистр в вызывающую программу возвраща- возвращается семисегментный код. В директиве аь можно задавать сразу несколько констант, разделенных запятыми. Можно одновременно использовать все системы счисления, но обычно имеет смысл снабдить каждую константу комментарием, как это сделано в предыдущем примере. Так программа становится более понятной и ее легче отлаживать. Эта же директива позволяет легко размещать в памяти строки, которые в дальнейшем потребуется высвечивать на встроенном дисплее или экране дисплея универсального компьютера, подключенного к разрабатывае- разрабатываемому устройству через какой-либо интерфейс. Пример использования директивы db для занесения строк в память программ микроконтроллера приведен а листинге 8.6. mov R7,#(EndNadp-NadpSvjazUst)/Занести количество символов в строке mov DPTR,#NadpSvjazUst /Подготовиться к передаче первого символа PrdSledSmv: clr A move A,@A+DPTR inc DPTR /Считать очередной символ надписи call PrdSmv dj n z R7,PrdS1edSmv ret /Передать очередной символ надписи, и ;если это был последний символ надписи, ;то выйти из подпрограммы NadpSvjazUst: db 'Связь установлена',10,13 EndNadp:
Язык программирования ASM-51 281 Директива dw позволяет заносить в память программ двухбайтные числа. В ней, как и в директиве аь, можно записывать несколько чисел, разде- разделенных запятой. Пример фрагмента программы приведен в листинге 8.7. Листинг 8Х Применений директивы dw 0016 0001 264 dw l,2,0abh,'a1,'QW 0018 0002 001А 00AB 001C 0061 001E 5157 В листинге 8.7 фрагмент программы приведен для того, чтобы можно было проследить, какие байты заносятся в память программ микрокон- микроконтроллера. В самой правой колонке листинга приведены адреса, в кото- которые будут занесены числа, являющиеся операндами директивы dw. В сле- следующей колонке приведены двухбайтовые числа, которые будут заноситься в память программ микроконтроллера. Обратите внимание: несмотря на то, что первые два операнда директивы dw состоят только из одной цифры, в память микроконтроллера заносятся четыре шестнадца- теричных цифры (двухбайтовое число). При трансляции исходного текста программ по умолчанию предполага- предполагается, что первая команда расположена по нулевому адресу. Адрес после- последующих команд зависит от длины и количества предыдущих команд. Пример начального участка программы приведен в листинге 8.8. [ Листинг, 8.8. Начальный участок программы . ] |. *Wb4h iwl 4 b j'V *^ fc в V*V * # V fc J b jyi^ b # V * 4 b + V Ь V b tVfc Л \ IV ( 4 b в V b tfklVHWWI 4 b Ivi^ViVt^h • V I 4 b 4у| 4 \ 4 V » 4 b * v\ rf b • V I 4 b Д V Ь 4 b • V % Л Ъ IVb Ih IVI 4V IVk rffc IVI 4VJVM 4b IVkVV IVt 4b 4Vi 1 \ JV4 4b «Vu 4b #V№ 4b IVI^I^I Viri k^Vl^k 4^ 4Vb AV^VwV LOC OBJ LINE SOURCE 0000 78FF 1 mov R0,#255 /Обнулить 255 ячеек памяти 0002 E4 2 clr A 0003 3 ClrOZU: 0003 F6 4 mov @R0,A /Обнулить очередную ячейку памяти 0004 D8FD 5 djnz R0,ClrOZU /Если все ячейки обнулены, б ;то продолжить выполнение программы Иногда нужно расположить команду по определенному адресу. Наибо- Наиболее часто это требуется при использовании прерываний, когда первая ЮЗак 328
282 Глава 8 команда подпрограммы-обработчика прерываний должна быть распо- расположена точно в ячейке с определенным адресом (вектором), зависящим от источника прерывания. Векторы размещаются в начальных ячейках программной памяти и занимают 8 байтов каждый. Если эта область не используется целиком, то можно использовать команду пор для заполне- заполнения промежутков между векторами прерывания. Но лучше для назначе- назначения нужных адресов подпрограммам прерываний воспользоваться ди- директивой org. Директива org предназначена для записи в счетчик адреса сегмента зна- значения своего операнда. То есть при помощи этой директивы можно по- поместить команду (или данные) в памяти микроконтроллера по произ- произвольному адресу. Пример использования директивы org для размещения подпрограмм обработки прерываний в нужных адресах показан в лис- листинге 8.9. reset: ljmp main ;Перезагрузка таймера ORG AT Obh /Вектор прерывания от таймера О IntTO: mov TLO, #LOW(-(F_ZQ/12)*10-2) /Настроить таймер mov THO, #HIGH(-(F_ZQ/12)*10-2) ;на период Юме reti /Начало основной программы микроконтроллера rseg _code main: mov SP,#VershSteka /Настроить указатель стека на вершину стека lcall init /Настроить микроконтроллер Необходимо отметить, что при использовании этой директивы возможна ситуация, когда программист приказывает транслятору поместить новый код программы в уже занятом участке памяти, поэтому использование
Язык программирования ASM-51 283 этой директивы допустимо только в крайних случаях. Обычно это раз- размещение подпрограмм прерываний. Директива using. При использовании прерываний критичным является время выполнения подпрограммы-обработчика прерываний. Его можно значительно сократить, выделив для обработки прерываний отдельный банк регистров при помощи директивы using. Номер используемого банка регистров указывается в директиве в качестве операнда. При этом реальное включение банка регистров производится записью необходи- необходимой константы в регистр PSW. Пример использования директивы using для подпрограммы обслуживания прерываний от таймера 0 приведен в листинге 8.10. USING 2 /Использовать второй банк регистров IntTO: push PSW /Сохранить содержимое слова состояния микроконтроллера push ACC /Сохранить содержимое аккумулятора mov PSW,#00010000В /Включить второй банк регистров mov TL0, mov THO, pop ACC pop PSW reti #LOW(-(F_ZQ/12)*10-2) /Настроить таймер #HIGH(-(F_ZQ/12)*10-2) /на период Юме /Восстановить содержимое аккумулятора /Восстановить содержимое слова состояния микроконтроллера Остальные директивы ассемблера предназначены для управления сег- сегментами памяти и будут рассмотрены позднее. Управляющие команды Кроме директив, для управления процессом трансляции используются команды языка программирования. С их помощью можно управлять ра- работой компилятора ASM-51. Команды могут задаваться как параметры в DOS-строке вызова компилятора или как управляющие строки в исход- исходном тексте файла. Если знак доллара ($) стоит в самом крайнем левом поле строки, то такая строка воспринимается компилятором как управляющая. Управляющие
284 Глава 8 строки должны начинаться знаком доллара и могут содержать одну или более команд, разделенных пробелами. Примеры управляющих строк: $PRINT(A:\PROG.LST) OBJECT(PROG.OBJ) $LIST DEBUG XREF Так как целью книги является дать минимальные сведения, достаточные для того, чтобы начать работать с микроконтроллерами, то в данной книге будут рассмотрены только основные команды языка программи- программирования ASM-51. Команда include. Это, пожалуй, наиболее часто используемая команда языка программирования ASM-51. Она позволяет включать в состав про- программы участки текста из другого файла. Это удобно при многофайловом написании программы, например, для того, чтобы вынести описания внутренних регистров микроконтроллера в отдельный файл. Пример ис- использования команды include для включения файла описания внутренних регистров микроконтроллера 89с51 выглядит следующим образом: $INCLUDE (RBG51.INC) При использовании этой команды все содержимое включаемого файла помещается в выходной листинг программы, в результате чего становит- становится трудно читать этот листинг. Поэтому в состав команд языка програм- программирования ASM-51 ВКЛЮЧенЫ КОМанДЫ list/nolist. Команды list/noiist позволяют включать и выключать листинг исход- исходного текста соответственно. При активной команде noiist в файл лис- листинга будут помещаться только сообщения об ошибках. Пример запрета размещения содержимого включаемого файла в листинге программы бу- будет выглядеть следующим образом: $NOLIST //Запретить создание листинга включаемого файла $INCLUDE (RBG51.INC) $LIST //Разрешить создание листинга дальнейшего текста Команда debug/nodebug позволяет помещать в объектный модуль отла- отладочную информацию (имена и местоположение переменных, меток и операторов) или запрещать размещение отладочной информации в объ- объектном модуле. Команда pageiength (n) определяет максимальное число строк на стра- странице файла листинга. Это число включает заголовок страницы. Количе- Количество строк в странице может изменяться в пределах от 10 до 65535. Команда pagewidth (n) определяет максимальное число символов в строке листинга. Количество символов в строке листинга может изме- изменяться от 72 до 132.
Язык программирования ASM-51 285 Реализация подпрограмм на языке ASM-51 Подпрограммы на языке программирования ASM-51 выносятся отдель- отдельно от основного текста программы. Обычно при программировании на языке ассемблера подпрограммы размещают после основного текста программы для того, чтобы случайно не передать управление подпро- подпрограмме не командой ее вызова, а последовательным выполнением опера- операторов основной программы. Такая ситуация может произойти из-за то- того, что ассемблер назначает адреса машинным командам в порядке их написания. Если в начале поместить исходный текст подпрограммы, то именно она будет размещена по нулевому адресу памяти программ и по- после сброса будет выполнена раньше, чем основная программа. При завершении подпрограммы команда ret передаст управление по неопре- неопределенному адресу памяти программ, что может привести к непредсказуе- непредсказуемым последствиям. Если в начале поместить текст основной программы, то после сброса начнется ее выполнение. После инициализаций (включая установку начального значения указателя стека) основная программа всегда содержит бесконечный цикл. Это означает, что попасть в подпро- подпрограмму в результате последовательного выполнения операторов невоз- невозможно. Управление в нее может быть передано только с помощью команды вызова подпрограммы lean. Исходный текст подпрограммы начинается с метки, которая одновре- одновременно является именем подпрограммы. Именно это имя указывается в качестве операнда в команде вызова подпрограммы lean. Возвращение из подпрограммы к команде, следующей за вызовом подпрограммы, осуществляется оператором ret. Все команды, которые должны быть выполнены в подпрограмме, располагаются между меткой, обозна- обозначающей имя подпрограммы, и оператором возврата из подпрограммы. В главе 7 говорилось, что подпрограммы бывают двух видов: подпро- подпрограммы-функции и подпрограммы-процедуры. На языке программиро- программирования ассемблер проще реализуются подпрограммы-процедуры, поэтому сначала рассмотрим их. Реализация подпрограмм-процедур на языке ASM-51 Подпрограмма-процедура вызывается командами процессора lean и асан. В языке программирования ASM-51 допустимо использование ди- директивы call. Выполняя ее, компилятор автоматически подбирает наи-
286 Глава 8 более подходящую к данному случаю по размеру команду. В листин- листинге 8.11 приведен пример использования подпрограммы-процедуры для управления последовательным портом. ШШШШШШШ'ШШШШШШШ MOV G_Per,#56 /Передать число 56 через CALL PeredatByte /последовательный порт • • • MOV G_Per,#37 /Передать число 37 через CALL PeredatByte /последовательный порт .•**••**•*•***•**••*•*•*•*•••••*•**•••••*••*• /Подпрограмма передачи байта /через последовательный порт .••••••**•***••••••••••••••**••••••••*••••••• г PeredatByte: JB TI, $ /Если предыдущий байт передан, MOVSBUF, G_Per /то передать очередной байт RET Передача переменных-параметров в подпрограмму В приведенном на листинге 8.11 примере байт передается в подпрограм- подпрограмму через глобальную переменную GPer. Однако программа будет эффек- эффективнее при использовании подпрограммы с параметрами. Мы уже знаем, что параметр подпрограммы — это локальная переменная, а при исполь- использовании локальных переменных могут значительно снизиться требова- требования к памяти данных, т. к. локальные переменные разных подпрограмм располагаются в одних и тех же ячейках памяти микроконтроллера. Для размещения локальных переменных лучше всего использовать внутрен- внутренние регистры процессора, т. к. кроме экономии памяти данных, исполь- использование регистровых переменных приводит к сокращению длины ма- машинных команд, а значит и длины всей программы в целом. Кроме того, использование подпрограмм с параметрами позволяет вызывать подпро-
Язык программирования ASM-51 287 грамму саму из себя, например, при реализации рекурсивных алгорит- алгоритмов. На языке ASM51 для передачи параметра размерностью один байт обычно используется аккумулятор, как показано в примере программы, приведенном в листинге 8.12. MOV А,#56 /Передать число 56 через CALL PeredatByte /последовательный порт • • • MOV А,#37 /Передать число 37 через CALL PeredatByte /последовательный порт .**•*•••••••••••••••••••••••••••••••••••••••• /Подпрограмма передачи байта /через последовательный порт .•••••••*••••••••••••••••••••••••••••••••••*•*•• г PeredatByte: JB TI, $ /Если предыдущий байт передан, MOV SBUF, А /то передать очередной байт RET Часто пример использования подпрограммы с параметрами более по- понятно выглядит на языке высокого уровня. Вызов подпрограммы с од- одним параметром, приведенный в листинге 8.12, на языке программиро- программирования С выглядел бы следующим образом: PeredatByteE6); //Передать число 56 PeredatByteC7)/ //Передать число 37 Часто в подпрограмме требуется обрабатывать большие объемы данных, такие как массивы или структуры. При обращении к массивам или структурам, расположенным во внутренней памяти данных в качестве указателя адреса обычно используются регистры ro или ri. Пример пе- передачи в подпрограмму массива в качестве параметра, написанный на языке программирования ASM-51, приведен в листинге 8.13.
288 Глава 8 шшшшшттттштшштйшшшшшшмттвш MOV RO,#Massiv ;Задать адрес обрабатываемого массива CALL ObrabotatMassiv /Вызвать подпрограмму обработки массива Если требуется, чтобы подпрограмма обработала такого же вида данные, но расположенные во внешней памяти данных или в памяти программ, то начальный адрес этих данных можно передать через двухбайтовый параметр-указатель. В качестве такого указателя обычно используется регистр-указатель данных dptr. Пример передачи в подпрограмму адреса начального элемента строки в качестве параметра, написанный на языке программирования ASM-51, приведен в листинге 8.14. Строка располо- расположена в памяти программ. Ее размещение в памяти программ показано в последней строке этого же листинга. с MOV DPTR,#Stroka /Задать адрес первого байта строки CALL PeredatStroky /Вызвать подпрограмму передачи строки • • • Stroka: db *Напечатать строку' Если в подпрограмму нужно передать в качестве параметра двухбайто- двухбайтовое число, то для этого используется пара регистров (обычно это регист- регистры R6 — старший байт и R7 — младший байт). Пример вызова подпро- подпрограммы с передачей в нее двухбайтового параметра, написанный на языке программирования ASM-51 приведен в листинге 8.15. /Пример передачи в подпрограмму двухбайтового числа MOV R7,#56 /Передать младший байт
Язык программирования ASM-51 289 MOV R6,#0 /Передать старший байт CALL Podprogr /Вызвать подпрограмму Если в подпрограмму нужно передать четырехбайтовое значение (параметр ТИПа long, unsigned long ИЛИ float), TO обыЧНО ИСПОЛЬЗуЮТСЯ регистры R4—R7 (регистр R4 — старший байт). Пример вызова подпро- подпрограммы с передачей в нее четырехбайтового параметра, написанный на языке программирования ASM-51, приведен в листинге 8.16. |шг &16* Пример вызова подпрограммы-процедуры с перщач^й в нее Ыхбайтового числа (параметра) через регистры Е4-&6 ' * /Пример передачи в подпрограмму четырехбайтового числа MOV R7,#56 /Передать младший байт MOV R6,#0 MOV R5,#0 MOV R4,#0 /Передать старший байт CALL Podprogr /Вызвать подпрограмму В примере показана передача в подпрограмму константы, но точно так- также можно передавать и переменную, расположенную во внутренней или внешней памяти данных. Для этого достаточно просто скопировать пе- переменную В реГИСТрЫ R4—R7. Реализация подпрограмм-функций на языке ASM-51 Часто требуется Передавать результат вычислений из подпрограммы в основную программу. Для этого обычно используется подпрограмма- функция. Наиболее наглядным примером использования подпрограмм- функций является вычисление элементарных функций. Подпрограмма- функция для вычисления синуса в программе на языке высокого уровня вызывается следующим образом: Y=sin(x); //Вызов подпрограммы-функции Как видно из приведенного примера, использование подпрограмм- функций значительно увеличивает наглядность программ и приближает
290 Глава 8 запись на языке программирования к общепринятой математической форме. На языке программирования ASM-51 этот же вызов подпро- подпрограммы-функции выглядит следующим образом: mov А,х /Передать в подпрограмму вычисления синуса параметр х call sin ;Вызвать подпрограмму вычисления синуса mov Y,A ;Запомнить значение, которое вернула подпрограмма в Y В этом примере подпрограмма вычисления синуса перед выполнением оператора возврата в основную программу должна поместить результат вычисления синуса в аккумулятор. Переменные х и у должны быть объ- объявлены в начале программы при помощи директивы equ, как это показы- показывалось ранее. Как видно из приведенного примера, вызов подпрограм- подпрограммы-функции на языке ассемблера менее нагляден по сравнению с языком программирования высокого уровня, но использование подпрограмм- функций позволяет значительно сокращать требования к внутренней па- памяти микроконтроллера благодаря максимальному использованию внутренних регистров микроконтроллера. Элементарные операции на языке программирования ассемблер чаще всего вычисляются табличным способом, подобным тому, как проводи- проводилась перекодировка чисел, приведенная в примере листинга 8.5. Сами значения функций при этом рассчитываются заранее с использованием компьютера и вводятся во внутреннюю память микроконтроллера при помощи директивы db. Подпрограмма-функция может возвращать и многобайтовые перемен- переменные. Для этого можно использовать два или четыре регистра. Обычно используются регистровая пара R6, r7 или регистры R4—R7. Можно так- также рассчитать и записать во внутренней памяти полученную в результате вычислений в подпрограмме переменную-массив или структуру и пере- передать в вызывающую программу адрес этой переменной при помощи ре- регистра-указателя R0 ИЛИ R1. Кроме подпрограмм-процедур и подпрограмм-функций существует осо- особый класс подпрограмм. Это подпрограммы обработки аппаратных прерываний. Реализация подпрограмм обработки прерываний на языке ASM-51 Подпрограммы обработки прерываний вызываются аппаратурой в про- произвольный момент времени и не могут иметь параметров. Подпрограм- Подпрограммы обработки прерываний не могут быть подпрограммами-функциями. При переходе на подпрограмму обслуживания прерывания автоматиче-
Язык программирования ASM-51 291 ски запрещается возникновение последующих прерываний, поэтому при возвращении из подпрограммы обработки прерывания должны быть разрешены прерывания. Команда возвращения из подпрограммы ret не снимает запрет на обработку прерываний, поэтому возврат из подпро- подпрограммы обработки прерывания может быть осуществлен только специ- специальной командой возврата из подпрограммы обслуживания прерывания reti. Пример подпрограммы обработки прерывания на языке програм- программирования ASM-51 приведен в листинге 8.17. ;Старт программы ORG 0 ;Вектор рестарта процессора Reset: jmp main ORG OBh ;Вектор прерывания таймера О jmp IntTO ORG 23h ;Вектор прерывания последовательного порта jmp PoslPort IntTO: /Перезагрузка таймера mov TL0,#LOWA5000) /Настроить таймер mov TH0/#HIGHA5000) ;на период 15 мс reti /Начало основной программы main: Достаточно часто требуется обработка прерываний от нескольких ис- источников. В результате подпрограмма обработки прерываний не может уместиться между векторами прерываний на участке памяти длиной 8 байтов, поэтому подпрограммы выносятся из области векторов преры- прерывания. Для перехода на эти подпрограммы используются команды безус- безусловного перехода. В листинге 8.17 директива org использована для того, чтобы поместить команду перехода на подпрограмму обработки преры- прерывания точно на вектор прерывания таймера 0. Сигнал прерывания, а значит и вызов подпрограммы обработки преры- прерывания может произойти в произвольный момент времени, т. е. в любом месте выполнения основной программы. Чтобы не повлиять на выпол-
292 Глава 8 нение основной программы, подпрограмма обработки прерываний не должна изменять содержимое регистров, ведь в них могут быть записаны данные, используемые в основной программе. Поэтому все регистры, ко- которые используются подпрограммой обработки прерываний, должны быть сохранены в стеке, а затем восстановлены из него. Если подпрограмма обработки прерывания использует несколько реги- регистров, то на сохранение регистров в стеке и на восстановление их из сте- стека тратится достаточно много времени. Микроконтроллеры семейства MCS-51 предлагают возможность использовать для подпрограмм пре- прерываний отдельный банк регистров. Переключение банков регистров производится при помощи регистра psw. В языке программирования ASM-51 то, что программа использует не нулевой банк регистров, ука- указывается при помощи директивы using. Переключение банков регистров в подпрограмме обработки прерывания от таймера ТО, а также резерви- резервирование первого банка регистров при помощи директивы using показано в листинге 8.18. 1Z: Ш^Ш^^^^ШщФ^^ШШ^р^ШкУЛ обработки' прерывания ;Старт программы ORG 0 /Вектор рестарта процессора Reset: jmp main ORG OBh ;Вектор прерывания таймера О jmp IntTO ORG 23h ;Вектор прерывания последовательного порта jmp PoslPort USING 1 PoslPort: /Подпрограмма обработки прерывания от поел, порта push PSW /Сохранить регистр слова состояния в стеке mov PSW,#00001000b /Включить первый банк регистров mov @R0,SBUF /Записать принятое значение в буфер приемника inc R0 /Перейти к следующей ячейке буфера приемника cjne R0,#KonBuf,EndProv /Если достигнут конец буфера приемника, mov R0,#NachBuf /то перейти к первой ячейке
Язык программирования ASM-51 293 EndProv: pop PSW /Восстановить регистр слова состояния из стека reti Структурное программирование на языке ASM-51 Применение структурного программирования позволяет увеличить ско- скорость написания программ и облегчить их отладку. Языки программи- программирования С, PASCAL, PL/M разрабатывались на основе принципов структурного программирования, поэтому в состав этих языков входят структурные операторы. Ассемблер не относится к структурированным языкам программирования. Тем не менее, структурное программирова- программирование возможно и на языках программирования низкого уровня, в том числе и на языке программирования ASM-51, где не предусмотрено структурных операторов. При разработке программы с использованием методов структурного программирования она может быть оттранслирована и выполнена на любом этапе написания, при этом можно отследить все алгоритмические действия программы, реализованные к этому времени. При использова- использовании методов структурного программирования процесс написания про- программы не отличается от процесса создания алгоритма. Более того! Эти этапы создания программы можно объединить! Для реализации методов структурного программирования огромное значение имеет использование «говорящих» меток, обозначаемых не просто мо, mi и т. д., а в названии которых отображается действие, вы- выполняемое программой. Для людей, не владеющих иностранным языком, ограничение в использовании для назначения меток букв только латин- латинского алфавита создает определенные трудности. Однако, используя транслитерацию, и латинскими буквами можно писать русские слова. При этом для обозначения действия может потребоваться несколько слов, использование же пробелов внутри метки недопустимо! Выйти из такой ситуации можно двумя способами: ? применять специальные символы-разделители; ? начинать каждое новое слово внутри метки с буквы верхнего регистра. В качестве разделителей внутри метки можно использовать символы подчеркивания (_) и вопроса (?). Примеры назначения «говорящих» меток: Priem_Comandy /Использование символов-разделителей ProveritBitGotovnosti /Использование букв верхнего регистра
294 Глава 8 Надо сказать, что в языке программирования ассемблер роль метки ис- исключительно важна. Метка используется для обозначения переменных и констант, а также имен подпрограмм и программных модулей. Одна из основных идей структурного программирования заключаются в том, чтобы использовать только четыре структурных конструкции управления. При помощи этих структурных конструкций управления можно построить сколь угодно сложную программу. Наиболее распространенная структурная конструкция управления — ли- линейная цепочка операторов. Любая задача может быть разбита на не- несколько более простых подзадач. Выполнение подзадач лучше оформить как вызов подпрограмм, в названии которых можно (и нужно) отразить подзадачу, которую решает эта подпрограмма. Например: ProchitatPort /Прочитать порт Vklychitlndikator ;Включить индикатор При этом с точки зрения структурного программирования использовать подпрограмму имеет смысл даже в том случае, когда действие будет вы- выполняться только один раз! Выполняемое алгоритмическое действие отображается в названии подпрограммы, поэтому программу можно чи- читать по названиям подпрограмм. Человеческий глаз может охватить большую часть алгоритма, а значит, программа будет более понятна, что приведет к более быстрому завершению ее отладки. Программы, понят- понятные при чтении исходного текста программы, часто называют самодо- самодокументирующимися. На момент написания алгоритма (и программы) верхнего уровня нас не интересует, как будут решаться задачи, зато очень интересуют взаимо- взаимосвязи между ними. Поэтому первоначально вместо законченных подпро- подпрограмм можно (и нужно) использовать подпрограммы-заглушки. Исполь- Использование подпрограмм-заглушек позволяет отработать взаимодействие между задачами, убедиться, что все они выполняются в нужной последо- последовательности и именно тогда, когда возникает необходимость в решении данной конкретной задачи. Для взаимодействия между задачами обычно используются глобальные переменные. Эти переменные и вводятся на верхнем уровне программы. Если переменные отвечают за переключение между задачами, то измене- изменение переменных производят вручную в отладчике программ. Затем при пошаговой отладке проверяют, вызывается ли подпрограмма, отвечаю- отвечающая за выполнение поставленной задачи, и не вызываются ли при этом лишние подпрограммы. После завершения отладки верхнего уровня программы приступают к написанию и отладке каждой из подпрограмм-заглушек, т. е. к превра- превращению подпрограмм-заглушек в законченные подпрограммы. При этом,
Язык программирования ASM-51 295 т. к. программа верхнего уровня уже отлажена, то решается только зада- задача, выполняемая отлаживаемой в данный момент подпрограммой. Осо- Особенно тщательно отслеживается взаимодействие с программой верхнего уровня для того, чтобы не нарушить логику ее работы. Одновременно отрабатывается взаимодействие с подпрограммами более нижнего, по сравнению с отлаживаемым, уровня. Пример реализации линейной цепочки операторов на языке программи- программирования ASM-51 приведен в листинге 8.19. ;Главная программа .•••••••••••••••••••••••••••••••••••••••••••••••••*•*•••••••*•*••*•• Линейная цепочка операторов Call Deistviel /Алгоритмическое действие 1 Call Deistvie2 /Алгоритмическое действие 2 ;Определения подпрограмм г ; Подпрограмма-заглушка 1 Deistviel: ret ; Подпрограмма-заглушка 2 Deistvie2: ret Вторая структурная конструкция управления — условное выполнение оператора. Как уже рассматривалось в предыдущей главе, эта конструк- конструкция может быть двух видов — с одной ветвью и с двумя ветвями. Если реализуется конструкция условного выполнения оператора только с одной ветвью, то можно воспользоваться любой командой условного перехода, входящей в набор команд микроконтроллера. Соответствую- Соответствующий пример приведен в листинге 8.20. В приведенном примере перемен- переменная svi и константа NajKnZvezd должны быть объявлены ранее (напри- (например, при помощи директивы equ).
296 Глава 8 ;'л" " ' ''"""' *"' • ч'"" » n-iin*.;f '*'у '¦'""'" '' '*';"чич-г ift4nn.ty 1"' "'"' V/^' "|"'""" *«" "m.m-itimmm.-пм- г,.,..,.,.,.,,.,,.,.,,.,.,,.,.,,.,.,,.,.,,.,,,,, : Листинг 8,20. Пример использования команд условного перехода [ №* реализации конструкции условного выполнений оператора > с одной ветвью : /Оператор обработки нажатой кнопки cjne A,#NajKnZvezd,NeGasitSvDiod ;Если нажата кнопка у*', clr SV1 ;то погасить светодиод SV1 NeGasitSvDiod: Полная конструкция условного выполнения операторов реализуется на языке ассемблера более сложным образом. Для этого потребуются уже две команды перехода. Для проверки результата логического выражения используется команда условного перехода. Чтобы исключить выполне- выполнение второй ветви, потребуется команда безусловного перехода. Пример реализации полной конструкции условного выполнения операторов приведен в листинге 8.21. |'y ** W * изации конструкции условного выполнения ,*¦ IXVJ .-*••••••••••••••*••••*•••••••••••••• -А-*************** / /Главная программа ; Условный оператор jb PrinjatByte,ElseUsl /Условная операция Call Plechol ;Реализация jmp EndUsl ;ветви 1 ElseUsl: Call Plecho2 /Реализация ветви 2 EndUsl:; .********************************************** ;Определения подпрограмм .••••А- •*¦••••••*¦•••*¦••*•••*¦•••••*¦•*¦•*¦••*¦•••*••*••*¦•••*••*•**•*** /
Язык программирования ASM-51 297 ;—Пока это только подпрограмма-заглушка!— Plechol: ;Метка помечает следующий оператор ret ;—Пока это только подпрограмма-заглушка! Plecho2: ;Метка помечает следующий оператор ret Третья структурная конструкция — это цикл с проверкой условия после тела цикла. Такая конструкция легко реализуется на ассемблере при по- помощи одной команды условного или безусловного перехода. Отличие этой конструкции от условного выполнения операторов заключается в том, что передача управления осущестрляется не вперед, а назад. Однако в системе команд микроконтроллера MCS-51 для реализации цикла пре- предусмотрена специальная команда, выполняющая сразу два алгоритмиче- алгоритмических действия, необходимых для реализации цикла, — djnz. Пример ис- использования этой команды для реализации цикла с проверкой условия после тела цикла приведен в листинге 8.22. Листинг 8,22, Пример реализации цикла с проверкой условия после тела цикла на языке программирования ASM-51 /Программа обнуления внутренней памяти микроконтроллера mov R0,#128 /Обнулить 128 ячеек mov A,#0 /внутренней памяти Obnulenie: mov @R0,A /Обнулить очередную ячейку, DJNZ R0, Obnulenie /и если все ячейки обнулены, /то выйти из цикла Четвертая структурная конструкция управления — это цикл с проверкой условия до тела цикла. В отличие от предыдущего варианта цикла, тело цикла в данном случае может ни разу не выполниться, если условие цик- цикла сразу же выполнено. Этот цикл, как и конструкцию условного выпол- выполнения операторов, невозможно реализовать при помощи одной машинной команды. Дополнительно потребуется команда безусловного перехода. Пример реализации цикла с проверкой условия до тела цикла приведен в листинге 8.23.
298 Глава 8 ***************************************** /Главная программа ***************************************** ; Оператор цикла Nachalo: jb KnNaj,KonCykla /Условная операция Call TeloCykla ;Реализация обработки sjmp Nachalo /подпрограмм ожидания KonCykla: .**************************************•** ;Определения подпрограмм .***************************************** ; Подпрограмма-заглушка TeloCykla: ret /Оператор помечен предыдущей меткой Многомодульные программы Как это обсуждалось в предыдущей главе, разбиение исходного текста программы на отдельные модули делает его более понятным для про- программиста или нескольких программистов, участвующих в создании программного продукта. Язык программирования ASM-51 позволяет писать многомодульные программы. Однако каждый модуль программы должен быть оформлен соответствующим образом. Обычно все переменные и константы (хранящиеся в памяти программ) использующиеся в программном проекте, оформляются в отдельном модуле. В отдельный модуль выносятся подпрограммы, отвечающие за работу с каким-либо внешним или внутренним устройством микрокон- микроконтроллерной системы. Все эти элементы программы должны быть доступ-
Язык программирования ASM-51 299 ны из основной программы или других модулей. Для того чтобы транс- транслятор записал в объектный модуль информацию, необходимую для объ- объединения модулей в единую программу, нужно использовать специальные директивы ссылок на метки, применяемые для обозначения переменных и подпрограмм. В языке программирования ASM-51 для этой цели используется дирек- директива public (общедоступные). Директива может быть использована в лю- любом месте исходного текста модуля, однако обычно она размещается в его начале. Имена переменных в этой директиве перечисляются через за- запятую. Если в результате получается слишком длинная строка, то можно использовать несколько таких директив. Глобальное имя может быть объявлено только в одном модуле программы. Несколько глобальных переменных или подпрограмм с одним и тем же именем недопустимы. Пример использования директивы public на языке программирования ASM-51: PUBLIC Buflnd, Parametr PUBLIC Podprogr, ?Podprogr?Byte Для ссылки на переменную или метку, объявленную в другом модуле, используется директива extrn. Идентификатор в пределах одного модуля не может быть одновременно объявлен как public и как extrn. В директи- директиве extrn перечисляются через запятую имена подпрограмм и переменных, числовое значение которых редактор связей должен получить из других модулей и модифицировать все команды, в которых эти метки или пере- переменные используются. Кроме того, для правильного использования ин- инструкций микроконтроллера в директиве extrn должен быть указан тип памяти (data, bit, code, idata или xdata), в которой расположена перемен- ная или метка. Для передачи числовых констант между модулями можно воспользоваться вспомогательным словом number Директива extrn мо- может располагаться в любом месте исходного текста модуля. Идентифика- Идентификатор внешнего имени не может быть переопределен в программном моду- модуле каким-либо способом. Рекомендуется с целью оптимизации результирующего объектного кода (в частности, команд jmp и call) раз- размещать директиву extrn до ссылки на соответствующее внешнее имя (как правило, в начале исходного текста программного модуля или про- программного сегмента). Пример использования директивы extm на языке программирования ASM-51: EXTRN DATA (Buflnd, ERR), CODE (ASC_BIN, BIN_ASC) , NUMBER (LIMIT) EXTRN CODE (Podprogr) Объявления переменных и имен подпрограмм внешних модулей загро- загромождают исходный текст модуля. Кроме того, при использовании чужих модулей трудно объявить переменные и подпрограммы без ошибок. По-
300 Глава 8 этому, как это обсуждалось в предыдущей главе, объявления имен хранят во включаемых файлах, которые называются файлами-заголовками. Файл-заголовок на языке программирования asm-51 записывается на диск с расширением *.inc (сокращение от английского слова include — включать) и включается в исходный текст программы при помощи ди- директивы include. Например: $INCLUDE (REG51.INC) При работе с пакетом программ, поставляемым фирмой keil, программа- транслятор с языка программирования ASM-51 «понимает» и файлы- заголовки, написанные для языка программирования С-51. Поэтому можно воспользоваться и этими файлами. Например: #include <at87f51rc.h> $include (init.inc) Теперь рассмотрим команды редактора связей, которые позволят объе- объединить несколько объектных модулей в один. В простейшем случае для объединения модулей можно использовать имя программы-редактора связей с необходимыми ключами. Для объединения нескольких модулей в исполняемую программу имена всех модулей передаются в редактор связей ri5i.exe в качестве параметров при запуске этой программы. Приведем пример вызова редактора связей из командной строки DOS для объединения трех модулей: г151.exe progr.obj, moduli.obj, modul2.obj В результате работы редактора связей в этом примере будет создан ис- исполняемый модуль с именем progr. Формат записи информации в этом файле остается прежним — объектным. Это позволяет объединять моду- модули по частям, т. е. при желании можно из нескольких мелких модулей получить один более крупный. В настоящее время часто пользуются интегрированными средами про- программирования, например, фирм Franclin или keil, в состав которых вхо- входит язык программирования ASM-51. В этих программах создание стро- строки вызова редактора связей производится автоматически при настройке программного проекта, а вызов редактора связей при помощи этой строки производится в ходе построения программного проекта. На- Настройка программного проекта происходит при подключении к нему но- новых программных модулей и при изменении его свойств, таких как раз- разрешение или запрет создания карты памяти программы, выбор папки для хранения выходных файлов, разрешение или запрет помещения в вы- выходной файл отладочной информации, разрешение или запрет создания загрузочного НЕХ-файла.
Язык программирования A SM-51 301 Использование сегментов в языке программирования ассемблер При трансляции программы по частям возникает вопрос, как с этими частями работать. Иначе говоря, дает о себе знать проблема сегментов. Справедливости ради необходимо отметить, что даже когда мы не заду- задумываемся о сегментах, в программе присутствуют два сегмента: сегмент кода и сегмент данных. Если внимательно присмотреться к программе, то можно обнаружить, что кроме кодов команд в памяти программ хра- хранятся константы, т. е. в памяти программ микроконтроллера располага- располагаются, по крайней мере, два сегмента: код и данные. Чередование кода и данных может привести к нежелательным последствиям. Вследствие ка- каких-либо причин данные могут быть случайно выполнены в качестве машинных команд или наоборот коды машинных команд могут быть восприняты и обработаны как данные. Перечисленные выше причины приводят к тому, что желательно явным образом выделить, по крайней мере, четыре сегмента: 1) кода; 2) переменных; 3) стека; 4) констант. И лучше, если эти сегменты будут перемещаемыми. Тогда редактор связей сможет автоматически скомпоновать программу наилучшим способом. Пример размещения сегментов в адресном пространстве памяти про- программ и внутренней памяти данных приведен на рис. 8.4. На этом рисун- рисунке видно, что при использовании нескольких сегментов переменных во внутренней памяти данных редактор связей может разместить меньший из них на месте неиспользованных банков регистров. Под сегмент стека обычно отводится вся область внутренней памяти, не занятая перемен- переменными. Это позволяет создавать программы с максимальным уровнем вложенности подпрограмм. Сегмент переменных, расположенный на рис. 8.4 во внешней памяти данных, при использовании современных микросхем, таких как AduC842, может находиться и в ОЗУ, расположен- расположенном на кристалле микроконтроллера. Наиболее простой способ определения сегментов — это использование абсолютных сегментов памяти. При этом способе распределение памяти ведется вручную точно так же, как это делалось при использовании ди- директивы equ. В этом случае начальный адрес сегмента жестко задается программистом, и он же следит за тем, чтобы сегменты не перекрывались
302 Глава 8 друг другом в памяти микроконтроллера. Использование абсолютных сегментов позволяет более гибко работать с памятью данных, т. к. теперь байтовые переменные в памяти данных могут быть назначены при по- помощи директивы резервирования памяти ds, а битовые переменные при помощи директивы резервирования битов dbit. 65535 0 Память программ Сегмент констант Сегмент кода 128 32 0 Память данных Стек Второй сегмент переменных Сегмент битовых переменных Первый сегмент переменных Регистры Внешняя память данных 0 Третий сегмент переменных Рис. 8.4. Разбиение памяти программ и памяти данных на сегменты Для определения абсолютных сегментов памяти используются следую- следующие директивы: ? bseg — абсолютный сегмент в области битовой адресации; ? cseg — абсолютный сегмент в области памяти программ; ? dseg — абсолютный сегмент в области внутренней памяти данных; ? iseg — абсолютный сегмент в области внутренней памяти данных с косвенной адресацией; ? xseg — абсолютный сегмент в области внешней памяти данных. Директива bseg позволяет определить абсолютный сегмент во внутрен- внутренней памяти данных с битовой адресацией по определенному адресу. Эта директива не назначает имени сегменту, т. е. объединение сегментов из различных программных модулей невозможно. Для определения кон- конкретного начального адреса сегмента применяется атрибут at. Если ат- атрибут at не используется, то начальный адрес сегмента предполагается равным нулю. Использование битовых переменных позволяет значи- значительно экономить внутреннюю память программ микроконтроллера.
Язык программирования ASM-51 303 Пример использования директивы bseg для объявления битовых пере- переменных приведен в листинге 8.24. __...,,..,„_,„.„.,..,.,,v.r.,.,.. ..... использования директивы bseg перед определениями 1ШНЫХ BSEG AT 8 ;Сегмент начинается с восьмого бита Rejlnd DBIT 1 ;Флаг режима индикации RejPriem DBIT 1 ;Флаг режима приема Flag DBIT 1 ;Флаг общего назначения Директива cseg позволяет определить абсолютный сегмент в памяти программ по определенному адресу. Директива не назначает имени сег- сегменту, т. е. объединение сегментов из различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут at. Если атрибут at не используется, то начальный адрес сегмента предполагается равным нулю. Пример использования ди- директивы cseg для размещения подпрограммы обслуживания прерывания от таймера 0 приведен в листинге 8.25. Дирокгивы .о w дп» размещения ;Перезагрузка таймера CSEG AT Obh ;Вектор прерывания от таймера О IntTO: mov TLO, #LOW(-(F_ZQ/12)*10-2) ;Настроить таймер mov THO, #HIGH(-(F_ZQ/12)*10-2) ;на период Юме reti Директива dseg позволяет определить абсолютный сегмент во внутрен- внутренней памяти данных по определенному адресу. Предполагается, что к этому сегменту будут обращаться команды с прямой адресацией. Эта ди- директива не назначает имени сегменту, т. е. объединение сегментов из раз- различных программных модулей невозможно. Для определения конкрет- конкретного начального адреса сегмента применяется атрибут at. Если атрибут at не используется, то начальный адрес сегмента предполагается равным нулю. Пример использования директивы dseg для объявления байтовых переменных приведен в листинге 8.26.
304 Глава 8 „.„,,.„„„„„„.,, .,, директивы 0$яа перед опредеяениам Г- DSEG AT 20 /Разместить сегмент в битовом пространстве микроконтроллера ;(для возможности одновременно битовой и байтовой адресации) Rejlnd DS 1 /Переменная, отображающая состояние программ обслуживания ;аппаратуры Rejim DS 1 /Переменная, отображающая режимы работы Massiv DS 10 /Десятибайтовый массив Последний пример связан с примером, приведенным в листинге 8.24. То еСТЬ КОМанДЫ, ИЗМенЯЮЩИе битовые Переменные Rejlnd, RejPriem ИЛИ Flag, одновременно будут изменять содержимое переменной Rejim, и на- наоборот команды, работающие с переменной Rejim, одновременно изме- изменяют содержимое флагов Rejlnd, RejPriem или Flag. Такое объявление переменных позволяет написать наиболее эффективную программу управления контроллером и подключенными к нему устройствами. Директива iseg позволяет определить абсолютный сегмент во внутрен- внутренней памяти данных с косвенной адресацией по определенному адресу. Напомню, что адресное пространство внутренней памяти с косвенной адресацией в два раза больше адресного пространства памяти с прямой адресацией. Именно в этой области памяти размещается стек. Директива iseg не назначает имени сегменту, т. е. объединение сегментов из различ- различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут at. Если атрибут at не используется, то начальный адрес сегмента предполагается равным ну- нулю. Пример использования директивы iseg для объявления байтовых переменных приведен в листинге 8.27. Листинг^8,2Т/ПримерйепоЬ^0Еания директивы XS&G доя объявления байтовых переменных ISEG AT 80 ; Разместить сегмент в диапазоне адресов, совмещенных с SFR Bufer DS 10 /Десятибайтовый массив Stack DS 245 ;Стек Директива xseg позволяет определить абсолютный сегмент во внешней памяти данных по определенному адресу. Эта директива не назначает имени сегменту, т. е. объединение сегментов из различных программных
Язык программирования ASM-51 305 модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут at. Если атрибут at не используется, то начальный адрес сегмента предполагается равным нулю. До недавнего времени использование внешней памяти не имело смысла, т. к. это зна- значительно увеличивало габариты и цену устройства. Однако в последнее время ряд фирм стал размещать на кристалле значительные объемы ОЗУ, доступ к которому осуществляется как к внешней памяти. Так как эта директива применяется так же, как dseg, to отдельный пример приво- приводиться не будет. Использование абсолютных сегментов позволяет облегчить работу про- программиста по распределению памяти микроконтроллера для различных переменных. Однако в большинстве случаев абсолютный адрес перемен- переменной нас совершенно не интересует. Исключение составляют только реги- регистры специальных функций. Так зачем же вручную задавать начальный адрес сегментов? Одна из ситуаций, когда нас не интересует начальный адрес сегмента, — это программные модули. Как уже говорилось ранее, в программные модули обычно выносятся подпрограммы. Естественно, что конкретные адреса, по которым будут находиться эти подпрограммы в адресном пространстве микроконтроллера, нас тоже мало интересуют. Если абсолютные адреса переменных или участков программ не интерес- интересны, то можно воспользоваться перемещаемыми сегментами. Имя пере- перемещаемого сегмента задается директивой segment. Директива segment позволяет определить имя сегмента и область памяти, где будет размещаться данный сегмент памяти. Для каждой области па- памяти определено ключевое слово: ? data — размещает сегмент во внутренней памяти данных с прямой адресацией; ? idata — размещает сегмент во внутренней памяти данных с косвен- косвенной адресацией; ? bit —размещает сегмент во внутренней памяти данных с битовой адресацией; ? xdata — размещает сегмент во внешней памяти данных; ? code —размещает сегмент в памяти программ. После определения имени сегмента можно использовать этот сегмент при помощи директивы rseg. Директива rseg позволяет поместить в конкретный перемещаемый сег- сегмент переменные или фрагмент кода программы. Обращение к одному и тому же сегменту может осуществляться в разных местах исходного тек-
306 Глава 8 ста программы (даже в разных файлах). При этом все участки сегмента будут находиться в соседних участках области памяти микроконтролле- микроконтроллера, выделенного для этого сегмента. Использование сегмента зависит от области памяти, для которой он предназначен. Если это память данных, то в сегменте объявляются бай- байтовые или битовые переменные. Если это память программ, то в сегменте размещаются константы или участки кода программы. Пример использования директив segment и rseg для определения байтовых пере- переменных во внутренней памяти данных с косвенной адресацией приведен в листинге 8.28. _data segment idata public Vershsteka ;Определение переменных- ^"seg _data buferKlav: ds 8 Vershsteka: End В этом примере объявлен массив buferKlav, состоящий из восьми байто- байтовых переменных. Кроме того, в данном примере объявлена переменная vershsteka, соответствующая последней ячейке памяти, используемой для хранения переменных. Переменная vershsteka может быть использована для начальной инициализации указателя стека для того, чтобы отвести под стек максимально доступное количество ячеек внутренней памяти. Это необходимо для того, чтобы избежать переполнения стека при вложенных вызовах подпрограмм. Объявление и использование сегментов данных в области внутренней или внешней памяти данных не отличается от приведенного в последнем примере за исключением ключевого слова, определяющего область памяти данных. Еще один пример использования директив segment и rseg приведен в лис- листинге 8.29. В этом примере директива segment используется для опреде- определения сегмента битовых переменных.
Язык программирования ASM-51 307 _bits segment bit public knIzm,strVv /Определение битовых переменных rseg _bits knlzm: dbit 1 strVv: dbit 1 end Наибольший эффект от применения сегментов можно получить при на- написании основного текста программы с использованием модулей. Обыч- Обычно каждый программный модуль оформляется в виде отдельного пере- перемещаемого сегмента. Это позволяет редактору связей скомпоновать программу оптимальным образом. При использовании абсолютных сег- сегментов памяти программ пришлось бы это делать вручную, а т. к. в про- процессе написания программы размер программных модулей постоянно меняется, то пришлось бы вводить защитные области неиспользуемой памяти между программными модулями. Пример использования перемещаемых сегментов в исходном тексте про- программы содержится в листинге 8.30. В этом примере приведен начальный участок основной программы микроконтроллера, на который произво- производится переход с нулевой ячейки памяти программ. Использование такой структуры программы позволяет в любой момент времени при необхо- необходимости использовать любой из векторов прерывания, доступный в кон- конкретном микроконтроллере, для которого пишется эта программа. До- Достаточно поместить определение этого вектора с использованием дирек- директивы cseg. В приведенном примере использовано имя перемещаемого сегмента _code. Оно было объявлено в самой первой строке исходного текста про- программы. Конкретное имя перемещаемого сегмента может быть любым, но, как уже говорилось ранее, оно должно отображать ту задачу, кото- которую решает данный конкретный модуль.
308 Глава 8 | Листинг 8,30? Пример использования директив segment и Г в программном модуле code segment code ;Старт программы CSEG AT 0 /Вектор рестарта процессора reset: jmp main /Начало основной программы микроконтроллера rseg _code main: MOVX @DPTR,A mov SP,#VershSteka /Настроить указатель стека на вершину стека call init /Настроить микроконтроллер Итак, подведем итоги В данной главе рассмотрены основные средства языка программирова- программирования ASM-51, достаточные для написания довольно сложных программ, однако в процессе работы может потребоваться дополнительная инфор- информация, которую можно получить в описании языка программирования, поставляемом вместе с самой программой-транслятором. Язык программирования ассемблер позволяет разрабатывать самые компактные и эффективные программы, однако процесс создания про- программ на этом языке трудоемкий, а это значит, что он занимает доста- достаточно длительное время. В то же время сейчас предлагаются, причем по приемлемой цене, микросхемы с внутренними ресурсами, достаточны- достаточными для размещения и выполнения программ, написанных на языке высокого уровня. Поэтому в настоящее время программы все чаще соз- создаются на языке С как наиболее распространенном для микроконтрол- микроконтроллеров. В следующей главе мы рассмотрим один из таких языков про- программирования — С-51.
Ш0011 Глава 9 Язык программирования С-51 С — это язык программирования общего назначения, предназначенный для написания программ, эффективных по исполняемому коду, с элемен- элементами структурного программирования и богатым набором операторов. Это позволяет использовать его для эффективного решения широкого круга задач. Однако при написании программ для микроконтроллеров, принадлежащих к семейству MCS-51, необходимо учитывать особенно- особенности построения аппаратуры этих микросхем, поэтому создан диалект этого языка, С-51. В состав языка программирования С-51 введен ряд изменений, отобра- отображающих особенности построения памяти микроконтроллеров семейства MCS-51. Кроме того, эти изменения позволяют непосредственно обра- обращаться к встроенным портам, таймерам и другим устройствам микро- микроконтроллеров указанного семейства. Особенности микроконтроллеров этого семейства в основном отображаются через описания переменных. Язык программирования С-51 удовлетворяет стандарту ANSI-C и пред- предназначен для получения компактных быстродействующих программ для микроконтроллеров семейства MCS-51. Язык С-51 обеспечивает гиб- гибкость программирования на широко известном языке С, при скорости работы и компактности, сравнимой с программами, написанными на ас- ассемблере. Так как язык программирования С не имеет собственных средств ввода и вывода, то он обращается к соответствующим функциям операционных систем. В языке программирования С-51 вместо этого имеется возмож- возможность изменять библиотечные функции, и тем самым обращаться к кон- конкретным ячейкам памяти микроконтроллера, для которого пишется про- программа. Язык программирования С-51 поддерживает модульное написание про- программ, что позволяет в полной мере воспользоваться преимуществами структурно-модульного программирования. В том числе и написание
310 Глава 9 отдельных модулей программы на языке ассемблер. Возможно использо- использование уже готовых модулей, в том числе и написанных на языках про- программирования ASM-51 и PLM-51. Графическое изображение процесса разработки и отладки программы на языке программирования С-51 приведено на рис. 9.1. Необходимо отме- отметить, что в состав языков программирования высокого уровня, предна- предназначенных для написания программ для микроконтроллеров, обязатель- обязательно входит язык программирования ассемблер. Это, как уже говорилось ранее, позволяет писать эффективные программы как с точки зрения скорости работы, так и с точки зрения наглядности программы и скоро- скорости ее написания. Текстовый редактор c51.exe Исходный текст программы 1 Объектные модули asm51.exe т bl51.exe Связанные объектные модули Внутрисхемный эмулятор Программный симулятор Рис. 9.1. Разработка и отладка программы на языке программирования С-51 При разработке программного обеспечения выполняются следующие этапы: ? постановка задачи (полное определение решаемой проблемы);* ? разработка принципиальной схемы и выбор необходимого программ- программного обеспечения; ? разработка системного программного обеспечения. Этот важный шаг состоит из нескольких этапов, включающих: описание последователь- последовательности выполняемых каждым блоком задач, выбор языка программи- программирования и используемых алгоритмов; ? написание текста программы и подготовка к трансляции при помощи любого текстового редактора; ? компиляция программы; ? исправление синтаксических ошибок, выявленных компилятором, в текстовом редакторе с последующей перетрансляцией;
Язык программирования С-51 311 П создание и сохранение библиотек часто используемых объектных мо- модулей при помощи программы Iib51.exe; ? связывание полученных перемещаемых объектных модулей в абсо- абсолютный модуль и размещение переменных в памяти микроконтролле- микроконтроллера при помощи редактора связей bl51.exe; ? создание программы, записываемой в ПЗУ микроконтроллера (загру- (загружаемый модуль) в hex формате, при помощи программы oh.exe; ? проверка полученной программы при помощи символьного отладчи- отладчика или других программных или аппаратных средств. Файл, в котором хранится программа, написанная на языке С-51 (исходный текст программы), называется исходным модулем. Для исход- исходного текста программы, написанной на языке программирования С-51, принято использовать расширение имени файла «*.с». Исходный текст программы можно написать, используя любой текстовый редактор, одна- однако намного удобнее воспользоваться интегрированной средой програм- программирования, подобной Keil-C. Кроме текстового редактора, в интегриро- интегрированную среду программирования обычно входят отладчик программ, менеджер проектов и средства запуска программ-трансляторов. В интегрированной среде программирования процесс трансляции исход- исходного текста программы проходит намного проще. Для получения объ- объектного модуля достаточно нажать на кнопку трансляции файла, как это показано на рис. 9.2. кнопка трансляции Рис. 9.2. Кнопка трансляции исходного текста файла в интегрированной среде программирования Keil-C Готовый оттранслированный участок программы обычно хранится на диске в виде файла, записанного в объектном формате. Такой файл на- называется объектным модулем. Получить объектный модуль можно, ука- указав имя исходного модуля программы в качестве параметра программы- транслятора с51 в командной строке или строке командного файла опе- операционной системы, как это показано в следующем примере: c51.exe modul.c
312 Глава 9 В этом примере в результате трансляции исходного текста программы, содержащегося в файле modul.c, будет получен объектный модуль, ко- который будет записан в файл с именем modul.obj. Как показано на рис. 9.1, объектный модуль не может быть загружен в память программ микроконтроллера. В память микроконтроллера загружается испол- исполняемый модуль. Программа, которая может быть выполнена микроконтроллером, полу- получается после соединения объектных модулей в единый исполняемый мо- модуль. Получить исполняемый модуль программы можно, указав все име- имена объектных модулей программы в качестве параметров программы- редактора связей Ы51 в командной строке операционной системы или строке командного файла, как это показано в следующем примере: Ы 51. exe main. obj , modul 1. obj , modul2 . obj Имя исполняемого модуля программы по умолчанию совпадает с име- именем первого объектного файла в списке параметров командной строки редактора связей. Исполняемый модуль программы хранится на жестком диске компьютера в объектном формате и записывается в файл с именем, но без расширения. При выполнении приведенной выше в качестве при- примера командной строки будет получен исполняемый модуль, который будет записан в файл с именем main. В интегрированной среде программирования процесс получения испол- исполняемого модуля не сложнее предыдущего варианта. Для трансляции все- всего программного проекта достаточно нажать на соответствующую кнопку, как это показано на рис. 9.3. Кнопка трансляции исходного файла и создания загрузочного модуля Рис. 9.3. Кнопка получения исполняемого и загрузочного модулей в интегрированной среде программирования Keil-C Большинство программаторов не может работать с объектным форма- форматом исполняемого модуля программы, поэтому для загрузки машинного кода в микроконтроллер необходимо преобразовать объектный формат исполняемого модуля в общепринятый для программаторов НЕХ- формат. При преобразовании форматов вся отладочная информация, содержащаяся в исполняемом модуле, теряется. Машинный код процес-
Язык программирования С-51 313 сора, записанный в отдельном файле в НЕХ-формате, называется загру- загрузочным модулем. Загрузочный модуль программы можно получить при помощи програм- программы-преобразователя oh.exe, передав ей в качестве параметра имя файла исполняемого модуля программы в командной строке операционной системы или строке командного файла, как это показано в следующем примере: oh.exe main В интегрированной среде программирования загрузочный файл получа- получается автоматически при выполнении трансляции программного проекта, т. к. интегрированная среда программирования сама выполняет перечис- перечисленные выше действия в соответствии с настройками программного про- проекта. После того как программные модули были успешно оттранслированы, размещены по конкретным адресам и связаны между собой, для отладки программы можно воспользоваться любым из методов, показанных на рис. 9.1: внутрисхемным эмулятором; встроенным программным отладчиком; внешним программным отладчиком; отлаживаемым устройством с записанным в память программ двоич- двоичным кодом программы. Внутрисхемный эмулятор с отображением переменных языка програм- программирования на дисплее компьютера оказывает значительную помощь при отладке программ непосредственно на разрабатываемой аппаратуре. Этот метод отладки предоставляет наиболее удобную среду, когда мож- можно непосредственно в отлаживаемом устройстве останавливать про- программу, контролировать ее выполнение непосредственно по исходному тексту, отслеживать состояние внешних портов и внутренних перемен- переменных, как входящих в состав микросхемы, так и объявленных при написа- написании исходного текста программы. Необходимое для отладки программ оборудование показано на рис. 9.4. При отладке программы с использованием внутрисхемного эмулятора необходимо включать в объектные модули символьную информацию. Для этого используются директивы компилятора. (При использовании интегрированной среды программирования достаточно установить со- соответствующую галочку в свойствах проекта.) В компиляторе языка про- программирования С-51 возможны следующие действия: ? включение информации о типе переменных для проверки типов при связывании модулей. Эта же информация используется внутрисхем- 1 Зак. 328
314 Глава 9 ным эмулятором. Исключение информации о переменных пользовате- пользователя может использоваться для создания прототипов или для уменьше- уменьшения размера объектного модуля; Рис. 9.4. Пример системы отладки программного обеспечения для микроконтроллеров ? включение или исключение таблиц символьной информации; ? конфигурация вызовов функций для обеспечения связывания с моду- модулями, написанными на языке программирования ASM-51; ? определение желаемого содержания и формата выходного листинга программы. Распечатка промежуточных кодов на языке ассемблер по- после компилирования программ, написанных на языке программиро- программирования PLM-51. Включение или исключение листингов отдельных бло- блоков исходного текста. Структура программ С-51 Язык программирования С-51 является структурно-модульным языком. Каждая программа, написанная на языке программирования С-51, со- состоит из одного или более модулей. Каждый модуль записывается в от- отдельном файле и компилируется отдельно. В модуле помещаются операторы, составляющие программу. Эти опера- операторы выполняют необходимые действия, а также объявляют константы или переменные. Операторы, выполняющие действия, обязательно должны быть помещены в функции. В главе 7 при описании ассемблера было введено понятие подпрограммы и рассмотрены две разновидности
Язык программирования С-51 315 подпрограмм: процедуры и функции. В С-51 применяется другая терми- терминология. Все подпрограммы, независимо от того, возвращают они зна- значения или нет, называются функциями. Исполнение программы всегда начинается с функции с именем main (т. е. в простейшем случае достаточ- достаточно написать только эту функцию). Функция начинается с заголовка, в который входит тип возвращаемого значения, имя функции и круглые скобки, внутри которых объявляются параметры функции. Параметр — это определяемая функцией перемен- переменная, которая принимает передаваемый функции аргумент. Во всех функ- функциях, которые ничего не возвращают, вместо типа возвращаемого значения указывается ключевое слово void. Исполняемые операторы, составляю- составляющие тело функции, заключаются в фигурные скобки. Все переменные и константы обязательно должны быть объявлены до первого использования. При разработке программы для микроконтроллеров всегда необходимо иметь перед глазами принципиальную схему устройства, для которого пишется программа, т. к. схема и программа тесно связаны между собой и дополняют друг друга. Для иллюстрации простейшей программы, на- написанной на языке программирования С-51, воспользуемся схемой, при- приведенной на рис. 9.5. +5В Ucc Uss U RST Ц«ха Питание Питание Корпус Корпус Кокт. п Ucc Uss U Ublix XTAL2 XTAL1 RESET ЁА Ucci UCC2 Uss CPU +5B Рис. 9.5. Пример простейшей схемы устройства, построенного с использованием микроконтроллера
316 Глава 9 Для примера заставим гореть светодиод VD1. Этот светодиод будет све- светиться только, если через него будет протекать ток. Для этого на шестом выводе порта РО должен присутствовать нулевой потенциал. Для его по- получения служит первая же команда программы, приведенной ниже: #include<reg51. void main(void) {P0=0; //Зажигание светодиода whileA); //Бесконечный цикл Программа начинается с оператора присваивания ро=о. Следующий опе- оператор, while A), обеспечивает зацикливание программы. Это сделано для того, чтобы микроконтроллер не выполнял больше никаких дейст- действий. В противном случае он перейдет к следующей ячейке памяти про- программ и будет выполнять команды, которые мы не записывали. Обратите внимание на то, что язык программирования «знает», где на- находится порт РО. Эту информацию он получает из команды включения файла, содержащейся в операторе #inciude<reg5i.h>. Для того чтобы получить более полное представление о структуре про- программ, написанных на языке программирования С-51, приведем пример исходного текста программы с использованием нескольких функций. #include<reg51. void svGorit(void) {P0=0; //Зажигание светодиода void main(void) {svGoritO; //Вызов функции с именем svGorit whileA); //Бесконечный цикл В приведенном примере использование функции никаких преимуществ не дает, но в более сложных программах использование «говорящих» имен функций и переменных может приблизить исходный текст про- программы к алгоритму и, тем самым, сделать программу более понятной. Это в свою очередь значительно уменьшит время отладки программы.
Язык программирования С-51 317 Элементы языка С-51 В предыдущих главах мы уже выяснили, что программы пишутся как обычные текстовые файлы. При этом программа-транслятор с языка программирования должна однозначно преобразовывать этот текст в машинные коды процессора. Для этого в исходном тексте программы должны быть использованы только определенные символы кодовых таб- таблиц. Недопустимо использование форматирования (выделение жирным, подчеркивание или курсив). Рассмотрим набор символов, допустимых при написании программ на языке С-51. Используемые символы алфавита В исходном тексте программы, написанной на языке программирования С-51, используется часть ASCII- или ANSI-символов. Множество симво- символов, используемых в языке программирования С, можно разделить на пять групп: I. Символы, используемые для образования ключевых слов и идентифи- идентификаторов, приведены в табл. 9.1. В эту группу входят прописные и строчные буквы английского алфавита, а также символ подчеркива- подчеркивания. Следует отметить, что в языке программирования С-51 различа- различаются прописные и строчные буквы. Например, идентификаторы start и start будут считаться различными. Цифры, кроме применения в ключевых словах и идентификаторах, могут быть использованы для записи числовых констант, хотя могут быть использованы и в иден- идентификаторах констант и переменных. Таблица 9.1. Символы, используемые для образования ключевых слов языка С и идентификаторов Прописные буквы латинского алфавита Строчные буквы латинского алфавита Символ подчеркивания Арабские цифры ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz _ 0123456789 2. Группа прописных и строчных букв русского алфавита приведена в табл. 9.2. Эти буквы могут быть использованы в комментариях к ис- исходному тексту программы и строковых константах.
318 Глава 9 Таблица 9.2. Прописные и строчные буквы русского алфавита, используемые в программах на языке С Прописные буквы русского алфавита Строчные буквы русского алфавита АБВГДЕЖЗИКЛМНОПРСТУФХЦЧШЩЫЬЭЮЯ абвгдежзиклмнопрстуфхцчшщъыьэюя 3. Специальные символы (табл. 9.3). Эти символы используются для записи вычисляемых выражений, а также для передачи компилятору определенного набора инструкций. 4. Управляющие и разделительные символы. К этой группе символов от- относятся: пробел, символы табуляции, перевода строки, возврата ка- каретки, новой страницы и новой строки. Символы-разделители отде- отделяют друг от друга лексические единицы языка, к которым относятся ключевые слова, константы, идентификаторы и т. д. Последователь- Последовательность разделительных символов рассматривается компилятором как один символ (последовательность пробелов). Таблица 9.3. Специальные символы языка С-51 Символ 1 ¦ • 1 • ? ' 1 / \ * + - Наименование запятая точка точка с запятой двоеточие вопросительный знак апостроф восклицательный знак вертикальная черта дробная черта обратная черта тильда звездочка плюс минус Символ ) ( } { < > [ ] # % & л = it Наименование круглая скобка правая круглая скобка левая фигурная скобка правая фигурная скобка левая меньше больше квадратная скобка квадратная скобка номер процент амперсанд исключающее ИЛИ равно кавычки
Язык программирования С-51 319 5. Управляющие последовательности, т. е. специальные символьные комбинации, используемые в функциях ввода и вывода информации. Управляющая последовательность начинается с обратной косой чер- черты (\), за которой следует комбинация латинских букв и цифр. Список управляющих последовательностей приведен в табл. 9.4. Таблица 9.4. Управляющие последовательности языка С Управляющая последовательность \а \Ь \t \п \v \г \f \" \' \0 \\ \ООО \xHHH Наименование звонок возврат на шаг горизонтальная табуляция переход на новую строку вертикальная табуляция возврат каретки новая страница кавычки апостроф ноль-символ обратная дробная черта восьмеричный код ASCII- или ANSI-символа шестнадцатеричный код ASCII- или ANSI-символа Шестнадцатеричный код 007 008 009 00А 00В 00D ООС 022 027 000 05С ООО ННН Управляющие последовательности \ооо и \хннн (здесь о обозначает вось- восьмеричную цифру; н обозначает шестнадцатеричную цифру) позволяют представить символ из кодовой таблицы ASCII или ANSI как последова- последовательность восьмеричных или шестнадцатеричных цифр соответственно. Например, символ возврата каретки может быть представлен следую- следующими способами: ? \г — управляющая последовательность; ? \015 — восьмеричный код символа возврата каретки; ? \xOOD — шестнадцатеричный код символа возврата каретки.
320 Глава 9 Следует отметить, что в строковых константах всегда обязательно зада- задавать все три цифры управляющей последовательности. Например, от- отдельную управляющую последовательность \п (переход на новую стро- строку) можно представить как \ою или \ха, но в строковых константах необходимо задавать все три цифры, в противном случае символ или символы, следующие за управляющей последовательностью, будут рас- рассматриваться как ее недостающая часть. Например: "ABCDE\x009FGH" Данная строковая команда будет напечатана с использованием опреде- определенных функций языка С, как два отдельных слова: abcde и fgh, — разде- разделенные табуляцией. Если указать неполную управляющую строку abcde\xO9fgh, то при печати появится строка abcde?gh, т. к. компилятор воспримет последовательность \xO9f как символ ?. Отметим, что если обратная дробная черта предшествует символу, не яв- являющемуся управляющей последовательностью (т. е. не включенному в табл. 9.4) и не являющемуся цифрой, то эта черта игнорируется, а сам символ представляется как литеральный. Например, в строковой или символьной константе символ \h представляется символом h. Кроме определения управляющей последовательности, символ обратной дробной черты (\) используется также как символ продолжения. Если за (\) следует (\п), то оба символа игнорируются, а следующая строка явля- является продолжением предыдущей. Это свойство может быть использовано для записи длинных строк. Например: printf("Это очень длинная \ строка") Если в тексте исходной программы встречается символ, отличающийся от символов, перечисленных выше, то компилятор С-51 выдает сообще- сообщение об ошибке. Лексические единицы, разделители и использование пробелов Наименьшей единицей операторов С-51 является лексическая единица. Каждая из лексических единиц относится к одному из классов: ? идентификаторы; ? ключевые слова; ? простые ограничители (все специальные символы, кроме «_», являют- являются простыми ограничителями);
Язык программирования С-51 321 ? составные ограничители (они образуются посредством определенных комбинаций двух спецсимволов, а именно: !=, +=, -=, *=, «, >>, <=, >=, /*, */,//); ? числовые константы; ? текстовые строковые константы. В большинстве случаев вполне очевидно, где заканчивается одна лекси- лексическая единица и начинается следующая. Например, в выражении Х=АР*(FT-3)/А х, ар, ft, а — являются идентификаторами переменных; 3 — числовой константой; все прочие символы — простыми ограничителями. Ключевые слова, идентификаторы и числовые константы должны обяза- обязательно отделяться друг от друга. Если между двумя идентификаторами, числовыми константами или ключевыми словами не может быть указан простой или составной ограничитель, то в качестве разделителя между ними должен вставляться символ пробела. Для улучшения наглядности программы вместо одного может использоваться несколько символов пробела. Идентификаторы Идентификаторы в языке программирования С-51 используются для определения имени переменной, функции, символической константы или метки оператора. Длина идентификатора может достигать 255 симво- символов, но транслятор различает идентификаторы только по первым 31 сим- символам. Возникает вопрос: а зачем тогда нужен такой длинный идентификатор? Ответ: для создания «говорящего» имени функции или переменной, ко- которое может состоять из нескольких слов. Например: ProchitatPort(); //Прочитать порт Vklychitlndikator(); //Включить индикатор В приведенном примере функция ProchitatPort выполняет действия, не- необходимые для чтения порта, а функция vklychitlndikator выполняет действия, необходимые для зажигания индикатора. Естественно, что на- намного легче понять, какое действие выполняет функция непосредственно из ее имени, чем заглядывать каждый раз в алгоритм программы или ис- искать исходный текст функции, для того чтобы в очередной раз разо- разобраться: что же она делает? Для этого при объявлении имени функции можно потратить количество символов и большее, чем 31!
322 Глава 9 То же самое можно сказать и про имена переменных. Например: sbit ReleVklPitanija = 0x80; //К нулевому выводу порта Р0 подключено реле //включения питания sbit svDiod = 0x81; //К первому выводу порта Р0 подключен //светодиод sbit DatTemperat = 0x82; //Ко второму выводу порта Р0 подключен //датчик температуры В приведенном примере каждому выводу порта микроконтроллера на- назначается переменная с именем, указывающим на устройство, подклю- подключенное к этому выводу. В результате при чтении программы не потребу- потребуется обращаться к принципиальной схеме устройства каждый раз, как только производится операция записи или чтения переменной, связанной с портами микроконтроллера. (Разбираться с принципиальной схемой занятие не менее «увлекательное», чем поиск неизвестной и неизвестно что выполняющей функции.) В качестве идентификатора может быть использована любая последова- последовательность строчных или прописных букв латинского алфавита и цифр, а также символов подчеркивания (_). Идентификатор может начинаться только с буквы или символа «_», но ни в коем случае не с цифры. Это по- позволяет программе-транслятору различать идентификаторы и числовые константы. Строчные и прописные буквы в идентификаторе различают- различаются. Например: идентификаторы abc и две, А128в и а128ь воспринимаются как разные. Идентификатор создается при объявлении переменной, функции, струк- структуры и т. п., после этого его можно использовать в последующих опера- операторах разрабатываемой программы. Следует отметить важные особен- особенности при определении идентификатора: 1. Идентификатор не должен совпадать с ключевыми словами, с зарезер- зарезервированными словами и именами функций из библиотеки компилято- компилятора языка С. 2. Следует обратить особое внимание на использование символа под- подчеркивания (_) в качестве первого символа идентификатора, посколь- поскольку идентификаторы, построенные таким образом, могут совпадать с именами системных функций или переменных, в результате чего они станут недоступными. Следует отметить, что никто не запрещает объявлять идентификатор, совпадающий с именами функций из библиотек компилятора языка С. Однако после объявления такого идентификатора вы не сможете обра- обратиться к функции с таким же именем никаким образом.
Язык программирования С-51 323 Примеры правильных идентификаторов: А XYR_56 OpredKonfigPriem Byte_Prinjat SvdiodGorit Ключевые слова Ключевые слова — это зарезервированные слова, которые используются для построения операторов языка. Список ключевых слов: _at_ char do for long sfr struct void alien code double goto pdata sfrl6 switch volatile auto compact else idata _priority_ short typedef while bdata const enum if reentrant signed _task_ xdata bit continue extern int register sizeof union break data far interrupt return small unsigned case default float large sbit static using Отметим, что ключевые слова не могут быть использованы в качестве идентификаторов. Константы Константы предназначены для введения чисел и символов в состав вы- выражений. В языке программирования С-51 разделяют четыре типа кон- констант: ? целые знаковые и беззнаковые константы; ? константы с плавающей запятой; ? символьные константы; ? литеральные строки. Целочисленные константы могут быть представлены в десятичной, вось- восьмеричной или шестнадцатеричной форме в зависимости от того, какая
324 Глава 9 система счисления удобнее. При выполнении вычислений обычно поль- пользуются десятичными константами, однако при работе с внешними выво- выводами микроконтроллера или передаче двоичных данных удобнее пользо- пользоваться двоичными числами или их более короткой формой записи — восьмеричными или шестнадцатеричными числами. Десятичная константа состоит из одной или нескольких десятичных цифр, причем первая цифра не может быть нулем (иначе число будет воспринято как восьмеричное). Восьмеричная константа состоит из обязательного нуля и одной или не- нескольких восьмеричных цифр (среди цифр должны отсутствовать цифры восемь и девять, т. к. они не входят в восьмеричную систему счисления). Если константа содержит цифру, недопустимую в восьмеричной системе счисления, то константа считается ошибочной. Шестнадцатеричная константа начинается с обязательной последова- последовательности символов Ох или ОХ и содержит одну или несколько шестна- дцатеричных цифр: 0, 1,2, 3, 4, 5, 6, 7, 8, 9, А, В, С, D, E, F. Примеры целых констант: Десятичные константы 16 127 240 Восьмеричные константы 020 0117 0360 Шести адцатеричные константы 0x10 0х2В 0xF0 Если требуется сформировать отрицательную целую константу, то ис- используют знак «-» перед записью константы (который будет называться унарным минусом). Например: -0х2а, -088, -16. Каждой целой константе присваивается тип, определяющий преобразо- преобразования, которые должны быть выполнены, если константа используется в выражениях. Тип константы определяется следующим образом: П десятичные константы рассматриваются как числа со знаком, и им присваивается тип int (целая) или long (длинное целая) в соответствии со значением константы. Если константа меньше 32768, то ей присваи- присваивается ТИП int В ПРОТИВНОМ Случае — long. ? восьмеричным и шестнадцатеричным константам присваивается тип int, unsigned int (беззнаковое Целое), long ИЛИ unsigned long В завиСИ- мости от значения константы согласно табл. 9.5.
Язык программирования С-51 325 Таблица 9.5. Типы шестнадцатеричных и восьмеричных констант, присваиваемые по умолчанию Диапазон шестнадца- шестнадцатеричных констант 0x0-0x7 0x0-0x7FFF 0x8000-0xFFFF 0x10000-0x7FFFFFFF 0x8 0000000-OxFFFFFFFF Диапазон восьмеричных констант 0-07 0-077777 0100000-0177777 0200000-017777777777 020000000000-037777777777 Тип char int unsigned int long unsigned long Иногда требуется с самого начала интерпретировать константу как длинное целое число. Для того чтобы любую целую константу опреде- определить типом long, достаточно в конце константы поставить букву i или l. Пример записи целой константы типа long: 51, 61, 128L, 0105L, 0x2AllL. Примеры синтаксически недопустимых целочисленных констант: 12af — шестнадцатеричная константа не имеет символов Ох в начале константы, поэтому по умолчанию для нее принимается десятичная сис- система счисления, но тогда в ней присутствуют недопустимые символы. В результате эта последовательность символов будет восприниматься как идентификатор. 0x2adg — символ G недопустим при записи шестнадцатеричных чисел. Кроме целых констант в языке программирования С-51 используются числовые константы с плавающей запятой. Константа с плавающей запятой — это десятичное число, представленное в виде действительной величины с десятичной точкой и (или) экспонен- той. Формат записи константы имеет вид: [ Цифры ].[ Цифры ] [ ЛЕ'|'е' [Н'|'-Ч Цифры ] Число с плавающей запятой состоит из целой и дробной частей и (или) экспоненты. Для определения отрицательного числа необходимо сфор- сформировать константное выражение, состоящее из знака минус и положи- положительной константы. В языке программирования С-51, в отличие от стан- стандартного языка С, константы с плавающей запятой представляются с одинарной точностью (имеют тип float). Для определения отрицатель- отрицательного числа необходимо записать константное выражение, состоящее из знака минуса и положительной константы. Например: 115.75, 1.5Е-2, -0.025, .075, -0.85Е2
326 Глава 9 Символьная константа — представляется символом, заключенным в апо- апострофы. Управляющая последовательность рассматривается как одиноч- одиночный символ, поэтому ее допустимо использовать в символьных констан- константах. Значением символьной константы является числовой код символа. Примеры записи символьных констант: 1 • — пробел; •Q1 —буква Q; 1 \п! — символ новой строки; 1 \\' — обратная дробная черта; 1 \vf — вертикальная табуляция. Символьные константы в языке программирования С-51 имеют тип char, поэтому при использовании функций преобразования типов дополняют- дополняются знаком. Символьные константы используются, например, при анализе управляющего кода, введенного с клавиатуры микропроцессорной сис- системы. Пример использования символьной константы на языке програм- программирования С-51 приведен ниже: if (NajKn=='pf) VklUstrO; В этом примере если в переменной NajKn содержится код, соответствую- соответствующий букве fpf, то будет выполнена функция vkiustr. Строковая константа (литерал или литеральная строка) — это последо- последовательность символов, включая строковые и прописные буквы русского и латинского алфавита, а также цифры, знаки пунктуации и разделители, заключенные в кавычки ("). Например: «школа n 35", «город Тамбов", «YZPT КОД". Отметим, что все управляющие символы, кавычка ("), обратная дробная черта (\) и символ новой строки в литеральной строке и в символьной константе представляются соответствующими управляющими последо- последовательностями. Каждая управляющая последовательность представляет- представляется как один символ. Например, при печати литеральной константы «школа \n n 35» ее часть «школа» будет напечатана на одной строке, а вторая часть «n 35» на следующей строке. Символы литеральной строки хранятся в памяти программ, но могут храниться и в памяти данных. В конец каждой литеральной строки ком- компилятором добавляется нулевой символ, который можно записать как: «\ои. Именно этот символ и является признаком конца строки. Литеральная строка рассматривается как массив символов (char []). От- Отметим важную особенность: число элементов массива равно числу сим- символов в строке плюс 1, т. к. нулевой символ (символ конца строки) также является элементом массива. Все литеральные строки рассматриваются
Язык программирования С-51 327 компилятором как различные объекты. Одна литеральная строка может выводиться на дисплей как несколько строк. Такие строки разделяются при помощи обратной дробной черты и символа новой строки \п. На одной строке исходного текста программы можно записать только одну литеральную строку. Если необходимо продолжить написание одной и той же литеральной строки на следующей строке исходного текста, то в конце строки исходного текста можно поставить обратную строку. На- Например, исходный текст: "строка неопределенной \ длины" полностью идентичен литеральной строке: "строка неопределенной длины". Однако более удобно для объединения литеральных строк использовать символ (символы) пробела. Если в программе встречаются два или более литерала, разделенные только пробелами или символами табуляции, то они будут рассматриваться как одна литеральная строка. Этот принцип можно использовать для формирования литералов, занимающих более одной строки. Использование комментариев в тексте программы Комментарий — это набор символов, которые игнорируются компиля- компилятором языка программирования. Примеры использования комментариев при написании программы подробно рассматривались в предыдущих главах, поэтому здесь сделаем основной упор на синтаксические правила записи комментариев на языке программирования С-51. В языке программирования С-51, в отличие от ASM-51, возможно ис- использование двух типов комментариев: 1. Комментарий, который может быть использован внутри строки. 2. Комментарий, который игнорирует символы до конца строки. Первый вид комментария начинается парой символов (/*) и завершается парой символов (*/). Данная особенность позволяет использовать этот вид комментария внутри операторов языка программирования. Кроме того, комментарий может занимать несколько строк. Например: /* комментарий к программе */ /* начало алгоритма */
328 Глава 9 или /*комментарий можно записать в следующем виде, однако надо быть осторож- осторожным, чтобы внутри строк, которые игнорируются компилятором, не попались операторы программы, которые также будут игнорироваться */ В тексте комментария не может быть символов, определяющих начало и конец комментариев (/* и */), т. е. применение вложенных комментариев запрещено. Пример недопустимого определения комментариев: /* комментарии к алгоритму /* решение краевой задачи */ */ ИЛИ /* комментарии к алгоритму решения */ краевой задачи */ Второй вид комментария начинается парой символов (//) и завершается концом строки. Этот вид комментария похож на комментарий языка программирования ассемблер, но иногда его использование более вы- выгодно по сравнению с предыдущим вариантом. Например: PrmDem(); //Получить, отфильтровать и демодулировать сигнал Особенно оправдано использование этого вида комментария при отлад- отладке программы, когда нужно временно исключать операторы из исходно- исходного текста программы. Пример использования этого вида комментария для временного отключения операторов программы: //PrmDemO; //Получить, отфильтровать и демодулировать сигнал Типы данных языка программирования С-51 и их объявление Описание переменных в языке программирования С имеет огромнейшее значение, т. к. именно оно в большинстве случаев определяет объем про- программы. Обычно большой объем загрузочного модуля программы вы- вызван неправильным объявлением переменных в исходном тексте про- программы. Обращение к внутренним регистрам микроконтроллеров и внешним ресурсам разрабатываемого устройства тоже производится при помощи заранее объявленных переменных. В языке программирования С-51 любая переменная должна быть объяв- объявлена до первого использования этой переменной в программе. Как уже говорилось ранее, этот язык программирования предназначен для напи- написания программ для микроконтроллеров семейства MCS-51, поэтому в составе языка должна отображаться внутренняя структура этого семей- семейства микроконтроллеров. Особенности микроконтроллеров отражены во
Язык программирования С-51 329 введении в состав языка программирования новых типов данных. В ос- остальном язык программирования С-51 не отличается от стандартного ANSI С.¦ Начиная с этого момента для описания синтаксических правил языка программирования С-51 применяются синтаксические диаграммы. Пояс- Поясним основные понятия и обозначения, которые в них используются. Синтаксические диаграммы являются формальным и одновременно на- наглядным представлением правил, составленных из терминальных и не- нетерминальных имен. Для того чтобы сделать описание синтаксиса более компактным, часть определений нетерминальных имен будет приводить- приводиться в словесной форме. Терминальными называются имена, входящие в текст программы так, как они написаны. Например, терминальными именами являются сим- символьные или строковые константы. В синтаксических правилах такие терминальные имена заключаются в апострофы и кавычки соответст- соответственно. Нетерминальные имена — это понятия, которые выводятся при помощи синтаксических правил с использованием других нетерминальных и тер- терминальных имен, а также символов. Нетерминальные имена будем начи- начинать с заглавной буквы и использовать для их написания курсивный Шрифт Courier, например, Спецификатор класса памяти. Элементы синтаксических правил, заключенные в квадратные скобки ([ ]), являются необязательными. Итак, вооружившись этим набором несложных понятий и договоренно- договоренностей, приступим к описанию синтаксиса языка программирования С-51. Объявление переменной в этом языке представляется в следующем виде: [Спецификатор класса памяти] Спецификатор типа [Спецификатор типа памяти] Описатель [ х=' Инициатор] [, Описатель [х=' Инициатор] ]... описатель — идентификатор простой переменной либо более сложная конструкция с квадратными скобками, круглыми скобками или звездоч- звездочкой (набором звездочек). спецификатор типа — одно или несколько ключевых слов, определяющих тип объявляемой переменной. В языке С-51 имеется стандартный набор типов данных, используя который, можно сконструировать новые (уникальные) типы данных. Перечень стандартных типов данных С-51 приведен в табл. 9.6. Последующие 5 абзацев написаны редактором книги В. Б. Харитоновым.
330 Глава 9 инициатор — задает начальное значение или список начальных значений, которое (которые) присваивается переменной при объявлении. Спецификатор класса памяти — определяется ОДНИМ ИЗ Ключевых СЛОВ ЯЗЫКа С-51: auto, bit, extern, register, sbit, sfr, sfrl6 static, И ука- зывает, каким образом и в какой области памяти микроконтроллера бу- будет распределяться память под объявляемую переменную, с одной сторо- стороны, а с другой — область видимости этой переменной, т. е. из каких программных модулей можно будет к ней обратиться. Спецификатор типа памяти — определяется одним из шести ключевых СЛОВ ЯЗЫКа С-51: code, data, idata, bdata, xdata, pdata, И указывает, В ка- кой области памяти микроконтроллера будет размещена переменная. Таблица 9.6. Стандартные типы данных языка программирования С-51 Типы данных bit signed char unsigned char enum signed short unsigned short signed int unsigned int signed long unsigned long float sbit sfr sfrl6 Размер битов 1 8 8 8/16 16 16 16 16 32 32 32 1 8 16 байтов 1 1 1 или 2 2 2 2 2 4 4 4 0 1 2 Область значений от 0 до 1 от-128 до+127 от 0 до 255 от -32768 до +32767 от -32768 до +32767 от 0 до 65535 от -32768 до +32767 от 0 до 65535 от-2147483648 до 2147483647 от 0 до 4294967295 от ±1.175494Е-38 до ±3.402823Е+38 от 0 до 1 от 0 до 255 от 0 до 65535 Компилятор С51 обеспечивает следующие расширения ANSI-стандарта языка программирования С, необходимые для программирования мик- микроконтроллеров семейства MCS-51: ? области памяти; ? типы памяти;
Язык программирования С-51 331 ? модели памяти; ? описатели типа памяти; ? описатели изменяемых типов данных; ? битовые переменные и данные с битовой адресацией; ? регистры специальных функций; ? указатели; ? атрибуты функций. Типы данных bit, sbit, sfr и sfri6 являются расширением языка про- программирования С-51 для поддержки процессора 8051. Они не описаны стандартом ANSI, поэтому к ним нельзя обращаться при помощи пе- переменных-указателей. Категории типов данных Основные типы данных определяют с использованием следующих клю- ключевых слов. ДЛЯ Целых ТИПОВ данных: bit, sbit, char, int, short, long, signed, unsigned, sfr, sfrl6. Для типов данных с плавающей запятой: float. Переменная любого типа может быть объявлена как неизменяемая. Это достигается добавлением ключевого слова const к спецификатору типа. Объекты с квалификатором const представляют собой данные, исполь- используемые только для чтения, т. е. этой переменной в ходе выполнения про- программы не может быть присвоено новое значение. Отметим, что если по- после слова const отсутствует спецификатор типа, то подразумевается спецификатор типа int. Если ключевое слово const стоит перед объявле- объявлением составных типов (массив, структура, объединение, перечисление), то это приводит к тому, что каждый элемент также будет немодифици- руемым, т. е. значение ему может быть присвоено только один раз. Примеры использования ключевого слова const: const float A=2.128E-2; const В=28б; //подразумевается const int В=28б Отметим, что переменные со спецификатором класса памяти размещают- размещаются во внутреннем ОЗУ. Неизменяемость контролируется только на этапе трансляции. Для размещения переменной в ПЗУ лучше воспользоваться спецификатором типа памяти code.
332 Глава 9 Целочисленный тип данных Для определения данных целочисленного типа используются различные ключевые слова, которые определяют диапазон значений и размер об- области памяти, выделяемой под переменные (табл. 9.7). Отметим, что ключевые слова signed и unsigned необязательны. Они ука- указывают, как интерпретируется старший бит объявляемой переменной, т. е. если указано ключевое слово unsigned, то нулевой бит интерпретиру- интерпретируется как часть числа, в противном случае нулевой бит интерпретируется как знаковый. Таблица 9.7. Спецификаторы целочисленных типов данных Тип bit char unsigned char int, short unsigned int, unsigned short long unsigned long sbit sfr sfrl6 Размер памяти в битах 1 8 8 16 16 32 32 1 8 16 Размер памяти в байтах 1 1 2 2 4 4 1 2 Диапазон значений от 0 до 1 от-128 до 127 от 0 до 255 от -32768 до 32767 от 0 до 65 535 от-2147483648 до 2147483647 от 0 до 4294967295 0 или 1 от 0 до 255 от 0 до 65535 При отсутствии ключевого слова unsigned целочисленная переменная считается знаковой. В том случае, если спецификатор типа состоит из ключевого типа signed или unsigned и далее следует идентификатор пе- переменной, то она будет рассматриваться как переменная типа int. На- Например: unsigned int n; //Беззнаковое шестнадцатиразрядное число п unsigned int b; int с; /^подразумевается signed int с */ unsigned d; ^подразумевается unsigned int d */ signed f; /^подразумевается signed int f */
Язык программирования С-51 333 Отметим, что модификатор типа char используется для представления одиночного символа или для объявления литеральных строк. Численное значение объекта типа char соответствует ANSI-коду записанного сим- символа (размером I байт). Отметим также, что восьмеричные и шестнадцатеричные константы также могут иметь модификатор unsigned. Это достигается указанием префикса и или и после константы, константа без этого префикса счита- считается знаковой. Например: 0хА8С //int signed; 017861 //long signed; 0xF7u //int unsigned; Числа с плавающей запятой Для переменных, представляющих число с плавающей запятой? исполь- используется модификатор типа float. Спецификатор double тоже допустим в языке программирования С-51, но он не приводит к увеличению точно- точности результата. Величина со спецификатором типа float занимает 4 байта. Из них 1 бит отводится для знака, 8 битов для избыточной экспоненты и 23 бита для мантиссы. Отметим, что старший бит мантиссы всегда равен 1, поэтому он явным образом в битовом представлении числа не указывается, в свя- связи с этим диапазон значений переменной с плавающей точкой равен от ±1.175494Е-38 до ±3.402823Е+38. Пример объявления переменной: float f, a, b; Переменные перечислимого типа Переменная, которая может принимать значение из некоторого списка значений, называется переменной перечислимого типа или перечислени- перечислением (enum). Использование такого вида переменной эквивалентно приме- применению целочисленного знакового значения типа char или int. Это озна- означает, что для переменной перечислимого типа будет выделен один или два байта в зависимости от максимального значения используемых этой переменной констант. В отличие от переменных целого типа, переменные перечислимого типа позволяют вместо безликих чисел использовать имена констант, которые более понятны и легче запоминаются.
334 Глава 9 Например, вместо использования чисел 1, 2, 3, 4, 5, 6, 7 можно использо- использовать Названия Дней Недели: Poned, Vtorn, Sreda, Chetv, Pjatn, Subb, Voskr. При этом каждой константе будет соответствовать конкретное число. Использование имен констант приведет к более понятной программе. Более того, транслятор отслеживает правильность использования кон- констант и при попытке использования константы, не входящей в объявлен- объявленный заранее список, выдает сообщение об ошибке. Переменные enum-типа могут использоваться в индексных выражениях и как операнды в арифметических операциях и в операциях отношения. Например: If(rab_ned == SUB) dejstvie = rabota [rab_ned]; При объявлении перечисления определяется тип переменной перечисле- перечисления и определяется список именованных констант, называемый списком перечисления. Значением каждого имени этого списка является целое число. Объявление перечислимой переменной начинается с ключевого слова enum и может быть представлено в двух формах: "enum" [Имя типа перечисления] МЛ Список констант'}' Имя1 [Л,' Имя2 ...] ; "enum" Имя типа перечисления Описатель [\' Описатель..]; В первом формате имена и значения констант задаются в списке кон- констант. Необязательное имя типа перечисления — это идентификатор, который представляет собой тип переменной, соответствующий списку констант. За списком констант записывается имя одной или нескольких переменных. Список констант содержит одну или несколько конструкций вида: Идентификатор [*=' Константное выражение] Каждый идентификатор — это имя константы. Все идентификаторы в списке констант оператора enum должны быть уникальными. Если кон- константе явным образом не присваивается константное выражение (чаще всего это число), то первому идентификатору присваивается значение О, следующему — значение 1 и т. д. Пример объявления переменной rab_ned и типа week для переменных, совместимых с переменной rab_ned, выглядит следующим образом: enum week {SUB =0, /* константе SUB присвоено значение 0 */ VOS =0, /* константе VOS присвоено значение 0 */ POND, /* константе POND присвоено значение 1 */ VTOR, /* константе VTOR присвоено значение 2 */ SRED, /* константе SRED присвоено значение 3 */
Язык программирования С-51 335 HETV, /* константе HETV присвоено значение 4 */ PJAT /* константе PJAT присвоено значение 5 */ } rab_ned; Идентификатор, СВЯЗаННЫЙ С Константным выражением, принимает значение, задаваемое ЭТИМ Константным выражением. Результат вычисления Кон- Константного выражения должен иметь тип int и может быть как положи- положительным, так и отрицательным. Следующему идентификатору в списке, если ЭТОТ Идентификатор не имеет Своего Константного выражения, при- сваивается значение, равное константному выражению предыдущего идентификатора плюс 1. Использование констант должно подчиняться следующим правилам: ? объявляемая переменная может содержать повторяющиеся значения констант; ? идентификаторы в списке констант должны быть отличны от всех других идентификаторов в той же области видимости, включая имена обычных переменных и идентификаторы из других списков констант; ? Имена типов перечислений должны быть отличны от других имен типов перечислений, структур и объединений в этой же области видимости; ? значение может следовать за последним элементом списка констант перечисления. Во втором формате для объявления переменной перечислимого типа ис- используется готовый тип переменной, уже объявленный ранее. Например: enum week rabl; К переменной перечислимого типа можно обращаться при помощи ука- указателей. При этом необходимо заранее определить тип переменной, на которую будет ссылаться указатель. Это может быть сделано, как описы- описывалось выше или при помощи оператора typedef. Например: typedef enum {SUB = 0, /* константе SUB присвоено значение 0 */ VOS =0, /* константе VOS присвоено значение 0 */ POND, /* константе POND присвоено значение 1 */ VTOR, /* константе VTOR присвоено значение 2 */ SRED, /* константе SRED присвоено значение 3 */ HETV, /* константе HETV присвоено значение 4 */ PJAT /* константе PJAT присвоено значение 5 */ } week; Этот оператор не объявляет переменную, а только определяет тип перемен- переменной, отличающийся от стандартного. В дальнейшем этот тип может быть использован для объявления переменных и указателей на переменные.
336 Глава 9 Указатели Указатель — это переменная, которая может содержать адрес другой пе- переменной. Указатель может быть использован для работы с переменной, адрес которой он содержит. Для инициализации указателя (записи в него начального адреса) можно использовать идентификатор переменной, при этом в качестве идентификатора может выступать имя переменной, массива, структуры, литеральной строки. При объявлении переменной-указателя необходимо определить тип объ- объекта данных, адрес которых будет содержать эта переменная, и иденти- идентификатор указателя с предшествующей звездочкой (или группой звездо- звездочек). Формат объявления указателя: Спецификатор типа [Модификатор] Л*' Описатель. Спецификатор типа задает тип объекта и может быть любого основного типа, структуры или объединения (об этих типах данных будет сказано ниже). Примеры объявления указателей: unsigned int * а; /^переменная а представляет собой указатель на целочисленную беззнаковую переменную */ float * х; /^переменная х может указывать на переменную с плавающей точкой */ char * fuffer ; /^объявляется указатель с именем fuffer, который может указывать на символьную переменную */ float *nomer; Задавая вместо спецификатора типа ключевое слово void, можно отсро- отсрочить определение типа, на который ссылается указатель. Переменная, объявляемая как указатель на тип void, может быть использована для ссылки на объект любого типа. Однако для того, чтобы можно было вы- выполнить арифметические и логические операции над указателями или над объектами, на которые они указывают, необходимо при выполнении каждой операции явно определить тип объектов. Такие определения ти- типов могут быть выполнены с помощью операции приведения типов. void *addres; /^Переменная addres объявлена как указатель на объект любого типа. Поэтому ей можно присвоить адрес любого объекта */ addres = &nomer; /*(& — операция вычисления адреса). */ (float *)address ++;/* Однако, как было отмечено выше, ни одна арифметическая операция не может быть выполнена над указателем, пока не будет явно определен тип данных, на которые он указывает.
Язык программирования С-51 337 В данном примере используется операция приведения типа (float *) для преобразования типа указателя address к типу float. Затем оператор ++ отдает приказ перейти к следующему адресу переменной с таким же типом. */ В качестве модификаторов при объявлении указателя могут выступать ключевые СЛОВа const, data, idata, xdata, code. Ключевое СЛОВО const ука- зывает, что указатель не может быть изменен в программе. Вследствие уникальности архитектуры контроллера 8051 и его произ- производных компилятор С-51 поддерживает 2 вида указателей: специализи- специализированные (memory-specific pointers) и общего вида (generic pointers). Указатели общего вида Указатели общего вида объявляются точно так же, как указатели в стан- стандартном языке программирования С. Для того чтобы не зависеть от типа памяти, в которой может быть размещена переменная, для указателей общего вида выделяется 3 байта. В первом байте указывается вид памяти переменной, во втором байте — старший байт адреса, в третьем — младший байт адреса переменной. Указатели общего вида могут быть использованы для обращения к любым переменным независимо от типа памяти микроконтроллера. Многие библиотечные функции языка про- программирования С-51 используют указатели этого типа, поскольку в этом случае совершенно неважно, в какой именно области памяти размеща- размещаются переменные. Приведем листинг 9.1, в котором отображаются осо- особенности трансляции указателей общего вида. §|щимер использование указателей различного вида от ' . ¦ . ¦ ¦ ¦ stmt level source 1 char *c_ptr; /* char ptr */ 2 int *i_ptr; /* int ptr */ 3 long *l_ptr; /* long ptr */ 4 5 void main (void) 6 { 7 1 char data dj; /*переменные во внутренней памяти данных data */ 8 1 int data dk; 9 1 long data dl; 10 1
338 Глава 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 char xdata xj; /*переменные во внешней памяти данных xdata */ 1 int xdata хк; 1 long xdata xl; 1 1 char code cj = 9; /*переменные в памяти программ code */ 1 int code ck = 357; 1 long code cl = 123456789; 1 1 /*настроим указатели на внутреннюю память данных data */ 1 c_ptr = &dj; 1 i_ptr = &dk; 1 l_ptr = &dl; 1 /^настроим указатели на внешнюю память данных xdata */ 1 c_ptr = &xj; 1 i_ptr = &xk; 1 l_ptr = &xl; 1 /^настроим указатели на память программ code */ 1 c_ptr = &сj; = &cl; 1 } ASSEMBLY LISTING OF ; FUNCTION main 0000 750000 R MOV 0003 750000 R MOV 0006 750000 R MOV 0009 750000 R MOV 000C 750000 R MOV 000F 750000 R MOV 0012 750000 R MOV 0015 750000 R MOV OBJECT CODE (BEGIN) ; SOURCE LINE # 5 ; SOURCE LINE # б ; SOURCE LINE #20 c_ptr,#00H c_ptr+01H,#HIGH dj c_ptr+02H,#LOW dj ; SOURCE LINE #21 i_ptr,#00H i_ptr+01H,#HIGH dk i_ptr+02H,#LOW dk ; SOURCE LINE #22 l_ptr,#00H l_ptr+01Hf#HIGH dl
Язык программирования С-51 339 0018 750000 R MOV 001В 750001 R MOV 001Е 750000 R MOV 0021 750000 R MOV 0024 750001 R MOV 0027 750000 R MOV 002А 750000 R MOV 002D 750001 R MOV 0030 750000 R MOV 0033 750000 R MOV 0036 7500FF R MOV 0039 750000 R MOV 003С 750000 R MOV 003F 7500FF R MOV 0042 750000 R MOV 0045 750000 R MOV 0048 7500FF R MOV 004В 750000 R MOV 004Е 750000 R MOV l_ptr+02H,#LOW dl ; SOURCE LINE #24 c_ptr,#01H c_ptr+01H,#HIGH xj c_ptr+02H,#LOW xj ; SOURCE LINE #25 i_ptr,#01H i_ptr+01H,#HIGH xk i_ptr+02H,#LOW xk ; SOURCE LINE #26 l_ptr,#01H l_ptr+01H,#HIGH xl l_ptr+02H,#LOW xl ; SOURCE LINE #28 c_ptr,#0FFH c_ptr+01H,#HIGH cj c_ptr+02H,#LOW cj ; SOURCE LINE #29 i_ptr,#0FFH i_ptr+01H,#HIGH ck i_ptr+02H,#LOW ck ; SOURCE LINE #30 l_ptr,#0FFH l_ptr+01H,#HIGH cl l_ptr+02H,#LOW cl ; SOURCE LINE #31 0051 22 RET ; FUNCTION main (END) Специализированные указатели В объявления специализированных указателей всегда включается моди- модификатор памяти. Обращение всегда происходит к указанной области па- памяти, например: char data *str; /^указатель на строку во внутренней памяти данных data */ int xdata *numtab; /^указатель на целое во внешней памяти данных xdata */ long code *powtab; /^указатель на длинное целое в памяти программ code */
340 Глава 9 Поскольку модель памяти определяется во время компиляции, специали- специализированным указателям не нужен байт, в котором указывается тип памя- памяти микроконтроллера. Поэтому программа с использованием типизиро- типизированных указателей короче и будет выполняться быстрее по сравнению с программой, использующей указатели общего вида. Специализирован- Специализированные указатели могут иметь размер в 1 байт (указатели на память idata, data, bdata И pdata) ИЛИ В 2 байта (указатели на память code И xdata). Массивы При обработке данных достаточно часто приходится работать с рядом переменных одинакового типа (и описывающих одинаковые объекты). В этом случае эти переменные имеет смысл объединить одним идентифи- идентификатором. Это позволяют сделать массивы. Массивы — это группа элементов одинакового типа (char, float, int и т. п.). Из объявления массива компилятор должен получить информацию о ти- типе элементов массива и их количестве. Объявление массива имеет два формата: Спецификатор типа Имя [Константное выражение] ; Спецификатор типа' Имя [ ]; имя — это идентификатор массива. спецификатор типа задает тип элементов объявляемого массива. Элемен- Элементами массива не могут быть функции и элементы типа void. константное выражение в квадратных скобках задает количество элемен- элементов массива — размерность массива. При объявлении массива размер- размерность может быть опущена в следующих случаях: ? массив инициализируется при объявлении; ? массив объявлен как формальный параметр функции; ? массив объявлен как внешняя переменная, явно определенная в дру- другом файле. В языке С-51 определены только одномерные массивы, но поскольку элементом массива в свою очередь тоже может быть массив, то таким образом можно определить и многомерные массивы. Они формализуют- формализуются списком размерностей массива, следующих за идентификатором мас- массива, причем каждое константное выражение размерности массива за- заключается в свои квадратные скобки. Каждое константное выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмер- двухмерного массива содержит две размерности, трехмерного — три и т. д.
Язык программирования С-51 341 К каждому конкретному элементу массива можно обратиться при помо- помощи его индекса (порядкового номера). Отметим, что в языке С первый элемент массива всегда имеет индекс, равный 0. Например: А[0]=78; //Записать число 78 в первый элемент массива А int а[2] [3]; /* Определить двумерный массив, представленный в виде матрицы а[0][0] а[0][1] а[0][2] а[1] [0] а[1] [1] а[1][2] */ float b[10]; /* Определить массив из 10 элементов типа float */ int w[3] [3] = { { 2, 3, 4 }, { 3, 4, 8 }, { 1, 0, 9 } }; В последнем примере определен и инициализирован двумерный массив w[3] [3], состоящий из трех трехэлементных строк. Списки, выделенные в фигурные скобки, соответствуют строкам массива и используются для инициализации (присваивания начальных значений) элементов массива. В случае отсутствия скобок инициализация будет выполнена неправильно. В языке программирования С-51 можно использовать сечения массива, как и в других языках высокого уровня. Сечение массива — это массив меньшей размерности. Однако на использование сечений накладывается ряд ограничений. Сечения формируются вследствие опускания одной или нескольких пар квадратных скобок. Пары квадратных скобок можно отбрасывать только справа налево и строго последовательно. Сечения массивов используются при организации вычислительного процесса в подпрограммах-функциях, разрабатываемых пользователем. Примеры: int s[2][3]; Если при обращении к некоторой функции написать s [0], то будет пере- передаваться нулевая строка массива s. int b[2][3][4]; При обращении к массиву ь можно написать, например, ь[1] [2], и будет передаваться вектор из четырех элементов, а обращение b[i] даст двух- двухмерный массив размером 3 на 4. Нельзя написать Ь[2] [4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограни- ограничению, наложенному на использование сечений массива. Для работы с литеральными строками в языке программирования С ис- используются массивы символов, например: char str[] = «объявление символьного массива";
342 Глава 9 Следует учитывать, что размер символьного массива всегда на один эле- элемент больше числа символов в строке, т. к. последний из элементов мас- массива является управляющей последовательностью ' \о?, являющейся при- признаком конца строки. В примере использовано неявное задание длины массива символов. Это стало возможным, т. к. массиву сразу присваива- присваивается конкретное значение. При программировании микроконтроллеров семейства MCS-51 такое задание массива может привести к неоправдан- неоправданному расходу внутренней памяти данных, поэтому лучше воспользовать- воспользоваться размещением строки в памяти программ: char code str[] = «объявление массива символов"; Структуры Работа с массивами облегчает понимание и написание программы, когда для обозначения похожих элементов используется один идентификатор. Однако в ряде случаев приходится обрабатывать разнородные элементы, описывающие один объект. В этом случае вместо массива используется структура. Структура — это составной объект, в который входят элементы — назы- называемые членами или полями — любых типов, за исключением функций, а также типа void или неполного типа. В отличие от массива, который яв- является однородным объектом, структура может быть неоднородной. В простейшем случае тип структуры определяется записью вида: "struct" [Идентификатор] МЛ Список описаний Л}' В структуре обязательно должно быть указано хотя бы одно поле. Опре- Определение Описание полей структур имеет следующий ВИД! Тип данных Описатель'; ' где тип данных указывает тип поля структуры для объектов, определяе- определяемых в описателях. В простейшей форме описатели представляют собой идентификаторы переменных или массивы. Пример объявления структур: struct//Описание типа структуры {char tzvet;//UBeT точки int x, //Координата X int у; //Координата Y }// tochkal, tochka2, //Переменные, обозначающие точки дисплея simv[7][9]; //Переменная, содержащая рисунок символа
Язык программирования С-51 343 struct {int year; //Поле структуры, в котором хранится год char moth, //Поле структуры, в котором хранится месяц day; //Поле структуры, в котором хранится день datel, date2;//Переменные, обозначающие две различных даты. struct { double x,y; } si, s2, sm[9]; struct { int year; char moth, day; } datel, date2; Переменные tochkal, tochka2 объявляются как структуры, каждая из ко- которых состоит из трех полей: tzvet, x и у. Переменная simv объявляется как двумерный массив, состоящий из 63 элементов, описывающих рису- рисунок символа. Во втором объявлении каждая из двух переменных — datel, date2 — СОСТОИТ ИЗ трех ПОЛеЙ: year, moth, day. Существует и другой способ объявления переменной структурного типа. Этот способ основан на использовании заранее объявленного типа структуры. Объявление структурного типа аналогично объявлению пе- перечислимого типа. Структурный тип объявляется следующим образом: "struct" Тип Мл Список описаний *}'; где тип—это идентификатор. В приведенном ниже примере идентификатор student объявляется как тип структуры, список описаний полей которой приводится далее в фи- фигурных скобках: struct student {char name[25];//Имя и фамилия студента int id; //Номер в журнале int age; //Возраст char usp; //успеваемость }; Тип структуры используется для последующего объявления структур данного вида в форме: struct Тип Список идентификаторов';' Пример: struct student st[23];
344 Глава 9 Поле структуры может быть указателем на структуру того же самого типа, в которой оно объявлено. Ниже рассматривается пример такой ссылки. struct node { int data; struct node * next; } stl_node; Доступ к отдельным полям структуры осуществляется с помощью указа- указания имени структуры и следующего через точку имени поля, например: st2.id=5; //Присвоить значение полю id структуры st2 stl.name="Иванов"; //Присвоить значение полю name структуры stl stl_node.data=1985; // Присвоить значение полю data структуры stl st[1].name="Иванов";//Занести студента Иванова в журнал st[l].id=2; //поместить его в журнал под вторым номером st[I].age=23; //Занести в журнал его возраст Битовые поля Элементом структуры может быть битовое поле, обеспечивающее доступ к отдельным битам памяти. Вне структур битовые поля объявлять нель- нельзя. Нельзя также организовывать массивы битовых полей и нельзя при- применять к полям операцию определения адреса. В общем случае тип структуры с битовым полем задается в следующем виде: "struct" 4х «unsigned» Идентификатор! у:' Длина поля1';' "unsigned" Мдентификатор2 х:' Длина поля2';' Ч' длина поля задается целым выражением или константой. Эта константа определяет число битов, отведенное соответствующему полю. Поле ну- нулевой длины обозначает выравнивание на границу следующего слова. Пример: struct { unsigned al : 1; unsigned a2 : 2; unsigned a3 : 5; unsigned a4 : 2; } prim; Структуры битовых полей могут содержать и знаковые компоненты. Та- Такие компоненты автоматически размещаются на соответствующих гра- границах слов, при этом некоторые биты слов могут оставаться неиспользо- неиспользованными. Доступ к элементам полей битов выполняется точно так же, как и к ком- компонентам обычных структур. Само же битовое поле рассматривается как целое число, максимальное значение которого определяется длиной по- поля. Например: Cntr.Cmd=30;
Язык программирования С-51 345 Объединения (смеси) Иногда один и тот же элемент данных удобно обрабатывать по-разному, в зависимости от ситуации. Например, кодовое слово помехоустойчиво- помехоустойчивого кода можно передавать целиком и можно осуществлять запись ин- информационных и проверочных битов различными процедурами. Еще один пример. Четыре соседних байта можно интерпретировать в один момент времени (для обработки) как число с плавающей запятой, и эти же четыре байта в другой момент времени интерпретировать (для пере- передачи или приема) как четырехэлементный массив байтов. Объявление объединения подобно структуре, однако в каждый момент времени может использоваться только один из элементов объединения. Тип объединения объявляется в следующем виде: "union" л{л Описание элемента 1';' • • ¦ Описание элементап' ;' х}' ; Для каждого из элементов объединения выделяется одна и та же область памяти, т. е. все элементы перекрываются. Хотя доступ к этой области памяти возможен с использованием любого из элементов, элемент для этой цели должен выбираться так, чтобы полученный результат не был бессмысленным. Доступ к элементам объединения осуществляется тем же способом, что и к полям структур. Тип объединения может быть объявлен точно так же, как и тип структуры. Объединение применяется для следующих целей: ? инициализации используемого объекта памяти, если в каждый момент времени только один объект из многих является активным; ? интерпретации основного представления объекта одного типа, как если бы этому объекту был присвоен другой тип. Размер области памяти, выделяемой для переменной типа объединения, определяется наиболее длинным элементом объединения. Когда исполь- используется элемент меньшей длины, то переменная типа объединения может содержать неиспользуемую память. Все элементы объединения хранятся в одной и той же области памяти, начиная с одного и того же адреса. Например, требуется передать число плавающего типа. Однако последо- последовательный порт может передавать или принимать только байты. В этом случае можно воспользоваться объединением: union {float Koeff; //Интерпретация объединения как переменной //плавающего типа 12 Зак 328
346 . Глава 9 char byte[4];//Интерпретация объединения как массива } bufer; //Объявление переменной bufer Объединение bufer позволяет последовательному порту получить доступ к отдельным байтам числа bufer.Koeff, начиная от младшего байта bufer.byte[O] и заканчивая старшим байтом bufer.byte[3]. В программе затем можно пользоваться загруженным числом как числом с плавающей запятой. Определение типов Кроме определения переменных различных типов, имеется возможность заранее объявить тип переменной, а затем воспользоваться им при опре- определении переменных. Использование при определении переменной зара- заранее объявленного типа позволяет сократить определение, избежать оши- ошибок при определении переменных в разных местах программы и добиться полной идентичности определяемых переменных. Это можно сделать двумя способами. Первый способ — указать имя типа при объявлении структуры, объединения или перечисления, а затем ис- использовать это имя в объявлении переменных и функций. Второй — ис- использовать для объявления типа ключевое слово typedef. Следует отме- отметить, что этот способ предпочтителен, т. к. использование его приводит к более наглядным и понятным программам. При объявлении с ключевым словом typedef идентификатор, стоящий на месте описываемого объекта, является именем вводимого в рассмотрение типа данных, и далее этот тип может быть использован для объявления переменных. Отметим, что любой тип может быть объявлен с использованием ключе- ключевого слова typedef, включая типы указателя, функции или массива. Имя с ключевым словом typedef для типов указателя, структуры, объединения может быть объявлено прежде, чем эти типы будут определены, но в пределах видимости объявителя. Примеры объявления и использования новых типов: typedef float (* MATH)( ); /* MATH - новое имя типа, представляющее указатель на функцию, возвращающую значения типа float */ MATH cos; /* cos — указатель на функцию, возвращающую значения типа float */ /* Можно провести эквивалентное объявление */ float (* cos)( );
Язык программирования С-51 347 typedef char FIO[40] /* FIO - массив из 40 символов */ FIO person; /* Переменная person - массив из сорока символов */ /* Это эквивалентно объявлению */ char person[40]; При объявлении переменных и типов здесь были использованы имена типов (math и fio). Помимо определения переменных, имена типов могут еще использоваться в трех случаях: в списке формальных параметров при определении функций, в операциях приведения типов и в операции sizeof. Инициализация данных При объявлении переменной ей можно присвоить начальное значение, присоединяя инициатор к описателю. Инициатор начинается со знака «=» и имеет следующие формы. х=' Инициатор';' (формат I) *=' М ' Список инициаторов М '' ;' (формат 2) Формат 1 используется при инициализации переменных основных типов и указателей, а формат 2 — при инициализации составных объектов. Примеры: char tol = 'N'; Переменная tol инициализируется символом ¦ n '. const long megabute = A024 * 1024); Немодифицируемая переменная megabute инициализируется константным выражением, после чего эта переменная не может быть изменена. static int b[2][2] = {1,2,3,4}; Инициализируется двухмерный массив ь целочисленных величин, эле- элементам массива присваиваются значения из списка. Эта же инициализа- инициализация может быть выполнена следующим образом: static intb[2J[2] = { { 1,2 }, { 3,4 } }; При инициализации массива можно опустить одну или несколько раз- размерностей static int b[3][] = { { 1,2 }, { 3,4 } };
348 Глава 9 Если при инициализации указано меньше значений для строк, то остав- оставшиеся элементы инициализируются 0, т. е. при описании static int b[2][2] = { { 1,2 }, { 3 } }; элементы первой строки получат значения 1 и 2, а второй — 3 и 0. При инициализации составных объектов нужно внимательно следить за использованием скобок и списков инициализаторов. Примеры: struct complex { float real; float imag; } comp [2][3] = { { {1,1}, {2,3}, {4,5} }, { {6,7}, {8,9}, {10,11} } }; В данном примере инициализируется массив структур comp из двух строк И Трех СТОЛбцОВ, Где Каждая Структура СОСТОИТ ИЗ ДВуХ ПОЛеЙ: real И imag. Рассмотрим пример неправильной инициализации аналогичного масси- массива. Ошибка связана с неправильным употреблением фигурных скобок. struct complex comp2 [2][3] = { {1,1},{2,3},{4,5}, {6,7},{8,9},{10,11} }; В этом примере компилятор интерпретирует рассматриваемые фигурные скобки следующим образом: ? первая левая фигурная скобка — начало составного инициатора для массива сотр2; ? вторая левая фигурная скобка — начало инициализации первой стро- строки массива сотр2[0]. Значения l, i присваиваются двум полям первой структуры; ? первая правая скобка (после 1) указывает компилятору, что список инициаторов для строки массива окончен, и элементы оставшихся структур в строке сотр2 [0] автоматически инициализируются нулем; аналогично список {2,3} инициализирует первую структуру в строке сотр2 [1], а оставшиеся структуры массива обращаются в нули; на следующий список инициализаторов {4,5} компилятор будет со- сообщать о возможной ошибке, т. к. строка 3 в массиве, сотр2 [2], отсут- отсутствует. При инициализации объединения задается значение первого элемента объединения в соответствии с его типом. Пример: union tab { unsigned char name[10]; int tabl; } pers = {'A1, 'H1,'T1, 'O1,'H'};
Язык программирования С-51 349 Инициализируется переменная pers.name, и т. к. это массив, для его ини- инициализации требуется список значений в фигурных скобках. Первые пять элементов массива инициализируются значениями из списка, остальные — нулями. Инициализацию массива символов можно выполнить, используя лите- литеральную строку. char stroka[ ] = «привет11; Инициализируется массив символов из 7 элементов, последним элемен- элементом (седьмым) будет символ !\о!, которым завершаются все литераль- литеральные строки. В том случае, если задается размер массива, а литеральная строка длин- длиннее, чем размер массива, то лишние символы отбрасываются. Следующее определение инициализирует переменную stroka литераль- литеральной строкой, состоящей из семи элементов. char stroka[5] = «привет11; В переменную stroka попадают первые пять элементов литерала, а сим- символы "г1 и !\о! отбрасываются. Если строка короче, чем размер массива, то оставшиеся элементы масси- массива заполняются нулями. Отметим, что инициализация объединения типа tab может иметь сле- следующий вид: union tab persl = «Антон11; и, таким образом, в символьный массив попадут символы: 'А1, 'н\ 'т1, 'о1, 'н', 'NO1, а остальные элементы будут инициализированы нулем. Выражения Выражением называется комбинация знаков операций и операндов, ре- результатом которой является определенное значение. Знаки операций определяют действия, которые должны быть выполнены над операнда- операндами. Каждый операнд в выражении в свою очередь тоже может быть вы- выражением. Значение выражения зависит от расположения знаков опера- операций и круглых скобок в выражении, а также от приоритета выполнения операций. Примеры выражений: А+В A*(B+C)-(D-E)/F
350 Глава 9 Выражение в языке программирования С-51 состоит из операндов, кото- которые комбинируются при помощи различных арифметических или логи- логических операций, а также операций отношения. Над переменными- указателями возможно проведение адресных операций. При вычислении выражений тип каждого операнда может быть преобра- преобразован к другому типу. Преобразования типов могут быть неявными, при выполнении операций и вызовов функций, или явными, при использова- использовании функций приведения типов. Из-за того, что неявные преобразования типов могут различаться для трансляторов разных фирм, лучше при на- написании программы использовать явное преобразование. Примеры яв- явных преобразований типов операндов: а=(int)b+(int)с; //Переменные а и b могут быть восьмиразрядными. //Преобразование типов нужно, чтобы избежать //переполнения s=sin((float)a/15)); //Если не преобразовать тип переменной а, то деление //будет целочисленным и результат деления может //быть равен нулю (если а<15). В выражениях в качестве операндов могут использоваться подвыраже- подвыражения. Подвыражение — это обычное выражение, заключенное в скобки. Подвыражения могут использоваться для группировки частей выраже- выражения, точно так же, как и в обычной алгебраической записи. Использова- Использование подвыражений позволяет сократить количество операторов в про- программе, а значит и объем исходного текста (но не объем исполняемого кода), однако одновременно оно затрудняет отладку этой программы. Операнды и операции Операнд — это константа, литеральная строка, идентификатор, вызов функции, индексное выражение, выражение выбора элемента или более сложное выражение, сформированное комбинацией операндов, знаков операций и круглых скобок. Любой операнд, который имеет констант- константное значение, называется константным выражением. Каждый операнд имеет тип. Если в качестве операнда используется константа, то ему соответствует значение и тип представляющей его константы. Целочисленная констан- константа МОЖет быть ТИПа char, int, long, unsigned int, unsigned long, В ЗавИСИ- мости от ее значения и от формы записи. Символьная константа имеет тип char. Константа с плавающей точкой всегда имеет тип float. Литеральная строка состоит из последовательности символов, заклю- заключенных в кавычки, и представляется в памяти как массив элементов типа
Язык программирования С-51 351 char, инициализируемый указанной последовательностью символов. Значением литеральной строки является адрес первого элемента строки и синтаксически литеральная строка является немодифицируемым указа- указателем на тип char. Литеральные строки могут быть использованы в каче- качестве операндов в выражениях, допускающих величины типа указателей. Но т. к. строки не являются переменными, их нельзя использовать в ле- левой части операции присваивания. Следует помнить, что последним символом строки всегда является ' \0', который автоматически добавляется при хранении строки в памяти. Идентификаторы переменных и функций. Каждый идентификатор имеет тип, который устанавливается при его объявлении или определении. Значение идентификатора зависит от типа следующим образом: ? идентификаторы переменных целых и плавающих типов представля- представляют значения соответствующего типа; ? идентификатор переменной типа епшп представлен значением одной константы из множества значений констант, указанных в перечисле- перечислении. Значением идентификатора является константное значение. Тип значения — int, что следует из определения перечисления; ? идентификатор переменной типа struct или union представляет значе- значение, определенное структурой или объединением; ? идентификатор, объявляемый как указатель, представляет указатель на значение, заданное в объявлении типа; ? идентификатор, объявляемый как массив, представляет указатель, значение которого является адресом первого элемента массива. Тип адресуемых указателем величин — это тип элементов массива. Отме- Отметим, что адрес массива не может быть изменен во время выполнения программы, хотя значение отдельных элементов может изменяться. Значение указателя, представляемое идентификатором массива, не яв- является переменной, и поэтому идентификатор массива не может появ- появляться в левой части оператора присваивания; ? идентификатор, объявляемый как функция, представляет указатель, значение которого является адресом функции, возвращающей значе- значения определенного типа и могущей иметь параметры определенного типа. Адрес функции не изменяется во время выполнения программы, меняется только возвращаемое значение. Таким образом, идентифи- идентификаторы функций не могут появляться в левой части операции при- присваивания. Вызов функции состоит из выражения, за которым следует необязатель- необязательный список выражений в круглых скобках: Выражение! ММ Список выражений ]' )'
352 Глава 9 Значением выражения! должен быть адрес функции (например, ее иденти- идентификатор). Значения каждого выражения из списка выражений передаются в функцию в качестве фактического аргумента. Операнд, являющийся вызовом функции, имеет тип и значение возвращаемого функцией зна- значения. Индексное выражение задает элемент массива и имеет вид: Выражение 1 х[х Выражение2 х]' Тип индексного выражения совпадает с типом элементов массива, а зна- значение представляет величину, адрес которой вычисляется с помощью Значений Выражение 1 И Выражение2. Обычно Выражение1 — это указатель, например, идентификатор массива, а выражение2 — это целочисленная величина. Однако требуется только, чтобы одно из выражений было указателем, а второе целочисленной ве- величиной. Поэтому Выражение1 может быть целочисленной величиной, а Выражение2 — указателем. В любом случае выражение2 должно быть за- заключено в квадратные скобки. Хотя индексное выражение обычно ис- используется для ссылок на элементы массива, тем не менее, индекс может появляться с любым указателем. Индексные выражения используются для ссылки на элементы одномерно- одномерного массива. При этом адрес этого элемента вычисляется путем сложения целой величины, указанной в качестве индекса и умноженной на размер элемента массива, с начальным адресом массива. При этом в качестве индекса может быть использована не только константа, но и выражение любой сложности, результатом которого будет целочисленная величина. Пусть, например, объявлен массив элементов типа float. float arr[10]; Чтобы получить доступ к 5-му элементу массива агг, нужно написать агг[5] . При этом индекс 5 умножается на размер переменной float- типа (четыре байта) для того, чтобы вычислить смещение 5-го элемента массива агг относительно его начала. Затем полученное значение скла- складывается с начальным адресом массива агг, что в свою очередь дает адрес 5-го элемента массива. Таким образом, результатом индексного выражения arr[i] является зна- значение i-ro элемента массива. Многомерный массив — это массив, элементами которого являются мас- массивы. Например, первым элементом трехмерного массива является мас- массив с двумя измерениями. Выражение с несколькими индексами ссылает- ссылается на элементы многомерных массивов.
Язык программирования С-51 353 Для ссылки на элемент многомерного массива индексное выражение должно иметь несколько индексов, заключенных в квадратные скобки: Идентификатор массива х [ хИндексное выражениеV ] ' ' [х Индексное выражение2' ]' ... Такое индексное выражение интерпретируется слева направо, т. е. внача- вначале рассматривается первое индексное выражение: Идентификатор массива х[хИндексное выражениеV ]' Результат вычисления этого выражения — это адрес первого элемента вложенного массива, с которым складывается индексное выражение 2, и т. д. Считывание элемента массива осуществляется после вычисления последнего индексного выражения. Отметим, что если к двумерному массиву применить только один индекс, то результатом будет не значе- значение первого элемента вложенного массива, а его адрес. Например, пусть объявлен трехмерный массив mass: int mass [2] [5] [3] ; Рассмотрим процесс вычисления индексного выражения mass [и [2] [2]. 1. Вычисляется выражения mass [ 1]. Индекс I умножается на размер элемента этого массива, которым является двухмерный массив, со- содержащий 5x3 элементов типа int. Получаемое значение складыва- складывается с начальным адресом массива mass. Результатом является адрес вложенного двухмерного массива размером Ex3) в трехмерном мас- массиве mass. 2. Второй индекс 2 умножается на размер массива из трех элементов ти- типа int и складывается с адресом mass [1]. 3. Так как каждый элемент трехмерного массива — это величина типа int, то третий индекс 2 умножается на размер int-типа (в С-51 это два байта) перед сложением с адресом mass[i] [2]. 4. Наконец, выполняется считывание значения полученного элемента массива int-типа. Если было бы указано mass [1] [2], то результатом был бы адрес массива из трех элементов типа int. Соответственно значением индексного вы- выражения mass [1] является адрес двухмерного массива. Выражение выбора элемента применяется, если в качестве операнда надо использовать поле структуры или объединения. Такое выражение имеет значение и тип выбранного элемента. Рассмотрим две формы выражения выбора элемента: Имя' .' Поле Имя"->"Поле
354 Глава 9 В первой форме имя представляет величину типа struct или union, а поле — это имя элемента структуры или объединения. Во второй форме выраже- выражение используется при работе с указателями на структуры или объедине- объединения. При этом поле — это имя выбираемого элемента структуры или объединения. То есть выражение Имя "->" Поле эквивалентно записи хх(*" Имя')'.Поле Пример: struct tree {float num; int spisoc[5]; struct tree *left; } tr[5], elem; elem. left = & elem; В приведенном примере используется операция выбора (\') для доступа к полю left структурной переменной elem. Таким образом, элементу left структурной переменной elem присваивается адрес самой переменной elem, т. е. переменная elem хранит указатель на себя саму. Приведение типов — это изменение (преобразование) типа объекта. При- Приведение типов используется для преобразования объектов одного ска- скалярного типа в другой скалярный тип. Для выполнения преобразования необходимо перед объектом записать в скобках нужный тип: х(х Имя типа х)' Операнд. Пример использования функции приведения типов при вычислении вы- выражений: int i ; float x; х = (float)i+2.0; В этом примере переменная целого типа i с помощью операции приведе- приведения типов приводится к плавающему типу, и только затем участвует в вычислении выражения. Константное выражение — это выражение, результатом которого явля- является константа. Операндом константного выражения могут быть целые константы, символьные константы, константы с плавающей точкой, кон- константы перечисления, выражения приведения типов, выражения с опера- операцией sizeof и другие константные выражения. Однако на использование
Язык программирования С-51 355 знаков операций в константных выражениях налагаются следующие ограничения: 1. В константных выражениях нельзя использовать операции присваи- присваивания и последовательного вычисления (,). 2. Операция «адрес» (&) может быть использована только при инициали- инициализации. Выражения со знаками операций могут участвовать в выражениях как операнды. Выражения со знаками операций могут быть унарными (с од- одним операндом), бинарными (с двумя операндами) и тернарными (с тре- тремя операндами). Унарное выражение состоит из операнда и предшествующего ему знака унарной операции и имеет следующий формат: Знак унарной операции Операнд Бинарное выражение состоит из двух операндов, разделенных знаком бинарной операции: Операнд1 Знак бинарной операции Операнд2 Тернарное выражение состоит из трех операндов, разделенных знаками тернарной операции (х?' и х: ')> и имеет формат: 0перанд1 х ?' 0перанд2 х:' ОперандЗ . Операции. По количеству операндов, участвующих в операции, опера- операции подразделяются на унарные, бинарные и тернарные. В языке С-51 имеются следующие унарные операции, приведенные в табл. 9.8. Таблица 9.8. Унарные операции языка С-51 Знак операции — I • & + ++ — sizeof Наименование операции Унарный минус Поразрядное отрицание (дополнение) Логическое отрицание Разадресация (косвенная адресация) Вычисление адреса Унарный плюс Инкремент (увеличение на 1) Декремент (уменьшение на 1) Размер
356 Глава 9 Унарные операции выполняются справа налево. Операции инкремента и декремента увеличивают или уменьшают значе- значение операнда на единицу и могут быть записаны как справа, так и слева от операнда. Если знак операции записан перед операндом (префиксная форма), то изменение операнда происходит до его использования в вы- выражении. Если знак операции записан после операнда (постфиксная форма), то операнд вначале используется в выражении, а затем происхо- происходит его изменение. В отличие от унарных, бинарные операции, список которых приведен в табл. 9.9, выполняются слева направо. Таблица 9.9. Бинарные операции языка С-51 Знак операции * / % + — << >> < <= > >= == i — & I А && I Г Операция Умножение Деление Остаток от деления Сложение Вычитание Сдвиг влево Сдвиг вправо Меньше Меньше или равно Больше Больше или равно Равно Не равно Поразрядное И Поразрядное ИЛИ Поразрядное исключающее ИЛИ Логическое И Логическое ИЛИ Последовательное вычисление Группа операций Мультипликативные Аддитивные Операции сдвига Операции отношения Поразрядные операции Логические операции Последовательного вычисления
Язык программирования С-51 357 Таблица 9.9 (окончание) Знак операции = /= —= += <<= >>= &= 1 = А Операция Присваивание Умножение с присваиванием Деление с присваиванием Остаток от деления с присваиванием Вычитание с присваиванием Сложение с присваиванием Сдвиг влево с присваиванием Сдвиг вправо с присваиванием Поразрядное И с присваиванием Поразрядное ИЛИ с присваиванием Поразрядное исключающее ИЛИ с присваиванием Группа операций Операции присваивания Левый операнд операции присваивания должен быть выражением, ссылаю- ссылающимся на область памяти (но не идентификатором, объявленным с клю- ключевым словом const). Левый операнд не может также быть массивом. При записи выражений следует помнить, что символы **', *&', *-\ *+' могут обозначать как унарную, так и бинарную операцию. Преобразования типов при вычислении выражений При выполнении операций производится автоматическое преобразова- преобразование типов, чтобы привести операнды выражений к общему типу или чтобы расширить короткие величины до размера целых величин, исполь- используемых в машинных командах. Выполнение преобразования типов зави- зависит от специфики операций и от типа операнда или операндов. Рассмотрим общие арифметические преобразования. 1. Если один операнд имеет тип float, то второй также преобразуется к ТИПу float.
358 Глава 9 2. Если один операнд имеет тип unsigned long, то и второй также преоб- преобразуется К ТИПу unsigned long. 3. Если один операнд имеет тип long, то второй также преобразуется к ТИПу long. 4. Если один операнд имеет тип unsigned int, то второй операнд преоб- преобразуется к этому же типу. Таким образом, можно отметить, что при вычислении выражений опе- операнды преобразуются к типу того операнда, который имеет наибольший размер. Приведем пример преобразования типов при вычислении мате- математического выражения: float ft,sd; unsigned char ch; unsigned long in; int i; • • • • sd=ft*(i+ch/in); При выполнении оператора присваивания правила преобразования бу- будут использоваться следующим образом. Операнд ch преобразуется к unsigned long. По этому же правилу i преобразуется к unsigned long и ре- результат операции, заключенной в круглые скобки, будет иметь тип un- unsigned long. Затем он преобразуется к типу float, и результат всего вы- выражения будет иметь тип float. Операции унарного минуса, логического и поразрядного отрицания Арифметическая операция унарного минуса (-) меняет знак своего операн- операнда. Операнд должен быть целой или плавающей величиной. При выпол- выполнении осуществляются обычные арифметические преобразования. Пример: float u = 5; u = -u; /* меняется знак переменной и, т.е. она принимает значение -5 */ Операция логического отрицания (!) вырабатывает значение 0, если опе- операнд имеет не нулевое значение, и значение 1, если операнд равен нулю @). Результат имеет тип int. Операнд должен быть целого или плаваю- плавающего типа или типа указатель.
Язык программирования С-51 359 Пример: int t, z=0; t-= i 7 • Переменная t получит значение, равное 1, т. к. переменная z имела зна- значение, равное 0. Операция поразрядного отрицания (-) инвертирует каждый бит операнда. Операнд должен быть целого типа. Пример: char b = 9; char f; f = ~b; Двоичное значение 9 равно 00001001. В результате операции ~ь будет по- получено двоичное значение 11110110. Операции разадресации и вычисления адреса Эти операции используются для работы с переменными типа указатель. Операция разадресации (**') позволяет осуществить доступ к перемен- переменной при помощи указателя. Операнд операции разадресации обязатель- обязательно должен быть указателем. Результатом операции является значение пе- переменной, на которую указывает операнд. Типом результата является тип переменной, на которую ссылается указатель. В отличие от прямого использования переменных использование указа- указателей может приводить к непредсказуемым результатам. Результат не определен, если указатель содержит недопустимый адрес. Рассмотрим типичные ситуации, когда указатель содержит недопусти- недопустимый адрес: ? указатель является нулевым; ? указатель определяет адрес такого объекта, который не является ак- активным в момент использования указателя; ? указатель определяет адрес, который не выровнен до типа объекта, на который он указывает; ? указатель определяет адрес, не используемый выполняющейся про- программой. Операция вычисления адреса переменной (&) возвращает адрес своего опе- операнда. Операндом может быть любой идентификатор. Имя функции или массива также может быть операндом операции «адрес», хотя в этом
360 Глава 9 случае применение знака Л&' является лишним, т.к. имена массивов и функций изначально являются адресами. Операция & не может применяться к элементам структуры, являющимся полями битов, т. к. эти элементы не выровнены по байтам. Кроме того, эта операция не может быть применена к объектам с классом памяти reg- register. Примеры: int t, //Объявляется переменная целого типа t f=0, //Объявляется переменная f и ей присваивается О *adress;//Объявляется указатель на переменные целого типа adress = &t // указателю adress присваивается адрес переменной t *adress =f; /* переменной, находящейся по адресу, содержащемуся в переменной adress, т.е. переменной t, присваивается значение переменной f, т.е. О, что эквивалентно оператору t=f; */ Операция sizeof С помощью операции sizeof можно определить размер области памяти, которая соответствует идентификатору или типу переменной. Операция sizeof записывается в следующем виде: "sizeof{"Выражение1) ' В качестве выражения может быть использован любой идентификатор, либо имя типа, заключенное в скобки. Отметим, что не может быть ис- использовано имя типа void, а идентификатор не может относиться к полю битов структуры или быть именем функции. Если в качестве выражения указано имя массива или структуры, то ре- результатом является размер всего массива (т. е. произведение числа эле- элементов на длину типа) или структуры. Мультипликативные операции К этому классу операций относятся операции умножения (*), деления (/) и получения остатка от деления (%). Операндами операции % должны быть целые числа. Отметим, что типы операндов операций умножения и деления могут отличаться, и для них справедливы правила преобразова- преобразования типов. Типом результата является тип операндов после преобразо- преобразования.
Язык программирования С-51 361 Операция умножения (*) выполняет умножение операндов. Тип выпол- выполняемой операции умножения зависит от типа операндов. Перед операци- операцией операнды приводятся к одному типу. Например: int i=5; float f=0.2; float g,z; g=f*i; Тип переменной i преобразуется к типу float, затем выполняется умно- умножение а результат умножения присваивается переменной д. Операция деления (/) выполняет деление первого операнда на второй. Ес- Если в качестве операндов используются переменные целого типа, то вы- выполняется целочисленное деление. Если при этом операнды не делятся нацело, то остаток деления отбрасывается. При попытке деления на ноль выдается сообщение об ошибке во время выполнения программы. При- Пример использования операции деления: int i=49, з=10, n, m; n = i/j; /* результат 4 */ m = i/(-j); /* результат -4 */ Операция вычисления остатка от деления (%) дает остаток от деления пер- первого операнда на второй. Знак результата зависит от конкретной реали- реализации транслятора с языка программирования. В языке программирова- программирования С-51 знак результата совпадает со знаком делимого. Примеры выражений с использованием операции определения остатка: int n = 49, m = 10, i, j, k, 1; 1 j к 1 = n % = n % = (-n) = (-n) m; (-m) ; % m; % (-m); /* /* /* /* 9 9 -9 — 9 */ */ */ */ Аддитивные операции К аддитивным операциям относятся сложение (+) и вычитание (-). Опе- Операнды могут быть целого или плавающего типов. В некоторых случаях над операндами аддитивных операций выполняются общие арифметиче- арифметические преобразования. При аддитивных операциях не контролируется пе- переполнение результата и сообщение об ошибке не выдается. Пример переполнения результата: int 1=30000, 3=30000, к; k=i+j; 13 Зак. 328
362 Глава 9 В результате сложения переменная к получит значение, равное -5536 (принципы выполнения суммирования двоичных чисел в дополнитель- дополнительном двоичном коде приведены в главе 4). Результатом выполнения операции сложения является сумма двух опе- операндов. Операнды могут быть представлены переменными целого или плавающего типа. При этом операнды могут быть доступны как непо- непосредственно, так и при помощи указателей. Когда производится суммирование указателя с переменной целого типа, то к содержимому указателя прибавляется произведение количества яче- ячеек памяти, зависящее от типа указателя, на значение целочисленной пе- переменной. Например: char *a=5;//Объявить указатель и настроить на ячейку памяти с адресом 5 int *t>=5;//Объявить указатель и настроить на ячейку памяти с адресом 5 long *c=5;//Объявить указатель и настроить на ячейку памяти с адресом 5 а=а+5; //Увеличить значение указателя на 5 (адрес 10) t>=b+5; //Увеличить значение указателя на 5 (адрес 15) с=с+5; //Увеличить значение указателя на 5 (адрес 25) Когда указатель складывается с целым числом, то в результате будет со- содержать адрес переменной, расположенной на целое число ячеек дальше от исходного адреса. Новое значение указателя адресует тот же самый тип данных, что и исходный указатель. Операция вычитания (-) вычитает второй операнд из первого. Возможна следующая комбинация операндов: 1. Оба операнда — целого или плавающего типа. 2. Оба операнда являются указателями на один и тот же тип. 3. Первый операнд является указателем, а второй — целым числом. Отметим, что операции сложения и вычитания над адресами в едини- единицах, отличных от длины типа, могут привести к непредсказуемым ре- результатам. Пример работы с указателем: double d[10],* u; int i; u = d+2; /* u указывает на третий элемент массива */ i = u-d; /* i принимает значение равное 2 */
Язык программирования С-51363 Операции сдвига Операции сдвига осуществляют смещение операнда влево («) или впра- вправо (») на число битов, задаваемое вторым операндом. Оба операнда должны быть целыми величинами. Выполняются обычные арифметиче- арифметические преобразования. При сдвиге влево правые освобождающиеся биты устанавливаются в ноль. При сдвиге вправо метод заполнения освобождающихся левых би- битов зависит от типа первого операнда. Если тип сдвигаемой переменной unsigned, то свободные левые биты устанавливаются в ноль. В случае ис- использования знаковой переменной они заполняются копией знакового бита. Результат операции сдвига не определен, если второй операнд от- отрицательный. Преобразования, выполненные операциями сдвига, не обеспечивают об- обработку ситуаций переполнения. Информация теряется, если результат операции сдвига не может быть представлен типом первого операнда, после преобразования. Отметим, что сдвиг влево соответствует умножению первого операнда на 2 в степени, равной второму операнду, а сдвиг вправо соответствует де- делению первого операнда на 2 в степени, равной второму операнду. Примеры использования операции сдвига: int 1=0x1234, j, k ; k = i«4; /* k=x2340» */ j=i«8; /* j = H0x3400» */ i=j»8; /* i = 0x0034 */ Поразрядные операции К поразрядным (побитовым) операциям относятся: операция поразряд- поразрядного «И» (&), операция поразрядного «ИЛИ» (|) и операция поразрядно- поразрядного «исключающего ИЛИ» (л). Операнды поразрядных операций могут быть любого целого типа. При необходимости над операндами выполняются преобразования по умол- умолчанию, тип результата — это тип операндов после преобразования. Операция поразрядного «И» (&) сравнивает каждый бит первого операн- операнда с соответствующим битом второго операнда. Если оба сравниваемых бита единицы, то соответствующий бит результата устанавливается в 1, в противном случае в 0.
364 Глава 9 Операция поразрядного «ИЛИ» (|) сравнивает каждый бит первого опе- операнда с соответствующим битом второго операнда. Если любой (или оба) из сравниваемых битов равен 1, то соответствующий бит результата устанавливается в 1, в противном случае результирующий бит равен 0. Операция поразрядного «исключающего ИЛИ» (А) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если один из сравниваемых битов равен 0, а второй бит равен 1, то соответст- соответствующий бит результата устанавливается в 1, в противном случае, т. е. когда оба бита равны 1 или 0, бит результата устанавливается в 0. Пример: int i=0x45FF, /* i= 0100 0101 1111 1111 */ j=0x00FF; /* j= 0000 0000 1111 1111 */ char r; r = i"j; /* r=0x4500 = 0100 0101 0000 0000 */ r = i|j; /* r=0x45FF = 0100 0101 1111 1111 */ r = i&j /* r=0x00FF = 0000 0000 1111 1111 */ Логические операции К логическим относятся операция логического «И» (&&) и операция ло- логического «ИЛИ» (и). Операнды логических операций могут быть цело- целого типа, плавающего типа или типа указателя, при этом в каждой опера- операции могут участвовать операнды различных типов. Операнды логических выражений вычисляются слева направо. Если зна- значения первого операнда достаточно, чтобы определить результат опера- операции, то второй операнд не вычисляется. Логические операции не вызывают стандартных арифметических преоб- преобразований. Они оценивают каждый операнд с точки зрения его эквива- эквивалентности нулю. Результатом логической операции является 0 или 1, тип результата int. Операция логического «И» (&&) вырабатывает значение 1, если оба опе- операнда имеют ненулевые значения. Если хотя бы один из операндов равен 0, то результат также равен 0. Если значение первого операнда равно 0, то второй операнд не вычисляется. Операция логического «ИЛИ» (и) выполняет над операндами операцию включающего ИЛИ. Она вырабатывает значение 0, если оба операнда имеют значение 0, если какой-либо из операндов имеет ненулевое значе- значение, то результат операции равен 1. Если первый операнд имеет ненуле- ненулевое значение, то второй операнд не вычисляется.
Язык программирования С-51 365 Операция последовательного вычисления Операция последовательного вычисления обозначается запятой (,) и ис- используется для вычисления двух и более выражений там, где по синтак- синтаксису допустимо только одно выражение. Эта операция вычисляет два операнда слева направо. При выполнении операции последовательного вычисления преобразование типов не производится. Операнды могут быть любых типов. Результат операции имеет значения и тип второго операнда. Отметим, что запятая может использоваться также, как символ разделитель, поэтому необходимо по контексту различать запятую, ис- используемую в качестве разделителя или знака операции. Условная операция В языке С-51 имеется одна тернарная операция — условная операция: Операнм1 Л?' Операнд2 Л:' ОперандЗ В условной операции 0перанд1 должен иметь целый или плавающий тип или быть указателем. Он оценивается с точки зрения эквивалентности 0. Если 0перанд1 не равен 0, то вычисляется операнд2, и его значение явля- является результатом операции. Если операндг равен 0, то вычисляется опе- рандЗ и его значение является результатом операции. Следует отметить, что при выполнении этой операции вычисляется либо 0перанд2, либо операндЗ, но ни в коем случае не оба сразу. Тип результата зависит от ти- типов 0перанд2 И ОперандЗ Следующим образом: 1. Если операнды имеют целый или плавающий тип (отметим, что их типы могут отличаться), то выполняются обычные арифметические преобразования. Типом результата является тип операнда после пре- преобразования. 2. Если оба операнда имеют один и тот же тип структуры, объединения или указателя, то тип результата будет тем же самым типом структу- структуры, объединения или указателя. 3. Если оба операнда имеют тип void, то результат имеет тип void. 4. Если один операнд является указателем на объект любого типа, а дру- другой операнд является указателем на void, то указатель на объект пре- преобразуется к указателю на void, который и будет типом результата. 5. Если один из операндов является указателем, а другой константным выражением со значением 0, то типом результата будет тип указателя.
366 Глава 9 Пример: max = (d<=b) ? b : d; Переменной max присваивается максимальное значение переменных d и ь. Операции инкремента и декремента Операции инкремента (++) и декремента (--) являются унарными опера- операциями присваивания. Они соответственно увеличивают или уменьшают значения операнда на единицу. Эти операции обычно используются для организации циклов и перехода от адреса одной переменной к адресу другой переменной. Операнд может быть целого или плавающего типа или быть указателем и при этом обязательно должен быть модифици- модифицируемым. Тип результата соответствует типу операнда. Операнд адресно- адресного типа увеличивается или уменьшается на размер объекта, который он адресует. В языке программирования С-51 допускается префиксная или постфикс- постфиксная формы операций инкремента (декремента). Если знак операции стоит перед операндом (префиксная форма записи), то изменение операнда происходит до его использования в выражении и результатом операции является увеличенное или уменьшенное значение операнда. В том случае, если знак операции стоит после операнда (постфиксная форма записи), то операнд вначале используется для вычисления выра- выражения, и только затем происходит изменение операнда. Примеры использования операции инкремента: int t=l, S=2, z, f; z=(t++)*5; Вначале происходит умножение t*5, а затем увеличение t. В результате ПОЛУЧИТСЯ z=5, t=2. f=(++s)/3; Вначале значение s увеличивается, а затем используется в операции де- деления. В результате получим s=3, f=i. В случае, если операции увеличения и уменьшения используются как са- самостоятельные операторы, префиксная и постфиксная формы записи становятся эквивалентными. z++; /* эквивалентно */ ++z;
Язык программирования С-51 367 Простое присваивание Операция простого присваивания используется для замены значения ле- левого операнда, значением правого операнда. При присваивании произ- производится преобразование типа правого операнда к типу левого операнда по правилам, упомянутым раньше. Левый операнд должен быть моди- модифицируемым. Пример: int t; char f; long z; t=f+z; Значение переменной f преобразуется к типу long, вычисляется f+z, ре- результат преобразуется к типу int и затем присваивается переменной t. Составное присваивание Кроме простого присваивания, имеется группа операций присваивания, которые объединяют простое присваивание с одной из бинарных опера- операций. Такие операции называются составными операциями присваивания и имеют следующий вид: Операнд 1 Бинарная операция *=' 0перанд2. Составное присваивание эквивалентно следующему простому присваи- присваиванию: 0перанд1 *=' 0перанд1 Бинарная операция 0перанд2 . Каждая операция составного присваивания выполняет преобразования, которые осуществляются соответствующей бинарной операцией. Левым операндом операций «+=» и «-=» может быть указатель, в то время как правый операнд должен быть целым числом. Примеры: double arr[4]={ 2.0, 3.3, 5.2, 7.5 } ; double b=3.0; b+=arr[2]; /* эквивалентно оператору b=b+arr[2] */ arr[3]/=b+l; /* эквивалентно оператору arr[3]=arr[3]/(b+1) */ Заметим, что при втором присваивании использование составного при- присваивания дает заметный выигрыш времени выполнения программы, т. к. левый операнд является индексным выражением, а значит для его вычисления потребуется несколько команд микроконтроллера.
368 Глава 9 Приоритеты операций и порядок вычислений В языке С-51 операции с высшими приоритетами вычисляются первыми, Наивысшим является приоритет, равный 1. Приоритеты и порядок опе- операций приведены в табл. 9.10. Таблица 9.10. Приоритеты Приори- Приоритет 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Знак операции - - ! * & ++ — sizeof приведение типов 0 [] . -> * / % + - << >> i & I I I • • ^ / д_ ¦ / и порядок операций в языке Типы операции Унарные Выражение Мультипликативные Аддитивные Сдвиг Отношение Отношение (равенство) Поразрядное «И» Поразрядное «исключающее ИЛИ» Поразрядное «ИЛИ» Логическое «И» Логическое «ИЛИ» Условная Простое и составное присваивание Последовательное вычисление программирования С-51 Порядок выполнения Справа налево Слева направо Слева направо Справа налево Слева направо Побочные эффекты Операции присваивания в сложных выражениях могут вызывать побоч ные эффекты, т. к. они изменяют значение переменной. Побочный эф
Язык программирования С-51 369 фект может возникать и при вызове функции, если он содержит прямое или косвенное присваивание (через указатель). Это связано с тем, что ар- аргументы функции могут вычисляться в любом порядке. Например, по- побочный эффект имеет место в следующем вызове функции: prog (a/a=k*2); В зависимости от того, какой аргумент вычисляется первым, в функцию могут быть переданы различные значения. Порядок вычисления операндов некоторых операций зависит от реали- реализации компилятора, и поэтому могут возникать разные побочные эффек- эффекты, если в одном из операндов используются операции увеличения или уменьшения, а также другие операции присваивания. Например, выражение i*j + (j++) + (--i) может принимать различные зна- значения при обработке разными компиляторами. Чтобы избежать недора- недоразумений при выполнении программ из-за побочных эффектов, необхо- необходимо придерживаться следующих правил: 1. Не использовать операции присваивания переменной значения в вы- вызове функции, если эта переменная участвует в формировании других аргументов функции. 2. Не использовать операции присваивания переменной значения в вы- выражении, где она используется более одного раза. Преобразование типов При выполнении операций происходят неявные преобразования типов в следующих случаях: ? при выполнении операций осуществляются обычные арифметические преобразования (которые были рассмотрены выше); ? при выполнении операций присваивания, если значение одного типа присваивается переменной другого типа; ? при передаче аргументов функции. Кроме того, в языке программирования С-51 есть возможность явного приведения значения одного типа к другому. В операциях присваивания тип значения, которое присваивается, преоб- преобразуется к типу переменной, получающей это значение. Допускается пре- преобразование целых и плавающих типов, даже если такое преобразование ведет к потере информации. Преобразование типов целых знаковых переменных. Целая знаковая пере- переменная преобразуется к более короткой целой знаковой переменной от-
370 Глава 9 брасыванием старших битов. Целая знаковая переменная преобразуется к более длинной целой знаковой переменной путем копирования знако- знакового бита во все старшие биты. При преобразовании целой знаковой пе- переменной к целой беззнаковой переменной целое число со знаком преоб- преобразуется к размеру целого без знака, а результат рассматривается как беззнаковая переменная. Преобразование целого со знаком к плавающему типу происходит без потери информации, за исключением случая преобразования значения с типом long int или unsigned long int, когда точность плавающего числа может быть недостаточна для преобразования без потери. Преобразование типов целых беззнаковых переменных. Целые беззнаковые переменные преобразуется к более коротким целым беззнаковым или знаковым переменным отбрасыванием старших битов. Целые беззнако- беззнаковые переменные преобразуются к более длинным целым беззнаковым или знаковым переменным путем дополнения нулей слева. Когда целое без знака преобразуется к целому со знаком того же размера, битовое представление не изменяется. При преобразовании величины с плавающей точкой к целым типам она сначала преобразуется к типу long (дробная часть плавающей величины при этом отбрасывается), а затем величина типа long преобразуется к требуемому целому типу. Если значение слишком велико для long, то ре- результат преобразования не определен. Преобразование ИЗ float, double ИЛИ long double К ТИПу unsigned long производится с потерей точности, если преобразуемое значение больше, чем максимально возможное положительное значение, представленное ТИПОМ long. Преобразование типов указателя. Указатель на величину одного типа может быть преобразован к указателю на величину другого типа. Одна- Однако результат может быть не определен из-за отличий в требованиях к выравниванию и размерах для различных типов. Указатель на тип void может быть преобразован к указателю на любой тип и указатель на любой тип может быть преобразован к указателю на тип void без ограничений. Значение указателя может быть преобразова- преобразовано к целой величине. Метод преобразования зависит от размера указате- указателя и размера целого типа следующим образом: ? если размер указателя меньше размера целого типа или равен ему, то указатель преобразуется точно так же, как целое без знака; ? если размер указателя больше, чем размер целого типа, то указатель сначала преобразуется к указателю с тем же размером, что и целый тип, и затем преобразуется к целому типу.
Язык программирования С-51 371 Целый тип может быть преобразован к адресному типу по следующим правилам: ? если целый тип того же размера, что и указатель, то целая величина просто рассматривается как указатель (целое без знака); ? если размер целого типа отличен от размера указателя, то целый тип сначала преобразуется к размеру указателя (используются способы преобразования, описанные выше), а затем полученное значение трак- трактуется как указатель. Преобразования при вызове функции. Преобразования, выполняемые над аргументами при вызове функции, зависят от того, был ли задан прото- прототип функции (объявление «вперед») со списком объявлений типов аргу- аргументов. Если задан прототип функции, и он включает объявление типов аргу- аргументов, то над аргументами при вызове функции выполняются только обычные арифметические преобразования. Если прототип функции отсутствует, то при вызове происходят только обычные арифметические преобразования для аргументов. Эти преобра- преобразования выполняются независимо для каждого аргумента. Величины ти- типа float преобразуются к double, величины типа char и short преобра- ЗуЮТСЯ К int, веЛИЧИНЫ ТИПОВ unsigned char И unsigned short преобразуются к unsigned int. Могут быть также выполнены неявные преобразования переменных типа указатель. Задавая прототипы функ- функций, можно переопределить эти неявные преобразования и позволить компилятору выполнить контроль типов. Преобразования при приведении типов. Явное преобразование типов мо- может быть осуществлено посредством операции приведения типов, кото- которая имеет формат: *(уИмя типах) * Операнд В приведенной записи имя типа задает тип, к которому должен быть пре- преобразован Операнд. Пример: int i=2; long 1=2; double d; float f; d=(double)i * (doubleI; f=(float)d; В данном примере величины i, l, d будут явно преобразовываться к ука- указанным в круглых скобках типам.
372 Глава 9 Операторы Все операторы языка С-51 могут быть условно разделены на следующие категории: ? условные операторы, к которым относятся оператор условия if и опе- оператор выбора switch; ? операторы ЦИКЛа (for, while, do-while); ? операторы Перехода (break, continue, return, goto); ? другие операторы (оператор «выражение», пустой оператор). Операторы в программе можно объединять в составные операторы с по- помощью фигурных скобок. Любой оператор в программе может быть по- помечен меткой, состоящей из имени и следующего за ним двоеточия. Все операторы языка С-51, кроме составных, заканчиваются точкой с запятой (;). Оператор-выражение Любое выражение, которое заканчивается точкой с запятой, является оператором. Выполнение оператора-выражения заключается в вычислении выраже- выражения. Полученное значение никак не используется, поэтому, как правило, такие выражения вызывают побочные эффекты. Заметим, что вызвать функцию, не возвращающую значение, можно только при помощи опе- оператора-выражения. Правила вычисления выражений были сформулиро- сформулированы выше. Примеры: ++ i; Этот оператор представляет выражение, которое увеличивает значение переменной i на единицу. a=cos(b * 5); Этот оператор представляет выражение, включающее в себя операции присваивания и вызова функции. а(х,у) ; Этот оператор представляет выражение, состоящее из вызова функции.
Язык программирования С-51 373 Пустой оператор Пустой оператор состоит только из точки с запятой. При выполнении этого оператора ничего не происходит. Он обычно используется в сле- следующих случаях: ? в операторах do, for, while, if в строках, когда не требуется выполне- выполнение каких-либо действий, но по синтаксису требуется хотя бы один оператор; ? при необходимости пометить фигурную скобку. Синтаксис языка про- программирования С-51 требует, чтобы после метки обязательно следо- следовал оператор. Фигурная же скобка оператором не является. Поэтому, если надо передать управление на фигурную скобку, необходимо ис- использовать пустой оператор. Пример: int main ( ) { if (...) goto a; /* переход на скобку */ а: ; } return 0; Составной оператор Составной оператор, часто называемый блоком, представляет собой не- несколько операторов и объявлений, заключенных в фигурные скобки: х{* [Список объявлений] [Список опера торов] Ч' Заметим, что в конце составного оператора точка с запятой не ставится. Выполнение составного оператора заключается в последовательном вы- выполнении составляющих его операторов. Он используется в условных операторах и операторах цикла для того, чтобы выполнить несколько операторов.
374 Глава 9 Пример: int main () { int q,b; double t,d; • • • if (...) {int e,g; float f,q; return @); Переменные е, g, f, q будут уничтожены после выполнения составного оператора. Отметим, что переменная q является локальной в составном операторе, т. е. она никоим образом не связана с переменной q объявлен- объявленной В начале ФУНКЦИИ main С ТИПОМ int. Оператор if Формат оператора: 44 i f (" Выражение' )' Опера тор 1' ;' ["else" Опера тор2' ;' ] Выполнение оператора if начинается с вычисления выражения. Далее выполнение происходит по следующей схеме: 1) еСЛИ Выражение ИСТИННО (т. е. ОТЛИЧНО ОТ 0), ТО ВЫПОЛНЯетСЯ ОператорЦ 2) еСЛИ Выражение ЛОЖНО (т. е. раВНО 0), ТО ВЫПОЛНЯеТСЯ 0ператор2\ 3) если выражение ложно и отсутствует оператор2, то выполняется сле- следующий за if оператор. После выполнения оператора if значение передается на следующий опе- оператор программы, если последовательность выполнения операторов программы не будет принудительно нарушена использованием операто- операторов перехода. Пример: if (l < D) else
Язык программирования С-51375 Этот пример иллюстрирует также и тот факт, что на месте оператора 1, так же как и на месте оператора2, могут находиться сложные конструкции. Допускается использование вложенных операторов if. Оператор if мо- может быть включен в конструкцию if или в конструкцию else другого опе- оператора if. Чтобы сделать программу более читабельной, рекомендуется группировать операторы и конструкции во вложенных операторах if, ис- используя фигурные скобки (образуя составной оператор). Если же фигур- фигурные скобки опущены, то компилятор связывает каждое ключевое слово else с наиболее близким ключевым словом if, для которого нет else. Примеры: int main ( ) {int t=2, b=7, r=3; if(t>b) {if(b<r)r=b; } else r=t; return @); } В результате выполнения этой программы переменная г станет равной 2. Если же в программе опустить фигурные скобки, стоящие после опера- оператора if, то программа будет иметь следующий вид: int main( ) {int t=2,b=7,r=3; if(a>b) if (Ыс) t=b; else r=t; return @); } В этом случае г получит значение, равное 3, т. к. ключевое слово else от- относится ко второму оператору if, который не выполняется, поскольку не выполняется условие, проверяемое в первом операторе if.
376 Глава 9 Следующий фрагмент иллюстрирует вложенные операторы if: char ZNAC; int x,y,z; • if (ZNAC ==¦-¦) x = у - z; else if (ZNAC == '+') x = у + z; else if (ZNAC == '*') x = у * z; else if (ZNAC == '/') x = у / z; else ... Из рассмотрения этого примера можно сделать вывод, что конструкции, использующие вложенные операторы if, выглядят довольно громоздко. Другим способом организации выбора из множества различных вари- вариантов является использование специального оператора выбора switch. Однако надо сказать, что использование этого оператора приводит к ме- менее быстродействующим программам и объем программы возрастает по сравнению с предыдущим случаем использования условных операторов if. Оператор switch Оператор switch предназначен для организации выбора из множества различных вариантов. Формат оператора следующий: "switch (" Выражение s)' МЛ [Объявление] • • • [ "case'' Константное выражение 1}' :' [ Список операторов1] [ "case" Константное выражение2] ' :' [ Список операторов2] • • • [ "default:" [ Список операторов ]] } выражение, следующее за ключевым словом switch в круглых скобках, может быть любым выражением, допустимыми в языке С-51, значение которого должно быть целым. Отметим, что можно использовать явное приведение к целому типу, однако необходимо помнить о тех ограниче- ограничениях и рекомендациях, о которых говорилось выше. Значение этого выражения является ключевым для выбора из нескольких вариантов. Тело оператора switch состоит из нескольких операторов, на- начинающихся с ключевого слова case с последующим константным выра-
Язык программирования С-51 377 жением. Обычно в качестве константного выражения используются це- целые или символьные константы. Все константные выражения в операторе switch должны быть различны- различными. Кроме операторов, начинающихся с ключевого слова case, в составе оператора switch может быть один фрагмент, помеченный ключевым словом default. Он будет выполняться, если не выполнится ни одно из условий. Список операторов может быть пустым либо содержать один или более операторов. Причем в операторе switch не требуется заключать последо- последовательность операторов в фигурные скобки. Отметим также, что в операторе switch можно использовать свои ло- локальные переменные, объявления которых находятся перед первым клю- ключевым словом case, однако в объявлениях не должна использоваться инициализация. Схема выполнения оператора switch следующая: 1) вычисляется выражение в круглых скобках; 2) вычисленное значение последовательно сравнивается с константными выражениями, следующими за ключевыми словами case; 3) если одно из константных выражений совпадает со значением выраже- выражения, то управление передается на оператор, помеченный соответст- соответствующим ключевым словом case; 4) если ни одно из константных выражений не равно выражению, то управление передается на оператор, помеченный ключевым словом default. В случае отсутствия ключевого слова default управление пе- передается на следующий оператор. Отметим интересную особенность использования оператора switch: кон- конструкция со словом default может быть не последней в теле оператора switch. Все операторы между первым выполнившимся условием и концом опе- оператора switch выполняются последовательно вне зависимости от выпол- выполнения ПОСЛедуЮЩИХ УСЛОВИЙ, еСЛИ ТОЛЬКО В КаКОМ-ЛИбО ИЗ УСЛОВИЙ case выполнение оператора switch не будет прервано при помощи ключевого слова break. Поэтому программист должен сам позаботиться о выходе из оператора case, если необходимо, чтобы выполнялось только одно из условий оператора switch. Например: int i=2; switch (i)
378 Глава 9 {case 1: i += 2; case 2: i *= 3; case 0: i /= 2; case 4: i -= 5; default: ; } Выполнение оператора switch начинается со строки, помеченной case 2. Таким образом, переменная i получает значение, равное 6. Далее выпол- выполняется оператор, помеченный ключевым словом case о, а затем — case 4, переменная i примет значение 3, а затем значение -2. Пустой оператор, помеченный ключевым словом default, не изменяет значения переменной. Рассмотрим, как выглядит ранее приведенный пример, в котором иллю- иллюстрировалось использование вложенных операторов if, если его перепи- переписать с использованием оператора switch. char ZNAC; int x,y, z; switch (ZNAC) {case '+': x = у + z; break; case '-': x = у - z; break; case '*': x = у * z; break; case '/': x = u / z; break; default : ; } Оператор break позволяет в необходимый момент прервать последова- последовательность выполняемых операторов в теле оператора switch путем пере- передачи управления оператору, следующему за switch. Отметим, что в теле оператора switch можно использовать вложенные операторы switch, при этом в ключевых словах case можно использовать одинаковые константные выражения. Пример использования вложенного оператора выбора switch: • • • switch (a) {case 1: b=c; break; case 2: switch (d) {case 0: f=s; break; case 1: f=9; break;
Язык программирования С-51 ^ 379 case 2: f-=9; break; case 3: b-=c; break; Оператор break Оператор break обеспечивает прекращение выполнения самого внутрен- внутреннего из объемлющих его операторов: switch, do, for или while. После выполнения оператора break управление передается оператору, следую- следующему за прерванным оператором. Оператор цикла for Оператор for — это наиболее общий способ организации цикла. Он име- имеет следующий формат: 44for (" ВыражениеV ;' Выражение2' ;' ВыражениеЗ Л)' Тело цикла' ;' выражение1 обычно используется для задания начального значения пере- переменных, управляющих циклом. выражение2 определяет условие, при ко- котором тело цикла будет выполняться. ВыражениеЗ выполняется после ка- каждого прохода тела цикла (после каждой итерации). Обычно в выраженииз изменяются переменные, управляющие циклом. Последовательность выполнения оператора цикла for: 1) ВЫЧИСЛЯетСЯ Выражение 1\ 2) ВЫЧИСЛЯетСЯ Выражение2\ 3) если значение выражения2 отлично от нуля, то выполняется тело цикла, вычисляется ВыражениеЗ и осуществляется переход к пункту 2, если вы- ражение2 равно нулю, то управление передается на оператор, следую- следующий за оператором for. Обратите внимание, что проверка условия всегда выполняется в начале цикла. Это означает, что тело цикла может ни разу не выполниться, если условие выполнения оператора цикла сразу будет ложным. Пример использования оператора цикла for: int main () .{int i,b; for (i=l; i<10; i
380 Глава 9 b=i*i; return 0; } В этом примере вычисляются квадраты чисел от 1 до 9. Некоторые варианты применения оператора for повышают его возмож- возможности за счет использования сразу нескольких переменных, управляю- управляющих циклом. Пример использования нескольких переменных в операторе цикла for: int main() {int top,bot; char string[100] , temp,- for(top=0,bot=100; top<bot; top++,bot—) {temp=string[top]; string[bot]=temp; В этом примере, реализующем запись строки символов в обратном по- порядке, для управления циклом используются две переменные top и bot. Отметим, что на месте выражения! и выраженияЗ здесь используются не- несколько выражений, записанных через запятую и выполняемых последо- последовательно. В этом же примере можно наглядно проследить за тем, как влияет выбор типа переменных на размер загрузочного файла. В приведенном примере для организации цикла использованы переменные типа int. В результате получился машинный код размером 59 байт. При замене типа этих же переменных на unsigned char размер кода сокращается до 41 байта. Эти же действия увеличивают быстродействие программы в полтора раза! В микроконтроллерах оператор цикла for используется^для реализации бесконечного цикла, который необходим для непрерывной работы уст- устройства. Организация такого цикла возможна при использовании пусто- пустого выражения2. Иногда для реализации алгоритма работы устройства требуется при выполнении какого-либо условия выйти из бесконечного ЦИКЛа. ДЛЯ ЭТОГО МОЖНО ВОСПОЛЬЗОВаТЬСЯ Оператором break. Пример реализации бесконечного цикла с возможностью выхода из него при помощи оператора for: for (;;)
Язык программирования С-51 381 break; Так как в языке программирования С присутствует пустой оператор, то и в качестве тела цикла оператора for также можно использовать пустой оператор. Такая форма оператора может быть использована для органи- организации временных задержек или поиска. Пример использования пустого оператора для поиска: for(i=0;t[i]<10;i++); В данном примере при завершении цикла переменная цикла i принима- принимает значение номера первого элемента массива t, значение которого боль- больше 10. Оператор цикла while Оператор while называется циклом с предусловием и имеет следующий формат: "while {"Выражение')' Тело Л;' Этот оператор обычно приводит к более коротким и эффективным про- программам по сравнению с предыдущим оператором цикла, т. к. элемен- элементарно накладывается на машинные инструкции микроконтроллера. В качестве выражения допускается использовать любое выражение языка С-51, а в качестве тела — любой оператор, в том числе пустой или со- составной операторы. Последовательность выполнения оператора while: 1) ВЫЧИСЛЯетСЯ Выражение; 2) если выражение ложно, то выполнение оператора while заканчивается и выполняется следующий по порядку оператор. Если выражение истин- истинно, то выполняется тело оператора while; 3) переход к пункту 1. Оператор цикла вида "for ("Выражение 1';' Выражение^ -,' ВыражениеУ ) ' Тело *;' может быть заменен оператором while следующим образом: Вьражение1 ; "while ("Вьражение2') ' * { * Тело Выражение3;
382 Глава 9 Так же, как и при выполнении оператора цикла for, в операторе while вначале происходит проверка Выражения2. Поэтому оператор while удоб- удобно использовать в ситуациях, когда тело не всегда нужно выполнять. Внутри операторов for и while можно использовать локальные перемен- переменные, которые должны быть объявлены с определением соответствующих типов. Оператор цикла do-while Оператор цикла do-whiie называется оператором цикла с проверкой ус- условия после тела цикла и используется в тех случаях, когда необходимо выполнить тело цикла хотя бы один раз. Формат оператора do-whiie имеет следующий вид: "do» Тело «while» Л ( уВыражение") ; " Схема выполнения оператора do-whiie: 1) выполняется тело цикла (которое может быть составным оператором); 2) ВЫЧИСЛЯеТСЯ Выражение; 3) если выражение ложно, то выполнение оператора do-whiie заканчива- заканчивается и выполняется следующий по порядку оператор. Если выражение истинно, то выполняется переход к пункту 1. Чтобы прервать выполнение цикла до того, как условие станет ложным, МОЖНО ИСПОЛЬЗОВаТЬ оператор break. Операторы while И do-while МОГуТ быть ВЛОЖеННЫМИ. Пример использования вложенных циклов: int i,j,k; • • • i=O;j=O;k=O; j —; while(a[k]<i)k++; }while(i<30&&j<-30); Следует отметить, что приведенный пример использования оператора do-whiie не является образцом для подражания, т. к. использование опе- операции && заставляет компилятор создавать достаточно сложную про- программу выполнения логического выражения. Использование для той же цели оператора break приводит к более длинному исходному тексту про- программы. При этом код программы получается более коротким и быстро-
Язык программирования С-51 383 действующим, т. к. в этом случае один оператор языка программирова- программирования С соответствует одной машинной команде микроконтроллера: char 1=0,3=0,1^=0; ;э —; while(a[k]<i)k++; if(j>=-30)break; }while(i<30); Оператор continue Оператор continue используется только внутри операторов цикла, но в отличие от break, осуществляется не выход из цикла, а переход к следую- следующему циклу. Формат записи оператора continue: "continue;" Пример использования оператора continue: int main() {int a,b; for (a=l,b=0; a<100; b+=a,a++) {if (b%2) continue; ... /* обработка четных сумм */ return 0; Когда сумма чисел от 1 до а становится нечетной, оператор continue пе- передает управление на очередную итерацию цикла for, не выполняя опе- операторы обработки четных сумм. Оператор continue, как и оператор break, прерывает самый внутренний из объемлющих его циклов. Оператор возврата из функции return Оператор return завершает выполнение функции, в которой он задан, и возвращает управление в вызывающую функцию, в точку, непосредст- непосредственно следующую за вызовом данной функции. Формат оператора воз- возврата из функции: "return" [Выражение]' ;'
384 Глава 9 Значение выражения, если оно задано, возвращается в вызывающую функцию в качестве значения вызванной функции. Если выражение опу- опущено, то возвращаемое значение не определено. Это используется в функция типа void. Выражение может быть заключено в круглые скобки, хотя их наличие не обязательно. Если в какой-либо функции отсутствует оператор return, то передача управления в точку вызова происходит после выполнения последнего оператора вызываемой функции. При этом возвращаемое значение не определено. Если функция не должна возвращать значения (подпрограм- (подпрограмма-процедура), ТО ее НуЖНО ОбъЯВЛЯТЬ С ТИПОМ void. Таким образом, оператор return используется либо для немедленного выхода из функции, либо для передачи в основную программу возвра- возвращаемого из функции значения. Пример использования оператора return для возвращения результата работы функции суммирования двух переменных: int sum (int a, int b) {return (a+b);} Функция sum объявлена с двумя формальными параметрами, а и ь, int- типа и возвращает значение такого же типа, о чем говорит описатель, стоящий перед именем функции. Возвращаемое оператором return зна- значение равно сумме фактических параметров. Пример использования оператора return для выхода из подпрограммы- процедуры: void prov (int a, double b) { double с; if (a<3) return; else if (b>10) return; else { c=a+b; if (B*c-b)==ll) return; В этом примере оператор return используется для выхода из функции в случае выполнения одного из проверяемых условий. Оператор безусловного перехода goto Использование оператора безусловного перехода goto в практике про- программирования на языке С-51 настоятельно не рекомендуется, т. к. за-
Язык программирования С-51 385 трудняет понимание программ и возможность их модификаций. В то же самое время алгоритм любой степени сложности может быть построен при использовании оператора условного перехода if и операторов цик- циклов while и do-while. Оператор безусловного перехода goto может быть использован только в случае крайней необходимости. Формат этого оператора записывается в следующем виде: 44 go to" Имя метки'; ' • • • Шля метки' : ' Оператор' ; ' Оператор goto передает управление на оператор, помеченный меткой имя метки. Помеченный оператор должен находиться в той же функции, что и goto, а используемая метка должна быть уникальной, т. е. одно имя метки не может быть использовано для разных операторов программы, имя метки — это идентификатор. Любой оператор в составном операторе может иметь свою метку. Ис- Используя goto, можно передавать управление внутрь составного операто- оператора. Но нужно быть осторожным при входе в составной оператор, содер- содержащий объявления переменных с инициализацией, т. к. объявления располагаются перед выполняемыми операторами и значения объявлен- объявленных переменных при таком переходе будут не определены. Использование функций в языке программирования С-51 Определение и вызов функций Мощность языка С-51 во многом определяется легкостью и гибкостью в определении и использовании функций, написанных на языке програм- программирования С-51. В нем не существует отдельного ключевого слова для подпрограмм-процедур. Подпрограмма-процедура и подпрограмма-функ- подпрограмма-функция объявляются подобным образом. Функция — это совокупность операторов и объявлений локальных пе- переменных, обычно предназначенная для решения определенной задачи. Каждая функция должна иметь имя, которое используется для ее объяв- объявления, определения и вызова. В любой программе, написанной на языке программирования С-51, должна быть функция с именем main (главная функция), именно с нее, в каком бы месте программы она не находилась, начинается выполнение программы.
386 Глава 9 При вызове функции ей при помощи аргументов (формальных парамет- параметров) могут быть переданы некоторые значения (фактические параметры), используемые во время ее выполнения. Функция может возвращать зна- значение (одно!). Это возвращаемое значение и является результатом вы- выполнения функции, который после выполнение программы заносится в переменную, стоящую в левой части выражения приравнивая, в правой части которого происходит вызов функции. Допускается также исполь- использовать функции, не имеющие аргументов, и функции, не возвращающие никаких значений (подпрограммы-процедуры). С использованием функций в языке программирования С-51 связаны три понятия: определение функции (описание действий, выполняемых функ- функцией в виде операторов), объявление функции (задание формы обраще- обращения к функции) и вызов функции. Определение функции задает тип возвращаемого значения, имя функции, типы и число формальных параметров, а также объявления локальных переменных и операторы, называемые телом функции, и определяющие выполняемые ею действия. В определении функции также может быть задан класс памяти. Пример определения подпрограммы-функции: int rus (unsigned char r) {if (r>='Af && c<=' ') return 1; else return 0; } В данном примере определена функция с именем rus, имеющая один па- параметр с именем г и типом unsigned char. Функция возвращает целое значение, равное 1, если параметр функции является буквой русского ал- алфавита, или 0 в противном случае. В языке программирования С-51 требуется, чтобы определение функции обязательно предшествовало ее вызову. Определения используемых функций могут находиться перед определением функции main в одном с нею файле или в другом файле. Если же по каким-либо причинам требуется вызвать функцию раньше ее фактического определения или функцию, определение которой находит- находится в другом файле, то до вызова нужно поместить объявление (прототип) вызываемой функции. Это позволит компилятору проверить соответст- соответствия типов передаваемых фактических параметров типам формальных параметров функции.
Язык программирования С-51 387 Объявление функции имеет такой же вид, что и определение, с той лишь разницей, что тело функции (исполняемые операторы) отсутствует, а имена формальных параметров могут быть опущены. Для функции, определенной в последнем примере, прототип может быть представлен в виде: int rus (unsigned char r); ИЛИ int rus (unsigned char); В программах, написанных на языке программирования С-51, широко используются так называемые библиотечные функции, т. е. функции, предварительно разработанные и записанные в библиотеки. Прототипы библиотечных функций находятся в специальных заголовочных файлах, поставляемых вместе с библиотеками в составе систем программирова- программирования, И ВКЛЮЧаЮТСЯ В Программу С ПОМОЩЬЮ ДИреКТИВЫ #include. Если объявление функции не задано, то по умолчанию строится прото- прототип функции на основе анализа первой ссылки на функцию, будь то вы- вызов или определение функции. Однако такой прототип не всегда согласу- согласуется с последующим определением или вызовом функции. Рекомендуется всегда задавать прототип функции. Это позволит компилятору либо вы- выдавать диагностические сообщения при неправильном использовании функции, либо корректным образом регулировать несоответствие аргу- аргументов, устанавливаемое при выполнении программы. В соответствии с синтаксисом языка С-51, определение функции имеет следующую форму: [Спецификатор класса памяти] [Спецификатор типа] Имя функции х ( х [Список формальных параметров]' )' л{х Тело функции' }' Необязательный спецификатор класса памяти задает класс памяти функ- функции, который может быть static или extern. Подробно классы памяти будут рассмотрены в следующем разделе. спецификатор типа функции задает тип возвращаемого значения, кото- который может быть любым. Если спецификатор типа не задан, то предпола- предполагается, что функция возвращает значение типа int. Функция не может возвращать массив или функцию, но может возвра- возвращать указатель на любой тип, в том числе и на массив, и на функцию. Тип возвращаемого значения, задаваемый в определении функции, дол- должен соответствовать типу в объявлении этой функции. Функция возвращает значение, если ее выполнение заканчивается опера- оператором return, содержащим некоторое выражение. Указанное выражение вычисляется, преобразуется, если необходимо, к типу возвращаемого
388 Глава 9 значения и возвращается в точку вызова функции в качестве результата. Если оператор return не содержит выражения или выполнение функции завершается после выполнения последнего ее оператора (без выполнения оператора return), то возвращаемое значение не определено. Для функ- функций, не использующих возвращаемое значение, в описателе типа должен быть использован тип void, указывающий на отсутствие возвращаемого значения. Если функция определена как возвращающая некоторое зна- значение, а в операторе return при выходе из нее отсутствует выражение, то поведение вызывающей функции после передачи ей управления может быть непредсказуемым, поэтому транслятор с языка программирования проверяет такую ситуацию и выдает сообщение об ошибке. Список формальных параметров — это последовательность объявлений формальных параметров, разделенная запятыми. Формальные парамет- параметры — это переменные, используемые внутри тела функции и получающие значение при вызове функции путем копирования в них значений соот- соответствующих фактических Параметров. Список формальных параметров может заканчиваться запятой (,) или запятой с многоточием (,...). Это означает, что число аргументов функции переменно. Однако предпола- предполагается, что функция имеет, по крайней мере, столько обязательных аргу- аргументов, сколько формальных параметров задано перед последней запя- запятой в списке параметров. Такой функции может быть передано большее число аргументов, но для дополнительных аргументов не проводится контроль типов. Если функция не использует параметров, то наличие круглых скобок обязательно, а вместо списка параметров рекомендуется указать слово void. Порядок и типы формальных параметров должны быть одинаковыми в определении функции и во всех ее объявлениях. Типы фактических пара- параметров при вызове функции должны быть совместимы с типами соответ- соответствующих формальных параметров. Формальный параметр может иметь любой основной тип, а также быть структурой, объединением, перечис- перечислением, указателем или массивом. Параметр, тип которого не указан, считается имеющим тип int. Для формального параметра можно задавать класс памяти register, при этом для величин целого типа спецификатор типа можно опустить. Идентификаторы формальных параметров используются в теле функции в качестве ссылок на переданные при вызове значения. Они не могут быть переопределены в блоке, образующем тело функции, но могут быть переопределены во внутреннем блоке внутри тела функции. Несоответ- Несоответствие типов фактических аргументов и формальных параметров может быть причиной неверной интерпретации.
Язык программирования С-51 389 тело функции — это составной оператор, содержащий операторы, опре- определяющие действие функции. Все переменные, объявленные в теле функции без указания класса памя- памяти, являются локальными. По умолчанию они считаются автоматиче- автоматическими, но могут быть и статическими, если использован модификатор static. При этом значение, записанное в эту переменную, сохраняется даже при выходе из функции и последующем входе в нее. При вызове функции в стандартном языке программирования С автоматическим ло- локальным переменным отводится память в стеке и, если указано, произво- производится их инициализация. В языке программирования С-51 для локальных переменных выделяются ячейки внутренней памяти данных. При этом для различных функций используются одни и те же ячейки памяти. Это сделано из соображений экономии внутренней памяти. Иногда при написании программы требуется вызов функции самой из себя или функция может вызываться из основной программы и подпро- подпрограммы обслуживания прерывания. В стандартном языке программиро- программирования С это не создает проблем, ведь там локальные переменные хранят- хранятся в стеке. В языке программирования С-51 для таких функций следует применять атрибут reentrant. При его использовании локальные пере- переменные будут располагаться в стеке. При этом стек будет размещаться в зависимости от вида принятой для компиляции модели памяти (small, compact, large) в области памяти data, pdata, xdata соответственно. При- Пример ИСПОЛЬЗОВаНИЯ атрибута reentrant: int calc (char i, int b) reentrant { int x; x = table [i]; return (x * b); } При вызове функции производится инициализация локальных перемен- переменных. Затем управление передается первому оператору тела функции и начинается ее выполнение, продолжающееся до тех пор, пока не встре- встретится оператор return или последний оператор тела функции. Управле- Управление при этом возвращается оператору, следующему за точкой вызова, а локальные переменные становятся недоступными. При новом вызове функции для автоматических локальных переменных память распределя- распределяется вновь, и поэтому старые значения таких переменных теряются. Параметры функции могут рассматриваться как локальные переменные, для которых при вызове функции выделяется память и производится инициализация значениями фактических параметров, поэтому в теле функции нельзя изменить значения переменных вызывающей программы путем изменения значений параметров функции. При выходе из функции
390 Глава 9 значения этих переменных теряются. Однако если в качестве параметра передать указатель на некоторую переменную, то в функции можно бу- будет изменить значение этой переменной. Пример попытки неправильного использования параметров функции: /* Неправильное использование параметров */ void change (int х, int у) { int k=x; x=y; y=k; В данной функции значения переменных х и у, являющихся формальны- формальными параметрами, меняются местами, но поскольку эти переменные суще- существуют только внутри функции change, значения фактических парамет- параметров, переданные при вызове функции, останутся неизменными. Для того чтобы менялись местами значения фактических аргументов, нужно ис- использовать функцию, подобную приведенной в следующем примере: /* Правильное использование параметров */ void change (int *x, int *y) { int k=*x; *x=*y; *У=к; } При вызове такой функции в качестве фактических параметров необхо- необходимо использовать не значения переменных, а их адреса, как показано в следующем примере: change (&а,&b); Если требуется вызвать функцию до ее определения в рассматриваемом файле, или с определением, находящимся в другом исходном файле, то необходимо предварительно объявить эту функцию. Прототип — это явное объявление функции, которое предшествует ее определению. Тип возвращаемого значения при объявлении функции должен соответствовать типу возвращаемого значения в ее определении. В отличие от определения функции, в прототипе за заголовком сразу же следует точка с запятой, а тело функции отсутствует. Прототип функции необходимо задавать в следующих случаях: ? Функция возвращает значение типа, отличного от int. ? Требуется проинициализировать некоторый указатель на функцию до того, как эта функция будет определена.
Язык программирования С-51 391 Объявление (запись прототипа) функции производится в следующем формате: [Спецификатор класса памяти] [Спецификатор типа] Имя функции *{ * [Список формальных параметров]' )' [ \ ' Список имен функций]' ;' Если прототип не задан, а встретился вызов функции, то строится неяв- неявный прототип из анализа формы вызова функции. Тип возвращаемого значения создаваемого прототипа — int, а список типов и числа пара- параметров функции формируется на основании типов и числа фактических параметров, используемых при данном вызове. Учитывая, что построенный прототип функции может не совпасть с опре- определением, лучше не надеяться на автоматическое построение прототипа, а объявлять его явным образом. Наличие в прототипе полного списка типов параметров позволяет вы- выполнить проверку соответствия типов фактических параметров при вы- вызове функции типам формальных параметров, и, если необходимо, вы- выполнить соответствующие преобразования. Вызов функции имеет следующий формат: Адресное выражение х ( х [ Список выражений]' )' Поскольку синтаксически имя функции является адресом начала тела функции, в качестве обращения к функции может быть использовано Ад- Адресное выражение (в том числе и имя функции или разадресация указате- указателя на функцию), имеющее значение адреса функции. список выражений представляет собой список фактических параметров, передаваемых в функцию. Этот список может быть и пустым, но наличие круглых скобок обязательно. Фактический параметр может быть величиной любого основного типа, структурой, объединением, перечислением или указателем на объект лю- любого типа. Массив и функция не могут быть использованы в качестве фактических параметров, но можно использовать указатели на эти объ- объекты. Выполнение вызова функции происходит следующим образом: 1. Вычисляются выражения в списке выражений и подвергаются обыч- обычным арифметическим преобразованиям. Затем, если известен прото- прототип функции, тип полученного значения сравнивается с типом соот- соответствующего формального параметра. Если они не совпадают, то либо производится преобразование типов, либо формируется сооб- сообщение об ошибке. Число выражений в списке должно совпадать с чис- числом формальных параметров, если только функция не имеет перемен- переменного числа параметров. В последнем случае проверке подлежат только обязательные параметры. Если в прототипе функции указано,
392 Глава 9 что ей не требуются параметры, а при вызове они указаны, формиру- формируется сообщение об ошибке. 2. Происходит присваивание значений фактических параметров соответ- соответствующим формальным параметрам. 3. Управление передается на первый оператор функции. 4. Выполнение оператора return в теле функции возвращает управление и, возможно, значение в вызывающую функцию. При отсутствии опе- оператора return управление возвращается после выполнения последнего оператора тела функции, а возвращаемое значение не определено. Адресное выражение, стоящее перед скобками, определяет адрес вызывае- вызываемой функции. Это значит, что функция может быть вызвана через указа- указатель на функцию. Пример объявления переменной указателя на функцию: int (*fun)(int x, int *y); Здесь объявлена переменная fun как указатель на функцию с двумя пара- параметрами типа int и указателем на int. Сама функция должна возвращать значение типа int. Круглые скобки, содержащие имя указателя fun и при- признак указателя *, обязательны, иначе запись int *fun (intx, int *y); будет интерпретироваться как объявление функции fun, возвращающей указатель на int. Вызов функции при помощи указателя fun возможен только после ини- инициализации этого указателя. Вызов самой функции при этом будет вы- выглядеть следующим образом: (*fun)(i,&j); В этом выражении для получения адреса функции, на которую ссылается указатель fun, используется операция *. Указатель на функцию может быть передан в качестве параметра функ- функции. При этом разадресация происходит во время вызова функции, на которую ссылается указатель на функцию. Присвоить значение указате- указателю на функцию можно в операторе присваивания, употребив имя функ- функции без списка параметров. Пример: double (*funl)(int х, int у); double fun2(int k, int 1); funl=fun2; • /* инициализация указателя на функцию */ (*funl) B,7); /* обращение к функции */
Язык программирования С-51 393 В рассмотренном примере указатель на функцию funi описан как указа- указатель на функцию с двумя параметрами, возвращающую значение типа double, и также описана функция fun2. В противном случае т. е. когда указателю на функцию присваивается адрес функции, описание которой отличается от описания указателя, произойдет ошибка. Рассмотрим пример использования указателя на функцию в качестве па- параметра функции, вычисляющей производную от cos(x). double proiz(double x, double dx, double (*f)(double x) ); double fun(double z); int main() точка вычисления производной */ приращение */ значение производной */ ввод значений х и dx */ вызов функции */ печать значения производной */ double double double scanf( z=proi printf return it z ( x; dx z; %f (x 11 % 0; • f , %f" , dx, f",z ,&x,&dx); fun) ; ); /* /* /* /* /* /* double proiz(double x,double dx, double (*f)(double z) ) { /* функция, вычисляющая производную */ double xk,xkl,pr; xk=fun(x); xkl=fun(x+dx) ; pr=(xkl/xk-leO)*xk/dx; return pr; } double fun( double z) { /* функция, от которой вычисляется производная */ return (cos(z)); Итак, подведем итоги В данной главе было приведено краткое описание языка программиро- программирования С-51. Использование этого языка позволяет сократить время раз- разработки программ для микроконтроллеров. В большинстве случаев ре- 14 3ак. 328
394 Глава 9 сурсов выбранного микроконтроллера более чем достаточно для реали- реализации требуемого алгоритма. Это позволяет использовать для создания программы язык С-51. В главе показаны примеры использования С-51 для управления микроконтроллером. Этот язык позволяет создавать достаточно сложные программы при минимальных затратах времени. Однако следует помнить, что ничего не бывает бесплатно. Избавляя от одних проблем, язык программирования С-51 приводит к другим. Как это неоднократно подчеркивалось в тексте главы, при программирова- программировании на языке С-51 необходимо чрезвычайно тщательно выбирать типы используемых переменных и следить за их правильным использованием. При неправильном выборе типов можно значительно увеличить объем программы и снизить ее быстродействие по сравнению с программой, написанной на языке программирования ассемблер. Ну, вот мы и закончили краткое рассмотрения принципов работы с мик- микроконтроллерами. Надеюсь, что эта книга поможет вам начать работать с этими устройствами, получившими широчайшее распространение в на- настоящее время. Принципы работы с микроконтроллерами различных ти- типов практически не отличаются от рассмотренного в данной книге MCS- 51, поэтому, я думаю, вы легко сможете применить знания, полученные из этой книги, для разработки устройств на любых контроллерах.
Приложение Справочные данные по системе команд микроконтроллера MCS-51 и кодировке символов Таблица П1. Машинные команды, влияющие на значения флагов регистра PSW Мнемоника 4 ADD ADDC SUBB MUL DIV DA RRC RLC SETB С Флаги С + + + 0 0 + + + 1 ov + + + + + AC + + + Мнемоника CLR С CPL С ANL С, bit ANL С, /bit ORL C, bit ORL C, /bit MOV C, bit CJNE Флаги С 0 + + + + + + OV AC
396 Приложение Таблица П2. Обозначения и символы, используемые при описании команд Обозначение А Rn R direct @Ri data 8 data 16 data H data L adr 11 adr 16 adr L rel bit Назначение Аккумулятор Регистры текущего выбранного банка регистров Номер загружаемого регистра, указанного в команде Прямо адресуемая 8-битная ячейка памяти данных Косвенно адресуемая 8-битная ячейка внутреннего ОЗУ данных 8-битная константа, входящая в код операции (КОП) 16-битная константа, входящая в код операции (КОП) Старшие биты A5—8) 16-битной константы Младшие биты G—0) 16-битной константы Младшие 11 битов адреса Полный 16-битный адрес Младшие биты адреса Байт смещения с учетом знака Адрес бита Таблица ПЗ. Перечень команд микроконтроллеров семейства MCS-51 НЕХ- код 00 01 02 03 04 05 Об Число байт 1 2 3 1 1 2 1 Число циклов 1 2 2 1 1 1 1 Мнемокод NOP AJMP LJMP RR INC INC INC Операнды code addr @ стр) code addr А А data addr @R0 Описание команды Нет операции Безусловный переход в пределах 2 Кбайт Безусловный переход в пределах 64 Кбайт Циклический сдвиг вправо АСС <- АСС + 1 data <- data + 1 (R0) <- (R0) + 1
Справочные данные по системе команд микроконтроллера MCS-51... 397 Таблица ПЗ (продолжение) HEX- код 07 08 09 0А ОВ ОС 0D ОЕ OF 10 11 12 13 14 15 16 17 18 19 1А 1В 1С 1D 1Е 1F Число байт 1 1 1 1 1 1 1 1 1 3 2 3 1 1 2 1 1 1 1 1 1 1 1 1 1 Число циклов 1 1 1 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 Мнемокод INC INC INC INC INC INC INC INC INC JBC ACALL LCALL RRC DEC DEC DEC DEC DEC DEC DEC DEC DEC DEC DEC DEC Операнды em RO R1 R2 R3 R4 R5 R6 R7 bitaddr, codeaddr codeaddr @ стр) Dataaddr A A dataaddr @R0 em RO R1 R2 R3 R4 R5 R6 R7 Описание команды (R1)<-(R1) + 1 RO <- RO + 1 R1 <-R1 + 1 R2 <- R2 + 1 R3 <- R3 + 1 R4 <- R4 + 1 R5 <- R5 + 1 R6 <- R6 + 1 R7 <- R7 + 1 Условный переход, если бит = 1 и сброс бита Вызов подпрограммы в пределах 2 Кбайт Вызов подпрограммы в пределах 64 Кбайт Циклический сдвиг впра- вправо через флаг С АСС <- АСС - 1 data <- data - 1 (RO) <- (RO) - 1 (R1)<-(R1)-1 RO <- RO - 1 R1 <-R1 -1 R2 <- R2 - 1 R3 <- R3 - 1 R4 <- R4 - 1 R5 <- R5 - 1 R6 <- R6 - 1 R7 <- R7 - 1
398 Приложение Таблица ПЗ (продолжение) НЕХ- код 20 21 22 23 24 25 26 27 28 29 2А 2В 2С 2D 2Е 2F 30 31 32 33 34 35 36 Число байт 3 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 3 2 1 1 2 2 1 Число циклов 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 1 1 1 1 Мнемокод JB AJMP RET RL ADD ADD ADD ADD ADD ADD ADD ADD ADD ADD ADD ADD JNB ACALL RETI RLC ADDC ADDC ADDC Операнды bit addr, data addr code addr Остр) A A, #data A, data addr A, @R0 A, ©R1 A, RO A, R1 A, R2 A, R3 A, R4 A, R5 A, R6 A, R7 bltaddr, codeaddr codeaddr d стр) A A, #data A, dataaddr A, @R0 Описание команды Условный переход, если бит= 1 Безусловный переход в пределах 2 Кбайт Возвращение из подпро- подпрограммы Циклический сдвиг влево АСС <- АСС + число АСС «- АСС + data АСС <- АСС + (R0) ACC<-ACC + (R1) АСС <- АСС + R0 АСС <- АСС + R1 АСС <- АСС + R2 АСС <- АСС + R3 АСС <- АСС + R4 АСС <- АСС + R5 АСС <- АСС + R6 АСС <- АСС + R7 Условный переход, если бит = 0 Вызов подпрограммы в пределах 2 Кбайт Возврат из подпрограм- подпрограммы обслуживания преры- прерывания Циклический сдвиг влево через флаг С АСС <- АСС + число + С АСС <- АСС + data + С АСС <- АСС + (R0) + С
Справочные данные по системе команд микроконтроллера MCS-51... 399 Таблица ПЗ (продолжение) НЕХ- код 37 38 39 ЗА ЗВ ЗС 3D ЗЕ 3F 40 41 42 43 44 45 46 47 48 49 4А 4В 4С 4D 4Е 4F Число байт 1 1 1 1 1 1 1 1 1 2 2 2 3 2 2 1 1 1 1 1 1 1 1 1 1 Число циклов 1 1 1 1 1 1 1 1 1 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 Мнемокод ADDC ADDC ADDC ADDC ADDC ADDC ADDC ADDC ADDC JC AJMP ORL ORL ORL ORL ORL ORL ORL ORL ORL ORL ORL ORL ORL ORL Операнды a, em A, R0 A, R1 A, R2 A, R3 A, R4 A, R5 A, R6 A, R7 codeaddr codeaddr B стр) dataaddr, A dataaddr, #data A, #data A, data addr A, @R0 A, @R1 A, RO A, R1 A, R2 A,R3 A,R4 A, R5 A.R6 A, R7 Описание команды ACC*-ACC + (R1) + C ACC <- ACC + R0+ С ACC*-ACC + R1+C ACC <r- ACC + R2+ С ACC <- ACC + R3+ С ACC *- ACC + R4+ С ACC *- ACC + R5+ С ACC *- ACC + R6+ С ACC *- ACC + R7+ С Условный переход, если флаг С = 1 Безусловный переход в пределах 2 Кбайт data <r- data | ACC data <- data | число ACC <- ACC | число ACC <- ACC | data ACC *- ACC | (RO) ACC«-ACC|(R1) ACC *- ACC | RO ACC *- ACC | R1 ACC *- ACC | R2 ACC *- ACC | R3 ACC *- ACC | R4 ACC *- ACC | R5 ACC *- ACC | R6 ACC <- ACC | R7
400 Приложение Таблица ПЗ (продолжение) НЕХ- код 50 51 52 53 54 55 56 57 58 59 5А 5В 5С 5D 5Е 5F 60 61 62 63 64 65 66 67 Число байт 2 2 2 3 2 2 1 1 1 1 1 1 1 1 1 1 2 2 2 3 2 2 1 1 Число циклов 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 1 1 1 1 Мнемокод JNC ACALL ANL ANL ANL ANL ANL ANL ANL ANL ANL ANL ANL ANL ANL ANL JZ AJMP XRL XRL XRL XRL XRL XRL Операнды code addr code addr B стр) data addr, A data addr, #data A, #data A, data addr A, @R0 a, em A, RO A, R1 A, R2 A, R3 A, R4 A, R5 A, R6 A, R7 codeaddr codeaddr C стр) dataaddr, A dataaddr, #data A, #data A, data addr A,@R0 A,@R1 Описание команды Условный переход, если флаг С = 0 Вызов подпрограммы в пределах 2 Кбайт data <- data & АСС data <- data & число АСС <- АСС & число АСС <- АСС & data АСС <- АСС & (R0) ACC<-ACC&(R1) АСС <- АСС & R0 АСС <- АСС & R1 АСС <- АСС & R2 АСС <- АСС & R3 АСС <- АСС & R4 АСС <- АСС & R5 АСС <- АСС & R6 АСС <- АСС & R7 Если АСС = 0, то PC = = codeaddr, иначе PC + 2 Безусловный переход в пределах 2 Кбайт data <- data 0 АСС data <- data © число АСС <- АСС 0 число АСС <- АСС © data АСС <- АСС © (data) АСС <- АСС © (data)
Справочные данные по системе команд микроконтроллера MCS-51... 401 Таблица ПЗ (продолжение) НЕХ- код 68 69 6А 6В 6С 6D 6Е 6F 70 71 72 73 74 75 76 77 78 79 7А 7В 70 7D 7Е 7F Число байт 1 1 1 1 1 1 1 1 2 2 2 1 2 3 2 2 2 2 2 2 2 2 2 2 Число циклов 1 1 1 1 1 1 1 1 2 2 2 1 2 1 1 2 2 2 2 2 2 2 2 Мнемокод XRL XRL XRL XRL XRL XRL XRL XRL JNZ ACALL ORL JMP MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV Операнды A, R0 A, R1 A, R2 A, R3 A, R4 A, R5 A, R6 A, R7 codeaddr codeaddr C стр) С, bitaddr ©A+DPTR A, #data dataaddr, #data @R0, #data @R1, #data R0, #data R1,#data R2, #data R3, #data R4, #data R5, #data R6, #data R7, #data Описание команды ACC <- ACC 0 R0 ACC <- ACC Ф R1 ACC <- ACC 0 R2 ACC <- ACC 0 R3 ACC <- ACC 0 R4 ACC <- ACC 0 R5 ACC <- ACC 0 R6 ACC <- ACC 0 R7 Если ACC Ф 0, то PC = = codeaddr, иначе PC + 2 Вызов подпрограммы в пределах 2 Кбайт С <- С | bit Безусловный переход (PC = А + DPTR) АСС <- число data <- число (data) <— число (data) <- число R0 <- число R1 <- число R2 <- число R3 <— число R4 <— число R5 <- число R6 <— число R7 <- число
402 Приложение Таблица ПЗ (продолжение) НЕХ- код 80 81 82 83 84 85 86 87 88 89 8А 8В 8С 8D 8Е 8F 90 91 92 Число байт 2 2 2 1 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 Число циклов 2 2 2 2 4 2 2 2 2 2 2 2 2 2 2 2 2 2 Мнемокод SJMP AJMP ANL MOVC DIV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV ACALL MOV Операнды codeaddr codeaddr D стр) С, bitaddr А, @А+РС АВ dataaddri, dataaddr2 dataaddr, dataaddr, Dataaddr, R0 Dataaddr, R1 Dataaddr, R2 Dataaddr, R3 Dataaddr, R4 Dataaddr, R5 Dataaddr, R6 Dataaddr, R7 DPTR, #data codeaddr D стр) bitaddr, С Описание команды Безусловный переход в пределах ±127 байт Безусловный переход в пределах 2 Кбайт С <- С & bit АСС <r- (А+РС) А *- А/В, В *- А%В datai <- data2 data <- (data) data <- (data) data <- RO data <- RO data <- RO data <- RO data <- RO data <- RO data <- RO data <- RO DPTR <- число Вызов подпрограммы в пределах 2 Кбайт bit*-С
Справочные данные по системе команд микроконтроллера MCS-51... 403 Таблица ПЗ (продолжение) НЕХ- код 93 94 95 96 97 98 99 9А 9В 9С 9D 9Е 9F АО А1 А2 A3 А4 А5 А6 А7 А8 А9 АА АВ Число байт 1 2 2 1 1 1 1 1 1 1 1 1 1 2 2 2 1 1 Число циклов 2 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 4 Мнемокод MOVC SUBB SUBB SUBB SUBB SUBB SUBB SUBB SUBB SUBB SUBB SUBB SUBB ORL AJMP MOV INC MUL Операнды A, @A+DPTR A, #data A, dataaddr A, @R0 A, @R1 A, RO A, R1 A, R2 A.R3 A, R4 A, R5 A, R6 A, R7 C, /bitaddr codeaddr E стр) С, bitaddr DPTR AB Описание команды ACC <r- (A+DPTR) ACC <- ACC - число ACC <- ACC - data ACC <r- ACC - (data) ACC <r- ACC - (data) ACC <r- ACC - RO ACC <r- ACC - R1 ACC <r- ACC - R2 ACC <r- ACC - R3 ACC <r- ACC - R4 ACC <r- ACC - R5 ACC <r- ACC - R6 ACC <r- ACC - R7 С <r- С | not(bit) Безусловный переход в пределах 2 Кбайт С*-bit DPTR <r- DPTR+1 A *- A * В, В *- A * В Зарезервировано 2 2 2 2 2 2 2 2 2 2 2 2 MOV MOV MOV MOV MOV MOV dataaddr @R1, dataaddr RO, dataaddr R1, dataaddr R2, dataaddr R3, dataaddr (RO) <r- data (R1)*-data RO <- data R1 <- data R2 <- data R3 <- data
404 Приложение Таблица ПЗ (продолжение) НЕХ- код АС AD АЕ AF ВО В1 В2 ВЗ В4 В5 Вб В7 В8 В9 ВА ВВ ВС BD BE BF Число байт 2 2 2 2 2 2 2 1 3 3 3 3 3 3 3 3 3 3 3 3 Число циклов 2 2 2 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 Мнемокод MOV MOV MOV MOV ANL ACALL CPL CPL CJNE CJNE CJNE CJNE CJNE CJNE CJNE CJNE CJNE CJNE CJNE CJNE Операнды R4, dataaddr R5, dataaddr R6, dataaddr R7, dataaddr C, /bltaddr codeaddr bitaddr С A, #data, codeaddr A, dataaddr, codeaddr @R0, #data, codeaddr @R1, #data, codeaddr RO, #data, codeaddr R1,#data, codeaddr R2, #data, code addr R3, #data, code addr R4, #data, code addr R5, #data, code addr R6, #data, code addr R7, #data, code addr Описание команды R4 <- data R5 <- data R6 <- data R7 <- data С <- С & not(blt) Вызов подпрограммы в пределах 2 Кбайт bit <- not(bit) С <- not(C) Условный переход, если АСС Ф числу Условный переход, если АСС Ф data Условный переход, если (R0) Ф числу Условный переход, если (R1) Ф числу Условный переход, если R0 Ф числу Условный переход, если R1 Ф числу Условный переход, если R2 Ф числу Условный переход, если R3 Ф числу Условный переход, если R4 Ф числу Условный переход, если R5 Ф числу Условный переход, если R6 Ф числу Условный переход, если R7 Ф числу
Справочные данные по системе команд микроконтроллера MCS-51... 405 Таблица ПЗ (продолжение) НЕХ- код СО С1 С2 СЗ С4 С5 Сб С7 С8 С9 СА СВ СС CD СЕ CF DO D1 D2 D3 D4 D5 Число байт 2 2 2 1 1 2 1 1 1 1 1 1 1 1 1 1 2 2 2 1 1 3 Число циклов 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 2 Мнемокод PUSH AJMP CLR CLR SWAP ХСН ХСН ХСН ХСН ХСН ХСН ХСН ХСН ХСН ХСН ХСН POP ACALL SETB SETB DA DJNZ Операнды dataaddr code addr F стр) bitaddr С A A, dataaddr A, @R0 A,@R1 A, RO A, R1 A, R2 A, R3 A, R4 A, R5 A, R6 A, R7 dataaddr codeaddr F стр) bitaddr С A dataaddr, codeaddr Описание команды Сохранить ячейку памяти в стеке Безусловный переход в пределах 2 Кбайт bit <— 0 С<-0 АСС.З.. АСС.О <-> АСС.7.. АСС.4 АСС <-> data АСС <-> (R0) ACC<->(R1) АСС <-> R0 АСС <-> R1 АСС <-> R2 АСС <-> R3 АСС <-> R4 АСС <-> R5 АСС <-> R6 АСС <-> R7 Извлечь содержимое стека в ячейку памяти Вызов подпрограммы в пределах 2 Кбайт bit <— 1 С<-1 Десятичная коррекция аккумулятора data <- data - 1; если data Ф 0, то PC <r- codeaddr
406 Приложение Таблица ПЗ (продолжение) НЕХ- код D6 D7 D8 D9 DA DB DC DD DE DF ЕО Е1 Е2 ЕЗ Е4 Е5 Еб Е7 Е8 Число байт 1 1 2 2 2 2 2 2 2 2 1 2 1 1 1 2 1 1 1 Число циклов 1 1 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 Мнемокод XCHD XCHD DJNZ DJNZ DJNZ DJNZ DJNZ DJNZ DJNZ DJNZ MOVX AJMP MOVX MOVX CLR MOV MOV MOV MOV Операнды A, @R0 A, @R1 RO, codeaddr R1, codeaddr R2, codeaddr R3, codeaddr R4, codeaddr R5, codeaddr R6, codeaddr R7, codeaddr A, @DPTR codeaddr G стр) A, @R0 A,@R1 A A, dataaddr A, @R0 A, @R1 A, RO Описание команды АСС.З.. АСС.О <-> (R0.3.. R0.0) АСС.З.. АСС.О <->(R1.3.. R1.0) R0<-R0-1; если R0*0, то PC = codeaddr R1 <-R1 -1;ecnnR1 *0, то PC = codeaddr R2 <- R2 - 1; если R2 * 0, то PC = codeaddr R3 <- R3 - 1; если R3 Ф 0 то PC = codeaddr R4 <_ R4 - 1; если R4 Ф 0, то PC = codeaddr R5 <r- R5 - 1; если R5 Ф 0, то PC = codeaddr R6 <r- R6 - 1; если R6 Ф 0, то PC = codeaddr R7<- R7-1; если R7 * 0, то PC = codeaddr ACC <r- data из внешней памяти Безусловный переход в пределах 2 Кбайт АСС <- data из внешней памяти АСС <r- data из внешней памяти АСС<-0 АСС <r- data АСС <- (R0) ACC<-(R1) АСС 4- R0
Справочные данные по системе команд микроконтроллера MCS-51... 407 Таблица ПЗ (окончание) НЕХ- код Е9 ЕА ЕВ ЕС ED ЕЕ EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF Число байт 1 1 1 1 1 1 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 Число циклов 1 1 1 1 1 1 1 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 Мнемокод MOV MOV MOV MOV MOV MOV MOV MOVX ACALL MOVX MOVX CPL MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV Операнды A, R1 A, R2 A, R3 A, R4 A, R5 A, R6 A, R7 @DPTR, A codeaddr G стр) @R0, A @R1, A А dataaddr, A @R0, A @R1, A R0, А R1.A R2, А R3, А R4, А R5, А R6, А R7, А Описание команды АСС <- R1 АСС <- R2 АСС <- R3 АСС <- R4 АСС <- R5 АСС <- R6 АСС <- R7 data внешней памяти <- АСС Вызов подпрограммы в пределах 2 Кбайт (R0) <- АСС (R1)«-ACC АСС <- not(ACC) Data*- АСС data внешней памяти <- АСС data внешней памяти <- АСС R0 <- АСС R1 <-АСС R2 <- АСС R3 <- АСС R4 <_ АСС R5 <- АСС R6 <- АСС R7 <- АСС
408 Приложение Таблица П4. Таблица ASCII-кодов Десятич- Десятичный код 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Шестнадцате- ричный код 00 01 02 03 04 05 06 07 08 09 0А ОВ ОС 0D ОЕ OF 10 11 12 13 14 15 16 17 18 19 1А 1В Отображаемый символ © • ¦ • о о ¦ 9 : & > г и • • И § — т — Значение NUL SOH (слово управления дисплеем) STX (первое передаваемое слово) ЕТХ (последнее слово передачи) EOT (конец передачи) ENO (инициализация) АСК (подтверждение приема) BEL (звуковой сигнал) BS НТ (горизонтальная табуляция) LF (перевод строки) VT (вертикальная табуляция) FF (следующая страница) CR (возврат каретки) SO (двойная ширина) SI (уплотненная печать) DLE DC1 DC2 (отмена уплотненной печати) DC3 (готовность) DC4 (отмена двойной ширины) NAC (неподтверждение приема) SYN ЕТВ CAN ЕМ SUB ESC (начало управляющей последо- последовательности)
Справочные данные по системе команд микроконтроллера MCS-51... 409 Таблица П4 (продолжение) Десятич- Десятичный код 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 Шестнадцате- ричный код 1С 1D 1Е 1F 20 21 22 23 24 25 26 27 28 29 2А 2В 2С 2D 2Е 2F 30 31 32 33 34 35 36 37 Отображаемый символ L «—> А Т ! « # $ % & i ( ) + - ¦ / 0 1 2 3 4 5 6 7 Значение FS GS RS US Пробел Восклицательный знак Кавычки (двойные) Знак номера Знак денежной единицы (доллар) Знак процента Амперсанд Апостроф Левая круглая скобка Правая круглая скобка Звездочка Знак плюс Запятая Знак минус, дефис Точка Дробная черта Цифра ноль Цифра один Цифра два Цифра три Цифра четыре Цифра пять Цифра шесть Цифра семь
410 Приложение Таблица П4 (продолжение) Десятич- Десятичный код 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 Шестнадцате- ричный код 38 39 ЗА ЗВ ЗС 3D ЗЕ 3F 40 41 42 43 44 45 46 47 48 49 4А 4В 4С 4D 4Е 4F 50 51 52 53 Отображаемый символ 8 9 • • • < = > ? 9 А В С D Е F G Н 1 J К L М N О Р Q R S Значение Цифра восемь Цифра девять Двоеточие Точка с запятой Знак меньше Знак равно Знак больше Знак вопрос Коммерческое эт Прописная латинская буква А Прописная латинская буква В Прописная латинская буква С Прописная латинская буква D Прописная латинская буква Е Прописная латинская буква F Прописная латинская буква G Прописная латинская буква Н Прописная латинская буква 1 Прописная латинская буква J Прописная латинская буква К Прописная латинская буква L Прописная латинская буква М Прописная латинская буква N Прописная латинская буква О Прописная латинская буква Р Прописная латинская буква Q Прописная латинская буква R Прописная латинская буква S
Справочные данные по системе команд микроконтроллера MCS-51... 411 Таблица П4 (продолжение) Десятич- Десятичный код 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 Шестнадцате- ричный код 54 55 56 57 58 59 5А 5В 5С 5D 5Е 5F 60 61 62 63 64 65 66 67 68 69 6А 6В 6С 6D 6Е 6F Отображаемый символ Т и V W X Y Z [ \ ] Л \ а b с d е f g h • • k I m n 0 Значение Прописная латинская буква Т Прописная латинская буква U Прописная латинская буква V Прописная латинская буква W Прописная латинская буква X Прописная латинская буква Y Прописная латинская буква Z Левая квадратная скобка Обратная черта Правая квадратная скобка "Крылечка" Символ подчеркивания Обратный апостроф Строчная латинская буква а Строчная латинская буква b Строчная латинская буква с Строчная латинская буква d Строчная латинская буква е Строчная латинская буква f Строчная латинская буква g Строчная латинская буква h Строчная латинская буква i Строчная латинская буква j Строчная латинская буква к Строчная латинская буква I Строчная латинская буква m Строчная латинская буква п Строчная латинская буква о
412 Приложение Таблица П4 (продолжение) Десятич- Десятичный код 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 Шестнадцате- ричный код 70 71 72 73 74 75 76 77 78 79 7А 7В 7С 7D 7Е 7F 80 81 82 83 84 85 86 87 88 89 8А 8В Отображаемый символ Р q г S t U V W X У Z { I } А Б В Г Д Е Ж 3 И и к л Значение Строчная латинская буква р Строчная латинская буква q Строчная латинская буква г Строчная латинская буква s Строчная латинская буква t Строчная латинская буква и Строчная латинская буква v Строчная латинская буква w Строчная латинская буква х Строчная латинская буква у Строчная латинская буква z Левая фигурная скобка Вертикальная черта Правая фигурная скобка Тильда Знак стирания Прописная русская буква А Прописная русская буква Б Прописная русская буква В Прописная русская буква Г Прописная русская буква Д Прописная русская буква Е Прописная русская буква Ж Прописная русская буква 3 Прописная русская буква И Прописная русская буква Й Прописная русская буква К Прописная русская буква Л
Справочные данные по системе команд микроконтроллера MCS-51... 413 Таблица П4 (продолжение) Десятич- Десятичный код 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 Шестнадцате- ричный код 8С 8D 8Е 8F 90 91 92 93 94 95 96 97 98 99 9А 9В 9С 9D 9Е 9F АО А1 А2 A3 А4 А5 А6 Отображаемый символ М Н О п р с т У ф X Ц ч ш щ ъ ы ь э ю я а б в г Д е ж Значение Прописная русская буква М Прописная русская буква Н Прописная русская буква О Прописная русская буква П Прописная русская буква Р Прописная русская буква С Прописная русская буква Т Прописная русская буква У Прописная русская буква Ф Прописная русская буква X Прописная русская буква Ц Прописная русская буква Ч Прописная русская буква Ш Прописная русская буква Щ Прописная русская буква Ъ Прописная русская буква Ы Прописная русская буква Ь Прописная русская буква Э Прописная русская буква Ю Прописная русская буква Я Строчная русская буква а Строчная русская буква б Строчная русская буква в Строчная русская буква г Строчная русская буква д Строчная русская буква е Строчная русская буква ж
474 Приложение Таблица П4 (продолжение) Десятич- Десятичный код 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 Шестнадцате- ричный код А7 А8 А9 АА АВ АС AD АЕ AF ВО В1 В2 ВЗ В4 В5 Вб В7 В8 В9 ВА ВВ ВС BD BE BF СО С1 Отображаемый символ 3 и И к л м н 0 п Ш I I ^ II JJ л 1 L X Значение Строчная русская буква з Строчная русская буква и Строчная русская буква й Строчная русская буква к Строчная русская буква л Строчная русская буква м Строчная русская буква н Строчная русская буква о Строчная русская буква п Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики
Справочные данные по системе команд микроконтроллера MCS-51... 415 Таблица П4 (продолжение) Десятич- Десятичный код 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 Шестнадцате- ричный код С2 СЗ С4 С5 С6 С7 С8 С9 СА СВ СС CD СЕ CF DO D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC Отображаемый символ т — + It- Ik If =!l 1Г = JL 1Г _L JL T T IL F IT 1 + J Г 1 ¦ Значение Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики Символ псевдографики
416 Приложение Таблица П4 (продолжение) Десятич- Десятичный код 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 Шестнадцате- ричный код DD DE DF Е0 Е1 Е2 ЕЗ Е4 Е5 Е6 Е7 Е8 Е9 ЕА ЕВ ЕС ED ЕЕ EF F0 F1 F2 F3 F4 F5 F6 F7 Отображаемый символ 1 1 ¦ Р с т У Ф X Ц ч ш Щ ъ ы ь э ю я Ё ё е с Т Т 9 У Значение Символ псевдографики Символ псевдографики Символ псевдографики Строчная русская буква р Строчная русская буква с Строчная русская буква т Строчная русская буква у Строчная русская буква ф Строчная русская буква х Строчная русская буква ц Строчная русская буква ч Строчная русская буква ш Строчная русская буква щ Строчная русская буква ъ Строчная русская буква ы Строчная русская буква ь Строчная русская буква э Строчная русская буква ю Строчная русская буква я Прописная русская буква ё Строчная русская буква ё Прописная буква € Строчная буква е Прописная буква 1 Строчная буква 1 Прописная буква У Строчная буква у
Справочные данные по системе команд микроконтроллера MCS-51... 417 Таблица П4 (окончание) Десятич- Десятичный код 248 249 250 251 252 253 254 255 Шестнадцате- ричный код F8 F9 FA FB FC FD FE FF Отображаемый символ о • • № а ¦ Значение Знак градуса Булит (маркер абзаца) Знак умножения (точка в середине строки по высоте) Радикал (взятие корня) Знак номера Знак денежной единицы Символ псевдографики Неразрывный пробел
Литература 1. Угрюмов Е. П. Цифровая схемотехника. — СПб.: БХВ-Петербург, 2001. —528 с. 2. Путков В. Н. и др. Электронные вычислительные устройства: Учеб. пособие для радиотехнич. спец. вузов / В. Н. Путков, И. И. Обросов, С. В. Бекетов. — Мн.: Высш. школа, 1981. — 333 с. 3. Цифровая и вычислительная техника: Учебник для вузов / Э. В. Ев- реинов и др.; Под ред. Евреинова Э. В. — М.: Р и С, 1991. — 464 с. 4. Каган Б. М. ЭВМ и системы. — 1991. — 592 с. 5. Гольденберг Л. М. и др. Цифровые устройства и микропроцессорные системы. Задачи и упражнения: Учеб. пособие для вузов / Л. М. Голь- Гольденберг, В. А. Малеев, Г. Б. Малько. — М.: Р и С, 1992. — 256 с. 6. Пухальский Г. Я., Новосельцева Т. Я. Проектирование дискретных устройств на интегральных микросхемах: Справочник. — М.: Р и С, 1990. —304 с. 7. Зельдин Е. А. Цифровые интегральные микросхемы в информацион- информационно-измерительной аппаратуре. — Л.: Энергоатомиздат, 1986. — 280 с. 8. Цифровые интегральные микросхемы: Справочник / П. П. Мальцев, Н. С. Долидзе, М. И. Кратенко и др. — М.: Р и С, 1994. — 240 с. 9. Шило В. Л. Популярные цифровые микросхемы: Справочник. — М.: РиС, 1987.— 352 с. 10. ГОСТ 2.743-91. Обозначения условные графические в схемах. Эле- Элементы цифровой техники. 11. Титце У., Шенк К. Полупроводниковая схемотехника. — М.: Мир, 1983. 12. Майоров С. А., Кириллов В. В., Приблуда А. А. Введение в микро- ЭВМ— Л.: Машиностроение, 1988. 13. Рафикумазан М. Микропроцессоры и машинное проектирование микропроцессорных систем. — М.: Мир, 1988.
419 14. Уинн Л., Рош. Библия по техническому обеспечению Уинна Роша: Пер. с англ. — Минск: Динамо, 1992. 15. Джордейн Р. Справочник программиста персональных компьютеров IBM PC, XT и AT. — М.: Финансы и статистика, 1992. 16. Гук М. Аппаратные средства IBM PC. — СПб.: Нева, 1998. 17. Гук М. Аппаратные интерфейсы ПК. Энциклопедия. — СПб.: Питер, 2003. — 528 с. 18. Бабаян Б., Ким А., Сахин Ю. Отечественные универсальные микро- микропроцессоры серии «МЦСТ-R» // ЭЛЕКТРОНИКА: Наука. Техноло- Технология. Бизнес, 3 / 2003. 19. Atmel Corporation, at89s51 DATA SHEETS, rev. 2487A-10/01. 20. Atmel Corporation, at89c51rb2 DATA SHEETS, rev. 4105C — 8051- 02/02. 21. Dallas Semiconductor, DS87C550 DATA SHEETS, rev. 091698 1/47.
Предметный указатель 8 8-разрядные микроконтроллеры 140 А, В, С, D ASM-51 267 BEDO 69 CISC-процессоры 91 D-триггер с управлением по фронту 56 Е EDO 68 EXTRN 239 R RISC-процессоры 91 RS-триггер 52 SCON 187 SDRAM 69 SPI-интерфейс 130 T,Z TCON 181 Z-состояние 37 F,I,P FPM68 РС-интерфейс 131 PUBLIC 239 Абсолютный сегмент 302 Адресное выражение 392 Адресное пространство 109, 111 Аккумулятор 146 Аккумуляторные микропроцессоры 92 АЛУ86 Альтернативные функции 161 Аппаратный стек 208 Арифметико-логический блок 145 Арифметико-логическое устройство 87 Арифметические команды 148 Арифметические операции 275 Архитектура семейства MCS-51 142 Архитектура фон Неймана 92 Асинхронный последовательный порт 131 Асинхронный режим 192 Беззнаковые двоичные коды 74 Битовая адресация 171 Битовые команды 150 Битовые поля 344 Блок инверторов 21 Блок микропрограммного управления 94,97 Блок управления и синхронизации 143 БМУ97 В Векторы прерывания 166 Вершина стека 208 Виды адресации операндов 154 Внешнее устройство 119 Внешняя память данных 167
Предметный указатель 421 Внутренние таймеры микроконтроллера 173 Внутренняя память данных 169 Внутрисхемный эмулятор 313 Восьмеричная константа 324 Восьмеричное число 275 Вспомогательные слова 274 Встроенные имена 274 Выбор кристалла 43, 62 Вызов функции 351, 391 Выражение выбора элемента 353 Выражения 349 Вычитатель 87 Вычитающие таймеры 135 Гарвардская архитектура 92 Глобальные переменные 210 Глубина стека 208 Говорящие имена переменных 216 Д Двоично-десятичные коды 84 Двоичное число 275 Двоичные коды с плавающей запятой 81 Двоичные коды с фиксированной запятой 80 Демультиплексор 33 Десятичная константа 324 Десятичная коррекция 85 Десятичное число 275 Дешифратор 28 Диапазон доступных адресов микропроцессора 109 Динамическое ОЗУ 65 Директивы 273 bseg 302 cseg 303 db279 dseg 303 dw281 equ 278 extrn 299 include 231 iseg 304 org 282 public 299 rseg 305 segment 305 set 279 using 283 xseg 304 Диспетчер памяти 112 Дно стека 208 Дополнительные знаковые двоичные коды 76 Дребезг контактов 250 Загрузочный модуль 100, 268, 313 Запись комментариев 271 и Идентификатор 272, 277 внешнего имени 299 Идентификаторы 320, 321, 351 Измерение: длительности импульса 182 частоты 183 Имена переменных 322 Инвертор 16 Индексные выражения 352 Инициализация данных 347 Инициатор 330 Инкрементирование 90 Инструкции 273 Интегрированная среда программирования 311 Интерпретаторы 204 Исполняемый код программы 99, 231 Исполняемый модуль 268, 312 Источник данных 270 Исходный модуль 311 к Категории типов данных 331 Клавиатура 122, 245 Ключевые слова 273, 320, 323 Код опроса 247 Команда 147 include 284 mov 150 move 150 movx 150 pagelength 284 pagewidth 284 xch 150
422 Предметный указатель Команды: debug/nodebug 284 list/nolist 284 безусловного перехода 151 ветвления и передачи управления 151 микропроцессора 98 пересылки данных 149 . условных переходов 152 чтение-модификация-запись 158 Комбинации знаков 272 Комментарии 213, 327 Компиляторы 204, 205 Константное выражение 340, 354 Константы 323 с плавающей запятой 323, 325 Контроллер 10 Контроль переполнения 77 Косвенно-регистровая адресация 155 л Лексические единицы 320 Линейная цепочка операторов 217, 294 Литеральная: константа 276 строка 277, 323, 350 Логические команды 149 операции 276, 364 Логический элемент 16 Локальные переменные 210 м Макрос 217 Масочные ПЗУ 44 Массивы 340 Машинные коды 99 Менеджер проектов 311 Микроконтроллеры 7 Микропрограмма 97, 101 Микропроцессоры 3 Микропроцессоры с регистрами общего назначения 92 Мнемоническое обозначение: кода операции 147 команды 99, 270 Многомерный массив 352 Многомодульные программы 237, 298 Многофайловое программирование 236 Многофайловые программы 231 Модуль 314 захвата 138 сравнения 137 Монтажное ИЛИ 35 Мультиплексор 31 н Непосредственная адресация 156 Нетерминальные имена 329 Неявная адресация 154 о Обратные знаковые двоичные коды 75 Объединения 345 Объектный модуль 311 Объявление функции 391 Однокристальные микро-ЭВМ 139 Одноместная операция 276 Одноплатные компьютеры 9 Оконная адресация 116 Операнд 270, 350 Операторы 269, 372 выражение 372 языка программирования ASM-51 269 Операции 355, 358 в ассемблере 274 сдвига 363 Операционный блок 93, 94 Операция: вычисления остатка 361 деления 361 умножения 361 Описатель 329 Определяемые имена 274 Оптимизатор 204 Отладчик программ 311 п Память: данных 93 программ 93, 165 Параллельные порты 123 Параметры подпрограммы 211, 286 Переменные перечислимого типа 333 Перемещаемый сегмент 307 ПЗУ 42
Предметный указатель 423 ПЛИС 6 Подпрограмма инициализации 252 Подпрограмма обслуживания прерывания 256, 290 Подпрограммы 206 Подпрограммы на языке программирования ASM-51 285 Подпрограммы-заглушки 216, 217, 219 Подпрограммы-процедуры 210, 285 Подпрограммы-функции 210, 212, 289 Поле: комментария 271 метки 269 операции 270 Полный сумматор 24 Полусумматор 24 Поразрядные операции 363 Порт: Р0 161 Р1 161 Р2 163 РЗ 163 ввода 124 вывода 124 Порты ввода-вывода 125, 156 Последовательный порт микроконтроллера 185 Последовательный регистр 57 Преобразования типов 357, 369 Приведение типов 354 Приемник результата операции 270 Программа-монитор 241 Программируемые ПЗУ 46 Программный модуль 238 Программный проект 300 Программный счетчик 95 Произвольная таблица истинности 20 Простое присваивание 367 Простые ограничители 320 Прототип 390 Процесс разработки и отладки программы 310 Прямая байтовая адресация 154 Прямая битовая адресация 154 Прямые знаковые двоичные коды 74 Пустой оператор 269, 373 Регистр 56 адреса 95 команд 145 указателя данных 146, 147 управления 96 управления энергопотреблением 145 Регистровая адресация 154 Регистровый банк 170 Регистры: временного хранения 145 общего назначения 170 специальных функций 169, 172 Режимы пониженного энергопотребления 257 Репрограммируемые ПЗУ 48 Распределение памяти 110 Регенерирующее устройство 66 Сброс процессора 101 Свободнобегущие таймеры 136 Сегмент 301 Сегментная организация памяти 115 Сигнал: записи 62 стробирования данных 64 чтения 42 Сигнальные процессоры 7 12 Символ интервала 270, 271 Символы алфавита 317 Символьная константа 323, 326 Синхронные последовательные порты 127 Синхронный триггер 53 Система команд 98, 147 Системная шина 108 Скан-код 245 Составное присваивание 367 Составной оператор 373 Составные ограничители 321 Специализированные указатели 339 Специальные символы 318 Спецификатор: типа 329 типа памяти 330 Стандартные типы данных 330 Статические ОЗУ 60 Стек 208 Страничный метод адресации 112 Строковая константа 321, 326
424 Предметный указатель Структуры 342 Структурное программирование 214,294 Сумматор 23 по модулю два 23 Суммирующие таймеры 135 Схема подключения светодиодных индикаторов к параллельному порту 157 Счетчик команд 146 Таймеры 134 Тело функции 389 Терминальные имена 329 Тип памяти 299 Трансляция 204 Третье состояние 37 Триггер 52 Триггер-защелка 54 у Указатели общего вида 337 Указатель 336 стека 146 Универсальные: микропроцессоры 6 процессоры 7 Универсальный регистр 58 Управление потенциалами на выводах микроконтроллера 160 Управляющая конструкция 217 Управляющие и разделительные символы 318 Управляющие команды 283 Управляющие последовательности 319 Условная операция 365 Условное выполнение оператора 295 Условное выполнение операторов 220,221 Устройство формирования временных интервалов 144 ф Файл-заголовок 300 Физический адрес 115 Флэш-ПЗУ 51 Форматы команд микропроцессора 98 Функция 315, 385 Ц Целочисленные константы 323 Целочисленный тип данных 332 Целые знаковые и беззнаковые константы 323 Цикл: с проверкой условия до тела цикла 228,297 с проверкой условия после тела цикла 297 Циклическое выполнение оператора с проверкой условия после тела цикла 225 Цоколевка 143 Числа с плавающей запятой 333 Числовые константы 321 Чтение внешних выводов порта 158 ш Шестнадцатеричная константа 324 Шестнадцатеричное число 275 Шестнадцатеричные цифры 272 Шина: адреса 108 данных 108 управления 108 Шинный формирователь 34, 38 Электрически стираемые ПЗУ 50 Элемент "И" 17 Эффект распространения знака 77 я Языки: программирования высокого уровня 202 программирования для микроконтроллеров 202
«...Основной принцип книги — это микропроцессорная техника в картинках, но без формул, то есть формулы используются только там, где без них действительно невозможно обойтись...» А. Микушин о МИКРОКОНТРОЛЛЕР!) Н Книга в доступной форме вводит читателя в мир микропроцессорной техники. Здесь собраны материалы, затрагивающие различные аспекты проектирования микропроцессоров: от сведений о простейших логических элементах до изложения принципов разработки микропроцессорных систем и достаточно сложных многомодульных программ для них. Из всего многообразия микропроцессоров в качестве примера рассматриваются микроконтроллеры семейства MCS-51. Выбор связан с их распространен- распространенностью, доступностью и поддержкой такими крупнейшими производи- производителями, как Analog Devices и Texas Instruments. Описанные методы разработки микропроцессорных устройств можно применять и при использовании микросхем других семейств. Большое внимание уделено построению структуры, принципам написания и отладке программ для микроконтроллеров на языках Си и ассемблере. Приведены готовые шаблоны для написания программ на ассемблере и показаны особенности применения языка Си для реализации конкретных устройств. При подготовке книги были использованы материалы лекций по микропро- микропроцессорам, читаемых автором в течение ряда лет в Сибирском государ- государственном университете телекоммуникаций и информатики. "¦¦ Микушин Александр Владимирович, кандидат технических наук, доцент кафедры САПР Сибирского государственного университета телекоммуникаций и информатики. Автор пяти книг и более тридцати статей по применению микропроцессоров в устройствах радиосвязи и радионавигации. К настоящему времени его исследования внедрены в ряде комплексов конвенциональной, транкинговой и авиационной радиосвязи. БХВ-Петербург 194354, Санкт-Петербург, ул. Есенина, 5Б E-mail: mail@bhv.ru Internet: www.bhv.ru тел./факс: (812) 591-6243