Ошибка

ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ

Категория: Электроприводы
Опубликовано 11.07.2011 11:50
Автор: Super User
Просмотров: 2706

ГЛАВА

3

ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ

Краткое содержание

Средства разработки/Среды

Язык Ассемблера

Интерпретаторы

Языки высокого уровня

Нечеткая логика

Разработка программного обеспечения

Распределение ресурсов Программы, критичные ко времени Макросы и условные команды

Резидентный монитор и отладчик Операционные системы реального времени

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


Средства разработки/Среды

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

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

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


Например редактор, используемый для написания программ на языке С. в действительности может выполнять программу «REXX» после каждого нажатия на клавишу. Эта программа обрабатывает нажатия клавиатуры и обеспечивает специальные виды отклика в различных ситуациях. Например, после ввода оператора «if», редактор выдаст следующий отклик, который воспроизводит формат языка С для этого оператора:

if ()

{

} else

{

} /* endif */

Такая реакция редактора избавляет от необходимости заботится о правильном синтаксисе оператора.

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


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

Интерфейс, о котором пойдет речь, — это интерфейс между редактором и компилятором/ассемблером. Возможность передавать информацию об ошибках компиляции и отображать неправильные строки на дисплее может сделать процесс разработки более простым и эффективным. Для описанного выше редактора можно написать REXX-программу, которая в процессе компиляции будет сохранять исходный текст, выполнять компиляцию, находить ошибочные строки и выделять их в исходном тексте. Фактически эта REXX-npo-грамма производит комплексную обработку исходного текста.

Симуляторы — это программы, которые выполняют откомпилированный программный код в инструментальном компьютере системы разработки (host) так, как если бы он выполнялся в целевой системе (target). Это позволяет осуществлять наблюдение за программой и реакцией микроконтроллера на различные события. Симулятор может быть неоценимым инструментом в процессе разработки программного обеспечения, позволяя исследовать различные ситуации, которые трудно воспроизвести на реальной аппаратуре.


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

Шаг BitO Bit1 ; Определение входных битов

1 11; Начальные условия - Все единицы

0 1 ; Имитация сдвига данных

0 0

0 1

1 1 ; Переход к следующему биту

1 0

1 1

И так далее...

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


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

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

Специальная схема, реализующая интерфейс с микроконтроллером в реальном масштабе времени, называется «схемный эмулятор» (Ill-Circuit Emulator — ICE). Эмулятор использует микросхему микроконтроллера, подключенную не к ПЗУ, а к ОЗУ программ, которая выполняет прикладные задачи с реальной скоростью. Многие эмуляторы могут использоваться для записи команд, выполняемых процессором в определенное время. Это помогает понять, как реагирует процессор на данную ситуацию.


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

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


Последний инструмент разработчика — это программатор памяти программ микроконтроллера. Хотя некоторые производители микроконтроллеров предпочитают выпускать их с масочно-программируемой памятью программ, они обычно выпускают также аналогичные версии микроконтроллеров с E(E)PROM памятью для разработки приложений. Это значит, что существует возможность непосредственного программирования микроконтроллера при разработке приложения.

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

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

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


Язык Ассемблера

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

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

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


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

В качестве примера рассмотрим описание команды ADC (Сложение с переносом) для микроконтроллера 68НС05, структура которого показана на рис. 3.1.

Отметим на этой структуре прохождение данных при выполнении команды (рис. 3.2).

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

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


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

movlw 8 ; Цикл 8 повторов

movwf Count
Loop ; Вход в цикл

movlw 0 ; PortB == О?

iorwf PORTB, w

btfss STATUS, Z

goto Skip ; Нет, пропустить команды

movlw Ox07F ; Да, Вывести ответ 0x7F

movwf PORTC
Skip


decfsz Count ; Уменьшить Count и если != О вернуться к Loop

goto Loop

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

movlw 8 ; Цикл 8 повторов

movwf Count

Loop ; Вход в цикл

movlw 0 ; PortB == О?

iorwf PORTB, w

btfss STATUS, Z

goto Skip ; Нет, пропустить команды

movlw 0x07F ; Да, Вывести ответ 0x7F

movwf PORTC

Skip


decfsz Count ; Уменьшить Count и если != О вернуться к Loop

goto Loop

Теперь выделим условный фрагмент программы, что также упрощает чтение программы:

mol 8 ; Цикл 8 повторов

movwf Count

Loop ; Вход в цикл

mol 0 ; PortB == 0?

iorwf PORTB, w

btfss STATUS, Z

goto Skip ; Нет, пропустить команды

mol 0x07F ; Да, Вывести ответ 0x7F

movwf PORTC

Skip

decfsz Count ; Уменьшить Count и если != О вернуться к Loop


goto Loop

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

movlw 8 movwf Count

Loop ; Опросить PortB 8 раз

movlw 0 ; Если PortB == 0, то PortC = 0x7F

iorwf PORTB, w

btfss STATUS, Z

goto Skip

movlw 0x07F movwf PORTC

Skip

decfsz Count
goto Loop

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


Интерпретаторы

Некоторые разработчики еще помнят старые времена, когда персональные компьютеры Apple II или IBM PC программировались с помощью языка BASIC. При этом исходный текст выполнялся непосредственно процессором без промежуточной компиляции. Программа, которая анализирует каждую строку программы и затем выполняет указанную в ней команду, называется «интерпретатор». Это название отражает принцип ее работы, когда каждая строка сначала интерпретируется и затем выполняется.

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


Если Вы знакомы с микроконтроллером Parallax BASIC Stamp, который упоминался ранее в этой книге, то Вы, вероятно, думаете, что он работает как BASIC-интерпретатор. Действительно, при использовании этого микроконтроллера подключенный к нему инструментальный компьютер преобразует программный код в символы, которые загружаются во внутреннюю память программ EEPROM. После загрузки в EEPROM эти символы используются для выбора подпрограмм, обеспечивающих выполнение программы.

Некоторые микроконтроллеры имеют встроенный интерпретатор: например, Intel 8052 содержит встроенный интерпретатор языка BASIC и память RAM для загрузки исходного текста. Эти интерпретаторы не преобразуют текст в символы, поэтому работают медленно и требуют большого объема памяти для хранения исходных программных строк. Этот исходный программный код может быть использован для отладки прикладной программы непосредственно внутри микроконтроллера.

Языки высокого уровня

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


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

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


Основные характеристики языков высокого уровня:


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

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


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

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

Использование слишком большого числа различных типов данных может вызвать проблемы из-за отсутствия свободной памяти при использовании 8-разрядных микроконтроллеров. Для обработки данных с разрядностью более 8 бит необходимо вводить дополнительные команды для выполнения заданных операции. Например, выражение, написанное на языке С :


FirstVar = FirstVar + SecondVar;

выполняется микропроцессором 8051 с помощью следующей последовательности команд, выполняющими обработку 8-разрядных данных:

mov A, FirstVar ; Выбрать первую переменную

add A, SecondVar ; Сложить со второй переменной mov FirstVar, A

При использовании 16-разрядных переменных программный код усложняется:

mov A, FirstVar ; Сложить младшие 8 бит

add A, SecondVar

mov FirstVar, A

mov A, FirstVar +1 ; Сложить старшие 8 бит

addc A, SecondVar + 1 ; Сложение с переносом

mov FirstVar + 1, А

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


mov A, FirstVar ; Сложить младшие 8 бит

add A, SecondVar mov FirstVar, A

jnc Skip ; Если перенос не установлен, то

пропустить увеличение

inc FirstVar + 1 ; Увеличить старшие 8 бит результата

Skip

mov A, FirstVar + 1

add A, SecondVar + 1

mov FirstVar + 1, A

В данном примере представлен относительно простой вариант выполнения таких операций. Если операция становится более сложной (например, «FirstVar = SecondVar + (ThirdVar * FourthVar)»), то усложнение программного кода имеет экспоненциальный характер. При этом использование данных большой разрядности может привести к чрезмерному замедлению вычислений или потребовать большего объема памяти, чем имеется в системе.


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

В сложных операциях (таких как «FirstVar = SecondVar + (ThirdVar * FourthVar);») программный код может быть реализован с помощью ряда стековых операций.

push SecondVar

push ThirdVar

push FourthVar

mul


add

pop FirstVar

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

Для некоторых компиляторов представление реализуемой процедуры с помощью нескольких командных строк может быть более эффективным по сравнению с их представлением в виде одной строки. Например, процедура, описанная строкой FirstVar = SecondVar + ( ThirdVar * FourthVar ) ;

более эффективно реализуется в виде следующей последовательности операций:

Temp = ThirdVar * FourthVar; FirstVar = SecondVar + Temp;

