Программирование на языке СИ

 Rambler's Top100 Дата последнего обновления файла 5.10.04

ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ С51

ОГЛАВЛЕНИЕ

  1. ЯЗЫК ПРОГРАММИРОВАНИЯ С51
  2. ЭЛЕМЕНТЫ ЯЗЫКА СИ
    1. Используемые символы
    2. Константы
    3. Идентификатор
    4. Ключевые слова
    5. Использование комментариев в тексте программы
  3. ТИПЫ ДАННЫХ И ИХ ОБЪЯВЛЕНИЕ
    1. Категории типов данных
    2. Целый тип данных
    3. Числа с плавающей запятой
    4. Указатели
    5. Переменные перечислимого типа
    6. Массивы
    7. Структуры
    8. Объединения (смеси)
    9. Поля битов
    10. Переменные с изменяемой структурой
    11. Определение объектов и типов
    12. Инициализация данных
  4. ВЫРАЖЕНИЯ И ПРИСВАИВАНИЯ
    1. Операнды и операции
    2. Преобразования при вычислении выражений
    3. Операции отрицания и дополнения
    4. Операции разадресации и адреса
    5. Операция sizeof
    6. Мультипликативные операции
    7. Аддитивные операции
    8. Операции сдвига
    9. Поразрядные операции
    10. Логические операции
    11. Операция последовательного вычисления
    12. Условная операция
    13. Операции увеличения и уменьшения
    14. Простое присваивание
    15. Составное присваивание
    16. Приоритеты операций и порядок вычислений
    17. Побочные эффекты
    18. Преобразование типов
  5. ОПЕРАТОРЫ
    1. Оператор выражение
    2. Пустой оператор
    3. Составной оператор
    4. Оператор if
    5. Оператор switch
    6. Оператор break
    7. Оператор for
    8. Оператор while
    9. Оператор do while
    10. Оператор continue
    11. Оператор return
    12. Оператор goto
  6. ФУНКЦИИ
    1. Определение и вызов функций
    2. Вызов функции с переменным числом параметров
    3. Передача параметров функции main
  7. СТРУКТУРА ПРОГРАММЫ И КЛАССЫ ПАМЯТИ
    1. Исходные файлы и объявление переменных
    2. Объявления функций
    3. Время жизни и область видимости программных объектов
    4. Инициализация глобальных и локальных переменных

1.7. УКАЗАТЕЛИ И АДРЕСНАЯ АРИФМЕТИКА
 1.7.1. Методы доступа к элементам массивов
 1.7.2. Указатели на многомерные массивы
 1.7.3. Операции с указателями
 1.7.4. Массивы указателей
 1.7.5. Динамическое размещение массивов

1.8. ДИРЕКТИВЫ ПРЕПРОЦЕССОРА
 1.8.1. Директива #include
 1.8.2. Директива #define
 1.8.3. Директива #undef

Чтение по порядку глав


Содержание установочных лекций

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

Содержание установочных лекций для заочников по курсу "Цифровые устройства и микропроцессоры"

1. Введение.

  1. Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры.
  2. Области применения микроконтроллеров, микропроцессоров и сигнальных процессоров.

2.Принципы работы микроконтроллеров.

  1. Архитектура микроконтроллеров MCS-51. Представители этого семейства микроконтроллеров.
  2. Особенности построения параллельных портов микроконтроллеров MCS-51.
  3. Особенности построения памяти микроконтроллеров семейства MCS-51.
  4. Внутренние таймеры микроконтроллера, особенности их применения.
  5. Устройство и особенности применения последовательного порта микроконтроллеров семейства MCS-51.

3. Система команд микроконтроллеров семейства MCS-51.

  1. Инструкции микроконтроллеров семейства MCS-51.
  2. Виды адресации.
  3. Инструкции микроконтроллеров семейства MCS-51.


Александр Владимирович Микушин

Rambler's Top100 Александр Владимирович Микушин

pxx1.jpg (13500 bytes) кандидат технических наук, доцент кафедры САПР.

Родился 21 июня 1960 года. Выпускник факультета радиосвязи и радиовещания (1982) Новосибирского электротехнического института связи.

Работает в НЭИС (СибГУТИ) с 1982 года.

А.В. Микушин является специалистом в области радиосвязи. Он внёс вклад в разработку систем радионавигации, радио и транкинговой связи. Эти научные исследования прошли апробацию и внедрены в комплексе радиостанций "Сигнал-201", "Орлан-СТД", ряде базовых станций системы SmarTrunk и радиостанций специального назначения. Ему принадлежит около 50 научных и научно-методических работ.

Подготовил читал лекционные курсы:

  • цифровая и вычислительная техника;
  • Микропроцессоры в устройствах и системах;
  • Микропроцессоры и цифровая обработка сигналов;
  • Спецпроцессоры.

В настоящее время читает лекционные курсы:

  • цифровые устройства и микропроцессоры;

Область интересов:

  • применение микроконтроллеров и сигнальных процессоров;
  • разработка устройств приёма и передачи сигналов в цифровом виде;
  • кодирование и декодирование дискретной информации;
  • построение базовых станций в системах транкинговой связи;
  • адаптивный приём сигналов в системах конвенциальной и транкинговой связи;
  • разработка устройств подавления комплекса помех в каналах радиосвязи;
  • древняя история, история России и туризм

В последние годы А. В. Микушин ведёт интенсивные исследования, связанные с внедрением новых технологий в учебный процесс.

При работе с материалами, ссылки на которые расположены на этой странице, возникла необходимость отслеживать изменения в материалах, поэтому вводится новая страница, на которой будут отображаться изменения содержания лекционных курсов и справочных материалов.

Учебные материалы, расположенные на этой странице, находятся на стадии разработки. Автор был бы признателен, если бы Вы прислали свои замечания по содержимому или структуре материалов. Автор рассмотрит любые предложения по улучшению содержимого или структуры материалов.

Дата обновления информации: 16.06.2005


Цифровая и вычислительная техника

Микропроцессоры и цифровая обработка сигналов

Цифровые устройства

Микропроцессоры

Книги в электронном варианте

Справочные данные

Новости


Микроконтроллеры. Область применения

 Rambler's Top100 Дата последнего обновления файла 10.06.2005

Микроконтроллеры. Область применения

Термин контроллер образовался от английского слова to control - управлять. Эти устройства могут основываться на различных принципах работы от механических или оптических устройств до электронных аналоговых или цифровых устройств. Механические устройства управления обладают низкой надежностью и высокой стоимостью по сравнению с электронными блоками управления, поэтому в дальнейшем мы такие устройства рассматривать не будем. Электронные аналоговые устройства требуют постоянной регулировки в процессе эксплуатации, что увеличивает стоимость их эксплуатации. Поэтому такие устройства к настоящему времени почти не используются. Наиболее распространенными на сегодняшний день схемами управления являются схемы, построенные на основе цифровых микросхем.

В зависимости от стоимости и габаритов устройства, которым требуется управлять, определяются и требования к контроллеру. Если объект управления занимает десятки метров по площади, как, например, автоматические телефонные станции, базовые станции сотовых систем связи или радиорелейные линии связи, то в качестве контроллеров можно использовать универсальные компьютеры. Управление при этом можно осуществлять через встроенные порты компьютера (LPT, COM, USB или ETHERNET). В такие компьютеры при включении питания заносится управляющая программа, которая и превращает универсальный компьютер в контроллер.

Использование универсального компьютера в качестве контроллера позволяет в кратчайшие сроки производить разработку новых систем связи, легко их модернизировать (путём простой смены программы) а также использовать готовые массовые (а значит дешёвые) блоки.

Если же к контроллеру предъявляются особенные требования, такие, как работа в условиях тряски, расширенном диапазоне температур, воздействия агрессивных сред, то приходится использовать промышленные варианты универсальных компьютеров. Естественно, что эти компьютеры значительно дороже обычных универсальных компьютеров, но всё равно они позволяют экономить время разработки системы, за счёт того, что не нужно вести разработку аппаратуры контроллера.

Контроллеры требуются не только для больших систем, но и для малогабаритных устройств таких как радиоприёмники, радиостанции, магнитофоны или сотовые аппараты. В таких устройствах к контроллерам предъявляются жёсткие требования по стоимости, габаритам и температурному диапазону работы. Этим требованиям не могут удовлетворить даже промышленные варианты универсального компьютера. Приходится вести разработку контроллеров на основе однокристальных ЭВМ, которые в свою очередь получили название микроконтроллеры.

Любые устройства, в том числе и устройства связи, радиоавтоматики или аудиовизуальной аппаратуры требуют присутствия в своем составе устройства управления (контроллера). Контроллеры требуются практически во всех предметах и устройствах, которые окружают нас. В качестве примера на рисунке 1 приведены узлы автомобиля, в которых применяются микроконтроллеры.

Рисунок 1 Узлы автомобиля, в которых применяются микроконтроллеры.

Внешний вид автомобильной и носимой радиостанции, в которых тоже применяются микросхемы микроконтроллеров, показаны на рисунке 2 и рисунке 3.

Рисунок 2. Малогабаритная радиостанция с применением микроконтроллеров.

Рисунок 3. Малогабаритная радиостанция с применением микроконтроллеров.

Как выглядит носимая радиостанция внутри показывает фотография, приведённая на рисунке 4.

Рисунок 4. Печатная плата приёмопередатчика носимой радиостанции.

Наиболее распространёнными в настоящее время являются микроконтроллеры семейства MCS-51. Это семейсво поддерживается рядом фирм - производителей микросхем. Не менее распространёнными в мире но не в России являются микроконтроллеры фирмы Motorola. Это такие семейства как HC05, HC07, HC11 и многие другие. Пожалуй, не менее популярными микроконтроллерами являются микроконтроллеры семейства AVR фирмы Atmel. Одно перечисление семейств микроконтроллеров может занять несколько страниц текста, поэтому ограничимся приведёнными семействами восьмиразрядных микроконтроллеров.

[ Главная ]


Логические элементы

 Rambler's Top100 Дата последнего обновления файла 07.06.2005

Области применения цифровых микросхем.

Цифровые микросхемы первоначально разрабатывались для построения электронно-вычислительных машин, получивших в дальнейшем название компьютеры. То есть первое их предназначение было заменить человека при выполнении рутинной работы. Сейчас, наверное, никто и не вспомнит, что слово калькулятор ещё каких-нибудь шестьдесят лет назад обозначало не маленький карманный прибор, а профессию большого числа людей, которые занимались расчётами по конкретным математическим формулам.

Однако вскоре после начала массового производства цифровых микросхем выяснилось, что они оказались очень удобны для управления какими либо объектами. При этом управляемая схема может обычно находиться в двух состояниях. Например: схема может быть либо включена, либо выключена, светодиод может либо гореть, либо не гореть, соединение в телефонной станции может быть или не быть, радиостанция может находиться в режиме передачи или в режиме приёма. В результате цифровые микросхемы практически полностью вытеснили применявшиеся ещё с девятнадцатого века для управления приборами электромагнитные реле и перфокарты.

При выполнении задачи управления для описания состояния объекта достаточно двух значений: напряжение высокое или низкое (положительное или отрицательное) ток протекает или не протекает. Это позволило избавиться от многих неприятных моментов аналоговых схем. Например, ошибка при прохождении через схему не увеличивается (в отличие от шумов), а в ряде случаев даже может быть скомпенсирована. Сами цифровые схемы при правильном использовании не вносят ошибок. Эти свойства цифровых микросхем привели к бурному развитию цифровой техники.

Приведённые преимущества привели к тому, что в дальнейшем цифровая техника стала использоваться и для решения других задач. Например для формирования высокостабильных колебаний для радиотехнических изделий или для использования в часах. Здесь тоже нет необходимости формировать различные уровни напряжения генерируемого сигнала. Достаточно только, чтобы частота генерируемого колебания была стабильной.

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

Технологии производства цифровых микросхем.

В настоящее время используется несколько технологий построения логических элементов:

  • транзисторно-транзисторная логика (ТТЛ, TTL)
  • логика на основе комплементарных МОП транзисторов (КМОП, CMOS)
  • логика на основе сочетания комплементарных МОП и биполярных транзисторов (BiCMOS)

Первоначально получили распространение цифровые микросхемы, построенные на основе ТТЛ технологии. Поэтому до сих пор существует огромное количество микросхем, построенных по этой технологии или совместимые с этими микросхемами по напряжению питания, логическим уровням и цоколёвке.

Рассмотрим сначала микросхемы, совместимые с первыми ТТЛ микросхемами по питанию. Это микросхемы, питающиеся от источника напряжения +5В. Зарубежные ТТЛ микросхемы получили название серия SN74. Конкретные микросхемы этой серии обозначаются цифровым номером микросхемы, следующим за названием серии. Принципиальная схема типового элемента ТТЛ микросхемы приведена на рисунке 1.

Рисунок 1. Принципиальная схема типового элемента ТТЛ микросхемы.

Отечественные микросхемы этой серии выпускались в составе серий К134 (низкое быстродействие низкое потребление)


Что такое микропроцессоры, микроконтроллеры и сигнальные процессоры

 Rambler's Top100 Дата последнего обновления файла 10.06.2005

Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры.

Вся схемотехника разделяется на две большие области: аналоговую и цифровую Преимущества и недостатки этих технологий известны. Аналоговая схемотехника характеризуется максимальным быстродействием, малым потреблением энергии и малой стабильностью параметров. Цифровая схемотехника обладает прекрасной повторяемостью параметров. Это привело к её развитию в последние годы. В курсах электронных приборов рассматривались основные технологии производства цифровых микросхем: ТТЛ, ЭСЛ и КМОП, поэтому здесь особенности этих технологий рассматриваться не будут.

По мере развития цифровых микросхем их быстродействие достигло впечатляющих результатов. Наиболее быстрые из цифровых микросхем обладают скоростью переключения порядка 3..5 нс. (серия микросхем 74ALS), а внутри кристалла микросхемы, где нет больших ёмкостей нагрузки время переключения измеряется пикосекундами. Таким быстродействием обладают программируемые логические схемы и заказные БИС. В этих микросхемах алгоритм решаемой задачи заключён в их принципиальной схеме.

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

  1. Быстродействующие микросхемы потребляют значительный ток.
  2. Для решения задачи приходится использовать много микросхем, это выливается в стоимость и габариты устройства.

Первую задачу решает применение технологии КМОП цифровых микросхем (например микросхемы серий 1564, 74HC, 74AHC). Потребляемый ими ток зависит от скорости переключения логических вентилей. Именно поэтому в настоящее время подавляющее большинство микросхем выпускается именно по этой технологии.

Вторую задачу решают несколькими способами. Для жёсткой логики это разработка специализированных БИС. Использование специализированных БИС позволяет уменьшить габариты устройства, но стоимость его снижается только при крупносерийном производстве. Для среднего и малого объёмов производства такое решение неприемлемо.

Ещё одним решением уменьшения габаритов и стоимости устройства является применение программируемых логических схем (ПЛИС). Это направление активно развивается в настоящее время, но оно не входит в рамки рассмотрения данного курса.

Третий способ решения поставленной задачи заключается в том, что можно заставить одно очень быстродействующее устройство последовательно решать различные задачи, изменяя свою структуру во времени. Это микропроцессоры. В микропроцессорах возможен обмен предельного быстродействия на сложность реализуемого устройства. Именно по этой причине стараются максимально увеличить быстродействие микропроцессоров - это позволяет реализовывать все более сложные устройства в одном и том же объеме. Более того! В одном процессоре можно реализовать несколько устройств одновременно! Именно это решение задачи и рассматривается в данном учебном курсе.

В современном мире трудно найти область техники, где не применялись бы микропроцессоры. Они применяются при вычислениях, они выполняют функции управления, они используются при обработке звука и изображения. В зависимости от области применения микропроцессора меняются требования к нему. Это накладывает отпечаток на внутреннюю структуру микропроцессора. В настоящее время определилось три направления развития микропроцессоров:

  • универсальные микропроцессоры
  • микроконтроллеры
  • сигнальные микропроцессоры

Универсальные микропроцессоры используются для построения вычислительных машин. В них используются самые передовые решения по повышению быстродействия, не обращая особого внимания на габариты, стоимость и потребляемую энергию. В технике связи компьютеры используются для управления системами связи или устройствами связи, обладающими большими габаритами и стоимостью. Такие компьютеры называются контроллерами.

Для управления малогабаритными и дешёвыми устройствами связи используются однокристальные микроЭВМ, которые в настоящее время называются микроконтроллерами. В микроконтроллерах наоборот, максимальное внимание уделяется именно габаритам, стоимости и потребляемой энергии.

Еще один класс микропроцессоров решает задачи, которые традиционно решала аналоговая схемотехника. Это сигнальные процессоры. К сигнальным процессорам предъявляются специфические требования. От них требуются максимальное быстродействие, малые габариты, легкая стыковка с аналого-цифровыми и цифро-аналоговыми преобразователями, большая разрядность обрабатываемых данных и небольшой набор математических операций, обязательно включающий операцию умножения-накопления и аппаратную организацию циклов.

[ Главная ]


Изменения в содержании материалов

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

Изменения в содержании материалов.

1.06.06 Добавлен пример разработки микропроцессорного устройства

12.05.05 Добавлено описание генераторов на логических микросхемах

27.04.05 Добавлено описание двоичных счетчиков

26.02.05 Добавлены несколько новых книг по цифровой обработке сигналов

19.02.05 Добавлены новые главы в описание похода к Белухе

12.11.04 Изменено описание внутренней памяти программ с целью приближения к лекционному материалу.

6.11.04 Размещены задания на курсовое проектирование для группы РТ-14 расчетно-графические задания для группы РА-15.

13.10.04 В связи с участившимися запросами по семейству микроконтроллеров MCS-48 размещены материалы по этому семейству микроконтроллеров.

30.09.04 Начат набор желающих пройти обучение по курсу " цифровая обработка сигналов". Занятия начинаются по мере формирования групп. Количество человек в группе - 12 человек. Для записи обращаться: Главный корпус СибГУТИ каф. САПР к 302 (3 этаж) тел. для справок: 66-02-86.

30.09.04 Улучшена навигация между курсами. Исправлены ошибки в файлах описания двоичных кодов и работы с таймерами микроконтроллеров MCS-51. Кроме того выложены материалы статей А. Фрунзе по разработке программ для микроконтроллеров семейства MCS-51.

27.07.04 Полностью изменена структура материалов. Обеспечены ссылки для последовательного чтения материалов Добавлены материалы по языку программирования PLM-51. Добавлены материалы по языку программирования ASM-51.


Программирование на языке СИ

 Rambler's Top100 Дата последнего обновления файла 5.10.04

1.Элементы языка С51

1.1. Используемые символы

Множество символов используемых в языке СИ можно разделить на пять групп.

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

Таблица 1

Прописные буквы латинского алфавита | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Строчные буквы латинского алфавита | a b c d e f g h i j k l m n o p q r s t u v w x y z
Символ подчеркивания | _

2. Прописные и строчные буквы русского алфавита и арабские цифры (табл.2).

Таблица 2

Прописные буквы русского алфавита | А Б В Г Д Е Ж З И К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ы Ь Э Ю Я
Строчные буквы русского алфавита | а б в г д е ж з и к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я
Арабские цифры | 0 1 2 3 4 5 6 7 8 9

3. Знаки нумерации и специальные символы (табл. 3). Эти символы используются для организации процесса вычислений, а также для передачи компилятору определенного набора инструкций.

Таблица 2

Символ | Наименование | Символ | Наименование
, | запятая | ) | круглая скобка правая
. | точка | ( | круглая скобка левая
; | точка с запятой | } | фигурная скобка правая
: | двоеточие | { | фигурная скобка левая
? | вопросительный знак | < | меньше
' | апостроф | > | больше
! | восклицательный знак | [ | квадратная скобка
| | вертикальная черта | ] | квадратная скобка
/ | дробная черта | # | номер
\ | обратная черта | % | процент
~ | тильда | & | амперсанд
* | звездочка | ^ | исключающее ИЛИ
+ | плюс | = | равно
- | минус | " | кавычки

4. Управляющие и разделительные символы. К этой группе символов относятся: пробел, символы табуляции, перевода строки, возврата каретки, новая страница и новая строка. Эти символы отделяют друг от друга объекты, определяемые пользователем, к которым относятся константы и идентификаторы. Последовательность разделительных символов рассматривается компилятором как один символ (последовательность пробелов).

5. Управляющие последовательности, т.е. специальные символьные комбинации, используемые в функциях ввода и вывода информации. Управляющая последовательность строится на основе использования обратной дробной черты (\) (обязательный первый символ) и комбинацией латинских букв и цифр (табл.4).

Таблица 4

Управляющая последовательность | Наименование | Шестнадцатеричный код
\a | Звонок | 007
\b | Возврат на шаг | 008
\t | Горизонтальная табуляция | 009
\n | Переход на новую строку | 00A
\v | Вертикальная табуляция | 00B
\r | Возврат каретки | 00D
\f | Новая страница | 00C
\" | Кавычки | 022
\' | Апостроф | 027
\0 | Ноль-символ | 000
\\ | Обратная дробная черта | 05C
\OOO | Восьмеричный код ASCII или ANSI символа |
\xHHH | Шестнадцатеричный код ASCII или ANSI символа | HHH

Управляющие последовательности \OOO и \xHHH (здесь O обозначает восьмеричную цифру; H обозначает шестнадцатеричную цифру) позволяет представить символ из кодовой таблицы ASCII или ANSI как последовательность восьмеричных или шестнадцатеричных цифр соответственно. Например символ возврата каретки может быть представлен следующими способами:

\r - управляющая последовательность,

\015 - восьмеричный код символа возврата каретки,

\x00D - шестнадцатеричный код символа возврата каретки.

Следует отметить, что в строковых константах всегда обязательно задавать все три цифры в управляющей последовательности. Например отдельную управляющую последовательность \n (переход на новую строку) можно представить как \010 или \xA, но в строковых константах необходимо задавать все три цифры, в противном случае символ или символы следующие за управляющей последовательностью будут рассматриваться как ее недостающая часть. Например:

"ABCDE\x009FGH" данная строковая команда будет напечатана с использованием определенных функций языка СИ, как два отдельных слова ABCDE и FGH, разделенные табуляцией, в этом случае если указать неполную управляющую строку "ABCDE\x09FGH",то при печати появится строка ABCDEЯGH, так как компилятор воспримет последовательность \x09F как символ "Я".

Отметим тот факт, что, если обратная дробная черта предшествует символу не являющемуся управляющей последовательностью (т.е. не включенному в табл.4) и не являющемуся цифрой, то эта черта игнорируется, а сам символ представляется как литеральный. Например:

символ \h представляется символом h в строковой или символьной константе.

Кроме определения управляющей последовательности, символ обратной дробной черты (\) используется также как символ продолжения. Если за (\) следует (\n), то оба символа игнорируются, а следующая строка является продолжением предыдущей. Это свойство может быть использовано для записи длинных строк.

1.2. Константы

В языке программирования С разделяют четыре типа констант: целые знаковые и беззнаковые константы, константы с плавающей запятой, символьные константы и литеральные строки.

Константа может быть представлена в десятичной, восьмеричной или шестнадцатеричной форме.

Десятичная константа состоит из одной или нескольких десятичных цифр, причем первая цифра не может быть нулем (иначе число будет воспринято как восьмеричное).

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

Шестнадцатеричная константа начинается с обязательной последовательности символов 0х или 0Х и содержит одну или несколько шестнадцатеричных цифр (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)

      Примеры целых констант:
         Десятичная      Восьмеричная       Шестнадцатеричная
         константа       константа          константа
             16             020                0x10
            127             0117               0x2B
            240             0360               0XF0

Если требуется сформировать отрицательную целую константу, то используют знак "-" перед записью константы (который будет называться унарным минусом). Например: -0x2A, -088, -16 .

Каждой целой константе присваивается тип, определяющий преобразования, которые должны быть выполнены, если константа используется в выражениях. Тип константы определяется следующим образом:

- десятичные константы рассматриваются как знаковые числа, и им присваивается тип int (целая) или long (длинная целая) в соответствии со значением константы. Если константа меньше 32768, то ей присваивается тип int в противном случае long.

- восьмеричным и шестнадцатеричным константам присваивается тип int, unsigned int (беззнаковая целая), long или unsigned long в зависимости от значения константы согласно табл 5.

Таблица 5

Диапазон шестнадцатеричных констант | Диапазон восьмеричных констант | Тип
0x0 - 0x7FFF | 0 - 077777 | int
0X8000 - 0XFFFF | 0100000 - 0177777 | unsigned int
0X10000 - 0X7FFFFFFF | 0200000 - 017777777777 | long
0X80000000 - 0XFFFFFFFF | 020000000000 - 037777777777 | unsigned long

Для того чтобы любую целую константу определить типом long, достаточно в конце константы поставить букву "l" или "L". Пример:

5l, 6l, 128L, 0105L, OX2A11L.

Константа с плавающей запятой - десятичное число, представленное в виде действительного числа с десятичной запятой и порядком числа. Формат записи константы с плавающей запятой:

[ цифры ].[ цифры ] [ Е|e [+|-] цифры ] .

Число с плавающей запятой состоит из целой и дробные части и (или) порядка числа. Константы с плавающей запятой представляют собой положительные числа двойной точности (имеют тип double). Для определения отрицательной величины необходимо сформировать константное выражение, состоящее из знака минуса и положительной константы.

Примеры: 115.75, 1.5Е-2, -0.025, .075, -0.85Е2

Символьная константа - представляется символом заключенном в апострофы. Управляющая последовательность рассматривается как одиночный символ, ее допустимо использовать в символьных константах. Значением символьной константы является числовой код символа. Примеры:

' '- пробел ,

'Q'- буква Q ,

'\n' - символ новой строки ,

'\\' - обратная дробная черта ,

'\v' - вертикальная табуляция .

Символьные константы имеют тип int и при преобразовании типов дополняются знаком.

Строковая константа (литерал или литеральная строка) - последовательность символов (включая строковые и прописные буквы русского и латинского а также цифры) заключенные в кавычки ("). Например: "Школа N 35", "город Тамбов", "YZPT КОД".

Отметим, что все управляющие символы, кавычка ("), обратная дробная черта (\) и символ новой строки в строковом литерале и в символьной константе представляются соответствующими управляющими последовательностями. Каждая управляющая последовательность представляется как один символ. Например, при печати литерала "Школа \n N 35" его часть "Школа" будет напечатана на одной строке, а вторая часть "N 35" на следующей строке.

Символы литеральной строки сохраняются в оперативной памяти. В конец каждой литеральной строки компилятором добавляется нулевой символ, который можно записать как: "\0".

Литеральная строка рассматривается как массив символов (char[ ]). Отметим важную особенность, число элементов массива равно числу символов в строке плюс 1, так как нулевой символ (символ конца строки) также является элементом массива. Все литеральные строки рассматриваются компилятором как различные объекты. Одна литеральная строка может выводиться на дисплей как несколько строк. Такие строки разделяются при помощи обратной дробной черты и символа возврата каретки \n. На одной строке исходного текста программы можно записать только одну литеральную строку. Если необходимо продолжить написание одной и той же литеральной строки на следующей строке исходного текста, то в конце строки исходного текста можно поставить обратную строку. Например исходный текст:

"строка неопределенной \

длины"

полностью идентичен литеральной строке:

"строка неопределенной длины".

Однако более удобно для объединения литеральных строк использовать символ (символы) пробела. Если в программе встречаются два или более литерала, разделенные только пробелами или символами табуляции, то они будут рассматриваться как одна литеральная строка. Этот принцип можно использовать для формирования литералов, занимающих более одной строки.

1.3. Идентификатор

В качестве идентификатора может быть использована последовательность строчных или прописных букв латинского алфавита и цифр, а также символов подчёркивания '_'. Идентификатор может начинаться только с буквы или символа '_', но ни в коем случае с цифры. Строчные и прописные буквы в идентификаторе различаются. Например: идентификаторы abc и ABC, A128B и a128b воспринимаются как разные.

Важной особенностью является то, что компилятор допускает любое количество символов в идентификаторе, хотя значимыми являются первые 31 символ. Идентификатор создается на этапе объявления переменной, функции, структуры и т.п. после этого его можно использовать в последующих операторах разрабатываемой программы. Следует отметить важные особенности при определении идентификатора.

Во первых, идентификатор не должен совпадать с ключевыми словами, с зарезервированными словами и именами функций из библиотеки компилятора языка С.

Во вторых, следует обратить особое внимание на использование символа подчеркивание (_) в качестве первого символа идентификатора, поскольку идентификаторы, построенные таким образом, могут совпадать с именами системных функций или переменных, в результате чего они станут недоступными.

1.4. Ключевые слова

Ключевые слова - это зарезервированные идентификаторы, которые используются для построения операторов языка.

Список ключевых слов:

   alien      _at_   auto    bdata   bit        break     case     char   code     compact continue   data
   default    do     double  else    enum       extern    far      float  for      idata   if         int
   interrupt  large  long    pdata   _priority_ reentrant register return sbit     sfr     sfr16      signed
   sizeof     short  small   struct  switch     typedef   _task_   union  unsigned void    volatile   while

Ключевые слова не могут быть использованы в качестве идентификаторов.

1.5. Запись комментариев в тексте программы

Комментарий - это набор символов, которые игнорируются компилятором.

В языке программирования C51 возможно использование двух типов комментариев:

  1. комментарий, который может быть использован внутри строки;
  2. комментарий, который игнорирует символы до конца строки.

Первый вид комментария начинается парой символов (/* ) и завершается парой символов (*/). Эта особенность позволяет использовать этот вид комментария внутри операторов языка программирования. Кроме того, комментарий может занимать несколько строк. Например:

     /* комментарии к программе */
     /* начало алгоритма */
или
     /* комментарии  можно  записать в следующем виде,  однако надо
быть осторожным, чтобы внутри последовательности, которая игнорируется компилятором, не попались операторы программы,
которые также будут игнорироваться */

В тексте комментария не может быть символов, определяющих начало и конец комментариев (/* и */). Пример неправильного определения комментариев:

     /* комментарии к алгоритму /* решение краевой задачи */ */
или
     /* комментарии к алгоритму решения */ краевой задачи */

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

PrmDem(); //Получить, отфильтровать и демодулировать сигнал


Программирование на языке СИ

 Rambler's Top100 Дата последнего обновления файла 5.10.04

2. Типы данных и их объявление

В языке программирования C51 любая переменная должна быть объявлена до первого использования этой переменной. Как уже говорилось ранее этот язык программирования предназначен для написания программ для микроконтроллеров семейства MCS-51, поэтому в составе языка должна отображаться внутренняя структура этого семейства микроконтроллеров. Эти особенности отражены во введении новых типов данных. В остальном язык программирования C-51 не отличается от стандарта ANSI.

Объявление переменной в языке программирования C51 представляется в следующем виде:

   [спецификатор класса памяти]  спецификатор типа   описатель [=инициатор] [,описатель [= инициатор] ]...

Описатель - идентификатор простой переменной либо более сложная конструкция с квадратными скобками, круглыми скобками или звездочкой (набором звездочек).

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

Инициатор - задает начальное значение или список начальных значений, которые (которое) присваивается переменной при объявлении.

Спецификатор класса памяти - определяется одним из четырех ключевых слов языка С: auto, extern, register, static, и указывает, каким образом будет распределяться память под объявляемую переменную, с одной стороны, а с другой, область видимости этой переменной, т.е., из каких частей программы можно к ней обратиться.

2.1 Категории типов данных

Ключевые слова для определения основных типов данных

     Целые типы :                 Плавающие типы:
       bit                            float
       sbit
       char
       int
       short
       long
       signed
       unsigned
       sfr
       sfr16

Переменная любого типа может быть объявлена как неизменяемая. Это достигается добавлением ключевого слова const к спецификатору типа. Объекты с типом const представляют собой данные, используемые только для чтения, т.е. этой переменной не может быть присвоено новое значение. Отметим, что если после слова const отсутствует спецификатор типа, то подразумевается спецификатор типа int. Если ключевое слово const стоит перед объявлением составных типов (массив, структура, смесь, перечисление), то это приводит к тому, что каждый элемент также должен являться немодифицируемым, т.е. значение ему может быть присвоено только один раз.

Примеры:

      const float A=2.128E-2;
      const B=286; (подразумевается const int B=286)

Примеры объявления составных данных будут рассмотрены ниже.

2.2. Целый тип данных

Для определения данных целого типа используются различные ключевые слова, которые определяют диапазон значений и размер области памяти, выделяемой под переменные (табл. 6).

Таблица 6

Тип | Размер памяти в битах | Размер памяти в байтах | Диапазон значений
bit | 1 |  | от 0 до 1
char | 8 | 1 | от -128 до 127
unsigned shar | 8 | 1 | oт 0 до 255
int, short | 16 | 2 | от -32768 до 32767
long | 32 | 4 | от -2 147 483 648 до 2 147 483 647
unsigned int, unsigned short | 16 | 2 | от 0 до 65535
unsigned long | 32 | 4 | от 0 до 4 294 967 295
sbit | 1 |  | 0 или 1
sfr | 8 | 1 | oт 0 до 255
sfr16 | 16 | 2 | от 0 до 65535

Отметим, что ключевые слова signed и unsigned необязательны. Они указывают, как интерпретируется нулевой бит объявляемой переменной, т.е., если указано ключевое слово unsigned, то нулевой бит интерпретируется как часть числа, в противном случае нулевой бит интерпретируется как знаковый. В случае отсутствия ключевого слова unsigned целая переменная считается знаковой. В том случае, если спецификатор типа состоит из ключевого типа signed или unsigned и далее следует идентификатор переменной, то она будет рассматриваться как переменная типа int. Например:

     unsigned int n;  //Беззнаковое шестнадцатиразрядное число n
     unsigned int b;
     int c;        (подразумевается  signed   int c  );
     unsigned d;   (подразумевается  unsigned int d  );
     signed f;     (подразумевается  signed   int f  ).

Отметим, что модификатор типа char используется для представления одиночного символа или для объявления строковых литералов. Значением объекта типа char является код (размером 1 байт), соответствующий представляемому символу.

Отметим также, что восьмеричные и шестнадцатеричные константы также могут иметь модификатор unsigned. Это достигается указанием префикса u или U после константы, константа без этого префикса считается знаковой.

Например:

  0xA8C   (int  signed   );
  01786l  (long signed   );
  0xF7u   (int  unsigned );

2.3. Числа с плавающей запятой

Для переменных, представляющих число с плавающей запятой используется модификатор типа float. Модификатор double тоже допустим в языке программирования C51, но он не приводит к увеличению точности результата.

Величина с модификатором типа float занимает 4 байта. Из них 1 байт отводится для знака, 8 бит для избыточной экспоненты и 23 бита для мантиссы. Отметим, что старший бит мантиссы всегда равен 1, поэтому он не заполняется, в связи с этим диапазон значений переменной с плавающей точкой равен от ±1.175494E-38 до ±3.402823E+38.

Пример объявления переменной:

     float f, a, b;

2.4. Указатели

Указатель - это переменная, которая может содержать адрес другой переменной. Указатель может быть использован для работы с переменной, адрес которой он содержит. Для инициализации указателя (записи начального адреса) можно использовать идентификатор переменной, при этом в качестве идентификатора может выступать имя переменной, массива, структуры, литеральной строки.

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

спецификатор-типа [ модификатор ] * описатель.

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

В качестве модификаторов при объявлении указателя могут выступать ключевые слова const, data, idata, xdata, code. Ключевое слово const указывает, что указатель не может быть изменен в программе. Размер переменной, объявленной как указатель, зависит от модификатора и используемого вида памяти, для которой будет компилироваться программа. Указатели на различные типы данных не обязательно должны иметь одинаковую длину.

Для модификации размера указателя можно использовать ключевые слова data, idata, xdata, code.

Примеры:

   unsigned int * a; /* переменная  а  представляет собой указатель
                     на целую беззнаковую) переменную*/
   float * x;       /* переменная  х  указывает  на
                       переменную с плавающей  точкой*/
   char * fuffer ;   /*объявляется  указатель с именем fuffer
                      который указывает на символьную переменную*/

Задавая вместо спецификатора типа, ключевое слово void, можно отсрочить определение типа, на который ссылается указатель. Переменная, объявляемая как указатель на тип void, может быть использована для ссылки на объект любого типа. Однако для того, чтобы можно было выполнить арифметические и логические операции над указателями или над объектами, на которые они указывают, необходимо при выполнении каждой операции явно определить тип объектов. Такие определения типов могут быть выполнены с помощью операции приведения типов.

   float nomer;
   void *addres;
   addres = &nomer;
   (float *)addres ++;
  /* Переменная addres объявлена как указатель на объект любого типа.
     Поэтому ей можно присвоить адрес любого объекта (& - операция
     вычисления адреса). Однако, как было отмечено выше, ни одна
     арифметическая операция не может быть выполнена над указателем,
     пока не будет явно определен тип данных,  на которые он указывает. Это
     можно сделать,  используя операцию приведения типа (float *) для
     преобразования типа указателя addres к типу float. Затем оператор ++
     отдаёт приказ перейти к следующему адресу.*/

В качестве модификаторов при объявлении указателя могут выступать ключевые слова const, data, idata, xdata, code. Ключевое слово const указывает, что указатель не может быть изменен в программе.

Вследствие уникальности архитектуры контроллера 8051 и его производных компилятор С51 поддерживает 2 вида указателей: память-зависимые и нетипизированные.

2.4.1. Нетипизированные указатели

Нетипизированные указатели объявляются точно так же, как указатели в стандартном языке программирования C. Для того, чтобы не зависеть от типа памяти, в которой может быть размещена переменная, для нетипизированных указателей выделяется 3 байта. В первом байте указывается вид памяти переменной, во втором байте – старший байт адреса, в третьем – младший байт адреса переменной. Нетипизированные указатели могут быть использованы для обращения к любым переменным независимо от типа памяти микроконтроллера. Именно поэтому многие библиотечные функции языка программирования C51 используют указатели этого типа, при этом им совершенно неважно, в какой именно области памяти размещаются переменные. Приведем листинг, в котором отображаются особенности трансляции нетипизированных указателей:

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
  11     1 char xdata xj; /*переменные во внешней памяти данных xdata */
  12     1 int xdata xk;
  13     1 long xdata xl;
  14     1
  15     1 char code cj = 9; /*переменные в памяти программ code */
  16     1 int code ck = 357;
  17     1 long code cl = 123456789;
  18     1
  19     1 /*настроим указатели на внутреннюю память данных data */
  20     1 c_ptr = &dj;
  21     1 i_ptr = &dk;
  22     1 l_ptr = &dl;
  23     1 /*настроим указатели на внешнюю память данных xdata */
  24     1 c_ptr = &xj;
  25     1 i_ptr = &xk;
  26     1 l_ptr = &xl;
  27     1 /*настроим указатели на память программ code */
  28     1 c_ptr = &cj;
  29     1 i_ptr = &ck;
  30     1 l_ptr = &cl;
  31     1 }

ASSEMBLY LISTING OF GENERATED OBJECT CODE
      ; FUNCTION main (BEGIN)
                      ; SOURCE LINE # 5
                      ; SOURCE LINE # 6
                      ; SOURCE LINE # 20
0000 750000 R   MOV   c_ptr,#00H
0003 750000 R   MOV   c_ptr+01H,#HIGH dj
0006 750000 R   MOV   c_ptr+02H,#LOW dj
                      ; SOURCE LINE # 21
0009 750000 R   MOV   i_ptr,#00H
000C 750000 R   MOV   i_ptr+01H,#HIGH dk
000F 750000 R   MOV   i_ptr+02H,#LOW dk
                      ; SOURCE LINE # 22
0012 750000 R   MOV   l_ptr,#00H
0015 750000 R   MOV   l_ptr+01H,#HIGH dl
0018 750000 R   MOV   l_ptr+02H,#LOW dl
                      ; SOURCE LINE # 24
001B 750001 R   MOV   c_ptr,#01H
001E 750000 R   MOV   c_ptr+01H,#HIGH xj
0021 750000 R   MOV   c_ptr+02H,#LOW xj
                      ; SOURCE LINE # 25
0024 750001 R   MOV   i_ptr,#01H
0027 750000 R   MOV   i_ptr+01H,#HIGH xk
002A 750000 R   MOV   i_ptr+02H,#LOW xk
                      ; SOURCE LINE # 26
002D 750001 R   MOV   l_ptr,#01H
0030 750000 R   MOV   l_ptr+01H,#HIGH xl
0033 750000 R   MOV   l_ptr+02H,#LOW xl
                      ; SOURCE LINE # 28
0036 7500FF R   MOV   c_ptr,#0FFH
0039 750000 R   MOV   c_ptr+01H,#HIGH cj
003C 750000 R   MOV   c_ptr+02H,#LOW cj
                      ; SOURCE LINE # 29
003F 7500FF R   MOV   i_ptr,#0FFH
0042 750000 R   MOV   i_ptr+01H,#HIGH ck
0045 750000 R   MOV   i_ptr+02H,#LOW ck
                      ; SOURCE LINE # 30
0048 7500FF R   MOV   l_ptr,#0FFH
004B 750000 R   MOV   l_ptr+01H,#HIGH cl
004E 750000 R   MOV   l_ptr+02H,#LOW cl
                      ; SOURCE LINE # 31
0051 22         RET
      ; FUNCTION main (END)

2.4.2. Память зависимые указатели

В объявления память-зависимых указателей всегда включается модификатор памяти. Обращение всегда происходит к указанной области памяти, например:

char data *str;    /*указатель на строку во внутренней памяти данных data */
int xdata *numtab; /*указатель на целую во внешней памяти данных xdata */
long code *powtab; /*указатель на длинную целую в памяти программ code */

Поскольку модель памяти определяется во время компиляции, типизированным указателям не нужен байт, в котором указывается тип памяти микроконтроллера. Поэтому программа с использованием типизированных указателей будет короче и будет выполняться быстрее по сравнению с программой, использующей нетипизированные указатели. Типизированные указатели могут иметь размер в 1 байт (указатели на память idata, data, bdata, и pdata) или в 2 байта (указатели на память code и xdata).

2.5. Переменные перечислимого типа

Переменная, которая может принимать значение из некоторого списка значений, называется переменной перечислимого типа или перечислением.

Использование такого вида переменной эквивалентно применению целой знаковой переменной char или int. Это означает, что для переменной перечислимого вида будет выделен один или два байта в зависимости от максимального значения используемых этой переменной констант. В отличие от переменных целого типа, переменные перечислимого типа позволяют вместо безликих чисел использовать имена констант, которые более понятны и легче запоминаются человеком.

Например, вместо использования чисел 1,2,3,4,5,6,7 можно использовать названия дней недели: Poned, Vtorn, Sreda, Chetv, Pjatn, Subb, Voskr. При этом каждой константе будет соответствовать свое конкретное число. Однако использование имен констант приведет к более понятной программе.

Более того, транслятор сам позволяет отслеживать правильность использования констант и при попытке использования константы, не входящей в объявленный заранее список, выдает сообщение об ошибке.

Переменные enum типа могут использоваться в индексных выражениях и как операнды в арифметических операциях и в операциях отношения. Например:

If(rab_ned == SUB) dejstvie = rabota [rab_ned];

При объявлении перечисления определяется тип переменной перечисления и определяется список именованных констант, называемый списком перечисления. Значением каждого имени этого списка является целое число. Объявление перечислимой переменной начинается с ключевого слова enum и может быть представлено в двух форматах:

  1. enum [имя типа перечисления] {список констант} имя1 [,имя2 …];
  2. enum имя перечисления описатель [,описатель..];

В первом формате имена и значения констант задаются в списке констант. Необязательное имя типа объявляемой переменной - это идентификатор, который представляет собой тип переменной, соответствующий списку констант. За списком констант записывается имя одной или нескольких переменных.

Список констант содержит одну или несколько конструкций вида:

идентификатор [= константное выражение]

Каждый идентификатор - это имя константы. Все идентификаторы в списке enum должны быть уникальными. В случае если константе явным образом не задается число, то первому идентификатору присваивается значение 0, следующему идентификатору - значение 1 и т.д.

Пример объявления переменной rab_ned и типа переменных, совместимых с этой переменной, week выглядит следующим образом:

enum week {SUB = 0, /* константе SUB присвоено значение 0 */
           VOS = 0, /* константе VOS присвоено значение 0 */
           POND,    /* константе POND присвоено значение 1 */
           VTOR,    /* константе VTOR присвоено значение 2 */
           SRED,    /* константе SRED присвоено значение 3 */
           HETV,    /* константе HETV присвоено значение 4 */
           PJAT     /* константе PJAT присвоено значение 5 */
          } rab_ned;

Идентификатор, связанный с константным выражением, принимает значение, задаваемое этим константным выражением. Результат вычисления константного выражения должен иметь тип int и может быть как положительным, так и отрицательным. Следующему идентификатору в списке, если этот идентификатор не имеет своего константного выражения, присваивается значение, равное константному выражению предыдущего идентификатора плюс 1. Использование констант должно подчиняться следующим правилам:

  1. Объявляемая переменная может содержать повторяющиеся значения констант.
  2. Идентификаторы в списке констант должны быть отличны от всех других идентификаторов в той же области видимости, включая имена обычных переменных и идентификаторы из других списков констант.
  3. Имена типов перечислений должны быть отличны от других имен типов перечислений, структур и смесей в этой же области видимости.
  4. Значение может следовать за последним элементом списка перечисления.

Во втором формате для объявления переменной перечислимого типа используется уже готовый тип переменной уже объявленный ранее. Например:

enum week rab1;

К переменной перечислимого типа можно обращаться при помощи указателей. При этом необходимо заранее определить тип переменной, на которую будет ссылаться указатель. Это может быть сделано, как описывалось выше или при помощи оператора 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;

Этот оператор не объявляет переменную, а только определяет тип переменной, отличающийся от стандартного. В дальнейшем этот тип может быть использован для объявления переменных и указателей на переменные.

1.2.6. Массивы

Массивы - это группа элементов одинакового типа (double, float, int и т.п.). Из объявления массива компилятор должен получить информацию о типе элементов массива и их количестве. Объявление массива имеет два формата:

спецификатор-типа описатель [константное-выражение];
спецификатор-типа описатель [ ];

Описатель - это идентификатор массива.

Спецификатор-типа задает тип элементов объявляемого массива. Элементами массива не могут быть функции и элементы типа void.

Константное-выражение в квадратных скобках задает количество элементов массива. Константное- выражение при объявлении массива может быть опущено в следующих случаях:

  • при объявлении массив инициализируется,
  • массив объявлен как формальный параметр функции,
  • массив объявлен как ссылка на массив, явно определенный в другом файле.

В языке СИ определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком константных-выражений следующих за идентификатором массива, причем каждое константное-выражение заключается в свои квадратные скобки.

Каждое константное-выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных-выражения, трехмерного - три и т.д. Отметим, что в языке СИ первый элемент массива имеет индекс равный 0.

Примеры:

     int a[2][3]; /* представлено в виде матрицы
                     a[0][0]  a[0][1] a[0][2]
                     a[1][0]  a[1][1] a[1][2] */
     double b[10]; /* вектор из 10  элементов имеющих тип double */
     int w[3][3] = { { 2, 3, 4 },
                     { 3, 4, 8 },
                     { 1, 0, 9 } };

В последнем примере объявлен массив w[3][3]. Списки, выделенные в фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.

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

Примеры:

int s[2][3];

Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s.

int b[2][3][4];

При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению наложенному на использование сечений массива.

Пример объявления массива символов.

char str[] = "объявление массива символов";

Следует учитывать, что в символьной строке находится на один элемент больше, так как последним элементом строки должен быть '\0'.

1.2.7. Структуры

Cтруктуры - это составной объект, в который входят элементы любых типов, за исключением функций. В отличие от массива, который является однородным объектом, структура может быть неоднородной. Тип структуры определяется записью вида:

struct { список определений }

В структуре обязательно должен быть указан хотя бы один компонент. Определение структур имеет следующий вид:

тип-данных описатель;

где тип-данных указывает тип структуры для объектов, определяемых в описателях. В простейшей форме описатели представляют собой идентификаторы или массивы.

Пример:

            struct { double x,y; } s1, s2, sm[9];
            struct {  int   year;
                      char  moth, day; } date1, date2;

Переменные s1, s2 определяются как структуры, каждая из которых состоит из двух компонент х и у. Переменная sm определяется как массив из девяти структур. Каждая из двух переменных date1, date2 состоит из трех компонентов year, moth, day. >p>Существует и другой способ связывания имени с типом структуры, он основан на использовании тега структуры. Тег структуры аналогичен тегу перечислимого типа. Тег структуры определяется следующим образом:

struct тег { список описаний; };

где тег является идентификатором.

В приведенном ниже примере идентификатор student описывается как тег структуры:

     struct student { char name[25];
                      int  id, age;
                      char  prp;         };

Тег структуры используется для последующего объявления структур данного вида в форме:

struct тег список-идентификаторов;

Пример:

struct studeut st1,st2;

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

        struct node { int data;
                      struct node * next; }   st1_node;

Тег структуры node действительно является рекурсивным, так как он используется в своем собственном описании, т.е. в формализации указателя next. Структуры не могут быть прямо рекурсивными, т.е. структура node не может содержать компоненту, являющуюся структурой node, но любая структура может иметь компоненту, являющуюся указателем на свой тип, как и сделано в приведенном примере.

Доступ к компонентам структуры осуществляется с помощью указания имени структуры и следующего через точку имени выделенного компонента, например:

          st1.name="Иванов";
          st2.id=st1.id;
          st1_node.data=st1.age;

1.2.8. Объединения (смеси)

Объединение подобно структуре, однако в каждый момент времени может использоваться (или другими словами быть ответным) только один из элементов объединения. Тип объединения может задаваться в следующем виде:

     union {   описание элемента 1;
               ...
               описание элемента n; };

Главной особенностью объединения является то, что для каждого из объявленных элементов выделяется одна и та же область памяти, т.е. они перекрываются. Хотя доступ к этой области памяти возможен с использованием любого из элементов, элемент для этой цели должен выбираться так, чтобы полученный результат не был бессмысленным.

Доступ к элементам объединения осуществляется тем же способом, что и к структурам. Тег объединения может быть формализован точно так же, как и тег структуры.

Объединение применяется для следующих целей:

- инициализации используемого объекта памяти, если в каждый момент времени только один объект из многих является активным;

- интерпретации основного представления объекта одного типа, как если бы этому объекту был присвоен другой тип.

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

Пример:

     union {   char  fio[30];
               char  adres[80];
               int   vozrast;
               int   telefon;   } inform;
     union {   int ax;
               char al[2];      }   ua;

При использовании объекта infor типа union можно обрабатывать только тот элемент который получил значение, т.е. после присвоения значения элементу inform.fio, не имеет смысла обращаться к другим элементам. Объединение ua позволяет получить отдельный доступ к младшему ua.al[0] и к старшему ua.al[1] байтам двухбайтного числа ua.ax .

1.2.9. Поля битов

Элементом структуры может быть битовое поле, обеспечивающее доступ к отдельным битам памяти. Вне структур битовые поля объявлять нельзя. Нельзя также организовывать массивы битовых полей и нельзя применять к полям операцию определения адреса. В общем случае тип структуры с битовым полем задается в следующем виде:

     struct { unsigned идентификатор 1 :  длина-поля  1;
              unsigned идентификатор 2 :  длина-поля  2;    }

длинна - поля задается целым выражением или константой. Эта константа определяет число битов, отведенное соответствующему полю. Поле нулевой длинны обозначает выравнивание на границу следующего слова.

Пример:

      struct { unsigned a1 :  1;
               unsigned a2 :  2;
               unsigned a3 :  5;
               unsigned a4 :  2;  } prim;

Структуры битовых полей могут содержать и знаковые компоненты. Такие компоненты автоматически размещаются на соответствующих границах слов, при этом некоторые биты слов могут оставаться неиспользованными.

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

1.2.10. Переменные с изменяемой структурой

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

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

       struct figure {
                double area,perimetr;  /* общие компоненты       */
                int type;              /* признак компонента     */
                union                  /* перечисление компонент */
                     { double radius;  /* окружность             */
                       double a[2];    /* прямоугольник          */
                       double b[3];    /* треугольник            */
                      } geom_fig;
                      }  fig1, fig2  ;

В общем случае каждый объект типа figure будет состоять из трех компонентов: area, perimetr, type. Компонент type называется меткой активного компонента, так как он используется для указания, какой из компонентов объединения geom_fig является активным в данный момент. Такая структура называется переменной структурой, потому что ее компоненты меняются в зависимости от значения метки активного компонента (значение type).

Отметим, что вместо компоненты type типа int, целесообразно было бы использовать перечисляемый тип. Например, такой

      enum figure_chess { CIRCLE,
                          BOX,
                          TRIANGLE    } ;

Константы CIRCLE, BOX, TRIANGLE получат значения соответственно равные 0, 1, 2. Переменная type может быть объявлена как имеющая перечислимый тип :

enum figure_chess type;

В этом случае компилятор СИ предупредит программиста о потенциально ошибочных присвоениях, таких, например, как

figure.type = 40;

В общем случае переменная структуры будет состоять из трех частей: набор общих компонент, метки активного компонента и части с меняющимися компонентами. Общая форма переменной структуры, имеет следующий вид:

     struct { общие компоненты;
              метка активного компонента;
                union { описание компоненты 1 ;
                        описание компоненты 2 ;
                        :::
                         описание компоненты n ;
                        } идентификатор-объединения ;
             } идентификатор-структуры ;

Пример определения переменной структуры с именем helth_record

     struct { /* общая информация */
               char  name [25];   /* имя       */
               int   age;         /* возраст   */
               char  sex;         /* пол       */
               /*   метка   активного   компонента  */
               /*   (семейное положение)            */
               enum merital_status ins;
               /* переменная часть */
               union  {   /* холост        */
                          /* нет компонент */
                        struct {  /* состоит в браке */
                                 char marripge_date[8];
                                 char spouse_name[25];
                                 int  no_children;
                                }  marriage_info;
                         /* разведен */
                         char date_divorced[8];
                       }   marital_info;
                } health_record;

       enum marital_status { SINGLE, /* холост   */
                            MARRIGO, /* женат    */
                            DIVOREED /* разведен */
                            } ;

Обращаться к компонентам структуры можно при помощи ссылок:

  helth_record.neme,
  helth_record.ins,
  helth_record.marriage_info.marriage_date .

1.2.11. Определение объектов и типов

Как уже говорилось выше, все переменные используемые в программах на языке СИ, должны быть объявлены. Тип объявляемой переменной зависит от того, какое ключевое слово используется в качестве спецификатора типа и является ли описатель простым идентификатором или же комбинацией идентификатора с модификатором указателя (звездочка), массива (квадратные скобки) или функции (круглые скобки).

При объявлении простой переменной, структуры, смеси или объединения, а также перечисления, описатель - это простой идентификатор. Для объявления указателя, массива или функции идентификатор модифицируется соответствующим образом: звездочкой слева, квадратными или круглыми скобками справа.

Отметим важную особенность языка СИ, при объявлении можно использовать одновременно более одного модификатора, что дает возможность создавать множество различных сложных описателей типов.

Однако надо помнить, что некоторые комбинации модификаторов недопустимы:

- элементами массивов не могут быть функции,

- функции не могут возвращать массивы или функции.

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

Для интерпретации сложных описаний предлагается простое правило, которое звучит как "изнутри наружу", и состоит из четырех шагов.

1. Начать с идентификатора и посмотреть вправо, есть ли квадратные или круглые скобки.

2. Если они есть, то проинтерпретировать эту часть описателя и затем посмотреть налево в поиске звездочки.

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

4. Интерпретировать спецификатор типа.

Примеры:

          int    * ( * comp [10]) ();
           6     5   3   1    2    4

В данном примере объявляется переменная comp (1), как массив из десяти (2) указателей (3) на функции (4), возвращающие указатели (5) на целые значения (6).

          char  * ( * ( * var ) () ) [10];
            7   6   4   2  1     3     5

Переменная var (1) объявлена как указатель (2) на функцию (3) возвращающую указатель (4) на массив (5) из 10 элементов, которые являются указателями (6) на значения типа char.

Кроме объявлений переменных различных типов, имеется возможность объявить типы. Это можно сделать двумя способами. Первый способ - указать имя тега при объявлении структуры, объединения или перечисления, а затем использовать это имя в объявлении переменных и функций в качестве ссылки на этот тег. Второй - использовать для объявления типа ключевое слово typedef.

При объявлении с ключевым словом typedef, идентификатор стоящий на месте описываемого объекта, является именем вводимого в рассмотрение типа данных, и далее этот тип может быть использован для объявления переменных.

Отметим, что любой тип может быть объявлен с использованием ключевого слова typedef, включая типы указателя, функции или массива. Имя с ключевым словом typedef для типов указателя, структуры, объединения может быть объявлено прежде чем эти типы будут определенны, но в пределах видимости объявителя.

Примеры:

        typedef double (* MATH)( );
          /* MATH - новое имя типа, представляющее указатель на
          функцию, возвращающую значения типа double           */
          MATH cos;
          /* cos  указатель на функцию, возвращающую
          значения типа  double                                 */
          /* Можно провести эквивалентное объявление            */
          double (* cos)( );

       typedef char FIO[40]
           /* FIO - массив из сорока символов                   */
       FIO person;
           /*  Переменная person  -  массив из сорока символов  */
           /*  Это  эквивалентно объявлению                     */
       char person[40];

При объявлении переменных и типов здесь были использованы имена типов (MATH FIO). Помимо этого, имена типов могут еще использоваться в трех случаях: в списке формальных параметров, в объявлении функций, в операциях приведения типов и в операции sizeof (операция приведения типа).

Именами типов для основных типов, типов перечисления, структуры и смеси являются спецификаторы типов для этих типов. Имена типов для типов указателя массива и функции задаются при помощи абстрактных описателей следующим образом:

спецификатор-типа абстрактный-описатель;

Абстрактный-описатель - это описатель без идентификатора, состоящий из одного или более модификаторов указателя, массива или функции. Модификатор указателя (*) всегда задается перед идентификатором в описателе, а модификаторы массива [] и функции () - после него. Таким образом, чтобы правильно интерпретировать абстрактный описатель, нужно начать интерпретацию с подразумеваемого идентификатора.

Абстрактные описатели могут быть сложными. Скобки в сложных абстрактных описателе задают порядок интерпретации подобно тому, как это делалось при интерпретации сложных описателей в объявлениях.

1.2.12. Инициализация данных

При объявлении переменной ей можно присвоить начальное значение, присоединяя инициатор к описателю. Инициатор начинается со знака "=" и имеет следующие формы.

Формат 1: = инициатор;

Формат 2: = { список - инициаторов };

Формат 1 используется при инициализации переменных основных типов и указателей, а формат 2 - при инициализации составных объектов.

Примеры:

char tol = 'N';

Переменная tol инициализируется символом 'N'.

const long megabute = (1024 * 1024);

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

static int b[2][2] = {1,2,3,4};

Инициализируется двухмерный массив b целых величин элементам массива присваиваются значения из списка. Эта же инициализация может быть выполнена следующим образом :

static int b[2][2] = { { 1,2 }, { 3,4 } };

При инициализации массива можно опустить одну или несколько размерностей

static int b[3[] = { { 1,2 }, { 3,4 } };

Если при инициализации указано меньше значений для строк, то оставшиеся элементы инициализируются 0, т.е. при описании

static int b[2][2] = { { 1,2 }, { 3 } };

элементы первой строки получат значения 1 и 2, а второй 3 и 0.

При инициализации составных объектов, нужно внимательно следить за использованием скобок и списков инициализаторов.

Примеры:

        struct complex { double real;
                         double 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} };

В этом примере компилятор интерпретирует рассматриваемые фигурные скобки следующим образом:

- первая левая фигурная скобка - начало составного инициатора для массива comp2;

- вторая левая фигурная скобка - начало инициализации первой строки массива comp2[0]. Значения 1,1 присваиваются двум элементам первой структуры;

- первая правая скобка (после 1) указывает компилятору, что список инициаторов для строки массива окончен, и элементы оставшихся структур в строке comp[0] автоматически инициализируются нулем;

- аналогично список {2,3} инициализирует первую структуру в строке comp[1], а оставшиеся структуры массива обращаются в нули;

- на следующий список инициализаторов {4,5} компилятор будет сообщать о возможной ошибке так как строка 3 в массиве comp2 отсутствует.

При инициализации объединения задается значение первого элемента объединения в соответствии с его типом.

Пример:

      union tab { unsigned char name[10];
                  int tab1;
                 }           pers  =  {'A','H','T','O','H'};

Инициализируется переменная pers.name, и так как это массив, для его инициализации требуется список значений в фигурных скобках. Первые пять элементов массива инициализируются значениями из списка, остальные нулями.

Инициализацию массива символов можно выполнить путем использования строкового литерала.

char stroka[ ] = "привет";

Инициализируется массив символов из 7 элементов, последним элементом (седьмым) будет символ '\0', которым завершаются все строковые литералы.

В том случае, если задается размер массива, а строковый литерал длиннее, чем размер массива, то лишние символы отбрасываются.

Следующее объявление инициализирует переменную stroka как массив, состоящий из семи элементов.

char stroka[5] = "привет";

Это объявление будет восприниматься как ошибка.

Если строка короче, чем размер массива, то оставшиеся элементы массива заполняются нулями.

Отметим, что инициализация переменной типа tab может иметь следующий вид:

union tab pers1 = "Антон";

и, таким образом, в символьный массив попадут символы:

'А','Н','Т','О','Н','\0',

а остальные элементы будут инициализированы нулем.


Программирование на языке СИ

1.3. Выражения и присваивания

1.3.1. Операнды и операции

Выражением называется комбинация знаков операций и операндов, результатом которой является определенное значение. Знаки операций определяют действия, которые должны быть выполнены над операндами. Каждый операнд в выражении в свою очередь может быть выражением. Значение выражения зависит от расположения знаков операций и круглых скобок в выражении, а также от приоритета выполнения операций.

В языке СИ присваивание также является выражением, и значением такого выражения является величина, которая присваивается.

При вычислении выражений тип каждого операнда может быть преобразован к другому типу. Преобразования типов могут быть неявными, при выполнении операций и вызовов функций, или явными, при выполнении операций приведения типов. Из за того, что неявные преобразования типов могут различаться для трансляторов разных фирм, то лучше использовать явное преобразование типов переменных.

Операнд - это константа, литеральная строка, идентификатор, вызов функции, индексное выражение, выражение выбора элемента или более сложное выражение, сформированное комбинацией операндов, знаков операций и круглых скобок. Любой операнд, который имеет константное значение, называется константным выражением. Каждый операнд имеет тип.

Если в качестве операнда используется константа, то ему соответствует значение и тип представляющей его константы. Целая константа может быть типа int, long, unsigned int, unsigned long, в зависимости от ее значения и от формы записи. Символьная константа имеет тип int. Константа с плавающей точкой всегда имеет тип double.

Литеральная строка состоит из последовательности символов, заключенных в кавычки, и представляется в памяти как массив элементов типа char, инициализируемый указанной последовательностью символов. Значением литеральной строки является адрес первого элемента строки и синтаксически литеральная строка является немодифицируемым указателем на тип char. Литеральные строки могут быть использованы в качестве операндов в выражениях, допускающих величины типа указателей. Однако так как строки не являются переменными, их нельзя использовать в левой части операции присваивания.

Следует помнить, что последним символом строки всегда является нулевой символ, который автоматически добавляется при хранении строки в памяти.

Идентификаторы переменных и функций. Каждый идентификатор имеет тип, который устанавливается при его объявлении. Значение идентификатора зависит от типа следующим образом:

  • идентификаторы объектов целых и плавающих типов представляют значения соответствующего типа;
  • идентификатор объекта типа enum представлен значением одной константы из множества значений констант, указанных в перечислении. Значением идентификатора является константное значение. Тип значения - int, что следует из определения перечисления;
  • идентификатор объекта типа struct или union представляет значение, определенное структурой или объединением;
  • идентификатор, объявляемый как указатель, представляет указатель на значение, заданное в объявлении типа;
  • идентификатор, объявляемый как массив, представляет указатель, значение которого является адресом первого элемента массива. Тип адресуемых указателем величин - это тип элементов массива. Отметим, что адрес массива не может быть изменен во время выполнения программы, хотя значение отдельных элементов может изменяться. Значение указателя, представляемое идентификатором массива, не является переменной и поэтому идентификатор массива не может появляться в левой части оператора присваивания.
  • идентификатор, объявляемый как функция, представляет указатель, значение которого является адресом функции, возвращающей значения определенного типа. Адрес функции не изменяется во время выполнения программы, меняется только возвращаемое значение. Таким образом, идентификаторы функций не могут появляться в левой части операции присваивания.

Вызов функций состоит из выражения, за которым следует необязательный список выражений в круглых скобках:

выражение-1 ([ список выражений ])

Значением выражения-1 должен быть адрес функции (например, идентификатор функции). Значения каждого выражения из списка выражений передается в функцию в качестве фактического аргумента. Операнд, являющийся вызовом функции, имеет тип и значение возвращаемого функцией значения.

Индексное выражение задает элемент массива и имеет вид:

выражение-1 [ выражение-2 ]

Тип индексного выражения является типом элементов массива, а значение представляет величину, адрес которой вычисляется с помощью значений выражение-1 и выражение-2.

Обычно выражение-1 - это указатель, например, идентификатор массива, а выражение-2 - это целая величина. Однако требуется только, чтобы одно из выражений было указателем, а второе целочисленной величиной. Поэтому выражение-1 может быть целочисленной величиной, а выражение-2 указателем. В любом случае выражение-2 должно быть заключено в квадратные скобки. Хотя индексное выражение обычно используется для ссылок на элементы массива, тем не менее индекс может появляться с любым указателем.

Индексные выражения для ссылки на элементы одномерного массива вычисляются путем сложения целой величины со значениями указателя с последующим применением к результату операции разадресации (*).

Так как одно из выражений, указанных в индексном выражении, является указателем, то при сложении используются правила адресной арифметики, согласно которым целая величина преобразуется к адресному представлению, путем умножения ее на размер типа, адресуемого указателем. Пусть, например, идентификатор arr объявлен как массив элементов типа double.

double arr[10];

Таким образом, чтобы получить доступ к i-тому элементу массива arr можно написать аrr[i], что, в силу сказанного выше, эквивалентно i[a]. При этом величина i умножается на размер типа double и представляет собой адрес i-го элемента массива arr от его начала. Затем это значение складывается со значением указателя arr, что в свою очередь дает адрес i-го элемента массива. К полученному адресу применяется операция разадресации, т.е. осуществляется выборка элемента массива arr по сформированному адресу.

Таким образом, результатом индексного выражения arr[i] (или i[arr]) является значение i-го элемента массива.

Выражение с несколькими индексами ссылается на элементы многомерных массивов. Многомерный массив - это массив, элементами которого являются массивы. Например, первым элементом трехмерного массива является массив с двумя измерениями.

Для ссылки на элемент многомерного массива индексное выражение должно иметь несколько индексов заключенных к квадратные скобки:

выражение-1 [ выражение-2 ][ выражение-3 ] ...

Такое индексное выражение интерпретируется слева направо, т.е. вначале рассматривается первое индексное выражение:

выражение-1 [ выражение-2 ]

Результат этого выражения есть адресное выражение, с которым складывается выражение-3 и т.д. Операция разадресации осуществляется после вычисления последнего индексного выражения. Отметим, что операция разадресации не применяется, если значение последнего указателя адресует величину типа массива.

Пример:

int mass [2][5][3];

Рассмотрим процесс вычисления индексного выражения mass[1][2][2].

  1. Вычисляется выражения mass[1]. Ссылка индекс 1 умножается на размер элемента этого массива, элементом же этого массива является двухмерный массив содержащий 5х3 элементов, имеющих тип int. Получаемое значение складывается со значением указателя mass. Результатом является указатель на второй двухмерный массив размером (5х3) в трехмерном массиве mass.
  2. Второй индекс 2 указывает на размер массива из трех элементов типа int, и складывается с адресом, соответствующим mass [1].
  3. Так как каждый элемент трехмерного массива - это величина типа int, то индекс 2 увеличивается на размер типа int перед сложением с адресом mass [1][2].
  4. Наконец, выполняется разадресация полученного указателя. Результирующим выражением будет элемент типа int.

Если было бы указано mass [1][2], то результатом был бы указатель на массив из трех элементов типа int. Соответственно значением индексного выражения mass [1] является указатель на двухмерный массив.

Выражение выбора элемента применяется, если в качестве операнда надо использовать элемент структуры или объединения. Такое выражение имеет значение и тип выбранного элемента. Рассмотрим две формы выражения выбора элемента:

выражение.идентификатор,

выражение->идентификатор.

В первой форме выражение представляет величину типа 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;
      double x;
      b = (double)i+2.0;

В этом примере целая переменная i с помощью операции приведения типов приводится к плавающему типу, а затем уже участвует в вычислении выражения.

Константное выражение - это выражение, результатом которого является константа. Операндом константного выражения могут быть целые константы, символьные константы, константы с плавающей точкой, константы перечисления, выражения приведения типов, выражения с операцией sizeof и другие константные выражения. Однако на использование знаков операций в константных выражениях налагаются следующие ограничения:

  1. В константных выражениях нельзя использовать операции присваивания и последовательного вычисления (,) .
  2. Операция "адрес" (&) может быть использована только при некоторых инициализациях.

Выражения со знаками операций могут участвовать в выражениях как операнды. Выражения со знаками операций могут быть унарными (с одним операндом), бинарными (с двумя операндами) и тернарными (с тремя операндами).

Унарное выражение состоит из операнда и предшествующего ему знаку унарной операции и имеет следующий формат:

знак-унарной-операции операнд .

Бинарное выражения состоит из двух операндов, разделенных знаком бинарной операции:

операнд1 знак-бинарной-операции операнд2 .

Тернарное выражение состоит из трех операндов, разделенных знаками тернарной операции (?) и (:), и имеет формат:

операнд1 ? операнд2 : операнд3 .

Операции. По количеству операндов, участвующих в операции, операции подразделяются на унарные, бинарные и тернарные.

В языке Си имеются следующие унарные операции:

- арифметическое отрицание (отрицание и дополнение);

~ побитовое логическое отрицание (дополнение);

! логическое отрицание;

* разадресация (косвенная адресация);

& вычисление адреса;

+ унарный плюс;

++ увеличение (инкремент);

-- уменьшение (декремент);

sizeof размер .

Унарные операции выполняются справа налево.

Операции увеличения и уменьшения увеличивают или уменьшают значение операнда на единицу и могут быть записаны как справа так и слева от операнда. Если знак операции записан перед операндом (префиксная форма), то изменение операнда происходит до его использования в выражении. Если знак операции записан после операнда (постфиксная форма), то операнд вначале используется в выражении, а затем происходит его изменение.

В отличие от унарных, бинарные операции, список которых приведен в табл.7, выполняются слева направо.

Таблица 7

Знак операции | Операция | Группа операций
* | Умножение | Мультипликативные
/ | Деление
% | Остаток от деления
+ | Сложение | Аддитивные
- | Вычитание
<< | Сдвиг влево | Операции сдвига
>> | Сдвиг вправо
< | Меньше | Операции отношения
<= | Меньше или равно
>= | Больше или равно
== | Равно
!= | Не равно
& | Поразрядное И | Поразрядные операции
| | Поразрядное ИЛИ
^ | Поразрядное исключающее ИЛИ
&& | Логическое И | Логические операции
|| | Логическое ИЛИ
, | Последовательное вычисление | Последовательного вычисления
= | Присваивание | Операции присваивания
*= | Умножение с присваиванием
/= | Деление с присваиванием
%= | Остаток от деления с присваиванием
-= | Вычитание с присваиванием
+= | Сложение с присваиванием
<<= | Сдвиг влево с присваиванием
>>= | Сдвиг вправо присваиванием
&= | Поразрядное И с присваиванием
|= | Поразрядное ИЛИ с присваиванием
^= | Поразрядное исключающее ИЛИ с присваиванием

Левый операнд операции присваивания должен быть выражением, ссылающимся на область памяти (но не объектом объявленным с ключевым словом const), такие выражения называются леводопустимыми к ним относятся:

- идентификаторы данных целого и плавающего типов, типов указателя, структуры, объединения;

- индексные выражения, исключая выражения имеющие тип массива или функции;

- выражения выбора элемента (->) и (.), если выбранный элемент является леводопустимым;

- выражения унарной операции разадресации (*), за исключением выражений, ссылающихся на массив или функцию;

- выражение приведения типа если результирующий тип не превышает размера первоначального типа.

При записи выражений следует помнить, что символы (*), (&), (!), (+) могут\ обозначать унарную или бинарную операцию.

1.3.2. Преобразования при вычислении выражений

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

Рассмотрим общие арифметические преобразования.

1. Операнды типа float преобразуются к типу double.

2. Если один операнд long double, то второй преобразуется к этому же типу.

3. Если один операнд double, то второй также преобразуется к типу double.

4. Любые операнды типа char и short преобразуются к типу int.

5. Любые операнды unsigned char или unsigned short преобразуются к типу unsigned int.

6. Если один операнд типа unsigned long, то второй преобразуется к типу unsigned long.

7. Если один операнд типа long, то второй преобразуется к типу long.

8. Если один операнд типа unsigned int, то второй операнд преобразуется к этому же типу.

Таким образом, можно отметить, что при вычислении выражений операнды преобразуются к типу того операнда, который имеет наибольший размер.

Пример:

        double         ft,sd;
        unsigned char  ch;
        unsigned long  in;
        int            i;
        ....
           sd=ft*(i+ch/in);

При выполнении оператора присваивания правила преобразования будут использоваться следующим образом. Операнд ch преобразуется к unsigned int (правило 5). Затем он преобразуется к типу unsigned long (правило 6). По этому же правилу i преобразуется к unsigned long и результат операции, заключенной в круглые скобки будет иметь тип unsigned long. Затем он преобразуется к типу double (правило 3) и результат всего выражения будет иметь тип double.

1.3.3. Операции отрицания и дополнения

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

Пример:

       double  u = 5;
       u = -u;          /* переменной u присваивается ее отрицание,
                            т.е. u  принимает значение -5     */

Операция логического отрицания "НЕ" (!) вырабатывает значение 0, если операнд есть истина (не нуль), и значение 1, если операнд равен нулю (0). Результат имеет тип int. Операнд должен быть целого или плавающего типа или типа указатель.

Пример:

       int t, z=0;
       t=!z;

Переменная t получит значение равное 1, так как переменная z имела значение равное 0 (ложно).

Операция двоичного дополнения (~) вырабатывает двоичное дополнение своего операнда. Операнд должен быть целого типа. Осуществляется обычное арифметическое преобразование, результат имеет тип операнда после преобразования.

Пример:

       char            b = '9';
       unsigned char   f;
        b = ~f;

Шестнадцатеричное значение символа '9' равно 39. В результате операции ~f будет получено шестнадцатеричное значение С6, что соответствует символу 'ц'.

1.3.4. Операции разадресации и адреса

Эти операции используются для работы с переменными типа указатель.

Операция разадресации (*) осуществляет косвенный доступ к адресуемой величине через указатель. Операнд должен быть указателем. Результатом операции является величина, на которую указывает операнд. Типом результата является тип величины, адресуемой указателем. Результат не определен, если указатель содержит недопустимый адрес.

Рассмотрим типичные ситуации, когда указатель содержит недопустимый адрес:

- указатель является нулевым;

- указатель определяет адрес такого объекта, который не является активным в момент ссылки;

- указатель определяет адрес, который не выровнен до типа объекта, на который он указывает;

- указатель определяет адрес, не используемый выполняющейся программой.

Операция адрес (&) дает адрес своего операнда. Операндом может быть любое именуемое выражение. Имя функции или массива также может быть операндом операции "адрес", хотя в этом случае знак операции является лишним, так как имена массивов и функций являются адресами. Результатом операции адрес является указатель на операнд. Тип, адресуемый указателем, является типом операнда.

Операция адрес не может применятся к элементам структуры, являющимися полями битов, и к объектам с классом памяти register.

Примеры:

      int t, f=0,  * adress;
      adress = &t /* переменной adress, объявляемой как
                     указатель, присваивается адрес переменной t */
     * adress =f; /* переменной находящейся по адресу, содержащемуся
                     в переменной adress, присваивается значение
                     переменной f,  т.е.  0 , что эквивалентно
                     t=f;      т.е.   t=0;                       */

1.3.5. Операция sizeof

С помощью операции sizeof можно определить размер памяти которая соответствует идентификатору или типу. Операция sizeof имеет следующий формат:

sizeof(выражение) .

В качестве выражения может быть использован любой идентификатор, либо имя типа, заключенное в скобки. Отметим, что не может быть использовано имя типа void, а идентификатор не может относится к полю битов или быть именем функции.

Если в качестве выражения указанно имя массива, то результатом является размер всего массива (т.е. произведение числа элементов на длину типа), а не размер указателя, соответствующего идентификатору массива.

Когда sizeof применяются к имени типа структуры или объединения или к идентификатору имеющему тип структуры или объединения, то результатом является фактический размер структуры или объединения, который может включать участки памяти, используемые для выравнивания элементов структуры или объединения. Таким образом, этот результат может не соответствовать размеру, получаемому путем сложения размеров элементов структуры.

Пример:

      struct     { char   h;
                   int    b;
                   double f;
                 } str;
      int a1;
      a1  = sizeof(str);

Переменная а1 получит значение, равное 12, в то же время если сложить длины всех используемых в структуре типов, то получим, что длина структуры str равна 7.

Несоответствие имеет место в виду того, что после размещения в памяти первой переменной h длинной 1 байт, добавляется 1 байт для выравнивания адреса переменной b на границу слова (слово имеет длину 2 байта для машин серии IBM PC AT /286/287), далее осуществляется выравнивание адреса переменной f на границу двойного слова (4 байта), таким образом в результате операций выравнивания для размещения структуры в оперативной памяти требуется на 5 байт больше.

В связи с этим целесообразно рекомендовать при объявлении структур и объединения располагать их элементы в порядке убывания длины типов, т.е. приведенную выше структуру следует записать в следующем виде:

     struct  { double f;
               int    b;
               char   h;
              } str;

1.3.6. Мультипликативные операции

К этому классу операций относятся операции умножения (*), деления (/) и получение остатка от деления (%). Операндами операции (%) должны быть целые числа. Отметим, что типы операндов операций умножения и деления могут отличаться, и для них справедливы правила преобразования типов. Типом результата является тип операндов после преобразования.

Операция умножения (*) выполняет умножение операндов.

     int  i=5;
     float f=0.2;
     double g,z;
         g=f*i;

Тип произведения i и f преобразуется к типу double, затем результат присваивается переменной g.

Операция деления (/) выполняет деление первого операнда на второй. Если две целые величины не делятся нацело, то результат округляется в сторону нуля.

При попытке деления на ноль выдается сообщение во время выполнения.

     int i=49, j=10,  n, m;
     n = i/j;                 /* результат   4   */
     m = i/(-j);              /* результат  -4   */

Операция остаток от деления (%) дает остаток от деления первого операнда на второй.

Знак результата зависит от конкретной реализации. В данной реализации знак результата совпадает со знаком делимого. Если второй операнд равен нулю, то выдается сообщение.

     int n = 49, m = 10, i, j, k, l;
     i = n % m;             /*    9    */
     j = n % (-m);          /*    9    */
     k = (-n) % m;          /*    -9   */
     l = (-n) % (-m);       /*    -9   */

1.3.7. Аддитивные операции

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

Пример:

     int   i=30000, j=30000, k;
            k=i+j;

В результате сложения k получит значение равное -5536.

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

Когда целая величина складывается с указателем, то целая величина преобразуется путем умножения ее на размер памяти, занимаемой величиной, адресуемой указателем.

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

Операция вычитания (-) вычитает второй операнд из первого. Возможна следующая комбинация операндов:

1. Оба операнда целого или плавающего типа.

2. Оба операнда являются указателями на один и тот же тип.

3. Первый операнд является указателем, а второй - целым.

Отметим, что операции сложения и вычитания над адресами в единицах, отличных от длины типа, могут привести к непредсказуемым результатам.

Пример:

     double d[10],* u;
     int i;
     u = d+2;  /*  u  указывает на третий элемент массива */
     i = u-d;  /*  i  принимает значение равное 2         */

1.3.8. Операции сдвига

Операции сдвига осуществляют смещение операнда влево (<<) или вправо (>>) на число битов, задаваемое вторым операндом. Оба операнда должны быть целыми величинами. Выполняются обычные арифметические преобразования. При сдвиге влево правые освобождающиеся биты устанавливаются в нуль. При сдвиге вправо метод заполнения освобождающихся левых битов зависит от типа первого операнда. Если тип unsigned, то свободные левые биты устанавливаются в нуль. В противном случае они заполняются копией знакового бита. Результат операции сдвига не определен, если второй операнд отрицательный.

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

Отметим, что сдвиг влево соответствует умножению первого операнда на степень числа 2, равную второму операнду, а сдвиг вправо соответствует делению первого операнда на 2 в степени, равной второму операнду.

Примеры:

      int  i=0x1234, j,  k ;
      k = i<<4 ; /* k="0x0234" */ j="i<<8" ; /* j="0x3400" */ i="j">>8 ;         /*    i = 0x0034   */

1.3.9. Поразрядные операции

К поразрядным операциям относятся: операция поразрядного логического "И" (&), операция поразрядного логического "ИЛИ" (|), операция поразрядного "исключающего ИЛИ" (^).

Операнды поразрядных операций могут быть любого целого типа. При необходимости над операндами выполняются преобразования по умолчанию, тип результата - это тип операндов после преобразования.

Операция поразрядного логического И (&) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если оба сравниваемых бита единицы, то соответствующий бит результата устанавливается в 1, в противном случае в 0.

Операция поразрядного логического ИЛИ (|) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если любой (или оба) из сравниваемых битов равен 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 0000 0000   */
       r = i&j      /* r=0x00FF = 0000 0000 1111 1111    */

1.3.10. Логические операции

К логическим операциям относятся операция логического И (&&) и операция логического ИЛИ (||). Операнды логических операций могут быть целого типа, плавающего типа или типа указателя, при этом в каждой операции могут участвовать операнды различных типов.

Операнды логических выражений вычисляются слева направо. Если значения первого операнда достаточно, чтобы определить результат операции, то второй операнд не вычисляется.

Логические операции не вызывают стандартных арифметических преобразований. Они оценивают каждый операнд с точки зрения его эквивалентности нулю. Результатом логической операции является 0 или 1, тип результата int.

Операция логического И (&&) вырабатывает значение 1, если оба операнда имеют нулевые значения. Если один из операндов равен 0, то результат также равен 0. Если значение первого операнда равно 0, то второй операнд не вычисляется.

Операция логического ИЛИ (||) выполняет над операндами операцию включающего ИЛИ. Она вырабатывает значение 0, если оба операнда имеют значение 0, если какой-либо из операндов имеет ненулевое значение, то результат операции равен 1. Если первый операнд имеет ненулевое значение, то второй операнд не вычисляется.

1.3.11. Операция последовательного вычисления

Операция последовательного вычисления обозначается запятой (,) и используется для вычисления двух и более выражений там, где по синтаксису допустимо только одно выражение. Эта операция вычисляет два операнда слева направо. При выполнении операции последовательного вычисления, преобразование типов не производится. Операнды могут быть любых типов. Результат операции имеет значения и тип второго операнда. Отметим, что запятая может использоваться также как символ разделитель, поэтому необходимо по контексту различать, запятую, используемую в качестве разделителя или знака операции.

1.3.12. Условная операция

В языке СИ имеется одна тернарная операция - условная операция, которая имеет следующий формат:

операнд-1 ? операнд-2 : операнд-3

Операнд-1 должен быть целого или плавающего типа или быть указателем. Он оценивается с точки зрения его эквивалентности 0. Если операнд-1 не равен 0, то вычисляется операнд-2 и его значение является результатом операции. Если операнд-1 равен 0, то вычисляется операнд-3 и его значение является результатом операции. Следует отметить, что вычисляется либо операнд-2, либо операнд-3, но не оба. Тип результата зависит от типов операнда-2 и операнда-3, следующим образом.

1. Если операнд-2 или операнд-3 имеет целый или плавающий тип (отметим, что их типы могут отличаться), то выполняются обычные арифметические преобразования. Типом результата является тип операнда после преобразования.

2. Если операнд-2 и операнд-3 имеют один и тот же тип структуры, объединения или указателя, то тип результата будет тем же самым типом структуры, объединения или указателя.

3. Если оба операнда имеют тип void, то результат имеет тип void.

4. Если один операнд является указателем на объект любого типа, а другой операнд является указателем на vold, то указатель на объект преобразуется к указателю на vold, который и будет типом результата.

5. Если один из операндов является указателем, а другой константным выражением со значением 0, то типом результата будет тип указателя.

Пример:

max = (d<=b) ? b : d;

Переменной max присваивается максимальное значение переменных d и b.

1.3.13. Операции увеличения и уменьшения

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

Если знак операции стоит перед операндом (префиксная форма записи), то изменение операнда происходит до его использования в выражении и результатом операции является увеличенное или уменьшенное значение операнда.

В том случае если знак операции стоит после операнда (постфиксная форма записи), то операнд вначале используется для вычисления выражения, а затем происходит изменение операнда.

Примеры:

      int t=1, s=2, z, f;
           z=(t++)*5;

Вначале происходит умножение t*5, а затем увеличение t. В результате получится z=5, t=2.

           f=(++s)/3;

Вначале значение s увеличивается, а затем используется в операции деления. В результате получим s=3, f=1.

В случае, если операции увеличения и уменьшения используются как самостоятельные операторы, префиксная и постфиксная формы записи становятся эквивалентными.

z++; /* эквивалентно */ ++z;

1.3.14. Простое присваивание

Операция простого присваивания используется для замены значения левого операнда, значением правого операнда. При присваивании производится преобразование типа правого операнда к типу левого операнда по правилам, упомянутым раньше. Левый операнд должен быть модифицируемым.

Пример:

       int t;
       char f;
       long z;
       t=f+z;

Значение переменной f преобразуется к типу long, вычисляется f+z ,результат преобразуется к типу int и затем присваивается переменной t.

1.3.15. Составное присваивание

Кроме простого присваивания, имеется целая группа операций присваивания, которые объединяют простое присваивание с одной из бинарных операций. Такие операции называются составными операциями присваивания и имеют вид:

(операнд-1) (бинарная операция) = (операнд-2) .

Составное присваивание по результату эквивалентно следующему простому присваиванию:

(операнд-1) = (операнд-1) (бинарное операция) (операнд-2) .

Отметим, что выражение составного присваивания с точки зрения реализации не эквивалентно простому присваиванию, так как в последнем операнд-1 вычисляется дважды.

Каждая операция составного присваивания выполняет преобразования, которые осуществляются соответствующей бинарной операцией. Левым операндом операций (+=) (-=) может быть указатель, в то время как правый операнд должен быть целым числом.

Примеры:

     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+1;    /*  эквивалентно   arr[3]=arr[3]/(b+1)   */

Заметим, что при втором присваивании использование составного присваивания дает более заметный выигрыш во времени выполнения, так как левый операнд является индексным выражением.

1.3.16. Приоритеты операций и порядок вычислений

В языке СИ операции с высшими приоритетами вычисляются первыми. Наивысшим приоритетом является приоритет равный 1. Приоритеты и порядок операций приведены в табл. 8.

Таблица 8

Приоритет | Знак операции | Типы операции | Порядок выполнения
2 | () [] . -> | Выражение | Слева направо
1 | - ~ ! * & ++ -- sizeof приведение типов | Унарные | Справа налево
3 | * / % | Мультипликативные | Слева направо
4 | + - | Аддитивные
5 | << >> | Сдвиг
6 | < > <= >= | Отношение
7 | == != | Отношение (равенство)
8 | & | Поразрядное И
9 | ^ | Поразрядное исключающее ИЛИ
10 | | | Поразрядное ИЛИ
11 | && | Логическое И
12 | || | Логическое ИЛИ
13 | ? : | Условная
14 | = *= /= %= += -= &= |= >>= <<= ^= | Простое и составное присваивание | Справа налево
15 | , | Последовательное вычисление | Слева направо

1.3.17. Побочные эффекты

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

prog (a,a=k*2);

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

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

Например, выражение i*j+(j++)+(--i) может принимать различные значения при обработке разными компиляторами. Чтобы избежать недоразумений при выполнении побочных эффектов необходимо придерживаться следующих правил.

1. Не использовать операции присваивания переменной в вызове функции, если эта переменная участвует в формировании других аргументов функции.

2. Не использовать операции присваивания переменной в выражении, если эта переменная используется в выражении более одного раза.

1.3.18. Преобразование типов

При выполнении операций происходят неявные преобразования типов в следующих случаях:

- при выполнении операций осуществляются обычные арифметические преобразования (которые были рассмотрены выше);

- при выполнении операций присваивания, если значение одного типа присваивается переменной другого типа;

- при передаче аргументов функции.

Кроме того, в Си есть возможность явного приведения значения одного типа к другому.

В операциях присваивания тип значения, которое присваивается, преобразуется к типу переменной, получающей это значение. Допускается преобразования целых и плавающих типов, даже если такое преобразование ведет к потере информации.

Преобразование целых типов со знаком. Целое со знаком преобразуется к более короткому целому со знаком, посредством усечения старших битов. Целая со знаком преобразуется к более длинному целому со знаком, путем размножения знака. При преобразовании целого со знаком к целому без знака, целое со знаком преобразуется к размеру целого без знака и результат рассматривается как значение без знака.

Преобразование целого со знаком к плавающему типу происходит без потери] информации, за исключением случая преобразования значения типа long int или unsigned long int к типу float, когда точность часто может быть потеряна.

Преобразование целых типов без знака. Целое без знака преобразуется к более короткому целому без знака или со знаком путем усечения старших битов. Целое без знака преобразуется к более длинному целому без знака или со знаком путем дополнения нулей слева.

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

Целые значения без знака преобразуются к плавающему типу, путем преобразования целого без знака к значению типа signed long, а затем значение signed long преобразуется в плавающий тип. Преобразования из unsigned long к типу float, double или long double производятся с потерей информации, если преобразуемое значение больше, чем максимальное положительное значение, которое может быть представлено для типа long.

Преобразования плавающих типов. Величины типа float преобразуются к типу double без изменения значения. Величины double и long double преобразуются к float c некоторой потерей точности. Если значение слишком велико для float, то происходит потеря значимости, о чем сообщается во время выполнения.

При преобразовании величины с плавающей точкой к целым типам она сначала преобразуется к типу long (дробная часть плавающей величины при этом отбрасывается), а затем величина типа long преобразуется к требуемому целому типу. Если значение слишком велико для long, то результат преобразования не определен.

Преобразования из float, double или long double к типу unsigned long производится с потерей точности, если преобразуемое значение больше, чем максимально возможное положительное значение, представленное типом long.

Преобразование типов указателя. Указатель на величину одного типа может быть преобразован к указателю на величину другого типа. Однако результат может быть не определен из-за отличий в требованиях к выравниванию и размерах для различных типов.

Указатель на тип void может быть преобразован к указателю на любой тип, и указатель на любой тип может быть преобразован к указателю на тип void без ограничений. Значение указателя может быть преобразовано к целой величине. Метод преобразования зависит от размера указателя и размера целого типа следующим образом:

- если размер указателя меньше размера целого типа или равен ему, то указатель преобразуется точно так же, как целое без знака;

- если указатель больше, чем размер целого типа, то указатель сначала преобразуется к указателю с тем же размером, что и целый тип, и затем преобразуется к целому типу.

Целый тип может быть преобразован к адресному типу по следующим правилам:

- если целый тип того же размера, что и указатель, то целая величина просто рассматривается как указатель (целое без знака);

- если размер целого типа отличен от размера указателя, то целый тип сначала преобразуется к размеру указателя (используются способы преобразования, описанные выше), а затем полученное значение трактуется как указатель.

Преобразования при вызове функции. Преобразования, выполняемые над аргументами при вызове функции, зависят от того, был ли задан прототип функции (объявление "вперед") со списком объявлений типов аргументов.

Если задан прототип функции и он включает объявление типов аргументов, то над аргументами в вызове функции выполняются только обычные арифметические преобразования.

Эти преобразования выполняются независимо для каждого аргумента. Величины типа float преобразуются к double, величины типа char и short преобразуются к int, величины типов unsigned char и unsigned short преобразуются к unsigned int. Могут быть также выполнены неявные преобразования переменных типа указатель. Задавая прототипы функций, можно переопределить эти неявные преобразования и позволить компилятору выполнить контроль типов.

Преобразования при приведении типов. Явное преобразование типов может быть осуществлено посредством операции приведения типов, которая имеет формат:

( имя-типа ) операнд .

В приведенной записи имя-типа задает тип, к которому должен быть преобразован операнд.

Пример:

         int     i=2;
         long    l=2;
         double    d;
         float     f;
         d=(double)i * (double)l;
         f=(float)d;

В данном примере величины i,l,d будут явно преобразовываться к указанным в круглых скобках типам.


Программирование на языке СИ

1.4. Операторы

Все операторы языка СИ могут быть условно разделены на следующие категории:

- условные операторы, к которым относятся оператор условия if и оператор выбора switch;

- операторы цикла (for,while,do while);

- операторы перехода (break, continue, return, goto);

- другие операторы (оператор "выражение", пустой оператор).

Операторы в программе могут объединяться в составные операторы с помощью фигурных скобок. Любой оператор в программе может быть помечен меткой, состоящей из имени и следующего за ним двоеточия.

Все операторы языка СИ, кроме составных операторов, заканчиваются точкой с запятой ";".

1.4.1. Оператор выражение

Любое выражение, которое заканчивается точкой с запятой, является оператором.

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

Примеры:

++ i;

Этот оператор представляет выражение, которое увеличивает значение переменной i на единицу.

a=cos(b * 5);

Этот оператор представляет выражение, включающее в себя операции присваивания и вызова функции.

a(x,y);

Этот оператор представляет выражение состоящее из вызова функции.

1.4.2. Пустой оператор

Пустой оператор состоит только из точки с запятой. При выполнении этого оператора ничего не происходит. Он обычно используется в следующих случаях:

- в операторах do, for, while, if в строках, когда место оператора не требуется, но по синтаксису требуется хотя бы один оператор;

- при необходимости пометить фигурную скобку.

Синтаксис языка СИ требует, чтобы после метки обязательно следовал оператор. Фигурная же скобка оператором не является. Поэтому, если надо передать управление на фигурную скобку, необходимо использовать пустой оператор.

Пример:

     int main ( )
     {
          :
           { if (...) goto a;    /* переход на скобку */
               { ...
               }
      a:;  }
           return 0;
       }

1.4.3. Составной оператор

Составной оператор представляет собой несколько операторов и объявлений, заключенных в фигурные скобки:

       {  [oбъявление]
           :
           оператор; [оператор];
           :
       }

Заметим, что в конце составного оператора точка с запятой не ставится.

Выполнение составного оператора заключается в последовательном выполнении составляющих его операторов.

Пример:

        int main ()
        {
          int    q,b;
          double t,d;
            :
            if (...)
              {
                int    e,g;
                double f,q;
                :
               }
            :
            return (0);
        }

Переменные e,g,f,q будут уничтожены после выполнения составного оператора. Отметим, что переменная q является локальной в составном операторе, т.е. она никоим образом не связана с переменной q объявленной в начале функции main с типом int. Отметим также, что выражение стоящее после return может быть заключено в круглые скобки, хотя наличие последних необязательно.

1.4.4. Оператор if

Формат оператора:

if (выражение) оператор-1; [else оператор-2;]

Выполнение оператора if начинается с вычисления выражения.

Далее выполнение осуществляется по следующей схеме:

- если выражение истинно (т.е. отлично от 0), то выполняется оператор-1.

- если выражение ложно (т.е. равно 0),то выполняется оператор-2.

- если выражение ложно и отсутствует оператор-2 (в квадратные скобки заключена необязательная конструкция), то выполняется следующий за if оператор.

После выполнения оператора if значение передается на следующий оператор программы, если последовательность выполнения операторов программы не будет принудительно нарушена использованием операторов перехода.

Пример:

                  if (i < j)   i++:
                  else { j = i-3;   i++; }

Этот пример иллюстрирует также и тот факт, что на месте оператор-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 (0);
         }

В результате выполнения этой программы r станет равным 2.

Если же в программе опустить фигурные скобки, стоящие после оператора if, то программа будет иметь следующий вид:

        int main  ( )
         {
           int t=2,b=7,r=3;
           if ( a>b )
               if ( b < c ) t=b;
               else       r=t;
           return (0);
          }

В этом случае r получит значение равное 3, так как ключевое слово else относится ко второму оператору if, который не выполняется, поскольку не выполняется условие, проверяемое в первом операторе if.

Следующий фрагмент иллюстрирует вложенные операторы if:

     char ZNAC;
     int x,y,z;
       :
      if (ZNAC == '-') x = y - z;
      else  if (ZNAC == '+') x = y + z;
            else if (ZNAC == '*') x = y * z;
                  else if (ZNAC == '/') x = y / z;
                        else ...

Из рассмотрения этого примера можно сделать вывод, что конструкции использующие вложенные операторы if, являются довольно громоздкими и не всегда достаточно надежными. Другим способом организации выбора из множества различных вариантов является использование специального оператора выбора switch.

1.4.5. Оператор switch

Оператор switch предназначен для организации выбора из множества различных вариантов. Формат оператора следующий:

     switch ( выражение )
     {   [объявление]
              :
           [ case  константное-выражение1]: [ список-операторов1]
           [ case  константное-выражение2]: [ список-операторов2]
              :
              :
           [ default: [ список операторов ]]
     }

Выражение, следующее за ключевым словом switch в круглых скобках, может быть любым выражением, допустимыми в языке СИ, значение которого должно быть целым. Отметим, что можно использовать явное приведение к целому типу, однако необходимо помнить о тех ограничениях и рекомендациях, о которых говорилось выше.

Значение этого выражения является ключевым для выбора из нескольких вариантов. Тело оператора smitch состоит из нескольких операторов, помеченных ключевым словом case с последующим константным-выражением. Следует отметить, что использование целого константного выражения является существенным недостатком, присущим рассмотренному оператору.

Так как константное выражение вычисляется во время трансляции, оно не может содержать переменные или вызовы функций. Обычно в качестве константного выражения используются целые или символьные константы.

Все константные выражения в операторе switch должны быть уникальны. Кроме операторов, помеченных ключевым словом case, может быть, но обязательно один, фрагмент помеченный ключевым словом default.

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

Отметим также, что в операторе switch можно использовать свои локальные переменные, объявления которых находятся перед первым ключевым словом case, однако в объявлениях не должна использоваться инициализация.

Схема выполнения оператора switch следующая:

- вычисляется выражение в круглых скобках;

- вычисленные значения последовательно сравниваются с константными выражениями, следующими за ключевыми словами case;

- если одно из константных выражений совпадает со значением выражения, то управление передается на оператор, помеченный соответствующим ключевым словом case;

- если ни одно из константных выражений не равно выражению, то управление передается на оператор, помеченный ключевым словом default, а в случае его отсутствия управление передается на следующий после switch оператор.

Отметим интересную особенность использования оператора switch: конструкция со словом default может быть не последней в теле оператора switch. Ключевые слова case и default в теле оператора switch существенны только при начальной проверке, когда определяется начальная точка выполнения тела оператора switch. Все операторы, между начальным оператором и концом тела, выполняются вне зависимости от ключевых слов, если только какой-то из операторов не передаст управления из тела оператора switch. Таким образом, программист должен сам позаботится о выходе из case, если это необходимо. Чаще всего для этого используется оператор break.

Для того, чтобы выполнить одни и те же действия для различных значений выражения, можно пометить один и тот же оператор несколькими ключевыми словами case.

Пример:

      int i=2;
      switch (i)
        {
         case 1: i += 2;
         case 2: i *= 3;
         case 0: i /= 2;
         case 4: i -= 5;
         default:      ;
     }

Выполнение оператора switch начинается с оператора, помеченного case 2. Таким образом, переменная i получает значение, равное 6, далее выполняется оператор, помеченный ключевым словом case 0, а затем case 4, переменная i примет значение 3, а затем значение -2. Оператор, помеченный ключевым словом default, не изменяет значения переменной.

Рассмотрим ранее приведенный пример, в котором иллюстрировалось использование вложенных операторов if, переписанной теперь с использованием оператора switch.

     char ZNAC;
     int x,y,z;
     switch (ZNAC)
     {
          case '+':  x = y + z;    break;
          case '-':  x = y - z;    break;
          case '*':  x = y * z;    break;
          case '/':  x = u / z;    break;
          default : ;
        }

Использование оператора break позволяет в необходимый момент прервать последовательность выполняемых операторов в теле оператора switch, путем передачи управления оператору, следующему за switch.

Отметим, что в теле оператора switch можно использовать вложенные операторы switch, при этом в ключевых словах case можно использовать одинаковые константные выражения.

Пример:

       :
     switch (a)
      {
        case 1: b=c; break;
        case 2:
            switch (d)
            {   case 0:  f=s;  break;
                case 1:  f=9;  break;
                case 2:  f-=9; break;
            }
         case 3: b-=c; break;
         :
      }

1.4.6. Оператор break

Оператор break обеспечивает прекращение выполнения самого внутреннего из объединяющих его операторов switch, do, for, while. После выполнения оператора break управление передается оператору, следующему за прерванным.

1.4.7. Оператор for

Оператор for - это наиболее общий способ организации цикла. Он имеет следующий формат:

for ( выражение 1 ; выражение 2 ; выражение 3 ) тело

Выражение 1 обычно используется для установления начального значения переменных, управляющих циклом. Выражение 2 - это выражение, определяющее условие, при котором тело цикла будет выполняться. Выражение 3 определяет изменение переменных, управляющих циклом после каждого выполнения тела цикла.

Схема выполнения оператора for:

1. Вычисляется выражение 1.

2. Вычисляется выражение 2.

3. Если значения выражения 2 отлично от нуля (истина), выполняется тело цикла, вычисляется выражение 3 и осуществляется переход к пункту 2, если выражение 2 равно нулю (ложь), то управление передается на оператор, следующий за оператором for.

Существенно то, что проверка условия всегда выполняется в начале цикла. Это значит, что тело цикла может ни разу не выполниться, если условие выполнения сразу будет ложным.

Пример:

       int main()
       { int i,b;
          for (i=1; i<10; i++) b="i*i;" return 0; }

В этом примере вычисляются квадраты чисел от 1 до 9.

Некоторые варианты использования оператора 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;
          }
          return 0;
        }

В этом примере, реализующем запись строки символов в обратном порядке, для управления циклом используются две переменные top и bot. Отметим, что на месте выражение 1 и выражение 3 здесь используются несколько выражений, записанных через запятую, и выполняемых последовательно.

Другим вариантом использования оператора for является бесконечный цикл. Для организации такого цикла можно использовать пустое условное выражение, а для выхода из цикла обычно используют дополнительное условие и оператор break.

Пример:

       for (;;)
       { ...
         ...  break;
         ...
       }

Так как согласно синтаксису языка Си оператор может быть пустым, тело оператора for также может быть пустым. Такая форма оператора может быть использована для организации поиска.

Пример:

for (i=0; t[i]<10 ; i++) ;

В данном примере переменная цикла i принимает значение номера первого элемента массива t, значение которого больше 10.

1.4.8. Оператор while

Оператор цикла while называется циклом с предусловием и имеет следующий формат:

while (выражение) тело ;

В качестве выражения допускается использовать любое выражение языка Си, а в качестве тела любой оператор, в том числе пустой или составной. Схема выполнения оператора while следующая:

1. Вычисляется выражение.

2. Если выражение ложно, то выполнение оператора while заканчивается и выполняется следующий по порядку оператор. Если выражение истинно, то выполняется тело оператора while.

3. Процесс повторяется с пункта 1.

Оператор цикла вида

for (выражение-1; выражение-2; выражение-3) тело ;

может быть заменен оператором while следующим образом:

           выражение-1;
           while (выражение-2)
           {  тело
              выражение-3;
           }

Так же как и при выполнении оператора for, в операторе while вначале происходит проверка условия. Поэтому оператор while удобно использовать в ситуациях, когда тело оператора не всегда нужно выполнять.

Внутри операторов for и while можно использовать локальные переменные, которые должны быть объявлены с определением соответствующих типов.

1.4.9. Оператор do while

Оператор цикла do while называется оператором цикла с постусловием и используется в тех случаях, когда необходимо выполнить тело цикла хотя бы один раз. Формат оператора имеет следующий вид:

do тело while (выражение);

Схема выполнения оператора do while :

1. Выполняется тело цикла (которое может быть составным оператором).

2. Вычисляется выражение.

3. Если выражение ложно, то выполнение оператора do while заканчивается и выполняется следующий по порядку оператор. Если выражение истинно, то выполнение оператора продолжается с пункта 1.

Чтобы прервать выполнение цикла до того, как условие станет ложным, можно использовать оператор break.

Операторы while и do while могут быть вложенными.

Пример:

       int i,j,k;
       ...
       i=0;  j=0;  k=0;
       do { i++;
            j--;
            while (a[k] < i)  k++;
           }
       while (i<30 && j<-30);

1.4.10. Оператор continue

Оператор continue, как и оператор break, используется только внутри операторов цикла, но в отличие от него выполнение программы продолжается не с оператора, следующего за прерванным оператором, а с начала прерванного оператора. Формат оператора следующий:

continue;

Пример:

       int main()
       {   int a,b;
           for (a=1,b=0; a<100; b+="a,a++)" { if (b%2) continue; ... /* обработка четных сумм */ } return 0; }

Когда сумма чисел от 1 до а становится нечетной, оператор continue передает управление на очередную итерацию цикла for, не выполняя операторы обработки четных сумм.

Оператор continue, как и оператор break, прерывает самый внутренний из объемлющих его циклов.

1.4.11. Оператор return

Оператор return завершает выполнение функции, в которой он задан, и возвращает управление в вызывающую функцию, в точку, непосредственно следующую за вызовом. Функция main передает управление операционной системе. Формат оператора:

return [выражение] ;

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

Если в какой-либо функции отсутствует оператор return, то передача управления в вызывающую функцию происходит после выполнения последнего оператора вызываемой функции. При этом возвращаемое значение не определено. Если функция не должна иметь возвращаемого значения, то ее нужно объявлять с типом void.

Таким образом, использование оператора return необходимо либо для немедленного выхода из функции, либо для передачи возвращаемого значения.

Пример:

        int sum (int a, int b)
        {   renurn (a+b);    }

Функция sum имеет два формальных параметра a и b типа int, и возвращает значение типа int, о чем говорит описатель, стоящий перед именем функции. Возвращаемое оператором return значение равно сумме фактических параметров.

Пример:

     void prov (int a, double b)
     {  double c;
        if (a<3) return; else if (b>10) return;
             else { c=a+b;
                    if ((2*c-b)==11) return;
                   }
      }

В этом примере оператор return используется для выхода из функции в случае выполнения одного из проверяемых условий.

1.4.12. Оператор goto

Использование оператора безусловного перехода goto в практике программирования на языке СИ настоятельно не рекомендуется, так как он затрудняет понимание программ и возможность их модификаций.

Формат этого оператора следующий:

       goto имя-метки;
                  ...
       имя-метки: оператор;

Оператор goto передает управление на оператор, помеченный меткой имя-метки. Помеченный оператор должен находиться в той же функции, что и оператор goto, а используемая метка должна быть уникальной, т.е. одно имя-метки не может быть использовано для разных операторов программы. Имя-метки - это идентификатор.

Любой оператор в составном операторе может иметь свою метку. Используя оператор goto, можно передавать управление внутрь составного оператора. Но нужно быть осторожным при входе в составной оператор, содержащий объявления переменных с инициализацией, так как объявления располагаются перед выполняемыми операторами и значения объявленных переменных при таком переходе будут не определены.


Программирование на языке СИ

1.5.1. Определение и вызов функций

Мощность языка СИ во многом определяется легкостью и гибкостью в определении и использовании функций в СИ-программах. В отличие от других языков программирования высокого уровня в языке СИ нет деления на процедуры, подпрограммы и функции, здесь вся программа строится только из функций.

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

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

С использованием функций в языке СИ связаны три понятия - определение функции (описание действий, выполняемых функцией), объявление функции (задание формы обращения к функции) и вызов функции.

Определение функции задает тип возвращаемого значения, имя функции, типы и число формальных параметров, а также объявления переменных и операторы, называемые телом функции, и определяющие действие функции. В определении функции также может быть задан класс памяти.

Пример:

     int rus (unsigned char r)
     {  if (r>='А' && c<=' ') return 1; else return 0; }

В данном примере определена функция с именем rus, имеющая один параметр с именем r и типом unsigned char. Функция возвращает целое значение, равное 1, если параметр функции является буквой русского алфавита, или 0 в противном случае.

В языке СИ нет требования, чтобы определение функции обязательно предшествовало ее вызову. Определения используемых функций могут следовать за определением функции main, перед ним, или находится в другом файле.

Однако для того, чтобы компилятор мог осуществить проверку соответствия типов передаваемых фактических параметров типам формальных параметров до вызова функции нужно поместить объявление (прототип) функции.

Объявление функции имеет такой же вид, что и определение функции, с той лишь разницей, что тело функции отсутствует, и имена формальных параметров тоже могут быть опущены. Для функции, определенной в последнем примере, прототип может иметь вид

int rus (unsigned char r); или rus (unsigned char);

В программах на языке СИ широко используются, так называемые, библиотечные функции, т.е. функции предварительно разработанные и записанные в библиотеки. Прототипы библиотечных функций находятся в специальных заголовочных файлах, поставляемых вместе с библиотеками в составе систем программирования, и включаются в программу с помощью директивы #include.

Если объявление функции не задано, то по умолчанию строится прототип функции на основе анализа первой ссылки на функцию, будь то вызов функции или определение. Однако такой прототип не всегда согласуется с последующим определением или вызовом функции. Рекомендуется всегда задавать прототип функции. Это позволит компилятору либо выдавать диагностические сообщения, при неправильном использовании функции, либо корректным образом регулировать несоответствие аргументов устанавливаемое при выполнении программы.

Объявление параметров функции при ее определении может быть выполнено в так называемом "старом стиле", при котором в скобках после имени функции следуют только имена параметров, а после скобок объявления типов параметров. Например, функция rus из предыдущего примера может быть определена следующим образом:

        int rus (r)
        unsigned char r;
        { ...     /*  тело функции   */      ...  }

В соответствии с синтаксисом языка СИ определение функции имеет следующую форму:

   [спецификатор-класса-памяти] [спецификатор-типа] имя-функции
   ([список-формальных-параметров])
   {  тело-функции   }

Необязательный спецификатор-класса-памяти задает класс памяти функции, который может быть static или extern. Подробно классы памяти будут рассмотрены в следующем разделе.

Спецификатор-типа функции задает тип возвращаемого значения и может задавать любой тип. Если спецификатор-типа не задан, то предполагается, что функция возвращает значение типа int.

Функция не может возвращать массив или функцию, но может возвращать указатель на любой тип, в том числе и на массив и на функцию. Тип возвращаемого значения, задаваемый в определении функции, должен соответствовать типу в объявлении этой функции.

Функция возвращает значение если ее выполнение заканчивается оператором return, содержащим некоторое выражение. Указанное выражение вычисляется, преобразуется, если необходимо, к типу возвращаемого значения и возвращается в точку вызова функции в качестве результата. Если оператор return не содержит выражения или выполнение функции завершается после выполнения последнего ее оператора (без выполнения оператора return), то возвращаемое значение не определено. Для функций, не использующих возвращаемое значение, должен быть использован тип void, указывающий на отсутствие возвращаемого значения. Если функция определена как функция, возвращающая некоторое значение, а в операторе return при выходе из нее отсутствует выражение, то поведение вызывающей функции после передачи ей управления может быть непредсказуемым.

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

Если функция не использует параметров, то наличие круглых скобок обязательно, а вместо списка параметров рекомендуется указать слово void.

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

Для формального параметра можно задавать класс памяти register, при этом для величин типа int спецификатор типа можно опустить.

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

При передаче параметров в функцию, если необходимо, выполняются обычные арифметические преобразования для каждого формального параметра и каждого фактического параметра независимо. После преобразования формальный параметр не может быть короче чем int, т.е. объявление формального параметра с типом char равносильно его объявлению с типом int. А параметры, представляющие собой действительные числа, имеют тип double.

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

Тело функции - это составной оператор, содержащий операторы, определяющие действие функции.

Все переменные, объявленные в теле функции без указания класса памяти, имеют класс памяти auto, т.е. они являются локальными. При вызове функции локальным переменным отводится память в стеке и производится их инициализация. Управление передается первому оператору тела функции и начинается выполнение функции, которое продолжается до тех пор, пока не встретится оператор return или последний оператор тела функции. Управление при этом возвращается в точку, следующую за точкой вызова, а локальные переменные становятся недоступными. При новом вызове функции для локальных переменных память распределяется вновь, и поэтому старые значения локальных переменных теряются.

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

Пример:

       /*    Неправильное использование параметров   */
       void change (int x, int y)
       {    int k=x;
                x=y;
                y=k;
       }

В данной функции значения переменных x и y, являющихся формальными параметрами, меняются местами, но поскольку эти переменные существуют только внутри функции change, значения фактических параметров, используемых при вызове функции, останутся неизменными. Для того чтобы менялись местами значения фактических аргументов можно использовать функцию приведенную в следующем примере.

Пример:

      /*     Правильное использование параметров   */
       void change (int *x, int *y)
       {  int k=*x;
             *x=*y;
             *y=k;
       }

При вызове такой функции в качестве фактических параметров должны быть использованы не значения переменных, а их адреса

change (&a,&b);

Если требуется вызвать функцию до ее определения в рассматриваемом файле, или определение функции находится в другом исходном файле, то вызов функции следует предварять объявлением этой функции. Объявление (прототип) функции имеет следующий формат:

[спецификатор-класса-памяти] [спецификатор-типа] имя-функции ([список-формальных-параметров]) [,список-имен-функций];

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

Прототип - это явное объявление функции, которое предшествует определению функции. Тип возвращаемого значения при объявлении функции должен соответствовать типу возвращаемого значения в определении функции.

Если прототип функции не задан, а встретился вызов функции, то строится неявный прототип из анализа формы вызова функции. Тип возвращаемого значения создаваемого прототипа int, а список типов и числа параметров функции формируется на основании типов и числа фактических параметров используемых при данном вызове.

Таким образом, прототип функции необходимо задавать в следующих случаях:

1. Функция возвращает значение типа, отличного от int.

2. Требуется проинициализировать некоторый указатель на функцию до того, как эта функция будет определена.

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

В прототипе можно указать, что число параметров функции переменно, или что функция не имеет параметров.

Если прототип задан с классом памяти static, то и определение функции должно иметь класс памяти static. Если спецификатор класса памяти не указан, то подразумевается класс памяти extern.

Вызов функции имеет следующий формат:

адресное-выражение ([список-выражений])

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

Список-выражений представляет собой список фактических параметров, передаваемых в функцию. Этот список может быть и пустым, но наличие круглых скобок обязательно.

Фактический параметр может быть величиной любого основного типа, структурой, объединением, перечислением или указателем на объект любого типа. Массив и функция не могут быть использованы в качестве фактических параметров, но можно использовать указатели на эти объекты.

Выполнение вызова функции происходит следующим образом:

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

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 (*fun1)(int x, int y);
    double fun2(int k, int l);
       fun1=fun2;         /* инициализация указателя на функцию */
       (*fun1)(2,7);      /* обращение к функции                */

В рассмотренном примере указатель на функцию fun1 описан как указатель на функцию с двумя параметрами, возвращающую значение типа double, и также описана функция fun2. В противном случае, т.е. когда указателю на функцию присваивается функция описанная иначе чем указатель, произойдет ошибка.

Рассмотрим пример использования указателя на функцию в качестве параметра функции вычисляющей производную от функции cos(x).

Пример:

   double proiz(double x, double dx, double (*f)(double x) );
   double fun(double z);
   int main()
   {
     double x;               /*  точка вычисления производной */
     double dx;              /*  приращение                   */
     double z;               /*  значение производной         */
     scanf("%f,%f",&x,&dx);  /*  ввод значений x и dx         */
     z=proiz(x,dx,fun);      /*  вызов функции                */
     printf("%f",z);         /*  печать значения производной  */
     return 0;
   }
   double proiz(double x,double dx, double (*f)(double z) )
   {         /* функция вычисляющая производную  */
      double xk,xk1,pr;
      xk=fun(x);
      xk1=fun(x+dx);
      pr=(xk1/xk-1e0)*xk/dx;
      return pr;
   }
   double fun( double z)
   {     /* функция от которой вычисляется производная  */
      return (cos(z));
   }

Для вычисления производной от какой-либо другой функции можно изменить тело функции fun или использовать при вызове функции proiz имя другой функции. В частности, для вычисления производной от функции cos(x) можно вызвать функцию proiz в форме

z=proiz(x,dx,cos);

а для вычисления производной от функции sin(x) в форме

z=proiz(x,dx,sin);

Любая функция в программе на языке СИ может быть вызвана рекурсивно, т.е. она может вызывать саму себя. Компилятор допускает любое число рекурсивных вызовов. При каждом вызове для формальных параметров и переменных с классом памяти auto и register выделяется новая область памяти, так что их значения из предыдущих вызовов не теряются, но в каждый момент времени доступны только значения текущего вызова.

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

Классический пример рекурсии - это математическое определение факториала n! :

   n! = 1 при n=0;
        n*(n-1)!  при    n>1 .

Функция, вычисляющая факториал, будет иметь следующий вид:

       long fakt(int n)
       {
         return ( (n==1) ? 1 : n*fakt(n-1)  );
       }

Хотя компилятор языка СИ не ограничивает число рекурсивных вызовов функций, это число ограничивается ресурсом памяти компьютера и при слишком большом числе рекурсивных вызовов может произойти переполнение стека.

1.5.2. Вызов функции с переменным числом параметров

При вызове функции с переменным числом параметров в вызове этой функции задается любое требуемое число аргументов. В объявлении и определении такой функции переменное число аргументов задается многоточием в конце списка формальных параметров или списка типов аргументов.

Все аргументы, заданные в вызове функции, размещаются в стеке. Количество формальных параметров, объявленных для функции, определяется числом аргументов, которые берутся из стека и присваиваются формальным параметрам. Программист отвечает за правильность выбора дополнительных аргументов из стека и определение числа аргументов, находящихся в стеке.

Примерами функций с переменным числом параметров являются функции из библиотеки функций языка СИ, осуществляющие операции ввода-вывода информации (printf,scanf и т.п.). Подробно эти функции рассмотрены во третьей части книги.

Программист может разрабатывать свои функции с переменным числом параметров. Для обеспечения удобного способа доступа к аргументам функции с переменным числом параметров имеются три макроопределения (макросы) va_start, va_arg, va_end, находящиеся в заголовочном файле stdarg.h. Эти макросы указывают на то, что функция, разработанная пользователем, имеет некоторое число обязательных аргументов, за которыми следует переменное число необязательных аргументов. Обязательные аргументы доступны через свои имена как при вызове обычной функции. Для извлечения необязательных аргументов используются макросы va_start, va_arg, va_end в следующем порядке.

Макрос va_start предназначен для установки аргумента arg_ptr на начало списка необязательных параметров и имеет вид функции с двумя параметрами:

void va_start(arg_ptr,prav_param);

Параметр prav_param должен быть последним обязательным параметром вызываемой функции, а указатель arg_prt должен быть объявлен с предопределением в списке переменных типа va_list в виде:

va_list arg_ptr;

Макрос va_start должен быть использован до первого использования макроса va_arg.

Макрокоманда va_arg обеспечивает доступ к текущему параметру вызываемой функции и тоже имеет вид функции с двумя параметрами

type_arg va_arg(arg_ptr,type);

Эта макрокоманда извлекает значение типа type по адресу, заданному указателем arg_ptr, увеличивает значение указателя arg_ptr на длину использованного параметра (длина type) и таким образом параметр arg_ptr будет указывать на следующий параметр вызываемой функции. Макрокоманда va_arg используется столько раз, сколько необходимо для извлечения всех параметров вызываемой функции.

Макрос va_end используется по окончании обработки всех параметров функции и устанавливает указатель списка необязательных параметров на ноль (NULL).

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

Пример:

   #include
   int main()
   { int n;
     int sred_znach(int,...);
     n=sred_znach(2,3,4,-1);
                     /* вызов с четырьмя параметрами */
     printf("n=%d",n);
     n=sred_znach(5,6,7,8,9,-1);
                    /* вызов с шестью параметрами   */
     printf("n=%d",n);
     return (0);
   }

   int sred_znach(int x,...);
   {
      int i=0,  j=0,  sum=0;
      va_list uk_arg;
      va_start(uk_arg,x);  /*  установка указателя uk_arg на  */
                           /*  первый необязятельный параметр */
      if (x!=-1) sum=x;    /*  проверка на пустоту списка     */
      else return (0);
      j++;
      while ( (i=va_arg(uk_arg,int))!=-1)
                                   /* выборка очередного   */
      {                            /* параметра и проверка */
        sum+=i;                    /* на конец списка      */
        j++;
      }
      va_end(uk_arg);         /* закрытие списка параметров   */
      return (sum/j);
   }

1.5.3. Передача параметров функции main

Функция main, с которой начинается выполнение СИ-программы, может быть определена с параметрами, которые передаются из внешнего окружения, например, из командной строки. Во внешнем окружении действуют свои правила представления данных, а точнее, все данные представляются в виде строк символов. Для передачи этих строк в функцию main используются два параметра, первый параметр служит для передачи числа передаваемых строк, второй для передачи самих строк. Общепринятые (но не обязательные) имена этих параметров argc и argv. Параметр argc имеет тип int, его значение формируется из анализа командной строки и равно количеству слов в командной строке, включая и имя вызываемой программы (под словом понимается любой текст не содержащий символа пробел). Параметр argv это массив указателей на строки, каждая из которых содержит одно слово из командной строки. Если слово должно содержать символ пробел, то при записи его в командную строку оно должно быть заключено в кавычки.

Функция main может иметь и третий параметр, который принято называть argp, и который служит для передачи в функцию main параметров операционной системы (среды) в которой выполняется СИ-программа.

Заголовок функции main имеет вид:

int main (int argc, char *argv[], char *argp[])

Если, например, командная строка СИ-программы имеет вид:

A:\>cprog working 'C program' 1

то аргументы argc, argv, argp представляются в памяти как показано в схеме на рис.1.

     argc  [ 4  ]
     argv  [    ]--> [    ]-->   [A:\cprog.exe\0]
                     [    ]-->   [working\0]
                     [    ]-->   [C program\0]
                     [    ]-->   [1\0]
                     [NULL]
     argp  [    ]--> [    ]-->   [path=A:\;C:\\0]
                     [    ]-->   [lib=D:\LIB\0]
                     [    ]-->   [include=D:\INCLUDE\0]
                     [    ]-->   [conspec=C:\COMMAND.COM\]
                     [NULL]
     Рис.1. Схема размещения параметров командной строки

Операционная система поддерживает передачу значений для параметров argc, argv, argp, а на пользователе лежит ответственность за передачу и использование фактических аргументов функции main.

Следующий пример представляет программу печати фактических аргументов, передаваемых в функцию main из операционной системы и параметров операционной системы.

     Пример:
     int main ( int argc, char *argv[], char *argp[])
     {  int i=0;
        printf ("\n Имя программы %s", argv[0]);
        for    (i=1; i>=argc; i++)
        printf ("\n аргумент %d равен %s", argv[i]);
        printf ("\n   Параметры операционной системы:");
        while  (*argp)
          {  printf ("\n %s",*argp);
             argp++;
          }
        return (0);
     }

Доступ к параметрам операционной системы можно также получить при помощи библиотечной функции geteuv, ее прототип имеет следующий вид:

char *geteuv (const char *varname);

Аргумент этой функции задает имя параметра среды, указатель на значение которой выдаст функция geteuv. Если указанный параметр не определен в среде в данный момент, то возвращаемое значение NULL.

Используя указатель, полученный функцией geteuv, можно только прочитать значение параметра операционной системы, но нельзя его изменить. Для изменения значения параметра системы предназначена функция puteuv.

Компилятор языка СИ строит СИ-программу таким образом, что вначале работы программы выполняется некоторая инициализация, включающая, кроме всего прочего, обработку аргументов, передаваемых функции main, и передачу ей значений параметров среды. Эти действия выполняются библиотечными функциями _setargv и _seteuv, которые всегда помещаются компилятором перед функцией main.

Если СИ-программа не использует передачу аргументов и значений параметров операционной системы, то целесообразно запретить использование библиотечных функций _setargv и _seteuv поместив в СИ-программу перед функцией main функции с такими же именами, но не выполняющие никаких действий (заглушки). Начало программы в этом случае будет иметь вид:

   _setargv()
    {  return ;    /* пустая функция */
    }
   -seteuv()
    {  return ;    /* пустая функция */
    }
   int main()
    {      /* главная функция без аргументов */
    ...
    ...
    renurn (0);
    }

В приведенной программе при вызове библиотечных функций _setargv и _seteuv будут использованы функции помещенные в программу пользователем и не выполняющие никаких действий. Это заметно снизит размер получаемого exe-файла.


Программирование на языке СИ

Rambler's Top100 Дата последнего обновления файла 5.10.04

Цифровая и вычислительная техника Микропроцессоры и цифровая обработка сигналов цифровые устройства и микропроцессоры

1.6.1. Исходные файлы и объявление переменных

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

При такой структуре исходной программы функции, находящиеся в разных исходных файлах могут использовать глобальные внешние переменные. Все функции в языке Си по определению внешние и всегда доступны из любых файлов. Например, если программа состоит из двух исходных файлов, как показано на рис.2., то функция main может вызывать любую из трех функций fun1, fun2, fun3, а каждая из этих функций может вызывать любую другую.

 main ()
 {  ...
 }
 fun1()
 {  ...
 }
.
 fun2()
 {  ...
 }
 fun3()
 {  ...
 }
file1.c file2.c
Рис.2. Пример программы из двух файлов

Для того, чтобы определяемая функция могла выполнять какие либо действия, она должна использовать переменные. В языке СИ все переменные должны быть объявлены до их использования. Объявления устанавливают соответствие имени и атрибутов переменной, функции или типа. Определение переменной вызывает выделение памяти для хранения ее значения. Класс выделяемой памяти определяется спецификатором класса памяти, и определяет время жизни и область видимости переменной, связанные с понятием блока программы.

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

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

Все функции в СИ имеют глобальное время жизни и существуют в течение всего времени выполнения программы.

Область видимости - это часть текста программы, в которой может быть использован данный объект. Объект считается видимым в блоке или в исходном файле, если в этом блоке или файле известны имя и тип объекта. Объект может быть видимым в пределах блока, исходного файла или во всех исходных файлах, образующих программу. Это зависит от того, на каком уровне объявлен объект: на внутреннем, т.е. внутри некоторого блока, или на внешнем, т.е. вне всех блоков.

Если объект объявлен внутри блока, то он видим в этом блоке, и во всех внутренних блоках. Если объект объявлен на внешнем уровне, то он видим от точки его объявления до конца данного исходного файла.

Объект может быть сделан глобально видимым с помощью соответствующих объявлений во всех исходных файлах, образующих программу.

Спецификатор класса памяти в объявлении переменной может быть auto, register, static или extern. Если класс памяти не указан, то он определяется по умолчанию из контекста объявления.

Объекты классов auto и register имеют локальное время жизни. Спецификаторы static и extern определяют объекты с глобальным временем жизни.

При объявлении переменной на внутреннем уровне может быть использован любой из четырех спецификаторов класса памяти, а если он не указан, то подразумевается класс памяти auto.

Переменная с классом памяти auto имеет локальное время жизни и видна только в блоке, в котором объявлена. Память для такой переменной выделяется при входе в блок и освобождается при выходе из блока. При повторном входе в блок этой переменной может быть выделен другой участок памяти.

Переменная с классом памяти auto автоматически не инициализируется. Она должна быть проинициализирована явно при объявлении путем присвоения ей начального значения. Значение неинициализированной переменной с классом памяти auto считается неопределенным.

Спецификатор класса памяти register предписывает компилятору распределить память для переменной в регистре, если это представляется возможным. Использование регистровой памяти обычно приводит к сокращению времени доступа к переменной. Переменная, объявленная с классом памяти register, имеет ту же область видимости, что и переменная auto. Число регистров, которые можно использовать для значений переменных, ограничено возможностями компьютера, и в том случае, если компилятор не имеет в распоряжении свободных регистров, то переменной выделяется память как для класса auto. Класс памяти register может быть указан только для переменных с типом int или указателей с размером, равным размеру int.

Переменные, объявленные на внутреннем уровне со спецификатором класса памяти static, обеспечиваю возможность сохранить значение переменной при выходе из блока и использовать его при повторном входе в блок. Такая переменная имеет глобальное время жизни и область видимости внутри блока, в котором она объявлена. В отличие от переменных с классом auto, память для которых выделяется в стеке, для переменных с классом static память выделяется в сегменте данных, и поэтому их значение сохраняется при выходе из блока.

     Пример:
  /*  объявления переменной i на внутреннем уровне
            с  классом памяти static.                    */
  /*   исходный файл file1.c       */
     main()
        { ...
        }
     fun1()
        {  static int i=0; ...
        }
   /* исходный файл   file2.c       */
     fun2()
        {  static int i=0; ...
        }
     fun3()
        {  static int i=0; ...
        }

В приведенном примере объявлены три разные переменные с классом памяти static, имеющие одинаковые имена i. Каждая из этих переменных имеет глобальное время жизни, но видима только в том блоке (функции), в которой она объявлена. Эти переменные можно использовать для подсчета числа обращений к каждой из трех функций.

Переменные класса памяти static могут быть инициализированы константным выражением. Если явной инициализации нет, то такой переменной присваивается нулевое значение. При инициализации константным адресным выражением можно использовать адреса любых внешних объектов, кроме адресов объектов с классом памяти auto, так как адрес последних не является константой и изменяется при каждом входе в блок. Инициализация выполняется один раз при первом входе в блок.

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

     Пример:
  /*   объявления  переменной  i,  являющейся  именем внешнего
       массива длинных целых чисел, на локальном уровне      */
  /*      исходный файл    file1.c          */
     main()
        { ...
        }
     fun1()
        { extern long i[]; ...
        }
  /*     исходный файл      file2.c         */
     long i[MAX]={0};
     fun2()
        {  ...
        }
     fun3()
        {  ...
        }

Объявление переменной i[] как extern в приведенном примере делает ее видимой внутри функции fun1. Определение этой переменной находится в файле file2.c на глобальном уровне и должно быть только одно, в то время как объявлений с классом памяти extern может быть несколько.

Объявление с классом памяти extern требуется при необходимости использовать переменную, описанную в текущем исходном файле, но ниже по тексту программы, т.е. до выполнения ее глобального определения. Следующий пример иллюстрирует такое использование переменной с именем st.

     Пример:
     main()
     { extern int st[]; ...
     }
     static int st[MAX]={0};
     fun1()
     {   ...
     }

Объявление переменной со спецификатором extern информирует компилятор о том, что память для переменной выделять не требуется, так как это выполнено где-то в другом месте программы.

При объявлении переменных на глобальном уровне может быть использован спецификатор класса памяти static или extern, а так же можно объявлять переменные без указания класса памяти. Классы памяти auto и register для глобального объявления недопустимы.

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

1. Переменная объявлена с классом памяти static. Такая переменная может быть инициализирована явно константным выражением, или по умолчанию нулевым значением. То есть обявления static int i=0 и static int i эквивалентны, и в обоих случаях переменной i будет присвоено значение 0.

2. Переменная объявлена без указания класса памяти, но с явной инициализацией. Такой переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и static int i=1 будут эквивалентны.

Переменная объявленная глобально видима в пределах остатка исходного файла, в котором она определена. Выше своего описания и в других исходных файлах эта переменная невидима (если только она не объявлена с классом extern).

Глобальная переменная может быть определена только один раз в пределах своей области видимости. В другом исходном файле может быть объявлена другая глобальная переменная с таким же именем и с классом памяти static, конфликта при этом не возникает, так как каждая из этих переменных будет видимой только в своем исходном файле.

Спецификатор класса памяти extern для глобальных переменных используется, как и для локального объявления, в качестве ссылки на переменную, объявленную в другом месте программы, т.е. для расширения области видимости переменной. При таком объявлении область видимости переменной расширяется до конца исходного файла, в котором сделано объявление.

В объявлениях с классом памяти extern не допускается инициализация, так как эти объявления ссылаются на уже существующие и определенные ранее переменные.

Переменная, на которую делается ссылка с помощью спецификатора extern, может быть определена только один раз в одном из исходных файлов программы.

1.6.2. Объявления функций

Функции всегда определяются глобально. Они могут быть объявлены с классом памяти static или extern. Объявления функций на локальном и глобальном уровнях имеют одинаковый смысл.

Правила определения области видимости для функций отличаются от правил видимости для переменных и состоят в следующем.

1. Функция, объявленная как static, видима в пределах того файла, в котором она определена. Каждая функция может вызвать другую функцию с классом памяти static из своего исходного файла, но не может вызвать функцию определенную с классом static в другом исходном файле. Разные функции с классом памяти static имеющие одинаковые имена могут быть определены в разных исходных файлах, и это не ведет к конфликту.

2. Функция, объявленная с классом памяти extern, видима в пределах всех исходных файлов программы. Любая функция может вызывать функции с классом памяти extern.

3. Если в объявлении функции отсутствует спецификатор класса памяти, то по умолчанию принимается класс extern.

Все объекты с классом памяти extern компилятор помещает в объектном файле в специальную таблицу внешних ссылок, которая используется редактором связей для разрешения внешних ссылок. Часть внешних ссылок порождается компилятором при обращениях к библиотечным функциям СИ, поэтому для разрешения этих ссылок редактору связей должны быть доступны соответствующие библиотеки функций.

1.6.3. Время жизни и область видимости программных объектов

Время жизни переменной (глобальной или локальной) определяется по следующим правилам.

1. Переменная, объявленная глобально (т.е. вне всех блоков), существует на протяжении всего времени выполнения программы.

2. Локальные переменные (т.е. объявленные внутри блока) с классом памяти register или auto, имеют время жизни только на период выполнения того блока, в котором они объявлены. Если локальная переменная объявлена с классом памяти static или extern, то она имеет время жизни на период выполнения всей программы.

Видимость переменных и функций в программе определяется следующими правилами.

1. Переменная, объявленная или определенная глобально, видима от точки объявления или определения до конца исходного файла. Можно сделать переменную видимой и в других исходных файлах, для чего в этих файлах следует ее объявить с классом памяти extern.

2. Переменная, объявленная или определенная локально, видима от точки объявления или определения до конца текущего блока. Такая переменная называется локальной.

3. Переменные из объемлющих блоков, включая переменные объявленные на глобальном уровне, видимы во внутренних блоках. Эту видимость называют вложенной. Если переменная, объявленная внутри блока, имеет то же имя, что и переменная, объявленная в объемлющем блоке, то это разные переменные, и переменная из объемлющего блока во внутреннем блоке будет невидимой.

4. Функции с классом памяти static видимы только в исходном файле, в котором они определены. Всякие другие функции видимы во всей программе.

Метки в функциях видимы на протяжении всей функции.

Имена формальных параметров, объявленные в списке параметров прототипа функции, видимы только от точки объявления параметра до конца объявления функции.

1.6.4. Инициализация глобальных и локальных переменных

При инициализации необходимо придерживаться следующих правил:

1. Объявления содержащие спецификатор класса памяти extern не могут содержать инициаторов.

2. Глобальные переменные всегда инициализируются, и если это не сделано явно, то они инициализируются нулевым значением.

3. Переменная с классом памяти static может быть инициализирована константным выражением. Инициализация для них выполняется один раз перед началом программы. Если явная инициализация отсутствует, то переменная инициализируется нулевым значением.

4. Инициализация переменных с классом памяти auto или register выполняется всякий раз при входе в блок, в котором они объявлены. Если инициализация переменных в объявлении отсутствует, то их начальное значение не определено.

5. Начальными значениями для глобальных переменных и для переменных с классом памяти static должны быть константные выражения. Адреса таких переменных являются константами и эти константы можно использовать для инициализации объявленных глобально указателей. Адреса переменных с классом памяти auto или register не являются константами и их нельзя использовать в инициаторах.

     Пример:
    int global_var;
    int func(void)
    { int local_var;                      /* по умолчанию auto  */
      static int *local_ptr=&local_var;   /*  так неправильно   */
      static int *global_ptr=&global_var; /*  а так правильно   */
      register int *reg_ptr=&local_var;   /*  и так правильно   */
    }

В приведенном примере глобальная переменная global_var имеет глобальное время жизни и постоянный адрес в памяти, и этот адрес можно использовать для инициализации статического указателя global_ptr. Локальная переменная local_var, имеющая класс памяти auto размещается в памяти только на время работы функции func, адрес этой переменной не является константой и не может быть использован для инициализации статической переменной local_ptr. Для инициализации локальной регистровой переменной reg_ptr можно использовать неконстантные выражения, и, в частности, адрес переменной local_ptr.


Программирование на языке СИ

 Rambler's Top100 Дата последнего обновления файла 5.10.04

1.7.1. Методы доступа к элементам массивов

В языке СИ между указателями и массивами существует тесная связь. Например, когда объявляется массив в виде int array[25], то этим определяется не только выделение памяти для двадцати пяти элементов массива, но и для указателя с именем array, значение которого равно адресу первого по счету (нулевого) элемента массива, т.е. сам массив остается безымянным, а доступ к элементам массива осуществляется через указатель с именем array. С точки зрения синтаксиса языка указатель arrey является константой, значение которой можно использовать в выражениях, но изменить это значение нельзя.

Поскольку имя массива является указателем допустимо, например, такое присваивание:

         int arrey[25];
         int *ptr;
         ptr=array;

Здесь указатель ptr устанавливается на адрес первого элемента масcива, причем присваивание ptr=arrey можно записать в эквивалентной форме ptr=&arrey[0].

Для доступа к элементам массива существует два различных способа. Первый способ связан с использованием обычных индексных выражений в квадратных скобках, например, array[16]=3 или array[i+2]=7. При таком способе доступа записываются два выражения, причем второе выражение заключается в квадратные скобки. Одно из этих выражений должно быть указателем, а второе - выражением целого типа. Последовательность записи этих выражений может быть любой, но в квадратных скобках записывается выражение следующее вторым. Поэтому записи array[16] и 16[array] будут эквивалентными и обозначают элемент массива с номером шестнадцать. Указатель используемый в индексном выражении не обязательно должен быть константой, указывающей на какой-либо массив, это может быть и переменная. В частности после выполнения присваивания ptr=array доступ к шестнадцатому элементу массива можно получить с помощью указателя ptr в форме ptr[16] или 16[ptr].

Второй способ доступа к элементам массива связан с использованием адресных выражений и операции разадресации в форме *(array+16)=3 или *(array+i+2)=7. При таком способе доступа адресное выражение равное адресу шестнадцатого элемента массива тоже может быть записано разными способами *(array+16) или *(16+array).

При реализации на компьютере первый способ приводится ко второму, т.е. индексное выражение преобразуется к адресному. Для приведенных примеров array[16] и 16[array] преобразуются в *(array+16).

Для доступа к начальному элементу массива (т.е. к элементу с нулевым индексом) можно использовать просто значение указателя array или ptr. Любое из присваиваний

       *array = 2;
       array[0] = 2;
       *(array+0) = 2;
       *ptr = 2;
       ptr[0] = 2;
       *(ptr+0) = 2;

присваивает начальному элементу массива значение 2, но быстрее всего выполнятся присваивания *array=2 и *ptr=2, так как в них не требуется выполнять операции сложения.

1.7.2. Указатели на многомерные массивы

Указатели на многомерные массивы в языке СИ - это массивы массивов, т.е. такие массивы, элементами которых являются массивы. При объявлении таких массивов в памяти компьютера создается несколько различных объектов. Например при выполнении объявления двумерного массива int arr2[4][3] в памяти выделяется участок для хранения значения переменной arr, которая является указателем на массив из четырех указателей. Для этого массива из четырех указателей тоже выделяется память. Каждый из этих четырех указателей содержит адрес массива из трех элементов типа int, и, следовательно, в памяти компьютера выделяется четыре участка для хранения четырех массивов чисел типа int, каждый из которых состоит из трех элементов. Такое выделение памяти показано на схеме на рис.3.

arr
в
arr[0]
 а
arr[0][0]

arr[0][1]

arr[0][2]

arr[1]
 а
arr[1][0]

arr[1][1]

arr[1][2]

arr[2]
 а
arr[2][0]

arr[2][1]

arr[2][2]

arr[3]
 а
arr[3][0]

arr[3][1]

arr[3][2]
Рис.3. Распределение памяти для двумерного массива.

Таким образом, объявление arr2[4][3] порождает в программе три разных объекта: указатель с идентификатором arr, безымянный массив из четырех указателей и безымянный массив из двенадцати чисел типа int. Для доступа к безымянным массивам используются адресные выражения с указателем arr. Доступ к элементам массива указателей осуществляется с указанием одного индексного выражения в форме arr2[2] или *(arr2+2). Для доступа к элементам двумерного массива чисел типа int должны быть использованы два индексных выражения в форме arr2[1][2] или эквивалентных ей *(*(arr2+1)+2) и (*(arr2+1))[2]. Следует учитывать, что с точки зрения синтаксиса языка СИ указатель arr и указатели arr[0], arr[1], arr[2], arr[3] являются константами и их значения нельзя изменять во время выполнения программы.

Размещение трехмерного массива происходит аналогично и объявление float arr3[3][4][5] порождает в программе кроме самого трехмерного массива из шестидесяти чисел типа float массив из четырех указателей на тип float, массив из трех указателей на массив указателей на float, и указатель на массив массивов указателей на float.

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

Например, обращение к элементу arr2[1][2] можно осуществить с помощью указателя ptr2, объявленного в форме int *ptr2=arr2[0] как обращение ptr2[1*4+2] (здесь 1 и 2 это индексы используемого элемента, а 4 это число элементов в строке) или как ptr2[6]. Заметим, что внешне похожее обращение arr2[6] выполнить невозможно так как указателя с индексом 6 не существует.

Для обращения к элементу arr3[2][3][4] из трехмерного массива тоже можнo использовать указатель, описанный как float *ptr3=arr3[0][0] с одним индексным выражением в форме ptr3[3*2+4*3+4] или ptr3[22].

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

    struct INDEX {  int i,
                    int j,
                    int k }  min_index ;

    struct INDEX  * find_min (int *ptr1, int l, int m int n)
    {     int  min, i, j, k, ind;
          min=*ptr1;
          min_index.i=min_index.j=min_index.k=0;
          for (i=0; i*(ptr1+ind)
               {  min=*(ptr1+ind);
                  min_index.i=i;
                  min_index.j=j;
                  min_index.k=k;
               }
          }
          return &min_index;
    }

1.7.3. Операции с указателями

Над указателями можно выполнять унарные операции: инкремент и декремент. При выполнении операций ++ и -- значение указателя увеличивается или уменьшается на длину типа, на который ссылается используемый указатель.

Пример:

        int *ptr, a[10];
           ptr=&a[5];
           ptr++;      /* равно адресу элемента a[6] */
           ptr--;      /* равно адресу элемента a[5] */

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

Пример:

        int *ptr1, *ptr2, a[10];
        int i=2;
           ptr1=a+(i+4);   /*  равно адресу элемента a[6] */
           ptr2=ptr1-i;    /*  равно адресу элемента a[4] */

В операции вычитания могут участвовать два указателя на один и тот же тип. Результат такой операции имеет тип int и равен числу элементов исходного типа между уменьшаемым и вычитаемым, причем если первый адрес младше, то результат имеет отрицательное значение.

Пример:

        int *ptr1, *ptr2, a[10];
        int i;
           ptr1=a+4;
           ptr2=a+9;
           i=ptr1-ptr2;  /*   равно 5   */
           i=ptr2-ptr1;  /*   равно -5  */

Значения двух указателей на одинаковые типы можно сравнивать в операциях ==, !=, <, <=",">, >= при этом значения указателей рассматриваются просто как целые числа, а результат сравнения равен 0 (ложь) или 1 (истина).

Пример:

      int *ptr1, *ptr2, a[10];
         ptr1=a+5;
         ptr2=a+7;
         if (prt1>ptr2) a[3]=4;

В данном примере значение ptr1 меньше значения ptr2 и поэтому оператор a[3]=4 не будет выполнен.

1.7.4. Массивы указателей

В языке СИ элементы массивов могут иметь любой тип, и, в частности, могут быть указателями на любой тип. Рассмотрим несколько примеров с использованием указателей.

Следующие объявления переменных

     int a[]={10,11,12,13,14,};
     int *p[]={a, a+1, a+2, a+2, a+3, a+4};
     int **pp=p;

порождают программные объекты, представленные на схеме на рис.4.

  pp
в
  p
 а . . . . .
в в в в в
  a
 а
  11

  12

  13

  14

  15
Рис.4. Схема размещения переменных при объявлении.

При выполнении операции pp-p получим нулевое значение, так как ссылки pp и p равны и указывают на начальный элемент массива указателей, связанного с указателем p ( на элемент p[0]).

После выполнения операции pp+=2 схема изменится и примет вид, изображенный на рис.5.

  pp
в
  p
 а . . . . .
в в в в в
  a
 а
  10

  11

  12

  13

  14
Рис.5. Схема размещения переменных после выполнения операции pp+=2.

Результатом выполнения вычитания pp-p будет 2, так как значение pp есть адрес третьего элемента массива p. Ссылка *pp-a тоже дает значение 2, так как обращение *pp есть адрес третьего элемента массива a, а обращение a есть адрес начального элемента массива a. При обращении с помощью ссылки **pp получим 12 - это значение третьего элемента массива a. Ссылка *pp++ даст значение четвертого элемента массива p т.е. адрес четвертого элемента массива a.

Если считать, что pp=p, то обращение *++pp это значение первого элемента массива a (т.е. значение 11), операция ++*pp изменит содержимое указателя p[0], таким образом, что он станет равным значению адреса элемента a[1].

Сложные обращения раскрываются изнутри. Например обращение *(++(*pp)) можно разбить на следующие действия: *pp дает значение начального элемента массива p[0], далее это значение инкременируется ++(*p) в результате чего указатель p[0] станет равен значению адреса элемента a[1], и последнее действие это выборка значения по полученному адресу, т.е. значение 11.

В предыдущих примерах был использован одномерный массив, рассмотрим теперь пример с многомерным массивом и указателями. Следующие объявления переменных

     int a[3][3]={  { 11,12,13 },
                    { 21,22,23 },
                    { 31,32,33 }   };
     int *pa[3]={ a,a[1],a[2] };
     int *p=a[0];

порождают в программе объекты представленные на схеме на рис.6.

Рис.6. Схема размещения указателей на двумерный массив.

Согласно этой схеме доступ к элементу a[0][0] получить по указателям a, p, pa при помощи следующих ссылок: a[0][0], *a, **a[0], *p, **pa, *p[0].

Рассмотрим теперь пример с использованием строк символов. Объявления переменных

     char *c[]={ "abs", "dx", "yes", "no" };
     char **cp[]={ c+3, c+2 , c+1 , c };
     char ***cpp=cp;

можно изобразить схемой представленной на рис.7.

Рис.7. Схема размещения указателей на строки.

1.7.5. Динамическое размещение массивов

При динамическом распределении памяти для массивов следует описать соответствующий указатель и присваивать ему значение при помощи функции calloc. Одномерный массив a[10] из элементов типа float можно создать следующим образом

      float *a;
      a=(float*)(calloc(10,sizeof(float));

Для создания двумерного массива вначале нужно распределить память для массива указателей на одномерные массивы, а затем распределять память для одномерных массивов. Пусть, например, требуется создать массив a[n][m], это можно сделать при помощи следующего фрагмента программы:

   #include
   main ()
       {  double **a;
          int n,m,i;
          scanf("%d %d",&n,&m);
          a=(double **)calloc(m,sizeof(double *));
          for (i=0; i<=m; i++) a[i]="(double" *)calloc(n,sizeof(double)); . . . . . . . . . . . . }

Аналогичным образом можно распределить память и для трехмерного массива размером n,m,l. Следует только помнить, что ненужную для дальнейшего выполнения программы память следует освобождать при помощи функции free.

   #include
   main ()
       {  long ***a;
          int n,m,l,i,j;
          scanf("%d %d %d",&n,&m,&l);
          /* --------  распределение памяти -------- */
          a=(long ***)calloc(m,sizeof(long **));
          for (i=0; i<=m; i++) { a[i]="(long" **)calloc(n,sizeof(long *)); for (j="0;" i<="l;" j++) a[i][j]="(long" *)calloc(l,sizeof(long)); } . . . . . . . . . . . . /* освобождение памяти */ for (i="0;" i<="m;" i++) { for (j="0;" j<="l;" j++) free (a[i][j]); free (a[i]); } free (a); }

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

     Пример:
   #include
   main()
   {   int vvod(double ***, long **);
       double **a;     /*  указатель для массива  a[n][m]   */
       long *b;        /*  указатель для массива  b[n]      */
       vvod (&a,&b);
        ..   /* в функцию vvod передаются адреса указателей, */
        ..   /* а не их значения                             */
        ..
    }
    int vvod(double ***a, long **b)
    {   int n,m,i,j;
        scanf (" %d %d ",&n,&m);
        *a=(double **)calloc(n,sizeof(double *));
        *b=(long *)calloc(n,sizeof(long));
        for (i=0; i<=n; i++) *a[i]="(double" *)calloc(m,sizeof(double)); ..... }

Отметим также то обстоятельство, что указатель на массив не обязательно должен показывать на начальный элемент некоторого массива. Он может быть сдвинут так, что начальный элемент будет иметь индекс отличный от нуля, причем он может быть как положительным так и отрицательным.

Пример:

    #include
    int main()
    {  float *q, **b;
       int i, j, k, n, m;
       scanf("%d %d",&n,&m);
       q=(float *)calloc(m,sizeof(float));
    /* сейчас указатель q показывает на начало массива    */
       q[0]=22.3;
       q-=5;
    /* теперь начальный элемент массива имеет индекс 5,   */
    /* а конечный элемент индекс n-5                      */
       q[5]=1.5;
    /* сдвиг индекса не приводит к перераспределению      */
    /* массива в памяти и изменится начальный элемент     */
       q[6]=2.5;   /*  -  это второй элемент              */
       q[7]=3.5;   /*  -  это третий элемент              */
       q+=5;
    /* теперь начальный элемент вновь имеет индекс 0,     */
    /* а значения элементов q[0], q[1], q[2] равны        */
    /* соответственно 1.5, 2.5, 3.5                       */
       q+=2;
    /* теперь начальный элемент имеет индекс -2,          */
    /* следующий -1, затем 0 и т.д. по порядку            */
       q[-2]=8.2;
       q[-1]=4.5;
       q-=2;
    /* возвращаем начальную индексацию, три первых        */
    /* элемента массива q[0], q[1], q[2], имеют           */
    /* значения 8.2, 4.5, 3.5                             */
       q--;
    /* вновь изменим индексацию .                         */
    /* Для освобождения области памяти в которой размещен */
    /* массив q используется функция free(q), но поскольку */
    /* значение указателя q смещено, то выполнение     */
    /* функции free(q) приведет к непредсказуемым последствиям. */
    /* Для правильного выполнения этой функции    */
    /* указатель q должен быть возвращен в первоначальное */
    /* положение                                          */
       free(++q);
    /* Рассмотрим возможность изменения индексации и      */
    /* освобождения памяти для двумерного массива         */
       b=(float **)calloc(m,sizeof(float *));
       for (i=0; i < m; i++)
           b[i]=(float *)calloc(n,sizeof(float));
    /* После распределения памяти начальным элементом      */
    /* массива будет элемент b[0][0]                       */
    /* Выполним сдвиг индексов так, чтобы начальным        */
    /* элементом стал элемент b[1][1]                      */
       for (i=0; i < m ; i++) --b[i];
       b--;
    /* Теперь присвоим каждому элементу массива сумму его  */
    /* индексов                                            */
       for (i=1; i<=m; i++) for (j="1;" j<="n;" j++) b[i][j]="(float)(i+j);" /* Обратите внимание на начальные значения счетчиков */ /* циклов i и j, он начинаются с 1 а не с 0 */ /* Возвратимся к прежней индексации */ for (i="1;" i<="m;" i++) ++b[i]; b++; /* Выполним освобождение памяти */ for (i="0;" i < m; i++) free(b[i]); free(b); ... ... return 0; }

В качестве последнего примера рассмотрим динамическое распределение памяти для массива указателей на функции, имеющие один входной параметр типа double и возвращающие значение типа double.

Пример:

   #include
   #include
    double cos(double);
    double sin(double);
    double tan(double);
   int main()
   { double (*(*masfun))(double);
     double x=0.5, y;
     int i;
     masfun=(double(*(*))(double))
              calloc(3,sizeof(double(*(*))(double)));
     masfun[0]=cos;
     masfun[1]=sin;
     masfun[2]=tan;
     for (i=0; i<3; i++); { y="masfun[i](x);" printf("\n x="%g" y="%g",x,y);" } return 0; }


Программирование на языке СИ

Rambler's Top100 Дата последнего обновления файла 5.10.04

Цифровая и вычислительная техника Микропроцессоры и цифровая обработка сигналов цифровые устройства и микропроцессоры

1.8. Директивы Препроцессора

Директивы препроцессора представляют собой инструкции, записанные в тексте программы на СИ, и выполняемые до трансляции программы. Директивы препроцессора позволяют изменить текст программы, например, заменить некоторые лексемы в тексте, вставить текст из другого файла, запретить трансляцию части текста и т.п. Все директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой не ставятся.

1.8.1. Директива #include

Директива #include включает в текст программы содержимое указанного файла. Эта директива имеет две формы:

              #include "имя файла"
              #include <имя файла>

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

Директива #include может быть вложенной, т.е. во включаемом файле тоже может содержаться директива #include, которая замещается после включения файла, содержащего эту директиву.

Директива #include широко используется для включения в программу так называемых заголовочных файлов, содержащих прототипы библиотечных функций, и поэтому большинство программ на СИ начинаются с этой директивы.

1.8.2. Директива #define

Директива #define служит для замены часто использующихся констант, ключевых слов, операторов или выражений некоторыми идентификаторами. Идентификаторы, заменяющие текстовые или числовые константы, называют именованными константами. Идентификаторы, заменяющие фрагменты программ, называют макроопределениями, причем макроопределения могут иметь аргументы.

Директива #define имеет две синтаксические формы:

       #define  идентификатор текст
       #define  идентификатор (список параметров) текст

Эта директива заменяет все последующие вхождения идентификатора на текст. Такой процесс называется макроподстановкой. Текст может представлять собой любой фрагмент программы на СИ, а также может и отсутствовать. В последнем случае все экземпляры идентификатора удаляются из программы.

Пример:

      #define WIDTH 80
      #define LENGTH (WIDTH+10)

Эти директивы изменят в тексте программы каждое слово WIDTH на число 80, а каждое слово LENGTH на выражение (80+10) вместе с окружающими его скобками.

Скобки, содержащиеся в макроопределении, позволяют избежать недоразумений, связанных с порядком вычисления операций. Например, при отсутствии скобок выражение t=LENGTH*7 будет преобразовано в выражение t=80+10*7, а не в выражение t=(80+10)*7, как это получается при наличии скобок, и в результате получится 780, а не 630.

Во второй синтаксической форме в директиве #define имеется список формальных параметров, который может содержать один или несколько идентификаторов, разделенных запятыми. Формальные параметры в тексте макроопределения отмечают позиции на которые должны быть подставлены фактические аргументы макровызова. Каждый формальный параметр может появиться в тексте макроопределения несколько раз.

При макровызове вслед за идентификатором записывается список фактических аргументов, количество которых должно совпадать с количеством формальных параметров.

     Пример:
     #define  MAX(x,y) ((x)>(y))?(x):(y)
     Эта директива заменит фрагмент
                 t=MAX(i,s[i]);
     на фрагмент
                 t=((i)>(s[i])?(i):(s[i]);

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

  Например, при наличии скобок фрагмент
                 t=MAX(i&j,s[i]||j);
  будет заменен на фрагмент
                t=((i&j)>(s[i]||j)?(i&j):(s[i]||j);
  а при отсутствии скобок - на фрагмент
                t=(i&j>s[i]||j)?i&j:s[i]||j;
  в котором условное выражение вычисляется в совершенно другом порядке.

1.8.3. Директива #undef

Директива #undef используется для отмены действия директивы #define. Синтаксис этой директивы следующий #undef идентификатор

Директива отменяет действие текущего определения #define для указанного идентификатора. Не является ошибкой использование директивы #undef для идентификатора, который не был определен директивой #define.

Пример:

       #undef WIDTH
       #undef MAX

Эти директивы отменяют определение именованной константы WIDTH и макроопределения MAX.


Пред. страница След. страница


Содержание курса цифровые устройства

 Rambler's Top100 Дата последнего обновления файла 06.10.2005

Содержание лекций по курсу "Цифровые устройства"

1. Введение.

2. Логические элементы. Комбинационные устройства.

  1. Логические элементы
  2. Согласование логических микросхем между собой.
  3. Регенераторы цифровых сигналов.
  4. Принципы аппаратурной реализации таблицы истинности.
  5. Мультиплексоры,
  6. Декодеры
  7. Методы отображения цифровой информации.
  8. Динамическая индикация.

3. Генераторы.

  1. Реализация генераторов на цифровых микросхемах.
  2. Особенности кварцевой стабилизации частоты генераторов.

4. Триггеры.

  1. Построение триггерных схем,
  2. Построение регистров

5. Счетчики.

  1. Асинхронные двоичные счётчики
  2. Недвоичные счётчики с обратной связью
  3. Недвоичные счётчики с предварительной записью
  4. Синхронные счётчики.

6. Синтезаторы частоты.

  1. Цифровой фазовый детектор и фазовый компаратор.
  2. Цепи фазовой подстройки частоты.
  3. Умножители частоты

[ Главная ]


Цели и задачи изучения Содержание дисциплины Краткое описание курса Перечень литературы


список литературы

 Rambler's Top100 Дата последнего обновления файла 08.06.2005

Перечень литературы по дисциплине цифровая и вычислительная техника

Авторы | Наименование | Год издания | Примечание
ИЗДАТЕЛЬСТВО СТАНДАРТОВ | ГОСТ 2.743-91 | 1993 | ОБОЗНАЧЕНИЯ УСЛОВНЫЕ ГРАФИЧЕСКИЕ В СХЕМАХ ЭЛЕМЕНТЫ ЦИФРОВОЙ ТЕХНИКИ
У. Титце К. Шенк | Полупроводниковая схемотехника | 1983 | Очень хорошее описание цифровой схемотехники
С.А. Майоров В.В. Кириллов А.А. Приблуда | Введение в микро ЭВМ | 1988 | Прекрасный учебник, позволяющий понять как работает микропроцессор.
М. Рафикумазан | Микропроцессоры и машинное проектирование микропроцессорных систем | 1988 | Прекрасный учебник по принципам работы микропроцессоров и разработки программ для них. Можно использовать как пример по проектированию.
под ред. Е.В. Евреинова | Цифровая и вычислительная техника | 1991 | Учебник
Р. Джордейн | Справочник программиста персональных компьютеров IBM PC | 1992 | Неплохой справочник по программированию для аппаратуры компьютеров на языках программирования Бейсик и ассемблер.
Уинн Л. Рош | Библия по техническому обеспечению Уинна Роша | 1992 | Неплохой справочник по компьютерам. Можно использовать как учебник т.к. рассматриваемые компьютеры устарели
Михаил Гук | Аппаратные средства IBM PC | 1998 | Прекрасный справочник по компьютерам.
Е. Угрюмов | Цифровая схемотехника | 2001 | Хорошее описание современной цифровой схемотехники.
www.intel.com | Материалы сервера |  | (англ.)
www.intel.ru | Материалы сервера |  | (рус.)
www.ixbt.com | Материалы сервера |  | (рус.)
www.ferra.ru | Материалы сервера |  | (рус.)


Цели и задачи изучения дисциплины

Rambler's Top100 Дата последнего обновления файла 08.06.2005

Цифровая и вычислительная техника

1. Цели и задачи изучения

1.1 Цель преподавания дисциплины состоит в:

  • изучении принципов работы цифровой и вычислительной техники.
  • изучении принципов построения вычислительной техники;
  • изучении принципов разводки печатных плат микропроцессорных устройств и вычислительной техники;

1.2 В результате изучения курса студент должен знать

  • принципы построения микропроцессорных устройств и компьютеров;
  • принципы подключения ОЗУ, ПЗУ и внешних устройств к микропроцессорам;
  • способы повышения быстродействия микропроцессоров;

уметь

  • анализировать принципиальные схемы устройств связи с применением микропроцессоров;
  • работать на персональном компьютере;
  • разводить печатные платы;
  • пользоваться справочной литературой по микропроцессорам;

иметь навыки

  • работы на персональном компьютере типа IBM PC;
  • проектирования микропроцессорных систем различного назначения на основе средств вычислительной техники;
  • использования средств ручного и машинного проектирования печатных плат.


Содержание курса лекций "цифровая и вычислительная техника"

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

Содержание курса лекций "цифровая и вычислительная техника"

1. Введение.

2. Цифровая техника.

  1. Логические элементы
  2. Принципы аппаратурной реализации таблицы истинности.
  3. Сумматоры по модулю два. Построение многоразрядных арифметических сумматоров
  4. Построение мультиплексоров
  5. Построение декодеров
  6. Построение шинных формирователей.

3. Запоминающие устройства.

  1. Масочные ПЗУ, ППЗУ, РПЗУ, ЭСПЗУ, FLASH-память
  2. Построение триггерных схем, регистров и статических ОЗУ.
  3. Динамические оперативные запоминающие устройства.
  4. FPM, EDO, BEDO, SRAM.

4. Принципы работы микропроцессора.

  1. Виды двоичных кодов.
  2. Построение арифметико-логических устройств
  3. Понятие команд микропроцессора
  4. Блок обработки сигналов микропроцессора.
  5. Понятие микропрограммирования
  6. Системная шина микропроцессора
  7. Назначение микропроцессорных систем.
  8. Разновидности микропроцессорных устройств.
  9. Универсальные процессоры,
  10. Микроконтроллеры
  11. Сигнальные процессоры.
  12. Архитектура фон Неймана и гарвардская архитектура.
  13. Понятие внутренней и внешней тактовой частоты. Кэш память.

5. Принципы работы микропроцессорной системы.

  1. Подключение ОЗУ и ПЗУ к системной шине микропроцессора. Дешифратор адреса.
  2. Понятие адресного пространства и распределения памяти микропроцессорного устройства.
  3. Подключение внешних устройств к микропроцессору.
  4. Принципы построения параллельного порта.
  5. Принципы построения последовательных портов.
  6. Принципы построения таймеров.

6. Устройство универсального компьютера.

  1. Шины ввода/вывода ISA, EISA, PSI.
  2. Подключение ОЗУ к компьютеру. Понятие кэш памяти.
  3. Распределение памяти компьютеров IBM PC
  4. Структурная схема материнской платы IBM PC

[ Главная ]


Цифровая и вычислительная техника

 Rambler's Top100 Дата последнего обновления файла 08.06.2005

Цифровая и вычислительная техника

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

В процессе изучения предмета рассматривается устройство и принцип действия логических элементов, триггеров, последовательных и параллельных регистров, ОЗУ, ПЗУ, а также микропроцессоров и компьютеров.

Вычислительная техника изучается на примере компьютеров семейства IBM и совместимых с этим семейством.

В процессе изучения схемных решений компьютеров приобретаются навыки составления принципиальных схем на микропроцессорах и написания разводки печатных плат для этих схем.

Основные определения курса: микропроцессор, ОЗУ, ПЗУ, кэш-память, таймер, внешние устройства, параллельный порт, COM-порт.

    1. Цели и задачи изучения
    2. Cодержание дисциплины
    3. Перечень литературы
    4. Контрольные вопросы

В процессе изучения этой дисциплины выполняется курсовая работа.


Цели и задачи изучения Содержание дисциплины Краткое описание курса Курсовой проект Перечень литературы


Курсовое проектирование ЦВТ

 Rambler's Top100 Дата последнего обновления файла 08.06.2005

Курсовые проекты

В процессе курсового проектирования необходимо рассчитать принципиальную схему устройства, развести печатную плату для полученной схемы. Задания на курсовое проектирование для студентов группы К-27 можно скачать в WORD-формате:

Задания на курсовое проектирование (zip 11 кбайт)


Арифметико-логические устройства

 Rambler's Top100 Дата последнего обновления файла 10.06.2005

Арифметико-логические устройства

Ранее были рассмотрены схемы, осуществляющие суммирование многоразрядных кодов. Однако кроме суммирования часто требуется осуществлять не только суммирование, но и вычитание двоичных кодов. Двоичные коды, при помощи которых можно записывать отрицательные числа уже рассматривались в предыдущих лекциях. Там же было показано, что при использовании дополнительных кодов операцию вычитания двух положительных чисел можно заменить операцией суммирования положительного и отрицательного числа, при этом получение отрицательного числа из положительного числа является элементарной операцией. Для этого необходимо проинвертировать число и прибавить к нему 1.

Схема вычитателя числа A из числа B приведена на рисунке 1, а схема вычитателя числа B из числа A приведена на рисунке 2.

Рисунок 1. Схема вычитателя числа A из числа B.

Рисунок 2. Схема вычитателя числа B из числа A.

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

Рисунок 3. Структурная схема арифметического устройства.

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

Проанализируем эту таблицу. Если на все управляющие входы подать низкий потенциал, то к входу сумматора будут подключены коды A и B без инверсии. В этом случае будет производиться операция суммирования. Эта ситуация отображена первыми двумя строками таблицы выполняемых операций. Операция вычитания осуществляется второй, третьей, восьмой и девятой строкой. В этом случае один из операндов поступает на вход сумматора через блок инверторов. Правда для получения дополнительного кода не хватает единицы, но её можно подать на вход переноса сумматора PI. Ещё одной часто используемой операцией является увеличение числа на единицу или уменьшение числа на единицу. Эти операции позволяют легко организовывать циклы в программе и переходить от предыдущего операнда к следующему. Такие операции могут быть выполнены при помощи кодов, записанных в строках четыре, семь, шестнадцать и двадцать пять. Кроме того, схема арифметического устройства может просто передавать на выход любой из входных кодов без изменения, что позволяет осуществлять копирование данных (суммирование с константой ноль) через это устройство без дополнительных схем коммутации.

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

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

[ Главная ]


Двоичные асинхронные счётчики

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

Счётчики

Счётчики используются для построения таймеров или для выборки инструкций из ПЗУ в микропроцессорах. Они могут использоваться как делители частоты в управляемых генераторах частоты (синтезаторах). При использовании в цепи ФАП счётчики могут быть использованы для умножения частоты как в синтезаторах, так и в микропроцессорах.

Двоичные асинхронные счётчики

Простейший вид счётчика - двоичный может быть построен на основе T-триггера. T-триггер изменяет своё состояние на прямо противоположное при поступлении на его вход синхронизации импульсов. Для реализации T-триггера можно воспользоваться универсальным D-триггером с обратной связью, как это показано на рисунке 1.

Рисунок 1 Построение счетного T-триггера на универсальном D-триггере.

В этой схеме, так как на вход триггера подается сигнал с инверсного выхода микросхемы, при поступлении тактовых импульсов сигнал на выходе будет меняться с 0 на 1 и наоборот. Временная диаграмма сигналов на входе и выходах триггера приведена на рисунке 2.

Таким образом у нас появился счётчик, считающий до двух. Обычно требуется посчитать количество импульсов, которое больше двух. В этом случае можно использовать выходной сигнал счетного триггера как входной сигнал для следующего триггера, то есть соединить триггеры последовательно. Так можно построить любой счётчик, считающий до максимального числа, кратного степени два.

Схема счётчика, позволяющего посчитать до 16 импульсов приведена на рисунке 3, а временная диаграмма сигналов на входе и выходах этого счётчика приведена на рисунке 4.

Рисунок 3 Схема четырёхразрядного счётчика, построенного на универсальных D-триггерах.

Рисунок 4 Временная диаграмма четырёхразрядного счётчика.

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

Таблица 1. Изменение уровней на выходе суммирующего счётчика при поступлении на его вход импульсов.

номер входного импульса | Q3 | Q2 | Q1 | Q0
0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 0 | 1
2 | 0 | 0 | 1 | 0
3 | 0 | 0 | 1 | 1
4 | 0 | 1 | 0 | 0
5 | 0 | 1 | 0 | 1
6 | 0 | 1 | 1 | 0
7 | 0 | 1 | 1 | 1
8 | 1 | 0 | 0 | 0
9 | 1 | 0 | 0 | 1
10 | 1 | 0 | 1 | 0
11 | 1 | 0 | 1 | 1
12 | 1 | 1 | 0 | 0
13 | 1 | 1 | 0 | 1
14 | 1 | 1 | 1 | 0
15 | 1 | 1 | 1 | 1

Существуют готовые микросхемы асинхронных двоичных счётчиков. Классическим примером такого счётчика является микросхема 555ИЕ5. Её изображение на принципиальных схемах приведено на рисунке 5. В этой микросхеме существует вход обнуления микросхемы R, который позволяет записать во все триггеры счётчика нулевое значение.

Рисунок 5. Четырёхразрядный двоичный счётчик.

Двоичные вычитающие асинхронные счётчики

Счётчики могут не только увеличивать своё значение на единицу при поступлении на вход импульсов но и уменьшать его. Такие счётчики получили название вычитающих счётчиков. Для реализации вычитающего счётчика достаточно чтобы T-триггер срабатывал по переднему фронту входного сигнала. Это можно осуществить инвертированием этого сигнала. В схеме, приведенной на рисунке 6, для реализации вычитающего счётчика сигнал на входы последующих триггеров подаются с инверсных выводов предыдущих триггеров.

Рисунок 6 Схема четырёхразрядного двоичного вычитающего счётчика, построенного на универсальных D-триггерах.

Временная диаграмма этого счётчика приведена на рисунке 7. По этой диаграмме видно, что при поступлении на вход счётчика первого же импульса на выходах появляется максимально возможное для четырёхразрядного счётчика число 15. При поступлении следующих импульсов содержимое счётчика уменьшается на единицу. Этот процесс продолжается до тех пор, пока содержимое счётчика не станет вновь равно 0.

Рисунок 7. Временная диаграмма четырёхразрядного вычитающего счётчика.

Все возможные состояния сигналов на выходах счётчика при поступлении импульсов на вход микросхемы приведены в таблице 2:

Таблица 2. Изменение уровней на выходе вычитающего счётчика при поступлении на его вход импульсов.

номер входного импульса | Q3 | Q2 | Q1 | Q0
0 | 0 | 0 | 0 | 0
1 | 1 | 1 | 1 | 1
2 | 1 | 1 | 1 | 0
3 | 1 | 1 | 0 | 1
4 | 1 | 1 | 0 | 0
5 | 1 | 0 | 1 | 1
6 | 1 | 0 | 1 | 0
7 | 1 | 0 | 0 | 1
8 | 1 | 0 | 0 | 0
9 | 0 | 1 | 1 | 1
10 | 0 | 1 | 1 | 0
11 | 0 | 1 | 0 | 1
12 | 0 | 1 | 0 | 0
13 | 0 | 0 | 1 | 1
14 | 0 | 0 | 1 | 0
15 | 0 | 0 | 0 | 1

Для тех, кто привык работать с реально выпускаемыми микросхемами, следует обратить внимание, что для примера были использованы D-триггеры, работающие по заднему фронту. Микросхемы 1533ТМ2 (два D-триггера в одном корпусе) срабатывают по переднему фронту, поэтому схемы для суммирующего и вычитающего счётчика поменяются местами.


Недвоичные счётчики с обратной связью

 Rambler's Top100 Дата последнего обновления файла 03.05.2005

Недвоичные счётчики с обратной связью.

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

Рисунок 1. Временная диаграмма четырёхразрядного счётчика.

При использовании цифровых счётчиков в качестве устройств формирования опорных частот может потребоваться обеспечить коэффициент деления, отличающийся от степени числа 2. Ещё одна ситуация, когда необходимо применять недвоичные счётчики возникает при отображении информации, записанной в счётчике. Человек, который работает с электронной техникой, привык работать с десятичной системой счисления, поэтому возникает необходимость отображать хранящееся в счётчике число в непосредственно десятичном виде. Это намного проще сделать, если и счет вести сразу в двоично-десятичном коде. Иначе для индикации потребуется перекодировать информацию из двоичного в двоично-десятичный код.

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

Рисунок 2 Схема десятичного счётчика, построенного на основе двоичного счётчика.

В этой схеме дешифратор построен на двухвходовой схеме "2И", входящей в состав микросхемы двоичного счётчика. Дешифратор декодирует число 10 (1010 в двоичной системе счисления). В соответствии с принципами построения схем по произвольной таблице истинности для построения дешифратора требуется ещё два инвертора, подключённых к выходам 1 и 4. Однако после сброса счётчика числа, большие 10 никогда не смогут появиться на выходах микросхемы. Поэтому схема дешифратора упрощается и вместо четырёхвходовой схемы "4И" можно обойтись двухвходовой схемой. Инверторы тоже оказываются лишними.

При использовании счётчиков в качестве делителей частоты тоже можно воспользоваться обратной связью. Приведём в качестве примера схему делителя частоты на 1000. При разработке делителя прежде всего определим сколько потребуется микросхем двоичных счётчиков. Для этого определим степень числа 2, при которой число M=2n будет больше требуемого числа 1000. Это будет число 10. При возведении основания системы счисления 2 в 10 степень получится число 1024. То есть, при использовании для построения делителя частоты непосредственно триггеров, достаточно будет десяти триггеров. Однако обычно для построения делителей частоты используют готовые двоичные счётчики, поэтому определим необходимое количество микросхем двоичных счётчиков. При использовании четырёхразрядных двоичных счётчиков достаточно будет трёх микросхем, так как в трёх микросхемах будет 3*4=12 триггеров, что заведомо больше минимального числа триггеров.

Следующим этапом построения делителя частоты будет перевод коэффициента деления 1000 в двоичное представление. Десятичное число 1000 в двоичном виде будет выглядеть как 0011 1110 1000. В этом числе шесть единиц, поэтому для построения делителя будет достаточно шестивходовой схемы "И". Однако такие схемы не выпускаются, поэтому воспользуемся микросхемой "8И-НЕ". Неиспользуемые входы этой микросхемы подключим к питанию. Ненужную нам инверсию сигнала скомпенсируем дополнительным инвертором. Получившаяся схема делителя на 1000 приведена на рисунке 3.

Рисунок 3 Схема делителя на 1000, построенного на основе трёх двоичных счётчиков.

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

Рисунок 4. Схема делителя с переменным коэффициентом деления с максимальным коэффициентом деления 100, построенного на основе двух десятичных счётчиков.


Недвоичные счётчики с предварительной записью

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

Недвоичные счётчики с предварительной записью.

В счётчиках с обратной связью исключаются последние состояния двоичного счётчика. Можно поступить по другому. Начать с последнего состояния счётчика и воспользовавшись вычитающим счётчиком определять нулевое состояние счётчика. Это состояние очень просто можно определить при помощи схемы "И". В таком случае необходимо иметь возможность предварительной записи в счётчик. То есть счётчик при предварительной записи должен вести себя как параллельный регистр.


Синхронные счётчики

 Rambler's Top100 Дата последнего обновления файла 12.05.2005

Синхронные счётчики.

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


Декодеры

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

Рассмотрим пример построения декодера из двоичного кода в десятичный. Таблица истинности такого декодера приведена на рисунке 1.

Рисунок 1. Таблица истинности десятичного декодера.

В соответствии с принципами построения произвольной таблицы истинности по произвольной таблице истинности получим схему декодера, реализующего таблицу истинности, приведённую на рисунке 1. Эта схема приведена на рисунке 2.

Рисунок 2. Принципиальная схема двоично-десятичного декодера.

Точно так же можно получить схему для любого другого декодера или дешифратора.

Дешифраторы выпускаются в виде отдельных микросхем или используются в составе других микросхем, таких как мультиплексоры или ПЗУ. Изображение дешифратора на принципиальных схемах приведено на рисунке 3. На этом рисунке приведено обозначение двоично-десятичного дешифратора, принципиальная схема которого изображена на рисунке 2.

Рисунок 3. Изображение двоично-десятичного дешифратора на принципиальных схемах.


Генераторы периодических сигналов

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

Генераторы периодических сигналов.

При работе цифровых схем часто возникает задача синхронизации моментов изменения или записи сигналов. Для этого можно воспользоваться любым известным генератором сигналов, в том числе построенным на одиночном транзисторе или операционном усилителе. Однако в этом случае потребуется специальное устройство преобразования выходного сигнала генератора к цифровым логическим уровням, используемым в разрабатываемой схеме.

Намного проще использовать для построения генераторов цифрового сигнала логические элементы. Как известно из общей теории построения генераторов сигналов, для самовозбуждения генераторов необходимо выполнить два условия: баланс фаз и баланс амплитуд. Так как любые логические элементы обладают усилением, то для построения генераторов можно использовать как инверторы, так и схемы логического "И" и "ИЛИ". В некоторых случаях для построения генераторов используют даже триггеры.

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

Рисунок 1. Ёмкостная трёхточка, выполненная на биполярном транзисторе.

В этой схеме усилительный элемент включен в схему контура L1 C2 C3, резонансная частота которого и задаёт частоту генерации схемы. Глубина обратной связи задаётся соотношением ёмкостей этого контура и коэффициентом усиления транзистора на заданной частоте. Точно так же можно построить генератор и на основе логического инвертора. Схема LC генератора, построенного на основе логического инвертора, приведена на рисунке 2.

Рисунок 2. Ёмкостная трёхточка, выполненная на логическом инверторе.

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

Схема на одном инверторе чаще всего используется для построения кварцевых генераторов. В этом случае в ёмкостной трёхточке вместо индуктивности используется кварцевый резонатор. Схема кварцевого генератора на одном логическом инверторе приведена на рисунке 3.

Рисунок 3. Схема кварцевого генератора, выполненная на логическом инверторе.

Ёмкости в частотозадающей цепочке обычно выбираются в пределах от 10 до 30 пФ. Соотношение ёмкостей задаёт глубину обратной связи, а значит устойчивость запуска генератора в диапазоне температур. Кварцевый резонатор не пропускает постоянный ток, поэтому в кварцевом генераторе для обеспечения автоматического запуска генератора приходится использовать дополнительные резисторы. Именно соотношение этих резисторов определяет коэффициент усиления активного элемента генераторов. При использовании очень высокочастотных кварцевых резонаторов резистор R1 для облегчения самовозбуждения генератора может отсутствовать.

Достаточно часто возникает необходимость останавливать генератор для экономии потребления электроэнергии. В этом случае вместо логического инвертора можно использовать схему "И". Подобная схема приведена на рисунке 4. Именно такая схема используется внутри современных микросхем в качестве задающего тактового генератора.

Рисунок 4. Схема кварцевого генератора, выполненная на элементе логического "И".

Мультивибраторы.

Еще одной распространённой схемой генераторов на логических элементах является схема мультивибратора. В этой схеме для реализации положительной обратной связи используется два инвертора. Схема мультивибратора приведена на рисунке 5.

Рисунок 5. Схема мультивибратора, выполненная на двух логических инверторах.

В этой схеме возможна независимая регулировка частоты и скважности генерируемых колебаний. Длительность импульсов и длительность паузы между импульсами регулируется независимо при помощи RC цепочек R1 C2 и R3 C1. Если скважность генерируемых колебаний не важна, то можно упростить схему мультивибратора, использовав второй инвертор по прямому назначению. В этом случае схема мультивибратора примет вид, показанный на рисунке 6.

Рисунок 6. Упрощённая схема мультивибратора.

В этой схеме возможно задавать только частоту генерируемых импульсов. Эта частота будет определяться произведением R1 C1. Скважность генерируемых импульсов будет зависеть только от соотношения токов нуля и единицы выбранного логического элемента.

Достаточно часто требуется возможность получить генератор, выходная частота которого могла бы изменяться в достаточно широких пределах. В этом случае в качестве частотозадающего элемента в генераторе может быть использован элемент с изменяемыми параметрами, например варикап или полевой транзистор. Схема такого генератора, управляемого напряжением, приведена на рисунке 7.

Рисунок 7. Схема генератора, управляемого напряжением.

Учитывая, что сопротивление полевого транзистора может изменяться в пределах от 10 Ом до 10 МОм, генерируемая частота тоже может изменяться в десятки и сотни раз. Однако следует учесть, что такой генератор может быть использован только в цифровых схемах, так как его спектральные характеристики оставляют желать лучшего. Обычно такая схема используется в цепях умножения частоты внутри цифровых микросхем повышенной производительности. Примером специализированных микросхем - генераторов могут служить микросхемы 531ГГ1 и 564ГГ1.

В схеме на мультивибраторе можно использовать и кварцевую стабилизацию частоты. Для этого нужно кварцевый резонатор включить в цепь обратной связи. Схема мультивибратора с кварцевой стабилизацией частоты приведена на рисунке 8.

Рисунок 8. Схема мультивибратора с кварцевой стабилизацией частоты.


Индикаторы

Rambler's Top100 Дата последнего обновления файла 06.10.2005

Индикаторы

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

Малогабаритные лампочки накаливания

Наиболее простой схемой подключения к цифровым устройствам обладают лампочки накаливания. Эта схема приведена на рисунке 1.

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

К сожалению эти индикаторы не отличаются надёжностью, так как при включении питания через них протекает значительный ток, в результате которого лампа может выйти из строя. Кроме того они боятся ударов. Все эти причины, а также большой потребляемый ток привели к тому, что в настоящее время эти индикаторы практически не используются.

Газоразрядные лампы.

Эти индикаторы в отличие от ламп накаливания управляются не напряжением, а током. Поэтому в схему приходится вводить токоограничивающий резистор. Схема включения газоразрядного индикатора приведена на рисунке 2.

В этой схеме транзистор требуется в основном для согласования по напряжению, так как газоразрядные индикаторы питаются от напряжения 180 ... 300 В.

Это более экономичные индикаторы по сравнению с лампами накаливания, но использование высокого напряжения питания привело к тому, что они в настоящее время практически не используются.

В настоящее время практически везде используются светодиоды и жидкокристаллические индикаторы.

[ Главная ]


Особенности кварцевой стабилизации частоты генераторов

 Rambler's Top100 Дата последнего обновления файла 17.05.2005

Особенности кварцевой стабилизации частоты генераторов.

При разработке кварцевого генератора следует обращать внимание, что кварцевый генератор на основе мультивибратора работает несколько по другим принципам по сравнению с осцилляторной схемой. Если в осцилляторной схеме кварцевый резонатор используется в качестве индуктивности, входящей в колебательный контур резонатора, то в схеме мультивибратора кварцевый резонатор используется в качестве узкополосного фильтра в цепи обратной связи. Это приводит к тому, что один и тот же резонатор, включённый в схему мультивибратора и осцилляторную схему, будет генерировать различные частоты!

Для того, чтобы разобраться с этим явлением, вспомним эквивалентную схему кварцевого резонатора и характеристику зависимости сопротивления кварцевого резонатора от частоты. Эквивалентная схема кварцевого резонатора приведена на рисунке 9 а, а характеристика зависимости сопротивления от частоты - на рисунке 9 б.

Рисунок 9. а - эквивалентная схема кварцевого резонатора;
б - зависимость сопротивления кварцевого резонатора от частоты.

В схеме мультивибратора используется последовательный резонанс кварцевого резонатора (собственные колебания кристалла), а в осцилляторной схеме генерация производится на частоте, близкой к параллельному резонансу контура, образуемого индуктивностью резонатора и ёмкостью кварцедержателя. Эти частоты близки, но не могут совпадать по определению. В результате частоты генерируемых колебаний будут отличаться между собой. Обычно разность частот последовательного и параллельного резонансов составляет около 1 килогерца. Настолько же будут отличаться и частоты кварцевых генераторов, построенных по схеме мультивибратора и схеме ёмкостной трёхточки.

Так как генератор, собранный по схеме мультивибратора возбуждается на собственной частоте кварцевого кристалла, то стабильность кварцевого мультивибратора будет выше по сравнению с осцилляторной схемой, так как на частоту последовательного резонанса кварцевого резонатора не влияют внешние паразитные ёмкости. Однако в этой схеме возможно самовозбуждение генератора на частоте, далеко отстоящей от резонансной частоты кварцевого резонатора. Это обуславливается ёмкостью кварцедержателя, поэтому в схеме мультивибратора необходимо предусматривать специальные меры для борьбы с этим явлением.

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

Для уменьшения помех используются и конструктивные меры. Например, рядом с цепью генерируемого сигнала прокладывают корпусные проводники. Таким образом фактически образуется полосковая (или волноводная) линия передачи.


Логические элементы

 Rambler's Top100 Дата последнего обновления файла 13.07.2005

Логические элементы

Любые цифровые микросхемы строятся на основе простейших логических элементов "НЕ", "ИЛИ", "И".

Простейшим логическим элементом является инвертор, который работает в соответствии с таблицей, приведённой на рисунке 1. Этот логический элемент просто изменяет значение входного сигнала на прямо противоположное значение.

Tbl_Inv.gif (1170 bytes)

Рисунок 1. Таблица истинности логического инвертора

В качестве инвертора можно использовать обычный транзисторный усилитель с транзистором, включенном по схеме с общим эмиттером или истоком. Схемы, позволяющие реализовать функцию логического инвертирования, приведены на рисунке 2. На рисунке 2а приведена схема инвертора на обычном биполярном транзисторе, выполняющего функцию инвертирования, а на рисунке 2б приведена схема инвертора, выполненного на комплементарных МОП транзисторах.

Рисунок 2. Схемы, позволяющие реализовать функцию логического инвертирования.

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

Изображение инвертора на принципиальных схемах не зависит от технологии, по которой изготовлена цифровая микросхема, и приведено на рисунке 2.2. С этого момента схема инвертора в дальнейшем будет приводиться исключительно так, как это показано на рисунке 3.

inverter.gif (1082 bytes)
Рисунок 3. Изображение логического инвертора на принципиальных схемах.

Часто

Следующим наиболее распространённым элементом в цифровой технике является элемент, реализующий логическую операцию "И", однако чаще всего существуют не отдельные схемы логического "И", а более сложные схемы, выполняющие одновременно логическую функцию "И" и логическую функцию "НЕ". Таблица истинности схемы, выполняющей логическую функцию "2И-НЕ" приведена на рисунке 4.

Tbl_and.gif (1317 bytes)

Рисунок 4. Таблица истинности схемы, выполняющей логическую функцию "И-НЕ".

Как видно из приведённой таблицы истинности активный сигнал на выходе этого логического элемента появляется только тогда, когда и на входе X и на входе Y будут присутствовать логические единицы. То есть этот логический элемент действительно реализует операцию “И”

Проще всего построить такой элемент на самых обыкновенных ключах, как это показано на рисунке 5. В этой схеме ток будет протекать только тогда, когда оба ключа будут замкнуты, а значит, нулевой уровень на выходе схемы появится только при двух логических единицах на входе. Точно таким же образом выполняется элемент “И-НЕ” и на микросхемах, построенных по КМОП технологии, только в качестве ключа используется МОП транзистор. Схема логического элемента "И-НЕ", выполненного по КМОП технологии приведена на том же рисунке.

Рисунок 5. Принципиальные схемы, реализующие логическую функцию "2И-НЕ"

Изображение схемы, выполняющей логическую функцию "2И-НЕ", на принципиальных схемах приведено на рисунке 6, и с этого момента схемы, выполняющие функцию “И” будут приводиться именно в таком виде. Это изображение не зависит от конкретного типа технологии построения цифровой микросхемы.

Рисунок 6. Изображение схемы, выполняющей логическую функцию "И-НЕ".

Точно также как не существует отдельных схем логического "И", выполненных по технологии ТТЛ, не существует отдельных схем логического "ИЛИ". Таблица истинности схемы, выполняющей логическую функцию "2ИЛИ-НЕ" приведена на рисунке 7.

Tbl_and.gif (1317 bytes)

Рисунок 7. Таблица истинности схемы, выполняющей логическую функцию "ИЛИ-НЕ".

Как и в предыдущем случае воспользуемся для реализации схемы “ИЛИ” ключами. На этот раз соединим ключи параллельно. Схема, реализующая таблицу истинности 7, приведена на рисунке 8. Схема логического элемента "2ИЛИ-НЕ", выполненного по КМОП технологии приведена на этом же рисунке. Как видно из приведённых схем уровень логического нуля появится на выходе любой из этих схем, как только будет замкнут любой из ключей, то есть приведённые схемы реализуют таблицу истинности, приведённую на рисунке 7.

Рисунок 8. Принципиальные схемы, реализующие логическую функцию "2ИЛИ-НЕ"

Так как одна и та же функция может быть реализована различными схемами, то для обозначения этой функции на принципиальных схемах используется специальный символ ‘1’, как это приведено на рисунке 9.

or.gif (1087 bytes)

Рисунок 9. Изображение схемы, выполняющей логическую функцию "ИЛИ-НЕ".


Мультиплексоры

Мультиплексорами называются устройства, которые позволяют подключать несколько входов к одному выходу. Демультиплексорами называются устройства, которые позволяют подключать один вход к нескольким выходам. В простейшем случае такую коммутацию можно осуществить при помощи ключей:

Рисунок 1. Коммутатор (мультиплексор), собранный на ключах.

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

Рассмотрим таблицу истинности логического элемента "И". При этом один из входов логического элемента "И" будем рассматривать как информационный вход электронного ключа, а другой вход – как управляющий. Так как оба входа логического элемента "И" эквивалентны, то не важно какой из них будет управляющим входом. Пусть вход X будет управляющим, а Y– информационным. Для простоты рассуждений, разделим таблицу истинности на две части в зависимости от уровня логического сигнала на управляющем входе X.

По таблице истинности отчетливо видно, что пока на управляющий вход X подан нулевой логический уровень, сигнал, поданный на вход Y, на выход Out не проходит. При подаче на управляющий вход X логической единицы, сигнал, поступающий на вход Y, появляется на выходе Out. То есть логический элемент "И" можно использовать в качестве электронного ключа. При этом не важно какой из входов элемента "И" будет использоваться в качестве управляющего входа, а какой - в качестве информационного. Остается только объединить выходы элементов "И" в один выход. Это делается при помощи элемента "ИЛИ" точно так же как и при построении схемы по произвольной таблице истинности. Такой вариант схемы коммутатора приведен на рисунке 2.

Рисунок 2. Принципиальная схема мультиплексора, выполненая на логических элементах.

В схемах, приведенных на рисунках 1 и 2, можно одновременно включать несколько входов на один выход. Однако обычно это приводит к непредсказуемым последствиям. Кроме того, для управления таким коммутатором требуется много входов, поэтому в состав мультиплексора обычно включают двоичный дешифратор, как показано на рисунке 3. Это позволяет управлять переключением информационных входов при помощи двоичных кодов, подаваемых на управляющие входы. Количество информационных входов в таких схемах выбирают кратным степени числа два.

Рисунок 3. Принципиальная схема мультиплексора, управляемого двоичным кодом.

Мультиплексор с двоичным управлением изображается на принципиальных схемах как показано на рисунке 4.

Рисунок 4. Обозначение мультиплексора на принципиальных схемах.

Демультиплексоры

Задача передачи сигнала с одного входа микросхемы на один из нескольких выходов называется демультиплексированием. Демультиплексор можно построить на основе точно таких же схем логического "И", как и при построении мультиплексора. Существенным отличием от мультиплексора является возможность объединения нескольких входов в один без дополнительных схем. Однако для увеличения нагрузочной способности микросхемы, на входе демультиплексора для усиления входного сигнала лучше поставить инвертор.

Схема демультиплексора приведена на рисунке 5. В этой схеме для выбора конкретного выхода демультиплексора, как и в мультиплексоре, используется двоичный дешифратор.

Рисунок 5. Принципиальная схема демультиплексора, управляемого двоичным кодом.

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


Регистры

Регистром называется последовательное или параллельное соединение триггеров. Регистры обычно строятся на основе D триггеров. При этом для построения регистров могут использоваться как универсальные D триггеры, так и триггеры-защелки. При использовании для построения параллельного регистра триггеров-защелок регистр называется регистр-защелка. Параллельный регистр служит для запоминания многоразрядного двоичного слова. Количество триггеров, входящее в состав параллельного регистра определяет его разрядность. Схема четырёхразрядного параллельного регистра приведена на рисунке 1, а его обозначение на принципиальных схемах на рисунке 2.

Рисунок 1. Схема параллельного регистра.

Рисунок 2. Обозначение параллельного регистра на принципиальных схемах.

При записи информации в параллельный регистр все биты (двоичные разряды) записываются одновременно.

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

Рисунок 3. Схема последовательного регистра.

Рисунок 4. Обозначение последовательного регистра на принципиальных схемах.

Регистры сдвига выполняют обычно как универсальные последовательно-параллельные микросхемы. Переключение регистра из параллельного режима в последовательный и наоборот осуществляется при помощи мультиплексора. Схема такого регистра приведена на рисунке 5, а его изображение на принципиальных схемах - на рисунке 6.

Рисунок 5. Схема универсального регистра.

Рисунок 6. Обозначение универсального регистра на принципиальных схемах.


Логические элементы

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Построение произвольной таблицы истинности.

Любая логическая схема без памяти полностью описывается таблицей истинности. При построении сложных логических схем с произвольной таблицей истинности используется сочетание простейших схем "И" "ИЛИ" "НЕ".

При построении схемы, реализующей произвольную таблицу истинности, каждый выход анализируется (и строится схема) отдельно. Для реализации схемы можно воспользоваться как схемами “И” так и схемами “ИЛИ”. В настоящее время наиболее распространены микросхемы, совместимые с ТТЛ технологией, а в этой технологии проще всего получить элементы “И”. Поэтому рассмотрим способ реализации произвольной таблицы истинности основанный на логических элементах “И”.

Для реализации таблицы истинности при помощи логических элементов "И" достаточно рассмотреть только те строки таблицы истинности, которые содержат логические "1" в выходном сигнале. Строки, содержащие в выходном сигнале логический 0 в построении схемы не участвуют. Каждая строка, содержащая в выходном сигнале логическую "1", реализуется схемой логического "И" с количеством входов, совпадающим с количеством входных сигналов в таблице истинности.

Входные сигналы, описанные в таблице истинности логической единицей, подаются на вход этой схемы непосредственно, а входные сигналы, описанные в таблице истинности логическим нулем, подаются на вход этой же схемы "И" через инверторы. Объединение сигналов с выходов схем "И", реализующих отдельные строки таблицы истинности, производится при помощи схемы логического “ИЛИ”. Количество входов в схеме “ИЛИ” определяется количеством строк в таблице истинности, в которых в выходном сигнале присутствует логическая единица.

Рассмотрим конкретный пример. Пусть необходимо реализовать таблицу истинности, приведенную на рисунке 10:

Рисунок 10. Произвольная таблица истинности.

Для построения схемы, реализующей сигнал Out1, достаточно рассмотреть строки, выделенные красным цветом. Эти строки реализуются микросхемой D2 на рисунке 11. Каждая строка реализуется своей схемой "И", затем выходы этих схем объединяются. Количество входов элемента “И” однозначно определяется количеством входных сигналов в таблице истинности. Количество этих элементов, а значит и количество входов в логическом элементе “ИЛИ” определяется количеством строк с единичным сигналом на реализуемом выходе схемы.

Для построения схемы, реализующей сигнал Out2, достаточно рассмотреть строки, выделенные зеленым цветом. Эти строки реализуются микросхемой D3. Принцип построения этой схемы не отличается от примера, рассмотренного выше, и поэтому повторяться не будет.

Рисунок 11. Принципиальная схема, реализующая таблицу истинности, приведенную на рисунке 10.

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


Сумматоры

 Rambler's Top100 Дата последнего обновления файла 10.06.2005

Сумматоры

Построение двоичных сумматоров обычно начинается с сумматора по модулю 2. На рисунке 1 приведена таблица истинности этого сумматора. Ее можно получить исходя из правил суммирования в двоичной арифметике. Предполагается, что читатель знаком с основами двоичной арифметики. Более подробно операции над двоичными числами будут рассмотрены позднее.

Рисунок 1. Таблица истинности сумматора по модулю 2.

В соответствии с принципами построения произвольной таблицы истинности, рассмотренными в предыдущей главе, получим схему сумматора по модулю 2. Эта схема приведена на рисунке 2.

Рисунок 2. Принципиальная схема, реализующая таблицу истинности сумматора по модулю 2.

Сумматор по модулю 2 (для двоичной арифметики его схема совпадает со схемой исключающего "ИЛИ") изображается на схемах как показано на рисунке 3.

Рисунок 3. Изображение схемы, выполняющей логическую функцию исключающего "ИЛИ".

Сумматор по модулю 2 выполняет суммирование без учета переноса. В полном двоичном сумматоре требуется учитывать перенос, поэтому требуются схемы, позволяющие формировать перенос в следующий двоичный разряд. Таблица истинности такой схемы, называемой полусумматором, приведена на рисунке 4.

Рисунок 4. Таблица истинности полусумматора.

В соответствии с принципами построения произвольной таблицы истинности получим схему полусумматора. Эта схема приведена на рисунке 5.

Рисунок 5. Принципиальная схема, реализующая таблицу истинности полусумматора.

Полусумматор изображается на схемах как показано на рисунке 6.

Рисунок 6. Изображение полусумматора на схемах.

Схема полусумматора формирует перенос в следующий разряд, но не может учитывать перенос из предыдущего разряда, поэтому она и называется полусумматором. Таблицу истинности полного двоичного одноразрядного сумматора можно получить из правил суммирования двоичных чисел. Она приведена на рисунке 7. В обозначении входов использовано следующее правило: в качестве входов использованы одноразрядные числа A и B; перенос обозначен буквой P; для обозначения входа переноса используется буква I (сокращение от английского слова input – вход); для обозначения выхода переноса используется буква O (сокращение от английского слова output – выход).

Рисунок 7. Таблица истинности полного двоичного одноразрядного сумматора.

В соответствии с принципами построения принципиальной схемы по произвольной таблице истинности получим схему полного двоичного одноразрядного сумматора. Эта схема приведена на рисунке 8. Ее можно минимизировать, но это несколько усложняет принципы построения сумматоров, поэтому вопросы минимизации рассматриваться не будут.

Рисунок 8. Принципиальная схема, реализующая таблицу истинности полного двоичного одноразрядного сумматора.

Полный двоичный одноразрядный сумматор изображается на схемах как показано на рисунке 9.

Рисунок 9 Изображение полного двоичного одноразрядного сумматора на схемах.

Для того чтобы получить многоразрядный сумматор, достаточно соединить входы и выходы переносов соответствующих двоичных разрядов. Схема соединения одноразрядных сумматоров для реализации четырехразрядного сумматора приведена на рисунке 10.

Рисунок 10. Принципиальная схема многоразрядного двоичного сумматора.

Одноразрядные сумматоры практически никогда не использовались, так как почти сразу же были выпущены микросхемы многоразрядных сумматоров. Полный двоичный четырехразрядный сумматор изображается на схемах как показано на рисунке 11.

Рисунок 11. Изображение полного двоичного многоразрядного сумматора на схемах.

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

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

[ Главная ]


Триггеры

 Rambler's Top100 Дата последнего обновления файла 07.06.2005

Триггеры

Триггеры предназначены для запоминания двоичной информации. Использование триггеров позволяет реализовывать устройства оперативной памяти (то есть памяти, информация в которой хранится только на время вычислений). Однако триггеры могут использоваться и для построения некоторых цифровых устройств с памятью, таких как счётчики, преобразователи последовательного кода в параллельный или цифровые линии задержки.

Простейшая схема, позволяющая запоминать двоичную информацию, строится на основе простейших логических элементов, "ИЛИ" или "И". Такая схема, построенная на элементах "И" приведена на рисунке 1. Вход S (Set) позволяет устанавливать выход триггера Q в единичное состояние при подаче на его вход логического нуля. Вход R (Reset) позволяет сбрасывать выход триггера Q в нулевое состояние при подаче на его вход логического нуля. По названию своих входов и сам триггер получил название RS-триггера.

Рисунок 1 Схема простейшего триггера на схемах "И". Входы R и S инверсные (активный уровень'0')

Точно так же можно построить RS-триггер и на логических элементах "ИЛИ". Схема RS триггера, построенного на логических элементах "ИЛИ" приведена на рисунке 2. Единственное отличие будет заключаться в том, что сброс и установка триггера будет производиться единичными логическими уровнями.

Рисунок 2 Схема простейшего триггера на схемах "ИЛИ". Входы R и S прямые (активный уровень '1')

Так как триггер при построении его на различных элементах работает одинаково, то его изображение на принципиальных схемах тоже одинаково. Изображение простейшего триггера на принципиальных схемах приведено на рисунке 3.

Рисунок 3 Обозначение простейшего триггера на принципиальных схемах

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

Для таких цифровых схем требуются синхронные триггеры. Схема синхронного триггера приведена на рисунке 4, а обозначение на принципиальных схемах на рисунке 5.

Рисунок 4 Схема синхронного триггера на схемах "И"

Рисунок 5 Обозначение синхронного триггера на принципиальных схемах

В приведенной схеме для записи логического 0 и логической 1 требуются разные входы, что не всегда удобно. Поэтому для запоминания дискретной информации применяются D триггеры. Схема такого триггера приведена на рисунке 6, а обозначение на принципиальных схемах на рисунке 7.

D_trg.gif (1564 bytes)

Рисунок 6 Схема D триггера (защелки)

D_trg_S.gif (1333 bytes)

Рисунок 7 Обозначение D триггера (защелки) на принципиальных схемах

Во всех приведенных схемах синхросигнал работает по уровню, поэтому триггеры называются триггеры-защёлки. Легче всего объяснить появление этого названия по временной диаграмме, приведенной на рисунке 8.

DiagTrgZ.gif (5000 bytes)

Рисунок 8. Временная диаграмма D триггера (защелки)

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

Принципиально в этой схеме входной переходной процесс может беспрепятственно проходить на выход триггера. Поэтому там, где это важно, необходимо сокращать длительность импульса синхронизации до минимума. Чтобы преодолеть такое ограничение были разработаны триггеры, работающие по фронту. Схема такого триггера приведена на рисунке 9, а обозначение на принципиальных схемах на рисунке 10.

D_trg_F.gif (2144 bytes)

Рисунок 9 Схема универсального D триггера

Рисунок 10 Обозначение универсального D триггера на принципиальных схемах


Фильтры для устранения эффекта наложения спектров

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Фильтры для устранения эффекта наложения спектров (Антиалайзинговые фильтры)

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

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

Предположим, что частота среза фильтра равна fa. На рисунке 1а показан эффект возникновения помехи, обусловленной отображением сигнала из второй зоны Найквиста в первую. Именно эта помеха определяет динамический диапазон системы DR. В приведённом примере составляющие спектра, которые попадают в диапазон между fa и fs /2, не представляют интереса и не ограничивают динамический диапазон системы. Необходимо отметить, что в ряде источников этот эффект называется эффектом "заворота спектра".

Рисунок 1 Влияние частоты дискретизации на требования к аналоговому фильтру.

Таким образом крутизна АЧХ определяется верхней частотой сигнала fa, началом полосы задерживания fs-fa и требуемым затуханием в полосе задерживания DR. Динамический диапазон системы выбирается исходя из требований точности представления сигнала.

При всех прочих равных условиях фильтры становятся более сложными по мере того, как увеличивается крутизна АЧХ. Например, фильтр Баттерворта дает ослабление 6 дБ на октаву для каждого порядка. Для достижения ослабления 60 дБ на частоте 2 МГц при полосе сигнала 1 МГц (1 октава) требуется как минимум фильтр 10-го порядка - это фильтр, весьма трудный в разработке и дорогой в производстве.

Рисунок 2 АЧХ фильтра Баттерворта 10-го порядка.

Кроме сложности разработки и производства фильтры высокого порядка обладают ещё рядом недостатков, таких как нелинейная фазовая характеристика и увеличение групповой задержки на краю полосы пропускания фильтра. В качестве примера на рисунке 2 приведена амплитудно-частотная характеристика фильтра Баттерворта 10-го порядка, а на рисунке 3 - фазо-частотная характеристика и зависимость группового времени запаздывания от частоты. Всё это приводит к тому, что при преобразовании сигнала из аналоговой формы в цифровую нежелательно использовать аналоговые фильтры формирования спектра высокого порядка.

Рисунок 2 ФЧХ и групповая задержка фильтра Баттерворта 10-го порядка.

Из приведённых рассуждений видно, что недостаточная крутизна спада ФНЧ может компенсироваться более высокой частотой дискретизации АЦП. Выбрав более высокую частоту дискретизации (избыточную дискретизацию), мы уменьшаем требование к крутизне спада и, следовательно, сложность фильтра. Этот эффект достигается за счет использования более быстрого АЦП и более высокой скорости обработки данных. На рисунке 1б показан эффект, возникающий при увеличении частоты дискретизации в K раз, при неизменных требованиях к частоте среза fa и к динамическому диапазону DR. Более пологий скат делает этот фильтр проще для проектирования, по сравнению со случаем, показанным на рисунке 1а.

ИЗБЫТОЧНАЯ ДИСКРЕТИЗАЦИЯ УМЕНЬШАЕТ ТРЕБОВАНИЯ К КРУТИЗНЕ СПАДА ФНЧ

Процесс проектирования аналогового фильтра начинается с выбора начальной частоты дискретизации. Она обычно выбирается в диапазоне от 2,5 fa до 4 fa. Затем, исходя из требуемого динамического диапазона, определяется характеристика фильтра, и определяется реализуемость такого фильтра с учетом ограничений по стоимости системы и требуемой производительности этой системы. Если реализация окажется невозможной, полезно рассмотреть вариант с более высокой частотой дискретизации, для которого, возможно, потребуется более быстрый АЦП. Следует отметить, что sigma-delta-АЦП изначально являются преобразователями с избыточной дискретизацией, и данное обстоятельство существенно ослабляет требования к аналоговому фильтру, формирующему спектр, что является дополнительным преимуществом данной архитектуры.

Требования к аналоговому формирующему спектр фильтру могут быть несколько ослаблены, если вы уверены, что сигнал с частотой, которая попадает в полосу задержки fs - fa, никогда не достигнет амплитуды основного сигнала. Во многих приложениях появление таких сигналов на этой частоте действительно маловероятно. Если максимум сигнала в полосе частот fs - fa никогда не превысит X дБ над амплитудой основного сигнала, то требования к затуханию в полосе задержки фильтра может быть уменьшено на ту же самую величину. Новое требование к затуханию в полосе задержки fs - fa основано на понимании того факта, что в этом случае значение подавляемого сигнала составляет DR-X дБ. В случае реализации этого варианта будьте внимательны при устранении любых шумов, частоты которых могут быть выше частоты fa - это мешающие сигналы, которые также будут создавать НЧ- составляющую в полосе сигнала.

Субдискретизация (дискретизация гармонических и полосовых сигналов, дискретизация на промежуточной частоте (ПЧ), прямое преобразование ПЧ в цифровую форму)

До сих пор мы рассматривали случай дискретизации низкочастотных сигналов (видеосигналов или огибающих), когда все интересующие нас сигналы лежат в первой зоне Найквиста. На рис.2.6 A представлен случай, когда полоса оцифрованных сигналов ограничена первой зоной Найквиста, а в остальных зонах Найквиста появляются образы первоначального диапазона частот.

Рис. 2.6 Субдискретизация сигнала

Рассмотрим случай, показанный на рис.2.6 B, где полоса дискретизированного сигнала полностью находится во второй зоне Найквиста. Часто процесс дискретизации сигнала, находящегося вне первой зоны Найквиста, называется субдискретизацией или дискретизацией гармонического сигнала. Отметим, что образ сигнала в первой зоне Найквиста содержит всю информацию об исходном сигнале, за исключением его первоначального местоположения (кроме того порядок частот в спектре обратный, но это легко корректируется переупорядочиванием компонентов спектра на выходе БПФ).

На рис.2.6 C показан вариант дискретизированного сигнала, расположенного в третьей зоне Найквиста. Отметим, что в первой зоне Найквиста нет обращения частот. Действительно, частоты подлежащих дискретизации сигналов могут лежать в любой зоне Найквиста, и боковая полоса в первой зоне Найквиста является точным представлением сигнала (за исключением обращения частот, которое происходит, когда сигналы расположены в четных зонах Найквиста). Здесь мы можем вновь ясно сформулировать критерий Найквиста:

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

Обратите внимание, что в этой формулировке нет никакого упоминания об абсолютном местоположении полосы дискретизируемых сигналов в частотном спектре относительно частоты дискретизации. Единственное ограничение состоит в том, что полоса подлежащих дискретизации сигналов ограничена одной зоной Найквиста, то есть, полосы сигналов не должны перекрывать частоту fs/2 с любым множителем (это на самом деле и является основной функцией антиалайзингового фильтра).

Дискретизация сигналов, лежащих выше первой зоны Найквиста, стала популярной в аппаратуре связи так как этот процесс эквивалентен аналоговой демодуляции. Обычным становится дискретизация сигналов ПЧ с последующим использованием цифровых методов для обработки сигнала. таким способом исчезает необходимость использования демодулятора ПЧ. Ясно, что с ростом ПЧ растут и требования к производительности АЦП. Ширина полосы входа АЦП и характеристики, связанные с допустимыми искажениями сигналов, должны быть адекватны скорее ПЧ, чем основной полосе частот. Это является проблемой для большинства АЦП, предназначенных для обработки сигналов в первой зоне Найквиста, поэтому для субдискретизации нужен АЦП, который может обрабатывать сигналы в других более высокочастотных зонах Найквиста.


список литературы ЦОС

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Перечень литературы по дисциплине Микропроцессоры и цифровая обработка сигналов

Авторы | Наименование | Год издания |
Ж. Макс | Методы и техника обработки сигналов при физических измерениях | 1983 |
Ричард Блейхут | Быстрые алгоритмы цифровой обработки сигналов | 1986 |
Федорков Б.Г, Телец В.А. | Микросхемы ЦАП и АЦП: функционирование, параметры, применение | 1990 |
Walt Kester | Mixed signal and DSP design techniques | 2000 |
www.analog.com | Материалы сервера |  | (англ.)
www.ti.com | Материалы сервера |  | (англ.)
www.analog.com.ru | Материалы сервера |  | (рус.)
www.motorola.com | Материалы сервера |  | (рус.)


Квантование аналогового сигнала по времени

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Структурная схема цифрового устройства обработки сигнала.

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

Рисунок 1. Структурная схема цифрового устройства

На рисунке 1 представлена система, работающая в реальном масштабе времени. В ней устройство выборки и хранения (дискретизатор) непрерывно стробирует сигнал с частотой, равной fs, и АЦП выдает новый отсчет сигнала процессору ЦОС (DSP). Для обеспечения работы в реальном масштабе времени сигнальный процессор должен закончить все вычисления в пределах интервала дискретизации 1/fs и передать выходной отсчет на ЦАП до поступления следующего отсчета с АЦП. В качестве примера устройства цифровой обработки сигнала может выступать цифровой фильтр.

Возможна другая реализация устройств реального времени. При реализации на сигнальном процессоре алгоритма БПФ, входной блок данных целиком загружается в память этого процессора. Для обеспечения работы устройства в реальном масштабе времени пока сигнальный процессор выполняет алгоритм БПФ над ранее полученным блоком данных, новый блок данных накапливается в памяти. Сигнальный процессор должен успеть вычислить спектр в течение интервала накопления блока данных, чтобы быть готовым к процессу обработки следующего блока данных.

Обратите внимание, что ЦАП требуется только в том случае, когда данные необходимо преобразовать обратно в аналоговый сигнал (например, при обработке изображения или звука). Есть много устройств, где после первоначального аналого-цифрового преобразования сигнал остается в цифровом формате. Кроме того существуют устройства в которых сигнальный процессор предназначен исключительно для формирования сигнала, подаваемого на ЦАП такие как CD-проигрыватели. Если в устройстве используется ЦАП, то на его выходе для подавления нежелательных составляющих выходного спектра необходимо применять формирующий фильтр (anti-imaging filter).

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

Квантование аналогового сигнала по времени

Концепции квантования по времени и амплитуде аналогового сигнала показаны на рисунке 1. Дискретизация непрерывных аналоговых данных должна осуществляться с интервалом времени ts=1/fs, который должен быть тщательно выбран для гарантированно точного представления первоначального аналогового сигнала. Ясно, что чем больше будет взято отсчетов на интервале времени (больше частота дискретизации), тем более точным будет представление сигнала в цифровом виде, а при уменьшении количества отсчетов (уменьшении частоты дискретизации) может быть достигнута точка, где сигнал может быть потерян. Это следует из известного критерия Найквиста, показанного на рисунке 2.

КРИТЕРИЙ НАЙКВИСТА

  • Частота дискретизации fs сигнала с шириной полосы fa должна удовлетворять условию fs > 2fa, в противном случае информация о сигнале будет потеряна
  • Эффект наложения спектров возникает, когда fs < 2fa
  • Эффект наложения спектров широко используются в таких задачах, как прямое преобразование ПЧ в цифровую форму
    •

Рисунок 2 Критерии Найквиста.

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

Для понимания смысла наложения спектров как во временной, так и в частотной областях сначала рассмотрим случай представления во временной области выборки одного тонального сигнала синусоидальной формы, показанный на рисунке 3. В этом примере частота дискретизации fs лишь немного больше частоты аналогового входного сигнала fa, что не удовлетворяет критерию Найквиста. Обратите внимание, что в результате сделанная выборка соответствует сигналу, частота которого равна разности частот дискретизации и частоты исходного сигнала fs-fa. Та же самая ситуация в частотной области приведена на рисунке 4 b.

Теперь рассмотрим дискретизацию одиночного синусоидального сигнала с частотой fa идеальным дискретизатором (см. рис.2.4, A) с частотой следования дельта импульсов fs. Пусть, fs>2fa. В частотном спектре на выходе дискретизатора видны гармоники частоты дискретизации fs, промодулированные исходным сигналом, то есть появляются образы сигнала на частотах, равных |±Kfs ±fa|, где K = 1, 2, 3, 4, ...

Рисунок 3 Эффект наложения спектров во временной области.

Рисунок 4 Спектр дискретизированного аналогового сигнала

А-низкочастотного
B-полосового.

Полоса сигнала по Котельникову определяется как спектр от постоянного тока до fs/2. Частотный спектр разделен на бесконечное число зон Найквиста, каждая по 0,5 fs. На практике идеальный дискретизатор перемещает все образы в полосу от 0 до fs/2 и накладывает их на сигнал в первой зоне Котельникова.

Теперь рассмотрим случай, когда частота сигнала выходит за пределы первой зоны Котельникова (рис. 2.4 B). При частоте сигнала немного меньшей частоты дискретизации, временная диаграмма приведена на рисунке 3. Обратите внимание, что несмотря на то, что сигнал находится вне первой зоны Найквиста, его составляющая fs-fa попадает внутрь этой зоны. Возвращаясь к рис.2.4 A, становится ясно, что, если мешающий сигнал появляется на любом из образов частоты fa, он тут же переносится на частоту fa, приводя, таким образом, к появлению мешающего частотного компонента в первой зоне Котельникова.

Такой процесс подобен работе аналогового смесителя. Это означает, что перед дискретизатором требуется фильтрация, подавляющая компоненты, частоты которых находятся вне полосы Котельникова и после дискретизации попадают в ее пределы. Рабочая характеристика фильтра будет зависеть от того, как близко частота внеполосного сигнала отстоит от fs/2, а также величиной требуемого подавления.

Погрешности дискретизатора.

До сих пор предполагалось, что квантование по времени производится дельта импульсами. Однако это математическая абстракция. Обычно ключ дискретизатора открывается на определённое время, достаточное для запоминания аналогового сигнала на конденсаторе (даже если этот конденсатор паразитный). Теперь образы сигнала уже нельзя считать распространяющимися до бесконечности. Такая цепь обычно называется интегрирующей и её импульсная характеристика приведена на рисунке 5.

Рисунок 5 Нарастание напряжения на входе дискретизатора при открывании ключа.

Рисунок 6 Амплитудно-частотная характеристика дискретизатора

Именно эта характеристика определяет время открывания ключа дискретизатора, достаточное для установления напряжения, меньшего половины младшего разряда АЦП. Такой режим работы дискретизатора называется режимом слежения. Частотная характеристика этой цепи приведена на рисунке 6.

Теперь образы сигналов не будут распространяться до бесконечности. Амплитуда образа будет зависеть от частотной характеристики цепи заряда конденсатора. На рисунках 5 и 6 приведена частотная характеристика простейшей цепи заряда. Однако на высоких частотах необходимо учитывать переходный процесс более сложных цепей таких как индуктивность проводников корпуса, влияние входных и выходных ёмкостей усилителей. В результате переходная характеристика становится более сложной. В соответствии с ней изменится и ёё частотная характеристика. Пример импульсной и частотной характеристик такой цепи приведён на рисунках 7 и 8.

Рисунок 7

Рисунок 8

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

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

В качестве альтернативного режима работы дискретизатора предлагается интегрирующий режим работы. В этом режиме работы используется начальный участок переходной характеристики схемы. На этом участке напряжение на выходе линейно растёт при подаче на вход постоянного напряжения, то есть осуществляется интегрирование входного сигнала. При этом напряжение на конденсаторе после окончания стробирующего импульса будет пропорционально энергии входного сигнала, длительности и формы стробирующего импульса. Длительность и форма стробирующего сигнала может быть при этом учтена как константа. Уменьшение напряжения по сравнению с режимом слежения может быть скомпенсировано дополнительным усилителем на входе АЦП. Основное преимущество такого режима работы заключается в усреднении влияния переднего и заднего фронта, то есть большая верность преобразования сигнала. Кроме того уменьшается время стробирования, т.к. используется только начальный участок переходной характеристики схемы.


Цели и задачи изучения Содержание дисциплины Краткое описание курса Контрольная работа Перечень литературы


Контрольная работа, курсовое проектирование и расчётно-графические задания

 Rambler's Top100 Дата последнего обновления файла 09.06.2005

ЗАДАНИЯ К КОНТРОЛЬНОЙ РАБОТЕ

Контрольная работа посвящена изучению архитектуры, системы команд, методов программирования и использования в технике связи микроконтроллеров семейства MCS-51.

При решении заданий контрольной работы и подготовке к ее защите необходимо учесть, что общие вопросы построения микропроцессорных систем изложены в [9]. Конкретные примеры построения контроллеров на основе однокристальных ЭВМ этого семейства подробно изложены в [2] - [4]. Поэтому рекомендуется перед выполнением контрольной работы сначала ознакомиться с содержанием учебников, а затем подробно изучить вопросы построения микроконтроллеров на основе микро-ЭВМ MCS-51.

Контрольная работа состоит из двух заданий. В каждом задании номер варианта определяется по двум последним цифрам шифра студента, через i обозначена последняя, через j – предпоследняя цифра шифра студента.

Задание 1. Записать результат выполнения команд ОЭВМ семейства MCS-51, приведенных в таблице 5, указать источник, приемник и способы используемой адресации для каждого из операндов. При выполнении задания обязательно записывать содержимое регистров микроконтроллера до выполнения команды и содержимое регистров микроконтроллера после выполнения команды.

Таблица 1 Исходные данные к заданию 1

п/п | Мнемоника команды и исходные данные | Дополнительное задание
1 | MOV A, ij; (A)=2iH, (внутр. ОЗУ [ijH])=i, (PC)=1jiH |
2 | MOVX A, @DPTR; (A)=2iH, (DPTR)=0i0jH, (внешн. ОЗУ [0i0jH])=jiH, (PC)=2jiH |
3 | MOVC A, @A+DPTR; (A)=2iH, (DPTR)=0i0jH, (содержимое операнда-источника из ПЗУ)=jiH, (PC)=2jiH | Указать адрес операнда-источника в ПЗУ
4 | ADD A, @R0; (A)=1iH, (R0)=ijH, (внутр. ОЗУ [ijH])=i, (PC)=1jiH |
5 | ANL P1, #ijH; (P1)=jiH, (PC)=1jiH |
6 | ORL P1, #ijH; (P1)=jiH, (PC)=1jiH |
7 | SETB P1.3; (P1)=jiH, (PC)=1jiH |
8 | LJMP ijH, (PC)=4jiH |
9 | LABLE: JB P1.3, LABLE;;(P1)=jiH, (pc)=1jiH |
10 | LABLE: JNB P1.3, LABLE;;(P1)=jiH, (pc)=1jiH |

Задание 2. Написать фрагмент программ, обеспечивающий выполнение действий в соответствии с таблицей 6. При написании программы обязательно использование комментариев, поясняющих действие каждой группы команд. К каждой программе обязательно должна прилагаться принципиальная схема контроллера, соответствующая заданию.

Таблица 2 Исходные данные к заданию 2

Номер варианта | Задание 2.1. | Задание 2.2.
j1 | Обнуление всех ячеек внутренней памяти данных | Генерация меандра на выводе P1.0 с частотой 50кГц (период 20мкс).
j2 | Сложение двух 16-разрядных чисел. 1-е слагаемое: мл. байт расположен по адресу 14Н; ст. байт - 15Н; 2-е слагаемое: мл. байт расположен по адресу 12Н; ст. байт - 13Н | Включение привода и опрос концевого датчика
j3 | Вывод символа «6» при подключении к микроконтроллеру светодиодного индикатора АЛС324Б. | Запуск трёхфазного двигателя при нажатии кнопки S
j4 | Сложение 16-разрядного и 8-разрядного чисел. 1-е слагаемое: мл. байт (А)=11Н; ст. байт (R2)=23Н; 2-е слагаемое: (R3)=14Н | Программно реализованная временная задержка на 1 мс
j5 | Деление массива чисел, хранящихся во внутреннем ОЗУ (ячейки 24Н … 33Н) на 4 | Сохранение регистров текущего банка в стеке
j6 | Сложение двух двоично-десятичных чисел в упакованном формате. 1-е слагаемое: мл. байт расположен по адресу 14Н; ст. байт - 16Н; 2-е слагаемое: мл. байт расположен по адресу 11Н; ст. байт - 13Н | Реализовать временную задержку на 1 мс на таймере T0.
j7 | Сложение ячеек 33h …70h внутренней памяти данных с константой, равной 2 | Вывод символа «3» при подключении к микроконтроллеру светодиодного индикатора АЛС314Б.
j8 | Генерация меандра на выводе P1.4 с частотой 20 кГц (период 50 мкс) | Переход к выполению подпрограммы при срабатывании концевого датчика (замыкание ключа S)
j9 | Пересылка данных из внутреннего во внешнее ОЗУ ОЭВМ с теми же адресами | Вызов подпрограммы CNT с приходом 56-го импульса на входе Т0 микроконтроллера
j0 | Подключение 8-кнопочной клавиатуры к микроконтроллеру (схема, программа) | Обнуление всех ячеек внешней памяти данных

При выполнении контрольной работы необходимо отладить разработанные программы на языке программирования ASM-51, который можно скачать здесь или на языках программирования C51, ASM-51, входящих в среду программирования keil-c, демонстрационную версию которой можно скачать с www.keil.com или здесь.


микропроцессоры в аудиовизуальной аппаратуре

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Микропроцессоры и цифровая обработка сигналов

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

В процессе изучения предмета рассматривается устройство и принцип действия аналого-цифровых, цифро-аналоговых, а также сигнальных процессоров.

Сигнальные процессоры изучаются на примере микросхем семейства TMS320LC54x. В процессе изучения сигнальных процессоров приобретаются навыки составления принципиальных схем и написания программ. Изучаются языки программирования низкого (ассемблер) и высокого уровня (СИ), предназначенные для написания программ для сигнальных процессоров.

Основные определения курса: АЦП, ЦАП, микропроцессор, сигнальный процессор, программные и аппаратные средства систем цифровой обработки данных, многопроцессорные системы, структурно- модульное программирование, отладка программного обеспечения.

Курс микропроцессоры и цифровая обработка сигналов для заочной формы обучения в большей степени ориентирован на самостоятельную работу студентов и разбит на три этапа:

    1. Установочные лекции (10ч)
    2. Контрольная работа
    3. Основные лекции (2ч) и лабораторные работы (8ч)

Для желающих читается курс цифровая обработка сигналов

Курс цифровая обработка сигналов предполагает углублённое изучение вопросов цифровой обработки сигналов. Рассматриваются особенности выбора частоты преобразования и обработки сигналов, особенности подключения АЦП к сигнальным процессорам, особенности построения аналоговых формирующих фильтров, принципы реализации элементов цифровой обработки сигналов на микроконтроллерах.

Занятия начинаются по мере формирования групп. Количество человек в группе - 12 человек. Для записи обращаться: Главный корпус СибГУТИ каф. САПР к 302 (3 этаж) тел. для справок: 66-02-86.

    1. Содержание дисциплины
    2. Перечень литературы


Квантование аналогового сигнала по времени

 Rambler's Top100 Дата последнего обновления файла 30.09.04

СТАТИЧЕСКАЯ ПЕРЕДАТОЧНАЯ ФУНКЦИЯ АЦП И ЦАП И ПОГРЕШНОСТИ ПО ПОСТОЯННОМУ ТОКУ

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

Разрешающая способность АЦП или ЦАП может быть выражена несколькими различными способами: весом младшего разряда (LSB), долей от полной шкалы размером в один миллион (ppm FS), милливольтами (мВ) и т.д. Различные устройства (даже от одного производителя) определяются по-разному, так что для успешного сравнения устройств пользователи АЦП и ЦАП должны уметь преобразовывать различные характеристики. Некоторые значения младшего значащего разряда (LSB) приведены в таблице 1.

Таблица 1. Квантование: значение младшего значащего бита(LSB)

Разреш. способность N | 2N | Напряжение полной шкалы 10В | ppm FS | % FS | dB FS
2-бит | 4 | 2.5 В | 250000 | 25 | -12
4-бит | 16 | 625 мВ | 62500 | 6.25 | -24
6-бит | 64 | 156 мВ | 15625 | 1.56 | -36
8-бит | 256 | 39.1 мВ | 3906 | 0.39 | -48
10-бит | 1024 | 9.77 мВ (10 мВ) | 977 | 0.098 | -60
12-бит | 4096 | 2.44 мВ | 244 | 0.024 | -72
14-бит | 16384 | 610 мкВ | 61 | 0.0061 | -84
16-бит | 65536 | 153 мкВ | 15 | 0.0015 | -96
18-бит | 262144 | 38 мкВ | 4 | 0.0004 | -108
20-бит | 1048576 | 9.54 мкВ (10 мкВ) | 1 | 0.0001 | -120
22-бит | 4194304 | 2.38 мкВ | 0.24 | 0.000024 | -132
24-бит | 16777216 | 596 нВ* | 0.06 | 0.000006 | -144

*600 нВ - это тепловой шум в полосе частот 10кГц, возникающий на резисторе R=2.2 кОм при 25°C

Легко запомнить: 10-разрядное квантование при значении полной шкалы FS = 10В соответствует LSB = 10 мВ, точность 1000 ppm или 0.1%. Все остальные значения можно вычислить умножением на коэффициенты, равные степени числа 2.

Прежде чем рассматривать различные архитектуры АЦП и ЦАП, необходимо обсудить ожидаемые характеристики и важнейшие параметры цифро-аналоговых и аналого-цифровых преобразователей. Ниже будет рассмотрено определение погрешностей и технических требований, предъявляемых к АЦП и ЦАП. Это важно для понимания сильных и слабых сторон различных архитектур АЦП и ЦАП.

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

На рисунке 1 представлена идеальная функция передачи однополярного 3-разрядного ЦАП, а на рисунке 2 - однополярного 3-разрядного АЦП. В ЦАП входной и выходной сигналы квантованы, и график содержит восемь точек. Независимо от способа аппроксимации этой функции, важно помнить, что реальной характеристикой передачи является не линия, а множество дискретных точек.

Рисунок 1. ПЕРЕДАТОЧНАЯ ФУНКЦИЯ ИДЕАЛЬНОГО 3-РАЗРЯДНОГО ЦАП

Рисунок 2. ПЕРЕДАТОЧНАЯ ФУНКЦИЯ ИДЕАЛЬНОГО 3-РАЗРЯДНОГО АЦП

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

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

В АЦП и ЦАП используются много видов цифровых кодов: двоичные коды, двоичные коды со смещением, коды с дополнением до 1, с дополнением до 2, код Грея, двоично-десятичный код и другие. Здесь нас будут интересовать главным образом проблемы, связанные с аналоговым трактом АЦП и ЦАП. Для иллюстрации этих проблем будет использоваться простой двоичный код или двоичный код со смещением без рассмотрения преимуществ и недостатков этих и любых других способов цифрового кодирования.

В примерах на рисунках 1 и 2 применяются униполярные преобразователи, работающие с сигналом только одной полярности. Это самый простой тип, но в реальных устройствах более полезны биполярные преобразователи. Имеется два типа биполярных преобразователей. Более простой из них - это просто униполярный преобразователь с отрицательным смещением на величину, соответствующую единице старшего разряда (MSB), (во многих преобразователях можно переключать это смещение, чтобы использовать их и как униполярные, и как биполярные). Другой, более сложный тип, известен как знаковый АЦП (sign- magnitude) и имеет кроме N информационных разрядов дополнительный разряд, который показывает знак аналогового сигнала. Знаковые ЦАП применяется довольно редко, на знаковых АЦП сконструированы большинство цифровых вольтметров (DVM).

В АЦП и ЦАП различают четыре типа погрешностей по постоянному току: погрешность смещения, погрешность усиления и два типа погрешностей, связанных с линейностью. Погрешности смещения и усиления АЦП и ЦАП аналогичны погрешностям смещения и усиления в усилителях. На рисунке 3 показано преобразование биполярных входных сигналов (хотя погрешность смещения и погрешность нуля, идентичные в усилителях и униполярных АЦП и ЦАП, различны в биполярных преобразователях, и это следует учитывать). Характеристики передачи и ЦАП, и АЦП могут быть выражены как D=K+GA, где D - цифровой код, А - аналоговый сигнал, K и G - константы. В униполярном преобразователе K равно 0, в биполярном преобразователе со смещением - 1 старшего значащего разряда. Погрешность смещения - это величина, на которую фактическое значение K отличается от идеального значения. Погрешность усиления - это величина, на которую G отличается от идеального значения. В общем случае, погрешность усиления может быть выражена разностью двух коэффициентов, выраженной в процентах. Эту разность можно рассматривать, как вклад погрешности усиления (в мВ или значениях младшего разряда LSB) в общую погрешность при максимальном значении сигнала. Обычно пользователю предоставляется возможность минимизации этих погрешностей. Обратите внимание, что, в усилителе сначала регулируют смещение при нулевом входном сигнале, а затем настраивают коэффициент усиления при значении входного сигнала, близком к максимальному. Алгоритм настройки биполярных преобразователей более сложен.

Рисунок 3. ПОГРЕШНОСТЬ СМЕЩЕНИЯ НУЛЯ ПРЕОБРАЗОВАТЕЛЯ И ПОГРЕШНОСТЬ УСИЛЕНИЯ

Интегральная нелинейность ЦАП и АЦП аналогична нелинейности усилителя и определяется как максимальное отклонение фактической характеристики передачи преобразователя от прямой линии. В общем случае, она выражается в процентах от полной шкалы (но может представляться в значениях младших разрядов). Существует два общих метода аппроксимации характеристики передачи: метод конечных точек (end point) и метод наилучшей прямой (best straight line) (см. рисунок 4).

Рисунок 4. МЕТОД ИЗМЕРЕНИЯ СУММАРНОЙ ПОГРЕШНОСТИ ЛИНЕЙНОСТИ

При использовании метода конечных точек измеряется отклонение произвольной точки характеристики (после коррекции усиления) от прямой, проведенной из начала координат. Таким образом в компании Analog Devices, Inc. измеряют значения интегральной нелинейности преобразователей, используемых в задачах измерения и управления (так как величина погрешности зависит от отклонения от идеальной характеристики, а не от произвольного "наилучшего приближения").

Метод наилучшей прямой дает более адекватный прогноз искажений в приложениях, имеющих дело с сигналами переменного тока. Он менее чувствителен к нелинейностям технических характеристик. По методу наилучшего приближения через характеристику передачи устройства проводят прямую линию, используя стандартные методы интерполяции кривой. После этого максимальное отклонение измеряется от построенной прямой. Как правило, интегральная нелинейность, измеренная таким образом, учитывает только 50% нелинейности, оцененной методом конечных точек. Это делает метод предпочтительным при указании впечатляющих технических характеристик в спецификации, но менее полезным для анализа реальных значений погрешностей. Для приложений, имеющих дело с сигналами переменного тока, лучше определять гармонические искажения, чем нелинейность по постоянному току, так что для определения нелинейности преобразователя необходимость в использовании метода наилучшей прямой возникает довольно редко.

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

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

Если дифференциальная нелинейность ЦАП меньше, чем –1 LSB на любом переходе (см. рис.2.12), ЦАП называют немонотонным, и его характеристика передачи содержит один или несколько локальных максимумов или минимумов. Дифференциальная нелинейность, большая чем +1 LSB, не вызывает нарушения монотонности, но также нежелательна. Во многих приложениях ЦАП (особенно в системах с обратной связью, где немонотонность может изменить отрицательную обратную связь на положительную) монотонность ЦАП очень важна. Часто монотонность ЦАП явно оговаривается в техническом описании, хотя, если дифференциальная нелинейность гарантированно меньше единицы младшего разряда (то есть, |DNL| . 1LSB), устройство будет обладать монотонностью, даже если это явно не указывается.

Бывает, что АЦП немонотонен, но наиболее распространенным проявлением DNL в АЦП являются пропущенные коды. (см. рис.2.13). Пропущенные коды (или немонотонность) в АЦП столь же нежелательны, как немонотонность в ЦАП. Опять таки, это возникает при DNL > 1 LSB.

Рис. 2.12 Функция передачи неидеального 3-разрядного ЦАП

Рис. 2.13 Функция передачи неидеального 3-разрядного ЦАП

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

Рис. 2.14 Совместное действие шумов перехода кода и дифференциальной нелинейности (DNL)

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

ПОГРЕШНОСТИ ПО ПЕРЕМЕННОМУ ТОКУ В ПРЕОБРАЗОВАТЕЛЯХ ДАННЫХ

В течение последнего десятилетия основное применение АЦП и ЦАП находят в дискретизации и восстановлении аналоговых сигналов переменного тока. Очень упрощенно, дискретная система – это система, где мгновенное значение сигнала переменного тока оцифровывается с одинаковыми интервалами. Полученные цифровые коды могут использоваться для сохранения формы сигнала (на компакт-дисках CD или цифровых магнитных лентах DAT), для сложных вычислений с отсчетами (цифровая обработка сигнала DSP), для фильтрации, компрессии и других операций. Обратная операция – восстановление – требуется, когда ряд цифровых кодов подается на ЦАП для восстановления формы аналогового сигнала. Здесь ярким примером является CD- или DAT-плеер, но эта технология очень широко используется также в телекоммуникации, радио, синтезаторах и во многих других областях.

Преобразователи данных, используемые в таких устройствах, должны иметь высокую производительность при работе с сигналами переменного тока, но могут не требовать хороших характеристик по постоянному току.

Первые высококачественные преобразователи, разработанные для таких устройств, обычно создавались с хорошими характеристиками по переменному току, но плохими или ненормированными характеристиками по постоянному току. Сегодня существуют более приемлемые проектные компромиссы, и большинство преобразователей имеют гарантированные характеристики по постоянному и переменному току. Тем не менее, ЦАП для цифровой звукозаписи, которые должны быть чрезвычайно конкурентоспособны по цене, продаются со сравнительно низкими характеристиками по постоянному току, но не из-за низкой производительности по постоянному току, а из-за отсутствия проверки качества в ходе производства.

Если обсуждение параметров по постоянному току можно производить одновременно и для ЦАП, и для АЦП, то их характеристики по переменному току слишком различаются и потому заслуживают раздельного рассмотрения.

Искажения и шум в идеальном N-разрядном АЦП

До сих пор мы анализировали процесс дискретизации без рассмотрения такой операции АЦП, как квантование. Теперь будем трактовать АЦП как идеальный дискретизатор, но учитывать при этом эффекты квантования.

Идеальный N-разрядный АЦП имеет погрешности (по постоянному или переменному току), связанные только с процессами дискретизации и квантования. Максимальная погрешность, которую имеет идеальный АЦП при оцифровывании входного сигнала, равна ±1/2 LSB. Любой аналоговый сигнал, поступающий на вход идеального N- разрядного АЦП, производит шум квантования. Среднеквадратичное значение шума (измеренное по ширине полосы Найквиста, от постоянного тока до fs/2) приблизительно равно весу наименьшего значащего разряда (LSB) q, деленному на v12. (см. Приложение 2). При этом предполагается, что амплитуда сигнала составляет, по крайней мере, несколько младших разрядов, так что выход АЦП изменяет свое состояние почти при каждом отсчете. Сигнал ошибки квантования от входного линейного пилообразного сигнала аппроксимируется сигналом пилообразной формы с максимальным размахом q, и его среднеквадратичное значение равно q/v12 (см. рис.2.15).

Можно показать, что отношение среднеквадратичного значения синусоидального сигнала, соответствующего полной шкале, к среднеквадратичному значению шума квантования (выраженное в дБ) равно:

,

где N - число разрядов в идеальном АЦП. Это уравнение имеет силу только в том случае, если шум измерен на полной ширине полосы Найквиста от 0 до fs /2, как показано на рис.2.16. Если ширина полосы сигнала BW меньше fs /2, то значение отношения сигнал/шум (SNR) в пределах ширины полосы сигнала BW возрастет вследствие уменьшения энергии шума квантования в пределах ширины полосы. Для этого условия правильным будет следующее выражение:

.

Рис. 2.15 Шум квантования идеального N-разрядного АЦП

Рис. 2.16 Спектр шума квантования

Приведенное уравнение отражает состояние, именуемое избыточной дискретизацией, при котором частота дискретизации выше, удвоенной ширины полосы сигнала. Корректирующую величину часто называют запасом по дискретизации. Обратите внимание, что для заданной ширины полосы сигнала удвоение частоты дискретизации увеличивает отношение сигнал/шум на 3 дБ.

Хотя среднеквадратичное значение шума точно описывается формулой [image], его частотное распределение может сильно зависеть от входного аналогового сигнала. Например, корреляция будет больше для периодического сигнала малой амплитуды, чем для случайного сигнала большой амплитуды. Весьма часто в теории полагают, что шум квантования проявляется в виде белого шума, распределенного равномерно по всей ширине полосы Найквиста от 0 до fд /2. К сожалению, это не так. В случае сильной корреляции шум квантования будет сконцентрирован около каких угодно гармоник входного сигнала, но только не там, где бы Вы хотели.

В большинстве устройств входной сигнал АЦП (он обычно смешан с некоторым шумом) представляет собой полосу частот со случайным шумом квантования. Тем не менее, в устройствах спектрального анализа (или при выполнении БПФ на АЦП, использующих спектрально чистый синусоидальный сигнал, см. рис.2.17) корреляция между шумом квантования и сигналом зависит от отношения частоты дискретизации к частоте входного сигнала. Это демонстрируется на рис.2.18, где идеальный выход 12-разрядного АЦП представлен с использованием БПФ с 4096 точками. На левом графике отношение частоты дискретизации к входной частоте было выбрано равным точно 32, и худшая гармоника составляет 76 дБ от основной частоты. Правый график показывает эффект некоторого смещенного отношения, приводящего к относительному разбросу спектра случайного шума, благодаря которому динамический диапазон, свободный от гармоник (SFDR), достигает 92 дБ. В обоих случаях среднеквадратичное значение всех шумовых компонентов равно q/v12, но в первом случае шум сконцентрирован около гармоник основной частоты.

Рис. 2.17 Анализ динамических характеристик идеального N-разрядного АЦП

Рис. 2.18 Влияние отношения частоты дискретизации к входной частоте на динамический диапазон (SFDR) для идеального АЦП

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

Отмеченное очень важно, потому что для определения характеристик АЦП часто используется быстрое преобразование Фурье (БПФ) для монотонного синусоидального сигнала. Для точного измерения нелинейных искажений АЦП должны быть предприняты шаги, гарантирующие, что испытательная установка верно измеряет искажения, идущие от АЦП, с учетом эффекта корреляции шума квантования. Это достигается соответствующим выбором соотношения испытательных частот и частот дискретизации, а иногда – добавлением к входному сигналу некоторого шума (псевдослучайного сигнала).

Вернувшись к рис.2.18, обратите внимание, что минимальный уровень шума, полученного с помощью БПФ, приблизительно равен 100 дБ от полной шкалы АЦП, тогда как т еоретическое отношение сигнал/шум 12-разрядного АЦП равно 74 дБ. Минимальный уровень шума от БПФ не равен отношению сигнал/шум АЦП, потому что БПФ действует, подобно аналоговому анализатору спектра с шириной полосы fs /M, где М – число точек БПФ. Теоретически минимальный уровень шума БПФ равен 10 log10 (M/2) дБ, то есть ниже минимального уровня шума квантования из-за так называемого выигрыша БПФ в отношении сигнал/шум (см. рис.2.19). В случае идеального 12-разрядного АЦП с отношением сигнал/шум 74 дБ, использование БПФ с 4096 точками привело бы к выигрышу в отношении сигнал/шум в 10 log10 (4096/2) = 33 дБ, приводя, таким образом, к предельному отношению сигнал/шум 74+33=107 дБ. В действительности, минимальный уровень шума БПФ может быть еще уменьшен за счет увеличения количества точек БПФ, подобно тому, как минимальный уровень шума аналогового анализатора спектра может быть уменьшен за счет сужения ширины полосы пропускания. При испытаниях АЦП, использующих БПФ, важно быть уверенным, что количество точек БПФ достаточно велико для того, чтобы нелинейные искажения можно было отличить от минимального уровня ума БПФ.

Рис. 2.19 Уровень шума идеального 12-разрядного АЦП при 4096-точечном БПФ

Искажение и шум в реальных АЦП

На практике дискретизация сигнала в АЦП (с интегрированным устройством выборки- хранения УВХ), независимо от архитектуры, проходит при наличии шумов и искажений сигнала, как это показано на рис.2.20. Широкополосному аналоговому входному буферу присущи широкополосный шум, нелинейность и конечная ширина полосы. УВХ (SHA) вносит дальнейшую нелинейность, ограничение полосы и дрожание апертуры. Квантующая часть АЦП вносит шум квантования, интегральную и дифференциальную нелинейности. В этом обсуждении предполагается, что сигналы с последовательных выходов АЦП загружаются в буферную память длиной М и что БПФ процессор имеет спектральный выход. Также допускается, что арифметические операции БПФ не вносят никаких существенных погрешностей в АЦП. Однако при проверке минимального выходного уровня шума должен быть рассмотрен выигрыш в отношении сигнал/шум БПФ (зависящий от M).

МОДЕЛЬ АЦП, ПОКАЗЫВАЮЩАЯ ИСТОЧНИКИ

ШУМОВ И ИСКАЖЕНИЙ СИГНАЛА

Рис. 2.20

Приведенный ко входу тепловой шум

Широкополосные внутренние цепи АЦП вносят некоторое среднеквадратичное значение широкополосного шума из-за воздействия тепла и дисперсии шума kT/C. Этот шум присутствует даже для сигналов постоянного тока и объясняет тот факт, что результатом работы большинства широкополосных (с высокой разрешающей способностью) АЦП является распределение кодов, сконцентрированное вокруг номинального значения входного сигнала (см. рис.2.21). Чтобы измерить его значение, вход АЦП заземляется, накапливается большое количество выходных отсчетов и составляется график в виде гистограммы (иногда упоминаемый как гистограмма с заземленным входом). Так как шум имеет почти Гауссово распределение, стандартное отклонение гистограммы легко рассчитывается (см. Приложение 3) в соответствии с эффективным среднеквадратичным значением входного шума. Обычной практикой для выражения среднеквадратичного значения шума является его выражение в терминах младших разрядов, хотя оно может быть выражено как среднеквадратичное значение напряжения.

Существуют различные способы описания характеристик аналогового тракта АЦП. На ранней стадии технологии АЦП (более 30 лет назад) не существовало серьезной стандартизации характеристик аналогового тракта, измерительного оборудования и методов или они не были хорошо изучены либо были недоступны. Спустя почти 30 лет производители и заказчики узнали больше об измерении динамических характеристик преобразователей. Спецификации наиболее популярных сегодня преобразователей представлены на рис.2.22. Фактически все спецификации представляют характеристики преобразователя в частотной области. БПФ является основой практически всех измерений и подробно обсуждается в разделе 5 этой книги.

ГИСТОГРАММА, ПОКАЗЫВАЮЩАЯ РАСПРЕДЕЛЕНИЕ

ВЕРОЯТНОСТИ ВЫХОДНОГО КОДА

ПРИ ДЕЙСТВИИ ШУМА НА ВХОД АЦП

Рис. 2.21

  • Гармонические искажения

  • Наихудшие гармоники

  • Общие гармонические искажения (THD)

  • Общие гармонические искажения и шум (THD + N)

  • Отношение сигнал-шум и искажения (SINAD, or S/N +D)

  • Эффективное количество разрядов (ENOB)

  • Отношение сигнал-шум (SNR)

  • Аналоговая полоса пропускания (для полного сигнала, для малого сигнала)

  • Динамический диапазон, свободный от гармоник (SFDR)

  • Двухтональные интермодуляционные искажения

  • Многотональные интермодуляционные искажения

ОПРЕДЕЛЯЮЩИЕ ДИНАМИЧЕСКИЕ ХАРАКТЕРИСТИКИ

АЦП

Рис. 2.22

Явления интегральных и дифференциальных нелинейных искажений

Одним из важнейших для понимания аспектов при определении нелинейности АЦП и ЦАП является то, что передаточная функция преобразователя данных имеет особенности, которые отсутствуют в обычных линейных устройствах типа операционных усилителей (ОУ) или усилительных блоков. Полная интегральная нелинейность АЦП обусловлена интегральной нелинейностью входного буфера, УВХ (SHA) и полной интегральной нелинейностью передаточной функции АЦП. Но дифференциальная нелинейность, которая присутствует исключительно вследствие цифрового кодирования, может значительно изменяться в зависимости от принципов применяемого цифрового кодирования АЦП. Полная интегральная нелинейность дает составляющие искажений, у которых амплитуда изменяется в зависимости от амплитуды входного сигнала. В частности, интермодуляционные составляющие второго порядка увеличиваются на 2 дБ при увеличении сигала на 1 дБ, а составляющие третьего порядка увеличиваются на 3 дБ при повышении уровня сигнала на 1 дБ.

Дифференциальная нелинейность в передаточной функции АЦП порождает гармоники, которые зависят не только от амплитуды сигнала, но и от положения точки дифференциальной нелинейности на передаточной функции АЦП. На рис.2.23 показаны две передаточные функции АЦП, имеющих различную дифференциальную нелинейность. Левая диаграмма показывает погрешность, которая имеет место при наличии нелинейности в середине шкалы. Поэтому сигнал, проходящий через эту точку, и при "больших", и при "малых" сигналах подвергается искажениям, не зависящим от относительной амплитуды сигнала. Правая диаграмма показывает другую передаточную функцию АЦП, которая имеет погрешности дифференциальной нелинейности в точках, соответствующих 1/4 и 3/4 полной шкалы. Сигналы, превышающие 1/2 шкалы АЦП, подвергнутся действию этих искажений, в то время как сигналы, не превышающие 1/2 шкалы размаха, не имеют искажений.

ТИПИЧНЫЙ ВИД ДИФФЕРЕНЦИАЛЬНОЙ

НЕЛИНЕЙНОСТИ (DNL) АЦП/ЦАП

Рис. 2.23

Большинство быстродействующих АЦП разработаны так, чтобы дифференциальная нелинейность равномерно распределялась по всей ширине динамического диапазона АЦП. Поэтому для сигналов, которые находятся в пределах нескольких дБ полной шкалы АЦП, полная интегральная нелинейность передаточной функции определяет гармонические искажения. Для сигналов более низких уровней содержание гармоник определяется дифференциальной нелинейностью и в общем случае не уменьшается с уменьшением амплитуды сигнала.

Нелинейные искажения, наихудшая гармоника, общие нелинейные искажения (THD), общие нелинейные искажения плюс шум (THD + N)

Существует множество способов количественного описания искажений в АЦП. Анализ БПФ может использоваться для измерения амплитуды различных гармоник сигнала. Гармоники входного сигнала могут отличаться от других составляющих искажений их положением в частотном спектре. На рис.2.24 показан 7 МГц входной сигнал, дискретизированный с частотой 20 MSPS, и положение его первых девяти гармоник. Гармоники частоты fa попадают на частоты, равные |±Kfs±nfa|, где n – порядок гармоники и K = 0, 1, 2, 3, .... В общем, только вторая и третья гармоники точно определены в технической документации, потому что они, как правило, наибольшие, хотя в некоторых случаях могут определять значение наихудшей гармоники (worst harmonic). Нелинейные искажения обычно определяются в дБс (децибелы ниже несущей), хотя на звуковых частотах они могут быть определены в процентах. Нелинейные искажения, как правило, определяются при входным сигнале с размахом, близким к полной шкале преобразователя (от 0,5 до 1 дБ ниже полной шкалы для предотвращения амплитудного ограничения), хотя возможно определение их и на любом другом уровне. Для сигналов с размахом, существенно меньшим полной шкалы, из-за дифференциальной нелинейности преобразователя другие составляющие (не прямые гармоники) могут ухудшать характеристики прибора.

РАСПОЛОЖЕНИЕ СОСТАВЛЯЮЩИХ ГАРМОНИЧЕСКИХ

ИСКАЖЕНИЙ: ВХОДНОЙ СИГНАЛ = 7 МГЦ,

СКОРОСТЬ (ЧАСТОТА) ДИСКРЕТИЗАЦИИ = 20 MSPS

Рис. 2.24

Величина полных нелинейных искажений (THD) определяется как отношение среднеквадратичного значения основной частоты сигнала к среднему значению корня из суммы квадратов (root-sum-square) его гармоник (существенны только первые пять). Полные нелинейные искажения АЦП также определяются входным сигналом величиной, близкой к полной шкале АЦП, но могут быть найдены и на любом ином уровне. Полные нелинейные искажения плюс шум (THD + N) являются отношением среднеквадратичного значения основной частоты сигнала к среднему значению корня из суммы квадратов (root-sum-square) его гармоник и всех шумовых компонент (исключая постоянную составляющую). Ширина полосы, в которой измеряется шум, должна быть задана. В случае БПФ ширина полосы занимает промежуток от 0 до fs/2 (если ширина полосы измерения от 0 до fs/2, THD+N = SINAD – см. ниже).

Показатель сигнал/шум/искажения (SINAD), показатель сигнал/шум (SNR) и эффективное число разрядов (ENOB)

Показатель сигнал/шум/искажения (SINAD) и показатель сигнал/шум (SNR) заслуживают особого внимания, потому что все еще имеются некоторые разногласия между производителями АЦП относительно их точного определения. Сигнал/шум/искажения (SINAD, или S/N+D) – это отношение среднеквадратичного значения амплитуды сигнала к среднему значению корня из суммы квадратов (RSS) всех других спектральных компонентов, включая гармоники, но исключая постоянную составляющую. SINAD является хорошим индикатором общих динамических характеристик АЦП, таких как функция входной частоты, потому что включает все компоненты, которые создают шум (включая тепловой шум) и искажения. Он часто представляется в виде графика для различных амплитуд входного сигнала. Если ширина полосы сигнала и шума одинаковы, то SINAD = THD+N. Типичный график для 12-разрядного АЦП AD9220 с частотой дискретизации 10 MSPS представлен на рис.2.26.

ОТНОШЕНИЕ СИГНАЛ/(ШУМ И ИСКАЖЕНИЯ) (SINAD),

ЭФФЕКТИВНАЯ РАЗРЯДНОСТЬ (ENOB),

ОТНОШЕНИЕ СИГНАЛ/ШУМ (SNR)

Рис. 2.25

  • SINAD (Отношение сигнала к шуму и искажениям):

  • Отношение среднеквадратичного значения амплитуды сигнала

  • к среднему значению корня из суммы квадратов (RSS) всех

  • остальных составляющих спектра, включая гармоники, но

  • исключая постоянную составляющую.

    •

  • ENOB (Эффективная разрядность):

  • ENOB =

    •

  • SNR (Отношение сигнал/шум или отношение сигнал/шум без

  • гармоник):

    •

  • Отношение среднеквадратичного значения амплитуды сигнала

  • к среднему значению корня из суммы квадратов (RSS) всех

  • остальных составляющих спектра, исключая первые пять

  • гармоник и постоянную составляющую

  • SINAD – 1.76 дБ

  • 6.02 дБ

ОТНОШЕНИЕ СИГНАЛ/(ШУМ И ИСКАЖЕНИЯ) (SINAD) И ЭФФЕКТИВНОЕ ЧИСЛО РАЗРЯДОВ (ENOB) ПРИ РАЗЛИЧНЫХ УРОВНЯХ ВХОДНОГО СИГНАЛА 12-РАЗРЯДНОГО, 10 MSPS АЦП AD9220

ЧАСТОТА АНАЛОГОВОГО СИГНАЛА НА ВХОДЕ (МГц)

Рис. 2.26

График SINAD показывает, где характеристики АЦП по переменному току ухудшаются из-за искажений на высоких частотах, причем обычно этот график строится для частот, значительно превышающих частоту Найквиста для оценки характеристик в приложениях, использующих субдискретизацию. SINAD часто преобразуется в эффективное число разрядов (ENOB), используя выражение для теоретического отношения сигнал/шум идеального N-разрядного АЦП: SNR = 6,02N + 1,76dB. Уравнение решается для N, и значение отношения сигнал/шум заменяется на SINAD:

Отношение сигнал/шум (SNR или SNR без гармоник) рассчитывается так же, как и SINAD, за исключением того, что из выражения исключаются гармоники сигнала и оставлены только шумовые составляющие. Практически, необходимо исключить только первые пять доминирующих гармоник. Показатель сигнал/шум будет ухудшаться на высоких частотах, но не так быстро как SINAD, так как из него исключены компоненты гармоник.

Во многих описаниях АЦП довольно свободно принимается, что SINAD равно SNR, так что инженер должен быть внимательным при интерпретации этих характеристик.

Аналоговая ширина полосы

Аналоговая ширина полосы АЦП – это та частота, на которой спектральный выход основной смещенной частоты (как было определено при анализе БПФ) уменьшается на 3 дБ. Она может быть определено как для малого сигнала (полоса пропускания малого сигнала SSBW), так и для сигнала на уровне полной шкалы (полоса пропускания максимального сигнала FPBW). Поэтому между производителями могут встречаться большие различия в характеристиках.

Как и для усилителя, спецификация аналоговой полосы пропускания преобразователя не предполагает, что АЦП поддерживает хорошие характеристики гармонических искажений во всей полосе частот. В действительности, SINAD (или ENOB) большинства АЦП начинает ухудшаться значительно раньше, чем частота входного сигнала приблизится к значению, соответствующему ослаблению на 3 дБ. На рис.2.27 представлены эффективное число разрядов (ENOB) и частотная характеристика входного сигнала, соответствующего полной шкале АЦП с FPBW 1 МГц, но ENOB начинает быстро понижаться на частотах, превышающих 100 кГц.

ЗАВИСИМОСТЬ УСИЛЕНИЯ (ПОЛОСА ПРОПУСКАНИЯ) АЦП И ЭФФЕКТИВНОЙ РАЗРЯДНОСТИ (ENOB) ОТ ЧАСТОТЫ СИГНАЛА ПОКАЗАНЫ ВАЖНЫЕ ПАРАМЕТРЫ СПЕЦИФИКАЦИИ ENOB

Рис. 2.27

Динамический диапазон, свободный от гармоник(SFDR)

Вероятно, наиболее значительным моментом для АЦП, используемых в коммуникационных приложениях, является их динамический диапазон, свободный от гармоник (SFDR). Спецификация SFDR для АЦП аналогична спецификации точки пересечения уравнений третьего порядка для смесителей и малошумящих усилителей (LNA). SFDR АЦП определяется как отношение среднеквадратичного значения амплитуды сигнала к среднеквадратичному значению пикового побочного спектрального состава, измеренного в первой зоне Найквиста от 0 до fs/2. На графике SFDR строится как функция амплитуды сигнала и может быть выражен относительно амплитуды сигнала (дБс) или полной шкалы АЦП (dBFS), как показано на рис.2.28.

СВОБОДНЫЙ ОТ ГАРМОНИК ДИНАМИЧЕСКИЙ

ДИАПАЗОН (SFDR)

Рис. 2.28

Для сигнала, имеющего амплитуду, близкую к полной шкале АЦП, пиковая спектральная линия определяется несколькими первыми гармониками основной частоты. Но когда сигнал опускается на несколько дБ ниже полной шкалы, появляются другие спектральные линии, которые не являются прямыми гармониками входного сигнала. Это, как обсуждалось ранее, происходит из-за дифференциальной нелинейности передаточной функции АЦП. Поэтому, SFDR учитывает все источники искажения, независимо от их происхождения.

Широкополосный 12-разрядный АЦП AD9042 с частотой дискретизации 41 MSPS, является АЦП, разработанным для коммуникационных приложений, где SFDR очень важен. На рис.2.29 представлены характеристики SFDR для входного сигнала 19,5 МГц, дискретизированного с частотой 41 MSPS. Обратите внимание, что минимум SFDR в 80 дБс получен во всей первой зоне Найквиста (от 0 до 20 МГц). На графике также показано значение SFDR, выраженное как dBFS.

В общем случае SFDR существенно больше, чем теоретическое значение отношения сигнал/шум N-разрядного АЦП (6,02N + 1,76 дБ). Например, 12-разрядный АЦП AD9042 с SFDR 80 дБс имеет типичное отношение сигнал/шум 65 дБс (теоретическое 74 дБ). Это объясняется тем, что есть существенное различие между измерениями искажений и шума. Выигрыш в отношении сигнал/шум БПФ (33 дБ для БПФ с 4096 точками) допускает существование частотных линий значительно ниже наблюдаемого минимального уровня шума. Увеличение разрешающей способности АЦП может увеличивать отношение сигнал/шум АЦП, но не обязательно улучшает его SFDR.

ЗАВИСИМОСТЬ SFDR ОТ ВХОДНОЙ МОЩНОСТИ ДЛЯ 12-РАЗРЯДНОГО 41 MSPS АЦП AD9042

Рис. 2.29

Двухтональные интермодуляционные искажения (IMD)

Двухтональные интермодуляционные искажения (IMD) измеряют, подавая на АЦП два спектрально чистых синусоидальных сигнала с частотами f1 и f2, обычно довольно близкими друг к другу. Амплитуда каждой компоненты устанавливается на 6 дБ ниже полной шкалы для того, чтобы АЦП не входил в ограничение при совпадении сигналов по фазе. На рис.2.30 показано местоположение составляющих второго и третьего порядка. Обратите внимание, что составляющие второго порядка приходятся на те частоты, которые могут быть удалены цифровыми фильтрами. Но составляющие третьего порядка 2f2–f1 и 2f1–f2 располагаются близко к исходным сигналам и их более трудно фильтровать. Если не определено иное, двухтональные интермодуляционные искажения (IMD) относятся к этим составляющим третьего порядка. Значение интермодуляционных искажений выражается в дБс относительно уровня любой из двух первоначальных частот, а не их суммы.

Обратите внимание, что, если частоты имеют значения, близкие к fs/4, то третьи гармоники основных частот могут затруднить идентификацию компонент 2f2–f1 и 2f1–f2. Это происходит потому, что третья гармоника fs/4 равна 3 fs/4 и она, соответственно, порождает компоненту fs – 3 fs/4 = fs/4. Точно также, если две частоты располагаются близко к fs/3, то вторая гармоника может мешать измерениям по той же причине: вторая гармоника fs/3 равна 2 fs/3 и она, соответственно, порождает компоненту fs – 2 fs/3 = fs/3.

СОСТАВЛЯЮЩИЕ 2-ГО И 3-ГО ПОРЯДКА В РЕЗУЛЬТАТЕ ВОЗДЕЙСТВИЯ ДВУХТОНАЛЬНОГО СИГНАЛА f 1 = 5 МГц, f 2 = 6 МГц

Рис. 2.30

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

В коммуникационных приложениях часто измеряется многотональный SFDR. Большим числом тонов более точно моделируется широкополосный частотный спектр систем сотовой телефонии типа AMPS и GSM. На рис.2.31 представлены характеристики 4-тональной интермодуляции 12-разрядного АЦП AD6640 с быстродействием 65 MSPS. Большое значение SFDR увеличивает способность приемника фиксировать слабые сигналы в присутствии сильных и предотвращать маскировку слабых сигналов интермодуляционными помехами сильных.

ТЕСТИРОВАНИЕ МНОГОТОНАЛЬНЫМ СИГНАЛОМ: 12-РАЗРЯДНЫЙ 65 MSPS АЦП AD6640

Рис. 2.31

Уровень собственных шумов (NPR)

П роверка уровня собственных шумов широко применяется для измерения характеристики передачи линии связи, использующей систему с многоканальным доступом с частотным разделением каналов (FDMA) (см. Приложение 4). В типичной FDMA-системе звуковые каналы шириной 4 кГц загружаются в "частотный стек" для передачи через коаксиальный кабель, радиорелейную станцию микроволнового диапазона или спутниковое оборудование. На приемном конце системы FDMA данные демультиплексируются и возвращаются к 4 кГц индивидуальным каналам основной полосы частот. В FDMA системе, имеющей более 100 каналов, сигнал FDMA может быть аппроксимирован Гауссовым шумом с соответствующей шириной полосы. Индивидуальный 4 кГц канал может быть проверен на предмет собственных шумов, используя узкополосный режекторный фильтр и специально настроенный приемник, который измеряет мощность шума внутри 4 кГц полосы подавления (см. рис.2.32).

Измерения уровня собственных шумов (NPR) производятся весьма просто. Среднеквадратичное значение мощности шума сигнала внутри полосы подавления измеряется узкополосным приемником при отключенном режекторном фильтре. Затем подключается режекторный фильтр и измеряется остаточный шум внутри канала. Отношение этих двух значений, выраженное в дБ, является уровнем собственных шумов (NPR). Для соответствующей характеристики системы проверяется несколько интервалов частот в пределах шумовой полосы (в области низких, средних и высоких частот). Измерение уровня собственных шумов в АЦП осуществляется подобным же образом, за исключением использования аналогового приемника, который заменен буферной памятью и процессором БПФ.

ИЗМЕРЕНИЕ УРОВНЯ СОБСТВЕННЫХ ШУМОВ (NPR)

Рис. 2.32

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

В цифровой системе с АЦП шум в пределах интервала является, прежде всего, шумом квантования, если используются низкие уровни входного широкополосного сигнала. В этой части кривая NPR имеет линейную зависимость. По мере того, как уровень широкополосного входного сигнала увеличивается, некоторое время сохраняется линейное соответствие между уровнем входного шума и NPR. Но на некотором уровне шум амплитудного ограничения, вызванный жестким ограничивающим действием АЦП, начинает преобладать. Теоретическая кривая для 10-, 11- и 12-разрядных АЦП представлена на рис.2.33 (см. Приложение 5).

В многоканальных высокочастотных коммуникационных системах NPR может, также, использоваться для моделирования искажений, вызванных большим количеством индивидуальных каналов, подобно тому, как это имеет место в FDMA-системе. При этом режекторный фильтр помещается между источником шума и АЦП, и результат расчета БПФ используется вместо аналогового приемника. Для AD9042 ширина полосы режекторного фильтра устанавливается в несколько мегагерц, как показано на рис.2.34. Здесь уровень собственных шумов (NPR) – это глубина режекции. Идеальный АЦП генерирует только шум квантования внутри полосы режекции, но на практике существуют дополнительные шумовые компоненты из-за интермодуляционных искажений, вызванных нелинейностью АЦП. Обратите внимание, что уровень собственных шумов достигает 60 дБ, тогда как расчетное значение равно 62,7 дБ.

ТЕОРЕТИЧЕСКИЙ УРОВЕНЬ ШУМА (NPR) ДЛЯ 10, 11 И 12-РАЗРЯДНЫХ АЦП

Рис. 2.33

12-РАЗРЯДНЫЙ 41 MSPS АЦП AD9042:

ИЗМЕРЕННЫЙ NPR 60 ДБ

(РАСЧЕТНОЕ ЗНАЧЕНИЕ 62,7ДБ)

Рис. 2.34

Дрожание апертуры и апертурная задержка

Другая причина того, что отношение сигнал/шум (SNR) АЦП уменьшается с увеличением входной частоты, может быть выведена из рис.2.35, который показывает эффекты дрожания фазы в дискретизаторе АЦП (или внутреннем в УВХ). Дрожание фазы вызывает ошибку напряжения, которая является функцией скорости нарастания сигнала и приводит к существенному ухудшению отношения сигнал/шум, как показано на рис.2.36. Это довольно серьезный эффект, особенно на высоких частотах входного сигнала. Поэтому, должна соблюдаться особая осторожность при минимизации фазового шума в дискретизаторах любой системы. Эта осторожность должна распространяться на все компоненты, в которых присутствуют тактовые сигналы: непосредственно генератор (например, таймер серии 555 не отвечает требованиям, но даже кварцевый генератор может создавать проблемы, если он используется в активном устройстве совместно с шумной логикой); тракт передачи (эти тактовые сигналы очень уязвимы к помехам всех видов) и фазовый шум, вводимый в АЦП или ЦАП. Общим источником фазового шума в преобразователе является дрожание апертуры в общей цепи УВХ (SHA).

ВЛИЯНИЕ ДРОЖАНИЯ АПЕРТУРЫ

И ФАЗОВОГО ШУМА ТАКТОВОГО ГЕНЕРАТОРА

Рис. 2.35

Два десятилетия назад схемы дискретизации АЦП создавались отдельно из УВХ (SHA) и АЦП. Проектирование интерфейса было трудным делом, и главная причина этого заключалась в дрожании апертуры в УВХ. Сегодня большинство систем дискретизации использует схемы дискретизации АЦП с интегрированной схемой УВХ. Дрожание апертуры УВХ может быть не определено явным образом в спецификации, но это не служит поводом для беспокойства, если SNR или ENOB ясно определены. Иными словами, гарантия определенного отношения сигнал/шум (SNR) является неявной гарантией определенного адекватного значения дрожания апертуры. А использование дополнительной высококачественной схемы УВХ иногда приводит к улучшению значений эффективного числа разрядов (ENOB) на высоких частотах даже в лучших дискретизирующих АЦП и может оказаться более выгодным, чем замена АЦП на более дорогую модель.

Необходимо отметить, что существует также фиксированный компонент, который присутствует при определении апертуры дискретизации АЦП. Этот компонент, обычно называемый временем эффективной апертурной задержки, не дает ошибки. Его наличие приводит к появлению интервала между временем команды АЦП на дискретизацию и временем, когда получен реальный отсчет (см. рис.2.37). Интервал может быть положительным или отрицательным. Изменение или допуск этого параметра важны в приложениях с одновременной дискретизации с помощью двух АЦП или в других приложениях типа I- и Q-демодуляции, где два АЦП требуют совместной синхронизации.

УХУДШЕНИЕ SNR ИЗ-ЗА ДРОЖАНИЯ ФАЗЫ СИГНАЛА СИНХРОНИЗАЦИИ АЦП

Рис. 2.36

ВРЕМЯ ЭФФЕКТИВНОЙ АПЕРТУРНОЙ ЗАДЕРЖКИ

Рис. 2.37

Д ИНАМИЧЕСКИЕ ХАРАКТЕРИСТИКИ ЦАП

Очевидно, что для цифро-аналогового преобразователя наиболее важными являются такие характеристики сигнала, как время установки (settling time), всплеск сигнала вследствие перерегулирования при изменении сигнала на выходе ЦАП, называемый далее ложным сигналом (выбросом, glitch), искажения и свободный от помех динамический диапазон сигнала (SFDR).

Время установки ЦАП – это время от начала изменения цифрового кода до момента, когда сигнал стабилизируется в пределах некоторого диапазона ошибки, как это показано на рис.2.38. Сравнивать времена установки усилителей трудно, так как их диапазоны ошибки могут отличиться от усилителя к усилителю, но диапазон ошибки ЦАП практически не меняется и равен ±1 или ±½ LSB.

Время установки ЦАП состоит из четырех различных периодов: время переключения (в течение которого цифровое переключение осуществлено, но на выходе нет изменений), переходное время (slewing time) (в течение которого скорость изменения выходного сигнала ограничена скоростью нарастания на выходе ЦАП), время восстановления (recovery time) (когда ЦАП восстанавливает значение после быстрого перехода и может быть выброс на фронте) и линейное время установки (linear settling time) (когда значение на выходе ЦАП приближается к его конечной величине экспоненциально или почти экспоненциально). Если переходное время мало по сравнению с тремя другими (как это обычно бывает в случае с токовыми выходами ЦАП), то время установки не будет существенно зависеть от перепада уровня выходного сигнала. С другой стороны, если переходное время занимает существенную часть общего времени, то время установки будет тем больше, чем больше величина перепада.

ВРЕМЯ УСТАНОВЛЕНИЯ ЦАП

Рис. 2.38

В идеале изменения на выходе ЦАП от одной величины до другой должны проходить монотонно. На практике возможно появление выброса фронта (overshoot), отрицательного выброса перед фронтом (undershoot) или то и другое одновременно (см. рис.2.39). Это неконтролируемое состояние выхода ЦАП в течение перехода известно как ложный сигнал. Он может являться результатом двух явлений: емкостной связи цифровых переходов с аналоговым выходом и свойствами некоторых ключей в ЦАП, работающих более быстро, чем другие, и создающих временные выбросы по уровню.

ПЕРЕХОДНАЯ ХАРАКТЕРИСТИКА ЦАП (С ПАРАЗИТНЫМИ ВЫБРОСАМИ)

Рис. 2.38

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

Для оценки ложных сигналов измеряют площадь, огибаемую фронтом такого сигнала, и иногда неточно называемую энергией ложного сигнала. Употребление термина "энергия ложного сигнала" неправильно, так как площадь под кривой ложного сигнала измеряется вольт-секундами (Volt-seconds) (или более вероятно µV- секунды или pV- секунды). Пиковая площадь под кривой ложного сигнала – это площадь под максимальным положительным или отрицательным импульсом ложного сигнала. Площадь импульса ложного сигнала – это область под вольт-секундной кривой, которая может быть рассчитана после аппроксимации формы сигнала треугольниками и вычисления их площади посредством вычитания отрицательной площади из положительной. Величина ложного сигнала, порождаемого переходом между кодами 0111...111 и 1000...000, обычно является самой большой. Ложные сигналы в других точках перехода кода (таких как 1/4 и 3/4 полной шкалы) обычно имеют меньшую величину. На рис.2.40 отмечен ложный сигнал быстрого ЦАП с малым значением такого сигнала в середине его динамического диапазона. Пиковые и импульсные площади ложного сигнала рассчитываются с использованием треугольников, как это было описано выше. Время установки измеряется с момента, когда сигнал покидает начальный диапазон ошибки в 1 LSB, и до момента, когда он входит и остается в пределах конечного диапазона ошибки в 1 LSB. Размер шага между областями перехода также равен 1 LSB.

ВЫБРОСЫ СИГНАЛА ЦАП:

СУММАРНАЯ ПЛОЩАДЬ ИМПУЛЬСА – 1.34 пВ·с

ВРЕМЯ УСТАНОВЛЕНИЯ – 4.5 нс

Рис. 2.40

Время установки ЦАП важно в таких приложениях, как блок развертки RGB-сигнала в мониторах, а характеристики в частотной области типа SFDR в общем случае более важны в телекоммуникациях.

Если мы рассмотрим спектр сигнала, преобразованного в ЦАП из цифровой формы, то обнаружим, что, в дополнение к ожидаемому спектру (который будет содержать одну или больше частот, в зависимости от природы восстановленного сигнала), в нем также будет присутствовать шум и составляющие искажений. Искажения могут быть определены в терминах нелинейных искажений, динамического диапазона, свободного от помех (SFDR), интермодуляционных искажений или всех вышеперечисленных вместе. Под нелинейными искажениями понимается отношение высших гармоник к гармонике основной частоты, на которой восстановлен чистый (теоретически) синусоидальный сигнал. Эти искажения являются наиболее общей характеристикой искажений. Динамический диапазон, свободный от помех (SFDR) – это отношение энергии наибольшей из гармоник (обычно – это гармоника основной частоты, но не обязательно) к энергии основной частоты.

При восстановлении с помощью ЦАП синусоидального сигнала, сгенерированного в системе прямого цифрового синтеза (DDS), зависимые от кода ложные сигналы формируют гармоники как внутри полосы, так и за ее пределами. Сигнал проходит через уровень, соответствующий середине шкалы, дважды за один цикл. Поэтому ложный сигнал имеет вторую синусоидальную гармонику, как показано на рис.2.41. Обратите внимание, что гармоники более высокого порядка, составляющие которых попадают в основную полосу Найквиста (от 0до fs /2), не фильтруются.

ПРОЯВЛЕНИЕ КОД-ЗАВИСИМЫХ ВЫБРОСОВ СИГНАЛА В СПЕКТРЕ ВЫХОДНОГО СИГНАЛА

Рис. 2.41

Руководствуясь одной лишь характеристикой площади под кривой ложного сигнала, трудно предсказать нелинейное искажение или SFDR. Другие факторы, такие как полная линейность ЦАП, также способствуют возникновению искажений. Поэтому, общепринята проверка восстановительной способности ЦАП в частотной области (с использованием анализатора спектра) на различных тактовых и сигнальных частотах, как показано на рис.2.43. Типичное значение SFDR для 14-разрядного ЦАП AD9772 представлено на рис.2.44. Тактовая частота равна 65 MSPS и сигнальная частота анализируется до 25 MГц. Как и в случае с АЦП, шум квантования будет проявляться в виде увеличенного нелинейного искажения, если отношение между частотой синхронизации и выходной частотой ЦАП представляется целым числом. Таких отношений нужно избегать при измерении SFDR.

  • Разрешающая способность ЦАП

  • Общая нелинейность

  • Дифференциальная нелинейность

  • Код-зависимые выбросы

  • Отношение тактовой частоты к выходной (даже для идеального ЦАП)

  • Аналитический подход затруднен!

ИСТОЧНИКИ ИСКАЖЕНИЙ В ЦАП СИНТЕЗАТОРОВ ЧАСТОТЫ (DDS)

Рис. 2.42

СХЕМА ИЗМЕРЕНИЯ SFDR ЦИФРО-АНАЛОГОВОГО ПРЕОБРАЗОВАТЕЛЯ

Рис. 2.43

Спад частотной характеристики (Rolloff ) ЦАП sin (x)/x

Выходной сигнал ЦАП может быть представлен в виде ряда прямоугольных импульсов шириной, равной обратной величине тактовой частоты, как показано на рис.2.45. Обратите внимание, что восстановленная амплитуда сигнала составляет -3,92 дБ на частоте Найквиста fс /2. Для компенсации этого эффекта в большинстве случаев достаточно использовать инверсный фильтр sin(x)/x. Значения составляющих основной частоты также ослабляются функцией sin(x)/x.

СПЕКТР ВЫХОДОНОГО СИГНАЛА ЦАП С ОГИБАЮЩЕЙ ВИДА SIN X/X (АМПЛИТУДА НОРМАЛИЗОВАННАЯ)

Рис. 2.45

С ПИСОК ЛИТЕРАТУРЫ

  1. Осокин Ю.В., Судьин С.Л., Федорков Б.Г "Параметры, области применения и перспективы развития полупроводниковых преобразователей информации// микроэлектроника и полупроводниковые приборы" под редакцией А.А. Васенкова и Я.А. Федотова. М.: Радио и связь. 1983.

  2. Федорков Б.Г, Телец В.А. "Микросхемы ЦАП и АЦП: функционирование, параметры, применение" - М. Энергоатомиздат 1990.

  3. W. R. Bennett, “Spectra of Quantized Signals”, Bell System Technical Journal, No. 27, July 1948, pp. 446-472.

  4. Steve Ruscak and Larry Singer, Using Histogram Techniques to Measure A/D Converter Noise, Analog Dialogue , Vol. 29-2, 1995.

  5. M.J. Tant, The White Noise Book, Marconi Instruments, July 1974.

  6. G.A. Gray and G.W. Zeoli, Quantization and Saturation Noise due to A/D Conversion, IEEE Trans. Aerospace and Electronic Systems, Jan. 1971, pp. 222-223.

  7. Chuck Lane, A 10-bit 60MSPS Flash ADC, Proceedings of the 1989 Bipolar Circuits and Technology Meeting, IEEE Catalog No. 89CH2771-4, September 1989, pp. 44-47.

  8. F.D. Waldhauer, Analog to Digital Converter, U.S. Patent 3-187-325, 1965.

  9. J.O. Edson and H.H. Henning, Broadband Codecs for an Experimental 224Mb/s PCM Terminal, Bell System Technical Journal, 44, November 1965, pp. 1887-1940.

  10. J.S. Mayo, Experimental 224Mb/s PCM Terminals, Bell System Technical Journal, 44, November 1965, pp. 1813-1941.

  11. Hermann Schmid, Electronic Analog/Digital Conversions, Van Nostrand Reinhold Company, New York, 1970.

  12. Carl Moreland, An 8-bit 150MSPS Serial ADC, 1995 ISSCC Digest of Technical Papers, Vol. 38, p. 272.

  13. Roy Gosser and Frank Murden, A 12-bit 50MSPS Two-Stage A/D Converter, 1995 ISSCC Digest of Technical Papers , p. 278.

  14. Carl Moreland, An Analog-to-Digital Converter Using Serial-Ripple Architecture, Masters' Thesis, Florida State University College of Engineering, Department of Electrical Engineering, 1995.

  15. Walt Kester, Drive Circuitry is Critical to High-Speed Sampling ADCs, Electronic Design Special Analog Issue, Nov. 7, 1994, pp. 43-50.

  16. Walt Kester, Basic Characteristics Distinguish Sampling A/D Converters, EDN, Sept. 3, 1992, pp. 135-144.

  17. Walt Kester, Peripheral Circuits Can Make or Break Sampling ADC Systems, EDN , Oct. 1, 1992, pp. 97-105.

  18. Walt Kester, Layout, Grounding, and Filtering Complete Sampling ADC System, EDN , Oct. 15, 1992, pp. 127-134.

  19. Joey Doernberg, Hae-Seung Lee, David A. Hodges, Full Speed Testing of A/D Converters, IEEE Journal of Solid State Circuits, Vol. SC-19, No. 6, Dec. 1984, pp. 820-827.

  20. Brendan Coleman, Pat Meehan, John Reidy and Pat Weeks, Coherent Sampling Helps When Specifying DSP A/D Converters, EDN, October 15, 1987, pp. 145-152.

  21. James J. Colotti, Digital Dynamic Analysis of A/D Conversion Systems Through Evaluation Software Based on FFT/DFT Analysis, RF Expo East 1987 Proceedings, Cardiff Publishing Co., pp. 245-272.

  22. Dan Sheingold, Editor, Analog-to-Digital Conversion Handbook, Third Edition, Prentice-Hall, 1986.

  23. Lawrence Rabiner and Bernard Gold, Theory and Application of Digital Signal Processing, Prentice-Hall, 1975.

  24. Matthew Mahoney, DSP-Based Testing of Analog and Mixed-Signal Circuits, IEEE Computer Society Press, Washington, D.C., 1987.

  25. IEEE Trial-Use Standard for Digitizing Waveform Recorders, No. 1057-1988.

  26. Richard J. Higgins, Digital Signal Processing in VSLI, Prentice-Hall, 1990.

  27. Howard E. Hilton, A 10MHz Analog-to-Digital Converter with 110dB Linearity, H.P. Journal , October 1993, pp. 105-112.


Содержание ЦОС

Rambler's Top100 Дата последнего обновления файла 30.09.04

Содержание лекций микропроцессоры и цифровая обработка сигналов.

  1. Введение
  2. Квантование аналогового сигнала по времени
  3. Фильтры для устранения эффекта наложения спектров (Антиалайзинговые фильтры)
  4. Характеристики АЦП и ЦАП
  5. Виды АЦП
  6. Виды ЦАП
  7. Подключение АЦП и ЦАП к сигнальному процессору.


Введение

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Виды сигналов.

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

Цифровым сигналом называется сигнал, определённым образом обработанный и преобразованный в цифры. Обычно эти цифровые сигналы связаны с реальными аналоговыми сигналами, но иногда между ними и нет связи. В качестве примера можно привести передачу данных в локальных вычислительных сетях (LAN) или в других высокоскоростных сетях .

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

Другой ключевой концепцией в определении сигнала является тот факт , что сигнал всегда несет некоторую информацию. Это ведет нас к ключевой проблеме обработки физических аналоговых сигналов – проблеме извлечения информации.

Цели обработки сигналов.

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

Как только желаемая информация будет извлечена из сигнала, она может быть использована различными способами. В некоторых случаях желательно переформатировать информацию, содержащуюся в сигнале.

В частности, изменение формата сигнала происходит при передаче звукового сигнала в телефонной системе с многоканальным доступом и частотным разделением (FDMA). В этом случае используются аналоговые методы, чтобы разместить несколько голосовых каналов в частотном спектре для передачи через радиорелейную станцию СВЧ диапазона, коаксиальный или оптоволоконный кабель.

В случае цифровой связи аналоговая звуковая информация сначала преобразуется в цифровую с использованием АЦП. Цифровая информация, представляющая индивидуальные звуковые каналы, мультиплексируется во времени (многоканальный доступ с временным разделением, TDMA) и передается по последовательной цифровой линии связи (как в ИКМ - системе).

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

Промышленные системы сбора данных и системы управления используют информацию, полученную от датчиков, для выработки соответствующих сигналов обратной связи, которые, в свою очередь, непосредственно управляют процессом. Обратите внимание, что эти системы требуют наличия как АЦП и ЦАП, так и датчиков, устройств нормализации сигнала (signal conditioners) и DSP (или микроконтроллеров).

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

ЦЕЛИ ОБРАБОТКИ СИГНАЛОВ

  • Извлечение информации о сигнале (амплитуда, фаза, частота, спектральные составляющие ,временные соотношения)
  • Преобразование формата сигнала (телефония с разделением каналов FDMA, TDMA, CDMA)
  • Сжатие данных (модемы, сотовые телефоны, телевидение HDTV, сжатие MPEG)
  • Формирование сигналов обратной связи (управление промышленными процессами )
  • Выделение сигнала из шума (фильтрация, автокорреляция, свертка)
  • Выделение и сохранение сигнала в цифровом виде для последующей обработки (БПФ)

Рис . 1.2

Формирование сигналов.

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

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

Методы и технологии обработки сигналов.

Сигналы могут быть обработаны с использованием аналоговых методов (аналоговой обработки сигналов, или ASP), цифровых методов (цифровой обработки сигналов, или DSP) или комбинации аналоговых и цифровых методов (комбинированной обработки сигналов, или MSP). В некоторых случаях выбор методов ясен, в других случаях нет ясности в выборе и принятие окончательного решения основывается на определенных соображениях.

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

Термин "комбинированная обработка сигналов" подразумевает, что системой выполняется и аналоговая, и цифровая обработка. Такая система может быть реализована в виде печатной платы, гибридной интегральной схемы (ИС) или отдельного кристалла с интегрированными элементами. АЦП и ЦАП рассматриваются как устройства комбинированной обработки сигналов, так как в каждом из них реализованы и аналоговые, и цифровые функции.

Недавние успехи технологии создания микросхем с очень высокой степенью интеграции (VLSI) позволяют осуществлять комплексную (цифровую и аналоговую) обработку на одном кристалле. Сама природа ЦОС подразумевает, что эти функции могут быть выполнены в режиме реального масштаба времени.

Сравнение аналоговой и цифровой обработки сигналов

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

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

Несколько методов реализации процесса обработки сигналов показано на рис.1.3. В верхней области рисунка изображен чисто аналоговый подход. В остальных областях изображена реализация DSP. Обратите внимание, что, как только выбрана DSP технология, следующим решением должно быть определение местоположения АЦП в тракте обработки сигнала.

ОБРАБОТКА АНАЛОГОВЫХ И ЦИФРОВЫХ СИГНАЛОВ

Рис. 1.3 Способы обработки сигналов.

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

При наличии современных технологий производства ЦАП и АЦП с высокими частотами дискретизации и разрешающими способностями существенный прогресс достигнут в интеграции все большего числа цепей непосредственно в АЦП /ЦАП.

В сфере измерений, например, существуют 24-битные АЦП со встроенными программируемыми усилителями (PGA), которые позволяют оцифровывать полномасштабные мостовые сигналы 10 mV непосредственно, без последующей нормализации (например серия AD773x).

На голосовых и звуковых частотах распространены комплексные устройства кодирования - декодирования – кодеки (Analog Front End, AFE), которые имеют встроенную в микросхему аналоговую схему, удовлетворяющую минимуму требований к внешним компонентам нормализации (AD1819B и AD73322).

Существуют также видео - кодеки (AFE) для таких задач, как обработка изображения с помощью ПЗС (CCD), и другие (например, серии AD9814, AD9816, и AD984X).

Пример реализации.

В качестве примера использования DSP сравним аналоговый и цифровой фильтры низкой частоты (ФНЧ), каждый с частотой среза 1 кГц.

Цифровой фильтр реализован в виде типовой цифровой системы, показанной на рис. 1.4. Обратите внимание, что в диаграмме принято несколько неявных допущений. Во -первых, чтобы точно обработать сигнал, принимается, что тракт АЦП /ЦАП обладает достаточными значениями частоты дискретизации, разрешающей способности и динамического диапазона. Во -вторых, для того, чтобы закончить все свои вычисления в пределах интервала дискретизации (1/fs), устройство ЦОС должно иметь достаточное быстродействие. В -третьих, на входе АЦП и выходе ЦАП сохраняется потребность в аналоговых фильтрах ограничения и восстановления спектра сигнала (anti-aliasing filter и anti -imaging filter), хотя требования к их производительности невелики. Приняв эти допущения, можно сравнить цифровой и аналоговый фильтры.

Рис. 1.4 Структурная схема цифрового фильтра.

Требуемая частота среза обоих фильтров – 1 кГц. Аналоговое преобразование реализуется фильтром Чебышева первого рода шестого порядка (характеризуется наличием пульсаций коэффициента передачи в полосе пропускания и отсутствием пульсаций вне полосы пропускания). Его характеристики представлены на рис. 1.5. На практике этот фильтр может быть представлен тремя фильтрами второго порядка, каждый из которых построен на операционном усилителе и нескольких резисторах и конденсаторах. С помощью современных систем автоматизированного проектирования (САПР) фильтров создать фильтр шестого порядка достаточно просто, но чтобы удовлетворить техническим требованиям по неравномерности характеристики 0,5 дБ, требуется точный подбор компонентов.

Представленный же на рис 1.4 цифровой КИХ-фильтр со 129 коэффициентами имеет неравномерность характеристики всего 0,002 дБ в полосе пропускания, линейную фазовую характеристику и намного более крутой спад. На практике такие характеристики невозможно реализовать с использованием аналоговых методов. Другое очевидное преимущество схемы состоит в том, что цифровой фильтр не требует подбора компонентов и не подвержен дрейфу параметров, так как частота синхронизации фильтра стабилизирована кварцевым резонатором. Фильтр со 129 коэффициентами требует 129 операций умножения с накоплением (MAC) для вычисления выходного отсчёта. Эти вычисления должны быть закончены в пределах интервала дискретизации 1/fs, чтобы обеспечить работу в реальном масштабе времени. В этом примере частота дискретизации равна 10 кГц, поэтому для обработки достаточно 100 мкс, если не требуется производить существенных дополнительных вычислений. Семейство DSP ADSP-21xx может закончить весь процесс умножения с накоплением (и другие функции, необходимые для реализации фильтра) за один командный цикл. Поэтому фильтр со 129 коэффициентами требует быстродействия более 129/100 мкс = 1,3 миллиона операций с секунду (MIPS). Существующие DSP имеют намного большее быстродействие и, таким образом, не являются ограничивающим фактором для этих приложений. Быстродействие серии 16-разрядных ADSP-218x с фиксированной точкой достигает 75MIPS. На рис. 1.6 приведен ассемблерный код, реализующий фильтр на DSP процессорах семейства ADSP-21xx. Обратите внимание, что фактические строки исполняемого кода помечены стрелками; остальное – это комментарии.

Рис. 1.5 Амплитудно-частотные характеристики фильтров

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

ПРОГРАММА НА АССЕМБЛЕРЕ:
FIR ФИЛЬТР ДЛЯ ADSP-21XX (ОДИНАРНАЯ ТОЧНОСТЬ)

.MODULE fir_sub;
{ Подпрограмма КИХ фильтра
  Параметры вызова подпрограммы
    I0 --> Наиболее старые данные в линии задержки
    I4 --> Начало таблицы коэффициентов фильтра
    L0 = Длина фильтра (N)
    L4 = Длина фильтра (N)
    M1,M5 = 1
    CNTR = Длина фильтра - 1 (N-1)
  Возвращаемые значения
    MR1 = Результат суммирования (округлённый и ограниченный)
    I0 --> Наиболее старые данные в линии задержки
    I4 --> Начало таблицы коэффициентов фильтра
  Изменяемые регистры
    MX0,MY0,MR
  Время работы
    (N - 1) + 6 cycles = N + 5 cycles
  Все коэффициенты записаны в формате 1.15 }

.ENTRY fir;
fir:         MR=0, MX0=DM(I0,M1), MY0=PM(I4,M5)
             CNTR = N-1;
             DO convolution UNTIL CE;
convolution:   MR=MR+MX0*MY0(SS), MX0=DM(I0,M1), MY0=PM(I4,M5);
             MR=MR+MX0*MY0(RND);
             IF MV SAT MR;
             RTS;
.ENDMOD;

Рис. 1.6

ОБРАБОТКА СИГНАЛОВ В РЕАЛЬНОМ ВРЕМЕНИ

  • Цифровая обработка сигналов;
    • Ширина спектра обрабатываемого сигнала ограничена частотой дискретизации АЦП/ЦАП
      • Помните о критерии Найквиста и теореме Котельникова
    • Динамический диапазон сигнала ограничен разрядностью АЦП /ЦАП
    • Производительность процессора DSP ограничивает объем обработки сигнала, так как:
      • Для работы в реальном масштабе времени все вычисления, производимые сигнальным процессором, должны быть закончены в течение интервала дискретизации, равного 1/f s
  • Не забывайте об аналоговой обработке сигнала
    • высокочастотной /радиочастотной фильтрации, модуляции, демодуляции
    • аналоговых ограничивающих и восстанавливающих спектр фильтрах (обычно ФНЧ) для АЦП и ЦАП
    • там , где диктуют здравый смысл и стоимость реализации

Рис . 1.7

Назад Содержание Вперед

СПИСОК ЛИТЕРАТУРЫ

  1. Practical Design Techniques for Sensor Signal Conditioning, Analog Devices, 1998.
  2. Daniel H. Sheingold, Editor, Transducer Interfacing Handbook, Analog Devices, Inc., 1972.
  3. Richard J. Higgins, Digital Signal Processing in VLSI, Prentice-Hall, 1990.


Литература

 Rambler's Top100 Дата последнего обновления файла 07.10.2005

Литература по преподаваемым дисциплинам

Некоторые книги записаны в формате DJVu. Программу просмотра книг в этом формате можно скачать здесь.

Ричард Блейхут

На мой взгляд это самые лучшие книги по алгоритмам быстрой обработки сигналов и кодированию из тех, что я видел

  1. Быстрые алгоритмы цифровой обработки сигналов (К сожалению в приложениях, содержатся ошибки)
  2. Теория и практика кодов, контролирующих ошибки

Михаил Гук

По моему эти файлы, найденные в интернете, содержат информацию из книг Михаила Гука Аппаратные средства IBM PC и Периферийные устройства IBM PC, хотя прямых ссылок я не обнаружил.

  1. Последовательные порты IBM PC
  2. Параллельные порты IBM PC
  3. Шина PCI

Уолт Кестер

По моему это одна из лучших книг по цифровой обработке сигналов

  1. Введение (pdf 330 кбайт)
  2. Дискретизация и восстановление аналоговых сигналов (pdf 920 кбайт)
  3. Аналого-цифровые преобразователи (pdf 740 кбайт)
  4. Цифро-аналоговые преобразователи (pdf 490 кбайт)
  5. Быстрое преобразование Фурье (pdf 690 кбайт)
  6. Цифровые фильтры (pdf 880 кбайт)
  7. Микроконтроллеры, микропроцессоры и сигнальные процессоры (pdf 150 кбайт)
  8. Подключение АЦП и ЦАП к процессорам (pdf 560 кбайт)
  9. Применение сигнальных процессоров (pdf 1050 кбайт)
  10. Согласование уровней, изоляция, заземление и подавление помех в цифровых схемах (pdf 1300 кбайт)

С. Л. Марпл-мл.

Книга посвящена спектральному анализу коротких выборок данных. Рассмотренные методы альтернативны методам быстрого преобразования Фурье. Очень полезна для анализа непериодических коротких сигналов

С. Л. Марпл-мл., Цифровой спектральный анализ и его приложения. Москва: Мир, 1990.

А. Фрунзе

Перед тем как издать книгу, А. Фрунзе опубликовал ряд статей в журнале схемотехника по этой же тематике. Прекрасное сочетание схем и программ для них! Некоторые из них доступны в электронном виде:

  1. Первое знакомство (pdf 160 кбайт)
  2. Двоичные и шестнадцатеричные коды (pdf 360 кбайт)
  3. Сопряжение микроконтроллера с программно-управляемыми микросхемами (pdf 500 кбайт)
  4. Ассемблер (pdf 83 кбайт)
  5. Сопряжение с последовательными АЦП (pdf 101 кбайт)
  6. Регистры микроконтроллера (pdf 256 кбайт)
  7. Работа с внешней памятью данных (pdf 346 кбайт)
  8. Регистр-указатель данных (pdf 684 кбайт)
  9. Сопряжение со светодиодными индикаторами (pdf 327 кбайт) Не знаю как у Фрунзе, а у меня, когда я после окончания института сочинил подобную схему, изображение пришлось смотреть только в полной темноте! Яркость светодиодов падает пропорционально скважности коммутирующих импульсов! Можно скомпенсировать увеличением импульсного тока через светодиод, но тогда необходимо умощнить дешифраторы.
  10. Сопряжение с жидкокристаллическими индикаторами (pdf 952 кбайт)
  11. Сопряжение с матричными индикаторами (pdf 135 кбайт)
  12. Сопряжение с матричными индикаторами (продолжение) (pdf 54 кбайт)

Для тех, кто желает проверить работу программ, приведённых в этих статьях можно скачать ассемблер TASM, но лучше переделать программы под профессиональный свободно распространяемый ассемблер ASM51. Описание работы с этой программой можно найти здесь, а техническое руководство находится непосредственно в zip архиве.

Джон Прокис

Пытаться построить устройство цифровой обработки сигналов не зная для чего предназначены эти сигналы достаточно проблематично. Современные системы цифровой связи строятся на основе глубоких знаний структуры передаваемых сигналов и помех этим сигналам. Это невозможно без теоретических основ радиотехники. Джон Прокис написал на мой взгляд наиболее полную и в то же самое время наиболее доступную для понимания книгу по теоретическим основам цифровой радиосвязи. Настоятельно советую изучить эту книгу. При этом желательно неоднократное возвращение к ней после некоторых перерывов, во время которых будут рассматриваться более простые вопросы и разрабатываться реальные устройства.

Цифровая связь М. Радио и связь 2000 г.

Л.Р. Рабинер Р.В. Шафер

Цифровая обработка речевых сигналов

  1. Введение
  2. Основы цифровой обработки сигналов
  3. Цифровые модели речевых сигналов
  4. Цифровые модели речевых сигналов (продолжение)
  5. Методы обработки речевых сигналов во временной области
  6. Цифровое представление речевых сигналов
  7. Цифровое представление речевых сигналов (продолжение)
  8. Кратковременный анализ Фурье
  9. Реализация метода суммирования гребёнки фильтров с помощью БПФ
  10. Гомоморфная обработка речи
  11. Кодирование речевых сигналов на основе линейного предсказания
  12. Погрешность предсказания. Кепстр.
  13. Цифровая обработка речи в системах речевого общения человека с машиной
  14. Список литературы

Л.Р. Рабинер Б. Гоулд

Теория и применение цифровой обработки сигналов

  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. Применения цифровой обработки в радиолокации

Б Уидроу

Достаточно часто цифровые устройства реализуют алгоритмы адаптивного приема сигналов. В данной книге одного из основоположников адаптивного приема подробно рассматриваются математические основы таких алгоритмов.

Адаптивная обработка сигналов М. Радио и связь 1989 г.

[ Главная ]


Справочные материалы

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Справочные материалы для курсового проектирования и РГЗ

  • Микропроцессоры
  • ОЗУ
  • ПЗУ
  • Последовательные порты

Справочные материалы по микропроцессорам

Atmel

Справочные материалы по микросхемам семейства MCS-51:

  • at89c1051
  • at89c4051
  • at89s51
  • at89c52
  • at89s53
  • at89c55wd
  • at89s8252

Справочные материалы по микросхемам семейства AVR:

  • ATmega103 - описание на русском языке, составленное КТЦ-МК
  • ATmega128
  • ATmega163
  • AT90S1200
  • AT90S2313
  • AT90S8515b
  • AT90C8534
  • ATtiny28L

Analog Devices

Справочные материалы по микросхемам семейства MCS-51:

  • ADuC824

Микросхема прямого цифрового синтеза:

  • AD9856

Motorola

Справочные материалы по микросхемам семейства HC11:

  • 68HC11

ОЗУ

  • 62C256

Справочные материалы по ПЗУ:

  • 27C256
  • 29с256
  • 28с64

Порты

  • UM82C450

[ Главная ]


Немного об истории

Rambler's Top100 Дата последнего обновления файла 15.10.04

Немного об истории.

К сожалению мне не удалось прочитать большого количества книг по истории как нашего государства, так по истории других государств. Но даже того, что я прочитал хватило чтобы понять, что то что творится сейчас и даже то, что произойдёт в будущем уже было. Было если не в нашей истории, то в истории других государств. Проблемы, которые встают сейчас перед нами вставали и перед предыдущими поколениями людей. Решения этих проблем как это ни странно - стандартные! И одни приводят к немедленному краху государства (при этом обычно гибнут и люди, населяющие его), другие приводят к его процветанию. И тут развеялась ещё одна легенда - оказалось, что процветание государства не обязательно процветание народов, населяющих его! В общем я понял: история это не наука о прошлом - история это наука о будущем!

Наибольшее впечатление на меня произвела история государства российского Карамзина. Но только не урезанный вариант! Я видел и урезанный вариант этой книги - не то!

В библиотеке нашего университета есть книга с летописями освоения Сибири. Это тоже нечто! Читать советую на древнерусском языке - прочитав две страницы вы забудете, что это древнерусский язык. Зато исчезнут многие легенды, которыми нас потчуют учебники истории, а особенно телевизор! Наибольший шок у меня вызвало то, что у казаков, идущих на Сибирь не было превосходства в оружии! Сибирские народы были вооружены лучше! Одно то, что предводители казаков Ермак и Иван Кольцо были одеты в сибирские (а не русские) латы и вооружены сибирскими же саблями говорит о многом!

Успех их атаки объясняется другим - это была карательная экспедиция! Они выбивали среднеазиатского узурпатора! И сибирские народы поддерживали их! В общем лучше прочитать первоисточник самим!

Интересна и история освобождения Московии от власти татар. Наибольшие сведения я получил, прочитав Задонщину - летописное описание событий Куликовской битвы. И снова шок! Дмитрий Донской уменьшается и вдруг неизмеримо вырастают фигуры Боброка, который за три года до Куликовской битвы при Воже уже разбил татарскую орду, большую по численности чем орда Мамая, и Сергия Радонежского, организовавшего успех этих битв.

В общем лучше почитать самим.

Мне удалось найти описание русской истории Соловьёва. Если у кого есть Карамзин или есть ссылка на сайт, где находятся его книги пришлите пожалуйста мне по адресу mavr@neic.nsk.su

Сергей Михайлович СОЛОВЬЕВ "ИСТОРИЯ РОССИИ С ДРЕВНЕЙШИХ ВРЕМЕН"

том1 (rar-архив 160кбайт)
том2 (rar-архив 230кбайт)
том3 (rar-архив 220кбайт)
том4 (rar-архив 220кбайт)
том5 (rar-архив 250кбайт)
том6 (rar-архив 240кбайт)
том7 (rar-архив 240кбайт)
том8 (rar-архив 250кбайт)

[ Преподаватель]


Семейство MSC-48

 Rambler's Top100 Дата последнего обновления файла 29.03.05

Микроконтроллеры семейства MCS-48.

1. Внутреннее устройство микроконтроллеров.

  1. Представители семейства MCS-48.
  2. Архитектура микроконтроллеров MCS-48.
  3. Особенности построения параллельных портов микроконтроллеров MCS-48.
  4. Особенности построения памяти микроконтроллеров семейства MCS-48.
  5. Внутренний таймер микроконтроллера, особенности его применения.

2. Система команд микроконтроллеров семейства MCS-48.

  1. Виды адресации.
  2. Инструкции микроконтроллеров семейства MCS-51.


Описание команд микроконтроллеров семейства MCS-48

 Rambler's Top100 Дата последнего обновления файла 05.04.05

Описание машинных команд.

ADD A, <байт-источник> - сложение.

Описание: складывает содержимое аккумулятора А с содержимым байта- источника. Результат операции помещается в аккумулятор. Флаг переноса C устанавливается при переносе из 7го разряда. Флаг вспомогательного переноса AC устанавливается при переносе из 3го разряда. При сложении знаковых чисел флаг переполнения OV устанавливается при превышении максимального положительного числа или при получении числа меньшего минимально возможного. Для команды сложения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: ADD A, R7

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:
0 1 1 0 1 r r r
  • косвенно-регистровая;

Пример: ADD A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + ((Ri)) , i=0,1
Машинный код:
0 1 1 0 0 0 0 i
  • непосредственная.

Пример: ADD A, #38h

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (A) + (date 8)
Машинный код:
0 0 0 0 0 0 1 1
i i i i i i i i

ADDC A, <байт-источник> - сложение с учетом переноса.

Описание: складывает содержимое аккумулятора А с содержимым байта-источника, к получившемуся результату прибавляется значение флага переноса. Результат операции помещается в аккумулятор. Флаг переноса C устанавливается при переносе из 7го разряда. Флаг вспомогательного переноса AC устанавливается при переносе из 3го разряда. При сложении знаковых чисел флаг переполнения OV устанавливается при превышении максимального положительного числа или при получении числа меньшего минимально возможного. Для команды сложения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: ADDC A, R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + (C) + (Rn) , n=0, : ,7
Машинный код:

0 1 1 1 1 r r r
  • косвенно-регистровая;

Пример: ADDC A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + (C) + ((Ri)) , i=0,1
Машинный код:

0 1 1 1 0 0 0 i
  • непосредственная.

Пример: ADDC A, #100

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (A) + (C) + (date 8)
Машинный код:

0 0 0 1 0 0 1 1
i i i i i i i i

ANL <байт приемник>,<байт источник> - команда "логическое И" для байтовых переменных.

Описание: выполняет операцию побитового "логического И" над указанными переменными и помещает результат в байт приемник. Команда не воздействует на флаги.

Для команды ANL с аккумулятором в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: ANL A, R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) & (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:

0 1 0 1 1 r r r
  • косвенно-регистровая;

Пример: ANL A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) & ((Ri)) , i=0,1
Машинный код:

0 1 0 1 0 0 0 i
  • непосредственная.

Пример: ANL A, #100

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (A) & (date 8)
Машинный код:

0 1 0 1 0 0 1 1
i i i i i i i i

Для команды ANL возможна работа с портами и шиной данный в качестве приёмника информации. При этом источник информации использует непосредственную адресацию:

Пример: ANL BUS, #00010010B

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(BUS) = (BUS) & (direct)
Машинный код:

1 0 0 1 1 0 0 0
d d d d d d d d

Пример: P1, #10000000b

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(Pp) = (Pp) & (date 8), pp=1,2
Машинный код:

1 0 0 1 1 0 p p
d d d d d d d d

Примечание: при выполнении команды ANL над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

ANLD P, A - "логическое И" порта внешней микросхемы расширителя портов и аккумулятора A.

Описание: выполняет операцию побитового "логического И" над содержимым порта внешней микросхемы расширителя портов и аккумулятора. Результат помещается в порт. Команда не воздействует на флаги. При этом как источник, так и приемник информации использует неявную адресацию:

Пример: ANLD P6, A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(Pp) = (Pp) & (A), pp=4,5,6,7
Машинный код:

1 0 0 1 1 1 p p

CALL <addr 11> - вызов подпрограммы.

Описание: вызывает подпрограмму, размещенную по указанному адресу <addr 11>. Команда увеличивает содержимое счетчика команд на 2 и затем помещает полученный результат в стек. Кроме программного счетчика в стеке сохраняется содержимое регистра флагов PSW. После это содержимое указателя стека SP увеличивается на 1. Команда не воздействует на флаги.

Пример: CALL 311h

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
((SP)) = (PC), (PSW4-7)
(SP) = (SP) + 1
(PC10-0) = адрес подпрограммы (метки)
Машинный код:

a10 a9 a8 1 0 1 0 0
a7 a6 a5 a4 a3 a2 a1 a0

CLR A - сброс аккумулятора

Описание: сбрасывает (записывает '0' во все биты аккумулятора). Команда не изменяет содержимое флагов. Команда использует неявную адресацию:

Пример: CLR A ;Записывает в аккумулятор число 00h

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = 0
Машинный код:

0 0 1 0 0 1 1 1

CLR C - сбрасывает флаг переноса в нулевое значение.

Описание: сбрасывает (записывает '0') в флаг переноса. Команда использует неявную адресацию:

Пример: CLR C ;Записывает во флаг переноса '0'

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(C) = 0
Машинный код:

1 0 0 1 0 1 1 1

CLR F0 - сбрасывает флаг пользователя F0 в нулевое значение.

Описание: сбрасывает (записывает '0') в флаг пользователя F0. Команда использует неявную адресацию:

Пример: CLR F0 ;Записывает во флаг пользователя F0 '0'

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(F0) = 0
Машинный код:

1 0 0 0 0 1 0 1

CLR F1 - сбрасывает флаг пользователя F1 в нулевое значение.

Описание: сбрасывает (записывает '0') в флаг пользователя F1. Команда использует неявную адресацию:

Пример: CLR F1 ;Записывает во флаг пользователя F0 '0'

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(F1) = 0
Машинный код:

1 0 1 0 0 1 0 1

CPL A - каждый бит аккумулятора инвертируется.

Описание: каждый бит аккумулятора инвертируется, т.е. если в каком-либо из восьми бит аккумулятора записана '1', то в этот бит записывается '0' и наоборот.

Пример: CPL A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = not(A)
Машинный код:

0 0 1 1 0 1 1 1

CPL C - инвертируется флаг переноса 'C'.

Описание: флаг переноса 'C' инвертируется, т.е. если флаг переноса 'C' содержит '1', то в него записывается '0' и наоборот. Команда использует неявную адресацию:

Пример: CPL C

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(C) = not(C)
Машинный код:

1 0 1 0 0 1 1 1

CPL F0 - инвертируется флаг пользователя F0 в нулевое значение.

Описание: флаг пользователя 'F0' инвертируется, т.е. если флаг пользователя 'F0' содержит '1', то в него записывается '0' и наоборот. Команда использует неявную адресацию:

Пример: CLR F0 ;Инвертирует флаг пользователя F0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(F0) = 0
Машинный код:

1 0 0 0 0 1 0 1

CPL F1 - инвертируется флаг пользователя F1 в нулевое значение.

Описание: флаг пользователя 'F1' инвертируется, т.е. если флаг пользователя 'F1' содержит '1', то в него записывается '0' и наоборот. Команда использует неявную адресацию:

Пример: CLR F1 ;Инвертирует флаг пользователя F0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(F1) = 0
Машинный код:

1 0 1 0 0 1 0 1

DA A - десятичная коррекция аккумулятора при сложении двоично-десятичных чисел.

Описание: команда десятичной коррекции позволяет вести сложение чисел, представленных в упакованном двоично-десятичном коде. Команда применяется после инструкций ADD или ADDC. Инструкции (команды) ADD или ADDC позволяют суммировать сразу две тетрады, расположенные в одном байте.

Если биты аккумулятора с 0 по 3 содержат число большее 9 (xxxx1010:xxxx1111) или флаг вспомогательного переноса AC содержит '1', то к аккумулятору прибавляется число 6 для того, чтобы получить правильную двоично-десятичную цифру в младшей тетраде.

Если старшие биты аккумулятора (с 4 по 7) содержат число большее 9 (1010xxxx :1111xxxx) или флаг переноса C содержит '1', то к аккумулятору прибавляется число 60h для того, чтобы получить правильную двоично-десятичную цифру в старшей тетраде.

Если в результате операции DA A возникнет перенос, то флаг переноса C будет установлен в 1. Единичный флаг переноса после операции DA A означает, что результат суммирования больше 100 и этим можно воспользоваться для суммирования многоразрядных двоично-десятичных чисел. Команда десятичной коррекции не воздействует на флаг переполнения OV.

Примечание: команда DA A не может преобразовать двоичное число из аккумулятора в двоично-десятичный вид или правильно скорректировать двоично-десятичное вычитание.

Пример: DA A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
IF [[(A3-0) > 9] or [(AC) = 1]] THEN (A3-0) = (A3-0) + 6
AND
IF [[(A7-4) > 9] or [(C) = 1]] THEN (A7-4) = (A7-4) + 6
Машинный код:

0 1 0 1 0 1 1 1

DEC <байт> - производит вычитание 1 из указанного операнда.

Описание: операнд уменьшается на 1. Если первоначально в ячейке было записано значение 00h, то в нее заносится значение 0FFh. Команда не воздействует на флаги.

Для команды DEC разрешены следующие режимы адресации:

  • неявная.

Пример: DEC A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) - 1
Машинный код:

0 0 0 0 0 1 1 1
  • регистровая;

Пример: DEC R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(Rn) = (Rn) - 1, n=0,1,2,3,4,5,6,7
Машинный код:

1 1 0 0 1 r r r

DIS I - запрет внешнего прерывания.

Описание: запрещает прерывание выполнения программы по сигналу низкого уровня на внешней ножке INT.

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
Запретить прерывания от внешней ножки INT
Машинный код:

0 0 0 1 0 1 0 1

DIS TCNTI - запрет прерывания от таймера/счётчика.

Описание: запрещает прерывание выполнения программы по переполнению таймера/счётчика.

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
Запретить прерывания по переполнению таймера/счётчика
Машинный код:

0 0 1 1 0 1 0 1

DJNZ Rn,<адрес> - вычитание 1 из указанной ячейки и переход, если результат не равен 0.

Описание: вычитание 1 из указанной во втором байте команды ячейки памяти и переход к вычисляемому по второму байту команды адресу, если результат вычитания не равен 0. Если первоначально в ячейке памяти содержится '0', то в результате выполнения операции туда будет записано число '0FFH'. Команда не воздействует на флаги. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Для команды DJNZ используется регистровая адресация:

Пример: LABEL1: DJNZ R3 ,LABEL1;

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(Rn) = (Rn) - 1, n=0,1,2,3,4,5,6,7
IF (Rn) < > 0, THEN (PC0..7) = Address
Машинный код:

1 1 1 0 1 r r r
A d d r e s s

EN I - разрешение внешнего прерывания.

Описание: разрешает прерывание выполнения программы по сигналу низкого уровня на внешней ножке INT.

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
Разрешить прерывания от внешней ножки INT
Машинный код:

0 0 0 0 0 1 0 1

EN TCNTI - разрешение прерываний от таймера/счётчика.

Описание: разрешает прерывание выполнения программы по переполнению таймера/счётчика.

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
Разрешить прерывания от таймера/счётчика
Машинный код:

0 0 1 0 0 1 0 1

ENT0 CLK - разрешение выдачи синхросигнала на вывод T0.

Описание: разрешает выдачу синхросигнала на вывод микросхемы T0.

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
Разрешить выдачу синхросигнала на вывод T0
Машинный код:

0 1 1 1 0 1 0 1

IN Pp - пересылка данных из порта в аккумулятор.

Описание: копирует данные на выводах микросхемы в аккумулятор. Команда не воздействует на флаги и использует неявную адресацию.

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (Pp), p=1,2
Машинный код:

0 0 0 0 1 0 p p

INC <байт> - производит прибавление 1 к указанному операнду.

Описание: ячейка памяти адрес, которой указан во втором байте команды увеличивается на 1. Если первоначально в ячейке было записано значение 0FFh, то в нее заносится значение 00h. Команда не воздействует на флаги.

Для команды INC разрешены следующие режимы адресации байта - источника:

  • неявная.

Пример: INC A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + 1
Машинный код:

0 0 0 1 0 1 1 1
  • регистровая;

Пример: INC R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(Rn) = (Rn) + 1, n=0,1,2,3,4,5,6,7
Машинный код:

0 0 0 1 1 r r r
  • косвенно-регистровая;

Пример: INC @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
((Ri)) = ((Ri)) + 1, i=0,1
Машинный код:

0 0 0 1 0 0 0 i

JB0 <адрес> - переход если нулевой бит аккумулятора установлен.

Описание: Если нулевой бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB0 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.0) = 1 THEN (PC0..7) = Address
Машинный код:

0 0 0 1 0 0 1 0
A d d r e s s

JB1 <адрес> - переход если первый бит аккумулятора установлен.

Описание: Если первый бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB1 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.1) = 1 THEN (PC0..7) = Address
Машинный код:

0 0 1 1 0 0 1 0
A d d r e s s

JB2 <адрес> - переход если второй бит аккумулятора установлен.

Описание: Если второй бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB2 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.2) = 1 THEN (PC0..7) = Address
Машинный код:

0 1 0 1 0 0 1 0
A d d r e s s

JB3 <адрес> - переход если третий бит аккумулятора установлен.

Описание: Если третий бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB3 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.3) = 1 THEN (PC0..7) = Address
Машинный код:

0 1 1 1 0 0 1 0
A d d r e s s

JB4 <адрес> - переход если четвёртый бит аккумулятора установлен.

Описание: Если четвёртый бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB4 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.4) = 1 THEN (PC0..7) = Address
Машинный код:

1 0 0 1 0 0 1 0
A d d r e s s

JB5 <адрес> - переход если пятый бит аккумулятора установлен.

Описание: Если пятый бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB5 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.5) = 1 THEN (PC0..7) = Address
Машинный код:

1 0 1 1 0 0 1 0
A d d r e s s

JB6 <адрес> - переход если шестой бит аккумулятора установлен.

Описание: Если шестой бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB6 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.6) = 1 THEN (PC0..7) = Address
Машинный код:

1 1 0 1 0 0 1 0
A d d r e s s

JB7 <адрес> - переход если седьмой бит аккумулятора установлен.

Описание: Если седьмой бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JB7 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (ACC.7) = 1 THEN (PC0..7) = Address
Машинный код:

1 1 1 1 0 0 1 0
A d d r e s s

JC <адрес> - переход, если бит переноса установлен.

Описание: Если бит переноса равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JС LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (С) = 1 THEN (PC0..7) = Address
Машинный код:

1 1 1 1 0 1 1 0
A d d r e s s

JF0 <адрес> - переход, если бит переноса установлен.

Описание: Если флаг пользователя F0 равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JF0 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (F0) = 1 THEN (PC0..7) = Address
Машинный код:

1 0 1 1 0 1 1 0
A d d r e s s

JF1 <адрес> - переход, если бит переноса установлен.

Описание: Если флаг пользователя F1 равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JF0 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (F1) = 1 THEN (PC0..7) = Address
Машинный код:

0 1 1 1 0 1 1 0
A d d r e s s

JMP <addr 11> - переход на метку.

Описание: осуществляет переход на метку, размещенную по указанному адресу <addr 11>. Команда не воздействует на флаги.

Пример: JMP 311h

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC10-0) = адрес метки
Машинный код:

a10 a9 a8 0 0 1 0 0
a7 a6 a5 a4 a3 a2 a1 a0

JMPP @A - косвенный переход в текущей странице.

Описание: осуществляет переход на адрес, содержащийся в ячейке памяти программ на которую указывает содержимое аккумулятора. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с содержимым аккумулятора. Таким образом осуществляется переход в пределах страницы размером в 256 байт. Команда не воздействует на флаги и не изменяет содержимое аккумулятора.

Пример: JMPP @A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC7-0) = ((A))
Машинный код:

a10 a9 a8 0 0 1 0 0
a7 a6 a5 a4 a3 a2 a1 a0

JNC <адрес> - переход, если бит переноса сброшен.

Описание: Если бит переноса равен нулю, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JNС LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (С) = 0 THEN (PC0..7) = Address
Машинный код:

1 1 1 0 0 1 1 0
A d d r e s s


Описание команд микроконтроллеров семейства MCS-48

 Rambler's Top100 Дата последнего обновления файла 06.04.2005

Описание машинных команд (продолжение).

JNI <адрес> - переход, если сигнал на ножке запроса прерывания равен нулю.

Описание: Если на ножке запроса прерывания сигнал равен нулю, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JNI LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (INT) = 0 THEN (PC0..7) = Address
Машинный код:

1 0 0 0 0 1 1 0
A d d r e s s

JNT0 <адрес> - переход, если сигнал ножке микроконтроллера T0 равен нулю.

Описание: Если на ножке микроконтроллера T0 сигнал равен нулю, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JNT0 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (T0) = 0 THEN (PC0..7) = Address
Машинный код:

0 0 1 0 0 1 1 0
A d d r e s s

JNT1 <адрес> - переход, если бит переноса сброшен.

Описание: Если на ножке микроконтроллера T1 сигнал равен нулю, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги.

Пример: JNT1 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (T1) = 0 THEN (PC0..7) = Address
Машинный код:

0 1 0 0 0 1 1 0
A d d r e s s

JNZ <адрес> - переход, если содержимое аккумулятора не равно нулю.

Описание: Если любой бит аккумулятора равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое аккумулятора.

Пример: JNZ LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (A) <> 0 THEN (PC0..7) = Address
Машинный код:

1 0 0 1 0 1 1 0
A d d r e s s

JTF <адрес> - переход, если содержимое аккумулятора не равно нулю.

Описание: Если флаг переполнения таймера установлен, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги.

Пример: JTF LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (A) <> 0 THEN (PC0..7) = Address
Машинный код:

0 0 0 1 0 1 1 0
A d d r e s s

JT0 <адрес> - переход, если бит переноса сброшен.

Описание: Если на ножке микроконтроллера T0 сигнал равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JT0 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (T0) = 1 THEN (PC0..7) = Address
Машинный код:

0 0 1 1 0 1 1 0
A d d r e s s

JT1 <адрес> - переход, если бит переноса сброшен.

Описание: Если на ножке микроконтроллера T1 сигнал равен единице, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

Пример: JT1 LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (T1) = 1 THEN (PC0..7) = Address
Машинный код:

0 1 0 1 0 1 1 0
A d d r e s s

JZ <адрес> - переход, если содержимое аккумулятора не равно нулю.

Описание: Если все биты аккумулятора равны нулю, то производится переход к указанному во втором байте команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется соединением содержимого старших бит программного счетчика с вторым операндом (вторым байтом команды). Таким образом осуществляется переход в пределах страницы размером в 256 байт. Если команда окажется на границе двух страниц, то переход осуществляется в пределах страницы, где расположен второй байт команды. Команда не воздействует на флаги и не изменяет содержимое аккумулятора.

Пример: JZ LABEL1

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
IF (A) = 0 THEN (PC0..7) = Address
Машинный код:

1 1 0 0 0 1 1 0
A d d r e s s

MOV <приемник>,<источник> - скопировать байтовую переменную.

Описание: переменная, указанная во втором операнде, копируется в ячейку, указываемую первым операндом. Байт источник не изменяется. Другие регистры и флаги не изменяются. Для каждого операнда используется свой вид адресации.

Команда допускает следующие виды адресации:

первый операнд - неявная, второй операнд - неявная адресация;

Пример: MOV A, PSW

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (PSW)
Машинный код:

1 1 0 0 0 1 1 1

Пример: MOV A, T

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (T)
Машинный код:

0 1 0 0 0 0 1 0

Пример: MOV PSW, A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(PSW) = (A)
Машинный код:

1 1 0 1 0 1 1 1

Пример: MOV T, A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(T) = (A)
Машинный код:

0 1 1 0 0 0 1 0

первый операнд - неявная, второй операнд - регистровая адресация;

Пример: MOV A, R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:

1 1 1 1 1 r r r

первый операнд - неявная, второй операнд - косвенно-регистровая адресация;

Пример: MOV A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = ((Ri)) , i=0,1
Машинный код:

1 1 1 1 0 0 0 i

первый операнд - неявная, второй операнд - непосредственная адресация;

Пример: MOV A, #38h

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (data 8)
Машинный код:

0 0 1 0 0 0 1 1
i i i i i i i i

первый операнд - регистровая, второй операнд - неявная адресация;

Пример: MOV R3, A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(Rn) = (A) , n=0,1,2,3,4,5,6,7
Машинный код:

1 0 1 0 1 r r r

первый операнд - неявная, второй операнд - непосредственная адресация;

Пример: MOV R3, #38h

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(Rn) = (data 8) , n=0,1,2,3,4,5,6,7
Машинный код:

1 0 1 1 1 r r r
i i i i i i i i

первый операнд - косвенно-регистровая, второй операнд - неявная адресация;

Пример: MOV @R0, A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
((Ri)) = (A), i=0,1
Машинный код:

1 0 1 0 0 0 0 i

первый операнд - косвенно-регистровая, второй операнд - непосредственная адресация;

Пример: MOV @R0, #80

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
((Rn)) = (data 8) , n=0,1,2,3,4,5,6,7
Машинный код:

1 0 1 1 0 0 0 i
i i i i i i i i

MOVD A,<источник> - считать порт микросхемы расширителя портов.

Описание: содержимое порта расширителя портов копируется в младшую тетраду аккумулятора. Старшая тетрада обнуляется. Команда не воздействует на флаги. В обоих операндах используется неявная адресация.

Пример: MOVD A, P4

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (Pp), p=4,5,6,7
Машинный код:

0 0 0 0 1 1 p p

MOVP A, @A - переслать байт из текущей страницы памяти программ в аккумулятор.

Описание: загружает аккумулятор константой из памяти программ. Адрес считываемого байта задаётся исходным содержимым аккумулятора. Команда не воздействует на флаги.

Пример: MOVP A, @A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC0..PC7) = (A)
(A) = ((PC))
Машинный код:

1 0 1 0 0 0 1 1

MOVP3 A, @A - переслать байт из третьей страницы памяти программ в аккумулятор.

Описание: загружает аккумулятор константой из памяти программ. Адрес считываемого байта задаётся исходным содержимым аккумулятора. Команда не воздействует на флаги.

Пример: MOVP3 A, @A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC0..PC7) = (A)
(PC8..PC11) = 0011
(A) = ((PC))
Машинный код:

1 1 1 0 0 0 1 1

MOVX <приемник>,<источник> - переслать байтовую переменную во внешнюю память (из внешней памяти)

Описание: пересылает данные между аккумулятором и байтом внешней памяти.

В первом случае регистр R0 или R1 текущего банка регистров обеспечивает 8- битный адрес, который мультиплексируется с данными на выводах порта P0.

первый операнд - неявная, второй операнд - косвенно-регистровая адресация;

Пример: MOVX A, @R1 ;Скопировать данные из внешней памяти данных в аккумулятор

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC) = (PC) + 1
(A) = ((Ri)), i=0,1
Машинный код:

1 0 0 0 0 0 0 i

первый операнд - косвенно-регистровая, второй операнд - неявная адресация;

Пример: MOVX @R0, A ;Скопировать данные из аккумулятора во внешнюю память

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC) = (PC) + 1
((Ri)) = (A), i=0,1
Машинный код:

1 0 0 1 0 0 0 i

NOP - нет операции

Описание: Кроме программного счетчика не изменяет ни одного регистра, на флаги не воздействует.

Пример: NOP

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
Машинный код:

0 0 0 0 0 0 0 0

ORL <приемник>,<источник> - "логическое ИЛИ" для байтовых переменных

Описание: выполняет операцию побитового "логического ИЛИ" между указанными переменными. Результат сохраняется в приемнике. Команда не воздействует на флаги.

Для команды ORL с аккумулятором в качестве байта назначения разрешены следующие режимы адресации байта - источника:

первый операнд - неявная, второй операнд - регистровая адресация;

Пример: ORL A, R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) V (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:

0 1 0 0 1 r r r

первый операнд - неявная, второй операнд - косвенно-регистровая адресация;

Пример: ORL A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) V ((Ri)), i=0,1
Машинный код:

0 1 0 0 0 0 0 i

первый операнд - неявная, второй операнд - непосредственная адресация;

Пример: ORL A, #100

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(A) = (A) V (date 8)
Машинный код:

0 1 0 0 0 0 1 1
i i i i i i i i

Пример: ORL BUS, #100

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(BUS) = (BUS) V (date 8)
Машинный код:

1 0 0 1 1 0 0 0
i i i i i i i i

Пример: ORL P1, #10010000b

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(Pp) = (Pp) V (date 8), p=1,2
Машинный код:

1 0 0 1 1 0 p p
i i i i i i i i

Примечание: при выполнении команды ORL над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

ORLD Pp, A - логическое ИЛИ между портом расширителя и аккумулятором.

Описание: выполняет операцию побитового "логического ИЛИ" между портом микросхемы расширителя портов и аккумулятором. Результат сохраняется в порту. Команда не воздействует на флаги.

Пример: ORLD P5, A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC) = (PC) + 1
(Pp) = (Pp) V (A0...A3)
Машинный код:

1 0 0 0 1 1 p p

OUTL BUS, A - стробируемый вывод данных из аккумулятора в порт BUS.

Описание: осуществляет стробируемый вывод данных из аккумулятора в порт BUS. Команда не воздействует на флаги.

Пример: OUTL BUS, A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC) = (PC) + 1
(BUS) = (A)
Машинный код:

0 0 0 0 0 0 1 0

OUTL Pp, A - стробируемый вывод данных из аккумулятора в порт.

Описание: осуществляет вывод данных через порт. Команда не воздействует на флаги.

Пример: OUTL Pp, A

Количество байт: 1
Количество циклов: 2
Действие команды:
(PC) = (PC) + 1
(Pp) = (A), p=1,2
Машинный код:

0 0 1 1 1 0 p p

RET - возврат из подпрограммы.

Описание: последовательно выгружает старший и младший байты счетчика команд из стека, уменьшая содержимое указателя стека на 1. Выполнение программы продолжается с нового, только что загруженного в счетчик команд адреса. Команда не воздействует на флаги.

Пример: RET

Количество байт: 1
Количество циклов: 2
Действие команды:
(SP) = (SP) - 1
(PC) = ((SP))
Машинный код:

 1 0 0 0 0 0 1 1

RETR - возврат из подпрограммы обслуживания прерывания и восстановление слова состояния программы.

Описание: последовательно выгружает старший и младший байты счетчика команд из стека, уменьшая содержимое указателя стека на 1. Кроме того, команда восстанавливает состояние логики прерываний, разрешая обработку следующего прерывания. Выполнение программы продолжается с того же адреса, что был в программном счетчике (PC) до начала обработки прерывания (следующий за командой, во время выполнения которой был обнаружен запрос на прерывание). Команда не воздействует на флаги. Если к этому моменту обнаруживается новый запрос на прерывание, то до нового вызова подпрограммы обслуживания прерывания выполняется одна команда из основной программы.

Пример: RETR

Количество байт: 1
Количество циклов: 2
Действие команды:
(SP) = (SP) - 1
(PC) = ((SP))
(PSW4...PSW7) = ((SP))
Машинный код:

1 0 0 1 0 0 1 1

RL A - сдвиг содержимого аккумулятора влево.

Описание: сдвигает восемь бит аккумулятора на один бит влево, бит 7 засылается на место бита 0. Команда не воздействует на флаги.

Пример: RL A

Количество байт: 1
Количество циклов: 1
Действие команды:
(An+1) = (An) n=0..6
(A0) = (A7)
Машинный код:

1 1 1 0 0 1 1 1

RLC A - сдвиг содержимого аккумулятора влево через флаг переноса.

Описание: сдвигает восемь бит аккумулятора и флаг переноса на один бит влево. Содержимое флага переноса помещается на место бита 0 аккумулятора, а содержимое бита 7 аккумулятора переписывается во флаг переноса. На остальные флаги команда не воздействует.

Пример: RLC A

Количество байт: 1
Количество циклов: 1
Действие команды:
(An+1) = (An) n=0..6
(A0) = (C)
(C) = (A7)
Машинный код:

1 1 1 1 0 1 1 1

RR A - сдвиг содержимого аккумулятора вправо.

Описание: сдвигает восемь бит аккумулятора на один бит вправо, бит 0 засылается на место бита 7. Команда не воздействует на флаги.

Пример: RR A

Количество байт: 1
Количество циклов: 1
Действие команды:
(An) = (An+1) n=0..6
(A7) = (A0)
Машинный код:

0 1 1 1 0 1 1 1

RRC A - сдвиг содержимого аккумулятора через флаг переноса.

Описание: сдвигает восемь бит аккумулятора и флаг переноса на один бит вправо. Содержимое флага переноса помещается на место бита 7 аккумулятора, а содержимое бита 0 аккумулятора переписывается во флаг переноса. На остальные флаги команда не воздействует.

Пример: RRC A

Количество байт: 1
Количество циклов: 1
Действие команды:
(An) = (An+1) n=0..6
(A7) = (C)
(C) = (A0)
Машинный код:

0 1 1 0 0 1 1 1

SEL MB0 - выбор нулевого банка памяти программ.

Описание: сбрасывает старший бит счетчика команд в нулевое состояние. Команда используется для выбора нулевого банка памяти программ.

Пример: SEL MB0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(PC11) = 0
Машинный код:

1 1 1 0 0 1 0 1

SEL MB1 - выбор первого банка памяти программ.

Описание: устанавливает старший бит счетчика команд в 1. Команда используется для выбора первого банка памяти программ.

Пример: SEL MB0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(PC11) = 1
Машинный код:

1 1 1 1 0 1 0 1

SEL RB0 - выбор нулевого банка памяти программ.

Описание: сбрасывает флаг выбора банков в нулевое состояние. Команда используется для выбора нулевого банка регистров.

Пример: SEL RB0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(BS) = 0
Машинный код:

1 1 0 0 0 1 0 1

SEL RB1 - выбор нулевого банка памяти программ.

Описание: устанавливает флаг выбора банков в 1. Команда используется для выбора первого банка регистров.

Пример: SEL RB0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(BS) = 1
Машинный код:

1 1 0 1 0 1 0 1

STOP TCNT - остановить таймер-счетчик.

Описание: прекращает подачу импульсов на вход таймера-счетчика.

Пример: STOP TCNT

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
остановить таймер-счетчик
Машинный код:

0 1 1 0 0 1 0 1

STRT CNT - запустить счетчик.

Описание: разрешает подачу импульсов со входа микроконтроллера T1 на вход таймера-счетчика.

Пример: STRT CNT

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
запустить счетчик
Машинный код:

0 1 0 0 0 1 0 1

STRT T - запустить таймер.

Описание: разрешает подачу импульсов с выхода предделителя на вход таймера-счетчика.

Пример: STRT CNT

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
запустить таймер
Машинный код:

0 1 0 1 0 1 0 1

SWAP A - обмен тетрадами внутри аккумулятора.

Описание: команда осуществляет обмен между младшей (биты 0..3) и старшей (биты 4..7) тетрадами аккумулятора. (Тетрада - это четырехбитная переменная). Команду можно интерпретировать как циклический сдвиг на четыре бита. Команда не воздействует на флаги.

Пример: SWAP A

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A3..A0) <=> (A7..A4)
Машинный код:

0 1 0 0 0 1 1 1

XCH A,<байт> - обмен содержимого аккумулятора с переменной байтом.

Описание: команда загружает аккумулятор содержимым указанной переменной, в то же самое время первоначальное содержимое аккумулятора заносится по указанному адресу. Команда не воздействует на флаги.

В команде допускается следующие виды адресации:

первый операнд - неявная, второй операнд - регистровая адресация;

Пример: XCH A, R7

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) <=> (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:

0 0 1 0 1 r r r

первый операнд - неявная, второй операнд - косвенно-регистровая адресация;

Пример: XCH A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC)= (PC) + 1
(A) <=> ((Ri)) , i=0,1
Машинный код:

0 0 1 0 0 0 0 i

XCHD A, @Ri - обмен цифры.

Описание: команда осуществляет обмен между младшей (биты 0..3) тетрадой (тетрада это четырехбитная переменная) аккумулятора, где обычно хранится двоично-десятичная цифра с тетрадой ячейки внутреннего ОЗУ. Используется косвенно регистровая адресация. Старшие тетрады (биты 4..7) обоих операндов не изменяются. Команда не воздействует на флаги.

Пример: XCHD A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A3..A0) <=> ((Ri3..Ri0)) , i=0,1
Машинный код:

0 0 1 1 0 0 0 i

XRL <байт приемник>,<байт источник> - исключающее ИЛИ для переменных байтов.

Описание: выполняет операцию побитового "исключающее логического ИЛИ" между указанными переменными. Результат сохраняется в приемнике. Команда не воздействует на флаги.

Для команды XRL с аккумулятором в качестве байта назначения разрешены следующие режимы адресации:

первый операнд - неявная, второй операнд - регистровая адресация;

Пример: XRL A, R3

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) xor (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:

1 1 0 1 1 r r r

первый операнд - неявная, второй операнд - косвенно-регистровая адресация;

Пример: XRL A, @R0

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) xor ((Ri)) , i=0,1
Машинный код:

1 1 0 1 0 0 0 i

первый операнд - неявная, второй операнд - непосредственная адресация;

Пример: XRL A, #100

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC)= (PC) + 2
(A) = (A) xor (date 8)
Машинный код:

1 1 0 1 0 0 1 1
i i i i i i i i


Архитектура микроконтроллеров MCS-51

 Rambler's Top100 Дата последнего обновления файла 29.03.05

Архитектура микроконтроллеров MCS-48

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

Рисунок 1. Структурная схема контроллера К1816ВЕ48

Структурная схема контроллера представлена на рис.1. Основу микроконтроллера составляет системная шина, которая связывает между собой все основные функциональные узлы микросхемы: блок управления, арифметико-логического устройство, блока таймеров/счетчиков, блока последовательного интерфейса и прерываний, программного счетчика, памяти данных и памяти программ. Двусторонний обмен осуществляется с помощью внутренней 8-разрядной магистрали данных. По такой схеме построены все представители семейства MCS-48. Различные микросхемы этого семейства различаются только объёмом внутренней памяти. Система команд всех контроллеров семейства MCS-48 содержит 96 базовых команд с форматом 1 или 2 байта и не изменяется при переходе от одной микросхемы к другой. Это обеспечивает прекрасную переносимость программ с одного типа микросхем на другой. Рассмотрим подробнее назначение каждого блока.

Блок управления и синхронизации

Блок управления и синхронизации предназначен для выработки синхронизирующих и управляющих сигналов, обеспечивающих координацию совместной работы блоков микроконтроллера во всех режимах работы. В состав блока управления входят:

  • устройство формирования временных интервалов,
  • логика ввода-вывода,
  • регистр команд,
  • дешифратор команд, логика управления ЭВМ.
    •

Устройство формирования временных интервалов предназначено для формирования и выдачи внутренних синхросигналов фаз, тактов и циклов. Количество машинных циклов определяет продолжительность выполнения команд. Генератор построен на внутреннем инверторе и внешнем кварцевом или LC резонаторе. Допустимая частота кварцевого резонатора от 1 до 6 МГц. Схемы задающих генераторов тактовой частоты с использованием внутренней и внешней синхронизации приведены на рисунке 2.

Рисунок 2. Схемы генераторов тактовой частоты.

Нужно отметить, что запуск задающего генератора этого микроконтроллера был затруднённым (жёсткий режим самовозбуждения), поэтому для надёжного запуска задающего генератора следовало использовать либо внешний генератор, либо шунтировать ножки XTAL1 и XTAL2 внешним резистором.

Практически все команды микроконтроллера выполняются за один или два машинных цикла. Обозначим частоту задающего генератора через Fг. Тогда длительность машинного цикла равна 15/Fг или составляет 15 периодов сигнала задающего генератора. Именно с такой частотой выдаётся сигнал стробирования адреса ALE. Логика ввода - вывода предназначена для приема и выдачи сигналов, обеспечивающих обмен информации с внешними устройствами через порты ввода вывода и системную шину микроконтроллера.

Сброс микроконтроллера можно осуществить при помощи конденсатора, подключенного к ножке сброса RESET, как показано на рисунке 3. Минимальное время сброса контроллера 50 мс. В настоящее время для этой цели лучше бы подошла микросхема супервизора питания ADM809. После сброса микроконтроллера обнуляется содержимое счётчика команд PC, указателя стека в составе регистра PSW, выбираются 0 банк регистров и нулевой банк памяти программ. Запрещаются прерывания.

Рисунок 3. Схемы сброса микропроцессора.

Регистр команд предназначен для записи и хранения 8-ми разрядного кода операции выполняемой команды. Код операции, с помощью дешифратора команд и логики управления ЭВМ, преобразуется в микропрограмму выполнения команды, считанной из ПЗУ.

Арифметико-логический блок представляет собой параллельное восьмиразрядное устройство, обеспечивающее выполнение арифметических и логических операций. АЛБ состоит из:

  • регистров временного хранения TMP1 и TMP2,
  • аккумулятора (ACC),
  • ПЗУ констант,
  • арифметико-логического устройства,
  • регистра состояния программ (PSW).

Регистры временного хранения - восьмиразрядные регистры, предназначенные для приема и хранения операндов на время выполнения операций над ними. Регистры временного хранения информации программно не доступны.

Аккумулятор - восьмиразрядный регистр, предназначенный для приема и хранения результата, полученного при выполнении арифметико-логических операций или операций сдвига

ПЗУ констант обеспечивает выработку корректирующего кода при двоично-десятичном представлении данных, кода маски при битовых операциях и кода констант.

Арифметико-логическое устройство представляет собой схему комбинационного типа с последовательным переносом, предназначенную для выполнения арифметических операций сложения, вычитания и логических операций И, ИЛИ, исключающего ИЛИ инкремент, декремент, инверсию, циклический сдвиг вправо и влево, десятичную коррекцию содержимого аккумулятора.

При выполнении операций обработки данных в АЛУ вырабатываются флаги, которые сохраняются в регистре состояния программы PSW.

Кроме того, вырабатываются флаги, по которым осуществляется переход в командах условного перехода, такие как флаг нулевого содержимого аккумулятора и флаг наличия единицы в выбранном бите аккумулятора.

Блок обработки прерываний предназначен для организации ввода - вывода последовательных потоков информации и организации системы прерывания программ. Опрос входа запроса прерывания INT производится во время выдачи сигнала ALE. Передача управления на вектор прерывания 3 произойдёт только по завершению цикла команды. При обработке прерывания содержимое счётчика команд и старшей тетрады слова состояния программы сохраняется в стеке. При обработке прерывания запросы прерываний игнорируются до выхода из подпрограммы обработки прерывания по команде RETR. Прерывания могут быть запрещены командой DIS и разрешены командой EN. Приоритет от внешнего прерывания выше приритета прерывания от внутреннего таймера, то есть если эти прерывания возникнут одновременно, то будет осуществлён переход на вектор прерывания 3

Счетчик команд (Program Counter) предназначен для формирования текущего 11-разрядного адреса памяти программ. В состав счетчика команд входят 11-разрядные буфер РС, регистр РС и схема инкремента (увеличения содержимого на 1). Кроме того, под управлением команд SEL MB0 и SEL MB1 могут переключаться страницы памяти программ.

Память данных (RAM) предназначена для временного хранения информации, используемой в процессе выполнения программы.

Порты P1 и P2 являются квазидвунаправленными портами ввода - вывода и предназначены для обеспечения обмена информацией микроконтроллера с внешними устройствами, образуя 16 линий ввода- вывода.

Регистр состояния программы (PSW) предназначен для хранения информации о состоянии АЛУ при выполнении программы. Формат регистра PSW приведён ниже:

Номер бита | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
Имя флага | C | AC | F0 | BS | - | S2 | S1 | S0
C       - флаг переноса, формируемый АЛУ,
AC      - флаг вспомогательного переноса между тетрадами, формируемого при десятичных вычислениях.
F0      - флаг (битовая переменная), используемый пользователем в своих целях
BS      - флаг переключения регистровых банков,
S0...S2 - биты указателя стека.

Память программ предназначена для хранения программ и представляет собой постоянное запоминающее устройство (ПЗУ). В разных микросхемах семейства применяются ПЗУ различного объёма. В микросхеме 1816ВЕ35 внутренняя память программ отсутствует вовсе.


Построение памяти микроконтроллеров MCS-48

 Rambler's Top100 Дата последнего обновления файла 06.04.2005

Построение памяти микроконтроллеров семейства MCS-48

Микроконтроллеры семейства MCS-48 построены по Гарвардской архитектуре. Это означает, что память данных и память программ в этих микросхемах разделены и имеют отдельное адресное пространство. В этих микроконтроллерах имеется три адресных пространства: память программ, внешняя память данных и внутренняя память данных. Такое построение памяти позволяет реализовывать максимально надёжные системы.

Схема подключения внешних микросхем памяти к микроконтроллерам семейства MCS-48 показана на рисунке 1. Регистр адреса D3 на этой схеме предназначен для запоминания младших 8-ми бит адреса, передаваемых через шину данных/памяти. Старшие четыре бита адреса передаются через шину адреса, совмещенную с портом P2. Во время передачи адреса, микроконтроллер вырабатывает синхроимпульс на ножке ALE. Именно этот импульс позволяет запомнить младший байт адреса в регистре D3.

Для обращения к памяти данных и к памяти программ используются одни и те же шина адреса и шина данных, но разные управляющие сигналы. Для чтения памяти программ вырабатывается сигнал PSEN, а для чтения памяти данных вырабатывается сигнал RD. Для записи информации в память данных вырабатывается сигнал WR. То есть память программ доступна только для чтения, а память данных доступна и для чтения и для записи любой информации, записанной в двоичном коде.

Sx_Proc.gif (12875 bytes)

Рисунок 1. Схема подключения схем внешней памяти к микроконтроллерам семейства MCS-48

Память программ микроконтроллеров MCS-48

Память программ предназначена для хранения программ и имеет отдельное от памяти данных адресное пространство объемом 4 Кбайта, причем для некоторых микросхем (например КР1816ВЕ48, КМ1816ВЕ49) для хранения программ на кристалле микроконтроллера расположено ПЗУ. Это ПЗУ отображается в область младших адресов памяти программ. Учитывая, что выполнение программы после сброса микроконтроллера всегда начинается с нулевого адреса памяти программ, то при включении питания начнет выполняться программа, записанная во внутреннем ПЗУ микроконтроллера. Микроконтроллеры, не имеющие внутреннего ПЗУ (например КР1816ВЕ35 или 8035) могут работать только с внешней микросхемой ПЗУ емкостью до 4 Кбайт. Микроконтроллеры семейства MCS-48 имеют внешний вывод EA, с помощью которого можно запретить работу внутренней памяти, для чего необходимо подать на вывод EA логический "0" (соединить этот вывод с корпусом). При этом внутренняя память программ отключается и, начиная с нулевого адреса, все обращения происходят к внешней памяти программ.

Доступ к внешней памяти программ осуществляется в двух случаях:

  1. при действии сигнала EA=0 независимо от адреса обращения,
  2. в любом случае, если программный счетчик (РС) содержит число большее, чем максимальная ячейка внутренней памяти программ.

Распределение памяти программ микроконтроллера КР1816ВЕ48 представлено ниже:

Для чтения таблиц элементарных функций, перекодировок или строк, выводимых на дисплей, из памяти программ используются команды

MOVP A, @A и MOVP3 A, @A

Переключение страниц памяти программ осуществляется командами

SEL MB1 ;Выбрать первую страницу

SEL MB0 ;Выбрать нулевую страницу

Рисунок 2. Адресное пространство памяти программ.

Для других микроконтроллеров этого семейства изменяется только объем внутренней памяти программ. При использовании портов P1 и P2 в качестве дополнительных адресных расширителей объём доступной внешней памяти программ может быть увеличен до 16 Мбайт.

Ниже приведены адреса векторов прерываний и соответствующие им аппаратурные источники прерываний программы:

Вектор прерывания | Флаги, вызывающие прерывание | Источник прерывания
0000Н | - | Рестарт (сброс) контроллера RESET
0003Н | IE | внешнее прерывание INT
0007Н | TF | Таймер

Внешняя память данных микроконтроллеров MCS-48

Внешняя память данных предназначена для временного хранения информации, используемой в процессе выполнения программы. Эта память физически должна быть подключена к микросхеме микроконтроллера при помощи схемы, изображенной на рисунке 1. Максимальный объем этой памяти определяется регистрами R0 и R1 и составляет 256 байт. Точно также как и в случае внешней памяти программ, объем внешней памяти данных может быть увеличен за счет использования портов P1 и P2 до 16 Мбайт.

Для обращения к внешней памяти данных используются команды:

MOVX A, @R0 или MOVX A, @R1 (команды чтения)

MOVX @R0, или MOVX @R1, A (команды записи)

Рисунок 3. Адресное пространство внешней памяти данных.

Отметим, что в качестве внешней памяти данных могут быть использованы как микросхемы ОЗУ так и микросхемы ПЗУ.

Внутренняя память данных микроконтроллеров MCS-48

Внутренняя память данных (RAM) предназначена для временного хранения информации, используемой в процессе выполнения программы. Адресное пространство внутренней памяти данных представляет собой 256 восьмиразрядных ячеек, с адресами от 000h до 0FFh. Для микроконтроллеров 8048, 8035, КР1816ВЕ35, КР1816ВЕ48 из них доступно только 64 ячейки памяти. Для микроконтроллеров 8049, КР1816ВЕ49 из них доступно 128 ячеек памяти. И только для микроконтроллеров 1850ВЕ49 доступны все 256 ячеек внутренней памяти данных. Распределение адресного пространства памяти данных микроконтроллеров серии MCS-48 приведено на рисунке 4.

Младшие 32 байта внутреннего ОЗУ данных объединены с 2мя банками регистров (RB0 - RB1) и восьмиуровневым стеком микроконтроллера. Банк регистров состоит из восьми восьмиразрядных регистров с именами R0, R1, …, R7. Два банка регистров служат для организации независимой работы основной программы и подпрограмм обслуживания прерываний. Переключение банков регистров производится при помощи особого бита BS регистра слова состояния программы PSW командами SEL RB0 и SEL RB1.

Команды программы могут обращаться к регистрам, используя их имена R0-R7 (MOV A, R0 или MOV R7, A), или используя их адрес во внутренней памяти данных (доступна только косвенно-регистровая адресация). Например:

MOV R0, #5
MOV A, @R0

или

MOV R0, #7
MOV @R0, A).

Рисунок 4. Адресное пространство внутренней памяти данных.

Следующие после второго банка регистров ячейки памяти образуют обычное ОЗУ.

Ячейки внутренней памяти данных с адресами 8 - 23 представляют из себя аппаратный 8 - ми уровневый стек, где сохраняются адреса возвратов из подпрограмм. В составе системы команд отсутствуют команды сохранения регистров в стеке. То есть разработчик программы вынужден следить за использованием регистров во вложенных подпрограммах. Это, наряду с малой глубиной аппаратного стека, сильно ограничивает возможности по написанию программ для микроконтроллеров семейства MCS-48.


Порты микроконтроллеров MCS-48

 Rambler's Top100 Дата последнего обновления файла 06.04.2005

Устройство параллельных портов микроконтроллеров MCS-48

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

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

Рисунок 1. Упрощенная схема одного бита порта.

Один разряд регистра - защелки порта представляет собой D-триггер. Данные с внутренней шины микроконтроллера записываются в регистр-защелку по сигналу "запись в защелку". Значение сигнала с внешнего вывода порта считывается по сигналу "чтение вывода". При чтении ножки микросхемы осуществляется операция логического "И" между сигналом на ножке микросхемы и содержимым триггера квазидвунаправленного порта. Поэтому перед чтением ножки микросхемы необходимо записать в соответствующий разряд порта логическую единицу. Чтение внешних ножек микросхемы осуществляется командами:
IN A, P1      ;Скопировать состояние ножек порта P1 в аккумулятор
IN A, P2      ;Скопировать состояние ножек порта P2 в аккумулятор

Вывод информации через параллельные порты осуществляется командами:

OUTL P1, A   ;Скопировать содержимое аккумулятора в порт P1
OUTL P2, A   ;Скопировать содержимое аккумулятора в порт P2

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

Порты микросхемы служат для управления внешними устройствами, подключенными к микроконтроллеру. Схема подключения простейших внешних устройств приведена на рисунке 2. Этот рисунок иллюстрирует особенности подключения индикаторов к параллельным портам микроконтроллера MCS-48.

Рисунок 2. Схема подключения светодиодных индикаторов к параллельному порту.

Присутствие в схеме мощного транзистора позволяет подключать к выводам порта светодиодные индикаторы непосредственно без усилителя мощности. Однако при этом необходимо следить за максимальной допустимой мощностью, рассеиваемой на микросхеме и напряжением, подаваемом на светодиод. Эквивалентная схема, на которой показан путь протекания выходного тока порта приведена на рисунке 3. Как видно из этой схемы именно этот ток используется для зажигания светодиода.

Рисунок 3. Эквивалентная схема подключения светодиодного индикатора к параллельному порту.

Для умощнения выводов порта можно применить транзисторный ключ, показанный на рисунке 2. Обратите внимание, что база транзистора подключена непосредственно к выводу порта. Это стало возможным только благодаря использованию в схеме порта генератора тока в верхнем плече выходного каскада (Схему подключения устройств к портам с TTL выходами можно посмотреть здесь). Если выходного тока достаточно для открывания транзисторного ключа, то резистор R2 не используется. Этот резистор подключается для увеличения базового тока транзисторного ключа. На максимальное значение тока через этот резистор накладываются те же ограничения, что и для непосредственного подключения светодиодного индикатора к выводам порта.

Это были рассмотрены схемотехнические особенности применения параллельных портов. Однако управлять напряжением на выходе параллельного порта микроконтроллера можно только при помощи программы. В приведённой на рисунке 2 схеме, для зажигания светодиода VD1, в шестой вывод порта P0 необходимо записать логический 0. Для зажигания светодиода VD2 необходимо в седьмой разряд порта P2 записать логическую единицу.

Для записи числа в порт (изменения потенциалов на ножках микросхемы) можно воспользоваться следующими способами:

  1. OUTL (выдача в порт константы), например

    2.  MOV  A, #56h        ;Установить единичный сигнал на ножках 1,2,4 и 6 порта P2
 OUTL P2, A          ;и нулевой потенциал на ножках 0,3,5 и 7

 MOV  A, #01110011b  ;Выдать на все восемь выводов порта P1
 OUTL P1, A          ;двоичное число 01110011

  2. ANL (использование логического 'И' для обнуления выбранных маской бит), например:

    3.  MOV  A, 56          ;Занести в аккумулятор копию порта P1
 ANL P1, #11110011b  ;сформировать низкий потенциал на ножках P1.2 и P1.3
 OUTL P1, A          ;записать новое значение в порт P1

  3. XRL (использование операции исключающее 'ИЛИ' для инвертирования выбранных бит), например

    4.  MOV  A, 56          ;Занести в аккумулятор копию порта P1
 XRL  A, #01000010b  ;инвертировать состояние ножек P1.1 и P1.6
 OUTL P1, A          ;записать новое значение в порт P1
  4. ORL (использование операции логическое 'ИЛИ' для записи единиц в выбранные биты), например
    5.  MOV  A, 56          ;Занести в аккумулятор копию порта P1
 ORL  A, #00100001b  ;выдать высокий потенциал на ножках P1.0 и P1.5
 OUTL P1, A          ;записать новое значение в порт P1

По той же причине при настройке выводов порта на выполнение альтернативных функций в соответствующие разряды должны быть записаны логические '1'.

Порт P1. Этот квазидвунаправленный порт никаких особенностей не имеет. При сбросе микросхемы во все разряды порта P2 записываются '1'.

Sx_Proc.gif (12875 bytes)

Рисунок 4. Подключение внешней памяти программ и памяти данных.

  • Порт P2. Младшая тетрада порта может быть использована для передачи старших четырёх бит адреса при работе с внешней памятью программ и внешней памятью данных (с 12- разрядным адресом). Схема использования порта P2 в качестве шины адреса приведена на рисунке 4. При сбросе микросхемы во все разряды порта P2 записываются '1'. Кроме того через младшие четыре разряда порта 2 могут быть использованы для подключения микросхемы расширителя портов.

  • Порт D/A. Может быть использован для стробируемого вывода данных. Стробирование данных производится сигналом WR. Над этим портом возможно выполнение логических операций, что может сократить длину программ, приведённых выше, до одной команды.


Система команд MCS-48

 Rambler's Top100 Дата последнего обновления файла 05.04.05

Система команд микроконтроллеров MCS-48

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

Реализована побайтовая (8 бит) и потетрадная (4 бита) обработка данных. Микросхемы семейства MCS-48 - это 8-разрядные микропроцессоры, а это означает, что ПЗУ, ОЗУ, регистры специального назначения, АЛУ и внешние шины имеют байтовую организацию.

В машинном коде команда занимает один, или два байта в зависимости от типа команды. Команды выполняются за один или два машинных цикла. При этом большинство команд выполняются за один машинный цикл длительностью 2,5 мкс (при 6 МГц кварцевом резонаторе).

Запись команд в машинных кодах для человека неудобна, кроме того, разные машинные команды выполняют одинаковые действия только над разными ячейками памяти. Поэтому для записи команд микропроцессоров была придумана система мнемонических обозначений. Для записи команды микропроцессора сначала ставится мнемоническое обозначение, затем указывается ячейка памяти – приёмник результата выполнения операции и наконец источник данных для выполнения операции. Например, в команде

MOV A, R2

символы MOV обозначают операцию копирования, второй операнд R2 определяет, что данные необходимо взять из регистра R2 текущего банка регистров, а первый операнд A определяет, что результат необходимо поместить в регистр – аккумулятор. При этом старое значение регистра – аккумулятора будет стёрто.

Мнемоническое обозначение команды отделяется от операндов одним или несколькими символами пробела или табуляции, а операнды отделяются друг от друга запятыми.

Если операция требует для выполнения двух источников и одного приёмника результата операции (например, команда сложения ADD или логического умножения ANL), то первый операнд является одновременно и источником и приёмником результата операции. Например, в команде

ADD A, R1

символы ADD обозначают операцию сложения двух чисел, данные будут взяты из регистра R1 текущего банка регистров и аккумулятора а результат будет помещён в аккумулятор вместо старого значения этого регистра.

В таблице 1 приведены инструкции, влияющие на установку флагов.

Таблица 1

Мнемоника | Флаги
 | C | AC | F0 | F1 | TF | BS | DBF
ADD, ADDC | + | + | - | - | - | - | -
DA | + | + | - | - | - | - | -
CLR C | 0 | - | - | - | - | - | -
CPL C | + | - | - | - | - | - | -
CLR F0 | - | - | 0 | - | - | - | -
CPL F0 | - | - | + | - | - | - | -
CLR F1 | - | - | - | 0 | - | - | -
CPL F1 | - | - | - | + | - | - | -
JTF | - | - | - | - | 0 | - | -
RRC | + | - | - | - | - | - | -
RLC | + | - | - | - | - | - | -
MOV A, PSW | + | + | + | - | - | + | -
RETR | + | + | + | - | - | + | -
SEL MB0, SEL MB1 | - | - | - | - | - | - | +
SEL RB0, SEL RB1 | - | - | - | - | - | + | -

Систему команд микроконтроллера условно можно разбить на пять групп:

  • арифметические команды
  • логические команды
  • команды передачи данных
  • команды ветвления программ и передачи управления
  • команды управления режимами работы микроконтроллера

Арифметические команды

В наборе команд микроконтроллера имеются следующие арифметические операции:

  • сложение ADD,
  • сложение с учетом флага переноса ADDC,
  • инкрементирование (увеличение на 1) INC,
  • декрементирование (уменьшение на 1) DEC,
  • десятичная коррекция DA,

Действия производятся над целыми числами без знака. Команды сложения ADD позволяют сформировать перенос в следующий разряд. Команды сложения с учётом знака переноса позволяют выполнять многобайтное сложение. Вычитание может быть реализовано переводом одного из операндов в дополнительный код с последующим выполнением операции суммирования. Более сложные операции такие как умножение или деление могут быть реализованы только программным способом.

Логические команды.

Система команд микроконтроллера позволяет реализовать логические операции:

  • И ( ANL ANLD),
  • ИЛИ ( ORL ORLD),
  • ИСКЛЮЧАЮЩЕЕ ИЛИ ( XRL).
  • сброс и инвертирование всех восьми разрядов аккумулятора ( CPL A; CLR A);
  • сброс и инвертирование флагов микроконтроллера (
    CLR C;
    CLR F0;
    CLR F1;
    CPL C;
    CPL F0;
    CPL F1);
  • циклический сдвиг влево и вправо с учетом переноса и без (
    RR A;
    RRC A;
    RL A;
    RLC A);
  • обмен местами старшей и младшей тетрад внутри аккумулятора ( SWAP A).

Команды пересылки данных.

Как было рассмотрено ранее, арифметические и логические команды могут быть выполнены только над содержимым регистра аккумулятора, поэтому исключительно важное значение в системе команд приобретают команды пересылки данных. С помощью этих команд можно скопировать содержимое любой ячейки памяти в регистр-аккумулятор или наоборот скопировать содержимое аккумулятора в любую ячейку памяти. Так как в микроконтроллере присутствует три независимых области памяти, то для обращения к ним введены различные команды:

  • обмен данными во внутреннем ОЗУ: MOV, XCH
  • обмен данными из внешней памяти данных: MOVX
  • копирование данных из памяти программ: MOVP
  • обмен данными параллельных портов IN, OUTL, MOVD

Примеры использования команд пересылки данных:

Любая ячейка 256- байтового блока внутреннего ОЗУ данных может быть выбрана с использованием косвенно-регистровой адресации через регистры указатели R0 и R1 (выбранного банка рабочих регистров):

   MOV A, @R0             ;Скопировать число из ячейки памяти с адресом, хранящемся в R0, в аккумулятор
   MOV @R1, A             ;Скопировать число из аккумулятора, в ячейку памяти с адресом, хранящемся в R1

Таблицы символов (кодов), записанные в ПЗУ программы могут быть скопированы в аккумулятор с помощью команд передачи данных с косвенной адресацией:

   MOVP A, @A          ;Скопировать символ из текущей страницы памяти программ в аккумулятор
   MOVP3 A, @A         ;Скопировать символ из третьей страницы памяти программ  в аккумулятор

Ячейка адресного пространства 256 байт внешнего ОЗУ также может быть выбрана с использованием косвенно-регистровой адресации через регистры R0 или R1:

   MOVX A, @R0             ;Скопировать число из внешней ячейки памяти с адресом, ;хранящемся в R0, в аккумулятор
   MOVX @R1, A             ;Скопировать число из аккумулятора, в ячейку памяти с адресом, хранящемся в R1

Содержимое аккумулятора может быть обменено с содержимым рабочих регистров выбранного банка:

XCH A, R0.

Для работы с параллельными портами используется отдельные команды пересылки данных IN и OUTL:

   IN A, P0                ;Скопировать число из порта P0, в аккумулятор
   OUTL P1, A              ;Скопировать число из аккумулятора, в порт P1

Команды ветвления и передачи управления.

Команды ветвления позволяют реализовывать условные операторы и операторы циклов. В микроконтроллерах семейства MCS-48 доступны следующие команды:

  • безусловный переход: JMP
  • Вызов и возврат из подпрограммы: CALL, RET, RETR
  • проверка содержимого аккумулятора: JZ, JNZ, JMPP, JB0 ... JB7
  • проверка флага переноса С: JC, JNC
  • проверка сигнала на ножке T0: JT0, JNT0
  • проверка сигнала на ножке T1: JT1, JNT1
  • проверка сигнала на ножке INT: JNI
  • Проверка состояния флагов пользователя JF0, JF1

Команды безусловных переходов и вызовов подпрограмм позволяют осуществить переход в любую точку адресного пространства памяти программ в пределах страницы 2 Кбайт. Примеры команд:

   JMP Metka            ;Переход к команде, расположенной по адресу обозначенному меткой ‘Metka’
   CALL Podprogramma    ;Вызов подпрограммы по адресу, обозначенному меткой ‘Podprogramma’

В системе команд имеются команды условных переходов. Эти команды позволяют осуществлять переход в пределах страницы 256 байт.

Примеры использования команд условного перехода:

JB5 TstNxtUsl                ;Если в 6 бите аккумулятора нулевое значение,
  CALL Podprogramma             ;то вызвать подпрограмму, обозначенную меткой ‘Podprogramma’
JNZ A, #5, TstNxtUsl         ;Если в аккумуляторе содержится нулевое значение,
  CALL Podprogramma             ;то вызвать подпрограмму, обозначенную меткой ‘Podprogramma’

Команды проверки содержимого аккумулятора и флага переноса C могут быть использованы для реализации проверки различных условий:

  MOV A, 34           ;Если в переменной, хранящейся в ячейке внутренней памяти 34
  JB7 TstNxtUsl       ;число меньше нуля,
    CALL Podprogramma   ;то вызвать подпрограмму, обозначенную меткой ‘Podprogramma’
;---------------------------------------------------------------------------------
  MOV A, 34           ;Если в переменной,
  ADD A, -5           ;хранящейся в ячейке внутренней памяти 34
  JZ TstNxtUsl        ;занесено число 5,
    CALL Podpr5         ;то вызвать подпрограмму, обозначенную меткой ‘Podpr5’
;---------------------------------------------------------------------------------
  MOV A, 34           ;Если в переменной,
  ADD A, -5           ;хранящейся в ячейке внутренней памяти 34
  JNС TstNxtUsl       ;занесено число, меньшее 5,
    CALL PodprLT5       ;то вызвать подпрограмму, обозначенную меткой ‘PodprLT5’
;---------------------------------------------------------------------------------
  MOV A, 34           ;Если в переменной,
  ADD A, -6           ;хранящейся в ячейке внутренней памяти 34
  JC TstNxtUsl        ;занесено число, большее 5,
    CALL PodprGT5       ;то вызвать подпрограмму, обозначенную меткой ‘PodprGT5’
;---------------------------------------------------------------------------------
  MOV A, 34           ;Если в переменной,
  ADD A, -5           ;хранящейся в ячейке внутренней памяти 34
  JC TstNxtUsl        ;занесено число, большее или равное 5,
    CALL PodprGE5       ;то вызвать подпрограмму, обозначенную меткой ‘PodprGE5’
;---------------------------------------------------------------------------------
  MOV A, 34           ;Если в переменной,
  ADD A, -6           ;хранящейся в ячейке внутренней памяти 34
  JNC TstNxtUsl       ;занесено число, меньшее или равное 5,
    CALL PodprLE5       ;то вызвать подпрограмму, обозначенную меткой ‘PodprLE5’

Косвенный переход JMPP @A в системе команд микроконтроллера обеспечивает ветвление программы по содержимому аккумулятора А. Это позволяет реализовывать операцию перехода по заданному коду, эквивалентное оператору case в языке программирования pascal, но намного быстрее (за два машинных цикла). Пример реализации команды выбора варианта:

   ORG 256          ;Разместить команды переходов по границе страницы
     JMP Case0        ;Перейти к выполнению кода по числу 0
     JMP Case1        ;Перейти к выполнению кода по числу 1
     JMP EndCase      ;Это число в ячейке 33 в список разрешённых не входит
     JMP EndCase      ;Это число в ячейке 33 в список разрешённых не входит
     JMP Case4        ;Перейти к выполнению кода по числу 4

BeginOpCase:        ;Сюда нужно перейти командой JMP BeginOpCase
   MOV A, 33        ;В этой ячейке хранится переменная, по которой необходимо осуществить переход на обслуживающую программу

   CLR C            ;Осуществить арифметический сдвиг аккумулятора вправо
   RLC A            ;(умножить на 2) т.к. команды переходов занимают два байта

   JMPP @A          ;Перейти к выполнению заданного в 25 ячейке кода
EndCase:

Команды управления режимами работы микроконтроллера.

Команды управления микроконтроллером позволяют:

  • запускать и останавливать таймер/счётчик ( STRT CNT STRT T, STOP TCNT),
  • разрешать и запрещать прерывания ( EN I, EN TCNTI, DIS I, DIS TCNTI),
  • выбирать рабочий банк регистров ( SEL RB0, SEL RB1),
  • выбирать страницы памяти программ ( SEL MB0, SEL MB1),
  • разрешать выдачу синхросигнала на ножке T0 ( ENT0 CLC).

Способы адресации операндов.

Наибольшее количество видов адресации используется в командах пересылки данных. При определении способа адресации операндов в команде необходимо учитывать, что адресация для каждого операнда команды своя. В общем случае адресация определяется для каждого операнда отдельно.

Неявная адресация При неявной адресации регистр источник или регистр приёмник подразумевается в самом коде операции. Например:

   RR A          ;сдвиг содержимого аккумулятора вправо
   DA A          ;десятичная коррекция аккумулятора

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

 MOV A, R7 ;Во втором операнде использована регистровая адресация (в первом операнде неявная адресация)

Косвенно-регистровая адресация используется для обращения к ячейкам внутреннего ОЗУ данных. В качестве регистров-указателей используются регистры R0, R1 выбранного банка регистров. Примеры использования косвенно-регистровой адресации:

   MOV A, @R0          ;Косвенно-регистровая адресация использована во втором операнде
   MOV @R1, A          ;Косвенно-регистровая адресация использована в первом операнде

Косвенно - регистровая адресация используется также для обращения к внешней памяти данных. В этом случае с помощью регистров- указателей R0 и R1 (рабочего банка рабочих регистров) выбирается ячейка из блока 256 байт внешней памяти данных. Номер блока предварительно задается содержимым порта Р2. Например:

   MOVX A, @R0          ;Косвенно-регистровая адресация использована во втором операнде
   MOVX @R1, A          ;Косвенно-регистровая адресация использована в первом операнде

Косвенно- регистровая адресация по содержимому аккумулятора А упрощает просмотр таблиц, записанных в памяти программ. Любой байт из таблицы может быть выбран по адресу, определяемому содержимым аккумулятора А, например:

   MOVP3 A, @A

Непосредственная адресация позволяет выбрать из адресного пространства памяти программ константы, явно указанные в команде, например:

   MOV A, #11h     ;помещает в аккумулятор число 11h
   MOV R5, #48     ;помещает в регистр R5 число 48


Состав семейства MCS-48

 Rambler's Top100 Дата последнего обновления файла 29.03.05

Состав семейства MCS-48

Микроконтроллеры этого семейства явились одним из первых представителей однокристальных ЭВМ - микроконтроллеров. Первоначально фирмой Intel была разработана микросхема 8048, на основе модификации которой и было построено всё семейство микроконтроллеров. В структуре этого микроконтроллера явно прослеживается наследие от микропроцессора 8085 (отечественный аналог 1821ВМ85). Отечественная промышленность тоже выпускала микроконтроллеры этого семейства. Производство микроконтроллера 8048 осуществлялось в Новосибирске (КР1816ВЕ48, КР1816ВЕ49, КР1816ВЕ35, 1850ВЕ49). В таблице 1 приведены параметры этих микросхем.

Таблица 1. Микросхемы, входящие в состав семейства MCS-48

Микроконтроллер | ОЗУ | ПЗУ | Таймер | Fт | порты | системная шина
8048 | 64 байт | 1К байт | 1 | 6 | 2 | есть
8049 | 128 байт | 2К байт | 1 | 11 | 2 | есть
8035 | 64 байт | - | 1 | 11/6 | 2 | есть
КР1816ВЕ48 | 64 байт | 1К байт | 1 | 6 | 2 | есть
КР1816ВЕ49 | 128 байт | 2К байт | 1 | 11 | 2 | есть
КР1816ВЕ35 | 64 байт | - | 1 | 11/6 | 2 | есть
КР1850ВЕ49 | 256 байт | 2К байт | 1 | 11 | 2 | есть

Удачный набор периферийных устройств, возможность гибкого выбора внешней или внутренней программной памяти и приемлемая цена обеспечили популярность этому микроконтроллеру успех. К сожалению недостаточное количество параллельных портов и малые возможности внутреннего таймера привели к тому, что это семейство было быстро вытеснено семейством микроконтроллеров MCS-51.

Недостаточный объём внутренней памяти, как показал успех PIC-контроллеров фирмы microchip, не являлся определяющим в том, что это семейство микроконтроллеров исчезло с рынка. Возможно большую роль сыграло нежелание фирмы Intel снижать цены на свою продукцию. Стоимость отечественных микросхем семейства MCS-48 и MCS-51 практически не различались, поэтому естественно разработчики как только появилась возможность перешли на использование микроконтроллеров семейства MCS-51.


Устройство таймера микроконтроллеров MCS-48

 Rambler's Top100 Дата последнего обновления файла 29.03.05

Устройство таймера микроконтроллера MCS-48

В микроконтроллерах семейства MCS-48 внутренний таймер может быть использован как в режиме таймера так и в режиме счетчика внешних событий.

Режим таймера

Таймер состоит из пятиразрядного предварительного делителя на 32 и восьмиразрядного суммирующего счётчика. На вход предделителя поступают сигналы основной синхронизации ALE с периодом 2,5 мкс (15 периодов задающего генератора тактовой частоты). Таким образом минимальный промежуток времени, задаваемый при помощи таймера равен 80 мкс. Путём предварительной записи информации в таймер можно регулировать время, задаваемое таймером от 80 мкс до 20,48 мс. Эти значения определяются тем, что в таймер T можно записать 256 различных чисел. Если требуется больший временной интервал, то его можно получить программным путём с использованием любой ячейки внутренней памяти. Схема таймера приведена на рисунке 1.

Рисунок 1. Схема таймера микроконтроллеров семейства MCS-48.

Когда содержимое счетчика изменяется из состояния все "1" в состояние все "0" , то устанавливается (принимает значение "1") флаг прерывания таймера TF0 или TF1.

Обычно пользователя интересует не максимальный интервал времени, а свой конкретный интервал времени, меньший максимально возможного. Для уменьшения интервала времени в регистр таймера можно предварительно занести число и тем самым сформировать произвольный интервал времени. Рассмотрим пример подготовки таймера T для формирования временного интервала 5мс.

;Настроить таймер на генерацию 5-ти миллисекундного интервала времени--------------------------------------
    mov A, #-62             ;Загрузить таймер числом 9Eh, равным числу -62 - количество периодов
    mov T, A                ;входной частоты таймера (62 периода таймера = 62*80 мкс =  4,96 мс)

    STRT T                  ;Запустить таймер

OjidanTimer:
    JTF   SledKomanda       ;Подождать пока не переполнится таймер
    JMP  OjidanTimer
SledKomanda:
  STOP TCNT                 ;Остановить таймер

Режим счётчика

В режиме счетчика содержимое счетчика инкрементируется под воздействием перехода из 1 в 0 внешнего входного сигнала, подаваемого на вывод микроконтроллера T1. Так как на распознавание периода требуются три машинных цикла то, минимальное время между импульсами равно 7,5 мкс. Минимальная длительность единичного сигнала на входе T1 при частоте кварцевого резонатора 6 МГц равна 0,5 мкс. На длительность периода входных сигналов ограничений сверху нет.

Запуск счётчика осуществляется командой STRT CNT, а остановка STOP TCNT. Количество подсчитанных импульсов можно считать командой MOV A, T.


Описание команд микроконтроллеров семейства MCS-51

 Дата последнего обновления файла 07.06.2005

Описание машинных команд.

ACALL <addr 11> - абсолютный вызов подпрограммы.

Описание: вызывает подпрограмму, размещенную по указанному адресу <addr 11>. Команда увеличивает содержимое счетчика команд на 2 и затем помещает полученный результат в стек (младший байт первым). После это содержимое указателя стека SP увеличивается на 2. Т.к. в команде используется 11-разрядный адрес, полученный соединением пяти старших бит счетчика команд и второго байта команды, то подпрограмма должна начинаться в пределах той же 2K-байтной страницы. Команда не воздействует на флаги.

Количество байт: 2
Количество циклов: 2
Действие команды:
(PC) = (PC) + 2
(SP) = (SP) + 1
((SP)) = (PC7-0)
(SP) = (SP) + 1
((SP)) = (PC15-8)
(PC10-0) = адрес подпрограммы (метки)
Машинный код:

a10 a9 a8  1  0  0  0  1
a7  a6 a5 a4 a3 a2 a1 a0

Пример:

адрес   команда   исходный текст
1000    7111      ACALL 311h

Действие команды:

до команды    после команды
PC=1000       PC=0311
*SP=35        *SP=1002

ADD A, <байт-источник> - сложение.

Описание: складывает содержимое аккумулятора А с содержимым байта- источника. Результат операции помещается в аккумулятор. Флаг переноса C устанавливается при переносе из 7го разряда. Флаг вспомогательного переноса AC устанавливается при переносе из 3го разряда. При сложении знаковых чисел флаг переполнения OV устанавливается при превышении максимального положительного числа или при получении числа меньшего минимально возможного.

Для команды сложения разрешены следующие режимы адресации:

1) Первый операнд - неявная, второй операнд - регистровая;

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + (Rn) , n=0,1,2,3,4,5,6,7
Машинный код:

0 0 1 0 1 r r r

Пример:

адрес   команда   исходный текст
0000    2F        ADD A, R7

Действие команды:

до команды    после команды
PC=0000       PC=0001
A=35          A=7A
R7=46         R7=46
C=0           C=0

2) Первый операнд - неявная, второй операнд - косвенно-регистровая;

Количество байт: 1
Количество циклов: 1
Действие команды:
(PC) = (PC) + 1
(A) = (A) + ((Ri)) , i=0,1
Машинный код:

0 0 1 0 0 1 1 i

Пример:

адрес   команда   исходный текст
0010    26        ADD A, @R0

Действие команды:

до команды    после команды
PC=0010       PC=0011
R0=15         R0=15
A=95          A=16
*15=81       *15=81
C=0           C=1

3) Первый операнд - неявная, второй операнд - прямая;

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (A) + (direct)
Машинный код:

0 0 1 0 0 1 0 1
d d d d d d d d

Пример:

адрес   команда   исходный текст
0012    2564      ADD A, 100

Действие команды:

до команды    после команды
PC=0012       PC=0014
A=95          A=96
*100=01       *100=81
C=1           C=0

4) Первый операнд - неявная, второй операнд - непосредственная.

Пример: ADD A, #38h

Количество байт: 2
Количество циклов: 1
Действие команды:
(PC) = (PC) + 2
(A) = (A) + (date 8)
Машинный код:

0 0 1 0 0 1 0 0
i i i i i i i i

Пример:

адрес   команда   исходный текст
0014    2564      ADD A, #38h

Действие команды:

до команды    после команды
PC=0014       PC=0016
A=95          A=CD
C=1           C=0

ADDC A, <байт-источник> - сложение с учетом переноса.

Описание: складывает содержимое аккумулятора А с содержимым байта-источника, к получившемуся результату прибавляется значение флага переноса. Результат операции помещается в аккумулятор. Флаг переноса C устанавливается при переносе из 7го разряда. Флаг вспомогательного переноса AC устанавливается при переносе из 3го разряда. При сложении знаковых чисел флаг переполнения OV устанавливается при превышении максимального положительного числа или при получении числа меньшего минимально возможного. Для команды сложения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: ADDC A, R3

Количество байт: 1

Количество циклов: 1

Действие команды:

(PC) = (PC) + 1

(A) = (A) + (C) + (Rn) , n=0, : ,7

Машинный код: 0 0 1 1 1 r r r

  • косвенно-регистровая;

Пример: ADDC A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды:

(PC) = (PC) + 1

(A) = (A) + (C) + ((Ri)) , i=0,1

Машинный код: 0 0 1 1 0 1 1 i

  • прямая;

Пример: ADDC A, 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (A) + (C) + (direct)

Машинный код:

0 0 1 1 0 1 0 1

d d d d d d d d

  • непосредственная.

Пример: ADDC A, #100

Количество байт: 2

Количество циклов: 1

Действие команды:

(PC) = (PC) + 2

(A) = (A) + (C) + (date 8)

Машинный код:

0 0 1 1 0 1 0 0

i i i i i i i i

AJMP <addr 11> - абсолютный переход в пределах 2K-байтной страницы.

Описание: передает управление команде, размещенной по указанному адресу <addr 11>. Команда увеличивает содержимое счетчика команд на 2 и затем заменяет младший байт счетчика команд на содержимое второго байта команды. Три младших бита старшего байта заменяются тремя старшими битами первого байта команды. Т.к. в команде используется 11- разрядный адрес, то адрес перехода должен начинаться в пределах той же 2K-байтной страницы памяти программ.

Пример: AJMP 1024

Количество байт: 2

Количество циклов: 2

Действие команды:

(PC) = (PC) + 2

(PC10-0) = адрес метки

Машинный код:

a10 a9 a8 0 0 0 0 1

a7 a6 a5 a4 a3 a2 a1 a0

ANL <байт приемник>,<байт источник> - команда "логическое И" для байтовых переменных.

Описание: выполняет операцию побитового "логического И" над указанными переменными и помещает результат в байт приемник. Команда не воздействует на флаги.

Для команды ANL с аккумулятором в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: ANL A, R3

Количество байт: 1

Количество циклов: 1

Действие команды:

(PC) = (PC) + 1

(A) = (A) & (Rn) , n=0,1,2,3,4,5,6,7

Машинный код: 0 1 0 1 1 r r r

  • косвенно-регистровая;

Пример: ANL A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды:

(PC) = (PC) + 1

(A) = (A) & ((Ri)) , i=0,1

Машинный код: 0 1 0 1 0 1 1 i

  • прямая;

Пример: ANL A, 30h

Количество байт: 2

Количество циклов: 1

Действие команды:

(PC) = (PC) + 2

(A) = (A) & (direct)

Машинный код:

0 1 0 1 0 1 0 1

d d d d d d d d

  • непосредственная.

Пример: ANL A, #100

Количество байт: 2

Количество циклов: 1

Действие команды:

(PC) = (PC) + 2

(A) = (A) & (date 8)

Машинный код:

0 1 0 1 0 1 0 0

i i i i i i i i

Для команды ANL с произвольным адресом ячейки внутренней памяти данных в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • прямая;

Пример: ANL 30h,A

Количество байт: 2

Количество циклов: 1

Действие команды:

(PC) = (PC) + 2

(direct) = (A) & (direct)

Машинный код:

0 1 0 1 0 0 1 0

d d d d d d d d

  • непосредственная.

Пример: ANL direct, #100

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(direct) = (A) & (date 8)

Машинный код:

0 1 0 1 0 0 1 1

d d d d d d d d

i i i i i i i i

Примечание: при выполнении команды ANL над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

ANL C,<бит источника> - "логическое И" битовой переменной и флага переноса C.

Описание: Если бит источника равен 0, то происходит сброс флага переноса, в противном случае флаг переноса не изменяет текущего значения. На остальные флаги команда не воздействует.

  • прямая;

Пример: ANL С, 20h

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(C) = (C) & (bit)

Машинный код:

0 1 0 1 0 0 1 0

b b b b b b b b

Знак '/' перед операндом в языке ассемблера указывает на то, что в качестве значения используется логическое отрицание адресуемого бита, при этом сам бит источника не изменяется.

CJNE <байт назначения>,<байт источника>,<смещение> - сравнение и переход, если не равно.

Описание: сравнивает значения первых двух операндов и выполняет переход, если операнды не равны. Если значение байта назначения без учета знака меньше байта источника без учета знака, то флаг переноса C устанавливается в '1', иначе сбрасывается в '0'. Ни один из операндов после выполнения команды не изменяется. Новое значение программного счетчика при переходе вычисляется суммирование содержимого программного счетчика со вторым операндом (третьим байтом команды). Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака третьего байта команды, представленного в дополнительном коде.

Первые два операнда допускают четыре вида адресации:

  1. байт назначения - аккумулятор
  • прямая;

Пример: CJNE A, 30h, 15; direct=30h, rel=15

Количество байт: 3

Количество циклов: 2

Действие команды:

(PC) = (PC) + 3

IF (A) < > (direct) THEN

(PC) = (PC) + rel

IF (A) < (direct) THEN

(C) = 1

ELSE

(C) = 0

Машинный код:

1 0 1 1 0 1 0 1

d d d d d d d d

R e l A d r e s

  • непосредственная.

Пример: CJNE A, #100, -78; data=100, rel=-78

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

IF (A) < > data THEN

(PC) = (PC) + rel

IF (A) < data THEN

(C) = 1

ELSE

(C) = 0

Машинный код:

1 0 1 1 0 1 0 0

i i i i i i i i

R e l A d r e s

  2. байт назначения - ячейка ОЗУ с косвенно-регистровой или регистровой адресацией
  • непосредственная к регистровой

Пример: CJNE R5, #100, 78; Rn=R5 data=100, rel=78

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

IF (Rn) < > data THEN

(PC) = (PC) + rel

IF (Rn) < data THEN

(C) = 1

ELSE

(C) = 0

Машинный код:

1 0 1 1 1 r r r

i i i i i i i i

R e l A d r e s

  • непосредственная к косвенно - регистровой

Пример: CJNE @R0, #100, 78; Ri=R0 data=100, rel=78

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

IF ((Ri)) < > data, i=0,1 THEN

(PC) = (PC) + rel

IF ((Ri)) < data, i=0,1 THEN

(C) = 1

ELSE

(C) = 0

Машинный код:

1 0 1 1 0 1 1 i

i i i i i i i i

R e l A d r e s

CLR A - сброс аккумулятора

Описание: сбрасывает (записывает '0' во все биты аккумулятора). Команда не изменяет содержимое флагов.

Пример: CLR A ;Записывает в аккумулятор число 00h

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = 0

Машинный код:

1 1 1 0 0 1 0 0

CLR <bit> - сбрасывает указанный бит в нуль.

Описание: сбрасывает (записывает '0') в указанный во втором байте команды бит. Команда не изменяет содержимое флагов.

Пример: CLR C ;Записывает во флаг переноса '0'

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(C) = 0

Машинный код:

1 1 0 0 0 0 1 1

  • прямая битовая адресация;

Пример: CLR P1.2 ;Записывает во второй бит порта 1 '0'

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(bit) = 0

Машинный код:

1 1 0 0 0 0 1 0

b b b b b b b b

CPL A - каждый бит аккумулятора инвертируется.

Описание: каждый бит аккумулятора инвертируется, т.е. если в каком-либо из восьми бит аккумулятора записана '1', то в этот бит записывается '0' и наоборот.

Пример: CPL A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = not(A)

Машинный код: 1 1 1 1 0 1 0 0

CPL <bit> - инвертируется указанный бит.

Описание: бит адрес, которого указан во втором байте команды инвертируется, т.е. если бит содержит '1', то в этот бит записывается '0' и наоборот.

  • прямая битовая адресация;

Пример: CPL 27

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(bit) = not(bit)

Машинный код:

1 0 1 1 0 0 1 0

b b b b b b b b

CPL C - инвертируется флаг переноса 'C'.

Описание: флаг переноса 'C' инвертируется, т.е. если флаг переноса 'C' содержит '1', то в него записывается '0' и наоборот.

Пример: CPL C

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(C) = not(C)

Машинный код: 1 0 1 1 0 0 1 1

DA A - десятичная коррекция аккумулятора при сложении двоично-десятичных чисел.

Описание: команда десятичной коррекции позволяет вести сложение чисел, представленных в упакованном двоично-десятичном коде. Команда применяется после инструкций ADD или ADDC. Инструкции (команды) ADD или ADDC позволяют суммировать сразу две тетрады, расположенные в одном байте.

Если биты аккумулятора с 0 по 3 содержат число большее 9 (xxxx1010:xxxx1111) или флаг вспомогательного переноса AC содержит '1', то к аккумулятору прибавляется число 6 для того, чтобы получить правильную двоично-десятичную цифру в младшей тетраде.

Если старшие биты аккумулятора (с 4 по 7) содержат число большее 9 (1010xxxx :1111xxxx) или флаг переноса C содержит '1', то к аккумулятору прибавляется число 60h для того, чтобы получить правильную двоично-десятичную цифру в старшей тетраде.

Если в результате операции DA A возникнет перенос, то флаг переноса C будет установлен в 1. Единичный флаг переноса после операции DA A означает, что результат суммирования больше 100 и этим можно воспользоваться для суммирования многоразрядных двоично-десятичных чисел. Команда десятичной коррекции не воздействует на флаг переполнения OV.

Примечание: команда DA A не может преобразовать двоичное число из аккумулятора в двоично-десятичный вид или правильно скорректировать двоично-десятичное вычитание.

Пример: DA A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

IF [[(A3-0) > 9] or [(AC) = 1]] THEN

(A3-0) = (A3-0) + 6

AND

IF [[(A7-4) > 9] or [(C) = 1]] THEN

(A7-4) = (A7-4) + 6

Машинный код:

1 1 0 1 0 1 0 0

DEC <байт> - производит вычитание 1 из указанного операнда.

Описание: ячейка памяти адрес, которой указан во втором байте команды уменьшается на 1. Если первоначально в ячейке было записано значение 00h, то в нее заносится значение 0FFh. Команда не воздействует на флаги.

Примечание: при выполнении команды DEC над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

Для команды DEC разрешены следующие режимы адресации байта - источника:

  • непосредственная.

Пример: DEC A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) - 1

Машинный код:

0 0 0 1 0 1 0 0

  • регистровая;

Пример: DEC R3

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(Rn) = (Rn) - 1, n=0,1,2,3,4,5,6,7

Машинный код:

0 0 0 1 1 r r r

  • косвенно-регистровая;

Пример: DEC @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

((Ri)) = ((Ri)) - 1, i=0,1

Машинный код:

0 0 0 1 0 1 1 i

  • прямая;

Пример: DEC 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(direct) = (direct) - 1

Машинный код:

0 0 0 1 0 1 0 1

d d d d d d d d

DIV AB - деление.

Описание: делит 8-битовое беззнаковое целое число из аккумулятора А на 8-битовое целое без знака в регистре В. В аккумулятор A заносится целая часть результата деления, а в регистр В - остаток. Флаги переноса C и переполнения OV будут очищены (записан '0'). Если в регистре B перед операцией деления содержится '0', то в аккумуляторы A и B будут занесены неопределенные значения, а флаг переполнения будет установлен (записана '1').

Количество байт: 1

Количество циклов: 4

Действие команды: (PC) = (PC) + 1

(A) = (A) div (B)

(A) = (A) mod (B)

Машинный код:

0 1 0 0 0 1 0 0

DJNZ <байт>,<смещение> - вычитание 1 из указанной ячейки и переход, если результат не равен 0.

Описание: вычитание 1 из указанной во втором байте команды ячейки памяти и переход к вычисляемому по третьему байту команды адресу, если результат вычитания не равен 0. Если первоначально в ячейке памяти содержится '0', то в результате выполнения операции туда будет записано число '0FFH'. Команда не воздействует на флаги. Новое значение программного счетчика при переходе вычисляется суммирование содержимого программного счетчика со вторым операндом (третьим байтом команды). Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака третьего байта команды, представленного в дополнительном коде.

Примечание: при выполнении команды DJNZ над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

Для команды DJNZ разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: DJNZ R3 ,LABEL1;

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(Rn) = (Rn) - 1, n=0,1,2,3,4,5,6,7

IF (Rn) < > 0, THEN n=0,1,2,3,4,5,6,7

(PC) = (PC) + rel

Машинный код:

1 1 0 1 1 r r r

R e l A d r e s

  • прямая;

Пример: DJNZ 30h,LABEL1;

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(direct) = (direct) - 1

IF (direct) < > 0 THEN

(PC) = (PC) + rel

Машинный код:

1 1 0 1 0 1 0 1

d d d d d d d d

R e l A d r e s

[ Главная ]


Описание команд микроконтроллеров семейства MCS-51

 Дата последнего обновления файла 07.06.2005

Описание машинных команд (продолжение).

INC <байт> - производит прибавление 1 к указанному операнду.

Описание: ячейка памяти адрес, которой указан во втором байте команды увеличивается на 1. Если первоначально в ячейке было записано значение 0FFh, то в нее заносится значение 00h. Команда не воздействует на флаги.

Примечание: при выполнении команды INC над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

Для команды INC разрешены следующие режимы адресации байта - источника:

  • непосредственная.

Пример: INC A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) + 1

Машинный код:

0 0 0 0 0 1 0 0

  • регистровая;

Пример: INC R3

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(Rn) = (Rn) + 1, n=0,1,2,3,4,5,6,7

Машинный код:

0 0 0 0 1 r r r

  • косвенно-регистровая;

Пример: INC @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

((Ri)) = ((Ri)) + 1, i=0,1

Машинный код:

0 0 0 0 0 1 1 i

  • прямая;

Пример: INC 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(direct) = (direct) + 1

Машинный код:

0 0 0 0 0 1 0 1

d d d d d d d d

INC DPTR - увеличивает на 1 содержимое указателя данных.

Описание: увеличивает на 1 содержимое 16-разрядного указателя данных. Если первоначально в младшем байте DPTR (ячейка DPL) было записано значение 0FFh, то в него заносится значение 00h и увеличивается на 1 содержимое старшего байта DPTR (ячейка DPH). Команда не воздействует на флаги.

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

(DPTR) = (DPTR) + 1

Машинный код:

0 1 0 1 0 0 1 1

JB <bit>,<rel8> - переход если бит установлен.

Описание: Если указанный во втором байте команды бит равен единице, то производится переход к вычисляемому по третьему байту команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммирование содержимого программного счетчика со вторым операндом (третьим байтом команды). Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака третьего байта команды, представленного в дополнительном коде. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

  • прямая битовая адресация;

Пример: JB 30h, LABEL1

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

IF (bit) = 1

THEN

(PC) = (PC) + rel

Машинный код:

0 0 1 0 0 0 0 0

b b b b b b b b

R e l A d r e s

JBC <bit>,<rel8> - переход, если бит установлен и сброс этого бита.

Описание: Если указанный во втором байте команды бит равен единице, то производится переход к вычисляемому по третьему байту команды адресу. Бит не очищается, если он уже содержит ноль. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммированием содержимого программного счетчика со вторым операндом (третьим байтом команды). Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака третьего байта команды, представленного в дополнительном коде. Команда не воздействует на флаги.

  • прямая битовая адресация;

Пример: JBС 78h, LABEL1

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

IF (bit) = 1 THEN

(bit) = 0

(PC) = (PC) + rel

Машинный код:

0 0 0 1 0 0 0 0

b b b b b b b b

R e l A d r e s

JC <rel8> - переход, если бит переноса установлен.

Описание: Если бит переноса равен единице, то производится переход к вычисляемому по второму байту команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммированием содержимого программного счетчика со вторым байтом команды. Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака второго байта команды, представленного в дополнительном коде. Команда не воздействует на флаги.

Пример: JС LABEL1

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

IF (С) = 1 THEN

(PC) = (PC) + rel

Машинный код: 0 1 0 0 0 0 0 0

R e l A d r e s

JMP @A+DPTR - косвенный переход.

Описание: складывает 8- битовое содержимое аккумулятора без учета знака с 16- битовым указателем данных (DPTR) и загружает полученный результат в счетчик команд. Это будет адрес следующей исполняемой команды. Команда не воздействует на флаги.

Пример:

MOV DPTR, #JMP_TBL

JMP @A+DPTR

JMP_TBL: AJMP LABEL0

AJMP LABEL1

AJMP LABEL2

AJMP LABEL3

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (A) + (DPTR)

Машинный код:

0 1 1 1 0 0 1 1

JNB <bit>, <rel8> - переход если бит сброшен.

Описание: Если указанный во втором байте команды бит равен нолю, то производится переход к вычисляемому по третьему байту команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммирование содержимого программного счетчика со вторым операндом (третьим байтом команды). Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака третьего байта команды, представленного в дополнительном коде. Команда не воздействует на флаги и не изменяет содержимое проверяемого бита.

  • прямая битовая адресация;

Пример: JNB P1.3, LABEL1

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

IF (bit) = 0 THEN

(PC) = (PC) + rel

Машинный код:

0 0 1 1 0 0 0 0

b b b b b b b b

R e l A d r e s

JNC <rel8> - переход, если бит переноса сброшен.

Описание: Если бит переноса равен нолю, то производится переход к вычисляемому по второму байту команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммированием содержимого программного счетчика со вторым байтом команды. Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака второго байта команды, представленного в дополнительном коде. Команда не воздействует на флаги.

Пример: JNС LABEL1

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

IF (С) = 0 THEN

(PC) = (PC) + rel

Машинный код:

0 1 0 1 0 0 0 0

R e l A d r e s

JNZ <rel8> - переход, если содержимое аккумулятора не равно нулю.

Описание: Если любой бит аккумулятора равен единице, то производится переход к вычисляемому по второму байту команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммированием содержимого программного счетчика со вторым байтом команды. Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака второго байта команды, представленного в дополнительном коде. Содержимое аккумулятора не изменяется. Команда не воздействует на флаги.

Пример: JNZ LABEL1

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

IF (A) <> 0 THEN

(PC) = (PC) + rel

Машинный код:

0 1 1 1 0 0 0 0

R e l A d r e s

JZ <rel8> - переход, если содержимое аккумулятора равно.

Описание: Если все биты аккумулятора равны нулю, то производится переход к вычисляемому по второму байту команды адресу. В противном случае выполняется следующая команда. Новое значение программного счетчика при переходе вычисляется суммированием содержимого программного счетчика со вторым байтом команды. Перед выполнением суммирования в программный счетчик заносится адрес первого байта следующей команды. Суммирование производится с учетом знака второго байта команды, представленного в дополнительном коде. Содержимое аккумулятора не изменяется. Команда не воздействует на флаги.

Пример: JZ LABEL1

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

IF (A) = 0 THEN

(PC) = (PC) + rel

Машинный код:

0 1 1 0 0 0 0 0

R e l A d r e s

LCALL <addr 16> - дальний вызов подпрограммы.

Описание: вызывает подпрограмму, размещенную по указанному адресу <addr 16>. Команда увеличивает содержимое счетчика команд на 3 и помещает полученный результат в стек (младший байт первым). После этого содержимое указателя стека SP увеличивается на 2. Затем старший и младший байты счетчика команд PC загружаются вторым и третьим байтами команды LCALL соответственно. Выполнение программы продолжается с команды, расположенной с этого адреса. Команда не воздействует на флаги.

Пример: LCALL Podprogramma

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(SP) = (SP) + 1

((SP)) = (PC7-0)

(SP) = (SP) + 1

((SP)) = (PC15-8)

(PC15-0) = адрес подпрограммы (метки)

Машинный код:

0 0 0 1 0 0 1 0

а15 a14 a13 a12 a11 a10 a9 a8

a7 a6 a5 a4 a3 a2 a1 a0

LJMP <addr 16> - дальний переход.

Описание: передает управление команде, размещенной по указанному адресу <addr 16> загрузкой старшего и младшего байтов счетчика команд PC вторым и третьим байтами команды LJMP соответственно. Команда позволяет передавать управление в любую точку адресного пространства. Команда не воздействует на флаги.

Пример: LJMP Label

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(PC15-0) = адрес метки

Машинный код:

0 0 0 0 0 0 1 0

а15 a14 a13 a12 a11 a10 a9 a8

a7 a6 a5 a4 a3 a2 a1 a0

MOV <байт приемник>,<байт-источник> - переслать байтовую переменную.

Описание: переменная, указанная во втором операнде, копируется в ячейку, указываемую первым операндом. Байт источник не изменяется. Другие регистры и флаги не изменяются.

Команда допускает 15 комбинаций адресации байта- источника и байта приемника:

  • регистровая;

Пример: MOV A, R3

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (Rn) , n=0,1,2,3,4,5,6,7

Машинный код:

1 1 1 0 1 r r r

  • косвенно-регистровая;

Пример: MOV A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = ((Ri)) , i=0,1

Машинный код:

1 1 1 0 0 1 1 i

  • прямая;

Пример: MOV A, 100

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (direct)

Машинный код:

1 1 1 0 0 1 0 1

d d d d d d d d

  • непосредственная.

Пример: MOV A, #38h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (data 8)

Машинный код: 0 1 1 1 0 1 0 0

i i i i i i i i

  • регистровая;

Пример: MOV R3, A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(Rn) = (A) , n=0,1,2,3,4,5,6,7

Машинный код: 1 1 1 1 1 r r r

  • прямая к регистровой;

Пример: MOV R3, 120

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(Rn) = (direct) , n=0,1,2,3,4,5,6,7

Машинный код:

1 0 1 0 1 r r r

d d d d d d d d

  • непосредственная к регистровой;

Пример: MOV R3, 120

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(Rn) = (data 8) , n=0,1,2,3,4,5,6,7

Машинный код:

0 1 1 1 1 r r r

i i i i i i i i

  • прямая;

Пример: MOV 20, A

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(direct) = (A)

Машинный код:

1 1 1 1 0 1 0 1

d d d d d d d d

  • регистровая к прямой;

Пример: MOV 59, R5

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(direct) = (Rn), n=0,1,2,3,4,5,6,7

Машинный код: 1 0 0 0 1 r r r

d d d d d d d d

  • прямая к прямой;

Пример: MOV 20, 80

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(direct) = (direct)

Машинный код: 1 0 0 0 0 1 0 1

d d d d d d d d (источник)

d d d d d d d d (приемник)

  • косвенно-регистровая к прямой;

Пример: MOV 35, @R0

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(direct) = ((Ri)), i=0,1

Машинный код:

1 0 0 0 0 1 1 i

d d d d d d d d

  • непосредственная к прямой;

Пример: MOV 31, #120

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(direct) = (data 8)

Машинный код:

0 1 1 1 0 1 0 1

d d d d d d d d

i i i i i i i i

  • косвенно-регистровая;

Пример: MOV @R0, A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

((Ri)) = (A), i=0,1

Машинный код:

1 1 1 1 0 1 1 i

  • прямая к косвенно- регистровой;

Пример: MOV @R0, 80

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

((Ri)) = (direct), i=0,1

Машинный код:

1 0 1 0 0 1 1 i

d d d d d d d d

  • непосредственная к косвенно-регистровой;

Пример: MOV @R0, #80

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

((Ri)) = (direct), i=0,1

Машинный код:

0 1 1 1 0 1 1 i

i i i i i i i i

MOV <бит приемник>,<бит- источник> - переслать битовую переменную.

Описание: переменная, указанная во втором операнде, копируется по адресу, указываемом первым операндом. Бит источник не изменяется. Одним битом обязательно должен быть флаг переноса C, другим битом может быть любой прямо адресуемый бит. Другие регистры и флаги не изменяются.

  • прямая битовая адресация;

Пример: MOV C, 87

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(C) = (bit)

Машинный код:

0 1 0 1 0 0 1 0

b b b b b b b b

Пример: MOV 87, C

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(bit) = (C)

Машинный код:

1 0 0 1 0 0 1 0

b b b b b b b b

MOV DPTR, #data16 - загрузить указатель данных DPTR 16-битной константой.

Описание: загружает указатель данных DPTR 16- битной константой. Команда не воздействует на флаги.

  • непосредственная.

Пример: MOV DPTR, #Label

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(DPTR) = (data16)

Машинный код:

1 0 0 1 0 0 0 0

i15 i14 i13 i12 i11 i10 i9 i8

i7 i6 i5 i4 i3 i2 i1 i0

MOVC A, @A+(<R16>) - переслать байт из памяти программ.

Описание: загружает аккумулятор константой из памяти программ. Адрес считываемого байта вычисляется как сумма 8-битного исходного содержимого аккумулятора без знака и содержимого 16-битного регистра. В качестве 16- битового регистра может быть использован либо указатель данных DPTR, либо счетчик команд РС При использовании программного счетчика его содержимое перед суммированием увеличивается на 1. Команда не воздействует на флаги.

  • косвенно-регистровая;

Пример: MOVC A, @A+DPTR

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

(A) = ((A)+(DPTR))

Машинный код:

1 0 0 1 0 0 1 1

  • косвенно-регистровая;

Пример: MOVC A, @A+PC

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

(A) = ((A)+(PC))

Машинный код:

1 0 0 0 0 0 1 1

MOVX <байт приемник>,<байт источник> - переслать байтовую переменную во внешнюю память (из внешней памяти)

Описание: пересылает данные между аккумулятором и байтом внешней памяти. Имеется два типа команд, которые отличаются тем, что обеспечивают 8-битный или 16-битный доступ к внешней памяти данных.

В первом случае регистр R0 или R1 текущего банка регистров обеспечивает 8- битный адрес, который мультиплексируется с данными на выводах порта P0.

Во втором случае, при выполнении команды 16- битный адрес, берется из указателя данных DPTR. При этом через порт P2 выводятся старшие 8 бит адреса, а через порт P0 младшие 8 бит адреса, мультиплексируемые с байтом данных. Команда не воздействует на флаги.

  • косвенно-регистровая;

Пример: MOVX A, @Ri

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

(A) = ((Ri)), i=0,1

Машинный код:

1 1 1 0 0 0 1 i

  • косвенно-регистровая;

Пример: MOVX A, @DPTR

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

(A) = ((DPTR))

Машинный код:

1 1 1 0 0 0 0 0

  • косвенно-регистровая;

Пример: MOVX @Ri, A

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

((Ri)) = (A), i=0,1

Машинный код:

1 1 1 1 0 0 1 i

  • косвенно-регистровая;

Пример: MOVX @DPTR, A

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 1

((DPTR)) = (A)

Машинный код:

1 1 1 1 0 0 0 0

[ Главная ]


Описание команд микроконтроллеров семейства MCS-51

 Дата последнего обновления файла 07.06.2005

Описание машинных команд (продолжение).

MUL AB - умножение.

Описание: перемножает целые восьмибитовые беззнаковые числа, хранящиеся в аккумуляторе и регистре В. Старший байт 16-битового произведения помещается в регистр В, а младший байт - в регистр А.

Пример: MUL AB

Количество байт: 1

Количество циклов: 4

Действие команды: (PC) = (PC) + 1

(A) = Low((A)*(B))

(B) = High(A)*(B)

Машинный код:

1 0 1 0 0 1 0 0

NOP - нет операции

Описание: Кроме программного счетчика не изменяет ни одного регистра, на флаги не воздействует.

Пример: NOP

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

Машинный код:

0 0 0 0 0 0 0 0

ORL <байт приемник>,<байт источник> - "логическое ИЛИ" для байтовых переменных

Описание: выполняет операцию побитового "логического ИЛИ" между указанными переменными. Результат сохраняется в приемнике. Команда не воздействует на флаги.

Для команды ORL с аккумулятором в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: ORL A, R3

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) V (Rn) , n=0,1,2,3,4,5,6,7

Машинный код:

0 1 0 0 1 r r r

  • косвенно-регистровая;

Пример: ORL A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) V ((Ri)), i=0,1

Машинный код:

0 1 0 0 0 1 1 i

  • прямая;

Пример: ORL A, 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (A) V (direct)

Машинный код:

0 1 0 0 0 1 0 1

d d d d d d d d

  • непосредственная.

Пример: ORL A, #100

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (A) V (date 8)

Машинный код:

0 1 0 0 0 1 0 0

i i i i i i i i

Для команды ORL с произвольным адресом ячейки внутренней памяти данных в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • прямая;

Пример: ORL 30h,A

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(direct) = (A) V (direct)

Машинный код: 0 1 0 0 0 0 1 0

d d d d d d d d

  • непосредственная.

Пример: ORL direct, #100

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(direct) = (A) V (date 8)

Машинный код:

0 1 0 0 0 0 1 1

d d d d d d d d

i i i i i i i i

Примечание: при выполнении команды ORL над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

ORL C,<бит источника> - логическое ИЛИ битовых переменных.

Описание: Если бит источника равен 1, то происходит запись во флаг переноса единицы, в противном случае флаг переноса не изменяет текущего значения. На остальные флаги команда не воздействует.

  • прямая битовая адресация;

Пример: ORL С, 20h

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(C) = (C) V (bit)

Машинный код:

0 1 1 1 0 0 1 0

b b b b b b b b

Знак '/' перед операндом в языке ассемблера указывает на то, что в качестве значения используется логическое отрицание адресуемого бита, при этом сам бит источника не изменяется.

  • прямая битовая адресация;

Пример: ORL С, /20h

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(C) = (C) V not(bit)

Машинный код:

1 0 1 0 0 0 0 0

b b b b b b b b

РОР <direct> - чтение из стека.

Описание: Считывает содержимое ячейки внутренней памяти, на которую указывает регистр указателя стека, после этого содержимое указателя стека уменьшается на 1. Считанная величина помещается во внутреннюю память по адресу, указанному во втором байте команды.

  • прямая;

Пример: POP 30h

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(direct) = ((SP))

(SP) = (SP) - 1

Машинный код:

1 1 0 1 0 0 0 0

d d d d d d d d

PUSH <direct> - запись в стек.

Описание: Содержимое указателя стека увеличивается на 1. Содержимое ячейки внутренней памяти по адресу, указанному во втором байте команды копируется в ячейку внутренней памяти, на которую указывает регистр указателя стека.

  • прямая;

Пример: PUSH 30h

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

((SP)) = (direct)

(SP) = (SP) + 1

Машинный код:

1 1 0 0 0 0 0 0

d d d d d d d d

RET - возврат из подпрограммы.

Описание: последовательно выгружает старший и младший байты счетчика команд из стека, уменьшая содержимое указателя стека на 2. Выполнение программы продолжается с нового, только что загруженного в счетчик команд адреса. Команда не воздействует на флаги.

Пример: RET

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(PC15-8) = ((SP))

(SP) = (SP) - 1

(PC7-0) = ((SP))

SP) = (SP) - 1

Машинный код: 0 0 1 0 0 0 1 0=

RETI - возврат из подпрограммы обслуживания прерывания.

Описание: последовательно выгружает старший и младший байты счетчика команд из стека, уменьшая содержимое указателя стека на 2. Кроме того, команда восстанавливает состояние логики прерываний, разрешая обработку следующего прерывания того же уровня приоритета. Выполнение программы продолжается с того же адреса, что был в программном счетчике (PC) до начала обработки прерывания (следующий за командой, во время выполнения которой был обнаружен запрос на прерывание). Команда не воздействует на флаги и не восстанавливает состояние PSW, бывшее до обработки прерывания. Если к этому моменту обнаруживается новый запрос на прерывание, то до нового вызова подпрограммы обслуживания прерывания выполняется одна команда из основной программы.

Пример: RETI

Количество байт: 1

Количество циклов: 2

Действие команды: (PC) = (PC) + 2

(PC15-8) = ((SP))

(SP) = (SP) - 1

(PC7-0) = ((SP))

(SP) = (SP) - 1

Машинный код:

0 0 1 1 0 0 1 0

RL A - сдвиг содержимого аккумулятора влево.

Описание: сдвигает восемь бит аккумулятора на один бит влево, бит 7 засылается на место бита 0. Команда не воздействует на флаги.

Пример: RL A

Количество байт: 1

Количество циклов: 1

Действие команды: (An+1) = (An) n=0..6

(A0) = (A7)

Машинный код:

0 0 1 0 0 0 1 1

RLC A - сдвиг содержимого аккумулятора влево через флаг переноса.

Описание: сдвигает восемь бит аккумулятора и флаг переноса на один бит влево. Содержимое флага переноса помещается на место бита 0 аккумулятора, а содержимое бита 7 аккумулятора переписывается во флаг переноса. На остальные флаги команда не воздействует.

Пример: RLC A

Количество байт: 1

Количество циклов: 1

Действие команды: (An+1) = (An) n=0..6

(A0) = (C)

(C) = (A7)

Машинный код:

0 0 1 1 0 0 1 1

RR A - сдвиг содержимого аккумулятора вправо.

Описание: сдвигает восемь бит аккумулятора на один бит вправо, бит 0 засылается на место бита 7. Команда не воздействует на флаги.

Пример: RR A

Количество байт: 1

Количество циклов: 1

Действие команды: (An) = (An+1) n=0..6

(A7) = (A0)

Машинный код: 0 0 0 0 0 0 1 1

RRC A - сдвиг содержимого аккумулятора через флаг переноса.

Описание: сдвигает восемь бит аккумулятора и флаг переноса на один бит вправо. Содержимое флага переноса помещается на место бита 7 аккумулятора, а содержимое бита 0 аккумулятора переписывается во флаг переноса. На остальные флаги команда не воздействует.

Пример: RRC A

Количество байт: 1

Количество циклов: 1

Действие команды: (An) = (An+1) n=0..6

(A7) = (C)

(C) = (A0)

Машинный код:

0 0 0 1 0 0 1 1

SETB <bit> - установить бит.

Описание: устанавливает указанный бит в 1. Команда может воздействовать на флаг переноса или любой другой прямо адресуемый бит. На остальные флаги команда не воздействует.

Пример: SETB C

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(C) = 1

Машинный код:

1 1 0 1 0 0 1 1

Пример: SETB 27

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(bit) = 1

Машинный код:

1 1 0 1 0 0 1 0

b b b b b b b b

SJMP <rel8> - короткий переход

Описание: команда выполняет безусловный относительный короткий переход по указанному адресу. Адрес назначения вычисляется суммированием второго байта команды и программного счетчика предварительно увеличенного на два. Т.е. переход может осуществляться на метку, стоящую на 128 байт выше команды, следующей за SJMP и 127 байт ниже.

Пример: SJMP Label

Количество байт: 2

Количество циклов: 2

Действие команды: (PC) = + 2

(PC) = (PC) + rel8

Машинный код:

1 0 0 0 0 0 0 0

R e l A d r e s

SUBB A,<байт источник> - вычитание с заемом.

Описание: команда вычитает указанную переменную вместе с флагом переноса из содержимого аккумулятора, результат помещается в аккумулятор. SUBB устанавливает флаг переноса C, если требуется заем для 7 бита, и обнуляет его в противном случае. (Если флаг переноса C перед выполнением команды содержал 1, то перенос вычитается из аккумулятора, содержащего операнд источник). Флаг переноса C устанавливается, если требуется заем для 3 бита, и очищается в противном случае. Флаг переполнения OV устанавливается, если требуется заем для 7 бита, но не требуется для 6 или нужен заем для 6 бита, но не требуется для 7. Операнд источника допускает четыре режима адресации:

  • регистровая;

Пример: SUBB A, R7

Количество байт: 1

Количество циклов: 1

Действие команды: (PC)= (PC) + 1

(A) = (A) - (С) - (Rn) , n=0,1,2,3,4,5,6,7

Машинный код:

1 0 0 1 1 r r r

  • косвенно- регистровая;

Пример: SUBB A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) - (С) - ((Ri)) , i=0,1

Машинный код: 1 0 0 1 0 1 1 i

  • прямая;

Пример: SUBB A, 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (A) - (C) - (direct)

Машинный код:

1 0 0 1 0 1 0 1

d d d d d d d d

  • непосредственная.

Пример: SUBB A, #100

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (A) - (C) - (date 8)

Машинный код:

1 0 0 1 0 1 0 0

i i i i i i i i

SWAP A - обмен тетрадами внутри аккумулятора.

Описание: команда осуществляет обмен между младшей (биты 0..3) и старшей (биты 4..7) тетрадами аккумулятора. (Тетрада это четырехбитная переменная). Команду можно интерпретировать как циклический сдвиг на четыре бита. Команда не воздействует на флаги.

Пример: SWAP A

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A3..A0) <=> (A7..A4)

Машинный код:

1 1 0 0 0 1 0 0

XCH A,<байт> - обмен содержимого аккумулятора с переменной байтом.

Описание: команда загружает аккумулятор содержимым указанной переменной, в то же самое время первоначальное содержимое аккумулятора заносится по указанному адресу. Команда не воздействует на флаги.

Допускается три режима адресации:

  • регистровая;

Пример: XCH A, R7

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) <=> (Rn) , n=0,1,2,3,4,5,6,7

Машинный код:

1 1 0 0 1 r r r

  • прямая;

Пример: XCH A, 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) <=> (direct)

Машинный код:

1 1 0 0 0 1 0 1

d d d d d d d d

  • косвенно-регистровая;

Пример: XCH A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC)= (PC) + 1

(A) <=> ((Ri)) , i=0,1

Машинный код:

1 1 0 0 0 1 1 i

XCHD A, @Ri - обмен цифры.

Описание: команда осуществляет обмен между младшей (биты 0..3) тетрадой (тетрада это четырехбитная переменная) аккумулятора, где обычно хранится двоично-десятичная цифра с тетрадой ячейки внутреннего ОЗУ. Используется косвенно регистровая адресация. Старшие тетрады (биты 4..7) обоих операндов не изменяются. Команда не воздействует на флаги.

Пример: XCHD A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A3..A0) <=> ((Ri3..Ri0)) , i=0,1

Машинный код: 1 1 0 1 0 1 1 i

XRL <байт приемник>,<байт источник> - исключающее ИЛИ для переменных байтов.

Описание: выполняет операцию побитового "исключающее логического ИЛИ" между указанными переменными. Результат сохраняется в приемнике. Команда не воздействует на флаги.

Для команды XRL с аккумулятором в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • регистровая;

Пример: XRL A, R3

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) xor (Rn) , n=0,1,2,3,4,5,6,7

Машинный код:

0 1 1 0 1 r r r

  • косвенно- регистровая;

Пример: XRL A, @R0

Количество байт: 1

Количество циклов: 1

Действие команды: (PC) = (PC) + 1

(A) = (A) xor ((Ri)) , i=0,1

Машинный код: 0 1 1 0 0 1 1 i

  • прямая;

Пример: XRL A, 30h

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(A) = (A) xor (direct)

Машинный код:

0 1 1 0 0 1 0 1

d d d d d d d d

  • непосредственная.

Пример: XRL A, #100

Количество байт: 2

Количество циклов: 1

Действие команды: (PC)= (PC) + 2

(A) = (A) xor (date 8)

Машинный код:

0 1 1 0 0 1 0 0

i i i i i i i i

Для команды XRL с произвольным адресом ячейки внутренней памяти данных в качестве байта назначения разрешены следующие режимы адресации байта - источника:

  • прямая;

Пример: XRL 30h,A

Количество байт: 2

Количество циклов: 1

Действие команды: (PC) = (PC) + 2

(direct) = (A) xor (direct)

Машинный код:

0 1 1 0 0 0 1 0

d d d d d d d d

  • непосредственная.

Пример: XRL direct, #100

Количество байт: 3

Количество циклов: 2

Действие команды: (PC) = (PC) + 3

(direct) = (A) xor (date 8)

Машинный код:

0 1 1 0 0 0 1 1

d d d d d d d d

i i i i i i i i

Примечание: при выполнении команды XRL над содержимым внешнего порта используется значение из внутреннего регистра, а не данные, присутствующие на выводах микросхемы!

[ Главная ]


Архитектура микроконтроллеров MCS-51

 Дата последнего обновления файла 07.06.2005

Архитектура микроконтроллеров MCS-51

Архитектура семейства MCS-51 в значительной мере предопределяется ее назначением - построение компактных и дешевых цифровых устройств. Все функции микроЭВМ реализуются с помощью единственной микросхемы. В состав семейства MCS-51 входит целый ряд микросхем от самых простых микроконтроллеров до достаточно сложных. Микроконтроллеры семейства MCS-51 позволяют выполнять как задачи управления различными устройствами, так и реализовывать отдельные узлы аналоговой схемы. Все микросхемы этого семейства работают с одной и той же системой команд , большинство из них выполняется в одинаковых корпусах с совпадающей цоколевкой (нумерация ножек для корпуса). Это позволяет использовать для разработанного устройства микросхемы разных фирм - производителей (таких как Intel, Dallas, Atmel, Philips и т.д.) без переделки принципиальной схемы устройства и программы.

Рис 1. Структурная схема контроллера К1830ВЕ751

Структурная схема контроллера представлена на рис.1. и состоит из следующих основных функциональных узлов: блока управления, арифметико-логического устройства, блока таймеров/счетчиков, блока последовательного интерфейса и прерываний, программного счетчика, памяти данных и памяти программ. Двусторонний обмен осуществляется с помощью внутренней 8-разрядной магистрали данных. Рассмотрим подробнее назначение каждого блока. По такой схеме построены практически все представители семейства MCS-51. Различные микросхемы этого семейства различаются только регистрами специального назначения (в том числе и количеством портов). Система команд всех контроллеров семейства MCS-51 содержит 111 базовых команд с форматом 1, 2 или 3 байта и не изменяется при переходе от одной микросхемы к другой. Это обеспечивает прекрасную переносимость программ с одной микросхемы на другую.

Блок управления и синхронизации

Блок управления и синхронизации (Timing and Control) предназначен для выработки синхронизирующих и управляющих сигналов, обеспечивающих координацию совместной работы блоков ОЭВМ во всех допустимых режимах ее работы.В состав блока управления входят:

  • устройство формирования временных интервалов,
  • логика ввода-вывода,
  • регистр команд,
  • регистр управления потреблением электроэнергии,
  • дешифратор команд, логика управления ЭВМ.
    •

Устройство формирования временных интервалов предназначено для формирования и выдачи внутренних синхросигналов фаз, тактов и циклов. Количество машинных циклов определяет продолжительность выполнения команд. Практически все команды ОЭВМ выполняются за один или два машинных цикла, кроме команд умножения и деления, продолжительность выполнения которых составляет четыре машинных цикла. Обозначим частоту задающего генератора через Fг. Тогда длительность машинного цикла равна 12/Fг или составляет 12 периодов сигнала задающего генератора. Логика ввода - вывода предназначена для приема и выдачи сигналов, обеспечивающих обмен информации с внешними устройствами через порты ввода вывода Р0-Р3.

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

Регистр управления потреблением (PCON) позволяет останавливать работу микроконтроллера для уменьшения потребления электроэнергии и уменьшения уровня помех от микроконтроллера. Еще большего уменьшения потребления электроэнергии и уменьшения помех можно добиться, остановив задающий генератор микроконтроллера. Этого можно достичь при помощи переключения бит регистра управления потреблением PCON. Для варианта изготовления по технологии n-МОП (серия 1816 или иностранных микросхем, в названии которых в середине отсутствует буква 'c') регистр управления потреблением PCON содержит только один бит, управляющий скоростью передачи последовательного порта SMOD, а биты управления потреблением электроэнергией отсутствуют.

Арифметико-логическое устройство (ALU) представляет собой параллельное восьмиразрядное устройство, обеспечивающее выполнение арифметических и логических операций. АЛУ состоит из:

  • регистров аккумулятора, регистров временного хранения TMP1 и TMP2,
  • ПЗУ констант,
  • сумматора,
  • дополнительного регистра (регистра В),
  • аккумулятора (ACC),
  • регистра состояния программ (PSW).

Регистр аккумулятор и регистры временного хранения - восьмиразрядные регистры, предназначенные для приема и хранения операндов на время выполнения операций над ними. Эти регистры программно не доступны.

ПЗУ констант обеспечивает выработку корректирующего кода при двоично-десятичном представлении данных, кода маски при битовых операциях и кода констант.

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

Регистр B - восьмиразрядный регистр, используемый во время операций умножения и деления. Для других инструкций он может рассматриваться как дополнительный сверхоперативный регистр.

Аккумулятор - восьмиразрядный регистр, предназначенный для приема и хранения результата, полученного при выполнении арифметико-логических операций или операций сдвига

Блок последовательного интерфейса и прерываний (ПИП) предназначен для организации ввода - вывода последовательных потоков информации и организации системы прерывания программ. В состав блока входят:

  1. буфер ПИП,
  2. логика управления,
  3. регистр управления,
  4. буфер передатчика,
  5. буфер приемника,
  6. приемопередатчик последовательного порта,
  7. регистр приоритетов прерываний,
  8. регистр разрешения прерываний,
  9. логика обработки флагов прерываний и схема выработки вектора.

Счетчик команд (Program Counter) предназначен для формирования текущего 16-разрядного адреса внутренней памяти программ и 8/16-разрядного адреса внешней памяти программ. В состав счетчика команд входят 16-разрядные буфер РС, регистр РС и схема инкремента (увеличения содержимого на 1).

Память данных (RAM) предназначена для временного хранения информации, используемой в процессе выполнения программы.

Порты P0, P1, P2, P3 являются квазидвунаправленными портами ввода - вывода и предназначены для обеспечения обмена информацией ОЭВМ с внешними устройствами, образуя 32 линии ввода- вывода.

Регистр состояния программы (PSW) предназначен для хранения информации о состоянии АЛУ при выполнении программы.

Память программ (EPROM) предназначена для хранения программ и представляет собой постоянное запоминающее устройство (ПЗУ). В разных микросхемах применяются масочные, стираемые ультрафиолетовым излучением или FLASH ПЗУ.

Регистр указателя данных (DPTR) предназначен для хранения 16 - разрядного адреса внешней памяти данных или памяти программ.

Указатель стека (SP) представляет собой восьмиразрядный регистр, предназначенный для организации особой области памяти данных (стека), в которой можно временно сохранить любую ячейку памяти.

[ Главная ]


Построение памяти микроконтроллеров MCS-51

 Дата последнего обновления файла 07.06.2005

Построение памяти микроконтроллеров семейства MCS-51

Микроконтроллеры семейства MCS-51 построены по Гарвардской архитектуре. Это означает, что память данных и память программ в этих микросхемах разделены и имеют отдельное адресное пространство. В этих микроконтроллерах имеется пять адресных пространств: память программ, внешняя память данных три для внутренней памяти. Такое построение памяти позволяет удвоить доступное адресное пространство. Кроме того такое построение памяти позволяет в ряде случаев увеличить быстродействие микросхем.

Схема подключения внешних микросхем памяти к микроконтроллерам семейства MCS-51 показана на рисунке 1. Регистр адреса D3 на этой схеме предназначен для запоминания младших 8-ми бит адреса, передаваемых через шину данных/памяти, совмещенную с портом P0. Старшие восемь бит адреса передаются через шину адреса, совмещенную с портом P2. Во время передачи адреса через порт P0, микроконтроллер вырабатывает синхроимпульс на ножке ALE. Именно этот импульс позволяет запомнить младший байт адреса в регистре D3.

Для обращения к памяти данных и к памяти программ используются одни и те же шина адреса и шина данных, но разные управляющие сигналы. Для чтения памяти программ вырабатывается сигнал PSEN, а для чтения памяти данных вырабатывается сигнал RD. Для записи информации в память данных вырабатывается сигнал WR. То есть память программ доступна только для чтения, а память данных доступна и для чтения и для записи любой информации, записанной в двоичном коде.

Sx_Proc.gif (12875 bytes)

Рисунок 1. Схема подключения схем внешней памяти к микроконтроллерам семейства MCS-51

Память программ микроконтроллеров MCS-51

Память программ предназначена для хранения программ и имеет отдельное от памяти данных адресное пространство объемом 64 Кбайт, причем для некоторых микросхем (например КР1816ВЕ51, КМ1819ВЕ751, КР1830ВЕ51) для хранения программ на кристалле микроконтроллера расположено ПЗУ. Это ПЗУ отображается в область млаших адресов памяти программ. Учитывая, что выполнение программы после сброса микроконтроллера всегда начинается с нулевого адреса памяти программ, то при включении питания начнет выполняться программа, записанная во внутненнем ПЗУ микроконтроллера. Микроконтроллеры, не имеющие внутреннего ПЗУ (например КР1816ВЕ31 и КР1830ВЕ31) могут работать только с внешней микросхемой ПЗУ емкостью до 64 Кбайт (при использовании портов P1 и P3 в качестве расширителя адреса объем подключаемой ПЗУ может быть увеличен до 1Гбайта). Микроконтроллеры семейства MCS-51 имеют внешний вывод EA, с помощью которого можно запретить работу внутренней памяти, для чего необходимо подать на вывод EA логический "0" (соединить этот вывод с корпусом). При этом внутренняя память программ отключается и, начиная с нулевого адреса, все обращения происходят к внешней памяти программ.

Доступ к внешней памяти программ осуществляется в двух случаях:

  1. при действии сигнала EA=0 независимо от адреса обращения,
  2. в любом случае, если программный счетчик (РС) содержит число большее, чем максимальная ячейка внутренней памяти программ.

Распределение памяти программ микроконтроллера КР1830ВЕ51 представлено ниже:

pam_prog.gif (3480 bytes) Для чтения памяти программ используются команды

MOVC A, A+@DPTR и MOVC A, A+@PC

Рисунок 2. Адресное пространство памяти программ.

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

Ниже приведены адреса векторов прерываний и соответствующие им аппаратурные источники прерываний программы:

Вектор прерывания | Флаги, вызывающие прерывание | Источник прерывания
0000Н | - | Рестарт (сброс) контроллера RESET
0003Н | IE0 | внешнее прерывание INT0
000bН | TF0 | Таймер 0
0013Н | IE1 | внешнее прерывание INT1
001bН | TF1 | Таймер 1
0023Н | RI, TI | Последовательный порт
002bН | TF2, EXF2 | Таймер 2
0033Н | CF, CCFn(n=0:4) | Набор программируемых счётчиков (РСА)
003bН | AIF | Аналого-цифровой преобразователь
0043Н | CF1,C1CCFn(n=1:4) | Набор программируемых счётчиков (РСА1)
004bН | SEPIF | Последовательный порт SEP
0053Н | IE2 | внешнее прерывание INT2
005bН | IE3 | внешнее прерывание INT3
0063Н | IE4 | внешнее прерывание INT4
006bН | IE5 | внешнее прерывание INT5
0073Н | IE6 | внешнее прерывание INT6

Примечание: вектора прерывания, выделенные:

  1. жирным подчеркнутым текстом- присутствуют во всех микросхемах семейства;
  2. жирным текстом- отсутствуют в микросхемах 8051,8031, КР1816ВЕ31, КР1816ВЕ51, КР1816ВЕ751 КР1830ВЕ31, КР1830ВЕ51, КР1830ВЕ751;
  3. обычным текстом- присутствуют только в микросхемах 8Х51FA, FB, FC и GB
  4. курсивом- присутствуют только в микросхеме 8Х51GB

Внешняя память данных микроконтроллеров MCS-51

Внешняя память данных предназначена для временного хранения информации, используемой в процессе выполнения программы. Эта память физически должна быть подключена к микросхеме микроконтроллера при помощи схемы, изображенной на рисунке 1. Максимальный объем этой памяти определяется регистром DPTR и составляет 64 Кбайта. Точно также как и в случае внешней памяти программ, объем внешней памяти данных может быть увеличен за счет использования портов P1 и P3 до 1 Гбайта. Внешняя память данных для своей работы требует использование портов P0, P2 и P3. Это приводит к увеличению габаритов устройства, увеличению уровня помех и, в конечном итоге, увеличения стоимости устройства в целом. Поэтому в современных устройствах внешняя память не используется. Однако, в некоторых микроконтроллерах (например 87с550 фирмы DALLAS) команды обращения к внешней памяти используются для работы с дополнительной внутренней памятью большого объема.

vnsh_pam.gif (2095 bytes) Для обращения к внешней памяти данных используются команды

MOVX A, @DPTR (команда чтения) и

MOVX @DPTR, A (команда записи)

Иногда для того, чтобы сохранить порт P2 в качестве порта общего использования, для обращения к памяти данных используются команды

MOVX A, @R0 или MOVX A, @R0 (команды чтения)

MOVX@R0, A MOVX@R0, A (команды записи)

Рисунок 3. Адресное пространство внешней памяти данных.

Отметим, что в качестве внешней памяти данных могут быть использованы как микросхемы ОЗУ так и микросхемы ПЗУ.

Внутренняя память данных микроконтроллеров MCS-51

Несмотря на то, что это самое маленькое адресное пространство из рассматриваемых, оно устроено наиболее сложным образом. Распределение памяти данных микроконтроллеров серии MCS-51 приведено на рисунке 4.

pam_dann.gif (5584 bytes)

Рисунок 4. Адресное пространство внутренней памяти данных.

Внутреннее ОЗУ данных предназначено для временного хранения информации, используемой в процессе выполнения программы, и занимает 128 младших байт, с адресами от 000h до 07Fh для микроконтроллеров 8051, 8031, КР1816ВЕ31, КР1816ВЕ51, КР1816ВЕ751 КР1830ВЕ31, КР1830ВЕ51, КР1830ВЕ751 или 256 восьмиразрядных ячеек, с адресами от 000h до 0FFh для всех остальных микроконтроллеров семейства.

Регистры специальных функций занимают адреса внутренней памяти данных с 080h по 0FFh. Так как адреса регистров специальных функций совпадают со старшими адресами внутреннего ОЗУ данных, то имеются особенности при использовании этих адресов внутренней памяти данных.

Система команд микроконтроллера позволяет обращаться к ячейкам внутренней памяти данных при помощи прямой и косвенно-регистровой адресации. При обращении к ячейкам памяти с адресами 0-127 использование любого из этих видов адресации будет производить выборку одной и той же ячейки памяти. При обращении к ячейкам ОЗУ с адресами 128-256 следует воспользоваться косвенно-регистровой адресацией. Учитывая, что работа со стеком ведётся при помощи косвенной адресации, то имеет смысл размещать в этой области памяти стек. Если же требуется обратиться к регистрам специальных функций, то нужно использовать прямую адресацию. Например:

   MOV A, 80h   ;Скопировать сигналы с внешних ножек порта P0 в аккумулятор

   MOV R0, #80h ;Скопировать в аккумулятор содержимое
   MOV A, @R0   ;ячейки внутреннего ОЗУ  с адресом 80h

Регистры общего назначения позволяют писать самые эффективные программы. У микроконтроллеров семейства MCS-51 программирующему инженеру доступны восемь регистров. Более того, в этом семействе микроконтроллеров есть целых четыре набора (банка) регистров с именами RB0 - RB3. Банк регистров состоит из восьми восьмиразрядных регистров с именами R0, R1, …, R7. Несколько банков регистров служат для организации независимой работы нескольких параллельно выполняемых программ. Переключение банков регистров производится при помощи двух особых бит регистра слова состояния программы PSW (RS0 и RS1). Если организация нескольких параллельных потоков обработки данных не нужна, то можно пользоваться только нулевым банком регистров, включающимся автоматически после включения питания и сброса микроконтроллера, остальные ячейки памяти использовать как обычное ОЗУ.

Все четыре банка регистров объединены с 32 младшими байтами внутреннего ОЗУ данных (см. рисунок 4). Так как физически регистры и ячейки внутреннего ОЗУ объединены, то команды программы могут обращаться к регистрам, используя их имена R0-R7 ( регистровая адресация):

   MOV A, R0   ;Скопировать содержимое регистра R0 в аккумулятор
   MOV R7, A   ;Скопировать содержимое регистра R7 в аккумулятор

или используя их адрес во внутренней памяти данных ( прямая байтовая адресация):

   MOV A, 0   ;Скопировать содержимое нулевой ячейки ОЗУ в аккумулятор
   MOV 7, A   ;Скопировать содержимое аккумулятора в седьмую ячейку ОЗУ

Следующие после банков регистров внутреннего ОЗУ данных 16 ячеек памяти (адреса 20Н-2FH) образуют область памяти, к которой возможна как байтовая, так и битовая адресация. В этих ячейках располагаются 128 программных флагов (битовых ячеек памяти). Обращение к отдельным битам этих ячеек возможно по их битовым адресам. Например команды:

   SETB 15      ;Запомнить в 15 флаге логическую единицу
   JB 15, Metka ;Если в 15 флаге записана логическая единица, то перейти на метку

обращаются к 15 флагу, расположенному в старшем бите байтовой ячейки памяти 21h. Использование однобитовых ячеек памяти позволяет сократить необходимый для работы программы объём памяти данных, так как для хранения битовых переменных выделяется один бит в памяти данных, а не машинное слово, как это делается в универсальных микропроцессорах (компьютерах).

В битовой области сосредоточено только 128 флагов. Оставшиеся адреса в битовом пространстве используются для битовой адресации в области регистров специальных функций. Наиболее яркий пример использования битовой адресации в области регистров специальных функций - это обращение к отдельным ножкам параллельных портов:

   CPL 92      ;Проинвертировать второй бит порта P1

Оставшаяся область памяти используется как обычное ОЗУ без особенностей. Хотя, надо отметить, что в современных микроконтроллерах эту память следует рассматривать как встроенные 256 регистров сверхоперативного ОЗУ. Основной памятью постепенно становится внутренняя память, доступная при помощи команд MOVX @DPTR, A

Регистры специальных функций.

Регистры специальных функций - это дополнительные устройства, которые отображаются в адресное пространство внутренней памяти данных. В различных микроконтроллерах состав дополнительных устройств различается. Микроконтроллеры различаются между собой количеством параллельных портов, последовательных портов, таймеров. Некоторые из регистров специальных функций с указанием их адресов в адресном пространстве SFR внутреннего ОЗУ приведены на рисунке 5:

Рисунок 5. Адресное пространство регистров специальных функций.

Примечание: регистры, выделенные:

  1. жирным подчеркнутым текстом- присутствуют во всех микросхемах семейства;
  2. жирным текстом- отсутствуют в микросхемах 8051,8031, КР1816ВЕ31, КР1816ВЕ51, КР1816ВЕ751 КР1830ВЕ31, КР1830ВЕ51, КР1830ВЕ751;
  3. обычным текстом- присутствуют только в микросхемах 8Х51FA, FB, FC и GB
  4. курсивом- присутствуют только в микросхеме 8Х51GB

[ Главная ]


Порты микроконтроллеров MCS-51

 Rambler's Top100

Устройство параллельных портов микроконтроллеров MCS-51

Порты P0, P1, P2, P3 являются квазидвунаправленными портами ввода- вывода и предназначены для обеспечения обмена информацией микроконтроллера с внешними устройствами, образуя 32 линии ввода- вывода. Каждый из портов содержит восьмиразрядный регистр, имеющий байтовую и битовую адресацию для установки (запись '1') или сброса (запись '0') разрядов этого регистра с помощью программного обеспечения. Выходы этих регистров соединены с внешними ножками микросхемы. Упрощенная схема одного разряда порта показана на рис. 1

port.gif (2704 bytes)

Рис. 1. Упрощенная схема одного бита порта.

Один разряд регистра - защелки порта представляет собой D-триггер. Данные с внутренней шины микроконтроллера записываются в регистр-защелку по сигналу "запись в защелку". Выход "Q" D-триггера подключается к внутренней шине (считывается) по сигналу "чтение защелки". Значение сигнала непосредственно с внешнего вывода порта считывается по сигналу "чтение вывода". Некоторые команды чтения порта используют сигнал "чтение защелки ", другие "чтение выода". Чтение внешних ножек микросхемы осуществляется командами:
MOV A, P3      ;Скопировать состояние ножек порта P3 в аккумулятор
JB P3.4, Metka ;Если на 4 ножке порта P3 логическая ‘1’, то перейти на метку

Чтение регистра - защелки осуществляется командами чтение - модификация - запись. Например:

 CPL P3.1    ;Проинвертировать сигнал на первой ножке порта P3
 ORL P2,#56h ;Установить единичный сигнал на ножках 1,2,4 и 6 порта P2
 ANL P3,#03h ;Установить нулевой сигнал на ножках 0 и 1 порта P3

Порты микросхемы служат для управления внешними устройствами, подключенными к микроконтроллеру. Схема подключения простейших внешних устройств приведена на рисунке 2. Этот рисунок иллюстрирует особенности подключения индикаторов к параллельным портам микроконтроллера MCS-51.

Рисунок 2. Схема подключения светодиодных индикаторов к параллельному порту.

Присутствие в схеме мощного транзистора позволяет подключать к выводам порта светодиодные индикаторы непосредственно без усилителя мощности. Однако при этом необходимо следить за максимальной допустимой мощностью, рассеиваемой на микросхеме и напряжением, подаваемом на светодиод. Эквивалентная схема, на которой показан путь протекания выходного тока порта приведена на рисунке 3. Как видно из этой схемы именно этот ток используется для зажигания светодиода.

Рисунок 2. Эквивалентная схема подключения светодиодного индикатора к параллельному порту.

Для умощнения выводов порта можно применить транзисторный ключ, показанный на рисунке 2. Обратите внимание, что база транзистора подключена непосредственно к выводу порта. Это стало возможным только благодаря использованию в схеме порта генератора тока в верхнем плече выходного каскада (Схему подключения устройств к портам с TTL выходами можно посмотреть здесь). Если выходного тока достаточно для открывания транзисторного ключа, то резистор R2 не используется. Этот резистор подключается для увеличения базового тока транзисторного ключа. На максимальное значение тока через этот резистор накладываются те же ограничения, что и для непосредственного подключения светодиодного индикатора к выводам порта.

Микроконтроллеры предназначены для управления внешними устройствами, однако управлять напряжением на выходе параллельного порта микроконтроллера можно только при помощи программы, записанной в память программ. Какие напряжения необходимо подавать на выходы микросхемы зависят от схемы подключения индикатора. В приведённой на рисунке 2 схеме, для зажигания светодиода VD1, в шестой вывод порта P0 необходимо записать логический 0. Для зажигания светодиода VD2 необходимо в седьмой разряд порта P2 записать логическую единицу, а для его гашения – логический ноль.

Для записи числа в порт (изменения потенциалов на ножках микросхемы) можно воспользоваться командами с байтовой адресацией:

  1. MOV (пересылка), например

    2.  MOV P2, #56h        ;Установить единичный сигнал на ножках 1,2,4 и 6 порта P2
                     ;и нулевой потенциал на ножках 0,3,5 и 7
 MOV P1, #01110011b  ;Выдать на все восемь выводов порта P1 число 011100112
 MOV P3, A           ;Выдать на все восемь выводов содержимое аккумулятора

  2. ANL (логическое 'И'), например

    3.  ANL P1, #11110011b ;выдать низкий потенциал на ножках P1.2 и P1.3

  3. XRL (исключающее 'ИЛИ'), например

    4.  XRL P3, #01000100b ;инвертировать состояние ножек P3.2 и P3.6
  4. ORL (логическое 'ИЛИ'), например
    5.  ORL P1, #00001100b ;выдать высокий потенциал на ножках P1.2 и P1.3

Эти команды изменяют потенциал сразу на нескольких выводах порта. Кроме того, для изменения потенциалов на ножках микросхемы, можно воспользоваться командами с битовой адресацией:

  1. MOV (пересылка), например

    2.  MOV P1.2, C         ;выдать содержимое бита переноса через 2-й бит порта P2

  2. CPL (инверсия), например

    3.  CPL P1.2            ;проинвертировать второй бит порта P2

  3. SETB (установить бит), например

    4.  SETB P2.3           ;выдать высокий потенциал на 3-й ножке порта P2

  4. CLR (сбросить бит), например

    5. CLR P2.3             ;выдать низкий потенциал на 3-й ножке порта P2

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

По той же причине при настройке выводов порта на выполнение альтернативных функций в соответствующие разряды должны быть записаны логические '1'.

Кроме работы в качестве обычных портов ввода - вывода, внешние выводы портов Р0 .. Р3 могут выполнять ряд дополнительных (альтернативных) функций:

  • Порт P0 может быть использован для организации шины данных при работе микроконтроллера с внешней памятью данных или программ, при этом через него выводится младший байт адреса A0 - A7, выдается из микроконтроллера или принимается в микроконтроллер байт данных. Во время доступа к внешней памяти во все триггеры - защелки порта P0 аппаратно записываются "1" (т.е. содержимое порта теряется). Кроме того, через порт P0 передаюься данные при программировании внутреннего ППЗУ, и читается содержимое внутренней памяти программ при работе с программатором. При сбросе микросхемы во все разряды порта записываются '1'. Схема порта P0 отличается от всех других портов тем, что у этого порта нет внутреннего генератора тока. Поэтому при работе с этим портом приходится подключать внешние резисторы.

    • P0.gif (2948 bytes)

Схема использования порта P0 в качестве шины данных приведена на рисунке 3.

Sx_Proc.gif (12875 bytes)

Рисунок 3. Использование порта P0 в качестве шины данных.

  • Порт P1 может быть использован для чтения внутренней памяти программ или для передачи младшего байта адреса при программировании внутреннего РПЗУ. В младших моделях микроконтроллера семейства других альтернативных функций у порта P1 нет. При сбросе микросхемы во все разряды порта записываются '1'.

    • P1.gif (2890 bytes)

    P1.0 T2 -внешний вход таймера/счетчика 2
    P1.1 T2EX -вход управления перезагрузки/захвата таймера
    P1.2 ECI - внешний вход набора программируемых счетчиков (РСА)
    P1.3 CEX0 -внешний вход/выход для вывода ШИМ или сравнения/захвата модуля 0
    P1.4 CEX1 -внешний вход/выход для вывода ШИМ или сравнения/захвата модуля 0
    P1.5 CEX2 -внешний вход/выход для вывода ШИМ или сравнения/захвата модуля 0
    P1.6 CEX3 -внешний вход/выход для вывода ШИМ или сравнения/захвата модуля 0
    P1.7 CEX4 -внешний вход/выход для вывода ШИМ или сравнения/захвата модуля 0

    Примечание: альтернативные функции, выделенные:

    1. жирным подчеркнутым текстом - присутствуют во всех микросхемах
    2. жирным текстом - отсутствуют в микросхемах 8051,8031, КР1816ВЕ31, КР1816ВЕ51, КР1816ВЕ751 КР1830ВЕ31, КР1830ВЕ51, КР1830ВЕ751;
    3. курсивом - присутствуют только в микросхемах 8Х51FA, FB, FC и GB

  • Порт P2 может быть использован для передачи старшего байта адреса при программировании внутреннего ППЗУ и при чтении внутренней памяти программ. Через порт Р2 выводится старший байт адреса А8 - А15 при работе с внешней памятью программ и внешней памятью данных (с 16- разрядным адресом). Во время доступа к внешней памяти содержимое регистра - защелки порта P2 не изменяется. Схема использования порта P2 в качестве шины адреса приведена на рисунке 2. При сбросе микросхемы во все разряды порта P2 записываются '1'.

    • P2.gif (2827 bytes)

  • Порт P3. Каждая линия порта Р3 имеет индивидуальную альтернативную функцию, которая может быть задействована простым обращением к устройству, соединенному с ножкой порта (например, для того чтобы был выработан строб WR, достаточно обратиться с внешней памяти командой MOVX @DPTR, A или MOVX @R0,A). Линии порта Р3 могут выполнять альтернативные функции только в том случае, если в соответствующие этим линиям разряды регистра записаны логические '1', иначе на линиях порта будет присутствовать '0' независимо от характера принимаемой или передаваемой информации. При сбросе микросхемы во все разряды порта записываются '1'.

    • P3.gif (2784 bytes)

    Р3.0 RxD - вход последовательного порта;
    Р3.1 TxD - выход последовательного порта;
    Р3.2 INT0 -используется как вход 0 внешнего запроса прерываний;
    Р3.3 INT1 -используется как вход 1 внешнего запроса прерываний;
    Р3.4 Т0 - используется как вход счетчика внешних событий 0;
    Р3.5 Т1 - используется как вход счетчика внешних событий 1;
    Р3.6 WR - строб записи во внешнюю память данных;
    Р3.7 RD - строб чтения из внешней памяти данных.


Последовательный порт MCS-51

 Дата последнего обновления файла 07.06.2005

Последовательный порт микроконтроллера 8051.

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

  • Регистр управления/статуса приемопередатчика SCON
  • Бит SMOD регистра управления мощностью PCON
  • Буферный регистр приемопередатчика SBUF

Последовательный порт может работать в четырех различных режимах.

  • Режим 0. Синхронный режим . Информация передается, и принимается через вывод входа приемника RxD. Принимаются или передается 8 бит данных. Через вывод TxD выдаются импульсы синхронизации, которые сопровождают каждый бит. Скорость передачи фиксирована и составляет 1/12 Fген.
  • Режим 1. Асинхронный 8-ми битовый режим . Передаются (через TXD) или принимаются (через RXD) 10 бит: старт-бит (логический 0), 8 бит данных (младшим разрядом вперед) и стоп-бит (логическая 1). При приеме, стоп-бит поступает в бит RB8 регистра SCON. Скорость передачи в режиме 1 переменная: для управления скоростью передачи вы можете использовать таймер Т1 и/или Т2.
  • Режим 2. Асинхронный 9-ти битовый режим с фиксированной скоростью передачи. Передаются (через TXD) или принимаются (через RXD) 11 бит: старт-бит. 8 бит данных (младшим разрядом вперед), программируемый 9-й бит данных и стоп-бит. При передаче, в 9-й бит данных (бит ТВ8 регистра SCON) может быть записан логический 0 или 1, например, значение бита четности (бит Р регистра PSW). При приеме, 9-й бит данных поступает в бит RB8 регистра SCON. Присутствие стоп-бита контролируется схемой обнаружения ошибки кадра. Скорость передачи программируется и может быть равна либо 1/32, либо 1/64 частоты резонатора в зависимости от управляющего бита SMOD.
  • Режим 3. Асинхронный 9-ти битовый режим. совпадает с режимом 2 во всех деталях, за исключением частоты приема/передачи, которая задается таймером.

Во всех четырех режимах передача начинается любой командой, которая использует SBUF как регистр-приемник. Прием в режиме 0 начинается при условии RI = 0, REN = 1. Прием в других режимах начинается с приходом старт-бита, если бит REN установлен.

Регистр управления/статуса приемопередатчика SCON

Управление режимом работы приемопередатчика осуществляется через специальный регистр с символическим именем SCON. Этот регистр содержит не только управляющие биты, определяющие режим работы последовательного порта, но и девятый бит принимаемых или передаваемых данных (RB8 и ТВ8) и биты прерывания приемопередатчика (R1 и Т1).

Функциональное назначение бит регистра управления/статуса приемопередатчика SCON.
Символ | Позиция | Имя и назначение
SM0 SCON.7 Биты управления режимом работы приемопередатчика. Устанавливаются/сбрасываются программно см. примечание 1
SM0 | SM1 | Режим работы приемопередатчика
0 | 0 | Сдвигающий регистр расширения ввода/вывода
0 | 1 | 8 битовый приемопередатчик, изменяемая скорость передачи
1 | 0 | 9 битовый приемопередатчик. Фиксированная скорость передачи
1 | 1 | 9 битовый приемопередатчик, изменяемая скорость передачи
SM1 | SCON.6
SM2 | SCON.5 | Бит управления режимом приемопередатчика. Устанавливается программно для запрета приема сообщения, в котором девятьй бит имеет значение 0
REN | SCON.4 | Бит разрешения приема. Устанавливается/сбрасывается программно для разрешения/запрета приема последовательных данных
TB8 | SCON. 3 | Передача бита 8. Устанавливается/сбрасывается программно для задания девятого передаваемого бита в режиме 9-битового передатчика
RB8 | SCON.2 | Прием бита 8. Устанавливается/сбрасывается аппаратно для фиксации девятого принимаемого бита в режиме 9-битового приемника
TI | SCON. 1 | Флаг прерывания передатчика. Устанавливается аппаратно при окончании передачи байта. Сбрасывается программно после обслуживания прерывания
RI | SCON.0 | Флаг прерывания приемника. Устанавливается аппаратно при приеме байта. Сбрасывается программно после обслуживания прерывания

Прикладная программа путем загрузки в старшие биты регистра SCON двухбитного кода определяет режим работы приемопередатчика. Во всех четырех режимах работы передача инициализируется любой командой, в которой буферный регистр SBUF указан как получатель байта. Как уже отмечалось, прием в режиме 0 осуществляется при условии, что R1 = 0 и REN = 1, в остальных режимах - при условии, что REN = 1.

В бите ТВ8 программно устанавливается значение девятого бита данных, который будет передан 8 режиме 2 или 3. В бите RB8 в этих режимах фиксируется девятый принимаемый бит данных. В режиме 1 в бит RB8 заносится стоп-бит. В режиме 0 бит RB8 не используется.

Флаг прерывания передатчика ТI устанавливается аппаратно в конце периода передачи стоп-бита во всех режимах. Соответствующая подпрограмма обслуживания прерывания должна сбрасывать бит TL.

Флаг прерывания приемника RI устанавливается аппаратно в конце периода приема восьмого бита данных в режиме 0 и в середине периода приема стоп-бита в режимах 1, 2 и 3. Подпрограмма обслуживания прерывания должна сбрасывать бит RI.

Скорость приема/передачи информации через последовательный порт

Скорость приема/передачи, т.е. частота работы приемопередатчика в различных режимах, определяется различными способами.

В режиме 0 частота передачи зависит только от резонансной частоты кварцевого резонатора f РЕЗ:

f=fРЕЗ/12.

За машинный цикл последовательный порт передает один бит информации. В режимах 1, 2 и 3 скорость приема/передачи зависит от значения управляющего бита SMOD в регистре специальных функций PCON.

Регистр управления мощностью PCON

Символ | Позиция | Наименование и функция
SMOD | PCON.7 | Удвоенная скорость передачи. Если бит установлен в 1, то скорость передачи вдвое больше, чем при SMOD = 0. По сбросу SMOD = 0.
 | PCON.6 | Не используется
 | PCON.5 | Не используется
 | PCON.4 | е используется
GF1 GF0 | PCON.3 PCON.2 | Флаги, специфицируемые пользователем (флаги общего назначения)
PD | PCON.1 | Бит пониженной мощности. При установке бита в 1 микро-ЭВМ переходит в режим пониженной потребляемой мощности
IDL | PCON.0 | Бит холостого хода. Если бит установлен в 1, то микро-ЭВМ переходит в режим холостого хода

Примечание. При одновременной записи 1 в PD и IDL бит PD имеет преимущество. Сброс содержимого PCON выполняется путем загрузки в него кода 0XXX0000.

В режиме 2 частота передачи определяется выражением

f =2SMODfРЕЗ/64.

Иными словами, при SMOD = 0 частота передачи равна 1/64 частоты fРЕЗ, а при SMOD = 1 - 1/32 частоты fРЕЗ.

В режимах 1 и 3 в формировании частоты передачи, кроме управляющего бита SMOD, принимает участие таймер 1. При этом частота передачи f зависит от частоты переполнения f OVLT и определяется следующим образом:

f=2SMODfOVTL1/32

При использовании таймера 1 для тактирования последовательного порта прерывания от этого таймера должны быть запрещены. Таймер может быть использован как в режиме шестнадцатиразрядного таймера, так и в режиме таймера с автозагрузкой. Обычно используется режим таймера с автозагрузкой (старшая тетрада регистра TMOD = 0010В). При этом скорость передачи последовательного порта определяется выражением:

f = 2SMODfРЕЗ/(32х12х(256 -ТН1)).

Предельно низких скоростей приема и передачи по последовательному порту можно достичь при использовании таймера в режиме 1 (старший полубайт TMOD = 0001В). Перезагрузка 16-битного таймера должна осуществляться программным путем. При этом для того, чтобы можно было независимо от передачи выполнять дополнительные задачи, необходимо использовать механизм обработки прерываний и для этого разрешить прерывания от таймера 1.

Настройка таймера 1 для управления скоростью работы последовательного порта.

Частота приема/передачи (BAUD RATE) | Частота резонатора МГц | Таймер/счетчик 1
 |  | SMOD | С/Т | Режим (MODE) | Перезагружаемое число
Режим 0, макс: 1 МГц | 12 | X | X | X | X
Режим 2, макс: 375 КГц | 12 | 1 | X | X | X
Режим 1, 3: 62,2 Кгц | 12 | 1 | 0 | 2 | 0FFH
19,2 Кгц | 11,059 | 1 | 0 | 2 | 0FDH
9,6 Кгц | 11,059 | 0 | 0 | 2 | 0FDH
4,8 Кгц | 11,059 | 0 | 0 | 2 | 0FAH
2,4 Кгц | 11,059 | 0 | 0 | 2 | 0F4H
1,2 Кгц | 11,059 | 0 | 0 | 2 | 0F4H
137,5 Гц | 11,059 | 0 | 0 | 2 | 1DH
110 Гц | 6 | 0 | 0 | 2 | 72H
110 Гц | 12 | 0 | 0 | 1 | 0FЕЕВН

Отметим, что для старших моделей семейства MCS-51 при использовании для синхронизации последовательного порта таймеров 1 и 2 скорости приема и передачи информации по последовательному порту могут различаться.

Режим 0. Синхронный последовательный порт.

В нулевом режиме последовательный порт работает как обыкновенный сдвиговый регистр. Это позволяет использовать последовательный порт для увеличения количества внешних ножек микросхемы. Использование сдвиговых регистров для этой цели показано на рисунке 1 и 3. Передача по последовательному порту начинается после записи байта в регистр данных SBUF. Временная диаграмма сигнала, вырабатываемого последовательным портом микроконтроллера при передаче восьми бит данных приведена на рисунке 2. Приём байта по последовательному порту начинается после обнуления флага готовности приёмника RI. Временная диаграмма приёма входной информации последовательным портом в нулевом режиме приведена на рисунке 4.

Рисунок 1. Использование нулевого режима работы последовательного порта в качестве расширителя портов.

Рисунок 2. Временная диаграмма работы последовательного порта в нулевом режиме после записи передаваемого байта в регистр данных SBUF.

Нулевой режим работы задаётся записью комбинации 00 в биты SM0 и SM1 регистра SCON. В синхронном режиме работы информация передается, и принимается через вывод входа приемника RxD, то есть в этом режиме работы последовательный порт работаем в симплексном режиме. Через вывод TxD выдаются импульсы синхронизации, которые сопровождают каждый информационный бит. Скорость передачи в этом режиме фиксирована и составляет 1/12*Fген. Это означает, что при частоте задающего генератора 24 МГц обмен данными осуществляется на скорости 2 мегабита в секунду.

Для осуществления передачи байта данных достаточно занести его в буфер данных SBUF, как это показано в примере:

MOV SCON, #0          ;Настроить последовательный порт на передачу в синхронном режиме
MOV SBUF, A           ;Передать содержимое аккумулятора по последовательному порту
  JNB TI, $             ;Подождать окончания передачи
MOV SBUF, #56H        ;Передать  по последовательному порту число 56h
  JNB TI, $             ;Подождать окончания передачи

Рисунок 3. Использование нулевого режима работы последовательного порта для ввода информации.

Рисунок 4. Временная диаграмма приёма входной информации последовательным портом в нулевом режиме после обнуления флага готовности приёмника RI.

Для осуществления приёма байта данных достаточно настроить порт на приём в синхронном режиме работы и обнулить флаг приёма RI, как это показано в примере, приведённом на рисунке 5.

;Настроить режим работы последовательного порта-----------------------------------------------------------------------------------
 mov SCON,#00010000b                    ;настроить последовательный порт на нулевой режим работы
          ;||||||||
          ;|||||||+-------Обнулить флаг приёмника RI
          ;||||||+--------Обнулить флаг передатчика TI
          ;|||||+---------Обнулить девятый бит приёмника RB8
          ;||||+----------Обнулить  девятый бит передатчика TB8
          ;|||+-----------Разрешить работу приёмника
          ;||+------------В синхронном режиме не имеет значения
          ;++-------------Включить синхронный режим работы последовательного порта
;Так как предыдущая команда обнуляет флаг RI то с этого момента начинается приём байта--------------------------------------------
  JNB RI, $             ;Подождать окончания приёма байта по последовательному порту
  MOV A, SBUF           ;и скопировать его в аккумулятор

Рисунок 5. Программа считывания одного байта из внешнего регистра по последовательному порту.

В настоящее время разработано огромное количество микросхем таких как, например, синтезаторы частоты, микросхемы приёмников, блоков цветности телевизоров, микросхем памяти данных, управление которыми осуществляется по последовательному протоколу. При этом микросхемы обычно реализуют синхронные протоколы обмена SPI или I2C. Последовательный порт микроконтроллеров семейства MCS-51, работающий в нулевом режиме позволяет осуществлять обмен с такими микросхемами при минимальных программно-аппаратных затратах.

Справедливости ради необходимо отметить, что в современных микросхемах семейства MCS-51 присутствуют отдельные последовательные порты, работающие по протоколу SPI или I2C. В качестве примера такой микросхемы можно назвать ADuC834 фирмы Analog Devices. В микросхемах с отдельными SPI или I2C портами последовательный порт используется исключительно для связи с универсальным компьютером.

Режим 1. Асинхронный восьмиразрядный последовательный порт.

В первом режиме работы последовательный порт работает в асинхронном режиме. Временная диаграмма передаваемых сигналов через последовательный порт в асинхронном режиме работы показана на рисунке 6. Первый режим работы задаётся записью комбинации 01 в биты SM0 и SM1 регистра SCON. В асинхронном режиме работы информация передается через ножку передатчика последовательного порта микроконтроллера TxD, а принимается через вывод входа приемника RxD, то есть в этом режиме работы последовательный порт работает в дуплексном режиме. Это означает, что передача и приём информации может вестись независимо друг от друга. Скорость передачи в этом режиме настраивается при помощи таймера T1.

Рисунок 6. Временная диаграмма приёма или передачи информации последовательным портом в первом режиме работы.

При работе в асинхронном режиме работы два микроконтроллера могут обмениваться информацией между собой. Такой способ обмена позволяет сократить до минимума количество соединительных проводов между блоками или даже отдельными устройствами. Единственное условие: в отличие от синхронного режима работы, скорости работы последовательных портов должны быть одинаковыми. Обычно используются стандартные скорости передачи, такие как 1200бит/с, 2400 бит/с и т.д. Для таких скоростей передачи обычно используется кварцевый резонатор с частотой 11.0592 МГц. Скорости передачи и коэффициенты, загружаемые в таймер 1, для этих скоростей передачи приведены в таблице 1.

В отличие от нулевого режима работы в первом режиме работы возможен обмен информацией между двумя микроконтроллерами, а не только между микроконтроллером и исполнительными микросхемами. Схема соединения двух микроконтроллеров между собой для обмена информацией приведена на рисунке 7. Таким образом может быть построена простейшая многопроцессорная система.

Рисунок 7. Схема обмена информацией между двумя микроконтроллерами по последовательному порту.

В первом режиме работы, также как и в нулевом для передачи байта через последовательный порт достаточно скопировать его в буфер данных SBUF. Единственное отличие заключается в том, что, кроме настройки регистра SCON, необходимо настроить таймер для задания скорости передачи информации по последовательному порту. При приёме байта по последовательному порту приём начинается только после обнаружения стартового бита.

В качестве примера работы с последовательным портом приведём подпрограмму инициализации последовательного порта для работы в асинхронном режиме на скорости 9600 бит/с. Настройка режима работы последовательного порта в этой программе производится записью двоичной константы в регистр управления SCON. Выбор конкретных значений бит двоичной константы подробно приводится в комментариях к программе.

Так как для последовательного порта требуется таймер, то, кроме настройки последовательного порта, при помощи регистра выбора режима работы таймеров TMOD настраивается таймер T1. Эта настройка тоже производится при помощи записи двоичной константы.

Скорость работы последовательного порта настраивается записью константы 0FDh в старший байт таймера T1.

;*********************************************************************************************************************************
;НАСТРОЙКА ПОСЛЕДОВАТЕЛЬНОГО ПОРТА
;*********************************************************************************************************************************
;Настроить режим работы последовательного порта-----------------------------------------------------------------------------------
 mov SCON,#01110000b                    ;настроить последовательный порт на первый режим работы
          ;||||||||
          ;|||||||+-------Обнулить флаг приёмника RI
          ;||||||+--------Обнулить флаг передатчика TI
          ;|||||+---------Обнулить девятый бит приёмника RB8
          ;||||+----------Обнулить  девятый бит передатчика TB8
          ;|||+-----------Разрешить работу приёмника
          ;||+------------Проверять ошибку кадра (приём нулевого бита на месте стоп-бита)
          ;++-------------Включить асинхронный режим работы последовательного порта

;Настроить режим работы таймера T1 ----------------------------------------------------------------------------------------------
    anl TMOD,#00001111b ;Подготовить таймер T1 к настройке (таймер T0 не трогать!)
    orl TMOD,#00100000b ;перевести таймер T1 вo второй режим работы (таймер T0 не трогать!)
             ;||||
             ;||++--------------Перевести таймер T1 в режим автозагрузки
             ;|+----------------Синхронизироваться от внутреннего генератора
             ;+-----------------Запретить управление таймером от ножки INT1

;Настроить таймер на генерацию 3-x микросекундного интервала времени--------------------------------------------------------------
    mov TH0, #fdh           ;Загрузить старший байт таймера
    mov TL0, #fdh           ;Загрузить младший байт таймера
    setb TR1                ;Включить таймер 1

;*********************************************************************************************************************************
;РАБОТА С ПОСЛЕДОВАТЕЛЬНЫМ ПОРТОМ
;*********************************************************************************************************************************
  JNB RI, $             ;Подождать окончания приёма байта по последовательному порту
  MOV A, SBUF           ;и скопировать его в аккумулятор

Рисунок 8. Программа приёма одного байта по последовательному порту.

Возможность работы в асинхронном режиме позволяет использовать последовательный порт для связи с универсальным компьютером через его последовательный COM порт. К сожалению уровни последовательного порта микроконтроллера не совпадают с уровнями последовательного порта компьютера, поэтому для подключения микроконтроллера к последовательному порту компьютера используются специализированные микросхемы согласования уровней. Эти же микросхемы обеспечивают защиту микроконтроллера от вывода из строя статическим потенциалом при подключении разъёмов.

Обычно для работы используются только сигнальные цепи COM-порта компьютера. Тем не менее, оставшиеся буферы интерфейсной микросхемы могут быть использованы для контроля питания микроконтроллерной схемы. Типовая схема подключения компьютера к последовательному порту микроконтроллеров семейства MCS-51 с применением микросхемы ADM3202 приведена на рисунке 9.

Рисунок 9. Подключение последовательного порта микроконтроллеров семейства MCS-51 к последовательному COM порту компьютера.

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

Режим 2. Асинхронный девятиразрядный последовательный порт с фиксированной скоростью передачи.

В этом режиме последовательный порт работает на фиксированной скорости передачи также как и в нулевом режиме работы. Скорость передачи определяется значением бита SMOD и при частоте кварцевого резонатора 12 МГц составляет 375 кбит/с то есть для современных микроконтроллеров может превышать скорость передачи 1 Мбит/с.

Основной особенностью работы последовательного порта в этом режиме является передача девятого информационного бита, который может быть использован для контроля достоверности передаваемой информации. Для вычисления чётности передаваемого байта можно воспользоваться аппаратным вычислителем, подключенным к аккумулятору микроконтроллера A. Результат вычисления чётности байта сохраняется в бите чётности P регистра PSW, откуда его можно скопировать в девятый информационный бит последовательного порта TB8, расположенный в регистре управления последовательным портом SCON.

Ещё большие возможности для построения устройств предоставляет девятиразрядный режим работы при реализации многопроцессорных систем. Параллельные порты микроконтроллеров семейства MCS-51 построены по схеме с открытым стоком. Это позволяет объединять несколько выходов передатчиков в одну шину. Такое выполнение выходных каскадов микросхем облегчает построение многопроцессорных систем. В многопроцессорной системе один процессор должен быть главным (master), остальные - подчинёнными (slave). Естественно команды главного процессора должны восприниматься подчинёнными процессорами, поэтому выход передатчика главного процессора соединяется со входами приёмников подчинённых. Выходы же передатчиков подчинённых процессоров объединяются и подключаются ко входу приёмника главного процессора. Схема примера многопроцессорной системы приведена на рисунке 10.

Рисунок 10. Схема соединения нескольких микроконтроллеров между собой по последовательному порту, работающему в асинхронном режиме.

Команды главного процессора могут быть обращены к конкретному подчинённому процессору, поэтому в состав команд включается адрес подчинённого процессора. При работе в шине необходимо уметь отличать адресную информацию от данных. Это можно осуществить при помощи девятого бита. Обычно при передаче адреса в девятый бит записывают единицу, а в байтах данных и команд - 0. Таким образом микроконтроллер, даже подключившийся к шине позднее остальных, легко может осуществить синхронизацию с многопроцессорной шиной. Временная диаграмма работы многопроцессорной шины приведена на рисунке 11.

Рисунок 11. Временная диаграмма работы многопроцессорной шины.

При настройке и работе с портом во втором режиме никаких особенностей не возникает, поэтому можно воспользоваться примером программы, приведённом для нулевого режима работы. Все особенности работы сосредоточены на протокольном уровне, а это не входит в задачу рассмотрения последовательного порта.

Режим 3. Асинхронный девятиразрядный последовательный порт.

Работа последовательного порта в этом режиме не отличается от работы во втором режиме за исключением скорости передачи. Скорость передачи по последовательному порту задаётся таймером 1 также как и в первом режиме работы. Для построения программы можно воспользоваться примером, приведённым для первого режима работы с учётом того, что в регистре SCON необходимо задать вместо первого режима третий режим работы.

[ Главная ]


Система команд MCS-51

 Дата последнего обновления файла 07.06.2005

Система команд микроконтроллеров MCS-51

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

В этой системе команд реализована побитная, потетрадная (4 бита), побайтовая (8 бит) и 16-разрядная обработка данных. Микросхемы семейства MCS-51 - это 8-разрядные микропроцессоры, а это означает, что ПЗУ, ОЗУ, регистры специального назначения, АЛУ и внешние шины имеют байтовую организацию. Двухбайтовые данные используются только регистром-указателем (DPTR) и счетчиком команд (PC).

В машинном коде команда занимает один, два или три байта в зависимости от типа адресации.

Команды выполняются за один, два или четыре (умножение и деление) машинных цикла.

Запись команд в машинных кодах для человека неудобна, кроме того, разные машинные команды выполняют одинаковые действия только над разными ячейками памяти. Поэтому для записи команд микропроцессоров была придумана система мнемонических обозначений. Для записи команды микропроцессора сначала ставится мнемоническое обозначение, затем указывается ячейка памяти – приёмник результата выполнения операции и наконец источник данных для выполнения операции. Например, в команде

E535        MOV A, 35h

символы MOV обозначают операцию копирования, второй операнд 35 определяет, что данные необходимо взять из 35 ячейки памяти, а первый операнд A определяет, что результат необходимо поместить в регистр – аккумулятор. При этом старое значение регистра – аккумулятора будет стёрто. Слева приведена машинная команда микроконтроллера в шестнадцатеричной записи, соответствующая мнемонической записи команды.

Мнемоническое обозначение команды отделяется от операндов одним или несколькими символами пробела или табуляции, а операнды отделяются друг от друга запятыми.

Если операция требует для выполнения двух источников и одного приёмника результата операции (например, команда сложения ADD или вычитания SUBB), то первый операнд является одновременно и источником и приёмником результата операции. Например, в команде

2535        ADD A, 35h

символы ADD обозначают операцию сложения двух чисел, данные будут взяты из 35 ячейки памяти и аккумулятора а результат будет помещён в аккумулятор вместо старого значения этого регистра.

В таблице 1 приведены инструкции, влияющие на установку флагов микроконтроллера.

Таблица 1

Мнемоника | Флаги |  |  | Мнемоника | Флаги
 | C | OV | AC |  | C | OV | AC
ADD | + | + | + | CLR C | 0 |  |
ADDC | + | + | + | CPL C | + |  |
SUBB | + | + | + | ANL C, bit | + |  |
MUL | 0 | + |  | ANL C, /bit |  |  |
DIV | 0 | + |  | ORL C, bit | + |  |
DA | + |  |  | ORL C, /bit | + |  |
RRC | + |  |  | MOV C, bit | + |  |
RLC | + |  |  | CJNE | + |  |
SETB C | 1 |  |  |  |  |  |

Систему команд микроконтроллера условно можно разбить на пять групп:

  • арифметические команды
  • логические команды с байтовыми переменными
  • команды передачи данных
  • команды битового процессора
  • команды ветвления программ и передачи управления

Арифметические команды

В наборе команд микроконтроллера имеются следующие арифметические операции:

  • сложение ADD,
  • сложение с учетом флага переноса ADDC,
  • вычитание с заемом SUBB,
  • инкрементирование (увеличение на 1) INC,
  • декрементирование (уменьшение на 1) DEC,
  • десятичная коррекция DA,
  • умножение MUL
  • деление DIV.

Действия производятся над целыми числами без знака.

При операции умножения содержимое аккумулятора A умножается на содержимое регистра B, и результат размещается следующим образом: младший байт в регистре B, старший - в регистре А.

В случае выполнения операции деления целое от деления помещается в аккумулятор A, остаток - в регистр В.

Логические команды с байтовыми переменными.

Система команд рассматриваемого микроконтроллера позволяет реализовать логические операции

  • И ( ANL),
  • ИЛИ ( ORL),
  • ИСКЛЮЧАЮЩЕЕ ИЛИ ( XRL).

Логические операции выполняются над аккумулятором или непосредственно над портами ввода/вывода.

Существуют логические операции, которые выполняются только на аккумуляторе:

  • сброс всех восьми разрядов A ( CLR A);
  • инвертирование всех восьми разрядов A ( CPL A );
  • циклический сдвиг влево и вправо без учета флага переноса ( RR A; RL A);
  • циклический сдвиг влево и вправо с учетом флага переноса ( RRC A; RLC A);
  • обмен местами старшей и младшей тетрад внутри аккумулятора ( SWAP A).

Команды пересылки данных.

Как было рассмотрено ранее, арифметические и логические команды могут быть выполнены только над содержимым регистра аккумулятора, поэтому исключительно важное значение в системе команд приобретают команды пересылки данных. С помощью этих команд можно скопировать содержимое любой ячейки памяти в регистр-аккумулятор или наоборот скопировать содержимое аккумулятора в любую ячейку памяти. Так как в микроконтроллере присутствует три независимых области памяти, то для обращения к ним введены различные команды:

  • копирование данных во внутреннем ОЗУ: MOV;
  • обмен данными аккумулятора с внутренним ОЗУ: XCH, XCHD
  • копирование из внешней памяти данных: MOVX
  • копирование данных из памяти программ: MOVC

Примеры использования команд пересылки данных:

Любая ячейка 256- байтового блока внутреннего ОЗУ данных может быть выбрана с использованием косвенно-регистровой адресации через регистры указатели R0 и R1 (выбранного банка рабочих регистров):

MOV A, @R0             ;Скопировать число из ячейки памяти с адресом, хранящемся в R0, в аккумулятор
MOV @R1, A             ;Скопировать число из аккумулятора, в ячейку памяти с адресом, хранящемся в R1

Команды пересылки с прямой адресацией между ячейками памяти позволяют заносить содержимое порта в ячейку внутреннего ОЗУ или обмениваться содержимым ячеек внутреннего ОЗУ между собой без использования аккумулятора:

MOV 15, 25            ;Скопировать содержимое 25-й ячейки  в 15-ю ячейку

Таблицы символов (кодов), записанные в ПЗУ программы могут быть скопированы в аккумулятор с помощью команд передачи данных с косвенной адресацией:

MOVC A, @A+DPTR         ;Скопировать символ в аккумулятор

Ячейка адресного пространства 64 Кбайт внешнего ОЗУ также может быть выбрана с использованием косвенно-регистровой адресации через регистр указатель данных DPTR:

MOVX A, @DPTR          ;Скопировать число из внешней ячейки памяти с адресом, ;хранящемся в DPTR, в аккумулятор

Содержимое аккумулятора может быть обменено с содержимым рабочих регистров выбранного банка:

XCH A, R0.

Кроме того, любой бит с прямой адресацией может быть скопирован в бит переноса и наоборот:

MOV C, AdrBit

Битовые команды.

Каждый бит из битового пространства внутренней памяти может быть установлен в 1, сброшен в 0, или инвертирован:

  • установить бит (записать логическую единицу) SETB;
  • сбросить бит (записать логический ноль) CLR;
  • проинвертировать значение бита (изменить на прямо противоположное) CPL;
  • бит может быть записан во флаг переноса или считан из флага переноса MOV.

Могут быть реализованы переходы:

  • если бит установлен (содержит логическую 1) JB;
  • если бит не установлен (содержит логический 0) JNB;
  • переход, если бит установлен со сбросом этого бита после выполнения команды (запись в этот бит 0) JBC;

Между любым битом из битового пространства внутренней памяти и флагом переноса могут быть произведены логические операции "И" или "ИЛИ".

  • И ( ANL),
  • ИЛИ ( ORL),

Команды ветвления и передачи управления.

Команды ветвления позволяют реализовывать условные операторы и операторы циклов. В микроконтроллерах семейства MCS-51 доступны следующие команды:

  • безусловный переход: LJMP, AJMP, SJMP
  • Вызов и возврат из подпрограммы: LCALL, ACALL, RET, RETI
  • проверка содержимого аккумулятора: JZ, JNZ, CJNE, JMP
  • проверка флага переноса С: JC, JNC
  • проверка содержимого любого бита в битовом пространстве: JB, JNB, JBC

Команды 16-разрядных безусловных переходов и вызовов подпрограмм позволяют осуществить переход в любую точку адресного пространства памяти программ объемом до 64 Кбайт. Примеры команд:

LJMP Metka            ;Переход к команде, расположенной по адресу обозначенному меткой ‘Metka’
LCALL Podprogramma    ;Вызов подпрограммы по адресу, обозначенному меткой ‘Podprogramma’

Команды 11-разрядных переходов и вызовов подпрограмм позволяют сократить объем программы, но при этом обеспечивают переходы только внутри программного модуля 2 Кбайт. Эти команды принципиально могут приводить к необнаруживаемым транслятором ошибкам, когда программный модуль размещается на двух соседних 2 Кбайтовых сегментах памяти.

AJMP Metka            ;Переход к команде, расположенной по адресу обозначенному меткой ‘Metka’
ACALL Podprogramma    ;Вызов подпрограммы по адресу, обозначенному меткой ‘Podprogramma’

В системе команд имеются команды условных и безусловных переходов относительно начального адреса следующей команды в пределах от (РС)-127 до (РС)+127. Примеры команд:

SJMP Metka                   ;Переход к команде, расположенной по адресу обозначенному меткой ‘Metka’
JB P3.5, TstNxtUsl           ;Если на 6 выводе порта P3 нулевой потенциал,
  ACALL Podprogramma            ;то вызвать подпрограмму, обозначенную меткой ‘Podprogramma’
CJNE A, #5, TstNxtUsl        ;Если в аккумуляторе содержится число 5,
  ACALL Podprogramma            ;то вызвать подпрограмму, обозначенную меткой ‘Podprogramma’

Команды проверки содержимого аккумулятора и флага переноса C могут быть использованы для реализации проверки различных условий. При этом содержимое не изменяется, то есть если требуется произвести несколько проверок одной и той же переменной, то повторно заносить значение этой переменной в аккумулятор не нужно. Например:

  MOV A, 34            ;Если в переменной, хранящейся в ячейке внутренней памяти 34
  JNB ACC_7, TstEQ5    ;число меньше нуля,
    CALL Podprogramma    ;то вызвать подпрограмму, обозначенную меткой ‘Podprogramma’
TstEQ5 ;------------------------------------------------------------------------------------------------------
  CJNE A,#5,TstLT5     ;Если в переменной, хранящейся в ячейке внутренней памяти 34 занесено число 5,
    CALL Podpr5          ;то вызвать подпрограмму, обозначенную меткой ‘Podpr5’
TstLT5 ;------------------------------------------------------------------------------------------------------
  JNС TstGE5           ;Если в переменной, хранящейся в ячейке внутренней памяти 34 занесено число, меньшее 5,
    CALL PodprLT5        ;то вызвать подпрограмму, обозначенную меткой ‘PodprLT5’
TstGE5 ;---------------------------------------------------------------------------------
  JC TstNxtUsl         ;Если в переменной, хранящейся в ячейке внутренней памяти 34 занесено число, большее или равное 5,
    CALL PodprGE5        ;то вызвать подпрограмму, обозначенную меткой ‘PodprGE5’
TstGT5 ;------------------------------------------------------------------------------------------------------
  CJNE A,#6,$+3        ;Если в переменной, хранящейся в ячейке внутренней памяти 34
  JC TstNxtUsl         ;занесено число, большее 5,
    CALL PodprGT5        ;то вызвать подпрограмму, обозначенную меткой ‘PodprGT5’
;---------------------------------------------------------------------------------
  JNC TstNxtUsl        ;Если в переменной, хранящейся в ячейке внутренней памяти 34 занесено число, меньшее или равное 5,
    CALL PodprLE5        ;то вызвать подпрограмму, обозначенную меткой ‘PodprLE5’

Как видно из приведённых примеров, команды переходов этого микроконтроллера позволяет реализовать намного более эффективные по количеству команд программы по сравнению с другими процессорами, такими как, например MCS-48.

Косвенный переход JMP @A+DPTR в системе команд микроконтроллеров семейства MCS-51 обеспечивает ветвление программы по содержимому аккумулятора А. Это позволяет реализовывать операцию перехода по заданному коду, эквивалентную оператору case в языке программирования pascal, но намного быстрее (за два машинных цикла). Использование в этой команде указателя данных DPTR позволяет размещать таблицу переходов в любом месте памяти программ. Пример реализации команды выбора варианта:

BeginOpCase: ;Начало команды выбора вариантов------------------------------------------------------
  MOV DPTR, #JMP_TBL ;Задать начальный адрес таблицы переходов
  MOV A, 33          ;В этой ячейке хранится переменная, по которой необходимо осуществить переход на обслуживающую программу

  CLR C              ;Осуществить арифметический сдвиг аккумулятора вправо
  RLC A              ;(умножить на 2) т.к. команды переходов занимают два байта

  JMP @A+DPTR        ;Перейти к выполнению заданного в 33 ячейке кода

JMP_TBL:    ;начало таблицы переходов по содержимому переменной в ячейке памяти 33-----------------
     JMP Case0       ;Перейти к выполнению кода по числу 0
     JMP Case1       ;Перейти к выполнению кода по числу 1
     JMP EndCase     ;Это число в ячейке 33 в список разрешённых не входит
     JMP EndCase     ;Это число в ячейке 33 в список разрешённых не входит
     JMP Case4       ;Перейти к выполнению кода по числу 4
EndCase:;------------------------------------------------------------------------------------------

Способы адресации операндов.

При определении способа адресации операндов в команде необходимо учитывать, что адресация для каждого операнда команды своя. В общем случае адресация источника и приёмника могут не совпадать.

Неявная адресация При неявной адресации регистр источник или регистр приёмник подразумевается в самом коде операции. Например:

03      RR A      ;Сдвинуть содержимое аккумулятора вправо
D4      DA A      ;Произвести десятичную коррекцию результата суммирования
E8      MOV A, R0 ;В первом операнде использована неявная адресация, а во втором - регистровая

Регистровая адресация используется для обращения к восьми рабочим регистрам выбранного банка рабочих регистров, а также для обращения к регистрам А, В, АВ (сдвоенному регистру), DPTR, и к флагу переноса С. Номер регистра записывается в трех младших битах команды. Например:

F8      MOV R5, A ;в первом операнде использована регистровая адресация, а во втором - неявная

Прямая байтовая адресация используется для обращения к ячейкам внутренней памяти (ОЗУ) данных (адреса 0:127) и к регистрам специального назначения (адреса 128:256). Адрес ячейки памяти помещается во второй байт команды. Например:

E520    MOV A, 20h ;во втором операнде использована прямая байтовая адресация, а в первом – неявная
8D15    MOV 15h,R6 ;в первом операнде использована прямая байтовая адресация, а во втором – регистровая

Прямая битовая адресация используется для обращения к отдельно адресуемым 128 битам, расположенным в ячейках с адресами 20Н-2FH, и к отдельно адресуемым битам регистров специального назначения. Например:

D220    SETB 20h ;использована прямая битовая адресация
C215    CLR  15h ;использована прямая битовая адресация

Косвенно-регистровая адресация используется для обращения к ячейкам внутреннего ОЗУ данных. В качестве регистров-указателей адреса используются регистры R0, R1 выбранного банка регистров. Например:

E6    MOV A,@R0 ;В первом операнде использована неявная адресация, а во втором - косвенно-регистровая
F7    MOV @R1,A ;В первом операнде использована косвенно-регистровая адресация, а во втором - неявная

Косвенно - регистровая адресация используется также для обращения к внешней памяти данных. В этом случае с помощью регистров- указателей R0 и R1 (рабочего банка рабочих регистров) выбирается ячейка из блока 256 байт внешней памяти данных. Номер блока предварительно задается содержимым порта Р2. Например:

E2    MOVX A,@R0 ;В первом операнде использована неявная адресация, а во втором - косвенно-регистровая
F3    MOVX @R1,A ;В первом операнде использована косвенно-регистровая адресация, а во втором - неявная

Если в качестве регистра - указателя используется 16 - разрядный указатель данных (DPTR), то можно выбрать любую ячейку внешней памяти данных объемом до 64 Кбайт. (В некоторых моделях микроконтроллеров семейства MSC-51 таким образом можно обращаться к внутренней памяти данных объемом более 256 байт).

E0    MOVX A,DPTR;В первом операнде использована неявная адресация, а во втором - косвенно-регистровая
F0    MOVX DPTR,A;В первом операнде использована косвенно-регистровая адресация, а во втором - неявная

Косвенно-регистровая адресация по сумме базового и индексного регистра (содержимое аккумулятора А) упрощает просмотр таблиц, записанных в памяти программ. Любой байт из таблицы может быть выбран по адресу, определяемому суммой содержимого DPTR или РС и содержимого А, например:

83    MOV A, @A+PC ;В первом операнде использована неявная адресация, а во втором - косвенно-регистровая
93    MOV A, @A+DPTR ;В первом операнде использована неявная адресация, а во втором - косвенно-регистровая.

Непосредственная адресация позволяет выбрать из адресного пространства памяти программ константы, явно указанные в команде, например:

7414    MOV A, #14h      ;В первом операнде использована неявная адресация, а во втором - непосредственная
902048  MOV DPTR, #2048h ;В первом операнде использована неявная адресация, а во втором - непосредственная

[ Главная ]


Состав семейства MCS-51

 Дата последнего обновления файла 07.06.2005

Состав семейства MCS-51

В настоящее время среди всех 8-разрядных микроконтроллеров - семейство MCS-51 является несомненным чемпионом по количеству разновидностей и количеству компаний, выпускающих его модификации. Оно получило свое название от первого представителя этого семейства - микроконтроллера 8051, выпущенного в 1980 году на базе технологии n-МОП. Удачный набор периферийных устройств, возможность гибкого выбора внешней или внутренней программной памяти и приемлемая цена обеспечили этому микроконтроллеру успех на рынке. С точки зрения технологии микроконтроллер 8051 являлся для своего времени очень сложным изделием - в кристалле было использовано 128 тыс. транзисторов, что в 4 раза превышало количество транзисторов в 16-разрядном микропроцессоре 8086.

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

В результате на сегодняшний день существует более 200 модификаций микроконтроллеров семейства 8051, выпускаемых почти 20-ю компаниями. Эти модификации включают в себя кристаллы с широчайшим спектром периферии: от простых 20-выводных устройств с одним таймером и 1К программной памяти до сложнейших 100-выводных кристаллов с 10-разрядными АЦП, массивами таймеров-счетчиков, аппаратными 16-разрядными умножителями и 64К программной памяти на кристалле. Каждый год появляются все новые варианты представителей этого семейства. Основными направлениями развития являются: увеличение быстродействия (повышение тактовой частоты и переработка архитектуры), снижение напряжения питания и потребления, увеличение объема ОЗУ и FLASH памяти на кристалле с возможностью внутрисхемного программирования, введение в состав периферии микроконтроллера сложных устройств типа системы управления приводами, CAN и USB интерфейсов и т.п.

Микросхемы для этого семейства производятся целым рядом фирм различных стран мира таких как Philips, Siemens, Intel, Atmel, Dallas, Temic, Oki, AMD, MHS, Gold Star, Winbond, Silicon Systems и ряд других. Микроконтроллеры семейства MCS 51 выпускают и российские заводы. Производство микроконтроллера 8051 осуществлялось в Киеве, Воронеже (1816ВЕ31/51, 1830ВЕ31/51), Минске (1834ВЕ31) и Новосибирске (1850ВЕ31). В качестве примера, в таблице 1 приведены названия нескольких микросхем, производимых зарубежными фирмами, в таблице 2 приведены микросхемы российского производства.

Таблица 1. Микросхемы, производимые зарубежными фирмами

Микроконтроллер | ОЗУ | ПЗУ | EEPROM | SPI | Таймеры | PCA | PCA1 | АЦП
AT89C1051 | 128 байт | 1К байт | - | - | 2 | - | - | комп
AT89C2051 | 128 байт | 2К байт | - | - | 2 | - | - | комп
I8051 | 128 байт | 4К байт | - | - | 2 | - | - | -
I8031 | 128 байт | - | - | - | 2 | - | - | -
I8Х52 | 256 байт | 8К байт | - | - | 3 | - | - | -
AT89c52 | 256 байт | 8К байт | - | - | 3 | - | - | -
AT89с8252 | 256 байт | 8К байт | 2K байт | + | 3 | - | - | -
AT89c55 | 256 байт | 20К байт | - | - | 3 | - | - | -
I8Х54 | 256 байт | 16К байт | - | - | 3 | - | - | -
I8Х58 | 256 байт | 32К байт | - | - | 3 | - | - | -
I8Х51FA | 128 байт | 8К байт | - | - | 4 | + | - | -
I8Х51FB | 256 байт | 16К байт | - | - | 4 | + | - | -
I8Х51FC | 256 байт | 32К байт | - | - | 4 | + | - | -
I8Х51GB | 256 байт | 8К байт | - | + | 5 | + | + | +

Примечание: вместо символа 'X' в названии микроконтроллера должны стоять символы:

  • 0 - n-МОП без ПЗУ
  • 3 - n-МОП с ПЗУ
  • 7 - n-МОП с РПЗУ
  • 0с - КМОП без ПЗУ
  • 3с - КМОП с ПЗУ
  • 7с - КМОП с РПЗУ
  • 9с - КМОП с FLASH

Таблица 2. Микросхемы российского производства

Микроконтроллер | ОЗУ | ПЗУ | ППЗУ | Таймер 2 | PCA | PCA1 | АЦП
КР1816ВЕ51 | 128 байт | 4К байт | - | - | - | - | -
КР1816ВЕ751 | 128 байт | - | 4К байт | - | - | - | -
КР1816ВЕ31 | 128 байт | - | - | - | - | - | -
КР1830ВЕ51 | 128 байт | 4К байт | - | - | - | - | -
КР1830ВЕ751 | 128 байт | - | 4К байт | - | - | - | -
КР1830ВЕ 31 | 128 байт | - | - | - | - | - | -

Примечание:

  • Серия микросхем 1816 выполнена по n-МОП технологии,
  • Серия микросхем 1830 выполнена по КМОП технологии

[ Главная ]


Устройство таймеров микроконтроллеров MCS-51

 Дата последнего обновления файла 07.06.2005

Устройство таймеров микроконтроллеров MCS-51

В базовых моделях семейства имеются два программируемых 16-битных таймера/счетчика (T/C0 и T/C1), которые могут быть использованы как в качестве таймеров, так и в качестве счетчиков внешних событий. Каждый из них состоит из двух 8-битных регистров TH0 (старший байт) и TH0 (младший байт) для таймера 0 или TH1 (старший байт) и TH1 (младший байт) для таймера 1.

В режиме таймера содержимое соответствующего таймера/счетчика инкрементируется в каждом машинном цикле, т.е. через каждые 12 периодов колебаний кварцевого резонатора.

В режиме счетчика содержимое соответствующего таймера/счетчика инкрементируется под воздействием перехода из 1 в 0 внешнего входного сигнала, подаваемого на вывод микроконтроллера T0 или T1. Так как на распознавание периода требуются два машинных цикла, максимальная частота подсчета входных сигналов равна 1/24 частоты резонатора. На длительность периода входных сигналов ограничений сверху нет. Для гарантированного прочтения входной сигнал должен удерживать значение 1, как минимум, в течение одного машинного цикла микро-ЭВМ.

Схемы управления таймерами идентичны. Таймер 0 и Таймер 1 могут работать в четырех режимах работы:

  • режим 0: 13-битный таймер
  • режим 1: 16-битный таймер
  • режим 2: 8-битный автоперезагружаемый таймер
  • режим 3: Таймер 0 как 2 раздельных 8-битных таймера.

Кроме того, Таймер 1 можно использовать для задания скорости передачи (baud rate) последовательного порта.

Для переключения режимов работы таймеров используются биты M0 и M1 регистра специальной функции TMOD. Название образовано от сокращения двух английских слов: T(timer)- таймер и mode - режим. Имена и расположение битов приведено на рисунке 1:

TMOD.gif (3495 bytes)

Рисунок 1. Формат регистра управления режимами работы таймеров TMOD.

Так как управление таймерами 0 и 1 полностью идентично, то приведём назначение битов по именам:

Символ | Позиция бита | Имя и назначение
GATE TMOD.7 для таймера 1 и TMOD.3 для таймера 0

Управление блокировкой таймера от ножки INTx. Если бит установлен в 1, то таймер/счетчик "x" разрешен до тех пор, пока на входе "lNTx" высокий уровень и бит управления "TRx" установлен. Если бит сброшен в 0, то Т/С разрешается, как только бит управления "TRx" устанавливается в 1.

С/Т TMOD.6 для таймера 1 и TMOD.2 для таймера 0

Бит выбора режима таймера или счетчика событий. Если бит сброшен в 0, то таймер работает от внутреннего генератора, если установлен в 1, то работает от внешних сигналов на входе "Tx"

M1 TMOD.5 для таймера 1 и TMOD.1 для таймера 0 Выбор режима работы таймера
M1 | M0 |
0 | 0 | 13 битный таймер/счетчик "TLx" работает как 5-битный предварительный делитель
0 | 1 | 16 битный таймер/счетчик. "THx" и "TLx" включены последовательно
1 | 0 | 8-битный автоперезагружаемый таймер/счетчик. "THx" хранит значение, которое должно быть перезагружено в "TLx" каждый раз по переполнению
1 | 1 | Таймер/счетчик 1 останавливается. Таймер/счетчик 0: TL0 работает как 8-битный таймер/счетчик, и его режим определяется управляющими битами таймера 0. TH0 работает только как 8 битный таймер, и его режим определяется управляющими битами таймера 1
M0 | TMOD.4 для Т/С1 и TMOD.0 для Т/С0

Режим 0

В нулевом режиме таймер работает как 13-битный суммирующий счётчик. Этот счётчик состоит из 8 бит регистра ТНх и младших 5 бит регистра TLx, где x в обозначении регистра заменяется на 0 или 1 в зависимости от того таймера, которым мы управляем. Старшие 3 бита регистров TLx не определены и игнорируются. Установка запускающего таймер флага TR0 или TR1 не очищает эти регистры. Работе таймера 0 или таймера 1 в режиме 0 соответствует схема:

mode0.gif (1742 bytes)

Рисунок 2. Схема таймеров 0 или 1 в режиме 0.

Этот режим был введён для совместимости с устаревшим семейством микроконтроллеров MCS-48 для облегчения переноса уже разработанных программ на новые процессоры и поэтому в настоящее время не используется. Тем не менее, в этом режиме можно обеспечить формирование интервала времени длительностью до 8096 мс при частоте задающего генератора 12 МГц.

Когда содержимое счетчика изменяется из состояния все "1" в состояние все "0" , то устанавливается (принимает значение "1") флаг прерывания таймера TF0 или TF1.

Обычно пользователя интересует не максимальный интервал времени, а свой конкретный интервал времени. Для уменьшения интервала времени в регистры таймера можно предварительно занести число и тем самым сформировать произвольный интервал времени. Рассмотрим пример подготовки таймера T0 для формирования временного интервала 5мс.

;Настроить режим работы таймера-------------------------------------------------------------------------------------------
  mov TMOD,#00000000b          ;настроить таймеры T0 и T1 на нулевой режим работы
           ;||||||||
           ;||||||++-------Перевести таймер T0 в тринадцатиразрядный режим работы
           ;|||||+---------Синхронизироваться от внутреннего генератора
           ;||||+----------Запретить управление таймером от ножки INT0
           ;||++-----------Перевести таймер T1 в тринадцатиразрядный режим работы
           ;|+-------------Синхронизироваться от внутреннего генератора
           ;+--------------Запретить управление таймером от ножки INT1

;Настроить таймер на генерацию 5-ти миллисекундного интервала времени--------------------------------------
    mov TH0, #HIGH(-5000)  ;Загрузить старший байт таймера
    mov TL0, #LOW(-5000)    ;Загрузить младший байт таймера

В рассмотренном примере для расщепления 16-ти битной константы на два отдельных байта были использованы функции выделения старшего и младшего байта. Эти функции присутствуют в большинстве ассемблеров для микроконтроллеров MCS-51. Если же язык программирования не содержит в своём составе подобные функции, то можно для выделения байтов воспользоваться операцией деления на 256.

    mov TH0, #-5000/256          ;Загрузить старший байт таймера
    mov TL0, #-(5000-5000/256)   ;Загрузить младший байт таймера

Режим 1

В первом режиме работы таймер работает как шестнадцатиразрядный счётчик. Режим 1 похож на режим 0, за исключением того, что в регистрах таймера использует все 16 бит. В этом режиме регистры ТНх и TLx также включены друг за другом. Работе таймера 0 или таймера 1 в режиме 1 соответствует схема:

mode1.gif (1777 bytes)

Рисунок 3. Схема таймеров 0 или 1 в режиме 1.

В этом режиме можно обеспечить формирование интервала времени длительностью до 65536 мкс при частоте задающего генератора 12 МГц.

Рассмотрим пример использования таймера T0 для формирования временного интервала 15мс.

;Настроить режим работы таймера-------------------------------------------------------------------------------------------
    mov TMOD,#00000001b ;перевести таймер T0 в первый режим работы, а T1 - в нулевой
             ;||||||||
             ;||||||++-------Перевести таймер T0 в шестнадцатиразрядный режим работы
             ;|||||+-----------Синхронизироваться от внутреннего генератора
             ;||||+------------Запретить управление таймером от ножки INT0
             ;||++-------------Перевести таймер T1 в тринадцатиразрядный режим
             ;|+----------------Синхронизироваться от внутреннего генератора
             ;+-----------------Запретить управление таймером от ножки INT1

;Настроить таймер на генерацию 15-ти миллисекундного интервала времени------------------------------------
    mov TH0, #HIGH(-15000)  ;Загрузить старший байт таймера
    mov TL0, #LOW(-15000)   ;Загрузить младший байт таймера
OjidanTimer:
    jnb TF0, OjidanTimer    ;Подождать пока не переполнится таймер

В рассмотренном примере переполнение таймера произойдёт через 15000 циклов процессора, то есть через 15 мс. Программа будет постоянно проверять состояние флага переполнения таймера и как только он установится в единицу перейдёт к выполнению следующей команды.

Нулевой и первый режимы работы таймеров T0 и T1 предназначены для формирования одиночного интервала времени. Если возникает необходимость формировать последовательность интервалов времени для периодических процессов, то загрузка регистров TH0 и TL0 для задания нужного интервала времени производится программно, что для коротких интервалов времени может привести к значительным затратам процессорного времени.

Для формирования последовательности одинаковых интервалов времени используется режим работы таймера с перезагрузкой - режим 2.

Режим 2

В режиме 2 регистр таймера TLx работает как 8-битный счетчик с автоматической перезагрузкой начального значения из регистра ТНх в регистр TLx. Переполнение регистра TLx не только устанавливает флаг TFx, но и загружает регистр TLx содержимым регистра ТНх, который предварительно инициализируется программно. Перезагрузка не изменяет содержимое регистра ТНх. Работе таймера 0 или таймера 1 в режиме 2 соответствует схема:

mode2.gif (1847 bytes)

Рисунок 4. Схема таймеров 0 или 1 в режиме 2.

Работа с таймерами во втором режиме не отличается от рассмотренных ранее примеров, поэтому следующий пример инициализации таймера на генерацию частоты с периодом сто микросекунд (10кГц) приводится без комментария.

;Настроить режим работы таймера-------------------------------------------------------------------------------------------
   mov TMOD, #00000010b ;перевести таймер T0 во второй режим работы, а T1 - в нулевой
             ;||||||||
             ;||||||++---Перевести таймер T0 в режим 8-ми разр. таймера с автозагрузкой
             ;|||||+-----Синхронизироваться от внутреннего генератора
             ;|||+-------Запретить управление таймером от ножки INT0
             ;||++-------Перевести таймер T1 в тринадцатиразрядный режим
             ;|+---------Синхронизироваться от внутреннего генератора
             ;+----------Запретить управление таймером от ножки INT1

   mov TMOD,#2          ;перевести таймер T0 во второй режим работы, а T1 - в нулевой
   mov TH0, #-50        ;Загрузить старший байт таймера
   mov TL0, #-50        ;Загрузить младший байт таймера

OjidanTimer:
    jnb TF0, OjidanTimer    ;Подождать пока не переполнится таймер

  cpl P2.6              ;Проинвертировать сигнал на шестой ножке второго порта и
  sjmp OjidanTimer      ;снова перейти к ожиданию окончания временного интервала

Режим 3

Таймер 1 при работе в режиме 3 просто хранит свое значение. Эффект такой же как при сбросе бита TR1.

Таймер 0 в режиме 3 представляет собой два раздельных 8 битных счетчика (регистры TL0 и ТН0), Регистр TL0 использует биты управления таймера 0: С/Т0. GATE0, TR0 и TF0. Регистр ТН0 работает только в режиме таймера и использует биты TR1 и TF1 таймера 1. Таким образом, регистр ТН0 управляет прерыванием таймера 1. Логика работы таймера 0 в режиме 3 показана на схеме:

mode3.gif (1824 bytes)

Рисунок 5. Схема таймерa 0 в режиме 3.

Работа таймера TL0 разрешается, если бит TR0 = 1, а таймера TH0 - если бит TR1 = 1. Таймер 1 при работе таймера 0 в режиме 3 постоянно включен.

Этот режим работы позволяет реализовать два независимых таймера, если таймер 1 используется для работы последовательного порта, но надо сказать, что на практике режим 2 мало интересен.

Управление таймерами-счётчиками.

Схема управления таймерами 0 и 1 идентична и для таймера T0 приведена на рисунке 6. Для схемы управления таймером T1 изменятся только номера управляющих бит (нули будут заменены на 1). В приведенной схеме заштрихованным прямоугольником обозначены внешние ножки микросхемы микроконтроллера.

Рисунок 6. Схема управления таймерами 0 или 1.

Из схемы видно, что таймер может включаться и выключаться битами TRx. Таким образом можно уменьшать потребление микросхемы и уровень помех, создаваемый ею. Учитывая, что счетчики таймеров переключаются на высокой частоте, то они могут потреблять до половины тока потребления микроконтроллера. Следует отметить, что при включении и после сброса микроконтроллера работа таймеров запрещена.

Есть возможность управлять работой таймера извне при помощи внешней ножки T0 для таймера T0 или T1 для таймера T1. Для этого необходимо записать в бит GATEx логическую единицу (не забыв при этом разрешить работу таймера при помощи бита TRx).

Кроме того, таймер может синхронизироваться от внешнего генератора. Для этого в бит управления C/T нужно записать логическую единицу.

Биты включения таймеров TR0 и TR1 размещены в регистре TCON (control - управлять), а биты GATE и C/T в регистре TMOD. Формат регистра TCON приведён на следующем рисунке:

TCON.gif (2731 bytes)

Рисунок 7. Формат регистра управления режимами работы таймеров TCON.

Символ | Позиция | Имя и назначение
TF1 | TCON.7 | Флаг переполнения таймера 1. Устанавливается аппаратно при переполнении таймера/счетчика. Сбрасывается при обслуживании прерывания аппаратно
TR1 | TCON.6 | Бит управления таймера 1. Устанавливается/сбрасывается программой для пуска/останова
TF0 | TCON.5 | Флаг переполнения таймера 0. Устанавливается аппаратурно. Сбрасывается при обслуживании прерывания
TR0 | TCON.4 | Бит управления таймера 0. Устанавливается / сбрасывается программой для пуска/останова таймера/счетчика
IE1 | TCON.3 | Флаг фронта прерывания 1. Устанавливается аппаратно, когда детектируется срез внешнего сигнала INT1. Сбрасывается при обслуживании прерывания
IT1 | TCON.2 | Бит управления типом прерывания 1. Устанавливается / сбрасывается программно для определения типа запроса прерывания INT1 (срезу/низким уровнем).
IE0 | TCON.1 | Флаг фронта прерывания 0. Устанавливается по срезу сигнала INT0. Сбрасывается при обслуживании прерывания
IT1 | TCON .0 | Бит управления типом прерывания 0. Устанавливается / сбрасывается программно для определения типа запроса прерывания INT0 (срез/низкий уровень)

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

Использование таймера в качестве измерителя ширины импульсов.

Известно, что измерение длительности импульса можно произвести, подсчитав импульсы эталонной частоты. Принцип измерения длительности импульсов иллюстрируется рисунком 8.

Для измерения длительности импульса измеряемый сигнал подаётся на вывод микроконтроллера INTx и в бит управления GATE записывается разрешающий сигнал логической единицы. Таймер/счётчик настраивается в режим таймера записью в бит C/Tx логического нуля. Содержимое таймера обнуляется.

Пример программы измерения длительности импульса приведён на рисунке 9.

Рисунок 8. Принцип измерения длительности импульсов

     mov TMOD,#00001001b
               ;||||||||
               ;||||||++--Перевести таймер T0 в шестнадцатиразрядный режим
               ;|||||+----Синхронизироваться от внутреннего генератора
               ;||||+-----Включать таймер от ножки микроконтроллера INT0
               ;||++------Перевести таймер T1 в тринадцатиразрядный режим
               ;|+--------Синхронизироваться от внутреннего генератора
               ;+---------Запретить управление таймером от ножки INT1

         mov TH0, #0         ;Обнулить старший байт таймера
         mov TL0, #0         ;Обнулить младший байт таймера

         setb TR0            ;Включить измеритель ширины импульса

TstLog0: jnb INT0, TstLog0   ;Подождать начало импульса
TstLog1: jnb INT0, TstLog1   ;Подождать конец импульса

         Clr TR0             ;Отключить измеритель ширины импульса

Рисунок 9. Программа измерения длительности импульсов

Если теперь на вход микроконтроллера INT0 подать импульс с неизвестной длительностью, то в регистрах TH0 и TL0 будет записана его длительность в микросекундах.

Использование таймера в качестве частотомера.

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

Рисунок 10. Принцип измерения частоты

Для измерения частоты измеряемый сигнал подаётся на вывод микроконтроллера Tx. Таймер/счётчик настраивается в режим счётчика записью в бит C/Tx логической единицы. Содержимое таймера обнуляется. Таймер включается на строго определённый интервал времени. Этот интервал задаётся оставшимся таймером.

Пример программы измерения частоты сигнала на ножке микроконтроллера T0 приведён на рисунке 11.

     mov TMOD,#00010101b
              ;||||||||
              ;||||||++-------Перевести таймер T0 в шестнадцатиразрядный режим
              ;|||||+---------Работать от сигнала на ножке T0
              ;||||+----------Запретить управление таймером от ножки INT0
              ;||++-----------Перевести таймер T1 в шестнадцатиразрядный режим
              ;|+-------------Синхронизироваться от внутреннего генератора
              ;+--------------Запретить управление таймером от ножки INT1

     mov TH0, #0          ;Обнулить старший байт счётчика
     mov TL0, #0          ;Обнулить младший байт счётчика
;---измерение вести 1 мс---------------------------------------------------------
     mov TH1, #HIGH(-1000) ;Загрузить старший байт таймера
     mov TL1, #LOW(-1000)  ;Загрузить младший байт таймера

     mov TCON,#01010000b ;Включить частотомер
              ;||||||||
              ;|||||||+-------Прерывание от ножки INT1возникает по фронту
              ;||||||+--------Сбросить запрос прерывания от ножки INT1
              ;|||||+---------Прерывание от ножки INT1возникает по фронту
              ;||||+----------Сбросить запрос прерывания от ножки INT1
              ;|||+-----------Включить таймер T0
              ;||+------------Обнулить флаг таймера T0
              ;|+-------------Включить таймер T1
              ;+--------------Обнулить флаг таймера T1

TstTimeOut:
     jnb TF1, TstTimeOut     ;Если 1 мс прошла
          mov TCON, #00000000b    ;то отключить частотомер
                    ;||||||||
                    ;|||||||+-------Прерывание от ножки INT1 возникает по фронту
                    ;||||||+--------Сбросить запрос прерывания от ножки INT1
                    ;|||||+---------Прерывание от ножки INT1возникает по фронту
                    ;||||+----------Сбросить запрос прерывания от ножки INT1
                    ;|||+-----------Отключить таймер T0
                    ;||+------------Обнулить флаг таймера T0
                    ;|+-------------Отключить таймер T1
                    ;+--------------Обнулить флаг таймера T1

Рисунок 11. Программа измерения частоты

Если теперь на вход микроконтроллера T0 подать сигнал с неизвестной частотой, то в регистрах TH0 и TL0 будет записана его частота в килогерцах.

[ Главная ]


Язык программирования ASM-51.

Язык программирования АSМ51 поддерживает модульное написание программ. Графическое изображение процесса написания программы на языке программирования ASM-51 приведено на рисунке 1.

Рисунок 1. Процесс написания программы на языке программирования ASM-51.

Файл, в котором хранится программа, написанная на языке АSМ51 (исходный текст программы), называется исходным модулем. Для исходного текста программы принято использовать расширения файла: asm, a51, srs, s51. Исходный текст программы можно написать, используя любой текстовый редактор.

Получить объектный модуль можно, указав имя исходного модуля программы в качестве параметра программы-транслятора в DOS строке или строке командного файла:

asm51.exe modul.asm

Получить исполняемый модуль программы можно, указав все имена объектных модулей программы в качестве параметров программы редактора связей в DOS строке или строке командного файла:

rl51.exe main.obj, modul1.obj, modul2.obj

Имя исполняемого модуля программы по умолчанию совпадает с именем первого объектного файла в списке параметров строки запуска редактора связей. Исполняемый модуль программы записывается в файл без расширения.

Большинство программаторов не может работать с объектным форматом исполняемого модуля программы, поэтому для загрузки машинного кода в процессор необходимо преобразовать объектный формат исполняемого модуля в общепринятый для программаторов гексадецимальный формат. При преобразовании форматов вся отладочная информация теряется. Машинный код процессора в гексадецимальном формате называется загрузочным модулем.

Загрузочный модуль программы можно получить при помощи программы-преобразователя программы oh.exe, передав ей в качестве параметра имя файла исполняемого модуля программы:

oh.exe main

Отладка программ.

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

Рисунок 2. Пример системы отладки программного обеспечения для микроконтроллеров.

Запись исходного текста программы на языке программирования ASM-51.

Исходный текст программы представляет собой последовательность операторов языка, сгруппированных в сегменты и оформленных в виде файла.

Оператор - это базовая конструкция языка программирования, определяющая действия в программе. В языке программирования ASM-51 в одной строке может быть записан только один оператор! Максимальный размер строки - 255 символов. Признаком конца оператора является символ "возврат каретки".

Оператор состоит из трех полей:

<поле метки> <поле операции> <поле комментария>,

Любое из полей, в том числе и все поля, могут отсутствовать. Оператор, в котором все поля отсутствуют, называется пустым оператором. Он используется для увеличения наглядности программы.

Пример оператора, записанного на языке программирования ASM-51:

Поле метки используется для записи меток. Метки используются для организации условных и безусловных переходов, а также для объявления переменных и констант. Признаком конца поля метки является символ "двоеточие" (:). Однако язык программирования ASM-51, в виде исключения, допускает использовать символы интервала как признак конца поля метки.

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

Пример использования оператора, содержащего только метку:

Поле операции используется для записи директивы языка или инструкции микроконтроллера, которые состоят из мнемонического обозначения команды микроконтроллера и одного или нескольких операндов. В качестве операндов могут использоваться адреса ячеек памяти, обозначения регистров или метки операторов. Операнды отделяются друг от друга запятыми. Вместе с запятыми для увеличения читаемости программы допускается использование символов интервала.

Поле комментария начинается с символа "точка с запятой" (;). Это поле используется для записи пояснений к программе. Оператор, в котором присутствует только поле комментария, используется для увеличения наглядности программы.

Комментарий начинается с символа (;) и может содержать любые ASCII символы. Примеры комментариев:

;----------------------------------------------------------------------------------------
; ПОДПРОГРАММА ВЫЧИСЛЕНИЯ ФУНКЦИИ
;----------------------------------------------------------------------------------------
; X + Y * Z


Язык программирования ASM-51

 Rambler's Top100

1. Алфавит языка

Символы исходной программы представляют собой подмножество таблиц символов ASCII для DOS и ANSI для WINDOWS. В исходном тексте программы, написанном на языке программирования PL/M-51 допустимо использование следующих символов:

  • символы интервала,
  • буквы,
  • знаки
  • цифры.

Символы интервала определяют один или несколько пробелов в предложении исходного модуля. К этим символам относятся "пробел" и " табуляция".

В качестве букв воспринимаются латинские буквы верхнего и нижнего регистра:

A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z.

Ниже приведен перечень цифр:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

Наименования знаков и их обозначение приведено в таблице 1:

Наименование | Обозначение
Номер | #
Знак денежной единицы | $
Апостроф | '
круглая скобка левая | (
круглая скобка правая | )
Звездочка | *
Плюс | +
Запятая | ,
Минус | -
Точка | .
дробная черта | /
Двоеточие | :
Точка с запятой | ;
Меньше | <
Равно | =
больше | >
вопросительный знак | ?
коммерческое эт | @

Знаки, комбинации знаков (<>, >=, <= ), а также символы интервала являются разделителями конструкций языка. До и после знака - разделителя в любой конструкции языка могут быть вставлены символы интервала.

ASCII символы, не входящие в перечень основных символов алфавита языка, считаются дополнительными. Эти символы могут использоваться для пояснений в исходном тексте программы, а также для определения символьных констант.

Из символов формируются идентификаторы и числа.

2. Идентификаторы

Идентификатор это символическое обозначение объекта программы. В качестве идентификатора может быть использована любая последовательность букв и цифр. При этом в качестве буквы может быть использована любая буква латинского алфавита, а также вопросительный знак (?) и знак "нижнее подчеркивание" ( _ ). Идентификатор может начинаться только с буквы! Это позволяет отличать его от числа. В идентификаторах, язык программирования ASM-51 различает буквы верхнего и нижнего регистров.

Количество символов в идентификаторе ограничено длиной строки (255 символов). Транслятор различает идентификаторы по первым 31 символам.

Примеры идентификаторов:

ADD5, FFFFH, ?, ALFA_1.

В языке программирования ASM-51 имеются три категории идентификаторов:

  1. ключевые слова;
  2. встроенные имена;
  3. определяемые имена.

2.1. Ключевые слова

Ключевое слово является определяющей частью оператора языка ассемблера. Значения ключевых слов языка ассемблера АSМ-51 не могут быть изменены или переопределены в программном модуле каким-либо образом. Ключевому слову не может быть назначено имя- синоним. Ключевые слова могут быть написаны буквами как верхнего, так и нижнего регистров.

В языке АSМ-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.

Директивы совместно с вспомогательными словами определяют действия в программе, которые должны быть выполнены ассемблером в процессе преобразования исходного текста программы в объектный код. В языке программирования ASM51 используются:

Директивы: BIT, BSEG, CODE, CSEG, DATA, DB, DBIT, DS, DSEG, DW, END, EQU, EXTRN, IDATA, ISEG, NAME, ORG, PUBLIC, RSEG, SEGMENT, SET, USING, XDATA, XSEG.

Вспомогательные слова: 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.

2.2. Встроенные имена

Встроенные имена присвоены адресам регистров специальных функций, адресам флагов специальных функций AR0-AR7, рабочим регистрам R0-R7 текущего банка регистров, а также аккумулятору A и флагу переноса C.

Имя | Регистр
A | Аккумулятор
R0-R7 | 8-разрядный рабочий регистр текущего банка рабочих регистров
DPTR | 16-разрядный регистр-указатель данных
PC | 16-разрядный счетчик команд
C | флаг переноса
AB | регистровая пара, состоящая из аккумулятора A (старшая часть) и регистра B (младшая часть)

2.3. Определяемые имена

Определяемые имена объявляются пользователем. В языке программирования ASM-51 имеются следующие категории определяемых идентификаторов:

  • метки,
  • внутренние и внешние переменные адресного типа,
  • внутренние и внешние переменные числового типа,
  • имена сегментов,
  • названия программных модулей.

3. Числа

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

  • B двоичное число (разрешённые цифры 0,1)
  • Q\O восьмеричное число (разрешённые цифры 0,1,2,3,4,5,6,7)
  • [D] десятичное число (разрешённые цифры 0,1,2,3,4,5,6,7,8,9)
  • H шестнадцатеричное число (разрешённые цифры 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)

Для десятичного числа суффикс может отсутствовать. Количество символов в числе ограничено размером строки, однако значение числа определяется по модулю 2**16 (т.е. диапазон значений числа находится в пределах от 0 до 65535).

Примеры записи чисел:

011101b, 1011100B, 735Q, 456o, 256 , 0fah, 0CBH

Число всегда начинается с цифры. Это необходимо для того, чтобы отличать шестнадцатиричное число от идентификатора.

ADCH - идентификатор
0ADCH - число

Часто бывает удобно выполнить некоторые вычисления для того, чтобы получить число. Язык программирования ASM-51 позволяет выполнять беззнаковые операции над числами. В таких выражениях допустимо использовать арифметические операции:

  1. + суммирование
  2. - вычитание
  3. * умножение
  4. / деление
  5. mod вычисление остатка от целочисленного деления
В языке программирования ASМ-51 также определена одноместная операция '-'. Для нее требуется один операнд, которому она предшествует. Для изменения порядка выполнения операций можно воспользоваться скобками. Кроме арифметических операций в выражениях допустимо использование логических операций:
  1. not побитовая инверсия операнда
  2. and логическое "и"
  3. or логическое "или"
  4. xor "исключающее или" (суммирование по модулю два)

и функций выделения старшего HIGH и младшего LOW байта шестнадцатиразрядного числа.

Пример использования выражений для определения числовой константы:

Часто число используется для представления символов. В этом случае для определения числа можно воспользоваться литеральной константой. Литеральная константа заключается в апострофы:

'a', 'W'

Для записи фраз в памяти программ можно воспользоваться литеральными строками:

В этом случае каждый символ заменяется отдельным байтом и запоминается в ПЗУ памяти программ.


Директивы языка программирования ASM-51.

Язык программирования ассемблер всегда включает в себя машинные коды микроконтроллера, но этим не ограничивается набор команд этого языка. Дело в том, что нужно уметь управлять самим процессом трансляции программы. Полный список директив приведён в описании языка, а здесь будут подробно рассмотрены некоторые из них.

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

Директива equ позволяет назначать имена переменных и констант. Теперь можно назначить переменной адрес в одном месте и пользоваться идентификатором переменной во всей программе. Правда за использование идентификатора именно в качестве переменной отвечает программист, тем не менее, если в процессе написания программы потребуется изменить адрес переменной, это можно сделать в одном месте программы, а не просматривать всю программу, разбираясь является ли в данной конкретной команде число 10 константой, адресом ячейки ли количеством повторов в цикле. Все необходимые изменения сделает сам транслятор. Пример назначения переменных приведён на примере, показанном на рисунке 1.

Рисунок 1. Назначение переменных при помощи директивы equ.

Как видно на приведённом примере, использование идентификаторов значительно повышает понятность программы, так как в названии переменной отображается функция, за которую отвечает данная переменная.

При помощи директивы equ можно назначать не только переменные, но и константы. Как уже говорилось ранее, будет ли использован идентификатор как переменная или как константа зависит от команд и видов адресации, которые использует программист. Один раз назначенный идентификатор уже не может быть изменён и при повторной попытке назначения точно такого же имени идентификатора будет выдано сообщение об ошибке.

Если требуется в различных местах программы назначать одному и тому же идентификатору различные числа, то нужно пользоваться директивой set. Использование этой директивы полностью идентично использованию директивы equ, поэтому иллюстрироваться примером не будет.

Константы, назначаемые директивой equ, могут быть использованы только в одной команде. Достаточно часто требуется работа с таблицей констант, такой как таблица перекодировки, таблицы элементарных функций или синдромы помехоустойчивых кодов. Такие константы используются не на этапе трансляции, а хранятся в памяти программ микроконтроллера. Для занесения констант в память программ микроконтроллера используются директивы db и dw.

Директива db используется для занесения в память программ однобайтных констант. Пример использования директивы db приведён на рисунке 2.

Рисунок 2. Назначение констант при помощи директивы db.

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

В директиве db можно задавать сразу несколько констант, разделённых запятыми. Можно одновременно использовать все системы счисления, но обычно имеет смысл снабдить каждую константу комментарием, как это сделано в предыдущем примере. Так программа становится более понятной и легче искать допущенную ошибку.

Эта же директива позволяет легко записывать надписи, которые в дальнейшем потребуется высвечивать на встроенном дисплее или экране дисплея универсального компьютера, подключённого к разрабатываемому устройству через какой либо интерфейс. Пример использования директивы db для занесения надписей в память программ микроконтроллера приведён на рисунке 3.

Рисунок 3. Применение директивы db для занесения надписей в память программ микроконтроллера.

Директива dw позволяет заносить в память программ двухбайтные числа. В этой директиве, как и в директиве db числа можно заносить через запятую. Пример листинга фрагмента программы приведён на рисунке 4.

Рисунок 4. Применение директивы dw.

На рисунке 4 приведён фрагмент листинга программы для того, чтобы можно было проследить какие байты заносятся в память программ микроконтроллера. В самой правой колонке листинга приведены адреса в которые будут занесены числа, являющиеся операндами директивы dw. В следующей колонке приведены двухбайтовые числа, которые будут заноситься в память программ микроконтроллера. Обратите внимание, что несмотря на то, что первые два операнда состоят только из одной цифры, в память микроконтроллера заносятся четыре шестнадцатеричных цифры (двухбайтовое число).

При трансляции исходного текста программ предполагается, что первая команда расположена по нулевому адресу. Адрес последующих команд зависит от длины и количества предыдущих команд. Пример листинга начального участка программы приведён на рисунке 5.

Рисунок 5. Пример листинга программы.

Иногда требуется расположить команду по определённому адресу. Наиболее часто это требуется при использовании прерываний, когда первая команда программы-обработчика прерываний должна быть расположена точно на векторе прерывания. Это можно сделать используя команду nop для заполнения промежутков между векторами прерывания, но лучше воспользоваться директивой ORG.

Директива org предназначена для записи в счетчик адреса сегмента значения своего операнда. То есть при помощи этой директивы можно разместить команду (или данные) в памяти микроконтроллера по любому адресу. Пример использования директивы ORG для размещения подпрограмм обработки прерываний на векторах прерываний показан на рисунке 6.

Рисунок 6. Пример использования директивы ORG.

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

Директива using При использовании прерываний критичным является время, занимаемое программой, обработчиком прерываний. Это время можно значительно сократить, выделив для обработки прерываний отдельный банк регистров. Выделить отдельный банк регистров можно при помощи директивы USING. Номер банка используемых регистров указывается в директиве в качестве операнда. Пример использования директивы USING для подпрограммы обслуживания прерываний от таймера 0 приведён на рисунке 7.

Рисунок 7. Пример использования директивы USING.

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


Реализация процедур и функций на языке ASM51

 Rambler's Top100

Реализация подпрограмм на языке ASM51.

Подпрограммы на языке программирования ASM-51 выносятся отдельно от основного текста программы. Обычно подпрограммы размещают после основного текста программы для того, чтобы случайно не передать управление подпрограмме не оператором вызова подпрограммы. Это может произойти из-за того, что ассемблер назначает адреса операторам в порядке их написания.

Исходный текст подпрограммы начинается с метки, которая одновременно является именем подпрограммы. Именно это имя указывается в качестве операнда в команде вызова подпрограммы LCALL. Возвращение из подпрограммы на оператор, следующий за оператором вызова подпрограммы осуществляется оператором RET. Все операторы, которые должны быть выполнены в подпрограммы располагаются между меткой, обозначающей имя подпрограммы и оператором возврата из подпрограммы.

Реализация подпрограмм-процедур на языке ASM51.

Подпрограмма процедура вызывается командами процессора LCALL и ACALL. В языке программирования ASM51 допустимо использования директивы CALL эта директива подбирает наиболее подходящую к данному случаю по размеру команду.

Пример подпрограммы управления последовательным портом:

Рисунок 1. Пример подпрограммы - процедуры.

Передача переменных-параметров в подпрограмму.

В приведённом выше примере байт передаётся в подпрограмму через глобальную переменную G_Per. Однако программа будет эффективнее при использовании подпрограммы с параметрами. Мы знаем, что параметр подпрограммы - это локальная переменная. В этом случае могут значительно снизиться требования к памяти данных. Для размещения локальных переменных лучше всего использовать внутренние регистры процессора. На языке ASM51 для передачи параметра размерностью один байт обычно используется аккумулятор как показано в примере программы, приведённом на рисунке 2.

Рисунок 2. Пример подпрограммы - процедуры с передачей байта через аккумулятор.

Вызов такой подпрограммы на языке программирования С выглядел бы следующим образом:

Если в подпрограмму нужно передать двухбайтовое значение, то в качестве параметра подпрограммы используется пара регистров (обычно регистры R6-старший байт и R7-младший байт). Пример программы, передающей в подпрограмму двухбайтовое число, написанной на языке программирования ASM-51 приведён на рисунке 3.

Рисунок 3. Пример подпрограммы - процедуры с передачей двухбайтного числа через регистры R7 и R6.

Если в подпрограмму нужно передать четырёхбайтовое значение (это требуется для переменной, соответствующей типу long или float), то используются регистры R4...R7 (регистр R4 - старший байт):

Регистры R0 и R1 обычно используются в качестве указателей обрабатываемых переменных таких как строки или массивы. Если требуется, чтобы подпрограмма обработала значительный объём данных, как например:

то эти данные можно передать через параметр - указатель. В качестве указателя при обращении к внешней памяти данных или к памяти программ обычно используется регистр-указатель данных DPTR. Пример передачи в качестве параметра строки, написанный на языке программирования ASM-51 приведён на рисунке 4:

Рисунок 4. Пример подпрограммы - процедуры с передачей адреса строки через регистр DPTR.

При обращении к массивам или структурам, расположенным во внутренней памяти данных в качестве указателя адреса используется регистр R0 или R1. Пример передачи в подпрограмму массива в качестве параметра, написанный на языке программирования ASM-51 приведён на рисунке 5:

Рисунок 5. Пример подпрограммы - процедуры с передачей адреса массива через регистр R0.

Реализация подпрограмм-функций на языке ASM51.

Часто требуется передавать результат вычислений из подпрограммы в основную программу. Для этого можно воспользоваться подпрограммой - функцией. Подпрограмма - функция возвращает вычисленное значение. Пример использования подпрограммы - функции на языке программирования высокого уровня:

Как видно из приведённого примера, использование подпрограмм-функций значительно увеличивает наглядность программ и приближает запись на языке программирования к записи математического выражения. На языке программирования ASM51 этот же вызов подпрограммы-функции выглядит следующим образом:

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

Подпрограмма - функция может возвращать и многобайтовые переменные, используя регистр - указатель R0 или R1. Однако для копирования этих переменных потребуется ещё одна подпрограмма копирования.

Реализация подпрограмм обработки прерываний на языке ASM51.

Как известно, подпрограммы обработки прерываний вызываются аппаратурой, поэтому эти подпрограммы не могут иметь параметров. Кроме того эти подпрограммы не могут быть подпрограммами-функциями. При возвращении из подпрограммы обработки прерывания должны быть разрешены дальнейшие прерывания, поэтому возврат из подпрограммы обработки прерывания может быть осуществлён только командой RETI.

Подпрограмма обработки прерываний не должна портить содержимое регистров, поэтому все регистры, которые используются подпрограммой обработки прерываний должны быть сохранены в стеке, а затем восстановлены из него. Пример подпрограммы обработки прерывания приведён на рисунке 6.

Рисунок 6. Пример подпрограммы обработки прерывания.

В приведённом примере директива CSEG AT 0BH использована для того, чтобы разместить подпрограмму обработки прерывания на вектор прерывания от таймера 0.

Достаточно часто требуется обработка прерываний от нескольких источников, поэтому подпрограммы относятся из области векторов прерывания. Для перехода на эти подпрограммы используются команды безусловного перехода. Пример такой подпрограммы обработки прерывания приведён на рисунке 7.

Рисунок 7. Пример подпрограммы обработки прерывания.

Если подпрограмма обработки прерывания использует несколько регистров, то на сохранение регистров в стеке и на восстановление их из стека тратится достаточно много времени. Микроконтроллеры семейства MCS-51 предлагают возможность использовать для подпрограмм прерываний отдельный банк регистров. В языке программирования ASM-51 то, что программа использует не нулевой банк регистров отображается при помощи директивы USING как это показано в примере на рисунке 8.

Рисунок 8. Пример подпрограммы обработки прерывания с использованием второго банка регистров.


Многомодульные программы

 Rambler's Top100 Дата последнего обновления файла 21.01.05

Многомодульные программы.

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

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

Все эти проблемы могут быть решены при раздельной трансляции программы. То есть было бы неплохо уметь транслировать каждый файл с исходным текстом программы отдельно и соединять затем готовые оттранслированные участки программы.

На первый взгляд раздельная трансляция не должна вызывать каких либо проблем. Однако это не так. При компиляции исходного текста программы транслятор составляет таблицу ссылок на константы, переменные и команды. Если при втором просмотре исходного текста программы, во время которого формируется объектный модуль, транслятор не обнаружит имени переменной или метки в своей таблице, то будет сформировано сообщение об ошибке и объектный модуль будет стёрт с диска компьютера.

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

EXTRN DATA (BufInd, ERR)
EXTRN CODE (Podprogr)

Для того, чтобы редактор связей мог осуществить связывание модулей в единую программу, переменные и метки, объявленные по крайней мере в одном из модулей как EXTRN, в другом модуле должны быть объявлены как доступные для всех модулей при помощи директивы PUBLIC . Пример использования директивы PUBLIC на языке программирования ASM-51:

PUBLIC BufInd, Parametr
PUBLIC Podprogr, ?Podprogr?Byte

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

Для объединения нескольких модулей в исполняемую программу имена всех модулей передаются в редактор связей rl51.exe в качестве параметров при запуске этой программы. Пример вызова редактора связей из командной строки DOS для объединения трёх модулей:

rl51.exe progr.obj, modul1.obj, modul2.obj

В результате работы редактора связей в этом примере будет создан исполняемый модуль с именем progr. Формат записи информации в этом файле остаётся прежним - объектный. Это позволяет объединять модули по частям, то есть при желании можно из нескольких мелких модулей получить один более крупный.

В настоящее время часто пользуются интегрированными средами программирования, такими как Franclin или keil C, в состав которых входят язык программирования ASM‑51. В этих программах создание строки вызова редактора связей производится автоматически при настройке программного проекта, а вызов этой строки производится при трансляции программного проекта. Настройка программного проекта происходит при подключении к проекту новых программных модулей и при изменении свойств программного проекта, таких как разрешение или запрет создания карты памяти программы, выбор папки для хранения выходных файлов, разрешение или запрет помещения в выходной файл отладочной информации разрешение или запрет создания загрузочного HEX файла.


Многомодульные программы

 Rambler's Top100 Дата последнего обновления файла 21.01.05

Использование сегментов в языке программирования ассемблер.

Как только встал вопрос о транслировании программы по частям возникает вопрос как с этими частями работать. Справедливости ради необходимо отметить, что даже когда мы не задумываемся о сегментах, в программе присутствует два сегмента: память программ и память данных. Если внимательно присмотреться к программе, то можно обнаружить, что кроме команд в памяти программ хранятся константы, то есть в памяти программ располагаются по крайней мере два сегмента: программа и данные. Чередование программы и данных может привести к нежелательным последствиям. Вследствие каких либо причин случайно данные могут быть выполнены в качестве программы или наоборот программа может быть воспринята и обработана как данные.

Рисунок 1. Разбиение памяти программ и памяти данных на сегменты.

Перечисленные выше причины приводят к тому, что желательно явным образом выделить по крайней мере три сегмента:

  1. программу;
  2. переменные;
  3. константы.

Наиболее простой способ определения сегментов это использование абсолютных сегментов памяти. При этом способе распределение памяти ведётся вручную точно также, как это делалось при использовании директивы EQU. В этом случае начальный адрес сегмента жёстко задаётся программистом и он же следит за тем, чтобы сегменты не перекрывались друг с другом в памяти микроконтроллера. Использование абсолютных сегментов позволяет более гибко работать с памятью данных, так как теперь байтовые переменные в памяти данных могут быть назначены при помощи директивы резервирования памяти DS, а битовые переменные при помощи директивы резервирования битов DBIT.

Для определения абсолютных сегментов памяти используются директивы:

  1. BSEG - абсолютный сегмент в области битовой адресации
  2. CSEG - абсолютный сегмент в области памяти программ
  3. DSEG - абсолютный сегмент в области внутренней памяти данных
  4. ISEG - абсолютный сегмент в области внутренней памяти данных с косвенной адресацией
  5. XSEG - абсолютный сегмент в области внешней памяти данных

Директива BSEG позволяет определить абсолютный сегмент во внутренней памяти данных с битовой адресацией по определённому адресу. Эта директива не назначает имени сегменту, то есть объединение сегментов из различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут AT. Если атрибут AT не используется, то начальный адрес сегмента предполагается равным нулю. Использование битовых переменных позволяет значительно экономить внутреннюю память программ микроконтроллера. Пример использования директивы BSEG для объявления битовых переменных приведён на рисунке 2.

Рисунок 2. Пример использования директивы BSEG для объявления битовых переменных.

Директива CSEG позволяет определить абсолютный сегмент в памяти программ по определённому адресу. Эта директива не назначает имени сегменту, то есть объединение сегментов из различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут AT. Если атрибут AT не используется, то начальный адрес сегмента предполагается равным нулю. Пример использования директивы CSEG для размещения подпрограммы обслуживания прерывания от таймера 0 приведён на рисунке 3.

Рисунок 3. Пример использования директивы CSEG для размещения подпрограммы обслуживания прерывания.

Директива DSEG позволяет определить абсолютный сегмент во внутренней памяти данных по определённому адресу. Предполагается, что к этому сегменту будут обращаться команды с прямой адресацией. Эта директива не назначает имени сегменту, то есть объединение сегментов из различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут AT. Если атрибут AT не используется, то начальный адрес сегмента предполагается равным нулю. Пример использования директивы DSEG для объявления байтовых переменных приведён на рисунке 4.

Рисунок 4. Пример использования директивы DSEG для объявления байтовых переменных.

В приведённом примере предполагается, что он связан с примером, приведённом на рисунке 2. То есть команды, изменяющие битовые переменные RejInd, RejPriem или Flag одновременно будут изменять содержимое переменной Rejim, и наоборот команды работающие с переменной Rejim одновременно изменяют содержимое флагов RejInd, RejPriem или Flag. Такое объявление переменных позволяет написать наиболее эффективную программу управления контроллером и подключенными к нему устройствами.

Директива ISEG позволяет определить абсолютный сегмент во внутренней памяти данных по определённому адресу. Напомню, что внутренняя память с косвенной адресацией в два раза больше памяти с прямой адресацией. Эта директива не назначает имени сегменту, то есть объединение сегментов из различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут AT. Если атрибут AT не используется, то начальный адрес сегмента предполагается равным нулю. Пример использования директивы ISEG для объявления байтовых переменных приведён на рисунке 5.

Рисунок 5. Пример использования директивы ISEG для объявления байтовых переменных.

Директива XSEG позволяет определить абсолютный сегмент во внешней памяти данных по определённому адресу. Эта директива не назначает имени сегменту, то есть объединение сегментов из различных программных модулей невозможно. Для определения конкретного начального адреса сегмента применяется атрибут AT. Если атрибут AT не используется, то начальный адрес сегмента предполагается равным нулю. До недавнего времени использование внешней памяти не имело смысла, так как это значительно увеличивало габариты и цену устройства. Однако в последнее время ряд фирм стал размещать на кристалле значительные объёмы ОЗУ, доступ к которому осуществляется как к внешней памяти. Так как использование этой директивы не отличается от использования директивы DSEG, то отдельный пример приводиться не будет.

Использование абсолютных сегментов позволяет облегчить работу программиста по распределению памяти микроконтроллера для различных переменных. Однако в большинстве случаев абсолютный адрес переменной нас совершенно не интересует. Исключение составляют только регистры специальных функций. Так зачем же вручную задавать начальный адрес сегментов?

Еще одна ситуация, когда нас не интересует начальный адрес сегмента – это программные модули. Как уже говорилось ранее, в программные модули обычно выносятся подпрограммы. Естественно, что где конкретно будут находиться эти подпрограммы в адресном пространстве микроконтроллера, нас тоже мало интересует.

Если абсолютные адреса переменных или участков программ не интересны, то можно воспользоваться перемещаемыми сегментами. Имя перемещаемого сегмента задается директивой segment.

Директива segment позволяет определить имя сегмента и область памяти, где будет размещаться данный сегмент памяти. Для каждой области памяти определено ключевое слово:

  • data – размещает сегмент во внутренней памяти данных с прямой адресацией;

  • idata – размещает сегмент во внутренней памяти данных с косвенной адресацией;

  • bit – размещает сегмент во внутренней памяти данных с битовой адресацией;

  • xdata – размещает сегмент во внешней памяти данных;

  • code – размещает сегмент в памяти программ;

После определения имени сегмента можно использовать этот сегмент при помощи директивы rseg. Использование сегмента зависит от области памяти, для которой он предназначен. Если это память данных, то в сегменте объявляются байтовые или битовые переменные. Если это память программ, то в сегменте размещаются константы или участки кода программы. Пример использования директив segment и rseg для объявления битовых переменных приведен на рисунке 8.31.

_data segment idata

public VershSteka

;Определение переменных----------------------------

rseg _data

buferKlav: ds 8

VershSteka:

End

Рис. 8.31. Пример использования директив segment и rseg для объявления байтовых переменных

В этом примере объявлена строка buferKlav, состоящая из восьми байтовых переменных. Кроме того, в данном примере объявлена переменная VershSteka, соответствующая последней ячейке памяти, используемой для хранения переменных. Переменная VershSteka может быть использована для начальной инициализации указателя стека для того, чтобы отвести под стек максимально доступное количество ячеек внутренней памяти. Это необходимо для того, чтобы избежать переполнения стека при вложенном вызове подпрограмм.

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

Еще один пример использования директив segment и rseg приведен на рисунке 8.32. В этом примере директива segment используется для объявления сегмента битовых переменных.

_bits segment bit

public knIzm,strVv

;Определение битовых переменных -------------------------------------

rseg _bits

knIzm: dbit 1

strVv: dbit 1

end

Рис. 8.32. Пример использования директив segment и rseg для объявления битовых переменных


Структурное программирование

Структурное программирование на языке ASM-51.

Применение структурного программирования позволяет увеличить скорость написания программ и облегчить отладку написанной программы. Языки программирования C, PASCAL, PL/M разрабатывались на основе принципов структурного программирования, поэтому в состав этих языков программирования входят структурные операторы. Тем не менее структурное программирование возможно и на языках программирования низкого уровня в том числе и на языке программирования ASM-51, где не предусмотрено структурных операторов,

При написании программы с использование методов структурного программирования эта программа может быть оттранслирована и выполнена на любом этапе написания программы, при этом можно отследить все алгоритмические действия программы, написанные к этому времени. При использовании методов структурного программирования процесс написания программы не отличается от процесса создания алгоритма. Более того, эти этапы создания программы можно объединить.

Для реализации методов структурного программирования огромное значение имеет использование "говорящих меток", когда метки обозначаются не просто M0, M1 и т.д., а в названии метки отображается действие, выполняемое программой. Для людей, не владеющих иностранным языком ограничение в использовании для назначения меток букв только латинского алфавита создаёт определённые трудности. Тем не менее и латинскими буквами можно писать русские слова! При этом для обозначения действия может потребоваться несколько слов, использование же пробелов внутри метки недопустимо! Выйти из такой ситуации можно двумя способами:

  • использование специальных символов-разделителей;
  • начинать каждое новое слово внутри метки с буквы верхнего регистра

В качестве символов-разделителей можно использовать символы подчёркивания '_' и вопроса '?' Примеры назначения говорящих меток:

Надо сказать, что в языке программирования ассемблер роль метки исключительно важна. Метка используется для обозначения переменных и констант, а также имён подпрограмм и программных модулей.

Основная идея структурного программирования заключаются в том, что существует только четыре структурных оператора. Используя эти структурные операторы можно построить сколь угодно сложную программу.

Наиболее распространённый структурный оператор называется линейная цепочка операторов. Любая задача может быть разбита на несколько подзадач. Выполнение подзадач лучше оформить как подпрограмму, в названии которой можно (и нужно) отразить подзадачу, которую должна решать эта подпрограмма. Например:

При этом с точки зрения структурного программирования использовать подпрограмму имеет смысл даже тогда, когда действие будет выполняться только один раз! Выполняемое алгоритмическое действие отображается в названии подпрограммы, поэтому программу можно читать по названиям подпрограмм. Человеческий глаз может охватить большую часть алгоритма, а значит программа будет более понятна, что приведёт к более быстрому завершению отладки программы. Программы, понятные при чтении исходного текста программы, часто называют самодокументирующимися.

На момент написания алгоритма (и программы) верхнего уровня нас не интересует, как будет решаться эта задача, поэтому вместо настоящей подпрограммы поставим подпрограмму-заглушку. Пример подобной программы приведён на рисунке 1.

Рисунок 1. Пример использования подпрограмм для структурирования программы, написанной на языке программирования ASM-51.

Второй структурный оператор - условный оператор. Если условный оператор реализуется только с одним плечом, то для его реализации можно воспользоваться любой командой условного перехода. Пример использования команд условного перехода для реализации условного оператора с одним плечом приведён на рисунке 2.

Рисунок 2. Пример использования команд условного перехода для реализации условного оператора с одним плечом.

Полная схема условного оператора реализуется на языке ассемблер более сложным образом. Для реализации такого оператора потребуется уже две команды микроконтроллера. Для исключения выполнения второго плеча условного оператора потребуется команда безусловного перехода. Пример реализации условного оператора приведён на рисунке 3.

Рисунок 3. Пример реализации условного оператора на языке программирования ASM-51.

Третий структурный оператор - это оператор цикла с проверкой условия после тела цикла . Такой оператор легко реализуется на языке программирования ассемблер при помощи команды условного или безусловного перехода. Отличие от условного оператора заключается в том, что передача управления осуществляется не вперёд, а назад. На языках программирования высокого уровня такой оператор входит в состав языка (оператор do..while в языке программирования C или оператор repeat..until в языке программирования PASCAL). На языке программирования ассемблер для реализации этого оператора можно воспользоваться любой условной операцией. Однако для реализации оператора цикла в системе команд микроконтроллера MCS-51 предусмотрена специальная команда, выполняющая сразу два алгоритмических действия - DJNZ. Пример использования этой команды для реализации оператора цикла приведён на рисунке 4.

Рисунок 4. Пример оператор цикла с проверкой условия после тела цикла на языке программирования ASM-51.

Четвёртый структурный оператор - это оператор цикла с проверкой условия до тела цикла . В отличие от предыдущего оператора тело цикла в этом операторе может ни разу не выполниться, если условие цикла сразу же выполнено. Этот оператор как и условный оператор невозможно реализовать на одной машинной команде. Для реализации этого оператора тоже потребуется команда безусловного перехода:

Рисунок 5. Пример оператор цикла с проверкой условия до тела цикла на языке программирования ASM-51.


Структура языка программирования C-51

 Rambler's Top100 Дата последнего обновления файла 07.09.2005

Язык программирования C-51.

Язык программирования C – это язык программирования общего назначения, предназначенный для написания программ, эффективных по исполняемому коду с элементами структурного программирования и богатым набором операторов. Язык программирования C практически не имеет ограничений, что позволяет использовать язык программирования C для эффективного решения широкого круга задач. Однако при написании программ для микроконтроллеров необходимо учитывать особенности построения аппаратуры этих микросхем.

В состав языка программирования С-51 введён ряд изменений, отображающих особенности построения памяти микроконтроллеров семейства MCS-51. Кроме того, эти изменения позволяют непосредственно обращаться к встроенным портам, таймерам и другим устройствам микроконтроллеров указанного семейства. Особенности микроконтроллеров этого семейства в основном отображаются через описания переменных.

Язык программирования С-51 удовлетворяет стандарту ANSI-C. Этот язык программирования предназначен для получения компактных и быстродействующих программ, предназначенных для микроконтроллеров семейства MCS-51. Язык С-51 обеспечивает гибкость программирования на широко известном языке программирования C, при скорости работы и компактности, сравнимой с программами, написанными на языке программирования ассемблер.

Так как язык программирования C не имеет собственных средств ввода и вывода, то он обращается к соответствующим функциям операционных систем. В языке программирования С51 вместо этого имеется возможность изменять библиотечные функции, и тем самым обращаться к конкретным ячейкам памяти микроконтроллера, для которого пишется программа.

Компилятор c51.exe - это программное средство, которое транслирует исходный текст, написанный на языке программирования C51 в перемещаемые объектные модули. Эти модули затем могут объединяться с другими модулями, написанными на языках программирования C51, PLM-51 или ASM-51. Компилятор выводит на экран дисплея или в файлы листингов сообщения об ошибках и вспомогательную информацию, которая может быть использована при отладке и разработке программ.

Компилятор c51.exe может быть установлен на компьютерах серии IBM или совместимых с ними в операционной системе DOS 3.Х и выше и использоваться для генерации команд микроконтроллеров семейства MCS-51.

Применение.

Язык программирования C-51 и его библиотеки являются частью интегрированного набора средств разработки программного обеспечения для микроконтроллеров семейства MCS-51. Язык программирования C51 поддерживает модульное написание программ. Процесс разработки программ на языке программирования C-51 показан на рисунке 1.

Рисунок 1. Процесс написания программы на языке программирования С-51.

При разработке программного обеспечения выполняются следующие этапы:

  • постановка задачи (полное определение решаемой проблемы);
  • разработка принципиальной схемы и выбор необходимого программного обеспечения;
  • разработка системного программного обеспечения. Этот важный шаг состоит из нескольких этапов, включающих: описание последовательности выполняемых каждым блоком задач, выбор языка программирования и используемых алгоритмов;
  • написание текста программы и подготовка к трансляции при помощи любого текстового редактора;
  • компиляция программы;
  • исправление синтаксических ошибок, выявленных компилятором, в текстовом редакторе с последующей перетрансляцией;
  • создание и сохранение библиотек часто используемых объектных модулей при помощи программы lib51.ехе;
  • связывание полученных перемещаемых объектных модулей в абсолютный модуль и размещение переменных в памяти микроконтроллера при помощи редактора связей bl51.exe;
  • создание программы, записываемой в ПЗУ микроконтроллера (загружаемый модуль) в hex формате, при помощи программы oh.exe;
  • проверка полученной программы при помощи символьного отладчика или других программных или аппаратных средств.

Файл, в котором хранится программа, написанная на языке C51 (исходный текст программы), называется исходным модулем. Для исходного текста программы принято использовать расширения файла: '*.c'. Исходный текст программы можно написать, используя любой текстовый редактор, однако намного удобнее воспользоваться интегрированной средой программирования, подобной keil-C. В интегрированную среду программирования кроме текстового редактора обычно входят отладчик программ, менеджер проектов и средства запуска программ-трансляторов.

В интегрированной среде программирования процесс трансляции исходного текста программы проходит намного проще. Для получения объектного модуля достаточно нажать на кнопку трансляции файла, как это показано на рисунке 2.

Рисунок 2. Кнопка трансляции исходного текста файла в интегрированной среде программирования keil-c.

Готовый оттранслированный участок программы обычно хранится на диске в виде файла, записанного в объектном формате. Такой файл называется объектным модулем. Получить объектный модуль можно, указав имя исходного модуля программы в качестве параметра программы-транслятора в DOS строке или строке командного файла, как это показано в следующем примере:

c51.exe modul.c

В этом примере в результате трансляции исходного текста программы, содержащегося в файле modul.c будет получен объектный модуль, который будет записан в файл с именем modul.obj. Как показано на рисунке 1, объектный модуль не может быть загружен в память программ микроконтроллера. В память микроконтроллера загружается исполняемый модуль.

Программа, которая может быть выполнена микроконтроллером, получается после соединения объектных модулей в единый исполняемый модуль. Получить исполняемый модуль программы можно, указав все имена объектных модулей программы в качестве параметров программы редактора связей в DOS строке или строке командного файла, как это показано в следующем примере:

bl51.exe main.obj, modul1.obj, modul2.obj

Имя исполняемого модуля программы по умолчанию совпадает с именем первого объектного файла в списке параметров строки запуска редактора связей. Исполняемый модуль программы записывается в файл без расширения. При выполнении приведённой выше в качестве примера командной строки будет получен исполняемый модуль, который будет записан в файл с именем main.

В интегрированной среде программирования процесс получения исполняемого модуля не сложнее предыдущего варианта. Для трансляции всего программного проекта достаточно нажать на соответствующую кнопку, как это показано на рисунке 3.

Рисунок 3. Кнопка получения исполняемого и загрузочного модулей в интегрированной среде программирования keil-c.

Большинство программаторов, предназначенных для записи информации в память программ микроконтроллеров, не может работать с объектным форматом исполняемого модуля программы, поэтому для загрузки машинного кода в процессор необходимо преобразовать объектный формат исполняемого модуля в общепринятый для программаторов HEX-формат. При преобразовании форматов вся отладочная информация теряется. Машинный код процессора в HEX-формате называется загрузочным модулем.

Загрузочный модуль программы можно получить при помощи программы-преобразователя программы oh.exe, передав ей в качестве параметра имя файла исполняемого модуля программы, например:

oh.exe main

В результате выполнения этой командной строки будет получен загрузочный модуль программы, который будет записан в файл с именем main.hex.

В интегрированной среде программирования загрузочный файл получается автоматически при выполнении трансляции программного проекта, так как интегрированная среда программирования сама выполняет перечисленные выше действия в соответствии с настройками программного проекта.

Отладка программ.

После того, как программные модули были успешно оттранслированы, размещены по конкретным адресам и связаны между собой, для отладки программы можно воспользоваться любым из методов, показанных на рисунке 1:

  • внутрисхемным эмулятором
  • встроенным программным отладчиком
  • внешним программным отладчиком
  • отлаживаемым устройством с записанным в память программ двоичным кодом программы

Внутрисхемный эмулятор с отображением переменных языка программирования на дисплее компьютера оказывает значительную помощь при отладке программ непосредственно на разрабатываемой аппаратуре. Этот метод отладки предоставляет наиболее удобную среду, когда можно непосредственно в отлаживаемом устройстве останавливать программу, контролировать выполнение программы непосредственно по исходному тексту программы, состояние внешних портов и внутренних переменных, как входящих в состав микросхемы, так и объявленных при написании исходного текста программы. Необходимое для отладки программ оборудование показано на рисунке 2.

Рисунок 2. Пример системы отладки программного обеспечения для микроконтроллеров.

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

  • включение информации о типе переменных для проверки типов при связывании модулей. Эта же информация используется внутрисхемным эмулятором. Исключение информации о переменных пользователя может использоваться для создания прототипов или для уменьшения размера объектного модуля;
  • включение или исключение таблиц символьной информации;
  • конфигурация вызовов подпрограмм для обеспечения связывания с модулями, написанными на языке программирования ASM-51;
  • определение желаемого содержания и формата выходного листинга программы. Распечатка промежуточных кодов на языке ассемблер после компилирования программ, написанных на языке программирования PLM-51. Включение или исключение листингов отдельных блоков исходного текста.

[ Главная ]


Объявление переменных в PL/M-51

 Rambler's Top100 Дата последнего обновления файла 26.09.2005

Объявление массивов в языке программирования C-51

Массивы - это группа элементов одинакового типа (float, char, int и т.п.). Из объявления массива компилятор должен получить информацию о типе элементов массива и их количестве. Объявление массива имеет два формата:

спецификатор-типа описатель [константное-выражение];
спецификатор-типа описатель [ ];

Описатель - это идентификатор массива.

Спецификатор-типа задает тип элементов объявляемого массива. Элементами массива не могут быть функции и элементы типа void.

Константное-выражение в квадратных скобках задает количество элементов массива. Константное- выражение при объявлении массива может быть опущено в следующих случаях:

  • при объявлении массив инициализируется,
  • массив объявлен как формальный параметр функции,
  • массив объявлен как ссылка на массив, явно определенный в другом файле.

В языке СИ определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком константных-выражений следующих за идентификатором массива, причем каждое константное-выражение заключается в свои квадратные скобки.

Каждое константное-выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных-выражения, трехмерного - три и т.д. Отметим, что в языке СИ первый элемент массива имеет индекс равный 0.

Примеры:

     int a[2][3]; /* представлено в виде матрицы
                     a[0][0]  a[0][1] a[0][2]
                     a[1][0]  a[1][1] a[1][2] */
     double b[10]; /* вектор из 10  элементов имеющих тип double */
     int w[3][3] = { { 2, 3, 4 },
                     { 3, 4, 8 },
                     { 1, 0, 9 } };

В последнем примере объявлен массив w[3][3]. Списки, выделенные в фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.

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

Примеры:

int s[2][3];

Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s.

int b[2][3][4];

При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению наложенному на использование сечений массива.

Для работы с символьными строками в языке программирования С используются массивы символов, например:

char str[] = "объявление массива символов";

Следует учитывать, что в символьной строке находится на один элемент больше, так как последним элементом строки должен быть '\0'. В этом примере использовано неявное задание длины массива символов. Это стало возможным так как массиву сразу присваивается конкретное значение. При программировании микроконтроллеров семейства MCS-51 такое задание массива может привести к неоправданному расходу внутренней памяти данных, поэтому лучше воспользоваться размещением строки в памяти программ:

char code str[] = "объявление массива символов";

Структуры

Работа с массивами облегчает понимание и написание программы, когда для обозначения похожих элементов используется один идентификатор. Однако в ряде случаев приходится обрабатывать разнородные элементы, описывающие один объект. В этом случае вместо массива используется структура.

Cтруктура - это составной объект, в который входят элементы любых типов, за исключением функций. В отличие от массива, который является однородным объектом, структура может быть неоднородной. Тип структуры определяется записью вида:

struct { список описаний}

В структуре обязательно должен быть указан хотя бы один компонент. Компоненты структуры называются полями структуры. Объявление полей производится в следующем виде:

тип-данных описатель;

где тип-данных указывает тип структуры для объектов, определяемых в описателях. В простейшей форме описатели представляют собой идентификаторы переменных или массивов.

Пример объявления структур:

  struct//Описание типа структуры-------------------------
  {char tzvet,//Цвет точки
   int  x,    //Координата X
        y;    //Координата Y
  }//------------------------------------------------------
 tochka1, tochka2, //Переменные, обозначающие точки дисплея
 simv[7][9];       //Переменная, содержащая рисунок символа

 struct
 {int year;    //Поле структуры, в котором хранится год
  char  moth,  //Поле структуры, в котором хранится месяц
        day;   //Поле структуры, в котором хранится день
 }//-------------------------------------------------------
 date1, date2;//Переменные, обозначающие две различных даты

Переменные tochka1, tochka2 объявляются как структуры, каждая из которых состоит из трех полей tzvet, х и у. Переменная simv объявляется как двумерный массив, состоящий из 63 переменных, описывающих точку дисплея. Во втором объявлении каждая из двух переменных date1, date2 состоит из трех компонентов year, moth, day.

Существует и другой способ связывания имени переменной с типом структуры, он основан на использовании отдельного объявления типа структуры. Тип структуры описывается следующим образом:

struct тип-структуры { список описаний; };

где тип-структуры является идентификатором типа объявляемой структуры и может быть использован для последующего объявления структур данного вида (то есть содержащих точно такие же поля) в форме:

struct тип-структуры список-идентификаторов;

В приведенном ниже примере идентификатор student описывается как тип структуры:

 struct student
 {char name[25];//Имя и фамилия студента
  int  id,      //Номер в журнале
       age;     //Возраст
  char usp;     //успеваемость
  };

Пример:

struct student st1[23];//объявление массива переменных типа студент

Доступ к компонентам структуры осуществляется с помощью указания имени структуры и следующего через точку имени выделенного компонента, например:

  st[1].name="Иванов";
  st[1].id=2;
  st[1].age=23;

Поля битов

Элементом структуры может быть битовое поле, обеспечивающее доступ к отдельным битам памяти. Вне структур битовые поля объявлять нельзя. Нельзя также организовывать массивы битовых полей и нельзя применять к полям операцию определения адреса. В общем случае тип структуры с битовым полем задается в следующем виде:

struct { unsigned идентификатор 1 :  длина-поля  1;
         unsigned идентификатор 2 :  длина-поля  2;    }

длина-поля задается целым выражением или константой. Эта константа определяет число битов, отведенное соответствующему полю. Поле нулевой длинны обозначает выравнивание на границу следующего слова.

Пример:

struct
{unsigned R:  1;//Флаг приёма байта
 unsigned T:  1;//Флаг передачи байта
 unsigned Cmd:5;//Поле команды
 unsigned St: 1;//Поле статуса
} Cntr;

Структуры битовых полей могут содержать и знаковые компоненты. Такие компоненты автоматически размещаются на соответствующих границах слов, при этом некоторые биты слов могут оставаться неиспользованными.

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

Cntr.Cmd=30;

Объединения (смеси)

Главной особенностью объединения является то, что для каждого из объявленных элементов этого объединения выделяется одна и та же область памяти, т.е. они перекрываются. Хотя доступ к этой области памяти возможен с использованием любого из элементов, элемент для этой цели должен выбираться так, чтобы полученный результат не был бессмысленным.

Объединение применяется для следующих целей:

  1. использования одного и той же области памяти для размещения переменных различного типа;
  2. интерпретации представления переменной одного типа, как несколько переменных другого типа.

Объединение по описанию подобно структуре. Тип объединения может задаваться в следующем виде:

     union {   описание элемента 1;
               ...
               описание элемента n; };

Доступ к элементам объединения осуществляется тем же способом, что и к структурам.

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

Второй вариант можно проиллюстрировать следующим образом. Например, требуется передать число плавающего типа. Однако последовательный порт может передавать или принимать только однобайтовые числа. В этом случае можно воспользоваться объединением:

 union {float Koeff; //Интерпретация объединения как переменной плавающего типа
        char byte[4];//Интерпретация объединения как массива
        }   bufer;   //Объявление переменной bufer

Объединение bufer позволяет последовательному порту получить отдельный доступ ко всем байтам числа bufer.Koeff начиная от младшего байта bufer.byte[0], и заканчивая старшим байтом bufer.byte[3]. В программе затем можно пользоваться загруженным числом как числом с плавающей запятой.

[ Главная ]


Объявления функций в языке программирования C-51

 Rambler's Top100 Дата последнего обновления файла 04.10.2005

Использование подпрограмм в языке программирования С-51*.

В отличие от других языков программирования высокого уровня в языке С нет деления на основную программу, процедуры и функции. В этом языке вся программа строится только из функций. Мощность языка С во многом определяется легкостью и гибкостью объявления и реализации функций.

Функция - это совокупность объявлений и операторов, обычно предназначенная для решения определенной задачи. Термин функция в языке программирования С эквивалентен понятию подпрограммы. Действия, выполняемые основной программой в других языках программирования такие как очистка внутреннего ОЗУ и присваивание начального значения переменным, выполняются автоматически при включении питания. После завершения этих действий вызывается подпрограмма с именем main. Каждая функция должна иметь имя, которое используется для ее объявления, определения и вызова.

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

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

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

С использованием функций в языке С-51 связаны три понятия - определение функции (описание действий, выполняемых подпрограммой-функцией), объявление функции (задание формы обращения к функции) и вызов функции.

Определение подпрограмм

Определение функции состоит из заголовка и тела. Определение функции записывается в следующем виде:

[спецификатор класса памяти] [спецификатор типа] имя функции ([список формальных параметров]) //Заголовок функции
{                                                                                             //тело функции
}

Заголовок функции задает тип возвращаемого значения, имя функции, типы и число формальных параметров.

Тело функции - это составной оператор, содержащий операторы, определяющие действие функции. Тело функции начинается с фигурной скобки '{' и состоит из объявления переменных и исполняемых операторов. Именно эти операторы, входящие в тело функции, и определяют действие функции. Завершается тело функции закрывающей фигурной скобкой '}'.

Пример определения функции:

bit SostKnIzm(void)//Заголовок функции
{//---------------начало тела функции--------------
 bit tmp=0;
 if(P0!=0xff)tmp=1;
 return tmp;
}//---------------конец тела функции-----------------

//================== Вызывающая подпрограмма ==========
  ...
  if(SostKnIzm()) //Вызов подпрограммы SostKnIzm
    DecodSostKn();

В приведенном примере показано как при помощи функции, возвращающей битовую переменную можно повысить наглядность исходного текста программы. Оператор if(SostKnIzm()) DecodSostKn(); практически не требует комментариев. Имя функции SostKnIzm показывает что контролирует эта функция.

Необязательный спецификатор класса памяти задает класс памяти функции, который может быть static или extern.

При использовании спецификатора класса памяти static функция становится невидимой из других файлов программного проекта, то есть информация об этой функции не помещается в объектный файл. Использование спецификатора класса памяти static может быть полезно для того, чтобы имя этой функции могло быть использовано в других файлах программного проекта для реализации совершенно других задач. Если функция, объявленная с спецификатором класса памяти static, ни разу не вызывалась в данном файле, то она вообще не транслируется компилятором и не занимает места в программной памяти микроконтроллера, а программа-компилятор языка программирования С-51 выдает предупреждение об этом. Это свойство может быть полезным при отладке программ и программных модулей.

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

Спецификатор типа функции задает тип возвращаемого значения и может задавать любой тип. Если спецификатор типа не задан, то по умолчанию предполагается, что функция возвращает значение типа int. Функция не может возвращать массив или функцию, но может возвращать указатель на любой тип, в том числе и на массив и на функцию. Тип возвращаемого значения, задаваемый в определении функции, должен соответствовать типу в объявлении этой функции.

Функция возвращает значение если ее выполнение заканчивается оператором return, содержащим некоторое выражение. Указанное выражение вычисляется, преобразуется, если необходимо, к типу возвращаемого значения и возвращается в точку вызова функции в качестве результата. Пример определения подпрограммы-функции:

#include <reg51.h>    //Подключить описания внутренних регистров микроконтроллера

char getkey ()       //Заголовок функции, возвращающей байт, принятый по последовательному порту
{while (!RI);         //Если последовательный порт принял байт,
 RI = 0;              //то подготовиться к приёму следующего байта
 return (SBUF);       //и передать принятый байт в вызывающую подпрограмму.
}

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

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

void putchar (char c)  //Заголовок функции, передающей один байт через последовательный порт
{while (!TI);          //Если передатчик последовательного порта готов к передаче байта
 SBUF = c;             //то занести в буфер передатчика последовательного порта байт
 TI = 0;               //и начать передачу
}

Все переменные, объявленные в теле функции без указания класса памяти, имеют класс памяти auto, т.е. они являются локальными. Так как глубина стека в процессорах семейства MCS-51 ограничена 256 байтами, то при вызове функций аргументам назначаются конкретные адреса во внутренней памяти микроконтроллера и производится их инициализация. Управление передается первому оператору тела функции и начинается выполнение функции, которое продолжается до тех пор, пока не встретится оператор return или последний оператор тела функции. Управление при этом возвращается в точку, следующую за точкой вызова, а локальные переменные становятся недоступными. При выходе из функции значения этих переменных теряются, так как при вызове других функций эти же ячейки памяти распределяются для их локальных переменных.

Если необходимо, чтобы переменная, объявленная внутри подпрограммы сохраняла своё значение при следующем вызове подпрограммы, то ее необходимо объявить с классом памяти static.

Параметры подпрограмм.

Список формальных параметров - это последовательность объявлений формальных параметров, разделенная запятыми. Формальные параметры - это переменные, используемые внутри тела функции и получающие значение при вызове функции путем копирования в них значений соответствующих фактических параметров.

Пример определения функции с одним параметром:

int rus (unsigned char r)  //Заголовок функции
{//---------------начало тела функции--------------
 if (r>='А' && c<=' ')
      return 1;
    else
      return 0;
}//---------------конец тела функции-----------------

В данном примере определена функция с именем rus, имеющая один параметр с именем r и типом unsigned char. Функция возвращает целое значение, равное 1, если параметр функции является буквой русского алфавита, или 0 в противном случае.

Если функция не использует параметров, то наличие круглых скобок обязательно, а вместо списка параметров рекомендуется указать слово void. Например:

void main(void)
{P0=0;      //Зажигание светодиода
 while(1);  //Бесконечный цикл
}

Порядок и типы формальных параметров должны быть одинаковыми в определении функции и во всех ее объявлениях. Поэтому желательно объявление функции поместить в отдельный файл, который затем можно включить в исходные тексты программных модулей при помощи директивы #include. Типы фактических параметров при вызове функции должны быть совместимы с типами соответствующих формальных параметров. Тип формального параметра может быть любым основным типом, структурой, объединением, перечислением, указателем или массивом. Если тип формального параметра не указан, то этому параметру присваивается тип int.

Для формального параметра можно задавать класс памяти register, при этом для величин типа int спецификатор типа можно опустить. Однако все известные мне компиляторы языка программирования С-51 игнорируют этот спецификатор, так как расположение параметров в памяти микроконтроллера оптимизируется с точки зрения использования минимального количества необходимой внутренней памяти.

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

Таблица 1

Номер аргумента | char, однобайтовый указатель | int, двухбайтовый указатель | long,float | Нетипизированные указатели
1 | R7 | R6,R7 | R4 - R7 | R1 - R3
2 | R5 | R4,R5 | R4 - R7 | R1 - R3
3 | R3 | R2,R3 |  | R1 - R3

Поскольку при вызове функции значения фактических параметров копируются в локальные переменные, в теле функции нельзя изменить значения переменных в вызывающей функции. Например нужно поменять местами значения переменных x и y:

/*    Неправильное использование параметров функции   */
void change (int x, int y)
{int k=x;
     x=y;
     y=k;
}

В данной функции значения локальных переменных x и y, являющихся формальными параметрами, меняются местами, но поскольку эти переменные существуют только внутри функции change, значения фактических параметров, используемых при вызове функции, останутся неизменными.

Однако, если в качестве параметра функции использовать указатель на переменную, то можно изменить значение переменной, адрес которой будет содержаться в указателе. Для того чтобы менялись местами значения фактических аргументов можно использовать функцию приведенную в следующем примере:

/*     Правильное использование параметров функции     */
void change (int *x, int *y)
{int k=*x;
     *x=*y;
     *y=k;
}

При вызове такой функции в качестве фактических параметров должны быть использованы не значения переменных, а их адреса:

  change (&a,&b);

Предварительное объявление подпрограмм.

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

Если объявление функции не задано, то по умолчанию строится прототип функции на основе анализа первого вызова функции. Тип возвращаемого значения создаваемого прототипа int, а список типов и числа параметров функции формируется на основании типов и числа фактических параметров используемых при данном вызове. Однако такой прототип не всегда согласуется с последующим определением функции. При размещении функции в другом файле или после оператора ее вызова рекомендуется задавать прототип функции. Это позволит компилятору либо выдавать диагностические сообщения, при неправильном использовании функции, либо правильным образом преобразовывать типы аргументов при её вызове.

Прототип - это явное объявление функции, которое предшествует определению функции. Тип возвращаемого значения при объявлении функции должен соответствовать типу возвращаемого значения в определении функции. Если прототип задан с классом памяти static, то и определение функции должно иметь класс памяти static. Объявление (прототип) функции имеет следующий формат:

[спецификатор класса памяти] [спецификатор типа] имя функции ([список формальных параметров]);

В отличие от определения функции, в прототипе за заголовком сразу же следует точка с запятой, а тело функции отсутствует. Правила использования остальных элементов формата такие же, как и при определении функции.

Для функции, определенной в предыдущем параграфе, прототип может быть записан в следующем виде:

int rus (unsigned char r);

При этом в объявлении функции имена формальных параметров могут быть опущены:

int rus (unsigned char);

Вызов подпрограмм.

Вызов функции имеет следующий формат:

имя функции ([список выражений]);

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

DecodSostKn();
VypFunc();

Функция, если она возвращает какое-либо значение (подпрограмма-функция), может быть вызвана и в составе выражения, например:

y=sin(x);                //sin - это имя подпрограммы-функции
if(rus(c))SvDiod=Gorit;  //rus - это имя подпрограммы-функции

Выполнение вызова функции происходит следующим образом:

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

Поскольку имя функции является адресом начала тела функции, то в качестве обращения к функции может быть использовано не только имя функции но и значение указателя на функцию. Это значит что функция может быть вызвана через указатель на функцию. Пример объявления указателя на функцию:

int (*fun)(int x, int *y);

Здесь объявлена переменная fun как указатель на функцию с двумя параметрами: типа int и указателем на int. Сама функция должна возвращать значение типа int. Круглые скобки, содержащие имя указателя fun и признак указателя *, обязательны, иначе запись

int *fun (int x,int *y);

будет интерпретироваться как объявление функции fun возвращающей указатель на int.

Вызов функции возможен только после инициализации значения указателя:

float (*funPtr)(int x, int y);
float fun2(int k, int l);
   ...
   funPtr=fun2;         /* инициализация указателя на функцию */
   (*funPtr)(2,7);      /* обращение к функции                */

В рассмотренном примере указатель на функцию funPtr описан как указатель на функцию с двумя параметрами, возвращающую значение типа double, и также описана функция fun2. В противном случае, т.е. когда указателю на функцию присваивается функция описанная иначе чем указатель, произойдет ошибка.

Рассмотрим пример использования указателя на функцию в качестве параметра функции вычисляющей производную от функции cos(x).

Пример:

float proiz(float x,float dx,float(*f)(float x));
float fun(float z);

int main()
{float x;               /*  точка вычисления производной */
 float dx;              /*  приращение                   */
 float z;               /*  значение производной         */

 scanf("%f,%f",&x,&dx);  /*  ввод значений x и dx         */
 z=proiz(x,dx,fun);      /*  вызов функции                */
 printf("%f",z);         /*  печать значения производной  */
}

float proiz(float x,float dx,float (*f)(float z))/* функция вычисляющая производную  */
{float xk,xk1;
 xk=fun(x);
 xk1=fun(x+dx);
 return (xk1/xk-1e0)*xk/dx;
}

float fun( float z)       /* функция от которой вычисляется производная  */
{return (cos(z));
}

Для вычисления производной от какой-либо другой функции можно изменить тело функции fun или использовать при вызове функции proiz имя другой функции. В частности, для вычисления производной от функции cos(x) можно вызвать функцию proiz в форме

z=proiz(x,dx,cos);

а для вычисления производной от функции sin(x) в форме

z=proiz(x,dx,sin);

Рекурсивный вызов подпрограмм.

В стандартном языке программирования С все функции могут быть вызваны сами из себя или использоваться различными программными потоками одновременно. Для этого все локальные переменные располагаются в стеке. В микроконтроллерах семейства MCS-51 ресурсы внутренней памяти данных ограничены, поэтому в языке программирования С-51 для функций по умолчанию локальные переменные располагаются не в стеке, а непосредственно во внутренней памяти микроконтроллера. Если же подпрограмма должна вызываться рекурсивно, то ее необходимо объявить как программу с повторным вызовом (reentrant):

return_type funcname ([args]) reentrant

Классический пример рекурсии - это математическое определение факториала n!:

   n! = 1   при n=0;
   n*(n-1)! при n>1 .

Функция, вычисляющая факториал, будет иметь следующий вид:

long fakt(int n) reentrant
{return ((n==1)?1:n*fakt(n-1));
}

Подпрограммы обработки прерываний.

Атрибут INTERRUPT позволяет объявить подпрограмму-процедуру обработки сигналов прерываний, поступающих от внешних устройств. Подпрограмма процедура с этим атрибутом вызывается при получении микроконтроллером соответствующего сигнала прерывания. Подпрограмма обработки прерываний не может быть подпрограммой функцией и не может иметь переменные-параметры. Формат использования атрибута:

interrupt N;

где N-любое десятичное число от 0 до 31.

Число N определяет номер обрабатываемого прерывания. При этом номер 0 соответствует внешнему прерыванию от ножки INT0, номер 1 соответствует прерыванию от таймера 0, номер 2 соответствует внешнему прерыванию от ножки INT1 и так далее. Пример подпрограммы-обработчика прерывания от таймера 0:

void IntTim0(void) interrupt 2
{TH0=25; TL0=32;  //Задать новый интервал времени таймера T0
 TF=0;            //Сбросить флаг таймера T0 для разрешения следующего прерывания от данного таймера
}

При работе с прерываниями определяющим фактором является время реакции на прерывание. Для того, чтобы не сохранять содержимое используемых регистров микроконтроллера в стеке, в микроконтроллерах предусмотрено использование отдельных регистровых банков. В языке программирования С-51 для этого необходимо в объявлении подпрограммы указать используемый ею банк регистров. Для этого служить атрибут using:

void IntTim0(void) interrupt 2 using 1
{TH0=25; TL0=32;  //Задать новый интервал времени таймера T0
 TF=0;            //Сбросить флаг таймера T0 для разрешения следующего прерывания от данного таймера
}

* Для читателей, которые вышли на эту страницу по поиску, прошу обратить внимание, что здесь рассматривается не стандартный язык программирования С, а язык, адаптированный к микроконтроллерам серии MCS-51. Имеются отличия!

[ Главная ]


Символы языка программирования PL/M-51

 Rambler's Top100 Дата последнего обновления файла 03.10.2005

Лексические единицы, разделители и использование пробелов*.

Наименьшей единицей операторов C-51 является лексическая единица. Каждая из лексических единиц относится к одному из классов:

  • идентификаторы;
  • ключевые слова;
  • простые ограничители (все специальные символы, кроме _, являются простыми ограничителями);
  • составные ограничители (они образуются посредством определенных комбинаций двух спецсимволов, а именно: !=,+=,-=,*=,<<,>>, <=, >=, /*, */,//);
  • числовые константы;
  • текстовые строковые константы;

В большинстве случаев вполне очевидно, где заканчивается одна лексическая единица и начинается следующая. Например, в операторе присваивания:

X=AP*(FT-3)/A;

X, AP, FT, A - являются идентификаторами переменных;
3 - числовой константой;
все прочие символы - простыми ограничителями.

Ключевые слова, идентификаторы и числовые константы должны обязательно отделяться друг от друга. Если между двумя идентификаторами, числовыми константами или ключевыми словами не может быть указан простой или составной ограничитель, то в качестве разделителя между ними должен вставляться символ пробела. Для улучшения читабельности программы вместо одного символа пробел может использоваться несколько символов пробела.

Идентификаторы

Идентификаторы в языке программирования C-51 используются для определения имени переменной, подпрограммы, символической константы или метки оператора. Длина идентификатора может достигать 255 символов, но транслятор различает идентификаторы только по первым 31 символам.

Возникает вопрос - а зачем тогда нужен такой длинный идентификатор? Ответ: для создания "говорящего" имени подпрограммы или переменной, которое может состоять из нескольких слов. Например:

ProchitatPort();     //Прочитать порт
VklychitIndikator(); //Включить индикатор

В приведенном примере подпрограмма ProchitatPort выполняет действия необходимые для чтения порта, а подпрограмма VklychitIndikator выполняет действия, необходимые для зажигания индикатора. Естественно, что намного легче прочитать действие подпрограммы непосредственно из имени подпрограммы, чем лазить каждый раз в алгоритм программы или искать исходный текст подпрограммы для того чтобы в очередной раз разобраться - что же она выполняет? Для этого при объявлении имени подпрограммы можно потратить количество символов и большее чем 31!

То же самое можно сказать и про имена переменных. Например:

sbit ReleVklPitanija = 0x80; //К нулевому выводу порта P0 подключено реле включения питания
sbit svDiod = 0x81;          //К первому выводу порта P0 подключен светодиод
sbit DatTemperat = 0x82;     //Ко второму выводу порта P0 подключен датчик температуры

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

В качестве идентификатора может быть использована любая последовательность строчных или прописных букв латинского алфавита и цифр, а также символов подчёркивания '_'. Идентификатор может начинаться только с буквы или символа '_', но ни в коем случае с цифры. Это позволяет программе-транслятору различать идентификаторы и числовые константы. Строчные и прописные буквы в идентификаторе различаются. Например: идентификаторы abc и ABC, A128B и a128b воспринимаются как разные.

Идентификатор создается при объявлении переменной, функции, структуры и т.п. после этого его можно использовать в последующих операторах разрабатываемой программы. Следует отметить важные особенности при определении идентификатора:

  1. Идентификатор не должен совпадать с ключевыми словами, с зарезервированными словами и именами функций из библиотеки компилятора языка С.
  2. Следует обратить особое внимание на использование символа подчеркивание (_) в качестве первого символа идентификатора, поскольку идентификаторы, построенные таким образом, могут совпадать с именами системных функций или переменных, в результате чего они станут недоступными.

Следует отметить, что никто не запрещает объявлять идентификатор, совпадающий с именами функций из библиотек компилятора языка С. Однако после объявления такого идентификатора Вы не сможете обратиться к функции с таким же именем никаким образом.

Примеры правильных идентификаторов:

A
XYR_56
OpredKonfigPriem
Byte_Prinjat
SvdiodGorit

Ключевые слова

Ключевые слова - это зарезервированные слова, которые используются для построения операторов языка.

Список ключевых слов:

   alien      _at_   auto    bdata   bit        break     case     char   code     compact continue   data
   default    do     double  else    enum       extern    far      float  for      idata   if         int
   interrupt  large  long    pdata   _priority_ reentrant register return sbit     sfr     sfr16      signed
   sizeof     short  small   struct  switch     typedef   _task_   union  unsigned void    volatile   while

Ключевые слова не могут быть использованы в качестве идентификаторов.

Константы

Константы предназначены для введения чисел в состав выражений операторов языка программирования C. В отличие от идентификаторов, всегда начинающихся с буквы, константы всегда начинаются с цифры. В языке программирования С-51 разделяют четыре типа констант:

  1. целые знаковые и беззнаковые константы,
  2. константы с плавающей запятой,
  3. символьные константы и литеральные строки.

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

Десятичная константа состоит из одной или нескольких десятичных цифр, причем первая цифра не может быть нулем (иначе число будет воспринято как восьмеричное).

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

Шестнадцатеричная константа начинается с обязательной последовательности символов 0х или 0Х и содержит одну или несколько шестнадцатеричных цифр (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)

      Примеры целых констант:
         Десятичная      Восьмеричная       Шестнадцатеричная
         константа       константа          константа
             16             020                0x10
            127             0117               0x2B
            240             0360               0XF0

Если требуется сформировать отрицательную целую константу, то используют знак "-" перед записью константы (который будет называться унарным минусом). Например: -0x2A, -088, -16.

Каждой целой константе присваивается тип, определяющий преобразования, которые должны быть выполнены, если константа используется в выражениях. Тип константы определяется следующим образом:

- десятичные константы рассматриваются как знаковые числа, и им присваивается тип int (целая) или long (длинная целая) в соответствии со значением константы. Если константа меньше 32768, то ей присваивается тип int в противном случае long.

- восьмеричным и шестнадцатеричным константам присваивается тип int, unsigned int (беззнаковая целая), long или unsigned long в зависимости от значения константы согласно табл 5.

Таблица 5

Диапазон шестнадцатеричных констант | Диапазон восьмеричных констант | Тип
0x0 - 0x7FFF | 0 - 077777 | int
0X8000 - 0XFFFF | 0100000 - 0177777 | unsigned int
0X10000 - 0X7FFFFFFF | 0200000 - 017777777777 | long
0X80000000 - 0XFFFFFFFF | 020000000000 - 037777777777 | unsigned long

Иногда требуется с самого начала интерпретировать константу как длинное целое число. Для того чтобы любую целую константу определить типом long, достаточно в конце константы поставить букву "l" или "L". Пример:

5l, 6l, 128L, 0105L, OX2A11L.

Примеры синтаксически недопустимых целочисленных констант:

12AF - шестнадцатеричная константа не имеет символов 0x в начале константы, поэтому по умолчанию для нее принимается десятичная система счисления, но тогда в ней присутствуют недопустимые символы.

0x2ADG - символ G недопустим при записи шестнадцатеричных чисел.

Константа с плавающей запятой - это десятичное число, представленное в виде действительного числа с десятичной запятой и порядком числа. Формат записи константы с плавающей запятой:

[ цифры ].[ цифры ] [ Е|e [+|-] цифры ].

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

115.75, 1.5Е-2, -0.025, .075, -0.85Е2

Символьная константа - представляется ASCII или ANSI символом, заключенном в апострофы. Управляющая последовательность тоже может быть использована в символьных константах. При этом она рассматривается как одиночный символ. Значением символьной константы является числовой код символа. Примеры символьных констант:

' '- пробел ,
'Q'- буква Q ,
'\n' - символ новой строки ,
'\\' - обратная дробная черта ,
'\v' - вертикальная табуляция .

Символьные константы имеют тип int и при преобразовании типов дополняются знаком. Символьные константы используются обычно при управлении микроконтроллерным устройством от клавиатуры. Пример использования символьной константы на языке программирования C-51 приведён ниже:

if(NajKn=='p') VklUstr();

В этом примере если в переменной NajKn содержится код, соответствующий букве "p", то будет выполнена подпрограмма VklUstr.

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

Строковая константа (литерал или литеральная строка) - последовательность символов (включая строковые и прописные буквы русского и латинского а также цифры) заключенные в кавычки ("). Например: "Школа N 35", "город Тамбов", "YZPT КОД".

Отметим, что все управляющие символы, кавычка ("), обратная дробная черта (\) и символ новой строки в литеральной строке и в символьной константе представляются соответствующими управляющими последовательностями. Каждая управляющая последовательность представляет собой один символ. Например, при печати литерала "Школа \n N 35" его часть "Школа" будет напечатана на одной строке, а вторая часть "N 35" на следующей строке.

Символы литеральной строки обычно хранятся в памяти программ, но могут храниться и в памяти данных. В конец каждой литеральной строки компилятором добавляется нулевой символ, который можно записать как: "\0". Именно этот символ и является признаком конца строки.

Литеральная строка рассматривается как массив символов (char[ ]). Отметим важную особенность: число элементов массива равно числу символов в строке плюс 1, так как нулевой символ (символ конца строки) также является элементом массива. Все литеральные строки рассматриваются компилятором как различные объекты. Одна литеральная строка может выводиться на дисплей как несколько строк. Такие строки разделяются при помощи обратной дробной черты и символа возврата каретки \n. На одной строке исходного текста программы можно записать только одну литеральную строку. Если необходимо продолжить написание одной и той же литеральной строки на следующей строке исходного текста программы, то в конце строки исходного текста можно поставить обратную строку. Например исходный текст:

"строка неопределенной \
длины"

полностью идентичен литеральной строке:

"строка неопределенной длины".

Однако более удобно для объединения литеральных строк использовать символ (символы) пробела. Если в программе встречаются два или более литерала, разделенные только пробелами или символами табуляции, то они будут рассматриваться как одна литеральная строка. Этот принцип можно использовать для формирования литералов, занимающих более одной строки.

* Для тех читателей что вышли на эту страницу по поиску прошу обратить внимание, что здесь рассматривается не стандартный язык программирования С, а язык, адаптированный к микроконтроллерам серии MCS-51. Имеются отличия!

[ Главная ]


Операторы языка программирования PL/M-51

 Rambler's Top100 Дата последнего обновления файла 23.08.2005

Операторы языка программирования C-51.

В языке программирования C-51 используется два типа операторов: операторы объявления и выполняемые операторы. Все операторы C-51 заканчиваются точкой с запятой.

Операторы объявления.

Объявление является неисполняемым оператором, который объявляет некоторый объект или набор объектов, связывает с ним один или несколько идентификаторов и, если это необходимо, распределяет память микроконтроллера.

В объявлении могут быть объявлены три типа объектов: переменные, метки и функции. В программе для каждого имени допустимо только одно объявление. Метка полностью объявлена, если она стоит перед выполняемым оператором и заканчивается с двоеточием ':'. Например:

vfg: svGorit(); //Вызов подпрограммы с именем svGorit

Переменные, константы, литералы и подпрограммы должны быть объявлены раньше, чем они будут использоваться в исполняемом операторе. Объявление переменной заключается в задании типа этой переменной и ее имени. Тип переменной записывается перед именем переменной. Например:

char Rejim; //Переменная, хранящая номер режима размером в один байт
int Schet;  //Переменная, использующаяся как счётчик размером в два байта

В языке программирования C-51 нет необходимости знать конкретный адрес переменной, достаточно обратиться к ней по имени Rejim или Schet.

Функция объявляется точно так же как и переменные. То есть перед именем подпрограммы-функции записывается тип переменной, которую возвращает подпрограмма после своего завершения. Так как в подпрограмму в свою очередь тоже могут передаваться переменные, которые называются параметрами подпрограммы, то эти переменные записываются в скобках после имени подпрограммы-функции. Перед каждой переменной обязательно указывается ее тип. Например:

char PrinjatByte(void);  //Подпрограмма, предназначенная для приёма одного байта.

Так как подпрограмме приёма обычно не требуется никаких дополнительных переменных, то вместо переменной-параметра подпрограммы указано слово void, обозначающее, что у подпрограммы-функции нет параметров.

Исполняемые операторы.

  • Оператор присваивания:
  • Условный оператор.
  • Структурный оператор.
  • Оператор цикла for
  • Оператор цикла с проверкой условия до тела цикла
  • Оператор цикла с проверкой условия после тела цикла
  • Оператор continue
  • Оператор выбора
  • Оператор безусловного перехода
  • Оператор выражение
  • Оператор возвращения из подпрограммы
  • Пустой оператор

При вычислении операторов используются выражения, в состав которых входят одноместные, двухместные и трёхместные операции.

Оператор присваивания.

Оператор присваивания записывается в виде:

Переменная=выражение;

Выражение вычисляется, и полученное значение присваивается переменной. Например:

P0=2;       //Установить начальные потенциалы на ножках второго порта микроконтроллера
a=cos(b*5); //Этот оператор присваивания осуществляет вызов подпрограммы-функции.

Достаточно часто требуется изменять значение какой-либо переменной. То есть и источником и приёмником данных служит одна и та же переменная. В этом случае можно воспользоваться составным оператором присваивания. Использование составного оператора сокращает исходный текст программы. Например:

sum+=3;    //Оператор эквивалентен оператору sum=sum+3;
Umensh-=5; //Оператор эквивалентен оператору Umensh=Umensh-5;
a*=10;     //Оператор эквивалентен оператору a=a*5;
mask&=0x10;//Оператор эквивалентен оператору mask=mask&5; Обычно используется для записи нулей в определённые биты переменной

Условный оператор.

Оператор if обеспечивает условное выполнение операторов. Он записывается в следующей форме:

  if(<выражение>)
      <operator-1>;
    [else
      <operator-2>;]

При этом ключевое слово else со следующим за ним исполняемым оператором представляют собой необязательную часть условного оператора. Если результат вычисления выражения равен 1 (истина), то выполняется operator-1. Если результат вычисления выражения равен 0 (ложь), то выполняется operator-2. Если выражение ложно и отсутствует оператор-2, то выполняется оператор, следующий за условным. Пример записи условного оператора:

 if(Wes<Min)          /*Условная операция*/
   Schetch=Schetch+1;   /*Плечо 1*/
  else
   Schetch=0;           /*Плечо 2*/

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

 if(P1.5)fnKn5Naj();          //В этом примере предполагается, что к пятой ножке порта P1 подключена кнопка с надписью "5"
 if(Kn5Naj)fnKn5Naj();        //Этот пример эквивалентен предыдущему, но ножке P1.5 поставлена в соответствие переменная Kn5Naj
 if(PrinjatByte())DecodCmd(); //Предполагается, что функция PrinjatByte возвращает значение '1', если байт принят

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

Структурный оператор {}

Существует два основных способа использования структурного оператора:

  1. Структурный оператор может рассматриваться в качестве отдельного оператора языка С-51 и использоваться в программе везде, где может встречаться отдельный исполняемый оператор. Это используется в операторах for, while, do while, switch of и if;
  2. Структурный оператор ограничивает область действия локальных переменных.

Каждый оператор внутри структурного оператора может являться любым оператором языка C-51, в том числе и объявлением, при условии, что все объявления внутри структурного оператора должны быть выполнены до первого исполняемого оператора.

Структурный оператор начинается с открывающей скобки '{' и записывается в следующем виде:

{<operator-1>;  //Здесь могут быть объявления переменных
 <operator-2>;
    ...
 <operator-n>;
}

Заметим, что в конце составного оператора точка с запятой не ставится. Пример использования структурного оператора:

 if(Wes<Min)      /*Условная операция*/
   {incr=incr*2;        /*Структурный оператор*/
    Schetch=Schetch+1;  /*Содержит два оператора*/
   }

Структурные операторы могут вкладываться друг в друга:

{<operator-1>;
 <operator-2>;
 {<operator-A>;
  <operator-B>
  <operator-C>;
  }
 <operator-3>;
 <operator-4>;
}

Пример использования объявлений внутри вложенного структурного оператора:

int main ()
 {int q,b;
  float t,d;
  ...
  if(...)
    {int e,g;
     float f,q;
     ...
    }
  ...
  return (0);
 }

Переменные e,g,f,q будут уничтожены после выполнения составного оператора. Отметим, что переменная q является локальной в составном операторе, т.е. она никоим образом не связана с переменной q объявленной в начале функции main с типом int. Отметим также, что выражение стоящее после return может быть заключено в круглые скобки, хотя наличие последних необязательно.

Оператор цикла for

Оператор for - это наиболее общий способ организации цикла. Оператор цикла for записывается в следующей форме:

for ( выражение 1 ; выражение 2 ; выражение 3 ) тело цикла;

Выражение 1 обычно используется для установления начального значения переменных, управляющих циклом. Выражение 2 - это выражение, определяющее условие, при котором тело цикла будет выполняться. Выражение 3 определяет изменение переменных, управляющих циклом после каждого выполнения тела цикла. В качестве тела цикла может служить любой исполняемый оператор языка C-51, в том числе и составной оператор. Внутри составного оператора может быть заключено любое количество исполняемых операторов.

Схема выполнения оператора for:

  1. Вычисляется выражение 1.
  2. Вычисляется выражение 2.
  3. Если значения выражения 2 отлично от нуля (истина), выполняется тело цикла, вычисляется выражение 3 и осуществляется переход к пункту 2, если выражение 2 равно нулю (ложь), то управление передается на оператор, следующий за оператором for.

Обратите внимание, что проверка условия всегда выполняется в начале цикла. Это значит, что тело цикла может ни разу не выполниться, если условие выполнения сразу будет ложным.

Пример использования оператора for:

 for(i=1;i<10;i++)  //от i равного 1 до 10 с шагом 1 выполнить
   b=i*i;

В этом примере вычисляются квадраты чисел от 1 до 9.

Некоторые варианты использования оператора 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;
   }
  return 0;
 }

В этом примере, реализующем запись строки символов в обратном порядке, для управления циклом используются две переменные top и bot. Отметим, что на месте выражение 1 и выражение 3 здесь используются несколько выражений, записанных через запятую, и выполняемых последовательно.

Так как согласно синтаксису языка Си оператор может быть пустым, тело оператора for также может быть пустым. Такая форма оператора может быть использована для организации поиска.

Пример:

for(i=0;t[i]<10;i++);

В данном примере переменная цикла i принимает значение номера первого элемента массива t, значение которого больше 10.

При написании программ для микроконтроллеров достаточно часто требуется реализовать бесконечный цикл. В этом случае оператор цикла for принимает следующий вид:

for(;;)        //Постоянно
  {Knop=P2;      //опрашивать порт P2
   ObrabSobyt(); //и обрабатывать нажатие кнопок
  }

Оператор цикла for - это универсальный оператор, поэтому его реализация в машинных командах достаточно сложна. Для написания программ часто достаточно более простых операторов цикла. Использование таких операторов приводит к более компактным и быстродействующим программам.

Оператор цикла с проверкой условия до тела цикла while

Оператор цикла while называется циклом с предусловием и имеет следующий формат:

while (выражение) тело цикла;

Оператор while содержит условную операцию (такую же, как в операторе if), и вызывает исполнение операторов в этом блоке до тех пор, пока условие верно. Проверка условия производится до выполнения тела цикла, поэтому оператор тела цикла может быть не выполнен ни разу. В качестве выражения допускается использовать любое выражение языка Си, а в качестве тела любой оператор, в том числе пустой или составной. Схема выполнения оператора while следующая:

  1. Вычисляется выражение.
  2. Если выражение ложно, то выполнение оператора while заканчивается и выполняется следующий по порядку оператор. Если выражение истинно, то выполняется тело цикла (которое может быть составным оператором)
  3. Процесс повторяется с пункта 1.

Оператор while может быть полезен для ожидания срабатывания какого-либо устройства микроконтроллера, например таймера:

  ...
  while(!TF0);  //Программа ожидает переполнения таймера T0
  TF0=0;
  TL0=time;     //Настроить таймер T0
  TН0=time>>8;  //на очередной интервал времени
  ...

В следующем примере оператор while используется для пошагового прохождения по элементам массива Table до тех пор, пока очередной элемент не превысит значение скалярной переменной с именем Level (уровень англ.):

  i = 0;
  while(table(i)<=Level)i++;

В приведённом примере Table - это предварительно объявленный массив. Переменные Level и i тоже должны быть предварительно объявлены.

Переменной i первоначально присваивается значение 0, затем она используется как индекс для массива Table. Так как i увеличивается при каждом проходе цикла while, то каждый раз, когда выполняется оператор внутри блока while, с переменной Level сравнивается следующий элемент массива Table. Когда найден элемент, превышающий значение переменной Level, то условие в операторе while больше неверно, выполнение блока не повторяется и управление передается следующему за циклом while оператору. С этого момента переменная i является индексом первого элемента массива Table, который превышает значение переменной Level.

Оператор цикла с проверкой условия после тела цикла do while

Оператор цикла while называется циклом с постусловием и имеет следующий формат:

do тело цикла while (выражение);

Оператор do while содержит условную операцию (такую же, как в операторе if), и вызывает исполнение операторов в этом блоке до тех пор, пока условие верно. Проверка условия производится после выполнения тела цикла, поэтому оператор тела цикла будет выполнен хотя бы один раз. В качестве выражения допускается использовать любое выражение языка Си, а в качестве тела любой оператор, в том числе пустой или составной. Схема выполнения оператора do while следующая:

  1. Выполняется тело цикла (которое может быть составным оператором)
  2. Вычисляется выражение.
  3. Если выражение ложно, то выполнение оператора do while заканчивается и выполняется следующий по порядку оператор. Если выражение истинно, то выполнение оператора продолжается с пункта 1.

Чтобы прервать выполнение цикла до того, как условие станет ложным, можно использовать оператор break.

Оператор do while в большинстве случаев соответствует одной машинной команде, поэтому может быть использован для написания эффективных по коду и быстродействию программ. Например:

i=10
do тело цикла; while(--i<0);

Однако, конкретно в реализации компилятора C-51, намного эффективнее следующая конструкция:

for(i=10;i>0;i--) тело цикла;

Операторы while и do while могут быть вложенными.

Пример использования вложенных операторов цикла:

       int i,j,k;
       ...
       i=0;j=0;k=0;
       do{i++;j--;
          while (a[k]<i)k++;
         }
       while(i<30&&j<-30);

Оператор break

Оператор break обеспечивает прекращение выполнения самого внутреннего из объединяющих его операторов switch, do, for,while. После выполнения оператора break управление передается оператору, следующему за прерванным оператором цикла или выбора.

Оператор continue

Оператор continue, как и оператор break, используется только внутри операторов цикла, но в отличие от него выполнение цикла не прерывается, а начинается следующая итерация цикла. Формат записи оператора:

continue;

Пример:

int main()
{int a,b;
 for(a=1,b=0;a<100;b+=a,a++)
  {if(b%2)continue;
   ... /* обработка четных сумм */
  }
 return 0;
}

Когда сумма чисел от 1 до а становится нечетной, оператор continue передает управление на очередную итерацию цикла for, не выполняя операторы обработки четных сумм.

Оператор continue, как и оператор break, прерывает самый внутренний из объемлющих его циклов.

Оператор выбора switch

Оператор switch предназначен для организации выбора из множества различных вариантов. Формат оператора следующий:

switch ( выражение )
 {[объявление]
      ...
  [ case  константное-выражение1]: [ список-операторов1]
  [ case  константное-выражение2]: [ список-операторов2]
      ...
      ...
  [ default: [ список операторов ]]
 }

Выражение, следующее за ключевым словом switch в круглых скобках, может быть любым выражением, допустимыми в языке СИ, значение которого должно быть целым. Отметим, что можно использовать явное приведение к целому типу.

Значение этого выражения является ключевым для выбора из нескольких вариантов. Тело оператора smitch состоит из нескольких операторов, помеченных ключевым словом case с последующим константным выражением.

Так как константное выражение вычисляется во время трансляции, оно не может содержать переменные или вызовы функций. Обычно в качестве константного выражения используются целые или символьные константы.

Все константные выражения в операторе switch должны быть уникальны. Кроме операторов, помеченных ключевым словом case, может быть, но обязательно один, фрагмент помеченный ключевым словом default.

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

Отметим также, что в операторе switch можно использовать свои локальные переменные, объявления которых находятся перед первым ключевым словом case, однако в объявлениях не должна использоваться инициализация.

Схема выполнения оператора switch следующая:

  • вычисляется выражение в круглых скобках;
  • вычисленные значения последовательно сравниваются с константными выражениями, следующими за ключевыми словами case;
  • если одно из константных выражений совпадает со значением выражения, то управление передается на оператор, помеченный соответствующим ключевым словом case;
  • если ни одно из константных выражений не равно выражению, то управление передается на оператор, помеченный ключевым словом default, а в случае его отсутствия управление передается на следующий после switch оператор.

Отметим интересную особенность использования оператора switch: конструкция со словом default может быть не последней в теле оператора switch. Ключевые слова case и default в теле оператора switch существенны только при начальной проверке, когда определяется начальная точка выполнения тела оператора switch. Все операторы, между начальным оператором и концом тела, выполняются вне зависимости от ключевых слов, если только какой-то из операторов не передаст управления из тела оператора switch. Таким образом, программист должен сам позаботится о выходе из case, если это необходимо. Чаще всего для этого используется оператор break.

Для того, чтобы выполнить одни и те же действия для различных значений выражения, можно пометить один и тот же оператор несколькими ключевыми словами case.

Если значение выражения равно 0, то выполняется только первый оператор присваивания, и 0 будет присвоен переменной red (красный англ). Если значение выражения равно 1, то будет выполнен только второй оператор присваивания и переменной blue (голубой англ) будет присвоен 0. Значения выражения 2 и 3 вызовет присваивание 0 переменным green (зеленый англ) и gray (серый англ) соответственно.

Следует отметить, что с точки зрения программиста этот оператор выглядит очень эффектно. Однако при рассмотрении машинного кода получается довольно страшная конструкция с использованием таблиц переходов. Использование нескольких условных операторов if несмотря на то, что они не очень красиво выглядят в исходном тексте программы, приводит к короткому и быстродействующему машинному коду программы.

Оператор безусловного перехода goto.

Оператор goto изменяет порядок выполнения программы при помощи передачи управления на оператор, метка которого указана в операторе goto. Оператор goto записывается в следующем виде:

       goto имя-метки;
                  ...
       имя-метки: оператор;

Оператор goto передает управление на оператор, помеченный меткой имя-метки. Помеченный оператор должен находиться в той же функции, что и оператор goto, а используемая метка должна быть уникальной, т.е. одно имя-метки не может быть использовано для разных операторов программы. Имя-метки - это идентификатор.

Любой оператор в составном операторе может иметь свою метку. Используя оператор goto, можно передавать управление внутрь составного оператора. Но нужно быть осторожным при входе в составной оператор, содержащий объявления переменных с инициализацией, так как объявления располагаются перед выполняемыми операторами и значения объявленных переменных при таком переходе будут не определены.

Использование операторов goto является неизбежным при некоторых ситуациях, однако в большинстве случаев там, где должна быть предусмотрена передача управления, более предпочтительным является использование итеративного оператора while, do while, DO CASE, if или вызова процедуры. Неограниченное использование операторов goto в программе приводит к тому, что программу становится трудно понимать, модифицировать и сопровождать. Реальная практика использования языка C-51 показывает, что в большинстве случаев программные модули могут не содержать оператор goto без ухудшения их эффективности.

Оператор выражение

Любое выражение, которое заканчивается точкой с запятой, является оператором.

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

Примеры записи операторов-выражений:

++ i;         //Этот оператор представляет выражение, которое увеличивает значение переменной i на единицу.
a(x,y);       //Этот оператор представляет выражение состоящее из вызова подпрограммы-процедуры.

Оператор возвращения из подпрограммы return.

Оператор return завершает выполнение функции, в которой он задан, и возвращает управление в вызывающую функцию, в точку, непосредственно следующую за вызовом. Формат оператора:

return [выражение] ;

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

Если в какой-либо функции отсутствует оператор return, то передача управления в вызывающую функцию происходит после выполнения последнего оператора вызываемой функции. При этом возвращаемое значение не определено. Если функция не должна иметь возвращаемого значения, то ее нужно объявлять с типом void.

Таким образом, использование оператора return необходимо либо для немедленного выхода из функции, либо для передачи возвращаемого значения.

Пример:

int sum(int a,int b)
{return(a+b);
}

Функция sum имеет два формальных параметра a и b типа int, и возвращает значение типа int, о чем говорит описатель, стоящий перед именем функции. Возвращаемое оператором return значение равно сумме фактических параметров.

Пример:

void prov (int a, double b)
{float c;
 if(a<3)
     return;
   else if(b>10)
     return;
   else
     {c=a+b;
      if((2*c-b)==11)return;
     }
}

В этом примере оператор return используется для выхода из функции в случае выполнения одного из проверяемых условий.

Пустой оператор.

Пустой оператор состоит только из точки с запятой. У пустого оператора может быть метка. Пустой оператор не содержит ничего, кроме пробелов и комментариев. При выполнении этого оператора ничего не происходит. Он обычно используется в следующих случаях:

  • в операторах цикла do, for, while при использовании их в качестве элементов задержки, в операторе if в строках, когда место оператора не требуется, но по синтаксису требуется хотя бы один оператор;
  • при необходимости пометить структурный оператор.

Синтаксис языка СИ требует, чтобы после метки обязательно следовал оператор. Фигурная же скобка оператором не является. Поэтому, если надо передать управление на фигурную скобку, необходимо использовать пустой оператор.

Пример:

     int main ( )
     {
          ...
           { if (...) goto a;    /* переход на скобку */
               { ...
               }
      a:;  }
           return 0;
       }

[ Главная ]


Объявление указателей в языке программирования C-51

 Rambler's Top100 Дата последнего обновления файла 03.10.2005

Объявление указателей в языке программирования C-51*.

Указатель - это переменная, которая может содержать адрес другой переменной. Указатель может быть использован для работы с переменной, адрес которой он содержит. Использование указателей позволяет реализовать более эффективную обработку массивов, структур, а также реализовывать подпрограммы, которые будут работать над различными областями памяти микроконтроллера. Для этого в подпрограмму нужно только передать начальный адрес обрабатываемой области памяти.

Для инициализации указателя (записи начального адреса переменной) можно использовать идентификатор переменной, при этом в качестве идентификатора может выступать имя переменной, массива, структуры, литеральной строки.

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

спецификатор-типа [ модификатор ] *описатель.

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

Примеры объявления указателей на различные типы переменных:

unsigned int * ptr; /* переменная ptr  представляет собой указатель на целую беззнаковую) переменную*/
float * x;        /* переменная  х  указывает  на переменную с плавающей  точкой*/
char *buffer ;   /*объявляется  указатель с именем buffer который указывает на символьную переменную*/

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

ptr=&A;  //Присвоить адрес переменной A
*ptr=2+2;//Работаем с переменной A
a=&B;
*ptr=3*4;//А теперь работаем с переменной B

В качестве модификаторов при объявлении указателя могут выступать ключевые слова const, data, idata, xdata, code. Ключевое слово const указывает, что указатель не может быть изменен в программе. Размер переменной, объявленной как указатель, зависит от модификатора и используемого вида памяти, для которой будет компилироваться программа. Указатели на различные типы данных не обязательно должны иметь одинаковую длину.

Для модификации размера указателя можно использовать ключевые слова data, idata, xdata, code.

Задавая вместо спецификатора типа, ключевое слово void, можно отсрочить определение типа, на который ссылается указатель. Переменная, объявляемая как указатель на тип void, может быть использована для ссылки на объект любого типа. Однако для того, чтобы можно было выполнить арифметические и логические операции над указателями или над объектами, на которые они указывают, необходимо при выполнении каждой операции явно определить тип объектов. Такие определения типов могут быть выполнены с помощью операции приведения типов.

   float nomer;
   void *addres;
   addres = &nomer;
   (float *)addres ++;
  /* Переменная addres объявлена как указатель на объект любого типа.
     Поэтому ей можно присвоить адрес любого объекта (& - операция
     вычисления адреса). Однако, как было отмечено выше, ни одна
     арифметическая операция не может быть выполнена над указателем,
     пока не будет явно определен тип данных,  на которые он указывает. Это
     можно сделать,  используя операцию приведения типа (float *) для
     преобразования типа указателя addres к типу float. Затем оператор ++
     отдаёт приказ перейти к следующему адресу.*/

В качестве модификаторов при объявлении указателя могут выступать ключевые слова const, data, idata, xdata, code. Ключевое слово const указывает, что указатель не может быть изменен в программе.

Вследствие уникальности архитектуры контроллера 8051 и его производных компилятор С51 поддерживает 2 вида указателей: память-зависимые и нетипизированные.

Нетипизированные указатели

Нетипизированные указатели объявляются точно так же, как указатели в стандартном языке программирования C. Для того, чтобы не зависеть от типа памяти, в которой может быть размещена переменная, для нетипизированных указателей выделяется 3 байта. В первом байте указывается вид памяти переменной, во втором байте - старший байт адреса, в третьем - младший байт адреса переменной. Нетипизированные указатели могут быть использованы для обращения к любым переменным независимо от типа памяти микроконтроллера. Именно поэтому многие библиотечные функции языка программирования C51 используют указатели этого типа, при этом им совершенно неважно, в какой именно области памяти размещаются переменные. Приведем листинг, в котором отображаются особенности трансляции нетипизированных указателей:

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
  11     1 char xdata xj; /*переменные во внешней памяти данных xdata */
  12     1 int xdata xk;
  13     1 long xdata xl;
  14     1
  15     1 char code cj = 9; /*переменные в памяти программ code */
  16     1 int code ck = 357;
  17     1 long code cl = 123456789;
  18     1
  19     1 /*настроим указатели на внутреннюю память данных data */
  20     1 c_ptr = &dj;
  21     1 i_ptr = &dk;
  22     1 l_ptr = &dl;
  23     1 /*настроим указатели на внешнюю память данных xdata */
  24     1 c_ptr = &xj;
  25     1 i_ptr = &xk;
  26     1 l_ptr = &xl;
  27     1 /*настроим указатели на память программ code */
  28     1 c_ptr = &cj;
  29     1 i_ptr = &ck;
  30     1 l_ptr = &cl;
  31     1 }

ASSEMBLY LISTING OF GENERATED OBJECT CODE
      ; FUNCTION main (BEGIN)
                      ; SOURCE LINE # 5
                      ; SOURCE LINE # 6
                      ; SOURCE LINE # 20
0000 750000 R   MOV   c_ptr,#00H
0003 750000 R   MOV   c_ptr+01H,#HIGH dj
0006 750000 R   MOV   c_ptr+02H,#LOW dj
                      ; SOURCE LINE # 21
0009 750000 R   MOV   i_ptr,#00H
000C 750000 R   MOV   i_ptr+01H,#HIGH dk
000F 750000 R   MOV   i_ptr+02H,#LOW dk
                      ; SOURCE LINE # 22
0012 750000 R   MOV   l_ptr,#00H
0015 750000 R   MOV   l_ptr+01H,#HIGH dl
0018 750000 R   MOV   l_ptr+02H,#LOW dl
                      ; SOURCE LINE # 24
001B 750001 R   MOV   c_ptr,#01H
001E 750000 R   MOV   c_ptr+01H,#HIGH xj
0021 750000 R   MOV   c_ptr+02H,#LOW xj
                      ; SOURCE LINE # 25
0024 750001 R   MOV   i_ptr,#01H
0027 750000 R   MOV   i_ptr+01H,#HIGH xk
002A 750000 R   MOV   i_ptr+02H,#LOW xk
                      ; SOURCE LINE # 26
002D 750001 R   MOV   l_ptr,#01H
0030 750000 R   MOV   l_ptr+01H,#HIGH xl
0033 750000 R   MOV   l_ptr+02H,#LOW xl
                      ; SOURCE LINE # 28
0036 7500FF R   MOV   c_ptr,#0FFH
0039 750000 R   MOV   c_ptr+01H,#HIGH cj
003C 750000 R   MOV   c_ptr+02H,#LOW cj
                      ; SOURCE LINE # 29
003F 7500FF R   MOV   i_ptr,#0FFH
0042 750000 R   MOV   i_ptr+01H,#HIGH ck
0045 750000 R   MOV   i_ptr+02H,#LOW ck
                      ; SOURCE LINE # 30
0048 7500FF R   MOV   l_ptr,#0FFH
004B 750000 R   MOV   l_ptr+01H,#HIGH cl
004E 750000 R   MOV   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 */

Поскольку модель памяти определяется во время компиляции, типизированным указателям не нужен байт, в котором указывается тип памяти микроконтроллера. Поэтому программа с использованием типизированных указателей будет короче и будет выполняться быстрее по сравнению с программой, использующей нетипизированные указатели. Типизированные указатели могут иметь размер в 1 байт (указатели на память idata, data, bdata, и pdata) или в 2 байта (указатели на память code и xdata).

Объявление новых типов переменных

В языке программирования C-51 имеется возможность заранее объявить тип переменной, а затем воспользоваться им при объявлении переменных. Использование заранее объявленного типа позволяет при объявлении переменной сократить его длину, избежать ошибок при объявлении переменных в разных местах программы и добиться полной идентичности объявляемых переменных.

Объявить новый тип переменной можно двумя способами. Первый способ – указать имя типа при объявлении структуры, объединения или перечисления, а затем использовать это имя в объявлении переменных и функций. Второй – использовать для объявления типа ключевое слово typedef.

При объявлении типа с ключевым словом typedef, идентификатор стоящий на месте описываемого объекта, является именем объявляемого типа данных, и далее этот тип может быть использован для объявления переменных.

Отметим, что любой тип может быть объявлен с использованием ключевого слова typedef, включая типы указателей, функций или массивов. Имя с ключевым словом typedef для типов указателя, структуры, объединения может быть объявлено прежде чем эти типы будут определенны, но в пределах видимости объявителя.

Примеры объявления и использования новых типов:

typedef
 float
 (* MATH)( );     // MATH - новое имя типа, представляющее указатель на  функцию, возвращающую значения типа float

typedef
 char
 FIO[40]                      // FIO - массив из сорока символов

  MATH cos;      // cos  указатель на функцию, возвращающую значения типа  double

 // Можно провести эквивалентное объявление

  float
 (* cos)( );

 FIO person;            //Переменная person - массив из сорока символов

// Это эквивалентно объявлению

   char
 person[40];

При объявлении переменных и типов здесь были использованы имена типов (MATH FIO). Помимо объявления переменных, имена типов могут еще использоваться в трех случаях: в списке формальных параметров при объявлении функций, в операциях приведения типов и в операции sizeof .

Инициализация данных

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

Инициатор переменной начинается со знака "=" и может быть записан в следующих форматах:

Формат 1: = инициатор;
Формат 2: = { список - инициаторов };

Формат 1 используется при инициализации переменных основных типов и указателей, а формат 2 - при инициализации составных объектов.

Примеры присваивания первоначальных значений простым переменным:

char tol = 'N';                                       //Переменная tol инициализируется символом 'N'.
const long megabyte = (1024*1024);

Немодифицируемой переменной megabyte присваивается значение константного выражения, после чего эта переменная не может быть изменена. Отмечу, что для микроконтроллеров семейства MCS-51 внутренняя память является дефицитным ресурсом, поэтому использовать ее для хранения констант нерационально. Лучше объявить переменную с спецификатором типа памяти code.

static int b[2][2] = {1,2,3,4};

Инициализируется двухмерный массив b целых величин, элементам массива присваиваются значения из списка. Эта же инициализация может быть выполнена следующим образом:

static int b[2][2] = { { 1,2 }, { 3,4 } };

При инициализации массива можно опустить одну или несколько размерностей

static int
 b[3] = { { 1,2 }, { 3,4 } };

Если при инициализации указано меньше значений для строк, то оставшиеся элементы инициализируются 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} };

В этом примере компилятор интерпретирует рассматриваемые фигурные скобки следующим образом:

  • первая левая фигурная скобка - начало составного инициатора для массива comp2;
  • вторая левая фигурная скобка - начало инициализации первой строки массива comp2[0]. Значения 1,1 присваиваются двум элементам первой структуры;
  • первая правая скобка (после 1) указывает компилятору, что список инициаторов для строки массива окончен, и элементы оставшихся структур в строке comp[0] автоматически инициализируются нулем;
  • аналогично список {2,3} инициализирует первую структуру в строке comp[1], а оставшиеся структуры массива обращаются в нули;
  • на следующий список инициализаторов {4,5} компилятор будет сообщать о возможной ошибке так как строка 3 в массиве comp2 отсутствует.

При инициализации объединения задается значение первого элемента объединения в соответствии с его типом.

Пример:

union tab
 {unsigned char name[10];
  int tab1;
  }pers={'A','H','T','O','H'};

Инициализируется переменная pers.name, и так как это массив, для его инициализации требуется список значений в фигурных скобках. Первые пять элементов массива инициализируются значениями из списка, остальные нулями.

Инициализацию массива символов можно выполнить при помощи литеральной строки.

char stroka[ ] = "привет";

Инициализируется массив символов из 7 элементов, последним элементом (седьмым) будет символ '\0', которым завершаются все литеральные строки.

В случае, если задается размер массива, а литеральная строка длиннее, чем размер массива, то лишние символы отбрасываются. Следующее объявление инициализирует переменную stroka как массив, состоящий из семи элементов.

char stroka[5]="привет";

В переменную stroka попадают первые пять элементов литерала, а символы 'т' и '\0' отбрасываются. Если строка короче размерности массива, то оставшиеся элементы массива заполняются нулями. Отметим, что инициализация переменной типа tab может иметь следующий вид:

union tab pers1="Антон";

и, таким образом, в символьный массив попадут символы:

'А','Н','Т','О','Н','\0',

а в остальные элементы будут записаны нули.

* Для тех читателей что вышли на эту страницу по поиску прошу обратить внимание, что здесь рассматривается не стандартный язык программирования С, а язык, адаптированный к микроконтроллерам серии MCS-51. Имеются отличия!

[ Главная ]


Символы языка программирования PL/M-51

 Rambler's Top100 Дата последнего обновления файла 03.08.2005

Символы языка программирования С-51.

Как и в любом другом текстовом файле, в исходном тексте программы, написанной на языке программирования С51, используются ASCII или ANSI символы. Множество символов, используемых в языке программирования С-51 можно разделить на пять групп.

1. Символы, используемые для образования ключевых слов и идентификаторов (табл.1). В эту группу входят прописные и строчные буквы английского алфавита, а также символ подчеркивания. Следует отметить, что язык программирования С-51 различает прописные и строчные буквы. Например, идентификаторы start и Start будут считаться различными идентификаторами.

Таблица 1

Прописные буквы латинского алфавита | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Строчные буквы латинского алфавита | a b c d e f g h i j k l m n o p q r s t u v w x y z
Символ подчеркивания | _
Арабские цифры | 0 1 2 3 4 5 6 7 8 9

2. Прописные и строчные буквы русского алфавита (табл.2).

Таблица 2

Прописные буквы русского алфавита | А Б В Г Д Е Ж З И К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ы Ь Э Ю Я
Строчные буквы русского алфавита | а б в г д е ж з и к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я

3. Знаки нумерации и специальные символы (табл. 3). Эти символы используются для организации процесса вычислений, а также для передачи компилятору определенного набора инструкций.

Таблица 2

Символ | Наименование | Символ | Наименование
, | запятая | ) | круглая скобка правая
. | точка | ( | круглая скобка левая
; | точка с запятой | } | фигурная скобка правая
: | двоеточие | { | фигурная скобка левая
? | вопросительный знак | < | меньше
' | апостроф | > | больше
! | восклицательный знак | [ | квадратная скобка
| | вертикальная черта | ] | квадратная скобка
/ | дробная черта | # | номер
\ | обратная черта | % | процент
~ | тильда | & | амперсанд
* | звездочка | ^ | исключающее ИЛИ
+ | плюс | = | равно
- | минус | " | кавычки

4. Управляющие и разделительные символы. К этой группе символов относятся: пробел, символы табуляции, перевода строки, возврата каретки, символы новой страницы и новой строки. Эти символы отделяют друг от друга лексические единицы языка, к которым относятся ключевые слова, константы, идентификаторы и т.д. Последовательность разделительных символов (например, последовательность пробелов) рассматривается компилятором как один символ.

5. Управляющие последовательности, т.е. специальные символьные комбинации, используемые в функциях ввода и вывода информации. Управляющая последовательность начинается с использования обратной косой черты (\), за которой следует комбинация латинских букв и цифр. Список управляющих последовательностей приведён в таблице 4.

Таблица 4

Управляющая последовательность | Наименование | Шестнадцатеричный код
\a | Звонок | 007
\b | Возврат на шаг | 008
\t | Горизонтальная табуляция | 009
\n | Переход на новую строку | 00A
\v | Вертикальная табуляция | 00B
\r | Возврат каретки | 00D
\f | Новая страница | 00C
\" | Кавычки | 022
\' | Апостроф | 027
\0 | Ноль-символ | 000
\\ | Обратная дробная черта | 05C
\OOO | Восьмеричный код ASCII или ANSI символа |
\xHHH | Шестнадцатеричный код ASCII или ANSI символа | HHH

Управляющие последовательности \OOO и \xHHH (здесь O обозначает восьмеричную цифру; H обозначает шестнадцатеричную цифру) позволяет представить символ из кодовой таблицы ASCII или ANSI как последовательность восьмеричных или шестнадцатеричных цифр соответственно. Например символ возврата каретки может быть представлен следующими способами:

\r - управляющая последовательность,

\015 - восьмеричный код символа возврата каретки,

\x00D - шестнадцатеричный код символа возврата каретки.

Следует отметить, что в строковых константах всегда обязательно задавать все три цифры в управляющей последовательности. Например отдельную управляющую последовательность \n (переход на новую строку) можно представить как \010 или \xA, но в строковых константах необходимо задавать все три цифры, в противном случае символ или символы следующие за управляющей последовательностью будут рассматриваться как ее недостающая часть. Например:

"ABCDE\x009FGH" данная строковая команда будет напечатана с использованием определенных функций языка СИ, как два отдельных слова ABCDE и FGH, разделенные табуляцией, в этом случае если указать неполную управляющую строку "ABCDE\x09FGH",то при печати появится строка ABCDEЯGH, так как компилятор воспримет последовательность \x09F как символ "Я".

Отметим тот факт, что, если обратная дробная черта предшествует символу не являющемуся управляющей последовательностью (т.е. не включенному в табл.4) и не являющемуся цифрой, то эта черта игнорируется, а сам символ представляется как литеральный. Например:

символ \h представляется символом h в строковой или символьной константе.

Кроме определения управляющей последовательности, символ обратной дробной черты (\) используется также как символ продолжения. Если за (\) следует символ возврата каретки, то оба символа игнорируются, а следующая строка является продолжением предыдущей. Это свойство может быть использовано для записи длинных строк. Например:

printf("Это очень длинная \
строка")

Компилятор С-51 выдает сообщение об ошибке, если в тексте исходной программы встречается символ, отличающийся от символов, перечисленных выше.

[ Главная ]


Язык программирования C-51.

 Rambler's Top100 Дата последнего обновления файла 04.08.2005

Структура программ С-51.

Язык программирования С-51 является структурно-модульным языком. Каждый оператор в программе является частью, по крайней мере, одного модуля. Каждая программа, написанная на языке программирования С-51 состоит из одного или более модулей. Каждый модуль записывается в отдельном файле и компилируется отдельно.

В модуле помещаются операторы, составляющие программу. Эти операторы объявляют константы или переменные и выполняют необходимые действия. Операторы, выполняющие действия, обязательно должны быть помещены в подпрограммы. Исполнение программы всегда начинается с подпрограммы с именем main (Т.е. в простейшем случае достаточно написать только эту подпрограмму).

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

Все переменные и константы, которые будут использоваться в программе, обязательно должны быть объявлены до подпрограммы, где они будут использованы первый раз.

При написании программы для микроконтроллеров всегда необходимо видеть перед глазами принципиальную схему устройства, для которого пишется программа, так как схема и программа тесно связаны между собой и дополняют друг друга. Для иллюстрации простейшей программы, написанной на языке программирования C-51 воспользуемся схемой, приведённой на рисунке 1.

Рисунок 1. Пример простейшей схемы устройства, построенной с использованием микроконтроллера.

Для примера заставим гореть светодиод VD1. Этот светодиод будет светиться только тогда, когда через него будет протекать ток. Для этого на шестом выводе порта P0 должен присутствовать нулевой потенциал. Запишем его первой же командой нашей программы:

#include<reg51.h>

void main(void)
{P0=0;      //Зажигание светодиода
 while(1);  //Бесконечный цикл
}

Эта программа содержит только один исполняемый оператор. Это оператор присваивания 'P0=0;'. Следующий оператор 'while(1);' обеспечивает зацикливание программы. Зацикливание программы сделано для того, чтобы микроконтроллер не выполнял больше никаких действий. В противном случае микроконтроллер перейдёт к следующей ячейке памяти и будет выполнять команды, которые мы не записывали.

Обратите внимание, что язык программирования знает где находится порт P0. Эта информация содержится в строке #include<reg51.h>.

Для того, чтобы получить более полное представление о структуре программ, написанных на языке программирования С-51, приведём пример исходного текста программы с использованием подпрограмм.

#include<reg51.h>

void svGorit(void)
{P0=0;      //Зажигание светодиода
}

void main(void)
{svGorit(); //Вызов подпрограммы с именем svGorit
 while(1);  //Бесконечный цикл
}

В приведённом примере использование подпрограммы никаких преимуществ не даёт, но в более сложных программах использование "говорящих" имён переменных может приблизить исходный текст программы к алгоритму, и, тем самым, сделать программу более понятной. Это в свою очередь значительно уменьшит время отладки программы.

[ Главная ]


Объявление переменных в PL/M-51

 Rambler's Top100 Дата последнего обновления файла 03.10.2005

Объявление переменных в языке программирования C-51*.

В языке программирования C51 любая переменная должна быть объявлена до первого использования этой переменной. Как уже говорилось ранее, этот язык программирования предназначен для написания программ для микроконтроллеров семейства MCS-51, поэтому в составе языка должна отображаться внутренняя структура этого семейства микроконтроллеров. Эти особенности отражены во введении новых типов данных. В остальном язык программирования C-51 не отличается от стандарта ANSI.

Объявление переменной в языке программирования C51 представляется в следующем виде:

   [спецификатор класса памяти]  спецификатор типа  [спецификатор типа памяти] описатель [=инициатор] [,описатель [= инициатор] ]...

Описатель - идентификатор простой переменной либо более сложная конструкция с квадратными скобками, круглыми скобками или звездочкой (набором звездочек).

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

Инициатор - задает начальное значение или список начальных значений, которые (которое) присваивается переменной при объявлении.

Спецификатор класса памяти - определяется одним из четырех ключевых слов языка С: auto, extern, register, static, и указывает, каким образом будет распределяться память под объявляемую переменную, с одной стороны, а с другой, область видимости этой переменной, т.е., из каких частей программы можно к ней обратиться.

Спецификатор типа памяти - определяется одним из шести ключевых слов языка С-51: code, data, idata, bdata, xdata, pdata и указывает, в какой области памяти микроконтроллера будет размещена переменная.

Категории типов данных

Ключевые слова для определения основных типов данных

     Целые типы данных:     Типы данных с плавающей запятой:
       bit                            float
       sbit
       char
       int
       short
       long
       signed
       unsigned
       sfr
       sfr16

Переменная любого типа может быть объявлена как неизменяемая. Это достигается добавлением ключевого слова const к спецификатору типа. Объекты с типом const представляют собой данные, используемые только для чтения, т.е. этой переменной не может быть присвоено новое значение. Отметим, что если после слова const отсутствует спецификатор типа, то подразумевается спецификатор типа int. Если ключевое слово const стоит перед объявлением составных типов (массив, структура, смесь, перечисление), то это приводит к тому, что каждый элемент также должен являться немодифицируемым, т.е. значение ему может быть присвоено только один раз.

Примеры использования ключевого слова const:

      const float A=2.128E-2;
      const B=286; //подразумевается const int B=286

Отметим, что переменные с спецификатором класса памяти размещаются во внутреннем ОЗУ. Неизменяемость контролируется только на этапе трансляции. Для размещения переменной в ПЗУ лучше воспользоваться спецификатором типа памяти code

Целые типы данных

Для определения данных целого типа используются различные ключевые слова, которые определяют диапазон значений и размер области памяти, выделяемой под переменные (табл. 6).

Таблица 6

Тип | Размер памяти в битах | Размер памяти в байтах | Диапазон значений
bit | 1 |  | от 0 до 1
char | 8 | 1 | от -128 до 127
unsigned shar | 8 | 1 | oт 0 до 255
int, short | 16 | 2 | от -32768 до 32767
long | 32 | 4 | от -2 147 483 648 до 2 147 483 647
unsigned int, unsigned short | 16 | 2 | от 0 до 65535
unsigned long | 32 | 4 | от 0 до 4 294 967 295
sbit | 1 |  | 0 или 1
sfr | 8 | 1 | oт 0 до 255
sfr16 | 16 | 2 | от 0 до 65535

Отметим, что ключевые слова signed и unsigned необязательны. Они указывают, как интерпретируется нулевой бит объявляемой переменной, т.е., если указано ключевое слово unsigned, то нулевой бит интерпретируется как часть числа, в противном случае нулевой бит интерпретируется как знаковый. В случае отсутствия ключевого слова unsigned целая переменная считается знаковой. В том случае, если спецификатор типа состоит из ключевого типа signed или unsigned и далее следует идентификатор переменной, то она будет рассматриваться как переменная типа int. Например:

unsigned int n;  //Беззнаковое шестнадцатиразрядное число n
unsigned int b;
int c;           //подразумевается  signed   int c
unsigned d;      //подразумевается  unsigned int d
signed f;        //подразумевается  signed   int f

Отметим, что модификатор типа char используется для представления одиночного символа или для объявления строковых литералов. Значением объекта типа char является код (размером 1 байт), соответствующий представляемому символу.

Отметим также, что восьмеричные и шестнадцатеричные константы также могут иметь модификатор unsigned. Это достигается указанием суффикса u или U после константы, константа без этого префикса считается знаковой.

Например:

0xA8C   //int  signed
01786l  //long signed
0xF7u   //int  unsigned

Числа с плавающей запятой

Для переменных, представляющих число с плавающей запятой используется модификатор типа float. Модификатор double тоже допустим в языке программирования C51, но он не приводит к увеличению точности результата.

Величина с модификатором типа float занимает 4 байта. Из них 1 байт отводится для знака, 8 бит для избыточной экспоненты и 23 бита для мантиссы. Отметим, что старший бит мантиссы всегда равен 1, поэтому он не заполняется, в связи с этим диапазон значений переменной с плавающей точкой равен от ±1.175494E-38 до ±3.402823E+38.

Пример объявления переменной с плавающей запятой:

float f, a, b;

Переменные перечислимого типа

Переменная, которая может принимать значение из некоторого списка значений, называется переменной перечислимого типа или перечислением.

Использование такого вида переменной эквивалентно применению целой знаковой переменной char или int. Это означает, что для переменной перечислимого вида будет выделен один или два байта в зависимости от максимального значения используемых этой переменной констант. В отличие от переменных целого типа, переменные перечислимого типа позволяют вместо безликих чисел использовать имена констант, которые более понятны и легче запоминаются человеком.

Например, вместо использования чисел 1,2,3,4,5,6,7 можно использовать названия дней недели: Poned, Vtorn, Sreda, Chetv, Pjatn, Subb, Voskr. При этом каждой константе будет соответствовать свое конкретное число. Однако использование имен констант приведет к более понятной программе. Более того, транслятор сам позволяет отслеживать правильность использования констант и при попытке использования константы, не входящей в объявленный заранее список, выдает сообщение об ошибке.

Переменные enum типа могут использоваться в индексных выражениях и как операнды в арифметических операциях и в операциях отношения. Например:

if(rab_ned == SUB) dejstvie = rabota [rab_ned];

При объявлении перечисления определяется тип переменной перечисления и определяется список именованных констант, называемый списком перечисления. Значением каждого имени этого списка является целое число. Объявление перечислимой переменной начинается с ключевого слова enum и может быть представлено в двух форматах:

  1. enum [имя типа перечисления] {список констант} имя1 [,имя2 ...];
  2. enum имя перечисления описатель [,описатель..];

В первом формате имена и значения констант задаются в списке констант. Необязательное имя типа объявляемой переменной - это идентификатор, который представляет собой тип переменной, соответствующий списку констант. За списком констант записывается имя одной или нескольких переменных.

Список констант содержит одну или несколько конструкций вида:

идентификатор [= константное выражение]

Каждый идентификатор - это имя константы. Все идентификаторы в списке enum должны быть уникальными. В случае если константе явным образом не задается число, то первому идентификатору присваивается значение 0, следующему идентификатору - значение 1 и т.д.

Пример объявления переменной rab_ned и типа переменных, совместимых с этой переменной, week выглядит следующим образом:

enum week {SUB = 0, /* константе SUB присвоено значение 0 */
           VOS = 0, /* константе VOS присвоено значение 0 */
           POND,    /* константе POND присвоено значение 1 */
           VTOR,    /* константе VTOR присвоено значение 2 */
           SRED,    /* константе SRED присвоено значение 3 */
           HETV,    /* константе HETV присвоено значение 4 */
           PJAT     /* константе PJAT присвоено значение 5 */
          } rab_ned;

Идентификатор, связанный с константным выражением, принимает значение, задаваемое этим константным выражением. Результат вычисления константного выражения должен иметь тип int и может быть как положительным, так и отрицательным. Следующему идентификатору в списке, если этот идентификатор не имеет своего константного выражения, присваивается значение, равное константному выражению предыдущего идентификатора плюс 1. Использование констант должно подчиняться следующим правилам:

  1. Объявляемая переменная может содержать повторяющиеся значения констант.
  2. Идентификаторы в списке констант должны быть отличны от всех других идентификаторов в той же области видимости, включая имена обычных переменных и идентификаторы из других списков констант.
  3. Имена типов перечислений должны быть отличны от других имен типов перечислений, структур и смесей в этой же области видимости.
  4. Значение может следовать за последним элементом списка перечисления.

Во втором формате для объявления переменной перечислимого типа используется уже готовый тип переменной уже объявленный ранее. Например:

enum week rab1;

К переменной перечислимого типа можно обращаться при помощи указателей. При этом необходимо заранее определить тип переменной, на которую будет ссылаться указатель. Это может быть сделано, как описывалось выше или при помощи оператора 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;

Этот оператор не объявляет переменную, а только определяет тип переменной, отличающийся от стандартного. В дальнейшем этот тип может быть использован для объявления переменных и указателей на переменные.

* Для тех читателей что вышли на эту страницу по поиску прошу обратить внимание, что здесь рассматривается не стандартный язык программирования С, а язык, адаптированный к микроконтроллерам серии MCS-51. Имеются отличия!

[ Главная ]


Операторы языка программирования PL/M-51

 Rambler's Top100 Дата последнего обновления файла 10.08.2005

Выражения в операторах языка программирования C-51.

Выражением называется комбинация знаков операций и операндов, результатом которой является определенное значение. Знаки операций определяют действия, которые должны быть выполнены над операндами. Каждый операнд в выражении в свою очередь может быть выражением. Значение выражения зависит от расположения знаков операций и круглых скобок в выражении, а также от приоритета выполнения операций. Примеры выражений:

А+В
A*(B+C)-(D-E)/F

Выражение в языке программирования С-51 состоит из операндов, которые комбинируются при помощи различных арифметических или логических операций, а также операций отношения. Над переменными-указателями возможно проведение адресных операций.

Операндом в выражении может быть переменная, числовая константа, подпрограмма-функция или указатель. Любой операнд, который имеет константное значение, называется константным выражением. Каждый операнд имеет тип.

Если в качестве операнда используется константа, то ему соответствует значение и тип представляющей его константы. Целая константа может быть типа int, long, unsigned int, unsigned long, в зависимости от ее значения и от формы записи. Символьная константа имеет тип int. Константа с плавающей точкой всегда имеет тип float.

При вычислении выражений тип каждого операнда может быть преобразован к другому типу. Преобразования типов могут быть неявными, при выполнении операций и вызовов функций, или явными, при выполнении операций приведения типов. Из за того, что неявные преобразования типов могут различаться для трансляторов разных фирм, то при написании программы лучше использовать явное преобразование типов переменных. Примеры явных преобразований типов операндов:

a=(int)b+(int)c;     //Переменные a и b могут быть восьмиразрядными. Преобразование типов нужно чтобы избежать переполнения
s=sin((float)a/15)); //Если не преобразовать тип переменной a, то деление будет целочисленным и результат деления будет равен нулю.

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

В языке программирования C-51 используются арифметические операции, результат которых зависит от типа операндов:

  1. + суммирование
  2. - вычитание
  3. * умножение
  4. / деление
  5. % вычисление остатка от целочисленного деления

Примеры выражений, использующие арифметические операции:

А+В
А+В-С
A*T+F/D
A*(B+C)-(D-E)/F

В языке программирования C-51 также определено несколько одноместных арифметических операций:

  1. '-' изменение знака операнда на противоположное значение
  2. '+' знак плюс не влияет на значение операнда
  3. ++ увеличение значения операнда на единицу
  4. -- уменьшение значения операнда на единицу

Для одноместной операции требуется один операнд, которому она предшествует. Например:

P3 = -5;   //Присвоить порту P3 значение числа -5
a = -b;    //Присвоить переменной a отрицательное значение переменной b
с=++a + 2; //Увеличить значение переменной a на 1 и прибавить 2
с=a++ + 2; //Прибавить к переменной a 2, присвоить это значение переменной c и только после этого увеличить значение переменной a на 1.

Над операндами можно осуществлять логические операции:

  1. '&&' логическое "и"
  2. '&' побитовое логическое "и"
  3. '||' логическое "или"
  4. '|' побитовое логическое "или"
  5. '^' "исключающее или" (суммирование по модулю два)

Здесь следует объяснить различие между логическими и побитовыми логическими операциями. Дело в том, что в стандартном языке ANSI C не существует битовых переменных. Для хранения битовых значений истина '1' и ложь '0' используются стандартные целые типы переменных. В простейшем случае это байт. При этом все значения переменной, отличающиеся от 0 считаются 1. Например, пусть в переменной a хранится число 5, а в переменной b - число 6. Тогда:

a|b=7  //00000101 or 00000110 = 00000111
a||b=1 //(00000101)->1 (00000110)->1; (1 or 1= 1), Результат равен 00000001
a&b=4  //00000101 and 00000110 = 00000100
a&&b=1 //(00000101)->1 (00000110)->1; (1 and 1= 1), Результат равен 00000001
a^b=3  //00000101 xor 00000110 = 00000011

В языке программирования C-51 также определено несколько одноместных логических операций:

  1. '!' инверсия операнда
  2. '~' побитовая инверсия операнда

Например, пусть в переменной a хранится число 5. Тогда:

a=~a;  //~00000101 = 11111010 = 250
a=~a;  //~11111010 =  00000101 = 5
a=!a;  //(00000101)->1; ~1 = 0
a=!a;  // ~0 = 1

В условном операторе и операторах цикла используются операции отношения:

  1. < меньше
  2. > больше
  3. <= меньше или равно
  4. >= больше или равно
  5. == равно
  6. != не равно

Если указанное отношение между операндами верно, то результат равен 1, иначе 0. Например, если d=7, то:

(d > 5) результат будет 1 (истина)
(d = 4) результат будет 0 (ложь)

Над переменными-указателями возможно проведение адресных операций.

  1. '*' операция косвенной адресации
  2. '&' вычисление адреса переменной

Операция косвенной адресации '*' осуществляет доступ к переменной при помощи указателя. Результатом операции является значение переменной, на которую указывает операнд. Типом результата является тип переменной, адресуемой указателем. При работе с указателями необходимо быть предельно осторожными, так как, если указатель содержит недопустимый адрес, то результат операции чтения или записи будет непредсказуем и может привести к выходу проектируемого устройства из строя.

Операция вычисления адреса переменной '&' дает адрес ячейки памяти своего операнда. Операндом может быть любой идентификатор. Имя функции или массива также может быть операндом операции вычисления адреса переменной, хотя в этом случае знак операции вычисления адреса переменной является лишним, так как имена массивов и функций являются и так являются адресами. Операция вычисления адреса переменной не может применятся к элементам структуры, являющимися полями битов, и к объектам с классом памяти register.

Пример использования адресных операций при работе с указателем:

 int t, f=0,  *adress;
 adress = &t /* переменной adress, объявленной как указатель, присваивается адрес переменной t */
 *adress =f; /* переменной находящейся по адресу, содержащемуся в переменной adress, присваивается значение
                переменной f, т.е. 0, что эквивалентно t=f; т.е. t=0; */

Может возникнуть вопрос: а зачем тогда нужны указатели, если можно прекрасно обойтись обычным присваиванием переменной? Использование указателей очень удобно при написании подпрограмм. Ведь одни и те же действия подпрограмма должна выполнять над различными участками памяти. Например при выводе информации через последовательный порт:

void PutNadp(char code *c)//Объявлен указатель c на символ в памяти программ
{do{while(!TI);  //Подождать готовности последовательного порта
    TI=0;
    SBUF=*c++;   //Передать очередной символ
 }while(*c!=0);  //Если передан последний символ строки
}             //то выйти из подпрограммы
...
PutNadp("привет!"); //Вывод одной строки
...
PutNadp("Вася!");   //Вывод второй строки

Приоритеты выполнения операций.

В языке С-51 операции с высшими приоритетами вычисляются первыми. Наивысшим приоритетом является приоритет равный 1. Приоритеты и порядок операций приведены в табл. 1. Порядок вычисления выражения следующий: сначала выполняются операторы в круглых скобках, в них от старшего приоритета к младшему, а среди равнозначных операторов - слева направо.

Таблица 1

Приоритет | Знак операции | Типы операции | Порядок выполнения
2 | () [] . -> | Выражение | Слева направо
1 | - ~ ! * & ++ -- sizeof приведение типов | Унарные | Справа налево
3 | * / % | Мультипликативные | Слева направо
4 | + - | Аддитивные
5 | << >> | Сдвиг
6 | < > <= >= | Отношение
7 | == != | Отношение (равенство)
8 | & | Поразрядное И
9 | ^ | Поразрядное исключающее ИЛИ
10 | | | Поразрядное ИЛИ
11 | && | Логическое И
12 | || | Логическое ИЛИ
13 | ? : | Условная
14 | = *= /= %= += -= &= |= >>= <<= ^= | Простое и составное присваивание | Справа налево
15 | , | Последовательное вычисление | Слева направо

[ Главная ]


Символы языка программирования PL/M-51

Символы языка программирования PLM-51.

В исходном тексте программы, написанной на языке программирования PLM-51 можно использовать буквы латинского алфавита верхнего и нижнего регистров, а также арабские цифры:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d i f g h i j k l m n o p q r s t
0 1 2 3 4 5 6 7 8 9

В языке программирования PLM-51 используются также специальные символы:

= . / ( ) + ' < > : ; $ _

Кроме того, язык программирования PL/M-51 использует символы пробела, табуляции, возврата каретки, перевода строки.

Компилятор PLM-51 выдает сообщение об ошибке, если в тексте исходной программы встречается символ, отличающийся от символов, перечисленных выше. (То есть строки и символьные константы на русском языке запрещены!) Компилятор воспринимает последовательность непрерывных пробелов как один пробел.

PLM-51 не делает различий между строчными и заглавными буквами, кроме символьных строк. Например, имена xyz и XYZ одинаковы, а строки 'PLM' и 'plm' различны.

Идентификаторы в языке программирования PLM-51 используются для того, чтобы дать имя переменной, процедуре, символической константе или метке оператора. Длина идентификатора не превышает 31 символ. Первый символ обязательно должен быть буквой, последующие символы могут быть буквами, цифрами, знаками _ или $. Знак $ внутри идентификатора всегда игнорируется транслятором и может использоваться для улучшения читаемости идентификатора. Идентификатор, содержащий знак $, является полным эквивалентом идентификатора, из которого этот знак удален.

Примеры правильных идентификаторов:

A
XYR_56
DFG$$RTY$CFG
RT$EUI
RTEUI

Последние два примера эквивалентны.

Идентификаторы должны отличаться от зарезервированных (ключевых) слов.

Лексические единицы, разделители и использование пробелов.

Наименьшей единицей операторов PL/M-51 является лексическая единица. Каждая из лексических единиц относится к одному из классов:

  • идентификаторы;
  • ключевые слова;
  • простые ограничители (все специальные символы, кроме $ и _, являются простыми ограничителями);
  • составные ограничители (они образуются посредством определенных комбинаций двух спецсимволов, а именно: <>, <=, >=, /*, */);
  • числовые константы;
  • текстовые строковые константы;

В большинстве случаев вполне очевидно, где заканчивается одна лексическая единица и начинается следующая. Например, в операторе присваивания:

X=AP*(FT-3)/A;

X, AP, FT, A - являются идентификаторами переменных;
3 - числовой константой;
все прочие символы - простыми ограничителями.

Ключевые слова, идентификаторы и числовые константы должны обязательно отделяться друг от друга. Если между двумя идентификаторами, числовыми константами или ключевыми словами не может быть указан простой или составной ограничитель, то в качестве разделителя между ними должен вставляться символ пробела. Вместо одного символа пробел может использоваться непрерывная последовательность символов пробела.

Целочисленные константы.

Целочисленные константы могут быть записаны как двоичные, восьмеричные, десятичные или шестнадцатеричные числа в зависимости от того, какая система счисления удобнее для представления константы. Компилятор распознает основание системы счисления по одной из букв B, Q’ O’ D или Н, следующей за числом (суффикс).

Буква B используется для обозначения двоичных чисел. Примеры записи двоичных констант:

1001b, 1000$1100B.

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

Буквы 'O' или 'Q' используется для обозначения восьмеричных чисел (рекомендуется буква Q).

Для обозначения десятичных чисел используется буква D. Если буква за числом отсутствует, то считается, что это десятичная константа.

Шестнадцатеричные цифры определяются по букве H. Первым символом шестнадцатеричной константы обязательно должна быть цифра, это отличает ее от идентификаторов. Например, шестнадцатеричное представление числа 163 должно быть записано как 0A3H, а не А3Н, что будет принято компилятором за идентификатор.

Если константа содержит цифру, недопустимую в данной системе счисления, то данная константа считается ошибочной.

Максимальное значение целочисленной константы с размерностью word:

1111$1111$1111$1111В = 177777Q = 65535D = 0FFFFH

Примеры правильных целочисленных констант:

12AH, 2, 33Q, 1010B, 55D, 0BF3H, 65535, 0FC05H

Примеры синтаксически недопустимых целочисленных констант:

12AF - шестнадцатеричная константа не имеет буквы Н в конце, поэтому по умолчанию для нее принимается десятичная система счисления, но тогда в ней присутствуют недопустимые символы.

12AD - последний символ D может быть интерпретирован как основание системы счисления, но тогда символ А не десятичная цифра. Если же это шестнадцатеричная константа, то тогда в ней отсутствует указатель системы счисления буква Н.

11А2В - А и 2 недопустимые цифры для двоичного числа. Если необходимо записать шестнадцатеричную константу, то надо указать суффикс Н.

2ADGH - символ G недопустим при записи шестнадцатеричных чисел.

Строчные константы.

Строчная константа записывается при помощи символов кода ASCII заключенных в апострофы. Для того, чтобы включить в строку апостроф записывается два апострофа. Например, строка '''Q' состоит из двух символов - апострофа и буквы Q. В строке допускается использование пробелов. Транслятор представляет в памяти строки символов в коде ASCII-7, по одному восьмиразрядному байту на каждый семиразрядный код, с нулевым старшим разрядом. Строка, состоящая из двух символов, транслируется в двухбайтовое значение. Например: строка 'А' эквивалентна числу 41Н, а строка 'AG' эквивалентна числу 4147Н. Строки символов, имеющие длину более двух символов, не могут использоваться в качестве арифметических значений, поскольку арифметические значения ограничиваются 16 двоичными разрядами. Тем не менее, более длинная строка символов может использоваться для хранения текстовых сообщений.

Необходимо однако отметить, что язык программирования PLM-51 не поддерживает русских букв и воспринимает эти символы как ошибки. Если требуется написать какую либо команду на русском языке, то приходится использовать для этого цифровые константы.

Комментарии.

Поясняющие комментарии могут чередоваться с текстом программы для улучшения читаемости программы и ее документирования. Комментарии в языке программирования PL/M-51 являются последовательностью символов, которая слева ограничивается символами /*, справа ограничивается символами */. Эти ограничители указывают транслятору, что следует игнорировать любой текст между ними. Комментарий может содержать любой печатный символ кода ASCII, а также включать пробелы, возврат каретки, перевод строки и табуляцию. Комментарий не может быть вставлен внутрь содержимого строковой константы. Комментарий может встречаться везде, за исключением вставки его в лексическую единицу.

Пример комментария: /* начало сегмента данных */


Многомодульные программы.

Язык программирования PLM-51 позволяет писать многомодульные программы.

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

Раздельная трансляция программы возможна при использовании двух программ: транслятора исходного текста программы plm-51 и редактора связей rl-51.

На первый взгляд раздельная трансляция не должна вызывать каких либо проблем. Однако это не так. При компиляции исходного текста программы если транслятор обнаружит переменную или подпрограмму, которые не были заранее объявлены, то будет сформировано сообщение об ошибке и объектный модуль будет стёрт с диска компьютера.

Для того, чтобы транслятор вместо формирования сообщения об ошибке записал в объектный модуль информацию, необходимую для редактора связей, нужно осуществить объявление внешних переменных подпрограмм и меток. Для объявления внешних переменных после обычного объявления добавляется слово EXTERNAL. При таком объявлении при трансляции исходного текста программы для переменной память данных для переменных не распределяется, а создаются соответствующие записи для редактора связей, позволяющие осуществить соответствующие вызовы подпрограмм и переходы между модулями, а также обращение к переменным другого модуля. Пример объявления внешних переменных на языке программирования PLM-51:

declare
  RejRab  byte external,
  UrovGr  byte external,
  NomKan  word external,
  Sost    bit external,
  Soob    bit external;

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

Все используемые подпрограммы тоже должны быть предварительно объявлены. При использовании подпрограмм из других модулей они должны быть объявлены как внешние. При этом должны быть полностью объявлены все параметры подпрограмм. Пример объявления внешних подпрограмм на языке программирования PLM-51:

TestOZU: procedure byte external;
end TestOZU;

Rd558: procedure (AdrRAM,NachAdr,Nbyte) byte external;
var (AdrRAM,NachAdr,Nbyte )byte;
end Rd558;

Wr558: procedure (AdrRAM,NachAdr,Nbyte) byte external;
var (AdrRAM,NachAdr,Nbyte )byte;
end Wr558;

Для того, чтобы редактор связей мог связать вызов подпрограммы из одного модуля с самой подпрограммой в другом модуле, информация об этой подпрограмме должна быть помещена в объектный модуль. Для этого подпрограмма должна быть оттранслирована с атрибутом PUBLIC. Пример определения подпрограммы, доступной для других модулей, в исходном тексте модуля:

WrNadp: procedure(i,StrPtr) public;
declare
  StrPtr address,
  char based StrPtr byte constant,
  i byte;

  do while char<>0;
    BufInd(i)=char;
    StrPtr=StrPtr+1;
    i=i+1;
  end;
end WrNadp;

IndNom: procedure public;
declare
  Adres byte;

  if BufInd(2)=0 then
      Adres=0;
    else
      Adres=8;

  if RejNab=NabTlf1 then call WrNadp(Adres,.('T1',0));
  if RejNab=NabTlf2 then call WrNadp(Adres,.('T2',0));
  if RejNab=NabRadA then call WrNadp(Adres,.NadpRa);

  if Adres=0 then
      call WrInd;
    else
      call InitPolnInd(2);
end IndNom;

Переменные, к которым можно обращаться из других модулей, тоже должны быть объявлены с атрибутом PUBLIC.

Программа rl-51 объединяет несколько объектных файлов (модулей) в один. Для объединения нескольких модулей в исполняемую программу имена всех модулей передаются в редактор связей в качестве параметров при запуске этой программы. Пример вызова редактора связей из командной строки DOS для объединения трёх модулей:

rl51.exe progr.obj, modul1.obj, modul2.obj

В результате работы редактора связей в этом примере будет создан исполняемый модуль с именем progr.

Необходимость предварительного объявления внешних переменных и подпрограмм приводит к тому, что исходный текст программы загромождается этими объявлениями и найти собственно программу становится сложно. Кроме того при таких объявлениях возможно возникновение ошибок. Поэтому лучше вынести объявления подпрограмм и переменных в отдельные файлы, которые затем могут быть подключены в исходный текст программы директивой INCLUDE.

Наименьшая вероятность ошибиться при описании переменных и подпрограмм у программиста, который писал исходный текст модуля, к подпрограммам и переменным которого нужно обращаться из других модулей. Поэтому правила хорошего тона предполагают, что этот программист будет поставлять не только объектный модуль, но и файл описания своих переменных с атрибутом EXTERNAL. Такие файлы называются файлами заголовками и обычно записываются с расширением *.h. Пример исходного текста модуля приведён ниже:

/*Исходный текст модуля comm.plm*/
$CODE
$NOLIST

Kommand: do;
$INCLUDE (C:\COMP\PLM51\BIN\Rg51FA.Dcl)
$INCLUDE (stdio.h) /*Подключение других файлов заголовков*/
$INCLUDE (dcl.h)
$LIST

declare
  NomPult byte external,
  Bufer(7) byte external,
  RejRab byte public,
  NomKan word public,

PrmSoob: procedure using 2;
declare
  i byte;

  for i=0 to KolBytes;
    do while not RI;end;
    BufInd(i)=SBuf;
    RI=0;
  end;

  Soob=true;
end PrmSoob;

PriemKom: procedure interrupt 4 using 2;
  KodKom=(SBuf and 0f0h)/16;
  KolBytes=SBuf and 0fh;
  RI=0;
  If KodKom=KomSoob then call PrmSoob;
  If KodKom=KomSost then call PrmSost;
end PriemKom;
/*------- Конец модуля ---------*/

Исходный текст файла-заголовка этого модуля:

/*Начало файла заголовка comm.h*/
declare
  RejRab byte external,
  NomKan word external,

PriemKom:procedure external;end PriemKom;
/*------- Конец файла заголовка---------*/

Теперь для того, чтобы воспользоваться приведённым выше модулем достаточно записать строку:

$INCLUDE (comm.h)

Естественно, так как процесс трансляции разбит на два этапа, то ошибки могут возникать не только на этапе трансляции модулей, но и при связывании модулей в исполняемую программу. Наиболее распространённые ошибки - это забыть включить имя объектного модуля в строку вызова редактора связей, забыть объявить переменную или подпрограмму как PUBLIC или использовать одни и те же адреса для переменных или констант в различных модулях. Сообщения об этих ошибках выводятся в файл с расширением *.m51.

Полный путь написания программ на языке программирования plm51 показан на рисунке 1 файла описания языка программирования plm-51.


Области действия переменных PL/M-51

Вложенные блоки и области действия переменных.

Любой объект, который объявляется в программе на языке PL/M-51, имеет область действия. Область действия существует для:

  • переменных
  • подпрограмм
  • меток

Область действия объекта представляет собой часть программы, в которой объявляется идентификатор объекта за вычетом текста, содержащегося в любом вложенном в него блоке, в котором объявляется тот же самый идентификатор. К объектам запрещено обращение до того, как они будут объявлены. Это ограничение не касается меток.

Такое определение области действия позволяет не следить при написании программы за использованием идентификаторов, которые уже были использованы в программе в других модулях.

Некоторые блоки могут содержать вложенные блоки, как показано в следующих примерах. Использование внутренних блоков позволяет объявлять локальные переменные. Это позволяет использовать одни и те же ячейки памяти для различных переменных и тем самым экономить ресурсы памяти данных.

Пример 1:

Пример 2:

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

Это правило не распространяется на вызов подпрограмм. При вызове подпрограммы переменная, объявленная в блоке становится недоступной, но при возвращении в этот блок она сохраняет свое значение.


Операторы языка программирования PL/M-51.

В языке программирования PL/M-51 используется два типа операторов: операторы объявления и выполняемые операторы. Все операторы PL/M-51 заканчиваются точкой с запятой.

Операторы объявления.

Объявление является невыполняемым оператором, который объявляет некоторый объект или набор объектов, связывает с ним один или несколько идентификаторов и, если это необходимо, распределяет память.

В объявлении могут быть объявлены пять типов объектов: переменные, константы, литералы, метки и подпрограммы. В текущем блоке для каждого имени допустимо только одно объявление.

Переменные, константы, литералы и подпрограммы должны быть объявлены раньше, чем они будут использоваться в выполняемом операторе. Метка полностью объявлена, если она стоит перед выполняемым оператором и заканчивается с двоеточием (:) или определена в операторе DECLARE. Подпрограмма объявляется оператором PROCEDURE и заключается между операторами PROCEDURE и END. Переменные, константы и литералы должны объявляться оператором DECLARE.

DECLARE Width byte;

Этот оператор вводит идентификатор (переменную) Width (ширина англ) и резервирует 1 байт (8 бит) памяти. В языке программирования PL/M-51 нет необходимости знать конкретный адрес этой переменной, достаточно обратиться к ней по имени Width.

Группа операторов, предназначенных для выполнения какой-либо функции, может быть задана именем, объявляющим их как подпрограмму.

Address_Upper: PROCEDURE (Beta) byte;

Исполняемые операторы.

  • Оператор присваивания:
  • Условный оператор.
  • Структурный оператор.
  • Оператор цикла
  • Оператор цикла с проверкой условия до тела цикла
  • Оператор выбора
  • Оператор безусловного перехода
  • Операторы вызова подпрограммы
  • Оператор возвращения из подпрограммы
  • Пустой оператор

В языке программирования PLM-51 используются беззнаковые арифметические операции, результат которых зависит от типа операндов:

  1. + суммирование
  2. - вычитание
  3. * умножение
  4. / деление
  5. mod вычисление остатка от целочисленного деления
В языке программирования PLМ-51 также определена одноместная операция '-'. Для нее требуется один операнд, которому она предшествует.

При использовании в операции различных типов операндов (byte или word) происходит автоматическое преобразование типов к одному виду (word). Если в выражении необходимо одновременно использовать тип bit, то нужно использовать функции преобразования типов boolean, expand или propagate.

В условном операторе и операторах цикла используются операции отношения:

  1. < меньше
  2. > больше
  3. <= меньше или равно
  4. >= больше или равно
  5. = равно
  6. <> не равно

Если указанное отношение между операндами верно, то результат битового типа равен 1, иначе - 0. Например, если d=7, то:

(d > 5) результат будет 1 (истина)
(d = 4) результат будет 0 (ложь)

Над переменными можно осуществлять логические операции:

  1. not побитовая инверсия операнда
  2. and логическое "и"
  3. or логическое "или"
  4. xor "исключающее или" (суммирование по модулю два)

Приоритеты операций.

В таблице 1 приведены приоритеты операторов языка программирования PL/M-51 от высшего приоритета к низшему. Порядок вычисления выражения следующий: сначала выполняются операторы в круглых скобках, в них от старшего приоритета к младшему, а среди равнозначных операторов – слева направо.

Таблица 1

Оператор | Класс | Описание
(, ) | Скобки | Управляют порядком вычислений выражения внутри скобок, вычисляются до действий над операторами вне скобок
+, . , - | Унарная операция | Одиночный оператор плюс, оператор адреса, одиночный оператор минус
*, /, MOD, =, - , PLUS, MINUS | Арифметическая операция | Умножение, деление, модуль (остаток) от деления, сложение, вычитание
<, <=, <>, =, >=, > | Операция отношения | Меньше, меньше или равно, не равно, равно, больше или равно, больше
NOT AND OR, XOR | Логическая операция | Логическое отрицание Логическое 'И' Логическое 'ИЛИ', логическое исключающее 'ИЛИ'

Оператор присваивания.

Оператор присваивания записывается в виде:

Переменная=выражение;

Выражение вычисляется, и полученное значение присваивается переменной.

Пример оператора присваивания: A=B+2;

Выражение в языке программирования PL/M-51 состоит из операндов, которые комбинируются при помощи различных арифметических или логических операций, а также операций отношения.

Например:

А + В
А + В - С
A * T + F/D
A * (B + C) - (D - E)/F
A XOR B,

Операндом в выражении может быть переменная, подпрограмма-функция, числовая константа или указатель.

В выражениях в качестве операндов могут использоваться подвыражения. Подвыражение - это обычное выражение, заключенное в скобки. Подвыражения могут использоваться для группировки частей выражения, точно так же, как и в обычной алгебраической записи. Использование подвыражений позволяет сократить количество операторов в программе, а значит и объем исходного текста программы, но затрудняет отладку этой программы.

Язык программирования PL/M-51 обеспечивает автоматическое преобразование между типами BYTE и WORD, но не может автоматически преобразовывать битовые переменные в числовые.

Числовые значения могут быть преобразованы к битовому типу при помощи встроенной функции BOOLEAN, которая возвращает битовое значение, равное биту в младшем разряде исходного числа. Битовая переменная может быть преобразована в числовую при помощи встроенных функций EXPAND и PROPAGATE. Обе процедуры преобразуют 0 (ложь) в число 00h. Функция EXPAND преобразует 1 (истина) в число 01h, а PROPAGATE преобразует 1 в число 0ffh (255). Например, встроенная функция propagate преобразует битовое значение в байт:

I = J + Propagate(Magic_Bit);

Условный оператор.

Оператор IF обеспечивает условное выполнение операторов. Он записывается в следующей форме:

  IF <выражение> THEN
      <operator-1>;
    [ELSE
      <operator-2>;]

ключевое слово THEN и исполняемый оператор, следующий за ним, записываются всегда, а ключевое слово ELSE со следующим за ним исполняемым оператором представляют собой необязательную часть условного оператора. Если результат вычисления выражения равен 1 (истина), то выполняется operator-1. Если результат вычисления выражения равен 0 (ложь), то выполняется operator-2. Пример:

 IF Wes<Min then      /*Условная операция*/
   Schetch=Schetch+1;   /*Плечо 1*/
  else
   Schetch=0;           /*Плечо 2*/

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

 IF PrinjatByte then
   Call DecodCmd;

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

Структурный оператор do;end;

Существует три основных способа использования структурного оператора:

  1. Структурный оператор может рассматриваться в качестве отдельного оператора языка PL/M-51 и использоваться в программе везде, где может встречаться отдельный исполняемый оператор. Это используется в блоках DO CASE и операторах IF;
  2. Структурный оператор ограничивает область действия локальных переменных.
  3. Вся программа написанная на языке программирования PL/M-51 сама может рассматриваться как структурный оператор do;end, удовлетворяющим дополнительным требованиям.

Каждый оператор внутри структурного оператора может являться любым оператором языка PL/M-51, в том числе и объявлением, при условии, что все объявления внутри структурного оператора должны быть выполнены до первого исполняемого оператора.

Структурный оператор начинается с ключевого слова DO и записывается в следующем виде:

  do;
    <operator-1>;
    <operator-2>;
    ...
    <operator-n>;
    end;
Пример:
 IF Wes<Min then      /*Условная операция*/
   do;                  /*Структурный оператор*/
     incr=incr*2;          /*Содержит два*/
     Schetch=Schetch+1;    /*оператора*/
   end;

Структурные операторы могут вкладываться друг в друга. При этом максимальное число уровней вложенности не может превышать 16.

Пример:
do;
  <operator-1>;
  <operator-2>;
  do;
    <operator-A>;
    <operator-B>
    <operator-C>;
  end;
  <operator-3>;
  <operator-4>;
end;

Оператор цикла do

Оператор цикла DO записывается в следующей форме:

do <переменная цикла> = <начальное выражение>to<конечное выражение>;
  <operator-1;
  <operator-2>;
  ...
  <operator-n>;
end;

где переменная цикла должна быть простой скалярной переменной и иметь тип BYTE или WORD. Она не может быть элементом массива или быть базированной переменной. Начальное выражение и конечное выражение могут быть любыми разрешенными выражениями языка PL/M-51. Они тоже должны иметь тип byte или word. Оператор цикла работает следующим образом:

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

Начальное значение вычисляется один раз. Конечное значение вычисляется каждый раз при повторении блока. Отрицательное значение шага недопустимо.

Пример:
 do j = 0 to 9 by 2;
   Vector(j) = 0;
 end;

В более общей форме оператора цикла DO разрешается использовать значение шага цикла, отличающееся от 1. Эта форма выглядит следующим образом:

 do <переменная цикла> = <начальное выражение> to <конечное выражение> by <выражение шага>;
   <operator-1>;
   <operator-2>;
   ...
   <operator-n>;
end;

В данном случае переменная цикла, которая задается в операторе DO, увеличивается каждый раз при достижении оператора END на значение шага, равное значению выражения шага, а не на 1. Пример использования такой формы оператора DO:

SOS=1;
do i=1 to 2*X by 2;
  SOS= SOS*ARY(i);
end;

Значение выражения шага может иметь тип BYTE или WORD. Выражение шага цикла вычисляется каждый раз сразу же после выполнения всех операторов в операторе цикла. Аналогично структурному оператору, оператор цикла может рассматриваться как одиночный оператор языка PL/M-51. В отличие от структурного оператора, оператор цикла не может содержать в себе объявлений. Однако он может содержать вложенный структурный оператор, в котором можно поместить объявления переменных.

Оператор цикла с проверкой условия до тела цикла do while

Оператор DO WHILE содержит условную операцию (такую же, как в части IF оператора IF), и вызывает исполнение операторов в этом блоке до тех пор, пока условие верно. В следующем примере оператор DO WHILE используется для пошагового прохождения по элементам массива Table до тех пор, пока очередной элемент не превысит значение скалярной переменной с именем Level (уровень англ.):

  i = 0;
  do while table(i) <= Level;
    i = i + 1;
  end;

В этом примере Table – это предварительно объявленный массив. Переменные Level и i тоже должны быть предварительно объявлены.

Переменной i первоначально присваивается значение 0, затем она используется как индекс для массива Table. Так как i увеличивается при каждом выполнении блока DO WHILE, то каждый раз, когда выполняется исполняемый оператор внутри блока DO WHILE, с переменной Level сравнивается следующий элемент массива Table. Когда найден элемент, превышающий значение переменной Level, то условие в операторе DO WHILE больше неверно, выполнение блока не повторяется и управление передается следующему за зарезервированным словом END оператору. С этого момента переменная i является индексом первого элемента массива Table, который превышает значение переменной Level.

Оператор выбора do case

Оператор DO CASE, использует значение данного выражения для выбора исполняемого оператора. Следует отметить, что язык программирования PLM-51 ориентирован на микроконтроллеры MCS-51. Поэтому для реализации данного оператора используется команда процессора JMP @A+DPTR. Это означает, что команда выполняется за два машинных цикла. В следующем примере Tst_1 в операторе DO CASE может иметь любое значение от 0 до 3.

do case Tst_1;
  red = 0;
  blue = 0;
  green = 0;
  gray = 0;
end;

Если значение выражения равно 0, то выполняется только первый оператор присваивания, и 0 будет присвоен переменной red (красный англ). Если значение выражения равно 1, то будет выполнен только второй оператор присваивания и переменной blue (голубой англ) будет присвоен 0. Значения выражения 2 и 3 вызовет присваивание 0 переменным green (зеленый англ) и gray (серый англ) соответственно.

Максимальное число выбираемых операторов может быть 84. В операторе должны присутствовать все варианты выбора! Если какой либо оператор не нужен, то используется пустой оператор, состоящий только из символа ';'. Если же по одному из вариантов требуется выполнение нескольких операторов, то можно воспользоваться структурным оператором.

Оператор безусловного перехода GOTO.

Оператор GOTO изменяет порядок выполнения программы при помощи передачи управления на оператор, метка которого указана в операторе GOTO. Ключевое слово GOTO может также записываться со вставленным пробелом, т.е. в виде GO TO. Оператор GOTO записывается в следующем виде:

GoTo < метка >;

Использование операторов GOTO является неизбежным при некоторых ситуациях, однако в большинстве случаев там, где должна быть предусмотрена передача управления, более предпочтительным является использование итеративного оператора DO, DO WHILE, DO CASE, IF или вызова процедуры. Неограниченное использование операторов GOTO в программе приводит к тому, что программу становится трудно понимать, модифицировать и сопровождать. Реальная практика использования языка PL/M-51 для программирования как системных, так и прикладных задач, показывает, что в большинстве случаев программные модули могут не содержать оператор GOTO без ухудшения их эффективности.

Оператор вызова подпрограммы CALL.

Оператор CALL используется для того, чтобы вызвать подпрограмму- процедуру (т.е. подпрограмму, которая не возвращает значения). Пример использования оператора CALL:

   Call DecodCmd;

Оператор возвращения из подпрограммы RETURN.

Выполнение подпрограммы может завершаться выполнением оператора RETURN в теле подпрограммы. Подпрограмма-функция обязательно должна содержать оператор RETURN с выражением в качестве операнда. Пример использования оператора RETURN:

   RETURN 2+2;

Пустой оператор.

Пустой оператор не содержит ничего, кроме пробелов и комментариев. Это выполняемый оператор без какого-либо воздействия на программу. У пустого оператора может быть метка. Пустой оператор удобно использовать как часть конструкции DO CASE. Пустой оператор завершается точкой с запятой ‘;’.


Структура языка программирования PL/M-51

Язык программирования PLM-51.

Язык высокого уровня PLM-51 предназначен для программирования контроллеров серии MCS-51. Он удовлетворяет требованиям разработки программного обеспечения микроконтроллеров для систем различного назначения.

Компилятор plm51.exe - это программное средство, которое транслирует исходный текст, написанный на языке программирования PL/M-51 в перемещаемые объектные модули. Эти модули затем могут объединяться с другими модулями, написанными на языкax программирования PLM-51 или ASM-51. Компилятор выводит на экран дисплея или в файлы листингов сообщения об ошибках и вспомогательную информацию, которая может быть использована при отладке и разработке программ.

Компилятор plm51.exe может быть установлен на компьютерах серии IBM или совместимых с ними в операционной системе DOS 3.Х и выше и использоваться для генерации команд микроконтроллеров семейства MCS-51.

Необходимо отметить, что язык программирования PLM-51 предназначен для написания управляющих программ, поэтому не поддерживает знаковую арифметику и вычисления с плавающей запятой. Это является одновременно и преимуществом и недостатком этого языка программирования. Из-за указанной особенности загрузочные модули, созданные на этом языке программирования получаются практически такими же компактными, как и написанные на языке программирования ассемблер, но если в процессе реализуемого алгоритма управления каким либо объектом требуется достаточно сложные вычисления, то приходится использовать отдельно написанные библиотеки математической поддержки (или писать их самим).

Пожалуй в настоящее время, если требуются достаточно сложные математические вычисления, то стоит использовать язык программирования С-51. К настоящему времени появились трансляторы с этого языка программирования, создающие загрузочный модуль, лишь немногим уступающие компактностью загрузочному модулю, создаваемому языком программирования PLM-51 (естественно при правильном объявлении переменных и соответствующем стиле программирования).

Применение.

Язык программирования PL/M-51 и его библиотеки являются частью интегрированного набора средств разработки программного обеспечения для микроконтроллеров семейства MCS-51. Язык программирования PLМ51 поддерживает модульное написание программ. Процесс разработки программ на языке программирования PLM-51 показан на рисунке 1.

Рисунок 1. Процесс написания программы на языке программирования PLM-51.

При разработке программного обеспечения выполняются следующие этапы:

  • постановка задачи (полное определение решаемой проблемы);
  • разработка принципиальной схемы и выбор необходимого программного обеспечения;
  • разработка системного программного обеспечения. Этот важный шаг состоит из нескольких этапов, включающих: описание последовательности выполняемых каждым блоком задач, выбор языка программирования и используемых алгоритмов;
  • написание текста программы и подготовка к трансляции при помощи любого текстового редактора;
  • компиляция программы;
  • исправление синтаксических ошибок, выявленных компилятором, в текстовом редакторе с последующей перетрансляцией;
  • создание и сохранение библиотек часто используемых объектных модулей при помощи программы lib51.ехе;
  • связывание полученных перемещаемых объектных модулей в абсолютный модуль и размещение переменных в памяти микроконтроллера при помощи редактора связей rl51.exe;
  • создание программы, записываемой в ПЗУ микроконтроллера (загружаемый модуль) в hex формате, при помощи программы oh.exe;
  • проверка полученной программы при помощи символьного отладчика или других программных или аппаратных средств.

Файл, в котором хранится программа, написанная на языке PLМ51 (исходный текст программы), называется исходным модулем. Для исходного текста программы принято использовать расширения файла: plm или p51. Исходный текст программы можно написать, используя любой текстовый редактор.

Получить объектный модуль можно, указав имя исходного модуля программы в качестве параметра программы-транслятора в DOS строке или строке командного файла:

plm51.exe modul.plm

В этом примере в результате трансляции исходного текста программы, содержащегося в файле modul.plm будет получен объектный модуль, который будет записан в файл с именем modul.obj. Как показано на рисунке 1, объектный модуль не может быть загружен в память программ микроконтроллера. В память микроконтроллера загружается исполняемый модуль.

Получить исполняемый модуль программы можно, указав все имена объектных модулей программы в качестве параметров программы редактора связей в DOS строке или строке командного файла:

rl51.exe main.obj, modul1.obj, modul2.obj

Имя исполняемого модуля программы по умолчанию совпадает с именем первого объектного файла в списке параметров строки запуска редактора связей. Исполняемый модуль программы записывается в файл без расширения. При выполнении приведённой выше в качестве примера командной строки будет получен исполняемый модуль, который будет записан в файл с именем main.

Большинство программаторов, предназначенных для записи информации в память программ микроконтроллеров, не может работать с объектным форматом исполняемого модуля программы, поэтому для загрузки машинного кода в процессор необходимо преобразовать объектный формат исполняемого модуля в общепринятый для программаторов гексадецимальный формат. При преобразовании форматов вся отладочная информация теряется. Машинный код процессора в гексадецимальном формате называется загрузочным модулем.

Загрузочный модуль программы можно получить при помощи программы-преобразователя программы oh.exe, передав ей в качестве параметра имя файла исполняемого модуля программы, например:

oh.exe main

В результате выполнения этой командной строки будет получен загрузочный модуль программы, который будет записан в файл с именем main.obj.

Отладка программ.

После того, как программные модули были успешно оттранслированы, размещены по конкретным адресам и связаны между собой, для отладки программы можно воспользоваться любым из методов, показанных на рисунке 1:

  • внутрисхемным эмулятором
  • встроенным программным отладчиком
  • внешним программным отладчиком
  • отлаживаемым устройством с записанным в память программ двоичным кодом программы

Внутрисхемный эмулятор с отображением переменных языка программирования на дисплее компьютера оказывает значительную помощь при отладке программ непосредственно на разрабатываемой аппаратуре. Этот метод отладки предоставляет наиболее удобную среду, когда можно непосредственно в отлаживаемом устройстве останавливать программу, контролировать выполнение программы непосредственно по исходному тексту программы, состояние внешних портов и внутренних переменных, как входящих в состав микросхемы, так и объявленных при написании исходного текста программы. Необходимое для отладки программ оборудование показано на рисунке 2.

Рисунок 2. Пример системы отладки программного обеспечения для микроконтроллеров.

При отладке программы с использованием внутрисхемного эмулятора необходимо включать в объектные модули символьную информацию. Для этого используются директивы компилятора. В компиляторе языка программирования PLM-51 возможны следующие действия:

  • включение информации о типе переменных для проверки типов при связывании модулей. Эта же информация используется внутрисхемным эмулятором. Исключение информации о переменных пользователя может использоваться для создания прототипов или для уменьшения размера объектного модуля;
  • включение или исключение таблиц символьной информации;
  • конфигурация вызовов подпрограмм для обеспечения связывания с модулями, написанными на языке программирования ASM-51;
  • определение желаемого содержания и формата выходного листинга программы. Распечатка промежуточных кодов на языке ассемблер после компилирования программ, написанных на языке программирования PLM-51. Включение или исключение листингов отдельных блоков исходного текста.


Символы языка программирования PLM-51

Объявления подпрограмм в языке программирования PLM-51.

Подпрограмма объявляется точно также как и переменная, поэтому любое обращение к подпрограмме должно осуществляться внутри области действия объявления подпрограммы. Кроме того, обращение к подпрограмме не может встречаться внутри самой подпрограммы, т.е. до оператора END объявления этой подпрограммы.

Объявление подпрограммы состоит из 3-х частей: зарезервированного слова PROCEDURE, последовательности операторов, составляющих тело подпрограммы, и зарезервированного слова END:

<имя>:procedure [(<список параметров>)] [<адресное пространство>] [<атрибуты>];
  <operator-1>;
  <operator-2>;
   ...
  <operator-N>;
end [<имя>];

Например:

ProverkaDveri: Procedure;
   if VneshnDverZaperta and VnutrDverZaperta then
     Call VkluchitPitanie;
   else
     Call Trevoga;
end ProverkaDveri;

где VkluchitPitanie и Trevoga это подпрограммы а VneshnDverZaperta и VnutrDverZaperta глобальные битовые переменные, объявленные раньше описываемой подпрограммы.

Имя подпрограммы в операторе PROCEDURE выглядит точно также, как и определение метки, однако имя подпрограммы не является меткой. Область действия подпрограммы определяется местоположением ее объявления в тексте программы точно так же, как область действия переменной определяется местоположением оператора DECLARE. Объявление подпрограммы может содержать в себе операторы объявления локальных переменных DECLARE, и эти операторы должны предшествовать первому выполняемому оператору в теле подпрограммы.

Как и в блоке DO, идентификатор, следующий за словом END, не оказывает никакого действия на программу, а только повышает наглядность программы и облегчает ее отладку. Если оператор END содержит идентификатор, то он обязательно должен быть тем же самым, что и идентификатор имени подпрограммы.

Параметры подпрограмм.

Формальные параметры подпрограммы должны быть небазированными переменными, объявленными внутри подпрограммы. Их идентификаторы задаются в списке параметров в операторе PROCEDURE. Идентификаторы в списке разделяются запятыми, а сам список заключается в скобки. В списке параметров не допускаются применение массивов и структур. Если в подпрограмме нет формальных параметров, то список формальных параметров (включая скобки) в операторе PROCEDURE опускается. Каждый формальный параметр обязательно должен быть объявлен в теле подпрограммы оператором DECLARE, предшествующем первому исполняемому оператору.

При вызове подпрограммы с формальными параметрами в операторе CALL или обращении к функции должны содержаться фактические параметры. Каждый фактический параметр является выражением, значение которого присваивается соответствующему формальному параметру подпрограммы до того, как подпрограмма начнет выполняться. Например, следующая подпрограмма-процедура имеет 4 параметра, называемые Ukazat, N, Min, Max.

ProvDiapaz: Procedure(Ukazat, N, Min, Max);
  Declare Ukazat word;
  Declare (N, Min, Max, Perem Based Ukazat(1), I) byte;

  do I = 1 to N;
    if (Perem(I) < Min) or (Perem(I) > Max) then
      Call UstOshib; /*UstOshib это заранее объявленная подпрограмма */
  end;
end ProvDiapaz;
  ...
Call ProvDiapaz(.Value, 20, low, up);

Эта подпрограмма просматривает N байтовых переменных. Через параметр Ukazat передается адрес первой из этих переменных. Если какая-нибудь из этих переменных меньше параметра Min или больше параметра Max, то вызывается объявленная ранее в этой же программе процедура UstOshib.

Переменные I и Perem не являются параметрами подпрограммы. Это обычные локальные переменные.

Отметим, что массив Perem объявлен с размерностью в один элемент. Так как это базированный массив, то важен только адрес переменной, задаваемый переменной Ukazat. Индекс в массиве может быть любым. При объявлении переменной можно указать в качестве размерности массива любое число большее 0. Размерность указывается для того, чтобы переменная Perem воспринималась как массив.

Вызов подпрограммы в конце примера передаёт приказ проверить находятся ли элементы массива Value(20) в диапазоне чисел от low до up. Адрес массива передан оператором .Value количество элементов массива числом 20. Использование базированной переменной, адрес которой передается в качестве параметра, позволяет процедуре иметь свой собственный неизменяемый идентификатор (Perem) для разных переменных, передаваемых при вызове процедуры.

Подпрограммы обработки прерываний.

Атрибут INTERRUPT позволяет объявить подпрограмму-процедуру обработки сигналов прерываний, поступающих от внешних устройств. Подпрограмма процедура с этим атрибутом вызывается при получении микроконтроллером соответствующего сигнала прерывания. Подпрограмма обработки прерываний не может быть подпрограммой функцией и не может иметь переменные-параметры. Формат атрибута:

Interrupt N;

где N-любое десятичное число от 0 до 255.

Число N определяет номер обрабатываемого прерывания. При этом номер 0 соответствует внешнему прерыванию от ножки INT0, номер 1 соответствует прерыванию от таймера 0, номер 2 соответствует внешнему прерыванию от ножки INT1 и так далее. Пример подпрограммы-обработчика прерывания от таймера 0 приведён на рисунке 1.

IntTim0: procedure interrupt 2;
  TH0=25;
  TL0=32;
  TF=0;
end;

Подпрограммы-функции.

Пример подпрограммы из предыдущего параграфа - это подпрограмма процедура. Для нее в операторе PROCEDURE не задается тип, и такая процедура не возвращает никакого значения. Подпрограмма-процедура вызывается по ее имени оператором CALL. Тем не менее иногда удобно присваивать вычисленное значение сразу переменной. Примером является вычисление математических функций таких как синус или косинус. Запись математической операции была бы удобнее в следующем виде:

Y=sin(x);

Именно такую форму записи позволяет использовать подпрограмма-функция. В языке программирования PLM-51 подпрограмма-функция может иметь тип: bit, byte или word который указывается в операторе Procedure. Такая подпрограмма возвращает значение объявленного типа, которое может быть использовано в выражении или присвоено переменной.

Когда на этапе выполнения программы происходит обработка выражения, то запись имени функции осуществляет вызов подпрограммы-функции. Само имя функции заменяется значением, возвращаемым этой подпрограммой. Затем вычисляется оставшаяся часть выражения, и выполнение программы продолжается в нормальной последовательности.

Подобно подпрограмме-процедуре, подпрограмма-функция может иметь параметры. Тело подпрограммы-функции должно обязательно содержать оператор RETURN. Заметим, что подпрограмма-функция подобно подпрограмме-процедуре может изменять содержимое глобальных переменных.

Рассмотрим пример использования подпрограммы- функции для обнаружения нажатия на кнопку. Если к портам P0 и P1 подключена клавиатура, то при нажатии на кнопку на входах P0 на одном из выводов порта появится логический 0. Подпрограмма может обнаружить это состояние и в основной программе оператор обнаружения нажатия на кнопку будет совпадать с записью алгоритма.

SostKnIzm: Procedure bit;
  Declare tmp bit;

  bit=0;
  if  (P0 <> 0ffh)  then
      bit=1;
   return bit
end SostKnIzm;

/* Основная программа */
  ...
  if  SostKnIzm then Call DecodSostKn;


Язык программирования PLM-51.

Структура программ PLM-51.

PL/M-51 является блочно-структурированным языком, каждый оператор в программе является, частью, по крайней мере, одного блока.

Каждая программа на PL/M-51 состоит из одного или более модулей, записанных в отдельных файлах и компилируемых отдельно. Каждый модуль может состоять из одного или более блоков. В языке программирования PL/M-51 имеется два типа блоков: блоки DO и блоки подпрограмм.

Модуль должен начинаться оператором DO с меткой перед ним, и заканчиваться оператором END. Между этими двумя операторами помещаются операторы, составляющие программу. Эти операторы объявляют переменные и выполняют необходимые действия. Модуль может содержать несколько блоков.

Блок - это соответствующим образом записанная группа операторов, начинающихся оператором DO и заканчивающаяся оператором END.

Подпрограмма начинается с объявления подпрограммы и заканчивается оператором END. Переменные, объявленные в подпрограмме и исполняемые операторы, находящиеся между операторами начала и конца подпрограммы, используются только при вызове подпрограммы.

Любая программа, написанная на языке программирования PLM-51, начинается с оператора do, при этом имя программы записывается перед этим оператором и оформляется как метка. Перед первым исполняемым оператором программы обязательно должны быть объявлены все переменные и константы, которые будут использоваться в программе. Программа, написанная на языке программирования PLM-51, заканчивается оператором end. Пример программы, написанной на языке программирования PLM-51 приведён ниже:

Primer:do;
  declare a byte;

  a=2+2;
end;

Эта программа выполняет простейшие действия и содержит только один исполняемый оператор. Так как микроконтроллер не содержит встроенных средств отображения информации, то в языке программирования нет встроенных средств отображения полученного результата. Результат приведённой в примере программы можно посмотреть только во внутренней памяти микроконтроллера. То есть проверить работоспособность этой программы можно только на отладчике.

Для того, чтобы получить более полное представление о структуре программ, написанных на языке программирования PLM-51, приведём пример программы с использованием подпрограмм.

PrimerSIN:do;
/*---------- Объявление переменных -------------------------*/
declare tabsin(180) byte const (0,                 /*sin(0)*/
                                0.01745*32767,     /*sin(1)*/
                                0.03490*32767);    /*sin(2)*/
declare a byte at(80h) register,/*переменная значения синуса*/
        i byte;/*переменная аргумента в градусах*/

/*---------- Объявление подпрограмм -----------------------*/
sin:procedure(x) byte;
declare x byte;
  return(tabsin(x));
end sin;

/*--------- Начало основной программы ----------------------*/
  do i=0 to 180;
    a=sin(i);  /*вычислить очередное значение синуса*/
  end;
end;

В этом примере используется подпрограмма вычисления синуса с использованием табличного способа. Как видно из исходного текста программы все объявления были сделаны до первого исполняемого оператора. Переменная a в этом примере совпадает с адресом порта P0, поэтому синус можно наблюдать на выходе этого порта.


Объявление переменных в PL/M-51

Объявление переменных в языке программирования PLM-51.

В языке программирования PLM-51 могут быть объявлены пять типов объектов: переменные, константы, литералы, метки и подпрограммы. В одном блоке для каждого имени допустимо только одно объявление. Переменные, константы, литералы и подпрограммы должны быть объявлены раньше, чем они будут использованы в исполняемом операторе.

Метка может быть объявлена двумя способами:

  1. если она стоит перед выполняемым оператором и заканчивается с двоеточием (:)
  2. определена в операторе DECLARE.

Подпрограмма объявляется оператором PROCEDURE и определяется между операторами PROCEDURE и END.

Переменные, константы и литералы объявляются оператором DECLARE. При этом они могут объявляться как в разных операторах DECLARE, так и в одном. Если оператор DECLARE содержит более чем одно объявление, то они разделяются запятыми. При объявлении переменной обязательно указывается тип объявляемой переменной. Пример использования оператора DECLARE:

  declare Chr byte;
  declare Count word;
  declare Chr byte, Count word;

Переменная может быть скаляром, массивом или структурой.

Cкаляр является объектом, значение которого не известно на этапе трансляции, и может изменяться в процессе выполнения программы. К нему обращаются при помощи идентификатора переменной.

Скаляр обязательно имеет тип. В языке программирования PLM-51 это может быть восьмибитовая беззнаковая переменная - byte, шестнадцатибитовая беззнаковая переменная - word или однобитовая переменная - bit.

Массив - это набор скаляров одинакового типа, имеющих один идентификатор, и различающихся индексами.

Например:

А(0), A(1), A(2), A(3), и т.д.

Структура позволяет объединять под одним именем переменные разного типа. Ее элементы различаются друг от друга идентификаторами поля. Например, индикатор Employees.Name обращается к полю Name внутри структуры Employees. Массивы и структуры могут быть как переменной, так и константой.

Так как микроконтроллеры семейства MCS-51 имеют несколько адресных пространств, то транслятору необходимо указывать, в какой из областей памяти необходимо размещать переменные. Это осуществляется при помощи уточняющих слов, следующих за определением типа переменной.

  1. MAIN - переменная размещается во внутренней памяти данных с прямой адресацией
  2. IDATA - переменная размещается во внутренней памяти данных с косвенной адресацией
  3. REGISTER - переменная размещается в области регистров специальных функций
  4. AUXILIARY - переменная размещается во внешней памяти данных
  5. CONSTANT - константа размещается в памяти программ

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

declare SBUF byte at (99h) register; /*рег. данных последовательного порта */

В этом примере была объявлена переменная, совпадающая с регистром данных последовательного порта. Поэтому при записи байта в эту переменную, записанное число будет передано через последовательный порт.

Суффикс CONSTANT описывает переменные в адресном пространстве памяти программ, где должно находиться ПЗУ. Содержимое такой переменной в отличие от других не изменяется в процессе выполнения всей программы. Идентификатор такой переменной никогда не должен находиться в левой части оператора присваивания. Инициализация данных производится добавлением значения константы к ключевому слову CONSTANT. Следующий оператор:

declare Porog byte constant (48);

объявляет байт Porog в памяти программ и присваивает ему значение 48. Оператор:

declare (Counter, Limit, Incr) word constant (1024, 0, -2)

объявляет скаляры Counter (счетчик англ), Limit (граница англ) и Incr (увеличение англ) типа WORD, указывает, что они находятся в ПЗУ, и устанавливает значение константы Counter равным 1024, значение константы Limit - 0, значение константы Incr равным (-2).

Достаточно мощное средство программирования предоставляет макроподстановка LITERALLY. Строка, следующая за ключевым словом LITERALLY подставляется на этапе трансляции.

Следующий пример иллюстрирует использование ключевого слова LITERALLY:

declare True literally '1',  False literally '0';
declare Rough bit;
declare (x, y, Delta, Final) word;
...
rough = True;
do while Rough;
  x = smooth (x, y, Delta);/* smooth это подпрограмма, объявленная  в другом месте .*/
  if (x - Final) < Delta then Rough = False;
end;
...

В этом примере при помощи ключевого слова LITERALLY определяются булевы значения True и False для работы с операциями отношения. Это делает программу более удобной для чтения.

Ещё один вариант использования ключевого слова LITERALLY это объявление констант, неизменных во время одной компиляции, но которые могут принимать другое значение при последующих компиляциях исходного текста программы.

Рассмотрим следующий пример:

declare Buffer$Size literally '32'
declare Print$Buffer (Buffer$Size) word;
...
print$buffer (buffer$size - 10) = 'g';

Последующие изменения Buffer$Size могут быть сделаны в одном месте в первом операторе declare. Компилятор распространит изменение по всей программе во время компиляции. Таким образом, программист сократит утомительный и приводящий к ошибкам процесс поиска в программе тех мест, где строка '32' используется как размер буфера, и внесение нового значения размера буфера.

Язык программирования PLM очень похож на широко распространённый язык программирования PASCAL, так как оба этих языка произошли от общего родоначальника - языка программирования ALGOL-68. При помощи макроподстановок LITERALLY эти языки программирования можно сделать ещё более похожими. Это очень полезное свойство для людей, привыкших программировать на PASCAL.


Разработка принципиальной схемы микропроцессорного устройства

 Rambler's Top100 Дата последнего обновления файла 02.06.2005

Разработка принципиальной схемы.

Разработка принципиальной схемы начинается с анализа структурной схемы. Структурная схема приведена на рисунке 1.

Рисунок 1. Структурная схема часов.

Анализируя структурную схему часов, можно выделить часть схемы, которая может быть выполнена с применением микроконтроллера. Это, несомненно, делители частоты, счётчик временных интервалов, схема установки внутреннего состояния счётчика временных интервалов и дешифратор. Для реализации полной схемы часов микроконтроллер придётся дополнить кварцевым резонатором, кнопками и светодиодными индикаторами.

Из блока индикации только дешифратор можно реализовать программно. Светодиодные индикаторы естественно должны быть подключены к выводам микроконтроллера.

Так как у микроконтроллера есть четыре восьмиразрядных параллельных порта, то к ним можно подключить четыре семисегментных светодиодных индикатора. Четырёх индикаторов достаточно для отображения информации о текущем времени. Это десятки и единицы минут и десятки и единицы секунд.

После подключения этих индикаторов остаются свободными четыре одиночных вывода параллельных портов. Эти выводы можно использовать для подключения трёх кнопок блока коррекции. Трёх кнопок будет вполне достаточно. Это кнопки коррекции часов, минут и установки счётчика секунд в нулевое состояние.

Особенность разработки микропроцессорных устройств заключается в том, что большая часть схемы является стандартизованной. Как и любая микросхема, микроконтроллер требует подключения питания. Однако в состав микроконтроллера входит генератор, поэтому микроконтроллер является источником помех. Для подавления помех по цепям питания обязательно нужно поставить конденсатор. В качестве индуктивности этого фильтра обычно используется паразитная индуктивность проводника, по которому подводится питание. Конденсатор нужно использовать высокочастотный и располагать его как можно ближе к выводам микросхемы.

Следующей важной частью схемы включения микроконтроллера является задающий генератор. Обычно в справочных данных на микросхему приводится типовая схема включения генератора. Однако при отладке схемы могут возникнуть трудности запуска генератора. Например, генератор может не запускаться при пониженных температурах. В этом случае типовая схема может быть изменена в соответствии с общими принципами разработки генераторов.

Для правильной работы микроконтроллера при включении питания необходимо осуществить сброс микросхемы. В типовых схемах подключения микроконтроллеров обычно в качестве схемы сброса при включении питания используется конденсатор номиналом 1 мкф. Однако при плавном нарастании напряжения питания напряжения на выходе конденсатора может оказаться недостаточно для надёжного сброса микроконтроллера.

Для надёжного запуска часов при включении питания дополним схему специальной микросхемой супервизора питания, которая обеспечит сброс микроконтроллера при уменьшении напряжения питания ниже допустимого уровня.

Рисунок 2. Принципиальная схема подключения микроконтроллера.

Получившаяся принципиальная схема часов приведена на рисунке 3.

Рисунок 3. Принципиальная схема часов.


Написание программы для микропроцессорного устройства

 Rambler's Top100 Дата последнего обновления файла 02.06.2005

Написание программы для разрабатываемого микропроцессорного устройства

Теперь необходимо разделить аппаратную и программную часть схемы часов. В состав генератора эталонных интервалов времени входит делитель частоты, часть которого можно реализовать аппаратно при помощи делителя, входящего в состав одного из таймеров микроконтроллера.

Максимальный коэффициент деления на таймере можно получить 65536. Попробуем необходимый коэффициент деления генератора эталонных интервалов времени равный 12000000 разделить на несколько сомножителей. Прежде всего, выделим сомножитель, равный 12. Это внутренний делитель таймера, который всегда присутствует в составе микросхемы и не может быть нами отключен. То есть нам остаётся реализовать делитель на 1000000.

Выберем коэффициент деления таймера равным 50000. Это число меньше максимально возможного числа, допустимого для шестнадцатиразрядного таймера. В результате деления числа 1000000 на число 50000 остаётся число 20. Этот коэффициент деления можно реализовать программно на одной ячейке внутренней памяти данных.

Как уже обсуждалось ранее, алгоритм и программу можно писать одновременно. Начнём написание программы с организации простейшей программы-монитора. Этот первоначальный вариант программы приведен на рисунке 9.18.

Как видно из приведённого исходного текста программы эта программа пока ничего не делает. Однако в этой программе предусмотрен бесконечный цикл, который не позволит программе когда-либо завершиться до выключения питания устройства. По циклу при подключенном к микроконтроллеру кварцевом резонаторе 12МГц программа будет проходить один раз за 2 мкс.

;-------------СБРОС МИКРОКОНТРОЛЛЕРА---------------------------
  ORG 0
  Jmp init  ;Переход на начало выполнения программы

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------
init:
;-------------ОСНОВНАЯ ПРОГРАММА МИКРОКОНТРОЛЛЕРА--------------
Begin:
  Jmp begin  ;Переход на начало выполнения программы
  end

Рисунок 9.18. Исходный текст первоначального варианта программы.

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

Программа в основном режиме может ожидать переполнения таймера, опрашивая флаг TF0, но при использовании прерываний от таймера можно значительно снизить потребление микроконтроллера. Экономия реализуется при переведении микроконтроллера в спящий режим командой orl PCON,#1. После выполнения этой команды микроконтроллер может проснуться только после сброса микроконтроллера или возникновения прерывания.

Для реализации прохождения микроконтроллером по основному циклу один раз в 50мс разместим команду orl PCON,#1 в конце цикла. В качестве источника прерываний будет служить таймер T0. Переход на начало цикла будет осуществляться сразу после возврата из подпрограммы обслуживания прерывания.

Так как прерывания нам потребуются каждые 50 мс, то разрешение прерываний от таймера разместим тоже в подпрограмме инициализации таймера. Разрешение прерываний от таймера производится записью единиц в биты регистра специального назначения IE. Разрешение прерываний от таймера производится битом ET0, а общее разрешение всех прерываний битом EA. Установим эти биты в единичное состояние командой orl IE,#10000010b.

Теперь микроконтроллер каждые 50 мс будет не только просыпаться, но и передавать управление на вектор прерывания таймера T0. Этот вектор находится по адресу 0Bh. Подпрограмму повторной записи числа 50мс в таймер нужно поместить точно на этот адрес. Размещение подпрограммы на векторе прерывания можно произвести директивой ORG 0Bh. Так как пока нет прерываний от других источников, то подпрограмму обслуживания прерывания не будем выносить в конец программы.

;-------------СБРОС МИКРОКОНТРОЛЛЕРА---------------------------------
  ORG

  jmp init  ;Переход на начало выполнения программы

;-------------ВЕКТОР ПРЕРЫВАНИЯ ТАЙМЕРА T0---------------------------
 ORG 0Bh
  mov TH0, #HIGH(-50000) ;Загрузить старший байт таймера
  mov TL0, #LOW(-50000)  ;Загрузить младший байт таймера
  reti

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс

;-------------ОСНОВНАЯ ПРОГРАММА МИКРОКОНТРОЛЛЕРА--------------------
Begin:
  orl PCON,#1;Перевести микроконтроллер в пониженный режим
             ;потребления тока и подождать переполнения таймера
  jmp begin  ;Переход на начало выполнения программы
;-------------КОНЕЦ ОСНОВНОЙ ПРОГРАММЫ МИКРОКОНТРОЛЛЕРА--------------

;********************************************************************
;Подпрограмма настройки таймера T0 на 50мс режим работы
;********************************************************************
Timer0_Init:
    mov TMOD,#00000001b    ;перевести таймер T0 в первый режим
             ;||||||||      работы, а T1 - в нулевой режим
             ;||||||++------Перевести таймер T0 в
             ;||||||        шестнадцатиразрядный режим работы
             ;|||||+--------Синхронизироваться от внутреннего
             ;|||||         генератора
             ;||||+---------Запретить управление таймером от
             ;||||          ножки INT0
             ;||++----------Перевести таймер T1 в
             ;||            тринадцатиразрядный режим
             ;|+------------Синхронизироваться от внутреннего
             ;|+------------генератора
             ;+-------------Запретить управление таймером
             ;              от ножки INT1

;Настройка таймера на генерацию 50-ти миллисекундного интервала
;времени
  mov TH0, #HIGH(-50000) ;Загрузить старший байт таймера
  mov TL0, #LOW(-50000)  ;Загрузить младший байт таймера

  orl IE,#10000010b      ;Разрешить прерывания от таймера
  SetB TR0               ;включить таймер
  ret                    ;и вернуться в основную программу

  end

Рисунок 9.19. Исходный текст программы с 50мс циклом.

Исходный текст варианта программы c 50 мс циклом приведен на рисунке 9.19. Этот вариант программы можно тщательно проверить на работоспособность на программном эмуляторе или непосредственно на собранном устройстве. При измерении тока микроконтроллера будут отчётливо видны импульсы повышенного тока с периодом 50мс.

Программа, приведенная на рисунке 9.19, реализует генератор эталонных интервалов времени с периодом 50мс. Нам же требуется генератор с периодом 1с. То есть, нужен ещё один делитель с коэффициентом деления 20. Его можно реализовать на одиночной ячейке внутренней памяти микроконтроллера.

;-------------ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ----------------------------------
Delit    equ 8  ;Номер ячейки памяти делителя
NachStek equ 8  ;Номер начальной ячейки памяти стека

;-------------СБРОС МИКРОКОНТРОЛЛЕРА---------------------------------
 ORG 0
  jmp init  ;Переход на начало выполнения программы

;-------------ВЕКТОР ПРЕРЫВАНИЯ ТАЙМЕРА T0---------------------------
 ORG 0Bh
  mov TH0, #HIGH(-50000) ;Загрузить старший байт таймера
  mov TL0, #LOW(-50000)  ;Загрузить младший байт таймера
  reti

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  mov SP,#NachStek ;Изменить размер стека
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс
  mov Delit,#20    ;Настроить делитель на коэффициент деления 20

;-------------ОСНОВНАЯ ПРОГРАММА МИКРОКОНТРОЛЛЕРА--------------------
Begin:
  DJNZ Delit,Sleep ;Если прошла одна секунда, то
    mov Delit,#20    ;настроить делитель на коэффициент деления 20
    call Clock       ;и вызвать подпрограмму реализации часов.

Sleep:
  orl PCON,#1;Перевести микроконтроллер в пониженный режим
             ;потребления тока и подождать переполнения таймера
  jmp begin  ;Переход на начало выполнения программы
;-------------КОНЕЦ ОСНОВНОЙ ПРОГРАММЫ МИКРОКОНТРОЛЛЕРА--------------

;********************************************************************
;Подпрограмма реализации часов
;********************************************************************
Clock:
  ret

Рисунок 9.20. Исходный текст программы с 1 сек циклом.

Для выделения переменной воспользуемся директивой equ. Выделим для делителя ячейку с адресом 8. Это ячейка находится непосредственно после нулевого банка регистров. Кроме того, теперь потребуется изменить первоначальное значение указателя стека, равное 8, иначе при первом же вызове подпрограммы содержимое делителя будет уничтожено. Новый вариант программы приведен на рисунке 9.20.

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

Учитывая, что программа изменится незначительно, приведем исходный текст только изменённых участков программы. Эти участки программы приведены на рисунке 9.20. В первой части объявляется переменная SEC будет осуществляться счёт секунд. Во второй части этой переменной присваивается первоначальное значение, а переключение счётчика производится непосредственно в подпрограмме Clock

;-------------ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ----------------------------------
Delit    equ 8  ;Номер ячейки памяти делителя
SEC      equ 9  ;Номер ячейки памяти счётчика секунд
NachStek equ 9  ;Номер начальной ячейки памяти стека

  ...

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  mov SP,#NachStek ;Изменить размер стека
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс
  mov Delit,#20    ;Настроить делитель на коэффициент деления 20
  mov SEC,#60      ;Настроить счётчик секунд на коэффициент деления 60

  ...

;********************************************************************
;Подпрограмма реализации часов
;********************************************************************
Clock:
  DJNZ SEC,ExitClock;Если прошла одна минута, то
    mov SEC,#60       ;настроить счётчик секунд на коэффициент деления 60
ExitClock:
  ret

Рисунок 9.21. Исходный текст участков программы, отвечающих за организацию счётчика секунд.

И предделитель и счётчик секунд представляют собой двоичные вычитающие счетчики, реализованные при помощи команды DJNZ. Счётчик минут необходимо будет в дальнейшем отображать на светодиодных индикаторах, поэтому этот счётчик желательно реализовать как двоично-десятичный счётчик.

Готовой команды, способной реализовать суммирующий двоично-десятичный счётчик на любой ячейке памяти, в системе команд микроконтроллера нет. Поэтому придётся реализовывать двоично-десятичный счётчик на аккумуляторе. Исходный текст подпрограммы, реализующей счётчик минут, приведен на рисунке 9.22.

;-------------ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ----------------------------------
Delit    equ 8  ;Номер ячейки памяти делителя
SEC      equ 9  ;Номер ячейки памяти счётчика секунд
MIN      equ 10 ;Номер ячейки памяти счётчика минут
NachStek equ 10 ;Номер начальной ячейки памяти стека

  ...

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  mov SP,#NachStek ;Изменить размер стека
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс
  mov Delit,#20    ;Настроить делитель на коэффициент деления 20
  mov SEC,#60      ;Настроить счётчик секунд на коэффициент деления 60
  mov MIN,#0       ;Обнулить счётчик минут

  ...

;********************************************************************
;Подпрограмма реализации часов
;********************************************************************
Clock:
  DJNZ SEC,ExitClock;Если прошла одна минута, то
    mov SEC,#60       ;настроить счётчик секунд на коэффициент деления 60

    mov A,MIN             ;
    add A,#1              ;Переключить счётчик минут
    DA A                  ;
    mov MIN,A             ;

    CJNE A,#60h,ExitClock ;Если прошло 60 минут,
      mov MIN,#0            ;то обнулить счётчик минут
ExitClock:
  ret

Рисунок 9.22. Исходный текст участков программы, отвечающих за организацию счётчика минут.

В приведённом исходном тексте подпрограммы для увеличения показания минут использована команда суммирования ADD, так как команда INC не устанавливает флаги переносов, а соответственно не может быть выполнена команда десятичной коррекции результата.

Команды ADD и INC могут быть выполнены только над аккумулятором, поэтому в аккумулятор сначала копируется содержимое переменной счётчика минут, а затем, после выполнения операции двоично-десятичного суммирования, снова сохраняется в переменной счётчика минут. Исходный текст программы с подпрограммой реализации часов приведен на рисунке 9.23.

;-------------ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ----------------------------------
Delit    equ 8  ;Номер ячейки памяти делителя
SEC      equ 9  ;Номер ячейки памяти счётчика секунд
MIN      equ 10 ;Номер ячейки памяти счётчика минут
Chas     equ 11 ;Номер ячейки памяти счётчика минут
NachStek equ 11 ;Номер начальной ячейки памяти стека

  ...

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  mov SP,#NachStek ;Изменить размер стека
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс
  mov Delit,#20    ;Настроить делитель на коэффициент деления 20
  mov SEC,#60      ;Настроить счётчик секунд на коэффициент деления 60
  mov MIN,#0       ;Обнулить счётчик минут
  mov Chas,#0      ;Обнулить счётчик часов

  ...

;********************************************************************
;Подпрограмма реализации часов
;********************************************************************
Clock:
  DJNZ SEC,ExitClock;Если прошла одна минута, то
    mov SEC,#60       ;настроить счётчик секунд на коэффициент деления 60
    Call IncMin
    JC ExitClock
      Call IncChas
ExitClock:
  ret

;********************************************************************
;Подпрограмма увеличения содержимого счётчика минут
;********************************************************************
IncMin:
  mov A,MIN               ;
  add A,#1                ;Переключить счётчик минут
  DA A                    ;
  mov MIN,A               ;

  CJNE A,#60h,ExitIncMin  ;Если прошло 60 минут,
    mov MIN,#0              ;то обнулить счётчик минут
ExitIncMin:
  ret

;********************************************************************
;Подпрограмма увеличения содержимого счётчика часов
;********************************************************************
IncChas:
    mov A,Chas           ;
    add A,#1             ;Переключить счётчик часов
    DA A                 ;
    mov Chas,A           ;

    CJNE A,#24h,ExitIncHr;Если прошло 24 часа,
      mov Chas,#0          ;то обнулить счётчик часов
ExitIncHr:
  ret

Рисунок 9.23. Исходный текст участков программы, отвечающих за реализацию электронных часов.

Для того чтобы полностью воспользоваться преимуществами структурного программирования, операторы, выполняющие увеличение показаний счётчика минут, оформлены в виде подпрограммы. В результате подпрограмма реализации часов выглядит полностью как алгоритм. Для переключения счётчика часов используется команда проверки флага переноса C. Этот флаг устанавливается командой CJNE.

Счётчик часов реализуется точно таким же образом. Единственное отличие заключается в том, что в сутках двадцать четыре часа, поэтому счётчик часов будет обнуляться после достижения этого значения. Исходный текст подпрограмм увеличения содержимого счётчиков минут и часов тоже приведён на рисунке 9.23.

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

Учитывая, что изменение показаний часов при установке времени может происходить несколько раз в секунду, то выберем точку подключения блока индикации 50 мс, то есть подпрограмму индикации необходимо разместить внутри основного цикла программы.

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

В этом исходном тексте не отображены подпрограммы инициализации таймера и реализации часов. Естественно, что эти программы никуда не делись, они не показаны для уменьшения размера рисунка.

Теперь можно заняться подпрограммой блока индикации. На принципиальной схеме часов не указано, что и на каком индикаторе должно отображаться. Зададимся, что на индикаторе, подключенном к порту P0, будут отображаться единицы минут. На индикаторе, подключенном к порту P1, будут отображаться десятки минут. На индикаторе, подключенном к порту P2, будут отображаться десятки минут. На индикаторе, подключенном к порту P3, будут отображаться десятки минут.

Какой индикатор что отображает, определяется конструкцией часов. При необходимости изменить порядок индикаторов можно просто заменить в программе имена параллельных портов, к которым подключены индикаторы, и перетранслировать программу.

Для декодирования двоично-десятичного кода предусмотрим подпрограмму-функцию decod. Пусть декодируемая тетрада будет передаваться в подпрограмму через аккумулятор. Полученный семисегментный код тоже удобно вернуть из подпрограммы через аккумулятор. Исходный текст получившейся подпрограммы индикации приведен на рисунке 9.25.

Delit    equ 8  ;Номер ячейки памяти делителя
SEC      equ 9  ;Номер ячейки памяти счётчика секунд
MIN      equ 10 ;Номер ячейки памяти счётчика минут
Chas     equ 11 ;Номер ячейки памяти счётчика минут
NachStek equ 11 ;Номер начальной ячейки памяти стека

;-------------СБРОС МИКРОКОНТРОЛЛЕРА---------------------------------
 ORG 0
  jmp init  ;Переход на начало выполнения программы

;-------------ВЕКТОР ПРЕРЫВАНИЯ ТАЙМЕРА T0---------------------------
 ORG 0Bh
  mov TH0, #HIGH(-50000) ;Загрузить старший байт таймера
  mov TL0, #LOW(-50000)  ;Загрузить младший байт таймера
  reti

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  mov SP,#NachStek ;Изменить размер стека
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс
  mov Delit,#20    ;Настроить делитель на коэффициент деления 20
  mov SEC,#60      ;Настроить счётчик секунд на коэффициент деления 60
  mov MIN,#0       ;Обнулить счётчик минут
  mov Chas,#0      ;Обнулить счётчик часов
;-------------ОСНОВНАЯ ПРОГРАММА МИКРОКОНТРОЛЛЕРА--------------------
Begin:
  call Indic       ;Произвести индикацию состояния часов на светодиодных
                   ;индикаторах
  DJNZ Delit,Sleep ;Если прошла одна секунда, то
    mov Delit,#20    ;настроить делитель на коэффициент деления 20
    call Clock       ;и вызвать подпрограмму счётчика секунд.
Sleep:
  orl PCON,#1;Перевести микроконтроллер в пониженный режим
             ;потребления тока и подождать переполнения таймера
  jmp begin  ;Переход на начало выполнения программы
;-------------КОНЕЦ ОСНОВНОЙ ПРОГРАММЫ МИКРОКОНТРОЛЛЕРА--------------

;********************************************************************
;Подпрограмма блока индикации
;********************************************************************
Indic:
  ret

Рисунок 9.24. Исходный текст программы с вызовом подпрограммы блока индикации.

Выделение младшей тетрады осуществляется при помощи логического умножения на константу 0Fh. В этой константе старшие четыре бита равны нулю, поэтому при логическом перемножении операндов старшая тетрада результата обнуляется.

;********************************************************************
;Подпрограмма блока индикации
;********************************************************************
Indic:
  Mov A,MIN   ;Считать содержимое счётчика минут
  AnL A,#0Fh  ;Выделить младшую тетраду
  Call Decod  ;Преобразовать её в семисегментный код
  Mov  P1,A   ;и передать через порт P1 на индикатор

  Mov A,MIN   ;Считать содержимое счётчика минут
  SWAP A      ;Выделить
  AnL A,#0Fh  ;старшую тетраду
  Call Decod  ;Преобразовать её в семисегментный код
  Mov  P2,A   ;и передать через порт P2 на индикатор

  Mov A,Chas  ;Считать содержимое счётчика часов
  AnL A,#0Fh  ;Выделить младшую тетраду
  Call Decod  ;Преобразовать её в семисегментный код
  Mov  P0,A   ;и передать через порт P0 на индикатор

  Mov A,Chas  ;Считать содержимое счётчика часов
  SWAP A      ;Выделить
  AnL A,#0Fh  ;старшую тетраду
  Call Decod  ;Преобразовать её в семисегментный код
  Mov  P3,A   ;и передать через порт P3 на индикатор
ret

Рисунок 9.25. Исходный текст подпрограммы индикации.

Старшая тетрада счётчика выделяется аналогичным образом. Отличие заключается в том, что перед логическим умножением старшая и младшая тетрады меняются местами при помощи команды SWAP.

Собственно говоря, индикация осуществляется при копировании полученного из подпрограммы декодирования семисегментного кода двоично-десятичного числа в параллельный порт.

Рассмотрим подпрограмму преобразования двоично-десятичного кода в семисегментный. Исходный текст программы подпрограммы декодирования двоично-десятичного числа приведен на рисунке 9.26. Декодирование осуществляется за счёт таблицы перекодировки. Количество строк в таблице соответствует количеству комбинаций двоично-десятичного кода, то есть равно десяти. Нули и единицы в получаемом коде определяются свечением сегментов светодиодного индикатора.

Для того, чтобы определить при каком логическом уровне на выводе порта будет светиться светодиодный сегмент, необходимо воспользоваться принципиальной схемой. Для нашего устройства принципиальная схема приведена на рисунке 9.17. Для того чтобы в этой схеме засветился светодиодный сегмент, нужно пропустить через него ток. Для этого необходимо открыть транзистор. Транзистор открывается при протекании базового тока, а это произойдет, если на выводе порта будет присутствовать логическая единица.

Теперь необходимо поставить в соответствие выводы порта и название сегментов семисегментного индикатора. В приведенной схеме номер вывода порта соответствует сегменту индикатора. Для того чтобы не запутаться, в подпрограмме используется двоичная запись числа, а над каждым битом числа приводится имя сегмента, соответствующее этому биту.

;********************************************************************
;Подпрограмма семисегментного декодера
;********************************************************************
Decod:
  Mov DPTR,#TabSemiSeg ;Установить указатель на начало таблицы
  MovC A,@A+DPTR       ;Считать значение кода и
  ret                  ;вернуть через аккумулятор

TabSemiSeg:
;     abcdefg
  DB 11111110b ;символ '0'       a
  DB 10110000b ;символ '1'    -------
  DB 11101101b ;символ '2'   |       |
  DB 11111001b ;символ '3'  f|       | b
  DB 10110011b ;символ '4'   |   g   |
  DB 11011011b ;символ '5'    -------
  DB 11011111b ;символ '6'   |       |
  DB 11110000b ;символ '7'  e|       |c
  DB 11111111b ;символ '8'   |   d   |
  DB 11111011b ;символ '9'    -------

Рисунок 9.26. Исходный текст подпрограммы семисегментного декодера.

Теперь единственным блоком часов, который необходимо реализовать, остался блок коррекции показаний часов. В состав этого блока входят три кнопки. Обычно при нажатии или отпускании кнопки возникает переходный процесс, который называется дребезгом контактов. Начинающие разработчики аппаратуры применяют различные методы борьбы с этим явлением от применения специальных схемотехнических решений, до повторного опроса кнопок в течение некоторого времени.

Рассмотрим подробнее механизм возникновения явления дребезга контактов. Дребезг контактов возникает из-за упругости самих контактов. При нажатии на кнопку или при срабатывании какого-либо датчика контакт ударяется о другой контакт и снова отлетает от него. Процесс может повториться несколько раз. При этом количество замыканий и размыканий контактов случайно и зависит от упругости контактов и механической силы, воздействующей на эти контакты. Обычно этот процесс длится от одной до восьми миллисекунд.

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

Пример временной диаграммы сигнала на контактах кнопки приведен на рис. 9.27. На этой временной диаграмме четко просматривается зона дребезга контактов. Для иллюстрации эффекта подавления дребезга контактов за счет ввода информации в строго определенные моменты времени, на этой временной диаграмме выбран наихудший случай момента взятия отсчета. Этот момент совпадает с зоной дребезга контактов. При этом на выводе порта микроконтроллера может быть считан сигнал логического нуля или логической единицы. Но даже в этом случае дополнительного импульса не возникает! Дребезг контактов приводит только к неопределенности определения времени нажатия кнопки, который не превышает времени реакции системы.

Рисунок 9.27. Временные диаграммы напряжения на контактах кнопки и сигнала, введенного в микроконтроллер.

Новый вариант программы с включенной в цикл подпрограммой опроса кнопок блока коррекции времени приведен на рисунке 9.28. Для хранения состояния кнопок в этой программе пришлось ввести новую переменную. В программе мы не будем использовать битовое пространство. Это позволит увеличить глубину стека и не вводить ещё один сегмент данных.

Теперь можно заняться реализацией подпрограммы опроса кнопок. Её задача состоит в копировании логических уровней с выводов порта во внутреннюю переменную микроконтроллера SostKn. Так как это будет происходить быстро и с постоянной задержкой по времени, то время взятия отсчетов (а также время вывода на индикаторы) будет строго постоянным. Исходный текст подпрограммы опроса кнопок приведён на рисунке 9.29.

В этой подпрограмме кнопки, разнесённые по портам, сводятся в одну переменную. Копирование производится битовыми командами MOV через флаг переноса C.

;-------------ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ----------------------------------
Delit    equ 8  ;Номер ячейки памяти делителя
SEC      equ 9  ;Номер ячейки памяти счётчика секунд
MIN      equ 10 ;Номер ячейки памяти счётчика минут
Chas     equ 11 ;Номер ячейки памяти счётчика часов
SostKn   equ 12 ;Номер ячейки переменной состояния кнопок
NachStek equ 12 ;Номер начальной ячейки памяти стека

;-------------СБРОС МИКРОКОНТРОЛЛЕРА---------------------------------
 ORG 0
  jmp init  ;Переход на начало выполнения программы

;-------------ВЕКТОР ПРЕРЫВАНИЯ ТАЙМЕРА T0---------------------------
 ORG 0Bh
  mov TH0, #HIGH(-50000) ;Загрузить старший байт таймера
  mov TL0, #LOW(-50000)  ;Загрузить младший байт таймера
  reti

;-------------ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------
init:
  mov SP,#NachStek ;Изменить размер стека
  call Timer0_Init ;Настроить таймер T0 на прерывания с периодом 50мс
  mov Delit,#20    ;Настроить делитель на коэффициент деления 20
  mov SEC,#60      ;Настроить счётчик секунд на коэффициент деления 60
  mov MIN,#0       ;Обнулить счётчик минут
  mov Chas,#0      ;Обнулить счётчик часов

;-------------ОСНОВНАЯ ПРОГРАММА МИКРОКОНТРОЛЛЕРА--------------------
Begin:
  call OprosKnop   ;Опросить кнопки
  call Indic       ;Произвести индикацию состояния часов на светодиодных
                   ;индикаторах

  DJNZ Delit,Sleep ;Если прошла одна секунда, то
    mov Delit,#20    ;настроить делитель на коэффициент деления 20
    call Clock       ;и вызвать подпрограмму реализации часов.

Sleep:
  orl PCON,#1;Перевести микроконтроллер в пониженный режим
             ;потребления тока и подождать переполнения таймера
  jmp begin  ;Переход на начало выполнения программы
;-------------КОНЕЦ ОСНОВНОЙ ПРОГРАММЫ МИКРОКОНТРОЛЛЕРА--------------

;********************************************************************
;Подпрограмма опроса кнопок
;********************************************************************
OprosKnop:
  ret

Рисунок 9.28. Исходный текст программы с вызовом подпрограммы блока индикации.

;********************************************************************
;Подпрограмма опроса кнопок
;********************************************************************
OprosKnop:
  Mov A,SostKn   ;Считать переменную состояния кнопок

  Mov C,P1.7     ;Скопировать состояние кнопки "уст сек"
  Mov AСС.0,C    ;в нулевой бит аккумулятора

  Mov C,P2.7     ;Скопировать состояние кнопки "уст мин"
  Mov AСС.1,C    ;в первый бит аккумулятора

  Mov C,P3.7     ;Скопировать состояние кнопки "уст часов"
  Mov AСС.2,C    ;во второй бит аккумулятора

  Mov SostKn,A   ;Сохранить новое значение переменной состояния кнопок
  ret

Рисунок 9.29. Исходный текст подпрограммы опроса кнопок.

Исполнение команд, вводимых при помощи кнопок, можно осуществить в любом месте основного цикла программы. Это обеспечит время исполнения команды в пределах 50мс. Точно так же, как и в предыдущих случаях, выделим это действие в отдельную подпрограмму. Пусть эта подпрограмма называется CorrClock. Исходный текст этой подпрограммы приведен на рисунке 9.30.

Первое действие, которое мы выполним в этой подпрограмме – это обработаем команду, вводимую кнопкой установка секунд. По этой команде нужно просто обнулить счётчик секунд.

;********************************************************************
;Подпрограмма блока коррекции часов
;********************************************************************
CorrClock:
  Mov A,SostKn   ;Считать переменную состояния кнопок
  JB ACC.0,      ;Если нажата кнопка "уст сек",
    Mov SEC,#0     ;то обнулить переменную SEC
  ret

Рисунок 9.30. Исходный текст подпрограммы коррекции показания часов.

Обработка нажатия на кнопки "уст мин" и "уст часов" производится несколько иначе. Дело в том, что при нажатии на эти кнопки необходимо непрерывно увеличивать показания счётчика часов или минут. Пусть изменение показаний часов происходит пять раз в секунду. Эта скорость изменения показаний часов ещё может восприниматься человеком. Подпрограмма коррекции показания часов будет выглядеть так, как это приведено на рисунке 9.31.

Если такая скорость коррекции показаний часов пять раз в секунду покажется слишком высокой, то можно изменить соотношение коэффициентов деления таймера и делителя, например: 32*31250. Тогда можно будет выбрать скорость коррекции показания часов из набора вариантов два или четыре раза в секунду.

;********************************************************************
;Подпрограмма блока коррекции часов
;********************************************************************
CorrClock:
  Mov A,SostKn           ;Считать переменную состояния кнопок
  JB ACC.0,TstKnMin      ;Если нажата кнопка "уст сек",
    Mov SEC,#0             ;то обнулить переменную SEC
TstKnMin:
  Mov  A,Delit           ;Если в предделителе
  ANL  A,#3              ;число кратно 2,
  CJNE A,#2,ExitCorrClock;

    Mov A,SostKn           ;то считать переменную состояния кнопок.
    JB ACC.1,TstKnChs      ;Если нажата кнопка "уст мин",
      Call IncMin            ;то увеличить содержимое счётчика минут
TstKnChs:
    JB ACC.2, ExitCorrClock;Если нажата кнопка "уст мин",
      Call IncChas           ;то увеличить содержимое счётчика часов
ExitCorrClock:
  ret

Рисунок 9.31. Изменённый исходный текст подпрограммы коррекции показания часов.

В приведенном варианте программы проверяется два младших бита делителя. Для выделения двух младших бит используется логическое умножение содержимого переменной Delit с маской 00011b. Так как эти биты принимают значение 10b пять раз в секунду, то, соответствующее количество раз, будет вызываться подпрограмма увеличения значения содержимого счётчика минут (или часов).


Проектирование микропроцессорных устройств

 Rambler's Top100 Дата последнего обновления файла 02.06.2005

Проектирование цифровых устройств на микроконтроллерах.

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

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

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

Рассмотрим пример написания программы для микроконтроллера. Прежде всего, не нужно забывать, что программа не может существовать отдельно независимо от схемы устройства. Если при написании программы для универсального компьютера, такого как IBM PC можно не задумываться о схеме, так как она стандартная, то перед написанием программы для микроконтроллера необходимо разработать схему устройства, в состав которого будет входить микроконтроллер.

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

Как и разработка любого устройства, разработка микропроцессорного устройства начинается с разработки структурной схемы.

Разработка структурной схемы.

Часы обязательно должны содержать устройство измерения времени, которое в свою очередь всегда состоит из генератора эталонных интервалов времени и счётчика этих интервалов. Схема устройства измерения времени приведена на рисунке 1.

Рисунок 1. Структурная схема устройства измерения времени.

В простейшем случае генератор импульсов эталонной длительности должен вырабатывать минутные импульсы. В качестве генератора эталонных импульсов мог бы подойти кварцевый генератор, так как этот тип генераторов обладает высокой стабильностью колебаний. Но кварцевые генераторы вырабатывают колебания в диапазоне от 1 до 30 МГц. Это соответствует временным интервалам от 0.03 до 1 мкС. Тем не менее, если воспользоваться делителем частоты, можно получить импульсы с периодом 1 минута.

Выберем частоту работы кварцевого генератора. Мы предполагаем использовать микроконтроллер семейства MCS-51, поэтому выберем частоту кварцевого генератора обычную для этих микроконтроллеров - 12 МГц. Тогда для формирования секундных импульсов (частота 1 Гц) потребуется делитель частоты на 12000000. Для формирования минутных импульсов потребуется ещё один делитель частоты. Так как в минуте содержится 60 секунд, то нам потребуется делитель на 60.

Уточнённая структурная схема разрабатываемого микропроцессорного устройства приведена на рисунке 2.

Рисунок 2. Уточнённая структурная схема устройства измерения времени.

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

И, наконец, последнее замечание. Любые часы время от времени требуют коррекции своего значения с целью синхронизации своих показаний с всемирным временем. Это будет делать блок коррекции, который в свою очередь будет состоять из кнопок и схемы установки внутреннего состояния счётчика временных интервалов.

Структурная схема часов с учётом блока индикации и блока коррекции времени приведена на рисунке 3.

Рисунок 3. Структурная схема часов.


список литературы

 Rambler's Top100 Дата последнего обновления файла 22.08.2005

Перечень литературы

Основная литература

Авторы | Наименование | Год издания | Примечание
ИЗДАТЕЛЬСТВО СТАНДАРТОВ | ГОСТ 2.743-91 | 1993 | ОБОЗНАЧЕНИЯ УСЛОВНЫЕ ГРАФИЧЕСКИЕ В СХЕМАХ ЭЛЕМЕНТЫ ЦИФРОВОЙ ТЕХНИКИ
С.А. Майоров В.В. Кириллов А.А. Приблуда | Введение в микро ЭВМ | 1988 | Прекрасный учебник, позволяющий понять как работает микропроцессор.
В.Я. Нерода В.Э. Торбинский Е.Л. Шлыков | Однокристальные микроЭВМ MCS-51 Архитектура | 1995 | Замечательный справочник по микроконтроллерам семейства MCS-51
Сединин В.И. Микушин А.В. | Программирование микропроцессорных систем на языке PL/M-51. | 2003 | Подробное описание языка программирования PL/M-51.
Сединин В.И. Микушин А.В. | Программирование микропроцессорных систем на языке ASM-51 | 2003 | Подробное описание языка программирования ASM-51.

Дополнительная литература

а)Цифровая схемотехника

Авторы | Наименование | Год издания | Примечание
У. Титце К. Шенк | Полупроводниковая схемотехника | 1983 | Очень хорошее описание цифровой схемотехники
Е. Угрюмов | Цифровая схемотехника | 2001 | Хорошее описание современной цифровой схемотехники от логических элементов до программируемых логических микросхем.
М.И. Богданович | Цифровые интегральные микросхемы | 1996 |
В.Л. Шило | Популярные цифровые микросхемы | 1988 |

б)Учебники

Авторы | Наименование | Год издания | Примечание
М. Рафикумазан | Микропроцессоры и машинное проектирование микропроцессорных систем | 1988 | Прекрасный учебник по принципам работы микропроцессоров и разработки программ для них, но рассматриваемые микропроцессоры уже не производятся. Можно использовать как пример по проектированию.

в)Справочники

Авторы | Наименование | Год издания | Примечание
INTEL | EMBEDDED MICROCONTROLLERS and Processors | 1993 | Справочник по микроконтроллерам семейства MCS-51
В.В. Сташин А.В. Урусов О.Ф. Мологонцева | Проектирование цифровых устройств на однокристальных микроконтроллерах | 1990 | Справочник по микроконтроллерам семейств MCS-48, MCS-51 и примеры программирования
Боборыкин А.В. Липовецкий Г.П. и др. | Однокристальные микроЭВМ | 1994 | Справочник по микроконтроллерам семейства MCS-51
Карасев | Однокристальный микропроцессор семейства MCS-51 | 1995 | Справочник по микроконтроллерам семейства MCS-51
Под ред. И.В. Коршуна | Современные микроконтроллеры Архитектура, средства проектирования, примеры применения. | 1998 | Справочник по микроконтроллерам семейства MCS-51
Бродин В.Б. Калинин А.В. | Системы на микроконтроллерах и БИС программируемой логики. | 2001 | Справочник по микроконтроллерам семейства MCS-51 и программируемым логическим микросхемам
Сединин В.И. Микушин А.В. | Однокристальный микроконтроллер семейства MCS-51 фирмы INTEL 8xC51GB | 2001 | Справочник по одному из микроконтроллеров семейства MCS-51

г)Программирование для микроконтроллеров

Авторы | Наименование | Год издания | Примечание
Л.К. Гребенников А.А. Летник | Программирование микропроцессорных систем на языке ПЛ/М | 1986 | Подробное описание языка программирования PL/M-80 (практически совпадает с PL/M-51)
А.В. Фрунзе | Микроконтроллеры? Это же просто! | 2002 | Примеры программирования для микроконтроллеров семейства MCS-51.
INTEL | Embedded Applications | 1993/1994 | Примеры программирования внутренних узлов микроконтроллеров семейства MCS-51

Описание языка программирования С51

InterNet:

www.atmel.com Материалы сервера (англ.)
http://www.atmel.ru Материалы сервера (русск.)
http://gaw.ru Материалы сервера (русск.)
http://www.telesys.ru Телеконференция по микроконтроллерам

[ Главная ]


Цели и задачи изучения дисциплины ЦУ и МП

Rambler's Top100 Дата последнего обновления файла 10.10.04

Цифровые устройства и микропроцессоры

1. Цели и задачи изучения

1.1 Цель преподавания дисциплины состоит в

  • изучении современных методов построения аппаратуры с применением микропроцессоров;
  • изучении принципов построения и использования микроконтроллеров;
  • изучении применения микроконтроллеров в системах связи, телемеханики и автоматики.

1.2 В результате изучения курса студент должен

знать

  • архитектуру микроконтроллеров семейства MCS-51;
  • систему команд микроконтроллеров семейства MCS-51;
  • способы построения управляющих систем связи, телемеханики и автоматики;

уметь

  • анализировать и синтезировать принципиальные схемы c применением микроконтроллеров
  • пользоваться справочной литературой и базами данных по микропроцессорам
  • работать на персональном компьютере

иметь навыки

  • составления алгоритмов и программ для микроконтроллеров;
  • проектирования микропроцессорных устройств различного назначения
  • работы на персональном компьютере типа IBM PC
  • программирования на языке высокого уровня C-51;
  • программирования на ассемблере ASM-51;

[ Главная ]


Содержание курса лекций "цифровые устройства и микропроцессоры"

Rambler's Top100 Содержание курса лекций "Микропроцессоры"

1. Введение.

  1. Что такое микроконтроллеры, микропроцессоры и сигнальные процессоры.
  2. Области применения микроконтроллеров.

2. Принципы работы микропроцессоров.

  1. Сумматоры по модулю два. Построение многоразрядных арифметических сумматоров
  2. Виды двоичных кодов.
  3. Построение арифметико-логических устройств.
  4. Построение шинных формирователей.
  5. Масочные ПЗУ, ППЗУ, РПЗУ, ЭСППЗУ, FLASH - память
  6. Построение ОЗУ.
  7. Команды микропроцессора
  8. Блок обработки сигналов микропроцессора.
  9. Микрокоманды.
  10. Системная шина микропроцессора.
    Подключение ОЗУ и ПЗУ к системной шине микропроцессора.
    Дешифратор адреса.
    Понятие адресного пространства и распределения памяти микропроцессорного устройства.
  11. Подключение внешних устройств к микропроцессору.
  12. Принципы построения параллельного порта.
  13. Принципы построения последовательных портов
  14. Принципы построения таймеров.

3. Микроконтроллеры семейства MCS-51.

  1. Представители семейства MCS-51.
  2. Архитектура микроконтроллеров MCS-51.
  3. Система команд микроконтроллеров MCS-51. Виды адресации.
  4. Инструкции микроконтроллеров семейства MCS-51.
  5. Особенности построения параллельных портов микроконтроллеров MCS-51.
  6. Особенности построения памяти микроконтроллеров семейства MCS-51.
  7. Внутренние таймеры микроконтроллера, особенности их применения.
  8. Устройство и особенности применения последовательного порта микроконтроллеров семейства MCS-51.

4. Написание программ для микроконтроллеров

  1. Языки программирования для микроконтроллеров.
  2. Применение подпрограмм при программировании.
  3. Понятие подпрограммы процедуры и подпрограммы функции.
  4. Применение комментариев.
  5. Понятие структурного программирования.
  6. Понятие многофайлового программирования.
  7. Понятие многомодульного программирования.
  8. Написание программ для микроконтроллеров
  9. Отладка программ для микроконтроллеров

5. Язык программирования высокого уровня C-51.

  1. Язык программирования C-51
  2. Структура программ на языке программирования C-51
  3. Символы языка программирования C-51.
  4. Идентификаторы и константы.
  5. Выражения в операторах.
  6. Операторы.
  7. Объявление простых переменных.
  8. Объявление массивов и структур.
  9. Указатели.
  10. Объявление подпрограмм.
  11. Области действия переменных.
  12. Построение многомодульных программ.
6. Язык программирования ASM-51.
  1. Основные определения.
  2. Правила написания операторов на языке ассемблер.
  3. Символы, идентификаторы и числа языка ASM-51.
  4. Директивы языка ASM-51.
  5. Реализация подпрограмм процедур и подпрограмм функций на языке ассемблер.
  6. Способы реализации структурных операторов на языке ассемблер.
  7. Построение многомодульных программ на языке программирования ASM-51.
  8. Использование сегментов в языке программирования ассемблер.
7. Отладка программного обеспечения микроконтроллерного устройства.

8. Проектирование цифровых устройств на микроконтроллерах

  1. Разработка структурной схемы.
  2. Разработка принципиальной схемы.
  3. Написание программы для разрабатываемого микропроцессорного устройства
  4. Пример проекта программы

[ Главная ]


Описание курса цифровые устройства и микропроцессоры.

 Rambler's Top100 Дата последнего обновления файла 22.08.2005

Цифровые устройства и микропроцессоры

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

В процессе изучения предмета рассматривается устройство и принцип действия логических элементов, триггеров, последовательных и параллельных регистров, двоичных и недвоичных счетчиков, ОЗУ, ПЗУ, а также микропроцессоров и микроконтроллеров.

Микропроцессоры изучаются на примере микроконтроллеров семейства MCS-51 (серии микросхем 1816, 1830, AT89c51, ADuC824 и др.).

В процессе изучения микроконтроллеров семейства MCS-51 приобретаются навыки составления принципиальных схем с использованием микроконтроллеров и написания программ для этих микросхем. Изучаются языки программирования низкого (ASM-51) и высокого уровня (PLM-51), предназначенные для написания программ для контроллеров семейства MCS-51.

Основные определения курса: микропроцессор, микро-ЭВМ, однокристальная ЭВМ, микроконтроллер, программные и аппаратные средства микропроцессорных систем, многопроцессорные системы, структурно- модульное программирование, отладка программного обеспечения.

Курс цифровые устройства и микропроцессоры читается в двух вариантах: для дневной формы обучения и для заочной формы обучения.

Курс цифровые устройства и микропроцессоры для дневной формы обучения делится на две части:

  1. Цифровые устройства
    1. Цели и задачи изучения
    2. Содержание дисциплины
    3. Перечень литературы
  2. Микропроцессоры
    1. Цели и задачи изучения
    2. Содержание дисциплины
    3. Лабораторные работы
    4. Перечень литературы
    5. Контрольные вопросы

В процессе изучения курса цифровые устройства и микропроцессоры группы радиотехников выполняют курсовой проект, а группы аудио визуальной техники выполняют два расчётно-графических задания.

При выполнении контрольных или расчётно-графических заданий необходимо отладить разработанные программы на языке программирования ASM-51, который можно скачать здесь или на языках программирования C51, ASM-51, входящих в среду программирования keil-c, демонстрационную версию которой можно скачать с www.keil.com или здесь.

[ Главная ]


Контрольные вопросы

 Rambler's Top100 Дата последнего обновления файла 22.08.2005

Контрольные вопросы.

  1. Что такое микропроцессоры и для чего они применяются. Отличие микроконтроллеров от микропроцессоров. Основные типы микропроцессоров.
  2. Построение триггерных схем, регистров и оперативно - запоминающих устройств.
  3. Построение мультиплексоров, дешифраторов, демультиплексоров и шинных формирователей.
  4. Для чего нужно микропрограммирование. Какие функции микропроцессора реализуются микропрограммными средствами.
  5. Построение сумматоров и арифметико - логических устройств.
  6. Как устроен блок обработки данных микропроцессора.
  7. Что такое команда микропроцессора и чем она отличается от микрокоманды.
  8. Особенности проектирования цифровых устройств на микропроцессорах. Разработка принципиальных схем и алгоритмов работы микропроцессорных устройств.
  9. Виды программного взаимодействия микропроцессора и внешних устройств (портов).
  10. Способы ввода и вывода цифровой информации в микроконтроллер и из него. (Опрос кнопок, датчиков взаимодействие с компьютером, управление двигателями, исполнительными устройствами, отображение визуальной битовой, цифровой и буквенно-цифровой информации).
  11. Способы ввода и вывода аналоговой информации в микроконтроллер и из него.
  12. Принципы и способы построения многопроцессорных цифровых устройств. Понятие протокола обмена между микропроцессорами.
  13. Типы кодов, применяемых для представления чисел и текстов в микропроцессорах.
  14. Архитектура микроконтроллеров семейства MCS-51.
  15. Принципы работы и устройство последовательного порта ввода - вывода микроконтроллеров семейства MCS-51.Режимы работы последовательного порта ввода - вывода.
  16. Устройство параллельных портов микроконтроллеров семейства MCS-51, особенности работы этих портов на ввод и вывод информации. Альтернативные функции этих портов.
  17. Построение памяти в микроконтроллерах семейства MCS-51.
  18. Система команд микроконтроллеров семейства MCS-51. Арифметические, логические и битовые команды. Команды перехода. Виды адресации в командах микроконтроллеров семейства MCS-51.
  19. Написание и отладка программ для микроконтроллеров семейства MCS-51.
  20. Что такое прерывание? Работа с прерываниями. Понятие вектора прерывания.
  21. Таймерная система микроконтроллеров семейства MCS-51. Области применения таймеров.
  22. Что такое системная шина в микропроцессорном устройстве и для чего она применяется.
  23. Что такое распределение памяти микропроцессорного устройства. (Вектора прерывания, адресное пространство ОЗУ и ПЗУ, адреса внешних устройств).
  24. Принципы работы с числами, разрядность которых превышает разрядность микропроцессора, с двоично-десятичными числами и числами представленными в дополнительном коде со знаком.
  25. Язык программирования ASM-51. Понятие команд и директив. Написание многомодульных программ.
  26. Способы разработки сложных программ. Принципы написания программных модулей.
  27. Язык программирования С-51. Понятие команд и директив. Написание многомодульных программ.
  28. Области действия переменных в языке программирования С-51. Размещение переменных в различных областях памяти микроконтроллера семейства MSC-51.
  29. Понятие структурного программирования. Написание структурированных программ на языке ассемблера.
  30. Настройка цифровых микропроцессорных устройств. Отладка программного обеспечения для микроконтроллеров.
  31. Использование микропроцессоров для генерации аналоговых сигналов.
  32. Способы ввода аналоговой информации в микроконтроллер.
  33. Способы организации нескольких параллельных устройств на одном микроконтроллере.
  34. Способы подавления помех в радиоэлектронных устройствах.

[ Главная ]


Задания на курсовое проектирование и расчётно-графические задания

 Rambler's Top100 Дата последнего обновления файла 22.08.2005

Курсовые проекты

Группы радиотехников выполняют курсовое проектирование. В процессе курсового проектирования необходимо рассчитать принципиальную схему устройства, составить алгоритм и написать программу для выбранного микроконтроллера. Задания на курсовое проектирование для студентов группы РТ-14 можно скачать в WORD-формате:

Задания на курсовое проектирование (zip 11 кбайт)
Пример выполнения курсового проекта (zip 171 кбайт)

Расчётно-графические задания

Группы аудиовизуальной техники выполняют два расчётно-графических задания. Первое задание заключается в разработке принципиальной схемы для заданного устройства. Расчётно-графические задания для студентов группы РА-15 можно скачать в WORD-формате:

Расчётно-графическое задание (zip 11 кбайт)

Второе расчётно-графическое задание заключается в том, что нужно разработать программу для устройства, схема которого разработана в первом расчётно-графическом задании.

При выполнении курсового проекта или расчётно-графических заданий необходимо отладить разработанные программы на языке программирования ASM-51, который можно скачать здесь или на языках программирования C51, ASM-51, входящих в среду программирования keil-c, демонстрационную версию которой можно скачать с www.keil.com или здесь.

[ Главная ]


[ Главная ]


1.htm

 Rambler's Top100 Дата последнего обновления файла 4.12.03

1. Параллельные интерфейсы

Параллельные интерфейсы характеризуются тем, что в них для передачи бит в слове используются отдельные сигнальные линии, и биты передаются одновременно. Параллельные интерфейсы используют логические уровни ТТЛ (транзисторно-транзисторной логики), что ограничивает длину кабеля из-за невысокой помехозащищенности ТТЛ-интерфейса. Гальваническая развязка отсутствует. Параллельные интерфейсы используют для подключения принтеров. Передача данных может быть как однонаправленной (Centronics), так и двунаправленной (Bitronics). Иногда параллельный интерфейс используют для связи между двумя компьютерами - получается сеть, "сделанная на коленке" (LapLink). Ниже будут рассмотрены протоколы интерфейсов Centronics, стандарт IEEE 1284, а также реализующие их порты PC.

1.1. Интерфейс Centronics и LPT-порт

Для подключения принтера по интерфейсу Centronics в PC был введен порт параллельного интерфейса - так возникло название LPT-порт (Line PrinTer - построчный принтер). Хотя сейчас через этот порт подключаются не только построчные принтеры, название "LPT" осталось.

1.1.1. Интерфейс Centronics

Понятие Centronics относится как к набору сигналов и протоколу взаимодействия, так и к 36-контактному разъему на принтерах. Назначение сигналов приведено в табл. 1.1, а временные диаграммы обмена с принтером - на рис. 1.1.

Интерфейс Centronics поддерживается принтерами с параллельным интерфейсом. Его отечественным аналогом является интерфейс ИРПР-М.

Традиционный, он же стандартный, LPT-порт SPP (Standard Parallel Port) является однонаправленным портом, через который программно реализуется протокол обмена Centronics. Порт вырабатывает аппаратное прерывание по импульсу на входе Ack#. Сигналы порта выводятся на разъем DB-25S (розетка), установленный непосредственно на плате адаптера (или системной плате) или соединяемый с ней плоским шлейфом. Название и назначение сигналов разъема порта (табл. 1.2) соответствуют интерфейсу Centronics.

Сигнал | I/O* | Контакт | Назначение
Strobe# | I | 1 | Строб данных. Данные фиксируются по низкому уровню сигнала
Data [0:7] | I | 2-9 | Линии данных. Data 0 (контакт 2) - младший бит
Ack# | O | 10 | Acknowledge - импульс подтверждения приема байта (запрос на прием следующего). Может использоваться для формирования запроса прерывания
Busy | O | 11 | Занято. Прием данных возможен только при низком уровне сигнала
PaperEnd | O | 12 | Высокий уровень сигнализирует о конце бумаги
Select | O | 13 | Сигнализирует о включении принтера (обычно в принтере соединяется резистором с цепью +5 В)
AutoLF# | I | 14 | Автоматический перевод строки. При низком уровне принтер, получив символ CR (Carriage Return - возврат каретки), автоматически выполняет и функцию Lf(Line Feed - перевод строки)
Error# | O | 32 | Ошибка: конец бумаги, состояние OFF-Line или внутренняя ошибка принтера
Init# | I | 31 | Инициализация (сброс в режим параметров умолчания, возврат к началу строки)
Select ln# | I | 36 | Выбор принтера (низким уровнем). При высоком уровне принтер не воспринимает остальные сигналы интерфейса
GND | - | 19-30, 33 | Общий провод интерфейса

Рис. 1.1. Передача данных по протоколу Centronics

Контакт DB-25S | Номер провода в кабеле | Назначение
 |  | I/O* | Reg. Bit** | Сигнал
1 | 1 | O/I | CR.0\ | Strobe#
2 | 3 | O(I) | DR.0 | Data 0
3 | 5 | O(I) | DR.1 | Data 1
4 | 7 | O(I) | DR.2 | Data 2
5 | 9 | O(I) | DR.3 | Data 3
6 | 11 | O(I) | DR.4 | Data 4
7 | 13 | O(I) | DR.5 | Data 5
8 | 15 | O(I) | DR.6 | Data 6
9 | 17 | O(I) | DR.7 | Data 7
10 | 19 | I*** | SR.6 | Ack#
11 | 21 | I | SR.7 | Busy
12 | 23 | I | SR.5 | PaperEnd (PE)
13 | 25 | I | SR.4 | Select
14 | 2 | O/I | CR.1\ | Auto LF#
15 | 4 | I | SR.3 | Error*
16 | 6 | O/I | CR.2 | Init#
17 | 8 | O/I | CR.3\ | Select ln#
18-25 | 10, 12, 14, 16, 18, 20, 22, 24, 26 | - | - | -
* I/O задает направление передачи (вход/выход) сигнала порта. O/I обозначает выходные линии, состояние которых считывается при чтении из портов вывода; (I) - выходные линии, состояние которых может быть считано только при особых условиях (см. ниже).
** Символом "\" отмечены инвертированные сигналы (1 в регистре соответствует низкому уровню линии).
*** Вход Ack# соединен резистором (10 кОм) с питанием +5 В.

1.1.2. Традиционный LPT-порт

Адаптер параллельного интерфейса представляет собой набор регистров, расположенных в пространстве ввода/вывода. Регистры порта адресуются относительно базового адреса порта, стандартными значениями которого являются 3BCh, 378h и 278h. Порт может использовать линию запроса аппаратного прерывания, обычно IRQ7 или IRQ5. Порт имеет внешнюю 8-битную шину данных, 5-битную шину сигналов состояния и 4-битную шину управляющих сигналов,

BIOS поддерживает до четырех (иногда до трех) LPT-портов (LPT1-LPT4) своим сервисом - прерыванием INT 17h, обеспечивающим через них связь с принтером по интерфейсу Centronics. Этим сервисом BIOS осуществляет вывод символа (по опросу готовности, не используя аппаратных прерываний), инициализацию интерфейса и принтера, а также опрос состояния принтера.

Стандартный порт имеет три 8-битных регистра, расположенных по соседним адресам в пространстве ввода/вывода, начиная с базового адреса порта BASE (3BCh, 378h или 278h).

Data Register (DR) - регистр данных, адрес=ВASЕ. Данные, записанные в этот порт, выводятся на выходные линии интерфейса DATA[0:7]. Данные, считанные из этого регистра, в зависимости от схемотехники адаптера соответствуют либо ранее записанным данным, либо сигналам на тех же линиях, что не всегда одно и то же. Если в порт записать байт с единицами во всех разрядах, а на выходные линии интерфейса через микросхемы с выходом типа "открытый коллектор" подать какой-либо код (или соединить ключами какие-то провода со схемной землей), то этот код может быть считан из того же регистра данных. Таким образом на многих старых моделях адаптеров можно реализовать порт ввода дискретных сигналов, однако выходным цепям передатчика информации придется "бороться" с выходным током логической единицы выходных буферов адаптера. Схемотехника ТТЛ такие решения не запрещает, но если внешнее устройство выполнено на микросхемах КМОП, их выходного тока может не хватить для формирования логического 0. Однако современные адаптеры часто имеют в выходной цепи согласующий резистор с сопротивлением до 50 Ом. Выходной ток короткого замыкания выхода на землю обычно не превышает 30 мА. Простой расчет показывает, что в случае короткого замыкания контакта разъема на землю при выводе "единицы" на этом резисторе падает напряжение 1,5 В, что входной схемой приемника будет воспринято как "единица". Так что такой способ ввода не будет работать на всех компьютерах.

На некоторых адаптерах портов выходной буфер отключается перемычкой на плате. Тогда порт превращается в обыкновенный порт ввода.

Status Register (SR) - регистр состояния; представляет собой 5-битный порт ввода сигналов состояния принтера (биты SR.4-SR.7), адрес==BASE+1. Бит SR. 7 инвертируется - низкому уровню сигнала соответствует единичное значение бита в регистре, и наоборот.

Назначение бит регистра состояния (в скобках даны номера контактов разъема):

  • SR.7 - Busy - инверсные отображения состояния линии Busy (11): при низком уровне на линии устанавливается единичное значения бита - разрешение на вывод очередного байта.
  • SR.6 - Ack (Acknowledge) - отображения состояния линии Ack# (10).
  • SR.5 - РЕ (Paper End) - отображения состояния линии Paper End (12). Единичное значение соответствует высокому уровню линии - сигналу о конце бумаги в принтере.
  • SR.4 - Select - отображения состояния линии Select (13). Единичное значение соответствует высокому уровню линии - сигналу о включении принтера.
  • SR.3 - Error - отображения состояния линии Error (15). Нулевое значение соответствует низкому уровню линии - сигналу о любой ошибке принтера.
  • SR.2 - PIRQ - флаг прерывания по сигналу Ack# (только для порта PS/2). Бит обнуляется, если сигнал Ack# вызвал аппаратное прерывание. Единичное значение устанавливается по аппаратному сбросу и после чтения регистра состояния.
  • SR[1:0] - зарезервированы.

Control Register (CR) - регистр управления, адрес=BASE+2. Как и регистр данных, этот 4-битный порт вывода допускает запись и чтение (биты 0-3), но его выходной буфер обычно имеет тип "открытый коллектор". Это позволяет корректно использовать линии данного регистра как входные при программировании их в высокий уровень. Биты 0, 1, 3 инвертируются.

Назначение бит регистра управления:

  • CR[7:6] - зарезервированы.
  • CR.5 - Direction - бит управления направлением передачи (только для портов PS/2). Запись единицы переводит порт данных в режим ввода. При чтении состояние бита не определено.
  • CR.4 - AcklntEn (Ack Interrupt Enable) - единичное значение разрешает прерывание по спаду сигнала на линии Ack# - сигнал запроса следующего байта.
  • CR.3 - Select ln - единичное значение бита соответствует низкому уровню на выходе Select ln# (17) - сигналу, разрешающему работу принтера по интерфейсу Centronics.
  • CR.2 - Init - нулевое значение бита соответствует низкому уровню на выходе Init# (16) - сигналу аппаратного сброса принтера.
  • CR.1 - Auto LF - единичное значение бита соответствует низкому уровню на выходе Auto LF# (14) - сигналу на автоматический перевод строки (LF - Line Feed) по приему байта возврата каретки (CR). Иногда сигнал и бит называют AutoFD или AutoFDXT.
  • CR.0 - Strobe - единичное значение бита соответствует низкому уровню на выходе Strobe# (1) - сигналу стробирования выходных данных.

Запрос аппаратного прерывания (обычно IRQ7 или IRQ5) вырабатывается по отрицательному перепаду сигнала на выводе 10 разъема интерфейса (Ack#) при установке CR.4=1. Во избежание ложных прерываний контакт 10 соединен резистором с шиной +5 В. Прерывание вырабатывается, когда принтер подтверждает прием предыдущего байта. Как уже было сказано, BIOS это прерывание не использует и не обслуживает.

Процедура вывода байта по интерфейсу Centronics включает следующие шаги (в скобках приведено требуемое количество шинных операций процессора):

  1. Вывод байта в регистр данных (1 цикл IOWR#).
  2. Ввод из регистра состояния и проверка готовности устройства (бит SR.7 - сигнал Busy). Этот шаг зацикливается до получения готовности или до срабатывания программного тайм-аута (минимум 1 цикл IORD#).
  3. По получении готовности выводом в регистр управления устанавливается строб данных, а следующим выводом строб снимается (2 цикла IOWR#). Обычно, чтобы переключить только один бит (строб), регистр управления предварительно считывается, что добавляет еще один цикл IORD#.

Видно, что для вывода одного байта требуется 4-5 операций ввода/вывода с регистрами порта (в лучшем случае, когда готовность обнаружена по первому чтению регистра состояния). Отсюда вытекает главный недостаток вывода через стандартный порт - невысокая скорость обмена при значительной загрузке процессора. Порт удается разогнать до скоростей 100-150 Кбайт/с при полной загрузке процессора, что недостаточно для печати на лазерном принтере. Другой недостаток - функциональный - сложность использования в качестве порта ввода.

Стандартный порт асимметричен - при наличии 12 линий (и бит), нормально работающих на вывод, на ввод работают только 5 линий состояния. Если необходима симметричная двунаправленная связь, на всех стандартных портах работоспособен режим полубайтного обмена - Nibble Mode. В этом режиме, называемом также Hewlett Packard Bitronics, одновременно передаются 4 бита данных, пятая линия используется для квитирования. Таким образом, каждый байт передается за два цикла, а каждый цикл требует по крайней мере 5 операций ввода/вывода.

1.1.3. Расширения параллельного порта

Недостатки стандартного порта частично устраняли новые типы портов, появившиеся в компьютерах PS/2.

Двунаправленный порт 1 (Type 1 parallel port) -интерфейс, введенный в PS/2. Такой порт кроме стандартного режима может работать в режиме ввода или двунаправленном режиме. Протокол обмена формируется программно, а для указания направления передачи в регистр управления порта введен специальный бит CR.5:0 - буфер данных работает на вывод, 1 - на ввод. Не путайте этот порт, называемый также enhanced bidirectional, с ЕРР. Данный тип порта прижился и в обычных компьютерах.

Порт с прямым доступом к памяти (Type 3 DMA parallelport) применялся в PS/2 моделей 57, 90, 95. Был введен для повышения пропускной способности и разгрузки процессора при выводе на принтер. Программе, работающей с портом, требовалось только задать в памяти блок данных, подлежащих выводу, а затем вывод по протоколу Centronics производился без участия процессора.

Позже появились другие адаптеры LPT-портов, реализующие протокол обмена Centronics аппаратно - Fast Centronics. Некоторые из них использовали FIFO-буфер данных - Parallel Port FIFO Mode. He будучи стандартизованными, такие порты разных производителей требовали использования собственных специальных драйверов. Программы, использующие прямое управление регистрами стандартных портов, не умели более эффективно их использовать. Такие порты часто входили в состав мультикарт VLB. Существуют их варианты с шиной ISA, в том числе встроенные.

1.2. Стандарт IEEE 1284

Стандарт на параллельный интерфейс IEEE 1284, принятый в 1994 году, определяет порты SPP, ЕРР и ЕСР. Стандарт определяет 5 режимов обмена данными, метод согласования режима, физический и электрический интерфейсы. Согласно IEEE 1284, возможны следующие режимы обмена данными через параллельный порт:

  • Режим совместимости (Compatibility Mode) - однонаправленный (вывод) по протоколу Centronics. Этот режим соответствует стандартному порту SPP.
  • Полубайтный режим (Nibble Mode) - ввод байта в два цикла (по 4 бита), используя для приема линии состояния. Этот режим обмена может использоваться на любых адаптерах.
  • Байтный режим (Byte Mode) - ввод байта целиком, используя для приема линии данных. Этот режим работает только на портах, допускающих чтение выходных данных (Bi-Directional или PS/2 Type 1).
  • Режим ЕРР (Enhanced Parallel Port) (EPP Mode) - двунаправленный обмен данными. Управляющие сигналы интерфейса генерируются аппаратно во время цикла обращения к порту. Эффективен при работе с устройствами внешней памяти и адаптерами локальных сетей.
  • Режим ЕСР (Extended Capability Port) (ECP Mode) - двунаправленный обмен данными с возможностью аппаратного сжатия данных по методу RLE (Run Length Encoding) и использования FIFO-буферов и DMA. Управляющие сигналы интерфейса генерируются аппаратно. Эффективен для принтеров и сканеров.

В компьютерах с LPT-портом на системной плате режим - SPP, ЕРР, ЕСР или их комбинация - задается в BIOS Setup. Режим совместимости полностью соответствует стандартному порту SPP. Остальные режимы подробно рассмотрены ниже.

1.2.1. Физический и электрический интерфейсы

Стандарт IEEE 1284 определяет физические характеристики приемников и передатчиков сигналов. Спецификации стандартного порта не задавали типов выходных схем, предельных значений величин нагрузочных резисторов и емкости, вносимой цепями и проводниками. На относительно невысоких скоростях обмена разброс этих параметров не вызывал проблем совместимости. Однако расширенные (функционально и по скорости передачи) режимы

требуют четких спецификаций. IEEE 1284 определяет два уровня интерфейсной совместимости. Первый уровень (Level I) определен для устройств медленных, но использующих смену направления передачи данных. Второй уровень (Level II) определен для устройств, работающих в расширенных режимах, с высокими скоростями и длинными кабелями. К передатчикам предъявляются следующие требования:

  • Уровни сигналов без нагрузки не должны выходить за пределы -0,5... +5,5 В.
  • Уровни сигналов при токе нагрузки 14 мА должны быть не ниже +2,4 В для высокого уровня (Vон) и не выше +0,4 В для низкого уровня (Vol) на постоянном токе.
  • Выходной импеданс Ro, измеренный на разъеме, должен составлять 50±5 Ом на уровне Voh~Vol. Для обеспечения заданного импеданса используют последовательные резисторы в выходных цепях передатчика. Согласование импеданса передатчика и кабеля снижает уровень импульсных помех.
  • Скорость нарастания (спада) импульса должна находиться в пределах 0,05-0,4 В/нс.

Требования к приемникам:

  • Допустимые пиковые значения сигналов -2,0...+7,0 В.
  • Пороги срабатывания должны быть не выше 2,0 В (Vh) для высокого уровня и не ниже 0,8 В (Vl) для низкого.
  • Приемник должен иметь гистерезис в пределах 0,2...1,2 В (гистерезисом обладают специальные микросхемы - триггеры Шмитта).
  • Входной ток микросхемы (втекающий и вытекающий) не должен превышать 20 мкА, входные линии соединяются с шиной питания +5 В резистором 1,2 кОм.
  • Входная емкость не должна превышать 50 пФ.

Когда появилась спецификация ЕСР, фирма Microsoft рекомендовала применение динамических терминаторов на каждую линию интерфейса. Однако в настоящее время следуют спецификации IEEE 1284, в которой динамические терминаторы не применяются. Рекомендованные схемы входных, выходных и двунаправленных цепей приведены на рис. 1.2.

Стандарт IEEE 1284 определяет три типа используемых разъемов. Типы A (DB-25) и В (Centronics-36) используются в традиционных кабелях подключения принтера, тип С - новый малогабаритный 36-контактный разъем.

Рис. 1.2. Оконечные цепи линий интерфейса IEEE 1284:

а - однонаправленных, б - двунаправленных

Традиционные интерфейсные кабели имеют от 18 до 25 проводов, в зависимости от числа проводников цепи GND. Эти проводники могут быть как перевитыми, так и нет. К экранированию кабеля жестких требований не предъявлялось. Такие кабели вряд ли будут надежно работать на скорости передачи 2 Мбайт/с и при длине более 2 м. Стандарт IEEE 1284 регламентирует свойства кабелей. Все сигнальные линии должны быть перевитыми с отдельными обратными (общими) проводами.

  • Каждая пара должна иметь импеданс 62±б Ом в частотном диапазоне 4-16 МГц.
  • Уровень перекрестных помех между парами не должен превышать 10%.
  • Кабель должен иметь экран (фольгу), покрывающий не менее 85% внешней поверхности. На концах кабеля экран должен быть окольцован и соединен с контактом разъема.

Кабели, удовлетворяющие этим требованиям, маркируются надписью "lEEEStd 1284-1994 Compliant". Они могут иметь длину до 10 метров, обозначения типов приведены в табл. 1.3.

Тип | Расшифровка | Разъем 1 | Разъем 2
АМАМ | Type A Male - Type A Male | А(вилка) | А(вилка)
AMAF | Туре A Male - Type A Female | А(вилка) | А (розетка)
АВ | Type A Male - Туре В Plug (стандартный кабель к принтеру) | А(вилка) | В
АС | Type A Male - Type С Plug (новый кабель к принтеру) | А(вилка) | С
ВС | Type В Plug - Type С Plug | В | С
СС | Туре С Plug - Type С Plug | С | С

1.2.2. Режимы передачи данных

IEEE 1284 определяет пять режимов обмена, один из которых полностью соответствует стандартному выводу по протоколу Centronics. Стандарт определяет способ, по которому ПО может определить режим, доступный и хосту (PC), и ПУ (или присоединенному второму компьютеру). Режимы нестандартных портов, реализующих протокол обмена Centronics аппаратно (Fast Centronics, Parallel Port FIFO Mode), могут и не являться режимами IEEE 1284, несмотря на наличие в них черт ЕРР и ЕСР.

При описании режимов обмена фигурируют следующие понятия:

  • Хост - компьютер, обладающий параллельным портом.
  • ПУ - периферийное устройство, подключаемое к этому порту.
  • Ptr - в обозначениях сигналов обозначает передающее ПУ.
  • Прямой канал - канал вывода данных от хоста в ПУ.
  • Обратный канал - канал ввода данных в хост из ПУ.

Полубайтный режим ввода - Nibble Mode

Предназначен для двунаправленного обмена. Может работать на всех стандартных портах. Порты имеют 5 линий ввода состояния, используя которые ПУ может посылать в хост байт тетрадами (nibble - полубайт, 4 бита) за два приема. Сигнал Ack#, вызывающий прерывание, которое может использоваться в данном режиме, соответствует биту 6 регистра состояния, что усложняет программные манипуляции с битами при сборке байта. Сигналы порта приведены в табл. 1.4, временные диаграммы - на рис. 1.3.

Рис. 1.3. Прием данных в полубайтном режиме

Прием байта данных в полубайтном режиме состоит из следующих фаз:

  1. Хост сигнализирует о готовности приема данных установкой низкого уровня на линии HostBusy.
  2. ПУ в ответ помещает тетраду на входные линии состояния.
  3. ПУ сигнализирует о готовности тетрады установкой низкого уровня на линии PtrClk.
  4. Хост устанавливает высокий уровень на линии HostBusy, указывая на занятость приемом и обработкой тетрады.
  5. ПУ отвечает установкой высокого уровня на линии PtrClk.
  6. Шаги 1-5 повторяются для второй тетрады, после чего ПУ может сигнализировать о наличии данных для хоста (Selekt) и занятости прямого канала (Busy); вызывать прерывание (ACK).
Контакт | Сигнал SPP | I/O | Бит | Описание
14 | AutoFeed# | O | CR.1\ | HostBusy - сигнал квитирования. Низкий уровень означает готовность к приему тетрады, высокий подтверждает прием тетрады
17 | Selectln# | O | CR.3\ | Высокий уровень указывает на обмен в режиме IEEE 1284 (в режиме SPP уровень низкий)
10 | Ack# | I | SR.6 | PtrClk. Низкий уровень означает готовность тетрады, высокий - ответ на сигнал HostBusy
11 | Busy | I | SR.7 | Прием бита данных 3, затем бита 7
12 | РЕ | I | SR.5 | Прием бита данных 2, затем бита 6
13 | Sdect | I | SR.4 | Прием бита данных 1, затем бита 5
15 | Error# | I | SR.3 | Прием бита данных 0, затем бита 4

Полубайтный режим сильно нагружает процессор, так как сигналы CR и SR формируются программно, и поэтому поднять скорость обмена выше 50 Кбайт/с не удается. Безусловное его преимущество в том, что он работает на всех портах. Его применяют в тех случаях, когда поток данных невелик (например, для связи с принтерами). Однако при связи с адаптерами локальных сетей, внешними дисковыми накопителями и CD-ROM прием больших объемов данных требует изрядного терпения со стороны пользователя.

Двунаправленный байтный режим - Byte Mode

В данном режиме данные принимаются с использованием двунаправленного порта, у которого выходной буфер данных может отключаться установкой бита С/?.5=1. Как и предыдущие, режим является программно-управляемым - все сигналы квитирования анализируются и устанавливаются драйвером. Сигналы порта описаны в табл. 1.5, временные диаграммы - на рис. 1.4.

Контакт | Сигнал SPP | Имя в байтном режиме | I/O | Бит | Описание
1 | Strobe# | HostClk | O | CR.0\ | Импульс (низкого уровня) подтверждает прием байта в конце каждого цикла
14 | AutoFeed# | HostBusy | O | CR.1\ | Сигнал квитирования. Низкий уровень означает готовность хоста принять байт; высокий уровень устанавливается по приему байта
17 | Selectln# | 1284Active | O | CR.3\ | Высокий уровень указывает на обмен в режиме IEEE 1284 (в режиме SPP уровень низкий)
16 | Init# | Init# | O | CR.2 | Не используется; установлен высокий уровень
10 | Ack# | PtrClk | I | SR.6 | Устанавливается в низкий уровень для индикации действительности данных на линиях Data [0:7]. Низкий уровень устанавливается в ответ на сигнал HostBusy
11 | Busy | PtrBusy | I | SR.7\ | Состояние занятости прямого канала
12 | PE | AckDataReq* | 1 | SR.5 | Устанавливается ПУ для указания на наличие обратного канала передачи
13 | Select | Xflag* | I | SR.4 | Флаг расширяемости
15 | Error# | DataAvail#* | I | SR.2 | Устанавливается ПУ для указания на наличие обратного канала передачи
2-9 | Data [0:7] | Data [0:7] | I/O | DR[0:7] | Двунаправленный (прямой и обратный) канал данных
* Сигналы действуют в последовательности согласования (см. далее).

Рис. 1.4. Прием данных в байтном режиме

Фазы приема байта данных:

  1. Хост сигнализирует о готовности приема данных установкой низкого уровня на линии HostBusy.
  2. ПУ в ответ помещает байт данных на линии Data [0:7].
  3. ПУ сигнализирует о действительности байта установкой низкого уровня на линии PtrClk.
  4. Хост устанавливает высокий уровень на линии HostBusy, указывая на занятость приемом и обработкой байта.
  5. ПУ отвечает установкой высокого уровня на линии PtrClk.
  6. Хост подтверждает прием байта импульсом HostClk.
  7. Шаги 1-6 повторяются для каждого следующего байта.

Побайтный режим позволяет поднять скорость обратного канала до скорости прямого канала в стандартном режиме. Однако он может работать только на двунаправленных портах.

Режим ЕРР

Протокол ЕРР (Enhanced Parallel Port - улучшенный параллельный порт) был разработан компаниями Intel, Xircom и Zenith Data Systems задолго до принятия IEEE 1284. Он предназначен для повышения производительности обмена по параллельному порту. ЕРР был реализован в чипсете Intel 386SL (микросхема 82360) и впоследствии принят множеством компаний как дополнительный протокол параллельного порта. Версии протокола, реализованные до принятия IEEE 1284, отличаются от нынешнего стандарта (см. далее).

Протокол ЕРР обеспечивает четыре типа циклов обмена:

  • запись данных;
  • чтение данных;
  • запись адреса;
  • чтение адреса.

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

Контакт | Сигнал SPP | Имя в ЕРР | I/O | Описание
1 | Strobe" | Write# | O | Низкий уровень - цикл записи, высокий - цикл чтения
14 | AutoLF# | DataStb# | O | Строб данных. Низкий уровень устанавливается в циклах передачи данных
17 | Selecting | AddrStbft | O | Строб адреса. Низкий уровень устанавливается в адресных циклах
16 | Init# | Reset# | O | Сброс (низким уровнем ПУ переводится в режим совместимости)
10 | Ack# | INTR# | I | Прерывание от ПУ
11 | Busy | Wait# | I | Сигнал квитирования. Низкий уровень разрешает начало цикла (установку строба в низкий уровень), переход в высокий - разрешает завершение цикла (снятие строба)
2-9 | Data [0:7] | AD[0:7] | I/O | Двунаправленная шина адреса/данных
12 | PaperEnd | AckDataReq* | I | Используется по усмотрению разработчика периферии
13 | Select | Xflag* | I | Используется по усмотрению разработчика периферии
15 | Error# | DataAvail#* | I | Используется по усмотрению разработчика периферии
* Сигналы действуют в последовательности согласования (см. далее).

ЕРР-порт имеет расширенный набор регистров (табл. 1.7), который занимает в пространстве ввода/вывода 5-8 смежных байт.

Имя регистра | Смещение | Режим | R/W | Описание
SPP Data Port | +0 | SPP/EPP | W | Регистр данных SPP
SPP Status Port | +1 | SPP/EPP | R | Регистр состояния SPP
SPP Control Port | +2 | SPP/EPP | W | Регистр управления SPP
EPP Address Port | +3 | EPP | R/W | Регистр адреса EPP.Чтение или запись в него генерирует связанный цикл чтения или записи адреса EPP
EPP Data Port | +4 | EPP | R/W | Регистр данных EPP. Чтение (запись) генерирует связанный цикл чтения (записи) данных EPP
Not Defined | +5...+7 | EPP | N/A | В некоторых контроллерах могут использоваться для 16-/32-битных операций ввода/вывода

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

Цикл записи данных состоит из следующих фаз:

  1. Программа выполняет цикл вывода (IOWR#) в порт 4 (EPP Data Port).
  2. Адаптер устанавливает сигнал Write* (низкий уровень), и данные помещаются на выходную шину LPT-порта.
  3. При низком уровне Wait# устанавливается строб данных.
  4. Порт ждет подтверждения от ПУ (перевода Wait# в высокий уровень).
  5. Снимается строб данных - внешний ЕРР-цикл завершается.
  6. Завершается процессорный цикл вывода.
  7. ПУ устанавливает низкий уровень Wait#, указывая на возможность начала следующего цикла.

Рис. 1.5. Цикл записи данных ЕРР

Пример адресного цикла чтения приведен на рис. 1.6. Цикл чтения данных отличается только применением другого стробирующего сигнала.

Рис. 1.6. Адресный цикл чтения ЕРР

Главной отличительной чертой ЕРР является выполнение внешней передачи во время одного процессорного цикла ввода/вывода. Это позволяет достигать высоких скоростей обмена (0,5...2 Мбайт/с). ПУ, подключенное к параллельному порту ЕРР, может работать со скоростью устройства, подключаемого через слот ISA. Протокол блокированного квитирования (interlocked handshakes) позволяет автоматически настраиваться на скорость обмена, доступную и хосту, и ПУ. ПУ может регулировать длительность всех фаз обмена с помощью всего лишь одного сигнала Wait#. Протокол автоматически подстраивается под длину кабеля - вносимые задержки приведут только к удлинению цикла. Поскольку кабели, соответствующие IEEE 1284 (см. выше), имеют одинаковые волновые свойства для разных линий, нарушения передачи, связанного с "состязаниями" сигналов, происходить не должно. При подключении сетевых адаптеров или внешних дисков к ЈPP - nopтy можно наблюдать непривычное явление: снижение производительности по мере удлинения интерфейсного кабеля.

Естественно, ПУ не должно "подвешивать" процессор на шинном цикле обмена. Это гарантирует механизм тайм-аутов PC, который принудительно завершает любой цикл обмена, длящийся более 15 мкс. В ряде реализации ЕРР за тайм-аутом интерфейса следит сам адаптер - если ПУ не отвечает в течение определенного времени (5 мкс), цикл прекращается и в дополнительном (не стандартизованном) регистре состояния адаптера фиксируется ошибка.

Устройства с интерфейсом ЕРР, разработанные до принятия IEEE 1284, отличаются началом цикла: строб DataStb# или AddrStb# устанавливается независимо от состояния WAIT#. Это означает, что ПУ не может задержать начало следующего цикла (хотя может растянуть его на требуемое время). Такая спецификация называется ЕРР 1.7 (предложена Xircom). Именно она применялась в контроллере 82360. Периферия, совместимая с ЕРР 17, будет нормально работать и с контроллером ЕРР 1284, но периферия в стандарте ЕРР 1284 может отказаться работать с контроллером ЕРР 1.7.

С программной точки зрения контроллер EРР-порта выглядит просто (см. табл. 1.7). К трем регистрам стандартного порта, имеющим смещение 0, 1 и 2 относительно базового адреса порта, добавлены два регистра (ЕРР Address Port и ЕРР Data Port), чтение и запись в которые вызывает генерацию связанных внешних циклов.

Назначение регистров стандартного порта сохранено для совместимости fPP-порта с ПУ и ПО, рассчитанными на применение программно-управляемого обмена. Поскольку сигналы квитирования адаптером вырабатываются аппаратно, при записи в регистр управления СП биты 0, 1 и 3, соответствующие сигналам Strobeft, AutoFeed# и Selecting должны иметь нулевые значения. Программное вмешательство могло бы нарушить последовательность квитирования. Некоторые адаптеры имеют специальные средства защиты (ЕРР Protect), при включении которых программная модификация этих бит блокируется.

Использование регистра данных ЕРР позволяет осуществлять передачу блока данных с помощью одной инструкции REP INSB или REP OUTSB. Некоторые адаптеры допускают 16-/ 32-битное обращение к регистру данных ЕРР. При этом адаптер просто дешифрует адрес со смещением в диапазоне 4-7 как адрес регистра данных ЕРР, но процессору сообщает о разрядности 8 бит. Тогда 16- или 32-битное обращение по адресу регистра данных ЕРР приведет к автоматической генерации двух или четырех шинных циклов по нарастающим адресам, начиная со смещения 4. Эти циклы будут выполняться быстрее, чем то же количество одиночных циклов. Таким образом обеспечивается производительность до 2 Мбайт/с, достаточная для адаптеров локальных сетей, внешних дисков, стриммеров и CD-ROM. Адресные циклы ЕРР всегда выполняются только в однобайтном режиме.

Важной чертой ЕРР является то, что обращение процессора к ПУ осуществляется в реальном времени - нет буферизации. Драйвер способен отслеживать состояние и подавать команды в точно известные моменты времени. Циклы чтения и записи могут чередоваться в произвольном порядке или идти блоками. Такой тип обмена удобен для регистроориентированных ПУ или ПУ, работающих в реальном времени, - сетевых адаптеров, устройств сбора информации и управления и т. п.

Режим ЕСР

Протокол ЕСР (Extended Capability Port - порт с расширенными возможностями) был предложен Hewlett Packard и Microsoft для связи с ПУ типа принтеров или сканеров. Как и ЕРР, данный протокол обеспечивает высокопроизводительный двунаправленный обмен данными хоста с ПУ.

Протокол ЕСР в обоих направлениях обеспечивает два типа циклов:

  • циклы записи и чтения данных;
  • командные циклы записи и чтения.

Командные циклы подразделяются на два типа: передачу канальных адресов и передачу счетчика RLC (Run-Length Count).

В отличие от ЕРР, вместе с протоколом ЕСР сразу появился стандарт на программную (регистровую) модель его адаптера, изложенный в документе "The IEEE 1284 Extended Capabilities Port Protocol and ISA Interface Standard" компании Microsoft. Этот документ определяет свойства протокола, не заданные стандартом IEEE 1284:

  • компрессию данных хост-адаптером по методу RLE;
  • буферизацию FIFO для прямого и обратного каналов;
  • применение DMA и программного ввода/вывода.

Компрессия в реальном времени по методу RLE (Run-Length Encoding) позволяет достичь коэффициента сжатия 64:1 при передаче растровых изображений, которые имеют длинные строки повторяющихся байт. Компрессию можно использовать, только если ее поддерживает и хост, и ПУ.

Канальная адресация ЕСР применяется для адресации множества логических устройств, входящих в одно физическое. Например, в комбинированном устройстве факс/принтер/модем, подключаемом только к одному параллельному порту, возможен одновременный прием факса и печать на принтере. В режиме SPP, если принтер установит сигнал занятости, канал будет занят данными, пока принтер их не примет. В режиме ЕСР программный драйвер просто адресуется к другому логическому каналу того же порта.

Протокол ЕСР переопределяет сигналы SPP (табл. 1.8).

Контакт | Сигнал SPP | Имя в ЕСР | I/O | Описание
1 | Strobe# | HostClk | O | Используется в паре с PeriphAck для передачи в прямом направлении (вывод)
14 | AutoLF# | HostAck | O | Указывает тип цикла (команда/данные) при передаче в прямом направлении. Используется в паре с PeriphClk для передачи в обратном направлении
17 | Selecting | 1284Active | O | Высокий уровень указывает на обмен в режиме IEEE 1284 (в режиме SPP уровень низкий)
16 | Init# | ReverseRequest* | O | Низкий уровень переключает канал на передачу в обратном направлении
10 | Ack# | PeriphQk | I | Используется в паре с HostAck для передачи в обратном направлении
11 | Busy | PeriphAck | I | Используется в паре с HostClk для передачи в обратном направлении. Индицирует тип команда/ данные при передаче в обратном направлении
12 | PaperEnd | AckReverse# | I | Переводится в низкий уровень как подтверждение сигналу ReverseRequest#
13 | Select | Xflag* | I | Флаг расширяемости
15 | Error# | PeriphRequest#* | I | Устанавливается ПУ для указания на доступность (наличие) обратного канала передачи*
2-9 | Data [0:7] | Data [0:7] | I/O | Двунаправленный канал данных
* Сигналы действуют в последовательности согласования (см. далее).

Адаптер ЕСР тоже генерирует внешние протокольные сигналы квитирования аппаратно, но его работа существенно отличается от режима ЕРР.

На рис. 1.7а приведена диаграмма двух циклов прямой передачи: за циклом данных следует командный цикл. Тип цлкла задается уровнем на линии HostAck: в цикле данных - высокий, в командном цикле - низкий. В командном цикле байт может содержать канальный адрес или счетчик RLE. Отличительным признаком является бит 7 (старший): если он нулевой, то биты 0-6 содержат счетчик RLE (0-127), если единичный - то канальный адрес. На рис. 1.76 показана пара циклов обратной передачи.

Рис. 1.7. Передача в режиме ЕСР: a - прямая, б - обратная

В отличие от диаграмм обмена ЕРР, на рис. 1.7 не приведены сигналы циклов системной шины процессора. В данном режиме обмен программы с ПУ разбивается на два относительно независимых процесса, которые связаны через FIFO буфер. Обмен драйвера с FIFO-буфером может осуществляться с использованием как DMA, так и программного ввода-вывода. Обмен ПУ с буфером аппаратно выполняет адаптер ЕСР. Драйвер в режиме ЕСР не имеет информации о точном состоянии процесса обмена, но здесь обычно важно только то, завершен он или нет.

Прямая передача данных на внешнем интерфейсе состоит из следующих шагов:

  1. Хост помещает данные на шину канала и устанавливает признак цикла данных (высокий уровень) или команды (низкий уровень) на линии HostAck.
  2. Хост устанавливает низкий уровень на линии HostClk, указывая на действительность данных.
  3. ПУ отвечает установкой высокого уровня на линии PeriphAck.
  4. Хост устанавливает высокий уровень линии HostClk, и этот перепад может использоваться для фиксации данных в ПУ.
  5. ПУ устанавливает низкий уровень на линии PeriphAck для указания на готовность к приему следующего байта.

Поскольку передача в ЕСР происходит через FIFO-буферы, которые могут присутствовать на обеих сторонах интерфейса, важно понимать, на каком этапе данные можно считать переданными. Данные считаются переданными на шаге 4, когда линия HostClk переходит в высокий уровень. В этот момент модифицируются счетчики переданных и принятых байт. В протоколе ЕСР есть условия, вызывающие прекращение обмена между шагами 3 и 4. Тогда эти данные не должны рассматриваться как переданные.

Из рис. 1.7 видно и другое отличие ЕСР от ЕРР. Протокол ЕРР позволяет драйверу чередовать циклы прямой и обратной передачи, не запрашивая подтверждения на смену направления. В ЕСР смена направления должна быть согласована: хост запрашивает реверс установкой ReverseRequest#, после чего он должен дождаться подтверждения сигналом AckReverse#. Поскольку предыдущий цикл мог выполняться по прямому доступу, драйвер должен дождаться завершения прямого доступа или прервать его, выгрузить буфер FIFO, определив точное значение счетчика переданных байт, и только после этого запрашивать реверс.

Обратная передача данных состоит из следующих шагов:

  1. Хост запрашивает изменение направления канала, устанавливая низкий уровень на линии ReverseRequest#.
  2. ПУ разрешает смену направления установкой низкого уровня на линии AckReverse#.
  3. ПУ помещает данные на шину канала и устанавливает признак цикла данных (высокий уровень) или команды (низкий уровень) на линии PeriphAck.
  4. ПУ устанавливает низкий уровень на линии PeriphClk, указывая на действительность данных.
  5. Хост отвечает установкой высокого уровня на линии HostAck.
  6. ПУ устанавливает высокий уровень линии PeriphClk; этот перепад может использоваться для фиксации данных хостом.
  7. Хост устанавливает низкий уровень на линии HostAck для указания на готовность к приему следующего байта.

Режимы и регистры ЕСР - порта *

* Этот режим не входит в спецификацию Microsoft, но трактуется как EPP контроллером SMC FDC37C665/666 и многими другими.

Программный интерфейс и регистры ЕСР для адаптеров IEEE 1284 определяет спецификация Microsoft. Определены режимы (табл. 1.9), в которых может функционировать адаптер. Они задаются полем Mode регистра ECR (биты [7:5]).

Регистровая модель адаптера ЕСР (табл. 1.10) использует свойства архитектуры стандартной шины и адаптеров ISA - для дешифрации адресов портов ввода/вывода задействуются только 10 младших линий шины адреса. Поэтому, например, обращения по адресам Port, Port+400h, Port+800h... будут восприниматься как обращения к адресу Port, лежащему в диапазоне 0-3FFh. Современные PC и адаптеры декодируют большее количество адресных бит, поэтому обращения по адресам 0378h и 0778h будет адресованы двум различным регистрам. Помещение дополнительных регистров ЕСР "за спину" регистров стандартного порта (смещение 400-402h) преследует две цели. Во-первых, эти адреса никогда не использовались традиционными адаптерами и их драйверами, и их применение в ЕСР не приведет к сужению доступного адресного пространства ввода/вывода. Во-вторых, этим обеспечивается совместимость со старыми адаптерами на уровне режимов 000-001 и возможность определения присутствия EСР - адаптера через попытку обращения к его расширенным регистрам.

Режим | Название | Описание
000 | SPPmode | Стандартный (традиционный) режим
001 | Bi-directional mode | Двунаправленный порт (тип 1 для PS/2)
010 | Fast Centronics | Однонаправленный с использованием FIFO и DMA
011 | ECP Parallel Port mode | ECP
100 | EPP Parallel Port mode* | Перевод в режим EPP
101 | Зарезервировано | -
110 | Test mode | Тестирование работы FIFO и прерываний
111 | Configuration mode | Доступ к конфигурационным регистрам

Каждому режиму ECP соответствуют (и доступны) свои функциональные регистры. Переключение режимов осуществляется записью в регистр ECR. "Дежурными" режимами, включаемыми по умолчанию, являются 000 или 001. В любом из них работает полубайтный режим ввода. Из этих режимов всегда можно переключиться в любой другой, но из старших режимов (010-111) переключение возможно только в 000 или 001. Для корректной работы интерфейса перед выходом из старших режимов необходимо дождаться завершения обмена по прямому доступу и очистки FIFO-буфера.

В режиме 000 (SPP) порт работает как стандартный однонаправленный программно-управляемый SPP.

В режиме 001 (Bi-Di PS/2) порт работает как двунаправленный порт PS/2 типа 1. От режима 000 отличается возможностью реверса канала данных по биту CR.5.

Режим 010(Fast Centronics) предназначен только для высокопроизводительного вывода через FIFO-буфер с использованием DMA. Сигналы квитирования по протоколу Ceritromcs вырабатываются аппаратно. Сигнал запроса прерывания вырабатывается по состоянию FIFO-буфера, но не по сигналу Аск# (запрос одиночного байта "не интересует" драйвер быстрого блочного вывода).

Режим 011 является собственно режимом ЕСР, описанным ранее. Поток данных и команд, передаваемых в ПУ, помещается в FIFO-буфер через регистры ECPDFIFO и ECPAFIFO соответственно. Из FIFO они выводятся с соответствующим признаком цикла (состояние линии HostAck). Принимаемый поток данных от ПУ извлекается из FIFO-буфера через регистр ECPDFIFO. Получение адреса в командном цикле от ПУ не предусматривается. Обмен с регистром ECPDFIFO может производиться и по каналу DMA.

Компрессия по методу RLE при передаче выполняется программно. Для передачи подряд более двух одинаковых байт данных в регистр ECPAFIFO записывается байт, у которого младшие 7 бит содержат счетчик RLC (значение RLC=127 соответствует 128 повторам), а старший бит нулевой. После этого в ECPDFIFO записывается сам байт. Отсюда очевидно, что вывод данных с одновременным использованием компрессии и DMA невозможен. Принимая эту пару байт (командный байт и байт данных), ПУ осуществляет декомпрессию. При приеме потока от ПУ адаптер ЕСР декомпрессию осуществляет аппаратно и в FIFO-буфер помещает уже декомпрессированные данные.

Режим 100 (ЕРР) - один из способов включения режима ЕРР.

Режим 110 (Test Mode) предназначен для тестирования взаимодействия FIFO и прерываний. Данные могут передаваться в/из регистра TFIFO с помощью DMA или программным способом. На внешний интерфейс обмен не воздействует. Адаптер отрабатывает операции вхолостую на максимальной скорости интерфейса (как будто сигналы квитирования приходят без задержек). Адаптер следит за состоянием буфера и по мере необходимости вырабатывает сигналы запроса прерывания. Таким образом программа может определить максимальную пропускную способность канала.

Режим 111 (Configuration mode) предназначен для доступа к конфигурационным регистрам. Выделение режима защищает адаптер и протокол от некорректных изменений конфигурации в процессе обмена.

Смещение | Имя | R/W | Режимы ЕСР* | Название
000 | DR | R/W | 000-001 | Data Register
000 | ECPAF1FO | R/W | 011 | ЕСР Address FIFO
001 | SR | R/W | Все | Status Register
002 | CR | R/W | Все | Control Register
400 | SDFIFO | R/W | 010 | Parallel Pwt Data FIFO
400 | ECPDFIFO | R/W | 011 | ЕСР Data FIFO
400 | TFIFO | R/W | 110 | Test FIFO
400 | CNFGA | R | 111 | Configuration Register A
401 | CNFGB | R/W | 111 | Configuration Register В
402 | ECR | R/W | Все | Extended Control Register
* Регистры доступны только в указанных режимах (режим задается битами 7-5 регистра ECR).

Регистр данных DR используется для передачи данных только в программно-управляемых режимах (000 и 001).

Регистр состояния SR передает значение сигналов на соответствующих линиях (как в SPP).

Регистр управления CR имеет назначение бит, совпадающее с SPP. В режимах 010, 011 запись в биты 0, 1 (сигналы AutoLF# и Strobe#) игнорируется.

Регистр ECPAFIFO служит для помещения информации командных циклов (канального адреса или счетчика RLE, в зависимости от бита 7) в FIFO-буфер. Из буфера информация будет выдана в командном цикле вывода.

Регистр SDFIFO используется для передачи данных в режиме 010. Данные, записанные в регистр (или посланные по каналу DMA), передаются через буфер FIFO по реализованному аппаратно протоколу Centronics. При этом должно быть задано прямое направление передачи (бит CR.5=0).

Регистр DFIFO используется для обмена данными в режиме 011 (ЕСР). Данные, записанные в регистр или считанные из него (или переданные по каналу DMA), передаются через буфер FIFO по протоколу ЕСР.

Регистр TFIFO обеспечивает механизм тестирования FIFO - буфера в режиме 110.

Регистр ECPCFGA позволяет считывать информацию об адаптере (идентификационный код в битах [7:4]).

Регистр ECPCFGB хранит информацию, необходимую драйверу. Запись в регистр не влияет на работу порта.

Регистр ECR - главный управляющий регистр ЕСР.

Назначение бит регистра ECR:

  • ECR[7:5] -ЕСР MODE - задает режим ЕСР.
  • ECR.4 - ERRINTREN^t (Error Interrupt Disable) - запрещает прерывания по сигналу Error# (при нулевом значении бита по отрицательному перепаду на этой линии вырабатывается запрос прерывания).
  • ECR.3 - DMAEN (DMA Enable) - разрешает обмен по каналу DMA.
  • ECR.2 - SERVICEINTR (Service Interrupt) - запрещает сервисные прерывания, которые вырабатываются по окончании цикла DMA (если он разрешен), по порогу заполнения/опустошения FIFO-буфера (если не используется DMA) и по ошибке переполнения буфера сверху или снизу.
  • ECR.1 - FIFOFS (FIFO Full Status) - сигнализирует о заполнении буфера; при FIFOFS=1 в буфере нет ни одного свободного байта.
  • ECR.0 - FIFOES (FIFO Empty Status) - указывает на полное опустошение буфера; комбинация FIFOFS=FIFOES=i означает ошибку работы с FIFO (переполнение сверху или снизу).

Когда порт находится в стандартном или двунаправленном режимах (000 или 001), первые три регистра полностью совпадают с регистрами стандартного порта. Так обеспечивается совместимость драйвера со старыми адаптерами и старых драйверов с новыми адаптерами.

По интерфейсу с программой ECP-порт напоминает ЕРР: после установки режима (записи кода в регистр ECR) обмен данными с устройством сводится к чтению или записи в соответствующие регистры. За состоянием FIFO-буфера наблюдают либо по регистру ECR, либо по обслуживанию сервисных прерываний от порта. Весь протокол квитирования генерируется адаптером аппаратно. Обмен данными с ЕСР - портом (кроме явного программного) возможен и по прямому доступу к памяти (каналу DMA), что эффективно при передаче больших блоков данных.

1.2.3. Согласование режимов IEEE 1284

ПУ в стандарте IEEE 1284 обычно не требуют от контроллера реализации всех режимов, предусмотренных стандартом. Для определения режимов и методов управления конкретным устройством стандарт предусматривает последовательность согласования (negotiation sequence). Последовательность построена так, что старые устройства, не рассчитанные на применение IEEE 1284, на нее не ответят, и контроллер останется в стандартном режиме. Периферия IEEE 1284 может сообщить о своих возможностях, и контроллер установит режим, удовлетворяющий и хост, и ПУ.

Во время фазы согласования контроллер выставляет на линии данных байт расширяемости (extensibility byte), запрашивая подтверждение на перевод интерфейса в требуемый режим или прием идентификатора ПУ (табл. 1.11). Идентификатор передается контроллеру в запрошенном режиме (любой режим обратного канала, кроме ЕРР). ПУ использует сигнал Xflag (Select в терминах SPP) для подтверждения запрошенного режима обратного канала, кроме полубайтного. Полубайтный режим поддерживается всеми устройствами IEEE 1284. Бит Extensibility Link request послужит для определения дополнительных режимов в будущих расширениях стандарта.

Бит | Описание | Допустимые комбинации бит [7:0]
7 | Request Extensibility Link - зарезервирован | 10000000
6 | Запрос режима ЕРР | 01000000
5 | Запрос режима ЕСР с RLE | 00110000
4 | Запрос режима ЕСР без RLE | 00010000
3 | Зарезервировано | 00001000
2 | Запрос идентификатора устройства с ответом в режиме: |
 | полубайтный | 00000100
 | байтный | 00000101
 | ЕСР без RLE | 00010100
 | ЕСР с RLE | 0011 0100
1 | Зарезервировано | 00000010
0 | Запрос полубайтного режима | 00000001
none | Запрос байтного режима | 00000000

Последовательность согласования (рис. 1.8) состоит из следующих шагов:

  1. Хост выводит байт расширяемости на линии данных.
  2. Хост устанавливает высокий уровень сигнала Selecting и низкий - AutoFeed#, что означает начало последовательности согласования.
  3. ПУ отвечает установкой низкого уровня сигнала Ack# и высокого - Errorft, PaperEnd и Select. Устройство, "не понимающее" стандарта 1284, ответа не даст, и дальнейшие шаги не выполнятся.
  4. Хост устанавливает низкий уровень сигнала Strobe# для записи байта расширяемости в ПУ.
  5. Хост устанавливает высокий уровень сигналов Strobeft и AutoLF#.
  6. ПУ отвечает установкой в низкий уровень сигналов PaperEnd и Еггог^, если ПУ имеет обратный канал передачи данных. Если запрошенный режим поддерживается устройством, на линии Select устанавливается высокий уровень, если не поддерживается - низкий.
  7. ПУ устанавливает высокий уровень на линии Ack# для указания на завершение последовательности согласования, после чего контроллер устанавливает требуемый режим работы.

Рис. 1.8. Последовательность согласования режимов IEEE 1284

1.2.4. Развитие стандарта IEEE 1284

Кроме основного стандарта IEEE 1284, который уже принят, в настоящее время в стадии проработки находятся новые стандарты, дополняющие его. К ним относятся:

  • IEEE Р1284.1 "Standard for Information Technology for Transport Independent Printer/ Scanner Interface (TIP/SI)". Этот стандарт разрабатывается для управления и обслуживания сканеров и принтеров на основе протокола NPAP (Network Printing Alliance Protocol).
  • IEEE P1284.2 "Standard for Test, Measurement and Conformance to IEEE Std. 1284" - стандарт для тестирования портов, кабелей и устройств на совместимость с IEEE 1284.
  • IEEE P12843 "Standard for Interface and Protocol Extensions to IEEE Std. 1284 Compliant Peripheral and Host Adapter Ports" - стандарт на драйверы и использование устройств прикладным программным обеспечением (ПО). Уже приняты спецификации BIOS для использования ЕРР драйверами DOS. Прорабатывается стандарт на разделяемое использование одного порта цепочкой устройств или группой устройств, подключаемых через мультиплексор.
  • IEEE P1284.4 "Standard for Data Delivery and Logical Channels for IEEE Std. 1284 Interfaces" направлен на реализацию пакетного протокола достоверной передачи данных через параллельный порт. Основой служит протокол MLC (Multiple Logical Channels) фирмы Hewlett- Packard, однако совместимость с ним в окончательной версии стандарта не гарантируется.

1.3. Применение параллельных интерфейсов и LPT-портов

Параллельные интерфейсы применяются в компьютерах разных семейств и классов, здесь мы ограничимся рассмотрением IBM PC-совместимых компьютеров.

1.3.1. Использование параллельных интерфейсов

Распространенным применением LPT-порта является подключение принтера и плоттера. Остановимся на аппаратных аспектах - режиме порта и кабеле подключения. Практически все принтеры могут работать с портом в режиме SPP, но применение расширенных режимов дает свои преимущества:

  • Двунаправленный режим (Bi-Di) не повышает производительность, но служит для сообщения о состоянии и параметрах принтера.
  • Скоростные режимы (Fast Centronics) повышают производительность принтера, но могут потребовать качественного кабеля (см. далее). От принтера не требуется каких-либо дополнительных "интеллектуальных" способностей.
  • Режим ЕСР - потенциально самый эффективный, имеет системную поддержку во всех версиях Windows. На некоторых принтерах реализован не полностью (может отсутствовать аппаратная компрессия). ЕСР поддерживают принтеры HP DeskJet моделей бхх, LaserJet 4 и далее, современные модели фирмы Lexmark. Требует применения кабеля, по частотным свойствам соответствующего IEEE 1284.

Простейший вариант кабеля подключения принтера - 18-проводный кабель с неперевитыми проводами. Он используется для работы в режиме SPP. При длине более 2 м желательно, чтобы хотя бы линии Strobe# и Busy были перевиты с отдельными общими проводами. Для скоростных режимов может оказаться непригодным, причем сбои могут происходить нерегулярно и лишь при определенных последовательностях передаваемых кодов. Встречаются кабели Centronics, у которых отсутствует связь контакта 17 разъема PC с контактом 36 разъема принтера. При попытке подключения таким кабелем принтера, работающего в стандарте 1284, появится сообщение о необходимости применения "двунаправленного кабеля". Принтер не может сообщить системе о поддержке расширенных режимов, на что рассчитывают драйверы принтера.

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

Идеальным вариантом являются кабели, в которых все сигнальные линии перевиты с общими проводами и заключены в общий экран - то, что требует IEEE 1248. Такие кабели гарантированно работают на скоростях до 2 Мбайт/с, их длина может достигать 10 м.

В табл. 1.12 приводится распайка кабеля подключения принтера с разъемом XI типа A (DB25-P) со стороны PC и Х2 типа В (Centronics-36) или типа С (миниатюрный) со стороны принтера. Использование общих проводов (GND) зависит от качества кабеля (см. выше). В простейшем случае (18-проводный кабель) все сигналы GND объединяются в один провод. Качественные кабели требуют отдельного обратного провода для каждой сигнальной линии, однако в разъемах типа А и В для этого недостаточно контактов (см. табл. 1.12, где в скобках указаны номера контактов разъема PC типа А, которым соответствуют обратные провода). В разъеме типа С обратный провод (GND) имеется для каждой сигнальной цепи; сигнальным контактам 1-17 этого разъема соответствуют контакты GND 19-35.

XI,разъем PC типа А | Сигнал | Х2, разъем PRN типа В | Х2, разъем PRN типа С
1 | Strobe# | 1 | 15
2 | Data 0 | 2 | 6
3 | Data 1 | 3 | 7
4 | Data 2 | 4 | 8
5 | Data 3 | 5 | 9
6 | Data 4 | 6 | 10
7 | Data 5 | 7 | 11
8 | Data 6 | 8 | 12
9 | Data7 | 9 | 13
10 | Ack# | 10 | 3
11 | Busy | 11 | 1
12 | PaperEnd | 12 | 5
13 | Select | 13 | 2
14 | AutoLF# | 14 | 17
15 | Error* | 32 | 4
16 | lnit# | 31 | 14
17 | Selecting | 36 | 16
18 | GND(1) | 19 | 33
19 | GND (2 3) | 20 21 | 24 25
20 | GND (4 5) | 22 23 | 26 27
21 | GND (6 7) | 24 25 | 28 29
22 | GND (8 9) | 26 27 | 30 31
23 | GND (11 15) | 29 | 19 22
24 | GND (10 12 13) | 28 | 20 21 23
25 | GND (14 16 17) | 30 | 32 34 35

Ряд отечественных (и стран бывшего СЭВ) принтеров имеет интерфейс ИРПР (IFSP в документации на принтеры ROBOTRON). Он является близким родственником интерфейса Centronics, но со следующими отличиями:

  • Линии данных инвертированы. Протокол квитирования несколько иной.
  • Ко всем входным линиям (на принтере) подключены пары согласующих резисторов: 220 Ом к питанию +5 В и 330 Ом к общему проводу. Это позволяет использовать длинные кабели, но перегружает большинство интерфейсных адаптеров PC.
  • Сигналы ошибки и конца бумаги отсутствуют.

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

Для связи двух компьютеров по параллельному интерфейсу применяются различные кабели в зависимости от режимов используемых портов. Самый простой и медленный - полубайтный режим, работающий на всех портах. Для этого режима в кабеле достаточно иметь 10 сигнальных и один общий провод. Распайка разъемов кабеля приведена в табл. 1.13. Связь двух PC данным кабелем поддерживается стандартным ПО типа Interink из MS-DOS или Norton Commander.

Для машин PS/2 с двунаправленным портом фирма IBM выпускала переходное устройство в комплекте с программой Data Migration Facility. Переходник устанавливался на разъем LPT-порта PS/2, а к его разъему Х2 типа Centronics присоединялся обычный принтерный кабель, подключаемый к LPT-порту любого PC. Так предлагалось решить проблему переноса файлов со старых компьютеров, оснащенных 5" дисководами, на компьютеры PS/2 с дисководами 3,5". Распайка такого переходника приведена в табл. 1.14. Как видно, данный переходник нельзя использовать при связи через Interink или Norton Commander. Если обе соединяемые машины имеют двунаправленные порты, переходник обеспечивает симметричную двунаправленную связь. По скорости обмена превосходит вышеописанное полубайтное соединение в 2 раза. Это соединение не соответствует двунаправленному режиму IEEE 1284.

XI, разъем РС#1 |  | Х2, разъем РС#2
Бит | Контакт | Контакт | Бит
DR.O | 2 | 15 | SR.3
DR.1 | 3 | 13 | SR.4
DR.2 | 4 | 12 | SR.5
DR.3 | 5 | 10 | SR.6
DR.4 | 6 | 11 | SR.7
SR.6 | 10 | 5 | DR.3
SR.7 | 11 | 6 | DR.4
SR.5 | 12 | 4 | DR.2
SR.4 | 13 | 3 | DR.1
SR.3 | 15 | 2 | DR.O
GND | 18-25 | 18-25 | GND

Разъемы XI и Х2 - DB25-P (вилки).

XI |  | Х2
Контакт | Бит | Бит | Контакт
1 | CR.0 | SR.6 | 10
2 | DR.0 | DR.0 | 2
3 | DR.1 | DR.1 | 3
4 | DR.2 | DR.2 | 4
5 | DR.3 | DR.3 | 5
6 | DR.4 | DR.4 | 6
7 | DR.5 | DR.5 | 7
8 | DR.6 | DR.6 | 8
9 | DR.7 | DR.7 | 9
10 | SR.6 | CR.0 | 1
12 | SR.5 | CR.3 | 36
17 | CR.3 | SR.5 | 12
18-25 | GND | GND | 19-30, 33

Разъемы XI - DB25-P (вилка), Х2 - Centmnics-36 (розетка).

Высокоскоростная связь двух компьютеров может выполняться и в режиме ЕСР (режим ЕРР неудобен, поскольку требует синхронизации шинных циклов ввода/вывода двух компьютеров). В табл. 1.15 приведена распайка кабеля. В отличие от предыдущих таблиц, описывающих кабели для программно-управляемых режимов, в ней приведены имена сигналов, которые аппаратно генерируются адаптерами портов. Этот же кабель может использоваться и для связи в байтном режиме. Такая связь поддерживается Windows 95.

Разъем XI |  | Разъем Х2
Контакт | Имя в ЕСР | Имя в ЕСР | Контакт
1 | HostClk | PeriphClk | 10
14 | HostAck | PeriphAck | 11
17 | 1284Active | PeriphRequest# | 15
16 | ReverseRequest* | AckReverse* | 12
10 | PeriphClk | HostClk | 1
11 | PeriphAck | ^MostAck | 14
12 | AckReverse* | ReverseRequest# | 16
13 | Xflag | /- | -
15 | PeriphRequest# | 1284Active | 17
2-9 | Data [0:7] | Data [0:7] | 2-9

Подключение сканера к LPT-порту эффективно, только если порт обеспечивает хотя бы двунаправленный режим (Bi-Di), поскольку основной поток - ввод. Лучше использовать порт ЕСР, если этот режим поддерживается сканером (или ЕРР, что маловероятно).

Подключение внешних накопителей (lomega Zip Drive, CD-ROM и др.), адаптеров ЛВС и других симметричных устройств ввода/вывода имеет свою специфику. В режиме SPP наряду с замедлением работы устройства заметна принципиальная асимметрия этого режима: чтение данных происходит в два раза медленнее, чем (весьма небыстрая) запись. Применение двунаправленного режима (Bi-Di или PS/2 Type 1} устранит эту асимметрию - скорости сравняются. Только перейдя на ЕРР, можно получить нормальную скорость работы. В режиме ЕРР подключение к LPT-порту почти не уступает по скорости подключению через ISA- контроллер. Это справедливо и при подключении устройств со стандартным интерфейсом шин к LPT-портам через преобразователи интерфейсов (например, LPT - IDE, LPT - SCSI, LPT - PCMCIA).

В табл. 1.16 описано назначение выводов разъема LPT-порта в различных режимах и их соответствие битам регистров стандартного порта.

Контакт | I/O | Бит* | SPP | ECP | ЕРР
1 | O/I | CR.0\ | Strobe# | Hostdk | Write#
2 | O/I | DR.0 | Data0 | Data0 | Data0
3 | O/I | DR.1 | Data1 | Data1 | Data1
4 | O/I | DR.2 | Data2 | Data2 | Data2
5 | O/I | DR.3 | Data3 | Data3 | Data3
6 | O/I | DR.4 | Data4 | Data4 | Data4
7 | O/I | DR.5 | Data5 | Data5 | Data5
8 | O/I | DR.6 | Data6 | Data6 | Data6
9 | O/I | DR.7 | Data7 | Data7 | Data7
10 | I | SR.6 | Ack# | PeriphClk | INTR#
11 | I | SR.7\ | Busy | PeriphAck | Wait"
12 | I | SR.5 | PaperEnd | AckReverse* | ^*
13 | I | SR.4 | Select | Xflag | **
14 | O/I | CR.1\ | AutoLF# | HostAck | DataStb#
15 | I | SR.3 | Error" | PeriphRequest# | **
16 | O/I | CR2 | hit" | ReverseRequest* | Reset*
17 | O/I | CR.3\ | Selecting | 1284Active | AddrStb#
* Символом "\" отмечены инвертированные сигналы (1 в регистре соответствует низкому уровню линии).
** - означает "определяется пользователем".

1.3.2. Конфигурирование LPT-портов

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

Конфигурирование LPT-порта зависит от его исполнения. Порт, расположенный на плате расширения (мультикарте), устанавливаемой в слот ISA или ISA+VLB, конфигурируется джамперами на самой плате. Порт на системной плате конфигурируется через BIOS Setup.

Конфигурированию подлежат следующие параметры:

  • Базовый адрес - 3BCh, 378h или 278h. При инициализации BIOS проверяет наличие портов по адресам именно в этом порядке и, соответственно, присваивает обнаруженным портам логические имена LPT1, LPT2, LPT3. Адрес 3BCh имеет адаптер порта, расположенный на плате MDA или HGC. Большинство портов по умолчанию конфигурируются на адрес 378h и могут переключаться на 278h.
  • Используемая линия запроса прерывания: для LPT - IRQ7, для LPT2 - IRQ5. Традиционно прерывания от принтера не используются, и этот дефицитный ресурс можно сэкономить. Однако при использовании скоростных режимов ЕСР (или Fast Centronics) работа через прерывания может заметно повысить производительность и снизить загрузку процессора.
  • Использование канала DMA для режимов ЕСР и Fast Centronics - разрешение и номер канала DMA (по умолчанию - 3).

Режимы работы порта:

  • SPP - порт работает только в стандартном однонаправленном программно-управляемом режиме. PS/2, он же Bi-Directional - отличается от SPP возможностью реверса канала (установкой СЯ.5=7).
  • Fast Centronics - аппаратное формирование протокола Centronics с использованием FIFO-буфера и, возможно, DMA.
  • ЕРР - в зависимости от использования регистров порт работает в режиме SPP или ЕРР.
  • ЕСР - по умолчанию включается в режим SPP или PS/2, записью в ECR может переводиться в любой режим ЕСР, но перевод в ЕРР записью в ECR кода 100 не гарантируется.
  • ЕСР+ЕРР - то же, что и ЕСР, но запись в ECR кода режима 100 переводит порт в ЕРР.

Выбор режима ЕРР, ЕСР или Fast Centronics сам по себе не приводит к повышению быстродействия обмена с подключенными ПУ, а только дает возможность драйверу и ПУ установить оптимальный режим в пределах их "разумения". Большинство современных драйверов и приложений пытаются использовать эффективные режимы, так что "подрезать им крылья" установкой простых режимов без веских оснований не стоит.

Принтеры и сканеры могут пожелать режима ЕСР. Windows (3-х, 95 и NT) имеет системные драйверы для этого режима. В среде DOS печать через ЕСР поддерживается только специальным загружаемым драйвером. Сетевые адаптеры, внешние диски и CD-ROM, подключаемые к параллельному порту, могут использовать режим ЕРР. Для этого режима специальный драйвер пока еще не применяется; использование ЕРР включается в драйвер самого подключаемого устройства.

Большинство современных ПУ, подключаемых к LPT-порту, поддерживает стандарт 1284 и РпР. Для поддержки этих функций компьютером с аппаратной точки зрения достаточно иметь контроллер интерфейса, поддерживающий стандарт 1284. Если подключаемое устройство поддерживает РпР, оно по протоколу согласования режимов 1284 способно "договориться" с портом о возможных режимах обмена. Подключенное устройство должно сообщить операционной системе (ОС) все необходимые сведения о себе - идентификатор производителя, модель и набор поддерживаемых команд. Более подробная информация может содержать идентификатор класса, подробное описание и идентификатор устройства, с которым обеспечивается совместимость. В соответствии с принятой информацией ОС может предпринять действия по установке требуемого ПО для поддержки данного устройства.

1.3.3. Неисправности и тестирование параллельных портов

Тестирование параллельных портов разумно начинать с проверки их наличия в системе. Список адресов установленных портов появляется в таблице, выводимой BIOS на экран перед загрузкой ОС. Список можно посмотреть и с помощью тестовых программ или прямо в BIOS Data Area с помощью отладчика.

Если BIOS обнаруживает меньше портов, чем установлено физически, скорее всего, двум портам присвоен один адрес. При этом работоспособность ни одного из конфликтующих портов не гарантируется: они будут одновременно выводить сигналы, но при чтении состояния конфликт на шине скорее всего приведет к искажению данных. Программное тестирование порта без диагностической заглушки (Loop Back) не покажет ошибок, поскольку при этом читаются данные выходных регистров, а они у всех конфликтующих (по отдельности исправных) портов совпадут. Именно такое тестирование производит BIOS при проверке на наличие портов. Разбираться с такой ситуацией следует, последовательно устанавливая порты и наблюдая за адресами, появляющимися в списке.

Если физически установлен только один порт, a BIOS его не обнаруживает, то либо порт отключен при конфигурировании, либо он вышел из строя (скорее всего из-за нарушений правил подключения). Иногда вам везет, и неисправность устраняется при "передергивании" платы в слоте - там возникают проблемы с контактами.

Наблюдаются и такие "чудеса" - при "теплой" перезагрузке DOS после Windows 95 порт не виден (и приложения не могут печатать из MS-DOS). Однако после повторной перезагрузки LPT порт оказывается на месте. С этим явлением легче смириться, чем бороться.

Тестирование портов с помощью диагностических программ позволяет проверить выходные регистры, а при использовании специальных заглушек - и входные линии. Поскольку количество выходных линий порта (12) и входных (5) различно, то полная проверка порта с помощью пассивной заглушки принципиально невозможна. Разные программы тестирования требуют применения разных заглушек (рис. 1.9).

Рис. 1.9. Схема заглушки для тестирования LPT-порта: a - для программы Checkit, б - для программы Norton Diagnostics.

Большинство неприятностей при работе с LPT-портами доставляют разъемы и кабели. Для проверки порта, кабеля и принтера можно воспользоваться специальными тестами из популярных диагностических программ (Checkit, PCCheck и т. п.), а можно и попытаться вывести на принтер какой либо символьный файл.

  • Если вывод файла с точки зрения DOS проходит (копирование файла на устройство с именем LPTn или PRN совершается быстро и успешно), а принтер (исправный) не напечатал ни одного символа - скорее всего, это обрыв (неконтакт в разъеме) цепи Strobed.
  • Если принтер находится в состоянии On Line, но появляется сообщение о его неготовности, причину следует искать в линии Busy.
  • Если принтер, подключенный к порту, в стандартном режиме (SPP) печатает нормально, а при переходе в ЕСР начинаются сбои, следует проверить кабель - соответствует ли он требованиям IEEE 1284 (см. выше). Дешевые кабели с неперевитыми проводами нормально работают на скоростях 50-100 Кбайт/с, но при скорости 1-2 Мбайт/с, обеспечиваемой ЕСР, имеют полное право не работать, особенно при длине более 2 м.
  • Если при установке драйвера РпР-принтера появилось сообщение о необходимости применения "двунаправленного кабеля", проверьте наличие связи контакта 17 разъема DB-25 с контактом 36 разъема Centronics. Хотя эта связь изначально предусматривалась, в ряде кабелей она отсутствует.
  • Если принтер искажает информацию при печати, возможен обрыв (или замыкание) линий данных. В этом случае удобно воспользоваться файлом, содержащим последовательность кодов всех печатных символов. Вот пример программы на языке Basic:

10 OPEN "bincod.chr" FOR OUTPUT AS #1
20 FOR J=2 TO 15
30 FOR I=0 TO 15
40 PRINT#1, СНR$(1б*J+I);
50 NEXT I
60 PRINT#1
70 NEXT J
80 CLOSE #1
90 END

Файл BINCOD.CHR, созданный данной программой, представляет собой таблицу всех печатных символов (управляющие коды пропущены), расположенных по 16 символов в строке. Если файл печатается с повтором некоторых символов или их групп, по периодичности повтора можно легко вычислить оборванный провод данных интерфейса. Этот же файл удобно использовать для проверки аппаратной русификации принтера.

Аппаратные прерывания от LPT-порта используются не всегда. Даже DOS-программа фоновой печати PRINT работает с портом по опросу состояния, а ее обслуживающий процесс запускается по прерыванию от таймера. Поэтому неисправности, связанные с цепью прерывания от порта, проявляются не часто. Однако по-настоящему многозадачные ОС (например, NetWare) стараются работать с портом по прерываниям. Протестировать линию прерывания можно, только подключив к порту ПУ или заглушку. Если к порту с неисправным каналом прерывания подключить адаптер локальной сети, то он, возможно, будет работать, но с очень низкой скоростью: на любой запрос ответ будет приходить с задержкой в десятки секунд - принятый из адаптера пакет будет приниматься не по прерыванию (сразу по приходу), а по внешнему тайм-ауту.

1.3.4. Функции BIOS для LPT-порта

BIOS обеспечивает поддержку LPT-порта, необходимую для организации вывода по интерфейсу Centronics.

В процессе начального тестирования POST BIOS проверяет наличие параллельных портов по адресам 3BCh, 378h и 278h и помещает базовые адреса обнаруженных портов в ячейки BIOS Data Area 0:0408h, 040Ah, 040Ch, 040Eh. Эти ячейки хранят адреса портов LPT1-LPT4, нулевое значение адреса является признаком отсутствия порта с данным номером. В ячейки 0:0478, 0479, 047А, 047В заносятся константы, задающие тайм-аут для этих портов.

Поиск портов обычно ведется достаточно примитивно - по базовому адресу (в регистр данных предполагаемого порта) выводится тестовый байт (ААЬ или 55h), затем производится ввод по тому же адресу. Если считанный байт совпал с записанным, предполагается, что найден LPT-порт; его адрес помещается в ячейку BIOS Data Area. Базовые адреса портов могут быть впоследствии изменены программно. Адрес порта LPT4 BIOS самостоятельно установить не может, поскольку в списке стандартных адресов поиска имеются толь/ ко три указанных.

Обнаруженные порты инициализируются - записью в регистр управления формируется и снимается сигнал Init#, после чего записывается значение OCh, соответствующее исходному состоянию сигналов интерфейса. В некоторых случаях сигнал lnit# активен с момента аппаратного сброса до инициализации порта во время загрузки ОС. Это можно заметить по поведению включенного принтера во время перезагрузки компьютера - у принтера надолго гаснет индикатор On-Line. Следствие этого явления - невозможность распечатки экранов (например, параметров BIOS Setup) по клавише Print Screen до загрузки ОС.

Программное прерывание BIOS INT 17h обеспечивает следующие функции поддержки LPT- порта:

  • 00h - вывод символа из регистра AL по протоколу Centronics (без аппаратных прерываний). Данные помещаются в выходной регистр, и, дождавшись готовности принтера (снятия сигнала Busy), формируется строб.
  • 01h - инициализация интерфейса и принтера (установка исходных уровней управляющих сигналов, формирование импульса Init#, запрет аппаратных прерываний и переключение на вывод двунаправленного интерфейса).
  • 02h - опрос состояния принтера (чтение регистра состояния порта).

При вызове INT 17h номер функции задается в регистре АН, номер порта - в регистре DX(Q - LPT1, 1 - LPT2...). При возврате регистр АН содержит код состояния - биты регистра состояния SR[7:3] (биты 6 и 3 инвертированы) и флаг таймаута в бите 0. Флаг тайм-аута устанавливается при неудачной попытке вывода символа, если сигнал Busy не снимается в течение времени, определенного для данного порта в ячейках тайм-аута. В этом случае, согласно протоколу Centronics, строб данных не вырабатывается.

Перехват прерывания INT 17h является удобным способом внедрения собственных драйверов принтера. Потребность в них может возникать при подключении к порту принтера с интерфейсов ИРПР или необходимости перекодировки символов.


4.htm

4. Шины расширения

Шины расширения (Expansion Bus) предназначены для под-
ключения различных адаптеров ПУ. Интерфейсы шин рас-
ширения PC ведут историю с 8-битной шины ISA. Ее от-
крытость обеспечила появление широкого спектра плат
расширений, позволивших использовать PC в различных
сферах. С появлением АТ-286 шина была расширена по раз-
рядности и возможностям. Шина EISA была призвана сде-
лать обмен еще более производительным и надежным. Она
содержала прогрессивные идеи автоматизации конфигури-
рования (прототип РпР), позволяя устанавливать и ISA-адап-
теры. Шина МСА, предложенная IBM, не была поддержана
производителями PC, так как ее спецификация была закры-
той. С появлением процессора 486 родилась высокоскорост-
ная локальная шина VLB. Однако она являлась дополнени-
ем к слоту шины ISA/EISA и использовалась в основном
лишь для графических карт и дисковых контроллеров. Прин-
ципиальная привязка к шине процессора 486 не обеспечила
ей долголетия. Современная скоростная шина PCI является
стандартной для компьютеров с процессорами х86 всех по-
колений старше четвертого, она используется в Power PC и
других платформах. Развитием шины PCI, нацеленным на
дальнейшее ускорение обмена, явился порт AGP, предназна-
ченный для подключения графических адаптеров. Для блок-
нотных компьютеров, поначалу имевших закрытую архитек-
туру, потребность в подключении периферии привела к
появлению стандартизованной шины PCMCIA, впоследствии
переименованной в PC Card.

Шины расширения системного уровня позволяют адаптерам
максимально использовать системные ресурсы PC: простран-
ства памяти и ввода/вывода, прерывания, каналы прямого
доступа к памяти. Как следствие, изготовителям модулей
расширения приходится точно следовать протоколам шины,
выдерживая жесткие частотные и нагрузочные параметры, а

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

В табл. 4.1 даны характеристики стандартных шин расши-
рения PC.

Шина | Пропускная способность, Мбайт/с* |  | Bus- Master | ACFG** | Разрядность данных | Разрядность адреса | Частота, МГц
 |  | DMA
БД-8 | 4 | 3 | - | - | 8 | 20 (1 Мбайт) | 8
БД-16 | 8Д16) | 8 | + | - | 16 | 24 (16 Мбайт) | 8/(16)
ЕБД | 33,3 | 8 | + | + | 32 | 32 (4 Гбайт) | 8.33
МСД-16 | 16 | - | + | + | 16 | 24 (16 Мбайт) | 10
МСД-32 | 20 | - | + | + | 32 | 32 (4 Гбайт) | 10
VLB | 132 | - | (+) | - | 32/64 | 32 (4 Гбайт) | 33-50(66)
pa | 132/264 | - | - | + | 32/64 | 32 (4 Гбайт) | 33(66)
гсмад | - | - | - | + | 16 | 26 (64 Мбайт) | 33

* Указана максимальная пропускная способность. Реальная примерно в 2
раза ниже за счет прерываний, регенерации и протокольных процедур.

** Поддержка автоматического конфигурирования. Для ISA PnP являет-
ся позднейшей надстройкой, реализуемой адаптерами и ПО.

Шины расширения конструктивно оформляются в виде ще-
левых разъемов (слотов) на системной плате для установки
плат адаптеров. Унификация системных плат, корпусов и
плат расширения обеспечивается:

^ стандартизацией размеров, количества контактов и элект-
рического интерфейса слотов шин расширения;

^ фиксированным расстоянием от слота до задней кромки
платы;

т фиксированным шагом между соседними слотами, а также
их привязкой к крепежным точкам и разъему клавиатуры;

йй определением максимальных габаритов (длины и высо-
ты) карт расширения;

^ определением геометрии нижнего края платы расшире-
ния, формы и размера фиксирующей скобки.

Размеры карт расширения для самой популярной шины -
ISA - приведены на рис. 4.1.

Рис. 4.2. Вид и положение слотов шин расширения

Типы слотов легко определить визуально (рис. 4.2). На этом
рисунке присутствие всех типов шин условно - реально на

системных платах находится не более двух-трех типов сло-
тов. Распространенные сочетания: ISA+PCI, ISA+VLB,
EISA+PCI, EISA+VLB. Фирмой ASUSTek применяется слот
"Media BUS", дополняющий слот PCI сигналами шины ISA.

У адаптеров для шины PCI, в отличие от ISA/EISA и VLB,
компоненты расположены на левой стороне печатной пла-
ты. Для экономии места на системной плате используют так
называемый разделяемый слот (Shared Slot). На самом деле
это разделяемое окно на задней стенке корпуса, которое мо-
жет использоваться либо картой ISA, либо картой PCI. Та-
ким образом, максимальное суммарное количество доступ-
ных слотов оказывается на единицу меньшим, чем видимое
количество.

Для низкопрофильных корпусов системные платы имеют всего
один слот расширения, в который устанавливается специаль-
ная плата-переходник Riser Card. Этот переходник специфи-
чен для модели системной платы (корпуса), поскольку на
его краевой разъем заводятся линии нескольких системных
шин. Если Riser Card имеет слоты только шины ISA, он обыч-
но вставляется в стандартный слот ISA-16. С точки зрения
уменьшения наводок и паразитных емкостей лучше использо-
вать специальные платы с одним разъемом, чтобы не перегру-
жать шину неиспользуемыми проводниками и разъемами.

Шины расширения допускают конфигурирование, которое
предполагает в основном настройку их временных параметров:

^ Для шины VLB применяется перемычка, управляющая де-
лителем частоты сигнала синхронизации в зависимости от
того, превышает ли системная частота 33,3 МГц.

^ Для шины PCI частота синхронизации определяется ча-
стотой системной шины процессора. Кроме того, режи-
мы могут определяться в BIOS Setup.

йа Для шины ISA кроме частоты (которая должна быть по-
рядка 8 МГц) задают время восстановления для 8- и
16-битных обращений к памяти и вводу/выводу. Неус-
тойчивая работа адаптеров может потребовать замедле-
ния шины ISA. Понижение ее производительности не от-
ражается на общей производительности современных
компьютеров.

^ Иногда для шин ISA и PCI опциями BIOS Setup прихо-
дится распределять системные ресурсы (линии запросов
прерываний)(см. приложение А).

4.1. Шины ISA, EISA и PC-104

ISA Bus (Industry Standard Architecture) - шина расшире-
ния, применявшаяся с первых моделей PC и ставшая про-
мышленным стандартом. В компьютере XT использовалась
шина с разрядностью данных 8 бит и адреса - 20 бит. В
компьютерах AT ее расширили до 16 бит данных и 24 бит
адреса. В таком виде она существует и поныне. Конструк-
тивно шина выполнена в виде двух щелевых разъемов с ша-
гом выводов 2,54 мм (0,1 дюйма) (см. рис. 4.3). Подмноже-
ство ISA-8 использует только 62-контактный слот (ряды А,
В), в ISA-16 применяется дополнительный 36-контактный
слот (ряды С, D).

Шина обеспечивает возможность отображения 8- или 16-бит-
ных регистров на пространство ввода/вывода и памяти.
Диапазон адресов памяти ограничен областью UMA (выше
AOOOOh). Для шины ISA-16 опциями BIOS Setup может быть
разрешено пространство между 15-м и 16-м мегабайтами па-
мяти (при этом компьютер не сможет использовать более
15 Мбайт ОЗУ). Диапазон адресов ввода/вывода сверху огра-
ничен количеством используемьк для дешифрации бит адре-
са, нижняя граница ограничена областью адресов 0-FFh, за-
резервированных под устройства системной платы. В PC была
принята 10-битная адресация ввода/вывода, при которой ли-
нии адреса А[15:10] устройствами игнорировались. Таким об-
разом, диапазон адресов устройств шины ISA ограничивает-
ся областью 100h-3FFh, то есть всего 758 адресов 8-битных
регистров. На некоторые из адресов претендуют системные
устройства (см. табл. А.1). Впоследствии стали применять
12-битную адресацию (диапазон lOOh-FFFh). При ее исполь-
зовании необходимо учитывать возможность присутствия на
шине старых 10-битных адаптеров, которые "отзовутся" на
адрес с подходящими ему битами А[9:0] во всей допустимой
области 12-битного адреса четыре раза (у каждого 10-битно-
го адреса будет еще по три 12-битных псевдонима).

Рис. 4.3. Слот ISA

Шина ISA-8 может предоставить до 6 линий запросов пре-
рываний, ISA-16 - 11. Часть их могут "отобрать" устрой-
ства системной платы или шина PCI.

Шина позволяет использовать до трех 8-битных каналов DMA.
На 16-битной шине доступны еще три 16-битных канала. Сиг-
налы 16-битных каналов могут использоваться для прямого
управления шиной устройством Bus-Master. При этом канал
DMA применяется для арбитража шины, а адаптер Bus-Master
формирует все адресные и управляющие сигналы шины, не
забывая передать управление шиной процессору не позднее,
чем через 15 мкс (чтобы не нарушить регенерацию памяти).

Все перечисленные ресурсы системной шины должны быть
бесконфликтно распределены. Бесконфликтность подразу-
мевает следующее:

^ Каждое устройство должно управлять шиной данных
только при чтении по своим адресам или по используе-
мому им каналу DMA. Области адресов для чтения не
должны пересекаться. "Подсматривать" операции запи-
си, "адресованные не ему", не возбраняется.

ш Назначенную линию IRQx или DRQx устройство должно
держать на низком уровне в пассивном состоянии и пере-
водить в высокий уровень для активации запроса. Неис-
пользуемыми линиями запросов устройство управлять не
имеет права, они должны быть электрически откоммути-
рованы или подключаться к буферу, находящемуся в тре-
тьем состоянии. Одной линией запроса может пользовать-
ся только одно устройство. Такая нелепость (с точки
зрения схемотехники ТТЛ) была допущена в первых PC
и из требований совместимости тиражируется до сих пор.

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

С появлением 32-битных процессоров делались попытки
расширения разрядности шины, но все 32-битные шины ISA
не являются стандартизованными, кроме EISA.

EISA Bus (Extended ISA) - стандартизованное расширение
ISA до 32 бит. Конструктивное исполнение обеспечивает со-
вместимость с ней ISA-адаптеров (рис. 4.4). Узкие дополни-
тельные контакты расширения (ряды Е, F, G, Н) располо-
жены между ламелями (контактными площадками) разъема
ISA и ниже ламелей А, В, С, D таким образом, что адаптер
ISA, не имеющий дополнительных ключевых прорезей в кра-
евом разъеме, не достает до них. Установка карт EISA в сло-
ты ISA недопустима, поскольку ее цепи попадут на контак-
ты ISA, в результате чего системная плата окажется
неработоспособной (к счастью, "без дыма").

Рис. 4.4. Разъем шины EISA

Для режимов EISA используются дополнительные управля-
ющие сигналы, обеспечивающие более эффективные режи-
мы передачи. В обычном (не пакетном) режиме передачи за
каждую пару тактов может быть передано до 32 бит (один
такт на фазу адреса, один - на фазу данных). В пакетном
режиме (Burst Mode) пакеты данных пересылаются без ука-
зания текущего адреса внутри пакета. В пакете очередные
данные передаются в каждом такте шины, длина пакета дос-
тигает 1024 байт. Шина предусматривает более производи-
тельные режимы DMA (см. прил. А4), при которых скорость
обмена может достигать 33 Мбайт/с. Линии запросов пре-
рываний допускают разделяемое использование, причем со-
храняется совместимость с ISA-картами: каждая линия за-
проса может программироваться на чувствительность как по
высокому (как в ISA), так и по низкому уровню. Шина до-

пускает потребление каждой картой расширения мощности
до 45 Вт, но это не означает, что мощность блока питания
для 8 слотов должна быть более 360 Вт - полную мощность
не потребляет ни один из адаптеров.

Многие решения EISA напоминают МСА. Каждый слот (мак-
симум - 8) и системная плата имеют селективное разреше-
ние адресации ввода/вывода и отдельные линии запроса и
подтверждения управления шиной. Арбитраж запросов вы-
полняет устройство ISP (Integrated System Peripheral). При-
оритеты (в порядке убывания): регенерация, DMA, CPU, Bus-
Master. Обязательной принадлежностью системной платы с
шиной EISA является энергонезависимая память конфигу-
рации NVRAM, в которой хранится информация об ус-
тройствах EISA для каждого слота. Формат записей стан-
дартизован, для модификации информации применяется
специальная утилита ECU (EISA Configuration Utility). Ар-
хитектура позволяет при использовании программно кон-
фигурируемых адаптеров автоматически разрешать конфлик-
ты, но в отличие от РпР не допускает динамического
конфигурирования - после выхода из режима конфигури-
рования необходима перезагрузка. Изолированный доступ
к портам ввода/вывода каждой карты во время конфигури-
рования обеспечивается просто: сигнал AEN, разрешающий
декодирование адреса в цикле ввода/вывода, на каждый слот
приходит по отдельной линии AENx, в это время программ-
но-управляемой. Так можно обращаться и к картам ISA, но
из этого нельзя извлечь выгоды, поскольку они не поддер-
живают обмена конфигурационной информацией. Идеи кон-
фигурирования EISA были использованы в спецификации
РпР для шины ISA (формат конфигурационных записей
ESCD напоминает NVRAM EISA).

EISA - дорогая, но оправдывающая себя архитектура, при-
меняющаяся в многозадачных системах и на серверах, где
требуется высокоэффективное расширение шины ввода/вы-
вода. Перед шиной PCI у нее есть преимущество в количе-
стве слотов (8 против 4).

Назначение контактов слотов шин ISA и EISA приведено в
табл. 4.2 и 4.3.

РядР | Ряд В | N" | РЯДА | РЯДЕ
GND | GND | 1 | 10СНК | CMD^
+5 В | Reset | 2 | Data 7 | START"
+5 В | +5 В | 3 | Data 6 | EXRDY
Unused | IRQ 2/9' | 4 | Data 5 | EX32#
Unused | -5В | 5 | Data 4 | GND
Key | DRQ2 | 6 | Data3 | Key
Unused | -12В | 7 | Data 2 | EX16#
Unused | OWS#2 | 8 | Data1 | SLBURSTft
+12 В | +12 В | 9 | Data 0 | MSBURST^
M/-IO | GND | 10 | IOCHDRY | W/R#
-LOCK | SmemWR# | 11 | AENx | GND
Reserved | SmemRD# | 12 | Addr19 | EMB66#3
GND | IOWR# | 13 | Addi-18 | EMB133#3
Reserved | IORD# | 14 | Addr17 | Reserved
ВЕЗ" | DACK3# | 15 | Addr16 | GND
Key | DRQ3 | 16 | Addr15 | Key
BE2# | DACK 1# | 17 | Addr14 | BE 1#
BEO# | DRQ1 | 18 | Addr13 | LA 31^
GND | Refr" | 19 | Addr12 | GND
+5 В | Bclock | 20 | Addr11 | LA30#
LA29# | IRQ 7 | 21 | Addr10 | LA28#
GND | IRQ 6 | 22 | Addr 9 | LA27#
LA26# | IRQ 5 | 23 | Addr 8 | LA25#
LA24# | IRQ 4 | 24 | Addr 7 | GND
Key | IRQ3 | 25 | Addr 6 | Key
LA 16 | DACK2# | 26 | Addr 5 | LA 15
LA 14 | TC | 27 | Addr 4 | LA 13
+5 В | BALE | 28 | Addr3 | LA 12
+5 В | +5 В | 29 | Addr 2 | LA11
GND | Osc. | 30 | Addr1 | GND
LA 10 | GND | 31 | AddrO | LA9

'B4: XT=IRQ2, AT-IRQ9.

^8: XT-Card Selected.

^12, E13 - только для Fast EISA.

РядН | Ряд О | N# | РядС | Рядб
LA8 | MCS16# | 1 | SBHE# | LA7
LA6 | IOCS16# | 2 | LA 23 | GND
LA5 | IRQ 10 | 3 | LA 22 | LA4
+5 В | IRQ 11 | 4 | LA 21 | LA3
LA2 | IRQ 12 | 5 | LA 20 | GND
Key | IRQ 15 | 6 | LA 19 | Key
Data 16 | IRQ 14 | 7 | LA 18 | Data 17
Data 18 | DACKO# | 8 | LA 17 | Data 19
GND | DRQO | 9 | MemRD# | Data 20
Data 21 | DACK5^ | 10 | MemWR* | Data 22
Data 23 | DRQ5 | 11 | Data 8 | GND
Data 24 | DACK6# | 12 | Data 9 | Data 25
GND | DRQ6 | 13 | Data 10 | Data 26
Data 27 | DACK7# | 14 | Data 11 | Data 28
Key | DRQ7 | 15 | Data 12 | Key
Data 29 | +5 В | 16 | Data 13 | GND
+5 В | Master* | 17 | Data 14 | Data 30
+5 В | GND | 18 | Data 15 | Data 31
МАКх# | - | 19 | - | MREQx

Сигналы шины ISA восходят к шинам Microbus и Multibus,
они естественны для периферийных микросхем фирмы Intel
для процессоров 8080 и 80х86/88. Набор сигналов ISA-8 пре-
дельно прост. Программное обращение к ячейкам памяти и
пространства ввода/вывода обеспечивают следующие сигналы:

^ Data[7:0] - шина данных.
^ Addr[19:0] -шина адреса.

т AEN - разрешение адресации портов (запрещает ложную
дешифрацию адреса в цикле DMA).

^ IOWR# - запись в порт.
^ IORD# - чтение порта.

^ SMemWR-ft - запись в память
(в диапазоне адресов 0-FFFFFh).

^ SMemRD# - чтение памяти

(в диапазоне адресов 0-FFFFFh).

К сигналам запросов прерывания и каналам прямого доступа
к памяти относятся следующие:

йй IRQ2/9, IRQ[3:7] - запросы прерываний. Положительный
перепад сигнала вызывает запрос аппаратного прерыва-
ния. Для идентификации источника высокий уровень
должен сохраняться до подтверждения прерывания про-
цессором, что затрудняет разделяемое использование пре-
рываний. Линия IRQ2/9 в шинах XT вызывает аппарат-
ное прерывание с номером 2, а в AT - с номером 9.

^ DRQ[1:3] - запросы 8-битных каналов DMA (положитель-
ным перепадом).

т DACK[1:3]# - подтверждение запросов 8-битных каналов
DMA.

^ ТС - признак завершения счетчика циклов DMA.

Шина имеет и несколько служебных сигналов синхрониза-
ции, сброса и регенерации памяти, установленной на адап-
терах:

ш IOCHRDY - готовность устройства, низкий уровень удли-
няет текущий цикл (не более 15 мкс).

^ BALE - разрешение защелки адреса. После его спада в
каждом цикле процессора линии Addr 0-19 гарантиро-
ванно содержат действительный адрес.

^ Refr# - цикл регенерации памяти (в XT называется
DACK 0#). Сигнал появляется каждые 15 мкс, при этом
шина адреса указывает на очередную регенерируемую
строку памяти.

т 10СНК - контроль канала. Низкий уровень сигнала вы-
зывает NMI CPU (разрешение и индикация в системных
портах 061h, 062h).

^ Reset - сигнал аппаратного сброса (активный уровень -
высокий).

^ BCIock - синхронизация шины с частотой около 8 МГц.
ПУ могут не использовать этот сигнал, работая только
по управляющим сигналам записи и чтения.

т OSC - частота 14,431818 МГц, несинхронизированная с ши-
ной (использовалась старыми дисплейными адаптерами).

Кроме логических сигналов шина имеет контакты для раз-
водки питания +5, -5, +12 и -12В.

Дополнительный разъем, расширяющий шину до 16-битной,
содержит линии данных, адреса, запросов прерываний и ка-
налов прямого доступа:

as Data[15:8] -шина данных.
^ SB HE - признак наличия данных на линиях Data [15:8].

^ LA[23:17j - нефиксированные сигналы адреса, требующие
защелкивания по спаду сигнала BALE. Такой способ по-
дачи адреса позволяет сократить время цикла (схемы де-
шифратора адреса памяти плат расширения начинают де-
кодирование несколько раньше спада BALE).

т IRQ[10:12], IRQ[14:15] - дополнительные запросы преры-
ваний.

^ DRQ[5:7] - запросы 16-битных каналов DMA (положи-
тельным перепадом).

т DACK[5:7]# - подтверждение запросов 16-битных каналов
DMA.

С переключением разрядности данных связаны сигналы:

^ MCS16# - адресуемое устройство поддерживает 16-бит-
ные обращения к памяти.

^ IOCS16# - адресуемое устройство поддерживает 16-бит-
ные обращения к портам.

К новым управляющим сигналам относятся следующие:

^ MemWR# - запись в память в любой области до
16 Мбайт.

^ MemRD# - чтение памяти в любой области до 16 Мбайт.

^ OWS# - сигнал от устройства, разрешающий системной пла-
те укоротить текущий цикл (устранить такты ожидания).

^ MASTERS - запрос от устройства, использующего 16-бит-
ный канал DMA на управление шиной. При получении
подтверждения DACK [5:7] Bus-Master может захватить
шину (не более чем на 15 мкс).

Обобщенные временные диаграммы циклов чтения или за-
писи памяти или ввода/вывода приведены на рис. 4.5. Здесь
условный сигнал CMD* изображает один из сигналов:

^ SMEMRD#, MEMRD# - в цикле чтения памяти;

s SMEMWR#, MEMWR# - в цикле записи памяти;

^ IORD# - в цикле чтения порта ввода/вывода;

^ IOWR# - в цикле записи порта ввода/вывода.

Рис. 4.5. Временные диаграммы циклов чтения или записи
на шине ISA

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

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

ройство должно фиксировать для себя эти данные в конце
цикла по подъему сигнала. Обращение к портам ввода/вы-
вода отличается тем, что сигналы LA[32:17] не используются.

Минимальная длительность цикла определяется чипсетом и
может программироваться опциями BIOS Setup заданием
тактов ожидания. При этом циклы обращения к памяти ко-
роче циклов обращения к портам ввода/вывода. В шине AT
для управления минимальной длительностью цикла исполь-
зуются также сигналы управления разрядностью передачи:

если устройство поддерживает 16-битные передачи, предпо-
лагается, что оно может работать с меньшим количеством
тактов ожидания. Этим объясняется, что в Setup длитель-
ности циклов ISA задаются раздельно как для памяти и вво-
да/вывода, так и для 8- и 16-битных операций.

Если устройство не работает с заданными циклами, оно мо-
жет вводить дополнительные такты ожидания, используя
сигнал IOCHRDY, но при этом недопустимо удлинять цикл
более чем на 15 мкс.

Шина EISA позволяет устройствам работать как в режиме
ISA, так и в новых режимах EISA. Из сигналов ISA исполь-
зуются линии адреса/данных с расширением их до 32 бит,
сигналы прерываний и прямого доступа к памяти и синхро-
низации. Для своих циклов обмена EISA использует соб-
ственный набор управляющих сигналов с обязательной син-
хронизацией по сигналу BCLK. Сигналы IORD# и IOWR# при
обращении к EISA-портам не используются. Вместо них при-
меняются сигналы обращения М/10# и W/R#. В EISA-цик-
лах не используется сигнал SBHE; он заменен сигналами раз-
решения байт ВЕ[3:0]. Вместо общего сигнала AEN каждый
слот имеет собственный сигнал AENx. К сигналам расшире-
ния шины EISA относятся следующие:

^ LA[23:16] - опережающие сигналы адреса, требующие за-
щелкивания по спаду сигнала BALE.

ж LA[31:24]# - аналогично LA [2:23], но с инверсией.

^ ВЕ[3:0]# - индикаторы действительности данных в бай-
тах 0-3 при EISA-цикле.

^ М/Ю# - обращение к памяти (1) или портам (0) EISA.

m W/R# - запись (1) или чтение (0) EISA.

^ ЕХ16#, ЕХ32# - индикаторы разрядности ресурсов.

т SI-BURSTS - адресуемое устройство поддерживает пакет-
ный режим обмена.

ж MSBURST^ - уведомление устройства, подавшего сигнал
SLBURST, о намерении инициировать пакетный обмен.

ва LOCK# - обеспечение исключительного права доступа
активного EISA Bus-Master к памяти или портам.

ss EXRDY - готовность EISA-устройства; аналогично сигна-
лу IOCHRDCY.

^ STARTS - отмечает начало цикла EISA-доступа. Во вре-
мя действия этого сигнала фиксируется адрес и опреде-
ляется тип обращения.

^ CMD# - задает временные параметры цикла; действует
после сигнала STARTS.

^ MREQx# - EISA Bus-Master слота "х" запрашивает
управление шиной.

^ МАКх# - EISA Bus-Master слота "х" получает управле-
ние шиной от арбитра.

Рис. 4.6. Временные диаграммы одиночных циклов на шине EISA

Рис. 4.7. Временные диаграммы пакетных циклов на шине EISA

Временные диаграммы одиночных и пакетных циклов об-
мена по шине EISA приведены на рис. 4.6 и 4.7. Обратим
внимание на то, что действительные значения сигналов дол-
жны фиксироваться по положительному перепаду BCLKft, a
готовность проверяется по отрицательному.

Для шин ISA ряд фирм выпускают карты-прототипы
(Prototype Card), представляющие собой печатные платы
полного или уменьшенного формата с крепежной скобой. На
платах установлены обязательные интерфейсные цепи - бу-
фер данных, дешифратор адреса и некоторые другие. Осталь-
ная часть платы свободна, и здесь разработчик может раз-
местить макетный вариант своего устройства. Эти платы
удобны для проверки нового изделия, а также для монтажа
единичных экземпляров устройства, когда разработка и из-
готовление печатной платы нерентабельно.

На некоторых системных платах (ASUSTek) имеется неболь-
шой разъем с загадочным названием Media Bus, расположен-
ный позади разъема шины PCI одного из слотов. На этот
разъем выводятся сигналы шины ISA. Он предназначен для

того, чтобы на графическом адаптере с шиной PCI можно было
разместить недорогой чипсет звуковой карты, предназначен-
ный для шины ISA. Этот разъем и такие комбинированные
аудиовидеокарты широкого распространения не получили.

Обычно в PC разъемы шины расширения устанавливают на
системную плату. Для компьютеров инструментального и
промышленного назначения по ряду причин удобнее исполь-
зовать модули, соединяемые пассивной объединяющей пла-
той. Самый простой соответствующий конструктив заклю-
чается в использовании стандартной шины и карты ISA. Все
компоненты с традиционной системной платы перенесли на
карту ISA, получив одноплатный компьютер, называемый
микроРС (mPC - microPC). На такой карте содержатся про-
цессор, память, графический адаптер, контроллеры портов
и дисковые интерфейсы, иногда дополнительные контрол-
леры цифрового и аналогового ввода/вывода. Для подклю-
чения к модулям расширения используют пассивную кросс-
плату с обычными разъемами ISA. Если требуется более
высокопроизводительный канал, применяют шину PCI. При
этом на плате системного контроллера присутствуют два
краевых разъема - ISA на обычном месте и PCI примерно
на том месте, где располагался разъем VLB. Кросс-плата для
таких систем становится неоднородной - часть ее слотов
имеет разъемы PCI, другая часть - ISA, место для систем-
ного контроллера оборудовано обоими разъемами.

Логически эквивалентной ISA является шина PC-104, предна-
значенная для построения встраиваемых контроллеров. 104 -
число контактов коннектора, на который выводятся сигналы
шины ISA. От ISA шина PC-104 отличается только типом
коннектора и нагрузочными характеристиками линий. Осно-
вой контроллера является mPC с разъемом PC-104 (розетка).
Если требуется подключение платы расширения, она своей
вилкой PC-104 вставляется в плату контроллера. Кроме вил-
ки на плате расширения имеется розетка PC-104 (коннектор
двухсторонний), так что можно собрать "бутерброд" из не-
скольких плат. Если плат более трех, то сверху "бутерброда"
устанавливают терминатор. Для фиксации плат стандартизо-
вано расположение крепежных отверстий. Платы скрепляют-
ся несущими стойками (длинными винтами со втулками).

4.2. Шина МСА

МСА (MicroChannel Architecture) - микроканальная архи-
тектура - была введена фирмой IBM для своих компьюте-
ров PS/2, начиная с модели 50. Шина МСА абсолютно не-
совместима с ISA/EISA. Состав управляющих сигналов,
протокол и архитектура ориентированы на асинхронное
функционирование шины и процессора, что снимает про-
блемы согласования скоростей процессора и ПУ. Архитек-
тура позволяет эффективно и автоматически конфигуриро-
вать все устройства программным путем (в картах МСА нет
ни одного переключателя).

Слоты МСА имеют контакты с шагом 0,05 дюйма. Число сло-
тов на системной плате зависит от модели компьютера.

Рис. 4.8. Слоты МСА: а - 16-битный, б - 32-битный,
в - 16-битный с расширением

§? 16-битный слот (рис. 4.8а) использует контакты А1/В1-
А45/В45 для 8-битных операций и А48/В48-А58/В58
для 16-битных. Пропущенные номера 46, 47 - ключ для
всех слотов.

§* 32-битный слот (рис. 4.86) имеет удлиненную вторую
секцию с контактами А48/В48-А89/В89.

Перед контактами А1/В1 возможно одно из двух расшире-
ний за счет удлинения первой секции (рис. 4.8в):

ж АМ1/ВМ1-АМ4/ВМ4 - для плат расширения памяти;

т AV1/BV1-AV10/BV10 - для плат видеоадаптеров. Позво-
ляет использовать общие цепи встроенного в системную
плату VGA-адаптера, теоретически удешевляя расшире-
ние видеосистемы. По составу сигналов видеорасшире-
ние близко к разъему VGA Auxiliary Video Connector или
VESA Feature Connector.

При всей прогрессивности архитектуры МСА не пользуется
популярностью, в частности, из-за полной несовместимости
с ISA. МСА находит применение в мощных файл-серверах,
где требуется высоконадежный производительный ввод/
вывод.

4.3. Локальная шина VLB

Шины ввода/вывода ISA, МСА, EISA имеют низкую
производительность, обусловленную их ролью в структуре
PC. Современные приложения требуют существенного по-
вышения пропускной способности шины. Одним из реше-
ний проблемы стало применение локальной шины процес-
сора 486. Шину процессора использовали как место
подключения периферии (контроллера дисков и графичес-
кого адаптера).

VLB (VESA Local Bus) - стандартизованная 32-битная ло-
кальная шина, практически представляющая собой сигналы
системной шины процессора 486, выведенные на дополни-
тельные разъемы системной платы. Шина ориентирована
на процессор 486, хотя возможно ее использование с 386. Для

процессоров Pentium была принята спецификация 2.0, в ко-
торой разрядность шины данных увеличена до 64, но она
распространения не получила.

Конструктивно VLB-слот аналогичен 16-битному МСА-сло-
ту, но является расширением системного слота шины ISA-
16, EISA или МСА, располагаясь позади него вблизи от
процессора. Из-за ограниченной нагрузочной способности
шины процессора больше трех слотов VLB на системной
плате не устанавливают. Максимальная тактовая частота
шины - 66 МГц, хотя шина работает надежнее на частоте
33 МГц. Декларируется пиковая пропускная способность
132 Мбайт/с (33 МГцх4 байта), но она достигается только
при пакетной передаче. Реально в пакетном цикле передача
4х4 = 16 байт данных требует 5 тактов шины, так что даже
в нем пропускная способность составляет 105,6 Мбайт/с, а
в обычном режиме (по такту на фазу адреса и на фазу дан-
ных) - 66 Мбайт/с. Жесткие требования к временным ха-
рактеристикам процессорной шины при большой нагрузке
(со стороны микросхем внешнего кэша) могут привести к
неустойчивой работе: все три VLB-слота могут использо-
ваться только на частоте 40 МГц. При нагруженной сис-
темной плате на 50 МГц может работать только один слот.
Шина допускает применение активных (Bus-Master) адап-
теров, но арбитраж запросов возлагается на сами адапте-
ры. Разрешена установка не более двух Bus-Master-адапте-
ров, один из которых устанавливается в "Master"-слот.

Шину VLB использовали для подключения графического
адаптера и контроллера дисков. Встречаются системные пла-
ты, которые имеют встроенный графический и дисковый
адаптеры с шиной VLB, но самих слотов VLB нет. Это озна-
чает, что на плате установлены микросхемы указанных адап-
теров для шины VLB. Такая неявная шина по производи-
тельности не уступает обычной, а с точки зрения надежности
и совместимости она даже лучше.

Назначение контактов шины VLB представлено в табл. 4.4.
В названиях сигналов можно узнать сигналы процессо-
ра 486.

Ряд В |  | № | РЯДА
32/64- битный обмен | 64-битный обмен |  | 32/64-битный обмен | 64-битный обмен
Data 0 | - | 1 | Data1 | -
Data 2 | - | 2 | Data3 | -
Data 4 | - | 3 | GND | -
Data 6 | - | 4 | Data 5 | -
Data 8 | - | 5 | Data 7 | -
GND | - | 6 | Data 9 | -
Data 10 | - | 7 | Data 11 | -
Data 12 | - | 8 | Data 13 | -
VCC | - | 9 | Data 15 | -
Data 14 | - | 10 | GND | -
Data 16 | - | 11 | Data 17 | -
Data 18 | - | 12 | VCC | -
Data 20 | - | 13 | Data 19 | -
GND | - | 14 | Data 21 | -
Data 22 | - | 15 | Data 23 | -
Data 24 | - | 16 | Data 25 | -
Data 26 | - | 17 | GND | -
Data 28 | - | 18 | Data 27 | -
Data 30 | - | 19 | Data 29 | -
VCC | - | 20 | Data 31 | -
Addr31 | Data 63 | 21 | Addr30 | Data 62
GND | - | 22 | Addr28 | Data 60
Addr29 | Data 61 | 23 | Addr26 | Data 58
Addr27 | Data 59 | 24 | GND | -
Addr25 | Data 57 | 25 | Addr24 | Data 56
Addr23 | Data 55 | 26 | Addr 22 | Data 54
Addr21 | Data 53 | 27 | VCC | -

Ряд В |  | № | РЯДА
32/64- битный обмен | 64-битный обмен |  | 32/64-битный обмен | 64-битный обмен
Addr19 | Data 51 | 28 | Addr 20 | Data 52
GND | - | 29 | Addr 18 | Data 50
Addr17 | Data 49 | 30 | Addr16 | Data 48
Addr 15 | Data 47 | 31 | Addr 14 | Data 46
VCC | - | 32 | Addr 12 | Data 44
Addr13 | Data 45 | 33 | Addr 10 | Data 42
Addr11 | Data 43 | 34 | Addr 8 | Data 40
Addr 9 | Data 41 | 35 | GND | -
Addr 7 | Data 39 | 36 | Addr 6 | Data 38
Addr 5 | Data 37 | 37 | Addr 4 | Data 36
GND | - | 38 | Write Back | -
Addr3 | Data 35 | 39 | Byte Enable 0 | Byte Enable 4
Addr 2 | Data 34 | 40 | VCC | -
Unused | LBS64* | 41 | Byte Enable 1 | Byte Enable 5
Reset | - | 42 | Byte Enable 2 | Byte Enable 6
Data-Code Status | - | 43 | GND | -
Mem-l/0 Status | Data 33 | 44 | Byte Enable 3 | Byte Enable 7
Wr-Rd Status | Data 32 | 45 | Address Data Strobe | -
ключ | - | 46 | ключ | -
ключ | - | 47 | ключ | -
Ready Return | - | 48 | Local Ready | -
GND | - | 49 | Local Device | -
IRQ 9 | - | 50 | Local Request | -
Burst Ready | - | 51 | GND | -
Burst Last | - | 52 | Local Bus Grant | -

Ряд В |  | № | РЯДА
32/64- битный обмен | 64-битный обмен |  | 32/64-битный обмен | 64-битный обмен
ID 0 | - | 53 | VCC | -
ID1 | - | 54 | ID 2 | -
GND | - | 55 | IDS | -
Local Clock | - | 56 | ID 4 | ACK64#
VCC | - | 57 | Unused | -
Local Bus Size 16 | ^~ | 58 | Loc/Ext Address Data Strobe | "~

4.4. Шина PCI

PCI (Peripheral Component Interconnect) local bus - шина со-
единения периферийных компонентов. Будучи локальной, эта
шина занимает особое место в современной архитектуре PC,
являясь мостом (mezzanine bus) между системной шиной про-
цессора и шиной ввода/вывода ISA/EISA или МСА. Шина
PCI разрабатывалась в расчете на Pentium-системы, но хоро-
шо сочетается и с процессорами 486. Является четко стандар-
тизованной высокопроизводительной и надежной шиной рас-
ширения. В настоящее время действует спецификация PCI 2.1.
При частоте шины 33 МГц скорость теоретически достигает
132/264 Мбайт/с для 32/64 бит; при частоте синхронизации
66 МГц - в два раза выше (версия 2.1 допускает частоту до
66 МГц при согласии всех устройств на шине).

Шина является синхронной - фиксация всех сигналов вы-
полняется по положительному перепаду (фронту) сигнала
CLK. В каждой транзакции (обмене по шине) участвуют два
устройства - инициатор обмена (Initiator или Master, ини-
циирующее устройство, ИУ) и целевое устройство (Target
или Slave, ЦУ).

Шина PCI все транзакции трактует как пакетные: каждая
транзакция начинается фазой адреса, за которой может сле-

довать одна или несколько фаз данных. Для адреса и дан-
Hbix используются общие мультиплексированные линии AD.
Четыре мультиплексированные линии С/ВЕ[3:0] использу-
ются для кодирования команд в фазе адреса и разрешения
байт в фазе данных. В начале транзакции И У активизирует
сигнал FRAME#, по шине AD передает целевой адрес, а по
линиям С/ВЕ# - информацию о типе транзакции (коман-
де). Адресованное ЦУ отзывается сигналом DEVSEL#, после
чего И У может указать на свою готовность к обмену данны-
ми сигналом IRDY#. Когда к обмену данными будет готово и
ЦУ, оно установит сигнал TRDY#. Данные по шине AD могут
передаваться только при одновременном наличии сигналов
IRDYft и TRDY#. С помощью этих сигналов ИУ и ЦУ согла-
суют свои скорости, вводя такты ожидания. На рис. 4.9 при-
ведена временная диаграмма обмена, в которой и ИУ, и ЦУ
вводят такты ожидания. Если бы они оба ввели сигналы го-
товности в конце фазы адреса и не снимали их до конца
обмена, то в каждом такте после фазы адреса передавались
бы по 32 бита данных, что обеспечило бы выход на предель-
ную производительность обмена.

Рис. 4.9. Цикл обмена на шине РС1

Количество фаз (циклов) данных в пакете заранее не опре-
делено, но перед последним циклом ИУ при введенном сиг-
нале IRDY# снимает сигнал FRAMED. После последней фазы
данных ИУ снимает сигнал IRDY#, и шина переходит в со-
стояние покоя (PCI Idle) - оба. сигнала FRAME# и IRDY# на-
ходятся в пассивном состоянии. Максимальное количество

циклов данных в пакете может быть неявно ограничено тай-
мером, определяющим максимальное время, в течение кото-
рого И У может пользоваться шиной. И У завершает тран-
закцию одним из следующих способов:

^ Нормальное завершение выполняется по окончании об-
мена данными.

^ Завершение по тайм-ауту (Time-out) происходит, когда
во время транзакции у ИУотбирают право на управле-
ние шиной (снятием сигнала GNT#) или когда истекает
время, указанное в его таймере MLT (медленное ЦУ или
слишком длинная транзакция).

^ Транзакция отвергается (Abort), когда в течение заданно-
го времени ИУ не получает ответа ЦУ (DEVSEL#).

Транзакция может быть прекращена и по инициативе ЦУ,
для этого оно может ввести сигнал STOP#. Возможны три
типа прекращения:

^ Отключение (Disconnect) - сигнал STOP# вводится во
время активности TRDY#. В этом случае транзакция за-
вершается после фазы данных.

^ Отключение с повтором (Disconnect/Retry) - сигнал
STOP# вводится при пассивном состоянии TRDY#, и по-
следняя фаза данных отсутствует. Является указанием ИУ
на необходимость повтора транзакции.

^ Отказ (Abort) - сигнал STOP# вводится одновременно со
снятием DEVSEL# (в предыдущих случаях во время по-
явления сигнала STOP# сигнал DEVSEL^ был активен). В
этом случае последняя фаза данных тоже отсутствует, но
повтор не запрашивается.

Протокол квитирования обеспечивает надежность обмена -
ИУ всегда получает информацию об отработке транзакции
ЦУ. Средством повышения надежности (достоверности) яв-
ляется применение контроля паритета: линии AD[31:0] и
С/ВЕ#[3:0] и в фазе адреса, и в фазе данных защищены битом
паритета PAR (количество единичных бит этих линий, вклю-
чая PAR, должно быть четным). Действительное значение PAR
появляется на шине с задержкой в один такт относительно
линий AD и С/ВЕ#. При обнаружении ошибки ЦУ со сдви-

том на такт вырабатывается сигнал PERFW. В подсчете пари-
тета при передаче данных учитываются все байты, включая
и недействительные (отмеченные высоким уровнем сигнала
C/BE#i). Состояние бит и недействительных байт данных во
время фазы данных должно оставаться стабильным.

Арбитражем запросов на использование шины занимается
специальный узел, входящий в чипсет системной платы. Каж-
дое ИУ имеет пару сигналов - REQft для запроса на управ-
ление шиной и GNT# для подтверждения предоставления
управления шиной. Схема приоритетов (фиксированный,
циклический, комбинированный) определяется программи-
рованием арбитра.

Каждое устройство - потенциальное ИУ (PCIMaster) - име-
ет собственный программируемый таймер MLT (Master
Latency Timer), определяющий максимальное количество так-
тов шины, допустимое для одной транзакции. Его конфигу-
рированием осуществляется распределение полосы пропус-
кания шины между устройствами.

Каждое ЦУ имеет инкрементный механизм слежения за дли-
тельностью циклов (Incremental Latency Mechanism), который
не позволяет интервалу между соседними фазами данных в
пакете превышать 8 тактов шины. Если ЦУ не успевает ра-
ботать в таком темпе, оно обязано остановить транзакцию.

Адресация памяти, портов и конфигурационных регистров
различна. Байты шины AD, несущие действительную инфор-
мацию, выбираются сигналами С/ВЕ[3:0] в фазах данных
(внутри пакета эти сигналы могут менять состояние). В цик-
лах обращения к памяти адрес, выровненный по границе
двойного слова, передается по линиям AD[31:2], линии
AD[1:0] задают порядок чередования адресов в пакете:

^ 00 - линейное инкрементирование;

^ 01 - чередование адресов с учетом длины строки кэш-
памяти;

^ 1х -зарезервировано.

В циклах обращения к портам ввода/вывода для адресации
любого байта используются все линии AD[31:0]. В циклах
конфигурационной записи/считывания устройство выбира-

ется индивидуальным сигналом IDSEL#, конфигурационные
регистры выбираются двойными словами по линиям AD[7:2],
при этом AD[1:0]=00. Сигнал выборки IDSEL# воспринима-
ется устройством только в фазе адреса, поэтому обычно в
качестве него используют старшие биты адреса с позицион-
ным кодированием адреса устройства.

Команды шины PCI определяются значениями бит С/ВЕ# в
фазе адреса в соответствии с табл. 4.5.

С/ВЕ[3:0] | Тип команды
0000 | Interrupt Acknowledge - подтверждение прерывания
0001 | Special Cycle - специальный цикл
0010 | I/O Read - чтение порта ввода/вывода
0011 | I/O Write - запись в порт ввода/вывода
0100 | Зарезервировано
0101 | Зарезервировано
0110 | Memory Read - чтение памяти
0111 | Memory Write - запись в память
1000 | Зарезервировано
1001 | Зарезервировано
1010 | Configuration Read - конфигурационное считывание
1011 | Configuration Write - конфигурационная запись
1100 | Multiple Memory Read - множественное чтение памяти
1101 | Dual Address Cycle - двухадресный цикл
1110 | Memory Read Line - чтение строк памяти
1111 | Memory Write and Invalidate - запись с инвалидацией

В команде подтверждение прерывания контроллер прерыва-
ний передает вектор прерывания по шине AD.

Специальный цикл декодируется содержимым линий AD[15:0]
и используется для указания на отключение (Shutdown), ос-
танов (Halt) процессора или специфические функции процес-
сора, связанные с кэшем и трассировкой. Этим состояниям
соответствуют коды 0000, 0001 и 0002; коды 0003-FFFFh за-
резервированы.

В командах чтения и записи ввода/вывода линии AD содер-
жат адрес байта, причем декодированию подлежат и биты
ADO и AD1 (несмотря на то, что имеются сигналы ВЕх#).
Порты PCI могут быть 8-, 16- или 32-битными. Для адреса-
ции портов на шине PCI доступны все 32 бита адреса, но
процессоры х86 могут использовать только младшие 16 бит.
Порты с адресами OCF8 и OCFC зарезервированы под реги-
стры адреса и данных для доступа к конфигурационному
пространству. Обращение к порту данных приведет к гене-
рации шинного цикла конфигурационного чтения или за-
писи по предварительно записанному адресу.

В командах чтения и записи памяти шина AD содержит ад-
реса двойных слов, и линии ADO, AD1 не должны декодиро-
ваться - на конкретные байты указывают сигналы С/
ВЕ[3:0]#.

Команды конфигурационного чтения и записи адресуются к
конфигурационному пространству и обеспечивают доступ
к 256-байтным структурам. Обращение производится двой-
ными словами. Структура содержит идентификатор устрой-
ства и производителя, состояние и команду, информацию об
используемых ресурсах и ограничения на использование
шины.

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

Двухадресный цикл применяется, когда физическая шина
имеет 32 бита адреса, а требуется передача с 64-битной ад-
ресацией. В этом случае младшие 32 бита адреса передают-
ся в цикле данного типа, а за ним следует обычный цикл,
определяющий тип обмена и несущий старшие 32 бита ад-
реса. Шина PCI допускает 64-битную адресацию даже для
портов ввода/вывода (для х86 это бесполезно, но PCI суще-
ствует и на других платформах).

Чтение строк памяти применяется, когда в транзакции пла-
нируется более двух 32-битных передач (обычно это чтение
до конца строки кэша).

Запись с инвалидацией применяется к целым строкам кэша
и позволяет оптимизировать циклы обратной записи "гряз-
ных" строк кэша.

Выделение специальных циклов множественного чтения,
чтения строк и записи с инвалидацией позволяет контрол-
леру памяти предпринять определенные меры для оптими-
зации данных передач.

Слоты PCI с шагом 0,05 дюйма расположены несколько даль-
ше от задней панели, чем ISA/EISA или МСА. Компоненты
карт PCI расположены на левой поверхности плат. По этой
причине крайний PCI-слот обычно разделяет использование
посадочного места адаптера с соседним ISA-слотом (Shared
slot). Шина имеет версии с питанием 5 В, 33 В и универ-
сальную (с переключением линий +V I/O с 5 В на 3,3 В). Клю-
чами являются пропущенные ряды контактов 12, 13 и 50, 51.
Для слота на 5 В ключ расположен на месте контактов 50, 51;

для 3 В - 12, 13; для универсального - два ключа: 12, 13
и 50, 51. Ключи не позволяют установить карту в слот с не-
подходящим напряжением питания, 32-битный слот закан-
чивается контактами А62/В62, 64-битный - А94/В94. На
рис. 4.10 изображена 32-битная плата максимального размера
(Long Card), длина короткой платы (Short Card) - 6,875".
Плата может иметь обрамление (скобки), стандартное для
конструктива ISA или МСА. Назначение выводов универ-
сального разъема приведено в табл. 4.6, назначение сигна-
лов - в табл. 4.7.

Рис. 4.10. Карта расширения для шины PCI

На одной шине PCI может быть не более четырех устройств
(следовательно, и слотов). Для подключения к другим ши-
нам применяются специальные аппаратные средства - мос-

ты PCI (PCI Bridge). Главный мост (Host Bridge) использу-
ется для подключения PCI к системной шине. Одноранго-
вый мост (Peer-to-Peer Bridge) используется для соединения
двух шин PCI. Несколько шин PCI применяются в серве-
рах - это позволяет увеличить число подключаемых уст-
ройств. Для подключения шин ISA/EISA используются спе-
циальные мосты, входящие в чипсеты системных плат.
Каждый мост программируется - ему указываются диапа-
зоны адресов пространств памяти и ввода/вывода, отведен-
ные устройствам его шин. Если адрес ЦУ текущей транзак-
ции на одной шине (стороне) моста относится к шине
противоположной стороны, мост перенаправляет транзакцию
на соответствующую шину и выполняет действия по согла-
сованию протоколов шин. Таким образом, совокупность мо-
стов PCI выполняет маршрутизацию (routing) обращений по
связанным шинам. Считается, что устройство с конкретным
адресом может присутствовать только на одной из шин, а
на какой именно, "знают" запрограммированные мосты. Ре-
шать задачу маршрутизации призван также сигнал DEVSEL#.
Обращения, не востребованные абонентами PCI, обычно пе-
ренаправляются на шину ISA/EISA.

Ряд В | Nft | РЯДА | Ряд В | N# | РЯДА
-12 В | 1 | TRST# | PRSNT2# | 11 | Reserved
тек | 2 | +12 В | GND/Ключ 3,3В | 12 | GND/Ключ 3,3В
GND | 3 | TMS | GND/Ключ 3,3В | 13 | GND/Ключ 3,3В
TDO | 4 | TDI | Reserved | 14 | Reserved
+5 В | 5 | +5 В | GND | 15 | RST#
+5 В | 6 | INTRA# | Clock | 16 | +VI/0
INTRB# | 7 | INTRC# | GND | 17 | GNT#
INTRD# | 8 | +5 В | REQ# | 18 | GND
PRSNT1# | 9 | Reserved | +VI/0 | 19 | Reserved
Reserved | 10 | +VI/0 | AD 31 | 20 | AD 30

Ряд В | N# | РЯДА | Ряд В | N# | РЯДА
AD 29 | 21 | +3,3 В | GND/Ключ 5В | 50 | GND/Ключ 5В
GND | 22 | AD 28 | GND/Ключ 5В | 51 | GND/Ключ 5В
AD 27 | 23 | AD 26 | AD8 | 52 | С/ВЕО#
AD 25 | 24 | GND | AD7 | 53 | +3,3 В
+3,3 В | 25 | AD 24 | +3,3 В | 54 | AD 6
С/ВЕЗ# | 26 | IDSELff | AD5 | 55 | AD 4
AD 23 | 27 | +3,3 В | AD3 | 56 | GND
GND | 28 | AD 22 | GND | 57 | AD 2
AD 21 | 29 | AD 20 | AD 1 | 58 | ADO
AD 19 | 30 | GND | +VI/0 | 59 | +VI/0
+3.3 В | 31 | AD 18 | АСК64# | 60 | REQ64#
AD 17 | 32 | AD 16 | +5 В | 61 | +5 В
С/ВЕ2# | 33 | +3,3 В | +5 В | 62 | +5 В
GND | 34 | FRAMED | Конец 32-битного разъема
IRDY# | 35 | GND | Reserved | 63 | GND
+3,3 В | 36 | TRDY# | GND | 64 | C/BE7#
DEVSEL# | 37 | GND | С/ВЕ6# | 65 | С/ВЕ5#
GND | 38 | STOP* | С/ВЕ4# | 66 | +VI/0
LOCK* | 39 | +3,3 В | GND | 67 | PAR64
PERR# | 40 | SDONE# | AD63 | 68 | AD 62
+3,3 В | 41 | SDOFF^ | AD61 | 69 | GND
SERR# | 42 | GND | +VI/0 | 70 | AD 60
+3,3 В | 43 | PAR | AD59 | 71 | AD 58
С/ВЕ1# | 44 | AD 15 | AD57 | 72 | GND
AD 14 | 45 | +3,3 В | GND | 73 | AD 56
GND | 46 | AD 13 | AD55 | 74 | AD 54
AD 12 | 47 | AD 11 | AD53 | 75 | +VI/0
AD 10 | 48 | GND | GND | 76 | AD 52
GND/M66EN1 | 49 | AD 9 | AD51 | 77 | AD 50

Ряд В | N" | РЯДА | Ряд В | Ntf | РЯДА
AD 49 | 78 | GND | AD 37 | 87 | GND
+VI/0 | 79 | AD 48 | +VI/0 | 88 | AD 36
AD 47 | 80 | AD 46 | AD 35 | 89 | AD 34
AD 45 | 81 | GND | AD 33 | 90 | GND
GND | 82 | AD 44 | GND | 91 | AD 32
AD 43 | 83 | AD 42 | Reserved | 92 | Reserved
AD 41 | 84 | +VI/0 | Reserved | 93 | GND
GND | 85 | AD 40 | GND | 94 | Reserved
AD 39 | 86 | AD 38 | Конец 64-битного разъема

' Сигнал M66EN определен в PCI 2.1.

Сигнал | Назначение
AD[31:0] | Address/Data - мультиплексированная шина адре- са/данных. В начале транзакции передается адрес, в последующих тактах - данные
C/BE[3:0]# | Command/Byte Enable - команда/разрешение обра- щения к байтам. Команда, определяющая тип оче- редного цикла шины, задается четырехбитным кодом в фазе адреса
FRAME* | Кадр. Введением сигнала отмечается начало тран- закции (фаза адреса), снятие сигнала указывает на то, что последующий цикл передачи данных является последним в транзакции
DEVSEL# | Device Select - устройство выбрано (ответ ЦУ на адресованную ему транзакцию)
IRDY# | Initiator Ready - готовность И У к обмену данными
TRDY# | Target Ready - готовность ЦУ к обмену данными
STOP# | Запрос ЦУ к ИУ на останов текущей транзакции
LOCK# | Используется для установки, обслуживания и освобождения захвата ресурса PCI
REQ# | Request - запрос от PCI-мастера на захват шины
GNT# | Grant - предоставление мастеру управления шиной
PAR | Parity - общий бит паритета для линий AD[31:0] и С/ВЕ[3:0]

Сигнал | Назначение
PERR# | ParityError - сигнал об ошибке паритета (от устрой- ства, ее обнаружившего)
PRSNT[1,2]# | Present - индикаторы присутствия платы, коди- рующие запрос потребляемой мощности
RSTft | Reset - сброс всех регистров в начальное состояние
IDSEL# | Initialization Device Select - выбор устройства в циклах конфигурационного считывания и записи
SERR | System Error - системная ошибка. Активизируется любым устройством PCI и вызывает NMI
REQ64# | Request 64 bit - запрос на 64-битный обмен
ACK64# | Подтверждение 64-битного обмена
INTRA# INTRB# INTRC# INTRD# | Interrupt А, В, С, D - линии запросов прерывания. Циклически сдвигаются в слотах и направляются на доступные линии IRQ. Запрос по низкому уровню допускает разделяемое использование линий
CLK | Clock - тактовая частота шины. Должна быть в пределах 20-33 МГц, в PCI 2.1 - до 66 МГц
M66EN | 66MHzEriable - разрешение частоты синхронизации до 66 МГц
SDONE | Snoop Done - сигнал завершенности цикла слежения для текущей транзакции. Низкий уровень указывает на незавершенность цикла слежения за когерент- ностью памяти и кэша. Необязательный сигнал, ис- пользуется только устройствами шины с кэшируемой памятью
SBO# | Snoop Backoff - попадание текущего обращения к памяти абонента шины в модифицированную строку кэша. Необязательный сигнал, используется только абонентами шины с кэшируемой памятью при алгоритме обратной записи
TCK | Test Clock - синхронизация тестового интерфейса JTAG
TDI | Test Data Input - входные данные тестового интерфейса JTAG
TDO | Test Data Output - выходные данные тестового интерфейса JTAG
TMS | Test Mode Select - выбор режима для тестового интерфейса JTAG
TRST | Test Logic Reset - сброс тестовой логики

Одной из особенностей шины PCI является возможность
обмена данными между процессором и памятью одновремен-
но с обменом между другими устройствами PCI - Concurrent
PCI Transferring. Эта возможность реализуется не всеми чип-
сетами (в описаниях она всегда специально подчеркивает-
ся), а обь1чными устройствами (видеокарты и контроллеры
дисков) используется редко.

С мостами PCI/ISA связано понятие VGA Palette Snooping,
которое обеспечивает исключение из правила однозначной
маршрутизации обращений. Графическая карта в компью-
тере с шиной PCI обычно устанавливается на шину PCI. На
VGA-карте имеются регистры палитр (Palette Registers), при-
писанные к пространству ввода/вывода. Если графическая
система содержит еще и карту смешивания сигналов графи-
ческого адаптера с сигналом "живого видео", перехватывая
двоичную информацию о цвете текущего пиксела по шине
VESA Feature Connector (снимаемую до регистра палитр),
цветовая гамма будет определяться регистром палитр, раз-
мещенным на этой дополнительной карте. Возникает ситуа-
ция, когда операция записи в регистр палитр должна отра-
батываться одновременно и в графическом адаптере (на шине
PCI), и в карте видеорасширения, которая часто размещает-
ся на шине ISA. В BIOS Setup может присутствовать опция
PCI VGA Palette Snoop. При ее разрешении запись в порты
ввода/вывода по адресу регистра палитр будет вызывать
транзакцию как на шине PCI, так и на шине ISA, чтение же
по этим адресам будет выполняться только PCI. Реализа-
ция может возлагаться на графическую карту PCI. Для это-
го она во время записи в регистр палитр фиксирует данные,
но сигналы квитирования DEVSEL# и TRDY# не вырабаты-
вает, в результате чего мост распространяет этот неопознан-
ный запрос на шину ISA. В других реализациях мосту явно
указывают на данное исключение, и он сам распространяет
запись в регистры палитр на шину ISA.

Автоконфигурирование устройств (выбор адресов и преры-
ваний) поддерживается средствами BIOS и ориентировано
на технологию Plug and Play. Стандарт PCI определяет для
каждого слота конфигурационное пространство размером
до 256 8-битных регистров, не приписанных ни к простран-

ству памяти, ни к пространству ввода/вывода. Доступ к ним
осуществляется по специальным циклам шины Configuration
Read и Configuration Write, вырабатываемым контроллером
при обращении процессора к регистрам контроллера шины
PCI, расположенным в его пространстве ввода/вывода. После
аппаратного сброса (или по включении питания) устройства
PCI не отвечают на обращения к пространству памяти и вво-
да/вывода, они доступны только для операций конфигура-
ционного считывания и записи. В этих операциях устрой-
ства"'выбираются по индивидуальным сигналам IDSEL# и
сообщают о потребностях в ресурсах и возможных диапазо-
нах памяти. После распределения ресурсов, выполняемого
программой конфигурирования (во время POST), в устрой-
ства записываются параметры конфигурирования. Только
после этого к устройствам становится возможным доступ по
командам обращения к памяти и портам ввода/вывода.

Для ПЗУ расширения BIOS, установленных на картах PCI,
принят стандарт, несколько отличающийся от традицион-
ных дополнительных модулей ROM BIOS. Поскольку шина
PCI используется не только в PC, в ПЗУ карты может хра-
ниться несколько модулей. Тип платформы (процессора)
указывается в заголовке модуля, и при инициализации
BIOS активизируется нужный. Такой механизм позволяет,
например, один и тот же графический адаптер устанавли-
вать и в IBM PC, и в Power PC.

В состав шины PCI введены сигналы для тестирования адап-
теров по интерфейсу JTAG. На системной плате эти сигналы
задействованы не всегда, но они могут и организовывать ло-
гическую цепочку тестируемых адаптеров.

Некоторые фирмы выпускают для PCI карты-прототипы, но
доукомплектовать их адаптером собственной разработки
сложнее, чем карту ISA. Здесь сказываются сложные прото-
колы и высокие частоты.

Слот PCI достаточен для подключения адаптера (в отличие
от VLB), на системной плате он может сосуществовать с
любой из шин ввода/вывода и даже с VLB. На некоторых
системных платах позади одного из слотов PCI имеется
разъем Media Bus, на который выводятся сигналы ISA. Он

используется для размещения на графическом адаптере PCI
звукового чипсета, предназначенного для шины ISA.

Для устройств промышленного назначения в начале 1995 г.
был принят стандарт Compact PCI. Шина Compact PCI (сРСГ)
разрабатывалась на основе спецификации PCI 2.1. Эта шина
отличается большим количеством поддерживаемых слотов:

8 против 4. Появились новые 4 пары сигналов запросов и
предоставления управления шиной. Шина поддерживает
32-битный и 64-битный обмен (с индивидуальным разреше-
нием байт). При частоте шины 33 МГц максимальная про-
пускная способность составляет 133 Мбайт/с для 32 бит и
266 Мбайт/с для 64 бит (в середине пакетного цикла). Воз-
можна работа на частоте 66 МГц. Шина поддерживает спе-
цификацию РпР. Кроме того, в шине возможно применение
географической адресации, при этом адрес модуля (на кото-
рый он отзывается при программном обращении) определя-
ется его положением в каркасе. Для этого на коннекторе J1
имеются контакты GAO...GA4, коммутацией которых на "зем-
лю" для каждого слота задается его двоичный адрес. Геогра-
фическая адресация позволяет переставлять однотипные мо-
дули, не заботясь о конфигурировании их адресов (хорошая
альтернатива системе РпР - модуль "встанет" всегда в одни
и те же адреса, которые без физического вмешательства боль-
ше не изменятся). Конструктивно платы Compact PCI пред-
ставляют собой еврокарты высотой 3U (100х160 мм) с одним
коннектором (J1) или 6U (233х160 мм) с двумя кон-
некторами (J1 nJ2). Коннекторы - 7-рядные штырьковые
разъемы с шагом 2 мм между контактами, на кросс-плате -
вилка, на модулях - розетки. Контакты коннекторов имеют
разную длину: более длинные контакты цепей питания при
установке модуля соединяются раньше, а при вынимании
разъединяются позже, чем сигнальные. Такое решение по-
зволяет производить "горячую" замену модулей. Собствен-
но шина использует только один коннектор (J1), причем
в 32-битном варианте не полностью - часть контактов мо-
жет задействовать пользователь, 64-битная шина использу-
ет коннектор полностью. Одно посадочное место на кросс-
плате резервируется под контроллер шины, на который
возлагаются функции арбитража и синхронизации. На его

коннекторе шиной используется большее число контактов,
чем на остальных. У больших плат коннектор J2 предостав-
ляется пользователю, а между коннекторами J 1 и J2 может
устанавливаться 95-контактный коннектор J3. Конструкция
коннекторов позволяет для J2 применять специфические мо-
дификации (например, с разделяющим экраном и механи-
ческими ключами). В шине предусматривается наличие не-
зависимых источников питания +5 В, +3,3 В и ±12 В.

На базе шины Compact PCI фирмой National Instruments раз-
работана спецификация PXI (PCI extensions for Instrumenta-
tion - расширение PCI для инструментальных систем) в тех
же конструктивах. В шине PXI часть контактов, определенных
в Compact PCI как свободно используемые, предназначается
для дополнительных шин. Шина Trigger Bus (8 линий) звез-
дообразно соединяет слот своего контроллера (первый после
системного контроллера PCI) с остальными слотами. Шина
позволяет осуществлять синхронизацию разных модулей, что
зачастую требуется в измерительных системах. Для прецизи-
онной синхронизации имеется сигнал опорной частоты 10 МГц
PXI_CLK, который звездообразно (с одинаковыми задержка-
ми распространения сигнала) разводится по слотам. В PXI
определены локальные шины, предназначенные для связи со-
седних пар слотов. Каждая локальная шина имеет 13 линий,
которые могут использоваться как для цифровых, так и для
аналоговых (до 48 В) сигналов. Локальные шины объединя-
ют смежные слоты попарно (исключая слот системного кон-
троллера), образуя цепочку. Кроме механических и электри-
ческих характеристик PXI определяет ПО модулей: основной
ОС считается Windows NT/95, и модули должны поставляться
с соответствующими драйверами. Это экономит время, необ-
ходимое для системной интеграции. Модули PXI совмести-
мы с шиной Compact PCI, и модули Compact PCI - с шиной
PXI. Однако все преимущества спецификации реализуются
только при установке модулей PXI в шину PXI.

4.5. Магистральный интерфейс AGP

В настоящее время самой быстрой универсальной шиной рас-
ширения является PCI, имеющая при тактовой частоте

66 МГц и разрядности 32 бит пиковую пропускную способ-
ность 264 Мбайт/с. Одним из главных потребителей про-
пускной способности шины является графический адаптер.
По мере увеличения разрешения и глубины цвета требова-
ния к пропускной способности шины, связывающей дис-
плейный адаптер с памятью и центральным процессором
компьютера, повышаются. Одно из решений состоит в умень-
шении потока графических данных, передаваемых по шине.
Для этого графические платы снабжают акселераторами и
увеличивают объем видеопамяти, которой пользуется ак-
селератор при выполнении построений. В результате поток
данных в основном циркулирует внутри графической карты,
слабо нагружая внешнюю шину. Однако при трехмерных
построениях акселератору становится тесно в ограниченном
объеме видеопамяти, и его поток данных снова выплескива-
ется на внешнюю шину.

Фирма Intel на базе шины PCI 2.1 разработала новый стан-
дарт подключения графических адаптеров - AGP (Accelerated
Graphic Port - ускоренный графический порт). Этот порт
представляет собой 32-разрядную шину с тактовой частотой
66 МГц, по составу сигналов (табл. 4.8) напоминающую шину
PCI. Чипсет системной платы связывает AGP с памятью и
системной шиной процессора, не пересекаясь с "узким мес-
том" - шиной PCI. "Ускоренность" порта обеспечивается
следующими факторами:

йк конвейеризацией обращений к памяти;

^ сдвоенной передачей данных;

^ демультиплексированием шин адреса и данных.

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

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

РЯДА | № | Ряд В | РЯДА | № | Ряд В
Spare | 1 | 12V | Vddq3.3 | 34 | Vddq3.3
5.0V | 2 | Spare | AD21 | 35 | AD22
5.0V | 3 | Reserved | AD19 | 36 | AD20
USB+ | 4 | USB- | GND | 37 | GND
GND | 5 | GND | AD17 | 38 | AD18
INTB# | 6 | INTA# | C/BE2# | 39 | AD16
CLK | 7 | RST# | Vddq3.3 | 40 | Vddq3.3
RECW | 8 | GNT# | IRDY# | 41 | FRAME#
VCC3.3 | 9 | VCC3.3 |  | 42 |
STO | 10 | ST1 | GND | 43 | GND
ST2 | 11 | Reserved |  | 44 |
RBF# | 12 | PIPE# | VCC3.3 | 45 | VCC3.3
GND | 13 | GND | DEVSEL# | 46 | TRDY#
Spare | 14 | Spare | Vddq3.3 | 47 | STOP#
SBAO | 15 | SBA1 | PERR# | 48 | Spare
VCC3.3 | 16 | VCC3.3 | GND | 49 | GND
SBA2 | 17 | SBA3 | SERR# | 50 | PAR
SBSTB | 18 | Reserved | C/BE1# | 51 | AD15
GND | 19 | GND | Vddq3.3 | 52 | Vddq3.3
SBA4 | 20 | SBA5 | AD14 | 53 | AD13
SBA6 | 21 | SBA7 | AD12 | 54 | AD11
KEY | 22 | KEY | GND | 55 | GND
KEY | 23 | KEY | AD10 | 56 | AD9
KEY | 24 | KEY | AD8 | 57 | C/BEO#
KEY | 25 | KEY | Vddq3.3 | 58 | Vddq3.3
AD31 | 26 | AD30 | ADSTBO | 59 | Reserved
AD29 | 27 | AD28 | AD7 | 60 | AD6
VCC3.3 | 28 | VCC3.3 | GND | 61 | GND
AD27 | 29 | AD26 | ADS | 62 | AD4
AD25 | 30 | AD24 | AD3 | 63 | AD2
GND | 31 | GND | Vddq3.3 | 64 | Vddq3.3
ADSTB1 | 32 | Reserved | AD1 | 65 | ADO
AD23 | 33 | C/BE3# | SMBO | 66 | SMB1

4.5. Магистральный интерфейс AG P 171

Рис. 4.11. Циклы обращения к памяти РС1 и AGP

Сдвоенная передача данных обеспечивает при частоте 66 МГц
пропускную способность до 532 Мбайт/с, что для 32-битной
шины неожиданно. В AGP кроме "классического" режима,
называемого теперь "х1", в котором за один такт синхрони-
зации передается один 4-байтный блок данных, есть режим
".г2", когда блоки данных передаются как по фронту, так и
по спаду сигнала синхронизации (как в АТА Ultra DMA).
Управление передачей в таком режиме названо Sideband
Control (приставка SB к имени сигнала). Заказать режим х2
может только графическая карта, если она его поддержива-
ет. При переходе на тактовую частоту 100 МГц пропускная
способность повышается до 800 Мбайт/с.

Демультиплексирование (разделение) шины адреса и данных
сделано несколько необычным образом. Демультиплексиро-
вание подразумевает наличие двух полноразрядных шин -
адреса и данных. Однако такой вариант дорог. Поэтому шину
адреса в демультиплексированием режиме AGP представля-
ют 8 линий SBA (Sideband Address), по которым за три так-
та синхронизации передаются четыре байта адреса, длина за-
проса (1 байт) и команда (1 байт). За каждый такт
передаются по два байта - один по фронту, другой по спаду
тактового сигнала. Поддержка демультиплексированной
адресации не является обязательной для карты AGP. Требу-
ется также поддержка хост-контроллера. Альтернативным
способом подачи адреса является обычный - по мультиплек-
сированной шине AD.

AGP может реализовать всю пропускную способность 64-бит-
ной системы памяти компьютера на процессорах Pentium и
выше. При этом возможны конкурирующие обращения к

памяти как со стороны процессора, так и со стороны мостов
шин PCI.

Порт AGP может работать как в своем "естественном" ре-
жиме с конвейеризацией и сдвоенными передачами, так и в
режиме шины PCI. В конвейеризированном режиме, в кото-
ром начало цикла отмечается сигналом Р1РЕ#, возможны
только обращения к памяти. В режиме PCI циклы начина-
ются с сигнала FRAME#, и обращения возможны как к про-
странству памяти, так и к пространству ввода/вывода и кон-
фигурационному пространству. Кроме собственно AGP, в
порте AGP заложены сигналы шины USB, которую предпо-
лагается заводить в монитор. Внешне карты с портом AGP
похожи на PCI, но у них используется разъем повышенной
плотности с "двухэтажным" (как у EISA) расположением
ламелей. Сам разъем располагается дальше от задней кром-
ки платы, чем разъем PCI.

Фирма Intel ввела поддержку AGP в чипсеты для процессо-
ров Pentium Pro и Pentium II. Однако нет "противопоказа-
ний" для применения AGP с Pentium.

AGP строился исключительно для графического акселера-
тора. Порт позволяет работать в двух режимах - DMA и
исполнения (Executive Mode). В режиме DMA акселератор
при вычислениях рассматривает видеопамять как первичную,
а когда ее недостаточно, подкачивает данные из основной
памяти. При этом для трафика порта характерны длитель-
ные блочные передачи. В режиме DIME (Direct Memory
Execute) видеопамять и основная память для акселератора
равнозначны и располагаются в едином адресном простран-
стве. Трафик порта при этом будет насыщен короткими про-
извольными запросами.

Отметим, что многие преимущества AGP носят потенциаль-
ный характер и могут быть реализованы лишь при поддержке
аппаратных средств графического адаптера и ПО. Что каса-
ется большой пропускной способности AGP, то следует на-
помнить, что в графических адаптерах с памятью WRAM
или RDRAM внутренняя скорость обмена данными акселе-
ратора с видеопамятью достигает 1,6 Гбайт/с, так что DIME
выигрывает только за счет объема доступной памяти.

4.6. Шины PCMCIA (PC Card)

Организация PCMCIA (Personal Computer Memory Card Inter-
national Association - международная ассоциация производи-
телей карт памяти для персональных компьютеров) ввела ряд
стандартов на шины расширения блокнотных компьютеров.
Первый из них назывался PCIMCIA. Впоследствии он был
переименован в PC Card. Шина PC Card позволяет подклю-
чать расширители памяти, модемы, контроллеры дисков и
стриммеров, SCSI-адаптеры, сетевые адаптеры и т. д. Недо-
статочно строгое следование производителей этому стандар-
ту приводит к проблемам совместимости. Назначение контак-
тов разъема шины приведено в табл. 4.9. Шина адресует
64 Мбайт памяти, разрядность данных 16 бит, частота до
33 МГц, DMA и Bus-Mastering не поддерживаются. Теоре-
тически допускается до 4080 слотов PC Card. Шина ориен-
тирована на программное конфигурирование адаптеров. Боль-
шинство адаптеров выпускаются с поддержкой РпР и
предусматривают "горячее" подключение - интерфейсные кар-
ты могут вставляться и выниматься без выключения компь-
ютера. Для этого контакты шин питания имеют большую дли-
ну, чем сигнальные, чем обеспечивается их упреждающее
подключение и запаздывающее отключение. Два контакта об-
наружения карты (Card Detect) короче остальных. Все уст-
ройства имеют свою поддержку BIOS. Несмотря на возмож-
ность динамического конфигурирования, в некоторых случаях
при изменении конфигурации требуется перезагрузка системы.

Различают 4 типа PC Card. Электрически идентичные, они
варьируются по габаритам при совместимости снизу вверх
(меньшие адаптеры встают в большие гнезда). Адаптер типа 1
имеет размеры 54х85 мм и толщину не более 3,3 мм, типа 2 -
48х75 мм и толщину 5 мм, типа 3 толщину 10,5 мм (однако
HDD типа 3 имеет толщину 13 мм!).

Все устройства PC Card имеют минимальное энергопотреб-
ление. Существуют предпосылки для введения этой шины
как дополнительной в настольные PC.

Шина CardBus с тем же 68-контактным разъемом обеспечи-
вает расширение разрядности данных до 32 бит за счет муль-

типлексирования шины адреса и данных, обеспечивая об-
ратную совместимость с PC Card.

Контакт | Сигнал | Контакт | Сигнал
1 | GND | 35 | GND
2 | Data3 | 36 | Card Detect 1#
3 | Data 4 | 37 | Data 11
4 | Data 5 | 38 | Data 12
5 | Data 6 | 39 | Data 13
6 | Data 7 | 40 | Data 14
7 | Card Enable 1# | 41 | Data 15
8 | Addi-10 | 42 | Card Enable 2#
9 | Out Enable* | 43 | Refresh
10 | Addi-11 | 44 | RFU (IOR#)
11 | Addr9 | 45 | RFU (IOW#)
12 | Addr8 | 46 | Addr17
13 | Addr13 | 47 | Addr 18
14 | Addi-14 | 48 | Addr 19
15 | WrEnable#/Prog# | 49 | Addr 20
16 | Ready/Busyft (IREQ) | 50 | Addr 21
17 | +5 В | 51 | +5 В
18 | Vpp1 | 52 | Vpp2
19 | Addr16 | 53 | Addr 22
20 | Addr 15 | 54 | Addr 23
21 | Addr12 | 55 | Addr 24
22 | Addr 7 | 56 | Addr 25
23 | Addr 6 | 57 | RFU
24 | Addr 5 | 58 | Reset
25 | Addr 4 | 59 | WAIT#
26 | Addr3 | 60 | RFU (INPACK#)
27 | Addr2 | 61 | Register Select*
28 | Addr 1 | 62 | BatVDet2 (SPKR#)
29 | AddrO | 63 | BatVDetl (STSCHG#)
30 | Data 0 | 64 | Data 8
31 | Data 1 | 65 | Data 9
32 | Data 2 | 66 | Data 10
33 | WRProt/(IOCS16#) | 67 | Card Detect 2#
34 | GND | 68 | GND

Для карт памяти (динамической, статической, постоянной
и флэш-памяти) существует стандарт Miniature Card, пред-
ставляющий подмножество шины PC Card. Миниатюрная
карта размером 33х38х3,5 мм с 60-контактным разъемом
через переходный адаптер может устанавливаться и в слот
PC Card типа 2.


2.htm

 Rambler's Top100 Дата последнего обновления файла 22.01.04

2. Последовательные интерфейсы

Последовательный интерфейс для передачи данных использует одну сигнальную линию, по которой информационные биты передаются друг за другом последовательно. Отсюда название интерфейса и порта. Английские термины - Serial Interface и Serial Port (иногда их неправильно переводят как "серийные"). Последовательная передача позволяет сократить количество сигнальных линий и увеличить дальность связи. Характерной особенностью является применение неТТЛ сигналов. В ряде последовательных интерфейсов применяется гальваническая развязка внешних (обычно входных) сигналов от схемной земли устройства, что позволяет соединять устройства, находящиеся под разными потенциалами. Ниже будут рассмотрены интерфейсы RS-232C, RS-422А, RS-423A, RS-485, токовая петля, MIDI, а также СОМ-порт.

2.1. Способы последовательной передачи

Последовательная передача данных может осуществляться в асинхронном или синхронном режимах. При асинхронной передаче каждому байту предшествует старт-бит, сигнализирующий приемнику о начале посылки, за которым следуют биты данных и, возможно, бит паритета (четности). Завершает посылку стоп-бит, гарантирующий паузу межцу посылками (рис. 2.1). Старт-бит следующего байта посылается в любой момент после стоп-бита, то есть между передачами возможны паузы произвольной длительности. Старт-бит, имеющий всегда строго определенное значение (логический 0), обеспечивает простой механизм синхронизации приемника по сигналу от передатчика. Подразумевается, что приемник и передатчик работают на одной скорости обмена. Внутренний генератор синхронизации приемника использует счетчик-делитель опорной частоты, обнуляемый в момент приема начала старт-бита. Этот счетчик генерирует внутренние стробы, по которым приемник фиксирует последующие принимаемые биты. В идеале стробы располагаются в середине битовых интервалов, что позволяет принимать данные и при незначительном рассогласовании скоростей приемника и передатчика. Очевидно, что при передаче 8 бит данных, одного контрольного и одного стоп-бита предельно допустимое рассогласование скоростей, при котором данные будут распознаны верно, не может превышать 5%. С учетом фазовых искажений и дискретности работы внутреннего счетчика синхронизации реально допустимо меньшее отклонение частот. Чем меньше коэффициент деления опорной частоты внутреннего генератора (чем выше частота передачи), тем больше погрешность привязки стробов к середине битового интервала, и требования к согласованности частот становятся более строгими. Чем выше частота передачи, тем больше влияние искажений фронтов на фазу принимаемого сигнала. Взаимодействие этих факторов приводит к повышению требований к согласованности частот приемника и передатчика с ростом частоты обмена.

Рис. 2.1. Формат асинхронной передачи

Формат асинхронной посылки позволяет выявлять возможные ошибки передачи'.

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

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

Для асинхронного режима принят ряд стандартных скоростей обмена: 50, 75, 110, 150, 300, 600, 1200, 2400, 4800, 9600, 19 200, 38 400, 57 600 и 115 200 бит/с. Иногда вместо единицы измерения"бит/с" используют "бод" (baud), но при рассмотрении недвоичных передаваемых сигналов это некорректно. В бодах принято измерять частоту изменения состояния линии, а при недвоичном способе кодирования (широко применяемом в современных модемах) в канале связи скорости передачи бит (бит/с) и изменения сигнала (бод) могут отличаться в несколько раз (подробнее см. в приложении А).

Количество бит данных может составлять 5, 6, 7 или 8 (5- и 6-битные форматы распространены незначительно). Количество стоп-бит может быть 1, 1,5 или 2 ("полтора бита" означает только длительность стопового интервала). Асинхронный обмен в PC реализуется с помощью СОМ-порта с использованием протокола RS-232C.

Синхронный режим передачи предполагает постоянную активность канала связи. Посылка начинается с синхробайта, за которым сразу же следует поток информационных бит. Если у передатчика нет данных для передачи, он заполняет паузу непрерывной посылкой байтов синхронизации. Очевидно, что при передаче больших массивов данных накладные расходы на синхронизацию в данном режиме будут ниже, чем в асинхронном. Однако в синхронном режиме необходима внешняя синхронизация приемника с передатчиком, поскольку даже малое отклонение частот приведет к искажению принимаемых данных. Внешняя синхронизация возможна либо с помощью отдельной линии для передачи сигнала синхронизации, либо с использованием самосинхронизирующего кодирования данных, при котором на стороне приемника из принятого сигнала могут быть выделены импульсы синхронизации. В любом случае синхронный режим требует дорогих линий связи или оконечного оборудования. Для PC существуют специальные платы - адаптеры SDLC (дорогие), поддерживающие синхронный режим обмена. Они используются в основном для связи с большими машинами (mainframes) IBM и мало распространены. Из синхронных адаптеров в настоящее время применяются адаптеры интерфейса V.35.

Рис. 2.2. Стандарты последовательного интерфейса

На физическом уровне последовательный интерфейс имеет различные реализации, различающиеся способом передачи электрических сигналов. Существует ряд родственных международных стандартов: RS-232C, RS-423A, RS-422A и RS-485. На рис. 2.2 приведены схемы соединения приемников и передатчиков, а также показаны ограничения на длину линии (L) и максимальную скорость передачи данных (V).

Несимметричные линии интерфейсов RS-232C и RS-423A имеют самую низкую защищенность от синфазной помехи, хотя дифференциальный вход приемника RS-423A несколько смягчает ситуацию. Лучшие параметры имеет двухточечный интерфейс RS-422A и его магистральный (шинный) аналог RS-485, работающие на симметричных линиях связи. В них для передачи каждого сигнала используются дифференциальные сигналы с отдельной (витой) парой проводов.

В перечисленных стандартах сигнал представляется потенциалом. Существуют последовательные интерфейсы, где информативен ток, протекающий по общей цепи передатчик-приемник - "токовая петля" и MIDI. Для связи на короткие расстояния приняты стандарты беспроводной инфракрасной связи. Наибольшее распространение в PC получил простейший из перечисленных - стандарт RS-232C, реализуемый СОМ-портами. В промышленной автоматике широко применяется RS-485, а также RS-422A, встречающийся и в некоторых принтерах. Существуют преобразователи сигналов для согласования этих родственных интерфейсов.

2.2. Интерфейс RS-232C

Интерфейс предназначен для подключения аппаратуры, передающей или принимающей данные {О ОД - оконечное оборудование данных или АПД - аппаратура передачи данных; DTE - Data Terminal Equipment), к оконечной аппаратуре каналов данных (АКД', DCE - Data Communication Equipment). В роли АПД может выступать компьютер, принтер, плоттер и другое периферийное оборудование. В роли АКД обычно выступает модем. Конечной целью подключения является соединение двух устройств АПД. Полная схема соединения приведена на рис. 2.3. Интерфейс позволяет исключить канал удаленной связи вместе с парой устройств АПД, соединив устройства непосредственно с помощью нульмодемного кабеля (рис. 2.4).

Стандарт описывает управляющие сигналы интерфейса, пересылку данных, электрический интерфейс и типы разъемов. В стандарте предусмотрены асинхронный и синхронный режимы обмена, но СОМ-порты поддерживают только асинхронный режим. Функционально RS-232C эквивалентен стандарту МККТТ V.24/ V.28 и стыку С2, но они имеют различные названия сигналов.

Рис. 2.3. Полная схема соединения по RS-232C

Рис. 2.4. Соединение по RS-232C нуль-модемным кабелем

2.2.1. Электрический интерфейс

Стандарт RS-232C использует несимметричные передатчики и приемники - сигнал передается относительно общего провода - схемной земли (симметричные дифференциальные сигналы используются в других интерфейсах - например, RS-422). Интерфейс НЕ ОБЕСПЕЧИВАЕТ ГАЛЬВАНИЧЕСКОЙ РАЗВЯЗКИ устройств. Логической единице соответствует напряжение на входе приемника в диапазоне -12...-3 В. Для линий управляющих сигналов это состояние называется ON( "включено"), для линий последовательных данных - MARK. Логическому нулю соответствует диапазон +3...+12 В. Для линий управляющих сигналов состояние называется OFF ("выключено"), а для линий последовательных данных - SPACE. Диапазон -3...+3 В - зона нечувствительности, обусловливающая гистерезис приемника: состояние линии будет считаться измененным только после пересечения порога (рис. 2.5). Уровни сигналов на выходах передатчиков должны быть в диапазонах -12...-5 В и +5...+12 В для представления единицы и нуля соответственно. Разность потенциалов между схемными землями (SG) соединяемых устройств должна быть менее 2 В, при более высокой разности потенциалов возможно неверное восприятие сигналов.

Интерфейс предполагает наличие ЗАЩИТНОГО ЗАЗЕМЛЕНИЯ для соединяемых устройств, если они оба питаются от сети переменного тока и имеют сетевые фильтры.

Подключение и отключение интерфейсных кабелей устройств с автономным питанием должно производиться при отключенном питании. Иначе разность не выровненных потенциалов устройств в момент коммутации может оказаться приложенной к выходным или входным (что опаснее) цепям интерфейса и вывести из строя микросхемы.

Рис. 2.5. Прием сигналов RS-232C

Для интерфейса RS-232C специально выпускаются буферные микросхемы приемников (с гистерезисом и передатчиком двуполярного сигнала). При несоблюдении правил заземления и коммутации они обычно являются первыми жертвами "пиротехнических" эффектов. Иногда их устанавливают на разъёмах, что облегчает замену. Цоколевка микросхем формирователей сигналов RS-232C приведена на рис. 2.6. Часто буферные схемы входят прямо в состав интерфейсных БИС. Это удешевляет изделие, экономит место на плате, но в случае аварии оборачивается крупными финансовыми потерями. Вывести из строя интерфейсные микросхемы замыканием сигнальных цепей маловероятно: ток короткого замыкания передатчиков обычно не превосходит 20 мА.

Рис. 2.6. Формирование сигналов RS-232C: а - приемник 1489 (А - вход RS-232, С - управление гистерезисом (ТТЛ), Y - выход ТТЛ); б - передатчик 1488 (А, В - входы ТТЛ, Y - выход RS-232, VDD = +12 В, VEE = -12 В); в - таблица состояния выходов передатчика (*1В - логическая 1)

Стандарт RS-232C регламентирует типы применяемых разъемов.

На аппаратуре АПД (в том числе на СОМ-портах) принято устанавливать вилки (male - "папа") DB-25P или более компактный вариант - DB-9P. Девятиштырьковые разъемы не имеют контактов для дополнительных сигналов, необходимых для синхронного режима (в большинстве 25-штырьковых разъемов эти контакты не используются).

На аппаратуре АКД (модемах) устанавливают розетки (female - "мама") DB-25S или DB-9S.

Это правило предполагает, что разъемы АКД могут подключаться к разъемам АПД непосредственно или через переходные "прямые" кабели с розеткой и вилкой, у которых контакты соединены "один в один". Переходные кабели могут являться и переходниками с 9- на 25- штырьковые разъемы (рис. 2.7).

Рис. 2.7. Кабели подключения модемов

Если аппаратура АПД соединяется без модемов, то разъемы устройств (вилки) соединяются между собой нуль-модемным кабелем (Zero-modem или Z-modem), имеющим на обоих концах розетки, контакты которых соединяются перекрестно по одной из схем, приведенных на рис. 2.8.

Рис. 2.8. Нуль-модемный кабель: а - минимальный, б - полный

Если на каком-либо устройстве АПД установлена розетка - это почти стопроцентный признак того, что к другому устройству оно должно подключаться прямым кабелем, аналогичным кабелю подключения модема. Розетка устанавливается обычно на тех устройствах, у которых удаленное подключение через модем не предусмотрено.

В табл. 2.1 приведено назначение контактов разъемов СОМ - портов (и любой другой аппаратуры АПД). Контакты разъема DB-25S определены стандартом EIA/TIA-232-E, разъем DB-9S описан стандартом EIA/ TIA-574. У модемов название цепей и контактов такое же, но роли сигналов (вход-выход) меняются на противоположные.

Подмножество сигналов RS-232C, относящихся к асинхронному режиму, рассмотрим с точки зрения СОМ-порта PC. Следует помнить, что активному состоянию сигнала ("включено") и логической единице передаваемых данных соответствует отрицательный потенциал (ниже -3 В) сигнала интерфейса, а состоянию "выключено" и логическому нулю - положительный (выше +3 В). Назначение сигналов интерфейса приведено в табл. 2.2.

Обозначение цепи |  | Контакт разъема |  | № провода кабеля выносного разъёма РС |  |  |  | Направление I/O
RS-232 | Стык 2 | DB-25S | DB-9S | 1* | 2* | 3* | 4*
PG | 101 | 7 | 5 | (10) | (10) | (10) | 1 | -
SG | 102 | 7 | 5 | 5 | 9 | 1 | 13 | -
TD | 103 | 2 | 3 | 3 | 5 | 3 | 3 | 0
RD | 104 | 3 | 2 | 2 | 3 | 4 | 5 | I
RTS | 105 | 4 | 7 | 7 | 4 | 8 | 7 | 0
CTS | 106 | 5 | 8 | 8 | 6 | 7 | 9 | I
DSR | 107 | 6 | 6 | 6 | 2 | 9 | 11 | I
DTR | 108/2 | 20 | 4 | 4 | 7 | 2 | 14 | 0
DCD | 109 | 8 | 1 | 1 | 1 | 5 | 15 | I
RI | 125 | 22 | 9 | 9 | 8 | 6 | 18 | I

1*- шлейф 8-битных мультикарт.
2*- шлейф 16-битных мультикарт и портов на системных платах.
3* - вариант шлейфа портов на системных платах.
4*- широкий шлейф к 25-контактному разъему.

Сигнал | Назначение
PG | Protected Ground - защитная земля, соединяется с корпусом устройства и экраном кабеля
SG | Signal Ground - сигнальная (схемная) земля, относительно которой действуют уровни сигналов
ТО | Transmit Data - последовательные данные - выход передатчика
RD | Receive Data - последовательные данные - вход приемника
RTS | Request To Send - выход запроса передачи данных: состояние "включено" уведомляет модем о наличии у терминала данных для передачи. В полудуплексном режиме используется для управления направлением - состояние "включено" служит сигналом модему на переключение в режим передачи
CTS | Clear To Send - вход разрешения терминалу передавать данные. Состояние "выключено" аппаратно запрещает передачу данных. Сигнал используется для аппаратного управления потоками данных
DSR | Data Set Ready - вход сигнала готовности от аппаратуры передачи данных (модем в рабочем режиме подключен к каналу и закончил действия по согласованию с аппаратурой на противоположном конце канала)
DTP | Data Terminal Ready - выход сигнала готовности терминала к обмену данными. Состояние "включено" поддерживает коммутируемый канал в состоянии соединения
DCD | Data Carrier Detected - вход сигнала обнаружения несущей удаленного модема
RI | Ring Indicator - вход индикатора вызова (звонка). В коммутируемом канале этим сигналом модем сигнализирует о принятии вызова

2.2.2. Управление потоком данных

Для управления потоком данных (Flow Control) могут использоваться два варианта протокола - аппаратный и программный. Иногда управление потоком путают с квитированием, но это разные методы достижения одной цели - согласования темпа передачи и приема. Квитирование (Handshaking) подразумевает посылку уведомления о получении элемента, в то время как управление потоком предполагает посылку уведомления о невозможности последующего приема данных.

Аппаратный протокол управления потоком RTS/CTS (Hardware Flow Control) использует сигнал CTS, который позволяет остановить передачу данных, если приемник не готов к их приему (рис. 2.9). Передатчик "выпускает" очередной байт только при включенной линии CTS. Байт, который уже начал передаваться, задержать сигналом CTS невозможно (это гарантирует целостность посылки). Аппаратный протокол обеспечивает самую быструю реакцию передатчика на состояние приемника. Микросхемы асинхронных приемопередатчиков имеют не менее двух регистров в приемной части сдвигающий, для приема очередной посылки, и хранящий, из которого считывается принятый байт. Это позволяет реализовать обмен по аппаратному протоколу без потери данных.

Рис. 2.9. Аппаратное управление потоком

Аппаратный протокол удобно использовать при подключении принтеров и плоттеров, если они его поддерживают (рис. 2.10). При непосредственном (без модемов) соединении двух компьютеров аппаратный протокол требует перекрестного соединения линий RTS - CTS.

Если аппаратный протокол не используется, у передающего терминала должно быть обеспечено состояние "включено" на линии CTS перемычкой RTS - CTS. В противном случае передатчик будет "молчать".

Рис. 2.10. Кабель подключения принтера с протоколом RTS-CTS

Программный протокол управления потоком XON/XOFF предполагает наличие двунаправленного канала передачи данных. Работает протокол следующим образом: если устройство, принимающее данные, обнаруживает причины, по которым не может их дальше принимать, оно по обратному последовательному каналу посылает байт-символ XOFF (13h). Противоположное устройство, приняв этот символ, приостанавливает передачу. Когда принимающее устройство снова становится готовым к приему данных, оно посылает символ XON (13h), приняв который противоположное устройство возобновляет передачу. Время реакции передатчика на изменение состояния приемника по сравнению с аппаратным протоколом увеличивается по крайней мере на время передачи символа (XON или XOFF) плюс время реакции программы передатчика на прием символа (рис. 2.11). Из этого следует, что данные без потерь могут приниматься только приемником, имеющим дополнительный буфер принимаемых данных и сигнализирующим о неготовности заблаговременно (имея в буфере свободное место).

Рис. 2.11. Программное управление потоком XON/XOFF

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

Кроме этих двух распространенных стандартных протоколов, поддерживаемых и ПУ, и ОС, существуют и другие. Некоторые плоттеры с последовательным интерфейсом используют программное управление, но посылают не стандартные символы XON/XOFF, а слова (ASCII-строки). Такой обмен на уровне системной поддержки протокола практически не поддерживается (эти плоттеры непосредственно "разговаривают" с прикладной программой). Конечно, можно написать драйвер СОМ-порта (перехватчик INT 14h), но необходимость обработки в нем текстовых сообщений от устройства вывода обычно не вызывает восторга у системного программиста. Кабель для подключения совпадает с приведенным на рис. 2.12.

Рис. 2.12. Кабель подключения принтера по протоколу XON/XOFF

2.3. Интерфейс "токовая петля"

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

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

Токовая петля с гальванической развязкой позволяет передавать сигналы на расстояния до нескольких километров. Расстояние определяется сопротивлением пары проводов и уровнем помех. Поскольку интерфейс требует пары проводов для каждого сигнала, обычно используют только два сигнала интерфейса. В случае двунаправленного обмена применяются только сигналы передаваемых и принимаемых данных, а для управления потоком используется программный метод XON/XOFF. Если двунаправленный обмен не требуется, используют одну линию данных, а для управления потоком обратная линия задействуется для сигнала CTS (аппаратный протокол) или встречной линии данных (программный протокол).

Преобразовать сигналы RS-232C в токовую петлю можно с помощью несложной схемы (рис. 2.13). Здесь принтер подключается по токовой петле к СОМ-порту с аппаратным управлением потоком. Для получения двуполярного сигнала, требуемого для входных сигналов СОМ-порта, применяется питание от интерфейса.

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

Рис. 2.13. Подключение принтера с интерфейсом "токовая петля" к СОМ-порту

2.4. Интерфейс MIDI

Цифровой интерфейс музыкальных инструментов MIDI (Musical Instrument Digital Interface) является двунаправленным последовательным асинхронным интерфейсом с частотой передачи 31,25 Кбит/с. Этот интерфейс, разработанный в 1983 году, стал фактическим стандартом для сопряжения компьютеров, синтезаторов, записывающих и воспроизводящих устройств, микшеров, устройств специальных эффектов и другой электромузыкальной техники.

В интерфейсе применяется токовая петля 10 мА (возможно 5 мА) с гальванической развязкой входной цепи. Это исключает связь "схемных земель" соединяемых устройств через интерфейсный кабель, устраняя помехи, крайне нежелательные для звуковой техники. Снижению интерференционных помех служит и выбор частоты передачи, которая совпадает с одним из значений частот квантования, принятых в цифровой звукозаписи.

Асинхронная посылка содержит старт-бит, 8 бит информации и 1 стоп-бит, контроль четности отсутствует. Старший бит посылки является признаком "команда/данные". Его нулевое значение указывает на наличие семи бит данных в младших разрядах. При единичном значении биты [6:4] содержат код команды, а биты [3:0] - номер канала. Команды могут быть как адресованными конкретному каналу, так и широковещательными безадресными. К последней группе относятся команды старта, стопа и отметки времени, обеспечивающие синхронизацию устройств (система синхронизации MIDI Sync и МТС - MIDI Time Code).

Интерфейс определяет три типа портов: MIDI-In, MIDI-Out и MIDI-Thru.

Входной порт MIDI-In представляет собой вход интерфейса "токовая петля 10 мА", гальванически развязанного от приемника оптроном с быстродействием не хуже 2 мкс. Устройство отслеживает информационный поток на этом входе и реагирует на адресованные ему команды и данные.

Выходной порт MIDI-Out представляет собой выход источника тока 10 мА, гальванически связанного со схемой устройства. Ограничительные резисторы предохраняют выходные цепи от повреждения при замыкании на землю или источник 5 В. На выход подается информационный поток от данного устройства. В потоке может содержаться и транслированный входной поток.

Транзитный порт MIDI-Thru (не обязателен) служит для ретрансляции входного сигнала.

В качестве разъемов применяются 5-контактные разъемы DIN, распространенные в бытовой звуковой аппаратуре. На всех устройствах устанавливаются розетки, на кабелях - вилки. Все соединительные кабели MIDI унифицированы (рис. 2.14). Контакт 2 - экран кабеля - соединяется с общим проводом только на стороне передатчика (на разъемах MIDI-Out и MIDI-Thru).

Рис. 2.14. Соединительные кабели MIDI

В маркировке входов и выходов, указанной около разъемов, бывают разночтения. Одни производители пишут "In" или "Out" в соответствии с функцией разъема данного устройства (и это, правильно), тогда любой кабель соединяет "In" и "Out". Другие считают, что подпись должна обозначать функцию подключаемого устройства. Тогда кабель будет соединять разъемы с обозначениями "In" - "In" и "Out" - "Out".

Интерфейс позволяет объединить группу до 16 устройств в локальную сеть. Топология должна подчиняться правилу: вход MIDI-In одного устройства должен подключаться к выходу MIDI-Out или MIDI-Thru другого. При планировании MIDI-сети необходимо руководствоваться информационными потоками и связью устройств. Управляющие устройства - клавиатуры, секвенсоры (в режиме воспроизведения), источники синхронизации - должны находиться перед управляемыми. Если устройства нуждаются в двунаправленном обмене, они соединяются в кольцо. Возможно применение специальных мультиплексоров, позволяющих логически коммутировать несколько входных потоков в один выходной. Вырожденным случаем кольца является двунаправленное соединение двух устройств. Несколько вариантов соединения приведено на рис. 2.15.

В PC MIDI-порт имеется на большинстве звуковых адаптеров, его сигналы выведены на неиспользуемые контакты (12 и 15) разъема игрового адаптера. Для подключения устройств MIDI требуется переходной адаптер, реализующий интерфейс "токовая петля". Переходной адаптер обычно встраивается в специальный кабель, схема которого приведена на рис. 2.16. Некоторые модели PC имеют встроенные адаптеры и стандартные 5-штырьковые разъемы MIDI.

Рис. 2.15. Варианты топологии сети MIDI: a - цепь, б - кольцо с мультиплексором

В PC для интерфейса MIDI применяются порты, совместимые с контроллером MPU-401 (Roland) в режиме UART. В пространстве ввода/вывода MPU-401 занимает два смежных адреса MPU (обычно 330h) и МРU+1:

  • Порт DATA (адрес MPU+0) - запись и считывание байт, передаваемых и принимаемых по интерфейсу MIDI.
  • Порт STATUS/COMMAND (адрес MPU+1) - чтение состояния / запись команд (запись - только для интеллектуального режима). В байте состояния определены следующие биты:
  1. Бит 7 - DSR (Data Set Ready) - готовность (DSR=0) принятых данных для чтения. Бит устанавливается в единицу, когда все принятые байты считаны из регистра данных.
  2. Бит 6 - DRR (Data Read Ready) - готовность (DRR=0) UART к записи в регистр данных или команд. Условие готовности к записи не возникнет, если приемник имеет непрочитанный байт данных.

Рис. 2.16. Вариант схемы кабеля-адаптера MIDI

На некоторых системных платах применяются БИС контроллеров интерфейсов, в которых UART, используемая для СОМ-порта, конфигурированием через BIOS SETUP может быть переведена в режим MIDI- порта.

2.5. СОМ-порт

Последовательный интерфейс СОМ-порт (Communication Port - коммуникационный порт) появился в первых моделях IBM PC. Он был реализован на микросхеме асинхронного приемопередатчика Intel 8250. Порт имел поддержку BIOS (INT 14h), однако широко применялось (и применяется) взаимодействие с портом на уровне регистров. Поэтому во всех PC-совместимых компьютерах для последовательного интерфейса применяют микросхемы приемопередатчиков, совместимые с I8250. В ряде отечественных PC- совместимых (почти) компьютеров для последовательного интерфейса применялась микросхема КР580ВВ51 - аналог I8251. Однако эта микросхема является универсальным синхронно-асинхронным приемопередатчиком (УАПП или UART - Universal Asynchronous Receiver-Transmitter). Совместимости с PC на уровне регистров СОМ-порта такие компьютеры не имеют. Хорошо, если у соответствующих компьютеров имеется "честный" драйвер BIOS INT 14h, а не заглушка, возвращающая состояние модема "всегда готов" и ничего не делающая. Совместимость на уровне регистров СОМ-порта считается необходимой. Многие разработчики коммуникационных пакетов предлагают работу и через BIOS INT 14h, однако на высоких скоростях это неэффективно. Говоря о СОМ - порте PC, по умолчанию будем подразумевать совместимость регистровой модели с I8250 и реализацию асинхронного интерфейса RS-232C.

2.5.1. Использование СОМ-портов

СОМ-порты чаще всего применяют для подключения манипуляторов (мышь, трекбол). В этом случае порт используется в режиме последовательного ввода; питание производится от интерфейса. Мышь с последовательным интерфейсом - Serial Mouse -может подключаться к любому исправному порту. Для согласования разъемов порта и мыши возможно применение переходника DB-9S-DB-25P или DB-25S-DB- 9P. Для мыши требуется прерывание, для порта СОМ1 - IRQ4, для COM2 - IRQ3. Жесткая привязка номера IRQ к номеру порта обусловлена свойствами драйверов. Каждое событие - перемещение мыши или нажатие-отпускание кнопки - кодируется двоичной посылкой по интерфейсу RS-232C. Применяется асинхронная передача; двуполярное питание обеспечивается от управляющих линий интерфейса (табл. 2.3).

Сигнал | Контакты
 | DB-9 | DB-25
Data | 2 | 3
GND | 5 | 7
+V (питание) | 4,7 | 4,20
-V (питание) | 3 | 9

Две разновидности Serial Mouse - MS-Mouse и PC-Mouse (Mouse Systems Mouse) - требуют соответствующих драйверов, многие мыши имеют переключатель MS/PC. Мышь с "чужим" драйвером либо не отзывается, либо "скачет" загадочным образом. Эти разновидности используют различные форматы посылок: при одинаковой скорости 1200 бит/с, одном стоп-бите и отсутствии контроля четности Microsoft Mouse использует 7 бит данных, a PC-Mouse - 8 бит. Мышь посылает пакет при каждом изменении состояния - перемещении, нажатии или отпускании кнопки. Пакет, передаваемый MS-Mouse, состоит из трех байт (табл. 2.4). PC-Mouse передает 5 байт (табл. 2.5). Здесь LB (Left Buttom), MB (Middle Buttom) и RB (Right Buttom) означают состояние левой, средней и правой кнопок, Х[7:0] и Y[7:0] - биты относительного перемещения мыши с момента предыдущей посылки по координатам Х и Y. Положительным значениям соответствует перемещение по координате Х вправо, а по координате Y вниз для MS-Mouse и вверх для PC-Mouse. Отсюда становятся понятными беспорядочные перемещения курсора на экране при несоответствии драйвера типу мыши.

Биты | D6 | D5 | D4 | D3 | D2 | D1 | D0
1-й байт | 1 | LB | RB | Y7 | Y6 | Х7 | Х6
2-й байт | 0 | Х5 | Х4 | Х3 | Х2 | Х1 | X0
3-й байт | 0 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0

Биты | D7 | Dб | D5 | D4 | D3 | D2 | D1 | D0
1-й байт | 1 | 0 | 0 | 0 | 0 | LB | MB | RB
2-й байт | Х7 | Х6 | Х5 | Х4 | ХЗ | Х2 | Х1 | ХО
3-й байт | Y7 | Y6 | Y5 | Y4 | Y3 | Y2 | Y1 | YO
4-й байт | Совпадает со 2-м байтом
5-й байт | Совпадает с 3-м байтом

Для подключения внешних модемов используется полный (9-проводный) кабель АПД-АКД, схема которого приведена на рис. 2.7. Этот же кабель используется для согласования разъемов (по количеству контактов); возможно применение переходников 9-25, предназначенных для мышей. Для работы коммуникационного ПО обычно требуется использование прерываний, но здесь есть свобода выбора номера (адреса) порта и линии прерывания. Если предполагается работа на скоростях 9600 бит/с и выше, то СОМ-порт должен быть реализован на микросхеме UART 16550A или совместимой. Возможности работы с использованием FIFO-буферов и обмена по каналам DMA зависят от коммуникационного ПО.

Для связи двух компьютеров, удаленных друг от друга на небольшое расстояние, используют и непосредственное соединение их СОМ-портов нуль-модемным кабелем (рис. 2.8). Использование программ типа Norton Commander или Interink MS-DOS позволяет обмениваться файлами со скоростью до 115,2 Кбит/с без применения аппаратных прерываний. Это же соединение может использоваться и сетевым пакетом Lantastic, предоставляющим более развитый сервис.

Подключение принтеров и плоттеров к СОМ-порту требует применения кабеля, соответствующего выбранному протоколу управления потоком: программному XON/XOFF или аппаратному RTS/CTS. Схемы кабелей приведены на рис. 2.10 и 2.12. Аппаратный протокол предпочтительнее. Прерывания при выводе средствами DOS (командами COPY или PRINT) не используются.

СОМ-порт используется для подключения электронных ключей (Security Devices), предназначенных для защиты от нелицензированного использования ПО. Эти устройства могут быть как "прозрачными", позволяя воспользоваться тем же портом для подключения периферии, так и полностью занимающими порт.

СОМ-порт при наличии соответствующей программной поддержки позволяет превратить PC в терминал, эмулируя систему команд распространенных специализированных терминалов (VT-52, VT-100 и т. д.). Простейший терминал получается, если замкнуть друг на друга функции BIOS обслуживания СОМ-порта (INT 14h), телетайпного вывода (INT 10h) и клавиатурного ввода (INT 16h). Однако такой терминал будет работать лишь на малых скоростях обмена (если, конечно, его делать не на Pentium), поскольку функции BIOS хоть и универсальны, но не слишком быстры.

Интерфейс RS-232C широко распространен в различных ПУ и терминалах. СОМ-порт может использоваться и как двунаправленный интерфейс, у которого имеется 3 программноуправляемые выходные линии и 4 программно-читаемые входные линии с двуполярными сигналами. Их использование определяется разработчиком. Существует, например, схема однобитного широтно-импульсного преобразователя, позволяющего записывать звуковой сигнал на диск PC, используя входную линию СОМ-порта. Воспроизведение этой записи через обычный динамик PC позволяет передать речь. В настоящее время, когда звуковая карта стала почти обязательным устройством PC, это не впечатляет, но когдато такое решение было интересным.

СОМ-порт используют для беспроводных коммуникаций с применением излучателей и приемников инфракрасного диапазона - IR (Infra Red) Connection. Этот интерфейс позволяет осуществлять связь между парой устройств, удаленных на расстояние, достигающее нескольких метров. Различают инфракрасные системы низкой (до 115,2 Кбит/с), средней (1,152 Мбит/с) и высокой (4 Мбит/с) скорости. Низкоскоростные системы служат для обмена короткими сообщениями, высокоскоростные - для обмена файлами между компьютерами, подключения к компьютерной сети, вывода на принтер, проекционный аппарат и т. п. Ожидаются более высокие скорости обмена, которые позволят передавать "живое видео". В 1993 году создана ассоциация разработчиков систем инфракрасной передачи данных IrDA (Infrared Data Association), призванная обеспечить совместимость оборудования от различных производителей. В настоящее время действует стандарт IrDA 1.1. Имеются собственные системы фирм Hewlett Packard - HP-SIR (Hewlett Packard Slow Infra Red) - и Sharp - ASK (Amplitude Shifted Keyed IR). Основные характеристики интерфейсов следующие:

  • IrDA SIR (Slow Infra Red), HP-SIR - 9,6-115,2 Кбит/с;
  • IrDA MIR (Middle Infra Red) - 1,2 Мбит/с;
  • IrDA FIR (Fast Infra Red) - 4 Мбит/с;
  • Sharp ASK - 9,6-57,6 Кбит/с.

На скоростях до 115 200 бит/с для инфракрасной связи ис пользуются UART, совместимые с 16450/ 16550. В современных системных платах на использование инфракрасной связи может конфигурироваться порт COM2. В этом случае на переднюю панель компьютера устанавливается внешний приемопередатчик - "инфракрасный глаз", который подключается к разъему IR-Connector системной платы.

На средних и высоких скоростях обмена применяются специализированные микросхемы, ориентированные на интенсивный программно-управляемый обмен или DMA с возможностью прямого управления шиной.

Инфракрасные излучатели не создают помех в радиочастотном диапазоне и обеспечивают конфиденциальность передачи. ИК-лучи не проходят через стены, поэтому зона приема ограничивается небольшим легко контролируемым пространством. Инфракрасная технология привлекательна для связи портативных компьютеров со стационарными компьютерами или док-станциями. Инфракрасный интерфейс имеют некоторые модели принтеров.

2.5.2. Микросхемы асинхронных приемопередатчиков

Преобразование параллельного кода в последовательный для передачи и обратное преобразование при приеме данных выполняют специализированные микросхемы UART (Universal Asynchronous Receiver- Transmitter - универсальный асинхронный приемопередатчик). Эти же микросхемы формируют и обрабатывают управляющие сигналы интерфейса. СОМ-порты IBM PC XT/AT базируются на микросхемах, совместимых на уровне регистров с UART 18250 - 8250/16450/16550А. Это семейство представляет собой усовершенствование начальной модели, направленное на повышение быстродействия, снижение потребляемой мощности и загрузки процессора при интенсивном обмене. Отметим следующее:

  • 8250 имеет ошибки (появление ложных прерываний), учтенные в XT BIOS.
  • 8250А - ошибки исправлены, в результате чего потеряна совместимость с BIOS. Работает в некоторых моделях AT, но непригоден для скорости 9600 бит/с.
  • 8250В - исправлены ошибки 8250 и 8250А, восстановлена ошибка в прерываниях - возвращена совместимость с XT BIOS. Работает в AT под DOS (кроме скорости 9600 бит/с).

Микросхемы 8250х имеют невысокое быстродействие по обращениям со стороны системной шины. Они не допускают обращения к своим регистрам в смежных шинных циклах процессора - для корректной работы с ними требуется введение программных задержек между обращениями CPU.

В компьютерах класса AT применяют микросхемы UART следующих модификаций:

  • 16450 - быстродействующая версия 8250 для AT. Ошибок 8250 и полной совместимости с XT BIOS не имеет. Требуется для работы OS/2 с СОМ-портами.
  • 16550 - развитие 16450. Может использовать канал DMA для обмена данными. Имеет FIFO-буфер, но некорректность его работы не позволяет им воспользоваться.
  • 16550А - имеет работающие 16-байтные FIFO-буферы приема и передачи и возможность использования DMA. Именно этот тип UART должен применяться в AT при интенсивных обменах на скоростях 9600 бит/с и выше. Совместимость с этой микросхемой обеспечивает большинство микросхем контроллеров портов ввода/вывода, входящих в современные чипсеты.

Микросхемы UART 16550А с программной точки зрения представляют собой набор регистров, доступ к которым определяется адресом (смещением адреса регистра относительно базового адреса порта) и значением бита DLAB (бита 7 регистра LCR). В адресном пространстве микросхема занимает 8 смежных адресов. Список регистров UART 16550А и способы доступа к ним приведены в табл. 2.6. Микросхемы 8250 отличаются отсутствием регистра FCR и всех возможностей FIFO и DMA.

Доступ |  | Регистр |  | Чтение/запись R/W
Смещение | DLAB | Имя | Название
0h | 0 | THR | Transmit Holding Register | W
0h | 0 | RBR | Receiver Buffer Register | R
0h | 1 | DLL | Divisor Latch LSB | R/W
1h | 1 | DLM | Divisor Latch MSB | R/W
1h | 0 | IER | Interrupt Enable Register | R/W
2h | X | IIR | Interrupt Identification Register | R
2h | X | FCR | FIFO Control Register | W
3h | X | LCR | Line Control Register | R/W
4h | X | MCR | Modem Control Register | R/W
5h | X | LSR | Line Status Register | R/W*
6h | X | MSR | Modem Status Register | R/W*
7h | X | SCR | Scratch Pad Register | R/W

* Некоторые биты допускают только чтение. Запись в регистр может привести к сбою протокола.

THR - промежуточный регистр данных передатчика (только для записи). Данные, записанные в регистр, будут пересланы в выходной сдвигающий регистр (когда он будет свободен), из которого поступят на выход при наличии разрешающего сигнала CTS. Бит 0 передается (и принимается) первым. При длине посылки менее 8 бит старшие биты игнорируются.

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

DLL - регистр младшего байта делителя частоты.

DLM - регистр старшего байта делителя частоты. Делитель определяется по формуле D=115200/V, где V - скорость передачи, бит/с. Входная частота синхронизации 1,8432 МГц делится на заданный коэффициент, после чего получается 16-кратная частота передачи данных.

IER - регистр разрешения прерываний. Единичное значение бита разрешает прерывание от соответствующего источника.

Назначение бит регистра IER:

  • Биты 7-4=0 - не используются.
  • Бит 3 - Mod IE - по изменению состояния модема (любой из линий CTS, DSR, Rl, DCD).
  • Бит 2 - RxL IE - по обрыву/ошибке линии.
  • Бит 1 - TxD IE - по завершении передачи.
  • Бит 0 - RxD IE - по приему символа (в режиме FIFO - прерывание по тайм-ауту).

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

Назначение бит регистра IIR:

  • Биты [7:6] - признак режима FIFO:
    • 11 -режим FIFO 16550A,
    • 10 - режим FIFO 16550,
    • 00 - обычный.
  • Биты [5:4] - не используются.
  • Бит 3 - прерывание по тайм-ауту (не в режиме FIFO).
  • Биты [2:1] - причина прерывания с наивысшим приоритетом (в обычном, не FIFO-режиме):
    • 11 - ошибка/обрыв линии, сброс выполняется чтением регистра состояния линии,
    • 10 - принят символ; сброс - чтением данных,
    • 01 - передан символ (регистр THR пуст); сброс - записью данных,
    • 00 - изменение состояния модема; сброс - чтением регистра состояния модема.
  • Бит 0 - признак необслуженного запроса прерывания:
    • 1 - нет запроса,
    • 0 -есть запрос.

В режиме FIFO причину прерываний идентифицируют биты IIR [3:1]:

  • 011 - ошибка/обрыв линии; сброс - чтением регистра состояния линии.
  • 010 - принят символ; сброс - чтением регистра данных приемника.
  • 110 - индикатор тайм-аута (за 4-кратный интервал времени символа не передано и не принято ни одного символа, хотя в буфере имеется по крайней мере один). Сброс - чтением регистра данных приемника.
  • 001 - регистр THR пуст; сброс - записью данных.
  • 000 - изменение состояния модема (CTS, DSR, RI или DCD), сброс - чтением регистра MSR.

FCR - регистр управления FIFO (только для записи).

Назначение бит регистра FCR:

  • Биты [7:6] - ITL (Interrupt Trigger Level) - уровень заполнения FIFO-буфера, при котором вырабатывается прерывание:
    • 00-1 байт (по умолчанию),
    • 01-4 байта,
    • 10 -8байт,
    • 11 -14 байт.
  • Биты [5:4] зарезервированы.
  • Бит 3 - разрешение операций DMA.
  • Бит 2 -RESETTF(Reset Transmitter FIFO) - сброс счетчика FIFO-передатчика (записью единицы сдвигающий регистр не сбрасывается).
  • Бит 1 - RESETRF(Reset Receiver FIFO) - сброс счетчика FIFO-приемника (записью единицы сдвигающий регистр не сбрасывается).
  • Бит 0 - TRFIFOE(Transmit And Receive FIFO Enable) - разрешение (единицей) режима FIFO для передатчика и приемника. При смене режима FIFO-буферы автоматически очищаются.

LCR - регистр управления линией (настройки параметров канала).

Назначения бит регистра LCR:

  • Бит 7 - DLAB (Divisor Latch Access Bit) - управление доступом к делителю частоты.
  • Бит 6 - BRCON( Break Control) - формирование обрыва линии (посылка нулей) при BRCON=1.
  • Бит 5 - STICPAR (Sticky Parity) - принудительное формирование бита паритета:
    • 0 - контрольный бит генерируется в соответствии с паритетом выводимого символа,
    • 1 - постоянное значение контрольного бита: при EVENPAR=1 - нулевое, при EVENPAR=0 - единичное.
  • Бит 4 - EVENPARf Even Parity Select) - выбор типа контроля: 0 - нечетность, 1 - четность.
  • Бит 3 - PAREN( Parity Enable) - разрешение контрольного бита:
    • 1 - контрольный бит (паритет или постоянный) разрешен,
    • 0 - запрещен.
  • Бит 2 - STOPS (Stop Bits) - количество стоп-бит:
    • 0-1 стоп-бит,
    • 1-2 стоп-бита (для 5-битного кода стоп-бит будет иметь длину 1,5 бита).
  • Биты [1:0] - SERIALDB (Serial Data Bits) - количество бит данных:
    • 00 -5 бит,
    • 01 -6 бит,
    • 10 -7 бит,
    • 11 -8 бит.

MCR - регистр управления модемом.

Назначение бит регистра MCR:

  • Биты [7:5]=0 - зарезервированы.
  • Бит 4 - LME(Loopback Mode Enable) - разрешение режима диагностики:
    • 0 - нормальный режим,
    • 1 - режим диагностики (см. ниже).
  • Бит 3 - 1Е( Interrupt Enable) - разрешение прерываний с помощью внешнего выхода OUT2; в режиме диагностики поступает на вход MSR.7:
    • 0 - прерывания запрещены,
    • 1 - разрешены.
  • Бит 2 - OUT1C (OUT1 Bit Control) - управление выходным сигналом 1 (не используется); в режиме диагностики поступает на вход MSR.6.
  • Бит 1 - RTSC (Request To Send Control) - управление выходом RTS; в режиме диагностики поступает на вход MSR.4:
    • 1 - активен (-V),
    • 0 - пассивен (+V).
  • Бит 0 - DTRCfData Terminal Ready Control) - управление выходом DTR; в режиме диагностики поступает на вход MSR.5:
    • 1 - активен (-V),
    • 0 - пассивен (+V).

LSR - регистр состояния линии (точнее, состояния приемопередатчика).

Назначение бит регистра LSR:

  • Бит 7 - FIFOE (FIFO Error Status) - ошибка принятых данных в режиме FIFO (буфер содержит хотя бы один символ, принятый с ошибкой формата, паритета или обрывом). В не FIFO- режиме всегда 0.
  • Бит 6 - TEMPT (Transmitter Empty Status) - регистр передатчика пуст (нет данных для передачи ни в сдвиговом регистре, ни в буферных, THR или FIFO).
  • Бит 5 - THRE (Transmitter Holding Register Empty) - регистр передатчика готов принять байт для передачи. В режиме FIFO указывает на отсутствие символов в FIFO-буфере передачи. Может являться источником прерывания.
  • Бит 4 - BD (Break Detected) - индикатор обрыва линии (вход приемника находится в состоянии 0 не менее, чем время посылки символа).
  • Бит 3 - FE (Framing Error) - ошибка кадра (неверный стоп бит).
  • Бит 2 - РЕ (Parity Error) - ошибка контрольного бита (паритета или фиксированного).
  • Бит 1 - ОЕ (Overrun Error) - переполнение (потеря символа). Если прием очередного символа начинается до того, как предыдущий был выгружен из сдвигающего регистра в буферный или FIFO, прежний символ в сдвигающем регистре теряется.
  • Бит 0 - DR (Receiver Data Ready) - принятые данные готовы (в DHR или FIFO-буфере). Сброс - чтением приемника.

Индикаторы ошибок - биты [4:1] - сбрасываются после чтения регистра LSR. В режиме FIFO признаки ошибок хранятся в FIFO-буфере вместе с каждым символом. В регистре они устанавливаются (и вызывают прерывание) в тот момент, когда символ, принятый с ошибкой, находится на вершине FIFO (первый в очереди на считывание). В случае обрыва линии в FIFO заносится только один "обрывной" символ, и UART ждет восстановления и последующего старт-бита.

MSR - регистр состояния модема.

Назначение бит регистра MSR:

  • Бит 7 - DCD (Data Carrier Detect) - состояние линии DCD.
  • Бит 6 - Rl(Ring Indicator) - состояние линии Rl.
  • Бит 5 - DSR(Data Set Ready) - состояние линии DSR.
  • Бит 4 - CTS(Clear To Send) - состояние линии CTS.
  • Бит 3 - DDCD(Delta Data Carrier Detect) - изменение состояния DCD.
  • Бит 2 - TERI(Trailing Edge OfRing Indicator) -спад огибающей Rl (окончание звонка).
  • Бит 1 - DDSR (Delta Data Set Ready) - изменение состояния DSR.
  • Бит 0 - DCTS (Delta Clear To Send) - изменение состояния CTS.

Признаки изменения (биты [3:0]) сбрасываются по чтению регистра.

SCR - рабочий регистр (8 бит), на работу UART не влияет, предназначен для временного хранения данных (в 8250 отсутствует).

В диагностическом режиме (при LME=1) внутри UART организуется внутренняя заглушка:

  • Выход передатчика переводится в состояние логической 1. Вход приемника отключается.
  • Выход сдвигающего регистра передатчика логически соединяется со входом приемника.
  • Входы DSR, CTS, RI и DCD отключаются от входных линий и внутренне управляются битами DTRC, RTSC, OUT1C, IE.
  • Выходы управления модемом переводятся в пассивное состояние (логический ноль).

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

2.5.3. Ресурсы и конфигурирование СОМ-портов

Компьютер может иметь до четырех последовательных портов СОМ 1-COM4 (для машин класса AT типично наличие двух портов). СОМ-порты имеют внешние разъемы-вилки DB25P или DB9P, выведенные на заднюю панель компьютера (назначение выводов приведено в табл. 2.1).

СОМ-порты реализуются на микросхемах UART, совместимых с семейством 18250. Они занимают в пространстве ввода/вывода по 8 смежных 8-битных регистров и могут располагаться по стандартным базовым адресам. Порты вырабатывают аппаратные прерывания. Возможность разделяемого использования одной линии запроса несколькими портами (или ее разделения с другими устройствами) зависит от реализации аппаратного подключения и ПО. При использовании портов, установленных на шину ISA, разделяемые прерывания обычно не работают.

Управление последовательным портом разделяется на два этапа - предварительное конфигурирование (Setup) аппаратных средств порта и текущее (оперативное) переключение режимов работы прикладным или системным ПО. Конфигурирование СОМ-порта зависит от его исполнения. Порт на плате расширения конфигурируется джамперами на самой плате. Порт на системной плате конфигурируется через BIOS Setup.

Конфигурированию подлежат следующие параметры:

  • Базовый адрес, который может иметь значения 3F8h, 2F8h, 3E8h (ЗЕОЬ, 338h) или 2E8h (2EOh, 238h). При инициализации BIOS проверяет наличие портов по адресам именно в этом порядке и присваивает обнаруженным портам логические имена СОМ1, COM2, COM3 и COM4. Для PS/2 стандартными для портов СОМЗ-СОМ8 являются адреса 3220h, 3228h, 4220h, 4228h, 5220h и 5228h соответственно.
  • Используемая линия запроса прерывания: для СОМ1 и COM3 обычно используется IRQ4 или IRQ11, для COM2 и COM4 - IRQ3 или IRQ 10. В принципе номер прерывания можно назначать в произвольных сочетаниях с базовым адресом (номером порта), но некоторые программы и драйверы (например, драйверы последовательной мыши) настроены на стандартные сочетания. Каждому порту, нуждающемуся в аппаратном прерывании, назначают отдельную линию, не совпадающую с линиями запроса прерываний других устройств. Прерывания необходимы для портов, к которым подключаются устройства ввода, UPS или модемы. При подключении принтера или плоттера прерываниями пользуются только многозадачные ОС (не всегда), и этот дефицитный ресурс PC можно сэкономить. Также прерываниями обычно не пользуются при связи двух компьютеров нуль-модемным кабелем.
  • Канал DMA (для UART 16450/16550, расположенных на системной плате) - разрешение использования и номер канала DMA. Режим DMA при работе с СОМ-портами используют редко.

Режим работы порта по умолчанию (2400 бит/с, 7 бит данных, 1 стоп-бит и контроль четности), заданный при инициализации порта во время BIOS POST, может изменяться в любой момент при настройке коммуникационных программ или командой DOS MODECOMx: с указанием параметров.

2.5.4. Неисправности и тестирование СОМ-портов

Неполадки с СОМ-портами случаются (выявляются) при установке новых портов или неудачном подключении внешних устройств.

Проверка конфигурирования

Тестирование последовательных портов (как и параллельных) начинают с проверки их опознавания системой. Список адресов установленных портов обычно появляется в таблице, выводимой BIOS перед загрузкой ОС. Список можно посмотреть с помощью тестовых программ или прямо в BIOS Data AREA с помощью отладчика.

Если BIOS обнаруживает меньше портов, чем установлено физически, вероятно, двум портам присвоен один адрес или установлен нестандартный адрес какого-либо порта. Проблемы могут возникать с адресами портов COM3 и COM4: не все версии BIOS будут искать порты по альтернативным адресам 3E0h, 338h, 2E0h и 238h; иногда не производится поиск по адресам 3E8h и 2E8h. Нумерация найденных портов, отображаемая в заставке, может вводить в заблуждение: если установлены два порта с адресами 3F8h и 3E8h, в заставке они могут называться СОМ1 и COM2, и по этим именам на них можно ссылаться. Однако те же порты в заставке могут называться и СОМ 1 и COM3 (поскольку 3E8h является штатным адресом для COM3), но попытка сослаться на порт COM3 будет неудачной, поскольку в данном случае адрес 3E8h будет находиться в ячейке 0:402h BIOS Data Area, соответствующей порту COM2, а в ячейке порта COM3 (0:404h) будет нуль - признак отсутствия такового порта.

"Объяснить" системе, где какой порт, можно вручную любым отладчиком, занеся правильные значения базовых адресов в ячейки BIOS Data Area (это придется делать каждый раз после перезагрузки ОС перед использованием "потерянного" порта). Существуют тестовые утилиты, позволяющие находить порты (например, Port Finder).

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

Если физически установлен только один порт и его не обнаруживает BIOS, причины те же, что с LPT- портом: либо он отключен при конфигурировании, либо вышел из строя. Неисправность может устраниться при вынимании/вставке платы адаптера в слот системной шины.

При работе с СОМ-портом задействуются соответствующие аппаратные прерывания - их используют при подключении модема, мыши и других устройств ввода. Неработоспособность этих устройств может быть вызвана некорректной настройкой запроса прерывания. Здесь возможны как конфликты с другими устройствами, так и несоответствие номера прерывания адресу порта.

Функциональное тестирование

В первом приближении СОМ-порт можно проверить диагностической программой (Checkit) без использования заглушек. Этот режим тестирования проверяет микросхему UART (внутренний диагностический режим) и вырабатывание прерываний, но не входные и выходные буферные микросхемы, которые являются более частыми источниками неприятностей. Если тест не проходит, причину следует искать или в конфликте адресов/прерываний, или в самой микросхеме UART.

Для более достоверного тестирования рекомендуется использовать внешнюю заглушку, подключаемую к разъему СОМ-порта (рис. 2.17). В отличие от LPT-порта у СОМ-порта количество входных сигналов превышает количество выходных, что позволяет выполнить полную проверку всех цепей. Заглушка соединяет выход приемника со входом передатчика. Обязательная для всех схем заглушек перемычка RTS- CTS позволяет работать передатчику - без нее символы не смогут передаваться. Выходной сигнал DTR обычно используют для проверки входных линий DSR, DCD и RI.

Рис. 2.17. Заглушка для проверки СОМ-портов (LoopBack)

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

  1. Проверить наличие двуполярного питания выходных схем передатчиков (этот шаг логически первый, но поскольку он технически самый сложный, его можно отложить на крайний случай, когда появится желание заменить буферные микросхемы).
  2. Проверить напряжение на выходах TD, RTS и DTR: после аппаратного сброса на выходе TD должен быть отрицательный потенциал около -12 В (по крайней мере ниже -5 В), а на выходах RTS и DTR - такой же положительный. Если этих потенциалов нет, возможна ошибка подключения разъема к плате через шлейф.

    3. Распространенные варианты:

    • шлейф не подключен;
    • шлейф подключен неправильно (разъем перевернут или вставлен со смещением);
    • раскладка шлейфа не соответствует разъему платы.

    Первые два варианта проверяются при внимательном осмотре, третий же может потребовать некоторых усилий. В табл. 2.1 приведены три варианта раскладки 10-проводного шлейфа разъема СОМ-порта, известных автору; для СОМ-портов на системных платах возможно существование и других. Теоретически шлейф должен поставляться в соответствии с разъемом платы, на которой расположен порт.

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

  3. Соединив контакты линий RTS и CTS (или установив заглушку), следует попытаться вывести небольшой файл на СОМ-порт (например, командой COPYC:\AUTOEXEC. BAT СОМ 7;). С исправным портом эта команда успешно выполнится за несколько секунд с сообщением об успешном копировании. При этом потенциалы на выходах RTS и DTR должны измениться на отрицательные, а на выходе TD должна появиться пачка двуполярных импульсов с амплитудой более 5 В. Если потенциалы RTS и DTR не изменились, ошибка в буферных формирователях. Если на выходе RTS (и входе CTS) появился отрицательный потенциал, а команда COPY завершается с ошибкой, скорее всего, вышел из строя приемник линии CTS (или опять-таки ошибка в шлейфе). Если команда COPY успешно проходит, а изменения на выходе TD не обнаруживаются (их можно увидеть стрелочным вольтметром, но оценить амплитуду импульсов не удастся), виноват буферный передатчик сигнала TD.

Замена микросхем приемников и передатчиков существенно облегчается, если они установлены на разъёмах. Перед заменой следует с помощью осциллографа или вольтметра удостовериться в неисправности конкретной микросхемы. Расположение выводов микросхем приведено на рис. 2.6.

Если буферные элементы включены в состав интерфейсной БИС (что теперь весьма распространено), то такой порт ремонту не подлежит (по крайней мере в обычных условиях). Неисправный СОМ-порт, установленный на системной плате, можно попытаться отключить в BIOS SETUP, но порт мог сгореть и вместе со схемой своего отключения - тогда он останется "живым мертвецом" в карте портов ввода/ вывода и прерываний. Иногда он полностью выводит из строя системную плату.

Источниками ошибок могут являться разъемы и кабели. В разъемах встречаются плохие контакты, а кабели кроме возможных обрывов могут иметь плохие частотные характеристики. Частотные свойства кабелей обычно сказываются при большой длине (десятки метров) на высоких скоростях обмена (56 или 115 Кбит/с). При необходимости использования длинных кабелей на высоких скоростях сигнальные провода данных должны быть перевиты с отдельными проводами "схемной земли".

Питание от интерфейса, или Почему может не работать мышь

При подключении к СОМ-порту устройств с небольшим энергопотреблением возникает соблазн использования питания от выходных линий интерфейса. Если линии управления DTR и RTS не используются по прямому назначению, их можно задействовать как питающие с напряжением около 12 В. Ток короткого замыкания на "схемную землю" ограничен буферной микросхемой передатчика на уровне 20 мА. При инициализации порта эти линии переходят в состояние "выключено", то есть вырабатывают положительное напряжение. Линия TD в покое находится в состоянии логической единицы, так что на выходе вырабатывается отрицательное напряжение. Потенциалами линий можно управлять через регистры СОМ-порта (выход TD вырабатывает положительное напряжение, если установить бит BRCON).

Двуполярным питанием от линий интерфейса (+V от DTR и RTS, -V от TD) пользуются все манипуляторы, подключаемые к СОМ-портам. Зная это, в случае неработоспособности мыши с данным портом следует проверить напряжения на соответствующих контактах разъема. Бывает, что с конкретным портом не работает только конкретная мышь (модель или экземпляр), хотя другие мыши с этим портом и эти же мыши с другими портами работают нормально. Здесь дело может быть в уровнях напряжений. Стандарт требует от порта выходного напряжения не менее 5 В (абсолютного значения), и, если данный порт обеспечивает только этот минимум, некоторым мышам не хватит мощности для питания светодиодов (главных потребителей энергии).

Порт получает двуполярное питание через системную плату от блока питания компьютера. Отсутствие на выходе блока питания напряжения +12 В обычно обнаружится по неработоспособности дисков. Отсутствие напряжения -12 В "заметят" только устройства, подключенные к СОМ - портам. Блок питания теоретически контролирует наличие этих напряжений на своем выходе (сообщая о неполадках сигналом Power Good, вызывающим аппаратный сброс). Встречаются упрощенные схемы блоков питания, у которых контролируются не все напряжения. Кроме того, возможны плохие контакты в разъеме подключения питания к системной плате.

2.5.5. Функции BIOS для СОМ-портов

В процессе начального тестирования POST BIOS проверяет наличие последовательных портов (регистров UART 8250 или совместимых) по стандартным адресам и помещает базовые адреса обнаруженных портов в ячейки BIOS Data Area 0:0400, 0402, 0404, 0406. Эти ячейки хранят адреса портов с логическими именами СОМ 1-COM4. Нулевое значение адреса является признаком отсутствия порта с данным номером. В ячейки 0:047С, 047D, 047Е, 047F заносятся константы, задающие тайм-аут для портов.

Обнаруженные порты инициализируются на скорость обмена 2400 бит/с, 7 бит данных с контролем на четность (even), 1 стоп-бит. Управляющие сигналы интерфейса DTR и RTS переводятся в исходное состояние ("выключено" - положительное напряжение).

Порты поддерживаются сервисом BIOS INT 14h, который обеспечивает следующие функции:

  • 00h - инициализация (установка скорости обмена и формата посылок, заданных регистром AL; запрет источников прерываний). На сигналы DTR и RTS влияния не оказывает (после аппаратного сброса они пассивны).
  • 0lh - вывод символа из регистра AL (без аппаратных прерываний). Активируются сигналы DTR и RTS, и после освобождения регистра THR в него помещается выводимый символ. Если за заданное время регистр не освобождается, фиксируется ошибка тайм-аута и функция завершается.
  • 02h - ввод символа (без аппаратных прерываний). Активируется только сигнал DTR (RTS переходит в пассивное состояние), и ожидается готовность принятых данных, принятый символ помещается в регистр AL. Если за заданное время данные не получены, функция завершается с ошибкой тайм-аута.
  • 03h - опрос состояния модема и линии (чтение регистров MSR и LSR). Эту гарантированно быструю функцию обычно вызывают перед функциями ввода/вывода во избежание риска ожидания тайм-аута.

При вызове INT 14h номер функции задается в регистре АН, номер порта (0-3) - в регистре DX(0 - СОМ 1, 1 - COM2...). При возврате из функций 0,1 и 3 регистр АН содержит байт состояния линии (регистр LSR), AL - байт состояния модема (MSR). При возврате из функции 2 нулевое значение бита 7 регистра АН указывает на наличие принятого символа в регистре AL', ненулевое значение бита 7 - на ошибку приема, которую можно уточнить функцией 3.

Формат байта состояния линии (регистр АН):

  • Бит 7 - ошибка тайм-аута (после вызова функции 2 - признак любой ошибки).
  • Бит 6 - регистр сдвига передатчика пуст (пауза передачи).
  • Бит 5 - промежуточный регистр передатчика пуст (готов принять символ для передачи).
  • Бит 4 - обнаружен обрыв линии.
  • Бит 3 - ошибка кадра (отсутствие стоп-бита).
  • Бит 2 - ошибка паритета принятого символа.
  • Бит 1 - переполнение (потеря символа).
  • Бит 0 - регистр данных содержит принятый символ.

Формат байта состояния модема (регистр AL):

  • Бит 7 - состояние линии DCD.
  • Бит 6 - состояние линии RI.
  • Бит 5 - состояние линии DSR.
  • Бит 4 - состояние линии CTS.
  • Бит 3 - изменение состояния DCD.
  • Бит 2 - изменение огибающей RI.
  • Бит 1 - изменение состояния DSR.
  • Бит 0 - изменение состояния CTS.
Формат регистра AL при инициализации:
  • Биты [7:5] - скорость обмена:
    • 000-110; 010-300; 100-1200; 110-4800,
    • 001-150; 011-600; 101-2400; 111-9600 бит/с.
  • Биты [4:3] - контроль паритета:
    • 01 - число единиц нечетное,
    • 11 -четное,
    • 00 и 10 - без контроля.
  • Бит 2 - количество стоп-бит:
    • 0-1 бит,
    • 1-2 бита (на скорости 110 бит/с - 1,5 стоп-бита).
  • Биты [1:0] - длина посылки:
    • 00-5 бит,
    • 01-6 бит,
    • 10-7 бит,
    • 11-8 бит.

2.5.6. СОМ-порт и РпР

Современные ПУ, подключаемые к СОМ-порту, могут поддерживать спецификацию РпР. Основная задача ОС заключается в идентификации подключенного устройства, для чего разработан несложный протокол, реализуемый на любых СОМ-портах чисто программным способом (рис. 2.18):

Рис. 2.18. Запрос идентификатора устройства РпР

  1. Порт инициализируется с состоянием линий DTR=OA/, RTS=OFF, TXD=Mark - состояние покоя (Idle).
  2. Некоторое время (0,2 с) ожидается появление сигнала DSR, которое указало бы на наличие устройства, подключенного к порту. В простейшем случае устройство имеет на разъеме перемычку DTR-DSR, обеспечивающую указанный ответ. Если устройство обнаружено, выполняются манипуляции управляющими сигналами DTR и RTS для получения информации от устройства. Если ответ не получен, ОС, поддерживающая динамическое реконфигурирование, периодически опрашивает состояние порта для обнаружения новых устройств.
  3. Порт программируется на режим 1200 бит/с, 7 бит данных, без паритета, 1 стоп-бит, и на 0,2 с снимается сигнал DTR. После этого устанавливается DTR=1, а еще через 0,2 с устанавливается и RTS=1.
  4. В течение 0,2 с ожидается приход первого символа от устройства. По приходе символа начинается прием идентификатора (см. ниже). Если за это время символ не пришел (рис. 2.18), выполняется вторая попытка опроса (см. п. 5), несколько отличающаяся от первой.
  5. На 0,2 с снимаются оба сигнала (DTR=0 и RTS=0), после чего они оба устанавливаются (DTR=1 и RTS=1).
  6. В течение 0,2 с ожидается приход первого символа от устройства, по приходе символа начинается прием идентификатора (см. ниже). Если за это время символ не пришел, то в зависимости от состояния сигнала DSR переходят к проверке отключения Verify Disconnect (при DSR^O) или в дежурное состояние Connect Idle (при DSR=1).
  7. В дежурном состоянии Connect Idle устанавливается DTR=1, RTS=0, порт программируется на режим 300 бит/с, 7 бит данных, без паритета, 1 стоп-бит. Если в этом состоянии обнаружится DSR=0, ОС следует уведомить об отключении устройства.

Посимвольный прием идентификатора устройства имеет ограничения по тайм-ауту в 0,2 с на символ, а также общее ограничение в 2,2 с, позволяющее принять строку длиной до 256 символов. Строка идентификатора РпР должна иметь маркеры начала (28h или 08h) и конца (29h или 09h), между которыми располагается тело идентификатора в стандартизованном формате. Перед маркером начала может находиться до 16 символов, не относящихся к идентификатору РпР. Если за первые 0,2 с ожидания символа (шаг 4 или 6) маркер начала не пришел, или же сработал тайм-аут, а маркер конца не получен, или же какой-либо символ принят с ошибкой, происходит переход в состояние Connect Idle. Если получена корректная строка идентификатора, она передается ОС.

Для проверки отключения (Verify Disconnect) устанавливается DTR=1, RTS=0 и через 5 с проверяется состояние сигнала DSR. При DSR=1 происходит переход в состояние Connect Idle (см. п. 7), при DSR^O происходит переход в состояние Disconnect Idle, в котором система может периодически опрашивать сигнал DSR для обнаружения подключения устройства.

Описанный механизм разрабатывался фирмой Microsoft с учетом совместимости с не-РпР-устройствами - невозможность их вывода из строя и устойчивость системы к сообщениям, не являющимся РпР- идентификаторами. Например, обычная Microsoft Mouse при включении питания от интерфейса ответит ASCII-символом "М" (трехкнопочная - строкой "МЗ").


Шинные формирователи

 Дата последнего обновления файла22.08.2005

Шинные формирователи

Мультиплексоры предназначены для объединения нескольких выходов в тех случаях, когда заранее известно сколько выходов нужно объединять. Часто это неизвестно. Более того, часто количество объединяемых микросхем изменяется в процессе эксплуатации устройств. Наиболее яркий пример - это компьютеры, в которых в процессе эксплуатации изменяется объем оперативной памяти, количество портов ввода-вывода, количество дисководов. В таких случаях невозможно для объединения нескольких выходов воспользоваться логическим элементом "ИЛИ".

Для объединения нескольких выходов на один вход в случае, когда заранее не известно сколько микросхем нужно объединять, используется два способа:

  1. монтажное ИЛИ;
  2. шинные формирователи.

Исторически первой схемой объединения выходов были схемы с открытым коллектором (монтажное "ИЛИ"). Схема монтажного "ИЛИ" приведена на рисунке 1.

Рисунок 1. Схема монтажного "ИЛИ".

Такое объединение микросхем называется шиной и позволяет объединять до 10 микросхем на один провод. Естественно для того, чтобы микросхемы не мешали друг другу только одна из микросхем должна выдавать информацию на общий провод. Остальные микросхемы в этот момент времени должны быть отключены от шины (то есть выходной транзистор должен быть закрыт). Это обеспечивается внешней микросхемой управления не показанной на данном рисунке.

На принципиальных схемах такие элементы обозначаются как показано на рисунке 2.

OK.gif (1175 bytes)

Рисунок 2. Обозначение микросхемы с открытым коллектором на выходе

Недостатком приведенной схемы объединения нескольких микросхем на один провод является низкая скорость передачи информации, обусловленная затягиванием переднего фронта. Это явление связано с различным сопротивлением заряда и разряда паразитной ёмкости шины. Заряд паразитной ёмкости происходит через сопротивления R1 и R2, которые много больше сопротивления открытого транзистора. Величину этого сопротивления невозможно уменьшить меньше некоторого предела, определяемого напряжением низкого уровня, который определяется в свою очередь допустимым током потребления всей схемы в целом. Временная диаграмма напряжения на шине с общим коллектором приведена на рисунке 3.

Рисунок 3. Временные диаграммы напряжения на входе и выходе микросхемы с открытым коллектором.

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

Рисунок 4. Путь протекания сквозного тока при непосредственном соединении выходов цифровых микросхем.

Эта проблема исчезает, если появляется возможность закрывать транзисторы как в верхнем, так и в нижнем плече выходного каскада. Если в микросхеме закрыты оба транзистора, то такое состояние выхода микросхемы называется третьим состоянием или z-состоянием выхода микросхемы. Такая возможность появляется в специализированных микросхемах с третьим состоянием на выходе микросхемы. Принципиальная схема выходного каскада микросхемы с тремя состояниями на выходе микросхемы приведена на рисунке 5.

Рисунок 5. Принципиальная схема выходного каскада микросхемы с тремя состояниями на выходе

На принципиальных схемах такие элементы обозначаются как показано на рисунке 6.

Z.gif (1166 bytes)

Рисунок 6. Обозначение микросхемы с тремя состояниями на выходе

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

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

Часто в микросхеме, содержащей элементы с тремя состояниями выходного каскада объединяют управляющие сигналы всех элементов в один провод. Такие микросхемы называют шинными формирователями и изображают на схемах как показано на рисунке 7.

Buf.gif (1651 bytes)

Рисунок 7. Обозначение шинного формирователя.

[ Главная ]


Классификация микропроцессоров

Причины широкого распространения микропроцессоров.

Цифровые микросхемы к настоящему времени достигли впечатляющего быстродействия при приемлемом токе потребления. Наиболее быстрые из цифровых микросхем обладают скоростью переключения порядка 3..5 нс. (серия микросхем 74ALS). В то же время приходится платить за быстродействие микросхем повышеным током потребления. Исключением являются микросхемы, построенные на основе КМОП технологии (например микросхемы серий 1564, 74HC, 74AHC). В этих микросхемах потребляемый ток прямо пропорционален скорости переключения логических вентилей в микросхеме. Т.е. микросхема автоматически увеличивает ток потребления, если от нее требуется большее быстродействие, поэтому в настоящее время подавляющее большинство микросхем выпускается именно по этой технологии.

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

Ещё одной причиной широкого распространения микропроцессоров стало то, что микропроцессор - это универсальная микросхема, которая может выполнять практически любые функции. Универсальность обеспечивает широкий спрос на эти микросхемы, а значит массовость производства. Стоимость же микросхем обратно пропорциональна массовости их производства, то есть микропроцессоры становятся дешёвыми микросхемами и тем самым ещё больше увеличивают спрос.

В наибольшей степени все вышеперечисленные свойства проявляются в однокристальных микроЭВМ или как их чаще называют по области применения: микроконтроллерах. В микроконтроллерах на одном кристалле объединяются все составные части компьютера: микропроцессор (часто называют ядро микроконтроллера), ОЗУ, ПЗУ, таймеры и порты ввода-вывода.

Выводы:

  • КМОП технология позволяет обменивать скорость работы на потребляемый ток (чем с большей скоростью переключаются логические элементы микросхемы, тем больший ток потребляет микросхема);
  • Микроконтроллеры позволяют реализовывать схему управления практически любой сложности на одной универсальной микросхеме;
  • Микроконтроллеры позволяют обменивать скорость своей работы на сложность проектируемого устройства.
  • Микроконтроллеры позволяют реализовывать аппаратуру с минимальной стоимостью, габаритами и током потребления.
  • Срок разработки аппаратуры на микроконтроллерах минимален.
  • Модернизация аппаратуры заключается в смене управляющей программы.

Классификация микропроцессоров.

В современном мире трудно найти область техники, где не применялись бы микропроцессоры. Они применяются при вычислениях, они выполняют функции управления, они используются при обработке звука и изображения. В зависимости от области применения микропроцессора меняются требования к нему. Это накладывает отпечаток на внутреннюю структуру микропроцессора. По области применения определилось три направления развития микропроцессоров:

  • микроконтроллеры
  • универсальные микропроцессоры
  • сигнальные микропроцессоры

По внутренней структуре существует два основных принципа построения микропроцессоров:

  • Гарвардская архитектура
  • Архитектура Фон-Неймана

По системе команд микропроцессоры отличаются огромным разнообразием, зависящим от фирмы-производителя. Тем не менее можно определить две крайние политики построения микропроцессоров:

  • Аккумуляторные микропроцессоры
  • Микропроцессоры с регистрами общего назначения

В микропроцессорах с регистрами общего назначения математические операции могут выполняться над любой ячейкой памяти. В зависимости от типа операции команда может быть одноадресной, двухадресной или трёхадресной.

Принципиальным отличием аккумуляторных процессоров является то, что математические операции могут производиться только над одной особой ячейкой памяти - аккумулятором. Для того, чтобы произвести операцию над произвольной ячейкой памяти её содержимое необходимо скопировать в аккумулятор, произвести требуемую операцию, а затем скопировать полученный результат в произвольную ячейку памяти.

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

В Гарвардской архитектуре принципиально различаются два вида памяти:

  • Память программ
  • Память данных

В Гарвардской архитектуре принципиально невозможно производить операцию записи в память программ, что исключает возможность случайного разрушения управляющей программы в случае неправильных действий над данными. Кроме того, в ряде случаев для памяти программ и памяти данных выделяются отдельные шины обмена данными. Эти особенности определили области применения этой архитектуры построения микропроцессоров. Гарвардская архитектура применяется в микроконтролерах, где требуется обеспечить высокую надёжность работы аппаратуры и в сигнальных процессорах, где эта архитектура кроме обеспечения высокой надёжности работы устройств позволяет обеспечить высокую скорость выполнения программы, за счёт одновременного считывания управляющих команд и обрабатываемых данных, а так же запись полученных результатов в память данных.

Отличие архитектуры Фон Неймана заключается в принципиальной возможности работы над управляющими программами точно так же как над данными. Это позволяет производит загрузку и выгрузку управляющих программ в произвольное место памяти процессора, которая в этой структуре не разделяется на память программ и память данных. Любой участок памяти может служить как памятью программ, так и памятью данных. Причём в разные моменты времени одна и та же область памяти может использоваться и как память программ и как память данных. Для того, чтобы программа могла работать в произвольной области памяти, её необходимо модернизировать перед загрузкой, то есть работать с нею как с обычными данными. Эта особенность архитектуры позволяет наиболее гибко управлять работой микропроцессорной системы, но создаёт принципиальную возможность искажения управляющей программы, что понижает надёжность работы аппаратуры. Эта архитектура используется в универсальных компьютерах и в некоторых видах микроконтроллеров.


Виды двоичных кодов

 Rambler's Top100 Дата последнего обновления файла 22.08.2005

Виды двоичных кодов

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

Для представления числовой информации могут использоваться знаковые и беззнаковые коды. Для определённости примем длину слова процессора равной восьми битам.

Беззнаковые двоичные коды.

Первый вид двоичных кодов, который мы рассмотрим - это целые беззнаковые коды. В этих кодах каждый двоичный разряд представляет собой степень цифры 2:

UnsIntCd.gif (2998 bytes)

При этом минимально возможное число, которое можно записать таким двоичным кодом, равно 0. Максимально возможное число, которое можно записать таким двоичным кодом, можно определить как:

Formula1.gif (1236 bytes)

Этими двумя числами полностью можно определить диапазон, чисел которые можно представить таким двоичным кодом. В случае двоичного восьмиразрядного беззнакового целого числа диапазон будет: диапазон чисел, которые можно записать таким кодом: 0 .. 255. Для шестнадцатиразрядного кода этот 0 .. 65535. В восьмиразрядном процессоре для хранения такого числа используется две ячейки памяти, расположенные в соседних адресах. Для работы с такими числами используются специальные команды.

Второй вид двоичных кодов, который мы рассмотрим - это прямые целые знаковые коды. В этих кодах старший разряд в слове используется для представления знака числа. В прямом знаковом коде нулем обозначается знак '+', а единицей - знак '-'. В результате введения знакового разряда диапазон чисел смещается в сторону отрицательных чисел:

В случае двоичного восьмиразрядного знакового целого числа диапазон чисел, которые можно записать таким кодом: -127 .. +127. Для шестнадцатиразрядного кода этот диапазон будет: -32767 .. +32767. В восьмиразрядном процессоре для хранения такого числа тоже используется две ячейки памяти, расположенные в соседних адресах.

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

Знаковые обратные двоичные коды.

Обратные двоичные коды отличаются от прямых только тем, что отрицательные числа в них получаются инвертированием всех разрядов числа. При этом знаковый и цифровые разряды не различаются. Алгоритм работы с такими кодами резко упрощается.

Тем не менее при работе с обратными кодами требуется специальный алгоритм распознавания знака, вычисления абсолютного значения числа, восстановления знака результата числа. Кроме того, в прямом и обратном коде числа для запоминания числа 0 используется два кода, тогда как известно, что число 0 положительное и отрицательным не может быть никогда.

Знаковые дополнительные двоичные коды.

От перечисленных недостатков свободны дополнительные коды. Эти коды позволяют непосредственно суммировать положительные и отрицательные числа не анализируя знаковый разряд и при этом получать правильный результат. Все это становится возможным благодаря тому, что дополнительные числа являются естественным кольцом чисел, а не исскуственным образованием как прямые и обратные коды. Кроме того немаловажным является то, что вычислять дополнение в двоичном коде чрезвычайно легко. Для этого достаточно к обратному коду добавить 1:

Диапазон чисел, которые можно записать таким кодом: -128 .. +127. Для шестнадцатиразрядного кода этот диапазон будет: -32768 .. +32767. В восьмиразрядном процессоре для хранения такого числа используется две ячейки памяти, расположенные в соседних адресах.

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

Использование для представления знака числа двух бит предоставляет интересную возможность контролировать переполнения при выполнении арифметических операций. Рассмотрим несколько примеров.

1) Просуммируем числа 12 и 5

В этом примере видно, что в результате суммирования получается правильный результат. Это можно проконтролировать по флагу переноса C, который совпадает со знаком результата (действует эффект распространения знака).

2) Просуммируем два отрицательных числа -12 и -5

В этом примере флаг переноса C тоже совпадает со знаком результата, то есть переполнения не произошло и в этом случае

3) Просуммируем положительное и отрицательное число -12 и +5

В этом примере при суммировании положительного и отрицательного числа автоматически получается правильный знак результата. В данном случае знак результата отрицательный. Флаг переноса совпадает со знаком результата, поэтому переполнения не было (мы можем убедиться в этом непосредственными вычислениями на бумаге или на калькуляторе).

4) Просуммируем положительное и отрицательное число +12 и -5

В данном примере знак результата положительный. Флаг переноса совпадает со знаком результата, поэтому переполнения не было и в этом случае.

5)Просуммируем числа 100 и 31

В этом примере видно, что в результате суммирования произошло переполнение восьмибитовой переменной, т.к. в результате операции над положительными числами получился отрицательный результат. Однако если рассмотреть флаг переноса, то он не совпадает со знаком результата. Эта ситуации является признаком переполнения результата и легко обнаруживается при помощи операции "исключающее ИЛИ" над старшим битом результата и флагом переноса C. Большинство процессоров осуществляют эту операцию аппаратно и помещают результат во флаг переполнения OV.

В этом примере результате операции над отрицательными числами в результате суммирования произошло переполнение восьмибитовой переменной, т.к. получился положительный результат. И в этом случае если рассмотреть флаг переноса C, то он не совпадает со знаком результата. Отличие от предыдущего случая только в комбинации этих бит. В примере 5 говорят о переполнении результата (комбинация 01), а в примере 6 об антипереполнении результата (комбинация 10).

Представление дробных чисел в двоичном коде с фиксированной запятой.

Кроме целых чисел часто требуется работать с дробными числами. Следующий вид двоичных кодов, который мы рассмотрим - это дробные коды. Как и в случае целых чисел, дробные числа могут быть беззнаковые и знаковые. Для записи знаковых чисел могут быть использованы прямые, обратные и дополнительные коды. Принцип их построения точно такой же, как и в случае целых чисел.

Рассмотрим, как можно записать дробное число. До сих пор мы предполагали, что двоичная запятая находится правее самого младшего разряда. Но кто сказал, что она должна всегда находиться в этом месте? Мы можем договориться, что запятая находится слева от самого старшего разряда, и тогда в такой переменной можно будет записывать только дробные числа:

Или договоримся, что она находится точно посередине переменной, и тогда мы сможем записывать смешанные числа:

Остальные случаи рассматривать не будем. Они строятся точно так же как и для целых чисел.

Представление чисел в двоичном коде с плавающей запятой.

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

В десятичной арифметике для записи таких чисел используется алгебраическая форма. При этом число записывается в виде мантиссы, умноженной на 10 в степени, отображающей порядок числа, Например:

0,2*105; 0,16*10-38

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

А теперь рассмотрим промышленные стандарты, используемые для представления чисел в компьютерах. Существует стандарт IEEE 754 для представления чисел с одинарной точностью (float) и с двойной точностью (double). Для записи числа в формате с плавающей запятой одинарной точности требуется тридцатидвухбитовое слово. Для записи чисел с двойной точностью требуется шестидесятичетырёхбитовое слово. Чаще всего числа хранятся в нескольких соседних ячейках памяти процессора. Форматы числа в формате с плавающей запятой одинарной точности и числа в формате с плавающей запятой удвоенной точности приведены на рисунке

На рисунке буквой S обозначен знак числа, 0 - это положительное число, 1 - отрицательное число. e обозначает смещённый порядок числа. Смещение требуется, чтобы не вводить в число еще один знак. Смещённый порядок всегда положительное число. Для одинарной точности для порядка выделено восемь бит. Для смещённого порядка двойной точности отводится 11 бит. Для одинарной точности смещение принято 127, а для двойной точности - 1023. В десятичной мантиссе после запятой могут присутствовать цифры 1:9, а в двоичной - только 1. Поэтому для хранения единицы после двоичной запятой не выделяется отдельный бит в числе с плавающей запятой. Единица подразумевается, как и двоичная запятая. Кроме того, в формате чисел с плавающей запятой принято, что мантисса всегда больше 1. То есть диапазон значений мантиссы лежит в диапазоне от 1 до 2.

Рассмотрим несколько примеров:

1) Определить число с плавающей запятой, лежащее в четырёх соседних байтах:

11000001 01001000 00000000 00000000

- Знаковый бит, равный 1 показывает, что число отрицательное.

- Экспонента 10000010 в десятичном виде соответствует числу 130. Вычтя число 127 из 130, получим число 3.

- Теперь запишем мантиссу: 1,100 1000 0000 0000 0000 0000

- И, наконец, определим десятичное число: 1100,1b = 12,5d

2) Определить число с плавающей запятой, лежащее в четырёх соседних байтах:

11000011 00110100 00000000 00000000

- Знаковый бит, равный 1 показывает, что число отрицательное.

- Экспонента 10000110 в десятичном виде соответствует числу 134. Вычтя число 127 из 134, получим число 7.

- Теперь запишем мантиссу: 1,011 0100 0000 0000 0000 0000

- И, наконец, определим десятичное число: 10110100b=180d

Для того чтобы записать ноль, достаточно записать в смещенный порядок число 00000000b. Значение мантиссы при этом не имеет значения. Число, в котором все байты равны 0, тоже попадает в этот диапазон значений.

Бесконечность соответствует смещенному порядку 11111111b и мантиссе, равной 1,0. При этом существует минус бесконечность и плюс бесконечность (переполнение и антипереполнение), которые часто отображаются на экран монитора как +INF и -INF.

Все остальные комбинации битов (в том числе и все единицы) воспринимаются как не числа и отображаются на экран: NaN.

Запись десятичных чисел.

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

Остальные комбинации двоичного кода в тетраде являются запрещенными. Запишем пример двоично-десятичного кода:

1258 = 0001 0010 0101 1000

589 = 0000 0101 1000 1001

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

1258 =00000001
      00000010
      00000101
      00001000
589 = 00000000
      00000101
      00001000
      00001001

Суммирование двоично-десятичных чисел.

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

DecCorr1.gif (1567 bytes)

DecCorr2.gif (1536 bytes)

Запись текстов в памяти процессора.

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

[ Главная ]


Динамические ОЗУ

 Rambler's Top100 Дата последнего обновления файла 22.08.2005

Динамические оперативные запоминающие устройства (ОЗУ)

Статические оперативные запоминающие устройства позволяют обеспечивать хранение записанной информации до тех пор, пока на микросхему подаётся питание. Однако запоминающая ячейка статического ОЗУ занимает относительно большую площадь, поэтому для ОЗУ большого объема в качестве запоминающей ячейки применяют конденсатор. Заряд на этой ёмкости естественно с течением времени уменьшается, поэтому его необходимо подзаряжать с периодом приблизительно 10 мс. Этот период называется периодом регенерации. Подзарядка ёмкости производится при считывании ячейки памяти, поэтому для регенерации информации достаточно просто считать регенерируемую ячейку памяти.

Схема запоминающего элемента динамического ОЗУ и его конструкция приведена на рисунке 1.

Схема запоминающего элемента динамического ОЗУ и его конструкция.

При считывании заряда ёмкости необходимо учитывать, что ёмкость линии считывания много больше емкости запоминающей ячейки. Графики изменения напряжения на линии считывания при считывании информации с запоминающей ячейки без применения регенерации приведены на рисунке 2.

Рисунок 2. Графики изменения напряжения на линии считывания при считывании информации с запоминающей ячейки.

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

Для регенерации первоначального напряжения, хранившегося в запоминающей ячейке в схеме применяется RS триггер, включенный между двумя линиями записи/считывания. Схема такого включения приведена на рисунке 3. Эта схема за счет положительной обратной связи восстанавливает первоначальное значение напряжения в запоминающем элементе, подключенном к выбранной линии считывания. То есть, при считывании ячейки производится регенерация хранящегося в ней заряда.

Рисунок 3. Схема регенерирующего каскада.

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

Особенностью динамических ОЗУ является мультиплексирование шины адреса. Адрес строки и адрес столбца передаются поочередно. Адрес строки синхронизируется стробирующим сигналом RAS# (Row Address strobe), а адрес столбца - CAS# (Column Adress Strobe). Мультиплексирование адресов позволяет уменьшить количество ножек микросхем ОЗУ. Изображение микросхемы динамического ОЗУ приведено на рисунке 4, а временные диаграммы обращения к динамическому ОЗУ на рисунке 5.

Рисунок 4. Изображение динамического ОЗУ на принципиальных схемах.

Рисунок 5. Временная диаграмма обращения к динамическому ОЗУ

Именно так долгое время велась работа с динамическими ОЗУ. Затем было замечено, что обычно обращение ведется к данным, лежащим в соседних ячейках памяти, поэтому не обязательно при считывании или записи каждый раз передавать адрес строки. Данные стали записывать или считывать блоками и адрес строки передавать только в начале блока. При этом можно сократить общее время обращения к динамическому ОЗУ и тем самым увеличить быстродействие компьютера.

Такой режим обращения к динамическому ОЗУ называется быстрым страничным режимом доступа FPM (Fast Page Mode). Длина считываемого блока данных равна четырем словам. Для того, чтобы оценить время такого режима доступа к памяти время измеряют в тактах системной шины процессора. В обычном режиме доступа к памяти время доступа одинаково для всех слов. Поэтому цикл обращения к динамической памяти можно записать как 5-5-5-5. При режиме быстрого страничного доступа цикл обращения к динамической памяти можно записать как 5-3-3-3, то есть время обращения к первой ячейке не изменяется по сравнению с предыдущим случаем, а считывание последующих ячеек сокращается до трех тактов. При этом среднее время доступа к памяти сокращается почти в полтора раза. Временная диаграмма режима FPM приведена на рисунке 6.

Рисунок 6. Временная диаграмма обращения к динамическому ОЗУ в режиме FPM.

Еще одним способом увеличения быстродействия ОЗУ является применение микросхем EDO (Extended Data Out — ОЗУ с расширенным выходом данных). В EDO ОЗУ усилители-регенераторы не сбрасываются по окончанию строба CAS#, поэтому времени для считывания данных в таком режиме больше. Теперь для того чтобы сохранить время считывания на прежнем уровне можно увеличить тактовую частоту системной шины и тем самым увеличить быстродействие компьютера. Для EDO ОЗУ цикл обращения к динамической памяти можно записать как 5-2-2-2.

Следующим шагом в развитии схем динамического ОЗУ было применение в составе ОЗУ счетчика столбцов. То есть при переходе адреса ячейки к следующему столбцу запоминающей матрицы адрес столбца инкрементируется (увеличивается) автоматически. Такое ОЗУ получило название BEDO (ОЗУ с пакетным доступом). В этом типе ОЗУ удалось достигнуть режима обращения к динамической памяти 5-1-1-1.

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

Рисунок 7. Структурная схема конвейерной обработки данных.

Из приведенного рисунка видно что, несмотря на то, что при считывании одной ячейки памяти время доступа к ОЗУ увеличивается, при считывании нескольких соседних ячеек памяти общее быстродействие микросхем синхронного динамического ОЗУ увеличивается.


Подключение внешних устройств к микропроцессору.

 Дата последнего обновления файла 22.08.2005

Подключение внешних устройств к микропроцессору.

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

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

Согласование микросхем между собой не представляет трудностей, так как практически все современные микросхемы по входу и выходу согласованы с TTL уровнями. Если же это не так, то для согласования нестандартных уровней с TTL уровнями выпускаются специальные микросхемы. Несколько иначе обстоит дело с индикаторами и различными исполнительными устройствами.

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

Рисунок 1. Подключение одиночного светодиодного индикатора.

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

Несколько сложнее выглядит схема подключения внешних исполнительных устройств с индуктивной нагрузкой (например реле или электромагнит):

Рисунок 2. Подключение внешнего устройства с индуктивной нагрузкой.

Диод VD1 в этой схеме служит для ограничения напряжения импульсов самоиндукции, которые могут вывести из строя транзистор VT1.

При считывании информации из внешнего устройства возникают аналогичные проблемы. Источники дискретной информации могут иметь различную физическую природу. Они могут находиться на значительном расстоянии от контроллера, иметь различное напряжение питания, но их данные должны быть надежно введены в микропроцессор.

Для решения указанных проблем и реализации гальванической развязки датчиков и микропроцессорного устройства, все датчики с точки зрения схемы представляют собой контакты, работающие на замыкание. Поэтому схема подключения датчика и кнопки не различаются. Со стороны микропроцессорного устройства необходимо преобразовать замыкание/размыкание контактов в логические уровни, необходимые для правильной работы микропроцессорного устройства. Такая схема приведена на рисунке 3.

Рисунок 3. Подключение источника дискретной информации с гальванической развязкой.

Иногда требуется вводить информацию с большого количества кнопок. В этом случае для уменьшения количества линий ввода-вывода используется клавиатура. Для подключения клавиатуры используется два порта: порт ввода и порт вывода. Схема подключения клавиатуры приведена на рисунке 4.

Рисунок 4. Подключение клавиатуры к микропроцессорному устройству.

Собственно говоря, схема подключения не отличается от предыдущей схемы. Принципиальное отличие состоит в том, что корпус на кнопки подается не непосредственно, а через порт вывода. В каждый момент времени к корпусу подключен только один столбец кнопок. Временные диаграммы напряжения на выводах порта вывода приведены на рисунке 5.

Рисунок 5. Временные диаграммы напряжения на выводах порта вывода.

[ Главная ]


Команды микропроцессора

 Дата последнего обновления файла 22.08.2005

Команды микропроцессора

Команды микропроцессора в отличие от микрокоманд разрабатываются независимо от аппаратуры микросхемы, поэтому их разрядность обычно совпадает с разрядностью микропроцессора. Команда микропроцессора состоит из инструкции и обозначается код операции КОП (или INS в англоязычной литературе). Команда микропроцессора может состоять только из кода операции, когда не требуется указывать адрес операнда (операнды это данные, над которыми команда производит какое либо действие), или может состоять из кода операции и адресов операндов или данных. Форматы команд очень сильно зависит от структуры процессора. Рассмотрим построение команд для восьмиразрядного процессора, построенного по структуре Фон-Неймана. Примеры построения команд для такого процессора приведены на рисунке 1.

Ins.gif (4077 bytes)

Рисунок 1. Форматы различных команд микропроцессора.

Если для кода операции используется восьмибитное слово (байт), то при помощи этого слова можно закодировать 256 операций. В процессе разработки системы команд для операции может быть назначен любой код. Именно системой команд и определяется конкретное семейство процессоров. Однобайтовые команды позволяют работать с внутренними программно доступными регистрами процессора.

Для выполнения одной и той же операции над разными регистрами процессора назначаются разные коды. Запоминать эти коды очень утомительно для человека. При программировании в машинных кодах легко совершить ошибку и очень трудно найти её, особенно если коды различаются только на один бит. Для сокращения объёма записи вместо двоичного можно воспользоваться шестнадцатиричным кодом, однако это не увеличивает наглядности программы. Фрагмент исполняемого кода микропроцессора приведён на рисунке 2.

Ins.gif (4077 bytes)

Рисунок 2. Фрагмент исполняемого кода микропроцессора.

Ну как? Очень понятно?

Чтобы уменьшить объём запоминаемой информации и увеличить наглядность исходного текста программы, каждой операции процессора придумывают мнемоническое обозначение. В качестве мнемонического обозначения операции обычно используют сокращения английских слов, обозначающих эту операцию. Например, для операции копирования используется мнемоническое обозначение MOV; для операции суммирования используется мнемоническое обозначение ADD; для операции вычитания используется мнемоническое обозначение SUB; для операции умножения используется мнемоническое обозначение MUL и т.д.

Для полного обозначения команды используется мнемоническое обозначение операции и используемые ею операнды, которые перечисляются через запятую. При этом в большинстве процессоров операнд приёмник информации записывается первым, а операнд источник информации вторым. Например:

MOV R0, A ;Скопировать содержимое регистра A в регистр R0

ADD A, R5 ;Просуммировать содержимое регистров R5 и A, результат поместить в регистр A

Приведённые выше команды - это однобайтовые команды, так как в них используются только внутренние регистры процессора. Если в команде используется константа в качестве операнда или указывается адрес операнда в системной памяти, то команда будет занимать в системной памяти два или три байта. Например:

MOV A, 1025 ;Скопировать содержимое 1025 ячейки памяти в регистр A

ADD A, #110 ;Просуммировать содержимое регистра A с числом 110

Несмотря на то, что общий объём исходного текста программы увеличивается, скорость написания и особенно отладки программ в таком виде возрастает. Теперь вместо одного текста программы в памяти компьютера или на бумаге придется хранить два текста: один для человека, который в дальнейшем будем называть исходным текстом программы; другой для микропроцессора, который в дальнейшем будем называть загрузочным модулем.

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

[ Главная ]


Микропрограммирование

 Дата последнего обновления файла 22.08.2005

Микропрограммирование

Все действия микропроцессора и сигналы на его выводах определяются последовательностью микрокоманд, подаваемых на управляющие входы блока обработки сигналов. Эта последовательность микрокоманд называется микропрограммой.

При изучении принципов работы ОЗУ и ПЗУ приводились временные диаграммы, которые необходимо сформировать, для того, чтобы записать или прочитать необходимую информацию. Выберем одну из этих диаграмм:

DiagRAM.gif (4664 bytes)

Рисунок 1. Временные диграммы считывания

Любую временную диаграмму формирует микропроцессор. Устройство микросхемы, на примере которой мы будем формировать необходимые для работы сигналы рассматривалось при обсуждении блока обработки сигналов. По принципиальной схеме блока обработки сигнала можно определить формат микрокоманды, управляющей этим блоком.

Работа любого цифрового устройства начинается с заранее заданных начальных условий. Эти начальные условия формируются специальным сигналом RESET (сброс), который формируется после подачи питания на схему. Договоримся, что сигнал сброса микропроцессора будет записывать в регистр программного счетчика PC нулевое значение. (Это условие справедливо не для всех процессоров. Например, IBM совместимые процессоры при сбросе микросхемы записывают в программный счётчик значение F0000h.)

Выполнение любой команды начинается с её считывания из системной памяти (ОЗУ или ПЗУ). Необходимые для этого микрокоманды подаются на входы управления БОС из блока микропрограммного управления БМУ, как только снимается сигнал сброса со счётчика микрокоманд БМУ. При считывании однобайтной команды достаточно считать из системной памяти только код операции и выполнить эту операцию. Временная диаграмма этого процесса приведена на рисунке 2. Последовательность операций, которые необходимо выполнить микропрограмме, показана стрелочками. Для считывания следующей команды микропрограмма запускается заново.

RdIns.gif (3761 bytes)

Рисунок 2. Временные диаграммы сигналов считывания команд из системной памяти.

Для того, чтобы считать код операции из системной памяти, необходимо выставить на шине адреса адрес этой команды. Этот адрес хранится в счетчике команд PC. Скопируем его в регистр адреса RA, выходы которого подключены к шине адреса:

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
1) | PCH -> RAH | 1111 1111 | 1111 | 1010 | 0011 0 0 | 1100
2) | PCL -> RAL | 1111 1111 | 1111 | 1011 | 0011 0 0 | 1101

Затем сформируем сигнал считывания. Для этого в регистр управления запишем константу 1111 1101.

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
3) | const -> CR | 1111 1101 | 1111 | 1111 | 0011 0 0 | 1110

Теперь можно считать число с шины данных, а так как системная память в этот момент выдаёт на нее код операции, то мы считаем именно этот код. Запишем его в регистр команд и снимем сигнал чтения с системной шины. Для этого в регистр управления запишем константу 1111 1111.

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
4) | data -> RI | 1111 1111 | 1100 | 1111 | 1100 0 0 | 1001
5) | const -> CR | 1111 1111 | 1111 | 1111 | 0011 0 0 | 1110

Прежде, чем перейти к дальнейшему выполнению микропрограммы, увеличим содержимое счетчика команд на 1.

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
6) | PCL+1 -> PCL | 1111 1111 | 1011 | 1111 | 1100 1 0 | 1011
7) | PCH+C -> PCH | 1111 1111 | 1010 | 1111 | 1100 1 0 | 1010

После считывания команды её необходимо декодировать. Это можно выполнить микропрограммным способом проверяя каждый бит регистра команд и осуществляя ветвление по результату проверки или включить в состав блока микропрограммного управления аппаратный дешифратор команд, который сможет осуществить ветвление микропрограммы на 256 ветвей за один такт синхронизации микропроцессора. Выберем именно этот путь. Восьмым тактом микропрограмма направляется на одну из 256 ветвей, отвечающую за выполнение считанной инструкции. Например, если была считана команда MOV A, R0, то следующая микрокоманда будет выглядеть следующим образом:

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
9) | R0 -> ACC | 1111 1111 | 0000 | 1111 | 1100 0 0 | 1000

И так как в этом случае команда полностью выполнена, то счётчик микрокоманд сбрасывается для выполнения следующей команды.

Рассмотрим ещё один пример. Пусть из системной памяти считывается команда безусловного перехода JMP 1234. Первые восемь микрокоманд совпадают для всех команд микропроцессора. Различие наступает начиная с девятой команды, которая зависит от конкретной инструкции. При выполнении команды безусловного перехода необходимо считать адрес новой команды, который записан в байтах, следующих за кодом операции. Этот процесс аналогичен считыванию кода операции:

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
9) | PCH -> RAH | 1111 1111 | 1111 | 1010 | 0011 0 0 | 1100
10) | PCL -> RAL | 1111 1111 | 1111 | 1011 | 0011 0 0 | 1101
11) | const -> CR | 1111 1110 | 1111 | 1111 | 0011 0 0 | 1110
12) | data -> RI | 1111 1111 | 1100 | 1111 | 1100 0 0 | 1001
13) | const -> CR | 1111 1111 | 1111 | 1111 | 0011 0 0 | 1110
14) | PCL+1 -> PCL | 1111 1111 | 1011 | 1111 | 1100 1 0 | 1011
15) | PCH+C -> PCH | 1111 1111 | 1010 | 1111 | 1100 1 0 | 1010

Теперь считаем второй байт адреса перехода.

 |  | Поля микрокоманды БОС
N | Описание | константа | источник A | источник B | команда | приёмник
16) | PCH -> RAH | 1111 1111 | 1111 | 1010 | 0011 0 0 | 1100
17) | PCL -> RAL | 1111 1111 | 1111 | 1011 | 0011 0 0 | 1101
18) | const -> CR | 1111 1110 | 1111 | 1111 | 0011 0 0 | 1110
19) | data -> PCH | 1111 1111 | 1100 | 1111 | 1100 0 0 | 1110
20) | const -> CR | 1111 1111 | 1111 | 1111 | 0011 0 0 | 1110
21) | RI -> PCL | 1111 1111 | 1001 | 1111 | 1100 1 0 | 1001

В результате выполнения этой микропрограммы в программный счётчик будет загружен адрес, записанный во втором и третьем байтах команды безусловного перехода JMP 1234. Временная диаграмма, формируемая рассмотренной микропрограммой, приведена на рисунке 3.

RdJmp.gif (6120 bytes)

Рисунок 3. Временная диаграмма выполнения команды JMP 1234.

[ Главная ]


Блок обработки сигналов микропроцессора

 Дата последнего обновления файла 22.08.2005

Принципы работы микропроцессора.

В настоящее время наметилось два направления развития микропроцессоров:

  • RISC процессоры (процессоры с сокращённым набором команд)
  • CISC процессоры (процессоры с полным набором команд)

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

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

В большинстве случаев быстродействие RISC процессоров выше чем CISC процессоров, однако при выборе процессора нужно учитывать все параметры в целом, т.к. тактовая частота может оказаться значительно ниже по сравнению с CISC процессором (особенно если в нём применяются специальные меры по повышению производительности), разрядность команды может оказаться выше чем у CISC процессора (что чаще всего и бывает). В результате общий объём исполняемой программы для RISC процессора превысит объём подобной программы для CISC процессора.

В качестве примера рассмотрим устройство процессора с полным набором команд. Здесь будет рассматриваться упрощённая модель процессора для облегчения понимания работы. CISC микропроцессор состоит из двух частей:

  • Блок обработки сигналов;
  • Блок микропрограммного управления.

Блок обработки сигналов микропроцессора.

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

Блок обработки сигналов предназначен для считывания команд из системной памяти и выполнения считанных команд. Эти действия он осуществляет под управлением блока микропрограммного управления, который формирует последовательность микрокоманд, необходимую для выполнения команды. Схема одного из вариантов построения блока обработки сигналов приведена на рисунке 1.

Рисунок 1. Блок обработки сигналов.

В этой схеме явно просматривается, что отдельные биты микрокоманды (показанной внизу схемы) управляют различными блоками БОС, поэтому их можно рассматривать независимо друг от друга. Такие группы бит называются полями микрокоманды и составляют формат этой микрокоманды. Кроме бит, управляющих блоком обработки сигналов есть биты, управляющие блоком микропрограммного управления. Формат микрокоманды рассматриваемого процессора приведён на рисунке 3. Результат выполнения микрокоманды записывается по сигналу общей синхронизации CLK.

Для хранения и декодирования выполняемой команды выделим восьмиразрядный регистр, который назовём RI.

Для реализации более простой системы команд выберем аккумуляторный процессор. Соответственно необходимо один из регистров выделить в качестве аккумулятора ACC.

Так как мы выбрали для примера восьмиразрядный микропроцессор, то и все регистры в этом процессоре восьмиразрядные. Максимальное число, которое можно записать в такой регистр - 255, но для большинства программ такого объёма памяти недостаточно. В приведённой на рисунке 1 схеме для того, чтобы получить 16-ти разрядный адрес используется два 8-ми разрядных регистра адреса. Теперь максимальное число, которое можно записать в этих двух регистрах будет 65535, что вполне достаточно для записи программ и обрабатываемых ими данных. Для того, чтобы различать регистр старшего и младшего байта адреса обозначим их как PCH - старший байт и PCL- младший байт. Это позволяет при помощи восьмиразрядного АЛУ формировать 16-ти разрядный адрес.

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

Ещё один регистр используется для формирования сигналов управления системной шины микропроцессора. В простейшем случае это сигналы записи (WR) и чтения (RD). Для формирования необходимых сигналов достаточно записывать в определённый бит регистра логический 0 или 1. Определим формат регистра управления. Пусть нулевой бит этого регистра будет сигналом записи, а первый бит этого регистра будет сигналом чтения. Остальные биты этого регистра пока не важны. Полученный формат приведён на рисунке 2.

Рисунок 2. Формат регистра управления (CR).

Блок микропрограммного управления

Блок микропрограммного управления предназначен для формирования последовательности микрокоманд блока обработки сигналов. В простейшем случае его можно построить на счетчике с возможностью предзаписи и ПЗУ. Схема такого блока приведена на рисунке 3.

Рисунок 3. Блок микропрограммного управления.

В этой схеме адрес очередной микрокоманды формирует двоичный счётчик. Если требуется осуществить безусловный или условный переход, то новый адрес записывается из ПЗУ в этот счётчик как в обычный параллельный регистр по сигналу параллельной записи V. Переход к следующему адресу микрокоманды производится по сигналу общей синхронизации CLK.

Рисунок 4. Формат микрокоманды процессора.

[ Главная ]


Принципы построения параллельного порта

 Дата последнего обновления файла 22.08.2005

Принципы построения параллельного порта.

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

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

В зависимости от направления передачи данных параллельные порты называются портами ввода, вывода или портами ввода вывода.

Структурная схема порта ввода приведена на рис 1.

PortIn.gif (2913 bytes)

Рис. 1. Структурная схема порта ввода.

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

Выход шинного формирователя подключается к внутренней шине. Значение сигнала с внешнего вывода порта считывается по сигналу "RD".

Для отображения этого шинного формирователя только в одну ячейку памяти адресного пространства микропроцессорного устройства в составе порта ввода-вывода всегда присутствует дешифратор адреса.

Так как с точки зрения программиста эта ячейка памяти ничем не отличается от регистра данных порта вывода, то по аналогии она называется регистром данных порта ввода.

Структурная схема порта вывода приведена на рис 2.

PortOut.gif (2701 bytes)

Рис. 2. Структурная схема порта вывода.

В качестве порта вывода может быть использован параллельный регистр. В порт вывода возможна только запись.

Данные с внутренней шины микроконтроллера записываются в регистр по сигналу "WR". Выходы "Q" регистра могут быть использованы как источники логических уровней для управления внешними устройствами.

Для отображения этого регистра только в одну ячейку памяти адресного пространства микропроцессорного устройства в составе порта ввода-вывода всегда присутствует дешифратор адреса. Этот регистр называется регистром данных порта вывода.

Так как из порта ввода возможно только чтение, а в порт вывода возможна только запись, то для них обычно отводится один и тот же адрес в адресном пространстве памяти микропроцессора.

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

IOPort.gif (1665 bytes)

Рис. 3. Структурная схема параллельного порта ввода-вывода.

В некоторых микропроцессорах для портов ввода вывода выделяется отдельное адресное пространство. В этом случае для записи в порт и для чтения из порта используются отдельные сигналы чтения и записи. Чаще всего они называются IOWR# и IORD#.

Параллельные порты, предназначенные для обмена данными между компьютерами, или компьютером и принтером, устроены несколько иначе. Основным отличием обмена данных между компьютерами или контроллерами от обмена данными между компьютером и простым внешним устройством является большой объём передаваемых данных. В этом случае недостаточно выдачи на выход порта одного или даже нескольких байт информации, поэтому приходится передавать данные последовательно байт за байтом через один и тот же параллельный порт. Байты необходимо каким либо образом отличать друг от друга, поэтому вводится специальный сигнал синхронизации CLK, который позволяет отличать один байт от другого. Для формирования такого сигнала можно воспользоваться вторым параллельным портом, и получить его программным способом, но обычно этот сигнал формируется аппаратно из сигнала WR# при записи очередного байта в параллельный порт вывода. Временная диаграмма обмена данными через параллельный порт приведена на рисунке 4.

DiagParP.gif (2742 bytes)

Рис. 4. Временная диаграмма работы параллельного порта.

В лекции приведены только основы работы параллельного порта. Кому интересно познакомиться с особенностями работы параллельных портов может обратиться к специализированной литературе.

Далеко не полную информацию по LPT порту универсального компьютера можно посмотреть здесь.

[ Главная ]


Статические ОЗУ

 Дата последнего обновления файла 22.08.2005

Статические оперативные запоминающие устройства (ОЗУ)

В радиоаппаратуре часто требуется хранение временной информации, значение которой не важно при включении устройства. Такую память можно было бы построить на микросхемах EEPROM или FLASH -памяти, но, к сожалению, эти микросхемы дороги, обладают малым количеством перезаписей и чрезвычайно низким быстродействием при считывании и особенно записи информации. Для хранения временной информации можно воспользоваться параллельными регистрами. Так как запоминаемые слова не нужны одновременно, то можно воспользоваться механизмом адресации, который применяется в ПЗУ.

Схемы, в которых в качестве запоминающей ячейки используется параллельный регистр называется статической ОЗУ, т.к. информация в ней сохраняется все время, пока к микросхеме подключено питание. В отличие от статической ОЗУ в микросхемах динамического ОЗУ постоянно требуется регенерировать их содержимое, иначе информация будет испорчена.

В микросхемах ОЗУ присутствуют две операции: операция записи и операция чтения. Для записи и чтения информации можно использовать различные шины данных (как это делается в сигнальных процессорах), но чаще используется одна и та же шина данных. Это позволяет экономить выводы микросхем, подключаемых к этой шине и легко осуществлять коммутацию сигналов между различными устройствами.

Схема статического ОЗУ приведена на рисунке 1. Вход и выход микросхемы в этой схеме объединены при помощи шинного формирователя. Естественно, что схемы реальных ОЗУ будут отличаться от приведенной на этом рисунке. Тем не менее, приведенная схема позволяет понять как работает реальное ОЗУ. Изображение ОЗУ на принципиальных схемах приведено на рисунке 2.

Рисунок 1. Структурная схема ОЗУ.

Рисунок 2. Изображение ОЗУ на принципиальных схемах.

Сигнал записи WR позволяет записать логические уровни, присутствующие на информационных входах во внутреннюю ячейку ОЗУ. Сигнал чтения RD позволяет выдать содержимое внутренней ячейки памяти на информационные выходы микросхемы. В приведенной на рисунке 1 схеме невозможно одновременно производить операцию записи и чтения, но обычно это и не нужно.

Конкретная ячейка микросхемы выбирается при помощи двоичного кода - адреса ячейки. Объем памяти микросхемы зависит от количества ячеек, содержащихся в ней или, что то же самое, от количества адресных проводов. Количество ячеек в микросхеме можно определить по количеству адресных проводов возводя 2 в степень, равную количеству адресных выводов в микросхеме:

Вывод выбора кристалла CS позволяет объединять несколько микросхем для увеличения объема памяти ОЗУ. Такая схема приведена на рисунке 3.

Рисунок 3. Схема ОЗУ, построенного на нескольких микросхемах памяти.

Статические ОЗУ требуют для своего построения большой площади кристалла, поэтому их ёмкость относительно невелика. Статические ОЗУ применяются для построения микроконтроллерных схем из-за простоты построения принципиальной схемы и возможности работать на сколь угодно низких частотах, вплоть до постоянного тока. Кроме того статические ОЗУ применяются для построения КЭШ-памяти в универсальных компьютерах из-за высокого быстродействия статического ОЗУ.

Временные диаграммы чтения из статического ОЗУ совпадают с временными диаграммами чтения из ПЗУ. Временные диаграммы записи в статическое ОЗУ и чтения из него приведены на рисунке 4.

Рисунок 4. Временная диаграмма обращения к ОЗУ принятая для схем, совместимых со стандартом фирмы INTEL.

На рисунке 4 стрелочками показана последовательность, в которой должны формироваться управляющие сигналы. На этом рисунке RD - это сигнал чтения; WR - сигнал записи; A - сигналы выбора адреса ячейки (так как отдельные биты в шине адреса могут принимать разные значения, то показаны пути перехода как в единичное, так и в нулевое состояние); DI - входная информация, предназначенная для записи в ячейку ОЗУ, расположенную по адресу A1; DO - выходная информация, считанная из ячейки ОЗУ, расположенной по адресу A2.

Рисунок 5. Временная диаграмма обращения к ОЗУ принятая для схем, совместимых со стандартом фирмы MOTOROLA.

На рисунке 5 стрелочками показана последовательность, в которой должны формироваться управляющие сигналы. На этом рисунке R/W - это сигнал выбора операции записи или чтения; DS - сигнал стробирования данных; A - сигналы выбора адреса ячейки (так как отдельные биты в шине адреса могут принимать разные значения, то показаны пути перехода как в единичное, так и в нулевое состояние); DI - входная информация, предназначенная для записи в ячейку ОЗУ, расположенную по адресу A1; DO - выходная информация, считанная из ячейки ОЗУ, расположенной по адресу A2.

[ Главная ]


Постоянные запоминающие устройства

 Дата последнего обновления файла 22.08.2005

Постоянные запоминающие устройства

Очень часто в различных применениях требуется хранение информации, которая не изменяется в процессе эксплуатации устройства. Это такая информация как программы в микроконтроллерах, начальные загрузчики и BIOS в компьютерах, таблицы коэффициентов цифровых фильтров в сигнальных процессорах. Практически всегда эта информация не требуется одновременно, поэтому простейшие устройства для запоминания постоянной информации можно построить на мультиплексорах. Схема такого постоянного запоминающего устройства приведена на рисунке 1.

Рисунок 1. Схема постоянного запоминающего устройства, построенная на мультиплексоре.

В этой схеме построено постоянное запоминающее устройство на восемь одноразрядных ячеек. Запоминание конкретного бита в одноразрядную ячейку производится запайкой провода к источнику питания (запись единицы) или запайкой провода к корпусу (запись нуля). На принципиальных схемах такое устройство обозначается как показано на рисунке 2.

Рисунок 2. Обозначение постоянного запоминающего устройства на принципиальных схемах.

Для того, чтобы увеличить разрядность ячейки памяти ПЗУ эти микросхемы можно соединять параллельно (выходы и записанная информация естественно остаются независимыми). Схема параллельного соединения одноразрядных ПЗУ приведена на рисунке 3.

Рисунок 3. Схема многоразрядного ПЗУ.

В реальных ПЗУ запись информации производится при помощи последней операции производства микросхемы - металлизации. Металлизация производится при помощи маски, поэтому такие ПЗУ получили название масочных ПЗУ. Еще одно отличие реальных микросхем от упрощенной модели, приведенной выше - это использование кроме мультиплексора еще и демультиплексора. Такое решение позволяет превратить одномерную запоминающую структуру в многомерную и, тем самым, существенно сократить объем схемы дешифратора, необходимого для работы схемы ПЗУ. Эта ситуация иллюстрируется следующим рисунком:

Рисунок 4. Схема масочного постоянного запоминающего устройства.

Масочные ПЗУ изображаются на принципиальных схемах как показано на рисунке 5. Адреса ячеек памяти в этой микросхеме подаются на выводы A0 ... A9. Микросхема выбирается сигналом CS. При помощи этого сигнала можно наращивать объем ПЗУ (пример использования сигнала CS приведён при обсуждении ОЗУ). Чтение микросхемы производится сигналом RD.

Рисунок 5. Обозначение масочного постоянного запоминающего устройства на принципиальных схемах.

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

Такие микросхемы называются программируемыми ПЗУ (ППЗУ) и изображаются на принципиальных схемах как показано на рисунке 6. В качестве примера можно назвать микросхемы 155РЕ3, 556РТ4, 556РТ8 и другие.

Рисунок 6. Обозначение программируемого постоянного запоминающего устройства на принципиальных схемах.

Программируемые ПЗУ оказались очень удобны при мелкосерийном и среднесерийном производстве. Однако при разработке радиоэлектронных устройств часто приходится менять записываемую в ПЗУ программу. ППЗУ при этом невозможно использовать повторно, поэтому раз записанное ПЗУ при ошибочной или промежуточной программе приходится выкидывать, что естественно повышает стоимость разработки аппаратуры. Для устранения этого недостатка был разработан еще один вид ПЗУ, который мог бы стираться и программироваться заново.

ПЗУ с ультрафиолетовым стиранием строится на основе запоминающей матрицы построенной на ячейках памяти, внутреннее устройство которой приведено на следующем рисунке:

Рисунок 7. Запоминающая ячейка ПЗУ с ультрафиолетовым и электрическим стиранием.

Ячейка представляет собой МОП транзистор, в котором затвор выполняется из поликристаллического кремния. Затем в процессе изготовления микросхемы этот затвор окисляется и в результате он будет окружен оксидом кремния - диэлектриком с прекрасными изолирующими свойствами. В описанной ячейке при полностью стертом ПЗУ заряда в плавающем затворе нет, и поэтому транзистор ток не проводит. При программировании микросхемы на второй затвор, находящийся над плавающим затвором, подаётся высокое напряжение и в плавающий затвор за счет тунельного эффекта индуцируются заряды. После снятия программирующего напряжения на плавающем затворе индуцированный заряд остаётся и, следовательно, транзистор остаётся в проводящем состоянии. Заряд на плавающем затворе может храниться десятки лет.

Структурная схема постоянного запоминающего устройства не отличается от описанного ранее масочного ПЗУ. Единственно вместо перемычки используется описанная выше ячейка. В репрограммируемых ПЗУ стирание ранее записанной информации осуществляется ультрафиолетовым излучением. Для того, чтобы этот свет мог беспрепятственно проходить к полупроводниковому кристаллу, в корпус микросхемы встраивается окошко из кварцевого стекла.

При облучении микросхемы, изолирующие свойства оксида кремния теряются и накопленный заряд из плавающего затвора стекает в объем полупроводника и транзистор запоминающей ячейки переходит в закрытое состояние. Время стирания микросхемы колеблется в пределах 10 - 30 минут.

Количество циклов записи - стирания микросхем находится в диапазоне от 10 до 100 раз, после чего микросхема выходит из строя. Это связано с разрушающим воздействием ультрафиолетового излучения. В качестве примера таких микросхем можно назвать микросхемы 573 серии российского производства, микросхемы серий 27сXXX зарубежного производства. В этих микросхемах чаще всего хранятся программы BIOS универсальных компьютеров. Репрограммируемые ПЗУ изображаются на принципиальных схемах как показано на рисунке 8.

Рисунок 8. Обозначение репрограммируемого постоянного запоминающего устройства на принципиальных схемах.

Так так корпуса с кварцевым окошком очень дороги, а также малое количество циклов записи - стирания привели к поиску способов стирания информации из ППЗУ электрическим способом. На этом пути встретилось много трудностей, которые к настоящему времени практически решены. Сейчас достаточно широко распространены микросхемы с электрическим стиранием информации. В качестве запоминающей ячейки в них используются такие же ячейки как и в РПЗУ, но они стираются электрическим потенциалом, поэтому количество циклов записи - стирания для этих микросхем достигает 1000000 раз. Время стирания ячейки памяти в таких микросхемах уменьшается до 10 мс. Схема управления для таких микросхем получилась сложная, поэтому наметилось два направления развития этих микросхем:

  1. ЕСППЗУ
  2. FLASH -ПЗУ

Электрически стираемые ППЗУ дороже и меньше по объему, но зато позволяют перезаписывать каждую ячейку памяти отдельно. В результате эти микросхемы обладают максимальным количеством циклов записи - стирания. Область применения электрически стираемых ПЗУ - хранение данных, которые не должны стираться при выключении питания. К таким микросхемам относятся отечественные микросхемы 573РР3, 558РР и зарубежные микросхемы серии 28cXX. Электрически стираемые ПЗУ обозначаются на схемах как показано на рисунке 9.

Рисунок 9. Обозначение электрически стираемого постоянного запоминающего устройства на принципиальных схемах.

В последнее время наметилась тенденция уменьшения габаритов ЭСППЗУ за счет уменьшения количества внешних ножек микросхем. Для этого адрес и данные передаются в микросхему и из микросхемы через последовательный порт. При этом используются два вида последовательных портов - SPI порт и I2C порт (микросхемы 93сXX и 24cXX серий соответственно). Зарубежной серии 24cXX соответствует отечественная серия микросхем 558РРX.

FLASH - ПЗУ отличаются от ЭСППЗУ тем, что стирание производится не каждой ячейки отдельно, а всей микросхемы в целом или блока запоминающей матрицы этой микросхемы, как это делалось в РПЗУ.

Рисунок 10. Обозначение FLASH памяти на принципиальных схемах.

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

Рисунок 11. Временная диаграмма чтения информации из ПЗУ.

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

[ Главная ]


Принципы построения последовательного порта

 Дата последнего обновления файла 22.08.2005

Принципы построения последовательного порта.

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

  1. синхронные последовательные порты;
  2. асинхронные последовательные порты.

Синхронные последовательные порты

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

DiagSerP.gif (4407 bytes)

Рисунок 1. Временная диаграмма передачи одного кадра двоичной информации по последовательному порту.

Временная диаграмма, приведённая на рисунке 1, применяется в синхронных последовательных портах, которые используются чаще всего в сигнальных процессорах для обмена информацией с кодеками речи, аналого-цифровыми и цифро-аналоговыми преобразователями. На приведённой временной диаграмме показаны два сигнала синхронизации: сигнал тактовой синхронизации CLK и сигнал кадровой синхронизации FS. Сигнал кадровой синхронизации формируется аппаратно из сигнала WR# при записи очередного байта в параллельный порт вывода. Полярность сигналов синхронизации зависит от конкретного типа применяемых микросхем, поэтому в большинстве сигнальных процессоров возможна настройка полярности сигналов синхронизации.

Упрощённая схема синхронного последовательного порта приведена на рисунке 2. На этой схеме видно, что в состав последовательного порта входит параллельный порт, который позволяет подключаться к системной шине микропроцессора. Для преобразования параллельного кода, который поступает из системной шины в последовательный, используется сдвиговый регистр. При обращении центрального процессора к последовательному порту вырабатывается сигнал записи в последовательный порт, который подаётся на вход параллельной записи V универсального регистра. Этот же сигнал используется в качестве сигнала кадровой синхронизации FS. Сигнал тактовой синхронизации CLK, вырабатываемый отдельным генератором, подаётся на вход последовательного сдвига C универсального регистра порта.

PoslPort.gif (3025 bytes)

Рисунок 2. Упрощённая схема синхронного последовательного порта

Количество передаваемых в одном кадре бит может меняться от восьми до тридцатидвух. В качестве примера использования синхронного последовательного порта на рисунке 3 приведена схема подключения аналого-цифрового преобразователя фирмы Analog Devices к синхронному последовательному порту сигнального процессора той же фирмы.

SxrSPort.gif (3869 bytes)

Рисунок 3. Схема подключения кодека к синхронному последовательному порту.

В рассмотренной схеме синхронного последовательного порта на приёмном конце необходимо подсчитывать количество тактовых импульсов, прошедшее после импульса кадровой синхронизации. Кроме того, в таком синхронном последовательном порту информация передаётся непрерывно, что, конечно, удобно для устройств с непрерывным потоком информации, как, например, в кодеках речи. Но существуют устройства, к которым необходимо обращаться только периодически, как, например, синтезаторы частоты, микросхемы приёмников, блоков цветности телевизоров, микросхем памяти данных и многие другие устройства. В этих случаях используются другие виды синхронных последовательных портов такие как SPI порт и I2C шина. Временная диаграмма SPI интерфейса приведена на рисунке 4.

DiagSPI.gif (4889 bytes)

Рисунок 4. Временная диаграмма SPI интерфейса.

Основное отличие этого интерфейса от приведённого выше, заключается в том, что сигнал тактовой синхронизации передаётся только в момент действия импульса кадровой синхронизации. Активный уровень сигнала кадровой синхронизации длится до окончания передачи последнего бита в передаваемом кадре. По одним и тем же линиям передачи данных MISO (вход для главного, выход для ведомого) и MOSI (выход для главного, вход для ведомого) может передаваться информация к совершенно различным микросхемам. Выбор, для какой из микросхем предназначена информация, производится сигналом SS (выбор ведомого). В SPI интерфейсе в приёмнике не требуется счётчик тактовых импульсов. Запись принятой информации производится по окончанию кадрового импульса.

Если в устройстве используется несколько микросхем, то количество линий выбора ведомого становится значительным, поэтому в таких случаях используется ещё один вид синхронного последовательного интерфейса: I2C шина. Временная диаграмма этого интерфейса приведена на рисунке 5. В I2C шине приём и передача данных, а также передача адреса микросхемы и адреса регистра внутри микросхемы, к которому осуществляется обращение, производится по одному и тому же проводу. Для подключения к этому проводу используются микросхемы с открытым коллектором. Нагрузкой для всех микросхем, подключенных к линии SDA служит внешний резистор. Естественно, что скорость передачи данных по такому порту будет ниже, по сравнению с SPI портом. Тактовая синхронизация в I2C шине передаётся по линии SCL. Начало работы с микросхемой обозначается особой комбинацией сигналов SDA и SCL, которая называется условием старта. Эта же комбинация одновременно осуществляет кадровую синхронизацию. Завершение работы с микросхемой обозначается ещё одной комбинацией сигналов SDA и SCL. В качестве примера микросхем, использующих интерфейс I2C можно назвать микросхемы EEPROM серии 24сXX.

DiagI2C.gif (4902 bytes)

Рисунок 5. Временная диаграмма I2C интерфейса.

Асинхронные последовательные порты

Рассмотренные синхронные последовательные порты позволяют достигнуть больших скоростей передачи данных, но провод, по которому ведётся передача синхросигнала, практически не несёт информации. Такой сигнал можно было бы сформировать и на приёмном конце линии передачи, если заранее договориться о скорости передачи. Единственная проблема - это то, что невозможно построить два абсолютно одинаковых генератора. Генераторы необходимо синхронизировать. Для синхронизации внутренних генераторов используется особое условие начала асинхронной передачи: старт. Всё время, пока не ведётся передача информации, на линии присутствует стоп-сигнал единичного уровня. Перед началом передачи каждого байта передаётся старт-бит, сигнализирующий приемнику о начале посылки данных, за которым следуют информационные биты. Стартовый бит всегда передаётся нулевым уровнем с длительностью, равной длительности информационных бит. В некоторых случаях после передачи информационных бит может передаваться, бит паритета (четности). Завершается передача данных стоп-сигналом. Минимальная длительность стопового сигнала должна быть 1,5 длительности информационных бит, но обычно используют паузу между соседними пакетами данных две длительности информационного бита. Временная диаграмма передаваемых сигналов при асинхронной передаче приведена на рисунке 6.

DiagUART.gif (1878 bytes)

Рисунок 6. Временная диаграмма передаваемых сигналов при асинхронной передаче.

Продолжительность стопового бита не ограничена. Это позволяет регулировать скорость передачи в зависимости от скорости поступления информации.

Асинхронные последовательные порты широко используются в современной вычислительной технике. Для получения дополнительной информации можно обратиться к дополнительной литературе или к файлу

[ Главная ]


Принципы построения таймеров

 Дата последнего обновления файла 22.08.2005

Принципы построения таймеров.

Таймеры предназначены для формирования временных интервалов, позволяя микропроцессорной системе работать в режиме реального времени.

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

Генератор частоты, входящий в состав таймера, определяет минимальный интервал времени, который может определять таймер. Интервалы времени, задаваемые таймером, могут устанавливаться только из дискретного набора допустимых времён. Дискретность установки этих интервалов времени тоже определяется частотой задающего генератора. Разрядность цифрового счётчика, входящего в состав таймера, определяет максимальный интервал времени, который может определять таймер.

Обычно используются 16-ти разрядные таймеры, поэтому, для подключения такого таймера к 8-ми разрядному процессору требуется два параллельных порта. Кроме того, таймером нужно управлять. Таймер нужно включать и выключать, часто требуется определять не возникало ли переполнение таймера (факт переполнения легко запомнить в дополнительном триггере, подключенном к выходу переноса счетчика таймера). Этот триггер называется флагом переполнения таймера. Триггер (флаг) включения и выключения таймера и флаг переполнения таймера подключают к системной шине микропроцессора через дополнительный порт ввода вывода.

Структурная схема таймера, построенного по описанным выше принципам, приведена на рисунке 1.

Рисунок 1. Структурная схема таймера.

В зависимости от типа использованного цифрового счетчика таймеры бывают суммирующие или вычитающие. Если в таймере используется суммирующий счётчик, то таймер называется суммирующим. Если в таймере используется вычитающий счётчик, то таймер называется вычитающим.

Использование вычитающего счётчика позволяет проще задавать интервалы времени. В этом случае записываемый в таймер код будет соответствовать интервалу времени:

В случае использования суммирующего таймера код, записываемый в таймер для задания интервала времени, определяется из другой формулы:

В этой формуле код, который заносится в таймер, представляет собой дополнение кода интервала времени до максимального кода, который можно записать в таймер. Максимальный код таймера определяется по разрядности таймера. В рассмотренном примере разрядность таймера равна 16. Это означает, что максимальный код равен 65535.

Достаточно часто суммирующие таймеры используются в режиме свободнобегущего таймера. Схема такого таймера приведена на рисунке 2.

Рисунок 2. Структурная схема свободнобегущего таймера с модулем сравнения.

Свободнобегущие таймеры используются как системные часы, задающие время внутри микропроцессорной системы. Для задания промежутков времени микропроцессор считывает значение текущего системного времени и суммирует с ним код задаваемого промежутка времени. Полученный результат записывается в регистр сравнения таймера. При совпадении значений таймера и регистра сравнения устанавливается флаг совпадения. Значение этого флага можно определить программным опросом или воспользоваться механизмом прерывания работы процессора.

Часто с одним свободно бегущим таймером работает несколько модулей сравнения. В этом случае они образуют набор модулей сравнения (PCA). Практически все современные микроконтроллеры и сигнальные процессоры оснащены таймерами с такими наборами модулей.

Кроме модулей сравнения с свободнобегущим таймером работают модули захвата, которые позволяют аппаратно запоминать время какого-либо внешнего события без участия центрального процессора. Структурная схема свободнобегущего таймера с модулем захвата приведена на рисунке 3.

Рисунок 3. Структурная схема свободнобегущего таймера с модулем захвата.

[ Главная ]


Классификация микропроцессоров

Универсальные микропроцессы.

Универсальные микропроцессоры применяются в вычислительной технике и в настоящее время именно на них отрабатываются самые передовые решения по повышению быстродействия микросхем.

Паразитные ёмкости печатной платы компьютера или другого устройства, в котором используется микропроцессор, не позволяют достигнуть предельного быстродействия, с которым может работать кристалл микропроцессора. Кроме того, невозможно реализовать кварцевые резонаторы на частоты, на которых работают современные микропроцессоры. Поэтому внутренняя и внешняя тактовая частота микропроцессора различаются. Обычно внутренняя тактовая частота в несколько раз выше внешней тактовой частоты микропроцессора.

Умножение внешней тактовой частоты внутри кристалла процессора производится при помощи цепи фазовой автоподстройки частоты, поэтому для установления стабильной внутренней частоты микропроцессора требуется некоторое время, определяемое обычно десятками микросекунд.

Первым фактором, огранивающим быстродействие микропроцессорной системы в целом, является то, что для увеличения доступной ёмкости системной памяти компьютера, микросхемы ОЗУ выбираются динамического вида. Однако эти ОЗУ обладают относительно невысоким быстродействием. В результате возникает противоречие между высоким быстродействием микропроцессора и быстродействием системной памяти, которая ограничивает быстродействие микропроцессорной системы в целом.

В качестве решения этой проблемы в современных компьютерах предлагается использование КЭШ-памяти. Эта память с точки зрения программиста никак не видна и общий объём системной памяти не увеличивает. Предназначение КЭШ-памяти - увеличить общее быстродействие системной памяти в целом.

КЭШ-память выполняется в виде статической памяти небольшого размера и высокого быстродействия. КЭШ-память ставится как буфер между основной памятью и микропроцессором. Она располагается на материнской плате. Естественно что при первом обращении к системной памяти быстродействие снижается на задержку, вносимую КЭШ-памятью. Выигрыш в быстродействии достигается при повторном обращении к одному и тому же участку памяти. В этом случае обращение к основной памяти не требуется, так как в КЭШ-памяти уже хранится копия содержимого основной памяти компьютера. Учитывая, что выполнение программ обычно реализуется в виде циклов, когда один и тот же участок программного кода повторяется многократно, общее быстродействие системы в целом будет определяться быстродействием КЭШ-памяти.

Всю логику работы с КЭШ-памятью выполняет контроллер памяти, входящий в набор микросхем (Chip Set) материнской платы компьютера.

Рассмотренный выше метод увеличивает общее быстродействие системной памяти, но при этом быстродействие повышается только до значения тактовой частоты системной шины (внешняя тактовая частота микропроцессора). Согласовать внутреннее быстродействие микропроцессора и быстродействие системной шины позволяет использование внутренней КЭШ памяти. Естественно объём этой внутренней памяти меньше объёма КЭШ-памяти, расположенной на материнской плате компьютера.

При рассмотрении принципов работы цифровых микросхем мы узнали, что потребляемый микросхемой ток определяется быстродействием микросхемы, поэтому внутренняя КЭШ-память в свою очередь разделяется на два уровня: первый уровень малого объёма, но высокого быстродействия, совпадающего с внутренним быстродействием микропроцессора, и второй уровень, с большим объёмом памяти, но с меньшим быстродействием. По аналогии с этими двумя уровнями КЭШ-памяти, КЭШ-память, расположенную на материнской плате называют КЭШ-памятью третьего уровня.


Комментарии

 Дата последнего обновления файла 07.06.2005

Применение комментариев

Комментарий используется для увеличения наглядности исходного текста программы и может содержать любой печатный символ кода ASCII, в том числе включать пробелы и табуляцию. При компиляции исходного текста программы в исполняемый или объектный код комментарии игнорируются программами-трансляторами. Рассмотрим конкретные примеры использования комментариев.

Комментарии применяются при написании программы для того, чтобы поставить в соответствие блоку алгоритма написанные операторы программы. Так как алгоритм может быть написан с различной степенью детализации, то это должно быть отображено при помощи различных видов комментариев, существенно отличающихся друг от друга.

Комментарии для блоков алгоритма с наибольшей степенью детализации обычно пишут справа от операторов, которые реализуют этот алгоритм.

Более крупные блоки алгоритма отражаются комментариями, пересекающими всю программу. Эти комментарии пишут буквами верхнего регистра, чтобы было легко заметить этот комментарий.

Ещё более крупные блоки алгоритма выделяют специальными символами, которые сразу бросаются в глаза (обычно это звёздочки или символы знака минус '-'). Пример использования комментариев на языке программирования ассемблер приведён ниже:

  ...
;ПЕРЕДАТЬ ДВА ЧИСЛА ПО ПОСЛЕДОВАТЕЛЬНОМУ ПОРТУ  КОММЕНТАРИЙ АЛГОРИТМА ВТОРОГО УРОВНЯ

  MOV G_Per, #56   ;Передать число 56 через     КОММЕНТАРИЙ, ПОЯСНЯЮЩИЙ ДЕЙСТВИЯ
  CALL PeredatByte ;последовательный порт       НЕСКОЛЬКИХ ОПЕРАТОРОВ

  MOV G_Per, #37   ;Передать число 37 через
  CALL PeredatByte ;последовательный порт
;------------------------------------------     КОНЕЦ БЛОКА АЛГОРИТМА ВТОРОГО УРОВНЯ
  ...

;********************************************
;Подпрограмма передачи байта                     ТАК ВЫДЕЛЯЮТСЯ ОСОБО
;через последовательный порт                     ВАЖНЫЕ БЛОКИ АЛГОРИТМА
;********************************************
PeredatByte:
  JB TI,$       ;Если предыдущий байт передан    КОММЕНТАРИЙ, ПОЯСНЯЮЩИЙ ДЕЙСТВИЕ КОМАНДЫ В ДАННОМ КОНКРЕТНОМ СЛУЧАЕ
  MOV SBUF,G_Per  ;то передать очередной байт
  RET

В приведённом примере показан отрывок программы на языке ASM-51, но точно так же можно использовать комментарии и на языке высокого уровня. При этом нужно помнить, что те действия, которые абсолютно ясны в момент написания программы через месяц вызовут затруднения даже у программиста, написавшего эту программу, не говоря уже о человеке, который видит эту программу впервые.

Программа, написанная на языке программирования ассемблер, читается прежде всего по комментариям и только потом, если она по каким либо причинам не работает, проверяется на соответствие комментария конкретным операторам языка программирования.

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

[ Главная ]


Определения

 Дата последнего обновления файла 26.09.2005

Определения

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

Глобальные переменные существуют в течение всей работы устройства. К глобальным переменным относятся внутренние и внешние устройства микроконтроллера, а также переменные, через которые осуществляется обмен данными между подпрограммами.

Директива - это команда программе-транслятору выполнить какое-либо действие.

Загрузочный модуль - это готовая программа в машинных кодах, которая может быть записана во внутреннюю память микроконтроллера. Может храниться на компьютере в бинарном или HEX формате.

Идентификатор - это символическое обозначение объекта программы. В качестве идентификатора может быть использована любая последовательность букв и цифр. Идентификатор может начинаться только с буквы! Это позволяет отличать его от числа.

Интерпретатор - программа, осуществляющая трансляцию одного оператора исходного текста программы в машинные коды.

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

Исходный модуль - это текстовый файл части программы, написанный на каком-либо языке программирования. Исходный модуль обычно оформляется специальным образом для того, чтобы он мог быть оттранслирован (в объектный модуль).

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

Ключевые слова - являются определяющей частью оператора любого языка программирования.

Комментарий - это пояснение к программе, которое не оказывает влияния на ее выполнение.

Компилятор - программа, осуществляющая трансляцию всего исходного текста программы в машинные коды.

Локальные переменные имеют значение только в течение выполнения какого-то участка программы или подпрограммы. Локальные переменные обычно размещаются во внутренних регистрах микроконтроллера для увеличения быстродействия программы и сокращения её объёма.

Модуль - это часть программы, которая может быть откомпилирована отдельно. В дальнейшем готовые откомпилированные модули (объектные модули) могут объединяться в готовые программы или библиотеки. В модулях обычно хранятся подпрограммы, константы или переменные.

Объектный модуль программы получается в результате трансляции исходного текста модуля. В состав объектного модуля программы помещается оттранслированный код модуля, информация для редактора связей, позволяющая объединять модули в единую программу, и отладочная информация (переменные, константы, метки и их адреса). Для объектного модуля по умолчанию используется имя файла, совпадающее с именем файла исходного модуля и с расширением obj.

Параметры подпрограммы - это локальные переменные подпрограммы, которые доступны из вызывающей эту подпрограмму программы. Параметры подпрограммы записываются в скобках после имени подпрограммы. Например:

 real sin(real x);
 sin(0.707);
 sin(a);

Параметр программы - это последовательность символов, которая печатается после названия исполняемого файла. В качестве параметров могут использоваться команды, ключи и имена файлов, над которыми будут производиться какие-либо действия.

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

Подпрограмма-заглушка это подпрограмма, которая ничего не выполняет, а только возвращает управление главной программе. Действие, которое в дальнейшем должна выполнять эта программа, отображается в названии подпрограммы-заглушки.

Формальные параметры подпрограммы - это локальные переменные, использующиеся в подпрограмме. Объявления параметров подпрограммы записываются в скобках после имени подпрограммы. Например:

 real sin(real x).

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

 sin(0.707).

Реальные параметры подпрограммы - это переменные, использующиеся в вызывающей подпрограмму программе. При вызове подпрограммы они уже должны содержать конкретные значения. Реальные параметры подпрограммы записываются в скобках после имени подпрограммы. Например:

a=0.707;
sin(a);

Редактор связей - программа, позволяющая осуществить связывание отдельных оттранслированных программных модулей в единую программу.

Число - может быть целой знаковой или беззнаковой константой, константой с плавающей запятой, символьной константой и литеральной строкой.

[ Главная ]


Подпрограммы процедуры и подпрограммы функции

 Дата последнего обновления файла 07.06.2005

Подпрограммы процедуры и подпрограммы функции.

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

Подпрограммы процедуры

Если подпрограмма только осуществляет действия над глобальными переменными, то такая подпрограмма называется процедурой. Эта подпрограмма может осуществлять управление какими-то устройствами или осуществлять какие-либо вычисления. Если производятся вычисления, то результат помещается в глобальную переменную для того, чтобы этим результатом могла воспользоваться другая подпрограмма или основная программа. Пример управления последовательным портом:

  ...
  G_Per=56;
  PeredatByte();
  ...
  G_Per=37;
  PeredatByte();
  ...

/**********************************************
Подпрограмма передачи байта
через последовательный порт
**********************************************/
void PeredatByte(void)
{do;while(TI==0)//Если предыдущий байт передан
 SBUF=G_Per     //то передать очередной байт
}

Рисунок 1. Пример подпрограммы - процедуры.

Часто подпрограмма должна выполнять действия над каким то числом, значение которого неизвестно в момент написания программы. Это число можно передать через глобальную переменную как показано на рисунке 1. Однако намного удобнее использовать подпрограмму с параметрами. На языке высокого уровня вызов такой подпрограммы будет выглядеть следующим образом:

  ...
  PeredatByte(56);
  ...
  PeredatByte(57);
  ...
/*******************************************************
Подпрограмма передачи байта через последовательный порт
********************************************************/
void PeredatByte(char byte)
{do;while(TI==0)    //Если предыдущий байт передан
 SBUF=byte;         //то передать очередной байт
}

Рисунок 2. Пример подпрограммы - процедуры с передачей данных через параметр подпрограммы.

Сравните с программой, приведённой на рисунке 1. Как по вашему, какая из программ более наглядная? В подпрограмму можно передавать и значительные объёмы данных, как например:

PeredatStroky("Напечатать строку");

Естественно, что в этом случае сама вызываемая подпрограмма должна быть написана несколько иначе по сравнению с предыдущим случаем.

Подпрограммы функции.

Часто требуется передавать результат вычислений из подпрограммы в основную программу. Для этого можно воспользоваться подпрограммой - функцией. Подпрограмма - функция возвращает вычисленное значение. Пример использования подпрограммы - функции:

Y=sin(x);

Использование подпрограмм-функций позволяет приблизить процесс написания программ к математической записи выражений, которые необходимо вычислить. Использование подпрограмм-функций позволяет увеличить наглядность программ и, в результате, увеличить скорость написания и отладки программ.

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

[ Главная ]


Многофайловые программы

 Дата последнего обновления файла 07.06.2005

Многофайловые программы.

В процессе написания программ обычно накапливаются подпрограммы и участки кода, которые можно использовать в нескольких программах. Эти участки кода можно копировать из программы в программу при помощи текстового редактора, в котором Вы пишете программы. Однако это может привести к некоторым неудобствам. Прежде всего, разрастается исходный текст программы, и в нём становится трудно ориентироваться при написании и редактировании программы. Кроме того, при обнаружении ошибок в отлаженном ранее участке кода или при переходе к работе с другими устройствами приходится искать включенные ранее участки кода и заменять их новыми.

Это трудоёмкая работа, которая приводит к ошибкам и, в конечном счёте, замедляет написание и отладку программ. Намного удобнее использовать хранить исходную программу в нескольких файлах, предоставляя работу по соединению этих файлов в единую программу транслятору.

Самым простым способом соединения нескольких файлов в одну программу является использование директивы включения текстового файла в исходный текст программы INCLUDE.

При использовании этой директивы в исходный текст программы добавляется содержимое включаемого файла и только после этого производится трансляция исходного текста программы в объектный или исполняемый код программы. Иными словами содержимое исходного файла программы и включаемого файла объединяются препроцессором во временном файле и только после этого производится трансляция полученного временного файла. Пример использования директивы INCLUDE на языке программирования Си:

#include
 <stdio.h> /*Файл стандартного ввода-вывода*/

#include
 <reg51.h> /*Файл описания регистров специальных функций микроконтроллера*/

... /*Остальная часть программы*/

Приведём содержимое включаемых файлов:

В результате программа-транслятор формирует временный файл следующего содержания:

а затем транслирует его в загружаемый модуль.

Точно таким же образом можно использовать включение файлов и на языке программирования ASM-51:

$include (stdio.asm) ;Файл стандартного ввода-вывода
$include (reg51.inc) ;Файл описания регистров специальных функций микроконтроллера

... ;Остальная часть программы

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

[ Главная ]


Многомодульные программы

 Дата последнего обновления файла 07.06.2005

Многомодульные программы.

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

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

Все эти проблемы могут быть решены при раздельной трансляции программы. То есть было бы неплохо уметь транслировать каждый файл с исходным текстом программы отдельно и соединять затем готовые оттранслированные участки программы.

Компиляторы, которые позволяют транслировать отдельные участки программы называются компиляторами с раздельной трансляцией.

Исходный текст программы, который может быть отдельно оттранслирован, называется программным модулем.

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

Раздельная трансляция программы возможна при использовании двух программ: транслятора исходного текста программы и редактора связей.

Программа редактор связей позволяет объединять несколько объектных файлов (модулей) в один. Для объединения нескольких модулей в исполняемую программу имена всех модулей передаются в редактор связей в качестве параметров при запуске этой программы. Пример вызова редактора связей из командной строки DOS для объединения трёх модулей:

rl51.exe progr.obj, modul1.obj, modul2.obj

В результате работы редактора связей в этом примере будет создан исполняемый модуль с именем progr.

На первый взгляд раздельная трансляция не должна вызывать каких либо проблем. Однако это не так. При компиляции исходного текста программы транслятор составляет таблицу ссылок на константы, переменные и команды. Если при втором просмотре исходного текста программы, во время которого формируется объектный модуль, транслятор не обнаружит имени переменной или метки в своей таблице, то будет сформировано сообщение об ошибке и объектный модуль будет стёрт с диска компьютера.

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

EXTRN DATA (BufInd, ERR)
EXTRN CODE (Podprogr)

Для того, чтобы редактор связей мог осуществить связывание модулей в единую программу, переменные и метки, объявленные по крайней мере в одном из модулей как EXTRN, в другом модуле должны быть объявлены как доступные для всех модулей при помощи директивы PUBLIC . Пример использования директивы PUBLIC на языке программирования ASM-51:

PUBLIC BufInd, Parametr
PUBLIC Podprogr, ?Podprogr?Byte

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

[ Главная ]


Отладка программ

 Дата последнего обновления файла 07.06.2005

Отладка программ.

После того, как программные модули были успешно оттранслированы, размещены по конкретным адресам и связаны между собой, для отладки программы можно воспользоваться любым из следующих методов:

  • внутрисхемным эмулятором
  • встроенным программным отладчиком
  • внешним программным отладчиком
  • отлаживаемым устройством с записанным в память программ двоичным кодом программы

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

Рисунок 1. Пример системы отладки программного обеспечения для микроконтроллеров.

До недавнего времени внутрисхемный эмулятор являлся отдельным устройством, подключаемым к разрабатываемой плате вместо микроконтроллера. В состав современных микроконтроллеров часто входит встроенный внутрисхемный эмулятор. При этом наиболее удобным интерфейсом для связи с компьютером является JTAG интерфейс, хотя некоторые фирмы-производители микросхем предлагают свой интерфейс.

При использовании интегрированной среды программирования предоставляется удобный интерфейс, позволяющий легко отлаживать разрабатываемую программу. В настоящее время стандартом де-факто стал интерфейс, похожий на программную оболочку Visual C. Пример внешнего вида такой программной оболочки приведён на рисунке 2.

Рисунок 2. Пример внешнего вида отладчика интегрированной системы отладки программного обеспечения.

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

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

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

При написании достаточно простых программ иногда для отладки программ используют только этот последний этап тестирования. Однако обнаружение, поиск и устранение ошибок при использовании только этого метода очень трудоёмок! Это то же самое, что пытаться настроить аппаратуру без использования приборов!

Способы отладки программ.

Отладка программ заключается в проверке правильности работы программы и аппаратуры. Программа, не содержащая синтаксических ошибок тем не менее может содержать логические ошибки, не позволяющие программе выполнять заложенные в ней функции. Логические ошибки могут быть связаны с алгоритмом программы или с неправильным пониманием работы аппаратуры, подключённой к портам микроконтроллера.

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

Для отладки программ обычно применяют три способа:

  1. Пошаговая отладка программ с заходом в подпрограммы;
  2. Пошаговая отладка программ с выполнением подпрограммы как одного оператора;
  3. Выполнение программы до точки останова.

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

Если в программе имеются уже отлаженные подпрограммы, то подпрограмму можно рассматривать, как один оператор программы и воспользоваться вторым способом отладки программ.

Если в программе существует достаточно большой участок программы, уже отлаженный ранее, то его можно выполнить, не контролируя переменные, на которые он воздействует. Использование точек останова позволяет пропускать уже отлаженную часть программы. Точка останова устанавливается в местах, где необходимо проверить содержимое переменных или просто проконтролировать, передаётся ли управление данному оператору.

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

Контроль данных при пошаговой отладке. При использовании встроенного отладчика программ для контроля переменных можно воспользоваться окном Watch. В большинстве случаев это намного выгоднее, чем использовать просмотр памяти данных. Переменные в этом окне отображаются в том формате, в котором они были объявлены в программе. Преобразование данных из одной формы представления в другую осуществляется встроенными средствами отладчика. Если же отладочная информация по какой либо причине была потеряна или программирование ведётся на языке программирования ассемблер, то состояние переменных можно проконтролировать просмотром содержимого внутренней и внешней памяти микроконтроллера. Для определения конкретной ячейки памяти микроконтроллера, занятой под переменную можно воспользоваться листингом, создаваемым редактором связей компилятора или самим компилятором, если не используется многомодульное программирование.

Практически все отладчики позволяют проконтролировать содержимое рабочих регистров текущего банка.


Подпрограммы

 Дата последнего обновления файла 07.06.2005

Применение подпрограмм при программировании.

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

Участок программы, к которому можно обращаться из различных мест программы для выполнения некоторых действий называется подпрограммой.

Проблема, с которой приходится сталкиваться при многократном использовании участков кодов, это в какое место памяти программ возвращаться после завершения подпрограммы? Обращение к подпрограмме производится из нескольких мест основной программы. Описанную ситуацию иллюстрирует рисунок 1. На этом рисунке изображено адресное пространство микроконтроллера. Младшие адреса адресного пространства на этом рисунке находятся в нижней части рисунка.

Рисунок 1. Вызов подпрограммы и возврат к выполнению основной программы.

Для того, чтобы получить возможность возвращаться на команду, следующую за командой вызова подпрограммы, требуется запомнить адрес этой команды. Адрес возврата хранится в особых ячейках памяти. После выполнения подпрограммы необходимо осуществить переход к адресу, который записан в этих ячейках.

Для обращения к подпрограмме и возврата из неё в систему команд микропроцессоров вводят специальные команды. В микроконтроллерах семейства MCS-51 это команды LCALL, ACALL для вызова подпрограммы и команда RET для возврата из подпрограммы. Эти команды не только осуществляют передачу управления на указанный адрес, но и запоминают адрес команды, следующей за командой вызова подпрограммы. Команда возврата из подпрограммы RET передаёт управление команде, адрес которой был запомнен командой вызова подпрограммы. Пример использования подпрограммы на языке программирования ASM-51 приведён на рисунке 2:

  ...
  MOV A,#56
  CALL PeredatByte
  ...
  MOV A,#37
  CALL PeredatByte
  ...

;********************************************
;Подпрограмма передачи байта
;через последовательный порт
;********************************************
PeredatByte:
  JB TI,$          ;Если предыдущий байт передан

  MOV SBUF,G_Per   ;то передать очередной байт
  RET

Рисунок 2. Пример вызова подпрограммы.

Внимание! Ни в коем случае нельзя попадать в подпрограмму любым способом кроме команды вызова подпрограммы CALL! В противном случае команда возврата из подпрограммы передаст управление случайному адресу! По этому адресу могут быть расположены данные, которые в этом случае будут интерпретированы как программа, или обратиться к внешней памяти, откуда будут считываться случайные числа.

Очень часто требуется из одной подпрограммы обращаться к другой подпрограмме. Такое обращение к подпрограмме называется вложенным. Количество вложенных подпрограмм называется уровнем вложенности подпрограмм. Максимально допустимый уровень вложенности подпрограмм определяется количеством ячеек памяти, предназначенных для хранения адресов возврата из подпрограмм.

Ячейки памяти, в которых хранятся адреса возврата из подпрограмм называются стеком. Логически эти ячейки памяти организованы так, чтобы считывание последнего записанного адреса производилось первым, а первого записанного адреса производилось последним. Такая логическая организация формируется специальным счётчиком. Этот счётчик называется указателем стека SP. Ячейка памяти, в которую в данный момент может быть записан адрес возврата из подпрограммы, называется вершиной стека. Количество ячеек памяти, предназначенных для организации стека, называется глубиной стека. Последняя ячейка памяти, в которую можно производить запись называется дном стека. Логическая организация стека приведена на следующем рисунке:

Рисунок 3. Организация стека в памяти данных микропроцессора.

Первоначально стек выполнялся аппаратно на отдельных ячейках памяти, затем его стали размещать в обычной памяти данных микропроцессоров. Это позволило в каждом конкретном случае устанавливать необходимую для программы глубину стека. Оставшуюся память можно использовать для размещения глобальных и локальных переменных программы. Глубина стека устанавливается при помощи записи начального адреса вершины стека в указатель стека. Обычно глубина стека устанавливается один раз после включения питания в процедуре инициализации контроллера.

Например в микроконтроллерах семейства MCS-51 при занесении информации в стек содержимое указателя стека увеличивается (стек растёт вверх), поэтому стек размещается в самой верхней части памяти данных. Для того, чтобы установить глубину стека 28 байт, необходимо вычесть из адреса максимальной ячейки внутренней памяти микроконтроллера глубину стека и записать полученное значение в указатель стека SP:

Кроме содержимого программного счётчика часто требуется запоминать содержимое внутренних регистров и флагов процессора, локальных переменных подпрограммы. Стек оказался удобным средством и для этой задачи. Сохранение локальных переменных в стеке позволило осуществлять вызов подпрограммы самой из себя (реализовывать рекурсивные алгоритмы). Это привело к введению в систему команд специальных команд работы со стеком. В микроконтроллерах семейства MCS-51 это команды PUSH и POP. Использование этих команд показывается на следующем примере:

[ Главная ]


Языки программирования для микроконтроллеров

 Rambler's Top100 Дата последнего обновления файла 18.11.04

Языки программирования для микроконтроллеров.

Программирование для микроконтроллеров как и программирование для универсальных компьютеров прошло большой путь развития от программирования в машинных кодах до применения современных интегрированных систем написания программ, отладки и программирования микроконтроллеров. В настоящее время исходный текст программы пишется на одном из языков программирования.

Рисунок 1. Классификация программ-трансляторов языков программирования.

Сами языки программирования в свою очередь делятся на две группы:

  1. языки программирования "высокого" уровня
  2. языки программирования "низкого" уровня.

К языкам программирования "низкого" уровня относятся языки программирования в которых каждому оператору соответствует не более одной машинной команды. Набор машинных команд каждого конкретного процессора обязательно входит в состав такого языка программирования. Языки программирования низкого уровня в настоящее время называются ассемблерами (старое название автокоды). Для каждого процессора существует своя группа ассемблеров. Ассемблеры для одного и того же процессора различаются между собой дополнительными возможностями, облегчающими программирование.

Языки программирования "высокого" уровня позволяют заменять один оператор несколькими машинными командами. Это позволяет увеличивать производительность труда программистов. Кроме того, языки "высокого" уровня позволяют писать программы, которые могут выполняться на различных микропроцессорах. (Естественно, что при этом необходимо использовать программы - трансляторы для соответствующего процессора.) В настоящее время наиболее распространены такие языки программирования высокого уровня как С и PLM

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

В тех случаях, когда объём ОЗУ и ПЗУ мал (в районе нескольких килобайт) альтернативы ассемблеру нет. Именно эти языки программирования позволяют получать самый короткий и самый быстродействующий код программы (при прочих равных условиях, т.к. испортить можно всё!).

Языки программирования высокого уровня позволяют значительно сократить время создания программы, но при этом увеличивается размер программы, поэтому для выбора такого языка программирования для микропроцессорных систем необходимо иметь достаточно большой объём памяти программ (несколько десятков килобайт). Увеличение объёма программы связано с несколькими факторами:

  1. Язык программирования рассчитывается на все случаи жизни, поэтому в большинстве случаев человек мог бы написать программу короче (исключив не нужные в данном конкретном случае проверки или защиты).
  2. Программист не видит к чему приводит использование тех или других операторов языка программирования, поэтому может выбирать операторы, не оптимальные как с точки зрения длины машинного кода программы, так и с точки зрения быстродействия программы.
  3. Программист не использует подпрограммы там, где они могли бы сократить объём программы, так как на языке программирования высокого уровня это всего один или несколько операторов.

Первый из этих пунктов постепенно утрачивает своё значение с появлением всё более совершенных трансляторов. Третий пункт тоже решается тем же путём при применении различных видов оптимизаторов, входящих в состав компилятора. Однако в большинстве случаев оптимизатор не может определить одинаковые действия, если они отличаются хотя бы одной командой. Кроме того, оптимизатор работает только в пределах одного модуля!

Виды программ – трансляторов.

Процесс преобразования операторов исходного языка программирования в машинные коды микропроцессора называется трансляцией исходного текста. В настоящее время ручная трансляция программ практически не используется. Трансляция производится специальными программами-трансляторами.

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

Применение интерпретатора может обеспечить выигрыш только в случае его разработки для языка программирования “высокого” уровня. В этом случае может быть сэкономлена внутренняя память программ, а также облегчен процесс отладки программ (при применении языка программирования BASIC) или облегчен перенос программ с одного типа процессора на другой (при применении языка программирования JAVA).

При программировании на языке программирования ASSEMBLER применение интерпретатора приводит к проигрышу по всем параметрам, поэтому для языков программирования низкого уровня применяются только программы–компиляторы.

Для программирования микроконтроллеров как на языке программирования “низкого” уровня, так и на языке программирования “высокого” уровня используются только компиляторы, поэтому рассмотрим подробнее виды этих трансляторов.

Виды компиляторов

Программы-компиляторы бывают оценочные и профессиональные.

Оценочные или учебные компиляторы позволяют написать простейшие программы для конкретного процессора и определить подходит ли процессор для тех задач, которые предстоит решать в процессе разработки устройства. Конечно, если программа очень проста, то можно весь программный продукт написать на оценочном компиляторе. Оценочные компиляторы позволяют транслировать одиночный файл исходного текста программы. Иногда такие компиляторы позволяют включать в процесс трансляции содержимое отдельных файлов специальной директивой. В результате работы оценочного компилятора сразу получается исполняемый или загрузочный модуль программы, поэтому такие компиляторы называются компиляторы с единой трансляцией.

Профессиональные трансляторы позволяют производить трансляцию исходного текста программы по частям. Это позволяет значительно сократить время трансляции исходного текста программы, так как не нужно транслировать весь текст программы, а можно транслировать только ту часть программы, которая менялась после предыдущей трансляции. Кроме того, каждый программный модуль может писать отдельный программист. Это позволяет сократить время написания программы. Даже в том случае, если программу пишет один человек, время написания программы сокращается за счёт использования готовых отлаженных и оттранслированных программных модулей. В таких компиляторах процесс трансляции программы разбивается на два этапа: трансляция программного модуля и связывание программных модулей в единую программу. Поэтому такие компиляторы называются компиляторами с раздельной трансляцией.

Оценочные компиляторы обычно предлагаются бесплатно фирмами - производителями микроконтроллеров. Только фирма Intel предложила в своё время профессиональный пакет разработки программ - язык программирования PLM-51 в состав которого входит профессиональный язык программирования ASM-51.

Профессиональные компиляторы разрабатываются и продаются отдельными фирмами. Для микроконтроллеров семейства MCS-51 получили известность продукты таких фирм как FRANCLIN, IAR, KEIL. В состав современных средств написания и отладки программ для микроконтроллеров обычно входят эмуляторы процессоров или отладочные платы, текстовый редактор, компиляторы языка высокого уровня (чаще всего "C") и ассемблера, редактор связей и загрузчик программы в отладочную плату. Все программы обычно объединены интегрированной средой разработки программного проекта, позволяющую поддерживать один или несколько программных проектов.


Структурное программирование

 Дата последнего обновления файла 07.06.2005

Структурное программирование.

Программирование для универсальных компьютеров начиналось с программирования в машинных кодах, затем появились и начали своё развитие языки высокого уровня, затем Дейкстрой были развиты принципы структурного программирования, на смену структурному программированию пришло объектное программирование и в настоящее время активно развивается визуальное программирование.

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

Применение структурного программирования позволяет увеличить скорость написания программ и облегчить отладку написанной программы. Структурное программирование возможно и на языках программирования assembler, где не предусмотрено структурных операторов, подобных структурным операторам языков программирования C, PASCAL, PL/M.

В настоящее время существует два способа написания программ: снизу вверх и сверху вниз. При написании программы снизу вверх приступить к отладке программы невозможно, не написав полностью всю программу. При написании программы сверху вниз на любом этапе написания программы она может быть оттранслирована и выполнена, при этом можно отследить все алгоритмические действия программы, написанные к этому времени. Процесс написания программы не отличается от процесса создания алгоритма. Более того, эти этапы создания программы можно объединить. Выполняемое алгоритмическое действие отображается в названии подпрограммы. Например:

ProchitatPort ;Прочитать порт

VklychitIndikator ;Включить индикатор

Основная идея структурного программирования заключаются в том, что существует только четыре структурных оператора. Используя эти структурные операторы можно построить сколь угодно сложную программу.

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

Алгоритмическое изображение оператора

Язык программирования С

Язык программирования asm-51

Второй структурный оператор называется условный оператор. Достаточно часто одна или другая задачи должны исполняться в зависимости от определённого условия, которое зависит от результатов выполнения предыдущей программы или от внешних устройств. Каждая из таких задач называется плечом условного оператора.

Алгоритмическое изображение оператора

Язык программирования С

Язык программирования asm-51

Условный оператор может использоваться в неполном варианте, когда одно из плеч алгоритма отсутствует:

Алгоритмическое изображение оператора

Язык программирования С

Язык программирования asm-51

Третий структурный оператор - это оператор цикла с проверкой условия после тела цикла. Такой оператор легко реализуется на языке программирования ассемблер при помощи команды условного или безусловного перехода. Отличие от условного оператора заключается в том, что передача управления осуществляется не вперёд, а назад. На языках программирования высокого уровня такой оператор входит в состав языка (оператор do..while в языке программирования C или оператор repeat..until в языке программирования PASCAL).

Алгоритмическое изображение оператора

Язык программирования С

Язык программирования asm-51

Четвёртый структурный оператор - это оператор цикла с проверкой условия до тела цикла. В отличие от предыдущего оператора тело цикла в этом операторе может ни разу не выполниться, если условие цикла сразу же выполнено. Этот оператор как и условный оператор невозможно реализовать на одной машинной команде.

Алгоритмическое изображение оператора

Язык программирования С

Язык программирования asm-51

[ Главная ]


Написание программ для микропроцессоров

 Дата последнего обновления файла 07.06.2005

Написание программ для микропроцессоров.

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

Программа для микроконтроллера должна решать все перечисленные выше проблемы. Простейшим видом программы, которая может решать поставленные задачи является монитор.

Алгоритм программы-монитора приведён на рисунке 2.25. После включения питания эта программа должна настроить микросхему под выполняемую программой задачу, то есть настроить определённые ножки микросхемы на ввод или вывод информации, включить и настроить внутренние таймеры микроконтроллера и так далее. Этот блок алгоритма программы-монитора называется инициализацией процессора.

Рисунок 2.25. Алгоритм программы-монитора.

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

Рассмотрим пример реализации такого алгоритма работы программы. Для написания программы воспользуемся принципами структурного программирования, рассмотренными ранее. В этом случае для проверки работоспособности программы можно воспользоваться программами-заглушками. Исходный текст такой программы приведён на рисунке 2.26.

Рисунок 2.25. Пример реализации программы-монитора на языке СИ.

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

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

Объявим глобальную переменную SkanCode, в которой будем хранить значения электрических сигналов на выводах микроконтроллера, подключенных к контактам клавиатуры.

Достаточно часто программа, написанная для микроконтроллера, реализует одновременно несколько устройств или несколько режимов работы. В случае если реализуется несколько режимов работы, задача решается несколько проще. Так как в каждый отдельный момент времени требуется только один режим работы, то для реализации каждого режима работы можно использовать отдельный программный монитор.

[ Главная ]


31.07.2004

 Rambler's Top100 Дата последнего обновления файла 30.09.04

31.07.04 Дорога в горы

Ну, вот я и покинул город. Все встретились уже в поезде. Нас шестеро. С Александром Павловичем я встретился уже на станции Камышенская. Я подошёл немного пораньше, и поэтому пришлось пропустить одну электричку. Для того чтобы не пропустить его появление я вышел на улицу, по которой он по моим расчётам должен был подойти к станции. Рюкзак, двигающийся к станции, я увидел издалека. То, что он двигается не сам по себе, а на самом деле под ним находится человек, удалось разглядеть намного позже. Тем не менее, рюкзак, несмотря на его внушительные размеры, двигался с поразительной скоростью и менее чем за минуту он оказался около меня.

Около вокзала Главного находилось множество рюкзаков. Казалось, что если не весь город, то, по крайней мере, значительная его часть собралась переместиться на Алтай. Не без труда я разглядел два рюкзака, стоящие на лавочке немного в стороне от основной массы стоящих, сидящих и двигающихся рюкзаков. Около одного из них прохаживался Максим. Чуть попозже я познакомился ещё с одним парнем. Его звали Игорь. Павла, который прилетел сегодня из Москвы, и должен был присоединиться к нам, не было.

Шло время, но он не появлялся. Пока было время до поезда, мы решили купить минеральной воды. Я сбегал за бутылкой карачинской. (Обратите внимание! Эта бутылка очень скоро проявит свой характер.) Павла всё не было. Но вот объявили посадку на поезд. Лёгким движением руки с возгласом "ХА" со второй попытки (после первой меня унесло метров на десять в сторону) мне удалось забросить рюкзак на плечо и мы пошли грузиться на поезд.

В поезде меня ждал сюрприз. Мой рюкзак никак не желал умещаться под полку. Максим, у которого был несколько больший опыт, сочувственно посоветовал забросить его на верхнюю полку. Приглядевшись, я заметил, что его рюкзак уже покоился на соседней полке. Совместными усилиями, втроём, нам удалось запихать мой рюкзак на верхнюю полку, и стали ждать отправления поезда.

Наконец перрон медленно стал двигаться за окном. Через несколько минут появились Александр Павлович и Павел. Он успел буквально к отправлению поезда. Здесь выяснилось, что он ещё не до конца москвич. Родился и вырос он в Новосибирске и только после окончания университета переехал работать в Москву.

Мимо медленно проплывали берега Обского моря. Вскоре поезд подошёл к Бердску. Здесь к нам присоединилась Татьяна. Теперь вся группа была в сборе. Её казалось в это время волновала только одна проблема: судьба кошки, оставленной дома. Выяснилось, что для того, чтобы обеспечить безопасность кошки в её отсутствие, Татьяна поручила уход за кошкой своим домашним, для контроля взвесила кошку и пригрозила им всевозможными карами, если кошка похудеет хотя бы на сто грамм.

Правда сначала, пока я не разобрался в чём проблема, я не мог понять, кого она взвешивала кошку или себя, так как, на мой взгляд, её вес не намного отличался от веса кошки. Или, может быть, она хотела сравнить, кто весит больше: она или кошка?

В вагоне начали искать попутчиков до Тюнгура, чтобы дешевле доехать до места. В конце концов, нашли двух поляков, которые направлялись в те же места. Надо сказать, что это довольно интересная семейная пара: огромный мужик и его миниатюрная жена.

Наконец вагон постепенно успокоился. Наступила ночь. Я залез на верхнюю полку и стал постепенно засыпать. Вдруг я почуствовал движение воздуха в ногах и в последний момент успел подтянуть ноги, прежде чем дверь захлопнулась, чуть не отрубив мне ноги. Дело в том, что наше купе было самым последним, и мимо постоянно проходили люди, пытаясь попутно либо сбросить меня с полки, зацепив за ноги, либо пытаясь отрубить мне ноги дверью.

Внезапно среди размеренного течения ночи, во время которого я либо быстро подтягивал ноги, либо, засыпая, постепенно выпрямлял их, раздался глухой стук внизу. Я осторожно посмотрел вниз. Александр Павлович наполовину сидел на полке, нежно прижимая ко лбу бутылку с карачинской водой. Оказывается, ей надоело стоять на столике в полном одиночестве, и во время очередного торможения поезда она спланировала прямо на лоб к Александру Павловичу. Причём, как вскоре выяснилось, она умудрилась приземлиться углом пробки точно на бровь!

В общем, в скором времени Александр Павлович стоял с окровавленным лицом около туалета. Откуда ни возьмись, около него материализовался милиционер: "что случилось?" Уходя, он ещё некоторое время оглядывался, недоверчиво оглядывая Александра Павловича.

1.08.04 Дорога в горы (продолжение)

Наконец стало светать. Никто уже не спал. Подошли Татьяна с Павлом, ехавшие в другом купе в начале вагона. Они тоже не спали. Оказывается их всю ночь развлекали мужики. В промежутках между принятием алкогольных напитков они очень эмоционально обсуждали вопросы ядерной войны.

Вот наконец и Бийск! На вокзале нас уже ждали. Подошла очень активная тётя и провела к "газели", которая должна была доставить нас до Тюнгура. Вместе с нами ехали поляки с которыми мы договорились ещё в поезде. По пути газель заправилась бензином и газом. При этом для заправки мы заехали в какую-то шарагу, во дворе которой стояли бочки с квасом и было непонятно чем же будет заправляться машина.

Наш попутчик Роберт на фоне газели и вокзала в славном городе Бийске. Газель подпирает, чтобы она не упала, почётный бегун нашего отряда Павел.

Но вот, наконец, после непонятного кружения по улицам Бийска "газель" выезжает на Чуйский тракт. Мимо проплывают сосны с яркими почти оранжевыми стволами. К сожалению, сегодня снежные вершины вдали не видны. Как выяснилось, доехать до Бийска - это даже не половина дороги. Впереди предстояло преодолеть расстояние более пятисот километров.

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

Как только преодолели мост через Катунь, сосны закончились и мимо стали проплывать горы, на которых видны поля, иногда склоны, покрытые лиственницами. Дорога проложена таким образом, что не чувствуется, что она проходит в горах. Кое-где впечатление, что едем по равнине, только далеко вдали видны холмы. Это чем-то напоминает Уральские горы. Подъезжаем к Семинскому перевалу. Машина с трудом поднимается в гору. Но и здесь ничего, напоминающее горы. Обычная холмистая равнина. Единственное, что бросается в глаза - это то, что подъём всё не кончается и не кончается. Для охлаждения двигателя водитель включает печку и в салоне становится жарко.

Вскоре мы сворачиваем с Чуйского тракта и пересекаем весь Горный Алтай с востока на запад, затем поворачиваем на юго-восток и снова начинаем пересекать Алтай с севера на юг. Вокруг вообще не видно гор. Дорога идет по равнинной местности только иногда вдалеке синеет отдельная гора. Впереди показывается строительный вагончик, около которого стоит несколько машин. Останавливаемся и мы. Оказывается это пограничная застава. Мы собираем паспорта, и пограничник уносит их в вагончик. Жарко. Мы стоим на солнце. Чтобы немного размяться я выхожу из машины. У пограничной заставы (или блок поста - не знаю, как это точно называется) стоит худой мужик с велосипедом и пытается заяснить всем, кто его желает слушать (а от нечего делать желают все), что он является международной экспедицией, направленной на Алтай из Новосибирского Академгородка для поиска Шамбалы. Здесь я впервые услышал это слово. Дальше искатели шамбалы или их следы будут попадаться на каждом шагу. В общем, этот единственный представитель международной экспедиции по поиску Шамбалы кое-как объяснил, что Шамбала - это особый дух, обитающий в Гималаях, на Тянь-Шане и Алтае. Кроме того, он объяснил, что именно этот дух спасёт Землю от неминуемой гибели, и что это ему не удастся без деятельного участия международной экспедиции Юнеско в его лице.

Мне надоело стоять около импровизированного митинга, проходящего около лениво зевающего пограничника с автоматом, которому уже порядком надоели всякие искатели Шамбалы. Я решил узнать, чем же занимается пограничник в вагончике, куда унесли наши паспорта? Я зашёл в вагончик - лучше бы я этого не делал. Внутри вагончика было сумрачно и прохладно. Прямо у входа над вскрытой консервной банкой трудился облезлый котёнок, весь покрытый зелёнкой. За перегородкой пограничник с трудом разбирался, что же написано в паспортах. Перед ним на столе лежали три стопки паспортов. Закончив разбираться с очередной стопкой паспортов, он спросил, по отдельности ли мы будем возвращаться или надеемся выйти с гор вместе. Выяснив, что у меня такая надежда есть, он обрадовано назначил меня старшим над нашим автобусом и, записав данные только моего паспорта, вернул мне всю нашу стопку паспортов. Напоследок он вырвал клочок бумаги, что-то черканул там и сказал, чтобы я показал этот шматок бумаги, когда мы будем возвращаться обратно и, кто бы ни дежурил на заставе, нас даже останавливать не будет. (К слову сказать, именно так и случилось на обратном пути.)

Наконец мы снова в дороге. Справа появляется речка, сначала похожая на ручеёк. Постепенно она набирает силы. Внизу уже видны пороги. Вода приобретает красивый бирюзовый цвет, на котором особенно чётко видны пенные следы от подводных камней. Дорога идёт вдоль обрывистого берега реки. Теперь она то резко спускается вниз, то вновь идёт на подъём. По сторонам видны ответвления дороги, предназначенные для тех, у кого отказали тормоза. Чем дальше, тем круче обрыв и больше высота над рекой. Иногда ничего не видно кроме реки, бушующей далеко внизу. Кажется, что вот сейчас водитель не успеет повернуть или машина на повороте по инерции прокатится вперёд лишний метр и ... свободный полёт метров на шестьдесят вниз!

Наконец мы снова выезжаем к Катуни. Какой прекрасный вид открывается сверху! Но мы едем дальше вдоль реки. Здесь долина достаточно широка и мы не видим реки до тех пор, пока не подъезжаем к подвесному мосту через Катунь в посёлке Тюнгур. Как хорошо, что мы можем, наконец, выйти и размять ноги! Здесь мы снова впрягаемся в рюкзаки, и на целых две недели они становятся нашей верхней одеждой!

Мы на турбазе. Последняя проверка перед выходом в горы. На заднем плане просматриваются наши польские попутчики.

Из нас шестерых только я и Татьяна впервые в этих местах. Все, бодро взбрыкивая своими филейными частями тела, двинулись вверх по единственной дороге, идущей от двух турбаз, где мы высадились. Нас обгоняет местный "аксакал" и предлагает подбросить до перевала Козияк, где должен начаться наш поход. Но мы гордо отказываемся.

Наконец спустя два часа мы, преодолев по мосту речку Кучерла, подходим к какому-то ручейку. Мне объясняют, что этот ручеёк стекает с перевала Козияк, и что мы здесь будем ночевать. К этому моменту мне уже всё равно где слезет с меня рюкзак - здесь или где в другом месте. Я уже умудрился стереть ноги и теперь они горят! А ведь пластырь из дома я естественно не взял! Нежно обняв рюкзак, я отрешенно смотрю, как Александр Павлович пошёл собирать дрова для костра, Максим стал раскладывать палатку, а Игорь сосредоточенно стал копаться в рюкзаке. Наконец до меня дошло, что я один ничего не делаю! Отважно оторвавшись от рюкзака я доковылял до Максима и сделал вид, что держу какую-то верёвочку от палатки - в общем, помогаю ставить её! А вокруг постепенно начинает темнеть и холодать.

Схема нашего паломничества к подножию горы Белуха.

Продолжение следует.


2.08.2004

 Rambler's Top100 Дата последнего обновления файла 21.10.04

2.08.04 Вдоль Аккема.

Немного отдохнув, двигаемся вниз. Вниз двигаться почему-то легче. Спускаемся всё также по дороге. На этот раз ни у кого не возникает желания покинуть её. Похоже, во время дождя по дороге бежит небольшой ручей, который и прорыл прямо посередине дороги в камнях небольшой овраг метра полтора - не больше! Правда - правда! Колея проходит по обеим сторонам этого овражка. Татьяна и Павел по пути сметают все ягоды по сторонам дороги. А ягод попадается немерено! Одна кислица чего стоит! крупная - так и светится изнутри! Мне тоже хочется сорвать, и я не удерживаюсь, хотя знаю, что мне это даром не пройдёт. Потом буду маяться желудком. Постепенно по дороге, как и с противоположной стороны перевала, начинает журчать ручей. Здесь уже жарко. Солнце выпаривает из травы и кустов влагу и ощущение как в бане. Запах вокруг такой, что начинает кружиться голова. Очень хочется пить, но неумолимый начальник сразу же пресекает возможные попытки напиться из ручья - не пейте, а то тракторами станете! Это он намекает, что по этой дороге может проехать только трактор. Не знаю как насчёт тракторов, до этого вроде бы далеко, а вот лошадями, навьюченными рюкзаками мы уже, пожалуй, себя ощущаем.

Командир сбегая впереди по дороге время от времени покрикивает, что скоро должна показаться избушка, около которой должен быть родник. Вот там и отдохнём вот там и напьёмся! Наконец впереди раздаётся радостный крик, возвещающий о том, что избушка обнаружена. Подтягиваюсь ближе. В стороне от дороги прямо посреди небольшого болотца стоят все пятеро членов нашего небольшого, но абсолютно одинаково потного отряда. Пытаюсь разглядеть избушку - не вижу. Спрашиваю Игоря - где же избушка? Он махает в сторону болотца. Ничего не понимаю. Ещё раз оглядываю болотце, полностью размешанное копытами лошадей. Александр Павлович объявляет, что он идёт на разведку на поиск родника. Он смело шагает в сторону болотца, за что ему чуть ли не сразу приходится поплатиться. Ноги у него разъезжаются, и он делает почти классический шпагат. Правда штаны остаются сухими - выручает отменная физическая подготовка. Тут я, наконец, замечаю сооружение, напоминающее сарай, стоящий прямо посреди болотца. Оказывается это и есть та самая изба, к которой мы стремились! А болотце и есть бывший родник, тщательно размешанный копытами лошадей. В общем, тщательно обшаривший и почти обнюхавший всё вокруг Александр Павлович вынужден признать, что запастись водой не удастся.

Ну что ж двигаемся дальше. Склон здесь не очень крутой, поэтому двигаемся аккуратно, но быстро. Долго ли, коротко ли но добегаем до какого-то ручья. Здесь ещё один привал. Вода в ручье мутная, но Александр Павлович и тут показывает высший класс - он умудряется набирать воду в бутылку с самого верхнего слоя воды, там, где вода чистая. В общем не даёт умереть от жажды. Надо сказать, что вопреки моим опасениям я не особенно страдал от жажды. Больше доставалось Максиму и Игорю. Иногда приходилось спаивать им свою бутылку воды. И ещё одно обстоятельство - Татьяна и Игорь заблаговременно не запаслись пустыми пол-литровыми бутылками, поэтому они были вынуждены пользоваться чужими. Однако мы находились не в пустыне. В ту и другую сторону промелькивали группы туристов и вскоре Татьяна с Игорем обзавелись собственными бутылками для воды.

Вскоре мы вышли на поле, тянувшееся вдоль реки Аккем. По нему дошли до стоянки, где устроили привал, разложили костёр и начали готовить еду. Как сообщил наш сухопутный лоцман Максим, эта стоянка имела своё название - три берёзы. Тщательно пересчитав берёзы, мы не досчитались одной. Затем, немного посовещавшись, решили одну раздваивающуюся берёзу засчитать за две и тем самым не менять название стоянки.

Недалеко шумел Аккем. Очень хотелось посмотреть на него, но как выяснилось позже, это было суждено ещё не скоро. Я сходил за водой к соседнему ручью. Правда, сказать сходил - это громко сказано! Проковылял - это точнее, так как выяснилось, что я смозолил ноги. Только сейчас выяснилось, что я не взял самой нужной в походе вещи - лейкопластыря! К счастью Максим и Игорь запаслись им в достаточном количестве. Достаточном даже для того, чтобы снабжать им меня в течение всего похода. В общем, стоянка на время превратилась в лазарет.

Сверху как по заказу начал накрапывать дождик. Все бросились укрывать свои распакованные рюкзаки. Бросились - это вообще-то громко сказано! Ведь все смозолили ноги! Наша походка напоминала нечто среднее между переваливающимся шагом утки и прыганьем лягушки. Один Александр Павлович невозмутимо ковырялся у костра. У него как у опытного туриста рюкзак стоял под полиэтиленом. Дождик, понаблюдав, как мы доскакали до своих рюкзаков, и, видимо получив моральное удовлетворение, прекратился.

Стоянка "Три берёзы". Александр Павлович показывает Максиму, что пора выходить, а не фотографировать!

Пообедав, ставшей уже традиционной гречневой кашей, и получив традиционную же пайку конфет у Максима (по совместительству завхоза) мы блаженно вытянули ноги. Один только Павел, как и полагается истинному туристу, исследовал окрестности стоянки. Мимо время от времени бодрым шагом проходили другие группы туристов и, мне показалось, как-то подозрительно оглядывали нас. Казалось, что в их головах бродили смутные сомнения, не заняли ли мы принадлежащую им стоянку? Однако всё хорошее когда-либо кончается. Командир выразительно посмотрел на часы и скомандовал: в рюкзаки!

Ровное место закончилось почти сразу же за ручьём. Вскоре тропа нырнула в лес, склоны гор сошлись ближе и мы стали постепенно подниматься по склону этой горы. Сразу же стало сыро. Под ногами между камней зачавкала грязь. Наше счастье, что ещё не было дождя! Однако тропа казалось, издевалась над нами. Она то резко поднималась в гору, то не менее резко спускалась вниз. где-то внизу ревел Аккем, но увидеть его не удавалось. Всё закрывали деревья. Склоны гор покрыты кедром и лиственницей. Когда идёшь по горной тропе, то буквально хватаешь ртом воздух. В воздухе стоит резкий запах хвои. На земле повсюду лежат грызенные кедровые шишки. С ветвей деревьев свисают гроздья лишайников. Ущелье достаточно узкое (но не отвесное) и сырое.

Постепенно эти скачки вниз и вверх начали изматывать. Это напоминало приседания со штангой. Ведь на спине болтался тяжеленный рюкзак. Отличие было только в том, что штангу можно бросить, а здесь такая роскошь непозволительна. Единственное, что меня утешает - это то, что Максим и Игорь идут позади. Значит, я не торможу отряд. Максим то догонит меня, то останавливается в классической позе созерцания земли. (Интересно есть ли такая поза в Хатха-Йоге?) Павел и Татьяна давно скрылись где-то впереди.

Наконец то привал! Рюкзаки немедленно летят на землю. Кто-то находит себе бревно. Кто - садится прямо на свой рюкзак. Здесь я увидел ещё одно гениальное изобретение современных туристов - поджопник. Это такой обрезок туристического коврика на резинке, который прикрывает пятую точку. В результате можно садиться в любом месте даже на холодную и мокрую землю.

У меня естественно этого гениального изобретения нет, поэтому я нахожу достаточно сухой пень и ... обнаруживаю на нём кедровый орех. Учитывая, что я обожаю кедровые орехи, решил, что это подарок от местного духа или, на крайний случай, белки. В общем я нагло не делюсь находкой с остальными членами нашего доблестного отряда и, не менее нагло, съедаю этот орех!

После привала меня почему-то ставят первым, обосновывая это тем, что здесь заблудиться невозможно. Слева обрыв до самого Аккема, справа ну очень крутой подъём. И, что самое странное - под ногами тропа! На этот раз сзади мне на пятки наступает Татьяна. Она уже давно заранее предупредила всех, что не потерпит, если хоть кто-либо будет идти перед ней. Так что опасаюсь за свои пятки.

На этот раз очень крутых подъёмов и спусков не наблюдается. Зато в изобилии бревна, вальяжно разлёгшиеся поперёк тропы. В общем двигаюсь, совершенно не обращая внимания на то, что под ногами. В последний момент решаю, куда поставить ногу, как перемахнуть через бревно при этом рюкзак как это ни странно начинает помогать в движении. Благодаря инерционности, придаваемой мне этим устройством, я свободно пролетаю над бревнами, не успеваю поскользнуться на краю лужи и при этом стараюсь не думать, что будет, если нужно будет изменить направление движения. Иначе говоря, всё это, как выразилась сзади Татьяна, напоминает гонку на автомобиле в темноте. Не знаю как насчёт автомобиля, а вот поход на велосипедах вокруг Обского моря это движение мне напомнило, когда на полной скорости нужно было проезжать по кромке огромных колдобин в асфальте. Да и звуки, которые я время от времени слышу сзади, тоже очень похожи. То Татьяна в силу того, что она ниже меня ростом вместо того, чтобы плавно подталкиваемая тяжестью рюкзака пройти над бревном почему-то со всего хода врезается в него, то не оценив из за моих габаритов размеров очередной лужи не перешагивает её, а со всего маху влетает прямо в эту лужу. Хм-м странно. Может шаг у неё покороче?

Однако ничто не вечно на Земле! Заканчивается и ровный участок. Тропа снова идет в гору. Идёт... мягко сказано! Это как огромная лестница из камней и корней деревьев. Интересно, для какого гиганта были вырублены эти ступени? А рюкзак, вместо того чтобы подпрыгнуть вместе со мной, почему-то стремится сначала остаться на месте, а потом, когда он уже остановил меня, досылает прямо фейсом об ... Да, об стол было бы лучше. В общем, в скорости я занял своё законное место перед Максимом.

А затем вообще всё стало абсолютно поровну. Кто-то рассуждал о речке, которая должна была бы впадать в Аккем с противоположной стороны долины. Кто-то выбирал место для будущей стоянки. Умозрительно конечно. Сейчас мы шли по такому склону, что палатку можно было бы использовать разве что в качестве гамака, привязав её к комлю дерева, растущего выше тропы и вершине дерева, растущего ниже тропы. Я то размеренно переставлял ноги под медленно движущимся вдоль тропы рюкзаком, то втаскивал его на очередные ступени прошедшего передо мной гиганта, а то пытался изо всех сил остановить его, когда рюкзак радостно стремился вслед за тропой кинуться в объятия Аккема.

Тем не менее, ночевать пришлось на склоне горы. После очередного поворота я увидел небольшую относительно ровную площадку и огромный камень посередине. Уже темнело. Начинал накрапывать дождь. На площадке уже было поставлено около десятка палаток. Максим, двигаясь как в замедленной съёмке, или точнее как полузаржавевший робот, начинает раскладывать палатку за камнем. Я обречённо встаю и двигаюсь к нему. Вскоре около камня появляется палатка. Затаскиваем в палатку рюкзаки. Тут выясняется, что за поворотом течёт ручей. Немного подумав, я отправляюсь за водой. Двигаться удаётся исключительно на руках, подтягиваясь за корни деревьев, так как ноги практически не слушаются.

Ночью пошел дождь. В результате проверили палатку Максима. Палатка выдержала испытание блестяще! Не протекает. Шишкин с Татьяной развесили на ночь сушиться свои футболки и, естественно, они за ночь вымокли. Мы думали, что, как только залезем в палатки, заснём. Не тут то было! Мы проговорили до полуночи. Потом, когда устали языки, ещё долго слушали, как в соседней палатке Александр Павлович пытался заменить собой общеобразовательную программу всероссийского радио. При этом он всячески пытался "успокоить" свою аудиторию, рассказывая, где кто и когда свалился с горы, кто и где замёрз от невовремя пришедшего циклона, а также как иногда "вовремя" с соседних гор падают камни. Так постепенно под эти успокаивающие речи мы и заснули.

Продолжение следует.


2.08.2004

 Rambler's Top100 Дата последнего обновления файла 30.09.04

2.08.04 Штурм Козияка.

Ну, вот и снова утро! Как ни странно, но я ещё жив. И даже не замёрз, как я это ожидал вчера вечером. Осторожно выполз из палатки и побрёл умываться. Александр Павлович уже что-то колдует у костра. Больше никого не видно. Вокруг всё мокро от росы. Я, когда собирался в поход, думал, что каждое утро буду заниматься утренней гимнастикой, но сейчас нет никакого желания! Вода в ручье прохладная, но вполне терпимая. Умывшись и почистив зубы возвращаюсь к палатке. Если не считать возвышающуюся около нас гору, то вокруг самый обыкновенный лес. Снизу гора не кажется особенно высокой, так, просто немного высоковатый холм, но я уже знаю, что настоящая вершина отсюда не видна.

Народный контроль в лице Игоря наблюдает за процессом приготовления пищи в ресторане "Козияк". На заднем плане виден ручей.

Постепенно просыпается наш лагерь. Татьяна сразу же обнаружила за ручьём заросли красной смородины, и все желающие отправились на выпас. Вскоре Александр Павлович позвал завтракать. И тут выяснилось, что мне предстоит управиться с небольшой кастрюлькой гречневой каши. Это оказалось проблематичным. С этим экзаменом мне не удалось справиться. Я с удивлением смотрел на Максима, поглощающего свою кастрюльку каши, ведь я знал, что он обычно не употребляет такое количество пищи!

Загадка выяснилась через несколько дней. Оказывается, он не зря бегал за соседний куст. Макс не отказывался от добавки, когда ему предлагали. Однако он съедал ровно столько, сколько ему было нужно, а затем незаметно исчезал за соседний куст. И у муравьёв начиналось пиршество! И повар доволен, и Макс не в накладе, и, что характерно - муравьи тоже не против!

Наконец палатки собраны, рюкзаки уложены, а мы готовы к предстоящим подвигам. Вышли мы на штурм перевала Козияк в 10.00. Правда в том же направлении совсем недавно проехала машина, но ведь это же не важно! Она ведь нам не конкурент! В общем, мы бодро шагали прямо по грунтовой дороге, которая вела на перевал. На обочине дороги мы встретили семейку, которая похоже устроилась на пикник, обогнали парочку дедков, шагавших в том же направлении что и мы, несколько групп молодых людей спортивного вида обогнали нас. Но это тоже было не важно. Ведь мы были единственными настоящими покорителями перевала Козияк! Остальные же не в счёт - ведь так?

Я бодро пыхтел в спину Игорю, который шёл передо мной. Вдруг он остановился, вскинул свою заднюю часть, опёрся на лыжную палку и что-то внимательно стал разглядывать у себя под ногами прямо на дороге. Я тоже пригляделся, но ничего не заметил. Мысленно пожал плечами и, обогнув Игоря, попыхтел дальше. Через некоторое время Игорь обогнал меня, но не прошло и пяти минут, как снова всё повторилось - Игорь опять что-то нашёл на дороге, а я опять ничего не видел. Тут было что-то мистическое и главное не у кого больше было спросить. Татьяна, Павел и Александр Павлович уже давно скрылись вдали. Мы упорно карабкались по дороге. Иногда казалось, что я затаскиваю рюкзак на склон оврага по соседству от моего дома, но время шло, а склон оврага и дорога, карабкающаяся наверх, всё не кончались. Становилось всё мокрее и мокрее. Несколько раз мы пересекали небольшой ручей. Наконец ручью надоело бежать вдоль дороги, и он побежал прямо по ней. Пришлось чавкать прямо по грязи. И вдруг, в очередной раз, огибая Игоря, меня осенило! Да ведь он, оказывается, ничего не разглядывает на дороге - он просто так отдыхает - СТОЯ! От этого открытия мне стало немного легче. Оказывается не только мне тяжело - рядом есть товарищи по несчастью. Поражённый этой мыслью я оглянулся. Метрах в десяти ниже меня полз Максим, подметая дорогу собственным языком. Выглядел он ничуть не лучше меня.

Теперь у меня появился шанс не остаться навсегда на склоне этой горы. Убегая вперёд, Александр Павлович прокричал, что здесь невозможно заблудиться - дорога одна и ведёт она точно на перевал Козияк. Остальные это подтвердили. Естественно, что я не поверил этой наглой лжи! Ведь как только они скрылись за поворотом, дорога стала раздваиваться с удивительной регулярностью. Я понял - они решили оставить меня здесь! Ведь я не знаю дороги! Но теперь всё изменилось - было ещё два человека, которые уже проходили здесь! И они, в принципе, не могли убежать от меня так же, как это сделали Татьяна с Павлом. Ну, наконец, привал! Скидываю рюкзак и падаю на землю.

Если кто не догадался, то это я. Это мы поднялись метров на триста. Воздуха уже не хватает, и я изображаю из себя собаку с высунутым языком, но жить пока ещё можно.

Двигаемся дальше. Ручей всё также течёт по дороге. Татьяна обнаружила по пути жимолость и успевает по пути объедать её. При этом она далеко впереди нас и всё удаляется и удаляется. Дорога для того, чтобы не быть такой крутой идёт серпантином. На очередном повороте вверху больше нет леса, и стала видна седловина между горами. Недолго думая, Татьяна устремляется прямо вверх. Александр Павлович бросается вдогонку. Павел, немного подумав, двинулся по дороге. Я, Максим и Игорь уже почти без сил. Особенно я. Присев на корягу, мы наблюдаем за удаляющимися фигурами Татьяны и Александра Павловича. Вокруг уже нет и намёка на ручёй, который течёт далеко внизу. Подкрепившись холодным чаем, оставшимся с утренней трапезы, продолжаем наблюдать за развивающейся перед нами на склоне горы погоней. Вскоре они скрылись за горизонтом. Делать нечего. Мы поднялись и поковыляли по дороге вслед за Павлом.

Снимите меня отсюда! А лучше донесите до перевала. До перевала сто метров, но сил уже нет.

Как оказалось, перевал был всего в сотне метров за поворотом дороги. Еще несколько сотен шагов и мы приближаемся к перевалу. Нас встречает Павел уже без рюкзака.

Ну, вот и последние шаги. Мы с Игорем подползаем к перевалу.
Нас встречает и подбадривает Павел. Он уже на перевале.

На перевале все деревья увешаны небольшими лоскутками материи - Алтайское приношение духам. Здесь заметно холоднее по сравнению с подножьем перевала. Дует холодный ветер. Я всю дорогу поднимался в штормовке, и теперь она вся мокрая. Меня начинает продувать, а Татьяны и Александра Павловича не видать. Наконец, спустя минут пять они подходят откуда-то сбоку.

Наконец все вместе. Перевал взят.

Наконец-то! Наконец-то съедается первая в этом походе традиционная шоколадка! Жаль конечно, что она быстро заканчивается, но ничего - впереди ещё не один перевал!

Продолжение следует.


3.08.2004

 Rambler's Top100 Дата последнего обновления файла 22.10.04

3.08.04 Вдоль Аккема (продолжение).

Утро не принесло желанного восстановления сил. Двигающиеся вокруг наших палаток люди напоминали завершающие сцены из известного французского фильма "Жандарм и инопланетяне". Все ходили как-то странно переставляя ноги, а туловище при этом раскачивалось из стороны в сторону. Вспомнив, что с утра желательно было бы почистить зубы, я с тоской посмотрел в сторону ручья. Ноги не гнулись. К тому же, судя по окрестным кустам, подъём от ручья после дождя явно не стал менее скользким.

Побродив немного вокруг и постепенно свыкнувшись с мыслью, что деваться всё-таки некуда сходил и умылся. Затем развлёкся, немного понаблюдав, как поднимаются от ручья другие обитатели нашего лагеря. Тут и время завтрака подоспело. Кое-как запихал в себя куски сои, которые мы добавляли к каше вместе с тушёнкой. Макс опять проделал известную процедуру и тем самым избежал процедуры долгого уговаривания взять добавку. Правда, в это время я ещё не знал, что местная фауна жива исключительно благодаря многолетним походам Максима в окрестности Белухи. Знание пришло позже.

Сразу же после завтрака быстро собираем палатки, укладываем рюкзаки и в путь. Звучит команда в рюкзаки. Я, забросив рюкзак, на спину говорю: какое до боли знакомое ощущение, на что командир заботливо уточняет: в каком месте?

Тем не менее, мы к этому времени уже восстановили координацию движений, тропа немного подсохла, и мы довольно-таки бодро зашагали дальше. По сравнению со вчерашним днём ничего практически не изменилось. Всё такой же склон под ногами, всё такой же одуряющий запах хвои и шум Аккема где-то далеко внизу. На привале Татьяна попыталась поднять бунт против завхоза, но Макс отнёсся к этому философски - ничего не говоря он занялся созерцанием ветки дерева, нависающей над тропой. Остальные тоже не поддержали бунт, а Александр Павлович взял вину на себя, сказав, что он должен был проследить за продуктами, запасаемыми в поход. В общем, попытка насильственного отбирания мешка с конфетами с треском провалилась! Максим остался непоколебим!

Над нами вдоль долины постоянно летает вертолёт. Это очень удивляет всех, так как стоимость одного полёта вертолёта стоит бешенных денег. Говорят, что это забрасывают экспедицию для восхождения на Белуху.

Я шел третьим после Татьяны и Павла. Вскоре показался очередной ручей. Татьяна стояла в сторонке, почему-то не решаясь перейти ручей по брёвнам, перекинутым через него. Павла не было видно. Я, не снижая хода, двинулся к этому импровизированному мостику. Вдруг ко мне прямо в грудь прилетела лыжная палка, запущенная как копьё. Я с удивлением заметил на противоположном берегу ручья Павла, стоящего в классической позе Чингачгука, вышедшего на тропу войны. Пришлось с удивлением остановиться. Неужели наш впереди бегущий член отряда решил устроить охоту на мамонтов, для того, чтобы подкормить голодающую единственную женщину нашего отряда, а я не вовремя ему помешал? Слава Богу ещё, что подкожная прослойка сала сработала как амортизатор и импровизированное копьё не принесло мне вреда!

Ситуация разъяснилась довольно-таки быстро. Оказывается Павел, не желая перенастраивать свои универсальные палки, с которыми он прошел весь маршрут, взял у Татьяны лыжную палку, чтобы перейти ручей, а затем метнул её обратно. Именно в это время я и вывернул из-за кустов. Как только всё выяснилось, мы начали переправу через ручей.

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

Вскоре мы стали заметно спускаться к Аккему и вот, наконец, впервые удалось увидеть перед собой эту реку. Тропа вышла к Аккему и упёрлась прямо в воду. Неужели придётся форсировать эту реку вброд или идти по реке вверх по течению? Однако при первом же взгляде на бушующие на реке буруны всякие подобные мысли испарились из головы. Прямо перед нами вниз проносилась абсолютно белая вода. Проносилась она с такой скоростью, что если непрерывно смотреть в поток воды, то начинала кружиться голова. Немного отдохнув, мы тронулись дальше. Тропа, которая казалось упиралась прямо в Аккем, резко повернула вправо. Теперь она шла по камням у самого среза воды. Мы снова выстроились в походную колонну. На этот раз впереди шёл командир, но не на лихом коне, а с фотоаппаратом наперевес.

Татьяна в перерыве между отработкой приёмов "карате-до" и "карате-после". Палку, однако, она держит наготове.

На этот раз я шёл за Татьяной. Вскоре мне довелось оценить все прелести этой позиции. Оказалось, что лыжная палка использовалась ею вовсе не для того, чтобы опираться. Она отрабатывала с нею приёмы карате с элементами фехтования на пике и саблях. В этом мне вскоре пришлось убедиться на собственной шкуре. Когда на пути попался достаточно большой камень, Татьяна задержалась, пытаясь вскарабкаться на него. Роста явно не хватало. Я ускорил шаг, и приготовился помочь ей взобраться на камень. Но как только я приблизился на расстояние вытянутой руки, Татьяна резко выбросила лыжную палку назад, явно целясь мне в грудь. Но, наученный недавним горьким опытом, я был начеку и мне удалось, несмотря на рюкзак за спиной увернуться от этого выпада. Тогда Татьяна резко перебросила лыжную палку в правую руку, зачем-то закинула на камень другую ногу и повторила выпад. На этот раз мне пришлось отвести летящую лыжную палку рукой, так как увернуться я уже не успевал. После нескольких безуспешных попыток пробиться сквозь серию ударов лыжной палкой, сопровождаемую непонятными взмахами ногами, мне удаётся подсадить её на камень. Движение вдоль Аккема продолжается. Татьяна немедленно уходит в отрыв.

Прижим на реке Аккем

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

Последние из "могикан". (В смысле, что весь отряд преодолел прижим.) На снимке видны веселые улыбки победителей и предвкушение продолжения "прогулки".

Павел напоследок фотографирует виды Аккема и окружающих гор, а мы двигаемся дальше. Он потом нас догонит. Мы в этом нисколько не сомневаемся. Татьяна, как всегда, обнаружила заросли ягод жимолости и брусники. Теперь она сметает их с кустов, попадающихся по пути. Очень хочется пить, а брусника идеально утоляет жажду. Я тоже попытался сорвать несколько ягод, однако скоро пришел к выводу, что две - три ягодки не стоят той борьбы с рюкзаком, которую при этом приходится выдерживать. Наклоны с рюкзаком - это то же самое, что и наклоны со штангой, только рюкзак вдобавок норовит прыгнуть вперед, а как потом из под него выбираться?

Оттуда мы пришли. Издалека камушки почему-то не смотрятся такими уж большими.
А там нам ещё предстоит пройти. Из-за шума Аккема вокруг ничего не слышно.

Местность теперь заметно изменилась. Мы идём по практически ровной местности между двумя горами. На противоположной стороне долины видели несколько живописных водопадов. Рядом бушует Аккем. Достают корни деревьев, выпирающие высоко из земли. Почва вокруг превратилась почти в болото. Единственное отличие - это полное отсутствие комаров. Временами кажется, что я иду вдоль Оби, особенно когда окружающие деревья закрывают склоны гор. Заметно похолодало. Говорят, что это ветер с ледников.

По пути постоянно попадаются заросли жимолости и брусники. Татьяна естественно не может упустить это и пытается устроить выпас.

В обед стоянка около ручья оказалась занята. Проходя мимо мы одарили обитателей стоянки соответствующими ситуации взглядами. Правда, они похоже этого не заметили. Теперь нам пришлось топать дальше, а так как ручьёв больше не попадалось, то пришлось остановиться около Аккема. Это было единственное относительно сухое место посреди болота. Готовить пришлось, используя воду из Аккема. Это что-то! Каша получилась какая-то хрустящая. После того, как поели, выяснилось, что половину котелка занимал осадок от воды! Если будете в этих местах - никогда не используйте воду из Аккема! Пользуйтесь ручьями!

Путевые записки на привале.

Остаток дня прошёл без приключений. Все так же топаем по долине. В основном это болото, но по тропе пройти можно. Сильно достают высоко поднятые над землей корни. Без рюкзака на них не обратил бы внимания, но с рюкзаком...! Однажды встретили отца и сына, которые обречённо сидели на упавшем стволе дерева и сосредоточенно разглядывали то подошвы от кроссовок, торчащие из грязи перед ними, то шевелящиеся пальцы своих ног, виднеющихся из под верхней части кроссовок на их ногах.

Ночевали снова на берегу Аккема, но на этот раз недалеко протекал ручей. Вокруг простиралось болото. Хорошо, что не было ни одного насекомого! Как только скрылось солнце меня начало колотить. Почему я замерз - не понял, ведь обычно я не мерзну. Быстренько полез в палатку. Какая тонкая ткань! Но как внутри быстро становится тепло! Ночью мы наблюдали ночной переход настоящих туристов, которые промелькнули мимо нас размеренным шагом в свете светодиодных фонариков. Как только они не запинались о корни деревьев, через которые мы недавно еле еле перебирались?

Ночью опять был дождь. Это была последняя тёплая ночёвка.

Продолжение следует.


4.08.2004

 Rambler's Top100 Дата последнего обновления файла 31.01.05

4.08.04 Аккемское озеро.

Ну вот снова и утро! Дождя нет, но и солнышка тоже что-то не видно. Выползаю из палатки. Как хорошо, что сегодня дежурит не наша палатка! Медленно, очень медленно, стараясь попасть точно на тропинку передвигаюсь в сторону ручья. Пора приводить себя в порядок. Утренняя процедура несколько освежает. Брр! Мягко сказано! Желание помыть голову мигом исчезает. Вода в ручье настолько холодная, что стоит сунуть руку в ручей, как сразу же ее сводит судорогой. В такой воде даже рыба не водится. В воздухе висит не то туман, не то дым от костра. Ладно. Ограничимся чисткой зубов и бритьем.

В лагере Александр Павлович готовит еду. У нас чрезвычайно "разнообразное" питание. Каша гречневая, тушенка и соя. Тем не менее Татьяна не может удержаться от ценных указаний по приготовлению пищи. Указания в основном относятся к методам приготовления кусков сои, которые на пакете носят громкое и гордое название соевого мяса. Его почему-то очень трудно варить, да и заталкивать в себя потом нисколько не легче. Сейчас идет процесс разламывания сои на куски помельче.

Остальные обитатели лагеря пока не высовывают носа из палаток, хотя их голоса, доносящиеся оттуда, хорошо слышны. Вообще-то и поговорить между палатками можно было бы. Можно, если бы не рев Аккема, перекатывающего рядом камни. Утром правда его шум намного тише по сравнению со вчерашним. Наверное его приглушает туман. Трава вокруг мокрая не то от дождя, не то от росы. Сходить с тропинки - смерти подобно. Мигом станешь мокрый по это самое или как говорил известный герой фильма "A зори здесь тихие" - в общем вам по пояс будет.

Резко раздается звон половника по котелку. Завтрак готов. Мигом оживают все палатки. Из них появляются фигуры (иначе это явление заспанных лиц в полном боевом обмундировании и с мисками наперевес не назовешь). Все рассаживаются вокруг костра. А бревна то - мокрые! Тут надо сказать слово об еще одном изобретении туристического гения - ОПА. Это такой обрезок полиуретанового коврика на резинке - поджопник в общем. Нужно куда сесть - надвинул на соответствующее место и опа! А все остальные стоят! Сегодня остальными оказался я.

Александр Павлович под чутким руководством Татьяны готовит завтрак.

После завтрака палатки быстро сворачиваются и мы снова готовы к походу. Сверху начинает накрапывать дождь, а холодный ветер с верховий Аккемы быстро разогнал туман. Впрочем может он просто немного поднялся повыше и превратился в низко висящие над нами облака. Сверху начинает капать дождик. Александр Павлович демонстрирует очередное превращение куска полиэтиленовой пленки. На этот раз пленка превращается ... превращается пленка ... в не очень элегантное подобие накидки, под которым умещается не только он сам, но и его рюкзак. Остальные проделывают подобную операцию. Я же гордо натягиваю на рюкзак заранее припасенный огромный полиэтиленовый мешок.

То, что нехорошо отрываться от коллектива я понял уже через несколько минут. Дождь скатываясь по полиэтиленовому мешку действительно не попадал в рюкзак. Он попадал мне на спину! И я бы не сказал, что это было приятно.Тем не менее другого выбора не было, и я вместе с остальными двигался вперед по тропинке. Болото вскоре закончилось и впереди показались какие-то домики. На веранде домиков стояли люди и смотрели на полудурков, которые в это время топали мимо них по расплывающейся на глазах грязи.

Впрочем, скоро дождь прекратился и даже показалось небо над головой, а впереди показалось озеро. Правда озером его можно было назвать с большой натяжкой. Около мореного вала еще и было немного воды, а немного выше по дну высохшего озера растекались многочисленные рукава Аккема. Прямо перед нами находилось несколько "бочек Диогена". Это и была база МЧС. Мы подошли к ней, и ... наконец-то можно хотя-бы на время сбросить рюкзаки. Александр Павлович побежал выяснять обстановку, а мы просто откровенно отдыхаем. Сверху греет солнышко. Хорошо.

Мы у базы МЧС на берегу Аккемского озера.

Над нами снова послышался рокот вертолета. Он все кружился и кружился над озером. Павел устроил настоящую охоту на вертолет. Как вертолет ни пытался увернуться от зоркого глаза фотоаппарата нашего папарацци, ему это сделать не удалось. Результаты охоты можно увидеть ниже.

"Банный" вертолёт.

Вскоре появился Александр Павлович. Здесь, наконец, мы узнали зачем летает вертолет. Он рассказал, что наши предположения о переброске альпинисткой экспедиции оказались неверными. Оказывается вертолет перевозил баню! Недалеко строится туркомплекс. Вокруг базы МЧС расстилались прекрасные места, но, к сожалению, нас предупредили, что ставить палатки здесь запрещено. Мы потопали дальше к началу озера. Здесь начинались болота, но место перед болотом было полностью заполнено палатками. Тем не менее, недалеко со склонов гор стекали ручьи с кристально прозрачной водой. Мы с большим трудом нашли свободное место для двух палаток.

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

Тем не менее, мы не стали перемещать свой лагерь, а стали обживаться далее. Погода снова испортилась и сверху начал накрапывать дождик. Впереди, между двумя горами, откуда вытекал Аккем, Александр Павлович пытался показать Аккемскую стену, а также рассказать, что именно там и находится гора Белуха. Однако из за низко висящих облаков ничего не было видно. Видимость там иногда несколько улучшалась, и тогда возникало подозрение, что Александр Павлович не врет. Но с соседней горы тут же опускалось очередное облако, и все снова окутывалось туманом. А может дождем или снегом. Снизу не видно. Все это время позади нас синело ярко-голубое небо!

Наша стоянка на берегу Аккемского озера.

Идти туда как-то не хотелось. Время шло и мы решили, что лучше пока остаться здесь. Может погода завтра будет лучше. Макс постоянно то заползал в палатку, то вылезал из нее. Как-то, в очередной раз, высунув голову из палатки и оставив все остальное в палатке он попросил дать ему под зад. Мы с Игорем удивленно переглянулись. Однако Макс настойчиво повторил свою просьбу. Мы терялись в догадках - неужели он застрял и не может самостоятельно покинуть палатку? Все объяснилось достаточно прозаично - оказывается Макс начал вылезать из палатки и вдруг вспомнил, что забыл взять поджопник (а также забыл как его зовут) и попросил нас подать его!

Макс "в интерьере". Вдали, за ближайшей горой, не видна из-за облаков Аккемская стена.

В конце концов, для того чтобы постоянно не лазить в палатку и из нее, Макс решил устроить "телевизор". Мы все залезли в палатку, а Макс открыл окно с видом на Аккемскую стену. Так можно было не мерзнуть и видеть, что происходит в тех местах, куда мы собрались идти в скором времени. Очень быстро такая тактика оправдала себя. Дождику надоело поливать горы перед нами и очередное облако выплеснуло заряд дождя на нас.

Тем временем соседняя палатка решила устроить "совет в Филях". В результате в нашей палатке собрались все шестеро участников нашей экспедиции. Как тут же выяснилось этот набег на нашу палатку был не случаен. Оказывается они решили, что идти с двумя палатками - это роскошь и теперь проверяли, могут ли уместиться в одной палатке шестеро человек. А мы, ничего не подозревая, позволили им залезть в нашу палатку!

Идти было решено завтра и с одной палаткой. Так как после перехода на Томские стоянки предполагалось вернуться назад, то остальные вещи было решено оставить в другой палатке под присмотром соседей. С собой было решено взять только теплые вещи. Еще один вопрос должен был решиться этим походом - что лучше: бензин или газ? У нас был взят с собой примус "шмель", а Павел взял газовую горелку. На Томские стоянки было решено взять с собой газовую горелку и испытать ее там.

Газовая горелка в действии

Продолжение следует.


5.08.2004

 Rambler's Top100 Дата последнего обновления файла 02.02.05

5.08.04 Томские стоянки.

Погода утром практически не отличается от вчерашней. Однако сразу после завтрака все бодро начинают собираться в поход на Томские стоянки. Первоначально планируется взять всего три рюкзака, однако после некоторых препирательств на стоянке остается только рюкзак Игоря. Вдоль Аккема ведет хорошо различимая тропинка, и мы бодро топаем по ней. Время от времени ботинки начинают чавкать по воде, иногда лыжная палка царапает по камню, но главное - есть тропа, и значит люди уже здесь проходили.

Вид на Аккемскую стену со стороны Аккемского озера. Отчетливо видны восточная и западная вершины Белухи. На переднем плане видно болото около нашей стоянки и ручьи, впадающие в него.

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

Переправа через ручей.

Следующее препятствие оказалось более серьезным. Это река Аккем. Нам, оказывается, нужно переправиться на другой берег Аккема! Переправа как то не выглядит слишком надежной... Для начала решили сфотографироваться на ее фоне. Может это поможет переправиться на другой берег? Александр Павлович решил подбодрить нас, как всегда в своем духе - он рассказал, что несколько лет назад здесь не было и этой переправы и как легко при переправе через это самое место можно оказаться в воде и что выныривать придется на несколько десятков метров ниже по течению... если удастся... Подбодрив нас таким образом, Александр Павлович быстренько перебежал на другой берег и приготовил фотоаппарат. Как он крикнул через речку - чтобы сфотографировать на память момент полета.

Это мы перед штурмом Аккема.

С криком "не дождетесь" Макс бросился следом за Александром Павловичем и... тут же сделал шпагат на двух трубах, которые разъехались в разные стороны под его ногами, так как связать эти трубы между собой никто из строителей не догадался. Сделав несколько невообразимых пассов руками Макс восстановил первоначальное положение и меньше чем через минуту был на другой стороне реки. Хм... Никогда не догадывался об эквилибристких способностях у Макса.

Теперь моя очередь... Ну, ладно не будем об этом...

А это я! Пытаюсь наступить на трубу, а не мимо нее!

Сразу же за мостиком начинается моренный вал, который образовал верхнее Аккемское озеро. Мы вскарабкиваемся на этот вал. Здесь тропинка видна отчетливо. Правда, тропинок много - выбирай на вкус. Хочешь - посложнее, хочешь - попроще. Так как вода в Аккеме была достаточно низкая, то мы выбрали тропинку вдоль Аккема. Вокруг море можжевельника - и в виде кустарника и в виде травы. На веточках можжевельника видны красивые чёрные ягоды. На камнях - разноцветные пятна лишайников. Именно по этим камушкам нам и приходится прыгать. Тропа уже почти не видна.

Вид на тропу, по которой мы поднимаемся вдоль верхнего Аккемского озера.

По пути встретился довольно крупный ручей. На этот раз никто не догадался перекинуть бревнышко через этот ручей. Правда при этом бревнышко пришлось бы тащить снизу. Зона лесов закончилась. Деревья остались внизу. Приходится перепрыгивать ручей по камням Перепрыгнуть через ручей удаётся только при помощи Шишкина. Мешает рюкзак. Какие виды! Это просто не передать словами, да и фотоаппарат мало помогает. Ручей даже не пытаемся фотографировать.

Вид на верхнее Аккемское озеро

Вскарабкиваемся выше. Начинается курумник. Курумник - это крупные камни, многие из которых шевелятся. Движение вперед начинает напоминать гимнастические упражнения. Шаг вверх, шаг вниз и снова вверх, а теперь упражнение на равновесие... Ну как? Не упали вместе с камушком весом на полтонны? Тогда продолжаем движение! Вокруг уже нет ни травинки ни даже лишайника. Здесь царство камней, воды и облаков. Хотя нет - один раз мы разглядели движение между камней. Какое-то животное, размерами не больше мыши, деловито пробиралось между камней. Интересно, что оно здесь забыло?

Движение вперед начинает напоминать гимнастические упражнения. Ручеек внизу - это река Аккем и маленькой она выглядит только потому, что мы поднялись на несколько сот метров выше ее.

Так называемая тропа прослеживается по турам (камням, положенным друг на друга). Часто в качестве камней для туров используются кварциты - красивые белые полупрозрачные камни. Жаль, что любой лишний вес так тяжело тащить! А то бы прихватил парочку. Мы часто теряем тропу и скачем просто по камням. Учитывая, что приходится подниматься и опускаться вниз по склону горы, то это довольно тяжело. Кроме того, похоже, что каждый, кро прошел здесь до нас считал своим долгом пометить свой путь отдельной цепочкой туров!

Время от времени начинается дождь, несколько раз превращавшийся в снежную крупу. В общем всё повторяется как и вчера, только на этот раз мы не смотрим на всё это из окна палатки, а сами находимся в центре событий. Самое неприятное в этом то, что камни от воды, как это ни странно, становятся мокрыми! Ох уж эта "кухня погоды".

Вид на оба озера от истока Аккема
Исток Аккема с высоты сотни метров. Это не ручеек с соседней помойки! Это достаточно крупная река.

Идем дальше. Теперь внизу вместо Аккема уже ледник, кое-где покрытый камнями. Под нами тоже кое где между камнями поблескивает лёд. Наконец, впереди показывается стена льда - ледопад. Мы проходим (проскакиваем по камням) выше по склону. Здесь можно было бы выйти на ледник и спокойно подняться до короны, но мы упорно скачем по камням (по мореному валу). Как ни странно, но никто здесь не хочет расстаться с рюкзаком и, как Игорь ни предлагает всем свою помощь, но все "вежливо" отказываются. Под рюкзаком-то теплее!

Вид на каменный вал последнего ледопада Аккемского ледника с моренного вала.

Наконец, подходим к еще одной ледяной стене, прорезанной ручьями в различных направлениях. Слева от этой стены вниз простирается вал из камней. Похоже, по нему легче всего подняться на ледопад. Оглядевшись вокруг, и убедившись, что на этот раз нас не удастся провести по склону горы, где камни побольше, Александр Павлович, скрепя сердце, соглашается выйти на ледник. Спустившись на ледник, мы начинаем подъём по этому валу на корону Аккемского ледника. Подниматься тяжеловато из-за приличной крутизны. Приходится несколько раз отдыхать. Наконец мы наверху. Осторожно по снежному наносу выходим к скале, покрытой крупным курумником.

Перед нами возвышается Аккемская стена - соединённые между собой Восточная и Западная вершины горы Белуха, гора Корона и пик Делоне. Внизу Короны чётко выделяется ложбина, покрытая льдом. Ледник внизу, изрезанный ручьями, похож на огромные кристаллы драгоценного камня. Но, к сожалению, нет солнца. Идёт дождь. Поэтому зрелище не такое впечатляющее. Вершины гор полностью закрыты облаками. Иногда гремит гром. Стены гор вокруг образуют цирк и только сзади открывается изумительный вид на сотни километров. Виден Аккемский ледник, за ним два озера. На берегу одного из них видны домики спасательной станции. Ещё дальше видна долина Аккема, где где-то внизу должна проходить "тропа дураков". А ещё дальше видна долина Катуни.

Ледяная корона Аккемского ледопада. Правда, из-за плохой освещенности не видно ее сверкания, да и висящее прямо над ней облако - не лучший помощник для фотографа.

Любоваться всеми этими замечательными видами некогда. Свистит пронизывающий насквозь ветер. Из-за горы снова наползает тёмное облако. Похоже снова налетит дождь, а может и снег. Надо двигаться к Томским стоянкам, чтобы успеть поставить палатку. И мы снова карабкаемся по огромным камням по склону горы. Теперь мы двигаемся на восток и долина Аккема больше не видна. Вокруг нас стены гор, внизу по прежнему ледник. Время от времени нас обгоняют группы альпинистов и до нас, наконец, доходит, что двигаться по льду быстрее.

Спускаемся вниз, перепрыгиваем по камням ручей, бурлящий между ледником и скалой и исчезающий где-то внизу. И вот мы на склоне тающего ледника. Он покрыт мелкими камнями. Большие встречаются редко, поэтому двигаться легче. Но я уже на пределе. Еле переставляю ноги, постепенно приближаясь к груде камней, пересекающей ледник. На вершине этой груды камней виден домик спасателей.

Попробуйте разглядеть впереди между горами домик.

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

Вид на "Арбуз" с флагом посередине.

Холодно. Несмотря на то, что к этому времени ветер разогнал все тучи, и вершины гор ярко освещены солнцем, теплее от этого не стало. Само солнце закрыто от нас горами. Мы быстро ставим палатку. Татьяна и Игорь еле дошли (про себя не говорю), так как у них разболелись ноги. Игорь даже шёл без рюкзака. Все мокрые. Быстро переодеваемся в сухую одежду. Натягиваем на себя всё, что принесли с собой, но всё равно холодно. Между гор прямо через нас, в долину, дует холодный пронизывающий ветер. Я падаю в палатку и теперь никакими силами меня отсюда не вытащить! Павел на газовой горелке готовит суп. Впереди предстоит ночёвка шестерых человек в одной палатке...

Одно из мест для палаток. На заднем плане виден камень с табличкой с перечислением фамилий альпинистов, погибших в этих местах.

Продолжение следует.


6.08.2004

 Rambler's Top100 Дата последнего обновления файла 03.02.05

6.08.04 Томские стоянки.

Ночёвка - это нечто! С трудом размещаемся в палатке. Пытаемся заснуть, но, зажатые со всех сторон, ноги быстро затекают. Время от времени кто-либо из нас садится в палатке и его место тут же занимается соседями. Один Максим спит и даже похрапывает. Вот зануда! Хоть бы не дразнился! Время от времени он расширяет своё жизненное пространство. При этом Шишкин пытается увернуться от резко выброшенной ему в лицо ноги, а я с трудом удерживаю свою грудную клетку от раздавливания спиной Максима. Несмотря на отсутствие места в палатке я начинаю двигаться в направлении, заданном этой спиной. Игорь и Павел, лежащие за моей спиной, начинают громко возмущаться, что их выдавливают из палатки, а ноги Татьяны со звуком пробки, вылетающей из бутылки, подлетают вверх и исчезают на время где-то в противоположном конце палатки. Наконец, совместными усилиями, втроём, мы восстанавливаем статус-кво. Временно палатка затихает.

За тонкой тканью палатки слышен посвист ветра, проносящегося над нами. Как хорошо, что мы поставили палатку внизу, а не на вершине каменной гряды. Время от времени слышен грохот камня, падающего с окрестных гор вниз. На время становится жутко при мысли, а что если этот камушек попрыгает по палатке? Судя по звуку, в нём весу не одна тонна! Однако тут же вспоминаю, что палатка находится посередине горного цирка и камушку вряд ли удастся допрыгать даже треть расстояния до нас.

Снова пытаюсь заснуть. В палатке постепенно становится жарко. Надо же, сколько тепла выделяют шестеро человек! Снаружи слышится звук грома. Странно. Гром среди снегов? Звук повторяется. На этот раз до меня доходит, что нет привычных раскатов. Вместо этого гром плавно затихает. И тут до меня доходит! Это не гром! Это звук снежных лавин! Похоже, ветер наносит снег на склоны гор и он, не выдержав собственного веса, срывается и скатывается вниз. Я уже ночевал на высоте и повыше, но звук сходящих с гор лавин слышу впервые.

В палатке уже настоящая жара и Игорь приоткрывает вход в палатку, для того чтобы проветрить её. Татьяна не выдерживает тесноты, и, устав взывать к совести Максима, уползает к противоположной от меня стороне палатки. Там она в очередной раз напоминает всем, что она очень маленькая и сворачивается клубочком как кошка. На время всё затихает снова.

Так, в попытках заснуть, и в борьбе за жизненное пространство, проходит вся ночь. Постепенно в палатке становится светлее. И тут выясняются очень удивительные вещи! "Кошка" Татьяна спит, заняв треть палатки. "Захватчик" Макс вместе с Шишкиным умещается на другой трети палатки и, судя по всему, не превышает своей квоты на одну шестую палатки. Но самое удивительное происходит на нашей трети палатки! Потом, когда все уже покинули палатку, мы с Игорем долго разглядывали то место, где умудрился уместиться Павел. Отнюдь не миниатюрный, в отличие от Игоря, он умудрился занять треугольник, размерами 10x150 см! Сколько мы ни пытались уместить на это место хотя бы пустой спальник Павла, нам это не удалось! Похоже, Павел владеет приёмами перемещения части тела в четвёртое измерение.

Это нас только трое. Представьте как в такую маленькую палатку упихать шестерых! А ведь там было ещё и пять рюкзаков.

Утро возместило все наши мучения. Ветер стих. Прямо над нами, ярко освещённая солнцем, сияет кора Корона и обе вершины горы Белуха. Аккемская стена и пик Делоне пока в тени. На небе ни облачка, но наверху, похоже, ветер есть. Над снежными шапками Белухи взмывают вверх снежные вихри.

Макс вышел из палатки.

Шишкин вылазит из палатки и начинает фотографировать открывшуюся панораму. Быстро готовим традиционный суп из гречки (глаза бы его не видели!) и готовимся к подъёму на Арбуз. Флага на нём уже нет. Наверное, сдуло вчерашним ветром. Правда есть ещё одна версия, что его сняли перепившиеся в соседней палатке альпинисты. Они ржали весь вчерашний вечер, а затем один из них на спор полез за флагом без "кошек". Но теперь это неважно.

Перед выходом на ледник.

Альпинисты постепенно сворачивают палатки и уходят на Арбуз. Говорят, что они через перевал Делоне будут покорять Белуху. Если честно, то я не завидую им, ведь там такой холод!

Ну как, испугались?

Мы тоже облачаемся в очки, каски и ... увидев себя в таком виде, долго ржём. Наконец, перестав пугаться друг друга, и привыкнув к нашему новому виду, осторожно сбоку подходим к самому пологому краешку Арбуза. Арбуз протаял поперёк слоями, которые образовали подобие ступенек, и мы с трудом вскарабкиваемся по ним на ледник.

Максим в "кошках" на последних "ступеньках" ледника. Внизу виден домик спасателей.

Наверху это достаточно протяжённый язык льда, идущий от стен горного цирка до нас. Вдосталь налюбовавшись открывшимся видом на ледник и окружающие горы, а также Максимом, упорно штурмующим ледник при помощи кошек и лыжной палки (он не ищет лёгких путей), мы двинулись по леднику вперёд, к перевалам Титова и Делоне. Впереди бежит Александр Павлович, заботливо запугивая нас, что ледник может провалиться, Солнышко может обжечь нас, а с соседней горы обязательно скатится камушек весом на три тонны и тогда вся наша надежда на каски на голове. Хорошо. Ярко светит солнце, по поверхности ледника в промоинах текут прозрачные ручейки, а далеко впереди видно, как группа альпинистов карабкается на ледяной перевал Делоне.

Перевал Титова. На переднем плане видна промоина в леднике.

А это мы возвращаемся назад

Дойдя до перевала Титова, мы решаем, что пора возвращаться назад и быстро возвращаемся к палатке, оставшейся на Томских стоянках, сворачиваем ее и двигаемся вниз. Этот переход не похож на вчерашний. Вокруг сияет солнце, ярко освещая снежные шапки гор и склонов Аккемской стены.

Спускаться или не спускаться? И вообще, как мы сюда залезли?
Ну, была - не была! Поехали!

Вниз мы спускаемся по леднику, и этот спуск напоминает прогулку. После поворота опять открывается изумительный вид на долину Аккема. Здесь мы тоже не лезем на курумник, а продолжаем двигаться по леднику. Это значительно легче. Под ногами промоины, по которым текут ручейки. Они открывают многометровую зеленоватую толщу льда, сверкающую на солнце. Остальная поверхность льда покрыта мелкими и крупными камнями. Некоторые каменные глыбы стоят на ледяных постаментах и напоминают гигантские грибы. В спину дует снова поднявшийся ветер. На небе появляются облака, и по мере нашего спуска их становится всё больше.

Вид ледника на обратном пути.

К моменту нашего возвращения в лагерь на озере, начинается дождь. Спуск прошел без приключений и приятной неожиданностью оказался отремонтированный мост.

Вернувшись к озеру, мы быстро поставили палатку и легли спать. Назавтра запланирован переход в долину реки Кучерлы.

7.08.04 Аккемское озеро

Переход планировался через перевал Рига Турист. Не тут-то было! Ночью налетел ураган. Палатку чуть ли не сносило вместе с нами. Она почти пополам складывалась под порывами ветра, а шум дождя, обрушивающегося на нас, заглушал всё вокруг.

Наутро дождь стал слабее, но ветер оставался сильным. Кое-как приготовили поесть, с тоской глядя на то место, где должна быть Аккемская стена, но там только серое пространство между ближайшими горами. Такое впечатление, что там ничего больше и нет. Снизу время от времени то ярко синее небо, то наползают белые облака и плывут мимо нас, постепенно тая на противоположной горе.

Смотрим "телевизор". Каждый раз, как только облака приоткрывают вид на ближайшие горы, видим, что их вершины покрываются снегом. Причём с каждым новым зарядом граница снега опускается всё ниже и ниже. В очередной раз, после особенно сильного дождя, обрушившегося на нашу палатку, окрестные горы покрываются снегом. Граница снега проходит в какой-то сотне метров над нами. Лезть на перевал нет никакого желания.

Продолжение следует.


8.08.2004

 Rambler's Top100 Дата последнего обновления файла 09.02.05

8.08.04 Кара-Тюрек.

Утро. Ночью выпал снег. Вокруг все деревья в снегу. Шишкин с утра готовит на примусе. Сверху висит не то туман, не то облако, из которого сыплется мелкий снежок. Правда, озеро не замёрзло. На земле снега нет, так что температура, скорее всего больше нуля.

Утро туманное.

Сегодня собираемся на перевал Кара-Тюрек. Ждём, пока рассеются облака. Правда сейчас светит солнышко. Сначала собирались идти через перевал Рига-Турист, но, говорят, после прошлогоднего землетрясения его категория стала выше, и мы не сможем на него забраться. Откровенно говоря, после того, как я посмотрел на перевалы Титова и Делоне, я понял, что перевалом могут назвать и отвесную стену.

И зачем только надо вылазить из палатки?

Я боюсь, что скоро не смогу заходить в палатку. Так много я никогда не ел. Шишкин пытается запихнуть в каждого тазика по два еды, а если удастся, то и больше.

Вчера Татьяна пыталась поднять бунт, однако её никто не поддержал. Тогда она обидевшись ушла от костра. Костер почему-то следом не побежал, а так как погода была достаточно прохладной, то пришлось снова вернуться.

Облака рассеиваются буквально на глазах. Сейчас открылся вид на Белуху. Сейчас она вся белая. На соседних горах клочками висят облака. Вид изумительный. Снег вокруг нас мгновенно растаял. Мы выставили ботинки на улицу, и от них валит пар. Правда, пар сейчас валит от всего. От земли, кустов, деревьев. В палатке тепло, но на улицу вылазить неохота.

Ну вот я и готов к штурму перевала.

В 11.30 вышли из лагеря и прошли до начала озера. За прошедшие два дня озеро наполовину заполнилось. Сразу за домиком спасателей начинается подъём. Как обычно, тропа грязная, разбитая лошадьми. Подъём ведётся по лесу. Навстречу попадаются группы туристов, спускающиеся с перевала. Я, с трудом хватая ртом воздух, карабкаюсь вверх. Походка напоминает походку древнего старика, который, опираясь на клюку (лыжную палку) еле еле переставляет ноги. Тропа продолжает подниматься в гору. Приходится довольно часто останавливаться и отдыхать, опираясь на палку. Наконец вышли из зоны лесов, но легче от этого не стало.

Зона снега отступает перед нами.

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

Держите шапки товарищи!

Следом поднимаемся и мы. Я со свистом захватываю воздух. Ребята ушли вперёд. Время от времени они поджидают меня. Несмотря на то, что сверху пригревает солнышко, воздух становится всё холоднее, так как мы поднимаемся выше. Всего нам предстоит подняться на километр. Постепенно из-за горы начинают появляться облака, и когда облако закрывает солнце, то становится откровенно холодно.

А облака то под нами!

Травы становится всё меньше, всё больше лишайников на камнях. Наконец мы забираемся на вершину каменной гряды. Внизу видна долина Аккема, ручей, сбегающий с противоположной стороны этой долины, а по другую сторону гряды видна каменистая осыпь. Александр Павлович с радостью объявляет нам, что это перевал Кара-Тюрек I, но шоколадку он нам не даст, так как это не настоящий перевал а только учебный.

Перевал Кара-Тюрек I

Осторожно проходим по краю каменистой осыпи - и перед нами снова подъём. Между осыпью и горой течёт ручей. Немного отдохнув, снова продолжаем подниматься по склону горы. Травы больше нет - только камни. Навстречу спускается очередная группа туристов. Молодые девушки и дети с удивлением смотрят на хватающего ртом воздух дядю, медленно переставляющего ноги под рюкзаком.

Последний шаг, он трудный самый.
Последний привал под перевалом.

Подъём продолжается. Снова один гребень сменяет другой и не видно их конца и края. Теперь между камнями лежит снег, а я всё переставляю одну ногу за другой. Небольшой отдых, не снимая рюкзака, и процесс повторяется. Но вот, наконец, и груда камней с воткнутыми палками, обвязанными тряпочками, обозначающая перевал.

Перевал Кара-Тюрек.

Навстречу попадается алтаец на лошади. Ещё несколько лошадей следуют сзади, все они связаны одной верёвкой. Последняя лошадь шумно избавляется от лишней воды, показывая своё отношение к окружающему. От снега валит пар. Перевал пройден.

Лошади на перевале Кара-Тюрек.

Теперь начинается спуск в противоположную долину. Сначала тропа идёт прямо по хребту, с которого видны обе долины, потом постепенно сворачивает в сторону Кучерлы. Теперь главное не ошибиться по какой из долин следует спускаться вниз. Подходим к одной из них. Внизу расстилаются груды камней. Решаем, что туда не пойдём и двигаемся дальше. Тропы уже нет. Подходим к следующему понижению между холмами (так кажется при взгляде сверху) и начинаем спускаться. Под ногами снова начинает хлюпать вода. Вокруг камни и лишайник.

Наконец, между камнями по лошадиным какашкам находим подобие тропы и, поскальзываясь на мокрых камнях, начинаем спуск. Постепенно спускаемся всё ниже, пытаясь удержаться на скользких камнях. Тропа становится всё более заметной. Она огибает утёс, который мы обошли сверху. Ребята удрали далеко вперёд, я же боюсь поскользнуться и загреметь вниз (склон, по которому идёт тропа, довольно крутой), поэтому иду медленно. Правда это не единственная причина. Ноги тоже очень устали после подъёма, а во время спуска боюсь, что разболятся колени, поэтому изо всех сил опираюсь на палку.

Наконец спускаемся до истоков реки Текелюшки, по камням перепрыгиваем на другой берег, и продолжаем спуск по её левому берегу. Вскоре речка скрывается в глубоком ущелье с отвесными стенами, будто облицованными зеленоватым сланцем. Ещё небольшой спуск, затем подъём и мы входим в густой кедрач. Здесь останавливаемся на ночёвку.

Внизу течёт речка Текелюшка. Спуск довольно крутой, но добраться до воды можно. Кругом камни, но делать нечего - одну палатку ставим на камнях, а другую на корнях кедра. У кострища лежит свежая кедровая шишка и несколько старых, с орехами. Я не удержался и опустошил эти шишки.

Место очень живописное. За нами видны камни, покрытые лишайником, можжевельником и жимолостью. Над нами возвышается утёс, а внизу гремит река. Противоположная сторона реки лишена деревьев. Там поблескивает вкраплениями слюды зеленоватый сланец.

Александр Павлович разжигает костёр. Как только остановились, начинает донимать холод. Костёр совершенно не греет. Сегодня наша очередь дежурить. Мы с Максимом ставим палатку, а Игорь готовит еду. Натягиваем на себя всё что только можно, но всё равно холодно.

Игорь готовит еду.

Ноги как каменные. Вяло перепихиваемся кто завтра утром будет готовить. Макс храбро вызывается сбегать за водой, но готовить отказывается наотрез. Ладно. Значит готовить придётся мне. Смирившись с мыслью, что завтра мне, скорее всего, придётся и за водой пилить (вероятность, что Макс проснётся близка к нулю) залезаю в палатку.

Продолжение следует.


9.08.2004

 Rambler's Top100 Дата последнего обновления файла 15.03.05

9.08.04 На Кучерлу!

Ночь в палатке - это аттракцион! Постоянно съезжаем в сторону склона. Я одновременно пытаюсь обернуться вокруг корня, впивающегося в бок, но при этом начинает возмущаться Игорь. Всю ночь под Максимом что-то грызёт мышь, но его это не касается и он спокойно продолжает спать. Стукну по пакету - мышь успокоится а затем опять за своё.

Утром Максим сбегал за водой, а я принялся за приготовление еды. Возможно это будет каша ... а может и нет ... С трудом разжёг костёр. К этому времени проснулась Татьяна и начала давать ценные указания. Общими усилиями получилось нечто вроде каши. Надо отметить, что везде мы добавляем сушёную сою. Поэтому я полчаса лупцевал пакет с сушёной соей топором, пока соя не превратилась в порошок.

Это наше новое изобретение. Так как сою невозможно проглотить, если она остается куском, то мы придумали размельчать её не вынимая из пакета. Небольшая обработка пакета соевого мяса и вместо непроваривающихся кусков сои получается порошок, который, будучи добавлен в котёл, почти не отражается на вкусовом содержании варева. В общем есть можно. тем более, что тушенка, которую мы добавляем в котел, по вкусу поразительно напоминает этот порошок... Интересно, а мясо в тушенку добавляют или нет?

Процесс приготовления пищи. Вверху на фото, если не понятно - ствол упавшего кедра. Это Александр Павлович зачем-то залез под этот кедр, чтобы сфотографировать дежурного. При этом его пятая точка заметно возвышается над бревном. Бросить шишкой что ли? Шишкой в Шишкина - каламбур какой то! Ладно, пусть ползает, а то еще в котелок попаду.

После еды с меня стали требовать компот из бадана. Знал бы я что это такое! Пришлось особо нетерпеливым товарищам срочно объяснять что это такое и с чем его едят. Несмотря на уверения в съедобности этих бурых листиков меня продолжали мучать смутные сомнения. В общем, компота не получилось и на меня временно махнули рукой.

К Кучерлинскому озеру двинулись в 11.30. Сразу же начались споры куда идти. Вниз по предварительным разведданным можно попасть двумя путями - вдоль речки (там ребята уже ходили и повторить этот путь у них нет ни малейшего желания) и где-то по верху. Тропа же от нашей стоянки идёт вниз только одна. Решили идти по этой тропе. Сначала спустились немного ниже, затем тропа снова пошла в гору. На этот раз идти достаточно легко. По пути обсуждаем мировые проблемы. Татьяна с Павлом, как всегда, бегут впереди. Макс вспоминает "прелести" спуска вдоль Текелюшки и его впечатления от этого спуска в прошлый раз.

На привале Шишкин начинает всех фотографировать. Делаю ему козу, но он оказался проворнее.

Тропа постепенно спускается к лесу. Наконец, после очередного поворота, далеко внизу открывается вид на Кучерлинское озеро. Устроили привал. Шишкин похоже обеспокоился, что у него останется плёнка, и начал всех фотографировать. Досталось и мне. Поставил он меня около молодого кедра и начал тщательно выцеливать из фотоаппарата. Мне это надоело и я решил состроить ему козу, но он оказался проворнее и в результате получилось непонятно что.

Странно, но вниз с горы почему-то спускаться легче чем подниматься вверх в гору. Хотя и здесь есть свои особенности. Например очень трудно затормозить около очередной сосны. Иногда заносит на поворотах. И вообще, почему лошади не ходят в туалет куда-нибудь в сторону от тропы? Мало того, что они размесили тропу в чёрную грязь, так они её ещё и ароматизировали!

После очередного спуска вокруг тропы обнаруживаем заросли черники. Шишкин не планировал привал в этом месте, но на этот раз привал потребовала вся группа. Пришлось подчиниться воле большинства. Пока черника не была объедена полностью мы дальше не двинулись.

Вид на Кучерлинское озеро с моренного вала.

Ещё несколько спусков и подъёмов и мы около моренного вала. Это сооружение значительно более солидное по сравнению с Аккемским валом. Он покрыт травой и лиственным лесом. Вскарабкавшись на него, снова увидели Кучерлинское озеро. Это на самом деле, в отличие от Аккемского, озеро и достаточно солидное. Вода в нём, как и во всех местных речках, зеленовато-белая. Да, похоже Аккела в очередной раз промахнулся. По предварительным данным, полученным нами ещё у Аккемского озера, мы должны были выйти непосредственно на этот мореный вал. Однако пришлось карабкаться на него. Однако, по воспоминаниям первопроходцев, мы всё равно значительно сэкономили время и свои усилия.

Внизу наблюдалась какая-то туристическая база и мост через речку. Похоже у нас будут проблемы с выбором места для стоянки. Когда мы спустились вниз, то решили пройти вдоль вала и вскоре было обнаружено прекрасное место для стоянки. Здесь мы и решили разбить свой лагерь. Расположили лагерь непосредственно на берегу реки Кучерлы между двумя озёрами прямо под моренным валом около огромной лиственницы. Сразу же развели костёр и похоже останемся здесь дня на два. На берегу речки нашли полурастворённые камни светло-зелёного цвета. Наверное, именно эти камни и придают цвет местным рекам.

Река Кучерла намного шире Аккема и несколько теплее. Завтра планируется пробежка до верховий Кучерлинского озера, но меня даже не приглашают, так как планируется пробежать туда и обратно за один день. Скорее всего, побегут Шишкин, Павел и Татьяна как самые быстроногие. Игорь и Максим там уже были и во второй раз лазить между сгоревшими деревьями не желают. В общем нас оставляют охранять лагерь. Игорь сразу же бросается к реке мыть голову - ведь вода в этой реке теплее чем в Аккеме. Ну как тут мог утерпеть Шишкин? Естественно он запечатлел этот момент на века!

Вода в реке Кучерла на целых два градуса теплее!

У костра нашлось несколько недорубленных бревёшек, которые предназначены для дров. И тут выяснилось интересное обстоятельство. Оказывается некоторые товарищи из нашей отважной группы полны сил и энергии, которую некуда девать, поэтому Татьяна взялась перерубать брёвнышко туристическим топориком. Не прошло и полдня и брёвнышко было перерублено. Но, как выяснилось, энергия не закончилась. И тут Шишкину в голову пришла гениальная идея! Он обратил внимание на то, что один из сучков похож на нос Буратино. И Татьяна была выключена на два дня! Начался творческий процесс - рождение Буратины!

Процесс рождения Буратины.

Так в творческих муках под стук топора прошел день...

Продолжение следует.


10.08.2004

 Rambler's Top100 Дата последнего обновления файла 16.03.05

10.08.04 Кучерлинское озеро.

Сегодня с утра светит яркое солнце. Тепло, хорошо. Шишкин с Павлом и Татьяной убежали на другой конец озера на ледники. У нас полный разгул демократии. С утра и почти до обеда проспали в палатке, пока не стало припекать. Затем встали, поели каши, и стали щуриться на солнце как сытые коты.

Время шло а никто не пытался загнать нас в рюкзаки. Никто не пытался напасть на наш лагерь, охранять который мы остались. Похоже основная туристская тропа проходила где-то в стороне. Только один раз прямо по нашему лагерю протопала группа немцев. Похоже они, в отличие от наших ребят, напролом на мореный вал лезть не пожелали и спокойно обошли вокруг. Надо запомнить!

Тут мы стали припоминать, что помнится вчера Александр Павлович нам поручал посмотреть подходы к перевалу Рига-Турист со стороны Кучерлинского озера. После ленивой перепалки решили что лагерь охранять останется Игорь, а мы с Максимом побродим вокруг. И тут меня ждал шок - моего костыля (лыжной палки) нигде вокруг не было! Неужели её захватили гады немцы, когда проходили по нашему лагерю?! И как? Ведь мы все трое смотрели на них и ничего не увидели! Игорь, немного похихикав надо мною подвёл меня к палатке в которой ночевали наши участники скоростного забега в верховья озера и показал мою палку. Ребята просто скромно использовали мою палку для того, чтобы натянуть палатку. Ну что же, придётся позаимствовать другую палку. Не буду же я разрушать чужое жилище! Даже построенное на моей лыжной палке!

Мы с Максимом быстренько пробежали вдоль мореного вала (вода в реке явно пошла на убыль) и бодро пошагали вверх. Сначала вскарабкались на мореный вал. Без рюкзаков это было не так уж и сложно. Даже несмотря на то, что мы не особенно придерживались какой либо тропы. Затем, по каменистой осыпи, продолжили подъём. Здесь явно просматривалась тропа на перевал Кара-Тюрек, но мы двинулись прямо вверх.

По пути несколько раз сфотографировались и вдруг ... увидели малину! Естественно, тут же вместо того, чтобы скакать дальше, как это было бы если бы мы были все вместе, мы дружно подкинули свои зады вверх и стали пастись на склоне горы. Медленно, передвигаясь от куста малины к кусту смородины и снова к кусту малины, мы передвигались вверх. Никто нас не подгонял и мы ловили кайф на тёплых камнях, нагретых ярким солнцем. Передвигались исключительно от куста к кусту.

Наконец вспомнили, что неплохо было бы собрать ягоды и для остальных. Стали решать во что собрать ягоду. Решили, что пакет из под туалетной бумаги вполне подойдёт. Начали собирать - какая ягода послаще - то в рот, а покислее - в мешок. Так, между делом, добрались до границы леса. Немного подумав, решили, что ну её, разведку дороги на перевал Рига-Турист, подальше и двинулись в обратный путь. При этом нашли дорогу к лагерю более короткую и пологую, чем та, по которой ушли. По этой тропе мы вышли прямо к лагерю, не спускаясь к реке.

Вернувшись в лагерь, всучили ягоду Игорю. Мы по честному предупредили, что ягода кислая и что нужно или разделить ягоду на два раза или добавить сахару побольше. Однако Игорь недолго думая, кинул весь наш улов в котёл. Немного поварил ... Надо было видеть его лицо, когда он попробовал, что получилось! В общем все наши запасы сахара были тут же отправлены в котел с компотом! При этом я не соврем был уверен, что компот не кислый.

В 18.30 вернулась экспедиция, бегавшая в конец озера. Первым прибежал Шишкин. Все накинулись на наш, так называемый, компот. Проглотили, даже не заметив, какой он кислый. Татьяна тут же целеустремлённо продолжила творческий процесс ваяния Буратины. К вечеру произведение искусства было закончено.

Ну вот, Буратино, наконец, и готово!

Как только тень от горы накрыла наш лагерь, стало холодно и все быстро разбежались по палаткам. Да, плохо жить без солнышка!

11.08.04 Домой!

Сегодня с самого утра светит солнце. Ночью было холодно, и появление солнца все радостно приветствуют. Все уже засобирались домой, и обсуждают пути. Сошлись на мнении, что за один день до Тюнгура не дойти. Постепенно складываются палатки. Сейчас ласково светит солнце. Уже стало тепло.

Как хорошо когда светит солнышко!
Максим придирчиво осматривает свое хозяйство и перераспределяет груз между нами.
Идёт подготовка к очередному скоростному забегу.

Максим придирчиво осматривает свое хозяйство и перераспределяет груз между нами.

В последний раз окидываю взглядом реку, лиственный лес на противоположном берегу и горы. С этого места, где я сижу, озёр не видно, но всё равно красиво.

Продолжение следует. Может быть... Когда-нибудь...

<< >>


1.08.2004

 Rambler's Top100 Дата последнего обновления файла 30.09.04

Обычно я провожу всё время в городе, но иногда на меня находит и я срываюсь, причём обычно я срываюсь в горы. Срываюсь так, чтобы поблизости не было ничего, что напоминало бы о "цивилизации".

  • Покорение Красноярских столбов или шиза 1980
  • Хождение вокруг Обской лужи или шиза 1982
  • Взятие Кавказского хребта или шиза 1983
  • Эльбрус или в поисках приключений
  • Сочинение доцента о том как он провёл лето или шиза 2004