Другое важное соображение касается того, как компилятор преобразует числа и обрабатывает промежуточные переменные. Если в приведенном выше примере переменная «FirstVar» не определена как порт ввода-вывода, то можно представить программный код в следующем виде:


FirstVar = ThirdVar * FourthVar; FirstVar = FirstVar + SecondVar;

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

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

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


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

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


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

struct instruct { // Формат команды
int address; // Адрес команды

char instruct; // Команда
int value; // 16- битные данные

};

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

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


struct instruct * Ptr; // Определение указателя на структуру

i = Ptr -> value; // Прочесть «value» из текущего элемента При организации массива эта процедура выглядит следующим образом: struct instruct Array[1OO]; // Определение массива структур

i == Array[ Index ].value;

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

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

char Greeting [13] = «Hello there I»;

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


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

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

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


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

Остается еще один вопрос: зачем вообще использовать язык высокого уровня? Существует несколько причин для этого.

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

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


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

Нечеткая логика

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

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


Существует очень интересный нетрадиционный метод управления системами, который называется «нечеткая логика». Нечеткая логика может рассматриваться как расширенный вариант Булевой логики, где логические переменные имеют ряд значений в диапазоне между 1 и 0. Обработка поступающих входных переменных производится таким же способом, как в Булевой логике. Однако получаемый при этом результат будет также представлен не в двоичной форме.

Многие полагают, что нечеткая логика является недавним изобретением, однако впервые она описана в 1965 году — более 30 лет назад. Главная причина того, что нечеткая логика кажется недавним изобретением, заключается в том, что ее почти полностью игнорировали в Северной Америке. В Азии (особенно в Японии), нечеткая логика стала важной технологией, используемой в многих приложениях, от термостатов в кондиционерах до рекомендаций, когда и как часто следует кормить детей.

Изобретатель нечетной логики профессор Лофти Задех из университета Беркли определил характеристики нечетких систем следующим образом.

  1. В нечеткой логике точное утверждение (Истинно - Ложно) является пре
    дельным случаем приближенного утверждения.

  2. В нечеткой логике все утверждения даются в относительном представлении (скорее Истинно, чем Ложно).

  3. Любая логическая система может быть представлена в терминах нечеткой
    логики («фаззифицирована»).

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

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


Чтобы объяснять, как определить нечеткую логическую систему, рассмотрим классический пример системы управления перевернутым маятником (рис. 3.3). Цель управления системой состоит в том, чтобы, используя инерцию, удержать груз на конце маятника в вертикальном положении с помощью перемещения тележки назад или вперед. Чтобы практически познакомиться с решением данной задачи, попробуйте взять карандаш и удержать его вертикально на одном из пальцев (без предварительной тренировки это удается не более пяти секунд).

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

Для каждой входной переменной определяется «нечеткое» множество ее состояний («зон»). Выходным параметром является текущее положение тележки. Таким образом, можно определить положение тележки как пять различных позиций, указывающих находится ли тележка в «центре», «рядом» или «далеко» от центра. «Зоны» должны покрывать все части базовой переменной (ось X на рис. 3.4). Тоже самое необходимо реализовать для угла положения маятника и его угловой скорости.


Когда входные переменные «фаззифицированы», разрабатывается набор правил, определяющих величину выходного отклика на данные условия. Как показано на рис. 3.4, позиция тележки может быть в «центре» или «рядом», это означает, что множество правил могут иметь место для данного условия. Это может показаться необычным, но для нечетких систем это нормально. С учетом этого множества правил вычисляется отклик.

Некоторые правила для этой системы можно сформулировать в следующем виде:

  1. if Angle = Vertical AND Angular_Speed = Stopped AND Pos = Centre then
    Speed = 0 (если Угол = Вертикаль AND Угловая скорость = Останов AND
    Позиция = Центр, то Скорость = 0).

  2. if Angle = -Lean AND AnguiarSpeed = -Slow AND Pos = Centre then Speed
    = -Slow (если Угол = -Наклон AND Угловая скорость = -Низкая AND
    Позиция = Центр, то Скорость = -Низкая)

Аналогичным образом могут быть сформулированы и остальные правила. Для их определения могут использоваться различные методы, например правила типа «если — то», приведенные выше, или модифицированные карты Карно.


Когда правила определены, производится вычисление выходных переменных при различных значениях входных переменных. Если посмотреть на правило номер 2, то возможное значение отрицательного угла отображается, как показано на рис. 3.5. Значение этого угла равно нечеткому значению 0,4. Теперь, это значение объединяется с помощью операции Логическое И по правилу номер 2 со значениями «Angular_Speed» («Угловая скорость») и «Pos» («Положение»), чтобы получить окончательный результат. При выполнении операции И нечеткое значение одной переменной (0,4 для угла в этом примере) сравнивается с нечеткими значениями других переменных, и в качестве результата используется наименьшее из значений переменных.

Логические операции ИЛИ и НЕ также реализуются в нечеткой логике. Для операции ИЛИ результатом будет максимальное значение входных переменных. При операции НЕ текущее значение переменной вычитается из 1, и полученная разность является результатом. Все Булевы преобразования и законы (например, ассоциативность) применимы к нечеткой логике, поэтому результат вычисляется достаточно просто.

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


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

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

Разработка программного обеспечения

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

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


Можно использовать «нисходящий» способ проектирования (разработка «сверху-вниз») или что-то среднее между этими двумя способами. Каждый разработчик сам выбирает удобный для себя стиль программирования.

Распределение ресурсов

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

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


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

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

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

  3. Использовать везде, где возможно, локальные переменные (это можно
    реализовать только в языках высокого уровня)

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

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


Программы, критичные ко времени

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

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

Скорость 9600 бод соответствует периоду времени 104,167 мкс. Это означает, что временной интервал для чтения и записи данных должен занимать точно 104 цикла (ошибка порядка 0,16%). Пусть для чтения данных (приема) используется программный код:


mov Count, 8
Loop ; Получить 8 бит и сохранить в «Char»

mov A, Dlay ; Задержка на 104 цикла

DlayLoop

dec A

jnz DlayLoop

rr Char ; Сдвинуть «Char» вправо

; - Последний прочитанный бит теперь на 6-ой позиции

mov A, Port ; Получить данные из порта А

and А, 0x001 ; Проверить бит 0 в порте А

jz Skip

or Char, 0x080 ; Установить старший бит в Char

Skip

dec Count ; Прочитано 8 бит?


jnz Loop ; Еспи «не ноль», то «нет»

Теперь надо определить значение переменной «Dlay».

Сначала вычислим «собственное» время цикла — время, требуемое для организации его запуска. Глядя на приведенную программу, можно заметить следующую проблему: существует разница в один командный цикл между двумя ветвями программы — когда бит установлен в 1 или 0.

Если входной бит установлен в 0, то выполняется переход по команде «jz» (условие истинно), который занимает три командных цикла. Если этот бит установлен в 1, то команды «jz» (условие ложно, и переход не производится) n «or» выполняются за дна командных цикла. Чтобы выполнение программы всегда занимало одинаковое время, необходимо добавить дне команды «пор» после команды «or Char, 0x080».

После этого собственное время программного цикла составит 14 командных циклон. Необходимо дополнительно выполнить 90 циклов для реализации требуемой задержки. Каждый проход программы задержки требует четыре цикла (один для команды «dec А» и три -для команды «jn/ DIayLoop»). Таким образом значение «Dlay» следует принять равным 23 (при этом программа задержки будет пройдена 22 раза), а общее время задержки содержит 88 командных циклов. Далее прибавляем к этому 13, и все вместе составит 101 командный цикл (ошибка 2.98%). Добавляя три команды «пор» или один переход, получаем точно 104 командных цикла.


Чтобы определить, какой уровень ошибки является приемлемым, необходимо понимание того, что выполняет программа. Для асинхронного интерфейса эта ошибка умножается, как минимум, на десять, так как передаются восемь бит данных, один старт-бит и один стоп-бит. Таким образом ошибка в 0,86% при передаче одного бита приводит к ошибке 8,6% при передаче всего пакета, который имеет длину 10 бит. Вероятно, это приемлемо. Ошибка в 2,98% на один бит приведет к почти 30% ошибке в конце передачи байта, что может быть неприемлемо для ряда приложений.

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

Ниже дан пример программного кода для передачи байта со скоростью 9600 бод:

mov Char, 8
Loop ; Вывести 8 бит

mov A, Dlay ; Задержка на 104 цикла DiayLoop


dec A

jnz DiayLoop

mov A, Char ; Вывести О или 1

and A, 1 ; Поспать младшие бит первым

jz SendZero ; Вывести О

or Port, 2 ; Использовать бит 1 для вывода

goto SentBit
SendZero ; Вывести ноль

and PortO, OxOFD
SentBit

rr Char ; Поместить следующий бит на место младшего

dec Count ; Сделать 8 раз

jnz Loop

В примере чтения поступающие данные опрашивались в одной точке программы. При записи передаваемые данные выдаются в двух разных точках. Значение 1 выдается на три цикла раньше, чем значение 0. Это можно легко исправить путем введения двух команд «пор» перед выполнением команды «or Port, 2». Однако в этом случае при посылке 0 переход к метке «SentBit» реализуется на три команды раньше, чем при посылке 1. Можно поставить команду безусловного перехода «goto SentBit» следом за командой «and PortO, OxOFD». В таком случае при любом значении данных они будут поступать на выход порта в течение одного и того же числа циклов после начала процедуры «Loop».


После того, как все возможные ветви программы сбалансированы по времени выполнения, и вывод данных обеспечен в одни и те же моменты времени, можно произвести расчет параметра «Dlay», как это было выполнено в примере чтения данных.

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

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

Макросы и условная компиляция


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

Макрос может рассматриваться как функция, которая замещает в программе вызывающий ее оператор (макровызов), в то время как подпрограмма размещается вне основного программного кода. Например, при программировании ЖКИ-интерфейса, который требует подачи тактового сигнала Е, можно использовать код:

push A ; Сохранить аккумулятор

mov А, 0x0001 ; Установить высокий уровень сигнала Е

or Port, A

xor Port, А ; Установить снова низкий уровень сигнала Е

pop A ; Восстановить аккумулятор

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


pulse_E macro ; Импульс по линии «Е»

push A ; Сохранить аккумулятор

mov А, 0x0001 ; Установить высокий уровень сигнала Е

or Port, A

xor Port, А ; Установить снова низкий уровень сигнала Е

pop A macroend

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

pulse_E

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

pulse macro bit ; Импульс на линии Е

push A ; Сохранить аккумулятор


mov А, 1 « bit ; Определить бит

or Port, A ; Установить бит в 1

xor Port, A ; Сбросить бит в 0
pop A
macroend

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

pulse 2

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

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


Возвращаясь к первоначальному примеру, можно ввести макропеременную «debug», которая позволит выполнять специальные процедуры в процессе отладки. В нашем примере формирования сигнала Е для ЖК-индикатора можно реализовать инверсию сигнала на выводе, подключенном к светодиоду, каждый раз, когда подается импульс Е. Таким образом будет обеспечена визуальная индикация (зажигание светодиода), когда происходит запись данных в ЖКИ.

Большинство трансляторов проверяют выполнение условий компиляции перед тем, как компилировать файл. В ассемблерах эти условия обычно представлены в форме «If (Eckjdbt)/else/end» или в форме «ifdef (Параметр)». Последняя форма позволяет компилировать программный код при условии. что параметр определен ранее. В языках высокого уровня, которые используют формат «If(Условие)/еlsе/епd» используются несколько другие операторы условной компиляции, например, в языке С используется оператор «%if».

Теперь преобразуем наш макрос таким образом, чтобы инвертировать бит 7 порта А, к выводу которого подключен светодиод, когда параметр «Debug» определен. Получаем макрос:

pulse macro bit ; Импульс по линии Е


push A ; Сохранить аккумулятор

mov А, 1 « bit ; Определить бит

or Port, A ; Установить бит в 1

xor Port, A ; Сбросить бит в О

ifdef Debug ; Если «Debug» определен

mov A, 0x080 ; Инвертировать бит 7

xor Port, A endif

pop A

macroend

Условно компилируемый программный код можно помешать не только в макросах. Они могут быть использованы и в теле основной программы. Условно компилируемые коды обрабатываются в одно время с макросами, поэтому они обычно рассматриваются вместе с ними. Даже если Вы никогда ранее не использовали ассемблер, макросы и условное компилирование, вероятно, Вам знакомы. Что Вы могли не знать — это то что макросы и условное компилирование широко применяются в языках высокого уровня. Утверждение «#define» в языке С — фактически макрос, а оператор «#if/#else/ #end» используется для условной компиляции.


В приложении «Общие команды Ассемблера» условное компилирование и макросы рассмотрены более подробно на других примерах.

Резидентный монитор и отладчик

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

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

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


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

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


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

Для реализации точек останова и пошагового выполнения программ требуется модифицировать содержимое памяти, где хранится код прикладной программы. Во многих процессорах есть однобайтная команда для генерации программного прерывания. Например, в микропроцессорах семейства i86, которые используются в IBM PC, это команда программного прерывания «int 3» с кодом ОхСС. Для реализации точки останова эта команда помещается перед первым байтом следующей команды. Когда поступает команда программного прерывания, содержимое указателя стека декрементируется, адресуя ячейку, в которую загружается содержимое программного счетчика. Это содержимое восстанавливается после выполнения подпрограммы обслуживания прерывания. Пошаговое выполнение может быть реализовано аналогичным образом - путем передачи управления монитору после выполнения каждой команды. Но контроллеры прерываний некоторых процессоров имеют режимы работы, при которых автоматически генерируется прерывание после каждой команды, то есть реализуется пошаговый режим.


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

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


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

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

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

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


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


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

Операционные системы реального времени (ОСРВ)

Операционные системы реального времени — ОСРВ (RTOS — Real Time Operating Systems) предназначены для компьютерных систем, которые способны выполнять несколько задач одновременно. Например, на персональном компьютере одновременно может быть запущен графический редактор «Corel Draw», проигрываться музыкальный диск, осуществляться доступ в Интернет и выполняться вывод Web-страницы с помощью программы Netscape. Типичное приложение для микроконтроллера (например, микроконтроллер, который читает данные с клавиатуры и посылает их в компьютер) обычно выполняет только одну задачу.


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

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

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


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

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

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

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


■ Контроль окружающей среды.

■ Качество атмосферы и величина давления.

■ Нагревание и охлаждение (кондиционирование).

■ Освещение (уменьшение освещения ночью).

■ Управление энергопотреблением.

■ Ориентирование солнечных батарей по направлению к солнцу.

■ Контроль за режимом заряда-разряда батарей.

■ Контроль энергопотребления .

■ Связь.

■ Ориентирование антенны на станцию приема.

■ Мультиплексирование сообщений от различных источников.

■ Накопление сообщений.

■ Ориентация и контроль местоположения станции

■ Слежение за орбитой и ориентацией.


■ Управление двигателями.

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

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

Рис. 3.7. Блок-схема ОСРВ для управления космической станцией.

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


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

Возможно Вас поразят вычислительные мощности, которые имеют простые 8-разрядные микроконтроллеры. Два космических аппарата «Вояджер», первые посланцы Земли к другим планетам, управлялись микропроцессором (работающим на одной десятой от максимальной скорости), который имел существенно меньшие возможности, чем процессоры микроконтроллеров, описанных в данной книге. Эти микропроцессоры имели только 2Кбайт памяти программ, часть которой должна была обновляться с Земли, чтобы обеспечить возможность выполнения бортовым компьютером текущих задач управления. Работа в режиме реального времени не является слишком быстрой для компьютера, и события, которые кажутся быстрыми для людей, могут быть легко обработаны скромной компьютерной системой.

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


ГЛАВА

4

ОСНОВНЫЕ ТИПЫ

ИНТЕРФЕЙСОВ МИКРОКОНТРОЛЛЕРОВ

Краткое содержание

Подавление звона контактов

Вывод на светодиодную индикацию

7-сегментный светодиодный индикатор

Матричная клавиатура

Управление жидкокристаллическими индикаторами

Управление двигателем/реле

Шаговые двигатели

Управление RC-сервомоторами

Преобразование уровней RS-232


Генерация случайных чисел

Персональные компьютеры

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

Подавление звона контактов

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

Рис. 4.1. Дребезг контактов.

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


Один их простых схемотехнических способов устранения звона состоит в подключении RC-цепи (рис. 4.2). В этой схеме время, требуемое для заряда/ разряда конденсатора до порогового напряжения, маскирует «звон» контактов при переключении. Можно также установить триггер Шмидта между схемой ключа и микроконтроллером, чтобы усилить эффекта подавления «звона». Недостатки этого метода - дополнительные затраты на компоненты, которые должны быть установлены на плате, и дополнительное время, требуемое для заряда/разряда RC-цепи. Все это может затруднить использование данной схемы, так как для некоторых ключей с большим уровнем шумов дополнительная задержка может составить десятые доли секунды.

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

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

DBounce: // Начать при высоком уровне

сигнала на выходе ключа while (( Port & SW ) != О ); // Ожидать низкого уровня сигнала


на выходе ключа

TMR =0; // Сбросить таймер для ожидания 20мс

while ((( Port & SW ) == 0 ) && ( TMR < Twenty_msec )); if ( TMR < Twenty_msec )

goto DBounce; // Звон еще не кончился, повторить

еще раз

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

Подключение светодиодов

Очень часто вывод данных реализуется с помощью светодиодов (LED — Light Emitting Diode), который достаточно дешевы и легко подключаются к микроконтроллеру. Обычно для свечения светодиода требуется ток более 16мА, что для большинства микроконтроллеров находится в диапазоне допустимых значений выходных токов. Следует помнить, что светодиод является диодом, пропуская ток только в одном направлении.


Типичная схема подключения светодиода к выводу микроконтроллера показана на рис 4.3. В этот схеме светодиод будет светиться, когда микроконтроллер выдает на этот вывод сигнал «О» (низкое напряжение). Когда вывод работает в качестве входа данных или на него выводится «1», то светодиод будет выключен.

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

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

7-сегментный светодиодный индикатор

Вероятно, самый простой способ вывода числовых десятичных и шестнадцатеричных данных — это использование 7-сегментного светодиодного индикатора. Такие индикаторы были очень популярны в 70-х годах, но впоследствии их место заняли жидкокристаллические индикаторы. Но светодиодные индикаторы до сих пор являются полезными приборами, которые могут быть включены в схему без больших усилий для создания программного обеспечения. Включая определенные светодиоды (зажигая сегменты), можно выводить десятичные числа (рис. 4.4)


Каждый светодиод в индикаторе имеет свой буквенный идентификатор ( А, В, С, D, E, F или G), и одна из ножек светодиода подключена к соответствующему внешнему выводу. Вторые ножки всех светодиодов соединены вместе и подключены к общему выводу. Этот общий вывод определяет тип индикатора: с общим катодом или с общим анодом. Подключение индикатора к микроконтроллеру осуществляется весьма просто: обычно индикатор подключают как семь или восемь (если используется десятичная точка) независимых светодиодов.

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


Рис. 4.4. 7-сегментный светодиодный индикатор.

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

Int

- LED_Display = 1 « Cur ; Высветить значение для текущего индикатора


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

Рис. 4.5. Подключение к микроконтроллеру четырех 7-сегментных индикаторов

В некоторых ситуациях может оказаться, что выделение каждому светодиоду индикатора отдельного вывода микроконтроллера слишком расточительно. Можно использовать демультиплексор с высоким выходным током, например, ТТЛ-микросхему типа 74S138, вместо дискретных транзисторов. Когда на выбранном выходе демультиплексора устанавливается низкий уровень, то он пропускает ток подключенного к нему индикатора, обеспечивая вывод цифры. При этом разводка монтажных соединений в устройстве оказывается более простой. Следует обратить внимание на то, чтобы используемый демультиплексор был способен пропускать максимальный ток 140мА, который протекает через общий катод индикатора.


Наряду с 7-сегментными индикаторами существуют 14- и 16-сегментные индикаторы, которые позволяют выводить символы алфавита («A»-«Z» и «0»-«9»). При подключении этих индикаторов необходимо следовать тем же правилам, что и для 7-сегментного индикатора. В главе «Примеры применения микроконтроллера 8051» будет показано подключение 16-сегментного индикатора.

Ввод с матричной клавиатуры

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

Для чтения состояния определенного ключа на столбец подается сигнал, а затем считывается состояние рядов. Обычно ряды подключаются к высокому потенциалу, а опрашиваемый столбец соединяется с землей. Если при сканировании рядов считывается низкий уровень сигнала , то это означает, что ключ в данной позиции ряд/столбец замкнут (рис. 4.7). На рис. 4.7 показаны два МОП-транзистора, которые используются


для подключения столбцов к земле Как было сказано в главе «Аппаратные средства», выводы микроконтроллера могут работать в режиме с открытым коллектором. Таким образом, они могут имитировать работу этих транзисторов, делая их включение ненужным. Транзисторы, показанные на рис 4.7, введены для лучшего понимания работы схемы.

Рис. 4.7. Подключение к микроконтроллеру матричной клавиатуры.

Матричная клавиатура может быть расширена практически до любого размера, используя при этом небольшое число выводов микроконтроллера. Например, 104-клавишная клавиатура персонального компьютера - это матрица, содержащая 13x8 ключей. Требуемое программное обеспечение практически не изменяется при подключении клавиатуры различной размерности. Если не хочется писать программное обеспечение для клавиатуры или нет достаточного количества доступных выводов микроконтроллера, то Вы можете упростить

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

В схеме на рис. 4.8 показано использование микросхемы типа 74С922 в качестве интерфейса между клавиатурой с матрицей 4x4 ключа и микроконтроллером BASIC Stamp.


В соответствии с программой микроконтроллер непрерывно опрашивает значение поступающего от микросхемы сигнала «Готовность данных». При поступлении активного уровня этого сигнала четыре бита, содержащие адрес, считываются в микроконтроллер Stamp и выводятся на дисплей. Резисторы сопротивлением 10 К включаются для устранения конфликтов на шине, соединяющей микроконтроллер и жидко-кристаллический дисплей, когда два или более выходных драйверов этих устройств пытаются выводить на одну линию различные логические уровни. Если с выхода микросхемы 74С922 поступает сигнал, значение которого отличается от сигнала, выдаваемого микроконтроллером Stamp, то разность напряжений падает на резисторе, а на шине устанавливается уровень сигнала микроконтроллера. Таким образом исключается возможность неопределенного состояния линии.

Когда выводы микроконтроллера Stamp работают в режиме ввода, значение сигнала на шине устанавливает микросхема 74С922. При этом падение напряжения на резисторах 10 КОм очень мало, и микроконтроллер будет считывать значения сигналов, поступающих с выходов микросхемы 74С922.

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


Управление жидко-кристаллическим индикатором

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

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

Большинство алфавитно-цифровых ЖКИ используют для управления контроллер Hitachi 44780 и реализуют общий интерфейс подключения. Благодаря этим обстоятельствам ЖКИ, обеспечивающие вывод от 8 до 80 символов (организованных в виде 2 строк по 40 символов или 4 строк по 20 символов), являются полностью взаимозаменяемыми, так как их применение не требует какого-либо изменения программного обеспечения или аппаратных средств.


Чаще всего ЖКИ, использующие контроллер Hitachi 44780, имеют 14-выводные разъемы с шагом 2,54 мм. Выводы ЖКИ имеют следующее назначение:

Вывод 1 — «Земля».

Вывод 2 - Напряжение питания Vcc.

Вывод 3 — Вход регулировки контрастности изображения.

Вывод 4 — Сигнал выбора регистра данных или команд (R/S).

Вывод 5 - Сигнал выбора режима «чтение/запись» (R/W).

Вывод 6 - Синхросигнал Е.

Выводы 7-14 — Линии передачи данных.

Из данного описания видно, что интерфейс микроконтроллера с ЖКИ представляет собой параллельную шину, которая позволяет просто и быстро осуществлять чтение и запись данных в ЖКИ. Временные диаграммы сигналов на рис. 4.9 иллюстрируют процесс выдачи байта, содержащего ASCII-код символа, на экран ЖКИ. ASCII-код содержит 8 бит, которые посылаются в ЖКИ по четыре или по восемь бит за один цикл обмена. Если используется 4-битный режим обмена, то полный 8-битный код символа передается в виде двух 4-битных «нибблов» (полубайтов): сначала 4 старших бита, затем 4 младших. Каждая посылка сопровождается синхросигналом Е, который инициирует прием данных в ЖКИ.


Передача 4 или 8 бит данных - это два основных режима параллельного обмена. Рассмотрим некоторые соображения по поводу выбора того или иного режима. Восьми-битный режим передачи целесообразно использовать, когда требуется высокая скорость обмена и есть не менее 10 доступных линий для ввода-вывода данных. Четырехбитный режим передачи требует, как минимум, 6 линий ввода-вывода. Чтобы подсоединить микроконтроллер к ЖКИ при четырехбитном режиме используются только 4 старших разряда линии данных DB7-4 (рис. 4.10)

Дальнейшее сокращение числа требуемых линий ввода-вывода может быть обеспечено путем использования сдвигового регистра: в этом случае потребуется всего 3 линии (рис. 4.11). В качестве сдвигового регистра обычно используется микросхема 74x174 (где «х» — или НС, или LS). Восьми-битный режим также можно реализовать с помощью сдвигового регистра, но требуется передавать девятый бит, который используется, чтобы обеспечить выдачу сигнала R/S. Бит R/S указывает, какая информация передается — команда или данные. Если этот бит установлен в 1, то передаются данные, которые могут быть считаны или записаны в текущей позиции ЖКИ, определяемой положением курсора. Когда бит сброшен в 0, то при записи в ЖКИ передается команда, при чтении — считывается состояние ЖКИ после выполнения последней команды.


Набор символов, которые выводится ЖКИ под управлением контроллера 44780, в основном аналогичен символам, представляемым в ASCII-коде. Некоторые символы ЖКИ не совпадают с ASCII: самое важное отличие - это отсутствие символа «\», который имеет ASCII-код ОхО5В. Управляющие ASCII-коды с 0x008 по 0x01 F не воспринимаются ЖКИ как символы управления и могут отображаться как японские иероглифы. Имеется восемь программируемых символов, которые выводятся с помощью кодов с 0x000 по 0x007. Эти символы программируются с помощью команд, которые устанавливающих курсор ЖКИ на область памяти генератора символов («CGRAM») и задают восемь значений адреса для построчной записи изображения символа. Следующие восемь байтов, записанные в память, представляют собой изображение каждой строки программируемого символа, начиная сверху.

Приведенная ниже таблица содержит набор команд, реализуемых ЖКИ.

Назначение отдельных битов команд:

Указание направления движения курсора:

ID — Перемещение курсора после записи каждого байта, если бит установлен в 1,

S — Сдвиг изображения на экране после записи байта Включение экрана/курсора


D - Экран Включить(1)/Выключить(0)

С - Курсор Включить(1)/Выключить(0)

В — Мигание курсора Включить(1)/Выключить(0) Перемещение курсора/Сдвиг экрана

SC — Сдвиг экрана Включить(1)/Выключить(0)

RL - Направление сдвига Вправо(1)/Влево(0) Установка размерности интерфейса

DL — Разрядность данных 8(1)/4(0)

N — Число строк на экране 1(0)/2(1)

F - Размер шрифта 5хЮ(1)/5х7(0) Установка курсора на CGRAM

А - Адрес Чтение /запись ASCII- символов

D — Данные

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

Флаг «Занято» («busy») устанавливается на время выполнения команды. Для написания приложений, которые работают с максимально возможной скоростью, необходимо опрашивать этот флаг, чтобы исключить необходимость реализации задержки, рассчитанной на наихудший случай выполнения команд ЖКИ. Обычно скорость обмена с ЖКИ не очень важна, и целесообразно использовать программную задержку, которую несложно реализовать. Выполнение всех команд занимает не более 160мкс, кроме команд «Очистить индикатор» и «Вернуть курсор в начальную позицию», которые требуют максимум 4,1мс. Для наихудшего случая можно установить задержку в 5 мс, чтобы обеспечить некоторый запас для надежного функционирования.


Различные типы ЖКИ выполняют команды с разной скоростью. Выше указаны максимальные значения задержек, но некоторые индикаторы требуют меньшее время для выполнения команд. Однако, если не используется опрос флага «Занято», то рекомендуется всегда использовать максимальные задержки.

В большинстве применений линию «R/W» подсоединяют к земле, так как чтение состояния ЖКИ не требуется. Это значительно упрощает приложение, поскольку для считывания данных необходимо менять режим работы выводов - с записи на чтение. В некоторых случаях возможность чтения состояния ЖКИ бывает полезна, например, при прокручивании данных на экране. Подключение линии «R/W» к земле также освобождает один вывод микроконтроллера.

ЖКИ с размером символов 5x10 точек практически не выпускаются, поэтому бит «F» в команде «Установка размерности интерфейса» должен всегда быть равен 0.

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

Для 8-битного режима:

  1. Подождать более 15мс после подачи питания.

  2. Записать 0x30 в ЖКИ и ждать 5мс до завершения выполнения команды.

  3. Записать 0x30 в ЖКИ и ждать 160мкс до завершения выполнения команды.

  4. Снова записать 0x30 в ЖКИ и ждать 160мкс до завершения выполнения
    команды или опрашивать флаг «Занято».

  5. Установить рабочие характеристики ЖКИ.


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


  1. Подождать более 15мс после подачи питания.

  2. Записать 0x3 в ЖКИ и ждать 5мс до завершения выполнения команды.

  3. Записать 0x3 в ЖКИ и ждать 160мкс до завершения выполнения команды.

  4. Снова записать 0x3 в ЖКИ и ждать 160мкс до завершения выполнения
    команды или опрашивать флаг «Занято».

  5. Установить рабочие характеристики ЖКИ.


После того как инициализация завершена, ЖКИ готов к приему команд и данных.

Последний вопрос, касающийся ЖКИ, — как установить контрастность изображения. Обычно для этого используется потенциометр, включенный как делитель напряжения (рис. 4.12). Таким образом легко получается изменяющееся напряжение в диапазоне от «земли» до Vcc, которое обеспечивает регулировку контрастности изображения символов на экране ЖКИ.

Рис. 4.12. Управление контрастностью изображения ЖКИ.

В начале раздела было сказано, что ЖКИ имеют плохую репутацию из-за трудностей, возникающих при работе с ними. Самая большая проблема с ЖКИ заключается в том, чтобы правильно его инициализировать. Если следовать приведенным выше инструкциям, то проблем не должно возникнуть. Также следует помнить, что минимальная длительность импульса на входе Е должна составлять 450нс. Если длительность импульса меньше, то работа ЖКИ будет неустойчивой.

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


Управление двигателем/реле

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

Самый простой метод управления этими устройствами заключается в том, чтобы просто включать и выключать их. На рис. 4.13 микроконтроллер открывает транзисторную пару Дарлингтона, что приводит к протеканию тока через катушку реле, которое замыкает контакты. Чтобы разомкнуть реле, транзисторы закрываются подачей 0 на выход микроконтроллера. Шунтирующий диод используется для подавления импульса напряжения, возникающего при выключении тока. Это импульс индуцируется магнитным потоком в катушке и может привести к повреждению источника питания реле и даже микроконтроллера. Никогда не следует забывать про включение такого диода в схемах управления электромагнитными устройствами. Импульс напряжения имеет амплитуду порядка нескольких сотен вольт и длительность несколько наносекунд. При этом диод оказывается в режиме пробоя, и через него протекает ток, вызывающий снижение индуцированного напряжения.


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

Такие же аппаратные средства применяются для управления электромоторами. Если мотор должен вращаться только в одном направлении, то можно использовать схему на рис. 4.14.

Рис. 4.14. Набор выходных драйверов в микросхеме ULN2003A.

Для управления вращением мотора в любом направлении служит мостовая схема соединения ключей (транзисторов), показанная на рис. 4.15. Если в этой схеме открыты все ключи, то ток через мотор не протекает, и он не будет вращаться. Если замкнуты ключи 1 и 4, то мотор будет вращаться в одном направлении, если замкнуты ключи 2 и 3 — в другом. Если одновременно замкнуть оба ключа на одной стороне моста, то из-за короткого замыкания может сгореть предохранитель или источник питания.

Управление скоростью мотора обычно осуществляется при помощи сигналов с широтно-импульсной модуляцией (ШИМ). Частота ШИМ-сигналов должна быть больше 20 КГц, чтобы избежать возникновения при вращении мотора звукового сигнала, который может быть очень раздражающим.


Также как микросхема ULN2003A упрощает подключение реле, микросхема 293D может быть использована для управления мотором. Микросхема 293D, показанная на рис. 4.16, может управлять двумя моторами, присоединенными к выходным буферным каскадам (выводы 3, 6, 11 и 14). Выводы 2, 7, 10 и 15 используются для управления уровнем напряжения на буферных выходах микросхемы (ключи в мостовой схеме, показанной на рис 4.15). Выводы 1 и 9 управляют включением/выключением выходных буферов. На эти выводы могут подаваться ШИМ-сигналы, что делает управление скоростью вращения мотора очень простым.

Напряжение питания микросхемы Vs составляет +5В, а напряжение питания электромотора Vss может находиться в пределах от 4.5В до 36В. Максимальный ток, протекающий через электромотор, составляет 500мА. Также как ULN2003A, микросхема 293D содержит встроенные шунтирующие диоды. Это означает, что при подключении к ней электромотора не требуются внешние шунтирующие диоды (рис. 4.17).

На рис. 4.17 показаны резистор и конденсатор, которые иногда используются для гашения помех. Эти два компонента, подключенные к щеткам электромотора, уменьшают электромагнитное излучение и импульсные помехи, возникающие при его работе. Обычно их подключения не требуется, но если наблюдается неустойчивая работа микроконтроллера во время работы мотора, то можно ввести в схему конденсатор емкостью 0,1мкФ и резистор 5 Ом (2Вт).


Микросхема 293D может также использоваться для управления четырех-полюсным шаговым двигателем — каждый из буферных выходов служит для управления одним из полюсов двигателя. При этом выводы 1 и 9 должны быть подключены к питанию, так как не требуются ШИМ-сигналы для управления скоростью двигателя.

Шаговый двигатель

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

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

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


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

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

Шаговый двигатель может управляться микросхемами, аналогичными 293D, при этом каждая пара выходов управляет одной катушкой. Но существуют специальные микросхемы управления шаговым двигателем, такие как UC1517 (рис. 4.19). В этой микросхеме микроконтроллер посылает шаговый импульс STEP и задает направление вращения сигналом DIR. Вывод 1NH отключает выходные драйверы, давая возможность поворачивать двигатель вручную. Микросхема UC1517 может выдавать на катушки двухуровневые сигналы, что позволяет повысить к.п.д. и снизить уровень помех. При этом обеспечивается также возможность поворота вала на полшага, то есть на 45 градусов, а не только на 90. Указанные возможности реализуются специфическим способом для разных типов шаговых двигателей, поэтому прежде чем их использовать необходимо хорошо ознакомиться с устройством и принципом действия применяемого двигателя.


Управление сервоприводом

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

Выходом R/C сервомотора обычно служит колесо, которое поворачивается на угол от 0 до 90 градусов. Существуют сервомоторы, способные поворачиваться в диапазоне от 0 до 180 градусов, а также сервомоторы, обладающие очень большим вращающим моментом для специальных приложений. Обычно к сервомотору достаточно подключить напряжение питания +5В, «землю» и входной сигнал.

R/C сервомотор действительно аналоговое устройство. На вход подается ШИМ-сигнал с цифровыми уровнями напряжения 0 и 1. Длительность импульса от 1.0мс до 2.Оме, частота повторений 20мс (рис. 4.20). Длительность ШИМ-импульса определяет положение колеса сервомотора. Импульс длительностью 1.0мс соответствует положению колеса 0 градусов, импульс длительностью 2.Оме — 90 градусов.

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


Interrupt ; Используется обработчик прерывания

Сохранить содержимое регистров контекста
Вывести «1» на ШИМ линию
Ждать 1 мс
Цикл на 1 мс ; Вывести ШИМ-сигнал

if Loop_Counter > Specified_ServoPos

Output a 0 ; Завершение ШИМ-сигнала

Установить таймер на прерывание через 18 мс Восстановить содержимое регистров контекста Возврат из прерывания

Рис. 4.20. ШИМ-сигнал для управления сервомотором.

Эта программа может быть легко модифицирована для управления более чем одним сервомотором путем введения дополнительных выходных линий ШИМ-сигналов и переменных «Specified_ServoPos». Такой способ управления сервомоторами хорош тем, что переменные «SpecifiedServoPos» могут обновляться, не затрагивая работу обработчика прерываний. Обслуживание прерывания занимает 2 мс из каждых 20 мс. Это значит, что на обеспечение функций ШИМ требуется 10 процентов процессорного времени независимо от числа управляемых сервомоторов.


Преобразование уровней RS-232

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

Напряжения и логические уровни интерфейса RS-232 несколько необычны (рис. 4.21). Первое, что может вызвать проблему — это большой размах напряжения. Но, как показано в главе «Аппаратные средства», напряжения и токи могут быть уменьшены с помощью токоограничивающего резистора, включаемого между входом микроконтроллера и разъемом RS-232. Этот резистор будет защищать фиксирующие диоды на входах микроконтроллера от протекания большого тока, а также удерживать уровни входного напряжения в допустимых пределах.

Этот метод хорошо работает, так как отрицательное напряжение (логическая «1» в интерфейсе RS-232) будет восприниматься как 0В на входе микроконтроллера, а положительное напряжение (логический «0» в интерфейсе [image]


Рис. 4.21. Уровни напряжений для интерфейса RS-232.

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

Вместо этого отрицательный уровень напряжения для передачи можно получить от приемника (рис. 4.22). Как показано на рис. 4.22, приходящие данные поступают в микроконтроллер через резистор 10К. Нормально линия находится в отрицательном состоянии (передается «1»). Когда передается «О», напряжение установится на уровне Vcc. Это очень дешевый и элегантный способ реализации приема и передачи по стандарту RS-232: 3-проводной интерфейс RS-232 с «земляным» проводом.


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

Описанный метод позволяет реализовать только трехпроводной интерфейс RS-232. Если ведущий компьютер требует обмена сигналами квитирования (подтверждения готовности) DTR-DSR и CTS-RTS, то придется использовать другой вид интерфейса или замкнуть накоротко линии сигналов квитирования, соединив выводы DTR с DSR и CTS с RTS.

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


Если данный способ реализации интерфейса RS-232 вызывает проблемы в конкретном приложении, то следует использовать для организации интерфейса микросхему Maxim MAX232, которая содержит внутренний генератор отрицательного напряжения.

Генерация случайных чисел

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

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

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


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

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

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

Персональные компьютеры

Устройством, с которым чаще всего требуется реализовать интерфейс, является персональный компьютер. Существует четыре основных интерфейса, с помощью которых микроконтроллер связывается с компьютером: последовательный порт (RS-232), параллельный порт, интерфейс клавиатуры и мыши, шина ISA. Существуют и другие методы связи с компьютером, но вышеперечисленные являются наиболее распространенными. Существуют книги, где рассказано, как подключать устройства, используя данные интерфейсы. В этом разделе нет возможности рассмотреть все эти интерфейсы подробно, особенно шину ISA, которая обеспечивает прерывания и прямой доступ к памяти. Здесь будет дан только общий обзор этих интерфейсов и объяснение того, как можно с их помощью подключить к компьютеру микроконтроллер.


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

Большое значение имеет операционная система, установленная на персональном компьютере. Приложения для персональных компьютеров пишутся для операционных систем MS-DOS, Windows 3.1 и Windows/95; в меньшей степени используются OS/2, Windows NT и симуляторы MS-DOS, работающие с различными операционными системами. Каждая из этих операционных систем использует различные ресурсы (например, таймеры и вектора прерываний), что усложняет написание программного обеспечения для связи с микроконтроллером.


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

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

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

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


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

Последовательный интерфейс RS-232 лучше всего удовлетворяет этим правилам. Электрические и временные спецификации данного интерфейса не изменяются со временем. Компьютер может иметь 9-контактный (DB-9М) или 25-контактный (DB-25M) разъем, который подключается к интерфейсу RS-232 как терминальное оборудование DTE (DataTerminal Equipment). Назначение контактов разъемов приведено в таблице.

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

Линии RTS, CTS, DSR, DCD, DTR и RI служат для передачи сигналов квитирования, которые используются в некоторых видах связи, чтобы подтвердить готовность оборудования для посылки данных с помощью интерфейса RS-232. Например, эти линии используются базовой системой ввода-вывода (BIOS) некоторых компьютеров. Чтобы эти сигналы не вызывали проблем при обмене данными, можно подключить линию DSR к DTR и линию CTS к RTS. Такое подключение «обманет» аппаратное и программное обеспечение компьютера, которые в любое время будут получать сигналы готовности к приему и передаче данных.


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

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


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

Если требуется передавать большие объемы данных — порядка десятков Кбайт в минуту и более, то лучше не использовать интерфейс RS-232. Вместо этого лучше непосредственно подключиться к системной шине компьютера или использовать сетевой интерфейс.

Последняя особенность использования RS-232. Доступ к последовательному порту может быть получен через файловую систему путем «открытия» имен (от С0М1 до COM4) для четырех стандартных последовательных портов компьютера. Если компьютер содержит графическую карту Super-VGA, то порт COM4 будет недоступен, так как адресное пространство ввода-вывода порта COM4 используется графическим адаптером, совместимым с IBM 8514/А.


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

Рис. 4.23. Временная диаграмма функционирования параллельного порта.

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

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


При использовании параллельного порта существует проблема обеспечения временных параметров. В первоначальных моделях IBM PC (и даже в PC/ AT) время чтения и записи для этого порта было предсказуемо - например, запись продолжалась не менее 125нс. В новых компьютерах, которые работают значительно быстрее, чтение/запись содержимого регистра может длиться менее 20нс. Современные компьютеры будут вести себя так же как старые модели, если их параллельный порт подключен к шине ISA, а не использует интерфейс, реализованный с помощью специализированных заказных микросхем (ASIC).

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

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

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


Рис. 4.25. Временные диаграммы сигналов клавиатуры PC/AT.

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

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

При получении данных от клавиатуры необходимо следить за состоянием клавиш Shift, Alt, Ctrl, CapsLock, NumLock и ScrollLock. От этого зависит, как будет интерпретироваться компьютером скан-код, посланный с клавиатуры. Это также справедливо для команд, посылаемых компьютером клавиатуре.

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


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

OxOFF — Повторный запуск микроконтроллера клавиатуры.

OxOFE — Запрос на повторную посылку последнего символа.

OxOF7-OxOFD — «Пустые» команды NOP (эти команды игнорируются).

0x0F6 — Установить начальные значения по умолчанию (после включения питания).

0x0F5 - Установить начальные значения по умолчанию, но запретить сканирование клавиатуры.

0x0F4 — Разрешить сканирование клавиатуры.

0x0F3 — Установить скорость сканирования. Следующий символ определяет скорость сканирования состояния клавиш.

0x0EF-0x0F2 - «Пустые» команды NOP. Эти команды игнорируются.

ОхОЕЕ — «Эхо». Клавиатура возвращает код ОхОЕЕ.

OxOED — Установить состояние светодиодных индикаторов. Следующий символ определяет состояние индикаторов.

После каждой из этих команд клавиатура выдает код подтверждения «Аск» (0xFA>.


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

Последний из рассматриваемых интерфейсов — шина ISA (Industry Standard Architecture). Это микропроцессорная шина, которая обеспечивает доступ ко многим сигналам процессора. В современных компьютерах применяются также другие шины, например PCI и EISA, но шина ISA представляет наиболее традиционный интерфейс и является достаточно простой для использования. Далее рассматриваются сигналы для реализации 8-разрядного интерфейса, так как 16-разрядная шина вряд ли будет использоваться 8-разрядными микроконтроллерами. Ниже дается назначение контактов слота шины ISA.

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


Сигналы шины ISA имеют следующее назначение:

-СНКСНК Проверка канала. Когда сигнал активен, реализуется немаскируемое прерывание NMI

SD7-SDO Системная шина данных

CHRDY Готовность канала. Когда сигнал активен, вводятся такты ожиания обмена по шине

AEN Индикатор активности DMA. Когда сигнал активен, DMA кон
троллер работает в активном режиме

SA19-SA0 Системная шина адреса

-RESDRV - Системный сброс (Reset)

IRQx - Линии запроса прерываний. Активный уровень высокий

DRQx - Линии запроса DMA. Активный уровень низкий

DACx - Линии подтверждения DMA. Активный уровень низкий

-MEMR Чтение памяти

-MEMW Запись в память

-IOR Чтение устройств ввода-вывода


-IOW Запись в устройства ввода-вывода

-REFRESH Активен при регенерации динамической памяти

-NOWS Нет состояний ожидания. Операции ввода-вывода выполня-

ются без тактов ожидания со стороны процессора

ТС Окончание DMA. Активный уровень сигнала указывает на за-

вершение DMA

ALE Разрешен прием адреса . Активен, когда сигналы SA19-SA0

достоверны

Линии адреса и данных используются при выполнении циклов чтения и записи, как показано на рис. 4.26 и 4.27

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


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

Рис. 4.28. Микроконтроллер в качестве ведомого устройства на шине ISA

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

Возможно, у читателя возникнет вопрос, каким же образом следует осуществить интерфейс с персональным компьютером. В настоящее время на рынке появились микроконтроллеры, имеющие интерфейс с шиной USB («universal serial bus»), которая не упоминалась в этой книге. Популярность этих микроконтроллеров будет расти по мере расширения использования шины USB в компьютерах и ее программной поддержки различными операционными системами. Шина USB работает подобно CAN интерфейсу. Также как и CAN, она предназначена для реализации малых локальных сетей, обеспечивая при этом быструю передачу больших объемов данных


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

ГЛАВА

5

РАЗРАБОТКА ПРИЛОЖЕНИЙ

Краткое содержание

Выбор микроконтроллера

Особенности выбора характеристик и архитектуры

Программные средства и системы разработки

Доступность и ресурсы

Самотестирование


Программаторы

Отладка приложений

Симуляторы Эмуляторы

Выбор микроконтроллера

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

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


НАЗВАНИЕ ПРИЛОЖЕНИЯ:

Количество входных выводов: Количество выходных выводов: Количество линий ввода-вывода:

Тип запуска (сброса):

Тип синхронизации (требуемая точность):

Необходимость сторожевого таймера:

Защита памяти программ:

Доступный вид питания:

Необходимость асинхронного последовательного ввода-вывода:

Необходимость синхронного последовательного ввода-вывода:

Требуемый размер таблиц:

Необходимость ввод-вывода ШИМ-сигналов:

Требуемый тип аналогового ввода-вывода:

Необходимость однократного программирования (ОТР) при организации серийного выпуска:

Предпочтительный тип корпуса: Используемый язык программирования: Желаемая цена:


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

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

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

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


микроконтроллер со всей необходимой информацией, то делайте свой выбор и приступайте к разработке.

Программные средства и системы разработки

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

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

Если используется система, которая эмулирует персональный компьютер, то следует убедиться в том, что планируемые для использования программатор и эмулятор будут работать с вашим приложением. Даже если все хорошо работает, лучше купить дешевый персональный компьютер, на котором может работать Windows 3.11, 95 или NT, и запускать от него программатор/эмулятор. Большинство средств разработки написано для платформы «Wintel», которая упростит выбор инструментальных средств, работающих совместно.


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

Доступность и ресурсы

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

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

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


Самотестирование

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

Тестировать интерфейсы между микроконтроллером и-подключенными к нему внешними устройствами очень просто. Такие тесты обычно заключаются в посылке внешнему устройству тестовых символов (обычно это 0x55 и ОхАА) и их обратном чтении. Часто устройства, подключенные к шине, имеют специальные режимы и регистры, которые позволяют это сделать. Такой тест часто называется «тест присутствия», так как наряду с тестированием шины и интерфейсов проверяется присутствие внешнего устройства.

При проверке параллельной шины (в том числе шины микропроцессора) может потребоваться сначала записать тестовое значение по тестируемому адресу, а затем записать неверное значение по другому адресу, прежде чем выполнить считывание тестового значения. Дело в том, что в некоторых системах на шине данных устанавливается «плавающее» значение сигнала в течение некоторого промежутка времени после передачи. Это вызвано влиянием емкостей при переходе от режима записи к режиму считывания. Введение промежуточной записи неверного значения по другому адресу позволяет правильно выполнить последующее чтение тестовой величины. Такие проблемы иногда возникают при тестировании систем — например, оказывается, что тест присутствия дает правильное значение при обратном считывании в случае, когда внешнее устройство вообще не было подключено к шине. Значения тестовой величины должны быть выбраны таким образом, чтобы ни одно из подключенных к шине устройств не восприняло их как команды, а только как символы, которые необходимо записать, а затем сосчитать обратно.


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

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

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

Микроконтроллер

Рис 5.1. Аналоговая обратная связь для самотестирования.


При тестировании микропроцессора можно выполнить проверку каждой команды перед началом выполнения прикладной программы. Например, в старом руководстве по IBM-PC можно найти программу «POST» («power-on self-test»), которая является одним из первых тестов, реализующих проверку выполнения каждой команды с различными способами адресации. В настоящее время такая проверка не является необходимой, так как возрастание надежности микроэлектронной продукции привело к тому, что отказы процессоров стали чрезвычайно редкими. Для современных сложнофункциональных микросхем этот тест не имеет практического значения.

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


Программаторы

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

Большинство производителей микроконтроллеров продают также необходимые для них программаторы, которые могут содержать встроенные эмуляторы, чтобы привлечь пользователей к использованию их продукции. Такие средства называются «инструментальный набор разработчика» (developer's kits). Обычно такой набор кроме программатора/эмулятора включает образцы компонентов, ассемблер/симулятор/IDE, руководство по использованию и CD-ROM с информацией в формате Adobe «PDF». Эти наборы содержат все необходимое для начала разработки приложения. Их типичная цена — около 100 долларов, хотя при покупке отдельными частями все это будет стоить существенно больше. Если имеется такой набор для проектируемого вами устройства, то целесообразно его использовать, даже если вы являетесь радиолюбителем с ограниченным лимитом средств на выполнение разработки.


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

Как было указано ранее, многие микроконтроллеры выпускаются в варианте, допускающем их программирование в составе системы (ISP-микроконтроллеры). Такие микроконтроллеры могут быть запрограммированы без удаления из схемы устройства. Это особенно важно при использовании микроконтроллеров в SMT-корпусах, которые сложно выпаивать и затем снова монтировать в схему. Программирование ISP-микроконтроллеров требует большего времени по сравнению с микроконтроллерами, которые программируются с использованием параллельного протокола. Время программирования обычно составляет десятки секунд или минуты, а запись по одному адресу может потребовать от 10 до 250 мс. Это обстоятельство необходимо учитывать при планировании производственного процесса. Большинство ISP-микроконтроллеров можно запрограммировать с помощью ICT-тестера (устройство для тестирования в составе системы), однако тестовое оборудование это устройство имеет высокую стоимость, поэтому целесообразно производить программирование другими средствами. Наилучшим решением может стать разработка специального программатора, который подключается к системе и программирует микроконтроллер, отключая его от других устройств. Обычно ISP-микроконтроллеры имеют несколько специальных выводов для связи с программатором. Если микроконтроллер программируется в системе, то схема должна быть построена таким образом, что процесс программирования не оказывал влияния на другие компоненты схемы, а те, в свою очередь, не мешали процессу программирования. Можно, например, разместить на головке программатора специальный драйвер, который будет отключать все соединенные с микроконтроллером устройства на время программирования.


Отладка приложений

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

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


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

  1. Пользовательские процедуры вывода.

  2. Пользовательские процедуры ввода.

  3. Процедуры ввода-вывода по общей шине.

  4. Разнообразные дополнительные процедуры ввода-вывода.

Такая последовательность разработки позволяет получить необходимое программное обеспечение и аппаратные интерфейсы для реализации простых процедур отладки и программ тестирования процедур ввода-вывода. Таким образом, если проектируется устройство, в состав которого входит клавиатура 4x4, ЖК-индикатор, последовательный интерфейс к памяти EEPROM по шине I2C и аналоговые входы, информация с которых должна быть записана в EEPROM, то сначала надо разработать подпрограммы для функционирования ЖКИ и чтения с клавиатуры. Шина 12С и аналоговые входы могут обслуживаться подпрограммами пользовательского ввода-вывода. Если разрабатываемое приложение не имеет интерфейса с пользователем, то следует сначала реализовать последовательный интерфейс ввода-вывода, чтобы обеспечить доступ к отладочной консоли.


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

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

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


Если после тестирования функция приложения не реализуется на симуляторе, то причиной этого является, вероятно, не программное обеспечение, а какая-то «внешняя» проблема, например, плохие контакты. Такие проблемы обычно легко выявить при помощи вольтметра, логического пробника или осциллографа.

Симуляторы

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

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


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

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

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


Шаг Бит

1 1 ; Линия свободна (ничего не передается)

; - Ожидать пока приложение инициализируется

1000 0 ; Старт - бит

1104 1 ; Бит 0

1208 0

1312 1

1416 1

1520 0 ; Бит 4

1624 0

1728 0

1832 0

1936 1 ; Стоп - бит

2040 1 ; Пиния свободна


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

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

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

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


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

Эмуляторы

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

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


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

Существуют также эмуляторы, которые на самом деле представляют собой гибрид эмулятора и симулятора. Вместо использования эмуляторного кристалла такие эмуляторы содержат микроконтроллер, который подсоединен к ведущей системе и включен в схему приложения так, чтобы выполнять команды в пошаговом режиме, подобно тому, как интерпретатор выполняет исходный код программы. Обычно скорость выполнения получается в сто и более раз меньше, чем действительная скорость микроконтроллера. Данный тип эмуляторов намного дешевле «настоящих» эмуляторов, они стоят около 100 долларов, тогда как стоимость настоящего эмулятора 1000 долларов и выше. Несмотря на ограниченность функций такие эмуляторы могут дать довольно точное представление о том, как микроконтроллер будет выполнять приложение.

Рис 5.2. Структура эмулятора.

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


ГЛАВА

6

ПРИМЕРЫ ПРИЛОЖЕНИЙ

Краткое содержание

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

Первое приложение

Приложение часы/термометр

Специфичные приложения

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


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

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

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

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


Что касается разработки программного обеспечения, то лучше использовать ассемблер и симулятор, разработанные производителем микроконтроллера. Несмотря на то, что в некоторых случаях (особенно для микроконтроллеров 68НС05, 8051 и PIC) существует множество других инструментальных средств, поставляемых третьими фирмами (включая те, которые распространяются бесплатно), следует, при возможности применять средства, предлагаемые производителями.

Первое приложение

Назначение «первого приложения» — это познакомиться с конкретным микроконтроллером. Этого знакомство позволит Вам после завершения разработки самостоятельно выполнять следующие этапы проектирования:


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

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

Приложение часы/термометр

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


В качестве термометра используется микросхема DSI820 фирмы Dallas Semiconductor — однопроводной цифровой термометр. Эта микросхема выпускается в различных корпусах, например, можно использовать трехвыводной корпус, которых напоминает транзистор. Dallas Semiconductor использует интерфейс «1-Wiге»(торговая марка), который позволяет осуществлять двунаправленную передачу данных между ведущей системой и внешней периферией, такой как микросхема DS 1820.

Микросхема DS1820 обладает множеством полезных особенностей. Например, использование однопроводной шины для соединения нескольких устройств (при этом каждое устройство получает собственный порядковый номер, что позволяет общаться к нему индивидуально) и питание от ведущего устройства. Однако в настоящем примере эти особенности не используются, термометр подключается к напряжению питания Vcc и является единственным устройством на шине. Интерфейс «I-Wire» не был описан ранее в этой книге, так как он является специфичным для продукции фирмы Dallas Semiconductor.

Передача данных по шине «1-Wire» инициируется ведущей системой (в нашем примере — микроконтроллером). Передача осуществляется пакетами по 8 бит (младший бит передается первым). Передача каждого бита занимает по крайней мере 60 мкс. В исходном состоянии на шине «I -Wire» поддерживается высокий уровень сигнала путем ее подключения к напряжению питания через внешний резистор (рис. 6.2). При передаче данных ведущая система или периферийное устройство (в нашем примере цифровой термометр DSI82O) соединяют шину с землей, устанавливая низкий уровень сигнала. Если шина находится в низком состоянии в течение очень короткого интервала времени, то это соответствует передаче логической I. Если шина находится в низком состоянии более 15 мкс. то это соответствует логическому 0 (рис. 6.3).


Рис. 6.3. Временная диаграмма интерфейса «1-wire» фирмы Dallas Semiconductor.

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

Перед посылкой в DS1820 любой команды сначала передаются импульсы «сброса» и «присутствия». Импульс «сброса» реализуется ведущей системой путем перевода линии в низкое состояние на время от 480 мкс до 960 мкс. В ответ микросхема DS1820 переводит линию в низкое состояние на время около 100 мкс (допустимое значение от 60 до 240 мкс). Для упрощения программного обеспечения проверка поступления импульса «присутствия» часто не выполняется. В других приложениях, где термометр может быть отключен, такая проверка должна производиться.

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


  1. Послать импульс сброса и подождать, пока пройдет импульс присутствия.

  2. Послать код 0хСС(команда «skip ROM»), который сообщает DS1820, что ему будет адресована следующая команда.

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

  4. Подождать не менее 500 мкс, пока завершится преобразование.

  5. Послать импульс сброса и подождать, пока поступит импульс присутствия.

  6. Снова послать код ОхСС(команда «skip ROM»).

  7. Послать код ОхВЕ, вызывающий чтение внутренней памяти DS1820, в которой хранится значение температуры (в градусах Цельсия умноженных на два)

  8. Прочесть девять байт, поступающих из внутренней памяти DS1820.

  9. Отобразить температуру путем деления первого байта на 2 и посылки преобразованного


значения на ЖКИ. Если в качестве 9-го бита из внутренней памяти DS1820 получен 0, то в восьми первых битах указана отрицательная температура, и на ЖКИ выводится символ «-» (минус).

Вся процедура измерения температуры занимает около 5мс. Самый простой способ проверить работает ли термометр — это зажать его пальцами и посмотреть, как будет повышаться температура на ЖКИ.

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

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


Может создаться впечатление, что рассмотренный пример применения является искусственным и не отражает того, что может встретиться в реальном приложении. На самом деле здесь не все является надуманным, и данное приложение довольно полно представляет реальную ситуацию, где микроконтроллер обеспечивает интерфейс с различными внешними устройствами (в этом примере — кнопка, ЖКИ и DS1820) и выполняет несколько задач (в этом примере — измерение времени и температуры), хотя настоящие многозадачные системы или ОСРВ были реализованы только для микроконтроллеров 68НС05.

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

Специфичные приложения

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