/
Author: Брэй Б.
Tags: блоки обработки данных процессоры программирование микроконтроллеры
ISBN: 978-5-7931-0516-3
Year: 2008
Text
Барри Брэй
ПРИМЕНЕНИЕ
МИКРОКОНТРОЛЛЕРОВ
Архитектура, программирование и
построение интерфейсов с
применением С и ассемблера
WWW.MK-PRESS.COM
Applying PIC18 Microcontrollers
Architecture, Programming, and Interfacing
Using C and Assembly
Applying PIC 18 Microcontrollers
Architecture, Programming, and Interfacing
Using C and Assembly
Barry B. Brey
PEARSON
Prentice
НаИ
Pearson Education Inc.
Upper Saddle River,
New Jersey 07458
USA
Барри Брей
Применение
микроконтроллеров PIC18
Архитектура,программирование и построение
интерфейсов с применением С и ассемблера
Перевод с английского: В. В. Литвин
Киев «МК-Пресс»
СПб «КОРОНА-ВЕК»
2008
ББК 32.973-04
Б 87
УДК 004.312
Брей Б.
Б87 Применение микроконтроллеров PIC18. Архитектура, программирование и
построение интерфейсов с применением С и ассемблера: Пер. с англ. — К.:
«МК-Пресс», СПб:. «КОРОНА-ВЕК», 2008. — 576с„ ил.
ISBN 978-5-7931-0516-3 («КОРОНА-ВЕК»)
ISBN 978-966-8806-55-1 («МК-Пресс»)
ISBN 978-0-13-088546-3 (англ.)
Сегодня микроконтроллеры используются повсеместно в автомобилях, бытовой технике,
промышленном и медицинском оборудовании и т.п. Этот учебник дает всестороннее представление об
архитектуре, программировании и построении интерфейсов этого современного чуда. На примере се-
мейства микроконтроллеров PIC 18 производства Microchip в книге объясняется архитектура, програм-
мирование и построение интерфейсов. Семейство PICI8 выбрано не случайно, поскольку оно относит-
ся к самым современным восьмиразрядным микроконтроллерам. Изложенный в книге материал также
применим как к более ранним версиям микроконтроллеров Microchip, так и к аналогичным устройст-
вам других производителей. Он рассчитан на опытных практиков и радиолюбителей, интересующихся
микроконтроллерами.
ББК 32.973-04
Научный редактор: Ю. Ф. Авраменко
Компьютерная верстка: И. В. Авраменко
Главный редактор: Ю. А. Шпак
Подписано в печать 07.07.2008. Формат 70 х 100 1/16.
Бумага офсетная. Печать офсетная. Усл. печ. л. 46,8. Уч.-изд. л. 35,4.
Тираж 2000 экз. Заказ № 925
СПД Савченко Л.А., Украина, г.Киев, тел./ф.: (044) 517-73-77; e-mail: info@mk-press.com.
Свидетельство о внесении субъекта издательского дела в Государственный реестр издателей,
производителей и распространителей издательской продукции: серия ДК №51582 от 28.11.2003г.
Отпечатано в типографии ЧП Швец С.М. (свидетельство ДК №867 от 22.03.2002).
32300, Хмельницкая обл., г. Каменец-Подольский, ул. Пятницкая, 9а.
Тел.: (03849) 2-72-01, 2-20-79.
Авторизованный перевод с английского книги Pearson Education Inc., изданной под торговой маркой Prentice Hall,
Copyright © 2008. Все права закреплены. Никакая часть настоящего издания ни в каких целях не может быть вос-
произведена в какой бы то ни было форме и какими бы то ни было средствами, будь то электронные или механиче-
ские, включая фотокопирование и запись на любой носитель данных, если на это нет письменного разрешения из-
дательства Pearson Education Inc. Издано на русском языке издательством “МК-Пресс”, Copyright © 2008.
Authorized translation from the English language edition published by Pearson Education Inc., publishing as Prentice
Hall, Copyright © 2008. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without
permission from Pearson Education, Inc. Russian language edition published by publishing imprint MK-Press, Copyright
© 2008.
ISBN 978-5-7931- 0516-3 («КОРОНА-ВЕК»)
ISBN 978-966-8806-55-1 («МК-Пресс»)
ISBN 978-0-13-088546-3 (англ.)
© «МК-Пресс», 2008
© Pearson Education Inc., 2008
Содержание
5
СОДЕРЖАНИЕ
ГЛАВА 1. Введение в архитектуру компьютеров.........................7
1.1. Основы компьютерной архитектуры................................7
1.2. Системы счисления..............................................17
1.3. Компьютерные форматы данных....................................25
1.4. Резюме.........................................................34
1.5. Вопросы и задания..............................................35
ГЛАВА 2. Архитектура семейства PIC18 и разработка программ..........40
2.1. Архитектура PIC18..............................................40
2.2. Модель программирования........................................49
2.3. Интегрированная система разработки (IDE).......................58
2.4. Язык Ассемблера, программа «ассемблер» и компоновщик...........70
2.5. Резюме.........................................................76
2.6. Вопросы и задания..............................................77
ГЛАВА 3. Набор команд семейства PIC18...............................79
3.1. Литеральные команды............................................79
3.2. Битовые команды................................................84
3.3. Байтовые команды...............................................86
3.4. Команды управления выполнением программы и косвенная адресация.94
3.5. Табличные команды..............................................104
3.6. Макропоследовательности........................................108
3.7. Резюме.........................................................109
3.8. Вопросы и задания..............................................110
ГЛАВА 4. Программирование на языке Ассемблера.......................113
4.1. Структуры стека и очереди......................................113
4.2. Сложные арифметические операции................................119
4.3. Преобразования между десятичным и двоичным форматами...........128
4.4. Временные задержки.............................................133
4.5. Примеры программ...............................................136
4.6. Резюме.........................................................147
4.7. Вопросы и задания..............................................147
ГЛАВА 5. Программирование PIC18 на языке С..........................150
5.1. Компилятор С18 с языка С.......................................150
5.2. Использование включаемых файлов языка С........................159
5.3. Примеры программ на языке С....................................170
5.4. Математическая библиотека......................................181
5.5. Резюме^........................................................183
5.6. Вопросы и задания..............................................183
6
Применение микроконтроллеров PIC 18
ГЛАВА 6. Спецификации аппаратных средств семейства PIC18.........185
6.1. Цоколевка выводов и базовые операционные характеристики.....185
6.2. Выводы Ввод-Вывод...........................................201
6.3. Введение в прерывания.......................................213
6.4. Другие внутренние периферийные устройства...................229
6.5. Резюме......................................................246
6.6. Вопросы и задания...........................................247
ГЛАВА7. Базовый ввод-вывод.......................................249
7.1. Входы от ключевых схем......................................249
7.2. Устройства индикации........................................259
7.3. Управления электромоторами..................................289
7.4. Реле, соленоиды и датчики...................................306
7.5. Резюме......................................................328
7.6. Вопросы и задания...........................................329
ГЛАВА 8. Прерывания..............................................332
8.1. Повторное знакомство с прерываниями.........................332
8.2. USART и прерывания..........................................343
8.3. Прерывания по изменению состояния...........................357
8.4. Примеры систем, работающих с прерываниями ..................364
8.5. Резюме.................................................... 399
8.6. Вопросы и задания...........................................400
ГЛАВА 9. Системы управления......................................403
9.1. Формализация системы управления.............................403
9.2. Примеры системы.............................................408
9.3. Резюме......................................................440
9.4. Вопросы и задания...........................................441
ГЛАВА 10. Вопросы повышенной сложности...........................443
10.1. Расширение памяти..........................................443
10.2. Загрузочный блок...........................................465
10. 3. Расширение ввода-вывода...................................473
10.4. Интерфейс CAN..............................................482
10.5. Интерфейс USB..............................................490
10.6. Расширенный набор команд PIC18.............................524
10.7 . Резюме....................................................526
10.8. Вопросы и задания..........................................527
Приложения.......................................................529
Содержание компакт-диска........................................ 575
Глава 1. Введение в архитектуру компьютеров
7
ГЛАВА 1. Введение в архитектуру компьютеров
Микроконтроллеры PIC (программируемый интерфейсный контроллер) входят в
серию интегральных схем RISC (компьютер с сокращенным набором команд), выпус-
каемых фирмой Microchip Technology Incorporated (http://www.microchip.com). Имеется
целый ряд типоразмеров корпусов этих микросхем, начиная от малых корпусов с 18
выводами до больших - с 128 выводами. Выпускается также целый ряд изделий, пред-
назначенных для работы с PIC-микроконтроллерами, которые называются BASIC
Stamp® и выпускаются фирмой Parallax Incorporated (http://www.parallax.com). Они про-
граммируются на языке BASIC или Java вместо языка Ассемблера. Данная глава явля-
ется введением в микроконтроллерную и системную архитектуру в качестве базиса
управления аппаратными средствами с применением микроконтроллеров. Кроме того
в ней определяется много терминов, используемых в микроконтроллерных технологи-
ях, благодаря чему читатель знакомится с основами этой очень интересной предмет-
ной области.
После завершения изучения этой главы, вы сможете:
1. Давать определения терминам, используемым в области микроконтроллеров.
2. Описывать назначение каждой компоненты компьютерной системы.
3. Понимать работу каждой части компьютерной системы, а также ее взаимосвязи
с другими системными компонентами.
4. Определять типы данных, используемые с микроконтроллерами.
5. Выполнять преобразования между записями чисел в различных обычно исполь-
зуемых системах счисления.
1.1. Основы компьютерной архитектуры
Наиболее распространенная архитектура компьютеров иллюстрируется блок-
схемой, представленной на рис. 1.1. Впервые эта архитектура была предложена и ис-
пользована Чарльзом Беббиджем (Charles Babbage) в его «Аналитическом двигателе» в
1856 году (http://www.cbi.umn.edu). Она продолжает использоваться в качестве базо-
вой системной архитектуры в большинстве современных цифровых компьютеров.
«Аналитический двигатель» представлял собой механический компьютер, приводимый
в действие ручкой. В более недавнее время перед повторным открытием работ Чарльза
Беббиджа архитектура компьютера приписывалась Джону фон Нейману, — он описал
ее весной 1945. Сегодня об этой архитектуре часто говорят как об архитектуре фон
Неймана. В главе 2 мы будем рассматривать другую архитектуру компьютера, которая
называется гарвардской архитектурой. Эта архитектура не так широко распространена,
как архитектура фон Неймана, однако именно она используется в микроконтроллерах
семейства PIC.
Рис. 1.1. Блок-схема компьютерной системы
8
Применение микроконтроллеров PIC 18
Центральный процессор (ЦП)
Показанная блок-схема компьютерной системы, хотя и является простой, однако
содержит три основных блока, отражающих архитектуру большинства современных
цифровых компьютерных систем. Ее главным звеном является ЦП (центральный про-
цессор) - элемент, осуществляющий управление работой системы. Ранние процессоры
представляли собой механические системы, - такие, как «аналитический двигатель»,
арифмометры и т.д., которые широко использовались в 70-х годах прошлого столетия.
Первые цифровые электронные компьютеры первоначально создавались с использо-
ванием электронных ламп, а позднее - транзисторов. Современные компьютерные сис-
темы создаются на базе интегральных схем, использующих КМОП технологию.
Вторым изменяющимся свойством ЦП является его тактовая частота. Тактовая
частота ЦП варьируется в широких пределах, составляя в настоящее время несколько
мегагерц для микроконтроллеров и вплоть до нескольких гигагерц для более мощных
процессоров, используемых в настольных компьютерных системах. Мегагерцевые
(МГц) системы - это системы, основанные на использовании тактовой частоты в мил-
лион импульсов за секунду (частота в один импульс за секунду называется частотой в
1 Герц), в то время как гигагерцовая (ГГц) система - это система, основанная на такто-
вой частоте в миллиард импульсов в секунду. Хайнцу Рудольфу Герцу (Heinnch Rudolf
Hertz) (http://www.ideafinder.com/history/inventors/hertz.htm) выпала честь назвать сво-
им именем единицу измерения количества изменений полярности переменного тока за
секунду (первоначально эта единица называлась "циклы за секунду"). Хотя тактовая
частота микроконтроллера или микропроцессора может не указывать количество ко-
манд, которые они выполняют в секунду, однако она непосредственно определяет бы-
стродействие системы. Точное количество команд, выполняемых в секунду, определя-
ется внутренней конструкцией ЦП, сложностью выполняемых команд, а также выпол-
няемыми программами. Одно можно сказать наверняка: если компьютер на 10-мГц
сравнить с компьютером на 2 ГГц, то второй компьютер точно окажется более быстрым.
Тип микропроцессора может также определять его быстродействие. Процессор
типа RISC (компьютер с сокращенным набором команд) представляет собой устройст-
во, которое выполняет одну команду на каждый тактовый импульс, при этом его набор
команд содержит только базовые команды. Процессор типа CISC (компьютер с сокра-
щенным набором команд) может выполнять намного больше различных команд, в
сравнении с компьютером типа RISC, однако выполнение некоторых команд требует
более одного тактового периода. Сегодня эти термины стали несколько размытыми,
поскольку большинство микропроцессоров используют комбинацию CISC и RISC тех-
нологий с целью выполнения большинства команд в рамках одного тактового периода,
при этом некоторые из них - такие как процессоры семейства Pentium® от Intel, выпол-
няют многие команды всего лишь за одну треть тактового периода. При этом в новых
компьютерах часто содержится несколько блоков целочисленной арифметики, которые
работают одновременно.
Задача ЦП. ЦП ответственен за выполнение ряда последовательных команд, органи-
зованных в группы команд, которые называются программами. Фактически, единст-
венное, что ЦП может делать - это выполнять команды от момента подачи на него на-
пряжения питания вплоть до момента его выключения. Процессор неутомимо извле-
кает команды из памяти и выполняет их. Эта последовательность извлечения и выпол-
нения команд длится до тех пор, пока на ЦП присутствует напряжение питания. Идея
ЦП и способ, которым он должен работать, была впервые предложена Чарльзом Беб-
биджем. С тех пор они не изменялись и вероятно останутся такими же еще какое-то
Глава 1. Введение в архитектуру компьютеров
9
время. Более новые компьютеры выполняют более одной команды одновременно, так
как ЦП фактически состоит из ряда арифметических и логических процессоров. Неко-
торые из самых последних компьютеров имеют несколько ядер. Многоядерный компь-
ютер - это компьютер, в микросхеме процессора которого имеется более одного мик-
ропроцессора.
Программа компьютерной системы - это набор команд, сгруппированных после-
довательно, которые выполняются компьютером одна за одной. Например, предполо-
жим, что программа должна прибавить 6 к 2. Первым шагом (или командой) будет из-
влечение из памяти числа 6. Вторым шагом будет извлечение числа 2. Третий шаг бу-
дет заключаться в сложении 6 и 2. Заключительная операция будет состоять в сохране-
нии суммы в каком-либо месте памяти. Как иллюстрируется этим примером, простая
задача сложения 6 и 2 разбивается на шаги, называемые командами. Эти команды
формируют следующую программу, которая выполняется микропроцессором или мик-
роконтроллером:
1. Получить 6.
2. Получить 2.
3. Сложить 6 и 2.
4. Сохранить сумму в памяти
Каждый шаг этой простой программы переводится на язык, который компьютер
понимает. Этот язык называется машинным языком. Машинный язык - это последова-
тельность чисел, которые представляют команды. Если говорить о гипотетическом ЦП,
то «командой извлечения из памяти», может быть число 00, командой сложения может
быть число 01, а командой запоминания в памяти может быть число 02. Данная про-
грамма на численном машинном языке будет иметь вид: 00 06 00 02 01 02 00, или как
это показано в примере 1.1.
Пример 1.1
00. 06
00 02
01
02 00
Как можно видеть из этого примера, написание численных машинных кодов - это
громоздкая и запутанная процедура. К счастью, сейчас уже никто не пишет программы
в численных машинных кодах, хотя в ранние годы компьютерной эры это делалось.
Вместо этого стали использовать инструмент, называющийся ассемблер. При этом
программа записывается в символьной форме с использованием мнемонических обо-
значений кодов операций, - таких как GET и ADD. Ассемблер, который также является
программой, преобразует программу, написанную на символьном языке ассемблера, в
численные машинные коды. Программа на языке ассемблера, которая генерирует про-
грамму, показанную в примере 1.1, может иметь вид, показанный в примере 1.2.
Пример 1.2
GET 6
GET 2
ADD
STORE 0
Даже и такая запись программы достаточно громоздка, однако она, по крайней мере,
более читабельна, чем последовательность чисел. По причине того, что программы на языке
ассемблера могут быть достаточно длинными, а их написание иногда может представлять
собой вызов программисту, в современном программировании, как правило, для генерации
10
Применение микроконтроллеров PIC 18
машинных кодов используются языки программирования высокого уровня. Язык програм-
мирования высокого уровня - это программа, которая принимает в качестве входа псевдо-
англоподобный язык, а затем преобразует его в числовой машинный код. Примерами таких
языков могут быть BASIC, С, C++ или Java. Уже рассмотренная программа может быть напи-
сана на языке С, как показано в примере 1.3.
Пример 1.3
char answer; //отводится место для ответа
answer = 6+2; //выполняется сложение и //сохраняется сумма в переменной answer
Как видно из этой С-программы, при написании программы на языке высокого
уровня, нужно меньше вводить информации с клавиатуры, нет необходимости знать
машинные коды или численные значения адресов памяти, кроме того, эти программы
намного легче читаются. Машинный код, генерируемый языком С, может быть не столь
эффективным, как код, генерируемый ассемблером, однако программы на С намного
легче писать, понимать и обслуживать. Кроме того, программы на С пишутся намного
быстрее, чем на ассемблере, а обучение написанию программ на С требует намного
меньше времени и усилий. Именно по этой причине программное обеспечение часто
разрабатывается с использованием языков программирования высокого уровня. Про-
граммное обеспечение компьютерной системы - это ее программы, а аппаратное
обеспечение - это электронные схемы компьютерной системы. Иногда программное
обеспечение рассматривает аппаратное обеспечение как переменную величину, по-
скольку оно изменяет или модифицирует способ функционирования аппаратных
средств. Это особенно справедливо для микроконтроллерных систем.
Интересно отметить, что Августа Ада Байрон (Augusta Ada Byron) (позднее, после
выхода замуж за лорда Байрона - графиня Лавлес (Lovelace)) заслужила репутацию
первого компьютерного программиста. Это произошло по причине того, что она писала
программы на численном машинном языке для Чарльза Беббиджа и его «аналитическо-
го двигателя». В ее честь был назван язык программирования Ada, который использо-
вался Министерством Обороны США.
Функции ЦП. ЦП в компьютерной системе выполняет три основные задачи: (1) пере-
нос данных, (2) арифметические и логические операции и (3) управляет последова-
тельностью выполнения программ. Перенос данных - это одна из наиболее часто вы-
полняемых задач ЦП. Большая часть времени работы ЦП расходуется на перенос дан-
ных. Перенос данных включает извлечение команд из памяти, обмен данными между
регистрами или ячейками памяти, а также перемещение результатов некоторых логи-
ческих или арифметических операций между памятью и ЦП или между устройствами
ввода-вывода и ЦП. Та часть задачи переноса данных, которая связана с извлечением
команд из памяти, является наиболее часто выполняемой и важной операцией, реали-
зуемой ЦП. Извлечение команд из памяти позволяет ЦП выполнять программы, запи-
санные в памяти системы, с высоким быстродействием. Концепция сохраняемой про-
граммы делает компьютер весьма мощным устройством - она была впервые предло-
жена также Чарльзом Беббиджем. Большинство программ по крайней мере 50% вре-
мени своего выполнения заняты перемещением данных, часто этот процент будет на-
много более высоким. В табл. 1.1 перечислены некоторые из наиболее распространен-
ных операций переноса данных, выполняемых большинством ЦП.
Глава 1. Введение в архитектуру компьютеров
11
Таблица 1.1. Наиболее распространенных операций переноса данных
Операция Комментарий
Память --> Регистр операций Извлечение операции с занесением ве в ре- гистр операций
Память --> Регистр данных Извлечение данных из памяти с занесением их в регистр данных
Регистр данных —> Память Сохранение данных из регистра данных в ячейке памяти
Регистр данных —> Регистр данных Перенос содержимого регистра данных в дру- гой регистр данных
Регистр данных --> ввод-вывод Перенос содержимого регистра дашных в уст- ройство ввода-вывода
Ввод-вывод --> Регистр данных Перенос содержимого устройства ввода-вывода в регистр данных
На выполнение арифметических и логических операций ЦП тратит намного меньше
времени, чем на операции переноса данных. Очень часто программы т-ребуют, чтобы
ЦП уделял арифметическим и логическим операциям только небольшой процент сво-
его времени. В табл. 1.2 перечислены типичные арифметические и логические опера-
ции, выполняемые ЦП. Эти операции обычно выполняются целочисленным арифмети-
ческим устройством. ЦП не может работать с действительными числам и без использо-
вания соответствующих программ либо устройства, называемого арифметическим
устройством или цифровым процессором. Микропроцессор часто содержит, наряду с
целочисленным процессором, также и цифровой процессор, в то время как микрокон-
троллеры очень редко включают цифровой процессор.
Таблица 1.2. Обычные арифметические и логи ческие операции
Операция Комментарий
Сложение Между регистрами, регистром и памятью или с непосредственными данными.
Вычитание Между регистрами, регистром и памятью или с непосредственными данными.
Умножение Между регистрами, регистром и памятью или с непо средственными данными; результат может иметь удвоенный формат
Деление Между регистрами, регистром и памятью или с непосредственными данными; результат может иметь удвоенный формат . (Некоторые мик- роконтроллеры не выполняют операцию деления.)
Инверсия Знак числа изменяется
И Логическое побитовое И между регистрами, регистром и памятью или с непосредственными данными
ИЛИ Логическое побитовое ИЛИ между регистрами, регистром и памятью или с непосредственными данными
Исключитель- ное ИЛИ Логическое побитовое исключительное ИЛИ между регистрами, реги- стром и памятью или с непосредственными данные .и
НЕ Логическое побитовое НЕ между регистрами, регистром и памятью или с непосредственными данными
Наиболее мощной функцией, выполняемой ЦП, является его способность моди-
фицировать ход потока команд программы через использование простых числовых
решений. Управление выполнением команд программы обеспечивает возможность
многократного выполнения в программе секции либо секций программного кода. Ко-
манды управления выполнением команд программы также позволяют передать управ-
12
Применение микроконтроллеров PIC 18
ление выполнением программы функции или процедуре. Имеются условные и безус-
ловные команды передачи управления. Примерами команд безусловной передачи
управления являются команды GOTO и команда вызова функции CALL. Команды услов-
ной передачи управления обеспечивают возможность проверки чисел на их соответст-
вие каким-либо условиям с целью определения того, должна ли модифицироваться
последовательность управления выполнением программы.
Условные команды управления последовательностью выполнения программы
обычно проверяют числа с целью определения того, являются ли они нулевыми, имел
ли место перенос после сложения, либо того, является ли результат операции отрица-
тельным либо положительным. В табл. 1.3 перечислены многие из обычно проверяемых
условий для большинства ЦП. Условные команды управления последовательностью
выполнения программы обычно составляют небольшой процент от всех команд, со-
ставляющих типичную программу, однако эти команды делают ЦП мощным компонен-
том компьютерной системы, наделяя ее способностью принимать решения. Например,
как может компьютер определить, то, что с клавиатуры введено, например, число 3? Он
делает это, отнимая 3 от введенного числа, а затем проверяет, не является ли резуль-
тат нулевым. ЕЕсли результат нулевой, то последовательность выполнения программы
модифицируется таким образом, что как реакция на ввод с клавиатуры числа 3 выпол-
няется определенная задача. Здесь возникает иллюзия того, что компьютер может ду-
мать и рассуждать о причинах ввода числа 3 с клавиатуры, хотя в действительности
единственное, что он делает - так это вычитает число 3 из введенного числа, а затем
проверяет, не является ли результат нулевым. Что делает компьютерную систему мощ-
ным инструментом? Конечно же, - программное обеспечение, написанное программи-
стами, ибо именно оно создает иллюзию того, что компьютер может думать и рассуж-
дать.
Таблица 1.3. Условия, проверяемые многими ЦП.
Условие Комментарий
Ноль Является число нулевым или нет?
Перенос Имел или не имел место перенос?
Знак Число положительно или отрицательно?
Переполне- Некоторые ЦП выполняют проверку на арифметическое переполнение
ние
Память
Память - это чрезвычайно важный компонент компьютерной системы, поскольку
она обеспечивает место для размещения программ, а также данных, используемых в
программах. Без памяти компьютерная система была бы не более мощной или быст-
рой, чем обычный калькулятор на четыре действия. При наличии памяти компьютер
получает доступ к командам, хранящимся в HEPl. Он извлекает их оттуда с очень высо-
кой скоростью. “Аналитический двигатель” Чарльза Беббиджа имел память объемом в
1000 чисел по 20 десятичных разрядов. Этот компьютер также выполнял программы,
хранящиеся в памяти.
С микропроцессорами и микроконтроллерами используются два типа памяти:
постоянное запоминающее устройство (ПЗУ) и оперативное запоминающее устройство
(ОЗУ), которое еще иногда называют запоминающим устройством с произвольной вы-
боркой (ЗУПВ). ПЗУ в микроконтроллерных системах хранит статические данные, как
например программы, а также константы, используемые в программах. Большинство
встроенных микроконтроллерных или микропроцессорных систем сохраняют только
Глава 1. Введение в архитектуру компьютеров
13
одну программу в памяти, которая функционирует как операционная система. ОЗУ в
микроконтроллерной системе хранит динамические данные для системы. Важно отме-
тить, что дисковые накопители, а также другие подобные устройства, не рассматрива-
ются как память, а считаются устройствами ввода-вывода, хотя они и хранят данные и
программы. Это различие делается в силу того, что дисковые накопители и подобные
им устройства трактуются иначе, чем память, при подключении к системе. Драйвер
(программа, которая управляет устройством ввода-вывода) дискового накопителя пе-
редает в дисковый накопитель небольшой объем информации для того, чтобы заста-
вить его работать. Существенное отличие в случае ПЗУ или ОЗУ состоит в том, что дос-
туп к этим устройствам процессор осуществляет не через драйвер, а непосредственно
через ряд проводов, идущих от запоминающего устройства к ЦП и которые непосред-
ственно управляются сигналами, выдаваемыми ЦП.
ПЗУ. ПЗУ в современной компьютерной системе - это, как правило, стираемое про-
граммируемое постоянное ЗУ (СППЗУ), электрически стираемое программируемое
постоянное ЗУ (ЭСППЗУ), а иногда - запрограммированное на предприятии-
изготовителе ПЗУ. Как СППЗУ, так и ЭСППЗУ способны сохранять информацию при-
близительно на протяжении 20 лет или до момента их стирания. Фабрично-
запрограммированное ПЗУ запрограммировано навсегда. СППЗУ может быть стерто
примерно вплоть до 100 раз, в то время, как ЭСППЗУ может стираться от 10000 до
1000000 раз, в зависимости оттого, когда и кем оно было изготовлено.
СППЗУ используются уже довольно давно. Эти устройства необходимо извлекать
из системы, если нужно выполнить их стирание. СППЗУ стирается, будучи помещенным
под интенсивное ультрафиолетовое облучение в течении в среднем от 10 до 20 минут.
СППЗУ способно обеспечить скорость доступа для чтения порядка около 100 нс.
ЭСППЗУ стирается электрически без его извлечения из системы. ЭСППЗУ часто назы-
вают флэш-памятью. Это устройство также способно обеспечить скорость доступа для
чтения порядка около 100 нс. Основное его отличие от СППЗУ заключается в том, что
время стирания ЭСППЗУ является намного более коротким. В типичном случае для
ЭСППЗУ время стирания составляет миллисекунды, в то время как для СППЗУ - мину-
ты. Современные распространенные применения ЭСППЗУ включают системный BIOS
(базовая система ввода-вывода) в персональных компьютерах; флеш-накопители USB
(имеющие названия JumpDrives™, Pocket Drives™, PenDrives™ или ThumbDrives™), за-
меняющие накопители на гибких магнитных дисках в большинстве компьютерных сис-
тем, а также аудио-плееры MP3.
ОЗУ. ОЗУ системы может быть либо статическим ОЗУ (СОЗУ), либо динамическим ОЗУ
(ДОЗУ). Оба названные типа памяти являются разрушаемыми, т.е. они не обеспечива-
ют сохранения информации после отключения напряжения питания. СОЗУ сохраняет
данные в ячейках памяти, напряжение питания на которые подается постоянно. Это
делает их быстрыми, но также ведет к значительному расходу мощности. Устройства
СОЗУ обеспечивают время доступа порядка 1 нс и менее, что делает их отличными кан-
дидатами на использование в качестве системной памяти компьютеров, если закрыть
глаза на высокую потребляемую мощность. ДОЗУ хранят информацию в ячейках памя-
ти, которые представляют собой конденсаторы. Вследствие того, что конденсатор со-
храняет информацию конечное время, ячейки ДОЗУ должны периодически перезапи-
сываться с целью гарантии целостности информации. Процесс периодической переза-
писи данных в ДОЗУ называется обновлением памяти. ДОЗУ обычно сохраняет инфор-
мацию на протяжении от 2 до 4 миллисекунд, после чего ее нужно обновлять. Обновле-
ние информации в ДОЗУ требует расходования системного времени. Кроме того, ин-
14
Применение микроконтроллеров PIC 18
формация не может запоминаться и извлекаться даже приблизительно с той же скоро-
стью, что и в СОЗУ. Времена доступа к ДОЗУ лежат в диапазон около от 40 до 50 нс, в го
время как время доступа для СОЗУ может достигать 1 нс и менее. Сегодня ДОЗУ ис-
пользуются в больших компьютерных системах, а СОЗУ - в малых системах. Эю озна-
чает, что большинство микроконтроллеров не использует ДОЗУ, так как объем памяти в
них слишком мал. Однако технология меняется и можно надеяться, что в скором вре-
мени потребляемая мощность СОЗУ снизится настолько, что ЗУ этого типа буду! ис-
пользоваться в системах с большим объемом памяти, что принесет по крайней мере
50-ти кратное ускорение быстродействия системной памяти этих систем.
Ввод-вывод
Ввод-вывод системы - это связь ее ЦП с другими компьютерами или людьми. Без
ввода-вывода ЦП может решать задачи, однако он не будет в состоянии представить
результат людям или другим компьютерам. Вследствие широкой номенклатуры уст-
ройств ввода-вывода, подключаемых к ЦП, большая часть работы микропроцессоров
или микроконтроллеров сопряжена с организацией взаимодействия и управления (че-
рез программные драйверы) устройствами ввода-вывода компьютерной системы. Се-
годня устройства ввода-вывода реализуют почти все вообразимые задачи или функ-
ции. Большая часть этой книги посвящена организации взаимодейстйия микрокон-
троллеров с многими устройствами ввода-вывода, а также применению программных
драйверов для их управления. Среди наиболее распространенных устройств ввода-
вывода мюжно назвать клавиатуру, обеспечивающую возможность ввода информации,
а также ЖК-дисплеи, предназначенные.для вывода информации. В общем случае йбб,
что производит или принимает электрические сигналы, может быть подключен К Ком-
пьютеру ej качестве внешнего устройства.
Шины
Соединения между блоками, показанными на блок-схеме компьютерной систе-
мы, называются шинами. Шина - это набор проводников, которые несут информацию
специфического типа. Компьютерная система имеет три шины: (1) шину адреса, (2)
шину данных и (3) шину управления. Шина адреса несет адресную информацию, необ-
ходимую для выбора ячейки памяти или ячейки ввода-вывода, шина данных несет дан-
ные, которые передаются между памятью или устройствами ввода-вывода и микрокон-
троллером, а шина управления управляет чтением либо записью памяти или устройств
ввода-вывода. Именно благодаря использовании названных трех шин, микроконтрол-
лер становится способным выполнять программы, записанные в памяти системы, а
также управлять устройствами ввода-вывода, подключенными к системе.
Шина адреса. Все компьютеры имеют шину адреса, сигнальные линии которой почти
всегда обозначаются как АО, Al, А2 и т.д. Сигнал АО - это позиция самого младшего
разряда адреса, сигнал AI это позиция следующего в сторону возрастания разряда
адреса и так далее. Количество проводов шины адреса или сигналов изменяется от
компьютера к компьютеру. Например, если компьютер имеет 16-ти разрядную адрес-
ную шину (проводники которой нумеруются от АО до А15), то он может адресовать 64К
памяти или 64 X 1024 (65536) ячеек памяти запоминающей системы. Используемый в
компьютерной документации и литературе символ «К» означает 1024 или 210. мы можем
определить количество адресуемых ячеек памяти, возведя число 2 в степень, равную
количеству проводников шины адреса т.е. получив 2'6 в случае 16-разрядной шины ад-
Глава 1. Введение в архитектуру компьютеров
15
реса. Это число определяет количество двоичных комбинаций (64К) для случая 16-
разрядного адреса. Аналогичным образом, система, которая имеет 20-разрядную шину
адреса, адресует 1М ячеек памяти (220). 1М ячеек памяти означает 1К умноженное на 1К
ячеек или 1048576 ячеек. Разрядность шины адреса колеблется от 12 разрядов (4К) в
некоторых микроконтроллерах до 40 разрядов (1Т) в последних 64-разрядных микро-
процессорах Pentium (ЕМТ-64) от фирмы Intel Corporation. В табл. 1.4 перечислены раз-
рядности шины адреса и объемы памяти для ряда микропроцессоров и микроконтрол-
леров.
Ячейки памяти нумеруются с использованием шестнадцатиричных чисел (основа
системы счисления равна 16) от ячейки номер 0 до максимального номера ячейки для
данной разрядности шины адреса. Например, ячейки памяти объемом 4К, которая
имеет 12-разрядную адресную шину, нумеруются от ячейки памяти номер ООО до ячей-
ки номер FFF в шестнадцатиричной системе счисления. Она содержит 1000 (шестна-
дцатиричное число) ячеек памяти. Аналогичным образом, ячейки памяти объемом 64К,
которая имеет 16-разрядную адресную шину, нумеруются от 0000 до FFFF в шестна-
дцатиричной системе счисления. Эта память содержит 10000 (шестнадцатиричное
число) ячеек памяти. Для представления каждого разряда шестнадцатиричного адреса
требуется 4-разрядное двоичное число. Шестнадцатиричные числа часто записывают-
ся с использованием «Ох» перед числом или буквы Н после числа. Примерами такой
записи могут быть ОхЗА и ЗАН.
Таблица 1.4. Разрядность адреса и объемы памяти.
Разрядность Объем памяти Объем памяти в шестнадца- Приме-
адреса тиричнои нотации чание
10 разрядов 1К(1,024)или 2iU 400 Кило
12 разрядов 4К (4096 или 212) . 1000 Киби
16 разрядов 64К (65, 536) или 216 1 0000
20 разрядов 1 М (1,048, 576) или 220 100000 Мег
30 разрядов 1 G (1,073,741,824) или 230 4000 0000 Меби
Гиг
40 разрядов 1Т (1, 099,511, 627,766) или 240 10000000000 Гиби
Тера
50 разрядов 1Р (1К*1Т)или2э0 4 0000 0000 0000 Теби
Пета
60 разрядов IE (1К*1Р) или260 1000000000000000 Пеби
Екса
Ексби
Примечание: Киби, Меби, Гиби, Теби, Пеби и Ексби являются предлагаемыми на-
именованиями единиц объема памяти
Шина данных. Шина данных компьютерной системы - это обычно двунаправленная
шина, которая передает данные между ЦП и памятью, а также системой ввода-вывода.
Ширина шины данных, линии которой нумеруются от DO до Dn, изменяется. Как и в
случае с адресами памяти, нулевой разряд шины данных (DO) - это самый младший
разряд шины данных. 8-разрядный компьютер обычно имеет 8-разрядиую шину дан-
ных, 16-разрядный компьютер обычно имеет 16- разрядную шину данных и т.д. В неко-
торых компьютерах шина данных вдвое шире, чем разрядность машинного слова ЦП,
что имеет целью увеличить скорость информационного обмена. Так, микропроцессор
Pentium от фирмы Intel является 32-разрядным процессором, который использует
64-разрядную шину данных.
16
Применение микроконтроллеров PIC 18
Шина управления. Память и устройства ввода-вывода, подключенные к микропроцес-
сору, должны быть объектом управления. Шина управления выполняет эту задачу через
считывание сигнала, который часто называется RD, и запись сигнала, который часто
называется WR. Обратите внимание, что перечеркнутые символы (в печатном тексте -
черта сверху) означают приставку “НЕ”, т.е. они указывают, что сигнал будет активным
в нулевом состоянии. Например, сигнал RD (считывание) инициализирует считывание
тогда, когда он находится в состоянии логического нуля. Иногда символ # используется
для указания того, что сигнал является активным в нулевом состоянии, как, например,
#RD. Когда микроконтроллер извлекает команду из памяти, он размещает адрес памя-
ти на шине адреса, затем сигнал считывания переводится в нулевое состояние с тем,
чтобы информировать ЗУ о необходимости выполнения операции чтения, затем данные
переносятся из памяти в микропроцессор через шину данных. Подобным же образом
аналогичные шаги выполняются при выполнении операции записи в память, задача
исключением того, что вместо сигнала чтения микропроцессор выдает сигнал записи.
Любые другие сигналы, передаваемые по шине управления, являются специфическими
для каждого типа микропроцессора. Некоторые дополнительные сигналы, передавае-
мые по шине управления, обеспечивают ввод прерываний, а также выполняют различ-
ные другие функции управления, помимо управления памятью и прямого управления
компьютерной системой.
Микропроцессор и микроконтроллер
Чарльз Беббидж построил свой компьютер на основе технологии того времени,
которая носила механический характер. Его компьютер был сконструирован с исполь-
зованием шестеренок и рычагов. При этом механизмы одографического типа исполь-
зовались для хранения 1000 20-ти разрядных десятичных чисел в памяти устройства.
Ввод-вывод выполнялся через отверстия, пробитые в бумажной ленте. Эти ранние
идеи реализации механического компьютера некоторое время пребывали в забвении
до тех пор, пока в двадцатом столетии не появились более современные компьютеры.
Корпорация IBM создала целую индустрию, основываясь на использовании пер-
фокарт, которые доминировали в компьютерных применениях вплоть до середины
восьмидесятых годов прошлого столетия. Эти перфокарты (которые еще называли кар-
тами Холлерита по имени Германа Холлерита (Herman Hollerith) - основателя корпора-
ции IBM) были механическими носителями информации, которые использовались для
реализации ввода-вывода как в механических вычислителях 50-х годов, так и в элек-
тронных компьютерах 60-х годов прошлого столетия. Ранние механические компьюте-
ры часто называли счетными машинами - они программировались с использованием
проволочных перемычек. Эти ранние машины проложили дорогу электронным компью-
терам, которые часто называли “мейнфреймами”. Мейнфреймы были дорогими и
большими, с появлением интегральных схем они устарели. Процесс же полной победы
микропроцессоров на мейнфреймами начался в 80-х годах прошлого столетия.
Первый микропроцессор (4004) был создан фирмой Intel в 1971 - это был
4-разрядный ЦП, который работал на тактовой частоте, равной 20 кГц, и адресовал
память с четырехбитными ячейками при использовании 12-разрядного адреса (4К).
Технология быстро прогрессировала и в конце 70-х годов микропроцессор фирмы Intel
стал 16-разрядным при объеме памяти в 1М и тактовой частоте в 6 мГц (микропроцес-
сор 8086). Фирма Motorola также изготавливала микропроцессоры и она тоже имела
успехи в области технологии, выпустив 32-разрядный микропроцессор, который адре-
совал память объемом 16 мбайт, работая на тактовой частоте, равной 8 мГц (микро-
процессор 68000). Было совершенно очевидно, что Motorola имеет преимущество, од-
Глава 1. Введение в архитектуру компьютеров
17
нако ей не удалось добиться доминирующего положения на рынке. Это, вероятно, про-
изошло ио причине того, что IBM решила использовать микропроцессор Intel в своем
персональном компьютере. Архитектура IBM и микропроцессоры Intel, благодаря ре-
шению IBM, оказались на подъеме, микропроцессоры же Motorola были использованы
в компьютерах Macintosh фирмы Apple, которые не получили такого же успеха, как ПК
фирмы IBM. Недавно фирма Apple сообщила о том, что в ее новой линии компьютеров
будут использоваться микропроцессоры Pentium.
Микроконтроллер, который представляет собой самодостаточную компьютерную
систему, также был создан Intel в 1977 как 8-разрядное устройство (8048). Он содержал
микропроцессор, память и обеспечивал возможность подключения к устройствам вво-
да-вывода. Микроконтроллер был спроектирован в расчете на управление оборудова-
нием, а микропроцессор - как замена ЦП мейнфрейма. Первое широкое применение
микроконтроллеры нашли в точечных матричных принтерах FX-80 фирмы Epson и в кла-
виатурах ПК IBM. Принтеры FX-80 создавались на основе микроконтроллера 8048, что
дало впервые возможность поставить на рынок дешевые матричные принтеры. Клавиа-
тура содержала микросхему универсального периферийного интерфейса 8042 (UPI),
которая была выпущена в 1977 в качестве микроконтроллера, используемого для счи-
тывания символов, вводимых пользователем с клавиатуры. Это применение микрокон-
троллера привело к появлению термина «встроенный контроллер» или «встроенный
микропроцессор», потому что компьютерная система была скрыта в другом изделии (в
данном случае - в принтере) или встроена в него. По внешнему виду FX-80 был принте-
ром, хотя внутри он был компьютерной системой. То же самое было справедливо и в
отношении клавиатуры - извне клавиатура IBM была обычной клавиатурой, однако
внутренне она была компьютерной системой.
Когда в конце 80-х годов Intel отошла от идеи микроконтроллера и универсально-
го периферийного интерфейса, сделав выбор в пользу микропроцессоров, была соз-
дана фирма Microchip Incorporated, которая решила занять нишу в области микрокон-
троллеров в 1989 году. С момента своего формирования, фирма Microchip стала лиди-
рующим поставщиком технологии 8-разрядных микроконтроллеров. При этом даже
название выпускаемых ею устройств - PIC (периферийный контроллер интерфейса)
было предложено Intel несколькими годами ранее, так же как и похожее наименование
устройства UPI (универсальный периферийный интерфейс) 8042.
1.2. Системы счисления
Использование микропроцессоров и микроконтроллеров требует хорошего зна-
ния двоичной, десятичной и шестнадцатиричной систем рчисления. В этом подразделе
изложены основные сведения по этим вопросам, предназначенные для тех читателей,
которые не знакомы с этими системами счисления. В частности описывается преобра-
зование между десятичной и двоичной системами счислений, десятичной и шестна-
дцатиричной, а также двоичной и шестнадцатиричной системами счисления.
Цифры
Перед тем, как мы будем преобразовывать числа из системы счисления с одним
основанием в систему счисления с другим основанием, необходимо понять, что такое
цифры и какова их связь с системой счисления. В самом начале нашей учебы в школе
мы узнали, что десятичные числа (основание системы счисления равно 10) записыва-
ются с использованием 10-ти цифр - от 0 до 9. Первой цифрой в любой системе счис-
ления всегда является ноль.
18
Применение микроконтроллеров PIC 18
Например, система счисления с основанием 8 (восьмиричная) использует 8 цифр
- от 0 до 7; а система счисления с основанием 2 (двоичная) использует 2 цифры: 0 и 1.
Если основание системы счисления превышает 10, то используются дополнительные
цифры, в качестве обозначения которых берутся буквы алфавита, начиная с А. Напри-
мер, система счисления с основанием 12 использует числа от 0 до 9, а затем А для 10 и
В для 11. Обратите внимание, что при основании 10 не используется цифра «10», точно
так же, как и при основании 8 не используется цифра «8». В современных компьютерах
наиболее распространены десятичная, двоичная и шестнадцатиричная (основание 16)
системы счисления. (Много лет тому назад была популярна также восьмеричная сис-
тема счисления.) В данном подразделе будет описана каждая из названных систем
счисления.
Позиционная нотация
После того, как будут поняты цифры системы счисления, можно составлять из них
большие числа, используя позиционную нотацию. В начальной школе учат, что позиция
слева от единиц - это разряд десятков, позиция слева от десятков - это разряд сотен и
т.д. Примером этого может быть десятичное число 132: в это число входит 1 сотня, 3
десятка и 2 единицы. Чему не учат в начальной школе, - так это тому, что каждый разряд
числа имеет вес, вычисляемый по экспоненциальному закону. Так, разряд единиц име-
ет вес 10° или 1; разряд десятков имеет вес, равный 101 или 10; разряд сотен имеет вес
102 или 100. Показатель степени в значении веса разряда критически важен для пони-
мания чисел, записанных в системах счисления, отличных от десятичной. Позиция сле-
ва от запятой, которая называется десятичной запятой только в десятичной системе
счисления, всегда является позицией единиц в любой системе счисления. Например,
позиция слева от двоичной запятой всегда будет позицией с весом 2’, т.е. 1; позиция
слева от восьмиричной запятой будет иметь вес 8* или 1. В каждом случае любое чис-
ло, возведенное в степень 0 всегда будет равно 1.
Вес разряда слева от разряда единиц всегда будет равен основанию системы
счисления, возведенному в степень 1; в десятичной системе это будет 101 или 10. В
двоичной системе это будет 21 или 2; а в восьмеричной системе - 81 или 8. Таким обра-
зом, 11 в десятичной системе счисления будет иметь другое значение или количество
единиц, чем 11 в двоичной системе счисления. Десятичное число в данном случае со-
ставлено из одного десятка плюс единица и имеет значение, равное 11 единиц; в то
время как двоичное число 11 составлено из одной двойки плюс единица, что дает зна-
чение, равное 3 единицам. 11 в восьмеричной системе будет иметь значение, равное 9
единицам.
В десятичной системе веса разрядов справа от десятичной запятой имеют отри-
цательные показатели степени. Первый разряд справа от десятичной запятой имеет
вес, равный 10'1 или 0,1. В двоичной системе первый разряд справа от двоичной запя-
той имеет вес, равный 2’1 или 0,5. В общем случае принципы, применяемые к десятич-
ным числам, также применимы для любых других систем счисления.
Пример 1.4 демонстрирует двоичное число 110.101 (здесь и далее, как и во всех
примерах, используется запись чисел, принятая в англоязычной литературе, при кото-
рой в качестве разделителя целой и дробной части числа используется не запятая, а
точка (прим, пер.)) (часто записываемое, как 110.1012). Он также показывает степень и
вес или значение каждого разряда числа. Для преобразования двоичного числа в деся-
тичное складываются веса каждого разряда, умноженные на значения Соответствую-
щий разрядов, в результате формируется десятичный эквивалент. Так, число 110.1012
будет эквивалентным десятичному 6.625 (4+2 + 0.5 + 0.125). Обратите внимание, что
Глава 1. Введение в архитектуру компьютеров
19
это будет сумма 22 (или 4) плюс 2’ (или 2), однако 2* (или 1) не прибавляется, поскольку
в этой позиции нет цифр. Дробная часть числа формируется из 2’1 (.5) плюс 2'3 (или
.125), однако под 2'2 (или .25) цифр нет, поэтому .25 не прибавляется.
Пример 1.4
Степень 22 21 2° 2'1 2~2 2~3
Вес 4 2 1 .5 .25 .125
Число 1 1 0 . 1 0 1
Численное 4 + 2 + 0 + . 5 + 0 + .125 = 6.625
значение
Предположим, что мы хотим применить тот же метод преобразования к числу, записан-
ному в шестиричной системе счисления, например 25.2g. Пример 1.5 показывает это число,
расписанное по степеням и весам каждого разряда. В данном примере в разряде с весом 61
стоит цифра. Этот разряд имеет значение 12 (2X6) и 5 в разряде с весом 6’, который дает зна-
чение 5 (5 X1). Все значение числа имеет значение 12 + 5, т.е. 17. Число справа от десятичной
точки равно 2 под 6 ’, что дает значение .333 (2 х .167). Следовательно, число 25.26 имеет
значение 17.333 в десятичной системе.
Пример 1.5
Степень б1 6° б’1
Вес 6 1 .167
Число 2 5 . 2
Численное значение 12 + 5 + .333 = 17.333
Преобразование В десятичную форму
Предыдущие примеры продемонстрировали, что для преобразования из любой систе-
мы счисления в десятичную, нужно сначала определить веса всех разрядов числа, а затем про-
суммировать веса, умноженные на цифры числа, с целью получения десятичного эквивалента.
Предположим, что мы хотим преобразовать восьмеричное число 125.78 в десятичную систему
счисления. Для выполнения этого преобразования сначала запишем веса всех разрядов чис-
ла. Это показано в примере 1.6. Значение 125.78 равно 85.875 в десятичной системе счисления
или, or 1 х64 плюс 2x8 плюсбх 1 плюс7х.125.
Пример 1.6
Степень 82 81 8° 8-1
Вес 64 8 1 . 125
Число 1 2 5 . 7
Численное значение 64 + 16 + 5 + .875 = 85.875
Обратите внимание, что вес разряда, расположенного слева от разряда единиц,
равен 8. Это 8 раз по 1. Затем заметьте, что вес следующего слева разряда равен 64,
или 8 раз по 8. Если бы в данном числе имелся следующий слева разряд, то его вес был
бы равен 64 умноженное на 8, т.е. 512. Для того, чтобы определить следующего стар-
шего разряда, необходимо умножить вес текущего разряда на основание используе-
мой системы счисления (в данном случае на 8). Для вычисления весов разрядов, рас-
положенных справа от десятичной точки, выполняется деление на основание системы
счисления. Так, в восьмиричной системе вес разряда, стоящий непосредственно спра-
ва от десятичной точки, равен 1/8 или .125. Следующий справа разряд имеет вес, рав-
ный .125/8 или .015625, что может быть также записано как 1/64. Также обратите вни-
мание на то, что число из примера 1.6 может быть также записано как десятичное число
вида 85 7/8.
20
Применение микроконтроллеров PIC 18
Пример 1.7 показывает двоичное число 11011.0111, записанное с указанием веса
и показателя степени основания системы счисления для каждого разряда. Если про-
суммировать эти веса, умноженные на соответствующие, то значение двоичного числа,
преобразованного в десятичную систему, будет равно 27.4375.
Пример 1.7
Степень 24 23 22 2: 2° 2-1 2“2 2~3 2'4
Вес 16 8 4 2 1 .5 .25 . 125 .0625
Цифра 1 1 0 1 1 . 0 1 1 1
Численное 16 + 8 + 0 + 2 + 1 + 0 + .25 + .125 + .0625 = 27.4375
значение
Интересно отметить, что 2-1 также равно 1/2, 2 2 равно 1/4 и так далее. Также инте-
ресно отметить, что 2“ равно 1/16 или .0625. Дробная часть этого числа равна 7/16 или
.4375 в десятичной форме. Обратите внимание на то, что 0111 - эти число 7 в двоичном
коде, равное числителю, а самая правая 1 находится в разряде с весом 1/16, соответ-
ствующим знаменателю. Другие аналогичные примеры: двоичная дробная часть .101 -
это 5/8, а двоичная дробная часть .001101 равна 13/64.
Шестнадцатиричные числа часто применяются в компьютерах. В примере 1.8
расписано число 6А.С с указанием весов разрядов. Сумма его цифр, умноженных на
веса разрядов, равна 106.75 или 106 3/4. Целая часть этого числа может быть пред-
ставлена как 6x16 плюс 10 (А) х 1. Дробная же его часть имеет 12 (С) в качестве числи-
теля и 16(16’) в качестве знаменателя, т.е. равна 12/16 или после упрощения 3/4.
Пример 1.8
Степень 163 16° 16-1
Вес 16 1 .0625
Цифра 6 А . С
Численное значение 96 + 10 + .75 = 106.75
Преобразование из десятичной формы
Преобразование из десятичной системы счисления в другую систему счисления
выполнить несколько труднее, чем преобразование в десятичную форму. Для преобра-
зования целой части числа в десятичную форму необходимо делить его на значение
основания системы счисления. Для преобразования дробной части необходимо вы-
полнять ее умножение на основание системы счисления.
Преобразование целой части числа из десятичной формы. Для преобразования
целой части десятичного числа в иную систему счисления нужно последовательно де-
лить ее на основание новой системы счисления и записывать остатки в качестве зна-
чащих цифр результата. Алгоритм такого преобразования имеет следующий вид:
1. Поделить десятичное число на основание новой системы счислрния.
2. Сохранить остаток (первый остаток будет цифрой, стоящей в самом младшем
значащем разряде).
3. Повторять шаги 1 и 2 до тех пор, пока частное не будет нулевым.
Например, для преобразования десятичного числа 10 в двоичную форму, поде-
лим его на 2. Результатом будет 5 с остатком, равным 0. Первый остаток дает цифру
разряда единиц результата (в данном примере - 0). Далее делим 5 на 2. Результатом
Глава 1. Введение в архитектуру компьютеров
21
будет 2 с остатком 1.1 будет цифрой, стоящей в разряде с весом 2 (21) результата.
Продолжаем процесс деления до тех пор, пока частное не будет нулевым. Пример 1.9
иллюстрирует этот процесс преобразования. Результат записывается как 10102 снизу
вверх.
Пример 1.9
2)10 Остаток
2)5 Остаток
2)2 Остаток
2)_1 Остаток
'о
0
1
0
1
результат = 1010
Для преобразования десятичного числа 10 в восьмиричную форму, последова-
тельно делим его на 8, как показано в примере 1.10. Десятичное 10 будет равно вось-
меричному^.
Пример 1.10
Остаток = 2
8) 1 Остаток = 1 результат = 12
0
Преобразование из десятичной в шестнадцатиричную систему выполняется де-
лением на 16. Значение остатков при этом может иметь диапазон от 0 до 15. Любой
остаток в диапазоне между 10 и 15 затем переводится в буквенную форму с использо-
ванием букв от А до Р с целью формирования шестнадцатиричного числа. Пример 1.11
показывает преобразование десятичного числа 109 в шестнадцатиричное 6D.
Пример 1.11
16)109 Остаток =13 (D)
16)6 Остаток = 6 Результат = 6D
0
Преобразование дробной части десятичного числа. Преобразование дробной час-
ти десятичного числа в другую систему счисления выполняет посредством умножения
на значение основания системы счисления. Например, для преобразования дробной
части десятичного числа в двоичную форму, нужно выполнять умножение на 2. После
умножения целая часть результата сохраняется в качестве значащей цифры результа-
та, а дробный остаток вновь умножается на значение основания системы счисления.
Когда дробный остаток становится нулевым, процесс умножения останавливается.
Обратите внимание на то, что некоторые числа бесконечны (периодические дроби).
Таким образом, остаток при их умножении никогда не будет нулевым. Алгоритм для
преобразования дробной части десятичного числа имеет следующий вид:
1. Умножить дробную часть на основание новой системы счисления.
2. Сохранить целую часть результата (даже если она нулевая) в качестве цифры.
Обратите внимание на то, что первый результат записывается непосредственно спра-
ва отточки, разделяющей целую и дробную часть числа.
3. Повторять шагц 1 и 2, используя дробную часть шага 2 до тех пор, пока дробная
часть не станет равной нулю.
Предположим, что нам нужно преобразовать десятичное .125 в двоичную форму.
Это выполняется умножением на 2, как показано в примере 1.12. Обратите внимание на
то, что процесс умножения должен продолжаться до тех пор, пока дробный остаток не
22
Применение микроконтроллеров PIC 18
станет равным нулю. Целочисленные части результатов записывается как числа двоич-
ной дробной части (0.001 в данном примере).
Пример 1.12
.125
х 2
0.25 Цифра равна О
.25
х 2
0.5 Цифра равна 0
х 2
1.0 Цифра равна 1 результат = О.ОО12
Та же самая методика используется для преобразования дробной части десятич-
ного числа в любую систему счисления. Пример 1.13 показывает ту же самую дробную
десятичную часть .125 из примера 1.12, преобразованную в восьмиричную систему
посредством умножения на 8.
Пример 1.13
. 125
X 8
1.0 Цифра равна 1 результат = 0.18
Преобразование десятичной дробной части в шестнадцатиричную форму иллю-
стрируется примером 1.14. Здесь десятичная дробная часть .046875 преобразуется в
шестнадцатиричную систему счисления последовательным умножением ее на 16. Об-
ратите внимание на то, что .046875 равно шестнадцатиричному 0.0С.
Пример 1.14
. 046875
х____16
0.75 Цифра равна 0
. 75
X 16_____
12.0 Цифра равна 12(C) результат = О.ОС16
Двоично-кодированные шестнадцатиричные числа
Двоично-кодированные шестнадцатиричные числа (ВОН) используются для
представления шестнадцатиричных данных с использованием двоичного кода. Двоич-
но-кодированное шестнадцатиричное число - это шестнадцатиричное число, записан-
ное так, что каждая его цифра представлена 4-разрядным двоичным числом. Значения
цифр ВСН показаны в табл. 1.5. Обратите внимание на то, что часто мы записываем
шестнадцатиричные числа как, например, Ох8А, где Ох - это сигнал компьютеру, что
следующее далее число является шестнадцатиричным.
Шестнадцатиричные числа представляются в коде ВСН посредством преобразо-
вания каждой их цифры в ВСН-код с вводом пробела после каждой кодированной циф-
ры. Пример 1.15 показывает шестнадцатиричное число 2АС, преобразованное в код
ВСН. Обратите внимание, что каждая двоично-кодированная цифра отделяется пробе-
лом.
Глава 1. Введение в архитектуру компьютеров
23
Таблица 1.5. Двоично-кодированный шестнадцатиричный код
Шестнадцатиричная цифра Код ВСН
0 0000
1 0001
2 0010
3 ООН
4 0100
5 0101
6 оно
7 0111
8 1000
9 1001
А 1010
В 1011
С 1100
D 1101
Е 1110
F 1111
Пример 1.15
2АС = 0010 1010 1100
Назначением кода ВСН является обеспечение возможности записи двоичной
версии шестнадцатиричных чисел в форме, которая может легко преобразовываться в
шестнадцатиричную форму и обратно. Пример 1.16 показывает двоично-кодированное
шестнадцатиричное число, преобразованное обратно в шестнадцатиричную форму.
Пример 1.16
1000 ООН 1101 . 1110 = 83D.E
Дополнения
Иногда для представления отрицательных чисел, данные сохраняются в форме
дополнения для представления отрицательных данных. При этом используются две
системы. Одна использует дополнение до основания системы счисления, а вторая -
дополнение до основания системы счисления - 1. Первой появилась система, исполь-
зовавшая дополнение до основания системы счисления - 1, в которой при представле-
нии отрицательного числа каждая цифра числа вычитается из основания системы счис-
ления минус 1 с целью получения значения дополнения до основания системы счисле-
ния -1.
Пример 1.17 показывает, как получается дополнение 8-разрядного двоичного
числа 01001100 до значения основания системы счисления минус 1 с целью отображе-
ния его как отрицательного значения. Обратите внимание на то, что каждая цифра чис-
ла вычитается из единицы для генерирования дополнения до значения основания сис-
темы счисления минус 1 (единица). В данном примере отрицательное 01001100 пред-
ставляется как 10110011. Та же самая методика может применяться для любой систе-
мы счисления, как иллюстрируется в примере 1.18, в котором дополнение до пятнадца-
ти (основание системы счисления минус 1) шестнадцатиричного числа 5CD вычисляет-
ся посредством вычитания каждой цифры из пятнадцати.
24
Применение микроконтроллеров PIC 18
Пример 1.17
1Ш 1111
0100 1100
1011 0011
Пример 1.18
±5 15 15
- 5 С D________
А 3 2
Сегодня само по себе дополнение до основания системы счисления - 1 не ис-
пользуется; оно используется только в качестве этапа на пути к получению дополнения
до основания системы счисления. Дополнение до основания системы счисления ис-
пользуется для представления отрицательных чисел в современных компьютерных
системах. (Дополнение до основания системы счисления - 1 использовалось в ранние
дни компьютерной технологии.) Основная проблема дополнения до основания системы
счисления - 1 заключается в том, что при использовании этой системы возникает два
нуля: положительный и отрицательный; в системе, использующей дополнение до осно-
вания системы счисления, существует только положительный ноль.
Для формирования дополнения до основания системы счисления сначала нахо-
дят дополнение до основания системы счисления - 1, а затем добавляют единицу к ре-
зультату. Пример 1.19 показывает, как число 0100 1000 преобразуется в отрицательное
значение переводом его в дополнение до двух (основание системы счисления).
Пример 1.19
ini ini
- 0100 1000
1011 0111 (дополнение до одного)
+ _________1
1011 1000 (дополнение до двух)
Чтобы убедиться в том, что 0100 1000 является инверсией (отрицательным зна-
чением) 1011 1000, сложим их для формирования 8-разрядного результата. Девятый
разряд отбрасывается и результат будет нулем, потому что 0100 1000 - это положи-
тельное 72, в то время как 1011 1000 - это отрицательное 72. Та же самая методика
применима для любой системы счисления. Пример 1.20 показывает то, как инверсия
шестнадцатиричного 345 находится путем первичного определения дополнения данно-
го числа до пятнадцати, а затем добавления единицы к результату с целью определе-
ния дополнения до шестнадцати. Как и ранее, если исходное 3-разрядное число 345
добавить к его инверсии СВВ, то трехразрядным результатом будет 000. Как и в пре-
дыдущем примере, четвертый разряд (перенос) отбрасывается. Это подтверждает, что
345 является инверсией СВВ. Дополнительная информация о дополнениях до одног о и
двух представлена рассмотрением чисел со знаками в следующем подразделе.
Пример 1.20
15 15 15
--3 4 5 (дополнение до 15)
С В А
+ 1 (дополнение до 16)
СВВ
Глава 1. Введение в архитектуру компьютеров
25
1.3. Компьютерные форматы данных
Успешное программирование требует полного понимания форматов данных. В
данном подразделе описаны многие широко распространенные компьютерные форма-
ты данных в той мере, как они используются в семействе микроконтроллеров РЮ.
Обычно данные представляются в формате ASCII, как двоично-кодированные десятич-
ные числа, целые числа со знаком и без, а также иногда как числа с плавающей точкой
(действительные числа). Могут быть использованы и другие формы представления
данных, однако они здесь не описываются, поскольку не являются столь же широко
распространенными.
Данные в формате ASCII
Данные в формате ASCII (Американский Стандартный Код для Информационного
Обмена) представляют алфавитно-цифровые символы в памяти компьютерной систе-
мы (см. табл. 1.6). Стандартный ASCII-код является 7-битным кодом, в котором вось-
мой и самый старший бит, используются как бит паритета в некоторых антикварных
системах. Если ASCII-данные используются для вывода на принтер, то нулевое значе-
ние самого старшего бита будет означать режим алфавитно-цифровой печати, а еди-
ничное - режим графической печати. В персональном компьютере расширенный набор
символов ASCII выбирается установкой единичного состояния самого левого бита.
Табл. 1.7 показывает расширенный набор символов ASCII, использующий кодировку
Ox80-OxFF. Символы расширенного набора ASCII обозначают некоторые иностранные
буквы и знаки пунктуации, греческие и математические символы, символы псевдогра-
фики и другие специальные символы. Обратите внимание на то, что фактический вид
печатаемых символов расширенного набора ASCII может изменяться от принтера к
принтеру.
Таблица 1.6. Коды ASCII
Вторая часть кода
1 я ХО XI Х2 ХЗ Х4 X5 X6 X7 X8 X9 XA XB XC XD XE XF
часть кода
ОХ NUL SOH STX ЕТХ EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
IX DLE DC1 DC 2 DC3 DC 4 NAK SYN ETB CAN EMS SUB ESC FS GS RS US
2Х SP 1 И # $ "6 & ( ) * + - > /
ЗХ 0 1 2 3 4 5 6 7 8 9 < = > ?
4Х @ А В С D E F G H I J к L M N 0
5Х Р Q R S Т U V W X Y z [ \ ] A
6Х а Ь с d e F g h i j k I m n 0
7Х р q г S t u V w X У z { 1 }
Приведенная таблица символов рассчитана на использование с принтером IBM
ProPrinter, она также соответствует наборам специальных символов, введенным в
большинство текстовых процессоров.
Управляющие символы ASCII, также перечисленные в таблице 1.6, выполняют
функции управления в компьютерной системе, включая очистку экрана, символ «шаг
назад», перевод строки и т.д. Для ввода управляющих кодов с компьютерной клавиату-
ры нужно, удерживая в нажатом состоянии клавишу Ctrl (Control), вводить соответст-
вующие символы. Так для ввода 0x01, нужно ввести Control-A; а код 0x02 вводится как
Control-B и т.д. Обратите внимание на то, что управляющие коды часто появляются на
экране как АД для Control-A, ЛВ для Control-B и т.д. Также обратите внимание на то, что
26
Применение микроконтроллеров PIC 18
код возврата каретки (CR) в большинстве современных клавиатур соответствует кла-
више Enter (Ввод). Назначением символа CR является возврат курсора или печатаю-
щей головки на левое поле. Другим кодом, который часто появляется во многих про-
граммах, является код перевода строки (LF), который перемещает курсор вниз на одну
строку.
При использовании табл. 1.6 или 1.7 для преобразования алфавитно-цифровых
или управляющих символов в коды ASCII, сначала необходимо найти алфавитно-
цифровой код, подлежащий преобразованию. Затем следует найти первую цифру ше-
стнадцатиричного ASCII-кода. После этого - вторую цифру кода. Например, заглавной
букве А соответствует ASCII-код 0x41, а строчной букве а - ASCII-код 0x61.
ASCII-данные чаще всего сохраняются в памяти при использовании специальной
команды Ассемблера, которая называется declare byte (Объявить байт) или DB, либо
командой DATA в случае строк. (Ассемблер - это программа, которая используется для
программирования компьютера на его машинном языке.) Команды DB и DATA, а также
несколько примеров их использования с символами ASCII, приводятся в примере 1.21.
Обратите внимание, что каждый символ при использовании команды DB берется в апо-
строфы (') - никогда не используйте кавычки ("), если только вы не применяете команду
DATA.
Таблица 1.7. Расширенные ASCII-коды в том виде,
как они печатаются на принтере IBM ProPrinter.
первый второй
ХО Х1 Х2 хз Х4 Х5 Х6 Х7 Х8 Х9 ХА хв хс XD ХЕ XF
ох © о V ♦ ♦ * • а О П сГ $ J4 <>
1Х ► ч : !! I § а t т 1 —♦ ♦— L. ♦* ▲ ▼
8Х Q й ё а а а ё 9 ё ё ё i I 1 А А
9Х Ё ее /Е д 6 i> й й 9 0 0 ё £ ¥ Pt f
АХ а I ё й п N а О 6 г* —i ’/г % 1 »
ВХ 1 - л и 1 1 1
СХ L JL *г . - 11 1г |L — 4 1
DX 1 II L 1 f i 1 1
т т г т г 1
ЕХ а Р г гс S а р Y ф в Q б OQ $ е п
FX Г J Я о • • П 2
Пример 1.21
DB 'В'
DB 'г'
DB ' е'
DB 'У'
DB 0x00
DB ' Вгеу1, 0
DATA "Вгеу", 0
DATA "Barry", 0
Глава 1. Введение в архитектуру компьютеров
27
Двоично-кодированные десятичные данные
Двоично-кодированные десятичные (BCD) данные могут сохраняться как в упако-
ванной, так и неупакованной форме. Упакованные BCD-данные сохраняются в форме
двух цифр на байт, у неупакованные BCD-данные сохраняются как одно число на байт.
Диапазон BCD-цифр лежит от ОООО2 до 10012, что соответствует десятичным 0-9. Не-
упакованные BCD-данные поступают от клавиатуры либо малой численной клавиатуры.
Упакованные BCD-данные используются в некоторых командах набора команд микро-
процессора, включая BCD -сложение и вычитание.
Табл. 1.8 показывает некоторые десятичные числа, преобразованные, как в упа-
кованную, так и в неупакованную BCD-форму. Приложениями, которые в типичном слу-
чае требуют использования BCD-данных, являются локальные торговые терминалы, а
также почти любые иные устройства, выполняющие минимальное количество простых
арифметических операций. Если системы требуют выполнения сложных арифметиче-
ских операций, то BCD-данные в них используются редко, поскольку нет простого и
эффективного метода выполнения сложных арифметических BCD-операций.
Пример 1.22 демонстрирует то, как следует использовать Ассемблер для опре-
деления как упакованных, так и неупакованных BCD-данных. Пример 1.23 показывает
то, как это можно сделать, используя C/C++ и типы char или byte. Во всех случаях необ-
ходимо придерживаться соглашения о таком порядке записи данных в память, при ко-
тором первыми записываются младшие разряды чисел. Это означает, что для сохране-
ния в памяти, например, числа 83, сначала нужно сохранить 3, а затем - 8. Кроме того,
обратите внимание на то, что в случае упакованных BCD-данных, символы Ох (признак
шестнадцатиричных чисел) должны предшествовать цифрам с целью обеспечения га-
рантии того, что Ассемблер сохранит именно BCD-значение, а не десятичное значение
в случае упакованных BCD-данных. Обратите внимание на то, как числа сохраняются в
памяти по одной цифре в байте в случае неупакованных данных и по две цифры в байте
в случае упакованных данных.
Пример 1.22
/Неупакованные BCD-данные (сначала записываются младшие разряды)
NUMB1 DB 3,4,5 .определяет число 543
NUMB2 DB 7,8 .определяет число 87
/Упакованные BCD-данные (сначала записываются младшие разряды)
MUMB3 DB 0x37,0x34 .определяет число 3437
MUMB4 DB 3,0x45 .определяет число 4503
Таблица 1.8. Упакованные и неупакованные BCD-данные
Десятичные Упакованные___ _____________________Неупакованные_________________
12 0001 0010 0000 0001 0000 0010
623 0000 оно 0010 ООН 0000 оно 0000 0010 0000 ООН
910 0000 1001 0001 0000 0000 1001 0000 0001 0000 0000
28
Применение микроконтроллеров PIC 18
Пример 1.23
// Неупакованные BCD-данные (сначала записываются младшие разряды)
//
char Numbi = 3,4,5; // определяет число 543
char Numb2 =7,8; // определяет число 87
//
// Упакованные BCD-данные (сначала записываются младшие разряды)
//
char Numb3 = 0x37,0x34; // определяет число 3437
char Numb4 = 3,0x45; // определяет число 4503
Байтовые данные
Байтовые данные хранятся как в форме целых чисел без знака, так и в форме це-
лых чисел со знаком. Рис. 1.2 иллюстрирует как знаковую, так и беззнаковую формы
байтовых целых чисел. Разница между этими формами заключается в весе самого ле-
вого разряда. Его значение равно 128 для беззнакового целого и минус 128 для целого
со знаком. В формате целого со знаком самый левый разряд одновременно является
как знаковым разрядом числа, так и разрядом с весом минус 128. Например, 0x80
представляет значение 128 как беззнакового числа; в качестве же числа со знаком оно
представляет число -128. Целые числа без знака имеют диапазон значений OxOO-OxFF
(0-255). Целые числа со знаком имеют диапазон значений -128 до 0 и до +127.
Хотя отрицательные числа со знаком и представляются таким способом, они со-
храняются в памяти в форме дополнения до двух. Метод оценки чисел со знаком путем
использования весов позиций каждого разряда является намного более легким, чем
операция нахождения дополнения до двух числа с целью определения его значения.
Это особенно справедливо в мире калькуляторов, сконструированных для программи-
стов.
Всякий раз, когда выполняется нахождение дополнения до двух числа, знак этого
числа изменяется с отрицательного на положительный либо с положительного на офи-
цательный. Например, число 00001000 - это +8. Его офицаюльное значение (-8) нахо-
дится посредством определения дополнения до 2-х числа +8. Для нахождения допол-
нения числа до 2-х сначала находится его дополнение до одного. Для нахождения до-
полнения числа до одного, каждый разряд этого числа инвертируется - с нуля на еди-
ницу либо с единицы на ноль. Как только дополнение до единицы будет сформировано,
определяется дополнение числа до двух посредством добавления единицы к дополне-
нию до одного. Пример 1.24 демонстрирует определение дополнения до двух числа с
использованием данной методики.
Пример 1.24
+8 = 00001000
11110111 (дополнение до одного)
_+____________1_
-8 = 11111000 (дополнение до двух)
Глава 1. Введение в архитектуру компьютеров
29
Двоичные
веса
байтовое значение без знака
Рис. 1.2. Байтовые (8-битные) данные
Другой и, возможно более простой, метод нахождения дополнения числа до двух
заключается в следующем: число сначала записывается. Далее, прямо под ним, начи-
ная с правого разряда, оно начинает переписываться вплоть до первой единицы. После
этого справа налево записывается оставшаяся часть числа, однако с инвертированны-
ми разрядами. Пример 1.25 иллюстрирует эту методику с тем же числом, которое ис-
пользовалось в примере 1.24.
Пример 1.25
+8 = 00001000
1000 (записываем число до первой 1)
1111 (инвертируем оставшиеся биты)
-8 = 11111000
Для сохранения 8-битных данных в памяти в программе на Ассемблере следует
использовать команды DB или DATA, как в предыдущих примерах, либо ключевое слово
char, как это показано в ранее приведенном примере программного фрагмента для
C/C++. В примере 1.26 показано сохранения в памяти различных форм 8-битных чисел
в программе на Ассемблере. Байтовые данные могут также сохраняться в памяти с ис-
пользованием команды DATA или DE ('объявление данных для памяти ЭСППЗУ/ Обра-
тите внимание на то, что в данном примере шестнадцатиричные числа определяются
префиксом Ох, предшествующим числу, а также на то, что десятичные числа записы-
ваются с точкой, предшествующей числу. Пример 1.27 демонстрирует объявление тех
же байтовых данных в программе на C/C++.
Пример 1.26
/Байтовые данные без знака
DATA1 DB .254 ; определение десятичного 254
DATA2 DB 0x87 ; определение шестнадцатиричного 87
DATA3 DB .71 ; определение десятичного 71
; Байтовые данные со знаком
30
Применение микроконтроллеров PIC 18
DATA5 DB . 100 ; определение десятичного 100
DATA б DB OxFF ; определение десятичного -1
DATA7 DB .56 ; определение десятичного 56
Пример 1.27
// Байтовые данные без знака
И
unsigned char Datal = unsigned char Data2 = 254; 0x87; 71; // // // определение десятичного 254 определение шестнадцатиричного 87
unsigned char Dala3 = определение десятичного 71
// // Байтовые данные co // char Data4 = -100; знаком // определение десятичного -100
char Data5 = + 100; // определение десятичного -100
char Data6 = -1; // определение десятичного -1
char Data7 = 56; // определение десятичного 56
Пословные данные
Слово (16 битов) формируется двумя байтами данных. Младший байт всегда сохраняет-
ся в семействе PIC 18 в ячейке памяти с меньшим номером, а старший - в ячейке с большим
номером. Этот метод сохранения числа называется форматом с обратным порядком байтов.
Альтернативный метод, используемый во всех других членах семейства PIC, называется фор-
матом с прямым порядком. При использовании этого формата числа сохраняются так, что
ячейка с меньшим номером содержит старший байт данных.
старший байт
младший байт
(Ь) в ячейках памяти 0x200 и 0x20! записано слово 0x1234
Рис. 1.3. Пословные (16 бит) данные
Рис. I. За показывает веса для каждой битовой позиции слова данных, а рис. I. ЗЬ
показывает, как число 1234Н заносится в ячейки памяти 3000Н и 3001Н. Единственная
Глава 1. Введение в архитектуру компьютеров
31
разница между словом со знаком и беззнаковым словом связана с самой левой бито-
вой позицией. В беззнаковой форме самый левый бит не связан со знаком и имеет вес
32768; в форме со знаком его вес будет равен -32768. Как и в случае байтовых данных
со знаком, слово со знаком имеет форму дополнения до двух, когда оно представляет
отрицательное число. Кроме того обратите внимание на то, что младший байт сохраня-
ется в ячейке памяти с меньшим адресом (3000Н), а старший - в ячейке памяти с боль-
шим адресом (3001Н), если речь идет о семействе устройств PIC18.
Пример 1.28 показывает несколько знаковых и беззнаковых пословных данных,
сохраненных в памяти в рамках программы на Ассемблере. Пример 1.29 демонстриру-
ет сохранение тех же чисел программой на C/C++, которая использует ключевое слово
short для сохранения 16-разрядных целых чисел. Обратите внимание на то, что команда
declare word или DW на Ассемблере приводит к сохранению в памяти слов, а не байтов,
как в предыдущих примерах. Команда DATA может также быть использована для опре-
деления слова. При использовании компилятора С PIC С18, директива int также исполь-
зуется для объявления 16-разрядного целого числа.
Пример 1.28
;Беззнаковые пословные данные
DATA1 DW .2544 ; определяет десятичное 2544
DATA2 DW Ox87AC ;определяет шестнадцатиричное 8 7 АС
DATA3 DW .710 ; определяет десятичное 710
9 ;Пословные 9 данные co знаком
DATA 4 DW .13400 ;определяет десятичное 13400
DATA5 DW + 198 /•определяет десятичное +198
DATA 6 DW OxFFFF /•определяет десятичное - 1
Пример 1.29
//Пословные данные без знака
//
unsigned short Datal = 2’544; // определяет десятичное 2544
unsigned short Data2 = Ox87AC; // определяет шестнадцатиричное 87AC
unsigned int Data3 = 710; //определяет десятичное 710
11
// Пословные данные co знаком
И
short Data4 = 13400; // определяет десятичное 13400
short Data5 = +198; // определяет десятичное +198
int Data6 = -1; // определяет десятичное -1
int Data? = 3 ; // определяет десятичное +3
Действительные числа
Действительные числа иногда встречаются в приложениях - здесь они рассмат-
риваются в силу того, что иногда встроенные контроллеры должны иметь дело с дейст-
вительными числами. Действительное число или число с плавающей точкой, как его
32
Применение микроконтроллеров PIC 18
часто называют, состоит из двух частей: мантиссы, - значащей или дробной чаши и
экспоненты. Рис. 1.4 показывает как 4-байтовую, таки 8-байтовую форму дейшви тель-
ных чисел, как они сохраняются в системах Intel. Обратите внимание на то, чго
4-байтовая форма называется формой числа одинарной точности, а 8-байтовая форма
называется формой числа двойной точности. Представленные здесь формы сохране-
ния действительных чисел являются теми же, которые специфицированы стандартом
IEEE-754, версия 10.0. Этот стандарт был принят в качестве стандартной формы пред-
ставления действительных чисел практически всеми языками программирования, а
также многими прикладными пакетами. Данный стандарт также применяется при ма-
нипулировании данными в арифметических сопроцессорах персональных компьюте-
ров. Рис. I. 4а показывает форму числа одинарной точности, которая содержит бит зна-
ка, 8-битную экспоненту и 24-битную дробную часть (мантиссу). Обратите внимание на
то, что в силу того, что приложения часто требуют использования чисел с плавающей
точкой двойной точности, соответствующая форма также представлена на рис. I. 4Ь.
Простой арифметический подсчет показывает, что для сохранения всех назван-
ных фрагментов данных необходимо 33 бита. Однако это не так - 24-битная мантисса
содержит подразумеваемый (неявный) бит, что позволяет мантиссе представлять 24
бита, будучи сохраняемой всего в 23 битах. Неявный бит - это первый бит нормализо-
ванного действительного числа. При нормализации числа, оно подстраивается таким
образом, что его значение по крайней мере равно единице, однако меньше 2. Напри-
мер, если 12 преобразовать в двоичную форму (1 1002), то после нормализации резуль-
татом будет: 1.1 х 23. Целая часть нормализованного числа (1) не сохраняется при ис-
пользовании 23-битной части числа, задающей мантиссу; 1 находится в единичном
“скрытом” бите. Табл. 1.9 показывает форму этого и других чисел одинарной точности.
Экспонента сохраняется в форме смещенной экспоненты. В форме действитель-
ного числа одинарной точности смещение равно 127 (Ox7F), а при использовании фор-
мы действительного числа двойной точности она равна 1023 (Ox3FF). Значения смеще-
ния и экспоненты складываются перед сохранением экспоненты в соответствующей
части числа с плавающей точкой. В предыдущем примера показана экспонента, равная
23, представленная в форме смещенной экспоненты, равной 127 т 3 or 130 (0x82) в
форме действительного числа одинарной точности или как 1026 (0x402) в форме дей-
ствительного числа двойной точности.
31 30 23 22 0
знак экспонента мантисса
(а)
63 62 52 51 0
знак экспонента мантисса
(Ь)*
Рис. 1.4. Данные, заданные в формате с плавающей точкой:
(а) одинарная точность, (Ь) двойная точность
Глава 1. Введение в архитектуру компьютеров
33
Таблица 1.9. Действительные числа одинарной точности
Деся- тичное Двоичное Нормализо- ванное Знак Смещенная экспонента Мантисса
+12 1100 1.1 X 2J 0 10000010 10000000 00000000 00000000
-12 1100 1.1 X 23 1 10000010 10000000 00000000 00000000
+100 1100100 1.1001X 26 0 10000101 10010000 00000000 00000000
-1.75 1.11 1.11 X 2° 1 01111111 11000000 00000000 00000000
+0.25 0.01 1.0 x 2-2 0 01111101 00000000 00000000 00000000
+0.0 0 0 0 00000000 00000000 00000000 00000000
Имеется два исключения из правил занесения в память чисел с плавающей точ-
кой. Так, число 0.0 сохраняется в форме, все разряды которой равны нулю. Число “бес-
конечность” сохраняется в форме, все разряды экспоненты которой имеют единичное
значение, а мантиссы - нулевое. Знаковый бит в этом случае указывает либо положи-
тельную, либо отрицательную бесконечность.
В C/C++ числа одинарной точности определяются как float, а числа двойной точ-
ности определяются как double, как это показано в примере 1.30. Нет возможности
определять такие числа при использовании Ассемблера PIC, если только, конечно,
предварительно не преобразовать их в пословный или побайтовый формат вручную.
Компилятор CI8 PIC воспринимает как форму float, так и форму double, однако оба эти
типа чисел фактически сохраняются и используются как 32-разрядные числа одинар-
ной точности.
Пример 1.30
//Действительные числа одинарной точности
И
float Nurnbl = 1.234;
float Numb2 = -23.4;
float Numb3 = 4.3e2;
//
// Действительные числа двойной точности
double Numb4 = 123.4;
double Numb5 = -23.4;
34
Применение микроконтроллеров PIC 18
IEEE-754
seee ееее efff ffff ffff ffff ffff ffff
Microchip
eeee eeee sfff ffff ffff ffff ffff ffff
s = знаковый бит
e = экспонента
f = мантисса
Рис. 1.5. Форматы чисел с плавающей точкой Microchip и IEEE
Microchip использует другой формат для чисел с плавающей точкой в компилято-
ре с языка С С18. Рисунок 1.5 иллюстрирует разницу между форматом чисел с плаваю-
щей точкой фирмы Microchip и форматом IEEE. Разница заключается в размещении
знакового бита числа. Эта разница не оказывает воздействия на работу компилятора С.
1.4. Резюме
1. Чарльз Беббидж изобрел и создал первую вычислительную систему - “Аналитический
двигатель". Позднее, Джон фон Нейман усовершенствовал архитектуру компьютера.
2. Первым программистом была Августа Ада Байрон (позднее - графиня Лав-
лесс), она заслужила репутацию первого программиста в силу того, что писала про-
граммы для “Аналитического двигателя” Чарльза Беббиджа.
3. Первый в мире микропроцессор - Intel 4004, был 4-битным микропроцессором,
представлявшим собой программируемый контроллер в микросхеме. Он адресовал
4096 четырехбитных ячеек памяти.
4. ЦП является управляющим элементом компьютерной системы. ЦП выполняет
перенос данных, выполняет простые арифметические и логические операции, а также
принимает простые решения. ЦП выполняет программы, сохраненные в запоминаю-
щей системе, что обеспечивает возможность выполнения сложных операций задача
короткий период времени.
Глава 1. Введение в архитектуру компьютеров
35
5. Все компьютерные системы содержат три шины, предназначенные для управления
памятью и устройствами ввода-вывода. Шина адреса используется для обращения по адресу
памяти или к устройству ввода-вывода. Шина данных переносит данные между микропроцес-
сором и памятью, а также пространством ввода-вывода. Шина управления управляет памятью
и вводом-выводом, запрашивая чтение или запись данных.
6. Числа преобразуются из любой системы счисления в десятичную систему счисления,
учитывая вес каждого разряда. Вес разряда, расположенного непосредственно слева отточки
позиционной системы счисления, всегда равен единице в любой системе счисления. Вес раз-
ряда, расположенного непосредственно слева от позиции единиц всегда равен основанию
используемой системы счисления, умноженному На единицу. Вес следующего слева разряда
определяется умножением на основание системы счисления. Вес разряда, расположенного
непосредственно справа отточки позиционной системы счисления, всегда определяется де-
лением на основание системы счисления.
7. Преобразование целой части десятичного числа в любую иную систему счис-
ления выполняется делением на основание системы счисления. Преобразование
дробной части десятичного числа в любую иную систему счисления выполняется умно-
жением на основание системы счисления.
8. Шестнадцатиричные данные представляются в шестнадцатиричной форме или в ко-
дировке, называемой двоично-кодированным шестнадцатиричным кодом (ДКШК). А Двоично-
кодированное шестнадцатиричное число - это число, которое записывается четырехбитными
двоичными числами, представляющими каждый шестнадцатиричный разряд.
9. Код ASCII используется для хранения алфавитно-цифровых либо численных
данных. Код ASCII - это 7-битный код; однако, он может иметь восьмой бит, который
используется для расширения набора символов от 128 до 256 кодов. Код возврата ка-
ретки (Enter) возвращает печатающую головку или курсор на левое поле. Код перевода
строки перемещает курсор или печатающую головку вниз на одну строку.
10. Двоично-кодированные десятичные (ДКД) данные иногда используются в компью-
терной системе для хранения десятичных данных. Эти данные сохраняются либо в упакован-
ной (две цифры на байт) либо в неупакованной форме (одна цифра на байт).
11. Двоичные данные в компьютерных системах сохраняются в форме байтов (8
битов) или слов (16 битов). Эти данные могут быть со знаком или без. Отрицательные
числа со знаком всегда сохраняются в форме дополнения до двух. Данные, длина кото-
рых превышает 8 бит, всегда сохраняются с использованием формата с обратным по-
рядком байтов.
12. Формат с плавающей точкой используется в компьютерных системах для хра-
нения целых, смешанных и дробных чисел. Формат с плавающей точкой составляется
из знака, мантиссы и экспоненты.
13. Директивы Ассемблера DB (объявить байт) и DW (объявить слово) использу-
ются для сохранения байтов и слов данных в системах памяти.
1.5. Вопросы и задания
1. Кто построил “аналитический двигатель”?
2. Первый в мире микропроцессор был создан в 1971 году
3. Кем была графиня Лавлесс?
4. Что такое “машина фон Неймана”?
5. Какая компания разработала первый микроконтроллер?
6. Что значит сокращение CISC?
7. Что значит сокращение RISC?
36
Применение микроконтроллеров PIC 18
8. Двоичный бит хранит или.
9. Компьютерное “К" равно байтам.
10. Компьютерное “М” равно К байт.
11. Компьютерное “G” равно М байт.
12. Что такое полубайт?
13. Начертите блок-схему компьютерной системы.
14. Перечислите три шины, которые присутствуют во всех компьютерных систе-
мах.
15. Какая шина передает адрес памяти устройству ввода-вывода или памяти?
16. Какой сигнал управления заставляет память выполнить операцию чтения?
17. В чем заключается концепция сохраняемой программы?
18. В чем заключается разница между СППЗУ и ЭСППЗУ?
19. Если память имеет 14-битный адрес, сколько ячеек памяти она может содер-
жать?
20 Сколько ячеек памяти содержится в памяти объемом 4К х 8?
21. Что такое СОЗУ?
22. Какой тип запоминающего устройства должен использоваться для хранения
динамических данных?
23. Опишите назначение следующих директив Ассемблера:
a. DB
b.DATA
с. DW
24. Опишите назначение следующих директив C/C++:
a. char
b. short
с. int
d. float
е. double
25. Если адресная шина памяти содержит указанное далее количество линий, оп-
ределите количество ячеек памяти, которые могут быть адресованы.
а. 12
Ь. 14
с. 16
d. 18
е. 32
26. Преобразуйте приведенные далее двоичные числа в десятичные:
а. 1101.01
Ь. 111001.0011
с. 101011.0101
d. 111.0001
27. Преобразуйте приведенные далее восьмиричные числа в десятичные:
а. 234.5
Ь. 12.3
с. 7767.07
d. 123.45
е. 72.72
28. Преобразуйте приведенные далее шестнадцатиричные числа в десятичные:
а.АЗ.З
b. 129.С
с. AC.DC
Глава 1. Введение в архитектуру компьютеров
37
d. FAB.3
е. BB8.0D
29. Преобразуйте следующие десятичные целые числа в двоичную, восьмирич-
ную и шестнадцатиричную формы:
а. 23
Ь. 107
с. 1238
d. 92
е. 173
30. Преобразуйте следующие десятичные числа в двоичную, восьмиричную и ше-
стнадцатиричную формы:
а. 0.625
Ь. 0.00390625
с. 0.62890625
d. 0.75
е. 09375
31. Преобразуйте следующие шестнадцатиричные числа в двоично-
кодированный шестнадцатиричный код(ДКШК):
а. 23
b. AD4
с. 34.AD
d. BD32
е. 234.3
32. Преобразуйте следующие двоично-кодированные шестнадцатиричные числа
в шестнадцатиричные:
а. 1100 0010
Ь.0001 0000 1111 1101
с. 1011 1100
d. 0001 0000
е. 1000 1011 1010
33. Преобразуйте следующие двоичные числа в форму дополнения до одного:
а. 1000 1000
Ь. 0101 1010
с. 0111 0111
d. 1000 0000
34. Преобразуйте следующие двоичные числа в форму дополнения до двух:
а. 1000 0001
Ь. 1010 1100
с. 1010 1111
d. 1000 0000
35. Как объявляются байтовые данные при использовании Ассемблера?
36. Преобразуйте следующие слова в символьные строки в кодировке ASCII, ис-
пользуя Ассемблер:
a. FROG
b. Аге
с. Water
d. Well
37. Каким будет код ASCII для клавиши Enter и каково его назначение?
38. Используйте директиву Ассемблера для сохранения в памяти строки ASCII-
символов “What time is it?” (Который час?).
38
Применение микроконтроллеров PIC 18
39. Преобразуйте следующие десятичные числа в 8-разрядные двоичные числа
со знаком:
а.+32
Ь. -12
с. +100
d. -92
40. Преобразуйте следующие десятичные числа в пословные двоичные числа со
знаком:
а. +1000
6.-120
с. +800
d. -3212
41. Используйте директиву Ассемблера для сохранения в памяти байтового числа -34.
42. Создайте байтовую переменную с именем Fredl и сохраните в ней число -34
на C/C++. |
43. Продемонстрируйте, как следующие 16-разрядные шестнадцатиричные числа
сохраняются в запоминающей системе (используйте как форму с обратным порядком
байтов, так и форму с прямым порядком байтов):
а. 0x1234
Ь. ОхА122
с. ОхВЮО
44. В чем заключается разница между форматом с обратным порядком байтов и
форматом с прямым порядком байтов в случае сохранения чисел, превышающих по
длине восемь разрядов?
45 Используйте директиву Ассемблера для сохранения в памяти шестнадцати-
ричного 123А.
46. Преобразуйте следующие десятичные числа как в упакованную, так и в неупа-
кованную ДКД-формы:
а. 102
Ь. 44
с. 301
d. 1000
47. Преобразуйте следующие двоичные числа в десятичные числа со знаком:
а. 10000000
Ь. 00110011
с. 10010010
d.10001001
48. Преобразуйте следующие ДКД-числа (в предположении, что это упакованные
числа) в десятичные числа:
а. 10001001
Ь.00001001
с. 00110010
d.00000001
49. Преобразуйте следующие десятичные числа в числа одинарной точности с
плавающей точкой:
а.+1.5
Ь. -10.625
с. +100.25
d. -1200
50. Преобразуйте следующие числа с плавающей точкой одинарной точности в
Глава 1. Введение в архитектуру компьютеров
39
формате IEEE-754 версии 10.0 в десятичные числа:
а. 0 10000000 11000000000000000000000
Ь. 1 01111111 00000000000000000000000
с. О 10000010 10010000000000000000000
51. Используйте Интернет для того, чтобы написать краткое сообщение об одном
из нижеперечисленных пионеров в области компьютеров:
а. Чарльз Беббидж
Ь. Августа Ада Байрон
с. Джон фон Нейман
52. Используйте Интернет для того, чтобы написать краткое сообщение об одном
из нижеперечисленных языков программирования:
a. COBOL
b. ALGOL
с. FORTRAN
d. PASCAL
53. Используйте Интернет для того, чтобы написать краткое сообщение о свойст-
вах микроконтроллеров семейства PIC.
40
Применение микроконтроллеров PIC 18
ГЛАВА 2. Архитектура семейства PIC18
и разработка программ
До того, как приступить к программированию микроконтроллера или организа-
ции взаимодействия с другими устройствами, необходимо понять его архитектуру. В
данной главе представляется архитектура семейства микроконтроллеров PIC, при этом
особое внимание уделяется микроконтроллерам семейства PIC 18, выпускаемых фир-
мой Microchip Technology Incorporated. Семейство PIC 18 - это самое новое из семейств
PIC, имеющихся на рынке. В данной главе также представляются вводные сведения об
интегральной среде разработки (IDE) для микроконтроллеров PIC, а также рассматри-
вается процесс ассемблирования/компоновки.
После завершения изучения данной главы вы сможете:
1. Описать внутреннюю архитектуру микроконтроллера PIC и взаимодействие его
компонент.
2. Детально описать системную архитектуру PIC-основанной микропроцессорной
системы.
3. Объяснить назначение каждого регистра в обобщенной модели программиро-
вания микроконтроллера.
4. Запрограммировать простой порт ввода-вывода на осуществление операций
ввода-вывода.
5. Использовать интегральную среду разработки (IDE) для программирования
микроконтроллеров семейства PIC 18.
6. Имитировать выполнение программы для микроконтроллера PIC.
7. Описать функционирование команд языка ассемблера.
8. Пояснить процесс Ассемблирования и компоновки.
2.1. Архитектура PIC18
Архитектура PIC-основанной микроконтроллерной системы несколько отличается
от общей компьютерной системы, рассмотренной в главе 1. Вследствие того, что PIC
содержит память и устройства ввода-вывода, пригодные для большинства примене-
ний, микроконтроллер PIC - это просто отдельный блок PIC-основанной системы. До-
полнительная память или возможности ввода-вывода могут быть добавлены в систему,
однако во многих случаях память и возможности ввода-вывода, обеспечиваемые мик-
роконтроллером PIC достаточны для большинства применений.
Рис. 2.1 иллюстрирует простую систему, которая использует микроконтроллер
PIC. Эта система содержит ЖК-индикатор для отображения информации, клавиатуру
для ввода данных, оптический считыватель карточек для ввода информации с карточек
и последовательный интерфейс с хост-компьютером для выгрузки данных и загрузки
информации в контроллер. Эта, используемая в качестве примера, система не содер-
жит внешнюю память, помимо памяти, расположенной внутри микроконтроллера. Сис-
тема в целом содержит только устройства ввода-вывода и микроконтроллер, что дела-
ет ее по внешнему виду отличной от блок-схемы компьютерной системы, представлен-
ной в главе 1. Однако, если вычертить микроконтроллер в стиле рис. 1.1, то будет два
блока - один для PIC и один для ввода-вывода.
Глава 2. Архитектура семейства PIC18 и разработка программ
41
Рис. 2.1. Простая микроконтроллерно-основанная система.
Каково назначение этой простой системы? Она могла бы использоваться для то-
го, чтобы, например, получать информацию от рабочих на производстве, а также функ-
ционировать как табелирующие часы. Рабочий, приходя на работу, может вставить
свою идентификационную карточку в оптический считыватель карточек и система заре-
гистрирует его идентификационный номер через последовательный интерфейс в уда-
ленном компьютере хост-системы. Хост-компьютер затем проверит допустимость
идентификационной карточки и отобразит сообщение "принято", сообщение об ошибке
или какую-либо иную информацию на ЖК-индикаторе. Эта система содержит два уст-
ройства ввода данных (клавиатуру и оптический считыватель карточек), устройство
вывода (ЖК-индикатор), и двунаправленное устройство ввода - вывода (последова-
тельный интерфейс с хост-компьютером).
PIC микроконтроллер содержит: память для хранения программ и данных, под-
ключения устройств ввода-вывода, формирующие интерфейс со считывателем карто-
чек, ЖК-индикатором, клавиатурой, последовательным интерфейсом (внутренним ин-
терфейсом контроллера), и также таймером, который может использоваться в качестве
часов реального времени и календаря системы. Такой уровень интеграции делает мик-
роконтроллер мощным и недорогим средством создания систем. Микроконтроллер PIC
стоит всего несколько долларов и может программироваться на Ассемблере, С,
БЕЙСИКЕ или Java.
Краткий обзор внутренней архитектуры PIC
Теперь, когда мы имеем некоторое представление о мощности PIC как контрол-
лера системы, мы должны понять внутреннюю структуру этого устройства. Как уже
упоминалось, PIC содержит память и центральный процессор. Он также содержит ком-
поненты формирования интерфейса ввода - вывода, необходимые для управления
устройствами системы. Прежде, чем вы сможете программировать микроконтроллер,
необходимо понять его внутреннюю структуру.
42
Применение микроконтроллеров PIC 18
Рис. 2.2. Внутренняя структура микроконтроллеров семейства Р1С 18
Рис. 2.2 изображает внутреннюю архитектуру семейства контроллеров PIC 18.
Обратите внимание, что эта внутренняя архитектура подобна блок-схеме компьютер-
ной системы, показанной на рис. 1.1. Основное различие заключается в том, что па-
мять в РЮ разделена в два различных раздела - один для хранения программы, а дру-
гой - для хранения данных. Эта архитектура называется гарвардской архитектурой,
изобретенной в 1944 для электромеханического компьютера (Mark 1), разработанного
Говардом Хатавеем Айкеном, который в 1947 сказал: "Только шесть электронных циф-
ровых компьютеров потребуется для того, чтобы удовлетворить вычислительные по-
требности всех Соединенных Штатов." Гарвардская архитектура делит память системы
на два раздела с тем, чтобы повысить ее эффективность. В традиционной архитектуре
системы фон Неймана данные и команды выбираются через ту же самую шину, что час-
то вызывает задержки всякий раз, когда команда манипулирует данными, записанными
Глава 2. Архитектура семейства PIC 18 и разработка программ
43
в памяти. Данные в памяти и получаемые оит устройств ввода-вывод - обычно 8 имеют
длину в восемь битов, в то время как команды часто имеют большую разрядность. В
гарвардской архитектуре, реализованной в PIC- микроконтроллерах, память данных и
шины ввода-вывода имеют разрядность в 8 битов, а память программ имеет разряд-
ность в 16 битов. Такая организация позволяет командам выбираться из памяти про-
граммы в одном цикле чтения или в рамках одной операции, что повышает эффектив-
ность системы. Обратите внимание, что PIC-микроконтроллеры некоторых семейств
используют 12-разрядную память программ, однако здесь рассматривается
16-разрядная память программ, реализованная в семействе PIC 18.
Вследствие того, что память программ и память данных разделены, выборка ко-
дов операций перекрывает выполнение команды, что повышает эффективность микро-
контроллера. Этот эффект называется конвейерным режимом, он иллюстрируется на
рисунке 2.3. Обратите внимание на то, что во время первого тактового цикла выполне-
ния команды, команда 1 извлекается из памяти, затем во время второго тактового цик-
ла выполнения команды команда 2 извлекается из памяти 2 параллельно с выполнени-
ем команды 1. Это перекрытие или конвейерный режим обеспечивает то, что большин-
ство команд выполняются за один тактовый цикл. Перекрытие извлечения команд из
памяти и выполнения происходит только в системах, которые имеют раздельную па-
мять программ и данных, используя гарвардскую архитектуру. Такие микропроцессо-
ры, как Pentium от Intel фактически внутренне используют эту архитектуру через кэш
данных и кэш программ, которые применяются для внутренней реализации конвейер-
ного режима и гарвардской архитектуры.
Память программ. Память программ имеет разрядность, равную 16 битов, при
этом каждая ячейка памяти в большинстве случаев содержит одну пословную команду.
Обратите внимание, что некоторые команды требуют 32 бита памяти или две последо-
вательные ячейки памяти, однако большинство команд являются 16-битными. Память
программ делится на две части: одна часть - это внутрисхемная память программ, а
другая - это внешняя память программ, которая устанавливается в случае необходи-
мости. Объем внутрисхемной памяти изменяется для различных членов семейства PIC
18, находясь в диапазоне от 4К до 128К. Внутрисхемная память программ - это либо
флэш-память, которая может многократно перепрограммироваться в семействе 18F,
либо однократно-программируемая память (ОПП) в семействе 18С. Флэш-память про-
грамм обычно программируется с использованием внешнего программатора, однако
во многих версиях микроконтроллеров она может быть самопрограммируемой. Если
она является самопрограммируемой, то устройство обычно имеет блок загрузки, со-
держащий обычно программу, называемую загрузчиком программы раскрутки, которая
не стирается и не перепрограммируется при перепрограммировании флэш-памяти.
Более подробно самопрограммирование и загрузчик программы раскрутки разбира-
ются в главе 10. Однократно-программируемая память со всех точек зрения аналогич-
но СППЗУ, за исключением того, что в ее микросхеме нет кварцевого окошка стирания,
в силу чего она не может быть перепрограммирована. Она программируется только
один раз. Табл. 2.1 перечисляет все имеющиеся в настоящее время устройства семей-
ства PIC 18 с указанием объема внутренней памяти, имеющегося в каждой.
44
Применение микроконтроллеров PIC 18
Период тактовой частоты 1 Период тактовой частоты 2 Период тактовой частоты 3 Период тактовой частоты 4 Период тактовой частоты 5
Команда Выполнение
Команда Выполнение
Команда Выполнение
Команда Выполнение
Рис. 2.3. Конвейерная обработка команд и их выполнение в микроконтроллере.
Таблица 2.1. Объем памяти программ в устройствах семейства PIC18.
Код изделия Объем памяти в байтах
1220, 1230,2220,4220 4К
1320, 1330,2320, 2331,4 320, 4331, 6310,6390,8310, 8390 8К
2439,4439 12К
242,248,442,2410,2420,2431,2480,4410,4420,4431,4480, 16К
6410, 6490, 8410, 8490 2455,2539, 4455,4539 24К
252,258,452,458,658,858,2510,2520,2550,2580,4510,4520, 32К
4550,6520,65J10,8520,85J10 2515, 2525, 2585, 4515, 4525, 4585, 4 8К
6525,6527,6585,65Л5,8525, 8527,8585,85Л5 2610,2 620,2680, 4610,4 620,4 680, 66Л0, 64К
6620,6621,6622,6680, 8620, 8621, 8622, 8680, 86J.10 6627, 66Л5,8627, 86Л5 96К
6720, 6722, 67Л0, 8720,8722, 87Л0 128К
Примечание: Всем цифровым обозначениям предшествует префикс PIC18F или
PIC18C; устройства PIC18F имеют флэш-память, а устройства PIC18C имеют одно-
кратно программируемую память (ОПП). Устройства PIC18C601 и PIC18C801 не
имеют внутренней памяти программ.
Память программ адресуется через 21-разрядный программный адрес, содержащий-
ся в регистре, который называется счетчиком команд. В главе 1 вы узнали, что
адрес памяти в 21 разряд (221) может адресовать 2М памяти. В семействе PIC18
пространство памяти программ начинается с адреса 0x000000 и простирается до
OxIFFFFF. Предположим,.что для использования в системе выбрано устройство
PIC18F4520. Данный микроконтроллер имеет 32К памяти программ, при этом пер-
вые 32К памяти программ, которые нумеруются в байтах, начинаются с адреса
0x000000 и простираются до адреса Ox007FFF. Из главы 1 вы должны помнить,
что 4К памяти требуют 0x1000 ячеек, следовательно объем памяти 32К требует
32К - 4К = 8 или 0x8000 ячеек памяти.
Глава 2. Архитектура семейства PIC18 и разработка программ
45
OxlFFFFF
внешняя
память
программ
внутрисхемная
память программ
0x000018
0x000008
0x000000
вектор низкоприоритетного
прерывания
вектор высокоприоритетного
________прерывания________
вектор сброса
Рис. 2.4. Карта памяти программ семейства PIC18.
Рисунок 2.4 иллюстрирует структуру памяти программ. Некоторым из ячеек памя-
ти поставлены в соответствие важные для системы задачи. Одной из таких выделенных
ячеек памяти является ячейка по адресу 0x000000, в которой расположен адрес векто-
ра сброса. Адрес вектора сброса - это тот адрес, по которому программа начинает вы-
полняться после сброса. Поскольку имеется только 8 байтов памяти между этой ячей-
кой и адресом вектора высокоприоритетного прерывания, расположенном в ячейке
памяти по адресу 0x000008, то обычно выполняется переход на другую ячейку памяти
для продолжения выполнения программы от адреса вектора сброса. Этот переход
обычно выполняется отработкой в программе команды безусловного перехода GOTO.
Адреса векторов прерываний, которые будут обсуждаться в главе 6, совместно с пре-
рываниями, указывают наточки входа в памяти программ процедур обслуживания низ-
ко- и высокоприоритетных прерываний. Остальная часть памяти программ доступна
для хранения программ, а также статических данных. Статическими данными являются
различные таблицы и константы, значение которых не изменяется. Они доступны для
использования программами.
Память данных. Память данных - это обычно СОЗУ или СОЗУ и ЭСППЗУ. Память дан-
ных (которую иногда называют регистровым файлом) предоставляет место для хране-
ния данных, которые изменяются по мере выполнения приложения и стираются (за
исключением ЭСППЗУ) после отключения электропитания системы. Доступ к памяти
данных СОЗУ осуществляется через использование 12-разрядных адресов, поэтому
максимальный объем доступной памяти равен 3968 байт с адресами от 0x000 до OxF7F.
46
Применение микроконтроллеров PIC 18
Память данных СОЗУ также содержит адреса, которые используются для программи-
рования специальных функций микроконтроллера. Эти специальные функциональные
регистры (СФР) расположены в диапазоне адресов памяти от OxF80 до OxFFF или за-
нимают верхние 128 байт пространства памяти данных. Некоторые исполнения микро-
контроллеров используют дополнительную память данных, предназначенную для раз-
мещения дополнительных СФР. Другие ячейки памяти программ называются общими
функциональными регистрами (ОФР), они размещены в диапазоне адресов от 0x000 до
OxF7F. ОФР иногда также называют ячейками регистрового файла.
Если микроконтроллер PIC содержит ЭСППЗУ, то память данных ЭСППЗУ адресу-
ется через специальные функциональные регистры в отдельном адресном пространст-
ве, выделенном ЭСППЗУ. Объем ЭСППЗУ определяется кодом исполнения PIC и имеет
диапазон от 0 байт до максимального количества, равного 1024 байт. Согласно
Microchip, ячейка ЭСППЗУ может перезаписываться вплоть до одного миллиона раз.
Ячейки ЭСППЗУ должны использоваться для хранения информации, которая не изме-
няется очень часто. Казалось бы, что возможность перезаписи миллион раз ячеек
ЭСППЗУ позволяет использовать его для любых целей, однако не следует забывать, что
микроконтроллер может функционировать на частоте порядка 40 МГц, при этом за не-
сколько секунд можно перезаписать ячейку ЭСППЗУ много миллионов раз. В табли-
це 2.2 перечислены различные устройства семейства PIC18 с указанием объема ОЗУ
или ЭСППЗУ, доступного для хранения данных в каждом из устройстве.
Память стека. В дополнение к памяти программ, памяти данных СОЗУ, а также памяти
ЭСППЗУ, имеется также небольшая объемом 31 х 21 бит память СОЗУ, которая называ-
ется памятью стека. Память стека, как это будет обсуждаться в последующих подраз-
делах, содержит только адреса возврата из функций. Разрядность стека равна 21 би-
там, поскольку он рассчитан на хранение адресов памяти программ. Поскольку макси-
мальный объем памяти программ равен 2М байт, то для доступа к ней нужно использо-
вать 21-битный адрес, т.е. стек должен иметь разрядность в 21 бит. Почему он имеет
глубину в 31 ячейку? Просто Microchip решила, что стек глубиной в 31 достаточно велик
для обеспечения работы большинства приложений. Единственный способ использо-
вать ячейку стека заключается в вызове функции. Если функция вызывает другую функ-
цию, то две ячейки стека будут использоваться для хранения адресов возврата. Для
использования всех ячеек стека нужно чтобы глубина многократных вызовов функций
достигла 31, что бывает крайне редко, если вообще бывает. Фактически единственный
случай переполнения стека может иметь место тогда, когда в программе присутствует
ошибка, приводящая к постоянному вызову функций, возврат из которых не отрабаты-
вается. Рекурсия является единственной возможной причиной этого типа ошибки.
Вследствие этого при разработке рекурсивных программ этому вопросу необходимо
уделять внимание.
Таблица 2.2. Память данных СОЗУ и ЭСППЗУ в различных исполнениях устройств семейства 18F
Код изделия Объем ОЗУ в Объем ЭСППЗУ в
байтах байтах
1230,1330 256 128
1320 256 256
2220,2320,4220,4320 512 256
2439,4439 640 256
2410,4410,6310,6390, 6410,6490, 8310, 768 0
8390,8410,8490 242,248,442,448,2331,2420, 2431, 4331,4420,4431,4480 , 2480, 768 256
Глава 2. Архитектура семейства PIC18 и разработка программ
47
Объем ОЗУ в Объем ЭСППЗУ в
Код изделия байтах байтах
2539,4539 1408 256
2510,4510 1536 0
252, 258, 452, 458, 601, 658,801, 858,2520, 2580,4520, 4580 1536 256
65J10, 65J15, 66J10,85J10,85J15,86J10 2048 0
2455, 2550,4455,4550 2048 256
6520, 8520 2048 1024
2585, 2680, 4 585, 4 680, 6585, 6680,8585, 8680 3328 1024
6525,6620,6621,6720,8525,8620, 8621, 8720 3840 1024
2515, 2610, 4515,4610, 66J15,67J10,86J15, 87J10 3968 0
2525,2620,4525,4620,6527,6622,6627, 6722, 8527, 8622,8627,8722 3968 1024
Примечание: Ни одно из исполнений 18С не содержит ЭСППЗУ. Указанное количество
ячеек не включает пространство СФР
Порты ввода-вывода. Порты ввода-вывода используются для обеспечения взаимо-
действия микропроцессора с внешним миром. Каждый порт ввода-вывода обычно
имеет разрядность в 8 битов и может быть запрограммирован как на ввод, так и на вы-
вод информации. Количество битов и портов ввода-вывода колеблется для различных
устройств семейства PIC18 и в общем случае определяется количеством выводов инте-
гральной схемы. Таблица 2.3 перечисляет количество выводов ввода-вывода, присут-
ствующих в различных устройствах семейства PIC18. В данной таблице указано коли-
чество битов портов, однако при программировании микроконтроллера порты органи-
зуются как порт А для первых восьми битов, порт В для следующих восьми битов и так
далее. Например, 18F1320 имеет только порты А и В. Программирование портов ввода-
вывода выполняется через специальные функциональные регистры, размещенные на
вершине пространства памяти данных по адресам от ОхР80 до OxFFF.
Структура ввода-вывода для различных устройств рассматриваемого семейства
колеблется в широких пределах, однако все устройства имеют по крайней мере порт А
и порт В. В первых нескольких главах этой книги приведены примеры программ, ис-
пользующих порт А и В. При проведении экспериментов с базовыми функциями ввода-
вывода этих двух портов рекомендуется использовать реальную панель разработчика.
То, какую систему разработки программ выбрать при проведении экспериментов, дол-
жен решить преподаватель. Может быть использована любая из систем разработки,
предлагаемых Microchip или любой иной фирмой. В первых главах этой книги предпо-
лагается, что используется порт ввода-вывода, оснащенный, по крайней мере, четырь-
мя светодиодами и несколькими переключателями. В последующих главах будут ис-
следоваться дополнительные модули ввода-вывода как в составе PIC, так и в составе
иных устройств.
Таблица 2.3. Подключение портов ввода-вывода
в различных устройствах семейства PIC18
Код устройства Биты портов ввода-вывода
1220,1230,1320,1330 16
2439,2539 21
258,2331,2431 22
242,248,252,258,1320,2220 23
601 С 31
4439,4539 32
442, 448, 452, 458, 4220, 34
4320, 4331, 4420, 44 31,44 55, 4550
48
Применение микроконтроллеров PIC 18
Код устройства Биты портов ввода-вывода
4220, 4320, 4410, 4480,4510,4 515, 4520, 4525,4580,4585, 4 36
610,4620, 4680 801 42
6390, 6490, 65J10,65J15, 66J10, 66J15, 67Л0 50
658,6520,6620,6720 52
6525,6585,6621,6680 53
6310,6410,6527,6622,6627,6722 54
8390, 84 90, 85J10,8 6J10, 86 Л 5 66
858,8520,8620,8720 68
8525,8585,8621,8680 69
8310,8410,8527,85Л5,8622,8627,87Л0 70
8722 72
Таблица 2.4. Таймеры в устройствах семейства PIC18
Код изделия 8-битные таймеры 16-битные таймеры
С242, С252, С442, С452 3 1
1230,1330 0 2
2439,2539,4439,4539 0 3
242F, 248,252F, 258,448,452F, 458, 601, 658, 801,858,1220, 1320,2220,2320,2331,2410,2420,2431,2455,2480,2510, 2515,2520,2525,2550,2580,2610,2620,2680,4220,4320, 4331,4410,4420,4431,4455,4480,4510,4515,4520,4525, 4550,4580,4585,4610,4620,4680,6310, 6390, 6410, 6490 1 t 3
8310,8390,8410,8490 6520, 6525, 6527, 6585, 65Л0, 65Л5, 6620, 6621,6622, 6627 , 2 3
6680, 66Л0, 66Л5, 6720, 6722, 67Л0, 8520, 8525, 8527, 85Л0,85Л5, 8620, 8621, 8622, 8627, 8680, 86Л0, 86Л5, 8720, 8722,87Л0 8585,
Использование порта для простого ввода-вывода является весьма легкой зада-
чей. Регистр TRISA определяет направление (ввод или вывод) для каждого штырька
порта A. (TRISA предназначен для порта A, TRISB - для порта В, и так далее). Регистр
TRIS порта - это регистр направления перемещения данных порта. После того как мик-
роконтроллер сбрасывается, регистры TRIS устанавливаются на операцию вывода.
Это защищает схемы, подключенные к выводам порта ввода-вывода. Логический ноль
бита регистра TRISA устанавливает соответствующий бит порта А на вывод информа-
ции, а логическая единица в бите устанавливает соответствующий бит порта А на ввод
данных. Например, для программирования битов порта А от 0 до 3 (эти биты обознача-
ются от RAO до RA3) в качестве выходных битов, а битов порта А от 4 до 7 (эти биты
обозначаются от RA4 до RA7) в качестве входных битов, в регистр TRISA необходимо
загрузить OxFO.
Как только направление перемещения данных для битов порта будет запрограм-
мировано, доступ к этому порту можно осуществлять по его имени. Регистр PORTA ис-
пользуется для организации информационного обмена с портом А. Например, если в
регистр PORTA записано значение 0x28 штырьки PORTA (если они запрограммированы
как выходные) будут принимать данные. Аналогичным образом, для считывания данных
со штырьков порта А выполняется считывание регистра PORTA. Также является воз-
можным получить доступ к одному штырьку порта А, как это описано в последующих
подразделах, используя директиву PORTAbits языка С.
Глава 2. Архитектура семейства PIC18 и разработка программ
49
Таймеры. Таймеры представляют собой программируемые модули счетчиков. Таймер
может подсчитывать события и импульсы тактовой частоты, он также может выполнять
целый ряд сервисных функций для программ. Таймеры часто программируются на от-
работку тайм-аута по прохождении определенного количества тактовых импульсов.
Различные устройства семейства PIC имеют от двух до пяти таймеров. В табл. 2.4 пере-
числены различные устройства семейства PIC 18 с указанием количества имеющихся в
них таймеров.
Таймеры используются в микропроцессорах для генерации различных событий, -
от прерываний с периодической частотой до реализации счетчиков реального времени
при определении значения частоты или счете событий. Таймеры также используются
для генерирования сигналов для других устройств в системе. Более подробно таймеры
будут рассматриваться позже при обсуждении внутреннего ввода-вывода и его исполь-
зования в различных применениях.
Другие внутренние устройства ввода-вывода. Различные модели устройств семей-
ства PIC 18 также содержат другие устройства ввода-вывода, которые программируют-
ся через специальные функциональные регистры (СФР). Эти другие устройства могут
включать аналого-цифровые преобразователи (АЦП), широтно-импульсные (ШИМ)
модуляторы, а также последовательные коммуникационные порты ряда других типов.
Поскольку нам еще предстоит рассмотрение программирования PIC 18, эти внутренние
устройства ввода-вывода пока нами еще не рассматривались, однако они будут под-
робно рассмотрены с иллюстрацией на примерах позже в этой книге.
В общем случае порты ввода-вывода программируются через регистр TRIS. Ре-
гистр TRIS определяет направление штырьков ввода-вывода (ввод или вывод) для дан-
ного порта. Если бит регистра TRIS установлен в состояние логического нуля, то соот-
ветствующий бит порта программируется как выходной штырек. Если бит регистра TRIS
установлен в состояние логической единицы, то соответствующий бит порта програм-
мируется как входной штырек. Каждый порт имеет свой регистр TRIS. Они обозначают-
ся как TRISA для порта A, TRISB для порта В, и так далее. Данные считываются или за-
писываются через регистр PORT. При этом PORTA используется для порта A, PORTB
используется для порта В и так далее. Для выбора аналогового или цифрового режима
работы штырька для аналого-цифрового преобразователя используется регистр
ADCON1, специфицирующий, какие штырьки порта А и порта В будут цифровыми или
аналоговыми. По умолчанию устанавливается аналоговый режим работы.
2.2. Модель программирования
Перед программированием микроконтроллера необходимо ознакомиться с на-
бором внутренних файловых регистров, доступных для программиста. Этот набор ре-
гистров управляет микроконтроллером. Микроконтроллер - это 8-битное устройство,
поэтому многие регистры имеют разрядность, равную 8 либо кратную 8. Рис. 2.5 де-
монстрирует обобщенную модель программирования микроконтроллеров семейства
PIC18. На нем изображены регистры, наиболее часто используемые при программиро-
вании большинства команд. На нем не приведены все специальные функциональные
регистры, которые осуществляют управление устройствами ввода-вывода и функция-
ми ЦП. Эти остиальные специальные функциональные регистры будут обсуждаться,
наряду с устройствами ввода-вывода позднее в последующих главах.
50
Применение микроконтроллеров PIC 18
Регистровый файл
Область регистрового файла или память данных, размещенная во внутрисхем-
ном СОЗУ, представляет собой набор 8-битных регистров общего назначения (РОН),
используемых для хранения динамических данных. Как уже отмечалось ранее, различ-
ные модели устройств семейства PIC18 содержат различный объем памяти данных,
при этом все модели содержат, по крайней мере, адреса общего регистрового файла
от 0x000 до Ox07F, плюс специальные функциональные регистры от OxF80 OxFPP или
256 байт СОЗУ.
основные
специальные
функциональные
регистры
8 битов
Примечание
Примечание: счетчик команд является внутренним физическим 21-битным регистром, который
не может адресоваться.
Рис. 2.5. Обобщенная модель программирования микроконтроллеров семейства PIC18
Глава 2. Архитектура семейства PIC 18 и разработка программ
51
Доступ к регистровому файлу осуществляется через 12-разрядный адрес, 4
старшие разряды которого содержат адрес банка памяти. Каждый банк памяти данных
содержит 256 байтов памяти данных. Банк данных 0 (00002) содержит регистры от
0x000 до OxOFF, банк данных 1 (0001;) содержит регистры от 0x100 до OxIFF и т.д. Во
многих случаях при программировании используются адреса от 0x000 до Ox07F банка
данных 0 и адреса от OxF80 до OxPFF банка данных 15. Эти области памяти вместе на-
зываются банком доступа. Банк доступа адресуется без использования регистра банка
данных, поэтому доступ к нему из программы осуществляется легче и более эффектив-
но. (Названное разделение банка доступа может изменяться в различных устройствах
семейства PIC18. Так, например, в PIC 18F2480, используются адреса от 0x00 до Ox5F
из банка данных 0 и адреса от OxF60 до OxFFP для специальных функциональных реги-
стров.) Банк доступа адресуется с использованием одного 8-разрядного адреса. Для
доступа к ячейкам памяти в ОЗУ данных вне банка доступа используется комбинация
8-разрядного адреса и 4-разрядного регистра выбора банка (РВБ). Например, для
адресации ячейки 0x432, адрес банка будет равен 4, а 8-разрядный адрес памяти будет
равен 0x32. Бит команды, который называется a-битом, выбирает банк доступа (когда
а = 0) или же банк, указываемый регистром выбора банка (когда а = 1). Как, например,
осуществить доступ к ячейке 0x092? Она находится вне банка доступа, поэтому единст-
венный способ адресовать ячейку 0x092 заключается в адресации ее при регистре вы-
бора банка, установленном в 0 и 8-разрядном адресе 0x92 при a-бите, установленном в
1. Рисунок 2.6 демонстрирует адресацию банка доступа и банка данных.
Специальные функциональные регистры
Специальные функциональные регистры (СФР) используются для выполнения
целого ряда специальных задач в микроконтроллере. Регистр выбора банка является
одним из этих специальных функциональных регистров, при этом остальные специаль-
ные функциональные регистры осуществляют доступ к памяти непрямо, сохраняя про-
изведение после умножения, указывая состояние выхода команды, аккумулируя ре-
зультаты арифметических и логических операций и адресуя ячейку памяти в програм-
ме. Все специальные функциональные размещаются на вершине памяти данных в бан-
ке доступа. Все специальные функциональные регистры имеют имена и адреса, - и то и
другое может быть использовано для доступа к ним.
Аккумулятор (WREG). Аккумулятор или, как он часто называется, рабочий регистр
(регистр W или WREG) представляет собой 8-разрядный регистр, доступ к которому
осуществляют многие команды. Вероятнее всего, что этот регистр называется аккуму-
лятором вследствие того, что он представляет собой место, в котором аккумулируются
результаты многих команд. Большинство ЦП содержат аккумулятор в качестве главного
рабочего регистра. В семействе PIC18 рабочий регистр (WREG) размещен в области
специальных функциональных регистров по адресу OxFE8. Хотя этому регистру и при-
своен адрес, многие команды осуществляют доступ к нему без указания адреса - по
имени или неявно в рамках выполнения команды. Эта неявная форма адресации и есть
то, почему WREG называется рабочим регистром или аккумулятором. Литеральный или
непосредственный адрес команд адресует WREG как часть команды без необходимости
специфицирования его адреса. Многие другие команды также используют регистр W.
52
Применение микроконтроллеров PIC 18
(а) если а-бит = 0 (банк доступа)
OxFFF
0xF80
8-разрядный адрес
0x12
0x000
(Ь) если а-бит = 1 (выбор банка)
OxFFF
0x32F
0x000
Рис. 2.6. Выбор банка регистрового файла
Глава 2. Архитектура семейства PIC18 и разработка программ
53
Регистр выбора банка (BSR). Регистр выбора банка (размерность которого равна
4 бита) плюс 8-битный адрес объединяются с целью формирования 12-разрядного ад-
реса памяти данных, когда a-бит команды находится в состоянии логической единицы,
как это иллюстрируется на рис. 2.6. Это позволяет осуществлять доступ к любому реги-
стру в любом банке памяти данных. Если a-бит команды находится в состоянии логиче-
ского нуля, то доступ будет ограничен банком доступа, который обычно составляется
из ячеек с адресами от 0x000 до Ox07F ячеек от OxF80 до OxPPF. 8-разрядные адреса
от 0x00 до Ox7F выбирают ячейки памяти данных от 0x000 до Ox07F, 8-разрядные адре-
са от 0x80 до OxFF выбирают ячейки памяти данных от OxF80 до OxFFF банка доступа.
Это описание применимо к стандартному набору команд. (Если выбран расширенный
набор команд, банки и a-бит не функционируют описанным образом. Подраздел гла-
вы 10 детально описывает расширенный набор команд. До этого момента в тексте дан-
ной книги предполагается, что используется стандартный набор команд.) Смотрите
рис. 2.7 для описания битовой структуры побайтно-ориентированных команд и разме-
щения а-бита. Также обратите внимание на то, что другой бит, называемый d-битом
или битом адресата, выбирает, является ли адресатом команды 8-разрядный адрес
(когда d = 1) или регистр WREG (когда d = 0).
15 10 9 8 7 О
d=l - адрес памяти данных
Рис. 2.7. Двоичная битовая структура команды байтовой операции,
иллюстрирующая месторасположение а-бита.
Пример 2.1 иллюстрирует первую короткую последовательность команд на языке
Ассемблера PIC, которые складывают 6 и 2 и сохраняют сумму в регистре данных банка
доступа по адресу 0x000. Вспомните, что эта же задача уже рассматривалась в главе 1.
Как это выполняется? Во-первых, литеральная команда (MOVLW) помещает 0x06 в
WREG. Команда MOV на самом деле ничего не перемещает. Этот факт приводил в за-
мешательство начинающих программистов на протяжении многих лет. Команда MOV
выполняет КОПИРОВАНИЕ. MOV копирует 6 в регистр W. Буква L в команде указывает
на литерал, а буква W указывает регистр WREG. Следовательно, MOVLW копирует лите-
ральное значение в регистр W. Литеральные команды используются тогда, когда про-
грамме необходима константа известного значения. Вторая команда является другой
54
Применение микроконтроллеров PIC 18
литеральной командой. Команда ADDLW добавляет 0x02 (указывается в команде) к зна-
чению 0x06 во WREG с целью формирования суммы 0x08 в регистре W. (Обратите вни-
мание на то, что сумма аккумулируется в аккумуляторе или регистре W). И, наконец,
побайтно-ориентированная команда move (MOVWF) переносит результат из регистра W
в регистр памяти данных 0x000. Буква F в команде MOVWP обозначает ячейку регистро-
вого файла. Это означает, что MOVWF копирует содержимое WREG в ячейку регистро-
вого файла, в данном случае ячейку с адресом 0x00. Обратите внимание на то, что по-
сле команды MOVWF указываются два числа. Первое - это ячейка регистрового файла,
а вторая - а-бит (в данном примере - 0, в силу чего адресуется банк доступа). В качест-
ве альтернативы, может использоваться ключевое слово ACCESS (пишется заглавными
буквами) вместо 0 для второго параметра, как, например: MOVWF 0x00, ACCESS. Эта
запись отчетливо более читабельна, однако требует большего объема ввода с клавиа-
туры, в силу чего многие программисты не вводят слово ACCESS в программу, а просто
вводят ноль.
Пример 2.1
MOVLW 0x06 /помещает 0x06 в W
ADDLW 0x02 /добавляет 0x02 до W
MOVWF 0x00, 0 /копирует W для доступа к регистру банка 0x00
ИЛИ другая версия с использованием ключевого слова ACCESS
M0VLW 0x06 / помещает 0x06 в W
ADDLW 0x02 / добавляет 0x02 до W
MOVWF 0x00, ACCESS/ копирует W для доступа к регистру банка 0x00
Код операции - это код, который инструктирует микроконтроллер выполнить ка-
кую-то операцию. В примере 2.1, литеральные данные 0x06 помещаются во WREG ко-
дом операции MOVLW.
Литеральные данные называются операндом. Операнд используется в соответ-
ствии с кодом операции. Команда имеет только один код операции, однако может как
не иметь операнда, так и иметь столько операндов, сколько требуется командой.
Предположим, что нужно выполнить ту же операцию, что и в примере 2.1, однако
вместо помещения результата в регистр данных 0x000, результат должен быть поме-
щен в регистр данных 0x200. Адрес 0x200 находится в банке 2 памяти данных. Команд-
ная последовательность, приведенная в примере 2.2, выполняет эту операцию посред-
ством использования регистра выбора банка (РВБ) для адресации банка командой
MOVLB (перемещение литерала в РВБ). Обратите внимание, как второй операнд (а-
бит) команды MOVWP обозначает регистр выбора банка для команды вместо банка
доступа. Вследствие того, что команда обычно (по умолчанию) помещает данные в
ячейку банка данных, 1 в команде MOVWF 0x00 может опускаться. В качестве альтерна-
тивы 1 при доступе к банку данных может быть использовано ключевое слово BANKED.
Все три версии программы решают одну и ту же задачу.
Пример 2.2 M0VLW 0x06 ADDLW 0x02 MOVLB 2 MOVWF 0x00, 1 /помещает 0x06 в W /добавляет 0x02 к W /загружает BSR банком /копирует W в регистр /банка 2 или адресует 2 данных 0x00 0x200
ИЛИ используя ключевое слово BANKED:
MOVLW 0x06 /помещает 0x06 в W
Глава 2. Архитектура семейства PIC18 и разработка программ
55
ADDLW 0x02 /добавляет 0x02 к W
MOVLB 2 ,загружает BSR банком 2
MOVLF 0x00, BANKED /копирует W в регистр данных 0x00
/банка 2 или адресует 0x200
ИЛИ без указания банка
MOVLW 0x06 /помещает 0x06 в W
ADDLW 0x02 /добавляет 0x02 к W
MOVLB 2 /загружает BSR банком 2
MOVWF 0x00 /копирует W to регистр । данных 0x00
/банка 2 или адресует 0x200
В предыдущем подразделе были изложены вводные сведения о простом вводе-
выводе. Предположим, что в нашем распоряжении имеется система разработки, кото-
рая имеет два светодиода, подключенные к битам 0 и 1 порта А. (Это штырьки RAO и
RA1.) Задача заключается в том, чтобы поместить 0 в бит 0 и 1 в бит 1. Это выполняется
посредством программирования регистра ADCON1 на цифровые штырьки, в регистре
TRISA устанавливаются нули в младших разрядах 0 и 1, а затем передается 0x02 в ре-
гистр PORTA. Пример 2.3 показывает соответствующую последовательность команд.
Для команды MOVWF бит банка доступа не требуется при использовании поименован-
ного специального функционального регистра - такого как TRISA или PORTA. Имя по-
именованного регистра должно записываться заглавными буквами.
Пример 2.3
MOVLW 0x7F MOVWF ADCON1
MOVLW 0x00
MOVWF TRISA
MOVLW 0x02 MOVWF PORTA
/выбирает для портов все цифровые штырьки
/помещает 0x00 в регистр направления порта А
/для выбора операции вывода
/ помещает 0x02 в порт А
Регистры произведения. Регистры произведения содержат результат или произве-
дение после выполнения команды умножения. Для произведения нужен специальный
регистр, ибо произведение всегда имеет вдвое больше разрядов, чем операнды. Это
справедливо даже для десятичной системы - например, когда число 5 умножается на 5.
Результат 25 имеет вдвое больше разрядов, чем 5. Команда MULLW умножает регистр
W на литеральное значение. Поскольку это 8-битный микроконтроллер и произведение
- восьмиразрядное, то результат будет иметь 16 разрядов и будет сохранен в регистрах
PRODL и PRODH. Регистр PRODL хранит младшие 8 битов результата (L означает “low”
(младшие)), а регистр PRODH хранит старшие 8 битов результата (Н означает “high”
(старшие)). Упомянутые числа всегда будут беззнаковыми, потому что в наборе команд
микроконтроллера отсутствует команда умножения чисел семейство знаком.
Пример 2.4 показывает то, как 3 на 100 десятичное и как произведение сохраня-
ется по адресам 0x010 и 0x011. Десятичные числа в программах на Ассемблере обо-
значаются тем, что им предшествует точка. Обратите внимание на то, что результат
сохраняется с использованием формата с обратным порядком байтов, когда младшая
часть произведения сохраняется в регистре данных 0x010, а старшая часть произведе-
ния - в регистре данных 0x011. Команды MOVFF копируют результат в ячейки с адреса-
ми 0x010 и 0x011. Команда MOVFF (перемещение регистрового файла в регистровый
файл) допускает копирование любого регистра данных в любой регистр данных. Ко-
манда MOVFF не использует разбиение памяти на банки. После выполнения данной
программы регистр данных 0x010 будет содержать Ох2С, а регистр данных 0x011 будет
содержать 0x01. 0x12С равно 30010. Но где же a-бит? Команда MOVFF является
56
Применение микроконтроллеров PIC 18
32-битовой командой, которая не имеет а-бита. Вместо этого, она имеет битовое про-
странство, достаточное для хранения как адреса-источника, так и адреса-приемника в
32 битах. Адрес имеет 12 разрядов, поэтому только 24 бита из 32 используются для
хранения адресов; остальные биты используются для хранения численного кода опера-
ции команды.
Пример 2.4
MOVLW 3 ;помещает 3 в W
MULLW .100 ,умножает на 100 десятичное
MOVFF PRODL, 0x010 /сохраняет младшую часть произведения в 0x010
MOVFF PRODH, 0x011 ; сохраняет старшую часть произведения в 0x011
Регистры выбора файла (FSR). Регистры выбора файла используются для косвенной
адресации или индексирования памяти данных. Устройства семейства PIC18 содержат
три регистра выбора файла (FSRO, FSR1 и FSR2), каждый из которых содержит
12-разрядный адрес памяти данных. Для иллюстрации того, как работают регистры
FSR, смотрите пример 2.5, в котором выполняются те же операции, что и в примере 2.4.
Разница состоит в том, что в примере 2.5 регистр FSRO индексирует (адресует) реги-
стры данных 0x10 и 0x11. Команда LFSR 0, 0x10 загружает PSRO значением 0x10. Вся-
кий раз, когда регистр выбора файла адресует память, операнды INDFO, INDF1 или
INDF2 используются в программе для специфицирования косвенных адресов 0, 1 или 2.
(INDFO использует FSRO, INDF1 использует FSR1 a INDF2 использует FSR2). Ключевое
слово POSTINCO (пост-инкрементирование FSRO) в команде MOVFP добавляет едини-
цу к FSRO после его использования для адресации ячейки памяти данных. POSTING 1
добавляет 1 к FSR1, a POSTINC2 добавляет 1 к FSR2.
Пример 2.5
M0VLW 3
MULLW 0x64
LFSR 0,0x010
MOVFF PRODL, POSTINCO
MOVFF PRODH, INDFO
;помещает 3 в W
/умножает на 100
/адресует ячейку 0x010 через FSRO
/сохраняет младшую часть произведения,
инкрементирует FSRO
/сохраняет старшую часть произведения по адресу
0x011
Регистр состояния (SR). Регистр состояния (SR) индицирует состояние результата
операции. Биты регистра состояния часто проверяются в программах после выполне-
ния операции. Рис. 2.8 иллюстрирует содержимое регистра состояния. Только пять из
восьми битов индицируют состояние; они обозначаются как N (отрицательность), 0V
(переполнение), Z (ноль), DC (перенос разряда) и С (перенос). Биты состояния прове-
ряются командами условного перехода, которые наиболее часто используются для
формирования конструкций if-then-else при программировании, а также других про-
граммных конструкций. Биты регистра состояния обычно изменяются в устройствах PIC
только арифметическими и логическими операциями.
• N (отрицательность) - бит отрицательности имеет значение логической 1, если
результат арифметической или логической операции отрицателен и значение логиче-
ского нуля, если результат положителен.
• 0V (переполнение) - бит переполнения имеет значение логической 1, если
арифметическая операция привела к переполнению 8-разрядного результата семейст-
во знаком.
Глава 2. Архитектура семейства PIC18 и разработка программ
57
4 3 2 1 0
N OV Z DC С
перенос
--------0 = переноса нет
1 = перенос
перенос разряда
------------0 = переноса нет
1 = перенос
ноль
0 = нуля нет
1 = ноль
____________________переполнение
0 = переполнения нет
1= переполнение
_____________результат отрицател ьн ы й
0 = результат положительный
1 = результат отрицательный
Рис. 2.8. Регистр состояния
• 2(ноль)~ бит нуля находится в состоянии логической единицы, если результат
арифметической либо логической операции является нулевым. Если результат не яв-
ляется нулевым, то бит нуля находится в состоянии логического нуля.
• DC (перенос разряда)- бит переноса разряда индицирует половинный перенос.
Он содержит перенос из младшей части результата (4 бита), а также старшей полови-
ны байта (4 bits) и используется только командой DAW.
• С (перенос)- бит переноса регистра состояния содержит перенос из самого
старшего бита результата.
Счетчик команд (PC). Счетчик команд, хотя и не является непосредственно адресуе-
мым, как SR, является очень важным регистром. Счетчик команд в устройствах семей-
ства PIC18 представляет собой 21-разрядный регистр, он адресует следующую ячейку
памяти в памяти программ и позволяет осуществлять последовательный доступ к ко-
мандам в памяти программ. Счетчик команд является счетчиком, однако он не считает
команды программы. Он считает адреса памяти, чтобы обеспечить доступ к следую-
щей команде программы, что, вероятно, и привело к тому, что он называется сччетчи-
ком команд. В некоторых процессорах этот регистр называется регистром адреса ко-
манды (IAR).
Последовательность выполнения команд программы модифицируется, если со-
держимое счетчика команд изменяется. Для изменения содержимого счетчика команд
команда GOTO или команда условного перехода заносит новое значение в счетчик ко-
манд, что приводит к изменению последовательности выполнения команд программы.
Функции CALL и RETURN также изменяют содержимое счетчика команд. Функция CALL
помещает адрес возврата (адрес команды, следующей непосредственно после CALL) в
стек, а затем выполняет команду GOTO. Функция RETURN извлекает адрес возврата из
стека и помещает его в счетчик команд. Это приводит к тому, что следующей выполня-
ется команда, следующая непосредственно после CALL.
58
Применение микроконтроллеров PIC 18
2.3. Интегрированная система разработки (IDE)
Прежде, чем двигаться дальше, нам необходимо ознакомиться с интегрирован-
ной системой разработки для микроконтроллеров PIC. IDE позволяет осуществлять
разработку и написание программ как на языке Ассемблера, так и на языке С. Она так-
же позволяет выыполнять тестирование и имитацию выполнения программ с использо-
ванием инструментальных средств отладки, включенных в IDE. Микроконтроллер может
программироваться, если программатор подключен к IDE либо схемно эмулироваться,
если к IDE подключен эмулятор. IDE - это законченная система разработки программ
для микроконтроллеров PIC, она может служить также прекрасным средством обучения
ввиду интегрированных в нее возможностей отладки.
MPj.AB il)t. *7.10 - FileslMicrochipiMPASM SuitcUempIdleWbjecUI32О1тр».<ит*|
* Ffe Edfc View Project Debugger Programmer Took Corflgure Window Help
О И ' - В Ф ® Checksum! foccMs | 14 W Ц |
jnovtf BSS_TKHP,BSR ;rssscur* SSE; register
шм» jaovff VRSG-IBKP.VklG ;restore working register
»ovff STATUS-!SHE’,STATUS ;restore STATUS register
rotfie
' ♦ *»***»•»**»«* wt* *•****»«•**«••«**«•*** *•****•*••<*#«••***•*****•**
of am.
•. z ТЬа proerrsna ooiia as pAacad hare.
Магл:
' ; *** aain code goes here ***
J
_ raoxlw 3
nuXlw 0x64
Iter 0,0x10
♦ raovft ТФ0&1», POSTM'O
Movff PStODHf XWJO
s 'salt; goto wa.it-
;Xnd oi pragraa.
Рис. 2.9. Снимок экрана IDE для микроконтроллеров PIC
Обзор IDE
Рис. 2.9 демонстрирует снимок экрана IDE для микроконтроллеров PIC, которая
может быть бесплатно выгружена по адресу http://www.microchip.com. Этот Windows-
базированный интерфейс легко использовать для создания и отладки программ. Также
является возможным имитировать выполнение программ в ПК при помощи имитатора,
который является частью IDE. Кроме того могут использоваться аппаратные эмулято-
ры, управляемые от IDE и обеспечивающие более точную имитацию в масштабе реаль-
ного времени.
Для использования IDE для создания проекта первый шаг заключается в выборе
микроконтроллера, используемого в проекте, по его типу. Это выполняется щелчком на
Глава 2. Архитектура семейства PIC18 и разработка программ
59
позиции Configure (Конфигурировать) в меню, имеющемся в верхней части экрана IDE.
Далее нужно щелкнуть на позиции Select Device . . . (Выбор устройства) в появившем-
ся разворачивающемся меню. Теперь на экране развернется диалоговое окно, пока-
занное на рис 2.10. Выберите микроконтроллер, который будет использоваться в теку-
щем проекте из списка устройств. Эти действия сконфигурируют IDE на тот тип микро-
контроллера, который будет использоваться в проекте, - они должны быть выполнены
прежде всего, чтобы обеспечить правильную работу IDE.
Еще несколько шагов требуются для выполнения полной инициализации IDE. Так,
найдите и щелкните на позиции Project (Проект) меню и выберите позицию Project
Wizard (Мастер проектов) в разворачивающемся меню. Появится диалоговое окно,
показанное на рисунке 2.11.
Рис. 2.10. Выбор микроконтроллера для IDE.
В окне мастера проектов щелкните на кнопке Next (Далее). Появится диалоговое
окно, показанное на рис. 2.12. Опять выберите микроконтроллер, который будет ис-
пользоваться в проекте. Это, конечно, избыточная операция, однако все же необходи-
мо вновь указать микроконтроллер в меню Device Select (Выбор устройства).
На следующем шаге диалога (см. рис. 2.13) необходимо выбрать набор инстру-
ментальных средств, который будет использоваться при разработке программного
обеспечения микроконтроллера. В данном случае выбрана позиция Microchip
MPASM Toolsuite (Набор инструментальных средств Microchip MPASM), обеспечи-
вающая возможность разработки для проекта программ на языке Ассемблера
(см. рис. 2.13). MPASM - это ассемблер от фирмы Microchip для устройств PIC. Инди-
цируемые наименования путей файлов должны быть корректными - они не нуждаются в
модификации, если IDE была правильно установлена.
60
Применение микроконтроллеров PIC 18
& Welcome!
Project Wizard
This wizard helps you create and configure a new MPLAB
project.
То continue, click Next.
R-v-k f.......f ' Help......] -
Рис. 2.11. Окно мастера проектов IDE
Рис. 2.12. Выбор микроконтроллера
Глава 2. Архитектура семейства PIC18 и разработка программ
61
Active!oolsuite: :MicrochipMPASM Toolsuite V
F oolsuite Contenh
M PAS M Assembler fmpasmwh exel
,t MPLINK Object Linker (rnplink.exe)
i MPLIB Librarian (mplib.exe)
Location - •' - - - -
|C:\PfografflFite$\MicrccTiip\MPASM Suit^MPAsn^/ne:^
Helpl My Suite IsnT Listed! | Q show a# installed toolsiates
I < Back Next> 1 { Cancel I I Help |
Рис. 2.13. Меню выбора комплекта инструментальных средств
Рис. 2.14. Меню имени проекта
62
Применение микроконтроллеров PIC 18
Следующее диалоговое окно запрашивает имя проекта и пути файлов, как эго по-
казано на рис. 2.14. Задайте имя проекта, которое описывает проект, разрабатывае-
мый вами в текущий момент времени.
Последний и наиболее сложный шаг связан с выбором файлов компоновщика для
микроконтроллера, а также выбором файла шаблона программы, чтобы программа
могла быть написана. Рис. 2.15 демонстрирует снимок экрана для данного последнего
этапа настройки IDE на разработку программ для текшего проекта. Для выполнения
этого найдите каталог с именем Microchip; наиболее вероятно, что он расположен в
каталоге Program Files на диске С. Откройте в каталоге Microchip папку с именем
MPASM Suite (комплект инструментальных средств MPASM). В этой папке найдите во
вложенной папке Object folder (Папка объектов) файл шаблона для микроконтроллера,
используемого в проекте. Этот файл должен иметь имя типа, например, 1320tmpo.asm,
что соответствует случаю, когда в проекте используется микроконтроллер 18F1320
ввиду его низкой стоимости (менее 3-х долларов). Щелкните на имени файла и добавь-
те его в список, щелкнув на кнопке Add (Добавить). Теперь откройте папку LKR и найди-
те в ней файлы компоновщика для выбранного микроконтроллера. В данном случае два
из этих файлов - 18fl320.1 kr и 18tl320i.Ikr добавляются в список файлов компоновки для
микроконтроллера 18F1320. Как только все три файла будут перечислены в окошке
списка файлов, отметьте переключатели Add to project check box (Добавить в кон-
трольный список проекта), стоящие рядом с каждым именем файла, а затем щелкните
на кнопке Next (Далее). Появится последнее диалоговое окно, на котором будет кнопка
Finish (Завершить). Щелкните на этой кнопке для создания проекта - и новый проект
будет успешно создан.
Project Wizard
Step Four:
Add any existing lies to your project
' H 23 Microchip A j
> 1Q Docs |
J . В О MPASM Suite
I Й О Example J
I S П LKR |
й D T emplate |
& О Code
E CJ Object
® 1220tmpc
I ® 1320tmpc
।----:I 0 C:\Program FfesKMicrochipXMPAl
I —I * 0 CAProgram Ftes\Microchip\MPAti
J 0 C:\Program F8e$\Microchip\MPA^
[ Remove j *
1——— I ??
5 1 1320tmpcVl
К ; \ Г.Л! I
Check ths beat to copy the ffe to the
project directory
f Cancel | | Неф........... ]
Рис. 2.15. Выбор файлов компоновщика и файла шаблона проекта
Глава 2. Архитектура семейства PIC18 и разработка программ
63
дГМРГЛВ IDE V7.10
Re Edit View Project Debugger Proi
Рис. 2.16. Меню файлов проекта
Для того, чтобы посмотреть на шаблонный программный код (файл шаблона),
вставленный мастером проекта, щелкните на позиции View (Вид) меню, а затем выбе-
рите позицию Project (Проект). Рис. 2.16 показывает экран, который появится, когда
вы щелкните на позиции Project (Проект) разворачивающегося меню Project (Проект).
В этом небольшом окне будут отображены файлы, которые включены в проект. На дан-
ном этапе наиболее интересным будет файл исходного текста, который является шаб-
лоном, использованным в системе. Для просмотра этого файла дважды щелкните на
имени файла, - в этом примере на имени "1320tmpo asm". Казалось бы, это очень
трудно - создать проект и разработать его программное обеспечение, однако сущест-
вуют простые шаги, которых нужно придерживаться - и количество информации, кото-
рую необходимо ввести, значительно сократится. Как только вы разработаете несколь-
ко программ, эти шаги станут для вас естественными.
Пример 2.6 показывает листинг файла шаблона проекта. Большая часть того, что
имеется в данном файле на данном этапе будет для вас «тайной за семью печатями»,
однако позже будет все объяснено. Данный программный текст содержит обширные
комментарии, которые описывают назначение каждой секции, а также некоторые ко-
манды, которые необходимы для настройки базовых программ PIC. Символ точки с
запятой означает комментарий и все, что следует после этого символа до конца строки
не генерирует никакого кода. Фактически большая часть этого примера является про-
сто комментариями.
64
Применение микроконтроллеров PIC 18
Пример 2.6
; Этот файл представляет собой базовый шаблон создания
; перемещаемого кода ассемблера для PIC18F1320. Скопируйте
; этот файл в каталог вашего проекта и модифицируйте его в
; случае необходимости. Создайте проект, используя
; UPLINK в качестве языкового средства создания
; шестнадцатиричного файла. Добавьте в проект этот
; файл и файл 18F1320.LKR
; Архитектура IC18FXXXX допускает конфигурирование двух
; прерываний. Данный шаблонный код написан в расчете на
; уровни приоритета прерываний. При этом бит IPEN
; регистра RCON должен быть установлен для разрешения
; использования уровней прерываний. Если бит IPEN
; будет оставлен в устанавливаемом для него по умолчанию
; нулевом состоянии то, только вектор прерывания по адресу
; 0x008 будет использоваться, а переменные
; WREG_TEMP, BSR_TEMP и STATUS_TEMP не будут
; использоваться
; Смотрите Руководство Пользователя для получения
; дополнительной информации по свойствам ассемблера и
; компоновщика
; Смотрите технические спецификации PIC18F1220/1320
; для получения дополнительной информации об
; архитектуре и наборе команд
; Имя файла:
; Дата:
; Версия файла:
/ Автор:
/ Компания:
; Требуемые файлы: P18F1320.INC
; 18F1320.LKR
LIST P=18F1320, F=INHX32 /директива определения процессора и формата файла
♦include <P18F1320.INC> /определение процессорно-ориентированных переменных
; Биты конфигурации
/ Директива _CONFIG определяет данные конфигурирования
/ внутри файла .ASM. Метки, следующие после директивы,
/ определены в файле P18F1320.INC. Технические
/ спецификации PIC18F1220/1320 разъясняют функции
; битов конфигурации. Измените нижеследующие строки так,
/ чтобы они соответствовали вашему приложению.
_CONFIG _CONFIG1H, _IESO_OFF_1H & _FSCM_OFF_1H & _HS_OSC_1H
_CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_OFF_2L
_CONFIG _CONFIG2H, _WDT_OFF_2H
_CONFIG _CONFIG3H, _MCLRE_OFF_3H
Глава 2. Архитектура семейства PIC18 и разработка программ
65
CONFIG _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & STVR_OFF_4L
CONFIG _CONFIG5L, _CPO_OFF_5L & _CP1_OFF_5L
CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
CONFIG _CONFIG6L, _WRTO_OFF_6L & _WRT1_OFF_6L
CONFIG _CONPIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H Sc _WRTD_OFF_6H
CONFIG _CONFIG7L, _EBTRO_OFF_7L & _EBTR1_OFF_ 7L
CONFIG _CONFIG7H, _EBTRB_OFF_7H
.*****************************************************************************
; Определение переменных
; Эти переменные необходимы только, если используются
; низкоприоритетные прерывания
; Больше переменных может понадобиться для сохранения
; других специальных функциональных регистров,
; используемых в подпрограммах обслуживания прерываний.
□DATA
WREG_TEMP RES 1 ; Переменная в ОЗУ для
;сохранения контекста
STATUS_TEMP RES 1 /Переменная в ОЗУ для
;сохранения контекста
BSR_TEMP RES 1 ; Переменная в ОЗУ для
/сохранения контекста
UDATA_ACS
EXAMPLE RES 1 /пример переменной в ОЗУ
/доступа
/ Данные ЭСППЗУ
/ Здесь определяются данные, подлежащие
; программированию в ЭСППЗУ
DATA_EEPROM CODE OxfOOOOO
DE "Test Data",0,1,2,3,4,5
/Вектор сброса
; Этот код начнет выполняться после сброса.
RESET_VECTOR CODE 0x0000
goto Main /Переход на запуск
/основного фрагмента кода
/Вектор высокоприоритетного прерывания
/ Этот код начнет выполняться после возникновения
/ высокоприоритетного прерывания либо в случае
/ возникновения прерывания, когда приоритеты прерываний
/ не разрешены
HI_INT_VECTOR CODE 0x0008
bra Highint /переход на подпрограмму
; обработки высокоприоритетного прерывания
/ Вектор низкоприоритетного прерывания
66
Применение микроконтроллеров PIC 18
; Этот код начнет выполняться после возникновения
; низкоприоритетного прерывания
; Данный код может быть удален, если низкоприоритетные
; прерывания не используются
LOW_INT_VECTOR CODE 0x0018
bra Lowint ; переход на подпрограмму
; обработки низкоприоритетного прерывания
; Подпрограмма обработки высокоприоритетного прерывания
; Здесь помещается программный код обработки
; высокоприоритетного прерывания
CODE
Highint:
; *** сюда переходит код обработки высокоприоритетного
/ прерывания
retfie FAST
; Подпрограмма обработки низкоприоритетного прерывания
; Здесь помещается программный код обработки
; низкоприоритетного прерывания
; Данный код может быть удален, если низкоприоритетные
; прерывания не используются
Lowint:
movff STATUS,STATUS_TEMP ;сохранения регистра состояния
movff WREG,WREG_TEMP /сохранение рабочего регистра
movff BSR,BSR_TEMP /сохранение регистра BSR
/ *** сюда переходит код обработки низкоприоритетного прерывания ***
movff BSR_TEMP,BSR / сохранение регистра BSR
movff wreg_temp,WREG /восстановление рабочего регистра
movff STATUS_TEMP,STATUS /восстановление регистра состояния
retfie /Запуск главной программы
/ Сюда помещается код главной программы Main:
/ *** сюда переходит код главной программы ***
/Конец программ
END
Первыми двумя фактическими командными строками является директива LIST и
оператор #include. Директива LIST информирует ассемблер о том, что данный микро-
контроллер (Р) имеет тип 18F1320, а для файла выбран 32-битный шестнадцатиричный
форма Intel, который используется для сохранения программы, сформированной после
компиляции и компоновки программы на Ассемблере. Шестнадцатиричный файл ис-
пользуется для программирования памяти программ внутри микроконтроллера PIC.
Вторая секция программного кода конфигурирует микроконтроллер. Соответст-
вующие биты будут рассмотрены позже. На этом этапе нас устроит конфигурация IDE,
устанавливаемая по умолчанию, - она подходит для многих применений.
Глава 2. Архитектура семейства PIC18 и разработка программ
67
Следующая секция программного кода определяет любые пользовательские пе-
ременные и соответствующие ячейки памяти, а также любые данные, подлежащие со-
хранению в ЭСППЗУ. В данном случае в ЭСППЗУ будет заноситься символьная строка
"Test Data” (Тестовые данные), за которой будут следовать числа 0, 1,2, 3, 4 и 5. Вспом-
ните, что ЭСППЗУ используется для сохранения полупостоянных данных, которые из-
меняются от случая к случаю. Эти полупостоянные данные сохраняются и после снятия
электропитания.
Наиболее важной частью приведенного программного кода является установка
вектора сброса по адресу 0x0000. Вспомните, что микроконтроллер начинает выпол-
нять программу с адреса 0x0000. Также припомните, что имеются только 8 байтов па-
мяти между адресом вектора сброса и адресом вектора высокоприоритетного преры-
вания. По этой причине команда GOTO обычно размещается по адресу вектора сброса.
Единственная основная программа в этом примере продолжает выполняться по метке
Main. Команда GOTO изменяет состояние счетчика команд, устанавливая его на адрес
метки Main с тем, чтобы программа могла продолжать выполняться по этой метке. Об-
ратите внимание на то, что в данном случае по метке Main нет никакого программного
кода, а имеется просто комментарий, гласящий: ***здесь вводится код главной про-
граммы***.
Пример программы. Теперь, когда шаблон проекта отображается на экране IDE, не-
обходимо поместить некоторый программный код в секцию Main шаблона с тем, чтобы
узнать, как программировать микроконтроллер и использовать IDE для тестирования
программ.
Замените строку Main (;***здесь вводится код главной программы***) программ-
ным кодом на языке Ассемблера, показанным в примере 2.7. Эта программа делает не
так уж много работы, однако она формирует основу понимания того, как нужно исполь-
зовать IDE для тестирования программы.
Пример 2.7
MOVLW 0x01 /загрузка 0x01 в W
ADDLW 0x02 /добавление 0x02 к W
Wait: GOTO Wait /здесь вход в бесконечный цикл
Программа из примера 2.7 загружает регистр W литералом 0x01, а затем прибав-
ляет к нему литерал 0x02. Для того, чтобы увидеть эту программу в действии, введите
код из примера 2.7 в шаблон проекта по метке Main, заменив комментарий ***здесь
вводится код главной программы***. Как только эти строка кода будут ввёдены в шаб-
лон проекта, щелкните на позиции Project (Проект) меню. После этого щелкните на
позиции Build АН (Компоновать все) разворачивающегося списка, который появится.
Опция Build АН (Компоновать все) преобразует программу на языке Ассемблера в про-
грамму в численных машинных кодах, которая называется объектной программой. Эту
программу микроконтроллер может выполнить. Далее щелкните на позиции View
(Вид), а затем щелкните на позиции Special Function Registers (Специальные функ-
циональные регистры). Найдите регистр W (WREG) по адресу ОхРЕ8. Щелкните на по-
зиции меню Debugger (Отладчик), а затем выберите позицию MPLAB SIM. (Смотрите
снимок экрана на рис. 2.17.) MPLAB SIM - это программа, которая имитирует микро-
контроллер PIC на ПК. Для пошагового запуска программы нажмите функциональную
клавишу F7 клавиатуры или щелкните на иконке, расположенной непосредственно
справа от зеленой двойной стрелки, которая называется Step into (Шаг вперед). После
каждого шага зеленая стрелка будет перемещаться вниз по программе, показывая точ-
68
Применение микроконтроллеров PIC 18
ное место выполнения программы. Содержимое регистра WREG также изменяется по
мере выполнения программы. Для повторного запуска программы щелкните на желтой
иконке, расположенной справа от зеленой двойной стрелки, и программа начнет вы-
полняться сначала, чтобы можно было проследить ее выполнение вновь. Обратите
внимание на то, что программа выполняется в ПК и не нужно использовать микрокон-
троллер для того, чтобы изучить Ассемблер или то, как нужно программировать микро-
контроллер либо даже освоить отладку приложений. MPLAB SIM (имитатор) имитирует
микроконтроллер на ПК. Среди других функций этого имитатора можно назвать выпол-
нение трассирования команд (через меню View (Вид)), а также при использовании пор-
тов ввода-вывода просмотр данных ввода-вывода через позицию Logic Analyzer (Ло-
гический анализатор) меню View (Вид).
Rfe ЕА View Project Debugger Programmer Tools Cofigure Window Нф
unction Registers
00000000
00000000
00000000
00000000
POSTINC1
INDF1
WREG
FSRO
F3R0L
F3R0H
PLUSVO
PREINCO
00
0000 •
00
00
0
Oi
0
0
MyFrsLmcp
« Source Has
1320tmpo.asm
Header Ffes
Object Ffes
Ibrary Rtes
& Linker Scripts
10fl32O.fe
18fl320i.kr
Other files
Checksum: 6xcd88 ) & - Dt> (h
retfie
.;Ind ot program
IND
Рис. 2.17. Снимок экрана для примера 2.6
и окна специальных функциональных регистров.
-mt \ Hex I Dsciael I Binary-* Char
0FE6
0FE7
0FE8
0FE9
0FE9
OFEA
OFEB
OFEC
;Start of Main program
; The
main program code is placed here
Main:
Halt:
MDYUi 0x01
ADBLM OxOZ
goto Wait
»*• main code goes here
—M
ШШШш
Глава 2. Архитектура семейства PIC18 и разработка программ
69
Перенос программы в микроконтроллер
Для переноса программы в микроконтроллер необходимо использовать про-
грамматор. Некоторые Р1С18-базированные демонстрационные панели микроконтрол-
леров содержат программу, предназначенную для выгрузки программного обеспече-
ния и программирования микроконтроллеров. Фирма Microchip предлагает целый ряд
программаторов, которые могут программировать многие устройства семейства
PIC18. IDE поддерживает следующие программаторы: PICSTART plus, ICD 2, РМ 3 и
PROMATE II. Дополнительно, много других программаторов, которые также програм-
мируют СППЗУ, ЭСППЗУ и другие микроконтроллеры, обычно доступны. Если имеется
один из IDE-поддерживаемых программаторов, то IDE может управлять им и програм-
мировать микроконтроллер непосредственно из IDE.
0» gjilt
OxOZdO
Checksum;
1 5 Verson Cxikii; Fhd'iii
Ж Output
Dsable Prugtamc!
SeJert&ecramner
A&ovt
Reset Pieman SUUsLLs
□as® HashDevcs
Prewar
Verify
Shrtk Chetk Al
8bnk Check J.TP
Asrort Operannn
Рис. 2.18. Раскрывающееся меню программирования из IDE
w MPLA8 IDE
Как только программа скомпонована и отлажена в IDE, выбирается программатор
для того, чтобы передать шестнадцатеричный файл в микроконтроллер. Большинство
программаторов проверяет, правильно ли программируется программа в микрокон-
троллере. Этот учебник не пытается объяснять работу любого конкретного программа-
тора. Документация и программное обеспечение для программирования микрокон-
троллера поставляется с программатором, и задача программирования микрокон-
троллера выполняется очень просто.
При использовании одного из IDE-поддерживаемых программаторов, после кон-
фигурирования программирование, проверка, и тому подобные функции выполняются
через разворачивающиеся меню позиций главного меню IDE. Рис. 2.18 иллюстрирует
такое раскрывающееся меню для случая, когда программатор уже установлен и под-
ключен к хост-ПК. Если поддерживаемый IDE программатор отсутствует, то шестнадца-
теричный объектный файл должен быть передан в имеющийся программатор, а затем
загружаться в микроконтроллер.
70
Применение микроконтроллеров PIC 18
2.4. Язык Ассемблера, программа «ассемблер» и компоновщик
Прежде, чем ассемблер будет изучен и эффективно использован для программи-
рования, нужно освоить некоторую базисную информацию относительно ассемблера и
компоновщика программ. Этот подраздел объясняет роль этих инструментальных
средств в разработке систем, и описывает базисный синтаксис Ассемблера.
Ассемблер и компоновщик
Ассемблер - это программа, которая преобразовывает ассемблер (символьный
машинный код) из исходного файла в численный машинный код и сохраняет его в объ-
ектном файле. Как и любой ЦП, микроконтроллер понимает только численный машин-
ный код. Большинство программ ассемблера выполняют преобразование исходного
файла в объектный файл за два прохода через исходный файл. Первый проход генери-
рует таблицу символов, которая содержит каждую метку и ее адрес в программе. Пер-
вый проход также ищет ошибки ввода, называемые синтаксическими ошибками, и со-
общает о них посредством сообщений об ошибках. Второй проход выполняется, если
не обнаружено никаких ошибок в течении первого прохода. В течение этого второго
прохода извлекаются адреса из таблицы символов и коды каждой команды формируют
объектную программу на численном машинном языке.
Исходный файл для ассемблера - это обычно файл, который использует расши-
рение файла .asm; объектный файл, сгенерированный ассемблером, обычно имеет
расширение .о. Имена файлов должны соответствовать соглашениям, принятым в опе-
рационной системе. В большинстве случаев используется операционная система
Windows, в силу чего в именах файлов можно использовать почти любые символы, за
исключением нескольких специальных. Объектный файл обычно не имеет формы ис-
полнительного файла. Исполнительный программный файл - это обычно файл, пред-
назначенный для загрузки в микроконтроллер и имеющий шестнадцатиричный формат
Intel. Этот файл обычно генерируется другой программой, называемой компоновщи-
ком.
Программа компоновщика объединяет несколько объектных файлов для языков
Ассемблера и С в один исполняемый файл. В случае микроконтроллера PIC этот испол-
няемый файл обычно имеет шестнадцатеричный формат Intel, используемый в PIC-
программаторе, и часто имеет расширение .hex. Компоновщик также допускает ис-
пользование в процессе компоновки библиотечных файлов (.lib) и файлов сценария
компоновщика (.Ikr). Компоновщик также генерирует файл .coff (общий формат объект-
ного файла) и файл .cod (символьный и отладочный файл) для системы разработки и
процесса отладки. В дополнение к файлам .coff и .cod, генерируется файл .1st (полный
файл листинга программы), который рядом отображает как символьный, так и числен-
ный код программы; IDE имеет доступ к этому файлу листинга, отображая его при ди-
зассемблировании через меню View (Вид). Доступ к этим файлам обычно выполняется
изнутри IDE и они, как правило, не используются индивидуально. Даже программатор,
который использует .hex файл, обычно управляется из IDE.
Операторы языка Ассемблера
Строки ассемблерного кода называются операторами. Оператор содержит четыре
различных информационных поля: метка, код операции, операнд и комментарий. Метка со-
держит символьный адрес памяти, по которому оператор может быть адресован из любого
места программы. Так, оператор GOTO Main, расположенный по адресу вектора сброса,
ссылается на метку, размещенную в другом месте программы. Код операции содержит ко-
Глава 2. Архитектура семейства PIC18 и разработка программ
71
манду ассемблера или директиву, которая управляет работой микроконтроллера, ассембле-
ра или программы компоновщика. Слово GOTO в GOTO Main является примером кода опе-
рации. Операнд - это литерал, адрес регистрового файла или некоторая другая информа-
ция, используемая кодом операции для выполнения задачи. В Операторе GOTO Main, слово
Main - это операнд, используемый кодом операции GOTO. Поле комментария необязатель-
но, обычно оно указывает некоторую информацию о программе или же используется для
того, чтобы идентифицировать секцию кода. Комментарии должны начинаться символом
точки с запятой. Рис. 2.19 иллюстрирует строку кода с информацией в каждом поле опера-
тора языка Ассемблера.
Метка. Метка обычно проставляется только в строках кода, на которые имеются ссыл-
ки в каких-либо иных местах программы. Метка может состоять из любых символов, за
исключением зарезервированных лексем типа кодов операций или имен регистров.
Метка должна начаться с буквы (A-Z) или с символа подчеркивания, как, например
_Start. Метка может содержать любой символ, цифпу, символ подчеркивания либо сим-
вол вопросительного знака. Метки обычно заканчиваются двоеточием, но это не обяза-
тельно. Табл. 2.5 показывает несколько форм допустимых меток языка Ассемблера.
метка код операции операнд комментарий
Start MOVLW 0X00 загружает регистр WREG значением 0x00
Рис. 2.19. Оператор языка Ассемблера
Таблица 2.5. Примеры меток.
Пример метки Комментарий
START: Допустимая метка
Start- Start&Stop: Допустимая метка Недопустимая метка ввиду наличия символа &
4Ме: Недопустимая метка, поскольку метка должна начинаться с буквы либо символа подчеркивания
StartStop_?: Допустимая метка
Addlw: Недопустимая метка, потому что addlw представляет собой код операции
Код операции. Поле кода операции должно содержать допустимый код операции мик-
роконтроллера. Поле кода операции может также содержать директиву, которая пред-
ставляет собой специальную команду для ассемблера или компоновщика. Поле кода
операции может также содержать имя макроса. Макрос - это группа командЮ предва-
рительно определенная пользователем и идентифицируемая уникальной лексемой или
именем. Код операции может писаться как с использованием строчных, так и заглавных
букв, однако в большей части этой книги используются заглавные буквы, чтобы избе-
жать ошибок в прочтении буквы “I” и цифры “1". Так, например, при использовании
строчных букв команда movlw может быть неверно прочитана как movlw, в то время как
MOVLW трудно спутать с MOV1W. IDE использует шрифт “курьер” при отображении про-
граммы, а в этом шрифте строчная буква I и цифра 1 одинаковы. По этой причине при
использовании строчных букв вместе с цифрами ошибки прочтения будут обычным
явлением.
72
Применение микроконтроллеров PIC 18
Операнд. Поле операнда указывает информацию, с которой должна работать операция, за-
даваемая кодом операции. Оно размещается справа от кода операции и может быть пустым
либо содержать любое число полей, разделенных запятыми. Таблица 2.6 демонстрирует не-
сколько команд, которые используют различное количество операндов.
Комментарий. Комментарий - это все, что начинается с символа точки с запятой. Все,
что следует после символа точки с запятой, игнорируется до конца строки. Каждая
строка комментария должна начинаться символом точки с запятой, поскольку в Ас-
семблере нет способа продолжения комментария в нескольких строках, как это воз-
можно в других языках. Хорошая практика программирования связана с комментиро-
ванием секций программного кода, а не отдельных команд. Также хорошей практикой
является разделение секций кода по крайней мере одной пустой строкой. Хорошая
практика комментирования и программирования может быть проиллюстрирована уже
рассмотренным нами примером 2.6. Обратите внимание на то, что каждая программ-
ная секция в нем отделена от других пустыми и комментариями с использованием сим-
волов точки с запятой. Это важно, поскольку язык Ассемблера непрозрачен и коммен-
тарии помогают понять значение программного кода.
Директивы
Директивы - эти специальные команды ассемблеру, которые могут отображаться, а
могут и не отображаться на машинный код. Директивы классифицируются по их функ-
циям и объясняются в этой книге в соответствии с их функциональными группами. Сей-
час мы рассмотрим не все директивы, - некоторые из них будут рассмотрены позже. В
этом подразделе мы рассмотрим директивы, которые наиболее часто используются
при программировании.
Таблица 2.6. Примеры операндов некоторых команд
Код операции с операндами Комментарий
RETURN MOVLW 0x00 MOVFF 0x10,0x11 DE 1,2,4,6, 9 CALL HomeET Операнд отсутствует Один операнд (0x00) Два операнда (0x10 и 0x11) Несколько операндов Один операнд
Таблица 2.7. Директивы объектных файлов
Директива Коммента рий
ACCESS_OVR CODE CODEPACK EXTERN Оверлейный доступ к ОЗУ объектного файла Начало блока программного кода Начало упакованного блока кода Объявляет, что метка определена в каком-то другом программном модуле
GLOBAL Объявляет, что метка доступна другим программным модулям
I DATA IDATA_ACS UDATA Начинает секцию данных инициализации Начинает секцию данных инициализации в ОЗУ доступа Начинает секцию данных инициализации
UDATA_ACS UDATA OVR Начинает секцию данных инициализации доступа Начинает секцию оверлейных данных инициализации
Глава 2. Архитектура семейства PIC18 и разработка программ
73
Директивы объектного файла управляют тем, как ассемблер генерирует код в объ-
ектном файле. Обратитесь, вновь, к примеру 2.6, и обратите внимание на то, что неко-
торые директивы управляют способом, которым создается объектный файл. Табл. 2.7
перечисляет многие из директив объектного файла.
Наиболее обычными директивами объектного файла являются директивы CODE,
UDATA и UDATA_ACS. Директива CODE определяет различные секции программного
кода. Метка в данном случае будет именем секции программного кода, операнд - это
абсолютный адрес секции программного кода. Например, чтобы поместить код по ад-
ресу вектора сброса, используйте оператор RESET_ VECTOR CODE 0x0000, как это по-
казано в примере 2.6. Эта директива информирует ассемблер о том, что вектор сброса
начинается по адресу программы 0x0000. Если директива CODE используется без мет-
ки либо операнда, то тогда секцией кода обычно будет основной текст программы и
ассемблер сам определяет адрес. Пример 2.8 показывает то, как директива CODE мо-
жет использоваться в системе при разработке программ.
Пример 2.8
RESETS_HERE CODE 0x0000 ;по сбросу переход сюда
GOTO Ь HIGH_INT ly Stuff CODE 0x0008 /высокоприоритетное прерывание
GOTO LOW_INT Highlnterrupt CODE 0x0018 /низкоприоритетное прерывание
GOTO Lowlnterrupt
Highlnterrupt: CODE /код без предварительно определенного адреса
/ * * * * сюда заносится код обработки высокоприоритетного прерывания ****
Lowlnterrupt: сюда заносится код обработки низкоприоритетного прерывания ****
MyStuff: сюда заносится код приложения ****
END ;конец файла
Директивы UDATA и UDATA_ACS резервируют пространство в памяти данных для
переменных. Программы намного легче читаются, если в них метки, а не числовые ад-
реса используются для идентифицирования адресов памяти данных. Посмотрите вновь
пример 2.6 и обратите внимание на то, что область памяти зарезервирована для трех
переменных директивой UDATA. Эта область начинается по адресу регистра данных
0x080, кроме того область памяти для одной переменной определена директивой
UDATA_ACS. Эта область начинается по адресу регистра данных 0x000. Не забывайте,
что память банка доступа (ACS в директиве) находится по адресам регистров от 0x000
до Ox7F. Остальная часть банка доступа содержит специальные функциональные реги-
стры, размещенные по адресам от OxF80 до OxFFF, как это определено директивой
UDATA.
Директивы IDATA и IDATA_ACS похожи на директивы UDATA и UDATA_ACS, за ис-
ключением того, что они используются для инициализации памяти данными вместо
резервирования пространства памяти. Microchip отмечает, что директивы IDATA и
IDATA_ACS могут не функционировать корректно в случае использования эмулятора. По
этой причине они не должны использоваться для инициализации данных. Если вам не-
обходимо разместить данные в памяти, напишите программный код, который инициа-
лизирует данные.
Директива CODE также используется для инициализации памяти данных
ЭСППЗУ, как показано в примере 2.6. При сохранении данных в ЭСППЗУ используйте
74
Применение микроконтроллеров PIC 18
адреса от OxFOOOOO, как показано в примере 2.9. Убедитесь в том, что вы используете
директиву IDE для сохранения данных в ЭСППЗУ, как об этом говорилось в главе 1. Об-
ратите внимание на то, что адрес OxFOOOOO не является адресом в памяти программ,
он также не является реальным адресом ЭСППЗУ. Это адрес, который сигнализирует
IDE, что это данные для ЭСППЗУ - и ничего больше.
Пример 2.9
EEPROM_MEM CODE OxFOOOOO
DE "This is for my EEPROM!", 0 ;нулевая строка C-стиля
Директивы управления. Директивы управления являются следующей наиболее рас-
пространенной группой директив Ассемблера, которые управляют ассемблером, а
также, иногда, и процессом компоновки. Наиболее распространенными являются сле-
дующие управляющие директивы: #include, end, processor, equ и set. Табл. 2.8 пере-
числяет директивы управления микроконтроллеров PIC.
Не все директивы управления рассмотрены здесь, а только те, которые наиболее
часто используются при программировании. Более полное описание директив управ-
ления, не рассмотренных в данной книге, обращайтесь к документации на Ассемблер
MPASM, которая размещена на сайте фирмы Microchip.
Директива #include включает файлы кодов, часто называемые файлами заголов-
ков, языка С. Пример 2.6 показывает пример ее использования, когда она применяется
для добавления содержимого файла PI8F1320.INC к листингу кодов. Файл
P18P1320.INC - это включаемый файл, который содержит информацию (в основном,
это директивы equ), которая определяет конфигурацию PIC18P1320 и его регистров, а
также содержит другую информацию о микроконтроллере.
Директива end, хотя это и может показаться интуитивно ясным, должна поме-
щаться в конце файла программы. Если этого не сделать, то файл не будет ассембли-
роваться. Не помещайте директиву end во включаемый файл, ибо в этом случае про-
цесс ассемблирования, называемый построением, остановится в конце включаемого
файла. Директива end является сигналом ассемблеру завершить процесс ассемблиро-
вания, поэтому ничего, что следует после этой директивы, не будет охвачено этим про-
цессом.
Директива processor, которая идентифицирует процессор, используется с фай-
лом проекта, - она может использоваться, а может и не использоваться в этом файле.
Если тип процессора выбран в секции конфигурирования IDE, то нет необходимости
включать эту директиву в файл программы. Во многих случаях директива processor не
включается в файл программы.
Директива equ или директива эквивалентности устанавливает эквивалентность
значения или метки другой метке. Если вы просмотрите один из файлов заголовков,
предоставляемых IDE, то сможете заметить, что в них используются много директив
equ, приравнивающих адреса СФР меткам. Например, WREG приравнивается OxFES,
поэтому WREG может быть использован в программе по имени, а не по номеру. Файлы
включения и директивы equ делают программы на языке Ассемблера более легкими
для написания и прочтения.
Глава 2. Архитектура семейства PIC18 и разработка программ
75
Таблица 2.8. Директивы управления
Директива Комментарий
♦define Определяет текстовое замещение метки
♦include Включает исходный файл
♦undefine Удаляет замещение метки
Constant Определяет символьную константу
End Конец программы (необходима)
Equ Приравнивает константу
Org Задает начало блока
Processor Выбирает тип процессора
Radix Специфицирует используемое по умолчанию основание системы счисления
Set Определяет переменную Ассемблера
Variable Определяет символьную переменную
Таблица 2.9. Перечень директив
Директива Комментарий
error Выдает сообщение об ошибке
errorlevel Задает уровень сообщения об ошибке
list Устанавливает тип процессора и выходного файла, а также
иные используемые по умолчанию значения для программного листинга
messg Задает пользовательское сообщение
nolist Отключает листинг
page Вводит новую страницу листинга
space Вставляет пустую строку в листинг
subtitle Специфицирует подзаголовок программы
title Специфицирует название программы
Директива set используется для установки метки, эквивалентной значению, кото-
рое может быть изменено позже посредством новой установки значения этой же метки.
Директива set используется менее часто при программировании, чем директива equ,
при этом по действию она похожа на директиву equ.
Директива List. Директива list предназначена для управления процессом формирова-
ния листинга. Табл. 2.9 перечисляет имеющиеся директивы управления листингом.
Среди всех этих директив чаще всего используется директива list. Директива list управ-
ляет общим процессом формирования листинга для выбранного микропроцессора.
Появляется сообщение, как в примере 2.6, в котором в качестве типа процессора для
листинга установлено P=18F1320, a F=INHX32 выбирает тип выходного файла. В данном
примере выходной файл имеет 32-разрядный шестнадцатиричный форма Intel.
Директивы управления данными. Директивы управления данными, которые описывают
данные, появляются в программах во многих местах. Они, по-видимому, являются наи-
более используемым типом директив Ассемблера. Многие из них были описаны в главе
1 при определении данных, некоторые описываются здесь. Директивы управления
данными в общем случае определяют тип данных. Смотрите табл. 2.10, в которой пе-
речислены директивы управления данными
76
Применение микроконтроллеров PIC 18
Таблица 2.10. Директивы управления данными
Директива Комментарий
badram badrom config config Идентифицирует нереализованное ОЗУ Идентифицирует нереализованное ПЗУ Устанавливает биты конфигурирования процессора Устанавливает биты конфигурирования процессора в семействе PIC18
idloca Устанавливает значение ячеек памяти идентификации процессора
maxram Устанавливает максимальный объем ОЗУ
maxrom Устанавливает максимальный объем ПЗУ
cblock Определяет блок постоянных данных
da Сохраняет строки в памяти программ (PIC12/16)
data Создает численные и текстовые данные
db Определяет байты
de Определяет данные ЭСППЗУ
dt Определяет таблицы (PIC16/12)
dw Определяет слова
endc Завершает блок автоматических констант
fill Заполняет память константами
res Резервирует память
Наиболее часто используемыми директивами управления данными в семействе
PIC 18 являются: db, de, dw и res, как это описывалось в главе 1. Единственной другой
часто используемой директивой управления данными в программой PIC 18 является
директива config. Не путайте директиву _config с директивой config. Директива _config
может использоваться в семействе PIC 18 так, как это показано в примере 2.6. Эта ди-
ректива устанавливает конфигурацию микропроцессора для проекта. Эти биты и их
функции разбираются в последующих разделах этой книги.
2.5. Резюме
1. Архитектура PIC использует гарвардскую архитектуру, разделяя память про-
грамм и память данных. Назначением данной архитектуры является более эффектив-
ное выполнение программ.
2. PIC - это самодостаточная компьютерная система, содержащая память и уст-
ройства ввода-вывода. Это снижает стоимость реализации систем.
3. Память программ, доступная в PIC, имеет объем от 4К байт до 128К байт, в за-
висимости от устройства данного семейства, выбранного для реализации приложения.
Вследствие того, что большинство команд имеет длину в два байта, это обеспечивает
возможность использования в программах от 2К до 64К команд. Вся память программ
доступна через 21-разрядную адресацию.
4. Память программ организована в регистровый файл. Вся память данных имеет
разрядность в 8 бит и изменяется по объему от 256 до 3840 байт плюс дополнительные
128 байт для специальных функциональных регистров. Вся память данных адресуется
через 12-разрядный адрес.
5. Специальные функциональные регистры (СФР) используются как рабочий ре-
гистр (W); для содержание произведения после умножения (регистры произведения); и
для косвенной адресации регистров данных через регистры выбора файлов (FSR), би-
тов состояния в регистре состояния, а также счетчика команд для прослеживания хода
выполнения программы. Имеется также много других СФР, используемых для управле-
ния устройствами ввода-вывода микроконтроллера, как это будет обсуждаться в по-
Глава 2. Архитектура семейства PIC18 и разработка программ
77
следующих главах.
6. Направление перемещения данных для порта ввода-вывода программируется
через регистр TRIS порта, при этом логическая 1 программирует соответствующий бит
как вход, а 0 - как выход. Порт А использует TRISA, порт В использует TRISB и т.д.
7. Данные считываются либо записываются через штырьки ввода-вывода, ис-
пользуя регистр PORTA для регистра А или PORTB для порта В.
8. Система разработки программ, используемая для генерирования программ
для микроконтроллеров PIC, называется интегрированной средой разработки или IDE.
IDE предоставляет редактор для ввода программного кода, доступ к программатору
для программирования кода в микроконтроллер PIC, доступ к внутрисхемному эмуля-
тору, а также доступ к имитатору, позволяющему выполнять эмуляцию программы на
персональном компьютере.
9. IDE инициализируется для нового проекта посредством выбора типа процес-
сора из меню Configure/Select Device (Конфигурировать/Выбрать устройство), а так-
же посредством запуска мастера проектов - соответствующая позиция находится в
разворачивающемся меню позиции главного меню Project (Проект).
10. Оператор языка Ассемблера составлен из четырех полей: метка, код опера-
ции, операнд и комментарий.
11. Поле метки - это символьный адрес памяти, предназначенные для идентифицирования
ячейки памяти. Метка должна использоваться только, если ячейка должна адресоваться из программы.
12. Поле кода операции содержит команду микроконтроллера или директиву ассембле-
ра. Код операции дает команду микроконтроллеру выполнить какую-либо операцию.
13. Поле операнда содержит информацию, используемую кодом операции для выполнения
команды. Операндом может быть имя регистра, адрес ОЗУ данных, численное значение и т.д.
14. Поле комментария не обрабатывается ассемблером, однако оно предостав-
ляет программисту метод комментирования блоков кода с тем, чтобы программа стала
более читабельной.
15. Директива - это команда ассемблеру или компоновщику, которая часто не ге-
нерирует никаких кодов в памяти программ либо памяти данных. Директивы упрощают
задачу написания программы.
2.6. Вопросы и задания
1. На рисунке 2.1 микроконтроллерная система не содержит памяти. Где разме-
щена в ней память микроконтроллера?
2. Что такое гарвардская архитектура?
3. Сравните гарвардскую архитектуру с архитектурой фон Неймана.
4. Что такое конвейерная обработка информации и как она повышает эффектив-
ность выполнения программы?
5. Память программ имеет разрядность в битов.
6. Память данных имеет разрядность в битов.
7. Что такое первый и последний адреса в памяти программ PIC?
8. Что такое первый и последний адреса в памяти данных
9. Память программ использует адрес в разрядов в семействе PIC18.
10. Адрес данных в семействе Р1С18 является разрядным адресом.
11. В чем разница между 18F серией PIC и 18С серией PIC?
12. Если имеется ЭСППЗУ в Р1С18, где оно расположено и как адресуется?
13. Если PIC18F6620 используется при разработке системы, его адреса памяти
программ начинаются с и заканчиваются.
14. Если PIC18F442 используется при разработке системы, его адреса памяти
программ начинаются с и заканчиваются.
15. Сколько шестнадцатиричных ячеек памяти содержит память на 12К?
78
Применение микроконтроллеров PIC 18
16. Если область 16К памяти начинается по адресу памяти программ 0x004000,
каким будет последний адрес этой области?
17. Какими будут начальный и последний адреса памяти данных в микроконтрол-
лере 18F452 PIC?
18. Где находятся регистры, которые программируют устройства ввода вывода
системы?
19. Где в памяти данных находятся специальные функциональные регистры в
микроконтроллере PIC?
20. Каково назначение рабочего регистра?
21. Что такое аккумулятор?
22. Где расположен регистр W в микроконтроллере PIC?
23. Какую часть памяти PIC часто называют регистровым файлом?
24. Каково назначение трех регистров выбора файлов в PIC?
25. Каково назначение регистров выбора банка почему он необходим?
26. Где нужно смотреть - не произошел ли перенос после сложения?
27. Каково назначения бита В регистра состояния?
28. Что такое регистры TRIS?
29. Как регистр TR1SB программируется на выбор операции вывода для битов
порта В от 0 до 2 операции ввода для штырьков от 3 до 7 порта В?
30. Как число 0x33 передается на штырьки порта А, если порт А запрограммиро-
ван как порт вывода?
31. Почему имеется набор регистров для произведения и где эти регистры?
32. Сколько 8-битных регистров содержат счетчик команд?
33. Каково назначение счетчика команд и почему он называется счетчиком?
34. Что такое IDE?
35. Какую информацию содержит файл шаблона микроконтроллера?
36. IDE используется при разработке программ, а какие иные задачи она может
выполнять?
37. Что такое мастер проекта и почему он необходим?
38. Что такое имитатор?
39. Какие четыре части оператора Ассемблера вы знаете и каково их назначение?
40. В нижеприведенных операторах Ассемблера идентифицируйте поля операторов:
a. Start: GOTO Heaven
b. ADDLW 0x29 ;adda0x29
c. Loopy 1: MOVFF WREG, 0x145 перемещение
41. Какие из следующих меток являются допустимыми?
a. 2PAR
b. FARAWAY
с. FAR A WAY
d. FarAWay
42. Что такое процесс ассемблирования?
43. Что такое исходный файл?
44. Что такое объектный файл?
45. Каково назначение компоновщика?
46. Что такое . Ikr -файл?
47. Каково назначение директивы UDATA?
48. Каково назначение директивы CODE?
49. Директива DE используется для размещения данных в.
50. Что делает директива CODE 0x1000?
51. Для чего в проекте используется директива LIST?
52. Что делает оператор DATA1 RES 2?
53. Что делает команда GOTO?
Глава 3. Набор команд семейства PIC18
79
Глава 3. Набор команд семейства PIC18
Это одна из наиболее важных глав во всей этой книге. В ней разъясняется функ-
ционирование команд из набора команд микроконтроллеров семейства PIC18. Хотя
при программировании очень часто используются языки программирования высокого
уровня типа С, важно понимать работу каждой команды, поскольку при этом лучше по-
нимается работа микроконтроллера в целом. Эта глава также демонстрирует ограни-
чения микроконтроллера.
Каждая команда или группа команд в данной главе представляется с использова-
нием небольших приложений, которые могут быть введены и выполнены в IDE. Это по-
зволяет исследовать работу команд и лучше ее понять благодаря имитатору IDE. В
этой главе развиваются многие идеи и концепции, которые уже рассматривались в гла-
вах 1 и 2. Как только будет понят набор команд, в последующих главах будут рассмот-
рены приложения, которые выполняют доступ к устройствам ввода-вывода.
После изучения данной главы вы сможете:
1. Описывать функционирование режимов адресации, имеющихся в микрокон-
троллере.
2. Детально описывать работу каждой команды из набора команд микроконтрол-
лера.
3. Разрабатывать и имитировать выполнение коротких программ, используя IDE.
4. Описывать процесс программирования с использованием программных конст-
рукций.
5. Использовать косвенную адресацию при доступе к памяти данных.
6. Использовать табличную адресацию при доступе к памяти программ.
7. Генерировать и использовать в программе макропоследовательности.
3.1. Литеральные команды
Перед тем, как использовать команды в программе, необходимо понять режимы
адресации, которые могут использоваться этими командами. Данный подраздел разъ-
ясняет различные режимы адресации, доступные в микроконтроллерах семействе
PIC18, а также соответствующее применение команд с использованием языка Ассемб-
лера.
Литеральные команды
Литеральная адресация - это, по-видимому, самый легкий для понимания тип ад-
ресации, поэтому рассмотрим его первым. Литерал - это константа, такая как число
или ASCII-символ. Большинство из команд с литеральной адресацией работают с рабо-
чим регистром WREG. В табл. 3.1 все доступные литеральные команды, имеющиеся в
наборе команд семейства PIC18. Большинство литеральных команд используют второй
байт 16-ти разрядной команды для хранения литеральных данных. Если вам необходи-
мы более детальные сведения относительно численных машинных кодов команд, пожа-
луйста, обращайтесь к Приложению А, в котором перечислены все команды в формате
численного машинного кода совместно с другой полезной информацией о них.
80
Применение микроконтроллеров PIC 18
Таблица 3.1. Литеральные команды
Код операции Операнд 1 Операнд 2 Примеры Комментарий
ADDLW Литерал ADDLW 0x20 ADDLW.100 Добавляет 0x20 к W Добавляет 100 к W
ANDLW Литерал ANDLW OxOF ANDLW 15 ANDLW ObOOOOl 111 И OxOF с W И 15 десятичного с W И двоичного 00001111 с W
IORLW Литерал IORLW 0x80 IORLW 1 Включающее ИЛИ 0x80 с W Включающее ИЛИ 1 с W
LFSR Номер регистра FSR Литерал LFSR 0,0x123 LSFR2,OxlO Загружает FSRO 0x123 Загружает FSR2 0x010
MOVLB Литерал MOVLB 2 MOVLB 0 Загружает 2 в BSR Загружает 0 в BSR
MOVLW Литерал MOVLW 3 MOVLW 0x34 Загружает 3 в W Загружает 0x34 в W
MULLW Литерал MULLW .100 MULLW 2 Умножает W на 100 Умножает W на 2
RETLW Литерал RETLW 2 RETLW Ox2A Возврат при W = 2 Возврат W = Ох2А
SUBLW Литерал SUBLW 5 SUBLW.19 Вычитание W из 5 Вычитание W из 19
XORLW Литерал XORLW 4 XORLW OxFO Исключительное-ИЛИ 4 с W Исключительное-ИЛИ OxFO с W
Обратите внимание (см. табл. 3.1), что имеется не так много литеральных команд,
которые следует изучить. Первые три буквы большинства литеральных команд указы-
вают операцию, выполняемую командой. Как отмечалось в главе 1, ЦП может выпол-
нять только несколько операций: ADD (сложение), AND (логическое И), IOR (включаю-
щее ИЛИ), MOV (копирование), MUL (умножение), SUB (вычитание) и XOR (исключи-
тельное OR). Последние две буквы кода операции дают дополнительную информацию о
команде. Например, буква L указывает на литерал, а буква W указывает на регистр
WREG. Это означает, что команда ADDLW складывает литеральный операнд с содержи-
мым регистра WREG. Единственными командами, которые не придерживаются этой
схемы, являются команды LFSR и MOVLB. Команда LFSR загружает литерал (обычно
адрес регистрового файла) в один из трех регистров выбора файла FSR, используемых
для косвенной адресации памяти данных. Команда MOVLB загружает регистр выбора
банка (BSR) числом между 0, для банка 0, до 15, для банка 15.
В микроконтроллерах PIC набор арифметических и логических команд не являет-
ся полным. Так, команда деления в микроконтроллерах семейства PIC не реализована,
однако команда умножения реализована. Если в системе необходимо выполнить деле-
ние, то нужно реализовать программное обеспечение, которое решит эту задачу.
В общем случае арифметические и логические операции изменяют состояние
битов регистра состояния. Исключением является команда умножения, которая не ока-
зывает никакого влияния на биты регистра состояния. (Вспомните, что биты регистра
состояния играют важную роль, поскольку микроконтроллер использует их при приня-
тии решений). Для иллюстрации изменений битов регистра состояния может быть вы-
полнена простая программа, показанная в примере 3.1. Эта программа не выполняет
столь уж много работы, однако однако содержимое регистра состояния изменяется
Глава 3. Набор команд семейства PIC 18
81
после выполнения команды ADDLW. В этом примере программы Ox7F перемещается в
регистр WREG командой MOVLW, а затем добавляется 1 к регистру WREG командой
ADDLW для генерирования суммы, равной 0x80, в регистре WREG. Обратите внимание
на то, как для завершения программы используется команда GOTO. Вследствие того,
что единственная вещь, которую выполняет микроконтроллер, заключается в постоян-
ном извлечении и выполнении команд программы, то такая хитрость, как «GOTO Stop»
иногда используется для завершения программы. В реальном системном программ-
ном обеспечение нет необходимости использовать эту уловку, поскольку большинство
операционных систем работают в режиме непрерывного цикла по своему изначально-
му замыслу. Если операционная система остановится, то это приведет к фатальной
ошибке выполнения программы.
Пример 3.1
MOVLW ADDLW 0x7F 1 ;Загрузка W Ox7F добавление 1 к W
Stop: GOTO Stop ;stop here
Поместите этот простой пример в шаблонный файл IDE (используйте файл при-
мера 2. 6 из главы 2) в секцию, которая имеет метку Main. При выполнении этой про-
граммы отобразите содержимое специальных функциональных регистров в меню View
(Вид) и обратите внимание на то, что регистр WREG (по адресу OxFE8) содержит 0x80, а
регистр состояния содержит Ох1А. Для просмотра специальных функциональных реги-
стров запустите программу, а затем остановите ее перед просмотром содержимого
специальных функциональных регистров. Если вы посмотрите в нижнюю часть экрана,
то увидите, что там отображается содержимое регистра W, совместно с другой полез-
ной информацией. Если вы не остановите выполнение программы, то не сможете уви-
деть правильные значения регистров при использовании имитатора. Имитатор ото-
бражает обновленную информацию только тогда, когда программа остановлена.
Значение OxIA в регистре состояния говорит нам о том, что результат отрицате-
лен, потому что бит отрицательного результата (N) находится в состоянии логическое
единицы. Значение 0x80 или 1000 ОООО2 в регистре WREG является, конечно, отрица-
тельным . Вспомните, что самые правые пять битов регистра состояния содержат ин-
дикаторы, одним из которых является бит отрицательного результата. Этими битами
являются N, OV, С, DC и Z слева направо, начиная от битовой позиции 4. При значении
регистра состояния, равном 0x1 A, N = 1, 0V = 1, С = 0, DC = 1 и Z = 0. Такое состояние
перечисленных регистров означает, что результат отрицателен, имело место перепол-
нение регистра W, переноса не было, имел место перенос разряда полубайта, т.е. по-
ловинный перенос.
Переполнение возникло в этом примере вследствие того, что +1 (0x01) была до-
бавлена к +127 (Ox7F), а результат равен -128 (0x80). Максимальное положительное
число, которое помещается в восьмиразрядном регистре, равно +121 (Ox7F), а макси-
мальное отрицательное число равно -128 (0x80). Если любая из названных величин
превышена, то в результате возникнет переполнение. Условие переполнения относится
только к числам со знаком. Если числа в данном примере рассматривать как беззнако-
вые, то 0x80, что равно без знака 128, будет корректным и биты N и 0V регистра со-
стояния не будут иметь никакого значения для результата беззнаковой операции.
Рис. 3.1 иллюстрирует операцию сложения (см. пример 3.1) и местоположение двух
битов переноса.
82
Применение микроконтроллеров PIC 18
Пример 3.2
Stop:
MOVLW 6 ;перемещает 6 в W
SUBLW 5 ;вычитает W (6) из 5
GOTO Stop
Когда выполняется вычитание, то биты состояния переноса (С) и половинного
переноса (DC) регистра состояния фактически содержат информацию о заимствова-
нии (0 = заимствование, 1 = нет заимствования). Если программа по примеру 3.2 будет
выполнена, то результатом будет OxFF в регистре WREG, а регистр состоянии будет
содержать значение, равное 0x10. Команда SUBLW вычитает содержимое регистра
WREG из литерального значения. Создается впечатление, что эта операция выполняет-
ся в обратном порядке - так оно и есть: обратите внимание на то, как выполняется опе-
рация вычитания в этом микроконтроллере. В этом случае 6 вычитается из 5 и резуль-
тат будет отрицательной единицей или OxFF. Регистр состояния будет иметь единицы
как в бите С, так и в бите DC. Это означает, что при выполнения данной операции вычи-
тания было необходимо заимствование, как показано на рис. 3.2.
С DC
0 111 1111
+ 0000 0001
1000 0000
Рис. 3.1. Состояние битов С и DC
в ходе операции сложения по примеру 3.1.
Озаимство ванне
С DC
0000 0010
0000 0011
1111 1111
Рис. 3.2. Состояние битов С и DC в ходе операции сложения по примеру 3.2.
Литеральные логические команды. Имеются три логические литеральные инструк-
ции: AND (И), IOR (Включающее ИЛИ) и XOR (Исключающее ИЛИ). Таблица истинности
для всех трех операций показана на рисунке 3.3. Эти операции выполняются на побит-
ной основе (бит за битом) при выполнении программы. Операция AND часто использу-
ется для выборочной установки одного либо большего числа битов в ноль, потому что
при выполнении операции И с нулем результат всегда будет нулевым. Операция вклю-
чающего ИЛИ (IOR) часто используется для выборочной установки одного либо боль-
шего числа битов в единицу, потому что при выполнении операции включающего ИЛИ с
единицей результат всегда будет единичным. Операция исключающего ИЛИ (XOR) се-
Глава 3. Набор команд семейства PIC18
83
лективно инвертирует один либо несколько битов из нуля в единицу, либо из единицы в
ноль, потому что при выполнении операции исключающего ИЛИ единицы с каким либо
операндом, результатом будет инверсия этого операнда. Эти три факта также иллюст-
рируются на рис. 3.3, при этом X используется для представления любого числа; при-
меры показывают, как эти операции модифицируют число X.
хххх хххх
и 0000 1111
оооо хххх
хххх хххх
IOR 0 0 0 0 1 1 1 1
ХХХХ 1111
хххх хххх
XOR 0 0 0 0 1 1 1 1
хххх хххх
Рис. 3.3. Операция И, включающее ИЛИ и исключающее ИЛИ
Предположим, что ситуация требует, чтобы крайние левые два бита (бит 0 и 1) ре-
гистра WREG должны быть установлены в 1, а биты 6 и 7 должны быть сброшены в 0.
Это выполняется посредством использования команды AND, очищающей биты 0 и 1, а
также команды IOR, устанавливающей единичное состояние битов 6 и 7. В примере 3.3
84
Применение микроконтроллеров PIC 18
приводится небольшая программа, выполняющая эту задачу. В данном случае регистр
WREG прежде всего загружается тестовым значением OxIF. Если программа выполня-
ется под управлением IDE, то содержимое регистра WREG изменяется на OxDC.
Пример 3.3
MOVLW OxIF
ANDLW OxFC
IORLW OxCO
;очистка битов 0 и 1
;установка битов 6 и 7
Stop: GOTO Stop
В следующем примере требуется, чтобы самые левые три бита регистра W были
инвертированы. Это выполняется с использованием операции XOR с литеральным зна-
чением ОхЕО (1110 0000), что приводит к инвертированию крайних левых трех битов
регистра W. Пример 3.4 показывает тестовую программу, которая инвертирует самые
левые три бита значения 0x90 (1001 ОООО). Результатом является 0x70 (0111 0000).
Пример 3.4
MOVLW 0x90
XORLW ОхЕО
Stop: GOTO Stop
/инвертирует левые 3 бита
Если сравнивать частоту использования всех логических команд, то команда AND
чаще всего используется для программирования маскирования битов регистров. На-
пример, предположим, что регистр WREG содержит число Ох4А, необходимы только
четыре самых крайних правых бита (А). Как выполнить маскирование четырех левых
битов? Команда ANDLW OxOF сотрет 4 в Ox4F, сформировав ОхОА в качестве результа-
та. Аналогичным образом, если требуются только четыре самых левых бита 4, можно
использовать команду ANDLW OxFO, стирающую самые правые 4 и оставляющую 0x40 в
регистре W.
3.2. Битовые команды
Нами были рассмотрены логические операции. В данном подразделе рассматри-
ваются битовые операции. Эти операции устанавливают, сбрасывают и переключают
состояние только одного отдельного бита, в то время как команды AND, IOR и XOR, яв-
ляясь байтовыми командами, могут изменять состояние как одно, так и нескольких би-
тов. Табл. 3.2 перечисляет битовые команды, реализованные в семействе PIC. Многие
применения микроконтроллеров требуют использования битовых команд для управле-
ния и тестирования в программе отдельных битов. Это особенно справедливо при
формировании интерфейса и управлении устройствами ввода-вывода.
А-бит (см. табл. 3.2) необходим только тогда, когда при программировании на
Ассемблере численный адрес регистрового файла используется в команде для специ-
фицирования либо банка доступа, либо регистра выбора банка. Если команда обраща-
ется к регистру по его имени либо по имени ячейки памяти вместо численного адреса,
то а-бит в программе не используется. Обратите внимание на то, что в табл. 3.2 а-бит
не специфицируется, когда в качестве операнда 1 используется регистр WREG. Ас-
семблер достаточно «интеллектуален» для того, чтобы знать, что банк доступа - это то
место, где расположен регистр WREG, поэтому а-бит не является необходимым в ко-
мандах, которые именуют конкретный регистр, - такой как WREG.
Глава 3. Набор команд семейства PIC 18
85
Таблица 3.2. Битовые команды
Команда Операнд 1 0перанд2 ОперандЗ Примеры Комментарий
BCF Регистр Бит № а-бит BCFWREG,7 BCF 0x10, 1,0 BCF 0x10, 1, ACCESS Сбрасывает бит 7 регист- ра W Сбрасывает бит 1 регистра банка доступа 0x10 Сбрасывает бит 1 банка доступа
BSF Регистр Бит № а-бит BSFWREG, 1 Устанавливает бит 1 ре- гистра W
BTFSC Регистр Бит № а-бит BTFSC WREG, 2 Если бит 2 W равен 0, то пропуск следующей команды
BTFSS Регистр Бит № а-бит BTFSS WREG, 7 Если бит 7 W равен 1, то пропуск следующей команды
BTG Регистр Бит № а-бит BTG WREG, 4 Переключение (инвертиро-
вание) бита 4 регистра W
Для иллюстрации команд BCF (очистка бита F) и BSF (установка бита F), при-
мер 3.3 был преобразован в пример 3.5 с использованием битовых команд вместо ко-
манд ANDLW и IORLW. Если эти примеры сравнить, то можно отметить, что пример 3.5
легче понимается, хотя разницы в результате нет. Между этими примерами есть не-
сколько отличий; одно из них заключается в том, что битовые команды не модифици-
руют регистр состояния, вместе с тем команды ANDLW и IORLW модифицируют регистр
состояния. Кроме того, поскольку изменяются состояния пар битов, то две битовые
команды необходимы для сброса или установки двух битов. Для модификации состоя-
ний нескольких битов более эффективно будет использовать команды ANDLW и IORLW.
Пример 3.5
MOVLW OxlP
BCF WREG, 0 /сброс бита 0
BCF WREG, 1 /сброс бита 1
BSF WREG, 6 /установка бита 6
BSF WREG, 7 /установка бита 7
Stop: GOTO Stop
Пример 3.6 использует условные битовые команды для установки бита 0 регистра
WREG только тогда, когда бит 7 равен 0. Команда BTFSS (битовое тестирование регистра
файла и пропуск в случае установки) тестирует бит 7 регистра WREG и если он в единичном
состоянии, то следующая команда (BCF) пропускается. Если бит 7 регистра WREG находится
в нулевом состоянии, то тогда команда BCF выполняется и устанавливается нулевое значе-
ние этого бита. Для контроля этого процесс используйте IDE и ее имитатор. Используйте
различные значения для команды MOVLW, - такие как Ox7F и OxFF.
Пример 3.6
MOVLW 0x7F
BTFSS WREG, 7
BCF WREG, 0
Stop: GOTO Stop
/загрузка тестовых данных
/очистка бита О
86
Применение микроконтроллеров PIC 18
Предположим, что нам необходима программа, которую мы бы могли использо-
вать с панелью PICDEM2 PLUS и которая бы отображала 0x05 на светодиодах, подклю-
ченных к битам от 0 до 3 порта В, когда кнопка, подключенная к биту 4 порта А не нажа-
та. Программа должна отображать 0x03, когда кнопка нажата. Нажатие кнопки генери-
рует логический 0, в противном случае генерируется логическая 1. Пример 3.7 показы-
вает программу, которая выполняет эту задачу. Если используется другая демонстра-
ционная панель то порты ввода-вывода и позиции битов необходимо откорректировать
для конкретной панели. Порты ввода-вывода адресуются как PORTA и PORTB при пере-
даче данных. Направление переноса данных для бита порта программируется на выход
посредством размещения нуля в соответствующем бите регистра TRISA или TRISB, а на
вход - посредством размещения 1 в соответствующем бите регистра TRISA или TRISB.
Регистр ADCON1 программируется на функционирование цифровых штырьков разме-
щением Ox7F в регистре ADCON1 либо как аналоговых штырьков размещением 0x00 в
регистр ADCON1. Обратите внимание на то, что функционирование и соответствующие
значения загрузки регистра ADCON1 изменяются для различных членов семейства
PIC18. Рассматриваемые здесь программы написаны для микроконтроллера
PIC18F1320. Если используется другой микроконтроллер, то соответствующие значе-
ния могут быть другими, либо регистр ADCON1 может не использоваться вообще.
Пример 3.7 0x7F ADCON1 ;объявление всех портов цифровыми
Main: MOVLW MOVWF
MOVLW 0x00
MOVWF TRISB ;порт В объявляется выходом
MOVLW OxFF
MOVWF TRISA ;порт А объявляется входом
Mainl: MOVLW 0x05 ;основной программный цикл
BTFSS PORTA, 0 /проверка состояния кнопки
MOVLW 0x03 /и пропуск этой команды, если кнопка отпущена
MOVWF PORTB /изменение состояния порта В и светодиодов
GOTO Mainl /повтор
Если команда адресует биты регистра состояния, то часто используется имя для
адресации конкретного бита. Например, для сброса бита переноса используется ко-
манда BCF STATUS, С вместо BCF STATUS,2.
3.3. Байтовые команды
Байтовые команды наиболее многочисленны как в наборе команд, так и в программах.
Байтовые команды обеспечивают возможность использования в программах переменных
данных, в то время как литеральные команды обеспечивают возможность использования в
программах постоянных данных. В типичном случае байтовые команды используют регистр
W, а также ячейку регистрового файла для выполнения какой-либо операции. Таблица 3.1
перечисляет все байтовые команды с одним либо двумя примерами на команду. Большинст-
во из этик команд имеют три операнда: первым обычно является ячейкой регистрового фай-
Глава 3. Набор команд семейства PIC 18
87
ла, второй определяет ячейку-приемник, а третий выбирает банк доступа или банк регистро-
вого файла, задаваемый регистром выбора банка (BSR). Если второй операнд (d-бит) равен
О, то ячейкой-приемником будет регистр WREG, а если второй операнд равен 1, то ячейкой-
приемником будет ячейка регистрового файла. Если третий операнд (а-бит) будет равен
нулю, то тогда банк доступа будет использоваться как местоположение регистрового файла
(обычно OxOOO-Ox07F и OxPSO-OxFFF), а если он будет равен единице, то тогда банк, опре-
деляемый BSF, будет использоваться в качестве месторасположения регистрового файла.
А-бит требуется только при адресации регистра файла по номеру; если доступ будет осуще-
ствляться по метке, то а-бит не будет использоваться в команде. По умолчанию а = 1. D-бит
необходим только для размещения результата операции в регистр WREG; по умолчанию
d = 1. На языке Ассемблера буква W или F используются для указания необходимости ис-
пользования d-бита. Некоторые примеры этого приводятся в табл. 3.3.
Предположим, что два 16-разрядных числа складываются, формируя 16-разрядную
сумму. До этого подраздела эту операцию было выполнить довольно трудно, однако благода-
ря тому, что среди байтовых команд имеется команда сложения с переносом, сейчас можно
более легко складывать два числа, которые имеют больше, чем 8 разрядов. Пример 3.8 пока-
зывает короткую программу, которая складывает 16-разрядное число, расположенное в ячей-
ках банка доступа с адресами 0x10 и 0x11, с 16-разрядным числом, расположенным в ячейках
банка доступа с адресами 0x12 и 0x13. Оба эти числа хранятся с использованием формата с
обратным порядком байтов, когда младшая часть числа хранится в ячейке с меньшим номе-
ром. Результат этого 16-разрядного сложения сохраняется в ячейках банка доступа 0x14 и
0x15. Программа кажется слишком длинной, однако ее часть, которая выполняет собственно
сложение (последние шесть команд) весьма коротка. Обратите внимание на то, как складыва-
ются младшие байты, а затем складываются старшие байты с переносом. Используя эту мето-
дику, можно складывать числа любой длины. Рис. 3.4 демонстрирует работу программы, а
также то, как используется перенос при формировании 16-разрядной суммы.
Таблица 3.3. Байтовые команды
Команда Операнд! 0перанд2 ОперандЗ Примеры Комментарий
ADDWF регистр d-бит а-бит ADDWF 0x10,W, 0 ADDWFOx-Ю, F, 0 Складывает W и ячейку банка доступа 0x10, сохраняет результат в W Складывает W и ячейку банка- доступа 0x10, сохраняет результат в ячейке банка доступа 0x10
ADDWFC регистр d-бит а-бит ADDWFC 0x10,0,0 ADDWFCOx-10, 1, 1 Складывает W с переносом с ячейкой банка доступа 0x10, сохраняет результат в W Складывает WREG с переносом и ячейку банка BSR 0x10, сохраняет результат в ячей- ке банка BSR 0x10
ANDWF CLRF регистр регистр d-бит а-бит а-бит ANDWF 0x10,0, 1 CLRFWREG CLRF 0x10, ACCESS CLRF BOB И W с ячейкой банка доступа 0x10, сохраняет результат в W Сбрасывает W в 0x00 Очищает ячейку банка досту- па 0x10 в 0x00 Очищает ячейку ВОВ
COMF регистр d-бит а-бит COMFWREG COMF 0x10,0,0 Дополнение W до 1 Дополнение до единицы ячей-
ки банка доступа 0x10
88
Применение микроконтроллеров PIC 18
Команда Операнд! 0перанд2 ОперандЗ Примеры Комментарий
COMF 0x10, 1, 1 Дополнение до единицы ячей- ки банка BSR 0x10
CPFSEQ регистр А-бит CPFSEQ 0x10,0 CPFSEQOxH, 1 Сравнение W с ячейкой банка доступа 0x10 и пропуск сле- дующей команды, если есть равенство Сравнение W с ячейкой банка BSR 0x11 и пропуск следую- щей команды, если есть ра- венство
CPFSGT регистр а-бит CPFSGT 0x12,0 Сравнение W с ячейкой банка BSR 0x12 и пропуск следую- щей команды, если содержи- мое ячейки банка доступа 0x12 Больше, чем WREG
CPFSLT регистр а-бит CPFSLT 0x13, 1 Сравнение W с ячейкой банка BSR 0x13 и пропуск следую- щей команды, если содержи- мое ячейки банка доступа 0x13 меньше, чем WREG
DECF регистр d-бит а-бит DECFWREG DECF 0x10, 0,0 DECF 0x10,1,0 Вычитание 1 из W Вычитание 1 из ячейки банка доступа 0x10 и сохранение результата в ячейке банка доступа 0x10 Вычитание 1 из ячейки банка доступа 0x10 и сохранение результата в ячейке банка доступа 0x10
DECFSZ регистр d-бит а-бит DECFSZ WREG Декрементирование W и про- пуск следующей команды, если результат нулевой
DCFSNZ регистр d-бит а-бит DCFNSZOxlO, 1,0 Декрементирование ячейки банка доступа OxIC и про- пуск следующей команды, если результат не равен 0
INCF регистр d-бит а-бит INCFWREG INCF 0x10, 0,0 Инкрементирование W. Инкрементирование ячейки банка доступа 0x10
INCFSZ регистр d-бит а-бит INCFSZ WREG Инкрементирование W и если результат равен нулю, про- пуск следующей команды.
INFSNZ регистр d-бит а-бит INFSNZ WREG Инкрементирование W и если результат не равен нулю, пропуск следующей команды
IORWF регистр d-бит а-бит IORWF 0x10,0,0 Включающее-ИЛИ W с ячейкой банка доступа и сохранение результата в ячейке банка доступа 0x10
MOVE регистр d-бит а-бит MOVE 0x10,0,0 Копирование ячейки банка доступа 0x10 в W
MOVFF регистр source регистр destination MOVFF WREG, 0x130 Копирование W в ячейку 0x130
MOVWF регистр а-бит MOVWF 0x10,0 Копирование W в ячейку бан- ка доступа 0x10
Глава 3. Набор команд семейства PIC18
89
Команда Операнд! Операнд? ОперандЗ Примеры Комментарий
MULWF регистр а-бит MULWF 0x10,0 Умножение W на ячейку банка доступа 0x10 и сохранение произведения в PRODL и PRODH
NEGF регистр а-бит NEGF WREG Дополнение до 2 (отрицание) W
RLCF регистр d-бит а-бит RLCF WREG Циклический сдвиг влево W с переносом
RLNCF регистр d-бит а-бит RLNCF WREG Циклический сдвиг влево W без переноса
RRCF регистр d-бит а-бит RRCF WREG Циклический сдвиг вправо W с переносом
RRNCF регистр d-бит а-бит RRNCF WREG Циклический сдвиг вправо W без переноса
SETF регистр а-бит SETF WREG Загрузка OxFF в W
SETF 0x11, ACCESS Загрузка OxFF в ячейку бан- ка доступа 0x11
SUBFWB регистр d-бит а-бит SUBFWB 0x10, 0,0 Вычитание с заимствованием ячейки банка доступа 0x10 из W и сохранение результа- та в ячейке банка доступа 0x10
SUBWF регистр d-бит а-бит SUBWF 0x10,0,0 Вычитание W из ячейки банка доступа 0x10 и сохранение результата в ячейке банка доступа 0x10
SUBWFB регистр d-бит а-бит SUBWFB 0x10,0,0 Вычитание W и заимствование из ячейки банка памяти 0x10
и сохранение результата в ячейке банка доступа 0x10
SWAPF регистр d-бит а-бит SWAPF WREG Свопинг полубайтов в W
TSTFSZ регистр d-бит TSTFSZ WREG Пропуск следующей команы, если W равен нулю
XORWF регистр d-бит а-бит XORWF 0x10,0,0 Исключающее-ИЛИ W с ячейкой банка доступа 0x10 и сохра- нение результата в ячейке банка доступа 0x10
С
0x15
0000 0100
0x14
0000 0010
Рис. 3.4. Пример 16-разрядного сложения.
90
Применение микроконтроллеров PIC 18
Пример 3. 8
MOVLW MOVWF MOVLW MOVWF OxFF 0x10 0x01 0x11 ;сохранение OxOIFF /в 0x10 и 0x11
MOVLW 0x03 /сохранение 0x0203
MOVWF 0x12 /в 0x12 и 0x13
MOVLW 0x02
MOVWF 0x13
MOVF 0x10, W, ACCESS /сложение 0x10 и 0x12
ADDWF 0x12, W, ACCESS
MOVWF 0x14 /сохранение результата в 0x14
MOVF 0x11, W, ACCESS /сложение 0x11 и 0x13 с переносом
ADDWFC 0x13, W, ACCESS
MOVWF 0x15 /сохранение результата в 0x15
Stop: GOTO Stop
Намного более читабельная и легкая в написании версия этой программы приве-
дена в примере 3.9. Разница между примером 3.8 и примером 3.9 заключается в том,
что для определения ячеек памяти используется ассемблер, который делает ненужным
использование всех операндов, использованных в примере 3.8. Область UDATA уже
определена в шаблоне программы и секция программы по примеру 3.9 добавляется к
шаблону без дополнительной директивы UDATA (пользовательские данные). Если дан-
ные должны быть размещены в банке доступа, то директива UDATA_ACS перед коман-
дами RES (резервировать память). Это обеспечивает возможность выбора того, где
данные будут сохраняться. Данные, сохраненные в банке доступа, обычно извлекаются
быстрее, поскольку регистр выбора банка не должен инициализироваться адресом
банка.
Пример 3.9
UDATA
NumIL RES 1 ; переменные, зарезервированные по имени в UDATA
NumlH RES 1
Num2L RES 1
Num2H RES 1
AnsL RES 1
AnsH RES 1
Main:
MOVLW Oxff ; сохраняете OxOIff
MOVWF NumIL ; в Numi
MOVLW 0x01
MOVWF NumlH
MOVLW 0x03 ; сохраняет 0x0203
MOVWF Num2L ; в Num2
MOVLW 0x02
MOVWF Num2H
Глава 3. Набор команд семейства PIC18
91
MOVF NumIL ; складывает младшие части
ADDWF Num2H, W
MOVWF AnsL ; сохраняет результат AnsL
MOVF NumlH ;складывает старшие части с переносом
ADDWFC Num2H, W
MOVWF AnsH ; сохраняет результат в AnsH
Stop: GOTO Stop
Для выполнения 16-разрядного вычитания, программа по примеру 3.9 модифи-
цируется посредством замены команд ADDFW и ADDWFC командами SUBFW и SUBWFB.
Кроме того, ячейки операндов регистрового файла должны быть изменены ввиду спо-
соба, которым работает операция вычитания. Команда вычитания всегда вычитает
WREG из ячейки регистрового файла, указанной в команде. Пример 3.10 демонстриру-
ет 16-разрядное вычитание. Данный пример использует те же самые определения дан-
ных, что и пример 3.9.
Пример 3.10
MOVLW MOVWF MOVLW MOVWF OxFF NumIL 0x01 NumlH /сохраняет OxOIFF ;b Numl
MOVLW 0x03 /сохраняет 0x0203
MOVWF Num2L /в Num2
MOVLW 0x02
OVW Num2H
MOVF NumIL /вычитает младшие части
SUBWF Num2H, W
MOVWF AnsL / сохраняет результат AnsL
MOVF NumlH /вычитает старшие части с заимствованием
SUBWFB Num2H, W
MOVWF AnsH /сохраняет результат в AnsH
Stop: GOTO Stop
Циклический сдвиг. Набор команд семейства PIC18 включает четыре байтовых ко-
манды циклического сдвига. Байты сдвигаются вправо или влево с переносом, либо
без переноса. Рис. 3.5 иллюстрирует эти четыре команды циклического сдвига.
Один из методов умножения либо деления связан с циклическим сдвигом чисел.
Если число циклически сдвигается влево с нулем, помещаемым в самый правый раз-
ряд, то это значит, что число умножается на коэффициент, равный 2. Аналогичным об-
разом, если число циклически сдвигается вправо с нулем, помещаемым в самый левый
разряд, то это значит, что число делится на коэффициент, равный 2. Для деления се-
92
Применение микроконтроллеров PIC 18
мейство знаком на два бит знака циклически сдвигается в самый левый бит результата.
Однако, если число может быть умножено, либо поделено на два, то оно может быть
поделено либо умножено на любое число.
Например, для умножения на 5 (пять равно 4х плюс 1х или Ю12), нужно умножить
число на 4 (два циклических сдвига влево), а затем добавить к результату исходное
число. Эта операция иллюстрируется примером 3.11. Этот пример умножает тестовое
число 4, находящееся во WREG, на коэффициент 5 и оставляет результат, рав> 1ый 20, во
WREG. Эта программа функционирует корректно, однако команда умножения, входя-
щая в состав набора команд PIC, является более эффективной. Смотрите ту же про-
грамму, использующую команду MULWP в примере 3.12. Также обратите внимание в
этой программе, как очищается бит переноса при использовании команды BCF.
Рис. 3.5. Четыре команды циклического сдвига
Пример 3.11
UDATA_ACS
Num RES 1 /регистр в области доступа UDATA
Main:
MOVLW 4 ;загрузка тестового значения
MOVWF Num /сохранение 1х по адресу 0x10
BCF STATUS, 0 /сброс переноса
RLCF WREG /WREG х 2
BCF STATUS, 0
RLCF WREG /WREG х 4
ADDWF Num, 0 /WREG х 5
Stop: GOTO Stop
Глава 3. Набор команд семейства PIC18
93
Пример 3.12
UDATA_ACS
Num RES 1
Main:
; регистр в области доступа UDATA
MOVLW 5
MOVWF
MOVLW
MULWF
MOVFF
NUM
4
NUM
PRODL, WREG
/сохранение 5 в 0x10
/загрузка тестового значения
/умножение на 5
/занесение 8-разрядного произведения во WREG
Stop: GOTO
Stop
Если нужно выполнить деление на степень 2, то это достигается сдвигом числа
вправо.
При использовании команды циклического сдвига сдвиг вправо выполняется по-
средством предварительной очистки флага переноса, за которым следует команда
RRCF. Предположим, нам нужно поделить содержимое регистра WREG на 8. Это дости-
гается посредством трех сдвигов вправо, как это показано в.примере 3.13. Обратите
внимание, что результат округляется после того, как обнаружено возникновение пере-
носа после последнего циклического сдвига вправо. Бит переноса тестируется и ко-
манда пропуска по нулю используется для пропуска команды INCF (инкремент) в слу-
чае, если перенос является нулевым. В данном случае 100 десятичное делится на 8 и
результат, равный 12.5 остается boWREG как 13 (округленное 12.5). Больше информа-
ции и программы для деления приводятся в главе 4 в форме примеров программ на
языке Ассемблера.
Пример 3. .13
MOVLW .100 /загрузка во WREG 100 десятичное
BCF STATUS, 0 /деление на 8
RRCF WREG
BCF STATUS, 0
RRCF WREG
BCF STATUS, 0
RRCF WREG
BTFSC STATUS, 0 /округление результата
INCF WREG
Stop: GOTO Stop
Для иллюстрации работы команд циклического сдвига на демонстрационной па-
нели, - такой как PICDEM2 PLUS, следует предварительно запрограммировать порт В
как выходной порт, а порт А - как входной порт. Приведенный далее программный при-
мер в случайном порядке выбирает один из четырех светодиодов, подключенных к пор-
ту В, когда отпущена кнопка, подсоединенная к штырьку 4 порта А. Для выполнения
этого в примере 3.14 используется команда циклического сдвига без переноса. В дан-
ном примере при нажатии кнопки будут светиться все светодиода, а при ее отпускании
только один светодиод будет включаться в случайном порядке.
94
Применение микроконтроллеров PIC 18
Пример 3.14
Main:
Mainl:
MOVLW 0x00
MOVWF TRISB
MOVLW OxFF
MOVWF TRISA
MOVLW 0x11
MOVWF PORTB
BTFSS PORTA,
RLNCF PORTB
4
GOTO Mainl
/программирование портов А и В
/запуск порта В по 0x11
/циклический сдвиг, если кнопка нажата
/повторение
3.4. Команды управления выполнением программы и
косвенная адресация
Перед тем, как приступить к реальному программированию, нам следует изучить
команды управления выполнением программы. В данном подразделе рассмотрены
команды управления программой, приводятся также дополнительные примеры, выпол-
няющие простые задачи. Команды управления выполнением программы модифициру-
ют направление передачи управления в программе через условные переходы и вызовы
функций. Они также предоставляют некоторую степень контроля над некоторыми внут-
ренними функциями микроконтроллера. Также рассмотрена косвенная адресация че-
рез регистры выбора файлов (FSRO, FSR1 и FSR2). Табл. 3.4 иллюстрирует команды
управления выполнением программы, доступные микроконтроллерам семейства
PIC18.
Команда GOTO уже использовалась в программах, однако до сих пор она не раз-
биралась достаточно детально. GOTO - это 32-разрядная команда, которая может вы-
полнять переход на любую ячейку памяти программ. Команда BRA (постоянный пере-
ход), которая также выполняет безусловный переход, представляет собой
16-разрядную команду, диапазон перехода в которой ограничен. Команда BRA содер-
жит 11-разрядное число, которое является не адресом, а приращением адреса. Это
приращение или смещение, как его часто называют, позволяет BRA осуществлять пе-
реход в программе вперед на расстояние вплоть до 1024 байтов от адреса следующей
команды в программе либо назад вплоть до —1024 байт от адреса следующей коман-
ды в программе. Этот тип перехода часто называют относительным переходом, по-
скольку эта команда инициализирует переход в соответствии с указанным значением
смещения вне зависимости от того, в каком месте памяти она расположена. Все ко-
манды условного перехода используют форму адресации со смещением, однако в них
используется еще более короткий диапазон перехода - от +127 до -128 байт, отсчиты-
вая от адреса следующей команды программы. Причиной таких ограничений является
ограничение количества битов, доступных в команде для адресации памяти. Команду
GOTO часто называют абсолютным переходом, поскольку адрес перехода в ней явля-
ется фиксированным или абсолютным. Команду BRA и команду условного перехода
часто называют командами относительного перехода, потому что адрес перехода оп-
ределяется относительным адресом команды перехода в памяти программ.
Глава 3. Набор команд семейства PIC 18
95
Таблица 3.4. Команды управления выполнением программы.
Команда Операнд 1 Операнд 2 Примеры Комментарий
ВС nl ВС AGAIN Переход к AGAIN если перенос равен 1
BN nl BNWOW Переход к WOW если отрицателен
BNC nl BNC FLOP Переход к FLOP если перенос равен 0
BNN nl BNN POSITIVE Переход к POSITIVE если не отрицателен
BNOV nl BNOV BIG Переход к BIG если нет переполнения
BNZ nl BNZ MORE Переход к MORE если нет нуля
BOV nl BOV NOW Переход к NOW если переполнение
BRA n2 BRA WINK Безусловный переход к WINK
BZ nl BZ BOSTON Переход к BOSTON если ноль
CALL n3 S CALL HOME Вызов функции с именем НОМЕ
CLRWDT CLRWDT Сброс сторожевого таймера
DAW DAW Десятичная подстройка содержимого WREG
GOTO n3 GOTO ERIE Безусловный переход к ERIE
NOP NOP Нет операции
POP POP Извлечение адреса возврата из вершины
стека
PUSH PUSH Занесение адреса возврата в вершину
стека
RCALL n2 RCALL 6 Относительный CALL по адресу счетчик команд +2+2*6 вперед по программе
RESET RESET Программный сброс
RETFIE S RETFIE 1 Возврат из прерывания с теневыми реги- страми, загруженными в регистры и раз- решенными прерываниями
RETLW L RETLW 6 Возврат из функции со значением 6 во WREG
RETURN S RETURN 1 Возврат из функции с теневыми регист- рами, загруженными в регистры.
SLEEP SLEEP Вход в режим бездействия
Примечания: nl = 8-разрядное смещение, п2 = 11 - разрядное смещение,
пЗ = 21 -разрядный абсолютный адрес, s = теневой бит, I = 8-разрядный
литерал.
Многие из команд управления используются для реализации программных кон-
струкций, составляющих строительные блоки программ. Этими конструкциями являют-
ся следующие конструкции: «if-then-else» (Если-то-иначе), «repeat-until» (Повторять-
пока) («do-while» (делать-пока) или «do-for» (делать-для условия)), «while» (пока) и
функций.
Команды CALL и RETURN используются для создания функций или подпрограмм,
используемых в программе. Команда CALL заносит адрес возврата во внутренний про-
граммный стек, а затем выполняет операцию GOTO по адресу памяти, указанному в
операнде команды CALL. Команда RETURN выполняет возврат из функции, - точно так
же, как она это делает в языке С. Что команда RETURN делает фактически - так это из-
влекает адрес возврата из программного стека и заносит его в счетчик команд. Коман-
да CALL используется для вызова функции, a RETURN используется для возврата из
функции. Команда RETURN всегда возвращает управление команде, следующей непо-
средственно после самой последней команды CALL.
Команды PUSH и POP также осуществляют доступ к программному стеку микро-
контроллера. Команда PUSH используется для предварительной загрузки адреса воз-
врата, равного PC (счетчик команд) + 2 в программный стек, а команда POP использу-
96
Применение микроконтроллеров PIC 18
ется для извлечения адреса возврата из стека. Обе эти команды должны использовать-
ся с осторожностью.
Команда NOP не выполняет абсолютно ничего, за исключением того, что на нее
расходуется один командный цикл. Команда NOP иногда используется при отработке
временных задержек на один командный цикл. NOP также добавляется к некоторым
командам ассемблером.
Команда RETLW используется для возврата из функции с регистром WREG, за-
груженным операндом команды RETLW. Она используется в некоторых программах на
Ассемблере для возврата значения функции.
Рис. 3.6. Конструкция “if-then-else”
Программные конструкции
Программные конструкции - это строительные блоки программирования - их не-
обходимо обсудить с тем, чтобы программы, которые вы будете писать, были эффек-
тивными. Первая конструкция, которую мы разберем - это конструкция “if-then-else"
(если-то-иначе). Рис. 3.6 иллюстрирует общую форму этой конструкции.
Обратите внимание на вопрос, (см. рис. 3.6). Он звучит как: “В комнате жарко?”.
Если в комнате жарко, то программа переходит на блок кодов, обеспечивающих пони-
жение температуры в комнате, иначе (т.е. в противном случае) выполняется нагрев. Эта
конструкция используется тогда, когда в программе задается какой-либо вопрос. Блок
кода, назначением которого является задание вопроса, иллюстрируется в приме-
ре 3.15. Данный пример тестирует регистр банка доступа 0x10 на наличие значения,
равного 4. Если содержимое этого регистра равно 4, то по адресу 0x10 заносится 6.
Если это не так, то по адресу 0x10 заносится 9.
Глава 3. Набор команд семейства PIC18
97
Пример 3.15
MOVLW SUBWF BNZ MOVLW BRA 4 0x10, 0 NOPE 6 DONE1 / если ; если не 4 4
NOPE: DONE1 MOVLW MOVWF 9 0x10 /запись 6 или
Предположим, что нам нужно преобразовать числа от 0x00 до OxOF во WREG из
шестнадцатиричного кода в код ASCII. Цифры ASCII лежат в диапазоне от 0x30 до 0x39,
а буквы от А до F соответствуют значениям от 0x41 до 0x46. Для выполнения этого пре-
образования 0x30 прибавляется к шестнадцатиричной цифре (0x00-0x09) и 0x37 при-
бавляется к шестнадцатиричной букве (OxOA-OxOF). Конструкция "if” (если), иллюст-
рируемая примером 3.16, Используется для выполнения этой простой задачи. В этом
примере выполняется прибавление значения 0x30, а затем, соли результат является
меньшим, чем ОхЗА, добавляется еще семерка для преобразования букв. Данный при-
мер для обеспечения функционирования программы использует две временные ячейки
в регистровом файле данных. Хотя объявления этих ячеек в данном примере не приве-
дены, они определяются е Использованием RES 1 в секции UDATA исходного файла.
Команда CPFSGT выполняет сравнение содержимого Тетр2 (ОхЗА) с W и если Тетр2
больше, чем W,команда ADDLW пропускается.
Пример 3.16
ADDLW 0x30
MOVWF Tempi
MOVLW ОхЗА
MOVWF Temp2
MOVFF Tempi, WREG
CPFSGT Temp2
ADDLW 0x07
.•добавляет 0x30
/пропуск для от 0 до 9
/только для ЗА либо больше
Имеется еще более короткий, хотя и менее прозрачный, метод выполнения на-
званного преобразования - он иллюстрируется примером 3.17. В нем для выполнения
преобразования используется команда DAW в немного необычной манере. Команда
DAW предназначена для перевода числа boWREG в двоично-кодированную десятичную
(ДКД) форму после выполнения ДКД-сложения. Она выполняет это посредством оцен-
ки значения младшего полубайта и если оно является большим, чем 9 или установлен
DC-бит (бит половинного переноса), то выполняется добавление 6. Она также оценива-
ет старший полубайт и если он является большим, чем 9 или установлен бит С (бит пе-
реноса), то выполняется добавление 0x60. Это приводит к тому, что результат будет
равен от 0x30 до 0x39 для чисел и от 0x40 до 0x45 для букв. Как можно видеть, резуль-
таты для букв меньше на единицу, чем необходимые корректные значения, поэтому
применяется команда BTFSC (тестирование бита и пропуск, если сброшен) для про-
верки бита 6 результата. Бит 6 сбрасывается для шестнадцатиричных чисел и устанав-
ливается для шестнадцатиричных букв. После команды BTFSC выполняется команда
инкрементирования WREG только для значений от 0x40 до 0x45 с целью генерирования
корректных значений для букв - от 0x41 до 0x46.
98
Применение микроконтроллеров PIC 18
Пример 3.17
ADDLW 0x30
DAW
BTFSC WREG, 6
INCF WREG
Хотя это и эффективно, однако, возможно, более функциональным будет помес-
тить эту операцию в функцию. Функции часто используются для снижения трудоемко-
сти написания программ. Пример 3.18 показывает, как оформить программу, согласно
примеру 3.17, в функцию, называемую Hex2ASCII, что является удачным именем для
этой функции. Всегда старайтесь называть функцию так, чтобы ее имя отражало работу
функции . Эта функция Hex2ASCII преобразует шестнадцатиричные цифры во WREG в
ASCII-цифры boWREG.
Пример 3.18
,-*** Функция преобразования шестнадцатиричного формата в формат ASCI ***
;Преобразование правого полубайта во WREG в ASCII-код во WREG
Hex2ASCII:
ANDLW OxOF ;очистка старшего полубайта
ADDLW 0x30 /преобразование в ASCII
DAW BTFSC WREG, 6
INCF RETURN WREG
/***Главная программа
Main:
MOVLW 0x5c ;загрузка тестовых данных
MOVWF ASCII_H
CALL Hex2ASCII /преобразование младшего полубайта
MOVWF ASCII_L /сохранение его в ASCII_L
MOVFF ASCII_H, WREG
SWAPF WREG /получение старшего полубайта
CALL Hex2ASCII /преобразование его в ASCII
MOVWF ASCII_H /сохранение в ASCII_H
Stop: BRA Stop
Команда CALL помещает адрес возврата во внутренний стек (32x21), а затем от-
рабатывает переход по абсолютному адресу функции, которая в данном случае назы-
вается Hex2ASCII. Адрес возврата всегда указывает на команду, которая следует непо-
средственно после CALL. Если взять первую команду CALL в приведенной программе,
то адресом возврата будет адрес ячейки памяти, содержащей команду MOVWF ASCII_L.
Всякий раз, когда встречается команда RETURN, микроконтроллер извлекает самый
последний адрес возврата из стека и выполняет переход по этому адресу. Вследствие
того, что стек состоит из 31 ячейки, вложение вызовов функций может выполняться на
глубину вплоть до 31. Обратите внимание, что большинство программ используют все-
го несколько ячеек стека.
Глава 3. Набор команд семейства PIC18
99
Имеется два типа команд возврата: обычная уже описанная команда возврата
(RETURN) и другая команда (RETURN 1), которая называется быстрым возвратом, по-
скольку хотя она и не быстрее обычного RETURN, однако она автоматически восстанав-
ливает значение регистров WREG, STATUS и BSR. Для использования этой функции
восстановления, функция должна быть вызвана командой CALL SUBROUTINE, 1. CALL
со вторым параметром, равным 1, автоматически сохраняет регистры WREG, STATUS и
BSR во внутренних скрытых теневых регистрах. Команда RETURN 1 извлекает данные
из этих теневых регистров. Другим типом возврата является команда RETLW. Так, ко-
манда RETLW 6 возвращает управление вызывающей программе, однако также заносит
6 в регистр WREG при возврате. Большинство функций используют пару команд CALL и
RETURN.
Пример 3.19 иллюстрирует то, как пишется новая функция, названная Hex2ASC,
которая использует вложенный вызов функции Hex2ASCII. Функция Hex2ASCII вызыва-
ется функцией Hex2ASC два раза, что требует одну ячейку стека для адреса возврата
для Hex2ASC и еще одну - для Hex2ASCII. Программа стала более читабельной вследст-
вие использования новой функции, которая преобразует полностью байт. Единствен-
ными регистрами, которые использует эта программа, являются регистры WREG,
ASCII_L и ASCII_H. Программа также при своем выполнении использует два уровня сте-
ка. Одним из способов улучшения этой программы является возврат двух символов
ASCII в регистрах PRODL и PRODH. Благодаря этому при преобразовании не будуг ис-
пользоваться регистры общего назначения, это хорошо - так как регистры общего на-
значения часто бывают в дефиците.
Пример 3.19
;»************фуНКЦИЯ Нех2ASCII
; использует 1 уровень стека
;использует WREG
; преобразует правый полубайт во WREG из шестнадцатеричного формата в ASCII-код
Hex2ASCII:
ANDLW OxOF /изолирует младший полубайт
ADDLW 0x30
DAW
BTFSC WREG, 6
INCF WREG
RETURN
***** Функция Hex2ASC * *************
; использует 2 уровня стека
; использует WREG, ASCII_L и ASCII_H
; использует Hex2ASCII
; преобразует байт во WREG из шестнадцатиричного формата в формат ASCII
; при этом ASCII_L содержит самую правую ASCII-цифру
; a ASCII_H содержит самую левую ASCII - цифру
Hex2ASC:
MOVWF ASCII_H
CALL Hex2ASCII
MOVWF ASCII L
;преобразует младший полубайт
100
Применение микроконтроллеров PIC 18
MOVFF ASCII_H, WREG
SWAPF WREG
CALL Hex2ASCII
MOVWF ASCII H
/выполняет своппинг полубайтов
;преобразует старший полубайт
RETURN
.**************Главная программа ******************
Main:
MOVLW Ox5с
CALL Hex2ASC
Stop: BRA Stop
/загружает тестовые данные
/преобразует полностью байт в формат ASCII
Конструкция "repeat-until" (повторять до тех пор, пока) повторяет операцию фик-
сированное количество раз либо до тех пор, пока будет справедливо некое условие.
Рис. 3.7 иллюстрирует конструкцию "repeat-until".
Предположим, что регистры памяти данных с адресами от 0x10 до 0x28 сбрасы-
ваются программой в состояние 0x00. Это может быть выполнено посредством исполь-
зования нескольких команд MOVWF. Однако более элегантный способ заключается в
использовании косвенной адресации совместно с конструкцией "repeat-until". Цикл
будет повторяться 0x19 раз, сохраняя 0x19 нулей в 0x19 различных ячейках регистрово-
го файла. Имеется 0x19 ячеек между 0x10 и 0x28 (разность плюс 1). Пример 3.20 пока-
зывает программу, которая решает эту задачу.
Пример 3.20
LFSR MOVLW 0, 0x10 0x19 /адрес 0x10 через FSR0 /загрузка WREG счетчиком
Loop: CLRF POSTINCO /очистка ячейки и инкрементирование указателя
DECFSZ WREG /декрементирование счетчика, пропуск BRA, если 0
BRA Loop /повтор цикла до тех пор, пока WREG не станет
Stop: BRA Stop /нулевым
Таблица 3.5. Детали косвенной адресации
Мнемоника операндов Пример Комментарий
INDF0 MOVFF WREG, INDF0 Копирует WREG в ячейку памяти, косвен- но адресуемую FSR0
INDF1 INCF INDF1 Инкрементирует содержимое ячейки памя- ти, адресуемой FSR1
INDF2 MOVWF INDF2 Копирует WREG в ячейку памяти, косвен- но адресуемую FSR2
POSTDEC MOVWF POSTDECO Копирует WREG в ячейку памяти, косвен- но адресуемую FSR0, а затем вычитает 1 из FSR0
MOVFF POSTDECO, POSTDEC1 Копирует содержимое ячейки памяти, адресуемой FSR0, в ячейку памяти, ад- ресуемую FSR1, а затем выполняет дек- рементирование как FSR0, так и FSR1
POSTING CLRF POSTINC2 Очищает ячейку памяти, адресуемую FSR2, а затем инкрементирует FSR2
PREINC DECF PREINCI Инкрементирует FSR1, а затем декремен- тирует содержимое ячейки памяти, те- перь адресуемой FSR1
PLUSW INCF PLUSW0 Инкрементирует содержимое ячейки памя- ти, адресуемой FSR0 + WREG
Глава 3. Набор команд семейства PIC18
101
Рис. 3.7. Конструкция "repeat-until"
Косвенная адресация
Пример 3.21 является первым примером использования косвенной адресации.
Микроконтроллер имеет три регистра, которые используются для косвенной адреса-
ции ячеек памяти. Эти регистры называются регистрами выбора файла (FSRO, FSR1 и
FSR2). По некоторым причинам единственной командой, которая использует FSR в качестве
операнда, является команда LFSR, которая используется для занесения адреса ячейки памя-
ти файла данных в FSR. Все другие команды, выполняющие адресацию через регистр выбо-
ра файла, используют другие мнемонические обозначения. В табл. 3.5 перечислены мне- <.
ионические обозначения и их функции в случае применения этих мнемонических обо-
значений к косвенной адресации через регистры FSR.
Для иллюстрации возможностей этих косвенных операндов, предположим, что
блок данных по адресам памяти данных от 0x10 до 0x32 должен быть сложен с блоком
данных, расположенным по адресам памяти данных от 0x40 до 0x62. Каждый блок со-
держит 0x23 ячеек памяти. Соответствующая программа требует организации цикла,
выполняемого 0x23 раза, она также требует использования косвенной адресации для
доступа к обеим областям памяти данных с использованием двух регистров выбора
файлов (FSR0 и FSR1). Программа, выполняющая эту задачу, приведена в приме-
ре 3.22. Обратите внимание на то, как используется регистр 5 в качестве счетчика при
программировании цикла.
102
Применение микроконтроллеров PIC 18
Пример
LFSR
LFSR
MOVLW
MOVWF
Loop:
MOVF
ADDWF
DECFSZ
BRA
Stop: BRA
3.21
0, 0x10
1, 0x40
0x23
5
POSTINCO, 0
POSTINCI
5
Loop
Stop
/адресация 0x10 через FSRO
;адресация 0x40 через FSR1
/получение 0x23 для счета
;сохранение счетчика в ячейке 5
/получение ячейки блока 1 во WREG
/сложение WREG с ячейкой блока 2
/декрементирование счетчика
/прогон цикла 0x23 раза
Предположим, что в памяти содержится информация, полученная от некоторого
внешнего устройства и программа должна просмотреть память данных на предмет на-
личия вхождения числа OxOD. Соответствующая таблица расположена по адресам от
0x20 до 0х5А. Данная таблица имеет длину, равную ОхЗВ ячейкам. Если число OxOD бу-
дет обнаружено, то программа продолжит выполняться по метке Foundlt, а если это
число обнаружено не будет, то программа продолжит свое выполнение по метке
NotFound.
Пример 3. 22
LFSR 0, 0x20 /адресация 0x20 через FSRO
MOVLW 0x3В
MOVWF 5
Loop:
MOVLW OxOD /загрузка WREG значением OxOD
SUBWF POSTINCO, 0
BZ Foundlt /если найдено
DECFSZ 5 ;проверка счетчика на
BRA Loop /неравенство нулю
NotFound:
**** код для случая,
когда OxOD не найдено
Foundlt:
**** код для случая,
когда OxOD найдено ****
Stop: BRA Stop
Последней программной конструкцией является конструкция “while” (до тех пор,
пока), которая иллюстрируется рис. 3.8. Предположим, что пример 3.22 переписан с
использованием конструкции while вместо конструкции repeat-until. В этом примере-
поиск OxOD повторяется до тех пор, пока счетчик не станет нулевым. Для выполнения
этой задачи для всех ячеек, значение счетчика должно увеличиваться на 1. Пример 3.23
иллюстрирует новую программу, использующую конструкцию while.
Глава 3. Набор команд семейства PIC 18
103
Пример 3.23
LFSR 0, 0x20 ; адресация 0x20 через FSR0
MOVLW ОхЗС
MOVWF 5
Loop:
DCFSNZ 5 /проверка счетчика
BRA NotFound
MOVLW OxOD ;до тех пор, пока счетчик ненулевой
SUBWF POSTINCO, 0
BNZ Loop ;если число еще не найдено
Foundlt:
; * * ** код, если OxOD найдено ****
NotFound:
; **** код, если OxOD не найдено ****
Если сравнить два приведенные примера, то можно заметить, что фактически
изменилось только место размещения команды декрементирования счетчика. В вер-
сии программы, использующей конструкцию repeat—until по примеру 3.22, проверка
после декрементирования - это последняя проверка цикла, а в примере 3.23, проверка
после декрементирования - это первая проверка цикла. Во всем остальном приведен-
ные программы похожи, что в версии программы с конструкцией while используется
значение счетчика, которое на единицу больше, чем в версии с конструкцией repeat-
until, причиной чего является то в программе с конструкцией while декрементирование
выполняется сначала. Ни один из рассмотренных вариантов не имеет никаких объек-
тивных преимуществ перед другим.
104
Применение микроконтроллеров PIC 18
3.5. Табличные команды
Имеются две табличные команды: TBLRD (табличное считывание) и TBLWT (таб-
личная запись). Эти табличные команды перемещают информацию между памятью
программ, которая является неразрушаемой памятью, и памятью данных, которая яв-
ляется разрушаемой памятью. Таблицы, которые используются совместно с программ-
ными кодами, и могут, следовательно, храниться в памяти программ, в случае необхо-
димости переносятся для их использования в память данных. Команда табличного счи-
тывания считывает данные из памяти программ и сохраняет их в памяти данных. Ко-
манда табличной записи считывает данные из памяти данных и записывает их в память
программ. Табличное считывание считывает память программ, а табличная запись
осуществляет запись в память программ. Обратите внимание на то, что табличная за-
пись в память программ невозможна в микроконтроллерах исполнения ОТР (семейство
18С). Микроконтроллер должен иметь флэш-память для того, чтобы была возможна
запись в память программ. Исполнение микроконтроллеров ОТР не имеет флэш-
памяти.
Таблица 3.6. Табличные команды
Команда Комментарий
TBLRD* Данные переносятся из памяти программ тель не изменяется в TABLAT, табличный указа-
TBLWT* Данные переносятся из TABLAT в память тель не изменяется программ, табличный указа-
TBLRD*+ Данные переносятся из памяти программ тель затем инкрементируется в TABLAT, табличный указа-
TBLWT*+ Данные переносятся из TABLAT в память тель затем инкрементируется программ, табличный указа-
TBLRD*- Данные переносятся из памяти программ тель затем декрементируется в TABLAT, табличный указа
TBLWT*- Данные переносятся из TABLAT в память тель затем декрементируется программ, табличный указа-
TBLRD+* Табличный указатель инкрементируется, из памяти программ в TABLAT затем данные переносятся
TBLWT+* Табличный указатель инкрементируется, из TABLAT в память программ затем данные переносятся
Табличные команды используют указатель (называемый табличным указателем)
(TBLPTR) для доступа к памяти программ. Табличный указатель размещен в области
SFR, он имеет три байта в длину и может содержать 21-разрядный адрес. Регистр
TBLPTRL содержит 8 младших битов, регистр TBLPTRH содержит следующие по стар-
шинству 8 битов, а регистр TBLPTRU - самые старшие 8 битов адреса в памяти про-
грамм. Передача данных выполняется через регистр TABLAT в либо из памяти про-
грамм.
Варианты команд табличной записи и считывания иллюстрируются таблицей 3.6.
Эти варианты допускают инкрементирование или декрементирование табличного ука-
зателя до либо после табличного считывания или записи. Декрементирование перед
табличной записью или считыванием не допускается. Один из перечисленных вариан-
тов этих команд не инкрементирует и не декрементирует табличный указатель. Таблич-
ное считывание либо запись перемещает 8-разрядное число между ячейкой памяти
программ, адресуемой регистром табличного указателя (TBLPTR) и специальным
функциональным регистром, называемым регистром фиксации таблицы (TABLAT).
Глава 3. Набор команд семейства PIC 18
105
Табличное считывание. Табличный указатель (TBLPTR) (21-разрядный адрес и 22-й
разряд для адресации области конфигурации) и регистр фиксации таблицы (TABLAT)
(8-разрядный регистр) размещены в секции SFR памяти данных. Область памяти про-
грамм лежит в диапазоне адресов от 0x000000 до OxIFFFFF, а область конфигурации
находится в диапазоне адресов от 0x300000 до 0x30FFFF. Предположим, что нам необ-
ходимо преобразовать число в диапазоне между 0 и 9 из кода BCD (ДКД) в
7-сегментный код для отображения этого числа на сегментом светодиодном числен-
ном индикаторе. Для выполнения этого преобразования обычно используют поисковую
таблицу. Вследствие того, что память данных относительно невелика и имеет динамич-
ную природу, поисковая таблица хранится в памяти программ, которая имеет значи-
тельный объем и имеет статическую природу. При сохранении поисковой таблицы в
памяти программ эта таблица становится постоянной. Всегда, когда необходимо ис-
пользовать поисковую таблицу, соответствующие ячейки копируются в память данных
из памяти программ с использованием команды табличного считывания. Как это вы-
полняется? Прежде всего поисковая таблица сохраняется в памяти программ, исполь-
зуя блок программных кодов, показанный в примере 3.24.
Пример 3.24
;ж************* 7-Сегментная поисковая таблица ****************
7ABLE7 CODE_PACK OxlFFO
Look7:
db 0x06 ;0
db 0x5b ; 1
db 0x79 ;2
db 0x4F ;3
db 0x66 ;4
db 0x6D ;5
db 0x7D ;6
db 0x07 ;7
db 0x7F ;8
db 0x3F ; 9
Поисковая таблица по примеру 3.24 располагается перед главной программой,
непосредственно перед оператором RESET_VECTOR1 CODE 0x0000 в файле шаблона'/
Она определяется после пользовательских данных и данных ЭСППЗУ. Важно использо-
вать директиву CODE_PACK для сохранения в памяти программ байтов в форме двух
байтов на слово. Когда команда TBLRD осуществляет доступ к памяти программ, она
адресует байты памяти программ, поэтому таблица должна быть упакована побайтно в
случае байтовой таблицы. Числа в таблице задают биты, необходимые для реализации
7-сегментного кода, как это иллюстрируется рис. 3.9.
Сегменты помечены буквами - от а до д, а логическая 1 в данном примере озна-
чает свечение сегмента. Если, например, 0x66 передается на ЖК-индикатор, то вклю-
чатся сегменты b, с, f и д, отображая цифру 4 на ЖК-индикаторе. Таблица содержит все
7-сегментные коды в численном порядке, как это иллюстрируется примером 3.24. Про-
грамма, осуществляющая доступ к этой таблице, показана в примере 3.25. Наиболее
эффективный способ получения кода из таблицы заключается в использовании одной
команды TBLRD, которая осуществляет доступ к ячейке поисковой таблицы, соответст-
вующей нужному коду. Первая команда адресует таблицу Look7 посредством загрузки
в TBLPTR Look7. В данном случае написана функция, осуществляющая доступ к таблице
и выполняющая преобразование из кодировки BCD в 7-сегментный код. Использован-
106
Применение микроконтроллеров PIC 18
ный для экспериментов микропроцессор имел 4К памяти программ, поэтому таблица
была помещена в ячейки памяти программ в диапазоне адресов от 0x1 FFO до 0x1 FF9
поблизости от вершины памяти программ.
Байт таблицы
0Q f е d с b а
0 0 0 0 0 1 1 0 =°дин
Рисунок 3.9.7-сегментный числовой индикатор
Пример 3.25
;********** в 7—сегментный код
использует 1 уровень стека данных
использует WREG, TABPTR и TABLAT
доступ к таблице по адресам от OxlFFO до 0xlFF9
преобразует WREG из BCD в 7-сегментный код
7-сегментный код возвращается во WREG
To7seg:
ANDLW OxOF /очистка старшего полубайта
ADDLW OxFO ;генерирование адреса таблицы
MOVWF TBLPTRL
MOVLW OxIF
MOVWF TBLPTRH
MOVLW 0
MOVWF TBLPTRU
TBLRD* /получение 7-сегментного кода
MOVFF TABLAT, WREG
RETURN
Эта же методика может быть использована для выполнения доступа к любому ти-
пу фиксированной таблицы в памяти программ, при условии, что таблица сохраняется в
ячейке, которая легко модифицируется преобразуемым числом. Для иллюстрации это-
го, предположим, что таблица используется для преобразования шестнадцатиричных
кодов в коды ASCII вместо метода, использованного в примере 3.16. Вне всякого со-
мнения, метод, отражаемый примером 3.16, намного короче и гораздо более эффекти-
вен, одна вместе с тем это преобразование может быть также реализовано с использо-
Глава 3. Набор команд семейства PIC18
107
ванием таблицы. Смотрите пример 3.26 для ознакомления с соответствующей поиско-
вой таблицей и программой, осуществляющей преобразование. Эта функция была на-
звана Hex2ASCII, - точно также, как и функция из примера 3.18, поскольку она выполня-
ет точно ту же задачу.
Пример 3.26
; ************** поисковая таблица ASCII
TABLE7 CODE_ PACK OxlFFO
HexASC DB 0x30, 0x31, 0x32, 0x33
DB 0x34, 0x35, 0x36, 0x37
DB 0x38, 0x39, 0x41, 0x42
DB 0x43, 0x44, 0x45, 0x46
. ******** ** Hex2ASCII ** ****** ****** * * * * *
использует 1 уровень стека данных
использует WREG, TABPTR и TABLAT
доступ к таблице по адресам от OxlFFO до OxlFFF
преобразует WREG из шестнадцатиричного в ASCII-код
ASCII-код возвращается во WREG
Hex2ASCII:
ANDLW OxOF /очистка старшего полубайта
ADDLW OxFO ;генерирование адреса таблицы
MOVWF TBLPTRL
MOVLW OxIF
MOVWF TBLPTRH
MOVLW 0
MOVWF TBLPTRU
TBLRD* /получение ASCII-кода
MOVFF TABLAT, WREG
RETURN
Табличная запись. Операция табличной записи может оказаться рискованной. На-
пример, если во время выполнения записи в память программ произойдет сброс, to'
это может привести к разрушению данных. Если это возможно, то следует использо-
вать какой-либо метод верификации записи данных. Однако возможно это не всегда.
Могут возникнуть и другие проблемы, связанные с табличной записью, - когда, напри-
мер, во время записи произойдет сбой электропитания либо не будут запрещены пре-
рывания. По этим причинам табличная запись будет обсуждаться позже, когда упомя-
нутые вопросы будут проанализированы.
Один из методов верификации записи данных заключается в записи данных в две
отдельные таблицы. Каждая таблица также содержит байт счетчика. Когда выполняется
запись в таблицу, то байт счетчика инкрементируется. При сохранении таблицы она
записывается с инкрементированным значением счетчика. Затем записывается другая
таблица также с инкрементированным значением счетчика. Если произойдет сбой, то
эти две таблицы не будут соответствовать друг другу, байты счетчиков также будут раз-
ными. Восстановление после сбоя в данном случае будет заключаться в откате к табли-
це, содержащей меньшее значение счетчика. Хотя это и не полная процедура восста-
новления от сбоя, все же оно позволяет обнаружить ошибку и выполнить необходимый
откат.
108
Применение микроконтроллеров PIC 18
Команда табличной записи используется в главе 10, в программе загрузчика для
записи информации в память программ. Единственное применение табличной записи
заключается в записи информации в память программ или в регистры конфигурации.
3.6. Макропоследовательности
Макропоследовательности или макросы - это группы команд, которые работают
так же, как и функции, однако отсутствует связь для обращения к макропоследователь-
ности или для возврата из нее. Второе отличие заключается в том, что команды, вхо-
дящие в состав макроса, вставляются в программу всякий раз, когда имеется вызов
этого макроса.
Определение макросов
Макросу присваивается имя, за которым следует слово MACRO, после которого
следует любой параметр, связанный с этим макросом. Пример 3.27 иллюстрирует оп-
ределенный для ассемблера макрос, который сдвигает параметр “what" влево. Метка
“what” называется замещаемым параметром. Всякий раз, когда команды макроса ис-
пользуются в программе, метка “what” замещается параметром, указанным справа от
имени макроса. В этом примере макрос, названный ShiftL, используется дважды и вся-
кий раз параметр “what” замещается WREG.
Пример 3.27
ShiftL MACRO what /макрос и именем ShiftL
ADDWF what
endm
/Макрос ShiftL используется 2 раза
MOVLW 1
ShiftL WREG /использует макрос для WREG
ShiftL WREG /использует макрос для WREG
В примере 3.18 показана программа, которая использует функцию для преобразова-
ния из шестнадцатиричного формата в формат ASCII. Пример 3.28 показывает ту же самую
программу, однако вместо использования функции для преобразования из шестнадцати-
ричного формата в формат ASCII используется макрос. Если эти два примера сравнить, то
можно увидеть, что между ними не столь уж большая разница. Функция завершается коман-
дой return, а макрос - командой ENDM. ENDM не вносит никакого кода в программу, в то вре-
мя как RETURN вставляет одну команду. Макрос на одну команду короче, чем функция. В
главной программе функция вызывается дважды, макрос также вызывается дважды. Когда
вызывается функция, команда CALL требует двух машинных слов для своего размещения, а
при вызове макроса дополнительные машинные слова вообще не нужны. Из листинга по
примеру 3.28 видно, что команды макроса вставляются в программу два раза - по одному на
каждое обращение к макросу.
Глава 3. Набор команд семейства PIC 18
109
Пример 3.28
;*** Макрос преобразования из шестнадцатиричного формата в формат ASCII
; Преобразует правый полубайт WREG в формат кода ASCII, возвращаемого во WREG
Hex2ASCII MACRO
ANDLW OxOF /очистка правого полубайта
ADDLW 0x30 /преобразование его в ASCII
DAW
BTFSC WREG, 6
INCF WREG
ENDM
f
;*** Main program ***
Main:
MOVLW 0x5c /загрузка тестовых данных
MOVWF ASCII_H
Hex2ASCII /преобразование младшего полубайта
MOVWF ASCII_L /сохранение его в ASCII_L
MOVFF ASCII_H, WREG
SWAPF WREG /получение старшего полубайта
Hex2ASCII /преобразование его в ASCII
MOVWF ASCII_H /сохранение его в ASCII_H
Stop: GOTO STOP
Если вы скомпилируете этот пример, то понять способ, которым макрос отобра-
жается в листинге компиляции программы, может показаться вам трудным делом. В
этом листинге каждая команда макроса появляется дважды с различными несмежными
адресами. Однако, если вы мысленно переместите каждую команду макроса на соот-
ветствующее ей место в программе, то все станет на свои места. То, почему команды
макросов приводятся в листинге именно таким образом - это загадка.
3.7. Резюме
1. Литеральные команды позволяют использование литеральных или постоянных
данных, в основном с регистром WREG. Литеральные команды используют коды опера-
ций, - такие как MOVLW или ADDLW, при этом первые три буквы обозначают операцию,
а последние две - объект операции (L = литерал, W = WREG). При этом команда ADDLW
добавляет литеральные данные к WREG. Например, команда ADDLW 6 добавляет 6 к
WREG.
110
Применение микроконтроллеров PIC 18
2. Имеются также другие литеральные команды: вычитание (SUBLW), включаю-
щее ИЛИ (IORLW), исключительное ИЛИ (XORLW), И (ANDLW), а также умножение
(MULLW). Имеется также литеральный возврат из процедуры (RETLW), который позво-
ляет возвращать литерал во WREG.
3. Две литеральные команды не используют WREG. Это команды MOVLB и LFSR,
которые загружают регистр выбора банка (BSR) или регистр выбора файла (FSR0,
FSR1, or FSR2) литеральными данными.
4. Битовые команды обеспечивают возможность сброса отдельных битов (BCF),
установки (BSF) или переключения (BTG). Это обеспечивает полный контроль над со-
стоянием всех битов в любом месте памяти данных, включая специальные функцио-
нальные регистры.
5. Другими битовыми командами являются BTFSC и BTFSS, которые проверяют
состояние бита и пропускают следующую команду, если бит либо сброшен (BTFSC),
либо установлен (BTFSS).
6. Байтовых команд больше, чем команд какого-либо иного типа. Все они рабо-
тают с байтовыми данными. Способ, которым обозначаются эти команды, указывает на
то, как работает эта команда. Например, команда ADDWF добавляет байт из WREG к
ячейке регистрового файла или же содержимое ячейки регистрового файла к содер-
жимому регистра WREG. Направление операции может выбираться.
7. Данные адресуются посредством использования номера регистра или же кос-
венно через указатель, расположенный в регистре выбора файла (FSR). Если использу-
ется FSR, то операндами для косвенной адресации являются INDFO, INDF1 и INDF2.
Также доступными для косвенной адресации памяти являются POSTINCO, POSTINC1 и
POSTINC2, а также PREINCO, PREINC1 и PREINC2. PLUSWO, PLUSW1 и PLUSW2 могут
также использоваться для сложения WREG с регистром FSR.
8. Команды управления позволяют осуществлять проверку условий, а затем, ос-
новываясь на результатах этой проверки, выполнять переход к другой секции програм-
мы. Эти команды часто реализуют оператор if (если).
9. Программные конструкции являются строительными блоками программирова-
ния. Наиболее часто используются следующие программные конструкции: if-then-else,
repeat-until, while, а также функции.
10. Табличные команды обеспечивают доступ к памяти программ. Память про-
грамм считывается с использованием команды табличного чтения (TBLRD) и записыва-
ется с использованием команды табличной записи (TBLWR).
11. Данные в памяти программ адресуются с использованием регистра TBLPTR,
а переносятся данные всегда через регистр TABLAT.
12. Поисковые таблицы часто используются для преобразования данных из од-
ной формы в другую.
13. Макропоследовательности используются в программах для повышения их
скорости работы, однако обычно они требуют большего объема пространства памяти,
чем эквивалентные функции.
3.8. Вопросы и задания
1. Что такое литеральные данные?
2. С каким регистром микроконтроллера обычно работают литеральные коман-
ды?
3. Что делает команда ADDLW?
4.Выберите литеральную команду для выполнения каждой из следующих задач:
Глава 3. Набор команд семейства PIC18
111
а. поместить 0x34 в регистр WREG
b. добавить 3 к регистру WREG
с. выполнить операцию включающего ИЛИ для 6 и содержимого регистра WREG
d. загрузить 2 в регистр выбора банка
е. отнять от 0 содержимое регистра WREG
5. Поясните, что делают следующие литеральные команды:
a. MOVLW ОхбА
b. XORLW 4
с. LFSR 0x123
d. MULLW. 10
е. MOVLB 2
6. Напишите короткую последовательность команд, которая загружает 3 во
WREG, затем добавляет 9 и, наконец, выполняет операцию включающего ИЛИ для со-
держимого WREG и литерала 5.
7. Напишите короткую последовательность команд, которая помещает OxOF во
WREG, а затем очищает два самых правых бита, устанавливает самый левый бит, а за-
тем инвертирует битовую позицию 5, используя только литеральные команды для ре-
шения этой задачи.
8. Выберите битовую команду, которая:
а. Очищает битовую позицию 2 регистра WREG
b. Устанавливает битовую позицию 3 регистра банка доступа 0x11
с. Переключает битовую позицию 3 регистра банка доступа 0x1 А
d. Устанавливает регистровый бит состояния переноса
е. Очищает бит N регистра состояния
9. Что делает команда BTFSC?
10. Что делает команда BTFSS?
11 .Напишите последовательность команд, используя только битовые и литераль-
ные команды, которая выполнить прибавление 1 к содержимому регистра WREG, если
бит переноса регистра состояния находится в единичном состоянии 1.
12. Какие ячейки регистрового файла содержит банк доступа?
13. Объясните, как программа получает доступ к ячейке регистрового файла
0x200?.
14. В чем заключается разница между байтовым сложением и литеральным сло-
жением?
15. Опишите, что делает каждая из следующих команд:
a. MOVFF WREG, 0x10
b. ADDWF 0x20, 0
c. ADDWF0x20, 1, 1
d. DECF 0x34
e. INCF 0x34, 1
16. Напишите короткую программу, которая сохраняет 0х5А в ячейках банка дос-
тупа 0x10, 0x20 и 0x30.
17. Напишите короткую программу, которая дублирует содержимое ячейки банка
доступа 0x12.
18. Напишите короткую последовательность команд, которая возводит в квадрат
содержимое регистра WREG.
19. Какая байтовая команда выполняет сложение с учетом бита состояния пере-
носа?
20. Где находится информация о заимствовании после выполнения вычитания?
21. Что делает команда SETF?
112
Применение микроконтроллеров PIC 18
22. Напишите короткую последовательность команд, которая добавляет
24-разрядное число, находящееся в ячейках 0x10, 0x11 и 0x12 к 24-разрядному числу,
находящееся в ячейках 0x20, 0x21 и 0x22. Числа храняться в формате с обратным по-
рядком байтов. Результат сохраняется в ячейках 0x20, 0x21 и 0x22, люьые переносы
между байтами должны учитываться.
23. Объясните, как FSR0 используется для косвенной адресации ячейки памяти в
любой команде.
24. Что делает команда DCFSNZ?
25. Напишите последовательность команд, которая умножает содержимое реги-
стра WREG на десять. Вы не должны использовать команду умножения.
26. Для чего служит операнд POSTINC1 ?
27. Как получить дополнение до двух регистра WREG?
28. Как получить дополнение до единицы регистра WREG?
29. Что делает команда BRA?
30. Сравните и противопоставьте команды BRA и GOTO.
31. Команда BNZ выполняет относительный либо абсолютный переход?
32. Каков диапазон адресов, в пределах которого команда BZ может выполнять
переход в программе?
33. Напишите короткую программу, которая размещает 0x12 в область памяти
банка доступа от 0x00 до 0x22.
34. Контрольная сумма представляет собой сумму (при отбрасывании перено-
сов) всех чисел блока памяти. Напишите программу, которая генерирует 8-разрядную
контрольную сумму для содержимого банка памяти 0 (от 0x00 до OxFF) и сохраняет ее
boWREG.
35. Как работают команды CALL и RETURN?
36. Как используется стек функциями CALL и RETURN?
37. Напишите функцию, которая формирует 16-разрядную контрольную сумму
для всех ячеек банка памяти 0. Эта контрольная сумма должна быть сохранена в реги-
страх PRODL и PRODH в формате с обратным расположением байтов, поскольку опе-
рация умножения не выполнялась.
38. Объясните, как в примере 3.17 выполняется преобразование из шестнадца-
тиричного кода в код ASCII.
39. Что такое табличные команды?
40. Напишите функцию, которая осуществляет доступ к таблице простых чисел с
целью определения того, является ли число простым или нет. 8-разрядное проверяе-
мое число передается этой функции через WREG. Таблица должна содержать простые
числа вплоть до 251. Если число является простым, то должна отрабатываться команда
RETURN с установленным в 1 битом переноса, а если нет - то должна отрабатываться
команда RETURN с битом переноса, сброшенным в 0.
41. Как определяется макропоследовательность?
42. Каков расход памяти при вызове макропоследовательности?
43. Напишите макрос, который сдвигает 8-разрядное содержимое любого реги-
стра вправо на один разряд. (При сдвиге вправо помещается ноль в самый левый бит
результата).
Глава 4. Программирование на языке Ассемблера
113
Глава 4. Программирование на языке Ассемблера
Сейчас, после того, как вы изучили целый ряд команд PIC, вы можете их доста-
точно эффективно использовать в коротких программах. Однако, вам необходимо уз-
нать больше относительно программирования на языке Ассемблера. Вместе с тем,
если вы придете к выводу, что программирование на языке Ассемблера окажется для
вас слишком сложным, то вы сможете перейти к использованию языка программиро-
вания С при разработке программ для устройств PIC. Если вы уже решили, что будете
создавать проекты в основном на С, то можете пропустить эту главу и перейти непо-
средственно к изучению главы 5. Материал, который вы уже изучили в главе 3, является
достаточным, чтобы делать большую часть необходимых вставок на Ассемблере в про-
граммах на С.
В данной главе представлены некоторые алгоритмы и программы на Ассемблере,
- они предназначены для программистов, работающих с языком Ассемблера. Многие
из этих алгоритмов также рассматриваются в необходимых случаях также и главе 5 при
изучении программирования на языке С. Самым лучшим подходом в данном случае
будет изучение обеих глав - как главы 4, так и главы 5. В этой главе излагается важный
материал, - он позволит вам развить знания об Ассемблере, которые вы уже имеете.
После завершения изучения данной главы вы сможете:
1. Писать программы, работающие со стеком данных.
2. Писать программы, использующие очередь.
3. Писать программы, выполняющие деление и умножение чисел.
4. Манипулировать двоично-кодированными десятичными (BCD) числами, ис-
пользуя сложение и вычитание.
5. Осуществлять двунаправленное преобразование между двоичными и BCD-
числами.
6. Формировать программную временную задержку
4.1. Структуры стека и очереди
Очереди и стеки - это две структуры данных, которые используются во многих
программах с целью решения различных задач. Очередь хранит данные по принципу
“первым вошел - первым вышел”, который часто называют принципом FIFO. Стек хра-'
нит данные по принципу “первым вошел - последним вышел”, который часто называют
принципом LIFO. Очередь - это буфер, который часто используется между внешними
устройствами ввода-вывода и микроконтроллером. Стек часто используется для вре-
менного и эффективного хранения данных в памяти. Например, счетчик команд сохра-
няется в стеке как адрес возврата из функции. Благодаря стеку, вызовы функций могут
вкладываться. Обсуждаемые здесь стеки позволяют хранить данные в форме отдельно-
го стека в памяти данных.
Стек данных
Фирма Microchip не пошла пока по пути аппаратной реализации стека данных.
Вместе с тем, можно было бы предположить, что он существует, поскольку имеются
команды PUSH (Занести в стек) и POP (Извлечь из стека). Однако назначение команд
PUSH и POP не связано с сохранением либо извлечением данных из стека данных, - они
используются для занесения содержимого счетчика команд + 2 в программный стек, а
команда POP извлекает адрес возврата из программного стека.
114
Применение микроконтроллеров PIC 18
Стек данных - это хорошее место для временного сохранения данных внутри
функций либо иных прикладных программ. Стек данных является интегральной частью
компилятора языка С. Если содержимое всех регистров сохраняется в стеке внутри
функции, то эта функция становится прозрачной для программы, которая ее использу-
ет. Эта прозрачность обеспечивает возможность использования локальных перемен-
ных с локальной областью действия в функциях на языке С. Сохранение регистров
внутри функции предотвращает сбои. Для создания стека данных программе нужен
указатель на область памяти данных, а также метод занесения и извлечения данных из
стека данных. Регистр FSR2, который может применяться в качестве указателя стека,
используется в примере 4.1 для адресации области памяти, которая может работать
как стек данных. Для занесения данных в стек мы будет использовать форму косвенной
адресации POSTDEC2, а для извлечения данных из стека - форму косвенной адресации
PREINC2
Шестнадцать байтов памяти, зарезервированных под стек данных, обеспечивают
возможность формирования стека, достаточного по глубине для большинства про-
грамм. Стек данных эффективно многократно использует одну и ту же область памяти
данных. Как только данные помещаются в стек данных, стек увеличивается в размерах в
направлении, соответствующем уменьшению адресов памяти, а по мере того, как дан-
ные извлекаются из стека, он “сжимается” по направлению возрастания адресов памя-
ти. Занесение информации в стек называют “заталкиванием” данных в стек, а извлече-
ние данных из стека - их “выталкиванием”. Пример 4.1 иллюстрирует инициализацию
указателя стека, а также команды, заносящие данные в стек и извлекающие их из него.
Стек определяется в секции UDATA_ACS или UDATA как Stack RES 16. Любая область
может использоваться при том же времени доступа ввиду использования FSR2. Поря-
док данных в стеке данных реверсируется; стек данных работает по принципу FILO
(первым вошел, последним вышел) как буферный массив. В примере 4.1 в стек поме-
щается 2, затем 3. Когда данные извлекаются из стека, первой извлекается 3, затем 2.
Пример 4.1
UDATA_ACS
Stack RES .16
LFSR 2, Stack + .15 /инициализация указателя стека
;(адрес вершины стека)
t
/программный код, помещающий в стек два численных значения
MOVLW 2 /занесение в стек 2
MOVWF POSTDEC2
MOVLW 3 / занесение в стек 3
MOVWF POSTDEC2
/ **** выполнение других действий ******
/ программный код, извлекающий из стека два численных значения
MOVF PREINC2, 0 /извлечение из стека 3
MOVF PREINC2, 0 /извлечение из стека 2
Глава 4. Программирование на языке Ассемблера
115
Теперь, когда мы поняли ценность стека, нам следует использовать его в про-
граммах для временного хранения данных. Во многих примерах, приведенных в остав-
шейся части этой главы, предполагается, что в качестве указателя стека данных ис-
пользуется FSR2, а стек данных имеет глубину в 16 байтов.
Предположим, что пример 4.1 переписан таким образом, что он выполняет пре-
образование байта во WREG в двухразрядное число ASCII, возвращаемое в ASCII_L и
ASCII_H. Пример 4.2 иллюстрирует эту, уже рассмотренную нами ранее, функцию
(Hex2ASC). Единственная вещь, которая изменилась с тех пор, когда эту функцию мы
называли Hex2ASCII, является использование ячеек памяти ASCIIJ_ и ASCII_H. Стек ис-
пользуется для сохранения содержимого регистра WREG перед преобразованием и
восстановления его из стека после преобразования. Единственными регистрами вне
функции Hex2ASC, содержимое которых изменяется, являются ячейки регистрового
файла ASCII_LnASCII_H.
Пример 4.2
;данные в памяти данных
MyData UDATA_ACS
Stack RES .16
ASCII_L RES 1
ASCII_H RES 1
;определяет пространство стека
/•размещает младшую часть ASCII-кода
;размещает старшую часть ASCII-кода
************* фуНКция Hex2ASCII ***********
использует 1- уровень программного стека
использует 2 уровня стека данных
использует WREG
преобразует правый полубайт WREG из шестнадцатиричной кодировки
в код ASCII, возвращаемый в стеке данных
********************************************
Hex2ASCII:
ANDLW 0x0F
ADDLW 0x30
DAW
BTFSC WREG, 6
INCF WREG
RETURN
/изолирует младший полубайт
************ фуНКция Hex2ASC **************
использует 2 уровня программного стека
использует 1 ячейку стека данных
использует Hex2ASCII
использует ASCII_L и ASCII_H
преобразует байт во WREG из шестнадцатиричной кодировки
в код ASCII, результаты возвращаются в
ASCII L и ASCII Н
116
Применение микроконтроллеров PIC 18
Hex2ASC:
MOVFF WREG, POSTDEC2 /занесение WREG в стек (сохранение WREG)
CALL Hex2ASCII /преобразование младшего полубайта
MOVFF WREG, ASCII_L
MOVFF PREINC2, WREG /получение WREG
MOVFF WREG, POSTDEC2 /повторное занесение WREG в стек
SWAPF WREG ;своппинг полубайтов
CALL Hex2ASCII /преобразование старшего полубайта
MOVFF WREG, ASCII_H
MOVFF RETURN PREINC2, WREG /извлечение WREG из стека
.************** Главная программа ******************
; Иллюстрирует вызов функции Hex2ASC
; преобразует 0x5с в ASCII, передает результат в ASCII_L (0x43)
; и в ASCII_H (0x35)
Main:
;если в программе используется стек, то он должен
/предварительно инициализироваться и только один раз
LFSR 2, Stack+.15 /инициализация указателя стека
MOVLW 0x5с /загрузка тестовых данных
CALL Hex2ASC /преобразование всего байта в ASCII
/результаты помещаются в стек данных
;********* здесь находится продолжение программы
Stop: BRA Stop
Очередь
Очередью часто называют буферную область памяти. Очередь сохраняет порядок
заносимых в нее данных. Очереди часто размещаются между устройствами ввода-
вывода и программой. Очередь работает как буфер, поэтому данные не теряются. В
отличие от стека данных, для работы с очередью необходимо использовать два указа-
теля. Один указатель адресует ячейку, в которую данные заносятся в очередь, а другой
указатель адресует ячейку, из которой данные извлекаются из очереди. Должны распо-
знаваться два состояния очереди: очередь пуста и очередь заполнена. Когда очередь
пуста, оба указателя адресуют одну и ту же ячейку памяти. Когда очередь заполнена, то
указатель выхода адресует на одну ячейку ниже от указателя входа. Очередь - это кру-
говая область памяти, которая повторно использует одну и ту же область памяти, ана-
логично тому, как это происходит в случае стека. Одна ячейка над вершиной очереди -
это первая ячейка очереди. Указатели должны переключаться с вершины очереди на ее
самую нижнюю ячейку, когда указатель инкрементируется через конец очереди.
Пример 4.3
/быстрая память
UDATA ACS
Queue RES .16 /очередь
QEntry RES 1 /указатель входа
QExit RES 1 /указатель выхода
Глава 4. Программирование на языке Ассемблера
117
UDATA
Stack
RES .16
; стек
/•следующие коды размещаются в секции программы CODE
;для инициализации очереди
MOVLW
MOVFF
MOVFF
Queue ;инициализация
WREG, QEntry
WREG, QExit-
Пример 4.3 показывает, как зарезервировать 16 байтов памяти данных под оче-
редь 2 байта под указатели, адресующие очередь. Предполагается, что очередь будет
секцией памяти, которая по объему не перейдет 256-байтовую границу и размещена
ниже 0x07F банке доступа памяти данных, если это возможно. Для того, чтобы это сде-
лать, разместите объявление очереди в начале секции UDATA_ACS программы. Секция
доступа к данным используется для очереди, поскольку она адресуется одним 8-
разрядным адресом и не требует использования регистра выбора банка. Если также
используется стек, поместите его объявление в начале секции UDATA. Для того, чтобы
очередь была функциональной, нужно использовать две функции: одну для занесения
данных в очередь и другую - для извлечения данных из очереди. Эти функции названы
PutQ и GetQ в примере 4.4. С целью достижения их максимально возможной степени
прозрачности, также используется структура стека с регистром FSR2, работающим как
указатель стека. Функция PutQ сохраняет содержимое регистра WREG в очереди, а
функция GetQ извлекает данные из очереди и возвращает их во WREG. В обеих назван-
ных функциях бит переноса регистра состояния указывает на ошибку, если С = 1 при
возврате и на отсутствие ошибки, если при возврате С = 0. В примере 4.4 ошибка функ-
ции PutQ означает заполнение очереди, а ошибка функции GetQ означает, что очередь
пуста. Для инициализации очереди, убедитесь в том, что функции QEntry и QExit с адре-
сами очереди, как показано в примере.
Пример 4.4
**************** PutQ **********************
; использует 1 уровень программного стека
; использует 3 уровня стека данных, адресуемых FSR2
; сохраняет WREG в очереди
; при возврате С = 1, если очередь заполнена
PutQ:
MOVFF FSROL, POSTDEC2
MOVFF FSROH, POSTDEC2
MOVFF WREG, POSTDEC2
MOVFF QEntry, FSROL
MOVLW 0
MOVWF FSROH
MOVF POSTINCO, 0
MOVLW Queue+.16
SUBWF FSROL, 0
BNZ PutQl
;занесение в стек FSR0 и WREG
118
Применение микроконтроллеров PIC 18
MOVLW MOVFF Queue WREG, FSROL
PutQl:
MOVF SUBWF BNZ QEntry, 0 FSROL, 0 PutQ2 ;проверка на заполнение
SETF STATUS, 0 ;если полна, то
MOVFF BRA PREINC2, WREG PutQ3 /очистка стека
PutQ2:
MOVF MOVFF MOVFF QEntry, 0 FSROL, QEntry WREG, FSROL
MOVFF CLRF PREINC2, INDFO STATUS, 0 ;сохранение данных очереди
PutQ3:
MOVFF MOVFF RETURN PREINC2, FSROH PREINC2, FSROL ;выгрузка стека
.**************** GetQ **********************
Г
; использует 1 уровень программного стека
; использует 3 уровня стека данных, адресуемых FSR2
; извлекает WREG из очереди
; при возврате С = 1, если очередь пуста
GetQ:
MOVF QEntry, 0 ;проверка на пустоту
SUBWF QExit, 0
BNZ GetQl
SETF STATUS, 0 ;если пуста
RETURN
GetQl:
MOVFF FSROL, POSTDEC2 ;занесение FSR0 в стек
MOVFF FSROH, POSTDEC2
MOVFF QExit, FSROL
MOVLW 0
MOVWF FSROH
MOVFF POSTINCO, POSTDEC2 ;занесение в стек данных из очереди
MOVFF FSROL, QExit
MOVLW Queuet.16 ;контроль границ
SUBWF FSROL, 0
BNZ GetQ2
MOVLW Queue
MOVFF WREG, QExit
GetQ2:
MOVFF PREINC2, WREG ;выгрузка из стека данных очереди и FSR0
MOVFF PREINC2, FSROH
MOVFF PREINC2, FSROL
CLRF STATUS, 0
RETURN
Глава 4. Программирование на языке Ассемблера
119
Очередь наиболее полезна при организации взаимодействия микроконтроллера
с внешними устройствами. Данные с внешнего устройства ввода-вывода заносятся в
очередь и сохраняются в ней. Когда микроконтроллер будет готов к приему данных, он
извлекает данные из очереди. Очередь предоставляет метод буферизации данных ог
внешнего устройства на их пути к микроконтроллеру. Например, клавиатура может под-
ключаться к микроконтроллеру через порты ввода-вывода. Некоторые машинистки
могут настолько быстро вводить информацию с клавиатуры, что микроконтроллер мог
бы потерять часть данных, выполняя другие задачи. Очередь предотвращает потерю
каких-либо данных, особенно в случаях, когда обработка входных данных производится
в режиме прерываний, который будет рассмотрен позже.
4.2. Сложные арифметические операции
Этот подраздел не рассматривает исчерпывающе сложные арифметические опе-
рации; однако алгоритмы и методы, рассматриваемые в нем, конечно же, являются
сложными для микроконтроллеров, которые не умеют выполнять операцию деления.
Таким образом, данный подраздел рассматривает то, как нужно писать программы для
выполнения деления и умножения чисел, превосходящих по разрядности 8 разрядов,
для BCD-арифметики, а также для выполнения других арифметических операций, кото-
рые сложны для выполнения микроконтроллерами PIC.
BCD-арифметика
Встроенные системы часто используют BCD-числа, по причине возможности бы-
строго преобразования между двоичными и BCD-числами. Устройства отображения
часто требуют данные либо в BCD, либо в ASCII-форматах. Единственная разница меж-
ду BCD и ASCII заключается в наличии смещения, равного 0x30. Разница между двоич-
ным форматом и BCD намного более сложна, требуя реализации алгоритма, необхо-
димого для преобразования между ними. Например, возьмем двоичное число 11 1110
1000 (ОхЗЕ8). Есть ли простой способ преобразовать ОхЗЕ8 в 1000 десятичное либо
0001 0000 0000 0000 в упакованном BCD-формате? Конечно же, способ есть, однако он
требует для своей реализации значительного расхода процессорного времени и вы-'4
полнения операций деления, которые часто недоступны для встроенных приложений,
написанных на языке Ассемблера, в силу чего числа часто остаются в BCD-формате.
BCD сложение и вычитание
Для выполнения преобразования при BCD- сложении предусмотрена специаль-
ная команда, называемая командой десятичной настройки WREG (DAW). Команда DAW
корректирует результат BCD-упакованного (две цифры на байт) сложения. Эта команда
является необходимой вследствие того, что микроконтроллер складывает только дво-
ичные числа. Команда DAW выполняет показанные далее проверки после сложения
упакованных BCD-чисел во WREG с целью коррекции суммы для получения допустимо-
го BCD-числа во WREG. (Уделите внимание тому, чтобы прочесть сообщения завода-
изготовителя относительно используемого вами микроконтроллера, потому что одна
из версий микроконтроллера имеет проблемы с выполнением команды DAW. По-
видимому в одном из исполнений микроконтроллера для правильного выполнения ко-
манды DAW предварительно необходимо сбросить бит переноса. В данном подразделе
120
Применение микроконтроллеров PIC 18
мы будем предполагать, что команда DAW корректно функционирует во всех исполне-
ниях микроконтроллеров.) Итак, команда выполняет следующее:
1. Если самый правый полубайт WREG больше, чем 9 или бит DC = 1, то добавля-
ет 0x06.
2. Если самый левый полубайт WREG больше, чем 9 или бит С = 1, то добавляет
0x60
Команда DAW добавляет 0x00, 0x06, 0x60 или 0x66 к WREG для коррекции резуль-
тата после сложения чисел в упакованном BCD-формате. Если результат больше, чем
100 BCD, то бит переноса (С) устанавливается для индикации разряда сотен результа-
та. Следовательно, если будут сложены 99 BCD и 05 BCD, то результатом будет 04 BCD
с установленным в единицу битом С, индицирующим наличие сотни в результате после
выполнения команды DAW.
Предположим, что 4-разрядное упакованное BCD-число в регистрах файла дос-
тупа 0x10 и 0x11 суммируется с 4-разрядным упакованным BCD-числом в регистрах
файла доступа 0x20 и 0x21. Программа, показанная в примере 4.5, решает эту задачу.
Обратите внимание на то, что перенос после сложения байтов 0x10 и 0x20 прибавляет-
ся к результату сложения 0x11 с 0x21 с использованием команды сложения с перено-
сом. Введите программу в IDE и выполните ее с несколькими различными BCD-числами
в регистрах для изучения того, как работает эта программа. Также обратите внимание
на то, что если конечный перенос будет равен логической, то 0x01 будет заноситься в
ячейку 0x22, индицируя разряд 10000 результата.
Пример 4. 5
Main:
MOVF 0x10, 0 ;добавление 0x10 к 0x20
ADDWF 0x20, 0
DAW ;преобразование в BCD-формат
MOVWF 0x20
MOVF 0x11, 0 ;сложение с переносом 0x11 с 0x21
ADDWFC 0x21, 0
DAW ; преобразование в BCD-формат
MOVWF 0x21
CLRF 0x22
BTFSC STATUS, 0
INCF 0x22 ;по последнему переносу
Stop: BRA Stop
Предположим, что складываются 4-разрядные неупакованные BCD-числа. Пер-
вое число сохраняется в ячейках от 0x10 до 0x13, а второе - в ячейках от 0x20 до 0x23,
при этом 0x24 содержит разряд 10000 результата. Неупакованное BCD-число сохраня-
ется как одна цифра на байт. Поскольку для формирования суммы нужно выполнить
четыре операции сложения, косвенная адресация будет наилучшим выбором при напи-
сании данной программы, как это показано в примере 4.6. Данная программа может
складывать неупакованные BCD-числа любой разрядности посредством изменения
значения счетчика. Программа складывает одновременно два изолированных неупако-
ванных числа и, если результат равен 0x10 или больше после выполнения команды
DAW, программа удаляет 0x10 командой ANDLW OxOF, что сохраняет бит состояния пе-
Глава 4. Программирование на языке Ассемблера
121
реноса. Команда ANDLW изменяет только биты флагов нулевого и отрицательного ре-
зультатов.
Пример 4.6
Ma i п:
LFSR 0, 0x10 ;адресация чисел
LFSR 1, 0x20
MOVLW 4 ;загрузка счетчика
MOVWF 0x30
BCF STATUS, 0 ;очистка С
Loop:
MOVF POSTINC0, 0
ADDWFC INDF1, 0
DAW
BTFSC WREG, 4
BSF STATUS, 0 ;если сумма от 10 до 18
ANDLW OxOF ;удаление 10
MOVWF POSTINCI
DECFSZ 0x30 ; цикл
BRA Loop
CLRF INDF1
BTFSC STATUS, 0
INCF INDF1
Stop: BRA Stop
Однако, как выполняется вычитание BCD-чисел, если отсутствует команда DAW
для вычитания? Команда DAW функционирует корректно только для BCD-сложения.
BCD-вычитание выполняется посредством сложения с дополнением. Например, если
123 вычитается из 391, то правильное значение разности получается в результате сло-
жения дополнения числа 123 до десяти с числом 391. дополнение до десяти для числа
123 равно 877. 877 плюс 391 даст 1268. Перенос (показанный как 1,000) отбрасывается
и результатом будет 268, - правильное значение разности. Рис. 4.1 иллюстрирует полу-
чение дополнения числа 123 до 10.
Было бы неплохо написать функцию, которая складывает или вычитает упакован-
ные BCD-числа любой размерности. Возможно ли это? Да, пример 4.7 иллюстрирует .
такую функцию. Данная функция имеет четыре параметра вызова, которые должны
быть предварительно загружены для того, чтобы эта функция функционировала кор-
ректно. Параметрами вызова являются: адрес числа 1 (FSR0), адрес числа 2 (FSR1),
при этом результат записывается поверх числа 1; размерность чисел в байтах (PRODL),
а также значение 0x00 (для сложения) или 0х9А (для вычитания) в PRODH. Обратите
внимание, что в случае вычитания число 1 вычитается из числа 2.
122
Применение микроконтроллеров PIC 18
999
- 123
876 ◄----дополнение до 9
+ 1
877 4----дополнение до 10
OR
99А
123
877 <
дополнение до
10
Рис. 4.1. Дополнение до десяти
Пример 4.7
.*************** функция SubAdd ***************
; использует 1 уровень программного стека
; использует 2 уровня стека данных
; использует FSRO, FSR1, PRODL и PRODH
; Складывает/вычитает упакованное BCD-число,
/ адресуемое FSR0 к либо из числа, адресуемого
; FSR1. Результат замещает число в FSR0.
; Параметры вызова:
; FSR0 = адрес numberl и результат
; FSR1 = адрес number2
; PRODL = количество байтов каждом числе
; PRODH = 0x00 (сложение) or 0х9А (вычитание)
SubAdd:
MOVFF WREG, POSTDEC2 /занесение в стек WREG
MOVFF TABLAT, POSTDEC2 /занесение в стек TABLAT
BCF STATUS, 0 /сброс переноса
SubAddl:
MOVFF STATUS, TABLAT
MOVF POSTINCO, 0
TSTFSZ PRODH
SUBWF PRODH, 0
MOVFF TABLAT, STATUS
ADDWFC POSTINCI, 0
DAW
MOVWF POSTINC2
MOVLW 0x99
Глава 4. Программирование на языке Ассемблера
123
TSTFSZ PRODH
MOVWF PRODH
DECFSZ PRODL
BRA SubAddl
MOVFF PREINC2, TABLAT «•извлечение из стека TABLAT
MOVFF PREINC2, WREG ;извлечение из стека WREG
RETURN
Умножение
Рассматриваемый набор команд включает команду умножения, однако диапазон
ее действия ограничен выполнением 8-разрядного умножения. Однако бывают случаи,
когда нужно выполнить умножение чисел большей разрядности. Как только вы поймете
алгоритм умножения, то сможете писать программы, выполняющие умножение чисел
любой разрядности. Умножение в двоичной системе - это последовательность сдвигов
и операций сложения. Данный алгоритм требует сохранения произведения, которое
имеет вдвое больше разрядов, чем множимое и множитель. Например, 16-разрядное
умножение требует получения 32-разрядного произведения. Программный алгоритм
выполнения 16-разрядного беззнакового сложения может быть описан следующим
образом:
1. Сброс 32-разрядного произведения.
2. Сдвиг множителя вправо.
3. Если установлен бит переноса, сложить множимое с результатом произведе-
ния.
4. Если множитель равен 0, то завершить выполнение функции.
5. Сдвиг множимого влево на одну позицию
6. Повторить шаги от 2 до 5.
Этот алгоритм умножения работает только с беззнаковыми числами, он иллюст-
рируется программой по примеру 4.8. В этом примере 16-разрядный множитель пере-
дается функции через ячейку памяти данных, адресуемую FSRO, 16-разрядное множи-
мое находится в ячейке, адресуемой FSR1, а ячейка, предназначенная для хранения 32-
разрядного произведения, адресуется FSR2. Эта функция может быть модифицирова-
на таким образом, что при использовании того же алгоритма будет выполняться умно-
жение чисел любой разрядности.
Пример 4.8
;******************* Функция MUL16 ********************
; использует 2 уровня программного стека
; использует WREG, FSRO, FSR1, FSR2, TABLAT, PRODL и PRODH
; использует функции Add32 и Shift
; Умножает содержимое ячейки FSR1 на содержимое ячейки
; FSRO, сохраняет результат в FSR2
; 16-разрядное число х 16-разрядное число —> 32-разрядный
; результат
MUL16:
124
Применение микроконтроллеров PIC 18
MOVLW 3
MUL16a
CLRF PLUSW2 ;очистка произведения
DECF WREG
BNN MUL16a
MOVLW 3
CLRF PLUSWJ ;очистка 2 байтов множимого
MOVLW 2
CLRF PLUSWJ
MUL16b
MOVLW 1
RRCF PLUSWO ;сдвиг множителя вправо
RRCF 1NDF0
BNC MUL16c ;если нет переноса
CALL Add 32 ;прибавить множимое к произведению
MUL16C
CALL Shift ;сдвиг множимого влево
MOVF PLUSWO, 0
IORWF INDFO, 0
BNZ MUL16b ;если множитель не равен 0
RETURN
Функция Add32
Add32:
MOVFF FSR2L, PRODH
MOVFF FSR1L, PRODL
BCF STATUS, . 0
MOVLW 4
MOVWF TABLAT
Add32a:
MOVF POSTINCI, 0
ADDWFC DECFSZ BRA POSTINC2 TABLAT Add32a
MOVFF PRODH, FSR2L
MOVFF RETURN PRODL, FSR1L
Функция Shift *************
Shift:
MOVFF
BCF
MOVLW
Shiftl:
RLCF
DECFSZ
BRA
MOVFF
RETURN
FSR1L, PRODH
STATUS, 0
4
POSTINCI
WREG
Shiftl
PRODH, FSR1L
Эта функция легко модифицируется для умножения чисел любой разрядности,
однако, если задача заключается в выполнении 16-разрядного умножения, то ее следу-
Глава 4. Программирование на языке Ассемблера
125
ет решать посредством 4-х кратного выполнения команды MULWF с целью получения
16-разрядного произведения в ans3-ans0 по следующему алгоритму:
1. Умножить младшие байты и поместить результат в ansO, ansi.
2. Умножить старшие байты и поместить результат в ans2, ans3.
3. Выполнить перекрестное умножение младшего байта первого операнда со
старшим байтом второго операнда, прибавить произведение к ansi, ans2, ans3.
4. Выполнить перекрестное умножение младшего байта второго операнда со
старшим байтом первого операнда, прибавить произведение к ansi, ans2, ans3.
Этот процесс иллюстрируется примером 4.9, соответствующая программа го-
раздо короче, чем функция, показанная в примере 4.8. Эта функция использует множи-
тель, адресуемый FSRO, и множимое, адресуемое FSR1, при этом произведение адре-
суется FSR2. Пример 4.9 также выполняется быстрее и требует меньше памяти, чем
пример 4.8.
Пример 4.9
Функция MUL16I
использует 1 уровень стека
использует WREG, PRODL, PRODH, TABLAT, FSRO, FSR1, FSR2
: 16-разрядное беззнаковое умножение. Содержимое ячейки, адресуемой
; FSRO, умножается на содержимое ячейки, адресуемой
FSR1, результат помещается в ячейку, адресуемую FSR2
6f:
MOVF INDFO, 0
MULWF INDF1
MOVFF PRODL, INDF2
MOVLW 1
MOVFF PRODH, PLUSW2
MOVFF FSR1L, TABLAT
MOVF PLUSWO,0
MULWF PREINCI
MOVLW 2
MOVFF PRODL, PLUSW2
MOVLW 3
MOVFF PRODH, PLUSW2
MOVFF TABLAT, FSR1L
MOVFF FSR1L, TABLAT
MOVF INDFO, 0
MULWF PREINCI
MOVFF TABLAT, FSR1L
MOVFF FSR2L, TABLAT
MOVF PRODL, 0
ADDWF PREINC2
MOVF PRODH, 0
ADDWFC PREINC2
CLRF WREG
ADDWFC PREINC2
MOVFF TABLAT, FSR2L
MOVF PREINCO, 0
MULWF INDF1
126
Применение микроконтроллеров PIC 18
MOVE1 PRODL, О
ADDWF PREINC2
MOVF PRODH, 0
ADDWFC PREINC2
CLRF WREG
ADDWFC PREINC2
RETURN
Деление
К сожалению, команды деления в наборе команд PIC нет. Однако существует со-
ответствующий алгоритм, который можно использовать в случае необходимости вы-
полнения операции деления. Деление - это операция, противоположная умножению,
поэтому при генерации частного вместо сдвига вправо нужно использовать сдвиг вле-
во, а вместо сложения - вычитание. Является обычным делить делимое двойной раз-
рядности и генерировать целочисленное частное и целочисленный остаток. Например,
если 22 поделить на 5, то частным будет 4, а остатком - 2. Приводимый далее алгоритм
делит беззнаковое 16-разрядное число на беззнаковое 8-разрядное число, при этом
как частное, так остаток будут беззнаковыми 8-разрядными числами.
1. Сдвинуть делимое и частное влево на один разряд.
2. Сравнить самые старшие 8 разрядов делимого с делителем и, если они боль-
ше, чем делитель, вычесть делитель из самых старших восьми разрядов делимого, по-
сле чего инкрементировать частное.
3. Повторить шаг 2 восемь раз.
4. Остатком будут самые старшие 8 разрядов делимого.
Для иллюстрации выполнения деления, функция, показанная в примере 4.10, де-
лит содержимое PRODL и PRODH на содержимое TABLAT, помещая частное в PRODL, а
остаток - в PRODH после возврата из функции.
Пример 4.10
.***************** функция Div *******************
; использует один уровень программного стека
; использует WREG, PRODL, PRODH, TABLAT, TBLPTRL и TBLPTRH
; Частное возвращается в PRODL, а остаток - в PRODH
; TABLAT предварительно загружается делителем
; PRODL и PRODH предварительно загружается делимым
Div.
MOVLW 8 ;загружает в счетчик 8
MOVFF WREG, TBLPTRL
Divl:
BCF STATUS, 0 ;сдвигает частное влево
RLCF TBLPTRH
BCF STATUS, 0 ; сдвигает делимое влево
RLCF PRODL
RLCF PRODH
MOVF TABLAT, 0 ;сравнивает делимое с делителем
SUBWF PRODH, 0
BNC Div2 ;если делитель больше делимого
Глава 4. Программирование на языке Ассемблера
127
MOVFF WREG, PRODH
INCF TBLPTRH
' i v2:
DECFSZ TBLPTRL /декрементирует счетчик
BRA Divl
MOVFF TBLPTRH, PRODL /частное в PRODL
RETURN
Функция, показанная в примере 4.10, может быть модифицирована на деление
чисел любой разрядности, она также может выполнять деление со знаком, если перед
выполнением деления числа будут сделаны положительными. Если предпринимается
попытка деления чисел со знаком, то как частное, так и остаток будут отрицательными,
если выполняется деление чисел, имеющих разные знаки, в противном случае оба они
будут положительными. Исключающее Или используется для сравнения знаков дели-
мого и делителя с целью определения того, должен ли результат быть положительным
или отрицательным.
Пример 4.11 показывает то, как 32-разрядное число делится на 16-разрядное
число с целью получения 16-разрядного частного и 16-разрядного остатка. Сравните
его с примером 4.10, чтобы увидеть, как перейти к делению с более высокой точно-
стью. Вместо того, чтобы передать числа в функцию через регистры, в данном случае
числа передаются с использованием регистров выбора файла для их адресации, также
используются регистры PRODL и PRODH. В данном случае FSRO указывает на 32-
разрядное делимое, a PRODL и PRODH содержат 16-разрядный делитель. После за-
вершения деления, частное возвращается в ячейке памяти, адресуемой FSR2, а оста-
ток - в ячейке памяти, адресуемой FSRO, он соответствует старшим двум байтам дели-
мого. Счетчик был изменен с 8 на 16, поскольку в данном случае выполняется 16-
разрядное деление.
Пример 4.11
Функция Divl6
использует один уровень программного стека
использует WREG, PRODL, PRODH, TABLAT, TBLPTRL, TBLPTRH,
FSRO и FSR1
Частное возвращается в ячейке, адресуемой FSR2
PRODL и PRODH предварительно загружаются делителем
FSR0 предварительно загружается адресом делимого
FSRO адресует остаток при возврате
D1V16:
MOVLW .16
MOVFF WREG, TABLAT
/загружает в счетчик 16
Divl6a:
MOVLW 1
BCF STATUS, 0
RLCF INDF2
RLCF PLUSW2
/сдвигает частное влево
BCE' STATUS, 0
RLCF POSTINCO
RLCF' POSTINCO
/сдвигает делимое влево
128
Применение микроконтроллеров PIC 18
RLCF POSTINCO
RLCF POSTDECO
MOVF PRODL, 0 /сравнивает делитель и делимое
SUBWF’ POSTINCO, О
MOVWF TBLPTRL
MOVF’ PRODH, 0
SUBWFB POSTDECO, 0
MOVWF' TBLPTRH
BNC Divl6b
MOVFF TBLPTRL, POSTINCO /вычитание
MOVFF TBLPTRH, POSTDECO
LNCF INDF2 /инкрементирование частного
BNC Divl6b
MOVLW 1
INCF PLUSW2
Divl6b:
MOVLW 0
IORWF POSTDECO
IORWF POSTDECO
DECFSZ TABLAT /декрементирование счетчика
BRA Divl6a
IORWF POSTINCO
IORWF POSTINCO
RETURN
4.3. Преобразования между десятичным и двоичным форматами
Числа часто остаются в формате BCD, однако имеются случаи, когда числа из
формата BCD должны быть преобразованы в двоичный формат. Если нужны числа в
формате BCD, однако они доступны только в двоичной форме, то также необходимо
выполнить преобразование. В данном подразделе рассматривается преобразование
между двоичным форматом и форматом BCD. Формат ASCII также иногда требуется,
однако преобразование между форматами ASCII и BCD - это простая задача, связанная
с прибавлением или отниманием 0x30, как это объяснялось в предшествующих под-
разделах.
Преобразование из двоичного формата в формат BCD
Это преобразование выполняется достаточно легко, если имеется возможность
выполнения операции деления. Соответствующий алгоритм (называемый «правилом
Хорна») преобразования из двоичного формата в формат BCD использует деление на
10 и может быть описан следующим образом:
1. Поделить на 10
2. Сохранить остаток как цифру результата
3. Повторять шаги 1 и 2 до тех пор, пока частное не станет нулевым
Глава 4. Программирование на языке Ассемблера
129
Предположим, что 011001112 должно быть преобразовано в последовательность BCD-
цифр. Если 0110 01112 поделить на 10102, то будет получено частное 10102 и остаток, равный
00112. The 00112 представляет собой младшую цифру результата. Вследствие того, что част-
ное 10102 не является нулевым, выполняем деление на 10102 еще раз. На этот раз мы полу-
чим частное, равное 00012, и остаток, равный 00002. Опять-таки 00012 делится на 10102, при
этом получается частное, равное 00002, при остатке, равном 00012. Числа 00112 , 00002 и
00012 составляют ряд остатков, полученных в данном примере. Результат равен 103, поря-
док, в котором возвращаются числа, реверсируется.
Пример 4.12 показывает функцию, которая использует 8-разрядное из приме-
ра 4.10 для преобразования числа из PRODL в формат BCD, сохранив результат в ячей-
ке памяти, адресуемой FSRO. Это число сохраняется младшей цифрой вперед и огра-
ничивается в памяти числом 0x10. Число 103 сохраняется как 3, 0, 1 и 0x10.
Пример 4.12
BinBCD
; использует 2 уровня
программного стека
; использует
Div и ее регистры, а также FSRO
/преобразует двоичное число из PRODL в формат BCD в
/памяти, адресуемой FSRO. Результат заканчивается
/значением 0x10
BinBCD:
MOVLW • MOVFF .10 WREG, TABLAT
BinBCDl: CALL Div /делит на 10
MOVFF PRODH, POSTINCO /сохраняет остаток
CLRF PRODH
MOVF PRODL, 0
BNZ BinBCDl /до тех пор, пока частное не станет равным 0
MOVLW 0x10 /сохраняет метку конца
MOVWF POSTINCO
RETURN
Предположим, что последовательность BCD-цифр, сохраняемая в памяти, преобразу-
ется в строку символов ASCII NULL, что обеспечивает совместимость с языком С. Это выпол-
няется функцией, показанной в примере 4.13.
Пример 4.13
/ ************** ASCIInull ****************
/ использует 1 уровень программного стека
/ использует FSRO, FSR1, WREG, TABLAT
/ реверсирует порядок символов строки
/ и преобразует их в строку ASCII null
ASCIInull:
MOVFF FSROL, FSR1L
130
Применение микроконтроллеров PIC 18
MOVFF FSR0H, FSR1H
ASCIInulla:
MOVLW 0x30 /в ASCII
ADDWF INDFO
MOVLW 0x40
CPFSEQ POSTINCO
BRA ASCIInulla /если не конец
DECF FSR0L
MOVLW 0
SUBWFB FSR0H
MOVWF POSTDECO
ASCIInullb:
MOVFF INDFO, TABLAT /свопинг данных
MOVF INDF1, 0
MOVWF POSTDECO
MOVFF TABLAT, POSTINCI
MOVF FSR0H, 0
CPFSEQ FSR1H, 0
BRA ASCIInullb /если не конец
MOVF FSR0L, 0
CPFSEQ FSR1L, 0
BRA ASCIInullb /если не конец
RETURN
Алгоритм преобразования из двоичного формата в десятичный формат также работа-
ет для систем с другими основаниями счисления, если делитель изменяется в соответствии
с основанием системы счисления. Например, для преобразования из двоичной формы в
восьмеричную, необходимо выполнять деление на 8. Этот алгоритм используется для пре-
образования чисел в любую систему счисления посредством изменения делителя в соответ-
ствии с основанием системы счисления.
Вспомните, что преобразование из двоичного формата в формат BCD (примеры 4.9 и
4.10) требует, чтобы остатки сохранялись в памяти, однако порядок остатков реверсируется.
Одним из способов изменения порядка остатков является занесение их в стек перед сохра-
нением их в строке ASCII. Пример 4.14 показывает, как это выполняется с использованием
стека, при этом заменяются две функции, соответствующие примерам 4.12 и 4.13. Обрати-
те внимание на то, насколько короче стала программа после использования стека для ре-
версирования данных.
Пример 4.14
;************* BinBCDs **************
; использует 2 уровня программного стека
; использует Div и ее регистры, а также FSR0 и WREG
; использует TABLAT и PRODH
; преобразует двоичное число в PRODL в формат BCD по
/адресу памяти в FSR0; заканчивается 0x00
BinBCDs:
MOVLW .10
/загрузка делителя, равного 10
Глава 4. Программирование на языке Ассемблера
131
MOVFt MOVLW MOVWF WREG, TABLAT 0 POSTDEC2 ;сохранение метки конца в стеке
BinBCDsl: CALL MOVLW ADDWF MOVFF Div 0x30 PRODH PRODH, POSTDEC2 ;деление на 10 /преобразование в ASCII / сохранение остатка в стеке
CLRF MOVF BNZ PRODH PRODL, 0 BinBCDsl /пока частное не станет нулем
3. ''BCDs2: MOVF MOVWF BNZ RETURN PREINC2,0 POSTINCO BinBCDs2 ;извлечение данных из стека
Пример 4.14 использует PRODH и TABLAT для преобразования. С целью обеспе-
чения того, чтобы они не использовались еще где-то, целесообразно модифицировать
функцию таким образом, чтобы эти регистры сохранялись в стеке данных перед тем,
как функция будет их использовать, и восстанавливались бы перед возвратом из функ-
ции, как это показано в примере 4.15.
Пример 4.15
.************* BinBCDs
; использует 2 уровня программного стека
; использует 6 программных уровня (максимум) стека данных, адресуемого FSR2
/ использует Div и ее регистры, а также FSR0 и WREG
; сохраняет BCD-строку в памяти, адресуемой FSR0
; заканчивается 0x00 (нулевая строка С-стиля)
BinBCDs:
MOVFF TABLAT, POSTDEC2 /занесение в стек TABLAT и PRODH
MOVFF PRODH, POSTDEC2
MOVLW . 10
MOVFF WREG, TABLAT
MOVLW 0 /сохранение в стеке маркера конца
MOVWF POSTDEC2
BinBCDsl:
CALL Div / деление на 10
CALL Div /деление на 10
MOVLW 0x30
ADDWF PRODH /преобразование в ASCII
MOVFF PRODH, POSTDEC2 / сохранение остатка в стеке
CLRF PRODH
MOVF PRODL, 0
BNZ BinBCDsl /пока частное не станет нулем
BinBCDs2:
MOVF PREINC2,0
MOVWF POSTINCO /извлечение данных из стека
BNZ BinBCDs2
132
Применение микроконтроллеров PIC 18
MOVFF
MOVFF
RETURN
PREINC2,
PREINC2,
PRODH
TABLAT
/извлечение PRODH и TABLAT из стека
Обратите внимание на то, как регистры TABLAT и PRODH заносятся в стек перед
гем, как функция начинает работу и извлекаются из стека непосредственно перед вы-
полнением команды return. Эта функция теперь использует только FSRO, WREG и стек
данных. Обычно рабочий регистр не сохраняется. Какое пространство стека данных
необходимо? Два байта необходимы для TABLAT и PRODH и еще на три байта больше
для остатков, которые помещаются в стек. Маркер конца требует одного байта про-
странства стека данных, - в общем для данного примера необходимо использовать
вплоть до шести байтов пространства стека данных.
Преобразование формата BCD в двоичный формат
Прерывание чисел из формата BCD в двоичный формат требует использования
умножения вместо деления. Алгоритм такого преобразования требует, чтобы двоичное
число начиналось с нуля и по мере обработки каждого разряда, двоичное число должно
умножаться на 10, после чего новая цифра добавляется к двоичному результату. Этот
алгоритм описывается следующим образом:
1. Начать с результата, равного нулю.
2. Умножить результат на 10.
3. Добавить новую BCD-цифру к результату.
4. Повторять шаги 2 и 3 до тех пор, пока не будет достигнута последняя цифра.
Для иллюстрации этого алгоритма, функция в примере 4.16 преобразует нулевую
ASCII-строку, находящуюся в ячейке памяти, в двоичное число, возвращаемое как 8-
разрядное беззнаковое число в регистре TABLAT. Нулевая ASCII-строка адресуется
регистром выбора файла FSRO на входе функции.
Пример 4.16
.************** ASCIIBin ****************
; использует 1 уровень стека
; использует WREG, TABLAT, FSRO
; Преобразует нулевую ASCII-строку, адресуемую
; регистром FSR0, в 8-разрядное двоичное число,
; возвращаемое в регистре TABLAT
ASCIIBin:
CLRF TABLAT ;очистка результата
ASClIBinl:
MOVLW 0
CPFSEQ INDFO
BRA ASCHBin2
RETURN ;возврат по нулю
ASCIIBin2:
MOVLW . 10 ;х10
MULWF TABLAT
MOVFF PRODL, TABLAT
MOVLW 0x30 ;ASCII в BCD
SUBWF POSTINCO, 0
Глава 4. Программирование на языке Ассемблера
133
ADDWF TABLAT /добавление цифры
BRA ASCIIBinl
Как и в случае алгоритма преобразования двоичных чисел в десятичные, данный алго-
ритм также работает с любым основанием системы счисления, если изменить коэффициент
10 на значение основания системы счисления. Например, если требуется преобразовать
строку восьмиричных чисел, то нужно выполнять умножение на 8. Данная функция использу-
ет 8-разрядное умножение, однако в случае использования 16-разрядного умножения, мо-
жет быть получен двоичный результат большей разрядности.
4.4. Временные задержки
Многие применения микроконтроллеров требуют отработки временных задер-
жек. В данном подразделе рассматривается то, как нужно формировать точные вре-
менные задержки, используя программы, которые их генерируют. Например, предпо-
ложим, что нужно активировать соленоид на 100 мс для правильного перемещения ка-
кого-то механического приспособления. Для формирования этой временной задержки,
завной 100 мс, необходимо использовать какой-то метод генерирования временной
задержки.
Программы для формирования временных задержек
Для начала рассмотрения данного вопроса, исследуем простую функцию форми-
рования временной задержки, показанную в примере 4.17. В этой функции выполняет-
ся декрементирование регистра WREG и если результат будет нулевым, то отрабатыва-
ется возврат из функции. Если результат не будет равным нулю, toWREG декременти-
руется повторно и т.д. Эта функция является простой и достаточно короткой, она имеет
предсказуемое время выполнения, определяемое тем, сколько раз будет выполняться
декрементирование регистра WREG
Пример 4.17.
.'-lay:
DECFSZ WREG /декрементирование WREG
BRA Delay /переход, если WREG не равен 0
RETURN
Предположив, что WREG загружается перед вызовом функции, можно сказать,
нто количество времени, требуемое для выполнения этой процедуры, будет опреде-
ляться количеством командных циклов, нужных на отработку команд CALL и RETURN,
тлюс количество командных циклов, требуемых для последовательного декрементиро-
зания WREG до нулевого состояния. Декрементирование WREG выполняется командой
DECFSZ, за которой следует команда BRA. Вы можете обратиться к приложению А, в
котором указано количество командных циклов, требуемое для выполнения каждой
команды. Каждая из команд CALL и RETURN требует для своего выполнения два ко-
мандных цикла, т.е. всего на их выполнение требуется четыре командных цикла. Ко-
манда DECFSZ требует для своего выполнения один командный цикл, а команда BRA
134
Применение микроконтроллеров PIC 18
требует для своего выполнения два командных цикла. Пример 4.18 показывает уравне-
ние, которое нужно использовать для определения временной задержки в данном слу-
чае.
Пример 4.18
Число тактовых импульсов = 4 + WREG х 3
или
Число тактовых импульсов - 4
WREG = ---------------------------
3
Из этого уравнения, если WREG равен 1, получаем, что количество времени, тре-
буемое для выполнения функции Delay, равно 7 циклов. Если во WREG загрузить мак-
симальное количество нулей (1 ноль дает 256 итераций, то количество командных цик-
лов будет равно 4 + (256 ( 3) или 772 цикла. Командный цикл в семействе устройств
PIC18 имеет длительность, равную четырем периодам следования импульсов внешнего
тактового генератора. Если внешняя тактовая частота равна 4 мГц (250 нс), то частота,
соответствующая одному командному циклу, будет равна 1 мГц (1,0 мкс). Это означает,
что функция Delay по примеру 4.17 может генерировать временную задержку в диапа-
зоне от 7,0 мкс до 772 мкс, в зависимости от значения, загруженного во WREG. Это
время даже близко не соответствует значению временной задержки в 100 мс, о которой
говорилось в начале данного подраздела.
Пример 4.19 демонстрирует один из методов получения более длительной вре-
менной задержки. В данном случае в качестве счетчика во WREG загружено значение,
равное 165. При внешней тактовой частоте, равной 4 мГц, это дает время задержки,
равное 165 х 3 + 4 или 499 мкс (в этом примере округляем это значение до 500 мкс).
Если нужно точно 500 мкс, то в функцию Delay вводится операция NOP (отсутствие опе-
рации) (NOP для своего выполнения требует один командный цикл) непосредственно
перед командой RETURN, как это показано в примере 4.20. Для функций, показанных в
примерах 4.19 и 4.20, значение внешнего счетчика равно 200. Если мы отработаем
временную задержку в 500 мкс 200 раз, то получим время задержки, точно равное 100
мкс. Конечно же, точность этой временной задержки зависит от точности внешнего
источника тактовой частоты. Это время также не будет точным в силу того, что мы не
учитываем время, необходимое для декрементирования внешнего счетчика в TABLAT,
однако в случае соленоида точность временной задержки в пределах одной миллисе-
кунды при общей задержке в 100 мс является вполне приемлемой.
Пример 4.19
De 1 аут:
MOVLW .200 ;200 раз
MOVWF TABLAT
Delayml:
CALL Delay
DECFSZ TABLAT
BRA Delayml
RETURN
Delay: ;165 раз
MOVLW .165
Глава 4. Программирование на языке Ассемблера
135
е I d у 1 :
DECFSZ WREG
BRA Delayl
RETURN
Пример 4.20
De1 a ym:
MOVLW .200 ;200 раз
MOVWF TABLAT
Delayml:
CALL Delay
DECFSZ TABLAT
BRA Delayml
RETURN
Delay: ;165 раз
MOVLW .165
Delayl:
DECFSZ WREG
BRA Delayl
NOP ;плюс еще 1 командный цикл
RETURN
При использовании в качестве базиса временной задержки в 100 мс можно полу-
чать также более длительные временные задержки. Например, если требуется времен-
ная задержка в 5 секунд, то она может быть получена в результате 50-кратного вызова
функции Delay (см. пример 4.21). Далее в этой книге будут рассмотрены также иные
методы получения временных задержек, использующие внутренние таймеры. Будет
также рассмотрен метод получения временных задержек, предусматривающий ис-
пользование прерываний от таймера реального времени (RTC). Этот метод будет рас-
сматриваться тогда, когда будет анализироваться использование прерываний в раз-
личных приложениях. Основной проблемой, связанной с применением программного
таймера, является то, что микроконтроллер при отработке временной задержки не мо-
жет делать ничего другого. В некоторых случаях это приемлемо, а во многих других -
нет. Если, например, система использует прерывания, то отработка временной за-
держки может быть прервана, что приведет к некорректному значению временной за-
держки.
Пример 4.21
D5sec:
MOVLW .50
MOVWF TBLPTRL
D5secl:
CALL Delaym
DECFSZ TBLPTRL
BRA D5secl
;5-секундная задержка использует Delaym
RETURN
136
Применение микроконтроллеров PIC 18
4.5. Примеры программ
В этом подразделе рассмотрено несколько программных примеров, иллюстри-
рующих различные методы программирования. Как и в случае других примеров, рас-
сматриваемых в этой книге, примеры из данного подраздела должны быть введены IDE
и выполнены - как на полной скорости, так и в пошаговом режиме, чтобы было достиг-
нуто полное понимание соответствующих программ.
Первый программный пример
Этот первый программный пример иллюстрирует первый случай использования
ввода-вывода. Данный пример использует биты О (RA0) и 1 (RА1) пор та ввода-вывода
А микроконтроллера PIC для считывания данных с клавиатуры ПК-стиля. Клавиа-
тура ПК-стиля выбрана вследствие того, что она легко подключается к микроконтрол-
леру по причине ее ТТЛ-совместимости и использования 0/5 В логики. 6-штырьковый
соединительный разъем типа DIN клавиатуры ПК-стиля показан на рис. 4.2.
Соединительный разъем клавиатуры использует только 4 из 6 выводов для пода-
чи электропитания и передачи сигналов. При этом в качестве сигнальных используются
две из четырех линий. По сигнальным линиям передаются данные и тактовая частота.
Клавиатура запитывается от +5,0 В с заземляющим входом и требует максимум 250 мА
тока, который подается от источника питания микроконтроллера. Рисунок 4.3 иллюст-
рирует сигналы данных и тактовой частоты, которые обычно присутствуют на интер-
фейсе.
04
30
1О 02
Контакты, штырьки, выводы^ О | Об
1= данные
2 = не подсоединен
3 = земля
4- + 5 V
5 = тактовая частота
6 = не подсоединен
Разъем кабеля
клавиатуры
Рис. 4.2. 6-ти контактный соединительный
разъем типа DIN клавиатуры ПК-стиля
Один фрейм данных клавиатуры состоит из 11 импульсов тактовой частоты, по-
ложительные фронты которых используются для получения данных от клавиатуры. Так-
товые импульсы передаются на номинальной частоте, равной 10 кГц. Чтобы интерфейс
функционировал корректно, частота тактовых импульсов должна лежать в диапазоне
между 10 и 10,7 кГц. Время передачи бита (время между импульсами) следовательно,
номинально и равно 100 мкс. При приеме данных от клавиатуры контролируется со-
стояние линии тактовых импульсов, и всякий раз при переключении тактового импульса
с логического нуля в логическую единицу микроконтроллером производится выборка
линии данных. Это означает, что должна быть написана программа или функция, кон-
тролирующая тактовые импульсы и всякий раз, когда тактовый импульс переходит в
единичное состояние, данные подаются на вход микроконтроллера, а затем преобра-
зуются в символ, переданный от клавиатуры.
Глава 4. Программирование на языке Ассемблера
137
Ошибка фрейма возникает тогда, когда стартовый бит является ненулевым, а
сгоповый бит не является единичным в соответствующие моменты времени. Ошибки
фрейма возникают наиболее обычно тогда, когда данные принимаются при некоррект-
ной скорости информационного обмена. Таким образом, микроконтроллерная про-
грамма может содержать секции, контролирующие правильность скорости информа-
ционного обмена. Бит паритета добавляется к данным с целью обеспечения того, что
всегда будет передаваться нечетное количество единиц. В примере сигналов, пока-
занном на рис. 4.3, передается единичный бит паритета, формируя нечетный паритет.
Данные имеют два единичных бита, а также единичный бит паритета, что в сумме дает
три единичных бита. Поскольку три - это нечетное число, то сообщение имеет нечет-
ный паритет. Если обнаруживается неверный паритет (четный парите), то это означает,
чго сообщение является некорректным. Ошибки паритета возникают в случаях присут-
ствия помех В некоторых случаях в сообщение вводится символ вопросительного зна-
ка, если обнаружена ошибка паритета. В других случаях используются средства управ-
ления информационным потоком с целью запроса повторной передачи данных.
Cl С2 СЗ С4 С5 С6 С7 С8 С9 СЮ СИ
данные
ста . DO DI D2 D3 D4 D5 D6 D7 нечетныи стоп
паритет
Старт-бит всегда ноль
Паритет всегда нечетный
Стоп-бит всегда в единичном состоянии
Рис. 4.3. Сигналы тактовой частоты и данных клавиатуры
Вследствие того, что в этом примере используются биты 0 и 1 порта А, то нужно
знать, какая команда выполняет считывание порта А до того, как начать писать про-
грамму, считывающую нажатые клавиши клавиатуры. Порт А считывается посредством
чтения ячейки регистрового файла с адресом 0xF80. В программе обращение к PORTA
идет по адресу OxFO. Порт А программируется посредством загрузки соответствующим
значением регистра TRISA по адресу 0xF92. Единица в бите регистра TRISA задает ре-
жим ввода для соответствующего вывода, а ноль - режим вывода. В данном примере
используются биты 0 и 1 для установки режима ввода данных, поэтому в регистр TRISA
загружается значение 0x03. Пример 4.22 демонстрирует программу, требуемую для
138
Применение микроконтроллеров PIC 18
программирования битов 0 и 1 порта А так, чтобы они функционировали как входные
выводы. Биты порта должны также программироваться как цифровые выводы в некото-
рых версиях PIC посредством загрузки 0x7F в регистр ADCON1.
Пример 4.22
MOVLW 0x7F
MOVWF ADCON1
MOVLW 3
MOVWF TRISA
;порт программируется как цифровой
/биты 0 и 1 объявляются входами
Функция, которая принимает отдельный символ от клавиатуры, иллюстрируется
примером 4.23. В этой программе предполагается, что бит RAO (бит 0 порта А) подсое-
динен к выводу данных клавиатуры, а бит RA1 (бит 1 порта А) соединен с линией такто-
вых сигналов. Данная функция получает символ от клавиатуры и возвращает его в ре-
гистре WREG. Если обнаружена ошибка (фрейма или паритета), бит переноса устана-
ливается в единичное состояние при возврате из функции. Если в регистре WREG при-
сугствует корректный символ, бит переноса сбрасывается. Для того, чтобы сделать эту
процедуру более эффективной и читабельной, в нее включена функция, названная
Wait4Clock, которая ожидает перехода линии подачи тактовых сигналов в нулевое со-
стояние, а затем ожидает перехода линии подачи тактовых сигналов в единичное со-
стояние перед выходом из функции. Функция Wait4Clock показана первой в листинге.
Команды проверки состояния бита и пропуска используются в этой функции для кон-
троля изменения состояния входного сигнала.
Пример 4.23
. ************** wait4Clock *****************
; Ожидает перехода линии тактовых сигналов в нулевое
/состояние, а затем в единичное перед возвратом из
/функции
Wait4Clock:
BTFSC PORTA, 1 /проверка RAI
BRA Wait4Clock /если тактовый сигнал = 1
Wait4Clockl:
BTFSS PORTA, 1 / проверка RAI
BRA Wait4Clockl / если тактовый сигнал = 0
RETURN
GetData
/ использует 2 уровня программного стека
/ использует PRODL, PRODH и TABLAT
f
; Считывает символ с клавиатуры и возвращает его во WREG
ошибка = устанавливается бит переноса
Глава 4. Программирование на языке Ассемблера
139
SetDa La:
CALL.
BTFSS
BRA
BSF
Wait4Clock
PORTA, 0
GetDatal
STATUS, 0
RETURN
/ожидает первого тактового сигнала
/проверяет RAO
;если на линии данных стартовый
;бит, переход на GetDatal
/если начальное состояние
/ некорректно, установка бита переноса (CARRY)
/и возврат
/ программа продолжает выполняться с этого места,
/если распознан корректный стартовый бит
PRODL используется как счетчик битов данных
PRODH используется для подсчета единиц в потоке данных с целью контроля
.аритета
GetDatal:
MOVLW 8
MOVWF PRODL /установка счетчика на 8 /сброс счетчика паритета
CLRF PRODH
GetData2: CALL Wait4Clock /ожидание тактового импульса синхронизации бита данных
BTFSC PORTA, 0 /проверка RA0
INCF PRODH /учет одной единицы - бит паритета и сброс CARRY
BTFSC PORTA, 0 /проверка RA0
SETF STATUS, 0 /установка бита переноса, если бит данных = 1
RRCF TABLAT /циклический сдвиг бита переноса (бит данных) в TABLAT
DECF PRODL /декрементирование счетчика
BNZ GetData2 /повтор 8 раз для 8 битов данных
CALL Wait4Clock /ожидание синхроимпульса для бита паритета
MOVF PORTA, W /загрузка бита данных во WREG
XORWF PRODH /исключающее ИЛИ со счетчиком паритета
BTFSS BRA PRODH, 0 GetData3 /если паритет правилен
BSF STATUS,0 /если ошибка паритета, установка CARRY
RETURN
GetData3: CALL / если Wait4Clock нет ошибки паритета
BTFSC PORTA, 0 /проверка RAO на стоп-бит
BRA GetData4 /если все нормально, реакция на стоп-бит
BSF STATUS, 0 /если ошибка фрейма, установка бита переноса
RETURN
140
Применение микроконтроллеров PIC 18
GetData4: /если нет ошибок
MOVF TABLAT, W /загрузка байта данных во WREG
BCF STATUS, 0 /очистка бита переноса
RETURN
Функция, иллюстрируемая примером 4.23, получает байт от клавиатуры, однако
мы не получим ASCII-код нажатой клавиши до тех пор, пока не поймем, как работает
клавиатура, и не воспользуемся этим знанием. Всякий раз, когда нажимается клавиша
клавиатуры, клавиатура посылает т.н. скан-код клавиши. Скан-код не является
ASCII-кодом; это число, которое поставлено в соответствие каждой клавише клавиату-
ры. Табл. 4.1 перечисляет скан-коды клавиатуры.
Обратите внимание на то, что некоторые скан-коды имеют длину, соответствующую
двум либо большему числу символов. Все скан-коды, длина которых превосходит один сим-
вол, начинаются кодом ОхЕО, который распознается программно как сигнал о необходимости
приема дополнительных байтов скан-кода, состоящего из нескольких байт.
Когда на клавиатуре нажата клавиша, интерфейс клавиатуры посылает скан-код, а ко-
гда клавиша отпускается, интерфейс клавиатуры посылает код прерывания, за которым сле-
дует скан-код клавиши. Например, когда нажата клавиша А, посылается код 0x1 С. А когда
клавиша А отпускается, передается код OxFO, за которым следует код 0x1 С. Это позволяет
отслеживание программным обеспечением нажатия нескольких клавиш. Так, нажатие кла-
виши “Левый SHIR (Временный верхний регистр)” с последующим нажатием клавиши А
приведет к генерированию следующей последовательности кодов, если первой будет отпу-
щена клавиша Shift: 0x12, 0x1 С. Если же первой будет отпущена клавиша А, а затем будет
отпущена клавиша Shift, то будет послана следующая последовательность кодов: OxFO, 0x1 С,
OxFO, 0x12. Когда отпускается клавиша, генерирующая код, превосходящий по длине один
байт, как, например, клавиша Insert (Вставка), то после кода ОхЕО будет послан код, т.е. по-
следовательность кодов будет иметь вид: ОхЕО, OxFO, 0x70. Единственным исключением из
этих правил является клавиша Pause (Пауза) key, которая генерирует код, начинающийся с
0хЕ1, а при ее отпускании генерируется 0хЕ1, OxFO, 0x14. Последовательность кодов преры-
вания для клавиши Print Screen (Печать экрана) является другим исключением, она имеет
вид: ОхЕО, OxFO, 0х7С, ОхЕО, OxFO, 0x12.
Таблица 4.1. Скан-код клавиатуры
Кла- виша Код Клавиша Код Клавиша Код
0 0x45 Z 0х1А 0x49
1 0x16 F1 0x05 / 0х4А
2 0х1Е F2 0x06 Enter (Ввод) 0х5А
3 0x26 F3 0x04 Escape (Выход) 0x76
4 0x25 F4 ОхОС Print Screen (Печать экрана) ОхЕО, 0x12, ОхЕО, 0х7С
5 0х2Е F5 0x03 Scroll Lock (Замок прокрутки) 0х7Е
6 0x36 F6 0x0В Pause (Пауза) 0хЕ1, 0x14, 0x77
7 0x3D F7 0x83 Insert (Вставка) ОхЕО, 0x7 0
8 ОхЗЕ F8 ОхОА Ноте (В исходное) ОхЕО, ОхбС
Глава 4. Программирование на языке Ассемблера
141
Кла- виша Код Клавиша Код Клавиша Код
9 0x46 F9 0x01 Page Up (Страница вверх) ОхЕО, 0x7D
А 0х1С F10 0x09 Delete (Стереть) ОхЕО, 0x71
В 0x32 F11 0x78 End (Конец) ОхЕО, 0x69
С 0x21 F12 0x07 Page Down (Страница вниз) ОхЕО, 0х7А
D 0x23 Backspace (Шаг назад) 0x66 Up Arrow (Стрелка вверх) ОхЕО, 0x75
Е 0x24 Пробел 0x29 Left Arrow (Стрелка влево) ОхЕО, 0x6В
F 0x2В Tab (Табуляция) OxOD Down Arrow (Стрелка вниз) ОхЕО, 0x72
G 0x34 Caps Lock (Замок верхнего реги- стра) 0x58 Right Arrow (Стрелка вправо) ОхЕО, 0x74
Н 0x33 Left Shift (Левая клавиша времен- ного переключе- ния регистров) 0x12 Замок цифровой клавиатуры 0x7 7
I 0x43 Left Control (Управление левая) 0x14 / на цифровой клавиатуре ОхЕО, 0х4А
J ОхЗВ Left Alt Option (Левая клавиша Alt (Альтерна- тива) дополни- тельная) 0хЕ0, OxlF * на цифровой клавиатуре 0х7С
К 0x42 Left Alt (Левая клавиша Alt (Альтернатива)) 0x11 - на цифровой клавиатуре 0x7В
L 0x4В Right Shift (Правая клавиша временного пе- реключения ре- гистров) 0x59 + на цифровой клавиатуре 0x7 9
М ОхЗА Right Control (Правая клавиша управления) 0хЕ0, 0x13 Enter (Ввод) на цифровой клавиатуре ОхЕО, 0х5А
N 0x31 Right Alt Op- tion (Правая клавиша Alt (Альтерна- тива) дополни- тельная) ОхЕО, 0x27 . на цифровой клавиатуре 0x71
О 0x44 Right Alternate (Правая клавиша Alt (Альтернатива) ОхЕО, 0x11 0 на цифровой клавиатуре 0 0x7 0
Р 0x4D Applications (Приложение) ОхЕО, 0x2F 1 на цифровой клавиатуре 0x69
Q 0x15 0х0Е 2 на цифровой клавиатуре 0x72
R 0x2D - 0х4Е 3 на цифровой клавиатуре 0х7А
S 0x1В = 0x55 4 на цифровой клавиатуре ОхбВ
Т 0х2С \ 0x5D 5 на цифровой клавиатуре 0x73
142
Применение микроконтроллеров PIC 18
Кла- виша Код Клавиша Код Клавиша Код
и ОхЗС 1 0x54 6 на цифровой клавиатуре 0x74
V 0х2А 1 0x5В 7 на цифровой клавиатуре ОхбС
W OxlD 0х4С 8 на цифровой клавиатуре 0x7 5
X 0x22 0x52 9 на цифровой клавиатуре 0x7D
Y 0x35 f 0x41
Может быть написано программное обеспечение, которое сформирует интер-
фейс клавиатуры, однако в большинстве случаев весь этот процесс управляется пре-
рываниями. Необходимость использования прерываний связана со скоростью интер-
фейса клавиатуры. Если для считывания клавиатуры используются рассматриваемые
здесь программы, то микроконтроллер не должен выполнять никакой дополнительной
работы. Мы пока не будем рассматривать оставшуюся часть программного обеспече-
ния работы с клавиатурой - это будет сделано позже в этой книге, после исследования
назначения и роли прерываний. Здесь же мы рассмотрим то, как нужно распознавать
наличие тактового импульса и принимать данные через порт ввода-вывода, используя
несколько его штырьков.
Второй программный пример
Первый программный пример проиллюстрировал то, как проверять наличие сиг-
нала тактовой частоты, как организовать поисковую таблицу ASCII-кодов (хотя соответ-
ствующая программа не рассматривалась), а также то, как нужно работать с портом
ввода-вывода. Некоторые радиолюбители при передаче информации с целью сужения
полосы частот используют код Морзе. Сигнал незатухающих колебаний, используемый
при передаче кода Морзе, имеет полосу частот, ширина которой составляет всего 150
Гц. Код Морзе первоначально использовался телеграфистами, он был разработан для
организации свзи между железнодорожными станциями в 19 столетии и широко ис-
пользовался также и в 20 столетии.
Табл. 4.2 демонстрирует коды Морзе для букв и чисел. В таблице приведены сим-
волы и соответствующие им коды из точек (называемых “дит”) (.) и тире (называемых
“дах”) (-), а также шестнадцатиричные числа, указывающие количество точек и тире
(правые три бита), а также их структуру (левые 5 битов). Точке соответствует логиче-
ский ноль, а тире - логическая единица.
Предположим, что нам необходима система, которая посылает коды Морзе.
Вследствие того, что не так уж много людей знают код Морзе, мы решили разработать
простую микроконтроллерную систему, предназначенную для генерирования этого
кода. Поскольку аппаратные средства в этой книге пока еще не рассматривались, бу-
дем считать, что наша система берет ASCII - символ из регистра WREG и генерирует
для него код Морзе. Поскольку мы уже знаем, как считывать клавиатуру, например
стандартную клавиатуру ПК, то будем считать, что символы от клавиатуры передаются
в программу для их преобразования в код Морзе. Это позволит нам передавать коды
Морзе посредством ввода букв и цифр с клавиатуры.
В дополнение к таблице кода Морзе, которая сохраняется в памяти программ как
поисковая таблица, необходимо знать также некоторые другие факты относительно
кода Морзе. Время передачи тире в три раза больше, чем время передачи точки. Про-
межутки между буквами в слове равны трем периодам передачи точки. Промежутки
между словами равны семи периодам передачи точки. При передаче данных со скоро-
стью 50 слов в минуту, период передачи точки будет равен 24 миллисекундам. Эта ско-
рость передачи (50 слов в минуту) называется "Парижским" стандартом, потому что она
Глава 4. Программирование на языке Ассемблера
143
получена посредством передачи слова "PARIS" 50 раз в минуту. Слово "PARIS" дает
точно 50 периодов передачи точки с промежутками между словами
Соответствующая программа должна отрабатывать временную задержку, равную
одному периоду передачи точки (24 мс), а также трем периодам передачи точки
(72 мс). Поскольку мы пока еще не знаем, как активировать реле (ключ), то готовая
функция, называемая КеуОп, используется для активирования реле и функция KeyOff
используется для выключения реле. Функция КеуОп устанавливает бит RB0, а функция
KeyOff сбрасывает бит RB0. Пробел, соответствующий ASCII-коду, в табл. 4.2 не отра-
жен, однако между словами отрабатывается промежуток, равный семи периодам пере-
дачи точки. Пример 4.24 иллюстрирует поисковую таблицу в памяти программ, предна-
значенную для сохранения кода Морзе. Таблица в памяти состоит из двух частей:
Morze L содержит буквы, a Morze_N - цифры.
Таблица 4.2. Код Морзе
Символ Код Байт Символ Байт Байт Символ Код Байт
А • — 0x42 М — 0хС2 Y 0хВ4
В — • • • 0x84 N — • 0x80 Z 0хС4
С 0хА4 О — ОхЕЗ 0 OxFD
D — • • 0x83 Р — 0x64 1 . 0x7D
Е 0x01 Q — • _ 0xD4 2 . . 0x3D
F 0x24 R • — • 0x43 3 ...__ OxlD
G • ОхСЗ S 0x03 4 .... _ OxOD
Н 0x04 т — 0x81 5 0x05
I 0x02 и • • — 0x23 6 _ .... 0x85
J • 0x74 V • • • - 0x14 7 0xC5
К - - ОхАЗ W • — 0x63 8 0xE5
L 0x44 X 0x94 9 0xF5
Пример 4.24
MORSE CODE_PACK
Morse L: ;буквы от A до Z
‘ db 0x42, 0x84, 0xa4, 0x83, 0x01
db 0x24, ОхсЗ, 0x04, 0x02, 0x74
db ОхаЗ, 0x44, 0xc2, 0x80, 0xe3
db 0x64, 0xd4, 0x43, 0x03, 0x81
db 0x23, 0x14, 0x63, 0x94, 0xb4
db 0xc4
Morse_ N: ;числа от 0 до 9
’ db Oxfd, 0x7d, 0x3d, Oxld, OxOd
db 0x05, 0x85, 0xc5, 0xe5, Oxf 5
Процедура, которая берет один ASCII-символ из регистра WREG и посылает код
Морзе, показана в примере 4.25. Хотя ввод-вывод будет рассматриваться позже, дан-
ная процедура использует порт В, - один из портов ввода-вывода, и его бит 0 для акти-
вирования реле. Если к этому биту подключить осциллограф, то мы увидим код Морзе
144
Применение микроконтроллеров PIC 18
как последовательность нулей и единиц, которые используются для включения и вы-
ключения реле. Реле и его интерфейс будут обсуждаться в последующих главах. При-
веденная программа написана в расчете на тактовую частоту, равную 4 МГц; если ис-
пользуется иная тактовая частота, то то счетчики временных задержек должны быть
подстроены так, как это объяснялось в предыдущем подразделе данной главы.
Пример 4.25
Функция SendChar
; использует 3 уровня программного стека
; использует Lookup, KeyOn, KeyOff, Delay24, Delay72 и Delay
; использует WREG, PRODL, PRODH, TABLAT, TBLPTR
; посылает символ из WREG на телеграфный ключ (реле)
SendChar:
MOVWF MOVLW SUBWE' BN MOVLW SUBWE PRODL 0x61 PRODL, 0 SendCharl 0x20 PRODL ;сохраняет WREG ;если буквы заглавные ;преобразование в заглавные
SendChar1:
MOVLW 0x20
SUBWF PRODL, 0
BNZ SendChar2 ;если не пробел
CALL Delay72 ;плюс 4 точки
CALL Delay24
RETURN
SendChar2:
MOVLW 0x30
SUBWF PRODL, 0
BC SendChar3 ;если "0" или больше
RETURN
SendChar3:
MOVLW 0x3a
SUBWF PRODL, 0
BC SendChar4 ;если не "О" - "9"
CALL LookUp
BRA SendCharSend
SendChar4:
MOVLW 0x41
SUBWF PRODL, 0
BC SendChar5
RETURN ;если менее, чем "А"
SendChar5:
MOVLW 0x5b
SUBWF PRODL, 0
BNC SendChar6
RETURN ;если больше, чем "Z"
SendChar6:
CALL LookUpl
Глава 4. Программирование на языке Ассемблера
145
SendCha rSend: MOVWF MOVWF MOVLW ANDWF PRODL PRODH 7 PRODL ;код в PRODH ;счетчик в PRODL
SendCharSendl:
CALL KeyOn ;реле вкл
RLCF PRODH ;получение точки или тире
BNC SendCharSend2 ;если точка
CALL Delay72 ;задержка на три периода передачи точки
BRA SendCharSend3
SendCharSend2:
CALL Delay24 ;задержка на один период передачи точки
SendCharSend3:
CALL KeyOff ;реле выкл
CALL Delay24 ; задержка на один период передачи точки
DECF PRODL
BNZ SendCharSendl ;если не конец
CALL Delay24 ; задержка на два периода передачи точки
CALL Delay24
RETURN
; находит код в поисковой таблице кода Морзе
; код возвращается во WREG
Lookup:
MOVLW 0x30
SUBWF PRODL /преобразование из ASCII
MOVLW UPPER(Morse_N)
MOVWF TBLPTRU
MOVLW HIGH(Morse_N)
MOVWF TBLPTRH
MOVLW LOW(Morse_N)
MOVWF TBLPTRL
BRA LookUp2
IjOokUpl:
MOVLW 0x41
SUBWF PRODL
MOVLW UPPER(Morse_L)
MOVWF TBLPTRU
MOVLW HIGH(Morse_L)
MOVWF TBLPTRH
MOVLW LOW(Mo r s e_L)
MOVWF TBLPTRL
LookUp2:
MOVF PRODL,0
ADDWF TBLPTRL
MOVLW 0
ADDWFC TBLPTRH
ADDWFC TBLPTRU
146
Применение микроконтроллеров PIC 18
TBLRD*
MOVF TABLAT,0
RETURN
;код из поисковой таблицы
; Задержка на период передачи точки (дита)
Delay24:
MOVLW .48 ;48 раз
MOVWF TABLAT
Delay24a:
CALL Delay
DECFSZ TABLAT
BRA Delay24a
RETURN
; Задержка на
3 периода передачи точки (дита)
Delay72:
CALL Delay24
CALL Delay24
CALL Delay24
RETURN
; Временная задержка на 500 мкс;
Delay: ; 165 раз
MOVLW .165 ;500 мкс
Delayl:
DECFSZ WREG
BRA Delayl
RETURN
r
; Установка бита 0 порта В
KeyOn:
BSF PORTB, 0 ; установка бита 0 порта В
RETURN
/
; Сброс бита 0 порта В
KeyOff:
BCF PORTB, 0 ; сброс бита 0 порта В
RETURN
Процедура SendChar достаточно проста. Большая ее часть выполняет фильтра-
цию символов ASCII с тем, чтобы обрабатывались только числа, буквы и пробелы; лю-
бые иные символы ASCII игнорируются. Как только распознан допустимый
ASCII-символ, структура кода Морзе и значения счетчика ищутся в двух таблицах в па-
мяти программ с использованием команды TBLRD*. Обратите внимание, как адрес за-
гружается в регистр TBLPTR в функции LookUp. Директивы ассемблера UPPER, HIGH и
LOW используются для доступа к различным частям адреса при сохранении его в
TBLPTR. И, наконец, структура кода Морзе разделяется на значение счетчика и битовую
структуру для бита 0 порта В. Битовая структура затем сдвигается побитово для опре-
деления того, как долго бит 0 остается в состоянии логической единицы. Точке («диту»)
соответствует 24 мс, а тире («даху») - 72 мс.
Глава 4. Программирование на языке Ассемблера
147
4.6. Резюме
1. Стек данных - это место в памяти данных, в котором информация сохраняется
по принципу «первым вошел, последним вышел». Регистр выбора файла функциониру-
ет как указатель стека, использующий форму адресации POSTDEC для сохранения дан-
ных в стеке и форму PREINC для извлечения данных из стека.
2. Очередь - это буфер данных, который сохраняет информацию по принципу
’первым вошел, первым вышел». Для функционирования очереди необходимо исполь-
зовать два указателя. Первый адресует точку входа, а второй - точку выхода. Ошибоч-
ными состояниями, распознаваемыми программным обеспечением, работающим с
очередями, являются состояние заполненной очереди и состояние пустой очереди.
3. Операции сложения и вычитания двоично-кодированных десятичных чисел
(BCD) используют команду DAW для коррекции результата после BCD-сложения. В слу-
чае BCD-вычитания, используется прибавление дополнения до десяти для формирова-
ния разности и использования команды DAW.
4. Команда DAW корректирует результат BCD-сложения, исследуя состояние бита
переноса и бита половинного переноса регистра состояния, а также значение обеих
разрядов результата. Результат этого исследования определяет, прибавляется для
коррекции результата 0x00, 0x06, 0x60 или 0x66.
5. Двоичное умножение использует алгоритм сдвига и суммирования для форми-
рования произведения. Двоичное произведение также выполняется командами MULLW
и MULWF. Описанный алгоритм позволяет выполнять умножение чисел любого разме-
ра.
6. Двоичное деление использует алгоритм сдвига и вычитания для генерирования
частного и остатка. Частное и остаток при использовании этого алгоритма - это всегда
беззнаковые целые числа.
7. Преобразование двоичного числа в десятичное требует деления на десять. Ал-
горитм, требуемый для такого преобразования, называется правилом Хорна. Этот ал-
горитм также работает в случае преобразования двоичного числа в любую систему
счисления посредством изменения числа, на которое выполняется деление, установив
его равным основанию системы счисления.
8. Преобразование из десятичной в двоичную форму выполняется посредством
умножения на десять. Это преобразование также обеспечивает перевод из любой сис-
темы счисления в двоичную посредством изменения коэффициента с установкой его
равным основанию системы счисления.
9. Временная задержка часто формируется программно. Это выполняется вслед-
ствие того, что известно количество времени, необходимое для выполнения команды.
Таким образом точные временные задержки формируются за счет использования про-
граммных циклов.
4.7. Вопросы и задания
1. Что такое стек данных?
2. Что такое программный стек?
3. Сравните стек данных с программным стеком.
4. Если регистр FSR1 используется как указатель стека, выберите команды или
команду, которые:
а. Заносят содержимое WREG в стек
Ь. Извлекают данные из стека и заносят их во WREG.
с. Заносят произведение в стек
148
Применение микроконтроллеров PIC 18
5. Какая команда используется для инициализации FSR2 как указателя стека?
6. Если содержимое WREG было занесено в стек, после чего в стек было занесено
содержимое PRODL, какой из названных регистров будет первым выгружен из стека?
7. Что такое очередь?
8. Опишите состояния ошибок, который должны распознаваться программным
обеспечением работы с очередями.
9. Если очередь имеет размер, равный 16 байтов. Сколько байтов данных могут
быть сохранены в этой очереди?
10. Что означает, когда говорят, что очередь - это цикличная память?
11. Когда складываются BCD-числа, какая команда должна использоваться для
коррекции результата?
12. Опишите разницу между упакованными и неупакованными BCD-числами.
13. Определите число, добавляемое командой DAW в случае следующих опера-
ций сложения упакованных BCD-чисел.
а. 03 + 08
Ь. 10 + 28
с. 92 + 99
d. 92 + 90
14. Как выполняется вычитание BCD-чисел?
15. Что такое дополнение до 10 и как оно получается?
16. Почему BCD-числа используются в программах?
17. Умножение может быть выполнено при использовании последовательности
сдвигов и сложений.
18. Команда умножения работает только с 8-разрядными числами. Как она может
быть использована для 16-разрядного умножения?
19. Как долго выполняется команда умножения?
20. Напишите функцию, которая умножает содержимое WREG на содержимое
TABLAT. Эта функция должна возвращать результат во WREG в форме 8-разрядного
сложения, игнорируя старшую часть произведения.
21. Напишите функцию, которая возводит в квадрат число во WREG, возвращая
результат boWREG в форме 8-разрядного числа.
22. Опишите изменения, требуемые в примере 4.8 с тем, чтобы он выполнял ум-
ножение двух 16-разрядных чисел со знаком и генерировал 32-разрядное произведе-
ние со знаком.
23. Деление может быть выполнено при использовании последовательности
сдвигов и вычитаний.
24. Если число нужно поделить на 4, что будет наилучшим методом?
25. Может ли алгоритм деления, рассмотренный в этой главе, быть модифициро-
ван для выполнения 24-разрядного деления? Если да, то какие изменения в нем нужно
выполнить?
26. Можно ли написать программу, которая делит 256-разрядное число на
28-разрядное число?
27. Что такое правило Хорна?
28. Модифицируйте пример 4.15 так, чтобы выполнялось преобразование не в
десятичную, а в восьмиричную форму.
29. Предположим, что пример 4.15 должен преобразовать число в шестнадцати-
ричную форму. Опишите изменения, которые должны быть в нем выполнены с целью
достижения этого и формирования как чисел, так и букв в результирующей последова-
тельности ASCII-кодов.
30. Опишите, как программно преобразовывается десятичное число в двоичное
Глава 4. Программирование на языке Ассемблера
149
31. Можно ли преобразовать число из восьмиричной в двоичную форму? Если да,
то как?
32. Сколько времени займет выполнение функции по примеру 4.15, если тактовая
частота микроконтроллера равна 8 МГц?
33. Что такое командный цикл и сколько импульсов системной тактовой частоты
требуется для одного командного цикла?
34. Сколько времени займет выполнение нижеприведенной функции, если сис-
темная тактовая частота равна 40 МГц? (Учтите время выполнения команд CALL и
RETURN).
Wait:
MOVLW .10
Waitl:
DECFSZ WREG
BRA Waitl
RETURN
35. Напишите функцию, реализующую 100-миллисекундную временную задержку
с именем D100, а также функцию, реализующую 1-миллисекундную временную за-
держку с именем D1, если тактовая частота микроконтроллера равна 20 мГц.
36. Используйте функцию из примера 4.23 для считывания клавиши клавиатуры.
Новая функция должна заносить 0x00 в ячейку памяти 0x010 всякий раз, когда нажима-
ется правая клавиша Shift, и заносить OxFF в ячейку памяти данных 0x010 всякий раз,
когда правая клавиша Shift. Все другие клавиши и комбинации клавиш должны игнори-
роваться.
37. Повторите п.36 для обеих клавиш Shift.
38. Найдите таблицу кодов Морзе в Интернет и выделите из нее символы пунк-
туации. Добавьте коды символов пунктуации к таблице кодов Морзе, сохраняемой в
памяти в примере 2-24, введя третью секцию таблицы с именем Morse_P.
39. Каково назначение директив LOW, HIGH и UPPER в программе, приведенной в
примере 4.25?
150
Применение микроконтроллеров PIC 18
Глава 5. Программирование PIC18 на языке С
Теперь, после того, как Вы ознакомились с Ассемблером PIC, вам необходимо
узнать, как программировать устройства семейства PIC18 с использованием языка С.
Многие среды программирования используют язык С вместо Ассемблера, потому что в
этом случае цикл разработки программ получается намного короче, а программы бо-
лее легки в написании и обслуживании. В данной главе подразумевается использова-
ние компилятора языка С, который может быть бесплатно выгружен с сайта Microchip. В
данной главе не преследуется цель изучения языка С, так как предполагается, что чита-
тели уже знакомы с ним до некоторой степени. Используется компилятор С18, который
представляет собой компилятор с языка С для микроконтроллеров семейства PIC18.
Бесплатная версия этого компилятора - это версия полнофункционального компилято-
ра с ограниченными возможностями, она достаточна для изучения того, как нужно про-
граммировать PIC и создавать приложения. Разница между бесплатной версией и пол-
нофункциональной версией компилятора заключается в том, что в бесплатной версии
оптимизация не выполняется, что означает, что генерируемые коды могут быть немно-
го более длинными, кроме того, в ней также заблокирована обработка расширенных
команд, доступных в семействе PIC18.
Большинство программ и алгоритмов, представленных в этой главе, используют
в качестве платформы язык С. В некоторых примерах программ, присутствуют фраг-
менты, написанные на языке Ассемблера. Как отмечалось во введении в главу 4, самый
лучший подход заключается в изучении как главы 4, так и главы 5. После изучения дан-
ной главы Вы:
1. Сможете использовать компилятор языка С С18 в рамках интегрированной
системы разработки программ PIC для программирования микроконтроллеров семей-
ства PIC18.
2. Узнаете о некоторых функциях, имеющихся в библиотеках, прилагаемых к ком-
пилятору С18.
3. Научитесь использовать и генерировать случайные числа.
4. Сможете сохранять таблицы и другую информацию в памяти программ.
5. Сможете писать программы на С, используя временные задержки и библиоте-
ки временных задержек.
6. Узнаете, как использовать состояния на диаграмме переходов при реализации
программы.
7. Научитесь писать программы с использованием математической библиотеки.
5.1. Компилятор С18 с языка С
Программа, которая предназначена для разработки программ на языке С и кото-
рую Microchip предоставляет в рамках интегрированной среды разработки IDE, назы-
вается компилятором С18. Компилятор С18 может быть бесплатно выгружен с сайта
Microchip (http://www.microship.com). Время использования этой бесплатной версии
ограничено 60 днями. Вместе с тем ее функциональность достаточна для решения лю-
бой программной задачи, хотя генерируемые ею коды и будут несколько более длин-
ными, чем в случае применения полнофункциональной версии. Ограниченная версия
компилятора не включает расширенные команды; однако это не создает никаких про-
блем - просто результирующие программы получаются немного более длинными.
При разработке программ для семейства PIC18, следует придерживаться пред-
почтительного использования в программах беззнаковых символьных переменных,
поскольку микропроцессор имеет 8-битную архитектуру. Если использовать Числа
Глава 5. Программирование PIC 18 на языке С
151
большей разрядности, то это увеличит время выполнения программы, поэтому числа
большей размерности следует использовать как можно реже. Чем большим будет уход
от природы аппаратных средств, тем большими будут программы и тем дольше они
будут выполняться. Так 16-разрядное целочисленное сложение требует больше време-
ни и большего объема памяти программ, чем 8-разрядное целочисленное сложение;
32-разрядное сложение с плавающей точкой требует намного больше времени и объе-
ма памяти программ, чем 8-разрядное сложение. Переменные в программе следует
выбирать с осторожностью; если число беззнаковое, то убедитесь в том, что оно объ-
явлено беззнаковым. PIC - это не ПК, объем его памяти программ чрезвычайно мал, по
сравнению с персональным компьютером. В силу ограниченности памяти следует пи-
сать программы очень тщательно, уделяя особое внимание выбору переменных.
Смешанное программирование, совместно использующее Ассемблер и С, также
допускается и часто используется. Ассемблерные блоки начинаются с директивы asm
и заканчиваются директивой _endasm. Блоки кодов Ассемблера не берутся в фигурные
скобки {}, как это имеет место в программных блоках на языке С. Комментарии, раз-
мещаемые в ассемблерных блоках, должны быть комментариями С-стиля, а не исполь-
зовать символ точки с запятой, как это обычно делается в программах на языке Ас-
семблера. Данные, определенные на языке С, являются доступными для программ,
написанных с использованием внутритекстового ассемблера. Еще одной разницей
между языком Ассемблера и и внутритекстовым ассемблером языка С является то, что
в последнем ничего не предполагается. Так, если производится доступ к памяти дан-
ных в банке доступа, необходимо явным образом использовать ключевое слово
ACCESS и т.д.
Перед тем, как Вы сможете больше узнать о компиляторе С18, необходимо по-
нять его использование в IDE. IDE предназначена, как для разработки программ на язы-
ке Ассемблера, так и для разработки программ на языке С, поэтому, если Вы изучили
главу 4, новый интерфейс вам изучать не придется. Однако имеются несколько разли-
чий между настройкой IDE для разработки программ на языке С и ее настройкой для
разработки программ на языке Ассемблера.
Для использования компилятора С18 в IDE, установите компилятор, следуя под-
сказкам, выдаваемым на экран. Убедитесь в том, что при установке компилятора вы-
браны все необходимые позиции. Шаги, требуемые для настройки IDE на работу с ком-
пилятором С18, подобны шагам, необходимым для ее настройки на работу с Ассемб:‘
лером.
1. В раскрывающемся меню Configure (Конфигурирование) выберите позицию
Select Device (Выбрать устройство), а затем выберите используемый микроконтрол-
лер.
2. В раскрывающемся меню Project (Проект) выберите позицию Project Wizard
(Мастер проектов) и вновь выберите микроконтроллер, используемый в проекте.
3. На шаге 2 работы мастера проектов выберите Microchip С18 Toolsuite (Ком-
плект инструментальных средств Microchip С18), а затем щелкните на кнопке Next (Да-
лее). Если компилятор С18 был установлен правильно, то все пути будут указаны кор-
ректно и изменять их не надо.
4. Введите имя проекта и имя каталога, затем щелкните на кнопке Next (Далее).
5. На шаге 4 вы могли бы захотеть начать работать с файлом Example 1 из каталога
mcc18/example/GettingStarted. В этом случае вам следует добавить к проекту файл Ех-
amplel .с file.
6. Под позицией Project (Проект) главного меню, выберите Build Options (Опции
компоновки), затем выберите “h” в каталоге тсс18 в качестве пути включаемых фай-
лов. После этого щелкните на кнопке Apply (Применить), а затем на кнопке Ок.
152
Применение микроконтроллеров PIC 18
7. Щелкните правой кнопкой мышки на позиции Linker files (Файлы компоновщи-
ка) в списке файлов проекта на экране, затем выберите add file (Добавить файл), после
чего добавьте файл 18fxxxx.lkr. (Обратите внимание на то, что хххх - это серийный но-
мер микроконтроллера, используемого в проекте).
8. Под позицией Debugger (Отладчик) выберите инструментальное средство
“MPUXB SIM.” Это приведет к включению в проект инструментальных средств имита-
ции. Если в вашем распоряжении имеется внутрисхемный эмулятор (ICE), то добавьте
корректный эмулятор к разрабатываемому проекту.
Перечисленные шаги не более трудны, чем настройка проекта при использовании
Ассемблера. Пример 5.1 демонстрирует листинг программы Examplel.c. Этот листинг
программы является намного более коротким, чем листинг шаблонной программы,
предназначенной для использования с Ассемблером, поскольку язык С является на-
много более мощным и менее вербальным, чем язык Ассемблера.
Пример 5.1
/*
* Это пример 1 из каталога "Getting Started with MPLAB C18" (Начало работы с
MPLAB Cl 8)
*/
♦include <pl8cxxx.h> /* для объявлений TRISB и PORTB*/
/* Устанавливает биты конфигурации для использования с демонстрационной платой
ICD2/PICDEM2 PLUS:
* - устанавливает режим генератора HS
* - отключает сторожевой таймер
* - отключает низковольтное программирование
*/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
int counter;
void main (void)
(
counter = 1;
TRISB =0; /* конфигурирует PORTB на вывод */
while (counter <= 15)
{
PORTB = counter; /* отображает значение переменной "counter" на
светодиодах */
counter++;
1
} <instx/instx/emphasis>
Эта программа написана для использования с отладочной платой PICDEM2 plus.
Она имеет стандартный, для языка С формат, используя функцию main, содержащую
программу. Эта программа использует одну переменную, называемую counter. Она
конфигурирует Port В как входной порт, а затем отображает числа от 0 до 15 при помо-
щи светодиодов, подсоединенных к порту В. Если имеется в наличии демонстрацион-
ная плата PICDEM2 Plus, то данная программа может выполняться на ней. Если же эта
Глава 5. Программирование PIC 18 на языке С
153
плата отсутствует, то программа может выполняться на имитаторе. Имитатор отобра-
жает числа по мере их изменения в порте В. Для имитации выполнения этой программы
перейдите к меню View (Вид)и отобразите содержимое специальных функциональных
регистров, указав порт В. Выполняйте программу пошагово и наблюдайте за измене-
ниями состояния порта В по мере пошагового выполнения программы. В данном при-
мере используется PIC18F1220, поэтому для того, чтобы этот микроконтроллер функ-
ционировал корректно, к программе из примера 5.1 была добавлена одна команда,
выполняющая выбор цифровой режим работы всех выводов ввода-вывода. А именно
был добавлен оператор ADCON1 = 0x7F перед оператором counter = 1. Скомпонуйте и
выполните программу, а затем посмотрите на окно имитатора - вы должны увидеть
экран, показанный на рис. 5.1.
Для получения вида экрана, соответствующего показанному, используйте инст-
румент увеличения (квадрат) для увеличения окна и получения такого его внешнего
вида, который показан на упомянутом рисунке. Что не так на этом экране. В общем-то
все в порядке, за исключением того, что возникает ощущение того, что имеется ошиб-
ка, так как значение счетчика, равное 15, отображается в течении более одного перио-
да тактовой частоты. Однако, если посмотреть программу, то можно видеть, что она
отображает значения счетчика от 0000 до 1111, а затем перезапускается, что отнимает
дополнительное время. Для корректирования программного примера, приводимого
Microchip, модифицируем пример 5.1 таким образом, чтобы он выглядел так, как при-
мер 5.2. контролируя выход на логическом анализаторе. Выход теперь будет изменять-
ся от 0000 до 1111 и повторяться без «провалов» в значениях счетчика.
Рис. 5.1. Внешний вид окна
Пример 5.2
/*
* Это модифицированный пример 5.1,
* написанный для PIC18F1220
*/
154
Применение микроконтроллеров PIC 18
#include <pl8cxxx.h> /★ для объявлений TRISB и PORTB */
/* Устанавливает биты конфигурации для использования с
* демонстрационной платой ICD2/PICDEM2 PLUS:
* - устанавливает режим генератора HS
* - отключает сторожевой таймер
★ - отключает низковольтное программирование
V
#pragma config OSC = HS
^pragma config WDT = OFF
#pragma config LVP = OFF
int counter;
void main (void)
(
ADCON1 = 0x7F; // объявляет порты цифровыми
TRISB =0; /* конфигурирует PORTB на выход */
while (1)
{
counter = 0;
while (counter <= 15)
(
PORTB = counter; // счетчик передается на светодиоды
counter++;
)
1
}
Оператор #include включает файл заголовка, который определяет все регитры
ввода-вывода устройств семейства PIC18, выбранные для проекта. Это позволяет мик-
роконтроллеру выполнять операции ввода-вывода. Файл заголовка должен включаться
во все проекты.
Операторы #pragma config программируют биты конфигурации микроконтролле-
ра. Вероятно, что термин pragma произошел от слова pragmatic (прагматичный), что
означает практический способ делать что-либо. Команды pragma освобождают про-
граммиста от необходимости написания длинных последовательностей команд или
шагов при выполнении некоторых задач. Таким образом они отражают практичный или
прагматичный способ выполнения задачи. Директива #pragma используется для того,
чтобы дать команду компилятору. Биты конфигурации управляют первичной настрой-
кой микроконтроллера PIC18. Эти биты разъясняются в деталях в главе 6 при рассмот-
рении аппаратных средств микроконтроллера. Каждая версия микроконтроллера PIC18
имеет другие биты конфигурации, которые перечислены в документе “MPLAB С18 Con-
fig Settings” (Настройка конфигурации MPLAB С18), который доступен для выгрузки на
сайте Microchip.
Пример программы
Предположим, что нам нужна программа, которая считывает состояние переклю-
чателя через порт А и инкрементирует число, отображаемое через порт В один раз в
секунду только тогда, когда кнопка нажат. Эта программа похожа на программу из при-
мера 5.1, однако для отработки задержки используется функция временной задержки
из стандартной библиотеки С. Библиотека С обеспечивает временные задержки, ука-
занные в таблице 5.1. Эти функции являются важными, так как почти любая программа,
Глава 5. Программирование PIC 18 на языке С
155
используемая для управления периферийными устройствами, нуждается в отработке
временных задержек. Эти функции делают точное генерирование временных задержек
намного более простой задачей, чем в случае использования способов, обсуждавших-
ся в главе 4. Каждая из упомянутых функций формирует временную задержку, выра-
женную в количестве командных циклов, начиная от 1 командного цикла и вплоть почти
до любого командных циклов. Для использования этих функций в начале программы
используется оператор #include <delays.h> для включения функций временных задер-
жек. Описание стандартной библиотеки доступно на сайте Microchip в документе
“MPUXB С18 Libraries” (Библиотеки MPLAB С18). Как и в случае временных задержек,
которые рассматривались в главе 4, функции delays.h будут точно отрабатываться
только тогда, когда система не будет прерывать их выполнение.
Пример 5.3 демонстрирует программу, которая инкрементирует индикацию све-
тодиодов, подключенных к порту В, когда кнопка удерживается в нажатом состоянии по
крайней мере одну секунду. Если она будет удерживаться в нажатом состоянии немно-
гим дольше 2-х секунд, индикация на светодиодах инкрементируется дважды и т.д.
Опять-таки эта программа предполагает использование PIC18F1220. Этот микрокон-
троллер выбран по причине его низкой стоимости (менее $3) и малых размеров мик-
росхемы. В данном примере RA4 подключен к кнопке. Сигнал с кнопки находится в со-
стоянии логической единицы, когда кнопка не нажата, и в состоянии логического нуля,
когда кнопка нажата.
Пример 5.3
/*
* Это пример 5.3 для тактовой частоты 4 мГц,
* написанный для PIC18F1220
*/
♦include <pl8cxxx.h> //включение спецификаций портов
♦include <delays.h> //включение временных задержек
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
// ****************** ПЕРЕМЕННЫЕ В ПАМЯТИ ДАННЫХ********************
int counter;
/ / ********************* КОНСТАНТЫ *****************************
♦ define MSEC DelaylKTCYx (1) // MSEC = 1 миллисекунда
I/ ***************** ГЛАВНАЯ ПРОГРАММА ******************************
void main (void)
{
ADCON1 = ; 0x7F; // конфигурирование портов А и В как цифровых
// И Эти установки могут изменяться в зависимости от версии микроконтроллера
TRISB = 0; И конфигурирование PORTB на вывод данных
TRISA = OxFF; И конфигурирование PORTA на ввод данных
PORTB = 0; И светодиоды выкл.
156
Применение микроконтроллеров PIC 18
while (1) // бесконечный цикл программы
{
counter =0; // инициализация счетчика
while ((PORTA & 16) == 0) // пока кнопка нажата
{
MSEC; // ожидание 1 мс
counter++;
if (counter == 1000) // 1 секунда
{
PORTB++;
counter = 0;
1
Таблица 5.1. Функции отработки временных задержек из delays.h
Функция Пример Примечание
DelaylTCY DelaylTCY () ; Вставляет в программу одну команду NOP
DelaylOTCYx DelaylOTCYx(10); Вставляет 100 командных циклов (числа должны быть в диапазоне между 0 и 255) (0 вызывает задержку в 2560)
DelaylOOTCYx DelaylOOTCYx (10); Вставляет 1000 командных циклов (числа должны быть в диапазоне между 0 и 255) (0 вызывает задержку в 25600)
DelaylKTCYx DelaylKTCYx(3); Вставляет 3000 командных циклов (числа должны быть в диапазоне между 0 и 255) (0 вызывает задержку в 256000)
DelaylOKTCYx DelaylOKTCYx(20); Вставляет 20000 командных циклов (чис- ла должны быть в диапазоне между 0 и 255) (0 вызывает задержку в 2560000)
В этой программе одна переменная используется для подсчета приращений в 1
миллисекунду. Пример 5.3 предполагает, что тактовая частота микроконтроллера рав-
на 4 МГц (1/4 МГц = 250 нс), что означает, что командный цикл равен 1 мкс, поскольку 4
тактовых импульса требуется для одного командного цикла. Функция Delayl KTCYx(1)
вызывает задержку в 1000 командных цикла, либо в 1 мс. Эта временная задержка оп-
ределяется как MSEC с тем, чтобы повысить читабельность программы. Операторы
define должны использоваться показанным способом с тем, чтобы сделать программу
более ясной и менее зашифрованной. Состояние кнопки проверяется оператором
while. С этой кнопкой соединена битовая позиция 4 порта А, поэтому 16 (0x10) логиче-
ски умножается (AND) с портом А для определения состояния кнопки. Если кнопка не
нажата, то битовая позиция 4 находится в состоянии логической единицы, что после
логического умножения с 16 дает 16. Если же кнопка нажата, то результатом логическо-
го умножения порта А с 16 будет ноль. До тех пор, пока кнопка будет нажата, условие
оператора while будет истинным, что приведет к выполнению команд тела оператора
while. В данном случае по истечении одной секунды содержимое порта В инкремеши-
руется и выполняется сброс счетчика в ноль. Это перезапускает односекундный обрат-
ный отсчет.
Особый интерес в этой программе представляет способ проверки состояния би-
та порта А, соединенного с кнопкой. Как показано в рассматриваемом примере, опера-
ция AND используется для изоляции бита порта А. Число, используемое в операции
Глава 5. Программирование PIC 18 на языке С
157
AND, выделяет бит: так, 1 выбирает бит номер 0, 2 выбирает бит номер один, 4 выбира-
ет бит номер два, 8 выбирает бит номер три и так далее (см. рис. 5.2). Несколько мень-
ший интерес представляет счетчик, используемый для формирования односекундной
временной задержки шагами, равными одной миллисекунде.
Почему эта программа содержит бесконечный цикл в форме оператора while( 1)?
Среда, предоставляемая компилятором языка С, повторно выполняет main(). Проблема
здесь заключается в том, что оператор main(), который инициализирует программу,
должен выполняться только один раз. После инициализации программы оператор
while( 1) будет в режиме повторения выполнять команды цикла, то-есть будет сформи-
рован бесконечный цикл while. В случае встроенных систем или иных систем подобного
типа главная программа или сама операционная система работают в режиме беско-
нечного цикла. Рис. 5.3 иллюстрирует структуру всех операционных систем, - как
встроенных, так и иных. При этом термин холодный старт означает аппаратный сброс.
Программа из примера 5.2 непосредственно следует показанной модели. В компиля-
торе PIC С18 холодный старт предварительно выполняется функцией main().
Позиции битов
Рис. 5.2. Выделение разрядов числа
158
Применение микроконтроллеров PIC 18
Рис. 5.3. Структура операционной системы
Другим способом контроля состояния бита является использование директивы
PORTAbits языка С. Так, оператор PORTAbits.RA4 используется для проверки состояния
битовой позиции 4 порта А. Файл компоновщика для данного микроконтроллера опре-
деляет все выводы порта А, а команда PORTAbits.RA4 проверяет состояние битовой
позиции RA4 порта А. Пример 5.4 переработанный пример 5.3, при этом в новой версии
этой программы используется команда проверки состояния бита. Этот метод проверки
состояния бита не является необходимым, однако он является удобным способом тес-
тирования бита. Код на Ассемблере, сгенерированный для обоих методов проверки
состояния бита является идентичным, и нет никаких преимуществ в использовании
одного метода, в сравнении с другим. Если состояние бита регистра TRIS должно быть
изменено, то может быть использована вида TRISBbits.TRISB3 = 1, которая в данном
примере используется для установки бита 3 регистра TRISB в состояние 1. Иногда это
необходимо, когда требуется изменить состояние только одного бита в регистре TRIS.
Пример 5.4
/*
* Это пример 5
* написанный
4 для тактовой
для PIC18F1220
частоты 4 МГц,
*/
♦include <pl8cxxx.h> //включение спецификаций портов
♦include <delays.h> //включение временных задержек
/* Установка битов конфигурации
* -• установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
Глава 5. Программирование PIC 18 на языке С
159
♦cragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
_r.c counter;
♦zefine mSec DelaylKTCYx (1) // msec = 1 миллисекунда
md main (void)
ADCON1 = 0x7F; // конфигурирование портов А и В как цифровых
// Эти установки могут изменяться в зависимости
// от версии микроконтроллера
TRISB =0; // конфигурирование PORTB на вывод данных
TRISA = OxFF; // конфигурирование PORTA на ввод данных
PORTB =0; // светодиоды выкл.
•nile (1) // бесконечный цикл программы
{
counter = 0; // инициализация счетчика
while (PORTAbits.RA4 == 0) // пока кнопка нажата
{ mSec; // ожидание 1 мс
counter++; if (counter == 1000) // 1 секунда
{
PORTB++;
counter = 0;
1
}
5.2. Использование включаемых файлов языка С
В данном подразделе приведены дальнейшие примеры программ на языке С, ко- ’’
торые используют некоторые другие включаемые файлы, входящие в состав библиоте-
ки С18. В подразделе 5.1 был представлен включаемый файл delays.h, который содер-
жит функции отработки временных задержек, поскольку временные задержки исполь-
зуются в большинстве программ, написанных для микроконтроллеров. В данном под-
разделе мы рассмотрим некоторые другие полезные включаемые файлы, используе-
мые для программирования микроконтроллеров.
Преобразования
Как уже отмечалось в главе 4 при рассмотрении использования языка Ассембле-
ра, данные редко бывают изначально в нужной форме. Включаемые файлы преобразо-
ваний (в stdlib.h) используются для выполнения преобразований из одной численной
формы в другую. В табл. 5.2 перечислены многие из обычно используемых функций
преобразования, имеющихся в библиотеке, поставляемой совместно с компилятором
160
Применение микроконтроллеров PIC 18
С18 и объявляемой в файле заголовка стандартной библиотеки stdlib.h. Для использо-
вания функций stdlib в программе должен присутствовать оператор #includc <stdlib.h>.
Таблица 5.2. Часто используемые функции преобразований stdlib.h.
Функция Пример Примечание
atob atob( buffer ) Преобразует число из строковой формы в буфере. Возвращает байтовое число со знаком (от +127 до -128)
atof atof ( buffer ) Преобразует число из строковой формы в буфере. Возвращает число с плавающей точкой
atoi atoi( buffer ) Преобразует число из строковой формы в буфере. Возвращает 16-разрядное целое число со знаком (от + 32,767 до -32, 768)
atol atol ( buffer ) Преобразует число из строковой формы в буфере. Возвращает 32-разрядное целое число со знаком (от + 2 147 483 647 до -2417 483 648)
btoa btoa( num, buffer ) Преобразует байт со знаком в строку символов, сохраняемую в буфере
itoa itoa( num, buffer ) Преобразует 16-разрядное целое число со знаком в строку символов, сохраняемую в буфере
itol itol( num, buffer ) Преобразует 32-разрядное целое число со знаком в строку символов, сохраняемую в буфере
rand rand() Returns a 16-bit random number ( 0 to 32, 767)
srand srand( seed ) Устанавливает значение начального числа на 16- разрядное целое
tolower tolower( letter ) Переключает буквы в форме байтовых символов с верхнего регистра на нижний, возвращает буквы нижнего регистра.
toupper toupper( letter ) Переключает буквы в форме байтовых символов с нижнего регистра на верхний, возвращает буквы верхнего регистра.
ultoa ultoa(num, buffer ) То же, что и itol, , за исключением того, что num является числом без знака
Предположим, что нам нужно отображать случайные числа на светодиодах порта
В через каждую половину секунды. Программа, которая выполняет это, используя
функцию rand(), показана в примере 5.5. В данном случае при генерации случайных
чисел используется начальное число, равное 1.
Пример 5.5
Это пример 5.5 для тактовой частоты в 4 мГц
#include <pl8cxxx.h>
#include <delays.h>
#include <stdlib.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
Глава 5. Программирование PIC 18 на языке С
161
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
void main (void)
ADCON1 = 0x7F; // конфигурирование портов А и В как цифровых
// Эти установки могут изменяться в зависимости
// от версии микроконтроллера
TRISB =0; // конфигурирует PORTB на вывод данных
PORTB =0; // светодиоды выкл.
srand(l); // начальное число генератора случайных чисел
while (1) // повторять бесконечно
{
DelaylOKTCYx(50); // ожидание 1/2 секунды
PORTB = rand(); // отображение случайного числа
}
Пример 5,6 показывает другой метод отображения случайных чисел, однако при
этом случайные числа генерируются всегда, когда нажата кнопка. Показанная про-
грамма фактически инкрементирует счетчик на максимальной скорости и генерирует
случайные числа в диапазоне между 0 и 9. Одно из применений этой программы может
заключаться в выборе чисел для лотереи. В данном примере предполагается, что к биту
4 порта А подсоединен кнопочный переключатель. Эта программе не использует какие-
либо включаемые файлы, за исключением включаемого файла микроконтроллера
p18cxxxx.h. Длина программы, генерируемой по исходному тексту, приведенному в
этом примере, является намного, приблизительно наполовину, короче, чем в предыду-
щем примере. Чем меньше включаемых файлов и функций используется в программе,
тем лучше. Если имеется какой-либо способ избежать использования библиотечного
файла, то следует им воспользоваться.
Пример 5.6
/*
* Это пример 5.6
*/
♦include <pl8cxxx.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
«/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
int seed;
void main (void)
{
ADCON1 = 0x7 F; // конфигурирование портов А и В как цифровых
// Эти установки могут изменяться в зависимости
// от версии микроконтроллера
162
Применение микроконтроллеров PIC 18
TRISB =0; // конфигурирование PORTB на вывод данных
TRISA - OxFF; // конфигурирование PORTA на ввод данных
PORTB =0; // светодиоды выкл.
while (1) // бесконечный цикл программы
{'
while ( PORTAbits.RA4 == 0 ) 11 пока кнопка нажата
1
seed++;
if (seed == 10) // если начальное число равно 10
seed = 1;
PORTB = seed;
}
}
Память и строковые функции
Приводимая далее программа использует числа в форме строки символов для
иллюстрации использования другой функции из стандартной библиотеки. Эта про-
грамма не использует какой-либо ввод-вывод - это просто пример, иллюстрирующий
строковые функции. Строка символов с именем string 1 содержит сообщение “The time
is 22 hours” (Сейчас 22 часа). Программа извлекает число 22 после его нахождения в
строке и сохраняет его в ячейке памяти hour. В примере 5.7 строка символов просмат-
ривается на предмет нахождения первого вхождения цифры числа. После этого число,
заключенное в символьной строке, извлекается из нее с использованием функции atob,
которая преобразует число, заданное в форме строки символов, в данные, размером в
байт или символ.
Пример 5.7
/*
* Это пример 5.7
*/
#include <pl8cxxx.h>
#include <string.h>
♦include <stdlib.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
char bufferf] = "The time is 22 hours.";
char hour;
int a;
Глава 5. Программирование PIC 18 на языке С
163
void main (void)
for (a = 0; a < strlen(buffer); a++)
if (buffer[a] >= 'O' && buffer[a] <= '9')
break;
hour = atob (buffer + a);
Этот пример использует функцию strlen для определения длины строки, а также
цикл for с операторами if и break для организации сканирования символьной строки с
целью поиска символа цифры. Когда отрабатывается оператор break (Завершение),
переменная а содержит относительную позицию численного символа в массиве. Функ-
ция atob затем преобразует число из строковой формы в форму целого числа и сохра-
няет его в переменной hour. Строковые функции совместно с примерами их использо-
вания перечислены в табл. 5.3. Строковые функции расположены в файле string.h, ко-
торый должен быть включен в программу, если в ней используются строковые функции.
Имеется много строковых функций, которые обеспечивают решение для многих при-
ложений, предназначенных для работы со строками. Некоторые из них включены в
стандарт языка С (ANSI), а некоторые являются уникальными для микроконтроллеров
PIC. Необходимость наличия специальных функций для микроконтроллеров PIC выте-
кает из наличия в них памяти программ, что обычно не характерно для большинства
компьютерных систем.
Для иллюстрации строковых команд, предположим, что количество символьных
строк сохраняется в памяти программ. Память программ является постоянной, поэтому
она используется для хранения статичных программных данных. Для сохранения дан-
ных в памяти программ, в программе используются директивы гот и near или far. Ди-
ректива гот информирует компилятор о том, что он должен размещать данные в памя-
ти программ, а директивы near или far определяют длину адреса. Адрес модели памяти
near является 16-разрядным адресом, в то время, как адрес модели памяти far - это 21 -
разрядный адрес. Если микроконтроллер имеет менее, чем 64К памяти программ, ис-
пользуйте модель памяти near; если же он имеет более, чем 64К памяти программ, ис-
пользуйте модель памяти far.
Пример 5.8 демонстрирует, как следует сохранять несколько символьных строк в
массиве, расположенном в памяти программ. Данная программа также резервирует 20
байтов в памяти данных с тем, чтобы строка символов из памяти программ могла копи-
роваться в память данных для манипуляций ею в программе. В данном случае исполь-
зуется функция strcpypgm2ram (копирование строки из памяти программ в ОЗУ) для
копирования второй строки (элемент 1) в буферное пространство ОЗУ. Если просмот-
реть содержимое памяти программ и памяти данных в IDE после выполнения этой ко-
роткой программы, то буферная область будет содержать вторую символьную строку.
Таблица 5.3. Строковые функции, присутствующие в string.h
Функция Пример Примечание
memchr memchr (area51, ‘a’, 23) Просматривает первые 23 байта агеа51 на вхожде- ние ‘а’
memchrpgm memchrpgm (areal, 65, 5) Просматривает первые 5 байтов areal на вхождение 65 (если обнаружен, возвращается указатель на этот символ, если нет, то возвращается ноль)
memcmp memcmp (areal, area2, 4) Сравнивает areal с агеа2 для 4 байтов
memcmppgm memcmppgm (агеаЗ, area4, 2) Сравнивает агеаЗ в памяти программ с агеа4 в памя- ти программ для 2 байтов
164
Применение микроконтроллеров PIC18
Функция Пример Примечание
memcmppgmlram memcmppgm2ram (al, a2, 5) Сравнивает al с a2 в памяти программ на 5 байтах
niemcmpram2pgm memcmpram2pgm (a3, a4, 6 ) Сравнивает аЗ в памяти про!рамм с а4 на 6 байтах
memcpy memcpy (al, a2,4) (возврат <0, если первое меньше второго, возврат =0, если строки равны, возврат>0, если первая строка больше второй) Копирует а2 в al для 4 байт
memcpypgm memcpypgm (a3, a4, 5) Копирует память программ а4 в память программ
memcpypgm2ram memcpypgm2ram (a5, a6, 7) аЗ для 5 байтов Копирует память программ аб в память программ
memcpyram2pgm memcpyram2pgm (a7, a8, 2) а5 для 7 байтов Копирует а8 в память программ а7 для 2 байтов
memmove memmove (al, a2,3) То же, что и memcpy, за исключением того, что
memmovepgm memmovepgm (a3, a4, 3) разрешены перекрывающиеся области
mem- memmovepgm2ram (d, e, 3)
movepgm2ram mem- memmoveram2pgm (f, g, 45)
moveram2pgm strcat strcat (strl, str2) Добавляет strl к str2
strcatpgm strcatpgm (str3, str4) Добавляет str3 в памяти программ к str4
strcatpgm2ram strcatpgmram (str5, str6) Добавляет str5 к строке str6 в памяти программ
strcatram2pgm strcatpgmram (str3, str4) То же, что и strcatpgm
strchr strchr (strl, ‘a’) Находит первое вхождение буквы а в strl
strchrpgm strchrpgm (str2, ‘0’) Находит первое вхождение нуля в str2
strcmp strcmp (strl, str2) Сравнивает strl со str2
strcmppgm strcmppgm (str3, str4) Сравнивает str3 в памяти программ со str4 в памяти
strcmppgm2ram strcmppgmram (str5, str6) программ Сравнивает str5 с str6 в памяти программ
strcmpram2pgm strcmprampgm (str3, str4) Сравнивает str3 в памяти программ со str4 (возврат
strcpy strcpy (strl, str2) >0, если первая строка меньше второй, возврат =0, если строки равны, возврат<0, если первая строка больше второй) Копирует str2 в strl
strcpypgm strcpypgm (str3, str4) Копирует str4 в памяти программ в str3
strpypgm2ram strcpypgm2ram (str5, str6) Копирует str6 в позицию памяти программ str5
strcpyram2pgm strcpyram2pgm (str3, str4) То же, что и strcpypgm
strcspn strcspn (strl, str2) Просматривает strl на вхождение str2; возвращает-
strcspnpgm strcspnpgm (str3, str4) ся количество совпадений Просматривает str3 в памяти программ на вхожде-
strcspnpgmram strcspnpgmram (str5, str6) ние str4 из памяти программ Просматривает str5 в памяти программ на вхожде-
strcspnrampgm strcspnrampgm (str3, str4) ние str6 Просматривает str3 на вхождение str4 из памяти
strlen strlen (strl) программ Возвращает длину strl
strlenpgm strlenpgm (str2) Возвращает длину str2 в памяти программ
strlwr strlwr (strl) Преобразует символы верхнего регистра strl в
strlwrpgm strlwrpgm (str2) символы нижнего регистра Преобразует символы верхнего регистра str2 в
strncat strncat (strl, str2, 3) памяти программ в символы нижнего регистра Добавляет strl к str2 для 3 символов
strncatpgm strncatpgm (str3, str4, 2) Добавляет str3 в памяти программ к str4 для 2 сим-
strncatpgm2ram stmcatpgm2ram (str5, str6, 1) волов Добавляет str5 к строке str6 в памяти программ для
strncatramlpgm stmcatram2pgm (str3, str4, 2) 1 символа То же, что и strcatpgm
Глава 5. Программирование PIC18 на языке С
165
Функция________________Пример____________________________Примечание
йгпстр stmcmp (strl, str2, 2) Сравнивает strl co str2 для 2 символов
strncmppgm strncmppgm (str3, str4,4) Сравнивает str3 в памяти программ со str4 в памя- ти программ для 4 символов
stmcmppgm2ram stmcmppgmram (str5, str6, 3) Сравнивает str5 в памяти программ со str6 для 3 символов
strncmpram2pgm stmcmprampgm (str3, str4, 1) Сравновает str3 в памяти программ со str4 для 1 символа (возврат >0, если первая строка меньше второй, возврат —0, если сзроки равны, возврат<0, если первая строка больше второй)
strncpy stmcpy (strl, str2) Копирует str2 в strl
strncpypgm strncpypgm (str3, str4) Копирует str4 в памяти программ в str3
strnpypgm2ram stmcpypgm2ram (str5, str6) Копирует str6 в область памяти программ str5
strncpyram2pgm stmcpyram2pgm (str3, str4) То же, что и strcpypgm
strpbrk strpbrk (strl, str2) Просматривает strl на вхождение символов из str2
strpbrkpgm strpbrkpgm (str3, str4) Просматривает strl в памяти программ на вхожде- ние символов из str2 в памяти программ
strpbrkpgmram strpbrkpgmram (str5, str6) БПросматривает str5 в памяти программ на вхож- дение символов из str6
strpbrkrampgm strpbrkrampgm (str3, str4) Просматривает str3 на вхождение символов из str4 в памяти программ.
Strrchr strrchr (str, ‘0’) Возвращает указатель на последнее вхождение 0
strspn strspn (strl, str2) Возвращает количество последовательных вхожде- ний в strl символов из str2
strspnpgm strspnpgm (str3, str4) Возвращает количество последовательных вхожде- ний в str3 в памяти программ символов из str4 в памяти программ
strspnpgmram strspnpgmram (str5, str6) Возвращает количество последовательных вхожде- ний символов из str6 в str5 памяти программ
strspnrampgm strspnrampgm (str7, str8) Возвращает количество последовательных вхожде- ний символов из str8 памяти программ в str7
strstr strstr (strl, str2) Определяет первое вхождение str2 в strl
strstrpgm strstrpgm (str3, str4) Определяет первое вхождение в str3 памяти про- грамм str4 из памяти программ
strstrpgmram strstrpgmram (str5, str6) Определяет первое вхождение в str5 памяти про- грамм str6
strstrrampgm strstrrampgm (str7, str8) Определяет первое вхождение в str7 памяти про- грамм str8 (если вхождение найдено, возвращается указатель на него, в противном случае возвращает- ся ноль)
strtok strtok (strl, str2) Вставляет ноль в strl на место знаков, специфици- рованных str2
strtokpgm strtokpgm (str3, str4) Вставляет ноль в str3 из памяти программ на место знаков, специфицированных в str4
strtokpgmram strtokpgmram (str5, str6) Вставляет ноль в str5 из памяти программ на место знаков, специфицированных в str6
strtokrampgm strtokrampgm (str3, str4) То же, что и strtokpgm (возвращает нулевой указа- тель, если ничего не найдено)
strupr strupr (strl) Преобразует символы нижнего регистра из strl в символы верхнего регистра
struprpgm strupr (str2) Преобразует символы нижнего регистра из strl в
символы верхнего регистра для str2 из памяти про-
грамм
\66
Применение микроконтроллеров PIC18
Пример 5.8
/*
* Это пример 5.8
*/
♦include <pl8cxxx.h>
♦include <string.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
I/ program memory data
rom near char lookUpTable[][20] =
"ту first message"
"ту second message'
"ту third message"
"ту fourth message
"ту fifth message"
11 данные в памяти данных
char buffer[20];
I/ главная программа
void main (void)
{
strcpypgm2ram (buffer, lookUpTable[1]);
}
Пример 5.9 демонстрирует еще один пример осуществления доступа к памяти
программ. В этот раз доступ к памяти программ осуществляется с целью поиска
7-сегментного кода в поисковой таблице, предназначенного для вывод на
7-сегментный светодиодный индикатор. Для доступа к поисковой таблице использует-
ся соответствующая функция. Функция с именем Get7Seg преобразует BCD (ДКД) -
число в 7-сегментный код только тогда, когда это число отображает символ от 0 до 9.
Если функции передается какое-либо иное число, то возвращается значение 0x00.
Пример 5.9
/*
* Это пример 5.9
*/
♦include <pl8cxxx.h>
/* Установка битов конфигурации
Глава 5. Программирование PIC 18 на языке С
167
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
данные в памяти программ
rom near char lookUp7Seg[] = // поисковая таблица 7-сегментных кодов
0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7d, 7, 0x7f, 0x6f
/ память данных
char datal;
' function Get7Seg
char Get7Seg (char bed)
if (bed <= 9)
return lookUp7Seg[bed];
else
return 0;
' main program
/□id main (void)
datal = Get7Seg(3);
Программа по примеру 5.10 иллюстрирует использование функций управления
памятью из библиотеки строковых функций. Так, функция memset используется для
записи числа 0x20 во все ячейки буфера в памяти данных.
Пример 5.10
* Это пример 5.10
*/
♦include <pl8cxxx.h>
♦include <string.h>
* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
168
Применение микроконтроллеров PIC 18
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
//data memory
char buffer[20];
void main (void)
{
memset(buffer, 0x20, 20);
)
В главе 4, программа на языке Ассемблера (пример 4. 25) использовалась для
осуществления доступа к таблице символов кодов Морзе при помощи функции, кото-
рая называлась SendChar. Просмотрите еще раз этот пример и сравните его с версией
этой программы на языке С, приведенной в примере 5.11. Здесь, как и в главе 4, память
программ используется с целью хранения структур кодов Морзе для упомянутой функ-
ции. Программа тестирования функции SendChar передает буквы от а до z через бит 0
порта В, - точно так же, как в примере 4.25. Приведенная версия этой программы на
языке С намного более читабельна и легче понимается, чем ее версия на языке Ас-
семблера. Единственное, что еще можно добавить в эту программу - так это еще одну
поисковую таблицу для хранения кодов Морзе символов пунктуации. Самая лучшая
проверка работы этой программы, конечно же, связана с использованием осциллогра-
фа для наблюдения выходных сигналов для бита 0 порта В.
Пример 5.11
/*
* Это пример 5.11 для тактовой частоты в 4 МГц
*/
#include <pl8cxxx.h>
#include <delays.h>
/* Установка битов конфигурации 1
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
#pragma config OSC = HS
#pragma config WDT = OFF \
#pragma config LVP = OFF )
11 поисковые таблицы в памяти программ
rom near char Morse_L[] =
{
0x42, 0x84, 0xa4, 0x83, 0x01
0x24, ОхсЗ, 0x04, 0x02, 0x74
ОхаЗ, 0x44, 0xc2, 0x80, 0xe3
0x64, 0xd4, 0x43, 0x03, 0x81
0x23, 0x14, 0x63, 0x94, 0xb4
0xc4
Глава 5. Программирование PIC 18 на языке С
169
rom near char Morse_N[] =
Oxfd, 0x7d, 0x3d, Oxld, OxOd,
0x05, 0x85, 0xc5, 0xe5, 0xf5
I;
I functions
.oid sendDitDah (char pattern) // передача символа в коде Морзе
int a;
int count = pattern & 7;
for J (a = 0 ; a < count & 7; a ++)
t PORTB = 1; // ключ ВКЛ
if ((pattern & 0x80)) // контроль состояния бита
DelaylKTCYx (72); // тире
else
DelaylKTCYx (24); // точка
PORTB =0; // ключ выкл
DelaylKTCYx (24); // ожидание в течении периода передачи
точки
pattern <<= 1; // получение следующего бита
}
DelaylKTCYx (48); // ожидание в течении двух периодов пе-
редачи точки
1
void sendChar-(char sendData)
{
if (sendData >= 'a' && sendData <= 'z')
sendData -= 0x20; // перевод в символы верхнего регистра
if (sendData == ' ') (96); // если пробел // ожидание 96 мс
DelaylKTCYx
else if (sendData >= 'A' && sendData < 'Z')
sendDitDah (Morse_ _L [sendData - 0x41]) ;
else if (sendData >= 'O' && sendData - c= '9')
sendDitDah (Morse N [sendData - 0x30]) ;
1
// главная программа для тестирования функции sendChar
void main (void)
{
int a;
ADCON1 = 0x7F; // конфигурирование портов А и В как цифровых
// Эти установки могут изменяться в зависимости
// от версии микроконтроллера
TRISB = 0x00; // конфигурирование порта В как выходного
for (а = 0; а < 26; а++)
sendChar('а' + а) ; // тестирование sendChar
170
Применение микроконтроллеров PIC18
I Ugjc Analyzer у
Рис. 5.4. Снимок экрана логического анализатора для кода Морзе,
передаваемого программой из примера 5.11
Рис. 5.4 демонстрирует программу из примера 5.11 в действии. В данном случае
логический анализатор используется для демонстрации выходных данных на штырьке
RB0. На этом рисунке показана передача кодов Морзе символов, начиная с буквы В.
Поскольку программа передает символы в алфавитном порядке, после В следует С и
так далее. Список кодов Морзе смотрите в табл. 4. 2. Широкий высокий импульс соот-
ветствует тире, а узкий высокий импульс - точке.
Единственным способом получения этого снимка экрана была замена функции
временной задержки DelaylKTCYx на DelaylOKTCYx, - это было необходимо только для
того, чтобы выходной сигнал отображался на экране анализатора. Фирма Microchip в
версии IDE 7.11 не реализовала способ модификации частоты выборки логического
анализатора. Остается надеяться, что этот недостаток будет устранен в будущих вер-
сиях IDE.
5.3. Примеры программ на языке С
Теперь, после того, как были изложены вводные сведения языка С для семейства
PIC18, в данном подразделе рассматриваются примеры некоторых простых программ,
которые иллюстрируют дополнительные возможности программирования микрокон-
троллеров PIC на языке С. Как уже отмечалось, С для PIC в основном является таким
же, как язык С для любой иной системы, хотя некоторые библиотеки были расширены с
целью включения функций, работающих с пространством памяти PIC.
Пример первый
Этот первый пример программы (пример 5.12) демонстрирует переработанный
пример программы на языке Ассемблера из главы 4, который ориентирован на работу с
клавиатурой ПК-стиля. Этот новый пример возвращает ASCII-кодированные символы
для большинства клавиш клавиатуры. Работа с клавишами Ctrl и Alt не реализована,
Глава 5. Программирование PIC 18 на языке С
171
однако нажатие клавиши Shift отрабатывается. Две таблицы в памяти программ ис-
пользуются для обеспечения возврата ASCII-кодов как для ввода с клавиатуры без на-
жатия клавиши Shift, так и для ввода с нажатием клавиши Shift. Функция getChar реали-
зована с использованием рекурсии для получения дополнительных символов с клавиа-
туры. При реализации отработки нажатия клавиши Ctrl добавляются дополнительные
таблицы для Ctrl = 0 b Ctrl = 1. Коды для нажатой клавиши Ctrl обычно определяются в
диапазоне от 0x00 до 0x1 А для клавиш от А до Z.
Таблица 5.4. Коды специальных функциональных клавиш
Клавиша Код Клавиша Код Клавиша Код
F9 0x80 Левая Alt 0x8В 8 на цифровой 0x96
F5 0x81 Левая Ctrl 0х8С клавиатуре Num Lock 0x97
F3 0x82 Caps Lock 0x8D Fll 0x98
Fl 0x83 1 на цифровой 0х8Е + на цифровой 0x99
F2 0x84 клавиатуре 4 на цифровой 0x8F клавиатуре + на цифровой 0x99
F12 0x85 клавиатуре 7 на цифровой 0x90 клавиатуре 3 на цифровой 0х9А
F10 0x86 клавиатуре 0 на цифровой 0x91 клавиатуре - на цифровой 0x9В
F8 0x87 клавиатуре . на цифровой 0x92 клавиатуре * на цифровой 0х9С
F6 0x88 клавиатуре 2 на цифровой 0x93 клавиатуре 9 на цифровой 0x9D
F4 0x89 клавиатуре 5 на цифровой 0x94 клавиатуре Scroll Lock 0х9Е
Tab 0x8A клавиатуре 6 на цифровой клавиатуре 0x95 F7 0x9F
ASCII-код, возвращаемый функцией getChar, представляет собой стандартный
ASCII-код для всех клавиш, за исключением специальных клавиш, - таких как page up
(страница вверх), page down (страница вниз) и так далее. Специальные клавиши гене-
рируют коды, как это показано в табл. 5.4. Обратите внимание на то, что двухразрядпыё
коды не реализованы в данном примере, однако они могут быть добавлены в результа-
те модификации программы и добавления таблицы.
Пример 5.12
/*
* Это пример 5.12
*/
♦include <pl8cxxx.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
♦pragma config OSC = HS
♦pragma config WDT = OFF
172
Применение микроконтроллеров PIC 18
♦pragma config LVP = OFF
I/ данные в памяти программ
// поисковая таблица для букв верхнего регистра
rom near char upperCaseTable[] =
{
0x00, 0x80, 0x00, 0x81, 0x82, 0x83, 0x84, 0x85
0x00, 0x86, 0x87, 0x88, 0x89, 0х8А, 0х7Е, 0x00
0x00, 0x8В, 0x00, 0x00, 0х8С, 0x51, 0x21, 0x00
0x00, 0x00, 0х5А, 0x53, 0x45, 0x57, 0x40, 0x00
0x00, 0x43, 0x58, 0x44, 0x45, 0x24, 0x23, 0x00
0x00, 0x20, 0x56, 0x46, 0x54, 0x52, 0x25, 0x00
0x00, 0х4Е, 0x42, 0x48, 0x47, 0x59, 0х5Е, 0x00
0x00, 0x00, 0x4D, 0х4А, 0x55, 0x26, 0х2А, 0x00
0x00, ОхЗС, 0x4В, 0x49, 0x4F, 0x29, 0x28, 0x00
0х4Е, 0x3F, 0х4С, ОхЗА, 0x00, 0x50, 0x5F, 0x00
0x00, 0x00, 0x22, 0x00, 0x7В, 0x2В, 0x00, 0x00
0x8D, 0x00, 0x0D, 0x7D, 0x00, 0х7С, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00
0x00, 0х8Е, 0x00, 0x8F, 0x90, 0x00, 0x00, 0x00
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x1В, 0x97
0x98, 0x99, 0х9А, 0x9В, 0х9С, 0x9D, 0х9Е, 0x00
0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1;
// поисковая таблица для букв нижнего регистра
rom near char lowerCaseTable[] =
{
0x00, 0x80, 0x00, 0x81, 0x82, 0x83, 0x84, 0x85
0x00, 0x86, 0x87, 0x88, 0x89, 0х8А, 0x60, 0x00
0x00, 0x8В, 0x00, 0x00, 0х8С, 0x71, 0x31, 0x00
0x00, 0x00, 0х7А, 0x73, 0x61, 0x77, 0x32, 0x00
0x00, 0x63, 0x78, 0x64, 0x65, 0x34, 0x33, 0x00
0x00, 0x20, 0x76, 0x66, 0x74, 0x73, 0x35, 0x00
0x00, ОхбЕ, 0x62, 0x68, 0x67, 0x79, 0x36, 0x00
0x00, 0x00, 0x6D, ОхбА, 0x75, 0x37, 0x38, 0x00
0x00, 0х2С, 0x6В, 0x69, 0x6F, 0x30, 0x39, 0x00
0х2Е, 0x2F, ОхбС, ОхЗВ, 0x00, 0x60, 0x2D, 0x00
0x00, 0x00, 0x27, 0x00, 0x5В, 0x3D, 0x00, 0x00
0x8D, 0x00, 0x0D, 0x5D, 0x00, 0х5С, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00
0x00, 0х8Е, 0x00, 0x8F, 0x90, 0x00, 0x00, 0x00
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x1В, 0x97
0x98, 0x99, 0х9А, 0x9В, 0х9С, 0x9D, 0х9Е, 0x00
0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// данные в памяти данных
int shift = 0;
// функции
Глава 5. Программирование PIC 18 на языке С
173
Ожидание одного полного цикла изменения сигнала на тактовом входе
возврат, когда тактовый импульс переходит в единичное состояние
void Wait4Clock (void)
while (PORTAbits.RAI == 1); // while clock = 1
while (PORTAnits.RAI == 0); // while clock = 0
int readChar (void)
{
int parity = 0;
int keyData = 0;
int a;
Wait4Clock();
if (PORTAbits.RAO == 1)
keyData = 0x100; 11 если ошибка фрейма
else // корректный стартовый бит
{
for (а = 0; а < 8; а++)
(
keyData »= 1; //ассемблирование
<eyData
Wait4Clock ();
keyData |= (PORTAbits.RAO == Im-
parity += PORTAbits.RAO;
}
Wait4Clock(); // получение бита паритета
parity Л= PORTAbits.RAO;
if ((parity & 1) == 0)
keyData = 0x101; // если ошибка паритета
Wait4Clock () ;
if (PORTAbits.RAO == 0)
keyData = 0x100; // если нет ошибки фрейма на стоп-бите,
)
return keyData;
int getChar (void)
int step = 0;
int scanCode = readChar();
while (step == 0 && scanCode < 0x100)
{
switch (scanCode)
{
case 0x12: // сдвиг
case 0x59:
{
shift = 1;
scanCode = readChar();
break;
)
case OxFO: // освобождение
{
scanCode = readChar();
switch (scanCode)
174
Применение микроконтроллеров PIC 18
,
case 0x12: // сдвиг
case 0x59:
{
shift = 0;
break;
}
)
scanCode = readChar();
break;
}
default:
{
step = 1;
break;
}
)
I
if (step - 1 && scanCode < 0x100)
{ •
if (shift)
scanCode - upperCaseTable [scanCode];
else
scanCode = lowerCaseTable [scanCode];
}
return scanCode;
Эта функция считывает клавиатуру и возвращает ASCII-символ, однако она тре-
бует большого расхода времени микроконтроллера. Для того, чтобы снизить этот рас-
ход, лучше всего переделать программу так, чтобы она работала в режиме прерываний.
Эта методика будет обсуждаться в главе 8.
Пример второй
Существует система управления моделями железной дороги, которая называется
ОСС (управление при помощи цифровых команд). Система DCC посылает цифровые
сигналы через рельсы модели, которые управляют электромоторами и другими компо-
нентами модели железной дороги. Одна из функций контроллера в этом случае заклю-
чается в активировании дополнительных устройств модели с использованием про-
граммируемых адресов. Адрес посылается и принимается микроконтроллерной систе-
мой, которая активирует устройство. Схема, используемая для извлечения цепочки
последовательных сигналов, идущих через модель, показана на рис. 5.5. В этой схеме
используется оптическая развязка для изоляции системы от напряжения на рельсах
модели, а также генерации ТТЛ-совместимого сигнала для микроконтроллера. Поляр-
ность подключения к рельсам не имеет значения, поскольку сигнал на рельсах - это
сигнал переменного тока, а информация передается через ширину импульсов, переда-
ваемых по рельсам.
Глава 5. Программирование PIC 18 на языке С
175
Рис. 5.5. Детектирование сигнала DCC
Передаваемый через рельсы сигнал относится к сигналам переменного тока. Его
амплитуда изменяется в пределах ±14 В. Этот сигнал несет цифровую информацию
(см. рис. 5.6). Бит данных, состояние которого соответствует логической единице, пе-
редается сигналом, длительность которого лежит в пределах 54...64 мкс. Бит данных,
состояние которого соответствует логическому нулю, соответствует импульсам дли-
тельностью 90... 10000 мкс. Информационный пакет, передаваемый на устройства, со-
держит 3 байта. При этом заголовок пакета представляет собой последовательность
гз 12 единичных битов, за которыми следует нулевой стартовый бит адреса. Первый
байт пакета содержит первичный адрес в диапазоне от 0x80 (128) до OxBF (191). Второй
байт содержит еще три бита адреса, бит контроля данных и вторичный 3-битный адрес.
Третий и последний байт пакета содержит контрольную сумму пакета, полученную по
принципу исключительного ИЛИ. Этот пакет данных типа 1 иллюстрируется на рис. 5.6.
Биты адресы указываются посредством использования стандартного соглашения от-
носительно применения дополнения до единицы трех старших битов адреса.
В примере 5.13 показана программа, которая декодирует все биты пакета и вы-
полняет проверку на правильность контрольной суммы. Эта программа не задает ад-
рес, а также не выполняет иные функции, обычно характерные для типичного контрол-
лера устройств, она также не управляет устройствами. Перед тем, как мы сможем это
сделать, нам необходимо рассмотреть некоторые аппаратные схемы.
176
Применение микроконтроллеров PIC 18
(а)
1111111111 0 1OAsA4A3A2AiAo О 1А8А7АбСааа О ХХХХХХХХ 1
заголовок
ААААААААА = 9-битный первичный адрес
С = контрольный бит
ааа = адрес устройства
ХХХХХХХХ = контрольная сумма, полученная по принципу
исключительного ИЛИ
(b) NMRA type 1 accessory packet
Рис. 5.6. (а) Сигнал на рельсах в системе ОСС и (Ь) информационный пакет типа 1
Пример 5.13
/*
* Это пример 5.13 для тактовой частоты в 4 мГц
*/
♦include <pl8cxxx.h>
♦include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
Глава 5. Программирование PIC 18 на языке С
177
ipragma config OSC = HS
pragma config WDT = OFF
-pragma config LVP = OFF
z данные в памяти программ
-nt count;
-nt state;
int dataBit;
int preamblecount;
-nt firstByte;
-.nt secondByte;
int checksum;
I functions
void assembleByte (int* locale, int nextState)
if (preamblecount 1= 9)
(
*locale >>= 1;
*locale += dataBit;
preambleCount++;
1
else
{
preamblecount = 0;
state = nextState;
1
i
void stateO (void)
if (dataBit == 1)
{
preambleCount—;
if (preamblecount == 0 && dataBit == 0)
{
state =1; // принять корректный заголовок
preamblecount = 0;
1
else
preambleCount++; // в заголовке больше единиц
1
else
preamblecount = 10; //перезапуск
1
void statel (void)
{
assembleByte (&firstByte, 2);
if (dataBit == 1)
state =0; //по ошибке
1
void state2 (void)
{
assembleByte (&secondByte, 3) ;
if (dataBit == In-
state =0; //по ошибке
}
void state3 (void)
178
Применение микроконтроллеров PIC 18
{
assembleByte (&checkSum, 4);
if (dataBit == 0)
state =0; // по ошибке
}
void state4 (void) -
(
state = 0; // сброс state
if ((firstByte Л secondByte л checksum) == 0)
{
// сюда вставляется программа управления
// для программирования контроллера
// или активирования устройства, подключенного к порту в случае
соответствие адреса
)
)
typedef void (*ptr) (void); // массив указателей функций
ptr statesf] = // для состояния устройства
{
&state0,
&statel,
&state2,
&state3,
&state4 <;
);
void Update (void)
{
if (count == 0) // команда сброса системы
{
state = firstByte = secondByte = checksum = dataBit = 0;
preambleCount = 10; //минимальное значение счетчика битов
заголовка
count = 1;
)
// замер ширины импульса
// счетчик = 0 сброс системы
// счетчик = 1 или 2 (от 28 до 84 мкс)
значением данных является логическая единица
// счетчик содержит более 2 отсчетов значением данных является
логический ноль
else
(
count =0; // запуск нового счета
if (PORTBbits.RB0 == 1)
{
while (PORTBbits.RB0 == 1)
{
DelaylOTCYx(2); 11 20 мкс
count++;
}
1
else
{
while (PORTBbits.RB0 == 0)
{
DelaylOTCYx(2); // 20 мкс
count++;
Глава 5. Программирование PIC 18 на языке С
179
1
1
if (PORTBbits.RBO == 1) // пропуск следующего полубита
while (PORTBbits.RBO == 1);
else
while (PORTBbits.RBO == 0) ;
if (count == 0)
state =0; // сброс системы
else if (count < 3)
dataBit =1; // бит = 1
else
dataBit =0; // бит = 0
1
states[state] (); // вызов функции состояния
единственная главная программа
:id main (void)
ADCON1 = 0x7F; // конфигурирование портов А и В как цифровых
// Эти установки могут изменяться в зависимости
от версии микроконтроллера
TRISB =1; // конфигурирование порта В
state =0; // начальное состояние = 0
count =0; // сброс программы и начало ожидания
// корректного заголовка
while (1) // основной цикл
Update(); // ожидание заголовка и корректного пакета
Ожидание 10-ти полных
единиц заголовка
Выделение первого
байта пакета
Выделение второго
байта пакета
Выделение байта
контрольной суммы
Проверка контрольной
суммы и выполнение
нужной функции
Рис. 5.7. Состояния оборудования для примера 5.12
180
Применение микроконтроллеров PIC 18
Главная программа представляет собой бесконечный цикл while, который вызы-
вает функцию Update с нулевым значением счетчика (переменная count). Функция Up-
date распознает нулевое значение счетчика и очищает три байта пакета, а затем уста-
навливает счетчик заголовка на 10. Заголовок должен состоять, по крайней мере, из 10
последовательных логических единиц, однако количество единиц может быть намного
большим. Функция Update затем вызывает функцию, чей адрес хранится в массиве с
именем states (состояния). Поскольку начальное состояние является нулевым, вызыва-
ется функция stateO, которая отсчитывает по крайней 10 логических единиц во входных
данных. При этом первичном инициализирующем вызове функции ничего не считается
и отрабатывается возврат в главную программу, в которой счетчик сбрасывается после
обращения к функции Update.
Затем выполняется замер ширины входного импульса в функции Update. Если
входной бит находится в состоянии логической 1, запускается первый цикл while, от-
считывающий время, а если входной бит находится в состоянии логического нуля, от-
счет времени выполняется во втором цикле while. Эти циклы занимают точно 28 мкс на
итерацию при тактовой частоте, равной 4 МГц, при этом значение счетчика увеличива-
ется так долго, пока входной сигнал не изменяет свое состояние. Если значение входа
не изменяется в течении времени, лежащего в диапазоне от 28 до 56 мкс, значение
счетчика будет равно 1, аналогичным образом, если значение входа не изменяется в
течении времени, лежащего в диапазоне от 56 до 84 мкс, значение счетчика будет рав-
но 2. Длительность импульса логического нуля лежит в диапазоне между 52 и 64 мкс.
Импульс логической единицы имеет длительность, превосходящую 90 мкс, поэтому,
если счетчик достиг значения 3 или больше, то это означает, что вход не изменялся по
крайней мере в течении 84 мкс, что в свою очередь значит, что входной импульс пре-
восходит длительность логического нуля. Приведенная программа соответствует вре-
менным требованиям как для нулевых, так и для единичных битов. Как только произой-
дет смена сигнала, контролируется, однако не замеряется, вторая половина бита.
Должна замеряться только одна половина бита. После замера бита и его прохождения,
программа счета устанавливает либо сбрасывает dataBit, а затем вызывает функцию
states[state](), определяемую состоянием устройства. На рис. 5.7 приведена диаграм-
ма состояний, отражающая назначение каждой функции состояния (от stateO до state4).
Программы управления устройствами часто используют ряд состояний при вы-
полнении задачи. В данном примере массив адресов функций используется для вызова
различных функций для различных состояний. Благодаря такому подходу достигается
прямолинейная организация программы. Программа также должна использовать ка-
кой-то метод для определения факта «зависания» системы в течении более 10 милли-
секунд. Это выполняется при помощи использования сторожевого таймера, однако
поскольку эта тема будет рассматриваться позже, здесь она не иллюстрируется. Ис-
пользование системных и сторожевых таймеров будет рассмотрено и проиллюстриро-
вано примерами программ позже в этой книге. Если входной импульс «застыл» в со-
стоянии логической единицы, что может иметь место в случае отключения подачи на-
пряжения на рельсы модели, то система «зависнет» - это является причиной использо-
вания какого-либо механизма вывода системы из подобного состояния.
Глава 5. Программирование PIC 18 на языке С
181
5.4. Математическая библиотека
Хотя математическая библиотека и не используется столь же часто, как библио-
тека временных задержек, функции, входящие в состав математической библиозеки,
-аходят определенное применение при программировании. Математическая библио-
*ека использует только 32-разрядные числа с плавающей точкой, при этом 64-
зазрядные числа двойной точности не поддерживаются. Поскольку мы изучаем 8-
зазрядный микроконтроллер, 64-разрядные операции потребовали бы для своего вы-
полнения слишком много времени. Во встроенных микропроцессорных системах про-
'□аммы редко работают с данными в формате плавающей точки.
Таблица 5.5. Математические функции,
входящие в состав включаемого файла math.h
Функция Пример Комментарий
acos acos (datal) Возвращает арккосинус в радианах datal (от 0 до л)
asin as in (data2) Возвращает арксинус в радианах data2 (от -л/2 до л/2)
atan atan (data3) Возвращает арктангенс в радианах data3 (от -я/2 до 7с/2)
atan2 atan2 (datal, data2) Возвращает арктангенс в радианах datal / data2 ( от от - л до л)
ceil ceil (datal) Возвращает целое число, которое больше или равно числу с плавающей точкой datal
cos cos (data2) Возвращает косинус data2 в радианах
cosh cosh (data3) Возвращает гиперболический косинус data3
exp exp (data4) Возвращает £data4
fab fab (data5) Возвращает абсолютное значение data5
floor floor (data6) Возвращает целое число, которое больше или равно числу с плавающей точкой data6
fmod fmod (num, mod) Возвращает остаток num по модулю mod
frexp frexp (datal, intr) Разделяет datal на дробную (возвращает) и целую часть (сохра- няется по указателю intr)
ieeetomchp ieeetomchp (data2) Преобразует data2 в формат с плавающей точкой Microchip
idexp idexp (data3, inti) Возвращает data3 * 2intl
log log (data4) Возвращает натуральный логарифм data4
loglO log 10 (data5) Возвращает обычный логарифм data5
mchptoieee mchptoieee (data6) Преобразует data6 из формата с плавающей точкой Microchip
tnodf modf (data7, data8) Возвращает дробную часть data? и сохраняет целую часть по указателю data8
pow pow (datal, data2) Возвращает dataldata2
sin sin (data3) Возвращает синус угла в радианах data3
sinh sinh (data4) Возвращает гиперболический синус data4
sqrt sqrt (data5) Возвращает корень квадратный из data5
tan tan (data6) Возвращает тангенс угла в радианах data6
tanh tanh (data?) Возвращает гиперболический тангенс data?
Математическая библиотека, поставляемая совместно с компилятором С18, реа-
лизует те же функции, что и стандартная математическая библиотека языка ANSI С,
«эторая поставляется с большинством компиляторов. В табл. 5.5 перечислены эти
функции, включая примеры и комментарии о их работе.
Для иллюстрации использования математической библиотеки, программа из
примера 5.14 решает уравнение частоты резонанса, известное из курса электроники
Fr = 1/2 тг/ЬС). Эта программа находит частоту резонанса для конденсатора емко-
стью 1,0 мкФ и значений индуктивности в диапазоне от 1,0 до 10 мГ, сохраняя десять
результатов в массиве с именем Fr.
182
Применение микроконтроллеров PIC 18
Пример 5.14
/*
* Это пример 5.14
*/
♦include <pl8cxxx.h>
♦include <math.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
*/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
// данные в памяти программ
float Fr[10];
float L = 1.0e-3;
float C = 1.0e-6;
// главная программа
void main (void)
{
int a;
for (a = 0; a < 10; a++)
{
Fr[a] = 1 / (6.2831853 * sqrt( L * C ));
L += 1.0e-6;
)
Если вы напишите данную программу, используя IDE, и посмотрите на количество памяти,
использованной для сохранения этой задачи, то увидите, что ее длина будет составлять 1941
байта памяти программ. Такое большое количество памяти нужно в связи с использованием
математических функции для выполнения операции извлечения квадратного корня, а также опе-
раций с плавающей точкой. Как уже отмечалось, в прикладных программах следует использо-
вать символы и целые числа всегда, когда это возможно, ибо размер программы может превы-
сить объем доступной памяти программ.
Предположим, что нам нужно определить коэффициент усиления напряжения в
децибелах. Это достигается использованием уравнения Vgain = 20log10(Vou1/Vin). Функ-
ция, которая использует математическую библиотеку при решении этой задачи, пока-
зана в примере 5.15. Как и в случае примера 5.14, эта функция нуждается в большом
количестве памяти для выполнения операции 1од10, а также арифметических опера-
ций с плавающей точкой.
Пример 5.15
float gainDB (float vout, float vin)
{
return 20 * loglO (vout/vin);
Глава 5. Программирование PIC 18 на языке С
183
5.5. Резюме
1. Компилятор С18 языка С доступен в своей учебной версии как бесплатный вы-
гружаемый файл. Его можно выгрузить с сайта фирмы Microchip.
2. IDE полностью поддерживает программирование на С с использованием ком-
пилятора С18.
3. Операторы #pragma config конфигурируют микроконтроллер РС18 на языке С
anguage.
4. Директивы _asm и _endasm используются без {} для ввода ассемблерного кода
з программу на языке С.
5. Точные функции временных задержек имеются во включаемой библиотеке
компилятора С18, которая называется delays.h.
6. Доступ к портам ввода-вывода из программ на языке С организуется с исполь-
зованием, а также программирования регистров направления данных.
7. Файл заголовка stdlib.h содержит функции, которые выполняют преобразования.
Большинство из них являются функциями преобразования стандартного языка ANSI С.
8. Файл заголовка string.h содержит функции, которые обеспечивают возмож-
ность выполнения манипуляций с символьными строками и памятью, используя как
память программ, так и память данных.
9. Директивы rom near или гот far используются для сохранения информации в
памяти программ микроконтроллера.
10. Файл заголовка math.h содержит функции, которые выполняют математиче-
ские операции, стандартные для ANSI С.
11. В компиляторе С18 арифметика с плавающей точкой ограничена операциями
с 32-разрядными числами с плавающей точкой одинарной точности.
5.6. Вопросы и задания
1. Сравните язык С18 с ANSI С.
2. Как код языка Ассемблера вставляется в программу на языке С?
3. Каково назначение оператора #include <p18cxxx.h>?
4. Каково назначение оператора #pragma config?
5. Что такое набор инструментальных средств Microchip С18?
6. Объясните детально, как функция Delayl KTCYk используется для отработки
’О-миллисекундной временной задержки, если системная тактовая частота равна 4 мГц.
7. Повторите вопрос 6 для случая тактовой частоты, равной 20 мГц.
8. Используя библиотеку delays.h, напишите короткую программу, которая изме-
няет состояние битовой позиции 0 порта В так, чтобы в течении одной секунды она на-
ездилась в единичном состоянии и также в течении одной секунды в нулевом состоя-
-*и. Сделайте предположение о том, что тактовая частота микроконтроллера равна
4 МГц.
9. Напишите короткую программу, которая генерирует прямоугольные импульсы
z частотой 1 кГц в битовой позиции 2 порта В.
10. Напишите программу, которая выполняет простую проверку всех восьми
входных комбинаций на 3-входовой логической схеме NAND (НЕ-И), подключенной к
"юртам ввода-вывода микроконтроллера. Порт В, биты 0, 1 и 2 подключены ко входам
логической схемы NAND, а бит 4 порта А соединен с выходом логической схемы. Если
□езультат проверки положителен, поместите логическую единицу в битовую позицию 3
"юрта В, а если результат проверки отрицателен, поместите логический ноль в битовую
"юзицию 3 порта В.
184
Применение микроконтроллеров PIC 18
11. Используя функцию rand, напишите программу, которая будет генерировать числа
для лотереи в диапазоне между 1 и 47 на битах порта В микроконтроллера всякий раз, когда
нажимается кнопка, подключенная к биту 4 порта А. Исходите из того, что при нажатии кнопка
го; юрируе г логический ноль, а при отпускании - логическую единицу.
12. В чем разница между директивами rom near и гот far?
13. Создайте поисковую таблицу в памяти программ, которая содержит ASCII-
коды цифр от 0 до 9 и букв от А до F. После этого напишите функцию, которая будет
использовать поисковую таблицу для преобразования переданного ей символов от 0 до
15 в код ASCII.
14. Объясните, каким образом позиции таблицы в памяти программ из приме-
ра 5.11 кодируют коды Морзе.
15. Объясните, как функция sendDitDah работает в примере 5.11.
16. Сформируйте оператор языка С, который проверяет состояние битовой пози-
ции 2 порта В. Если этот бит находится в состоянии логической единицы, то программа
должна остановиться на этом операторе, а если в состоянии логического нуля, то про-
грамма должна продолжить свое выполнение.
17. Объясните, как функция Wait4Clock в примере 5.12 ожидает завершения одно-
го полного цикла тактовой частоты в битовой позиции 1 порта А.
18. Какое значение возвращает функция readChar в примере 5.12 в случае ошиб-
ки паритета?
19. Какое значение возвращает функция readChar в примере 5.12 в случае ошиб-
ки фрейма?
20. Объясните, как главная программа в примере 5.13 определяет ширину вход-
ного сигнала логического нуля или логической единицы в битовой позиции 0 порта В.
21. Каков смысл оператора &bob на языке С?
22. Объясните, как оператор states [state] () в примере 5.13 вызывает различные
функции, в зависимости от значения переменной state.
23. Если тактовая частота в примере 5.13 будет изменена с 4 на 8 МГц, то что
должно быть изменено в программе для того, чтобы она работала правильно?
24. Используя заголовочный файл math.h, напишите программу, которая будет
определять емкостное сопротивление (хс) конденсатора на 1,0 мкФ для частот от
100 Гц до 1000 Гц шагами по 100 Гц. Емкостное сопротивление определяется по фор-
муле: —!—
2яГС ’
25. Предположим, что портА (биты 0, 1 и 2) является входом от цифрового коди-
рующего устройства, которое генерирует трехразрядный двоичный код, который пред-
ставляет 45° на каждое приращение двоичного числа, то-есть 000 = 0°, 001 = 45°, 010 =
90° и так далее. Напишите функцию с именем sinPortA, которая считывает порт А и воз-
вращает синус угла. Используя функцию sin(bob) библиотеки math.h library, возвратите
синус угла bob, предполагая, что угол bob задан в радианах (360° = 2п radians). Запиши-
те длину функции, которая сообщается IDE.
26. Повторите вопрос 25, используя поисковую таблицу, сохраненную в памяти
программ, для возврата тех же значений, которые рассчитывались в вопросе 25.Срав-
ните длину этой функции с функцией, написанной вами при работе над вопросом 25.
27. Как вы считаете по результатам работы над вопросами 25 и 26, являются ли
поисковые таблицы важным средством создания программного обеспечения для уст-
ройств с ограниченным объемом памяти - таких, например, как микроконтроллеры?
Глава 6. Спецификации аппаратных средств семейства PIC18
185
ГЛАВА 6. Спецификации аппаратных
средств семейства PIC18
Прежде, чем может быть создана система на основе любого микроконтроллера
семейства PIC18, должно быть достигнуто полное понимание функционального назна-
чения его выводов, а также функций, реализованных в конкретном микроконтроллере.
Эта глава описывает характеристики семейства PIC18 как по постоянному, так и по пе-
эеменному току, схемы синхронизации, требуемые для функционирования PIC18, а
’акже приводит существенно важную информацию в отношении работы некоторых из
устройств ввода-вывода, имеющихся внутри микропроцессоров PIC18. Внутренние
устройства, не рассмотренные в этой главе, будут рассмотрены в последующих главах,
наряду с соответствующими приложениями.
После изучения этой главы Вы:
1. Сможете правильно организовать электропитание микроконтроллера, описать
его характеристики по постоянному току и правильно их использовать.
2. Сможете детально описать различия в микросхемах микроконтроллеров се-
мейства PIC18.
3. Сможете характеризовать минимальные и максимальные напряжения и токи на
выводах Ввод - Вывод и на выводах для подключения питания.
4. Сможете использовать сторожевой таймер.
5. Сможете программировать выводы портов.
6. Сможете сохранять и считывать данные из ЭСППЗУ данных.
7. Узнаете о прерываниях и сможете писать программы на языке С, использую-
щие прерывания.
8. Сможете описать внутренние периферийные устройства микроконтроллеров
семейства PIC18.
9. Использовать таймер, а также модуль сравнения и сбора данных в прикладных
программах.
6.1. Цоколевка выводов и базовые операционные характеристики
Как уже отмечалось в Главе 2, микроконтроллеры семейства PIC 18 могут иметь
разные исполнения. Этот подраздел описывает детали этих исполнений, а также спе-
цифицирует требования относительно потребляемой мощности по постоянному току и
нагрузочную способность микроконтроллеров. Эти знания необходимы при разработке
систем, способных функционировать продолжительное время.
Цоколевка выводов
Существует огромное количество версий микроконтроллеров семейства PIC18,
начиная от 18-выводных корпусов и заканчивая 128-выводными корпусами. Чтобы вы-
брать правильный микроконтроллер для конкретного применения, необходимо близкое
знакомство с различными вариантами цоколевки выводов. Микроконтроллеры семей-
ства PIC18 производятся в следующих вариантах корпусов: PDIP (пластмассовый двух
рядный корпус), SOIC (малая интегральная схема для поверхностного монтажа), PLCC
(пластмассовый безвыводной корпус), QFN (квадратный плоский безвыводной), QFP
(квадратный плоский), TQPP (тонкий квадратный плоский), LQPP (низкопрофильный
квадратный плоский) и SSOP (малый корпус заниженного профиля). Все эти корпуса, за
186
Применение микроконтроллеров PIC 18
исключением PDIP и PLCC, разработаны для поверхностного монтажа и не используют-
ся при работе с прототипами. Рис. 6.1 иллюстрирует названные варианты корпусов.
PDIP обычно используются для работы с прототипами систем, а корпуса с поверхност-
ным монтажом используются в промышленных изделиях.
SOIC
Рис. 6.1. Варианты корпусов микроконтроллеров.
Глава 6. Спецификации аппаратных средств семейства PIC18
187
PDIP, SOIC
RB3/CCP1/P1A
RB2/P1B/INT2
0SC1/CLKI/RA7
OSC2/CLKO/RA6
Vdd/AVdd
RB7/PGD/T10SI/
P1D/KBI3
RB6/PGC/T10S0/
T13CKI/P1C/KBI2
RB5/PGM/KBI1
RB4/AN6/RX/
DT/KBIO
18F1230/1330
MCLR/VPP/RE3----►
RAO/ANO *“*
RA1/AN1 *-*
RA2/AN2/VREF-/CVref *-*
RA3/AN3/VREF+
RA4/T0CKI/C1OUT
RA5/AN4/SS/LVDIN/C2OUT
Vss-----------------------*
OSC1/CLKI/RA7 *-*
OSC2/CLKO/RA6 —*
RCO/T10SO/T1CKI *-*
RC1/T1OSI/CCP2* *—
RC2/CCPVP1A
RC3/SCK/SCL —*
E‘
E
E
E
E
E
E
E
E
E
E
°1
2
3
4
5
6
7
8
9
10
11
E12
Е13
E14
CM
CM
CM
u.
co
T-
o
£L
CM
co
CM
LL
CO
T~
О
28 EJ
27
26
25
24
23
22
21
20
19
18
17
16
15
□
□
□
□
□
□
□
a
□
□
□
a
• и
*-* RB7/KBI3/PGD
*-* RB6/KBI2/PGC
RB5/KBI1/PGM
—RB4/AN11/KBI0
RB3/AN9/CCP2*
*-*• RB2/AN8/INT2
RB1/AN10/INT1
RB0/AN12/INT0
•"—Vdd
—Vss
RC7/RX/DT
•*-*- RC6/TX/CK
RC5/SDO
*-* RC4/SDI/SDA
PIC18F2220/2320
Рис. 6.2. Несколько представителей микросхем
семейства PIC18 в корпусах типа PDIP и SOIC (начало)
188
Применение микроконтроллеров PIC 18
Е
Е
Е
Е
MCLR/VPP/RE3
RA0/AN0
RA1/AN1
RA2/AN2/Vref-/CVref
RA3/AN3/VREF+
RA4/T0CKI/C1OUT ----► £
RA5/AN4/SS/LVDIN/C2OUT *—► Е
RE0/AN5/RD ----► £
RE1/AN6/WR ”---►£
RE2/AN7/CS —« £
VDD-----► £
Vss
OSC1/CLKI/RA7 -—► £
OSC2/CLKO/RA6 —..£
RC0/T1OSO/T1CKI -—►£
RC1/T1OSI/CCP2* .---» £
RC2/CCP1/P1A
RC3/SCK/SCL
RD0/PSP0
RD1/PSP1
MCLR/Vpp/RE3-----
RA0/AN0 *-*
RA1/AN1 *—
RA2/AN2/Vref- —
RA3/AN3/Vref+ —*
RA4/T0CKI *-*•
RA5/AN4/SS/HLVDIN ——
Vss —*•
OSC1/CLKI/RA7 —►
OSC2/CLKO/RA6 -----
RC0/T1OSO/T13CKI -<-*
RC1/T1OSI —*
RC2/CCP1 *—
RC3/SCK/SCL *-*
2
3
4
5
6
7
8
9
10
см
см
см
q 12
13
14
15
16
di7
E 18
E 19
E 20
О
О
40 p
39
38
37
36
35
34
33
32
31
30
29
28
27
26
25
24
23
22
21
2
□
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
----► RB7/KBI3/PGD
RB6/KBI2/PGC
----- RB5/KBI1/PGM
- «-- RB4/AN11/KBI0
~—- RB3/AN9/CCP2’
- *-► RB2/AN8/INT2
----► RB1/AN10/INT1
---► RB0/AN12/INT0
-----VDD
•----Vss
-—* RD7/PSP7/P1D
----► RD6/PSP6/P1C
-—► RD5/PSP5/P1B
► RD4/PSP4
----- RC7/RX/DT
» RC6/TX/CK
► RC5/SDO
-—- RC4/SDI/SDA
-—- RD3/PSP3
-—► RD2/PSP2
18F4220/4320
D
E
E
E
E
E
E
E
E
Ц10
и
Д12
E13
E14
a- 1
2
3
4
5
6
8
9
c
CM
U
co
in
CM
U
18F2480/2580
□
281
27 □
26 □
25
24
23
22
21
20
19
18
17
16
15
□
□
□
□
□
□
□
—* RB7/KBI3/PGD
—* RB6/KB12/PGC
*-*- RB5/KBI1/PGM
RB4/KBI0/AN9
*-* RB3/CANRX
RB2/INT2/CANTX
—RB1/INT1/AN8
*-* RB0/INT0/AN10
"•— Vdd
- •— Vss
* -* RC7/RX/DT
RC6/TX/CK
* -* RC5/SDO
*-* RC4/SDI/SDA
Рис. 6.2. Несколько представителей микросхем
семейства PIC18 в корпусах типа PDIP и SOIC (продолжение)
Глава 6. Спецификации аппаратных средств семейства PIC 18
189
MCLRA/PP/RE3 ------ Е
RAO/ANO/CVref ► £
RA1/AN1 -—-Е
RA2/AN2A/REF- £
RA3/AN3/VREF+
RA4/T0CKI ----► Е
RA5/AN4/SS/HLVDIN ----*Е
___RE0/RD/AN5 -----Е
RE1/WR/AN6/C1OUT -----► Е
RE2/CS/AN7/C2OUT -----► Е
Vdd-----► Г
Vss
0SC1/CLKI/RA7
OSC2/CLKO/RA6
RC0/T1OSO/T13CKI
RC1/T10SI
RC2/CCP1
RC3/SCK/SCL ----*р18
RD0/PSP0/C1IN+ ---19
RD1/PSP1/C1IN- <•—*Е 20
2
3
4
5
6
7
8
9
10
со
со
LD
Г 12
С 13
q 14
15
Е
Г 16
LL
СО
6
00
40 Р *----► RB7/KBI3/PGD
39
38
37
36
35
34
33
32
31
30
29
28
27
26
25
24
23
22
21
П ---- RB6/KBI2/PGC
ZJ --► RB5/KBI1/PGM
□ ► RB4/KBI0/AN9
J RB3/CANRX
п ► RB2/INT2/CANTX
П ----► RB1/INT1/AN8
П ----► RB0/INT0/FLT0/AN10
3 -<-----Vdd
Л -----Vss
2J ---- RD7/PSP7/P1D
3 «.--► RD6/PSP6/P1C
Ц-----► RD5/PSP5/P1B
□ ----. RD4/PSP4/ECCP1/P1A
3 „---». RC7/RX/DT
3 RC6/TX/CK
3 ► RC5/SD0
3 ----- RC4/SDI/SDA
3 ► RD3/PSP3/C2IN-
3 ----► RD2/PSP2/C2IN+
18F4480/4580
Рис. 6.2. Несколько представителей микросхем
семейства PIC18 в корпусах типа PD1P и SOIC (окончание)
Рис. 6.2'иллюстрирует цоколевку выводов некоторых микроконтроллеров семей-
ства PIC18. Показанные примеры являются типовыми для семейства микроконтролле-
ров PIC18, при этом в их состав не входят микросхем 18F242/248/252/258/448/458,
использование которых в новых проектах не рекомендуется фирмой Microchip, в связи
со снятием их с производства в недалеком будущем. Для ознакомления с полным пе-
речнем доступных в настоящее время устройств семейства 18F, посетите сайт фирмы
Microchip. В общем случае при использовании 18-выводных микросхем с корпусами
PDIP, ввод-вывод будет ограничен портами А и В; портами А, В и С при использовании
28-выводных версий микросхем и портами А, В, С, D и Е при использовании
40-выводных корпусов. Устройства рассматриваемого семейства в более, чем
40-выводных корпусах типа PDIP не являются общедоступными, поэтому здесь они не
рассматриваются, ибо могли бы возникнуть трудности при создании прототипов. Как
только эти младшие версии корпусов будут изучены, мы сможем легко переключиться
на изучение корпусов для поверхностного монтажа с большим количеством выводов,
поскольку все члены семейства во всем остальном идентичны. Единственное различие»
заключается в способе установки микросхемы (тип корпуса), добавлении дополнитель-
ных выводов для ввода-вывода, а также в некоторых дополнительных функциях, кото-
рые реализованы в версиях микросхем с меньшим количеством выводов.
Выводы для подключения напряжения питания
Как и в любой интегральной схеме на полевых МОП-транзисторах, для подачи
номинального напряжения питания, равного +5В (это напряжение может снижаться до
4,2 В для обеспечения максимального быстродействия) используется вывод VDD; для
подключения земли служит вывод VSS. Все выводы VDD и VSS должны быть подключе-
ны к источнику электропитания, включая те версии микроконтроллеров, которые имеют
более одного вывода VDD или VSS. Во всех случаях максимально допустимое напряже-
190
Применение микроконтроллеров PIC 18
ние питания нормируется уровнем + 7,5 В. Микросхемы позволяют использовать самые
различные источники электропитания, включая батареи. Имеется также версия микро-
контроллера со сниженным потреблением мощности (PIC18L), в которой допускается,
чтобы напряжение питания опускалось бы до уровня 2,5 В при работе с полным быст-
родействием. Микроконтроллер - это устройство выполнено на КМОП-структурах, с
которым нужно работать соответствующим образом. Микросхема может быть повреж-
дена электростатическим разрядом (ESD). Удостоверитесь в том, что микроконтроллер
хранится в антистатическом защитном корпусе до тех пор, пока он не установлен в схе-
му, а также в том, что при работе с ним применяются надлежащие методы. Они вклю-
чают правильное заземление, а также работу в среде с надлежащей влажностью (свы-
ше 20%). При работе с микроконтроллером, всегда одевайте на руку заземляющий
браслет, а также убедитесь, что рабочая зона заземлена надлежащим образом. Если
некоторые из входов микроконтроллера не используются, необходимо их подключить
на общий провод или к источнику питания, как того требует техническое описание на
микроконтроллер. Неподключенных выводов быть не должно. Электростатический раз-
ряд на «висячий» вывод, приведет к выводу из строя микросхемы.
В общем случае ток потребления определяется тактовой частотой, он может
иметь диапазон от 60 мкА при работе с тактовой частотой в 31 кГц до 12 мА и выше,
когда используется тактовая частота 40 МГц. Максимальное значение тока может дос-
тигать 300 мА, а максимальное значение мощности, рассеиваемой устройством, равно
1 Вт. Величина тока потребления изменяется в зависимости от тактовой частоты и на-
грузкой на выводах ввод - вывод, однако она указывается в технических данных кон-
кретного устройства для определенной частоты. Нагрузка на выводах для ввода - выво-
да должна быть определена для конкретного приложения и добавлена к мощности, по-
требляемой микроконтроллером.
В непосредственной близости от интегральной схемы должен быть установлен
развязывающий конденсатор емкостью 0,1 мкФ, шунтирующий вывод VDD на общий
провод (вывод VSS). Микроконтроллер PIC производит большое количество внутренне-
го переключательного шума, который может передаваться на другие компоненты сис-
темы через шины питания. По этой причине наличие развязывающего конденсатора
обязательно. Этот высокочастотный шум генерируется всякий раз, когда внутрен-
ний ключ на полевом МОП-транзисторе замыкается или размыкается, вызывая броски
тока на выводе питания. Все цифровые интегральные схемы производят этот тип шу-
мов, поэтому выводы питания должны шунтироваться. Даже линейный усилитель, такой
как операционный усилитель, генерирует шумы и наличие конденсаторов развязки на
выводах питания обязательно.
Подключения ввода-вывода
Характеристики ввода - вывода весьма важны для организации взаимодействия с
другими устройствами. Характеристики интерфейса микроконтроллеров перечислены
в табл. 6.1. В этой таблице максимальные токи логического нуля и единицы указаны
совместно с соответствующими диапазонами напряжения. Указанных значений необ-
ходимо твердо придерживаться, если выходы используются для управления логиче-
скими схемами. В других случаях (как, например, при управлении светодиодами и т.д.)
фактический максимальный выходной ток равен 25 мА для логического нуля или логи-
ческой единицы при условии, что не превышен общий ток потребления микросхемы
микроконтроллера. Если Вывод ввода - вывода имеет слабую нагрузочную способность
(порт В и порт D в некоторых версиях микросхем), как это будет описываться в после-
дующих разделах, то максимальный входной ток будет равен 400 мкА. Если требуется
Глава 6. Спецификации аппаратных средств семейства PIC18
191
ток, превышающий рекомендуемый, то в качестве интерфейса ввода- вывода исполь-
зуется усилитель. В общем случае ток на выходном выводе будет достаточным для
управления четырьмя стандартными ТТЛ-микросхемами или 10 высокоскоростными
КМОП-микросхемами. Если используются иные значения напряжения питания, то об-
ращайтесь к техническим данным на микроконтроллер для получения дополнительных
сведений о токе потребления и токах на выводах микросхемы.
Таблица 6.1. Логические уровни на выводах «ввод-вывод» при VDD = +5,0 В.
Лог. уровень Vmin Vmax Imax
0 вход 0.0 В 0.8В ±1.0 мкА
1 вход 2.0 В 5.0В ±1.0 мкА
0 выход 0.0 В 0.6В -8.5 мА
1 выход 4.3 В 5.0В 3 мА
*Максимально допустимый общий ток микросхемы равен 200 мА при вплоть до 25 мА
на каждый вывод, при условии, что предел в 200 мА не превышен для всей микро-
схемы, а ее выходы не подключены ко входам логических схем.
Сброс
Для правильной работы микроконтроллера, должна быть правильно выполнена
операция приведения его в исходное состояние или сброса. Входной Вывод МОШ - это
Вывод общего сброса, который инициализирует микроконтроллер таким образом, что
он начинает работу, выбирая команду из нулевой ячейки памяти, которая называется
адресом вектора сброса. Если питание растет со скоростью 0,05 В/мс (минимумом), то
тогда резистор с номиналом от 1 кОм до 10 кОм подключается между входом МОШ и +
5.0 V, при этом внутренние схемы автоматически сбрасывают микроконтроллер. Если
скорость роста напряжения нельзя гарантировать, как со всеми примерами в этой кни-
ге, потому что характер источника питания неизвестен, то схема, иллюстрируемая ри-
сунком 6.3, правильно сбрасывает микроконтроллер. Очень часто нормально разомк-
нутый кнопочный переключатель используется для ручного сброса микроконтроллера
(эта кнопка сброса может быть снята, если ручной сброс не требуется). RC-постоянная
времени цепи сброса должна быть между 10 мс и 20 мс. Схема на рис. 6.3 имеет по-
стоянную времени RC, равную 10К х 1.0 мкФ или 10 мкс.
Микроконтроллер также сбрасывается при следующих условиях в дополнение к
заземлению вывода общего сброса:
1. Сброс по сторожевому таймеру (WDT)
2. Программируемый сброс по частичной потере питания (BOR)
3. Командой RESET (Reset) при обращении к соответствующей функции на языке С.
4. Сброс по заполнению стека
5. Сброс по потере значимости стека
Прохождение сигнала общего сброса от входа общего сброса разрешается на
языке С оператором #pragma config MCLRE = ON. Если он не разрешен, то тогда вы-
полняется сброс по росту напряжения питания, контролируемого на выводе VDD при
условии, что его нарастание соответствует требованиям технических данных. Входом
общего сброса становится бит ввода-вывода порта А, если вход общего сброса дезак-
тивирован оператором #pragma config MCLRE = OFF. Фактический номер штырька и
позиция бита порта определяются версией микроконтроллера. Во многих случаях кон-
денсатор сброса и резистор требуются для того, чтобы гарантировать правильное вы-
полнение операции сброса.
192
Применение микроконтроллеров PIC 18
Рис. 6.3. Цепь сброса микроконтроллера PIC18
Команда #pragma config на языке С определяет состояние битов конфигурации
микроконтроллера. Эти биты размещены в пространстве памяти программы, которое
является доступным только через использование команд табличного чтения и записи
по адресам от 0x300000 до Ox3FFFFF. Ввиду значительного количества работы, тре-
буемой для того, чтобы изменить эти ячейки, язык С реализует команду #pragma config
для этой задачи. Биты конфигурации могут также изменяться в MPLAB IDE на вкладке
Configuration (Конфигурация) главного меню, но намного более описательно это бу-
дет, если конфигурирование будет выполнено с помощью оператора #pragma config.
Сторожевой таймер. Сторожевой таймер (WDT) - это внутренний счетчик, кото-
рый сбрасывает микроконтроллер по истечении заданного периода времени. Этот
таймер может программироваться. WDT можно включать или выключать, используя
команду #pragma config или же соответствующие команды программы на языке Ас-
семблера. На языке С команда #pragma config часто используется для того, чтобы
включать или отключать WDT для всей программной системы. WDT работает при пе-
риоде тактовой частоты равном 4 мс. Тактовая частота генерируется внутренним гене-
ратором. WDT масштабируется с коэффициентом от 1 до 32К, как это показано в
табл. 6.2 и может отсчитывать время в диапазоне между 4 мс и 131 секундой.
Другая команда конфигурирования используется для того, чтобы включить WDT.
#pragma config WDT = ON/OFF используется на языке С и WDT ON 2Н или
_WDT_OFF_2H (для 18F1320) используется на Ассемблере. Пример 6.1 иллюстрирует
версии соответствующих команд как на языке С, так и языке Ассемблера, включающие
WDT и задающие коэффициент масштабирования, равный 4, который программирует
WDT на сброс микроконтроллера по истечении 16 мс.
Глава 6. Спецификации аппаратных средств семейства PIC18
193
Пример 6.1
' / команды языка С для всех членов семейства 18F
♦pragma config WDT = ON
♦pragma config WDTPS =4 ; таймаут WDT равен 16 мс
; команды языка Ассемблера для PIC18F1320 _
_CONFIG _CONFIG2H, _WDT_ON_2H _WDTPS_4_2H
Таблица 6.2. Допустимые коэффициенты
масштабирования сторожевого таймера
Оператор С Язык Ассемблера Коэфф. масшт. Время до сброса
♦pragma config WDTPS = 1 WDTPS12H 1:1 4 мс
♦pragma config WDTPS = 2 WDTPS22H 1:2 8 мс
♦pragma config WDTPS - 4 WDTPS42H 1:4 16 мс
♦pragma config WDTPS = 8 WDTPS82H 1:8 32 мс
♦pragma config WDTPS =16 WDTPS162H 1:16 64 мс
♦pragma config WDTPS = 32 WDTPS322H 1:32 128 мс
♦pragma config WDTPS = 64 WDTPS642H 1:64 256 мс
♦pragma config WDTPS = 128 WDTPS1282H 1:128 512 мс
♦pragma config WDTPS = 256 WDTPS2562H 1:256 1.024 с
♦pragma config WDTPS =512 WDTPS5122H 1:512 2.048 с
♦pragma config WDTPS = 1024 WDTPS10242H 1:1024 4.096 с
♦pragma config WDTPS = 2048 WDTPS20482H 1:2048 8.192 с
♦pragma config WDTPS = 4096 WDTPS40962H 1:4096 16.384 с
♦pragma config WDTPS = 8192 WDTPS81922H 1:8192 32.768 с
♦pragma config WDTPS = 16384 WDTPS163842H 1:16384 65.536 с
♦pragma config WDTPS = 32768 WDTPS327682H 1:32768 131.072 с
Примечание: полный список команд языка Ассемблера имеется во включаемом файле
микроконтроллера PIC18F (здесь в качестве иллюстрации используется микрокон-
троллер PIC18F1320)
WDT запускается после сброса микроконтроллера, он начинает отсчитывать вре-
мя с интервалами в 4. В примере 6.1 интервал счета равен четыре периода по 4 мс или
16 мс. После работы программы в течении 16 мс WDT инициализирует сброс. Это по-
зволяет сбрасывать систему при переполнении WDT в случае сбоя программного обес-
печения. Если программа функционирует нормально, WDT перезапускается без ини-
циализации сброса, помещая команды SLEEP (Sleep() на С) или CLRWDT (ClrWdt() на С)
в нормальную последовательность команд программы (см. пример 6.2). WDT может
также быть включен (лог. 1) или выключен (лог. 0) с использованием бита SWDTEN ре-
гистра WDTCON. Если программа зависнет, то WDT не будет сброшен функцией
ClrWdtO и произойдет сброс системы. Перезапуск системы, в этом примере, происхо-
дит по истечении 16 мс. Такая особенность чрезвычайно важна в системах, которые
должны функционировать непрерывно без сбоев. Вообразите только, что WDT отсутст-
вует в системе антиблокировки тормозов автомобиля (ABS) и программа заблокирова-
лась, когда водитель нажал на тормоз! При наличии WDT система сбросится и запус-
тится вновь. И даже еще худший случай: что будет, если контроллер управления зажи-
ганием “зависнет”, когда ваш автомобиль несется по автостраде со скоростью 70 миль
в час?
194
Применение микроконтроллеров PIC 18
Пример б.2
// Операторы на языке С для всех версий семейства 18F
void MAin(void)
{
while (1) // системный цикл
{
CIrWdtO; // сброс сторожевого таймера
// здесь вставляется системное программное обеспечение
1
1
; язык Ассемблера
MAin:
CLRWDT ; сброс сторожевого таймера
; здесь вставляется системное программное обеспечение
GOTO Main
Сброс при частичной потере питания. Сброс при частичной потере питания
(BOR) перезапускает систему всякий раз, когда напряжение питания понижается ниже
предварительно запрограммированного уровня. Будучи перезапущенным, микрокон-
троллер не начинает работать, пока напряжение питания не поднимется выше предва-
рительно запрограммированного уровня. Этот сброс останавливает систему и переза-
пускает ее, если по какой-либо причине напряжение питания снижается ниже предва-
рительно заданного значения. Снижение напряжения могло бы быть вызвано перегруз-
кой или в случае батарейного питания - севшими батареями. Сброс BOR предотвраща-
ет программные сбои в ситуациях, связанных со снижением напряжения питания. По-
роговое значение напряжения, инициализирующее сброс по частичной потере пита-
ния, программируются, используя туже самую методику конфигурирования, что и при
программировании WDT. В табл. 6.3 перечислены параметры и уровни напряжения для
BOR. BOR разрешается конфигурирующим значением BOR = ON и запрещается значе-
нием BOR = OFF.
Предположим, что в системе для BOR используется пороговое значение напря-
жение питания, равное 4,2 В. Пример 6.3 иллюстрирует операторы языка С, устанавли-
вающие BOR.
Таблица 6.3. Уровни напряжения сброса по частичной потере напряжения питания
Язык С Язык Ассемблера Напряжение сброса по потере питания
#pragma config BORV = 45 #pragma config BORV = 42 #pragma config BORV = 27 #pragma config BORV = 20 _BORV_45_2L 4.5В _BORV_42_2L 4.2В _BORV_27_2L 2.7 В BORV 20 2L 2.0 В
Примечание: указанные уровни напряжения могут быть иными в других микрокон-
троллерах, поэтому обращайтесь к техническим данным на микроконтроллер или к
справке по битам конфигурирования компилятора С18 (здесь в качестве иллюстра-
ции рассматривается микроконтроллер PIC18F1320).
Глава 6. Спецификации аппаратных средств семейства PIC18
195
Пример б.3
#pragma config BORV =42 // установка порогового напряжения сброса на 4.2 В
#pragma BOR = ON
Сброс стека. Стек никогда не переполняется и не опустошается при нормальной ра-
боте программы. Если по какой- либо причине возникает сбой в системной программе, то
может возникнуть переполнение либо опустошение стека. Опустошение стека вызывается
слишком большим количеством возвратов или операций выталкивания адресов из стека, а
переполнение стека вызывается слишком большим количеством вызовов функций или опе-
раций вставки адресов в стек. Если происходит одна из названных ошибок, то система авто-
матически сбрасывается, если этот вид сброса разрешен. Сброс стека разрешает-
ся/запрещается командой #pragma config STVR = ON/OFF. Переполнение происходит, если
больше чем 31 адрес возврата помещается в стек, а опустошение происходит, если слишком
много адресов возврата удалено из стека.
Режим бездействия. Микроконтроллер переводится в состояние или режим бездейст-
вия, используя либо команду Sleep() языка С или команду SLEEP Ассемблера. В режиме без-
действия тактовый генератор микроконтроллера выключен и выполнение программы оста-
новлено с целью минимизации потребления енергии. Этот режим полезен в системах с ба-
тарейным питанием. В режиме бездействия сторожевой таймер может быть запрограмми-
рован так, чтобы после истечения контрольного интервала времени микроконтроллер был
выведен из состояния бездействия. События, которые генерируют прерывания, также выво-
дят микроконтроллер из состояния бездействия, поскольку прерывания прерывают этот
режим. Многие приложения извлекают пользу из режима бездействия, поскольку он позво-
ляет экономить электропитание, однако, если система не эксплуатируется в условиях бата-
рейного питания, то режим бездействия используется редко. Хорошим примером работы в
режиме бездействия является пульт дистанционного управления телевизором. При нажатии
кнопки для переключения на другой канал либо выполнения иной функции генерируется
прерывание, которое заставляет микроконтроллер выйти из режима бездействия и выпол-
*мть требуемую функцию. После завершения выполнения нужной функции микроконтроллер
вновь входит в режим бездействия. Это снижает потребление электроэнергии, доводя его до
очень низкого уровня, позволяя батарейкам пульта работать в течении длительного времени.
Синхронизация
Микроконтроллер - это синхронная система, которая для своей работы требует
использования источника тактовой частоты - тактового генератора. Большинство мик-
роконтроллеров семейства PIC18 имеют функцию выбора входа тактовой частоты, ко-
торая может поступать от вплоть до 10 различных источников. (Некоторые исполнения
•жкроконтроллеров, отмеченные звездочкой в нижеследующем списке, не имеют
»<утреннего тактового генератора, а некоторые другие исполнения микроконтролле-
ров могут реализовать дополнительные режимы.) Тактовый генератор задает скорость
работы микроконтроллера и используется также при отработке временных задержек и
обработке иных событий внутри микроконтроллера. Источниками тактовой частоты
могут быть:
1. Маломощный кварцевый генератор (LP)
2. Кварцевый либо керамический резонатор (XT)
3. Высокочастотный кварцевый либо керамический резонатор (HS)
4. Высокочастотный кварцевый либо керамический резонатор с контуром ФАПЧ
(HSPLL)
5. Внешний резистор/конденсатор с выходом Fosc/4 на OSC2 (RC)
196
Применение микроконтроллеров PIC 18
6. Внешний резистор/конденсатор с входом/выходом на OSC2 (RCIO)
7. Внутренний генератор с Fosc/4 на RA6 и входом/выходом на RA7 (INTI01)
8. Внутренний генератор с входом/выходом на RA6 и RA7 (INTI02)
9. Внешний генератор с Fosc/4 (ЕС)
10. Внешний генератор с входом/выходом на RA6 (ЕСЮ)
Первые четыре режима требуют внешнего кварцевого или керамического резо-
наторов, которые подключаются к выводам OCS1 и OSC2 микроконтроллера. Это - наи-
более распространенные способы обеспечить микроконтроллер тактовыми импульса-
ми. Если используется кварцевый резонатор, то необходимо использовать параллель-
ный, а не последовательный резонанс. При последовательном резонансе, тактовые
импульсы не генерируются после первичного включения системы, поэтому он редко
используются в системном проектировании. Рис. 6.4 иллюстрирует типовое подключе-
ние кварцевого резонатора к выводам OSC1 и OSC2. В данном случае конденсатор на
27 пФ используется совместно с кварцевым генератором. Может потребоваться не-
большой подбор емкости этого конденсатора (15 - 33 пФ), однако конденсатор емко-
стью 27 пФ надежно работает для большинства частот кварцевого либо керамического
резонаторов.
PIC
Рис. 6.4. Использование кварцевого либо
керамического резонатора в качестве источника тактовой частоты
Если выбран режим PLL (контур ФАПЧ), то внутренние цепи ФАПЧ обеспечат ум-
ножение частоты кварцевого генератора на коэффициент, равный 4. Следовательно,
при кварцевом резонаторе 4 МГц, подключенном к выводам OSC1 и OSC2, и выбран-
ном режиме PLL, микроконтроллер будет работать с внутренней тактовой частотой,
равной 16 МГц. Этот тип формирования тактовой частоты может потребоваться в тех
системах, в которых необходимо снизить уровень электромагнитных помех (EMI),
удерживая внешнюю тактовую частоту настолько низкой, насколько это возможно.
Глава 6. Спецификации аппаратных средств семейства PIC18
197
Тактовая частота может также формироваться при помощи внешней частотно за-
дающей RC-цепочки. Рис. 6.5 изображает соответствующее подключение. Близкой
аппроксимацией получаемого значения частоты будет выражение 1/4,2RC. Это значе-
ние частоты будет зависеть от напряжения питания и точности номиналов электронных
компонент. По причине разброса номиналов электронных компонентов, времязадаю-
щие RC-цепи должны использоваться только в тех системах, в которых не требуется
точной синхронизации выполнения команд. В режиме RC вывод OSC2 программирует-
ся как вывод Вход/Выход, либо как выход тактовой частоты, деленной на 4 (Fosc/4).
Fosc/4
работа на частоте 2 МГц достигается при R=3,9 кОм и С = 30 пФ;
Fosc/4 равно 500 кГц при указанных номиналах компонент;
от 3 кОм до 100 кОм;
С больше 20 пФ.
Рис. 6.5. Использование для синхронизации RC-цепочки
PIC
Вход внешней
тактовой-----
частоты
OSC1
Рис. 6.6. Управление PIC от входа внешней тактовой частоты
Два другие режима работы используют внешний источник тактовой частоты, при
этом внешняя тактовая частота подается на вывод OSC1. Вывод OSC2 используется
либо как вход/выход, либо как вывод тактового сигнала Fosc/4, который равен одной
четвертой тактовой частоты. Рис. 6.6 иллюстрирует подачу сигнала внешней тактовой
частоты.
Для выбора режима работы тактового генератора, соответствующим образом
программируются биты конфигурации. Пример 6.4 иллюстрирует код конфигурирова-
198
Применение микроконтроллеров PIC 18
ния системы на языке С при использовании в качестве источника тактовой частоты в 4
МГц кварцевого генератора. Значение OSC будет тем, которое указано в начале данно-
го подраздела, т.е. HS для режима 3, RC для режима 5 и т.д. Если программа создается
только при использовании языка Ассемблера, то смотрите включаемый файл микро-
контроллера, выбранного для использования в системе. Этот включаемый файл со-
держит информацию по языку Ассемблера, необходимую для программирования ре-
гистра конфигурации на соответствующий режим работы тактового генератора.
Пример б.4
frpragma config OSC = HS // выбирает высокочастотный кварцевый генератор
// ИЛИ
*
#pragma config OSC = RC // выбирает RC- генератор
Если выбран режим работы от внутреннего тактового генератора (режимы 7 и 8),
выводы OSC1 и OSC2 будут доступны для организации Ввода - Вывода (порт А, биты 6 и
7) или же для сигналов Fosc/4 и РА7. (Не все версии PIC имеют внутренний генератор.)
Доступны две частоты внутреннего тактового генератора, - 8 МГц и 31 кГц. Сигнал с
частотой 8 МГц может быть отмасштабирован в сторону уменьшения с 4 МГц до 125 кГц
внутренним делителем. Рис. 6.7 изображает регистр управления генератора и регистр
настройки генератора, который используется для управления внутренним генерато-
ром. Пример 6.5 показывает, как использовать язык С для программирования PIC на
использование внутреннего генератора при работе с частотой равной 4 МГц. В этом
примере задается средняя частота. В дополнение к программному коду по примеру
6.5, в программе должны присутствовать операторы #pragma config OSC INI02 или
#pragma config OSC = INTI01 для выбора режима работы от внутреннего тактового ге-
нератора. Режим INTI02 заставляет OSC1 и OSC2 функционировать для Ввода - Выво-
да, a INTI01 инициализирует выдачу на вывод OSC2 частоты Fosc/4, OSC1 при этом бу-
дет функционировать для Ввода - Вывода. Для выбора внутреннего генератора, рабо-
тающего с частотой 31 кГц, в программе используется псевдокомментарий INTRC.
Пример 6.5
OSCCON = 0x62; // выбирает частоту внутреннего генератора
OSCTUNE =0; // настройка генератора на среднюю частоту
Теперь, после того, как мы рассмотрели назначение выводов синхронизации и
сброса, целесообразно рассмотреть пример, который помог бы связать все это вме-
сте. Рис. 6.8 иллюстрирует микроконтроллер, использующий кварцевый генератор,
работающий с частотой 4-МГц с реальной кнопкой сброса и соответствующими цепя-
ми. Пример 6.6 показывает программу на языке С, используемую для программирова-
ния микроконтроллера таким образом, чтобы сторожевой таймер инициализировал
сброс один раз в секунду, пороговое напряжение сброса по частичной потере питания
устанавливается при этом на 4,2 В.
Глава 6. Спецификации аппаратных средств семейства PIC18
199
(а) регистр OSCCON
IDLEN 1RCF2 IRCFI IRCF0 OSTS IOFS SCSI SCSO
1DLEN = O разрешение режима
IDLEN = 1 разрешение режима бездействия
IECF2 IRCFI IRCF0
0 0 0 = 31 кГц
0 0 1 - 125 кГц
0 I 0 = 250 кГц
0 1 1 = 500 кГц
1 0 0 = 1 МГц
1 0 1 = 2 МГц
1 1 0 = 4 МГц
1 1 1 = 8 МГц
OSTS = 0 работа таймера запуска генератора
OSTS = 1 истечение интервала счета таймера
запуска генератора
IOFS = 0 внутренний генератор нестабилен
IOFS = 1 внутренний генератор стабилен
SCSI SCS0
О 0 = первичный генератор
О 1 = генератор таймера 1
1 0 = внутренний генератор
1 1 = внутренний генератор
(Ь) регистр OSCTUNE
Т5 Т4 тз Т2 TI ТО
Т-биты:
011111= максимальная частота
000001
000000= средняя частота
111111
минимальная частота
100000 =
Рис. 6.7. Внутренние регистры управления генератором
Цепь, показанная на рисунке, имеет дополнительный конденсатор (С4). Данный
конденсатор выполняет функцию развязки. Поскольку микроконтроллер - это синхрон-
ная система, то она генерирует высокочастотный шум (переключательный шум) на вы-
водах питания. Чтобы отфильтровать этот шум, С4 обеспечивает путь отвода любого
высокочастотного шума, сгенерированного микроконтроллером, на землю. Обычная
практика связана с использованием конденсатора на 0,1 мкФ для отвода шума на каж-
дой аналоговой или цифровой интегральной схеме системы. Если для шунтирования
выводов питания конденсатор не используется, то будут часто возникать проблемы и
таинственные программные сбои.
200
Применение микроконтроллеров PIC18
Пример б.б
#pragma config MCLRE = ON // разрешение использования входа общего сброса
#pragma config OSC = HS // выбор кварцевого генератора
#pragma config WDT = ON // установка сторожевого таймера
♦ pragma config WDTPS = 256 // время сторожевого таймера = 1 секунде
♦ pragma config BORV =42 // установка напряжения сброса по частичной потере
питания
♦ pragma BOR = ОМ // сброс по част. Потере питания вкл.
void main (void)
I/ инициализация системы
while (1) // главный программный цикл
{
CIrWdtf); // сброс сторожевого таймера
// здесь вставляется системное программное обеспечение
Рис. 6.8. Типичные цепи сброса и генератора.
Основной цикл в этой программе содержит функцию ClrWdt. Поскольку правильно
спроектированная система функционирует в основном цикле, WDT очищается и нико-
гда не срабатывает на сброс микроконтроллера. На языке С основной цикл программы
для любой операционной системы бесконечен - даже в случае таких сложных операци-
онных систем, как Windows и Linux. WDT можно также активировать, используя команду
WTCONbits.SWDTEN = 1 в программе на языке С вместо оператора #pragma.
Глава 6. Спецификации аппаратных средств семейства PIC18
201
6.2. Выводы Ввод-Вывод
Число портов Ввод - Вывод и количество выводов у этих портов различно для
членов семейства Р1С18, однако все версии микросхем имеют по крайней мере порт А
и порт В. Выводы портов Ввод - Вывод обозначаются так, как, например, RAO для бито-
вой позиции 0 порта A. R в обозначении “RAO” означает “регистр”, так что это вывод
бита 0 регистра А.
Порт А
Выводы Порта А используются в схеме, показанной на рисунке 6.8. Вход MGLR -
это RA5 (для PIC18F1220), в типовом случае он используется для ручного сброса, по-
этому он часто недоступен в качестве вывода Ввод - Вывод. Аналогично, биты RA7 и
RA6 (для PIC18F1220) используются в схеме (см. рис. 6.8) как выводы OCS1 (RA7) и
OSC2 (RA6). Порт А имеет три регистра, которые управляют его работой и используют-
ся в ходе этой работы: это регистры TRISA, PORTA и LATA. Регистр TRISA определяет
направление переноса данных на штырьках порта А, при этом логическая единица би-
товой позиции определяет Вывод как входной, а ноль битовой позиции определяет
Вывод как выходной. Некоторые версии микросхем используют регистр DDRA (регистр
направления данных), который является вторым названием (псевдонимом) регистра
TRISA, используемым при управлении битами TRISA. (Для конкретных версий микро-
контроллера, смотрите файл Ikr для знакомства с соответствующими определениями).
Регистр PORTA используется для считывания выводов порта А или записи в эти выво-
ды. Регистр LATA используется внутренне для считывания и модификации данных с
последующей их записью в порт А. В типичном случае он непосредственно не адресу-
ется программным обеспечением. Буферный регистр позволяет порту изменять свое
состояние без сбоев. Примером выполнения операций чтения, модификации и записи
может быть такая команда языка С, как PORTA ++, которая считывает порт А, инкремен-
тирует его, а затем записывает результат обратно в порт А. Чтобы лучше понять харак-
тер работы порта, посмотрите на рис. 6.9, который иллюстрирует внутреннюю структу-
ру порта. Чтобы записать данные в порт, необходимо записать их либо в регистр LATA
или в регистр PORTA. Чтобы считать выводы порта, нужно считать PORTA. Чтобы счи-
тать содержимое буферного регистра порта, нужно считать LATA. Обычно только
PORTA используется как регистр, в программе для обращения к данным порта А.
На языке С весь порт считывается или записывается, используя команду PORTA,
а отдельный бит считывается или записывается, используя команду вида
PORTAbits.RAO, которая считывает/записывает бит 0 порта А. Пример 6.7 показывает,
как записать значение 0x45 в порт А, ноль в бит 3 порта В и единицу в бит 5 порта В. При
этом принимается, что упомянутые порты определены как цифровые, а соответствую-
щие выводы запрограммированы на выполнение операции вывода данных. Данный
пример иллюстрирует также то, как нужно адресовать отдельные биты регистра TRIS
для программирования выводов порта на ввод (1) или вывод (0).
202
Применение микроконтроллеров PIC 18
Рис. 6.9. Внутренняя структура подключения выводов порта
Пример 6.7
TRISBbits.TR.ISB3 =0; //
TRISBbits.TRISB5 =0; //
PORTA = 0x45; //
PORTBbi.ts.RB3 =0; //
PORTBbits.RB5 =1; //
программирование RB3 как выхода
программирование RB5 как выхода
Порт А = 0x45
RB3 = 0
RB5 = 1
В табл. 6.4 перечислены все выводы порта А, а также их функции для микрокон-
троллера PIC18F1220. Другие версии микроконтроллеров могут иметь иные функции
выводов портов. По этой причине всегда необходимо обращаться к техническим дан-
ным микроконтроллера, выбранного для проекта. Кроме того, откройте файл .Ikr, чтобы
увидеть, какие имена регистров были определены для регистра TRISA (TRIS или DDR).
Многие выводы для ввода - вывода имеют две или три функции, выбранные при их про-
граммировании, как будет обсуждаться позже в этой главе. Вывод RA5 (общий сброс)
Глава 6. Спецификации аппаратных средств семейства PIC18
203
не может программироваться как вывод для вывода. Аналоговые входы используются
совместно с внутренним аналого-цифровым преобразователем, что также будет обсу-
ждаться позже в этой главе.
При сбросе микроконтроллера в некоторых версиях PIC18, биты 0...3 программи-
руются как аналоговые входы. Для программирования этих битов как цифровых входов,
регистр ADCON1 адресуется и программируется с установкой логической единицы для
каждого вывода порта А, который является цифровым входов, и нуля для каждого ана-
логового входа. По умолчанию выводы порта программируются как аналоговые входы,
потому, что регистр ADCON1 сбрасывается в ноль при сбросе. Самые правые семь би-
тов регистра ADCON1 идентифицируются программно как ANO-AN6. Некоторые из этих
аналоговых входов (ANO-AN3) находятся в порте А, а некоторые (AN4-AN6) - в порте В.
Чтобы сконфигурировать порт А как цифровой входной порт, в котором RAO-RA2 - бу-
дут входами, a RA3-RA4 - выходами, обратитесь к примеру 6.8. В данном случае прини-
мается, что MGtR разрешен и установлен режим генератора HS, в силу того, что OSC1,
так и OSC2 подключены к кварцевому резонатору.
Пример 6.8
ADCON1 = OxOf; // выводы портов А и В - цифровые
TRISA = 0x07; // биты 0-2 порта А - входы
// биты 3-4 порта А - выходы
Таблица 6.4. Функциональное назначение выводов порта А
Символ Позиция бита функция
RA0/AN0 0 Вывод ввода-вывода! аналоговый вход
RA1/AN1/LVDIN 1 Вывод ввода-вывода| аналоговый вход | вход распознавания низкого на-
пряжения
RA2/AN2/Vref- 2 Вывод ввода-вывода] аналоговый вход | Vref-
RA3/AN3/Vref+ 3 Вывод ввода-вывода] аналоговый вход | Vref+
RA4/T0CKI 4 Вывод ввода-вывода] вход внешней синхронизации таймера 0
RA5/MCLR //Vpp 5 Вывод ввода-вывода| общий сброс | программируемый вход напряжения
RA6/OSC2/CLKO 6 Вывод ввода-вывода| OSC2 | Вывод выхода тактововой частоты
RA7/OSC1/CLKI 7 Вывод ввода-вывода] OSC1 | Вывод входа синхронизации
Таблица 6.5. Функциональное назначение выводов порта В
Символ Позиция бита Функция
RB0/AN4/INT0 0 Вывод ввода-вывода | аналоговый вход| вход прерывания 0
RB1/AN5//INT1 1 Вывод ввода-вывода | аналоговый вход| вход прерывания 1
RB2/P1B/INT2 2 Вывод ввода-вывода | данные Р1В | вход прерывания 2
RB3/CCP1 3 Вывод ввода-вывода | регистрация/сравнение или выход ШИМ
RB4/AN6 4 Вывод ввода-вывода | аналоговый вход
RB5/PGM 5 Вывод ввода-вывода | программирование отдельного напряжения
RB6/PGC 6 Вывод ввода-вывода | синхронизация последовательного программирования
RB7/PGD 7 Вывод ввода-вывода [данные последовательного программирования
* Определения этих выводов изменяются в различных членах семейства
204
Применение микроконтроллеров PIC 18
Порт В
Порт В программируется тем же самым способом, что и порт А. Регистр TRISB
программирует направление переноса данных для битов порта В, регистр PORTB ис-
пользуется для того, чтобы считывать или записывать порт, а регистр LATB - для того,
чтобы считывать или записывать буферный регистр порта. Как уже упоминалось для
порта А, регистр ADCON1 программирует функционирование аналоговых и цифровых
выводов как для порта А, так и для порта В.
Функции выводов порта В (для PIC18F1220) перечислены в таблице 6.5. Как и в
случае порта А, выводы порта В имеют множественные функции. Не все версии микро-
схем имеют все перечисленные функции, в то же время некоторые из них имеют допол-
нительные функции. По мере рассмотрения каждой функции, множественность функ-
ций станет понятной. Выводы порта используются, прежде всего, как простые выводы
для цифрового ввода/вывода.
Слабые нагрузочные резисторы выбираются программированием бита регистра
INTCON2, который называется RBPU. Если в бит RBPU регистра INTCON2 помещен ло-
гический ноль в, то нагрузки для выводов порта В активируются. Эти нагрузки блокиру-
ются после сброса или же тогда, когда Вывод порта программируется как выходной.
Если слабые нагрузочные резисторы активированы, то микропроцессор подключает
вывод питания к 5 В через внутреннее сопротивление нагрузки. Это позволяет связы-
вать устройства ввода данных типа переключателей непосредственно с выводами пор-
та В без использования внешних нагрузочных резисторов. Это снижает общую стои-
мость системы ввиду сниженного количества компонент.
Пример 6.9 показывает, как можно активировать слабые нагрузочные резисторы
на языке С. Как и с другим программным обеспечением инициализации, соответст-
вующий программный код помещается в начале программы перед основным про-
граммным циклом.
Пример 6.9
INTCON2bits.RBPU =1; // активирование слабых нагрузок
Порты G, D, Ей другие
Многие члены семейства PIC18 имеют более двух портов ввода - вывода и могут
содержать порты С, D и Е. Эти дополнительные порты программируются тем же самым
способом, как порты А и В. Каждый порт имеет регистры TRIS, PORT и LAT для общего
цифрового программирования ввода - вывода. Как и с портами А и В, многие из выво-
дов дополнительных портов имеют более одного функционального назначения. В тех-
нических данных каждого конкретного члена семейства перечисляются множественные
функции каждого вывода для ввода - вывода. В общем случае, чем большее количество
выводов имеет корпус интегральной схемы, тем большее количество портов ввод - вы-
вод доступны для организации интерфейса.
Пример ввода - вывода
В этом подразделе описан полный пример, иллюстрирующий как аппаратные
средства, так и программное обеспечение, нацеленные на то, чтобы объединить вме-
сте материал, изложенный в этой и предшествующих главах. Это первый пример сис-
темы, которая уже может быть создана. Он демонстрирует, как разработать и запро-
граммировать простую систему электронной игры “выбрасывание костей", имеющую
Глава 6. Спецификации аппаратных средств семейства PIC18
205
кнопку и 14 светодиодов, отображающих пару костей. Это простая система с короткой
программой, написанной как на С, так и на Ассемблере с тем, чтобы выделить разли-
чия. Этот пример, использует микроконтроллер PIC18F1220 ввиду его невысокой стои-
мости ($2,78) и малого размера интегральной схемы (корпус PD1P с 18 выводами). На
рис. 6.10 показана принципиальная схема электронной игры “выбрасывание костей”.
На схеме указано напряжение питания, равное 5 В, однако в этой системе могут быть
использованы три последовательно соединенные батарейки типа АА батареи.
Эта схема использует RC-генератор, работающий на частоте около 2 МГц, что яв-
ляется достаточно для данного применения. Данное применение не имеет никаких кри-
тических временных функций, так что RC-генератор - это простейший метод получения
тактовой частоты, подходящий для данной системы. В этой системе используются две
кнопки, однако кнопку RESET (СБРОС) можно удалить, чтобы уменьшить стоимость
системы. Чтобы бросить кость, нажмите кнопку TOSS (Бросок); когда она будет отпу-
щена, отобразится произвольная пара лицевых поверхностей костей. Эта система бро-
сания костей может использоваться с любой игрой. Единственная аппаратная доработ-
ка может быть связана с подбором резисторов смещения светодиодов. Наиболее де-
шевые светодиоды требуют для своего свечения номинального тока в 10 мА и прямого
напряжения, равного 1,65 В. Так как PIC обеспечивает выходной ток (см. детали на пер-
вых нескольких страницах этой главы) равный 8,5 мА то между PIC и светодиодами до-
бавлен буферный каскад. Буферный каскад может быть удален, в этом случае яркость
свечения светодиодов уменьшится. В случае превышения значения 8,5 А, напряжение
на выводах снизится и может не достигать корректного ТТЛ-уровгщ напряжения. Хотя
выводы в этом примере не используются для передачи сигналов TTL, этот пример ог-
раничения уровней тока обеспечивает хороший практический опыт формирования ин-
терфейса.
Отдельный светодиод (LEDA) требует для своего смещения использования рези-
стора в 300 Ом. Прямое падение напряжения на светодиоде изменяется от 1,5 В до
2 В, хотя в спецификациях обычно указывается, что номинальным является 1,65 В. Для
расчетов примем, что на резисторе падает 3 В напряжения и 2 В падает на светодиоде,
когда выход буферного каскада становится логическим нулем. Вычисленное значение
будет равно (используя закон Ома R = U/I) 3 В/10 мА или 300 Ом. Резистор 100 Ом ис-
пользуется последовательно с парой светодиодов. Падение напряжения на резисторе
равно 1 В, при падении напряжения в 2 В на каждом светодиоде, что дает значение со-
противления в 100 Ом (1 В/10 мА).
Свечение светодиода обеспечивает логический 0 на соответствующем ему выво-
де. Буферный каскад выполнен на интегральном буфере 74LS244. Корректная битовая
структура подсвечивания светодиодов хранится данным приложением в поисковой
таблице в памяти программ. Чтобы сохранять данные в памяти программ, следует ис-
пользовать лексемы "rom" и "near" перед типом данных, в данном случае - это тип дан-
ных char. Лексема rom заставляет транслятор сохранять таблицу в памяти программ
(которая является статической), а лексема near заставляет транслятор использовать
16-разрядный ближний адрес, который должен использоваться в системах с количест-
вом памяти, меньшим, чем 64К памяти программ, потому что это более эффективно.
Если лексема near не используется, будет использоваться 24-разрядный адрес. Версия
соответствующей программы на языке С показана в примере 6.10. Эта программа ото-
бражает 36 комбинаций пар костей, которые сохранены в поисковой таблице. Для
сравнения пример 6.11 иллюстрирует версию этой же программы на языке Ассембле-
ра. Если эти версии сравнить, то очевидно, на написание которой уйдет меньше време-
ни. Обе версии используют, хотя в прикладной программе типа этой использование
WDT не является необходимым.
5V
О
DIE 1
DIE 2
TOSS
RESET
U1 PIC 18F1220 74LS244 1 О
U2 о
RAO §RBO RA1 > RB1 RA2 RB2 RA3 RB3 RA4 RB4 #MCLR RBS OSC1 WRB6 8 2 A1 U Y1 A2 > Y2 A3 Y3 A4 Y4 A5 Y5 A6 Y6 A7 Y7 A8 Y8 1QE § 2OE 0 18
9 4 16
17 6 14
18 8 12
10 11 9
11 13 - 7
12 16 5
13 17 3
VOL/Z Ю > ко/ 1 19
C4 x-1 r-'. C3
0.1 uF О 0.1 uF
Размещение светодиодов
Применение микроконтроллеров PIC18
Рис. 6.10. Пример системы электронной игры “выбрасывание костей
Глава 6. Спецификации аппаратных средств семейства PIC18
207
Пример 6.10
/*
* Пример программы бросания костей, написанный для PIC18F1220
*/
♦include < р18сххх. h >
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
♦pragma config OSC = RC
♦pragma config WDT = OM
♦pragma config WDTPS = 256
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = OM
II **************** данные в памяти программ ********************************
// поисковая таблица для костей
// 7 <0111>. = 1, Е <1110>. = 2, 6 <0110>. = 3,
// А <1010>. = 4, 2 ,<0010>. = 5, 8 <1000>. = 6
rom near char lookup[] = // все 36 комбинаций костей
{
0x77, 0х7Е, 0x76, И 1,1 1,2 1,3
0х7А, 0x72, 0x78, // 1,4 1,5 1, 6
0хЕ7, ОхЕЕ, ОхЕб, И 2, 1 2,2 2, 3
ОхЕА, 0хЕ2, 0хЕ8, // 2, 4 2,5 2, б
0x67, ОхбЕ, Охбб, // 3, 1 3,2 3,3
ОхбА, 0x62, 0x68, И 3,4 3, 5 3, 6
0хА7, ОхАЕ, ОхАб, И 4,1 4,2 4,3
ОхАА, 0хА2, 0хА8, И 4,4 4,5 4, 6
0x27, 0х2Е, 0x26, И 5,1 5,2 5, 3
0х2А, 0x22, 0x28, И 5, 4 5, 5 5, 6
0x87, 0х8Е, 0x86, И б, 1 6,2 б, 3
0х8А, 0x82, 0x88 И 6, 4 6,5 б, 6
И
данные в памяти данных **************************
int count; //случайное число
II ****************** главная программа ********************
void main (void)
{
И
// инициализация системы
и
ADCON1 = OxOF; //
TRISA = 0x01; //
TRISB =0; //
PORTB = OxFF; //
count =0; //
все выводы цифрового порта
Порт А, бит 0 является входомЦ
Порт В является выходом
все светодиоды выкл.
начать счет с нуля
208
Применение микроконтроллеров PIC 18
I/ *************** рабочий цикл системы************************************1
while (1) // единственный программный цикл
{
ClrWdt(); // сброс сторожевого таймера
if (PORTAbits.RAO == 0) // если TOSS =0
{
count++; // генерирование случайного числа
if (count ==3 6) // удерживание отсчета в диапазоне от 0 до
count = 0;
PORTB = lookup[count]; // отображение кода кости
}
}
}
Пример 6.11
/Пример программы бросания кости, написанный на языке Ассемблера
LIST P=18F1220, F=INHX32 /директива определения процессора и формата файла
♦include <P18F1220.INC>. /определение специфичных для процессора перемен-
ных / **********************************************************************
/Биты конфигурирования
__CONFIG _CONFIG1H, _IESO_OFF_1H & _FSCM_OFF_1H & _RC_OSC_1H
__CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_OFF_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_4_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H
__CONFIG _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVR_OFF_4L
__CONFIG _CONFIG5L, _CPO_OFF_5L & _CP1_OFF_5L
__CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
__CONFIG _CONFIG6L, _WRTO_OFF_6L & _WRT1_OFF_6L
__CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_^H & _WRTD_OFF_6H
__CONFIG _CONFIG7L, _EBTRO_OFF_7L & _EBTR1_OFF_7L
__CONFIG _CONFIG7H, _EBTRB_OFF_7H
/Определения для памяти данных
UDATA ACS
COUNT RES 1 /счетчик для случайного числа
/ Определения для памяти программ
/поисковая таблица
Look CODE_ PACK
Lookup: DB 0x77, 0x7E, 0x76 ; 1,1 1,2 1, 3
DB 0x7A, 0x72, 0x78 / 1,4 1,5 1, 6
DB 0xE7, OxEE, 0xE6 ; 2,1 2,2 2, 3
DB OxEA, 0xE2, 0xE8 ; 2,4 2,5 2, 6
DB 0x67, 0x6E, 0x66 ; 3,1 3,2 3, 3
DB 0x6A, 0x62, 0x68 ; 3,4 3, 5 3, 6
DB 0xA7, OxAE, 0xA6 ; 4,1 4,2 4, 3
DB OxAA, 0xA2, 0xA8 ; 4,4 4,5 4, 6
DB 0x27, 0x2E, 0x26 ; 5,1 5,2 5, 3
DB 0x2A, 0x22, 0x28 ; 5,4 5,5 5, 6
Глава 6. Спецификации аппаратных средств семейства PIC18
209
DB 0x87, 0х8Е, 0x86 / 6,1 6,2 6,3
DB 0х8А, 0x82, 0x88 ; 6,4 6,5 6,6
;Вектор сброса
; Этот код начнет выполняться после сброса.
RESET_VECTOR CODE 0x0000
goto Main ;переход на начало главной программы
CODE
/Начало главной программы
Main:
MOVLW MOVWF OxOF ADCON1 /все порты цифровые
MOVLW 0x01
MOVWF TRISA /порт А, бит 0 является входом
MOVLW 0
MOVWF TRISB /Порт В является выходом
CLRF PORTB /все светодиоды выкл.
CLRF COUNT ;сброс счетчика
MainLoop:
CLRWDT
;сброс сторожевого таймера
BTFSC PORTA,0 /проверка бита 0 порта А
BRA MainLoop /если бит 0 в единице
INCF COUNT /инкрементирование счетчика
MOVLW .36
SUBWF COUNT, 0
BNZ DoNotClear /если отсчет не равен 36
CLRF COUNT
DoNotClear:
MOVLW UPPER(Lookup) /получение адреса поисковой таблицы
MOVWF TBLPTRU
MOVLW HIGH(Lookup)
MOVWF TBLPTRH
MOVLW LOW(Lookup)
MOVWF TBLPTRL
MOVF COUNT,0 /добавление отсчета к адресу таблицы
ADDWF TBLPTRL
MOVLW 0
ADDWFC TBLPTRH
ADDWFC TBLRD* TBLPTRU /код поиска
MOVF TABLAT,0 /передача кода во WREG
MOVWF PORTB /отображение его
GOTO MainLoop
210
Применение микроконтроллеров PIC 18
/Завершение программы
END
Предположим, что схема (см. рис. 6.10) переработана с тем, чтобы использовать
все возможности, доступные в PIC18F1 с целью максимального уменьшения стоимости
системы. Одно изменение схемы должно уменьшить ток светодиодов до 8,5 мА и уда-
лить буферную микросхему. Другое изменение должно переместить переключатель
TOSS (Бросок) на Вывод порта В с тем, чтобы отпала необходимость в использовании
нагрузочного резистора. Выводы порта В имеют внутренние нагрузки, разработанные
для этих целей. Вместо RC-генератора может использоваться внутренний генератор,
чтобы устранить затраты на резистор и конденсатор. В заключение, кнопка СБРОСА
также может быть удалена. RC-контур в цепи сброса остается все же необходимым,
потому что природа источника питания неизвестна и может оказаться, что он не обес-
печит достаточно быстрое нарастание напряжения с тем, чтобы правильно сбросить
микроконтроллер. На рис. 6.11 приводится видоизмененная схема, а пример 6.12, ил-
люстрирует соответствующую версию программы на языке С. Для проведения назван-
ных изменений, потребовалось ввести только несколько строк программного кода.
Пример 6.12
/*
* Пример системы выбрасывания костей, написанный для PIC18F1220
*/
♦include <pl8cxxx.h>
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
♦pragma config OSC = INTI02
♦pragma config WDT = ON
♦pragma config WDTPS = 256
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
// данные в памяти программ
// поисковая таблица костей
//
// 7 <0111> = 1, Е <1110> = 2, б <0110> = 3
// А <1010> = 4, 2 <0010> = 5, 8 <1000> = б
И
rom near char lookup[] =
// все 36 комбинаций костей
0x77, 0х7Е, 0x76,
0х7А, 0x72, 0x78,
И 1,1 1,2 1,3
// 1,4 1,5 1,6
Глава 6. Спецификации аппаратных средств семейства PIC 18
211
0xE7, OxEE, 0xE6, // 2,1 2,2 2, 3
OxEA, 0xE2, 0xE8, // 2,4 2,5 2,6
0x67, 0x6E, 0x66, // 3,1 3,2 3, 3
0x6A, 0x62, 0x68, // 3,4 3,5 3, 6
0xA7, OxAE, 0xA6, // 4,1 4,2 4,3
OxAA, 0xA2, 0xA8, // 4,4 4,5 4,6
0x27, 0x2E, 0x26, // 5, 1 5,2 5, 3
0x2A, 0x22, 0x28, // 5, 4 5,5 5, 6
0x87, 0x8E, 0x86, // 6, 1 6,2 6, 3
0x8A, 0x82, 0x88 // 6, 4 6, 5 6, 6
// данные в памяти данных
int count;
//случайное число
// main program
void main (void)
//
// initialize system
// OSCCON = 0x64; // частота устанавливается на 4 мГц
ADCON1 = OxOF; // все выводы цифровых портов
TRISB = 0x01; // порт В, бит 0 - вход
TRISA = 0; // порт А - выход
PORTB = OxFO; PORTA = OxOF; // все светодиоды выкл
INTCON2bits.RBPU = 1; // нагрузки вкл. ____
count = 0; // начало счета с нуля
//
// цикл операционной системы
//
while (1) // единственный программный цикл
(
ClrWdt(); // сброс сторожевого таймера
if (PORTBbits.RB0 == 0) // если TOSS = 0
(
count++; // генерирование случайного числа
if (count == 36)
count = 0;
PORTA = lookup[count]; // получение кода кости
PORTB = lookup[count]; // получение кода кости
+ 5V
Рис. 6.11. Версия предыдущей схемы (см. рис. 6 1 0) с низкой себестоимостью
Применение микроконтроллеров PIC18
Глава 6. Спецификации аппаратных средств семейства PIC18
213
6.3. Введение в прерывания
Прерывания используются во многих прикладных программах для организации
почти всего, кроме самого простого, ввода - вывода. Семейство PIC18 имеет два базо-
вых уровня прерываний: низкоприоритетное прерывание, вектор которого расположен
в памяти программ по адресу 0x000018, и высокоприоритетное прерывание, вектор
которого расположен в памяти программ по адресу 0x000008. Приоритет прерывания
имеет значение только тогда, когда оба прерывания происходят одновременно и, в
таком случае, высокоприоритетное прерывание обслуживается или обрабатывается
первым. Высокоприоритетное прерывание будет всегда прерывать низкоприоритетное
прерывание.
Прерывание является либо аппаратным, либо программным событием, которое
инициализируется, когда обращение к функции прерывает выполняемую в настоящее
время программу. В силу того, что прерывание вызывает функцию, точка прерывания
помещается в программный стек, так что возврат возвратит управление к точке преры-
вания в конце функции обработки прерываний. Функцию, вызываемую прерыванием,
часто называют функцией обслуживания прерывания (ISF) или процедурой обслужива-
ния прерывания (ISP). В семействе PIC18 только две такие функции с непосредствен-
ным доступом могут фактически существовать в системе, потому что доступны только
два вектора прерывания. Вектор прерывания - это адрес процедуры обслуживания
прерывания. Как в случае низкоприоритетного, так и высокоприоритетного прерыва-
ния, процедура обслуживания прерывания определяет причину или источник прерыва-
ния, проверяя биты флагов прерываний, которые размещены в различных регистрах
управления прерываниями. Подобное тестирование флагов прерываний, часто назы-
вают опросом прерываний или пулингом. Опрос используется для того, чтобы распо-
ложить по приоритетам множественные прерывания, отсылая их либо на высокопри-
оритетный, либо на низкоприоритетный вектор прерывания.
Когда микроконтроллером обнаружено прерывание, соответствующий бит раз-
решения глобального прерывания очищается, блокируя тем самым прерывания равно-
го или более низкого уровня. Если произойдет высокоприоритетное прерывание, то'
никакое другое прерывание не будет возможным до тех пор, пока бит разрешения гло-
бального прерывания не будет установлен, что иногда может выполняться внутри про-
граммы обработки прерывания. Если происходит низкоприоритетное прерывание, эго
оно может быть прервано высокоприоритетным прерыванием. Биты управления пре-
рываниями размещены в регистре INTCON и регистре RCON, наряду с другими битами
управления, (см. рис. 6.12). Все версии микроконтроллеров PIC18 имеют регистры
INTCON и RCON (управление сбросом). Регистр управления сбросом указывает со-
стояние различных типов сбросов в системе, он также используется для того, чтобы
разрешать только высокоприоритетные прерывания (IPEN = 0) или высоко - и низко-
приоритетные прерывания (IPEN = 1). Этот регистр также проверяется с тем, чтобы
определить, какой сброс произошел, если программа должна определить тип сброса.
Типовое использование информации о сбросе заключается в определении того, явля-
ется ли перезапуск “холодным” или “горячим”. “Холодный” перезапуск связан с вклю-
чением напряжения питания системы, а “горячий” может инициализироваться сбросом
по сторожевому таймеру или сбросом по частичной потере питания.
214
Применение микроконтроллеров PIC 18
INTCON
£ д
GIE G1EH PEIE GIEL TMROIE INTOIE RBIE TMR0IF INTOIF RBIF
GIE/GIEH = О
GIE/GIEH = 1
PEIE/GIEL = 0
PEIE/GIEL = 1
TMROIE = 0
TMROIE = 1
INTOIE = 0
INTOIE = 1
RBIE=0
RBIE=I
TMROIF=0
TMROIF=1
INTOIF = 0
INTOIF = 1
RBIF=0
RBIF=1
IPEN=0
IPEN=1
LWRT=0
LWRT=1
R4-=0
Ri =1
TO =0
TO =1
PD=0
RD =1
POR =0
POR =1
BOR =0
BOR =1
Отключает все прерывания когда IPEN = 0; отключает высоко-
приоритетные прерывания, когда IPEN = 1
Разрешает все высокоприоритетные прерывания, когда IPEN = 1;
разрешает немаскированные прерывания, когда IPEN = 0
Отключает все прерывания? когда IPEN = 0; Отключает низко-
приоритетные прерывания когда IPEN = 1
Разрешает все низкоприоритетные прерывания, когда IPEN = 1;
Разрешает немаскированные прерывания, когда IPEN = 0
Отключает прерывания по переполнению таймера 0 Разрешает
прерывания по переполнению таймера 0
Отключает прерывания от вывода INTO
Разрешает прерывания от INTO
Отключает прерывания по изменению состояния порта В
Разрешает прерывания по изменению состояния порта В
Таймер 0 не переполнился
Таймер 0 переполнился (должен быть сброшен программно)
Прерывание от вывода INTO не происходило.
Прерывание от вывода INTO произошло (должно быть сброшено
программно)
Прерывание по изменению состояния выводов порта В не про-
изошло
Прерывание по изменению состояния выводов порта В произошло
(по крайней мере состояние одного из выводов RB4-RB7 измени-
лось)
Отключает приоритетные прерывания.
Разрешает приоритетные прерывания
Отключает табличную запись во внутреннюю память программы
Разрешает табличную запись во внутреннюю память программы
Команда RESET была выполнена (программное обеспечение должно
установить Ri после команды RESET)
Команда RESET не выполнялась
Таймаут WDT
Сброшен включением питания, CLRWDT или SLEEP
Выполнена команда SLEEP
Сброшен включением питания или CLRWDT
Сброшена сбросом по включению питания (должен быть установ-
лен программно после сброса по включению питания)
Сброс по включению питания не происходил
Произошел сброс по частичной потере питания (должен быть ус-
тановлен программно)
Сброс по частичной потере питания не происходил
Примечание: функциональное назначение бита LWRT может различаться в различных
версиях PIC18.
Рис. 6.12. Регистр управления сбросом и прерываниями (окончание)
Глава 6. Спецификации аппаратных средств семейства PIC18
215
Когда прерывание разрешено микроконтроллером, оно может происходить в лю-
бой точке программы. Из-за произвольного характера прерываний, все регистры, ис-
пользуемые процедурой обслуживания прерывания, должны быть предварительно со-
хранены, в противном случае любые их изменения в процедуре обслуживания преры-
вания изменит ход выполнения программы, которая была прервана. При использова-
нии Ассемблера это требует некоторой работы, на языке же С, большинство операций
по сохранению данных выполняется компилятором. (Точное сохранение состояния для
прерывания определено в конце файла .Ikr файла). Имеются, однако, случаи, когда
программа должна все же сохранять регистры и на языке С. Регистры, перечисленные
в табл. 6.6, сохраняются структурой обслуживания прерываний компилятора языка С. В
этой таблице не указан регистр произведения (PROD), потому что этот регистр не со-
храняется автоматически. Если процедура обслуживания прерывания использует ре-
гистр произведения или регистры таблиц, то они должны быть явным образом сохра-
нены, иначе процедура обслуживания прерывания изменит ход выполнения программ-
ного обеспечения. Примером этого может быть случай, когда прерывание происходит
после выполнения команды умножения, но прежде, чем регистры PRODL и PRODH бу-
дут сохранены. Если процедура обслуживания прерывания использует регистр PRODL
или PRODH, то соответствующие значения изменятся в программе, которая была пре-
рвана.
Таблица 6.6. Регистры, которые автоматически
сохраняются на языке С при прерывании
Ресурс Описание
PC WREG STATUS BSR FSRO FSR1 FSR2 Адресует команды Промежуточные переменные Биты условий Выбор банка памяти \ Указатель на память данных Указатель на стек данных Указатель фрейма
Пример 6.13 показывает, как сохранить регистр PROD или табличные регистры в
процедуре обслуживания прерывания. Процедура MyHighlnt сохраняет регистр PROD, а
процедура MyLowInt сохраняет регистры, используемые математической библиотекой.
Если функция, которая возвращает 16-разрядную переменную, вызывается из проце-
дуры обслуживания прерывания, то регистр PROD должен быть сохранен, а если функ-
ция возвращает 24-разрядную или 32-разрядную переменную, то секция "MATHJDATA"
должна быть сохранена. Если функция возвращает 8-разрядные данные или не воз-
вращает никаких данных, то никакие специальные действия по сохранению контекста
не требуются. Должны быть приложены все усилия для того, чтобы сделать процедуру
обслуживания прерывания такой короткой и простой, насколько это возможно. Обрати-
те внимание, что стандартная версия файла .Ikr уже сохраняет регистр PROD при пре-
рывании.
Пример 6.13
#pragma interrupt MyHighlnt save=PROD
#pragma interruptlow MyLowInt save=section("MATH_DATA")
#pragma interrupt Highint save=PROD, save=section("MATH_DATA")
216
Применение микроконтроллеров PIC 18
INTCON2
INTEDGO INTEDGI [NTEDG2 TMROIP RBIP
RBPU
RBPU=0 Нагрузки порта В заблокированы
RBPU =1 Нагрузки порта В разблокированы
INTEDGO = О INTO переключается по отрицательному перепаду
INTEDGO =1 INTO переключается по положительному перепаду
INTEDG1= О INT1 переключается по отрицательному перепаду
INTEDG1 = 1 INT1 переключается по положительному перепаду
INTEDG2 = О INT2 переключается по отрицательному перепаду
INTEDG2 =1 INT2 переключается по положительному перепаду
TMROIP = 0 Приоритет прерывания от таймера 0 = низкий
TMROIP = 1 Приоритет прерывания от таймера 0 = высокий
RBIP=0 Приоритет прерывания по изменению порта В = низкий
RBIP=1 Приоритет прерывания по изменению порта В = высокий
Рис. 6.13. Регистр INTCON2
Предположим, что счетчик (count) должен инкрементироваться в памяти каждый
раз, когда сигнал очень короткой длительности приходит на RBO (вход INTO). Этот сиг-
нал достаточно длинен, чтобы вызвать прерывание, но через несколько микросекунд,
он возвращается в состояние логической единицы, так что программное обеспечение
не всегда способно обнаружить этот сигнал. Вывод INTO представляет собой вход с
переключением по перепаду сигнала. Пока время нарастания сигнала достаточно для
распознавания микроконтроллером как перепад сигнала, будет происходить прерыва-
ние. Минимальная длительность импульса должна быть не менее 25 нс. Прерывание
используется для выполнения этой задачи в силу того, что система должна также быть
способна выполнять и другие задачи, помимо контроля сигнала, приложенного к RBO.
Пример 6.13 показывает программу на языке С, требуемую для того, чтобы инициали-
зировать вывод RBO как вход INTO, который вызывает высокоприоритетное прерыва-
ние. Обратите внимание на то, что вход INTO может вызывать только высокоприоритет-
ное прерывание. Рис. 6.13 показывает содержание регистра INTCON2, который выби-
рает уровень переключения по перепаду сигнала для вывода INTO.
Пример 6.14
ADCON1 = OxOF; // объявляет выводы порта цифровыми
TRISB = 1; // объявляет RBO входом
RCONbits.IPEN = 1; // IPEN = 1
INTCON2bits.INTEDGO = 0; // объявляет INTO переключаемым по отрицательному
перепаду
INTCONbits.INTOIE = 1; // активирует INTO
INTCONbits.GIEH = 1; // разрешает высокоприоритетные прерывания
// INTO сейчас подготовлен и активен
Глава 6. Спецификации аппаратных средств семейства PIC18
217
Пример 6.14 программирует RB0 порта В как входной Вывод порта и объявляет
Вывод INTO входом отрицательного сигнала прерывания. Последняя команда разреша-
ет прерывания таким образом, чтобы при появлении импульса на INTO происходило
высокоприоритетное прерывание. Как уже упоминалось, адрес вектора прерывания
для высокоприоритетного прерывания находится в ячейке памяти программ 0x0008.
Пример 6.15 показывает, как написать программу, которая использует высокоприори-
тетное прерывание. Он также демонстрирует определение низкоприоритетного преры-
вания. Первое, что присутствует в показанной программе - это прототип процедуры
обслуживания прерывания, за которым следуют два оператора псевдокомментария
#pragma, определяющих содержимое высокоприоритетного вектора прерывания как
прерывание. Как оператор #pragma interrupt MyHighlnt (идентифицирует MyHighlnt как
процедуру обслуживания прерывания), так и оператор #pragma code__high vector = 0x08
(идентифицирует расположение вектора прерывания) являются необходимыми. Опе-
ратор GOTO должен быть оператором Ассемблера внутри вектора. Остальная часть
программы довольно прямолинейна, за исключением того, что оператор #prama code
должен присутствовать перед программным кодом, который использует прерывания,
иначе компиляция не будет корректной. Кроме того, следует учесть, что только один
бит может быть изменен одновременно в регистре INTCON, иначе результаты будут
непредсказуемы.
Каждый раз, когда на входной Вывод INTO поступает отрицательный перепад сиг-
нала, вызывается функция обработки высокоприоритетных прерываний. Эта функция
имеет только две команды. Одна инкрементирует счетчик, который считает отрица-
тельные перепады входного сигнала, а вторая очищает запрос прерывания, размещен-
ный в бите INTOIF (флажок прерывания INTO) регистра INTCON (регистр управления
прерываниями). Если не очистить бит INTOIF, то никакие другие прерывания по INTO не
произойдут.
I
Пример 6.15
/*
* пример высокоприоритетного прерывания
*/
♦include <pl8cxxx.h.>
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
* /
♦ pragma config OSC = RC
♦ pragma config WDT = OFF
♦ pragma config LVP = OFF
♦ pragma config BOR = OFF
♦ pragma config MCLRE = ON
void MyHighlnt (void); // прототипы процедур обслуживания
void MyLowInt (void); // прерываний
♦ pragma interrupt MyHighlnt // MyHighlnt - это прерывание
♦ pragma code high_vector=0x08 // high_vector - это вектор по адресу 0x08
218
Применение микроконтроллеров PIC 18
<ИЯ
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
)
#pragma interruptlow MyLowInt // MyLowInt - это прерывание
((pragma code low_vector = 0x18 // low_vector - это вектор по адресу 0x18
void low_vector (void)
{
_asm GOTO MyLowInt _endasm
)
// данные в памяти данных
int count;
11 высокоприоритетное прерывание
((pragma code // этот оператор должен здесь присутство-
вать, иначе программа не будет корректно скомпилирована
void MyHighlnt (void)
{
count++;
INTCONbits.INTOIF = 0; // очистка флага INTOIF
)
void MyLowInt (void)
{
// обработка низкоприоритетного прерывания начинается здесь
)
// main program
void main (void)
{
ADCON1 = OxOF; //
TRISB =1; //
count =0; //
RCONbits.IPEN =0; //
//
INTCON2bits.INTEDG0 =0; //
//
INTCONbits.INT0IE = 1; //
INTCONbits.GIE =1; //
объявляет выводы порта цифровыми
объявляет RB0 входом
запуск счетчика с 0
IPEN = 0 (только высокоприоритетное
прерывание вкл.)
объявляет INTO переключаемым по
отрицательному перепаду сигнала
разрешает INTO
разрешает прерывания
// здесь выполняется дальнейшая инициализация
while (1)
{
// главный программный цикл
Глава 6. Спецификации аппаратных средств семейства PIC18
219
Существуют также другие регистры, помимо RCON, INTCON, и INTCON2, предна-
значенные для управления прерываниями микроконтроллера. Эти другие регистры
выбирают уровни приоритета и указывают состояние других прерываний в системе.
Рис. 6.14 иллюстрирует регистр управления номер три (INTCON3). Как и INTCON2, ре-
гистр INTCON3 содержит биты установки приоритета прерываний, биты разрешения
прерываний, а также биты состояния выводов для ввода прерываний.
Если в системе используется только один приоритет прерывания, то это проры-
вание должно быть высокоприоритетным. В этом случае GIEH бит часто помечается как
GIE (разрешение глобального прерывания), а бит GIEL игнорируется. Чтобы выбирать
один уровень приоритета для прерываний, поместите ноль в бит IPEN. Встречаются
случаи, когда желательно разрешать прерывания изнутри процедуры обработки пре-
рывания. Чтобы сделать это, устанавливайте бит GIEH или GIEL-бит в этой процедуре.
Предположим, что три входа прерывания связаны с INTO (непрограммируемый
вывод), INT1 и INT2. Все три прерывания установлены как высокоприоритетные. Все
они переключаются отрицательным перепадом входного сигнала. Программа объявле-
ния и активирования их показана в примере 6.16. Обратите внимание на то, как тести-
руются биты IF, с тем, чтобы направить программу на правильную процедуру обработки
прерываний для трех разных входных штырьков. В этой программе INTO имеет самый
высокий приоритет, a INT2 - самый низкий.
INTCON3
INT2IP INT11P INT2IE INT1IE INT2IF INT11F
INT2IP = 0 Приоритет вывода INT2 низкий
INT2IP = 1 Приоритет вывода INT2 высокий
INT1IP = 0 Приоритет вывода INT1 низкий
INT1IP = 1 Приоритет вывода INT1 высокий
INT2IE = 0 запрещает прерывание INT2
INT2IE = 1 разрешает прерывание INT2
INT1IE = 0 запрещает прерывание INT1
INT1IE = 1 разрешает прерывание INT1
INT2IF INT2IF = 0 = 1 INT2 не возникло INT2 возникло (должно быть сброшено программно)
INT1IF INT1IF = 0 = 1 INT1 не возникло INT1 возникло (должно быть сброшено программно)
Рис. 6.14. Регистр управления прерываниями номер три
Пример 6.16
/*
* приоритеты множественных прерываний
*/
♦include <pl8cxxx.h>.
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
» - Отключить низковольтное программирование
220
Применение микроконтроллеров PIC 18
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
#pragma config OSC = RC
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOR = OFF
#pragma config MCLRE = ON
void MyHighlnt (void)
# pragma interrupt MyHighlnt
# pragma code high_vector = 0x08
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
}
# pragma code
void Into (void)
{
INTCONbits.INTOIF =0; // сброс флага INTOIF
// здесь выполняется программа обслуживания INTO
}
void Inti (void)
{ '
INTCON3bits.INTIIF = 0; // сброс флага INT1IF
// здесь выполняется программа обслуживания INTI
}
void Int2 (void)
{
INTCON3bits.INT2IF = 0; // сброс флага INT2IF
// do INT2 software here
}
void MyHighlnt (void) // пудинг входов прерываний
{
if (INTCONbits.INTOIF == 1)
Int0(); // самое высокоприоритетное прерывание
else if (INTCON3bits.INT1IF == 1)
Intl(); //следующее по приоритету
else if (INTCON3bits.INT2IF == 1)
Int2(); // самое низкоприоритетное прерывание
}
11 главная программа
void main (void)
{
ADCON1 = OxOF; // объявление штырьков порта цифровыми
TRISB = 7; // объявление RBO, RB1 и RB2 входами
RCONbits.IPEN = 1;
// IPEN = 1
Глава 6. Спецификации аппаратных средств семейства PIC18
221
INTC0N2bits.INTEDGO = 0;
INTCON2bits.INTEDG1 = 0;
INTCON2bits.INTEDG2 = 0;
INTCON3bitS.INTIIP = 1;
INTCON3bits.INT2IP = 1;
INTCONbits.INTOIE = 1;
INTCON3bits.INTIIE = 1;
INTCON3bits.INT2IE = 1;
INTCONbits.GIEH = 1;
// объявление INTO переключаемым no
II отрицательному перепаду сигнала
II объявление INTI переключаемым
II по отрицательному перепаду сигнала
// объявление INT2 переключаемым
// по отрицательному перепаду сигнала
II объявление INT1 высокоприоритетным
II объявление INT2 высокоприоритетным
II разрешение INTO
II разрешение INT1
II разрешение INT2
// разрешение высокоприоритетных прерываний
// выполнение других операций инициализации
while (1)
{
// главный программный цикл
}
Каждое внутреннее периферийное устройство имеет три бита в трех разных ре-
гистрах, обеспечивающие управление работой каждого периферийного устройства в
структуре прерываний. Имеются регистры IPR, устанавливающие приоритеты преры-
ваний, регистры PIE, устанавливающие биты разрешения прерываний, а также регист-
ры PIR, содержащие биты флагов, которые проверяются с тем, чтобы определить, ка-
кой вход вызвал прерывание. Рис. 6.15...6.17 показывают все эти регистры и отражают
работу каждого бита управления/состояния.
Как можно видеть на этих трех рисунках, имеется много внутренних периферий-
ных устройств, которые могут быть использованы в системе, они включают таймеры,
аналого-цифровой преобразователь (АЦП), встроенный универсальный асинхрон-
но/синхронный приемник/передатчик (EUSART или USART) и т.д. Существует также
много других типов прерываний. Глава 8 посвящена обсуждению прерываний и их ис-
пользованию во встроенных системах.
Самый простой пример системы прерывания - это сигнализация. Этоу тип пре-
рывания является низкоприоритетным прерыванием. Подобное прерывание не случа-
ется часто и может ждать обслуживания. Электронная схема для этого типа прерывания
составляется из переключателей, помещенных на каждой двери и каждом окне. Ис-
пользуются переключатели типа SPST (однополюсные одноходовые), представляющие
собой датчики близости, обычно использующие магнитные ключи. Когда магнит распо-
ложен близко к переключателю, то последний замыкается, а при удалении магнита,
переключатель размыкается. Магнит установлен на двери или окне, а переключатель
установлен, например, на оконной раме.
222
Применение микроконтроллеров PIC 18
IPR1
PSPIP ADIP RCIP TXIP SSPIP ССР ИР TMR2IP TMRIIP
PSPIP прерывание чтения/записи ведомого параллельного порта (0 = низкий
приоритет, 1 = высокий приоритет)
ADIP прерывание АЦП(0 = низкий приоритет, 1 = высокий приоритет)
RCIP прерывание приема EUSART(0 = низкий приоритет,
1 = высокий приоритет)
TXIP » прерывание передачи EUSART(0 = низкий приоритет, 1 = высокий при-
оритет)
SSPIP = прерывание ведущего синхронного последовательного порта (0 = низ-
кий приоритет, 1 = высокий приоритет)
CCP1IP = прерывание ССР1 (0 = низкий приоритет, 1 = высокий приоритет)
TMR21P - прерывание соответствия таймера 2 PR2 (0 = низкий приоритет, 1 =
высокий приоритет)
TMR1IP = прерывание по переполнению таймера 1 (0 = низкий приоритет, 1 =
высокий приоритет)
IPR2
OSCFIP CMIP EEIP BCLIP HLVDIP TMR3IP ECCP1IP
OSCFIP =
CMIP -
EEIP
BCLIP =
HLVDIP =
TMR3IP =
ECCP1IP =
прерывание по сбою генератора (0 = низкий приоритет,
1 = высокий приоритет)
прерывание объявляет компаратора (0 = низкий приоритет, 1 = вы-
сокий приоритет)
прерывание по записи в ЭСППЗУ (0 = низкий приоритет,
1 = высокий приоритет)
прерывание по коллизии шины (0 = низкий приоритет,
1 = высокий приоритет)
прерывание обнаружения высокого/низкого напряжения (0 = низкий
приоритет, 1 = высокий приоритет)
прерывание по переполнению таймера 3 (0 = низкий приоритет, 1 =
высокий приоритет)
прерывание ССР1 (0 = низкий приоритет, 1 = высокий приоритет)
Рис. 6.15. Регистр IPR (начало)
Глава 6. Спецификации аппаратных средств семейства PIC18
223
IPR3
1RXIP WAKIP ERRIP TXB2IP TXBnlP ТХВПР TXBOIP RXB1IP RXBnIP RXBOIP FIFOWMIP
IRXIP
WAKIP
ERRIP
TXB2IP
TXBnlP
TXB1IP
TXBOIP
RXB1IP
RXBnIP
RXBOIP
FIFOWMIP
прерывание по неверному приему CAN (0 = низкий приоритет, 1 =
высокий приоритет)
прерывание по активированию шины CAN(0 = низкий приоритет, 1
высокий приоритет)
прерывание по ошибке шины CAN (0 = низкий приоритет,
1 = высокий приоритет)
прерывание буфера передачи 2, CAN, режим О
(О = низкий приоритет, 1 = высокий приоритет)
прерывание буфера передачи CAN, режим 0 или 1
(О = низкий приоритет, 1 = высокий приоритет)
прерывание буфера передачи 1 CAN (0 = низкий приоритет, 1 = вы-
сокий приоритет)
CAN transmit buffer 0 прерывание(0 = низкий приоритет, 1 = высо-
кий приоритет)
прерывание буфера приема CAN, режим 0 (0 = низкий приоритет, 1 =
высокий приоритет)
CAN receive buffer interrupt, mode 1 and 2 (0 = низкий
приоритет, 1 = high priorit]
прерывание буфера приема 0 CAN, режим 0 (0 = низкий приоритет, 1
= высокий приоритет)
прерывание по уровню FIFO, режимы 1 и 2 (0 = низкий приоритет, 1
= высокий приоритет)
Рис. 6.15. Регистр IPR (окончание)
\
PIE1
PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE
PSIE прерывание чтения/записи ведомого параллельного порта
(0 = низкий приоритет, 1 = высокий приоритет)
ADIE= прерывание АЦП(0 = низкий приоритет, 1 = высокий приоритет)
RCIE прерывание приема EUSART(0 = низкий приоритет,
1 = высокий приоритет)
TXIE прерывание передачи EUSART(0 = низкий приоритет,
1 = высокий приоритет)
SSPIE = прерывание ведущего синхронного последовательного порта (0 = низ-
кий приоритет, 1 ~ высокий приоритет)
ССР11Е= прерывание ССР1 (0 = низкий приоритет, 1 = высокий приоритет)
TMR2IE= прерывание соответствия таймера 2 PR2 (0 = низкий приоритет, 1 =
высокий приоритет)
TMR1IE = прерывание по переполнению таймера 1 (0 = низкий приоритет, 1 =
высокий приоритет)
Рис. 6.16. Регистры разрешения прерываний от периферийных устройств (начало)
224
Применение микроконтроллеров PIC 18
PIE2
OSCFIE CMIE EEIE BCLIE HLVDIE IMR3IE ECCP1IE
OSCFIE = прерывание по сбою генератора (0 = низкий приоритет,
1 = высокий приоритет)
CMIE прерывание от компаратора (0 = низкий приоритет,
1 = высокий приоритет)
EEIE прерывание по записи в ЭСППЗУ (0 = низкий приоритет,
1 = высокий приоритет)
BCLIE = прерывание по коллизии шины (0 = низкий приоритет,
1 = высокий приоритет)
HLVDIE= прерывание обнаружения высокого/низкого напряжения
(О = низкий приоритет, 1 = высокий приоритет)
TMR3IE = прерывание по переполнению таймера 3 (0 = низкий приоритет,
1 = высокий приоритет)
ЕССРИЕ= прерывание ССР1 (0 = низкий приоритет, 1 = высокий приоритет)
PIE3
IRXIE WAKIE ERRIE TXB2IE TXBnIE TXB11E TXBOIE RXB1IE RXBnIE RXBOIE FIFOWMIE
IRXIE
WAKIE
ERRIE
TXB2IE
TXBnIE
TXB1IE
TXBOIE
RXB1IE
RXBnIE
RXBOIE
FIFOWMIE =
прерывание по неверному приему CAN (0 = низкий приоритет, 1 =
высокий приоритет)
прерывание по активированию шины CAN(0 = низкий приоритет, 1 =
высокий приоритет)
прерывание по ошибке шины CAN (0 = низкий приоритет, 1 = высо-
кий приоритет) |
прерывание буфера передачи 2, CAN, режим 0 (0 = низкий приори-
тет, 1 = высокий приоритет)
прерывание буфера передачи CAN, режим 0 или 1 (0 = низкий при-
оритет, 1 = высокий приоритет)
прерывание буфера передачи 1 CAN (0 = низкий приоритет, 1 =
высокий приоритет)
CAN transmit buffer 0 прерывание(0 = низкий приоритет, 1 = вы-
сокий приоритет)
прерывание буфера приема CAN, режим 0 (0 = низкий приоритет, 1
= высокий приоритет)
CAN receive buffer interrupt, mode 1 and 2 (0 = низкий приори-
тет, 1 = high priorit]
прерывание буфера приема 0 CAN, режим 0 (0 = низкий приоритет,
1 = высокий приоритет)
прерывание по уровню FIFO, режимы 1 и 2 (0 = низкий приоритет,
1 = высокий приоритет)
Рис. 6.16. Регистры разрешения прерываний от периферийных устройств (окончание)
Глава 6. Спецификации аппаратных средств семейства PIC18
225
Электрическая схема для этой сигнальной системы приводится на рис. 6.18. Ко-
гда любой переключатель размыкается, он вызывает прерывание. Процедура функции
обработки прерывания заставляет срабатывать акустический сигнализатор. В данном
случае используются малые нагрузочные резисторы порта В с тем, чтобы подключить
входной вывод RB2 порта В к 5 В, так что, когда переключатель разомкнутый, вывод
RB2 подсоединяется к 5 В. Вход RB2 программируется как вход INT2 для микрокон-
троллера PIC18F1220, как показано на данном рисунке. Вывод RB4 программируется
как выход, чтобы включать акустический сигнализатор. Кнопка SW6, связанная с выво-
дом RB5, служит для выключения акустический сигнализатор. Единственный способ
выключить акустический сигнализатор состоит в том, чтобы отключить его электропи-
тание или нажать кнопку сброса тревоги, которая может быть где-либо скрыта, или же
это может быть ключ. Вся соответствующая программа показана в примере 6.17. Эта
тревожная система может быть включена в любое иное микроконтроллерное приложе-
ние при минимальных трудозатратах.
В этой системе, как только прерывания будут разрешены, программа остается в
бесконечном цикле while. Единственное, что происходит в цикле так это проверка со-
стояния кнопки, связанной с RB5, с тем, чтобы отключить тревожную сигнализацию.
Однако как после этого включается тревожный сигнал? Тревожный сигнал включается,
когда происходит прерывание и разрывается основной цикл программы. Это прерыва-
ние включает тревожный сигнал. В конце процедуры функции обработки прерывания,
управление возвращается обратно основному циклу программы, где тревожный сигнал
может быть выключен, если кнопка нажата. Сторожевой таймер также используется,
потому что это не было бы хорошей идеей - иметь программу тревожной сигнализации,
которая могла бы зависнуть на неопределенное время в результате случайной ошибки.
PIR1
PSPIF ADIF RCIF TX1F SSPIF ССР 1 IF г TMR2IF TMR1IF
PSPIF- прерывание чтения/записи ведомого параллельного порта (0 = низ-
кий приоритет, 1 = высокий приоритет)
ADIF = прерывание АЦП(0 = низкий приоритет, 1 = высокий приоритет)
RCIF= прерывание приема EUSART(0 = низкий приоритет, 1 = высокий при-
оритет) -
TXIF= прерывание передачи EUSART(0 = низкий приоритет, 1 = высокий
приоритет)
SSPIF = прерывание ведущего синхронного последовательного порта
(О = низкий приоритет, 1 = высокий приоритет)
CCP1IF = прерывание ССР1 (0 = низкий приоритет, 1 = высокий приоритет)
TMR2IF = прерывание соответствия таймера 2 PR2 (0 = низкий приоритет,
1 = высокий приоритет)
TMR1IF = прерывание по переполнению таймера 1 (0 = низкий приоритет,
1 = высокий приоритет)
Рис. 6.17. Регистры флагов запроса прерываний
от периферийных устройств (начало)
226
Применение микроконтроллеров PIC 18
PTR2
OSCFIF CMIF EEIF BCLIF HLVDIF TMR3IF ECCP1IF
OSCFIF =
CMIF =
EEIF =
BCLIF =
HLVDIF =
TMR3IF =
ECCP1IF =
IRXIF =
WAKIF =
ERRIF =
TXB2IF = l
TXBnIF =
TXB1IF =
TXBOIF =
RXB1IF =
RXBnIF =
RXBOIF =
FIFOWMIF =
прерывание по сбою генератора (0 = низкий приоритет, 1 = высокий
приоритет)
прерывание от компаратора (0 = низкий приоритет, 1 = высокий
приоритет)
прерывание по записи в ЭСППЗУ (0 = низкий приоритет, 1 = высокий
приоритет)
прерывание по коллизии шины (0 = низкий приоритет, 1 = высокий
приоритет)
прерывание обнаружения высокого/низкого напряжения(0 = низкий
приоритет, 1 = высокий приоритет)
прерывание по переполнению таймера 3 (0 = низкий приоритет,
1 = высокий приоритет)
прерывание ССР1 (0 = низкий приоритет, 1 = высокий приоритет)
PIR3
IRXIF WAKIF ERRIF TXB2IF TXBnIF TXB11F TXBOIF RXBIIF RXBnIF RXBOIF FIFOWMIF
прерывание по неверному приему CAN (0 = низкий приоритет,
1 = высокий приоритет)
прерывание по активированию шины CAN(0 = низкий приоритет,
1 = высокий приоритет)
прерывание по ошибке шины CAN (0 = низкий приоритет,
1 = высокий приоритет)
прерывание буфера передачи 2, CAN, режйм 0 ...
(О = низкий приоритет, 1 = высокий приоритет)
прерывание буфера передачи CAN, режим 0 или 1
(О = низкий приоритет, 1 = высокий приоритет)
прерывание буфера передачи 1 CAN (0 = низкий приоритет,
1 = высокий приоритет)
прерывание буфера передачи О CAN (0 = низкий приоритет,
1 = высокий приоритет)
прерывание буфера приема CAN, режим 0 (0 = низкий приоритет,
1 = высокий приоритет)
прерывание буфера приема CAN, режимы 1 и 2 (0 = низкий приори-
тет, 1 = высокий приоритет)
прерывание буфера приема О CAN, режим 0 (0 = низкий приоритет,
1 = высокий приоритет)
прерывание по уровню FIFO, режимы 1 и 2 (0 = низкий приоритет,
1 = высокий приоритет)
Рис. 6.17. Регистры флагов запроса прерываний
от периферийных устройств (окончание)
Глава 6. Спецификации аппаратных средств семейства PIC18
227
Пример 6.17
/*
* Прерывание от сторожевой системы
*/
♦include <pl8cxxx.h.>
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
♦pragma config OSC = RC
#pragma config WDT = ON
#pragma config WDTPS = 4
#pragma config LVP = OFF
#pragma config BOR = OFF
#pragma config MCLRE = ON
void MyHighlnt (void) ;
void MyLowInt (void) ;
#pragma interrupt MyHighlnt
#pragma code high_vector=0x08
void high_vector (void)
(
_asm GOTO MyHighlnt _endasm
) -
#pragma interruptlow MyLowInt // MyLowInt - это прерывание
#pragma code low_vector=0xl8 // low_vector - это вектор по адресу 0x18
void low_vector (void)
(
_asm GOTO MyLowInt _endasm
)
♦pragma code
void MyHighlnt (void) ,
{
)
void MyLowInt (void)
{
if (INTCON3bits.INT2IF == 1) // это Вывод INT2 ?
{
INTCON3bits.INT2IF = 0; // сброс флага INT2IF
PORTBbits.RB4 =1; // включение тревоги
)
I
'/ main program
void main (void)
228
Применение микроконтроллеров PIC 18
ADCON1 = OxOF; TRISB = 0x24; // объявляет выводы порта цифровыми // объявляет RB2 и RB5 входами // объявляет RB4 выходом
PORTB = 0x00; // тревога выкл
INTCON2bits.RBPU = 1; RCONbits.IPEN = 1; // вкл. Нагрузок порта В // IPEN = 1
INTCON2bits.INTEDG2 = 1; // объявляет INT2 переключаемым по // положительному перепаду сигнала
INTCON3bits.INT2IP = 0; // объявляет INT2 низкоприоритетным
INTCON3bits.INT2IE = 1; INTCONbits.GIEH = 1; INTCONbits.GIEL = 1; while (1) { ClrWdt(); // разрешает INT2 // разрешает высокоприоритетные // прерывания // разрешает низкоприоритетные // прерывания // главный программный цикл // настройка тона (низкий/высокий)
if (PORTBbits.RB5 == 0) // кнопка нажата
PORTBbits.RB4 = 0; 1 +5V 0 // тревога выкл
С2
1.0 uF
PIC18F1220
U1
SW1
8
9
17
Окно 1
°r во
RAO дпои
RA1 >RB1
RA2
RA3
---RA4
#MCLR
OSC1 S2RB6
OSC2 >RB7
____2
____6_
____7_
____3
Jfi.
15
RB2
RB3
RB4
RB5
18
10
Передняя
дверь
SW7
ARM
SW5
-o4"Vo-
Окно 4
SW3
Окно 3
Тревога выкл.
Рис. 6.18. Простая работающая по прерываниям
сторожевая система во взведенном состоянии
Глава 6. Спецификации аппаратных средств семейства PIC18
229
6.4. Другие внутренние периферийные устройства
Семейство PIC18 имеет много внутренних периферийных устройств, от таймеров
для синхронизации событий до многоканального АЦП для осуществления выборки ана-
логовых сигналов. Ввиду значительного числа внутренних периферийных устройств,
некоторые из них представляются в этом подразделе, а затем описываются и исполь-
зуется в прикладных программах в последующих главах. В этой книге фактически все
внутренние периферийные устройства, в конечном счете, используются в прикладных
программах.
Таймеры
Микроконтроллер содержит четыре или пять таймеров, которые используются
для решения различных задач. Некоторые из этих задач включают предварительное
масштабирование сигналов тактовой частоты, генерирование сигналов множественных
частот, инициализацию прерывания в специфицированное время и т.д. Этот подраздел
представляет таймер 1 наряду с его прерыванием, чтобы проиллюстрировать исполь-
зование таймера реального времени (RTC). Данное приложение иллюстрирует полез-
ность таймера. Это только один из внутренних таймеров, другие три или четыре тай-
мера также доступны для решения дополнительных задач.
Таймер 1 - это 16-разрядный таймер, который функционирует в трех режимах. На
рис. 6.19 показана внутренняя структура таймера 1. Таймер 1 может работать как тай-
мер, синхронный счетчик или как асинхронный счетчик. Таймер - это счетчик, рабо-
тающий от внутренней тактовой частоты командного цикла или от внешнего входа так-
товой частоты. По каждому командному циклу или периоду внешней тактовой частоты
таймер инкрементируется, и, если он переполнится и сбросится в ноль, то будет ини-
циализирован цикл прерывания. Например, предположим, что входная тактовая часто-
та микроконтроллера равна 4 МГц, сигналы которой заставляют таймер инкрементиро-
ваться один раз каждую микросекунду, потому что тактовая частота почти всегда де-
лится на четыре (командная тактовая частота) для большинства внутренних модулей.
Восьмиразрядный таймер считает от 0x00 до OxFF, а затем сбрасывается в ноль и начи-
нает считать снова от нуля. При входной тактовой частоте микроконтроллера, равной
4 МГц, будут генерироваться прерывание один раз каждые 256 мс. Синхронный счетчик
- это счетчик, который считает нарастающие фронты сигнала внешнего входа тактовой
частоты, приложенного к выводу T1OSI (RB7). Асинхронный счетчик - это счетчик, кото-
рый также работает с внешним входом, однако его внутренний счетчик не синхронизи-
рован с тактовой частотой микроконтроллера. В асинхронном режиме таймер не может
использоваться в операциях сравнения или сбора данных. ,
230
Применение микроконтроллеров PIC 18
ССРтриггер - >5, У V
Рис. 6.19. Внутренняя структура таймера 1
Предположим, что нам нужен таймер реального времени (RTC). Таймер реально-
го времени считает время в секундах, минутах и часах; он хранит реальное время дня,
как и подразумевает его наименование. RTC также используется для отработки вре-
менных задержек. RTC может работать от внешнего кварцевого генератора, связанного
со входом тактовой частоты таймера 1, или от внешнего кварцевого генератора, ис-
пользуемого для синхронизации работы микроконтроллера.
Однако, прежде чем написать соответствующую прикладную программу, необхо-
димо изучить регистр управления таймера 1. Рис. 6.20 иллюстрирует содержимое ре-
гистра управления таймера 1. Чтобы использовать таймер 1, регистр управления тай-
мера 1 (T1CON) и регистры управления прерываниями используется в этом примере
программы для организации таймера реального времени. Бит RD16 выбирает, будут ли
считываться и записываться все 16 битов счетчика сразу, или же каждая 8-разрядная
половина счетчика будет считываться или записываться отдельно. При одновременном
считывании или записи всех битов (RD = 1), старшая часть отсчета выводится первой и
сохраняется внутри микроконтроллера до тех пор, пока младшая часть отсчета не будет
записана при обновлении обеих половин отсчета таймера.
Глава 6. Спецификации аппаратных средств семейства PIC18
231
T1C0N
RD 16 T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON
RD 16 режим 16-разрядного считывания/записи
1 =считывание/запись 16 разрядов
О = считывание/запись по 8 разрядов
T1CKPS1
T1CKPS2
T10SCEN
T1SYNC
TMR1CS
TMR10N
т 00 = 4-1; 01 =4-2;
J 10 = 4-4и И = 4-8
би г активирования генератора
1 = активирован
0 == заблокирован
Синхронизация таймера 1
1 = стинхронизации нет
0 = синхронизация по внешнему тактовому входу
Источник синхронизации таймера 1
1 = внешняя синхронизация
0 = внутренняя синхронизация
бит включения таймера 1
1 = таймер 1 вкл.
0 = таймер 1 выкл. (остановлен)
Рис. 6.20. Регистр управления таймера 1
В таком применении использует типовой (часовой) кварцевый резонатор на час-
тоту 32,768 кГц, Этот кварцевый резонатор подключен к выводам таймера 1 (T1OSO и
Т10SI), см. рис. 6.21. Обратите внимание на то, что эта система содержит два источни-
ка тактовой частоты. Основная тактовая частота в 2 МГц, которая синхронизует выпол-
нение команд, формируется RC-генератором и подается на входной Вывод OSC1. Дру-
-ой источник тактовой частоты - это кварцевый генератор, связанный со выводами RB6
л RB7. Вывод RB6 - это T1OSO (выход генератора Т1), а вывод RB7 - это T1OSI (вход
'енератора Т1). Отсчет, равный 32768 или 0x8000 вызывает прерывание через одну
зекунду, если таймер программируется так, чтобы начинать считать с этого значения.
Зчетчик таймера 1 является 16-разрядным, поэтому для того, чтобы он вызывал преры-
вание один раз в секунду, он должен предварительно загружаться значением 0x8000.
Запрограммированный таким образом таймер потребует 32768 периодов входной час-
'оты для того, чтобы вызвать прерывание по переполнению один раз в секунду. В при-
мере 6.18 приведена программа на языке С, которая поддерживает 24-часовый отсчет
"аймера в доступных ячейках памяти, сохраняя секунды, минуты и часы.
232
Применение микроконтроллеров PIC 18
Рис. 6.21. Схема таймера реального времени
Пример 6.18
/*
* Таймер реального времени (RTC) для PIC18F1220
*/
#include <pl8cxxx.h>.
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
#pragma config OSC = RC
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOR = OFF
#pragma config MCLRE = ON
/! * *********** прототипы функций обработки прерываний ***********************
void MyHighlnt (void);
Глава 6. Спецификации аппаратных средств семейства PIC18
233
♦pragma interrupt MyHighlnt
♦pragma code high_vector = 0x08
************ вектор высокоприоритетного прерывания
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
)
II 4, * 4,4,4, * 4,4,4,4,4, память данных**************************************************
// счетчики времени дня
♦pragma udata access IntMyData
// размещение в банке доступа
near char seconds;
near char minutes;
near char hours;
//секунды
// минуты
// часы
II * * * 4, 4, 4, * * * * * * 4, 4, функЦИИ* ****************************************************
♦pragma code
// функция инкрементирования таймера
void { DoTime (void) // формирование сигнала счета каждую секунду
TMR1H = 0x80; PIRlbitS.TMR1IF = 0; seconds++; if (seconds == 60) { seconds = 0; minutes++; if (minutes == 60) { minutes = 0; hours++; if (hours == 24) hours = 0; } ) } // процедура обслуживания прерывания // // // // // и // // // // // предзагрузка таймера 1 значением 0x8000 TIMR1L уже 0x00 сброс прерывания от таймера 1 инкрементирование секунд если секунды достигли 60 сброс секунд в ноль инкрементирование минут если минуты достигли 60 60 сброс минут! инкрементирование часов если часы достигли 24 // сброс часов
void { MyHighlnt (void) // if (PIRlbitS.TMR1IF == 1) DoTime(); контекст сохраняется компилятором
// здесь тестируются другие флаги прерываний
}
//главная программа
234
Применение микроконтроллеров PIC 18
void main (void)
{
ADCON1 = OxOf; // программирование цифровых штырьков
TRISA = OxFF; // порт А - вход
RCONbits .IPEN = 1; // IPEN = 1
TMR1L = TMR1H = 0; 0x80; // предзагрузка таймера 1 0x8000
T1CON = OxOF; // выбор внешней синхронизации
// и активирование таймера 1
seconds = minutes = hours = 0; // начало счета с полудня
IPRlbits .TMR1IP = 1; // объявляет таймер 1 высокоприоритетным
PIElbits .TMR1IE = 1; // разрешает прерывание таймера 1
INTCONbi ts.GIEH = 1; // разрешение высокоприоритетных прерываний
' while (1) ' ‘ .....
{
// выполнение других необходимых операций
}
)
Каждый раз по истечении секунды, таймер 1 инициализирует прерывание, вызы-
вая функцию DoTime в процедуре функции обслуживания высокоприоритетного преры-
вания. В DoTime, таймер 1 перезагружается 0x8000, флаг прерывания таймера 1 сбра-
сывается и RTC инкрементируется. При каждом прерывании счетчик секунд инкремен-
тируется, один раз в минуту инкрементируется счетчик минут и один раз в час инкре-
ментируется счетчик часов. Приведенная программа довольно проста и хранит время
так, как если бы оно сохранялось дискретными счетчиками. Точность определяется
частотой кварцевого генератора, она обычно лежит в пределах +/-0,005%, что означает
погрешность несколько секунд в месяц.
Единственная небольшая проблема с этим таймером состоит в том, что необходима
функция, считывающая содержимое таймера и преобразующая его в последовательность
символов ASCII для отображения. Пример 6.19 иллюстрирует функцию, которая получает
время в 24-часовом или 12-часовом формате и сохраняет последовательность символов в
памяти в переменной timestring как последовательность символов С-стиля, в которой в каче-
стве разделителя используется символ нуля. Эта функция вызывается всякий раз, когда
время в этом формате необходимо подать на индикатор. Время сохраняется как 22:12:01 для
24-часового формата или как 10:12:01 РМ (пополудни) в 12-часовом формате. Параметр
режима выбирает формат 24/12, когда вызывается функция getTimeString. Если парамо гр
режима равен 1, го возвращается 12-часовый формат.
Обратите внимание, как ASCII- код создается добавлением 0x30 к значениям, по-
лученным для переменных часов, минут и секунд после деления их на 10 или по модулю
10. Если число часов равно 12 и оно делится на 10, то результатом будет 1, который не
соответствует ASCII-коду. После добавления 0x30 к 1 результатом будет 0x31, коюрый
является ASCII-кодом "1". Если 12 делится с использованием деления по модулю (%),
возвращается остаток 2.2 также преобразуется в ASCII-код посредством добавления
0x30. Аналогичным образом, операция включающего ИЛИ (|) может использоваться
для преобразования в код ASCII.
Глава 6. Спецификации аппаратных средств семейства PIC18
235
Пример 6.19
#pragma udata // выбор памяти данных
char timeString[12]; // строка времени
#pragma code
void getTimeString (char mode)
char ptr = 0; // указатель на элемент массива 0
char tempHours = hours;
char amPM = 'A';
if (mode == 1) // 12-часовый режим
{
if (hours .=12) // преобразование в 12-часовый формат
{
tempHours -= 12;
amPM = 'P';
}
if (tempHours == 0)
tempHours = 12;
}
if ((tempHours / 10) == 0) // чистый предшествующий ноль
timeString[ptr++] = ' ';
else
timeString[ptr++] = tempHours / 10 + 0x30;
timeString[ptr++] = tempHours 10 + 0x30;
timeString[ptr++] =
timeString[ptr++] = minutes / 10 + 0x30;
timeString[ptr++] = minutes Q, О 10 + 0x30;
timeString[ptr++] =
timeString[ptr++] = seconds / 10 + 0x30;
timeString[ptr++] = seconds *0 10 + 0x30;
if (mode == 1) // 12-часовый режим
timeString[ptr++] = ' ; 1
timeString[ptr++] = amPM;
timeString[ptr++] = 'M';
)
timeString[ptr] = 0;
// завершение строки символом нуля
Альтернативный метод обработки времени суток состоит в том, чтобы использо-
вать один 24-разрядный счетчик в памяти, который содержал бы часы, минуты, и се-
кунды. В дне имеется 86400 (60 * 60 * 24) секунд. Это число легко вписывается в 24-
разрядное целое число формата short long (короткий длинный формат). Это уменьшает
количество времени, затрачиваемого в процедуре функции обслуживания прерывания,
хотя сложность извлечения значения времени немного более трудна. Пример 6.20 ил-
люстрирует процедуру функции обслуживания прерывания с этим типом счетчика.
S
236 Применение микроконтроллеров PIC 18 j
(Операционная система Windows использует эту методику для RTC, однако в ней ис-
пользуется 64-разрядная переменная, которая отсчитывает миллисекунды от 100 до
9999). Пример 6.21 показывает функцию getTimeString для этого типа таймера. Здесь
часы получаются делением времени на 3600. Минуты получаются принимая остаток от
времени, разделенного 3600 и деля его на 60. Секунды получаются, беря остаток от
времени, разделенного на 3600, а затем разделенный на 60.
Метод, используемый для RTC, зависит от того, как RTC используется в других
функциях программы. Если RTC используется для организации точных временных за-
держек, то первый описанный метод будет самым лучшим. Если он просто использует-
ся для счета времени дня, то второй метод будет самым лучшим. Хороший пример
формирования точных временных задержек приведен в приложении D для USB-
активируемой системы, которая поддерживает точные временные задержки с шагом в
1 миллисекунду для системы реального времени.
Пример 6.20
#pragma udata access IntMyData // помещает в банк доступа
near short long time; // 24-разрядный счетчик
#pragma udata
char timeString[12]; // строка времени
#pragma code
// новая процедура обслуживания прерывания для RTC
void DoTime (void)
{
TMR1H = 0x80; PIRlbitS.TMR1IF = 0; time++; if (time == 86400) time = 0; } . Пример 6.21 void getTimeString (char mode) { char ptr = 0; char hours = time / 3600; char amPM = 'A'; char minutes = (time % 3600) char seconds = (time % 3600) if (mode == 1) { if (hours .= 12) { hours -= 12; amPM = 'P' ; // предзагрузка таймера 1 значением 0x8000 // сброс прерывания таймера 1 // если новый день // указатель на элемент массива // получение часов /60; // получение минут % 60; // получение секунд // 12-часовый режим // преобразование в 12-часовой формат
Глава 6. Спецификации аппаратных средств семейства PIC18
237
}
if (hours == 0)
hours ~ 12;
)
if ( (hours I 10) == 0)
timestring[ptr++] = '
else
timeString[ptr++] = hours I 10 | 0x30;
timestring[ptr++] = hours % 10 I 0x30;
timestring[ptr++] =
timestring[ptr++] = minutes / 10 I 0x30;
timestring[ptr++] = minutes % 10 | 0x30;
timestring[ptr++] =
timestring[ptr++] = seconds / 10 | 0x30;
timestring[ptr++] = seconds % 10 I 0x30;
if (mode == 1) // 12-часовый режим
{
timeString[ptr++] = ' ';
timestring[ptr++] = amPM;
timestring[ptr++] = 'M';
}
timestring[ptr] = 0;
Остальные таймеры, наряду с многими другими прикладными программами, ил-
люстрируются в последующих разделах. Некоторые из этих других приложений ис-
пользуют прерывания, другие - нет. Для определения таймеров может использоваться
файл заголовка Timers.h. Примеры из библиотеки timers.h приводятся в более поздних
разделах этой главы, в других главах данной книги, а также в приложении В.
АЦП
Другим внутренним периферийным устройством является аналого-цифровой
преобразователь (АЦП). АЦП преобразует аналоговое входное напряжение в число.
Большинство членов семейства PIC18 содержит 10-разрядный преобразователь, кото-
рый преобразовывает аналоговый вход в цифровое значений с разрешением, равным
(Vref+ - Vref- )/1023. Если Vref + равно - 5 V, a Vref- это земля, то значение шага напря-
жения будет равно (5/1023)*0,00489 В. Следовательно, если входное напряжение рав-
но 1,0 В, то преобразователь сгенерирует цифровой выход 1,0 В/0.00489 В или 205
десятичное. Преобразователь также имеет до 16 входов, в зависимости от исполнения
члена семейства. Эти входы используются для того, чтобы контролировать напряжения
от разных источников. Имеется также два бита управления, которые выбирают источ-
ник для входа Vref преобразователя. Внутренняя структура АЦП показана на рис. 6.22.
Обратите внимание, что несколько членов семейства содержат 12-разрядный преобра-
зователь, который использует ту же самую описанную здесь методику, за исключением
шага напряжения, который определяется делением на 4095 (212-1) вместо 1023 (210-1).
238
Применение микроконтроллеров PIC 18
CHS3—CHSO
CHS3—CHSO Выбор входного сигнала
VCFG1—VCFG0 Выбор источника опорного напряжения
00 = AVDD, AVSS
01 = Vref+, AVSS
10 = Vref- AVDD
11= Vref+, Vref-
Рис. 6.22. 16-канальный 10-разрядный АЦП
_>
Три регистра управления (ADCONO, ADCON1 и ADCON2) определяют работу АЦП. Р<
гистр ADCON1 определяет, будут ли входные выводы порта А и В функционировать как цис]
ровые или как аналоговые входы. Регистры управления АЦП показаны на рис. 6.23.
Чтобы проиллюстрировать простое применение АЦП, предположим, что нам нужно ко
тролировать подачу напряжения в 3,3 В источнике электропитания ПК. PIC может выполнить э
задачу при использовании одного из входов АЦП. Предположим, что схема, изображенная i
рис. 6.24, используется для контроля напряжения электропитания. Эта схема использует bhcl
ний кварцевый генератор на 4 МГц и только один вход ANO (RA0) для контроля напряжение.
Глава 6. Спецификации аппаратных средств семейства PIC18
239
Программа, требуемая для измерения напряжения, заключена в функции getVoltage(),
которая возвращает значение напряжения на AN0 в формате с плавающей запятой. Также в
пример 6.22 включена программа, требуемая для программирования штырька AN0, потому
что опрос аналогового входа размещен в начале функции main.
ADCONO
CHS3 CHS2 CHSI CHSO GO/DONE ADON
CHS3—CHSO
GO/DONE
ADON
Select the input channel as depicted in Figure 6-19
ADC status bit (0 = busy converting, 1 = done)
ADC on bit (0 = disabled, 1 = enabled)
ADCON1
VCFG1 VCFGO PCFG3 PCFG2 PCFG1 PCFGO
VCFG1—VCFGO Select the voltage reference as depicted in Figure 6-19
PCFG3—PCFGO Select the digital/analog input pins (see table)
PCFGn AN15 AN14 AN13 AN12 AN11 AN10 AN9 AN8 AN7 AN6 AN5 AN4 AN3 AN2 AN1 ANO
0000 A A A A A A A A A A A A A A A A
0001 D D A A A A A A A A A A A A A A
0010 D D D A A A A A A A A A A A A A
0011 D D D D A A A A A A A A A A A A
0100 D D D D D A A A A A A A A A A la
0101 D D D D D D A A A A A A A A A A
0110 D D D D D D D A A A A A A A A A
0111 D D D D D D D D A A A A A A A A
1000 D D D D D D D D D A A A A A A A
1001 D D D D D D D D D D A A A A A A
1010 D D D D D D D D D D D A A A A A
1011 D D D D D D D D D D D D A A A A
1100 D D D D D D D D D D D D D A A A
1101 D D D D D D D D D D D D D D A A
1110 D D D D D D D D D D D D D D D A
nil D D D D D D D D D D D D D D D D
ADCON2
ADFM ADCS2 ADCS1 ADCSO
ADFM ADC result format (0 = left justified, 1 = right justified)
ADCS2—ADCSO Clock select bits
000 = Fosc/2
001 = Fosc/8
010=- Fosc/32
011= FRC (internal RC clock; 1 MI Iz max)
100 - Fosc/4
101 =Fosc/16
110 = Fosc/64
111= FRC (Clock from RC oscillator, 1 MHz max)
Рис. 6.23. Регистры управления АЦП
240
Применение микроконтроллеров PIC 18
Рис. 6.24. Использование PIC для контроля подачи
напряжения в 3,3 В источнике питания ПК
Пример 6.22
/*
* Отбор напряжения с источника питания 3.3 В для PIC18F1220
*/
♦include ,pl8cxxx.h.
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
♦pragma config OSC -= HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
♦pragma code
float getVoltage (void)
Глава 6. Спецификации аппаратных средств семейства PIC18
241
ADCONObits.GO = 1; //запуск преобразования
while (ADCONObits.GO == 1); // ожидание завершения
return (ADRESL | (ADRESH ,, 8)) * 0.00489;
}
// main program
void main (void)
ADCONO = 0x01; // выбор входа ANO, активирование АЦП
ADCON1 = ОхОе; // ANO - аналоговый, VDD и VSS - опорные
ADCON2 = 0x84; // преобразование с использованием 1 мГц
TRISA = 1; // Порт А, бит 0 = вход для АЦП
PORTA = 0; // сигнал выкл.
while (1)
t if (getVoltage() . , 3. 465 || getVoltage() , 3.135)
PORTAbits.RAI = 1 ; // сигнал вкл.
else
PORTAbits.RAI = 0 ; // сигнал выкл.
Когда вызывается функция getVoltage, бит GO в ADCONO устанавливается в 1,
чтобы запустить преобразование. Он затем проверяется с тем, чтобы проконтролиро-
вать, завершено ли преобразование (GO = 0) с использованием цикла while. Программа
может быть расширена таким образом, чтобы один раз в секунду контролировалось
напряжение в процедура функции обработки прерывания RTC. Если имеет место по-
вышение напряжения на 5% или его снижение на 5%, то включается пьезоэлектриче-
ский зуммер. В примере 6.22 сигнал тревоги подается на RA1. Дополнительные приме-
ры использования АЦП приводятся в более поздних главах.
ЭСППЗУ данных
ЭСППЗУ данных имеется во многих версиях микроконтроллера, оно используется
для того, чтобы сохранять статические данные. Пароли, данные настройки или любой
иной тип данных, которые сохраняются длительное врем^, могут сохраняться в
ЭСППЗУ данных. В настоящее время используются два размера памяти данных
ЭСППЗУ "на чипе": 256 и 1024 байта. Доступ к устройству с 256 байтами выполняется
через один 8-разрядный адрес, помещенный в регистр EEADR, а устройство с 1024
байтами использует два 8-разрядных регистра адреса для организации доступа:
EEADR и EEADRH. EEADR содержит младшие 8 разрядов 10-разрядного адреса, а
EEADRH содержи старшие 2 бита адреса. Так как много устройств имеют только 256
только байтов ЭСППЗУ, в этом подразделе рассматривается только использование
регистра EEADR для выбора ячейки памяти ЭСППЗУ.
ЭСППЗУ данных сохраняет данные в течение 40 лет без какого-либо питания и
может быть перезаписано до 1 миллиона раз (технические спецификации приводят
цифру минимум 100000, так что это единственное гарантируемое число). Почему
ЭСППЗУ рассматривается в этом подразделе, вместо того, чтобы рассматриваться
вместе с памятью? ЭСППЗУ трактуется как устройство ввода - вывода, в него нельзя
242
Применение микроконтроллеров PIC 18
непосредственно писать или читать как в случае нормальной памяти. Чтение или за-
пись в ЭСППЗУ требует дополнительных усилий и понимания команд ввода - вывода.
Пример 6.23 показывает функцию, которая читает любую ячейку ЭСППЗУ объемом в
256 байт. Эта функция возвращает содержимое ячейки ЭСППЗУ, передаваемое как
параметр.
Пример 6.23
char eeRead (char address)
{
EECONlbits.EEPGD = 0;
EEADR = address;
EECONlbits.RD = 1;
return EEDATA;
выбирает ЭСППЗУ данных
устанавливает адрес ЭСППЗУ
выбирает операцию чтения
считывает данные из ЭСППЗУ
Эта короткая функция помещает ноль в бит EEPGD. Бит EEPGD выбирает либо
ЭСППЗУ данных, либо флеш-память программ (EEPGD = 1). Флеш-память программ
обсуждается в главе 10 совместно с программой начальной загрузки.
Запись в ЭСППЗУ требует немного больше усилий, чем считывание, поэтому
функция записи в ЭСППЗУ данных более длинна. Пример 6.24 показывает функцию
записи байта в ЭСППЗУ данных EEPROM.
Пример 6.24
)
void eeWrite (char address, char data)
{
INTCONbits.GIEH = 0; // отключает все прерывания
EECONlbits.EEPGD > = 0; // выбирает ЭСППЗУ данных
EECONlbits.WREN = 1; // снимает защиту записи
EEADR = address; // задает адрес ЭСППЗУ
EEDATA = data; // задает данные ЭСППЗУ
EECON2 = 0x55; EECON2 = OxAA; // стирает текущий байт
EECONlbits.WR = 1; // выбирает операцию записи
while (PIR2bits. EEIF == 0); // ожидание окончания
PIR2bits.EEIF = 0; // сбрасывает флаг прерывания ЕЕ
EECONlbits.WREN = 0; // защищает ЭСППЗУ от записи
INTCONbits.GIEH = 1; // повторно активирует все прерывания
Как уже отмечалось, большее количество работы требуется для того, чтобы запи-
сать данные в ЭСППЗУ. Так как логические схемы ЭСППЗУ вызывают прерывание, ко-
торое обычно не используется, первые и последние шаги соответствующей программы
отключают и заново включают системные прерывания. В данном случае как низкопри-
оритетные, так и высокоприоритетные прерывания блокируются битом GIEH регистра
управления прерываниями. Бит WREN защищает ЭСППЗУ от ошибочной записи, кото-
рая могла бы произойти. При записи в ЭСППЗУ этот бит устанавливается, а затем
сбрасывается, чтобы защитить ЭСППЗУ в конце функции.
Ячейка памяти ЭСППЗУ, выбранная EEADR стирается записью 0x55, а затем ОхАА
в регистр EECON2. Это сохраняет OxFF в выбранной ячейке памяти, - это состояние
рассматривается как состояние стирания. Фактическая запись в память ЭСППЗУ со-
храняет только нулевые биты числа в ячейке памяти. Как только запись будет инициа-
лизирована, бит EEIF (EEIF = 0) в регистре PIR2 указывает на то, что ЭСППЗУ занято
Глава 6. Спецификации аппаратных средств семейства PIC18
243
записью данных. Процесс записи ЭСППЗУ требует приблизительно 4 мс для своего
выполнения. Бит флага прерывания используется для того, чтобы указать, что ЭСППЗУ
занято выполнением записи, если программа решает прерывать эту операцию. В этом
примере программа ожидает единичного состояния флага EEIF перед записью в него
нуля и последующим продолжением работы. Глава 10 обсуждает программирование
внутренней флэш-памяти программ, которое выполняется почти так же, как и програм-
мирование ЭСППЗУ данных.
Поскольку имена переменных не могут быть назначены в программе для ЭСППЗУ,
один из методов решения этой задачи связан с использованием оператора #define,
чтобы присвоить числовые адреса меткам. Пример 6.25 иллюстрирует то, как выпол-
нить эту задачу, а затем использует функцию eeRead, чтобы считать переменную в ре-
гистровый файл данных.
Пример 6.25
//*********** данные
ЭСППЗУ **************************************************
#define timeMode 0
#define unitAddressL 1
#define unitAddressH 2
// timeMode присваивается адрес 0
// unitAddressL присваивается адрес 1
// unitAddressH присваивается адрес 2
// ********* переменные в памяти данных
tfpragma udata
char TimeMode;
char UnitAddressL;
char UnitAddressH;
// далее в программе
TimeMode = eeRead (timeMode); // считывание ЭСППЗУ по адресу 0x00
UnitAddressL = eeRead (unitAddressL)
UnitAddressH = eeRead (unitAddressH)
' I still later in the program
eeWrite (timeMode, TimeMode) // запись TimeMode в ЭСППЗУ
Модуль сравнения и сбора данных (ССР)
Модуль сравнения и сбора данных может использоваться с ШИМ-модулятором
(PWM) или регистрировать отсчеты таймера 1 или Таймере 3 при замере продолжи-
тельности интервала времени. Например, предположим, что таймер 3 работает с пе-
риодом счета в миллисекунду, а входной измеряемый сигнал изменяет скорость своего
изменения. Модуль ССР может измерять эти изменения, регистрируя содержание
таймера при изменении входного сигнала. Это позволяет замерять скорость измене-
ния входного сигнала в миллисекундах, потому что таймер считает миллисекунды.
Рис. 6.25 показывает PIC18F1220, который измеряет частоту сети электропита-
ния в системе контроля потребления мощности. В показанной схеме, сеть изолирова-
на от микроконтроллера. В качестве развязки используется оптопара, которая преоб-
разует сетевое напряжение 120 В в TTL-уровень. ТТЛ-уровень прикладывается ко входу
ССР1 (RB3) микроконтроллера. Модуль ССР программируется так, чтобы регистриро-
244
Применение микроконтроллеров PIC 18
вать содержимое таймера 3 всякий раз, когда положительный перепад сигнала появля-
ется на выводе ССР1. В этом примере таймер 3 работает с периодом 8 мкс. Отсчет,
снятый с вывода ССР1, используется для того, чтобы определить частоту входного сиг-
нала и сохранить эту частоту в ячейке памяти. Содержимое таймера 3 делится на
125000, чтобы вычислить частоту. Пример 6.26 иллюстрирует программу, используе-
мую для того, чтобы выполнить это измерение, используя модуль ССР микроконтрол-
лера. Эта программа использует файлы timers.h и capture.h для функций таймера 3 и
ССР. Файл заголовка таймера охватывает функции инициализации, чтения и записи
любого таймер. Файл заголовка модуля сбора данных охватывает функции, которые
открывают модуль сбора данных и обеспечивают его считывание.
Рис. 6.25. Схема, использующая модуль ССР
для измерения частоты в сети электропитания
Пример 6.26'
/*
* Измерение частоты в линии электропитания по переменному току
*/
// Для того, чтобы этот программный код вписался в загрузочный блок,
// файл компоновщика был изменен для использования файла инициализации с018.о
// вместо файла С0181.0
//
// Эффектом этого является то, что в программе не будет неинициализированных
ячеек памяти данных
#include ,pl8cxxx.h.
#include ,timers.h.
#include ,capture.h.
Глава 6. Спецификации аппаратных средств семейства PIC18
245
/* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* Отключить сброс по частичной потере
* - Разрешить общий сброс
*/
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
#pragma interrupt MyHighlnt
#pragma code high_vector = 0x08
void high_vector (void)
(
_asm GOTO MyHighlnt _endasm
коприоритетного прерывания
}
float frequency;
#pragma code
void MyHighlnt (void)
{
int count;
if (PIRlbits.CCPlIF == 1)
{
PIRlbits.CCPlIF = 0;
count = ReadCapturel();
WriteTimer3 (0);
frequency = 125000.0 /
}
}
void main (void)
{
питания
// внешний генератор на 4 мГц
save=PROD
// high_vector по адресу 0x0008
// высокоприоритетный вектор
// переход на программу обработки высо-
// частота линии электропитания
(count); // в Герцах
TRISBbits.TRISB3 = 1; // RB3 является входом
OpenCapturel (C1_EVERY_RISE_EDGE & // прерывание по подъему фронта
CAPTURE_INT_ON);
OpenTimer3 (TIMER_INT_OFF & //8 мкс
T3_PS_1_8 &
T3_SOURCE_INT);
WriteTimer3 (0); // сброс таймера 3
INTCONbits.GIEH =1; // разрешение высокоприоритеных прерываний
while (1)
246
Применение микроконтроллеров PIC 18
Дополнительные внутренние устройства
В данной главе были изложены вводные сведения о микроконтроллерах и неко-
торых их внутренних устройствах; обсуждение других внутренних устройств будет вы-
полняться в последующих главах, наряду с рассмотрением их работы. В состав этих
других устройств входит USART (универсальный синхронно/асинхронный приемопере-
датчик) и различные другие устройства, которые могут быть, а могут и не быть уникаль-
ными для конкретной версии микроконтроллера.
6.5. Резюме
1. Устройства семейства PIC18 производятся в различных корпусах - от PDIP с 18
выводами до корпуса TQFPc 128 выводами.
2. Напряжение питания для PIC18 может опускаться до 4,2 В при работе с полным
быстродействием и током от 60 мкА для работы с низким быстродействием до 12 мА
при работе на частоте 40 МГц.
3. Ток нагрузки достаточен для четырех стандартных TTL-схем и десяти КМОП-схем.
4. Микроконтроллер сбрасывается автоматически, если напряжение питания бы-
стро растет до 5,0 В (0,05 В/мс), иначе он часто сбрасывается с использованием
внешней комбинации резистора/конденсатора и кнопки сброса.
5. Микроконтроллер сбрасывается сбросом от сторожевого таймера (WDT),
сбросом по частичной потере питания (BOR), командой RESET (Reset () на С), сбросом
по переполнению стека, сбросом по освобождению стека или другими схемами.
6. Сторожевой таймер - это программируемый счетчик, который сбрасывает
микропроцессор, если ему позволяют переполниться. Количество времени до пере-
полнения может корректироваться, оно может достигать 131 секунды.
7. Сброс по частичной потере питания программируется так, чтобы сбросить
микроконтроллер, если напряжение питания понижается ниже заданной отметки.
8. Микроконтроллер может программироваться на сброс в случае переполнения
или опустошения стека.
9. Тактовая частота для PIC18 может поступать от внешнего источника, кварцево-
го генератора или резонатора, RC-схемы синхронизации или внутреннего генератора.
10. Оператор #pragma config определяет конфигурацию микроконтроллера в -
программе на С.
11. Выводы ввода - вывода в PIC18 сгруппированы в 8-разрядные порты, число
которых изменяется от одного члена семейства к другому. Все версии микросхем со-
держат порт А и В, а некоторые версии содержат порты С к J.
12. Порт ввода - вывода содержит регистр TRIS для программирования направ-
ление переноса данных на штырьках порта, регистр PORT для чтения или записи порта,
а также регистр порта LAT для записи во внутренний буфер порта. Многие версии мик-
росхем также содержат регистр ADCON1, который программирует выводы порта на
работу в аналоговом или цифровом режиме.
13. Прерывание - это обращение к функции, вызванное аппаратным сигналом
или некоторым внутренним событием. Когда происходит прерывание, микроконтрол-
лер использует или высоко- или низкоприоритетный вектор прерывания для вызова
процедуры обслуживания прерывания.
14. Структура прерывания управляется несколькими регистрами, которые про-
граммируют уровень приоритета, указывают состояние прерывания, а также разреша-
ют или запрещают прерывание.
Глава 6. Спецификации аппаратных средств семейства PIC 18
247
15. Таймеры используются для того, чтобы вызвать прерывание при своем пере-
полнении или для подсчета синхронных либо асинхронных событий.
16. Микроконтроллер содержит 10-разрядный аналого-цифровой преобразова-
тель, который имеет до 16 каналов входных данных.
17. ЭСППЗУ данных - это не такая память, как СЗУПВ регистрового файла дан-
ных или память программ. Доступ к ЭСППЗУ данных производится так, как будто это
устройство ввода - вывода через регистр адреса и регистр данных.
6.6. Вопросы и задания
1. Зайдите на сайт Microchip и определите, какие форматы корпусов микросхем
доступны для PIC18F1320.
2. Что такое корпус PDIP?
3. Что такое корпус SOIC?
4. Что такое корпус SSOP?
5.Вновь посетите сайт Microchip и определите минимальную и максимальную це-
ну версии устройства семейства PIC18. Минимальная цена за устройство PIC18 =
, а максимальная цена за устройство PIC18 =.
6. Как называются линии подачи электропитания на PIC18?
7. Каков диапазон напряжений, допустимых для высокоскоростной работы мик-
роконтроллера? .
8. Какой ток требуется для работы PIC18 на максимальной частоте?
9. Какой ток требуется для цифрового входного сигнала микроконтроллера PIC?
10. Микроконтроллер может перевести нагрузку в состояние логического нуля
при максимуме тока в.
11. Микроконтроллер может перевести нагрузку в состояние логической единицы
при максимуме тока в.
, 12. Если в цепи сброса (см. рис. 6.3) используется резистор на 15 кОм и конден-
сатор на 1,0 мФ, постоянная времени будет равна
13. Каково значение вывода MGER микроконтроллера?
14. Где расположен адрес вектора сброса?
15. Какая команда обычно размещается по адресу вектора сброса и почему?
16. Что такое сторожевой таймер (WDT) и что происходит, когда WDT переполняется?
17. WDT программируется на минимальный отсчет, равный и максималь-
ный отсчет, равный.
18. С какой тактовой частотой работает WDT?
19. Что такое BOR и какие напряжения могут программироваться для BOR?
20. Что такое сброс стека и что является причиной его возникновения?
21. Каково назначение оператора #pragma config MCLRE = ON на языке С?
22. Какова максимальная тактовая частота для PIC18?
23. Имеется ли минимальная тактовая частота для PIC18?
24. Один командный цикл формируется из периодов тактовой частоты.
25. Что такое режим XT тактового генератора для PIC18?
26. Что такое режим RCIO тактового генератора для PIC18?
27. Выберите резистор и конденсатор для работы PIC18 на частоте, приблизи-
тельно равной 750 кГц.
28. Как режим синхронизации HSPLL устанавливается для PIC18 в программе,
написанной на языке С?
29. Какие выводы микроконтроллера подсоединяются к кварцевому или керами-
248
Применение микроконтроллеров PIC 18
ческому резонатору?
30. Выполните поиск в Internet и найдите поставщиков керамических резонато-
ров. Какие значения частот обеспечиваются этими резонаторами (составьте список
Web-адресов упомянутых поставщиков)?
31. Объясните, как работает режим синхронизации HSPLL.
32. Объясните, как в примере электронной игры «Выбрасывание костей» выбира-
ется случайное число между 0 и 35.
33. Если для светодиода нужно напряжение в 2,5 В и ток в 20 мА, какой номинал
резистора смещения требуется, если напряжение источника питания равно 5,0 В?
34. Если для светодиода нужно напряжение в 2,5 В и ток в 20 мА, какой номинал
резистора смещения требуется, если напряжение источника питания равно 12 V?
35. Какова роль регистров TRISA, LATA и PORTA во вводе-выводе порта А?
36. Напишите короткую последовательность команд, которая запрограммирует
порт В как выходной порт, в котором все выводы будут предназначены для вывода
цифровой информации.
37. Напишите короткую последовательность команд, которая запрограммирует
битовые позиции 2 и 3 порта В на ввод информации, а остальные битовые позиции пор-
та В - на вывод информации.
38. Опишите, как работают прерывания.
39. Что происходит, когда возникает высокоприоритетное прерывание?
40. Объясните назначение операторов #pragma interrupt MyHighlnt и #pragma
code high_vector = 0x08.
41. Если функция, возвращающая 16-разрядное число, используется в процедуре
обслуживания прерываний, что должно быть указано в операторе #pragma для соот-
ветствующего прерывания?
42. Что выполняет написанная на языке С команда INTCONbits.GIEH = 1?
43. Каково назначение регистров IPR, PIE и PIR?
44. Опишите, как таймер 1 используется для того, чтобы вызывать 1-секундные
прерывания в примере таймера реального времени, рассмотренном в разделе 6.4.
45. Перепишите процедуру таймера реального времени так, чтобы отсчеты се-
кунд, минут и часов хранились не в двоичном, а в двоично-кодированном десятичном
формате (смотрите описание команды DAW в тексте данной книги).
46. Что будет, если флаг запроса прерывания не будет сброшен в ноль внутри
процедуры обслуживания прерывания? •
47. Сформируйте высокоприоритетное прерывание, которое будет вызывать
функцию tick(void) один раз в миллисекунду. Примите, что тот же самый кварцевый ге-
нератор на 32768 Гц используется для формирования масштаба по оси времени для
таймера 1.
48. Если вход Vref+ PIC равен 3,3 В, а на вход Vref-подана земля, каков будет шаг
напряжения АЦП?
49. Опишите, как программа может осуществлять выборку входа АЦП на RA0 2000
раз в секунду.
50. Как начинается процесс преобразования в АЦП?
51. Как выбирается входной канал АЦП?
52. Объясните, как выполняется считывание данных из ЭСППЗУ данных.
53. Как долго ЭСППЗУ данных сохраняет информацию без подачи на него напря-
жения питания?
54. Сколько времени занимает запись в ЭСППЗУ данных?
55. Почему прерывания запрещаются в функции, приведенной в примере 6.24?
56. Объясните, как модуль ССР замеряет частоту в сети переменного тока в примере 6.26.
Глава 7. Базовый ввод-вывод
249
ГЛАВА 7. Базовый ввод-вывод
Данная глава описывает то, как организовать интерфейс и использовать многие
различные базовые устройства ввода-вывода систем PIC18. В ней изложена информа-
ция по аппаратным и программным средствам, необходимая для организации интер-
фейса микроконтроллера с переключательными и дисплейными устройствами, а также
изложены основы программных средств, необходимых для управления этими устрой-
ствами. Эта глава также описывает много датчиков, предназначенных для того, чтобы
снимать информацию о мире вокруг нас и управлять различными аспектами среды, в
которой мы находимся. После завершения изучения этой главы вы сможете:
1. Выполнять устранение дребезга контактов и разрабатывать программы для
работы с ключами.
2. Формировать интерфейс и программировать клавиатуры любых размеров.
3. Писать программы как для отдельных светодиодов, так и для сегментирован-
ных светодиодных дисплеев, работающие в микроконтроллерах PIC18.
4. Управлять ЖК-индикаторами, подключенными к микроконтроллеру.
5. Разрабатывать программы управления шаговыми электромоторами, а также
электромоторами постоянного тока.
6. Формировать интерфейс и управлять реле и соленоидами.
7. Использовать датчики для распознавания различных событий.
8. Использовать код RC5 при реализации дистанционного управления в приложе-
ниях, рассматриваемых в качестве примеров.
9. Выполнять замеры различных газообразных веществ в окружающей среде.
7.1. Входы от ключевых схем
Переключатели уже использовались в примерах программирования, рассмотренных в
предыдущих главах, однако при этом не давалась никакая информация о их подключении.
Переключатели должны подключаться корректно, иначе могут возникнуть проблемы - такие,
например, как чувствительность к помехам или механический дребезг контактов.
Переключательный интерфейс
Переключатели часто представляют собой однополюсное одноходовое устройст-
во (SPST), которое при своем'срабатывании соединяет вместе полюсные детали (кон-
такты). Контакты замыкаются или размыкаются, когда переключатель выключается. На
рис. 7.1 представлено несколько типов механических переключателей, наиболее часто
используемых с микроконтроллерами. Каждый переключатель или кнопка включаются в
схему таким образом, чтобы на его выходе или выходах присутствовал или логический
ноль, или логическая единица. На рисунке показаны переключатели типов SPST, SPDT
(однополюсный двухходовой) и DPDT (однополюсный двухходовой) переключатели и
кнопочные. Во всех случаях используется нагрузочный резистор в 10 кОм, подающий
на выход переключателя логическую единицу, когда контакты переключателя разомкну-
ты. Значение этого резистора может изменяться от относительно малого в 1 кОм (бо-
лее низкие значения сопротивления вызовут чрезмерный ток) до максимального зна-
чения в 47 кОм (большие значения вызовут проблемы с помехами). Из главы 6 вы могли
бы вспомнить, что выводы порта В снабжены слабыми нагрузочными резисторами,
которые используются как нагрузки при работе как с переключателями, так и другими
устройствами, требующими наличия нагрузочных сопротивлений. Некоторые версии
PIC имеют также слабые нагрузки выводов порта D.
250
Применение микроконтроллеров PIC 18
тумблер типа SPST
переключатель SPST
Рис. 7.1. Различные переключатели.
Для организации простого ввода сигналов в микроконтроллер в системах часто
используются тумблеры типа SPST или кнопочные переключатели. Переключатель типа
SPST - это самый дешевый из имеющихся в настоящее время переключателей. В об-
щем случае переключатели могут создавать проблемы при их использовании для ввода
некоторых типов данных в силу того, что они подвержены механическому дребезгу кон-
тактов. Внутри переключателя находятся металлические контакты, при соединении
которых физически возникает явление механического дребезга контактов, которое
длится некоторое время. Этот дребезг должен быть компенсирован в системах, в кото-
рых количество соединений или синхронизация срабатывания переключателей являет-
ся важной.
Глава 7. Базовый ввод-вывод
251
Компенсация дребезга контактов переключателей
Имеются различные схемы устранения дребезга контактов переключателей.
Рис. 7.2 показывает форму электрического сигнала в случае дребезга контактов пере-
ключателя. Помехи возникают в сигнальных линиях переключателей в силу того, что
обычно является невозможным экранировать переключатель и его соединения с сис-
темой от окружающих помех. В большинстве случаев помехи, так же, как и дребезг,
должны быть удалены с контактов системы для обеспечения ее надежной работы.
Как можно видеть на иллюстрации, переключатели могут оказаться чрезвычайно
шумными устройствами. Количество шума зависит от окружающей среды, при этом на
рис. 7.2 представлен экстремальный случай. Дребезг контактов также является пере-
менной величиной. Когда переключатель является новым, дребезг контактов будет ми-
нимальным, однако по мере старения переключателя дребезг контактов становится все
более серьезным. Помехи, возникающие при разрыве контактов, практически отсутст-
вуют, когда переключатель новый, однако они возникают по мере старения переключа-
теля и становятся все более интенсивными со временем.
Как устранить эти проблемы, чтобы получить чистый сигнал, показанный в ниж-
ней части рисунка? Программные временные задержки часто используются, чтобы
пропустить проблемные временные области сигналов. Могут также использоваться
специальные электронные схемы, однако они стоят денег, поэтому используются до-
вольно редко. Рис. 7.3 демонстрирует некоторые электронные схемы, которые приме-
няются для устранения дребезга механических переключателей. Эти схемы весьма
эффективны, однако достаточно дороги.
Лучшим и менее дорогостоящим способом устранения проблемы дребезга кон-
тактов и шума является использование программного обеспечения. Функция, которая
удаляет дребезг контактов и шум переключателя, подключаемого к любому биту порта
А, иллюстрируется примером 7.1. Этот пример использует временные задержки для
устранения шума и проблем дребезга контактов переключателя. Когда переключатель
^находится в устойчивом состоянии логического нуля, отрабатывается выход из функ-
ции. Предполагается, что тактовая частота равна 4 МГц, а временная задержка равна -
15 мс. Переключатели имеют максимальное время дребезга контактов, равное 8 мс,
поэтому в данном примере используется время задержки, равное 15 мс, гарантирую-
щее пропускание периода дребезга контактов. В общем случае для удаления дребезга
контактов приемлемыми являются времена задержки от 10 до 20 мс. Если время за-
держки будет намного большим 20 мс, работа переключателя замедлится, потому что
он должен будет удерживаться в состоянии срабатывания слишком долго. В приведен-
ной программе используются два оператора #define, определяющих порт, а также зна-
чение временной задержки. Применение операторов #define позволяет легко изменять
порт и значение временной задержки.
252
Применение микроконтроллеров PIC 18
vcc
<?
тумблер типа SPST
Фактический сигнал на переключателе
Побочные помехи
Побочные
помехи
Побочные
помехи
Дребезг
контактов
Разрывные
помехи
Сигнал на переключателе,
очищенный от дребезга
контактов
Рис. 7.2. Дребезг контактов переключателя и шум
Глава 7. Базовый ввод-вывод
253
Рис. 7.3. Электронные схемы подавления дребезга контактов.
254
Применение микроконтроллеров PIC 18
Пример 7.1
// >>> Не забудьте включить оператор #include <delays.h> <<<
// *************** переключатель *************************
// для использования этой функции она должна вызываться следующим образом:
//
// Switch (0x04) <- переключатель на бите 2
//
// or
//
// Switch (0x40) <- переключатель на бите 6
//
// или
//
// Switch (0x03) <- переключатель на битах 0 и 1
//
II КОНСТАНТЫ *************************
#define KEYPORT PORTA // изменить для соответствия реальному порту
#define DELAY 15 // изменить, если нужно
// для соответствующей временной задержки
void Switch (char bit)
{
do // ожидание освобождения
{
while ((KEYPORT & bit) != bit);
// while ((KEYPORT & bit) ‘1= bit) CIrWdtO; если необходимо
DelaylKTCYx (DELAY) ;
}
while ((KEYPORT & bit) != bit); ‘
do // ожидание нажатия
( ... „ . ... '
while ((KEYPORT & bit) == bit);
// while ((KEYPORT & bit) == bit) CIrWdt () ; если необходимо
DelaylKTCYx (DELAY) ;
)
while ((KEYPORT Sc bit) == bit) ;
}
Первый цикл do-while гарантирует, что переключатель находится в состоянии ло-
гической единицы, т.е. в отпущенном состоянии - если это не так, то программа будет
циклить в этом месте. В некоторых случаях цикл while будет содержать функцию
ClrWdt(), сбрасывающую сторожевой таймер. (Если вам потребуется эта функция, рас-
комментируйте оператор while перед оператором //while). Первый цикл do-while устра-
няет всякие импульсы помех, возникающие при переходе выхода переключателя из
состояния логической единицы в состояние логического нуля, как это показано на
рис. 7.2. Для получения устойчивого открытого состояния переключатель должен раз-
мыкаться с отработкой как до, так и после открытия временной задержки в 15 мс.
Именно так устраняется дребезг контактов и шумы. Как только переключатель будет
открыт, второй цикл do-while тестирует переключатель на состояние логического нуля,
т.е. на замкнутое состояние. (Этот цикл также может включать функцию ClrWdtQ.) Если
распознано устойчивое состояние логического нуля, продолжающееся дольше, чем 15
Глава 7. Базовый ввод-вывод
255
мс), отрабатывается возврат из функции. Это эффективно удаляет любой дребезг или
шумы на любом входном бите порта, соединенном с переключателем либо кнопкой.
Единственный случай, когда описанный алгоритм не сработает, - это очень редкий,
однако все же возможный случай, когда импульсы шумов следуют точно с 15-
миллисекундным интервалом. Эта программа предполагает, что переключатель вклю-
чен, когда его выходной сигнал находится в состоянии логического нуля; если же это не
так, то нужно поменять местами два цикла do-while в функции. Эта программа обеспе-
чивает также удаление дребезга контактов и шумов для нескольких переключателей,
если задано корректное значение переменной установки битов. Например, для удале-
ния дребезга контактов и шумов от переключателей, подключенным к битам 1 и 5 порта
А, следует использовать вызов функции Switch (0x22). Значение 0x22 (0010 0010) выби-
рает биты 1 для 5 тестирования. Возврат будет отработан, если какой либо переключа-
тель будет активирован.
Клавиатуры
D прикладных программах, иногда используются цифровые клавиатуры, в них
также нужно устранять дребезг контактов. В дополнение к устранению дребезга контак-
тов, цифровая клавиатура должна возвращать код нажатой клавиши. Рис. 7.4 иллюст-
рирует цифровую клавиатуру телефонного типа, подключенную к портам А и В. Это
матрица размерности 4x3 клавиши. Цифровые клавиатуры доступны в целом ряде
стилей и размеров - от размера 2 х 2 до почти любого размера. Матрица цифровой кла-
виатуры создается с использованием кнопочных переключателей типа SPST, которые
при нажатии соединяют вертикальный столбец с горизонтальным рядом матрицы. Кла-
виатурная матрица - это наиболее распространенная схема коммутации клавиш в ма-
лых клавиатурах.
В этом интерфейсе, порт А используется как входной порт для считывания строк,
а порт В используется как выходной порт для выбора столбцов. Нагрузочные резисторы
должны быть установлены во входной порт для обеспечения его правильной работы.
Если порт В используется как входной порт со включенными слабыми нагрузками, на-
-рузочные резисторы не устанавливаются). Матрицы любых размеров подключаются
аналогичным способом, за исключением того, что выбор портов ввода - вывода может
отличаться. Программа, используемая для обнаружения замыкания ключей, также уст-
раняет дребезг контактов малой клавиатуры. Для устранения дребезга контактов малой
клавиатуры логический ноль помещается во все три бита порта В. Программа для уст-
ранения дребезга контактов любых клавиш идентична приведенной в примере 7.1, за
исключением того, что проверяются биты от'ЛАО до RA3 вместо одного бита. Как толь-
ко дребезг замкнутого ключа устранен, его позиция рассчитывается программно по-
средством контроля каждого столбца по отдельности и тестирования порта А, на пред-
мет замыкания какого либо ключа в столбце. В примере 7.2 приведена функция, кото-
рая возвращает код клавиши для данного ключа. Эта функция использует функцию
Switch, приведенную в примере 7.1 для устранения дребезга контактов клавиши, одна-
ко битовая структура в битовой переменной функции Switch в ней изменена на OxOF,
результате чего функция проверяет самые правые 4 бита порта А.
256
Применение микроконтроллеров PIC 18
Фактическая
клавиатура
Клавиатура с точки зрения
программы перед просмотром
поисковой таблицы
Рис. 7.4. Матрица малой клавиатуры телефонного типа
Глава 7. Базовый ввод-вывод
257
Пример 7.2
//
// коды клавиш клавиатуры телефонного типа,
// сохраняемые как статичные константы в памяти программ
//
rom near char iookupKey[] = i
1, 4, 7, Ю, // левый столбец
1, 5, 8, 0, И средний столбец
3, 6, 9, 11 // правый столбец
И
// использует функцию Switch из примера 7.1
//
unsigned char Key (void)
{
#define MASK OxOf #define ROWS 4 // установка маски // установка числа строк
char a ;
char keyCode;
PORTB = keyCode =0; // очистка порта В и keyCode
Switch (MASK); // устранение дребезга и ожидание любой клавиши
PORTB = OxFE; // выбор самого левого столбца
while ((PORTA & MASK) == MASK) // пока клавиша не найдена
PORTB = (PORTB << 1) | 1; // получение следующего столбца
keyCode += ROWS. ) ; // прибавление строки к коду клавиши
for (a = 1; a 1= 0; а «= 1)
{ // find row
if ((PORTA & а) == 0)
break;
keyCode++; i
return lookupKey[keyCode]; // просмотр на корректный код клавиши
Клавиатурная программа сканирует клавиатуру слева направо и сверху вниз. Это
показано на рис. 7.4, наряду с фактическими кодами клавиш для этой клавиатуры. Как
только столбец найден, число 0, 4 или 8 помещается в переменную keyCode, чтобы ука-
зать стартовый код клавиши (код верхней клавиши) для найденного столбца. После
нахождения столбца, строка просматривается на логический ноль в порте А с тем, что-
бы найти клавишу и ее строку. Если клавиша не найдена, keyCode инкрементируется,
чтобы было получено число между 0 и 11, которое соответствует клавише на клавиату-
ре. Если клавиша найдена, то производится обращение к поисковой таблице с тем,
чтобы преобразовать просканированный код клавиши (скан-код) в фактический код
клавиши, соответствующий ее обозначению. Программа генерирует коды клавиш 0, 1,2
258
Применение микроконтроллеров PIC 18
и 3 для крайнего левого столбца; 4, 5, 6 и 7 для среднего столбца и 8, 9, 10, и 11 для
самого правого столбца. В силу того, что обозначения клавиш не совпадают с этими
кодами, используется поисковая таблица таблицы для того, чтобы преобразовать най-
денные коды в правильные обозначения клавиш клавиатуры.
Функция Key написана с использованием нескольких операторов #define, кото-
рые облегчают выполнение изменений в конфигурации клавиатуры. Например, если
используется клавиатура 5 х 6, то 5 строк ее матрицы подключаются к выводам от RAO
до RA4, а 6 столбцов этой матрицы подсоединяются к выводам от RBO до RB5. Опера-
торы #define изменяются при этом так, чтобы переменная MASK была равна OxIF, а
переменная ROWS - пяти. При этом программа будет работать с новыми размерами
матрицы клавиатуры. Поисковая таблица также должна быть изменена с тем, чтобы
содержать 30 входов вместо 12, потому что клавиатура с матрицей 5x6 имеет 30 кла-
виш, а не 12.
Предположим, что число считывается из клавиатуры в программу. Для его ввода
используется функция #кеу, при этом функция *кеу используется для забивки любых
ошибок ввода. Функция, которая использует функцию Key для считывания числа с кла-
виатуры, показана в примере 7.3. Эта функция возвращает 16-разрядное целое без-
знаковое число при нажатии клавиши. Этот возвращаемый параметр трудно использо-
вать, потому что отсутствует соответствующее устройство отображения, о чем будет
говориться в следующем подразделе. Приводимый пример программы, однако пока-
зывает, как осуществляется ввод числа с клавиатуры.
Пример 7.3
unsigned int GetNumber (void)
{
char number[5] ;
int retval = 0 ;
char count = 0;
char temp = Key();
while (temp != 11) // пока нет ввода
{
if (temp == 10 && count != 0) '
count—; //шаг назад
else
{
number[count] = temp; // принять число
if (count != 5) /
count++;
}
temp == Key() ;
}
for (temp = 0; temp < count; temp++) 11 преобразовать в двоичную форму
retval = retval * 10 + number[temp] ;
return retval;
Глава 7. Базовый ввод-вывод
259
7.2. Устройства индикации
Сегодня доступно много индикаторных устройств, включая светодиоды, жидкок-
ристаллические индикаторы, флуоресцентные индикаторы и т.д. Этот раздел описыва-
ет эти индикаторные устройства, наряду с электронными схемами и программным
обеспечением, нужными для того, чтобы связать их с микроконтроллером.
Светодиоды
Светодиоды впервые появились в середине 1960-ых. Сегодня доступны свето-
диоды многих различных цветов, ожидается, что скоро они будут иметь вид гибкой ор-
ганической панели, которая была названа OLED (органический светодиод). Из-за их
дешевизны и длительного срока службы, через относительно короткое время свето-
диоды могут заменить лампы накаливания и флуоресцентные трубки в качестве источ-
ников освещения общего назначения. Светодиоды часто подключаются к встроенным
системам в качестве индикаторов или сегментных цифровых индикаторов. Их главное
преимущество заключается в высокой видимости и долговечности. Светодиоды обычно
работают в течении приблизительно 20 лет. Другими их преимуществами являются
относительно низкие требования к потребляемой мощности и низкое тепловыделения,
по сравнению с лампами накаливания.
Стандартный красный, зеленый, или желтый СВЕТОДИОД требует для своего
полного свечения ток в 10 мА и напряжение в 1,65 В. Потребляемая мощность свето-
диода в режиме полного свечения (10 мА х 1,65 В) равна 16,5 мВт. Эквивалентная лам-
па накаливания требует 6,3 В напряжения при токе в 100 мА или 630 мВт мощности. Т.е
для своей работы СВЕТОДИОД требует в 40 раз меньшей мощности, чем эквивалент-
ная лампа накаливания. Рис. 7.5 показывает один светодиод, подключенный при помо-
щи интерфейса к выводу порта PIC18. Один из показанных интерфейсов потребляет ток
равный 10 мА и имеет инвертор, который обеспечивает ток, достаточный для свечения
светодиода, что немного больше, чем ток, допускаемый для вывода порта. Второй из
показанных интерфейсов пропускает ток в 8,5 мА, - этот ток является допустимым для
вывода порта. В обоих случаях используется последовательное включение токоограни-
чивающего резистора, величина которого выбирается в соответствии с законом Ома (R
= U/I). Поскольку падение напряжения на светодиоде равно 1,65 В, падение напряже-
ния на резисторе равно 3,35 В, то ток в 10 мА определяет резистор в 335 Ом (3,35/10
мА). Резисторов номиналом 335 Ома не существует, поэтому выбирается стандартный
резистор с номиналом в 330 Ом. (Перечень стандартных номиналов резисторов может
быть найден в Интернет.) Значения резистора для тока в 8,5 мА выбирается тем же са-
мым способом. Использование тока в 8,5 мА заставляет светодиод светиться почти так
же сильно, как и при использовании тока в 10 мА, -этот ток является приемлемым в
большинстве приложений. Как объясняется в Главе 6, в зависимости от общей мощно-
сти потребления PIC и использования выводов ввода-вывода, на отдельных выводах
ток может достигать величины 25 мА.
260
Применение микроконтроллеров PIC 18
Вывод
порта
Рис. 7.5. Управление светодиодом при использовании
напряжения питания, равного +5,0 В
10mA
Вывод
порта
R2
390
8.5 mA
Предположим, что для управления светодиодом используется напряжение пита-
ния не 5 В, а 12 В. Максимальное напряжение на любом выводе PIC 18 равно 7,5 В, -
это означает, что 12 В выведет микроконтроллер из строя. Чтобы связать источник пи-
тания в 12 В со светодиодом в этом случае необходима соответствующая схема управ-
ления. Во многих случаях наиболее эффективной, с точки зрения стоимости, схемой
управления будет простой транзисторный инвертор, как это показано на рис. 7.6. На
показанной схеме транзистор 2N2222 изолирует микроконтроллер от напряжения пи-
тания 12 В и обеспечивает соответствующий ток для СВЕТОДИОДА. В этом примере
используется синий светодиод, который требует для своей работы напряжения в 3,5 В
и тока в 20 мА. Транзистор в данном случае работает как усилитель тока, который ум-
ножает входной ток базы на коэффициент усиления транзистора, модулируя ток эмит-
терного перехода и формируя ток коллектора. В данном примере требуется ток коллек-
тора, равный 20 мА, при этом минимальный коэффициент усиления тока для данного
транзистора (2N2222) равен 100. Таким образом, ток базы, необходимый для того, что-
бы получить ток коллектора в 20 мА, следовательно равен 20 мА/100 или 0,2 мА, - этот
ток может быть легко сформирован микроконтроллером. Резистор в цепи базы рассчи-
тывается, используя ток в 0,2 мА и значение падение напряжения на резисторе базы,
равное 3,6 В. Падение напряжения база-эмиттер в данном случае будет равно 0,7 В.
Вспомните из главы 6, что минимальное выходное напряжение логической единицы
для микроконтроллера равно 4,3 В, а максимальный ток - 3,0 мА.
Предположим, что нам нужна светодиодная индикаторная панель сигналов пово-
рота, устанавливаемая на заднем стекле автомобиля или же над номерным знаком мо-
тоцикла. Для создания этой индикаторной панели мы будем использовать 20 ярких
красных светодиодов, а в качестве микроконтроллера - PIC18F1220. Рис. 7.7 показыва-
ет организацию подобной системы. Десять выводов порта микроконтроллера управля-
ют светодиодами, и два входных вывода служат интерфейсом электрической системы.
Программное обеспечение должно обнаруживать сигнал левого и правого поворота от
автомобиля, а также сигнал тормоза. Напряжение от левой и правой задней лампы по-
Глава 7. Базовый ввод-вывод
261
нижается до 5,1 Вс использованием туннельного диода. После них стоит пара транзи-
сторных инверторов. 12 В появляется тогда, когда включаются задние лампы и снима-
ется, когда они выключаются. Инверторы необходимы при использовании резисторов
слабых нагрузок в порте В для генерирования входных сигналов микроконтроллера.
Для указания левого или правого поворота должны включаться только левые или пра-
вые светодиоды. Для индикации сигнала тормоза, должны включаться все светодиоды.
Яркие красные светодиоды требуют для своего свечения напряжения в 2 В и тока в 30
мА. Неинвертирующая буферная схема 74LS244 обеспечивает вплоть до 32 мА тока
нагрузки на выходном выводе (Y). На приведенной схеме 7805 используется для того,
чтобы обеспечить питанием + 5,0 В микроконтроллер и буферные схемы. Альтернатив-
ным решением будет использование МАХ603 от Maxim Technology (http://www.maxim-
ic.com) в качестве стабилизатора. Фирма Maxim Technology бесплатно предоставляет
образцы своих изделий учащимся.
+12 V
Рис. 7.6. Управление светодиодом при
использовании транзисторного усилителя.
Программное обеспечение для этого приложения использует временные задерж-
ки, предполагая использование тактовой частоты в 2 МГц, снимаемой от RC генерато-
ра. В примере 7.4 приводится программа на языке С, которая управляет сигналами,
подаваемыми на светодиоды поворота и тормоза. В данном примере переменная
DELAY (ЗАДЕРЖКА) определяется как 20, что вызывает временную задержку в 40 мс.
Это время может регулироваться на установку предпочтительного времени свечения,
262
Применение микроконтроллеров PIC 18
однако 20 должно быть приемлемым значением. Также обратите внимание на то, что
используется сторожевой таймер на случай зависания программы - когда это произой-
дет, система автоматически перезарядится и восстановится от сбоя. Работа задних
ламп является важной для этой системы - любое нарушение их работы должно быть
предотвращено. В этом примере сброс сторожевого таймера (WDT) выполняется в трех
различных местах программы.
Пример 7.4
/*
* Пример подачи сигналов поворота для PIC18F1220
* частота RC-генератора равна 2 MHz
*/
#include <pl8cxxx.h>
#include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
#pragma config OSC = RC
#pragma config WDT = ON
#pragma config WDTPS = 64
#pragma config LVP = OFF
#pragma config BOR = OFF
#pragma config MCLRE = ON
#pragma code
// главная программа
void main (void)
{
// сторожевой таймер на 256 мс
#define DELAY 20 // установка отсчета задержки на 20 (40 мс)
ADCON1 = OxOF; // Порт А и В - цифровые
TRISA =0; // порт А - выход
TRISB = OxCO; // порт В - выход, за исключением
// битов 6 и 7
IMTCON2bits.RBPU =1; // нагрузочные резисторы вкл.
while (1) // главный цикл
(
CIrWdtO; // сброс сторожевого таймера
if ((PORTB & OxCO) == 0) // если ТОРМОЗ
{
PORTA =0;
// все светодиоды вкл.
Глава 7. Базовый ввод-вывод
263
PORTB = 0;
}
else if ((PORTB & 0x40) == 0x40) // если ВЛЕВО
{
PORTB = 0x10; // ....X
DelaylKTCYx(DELAY) ;
PORTB = 0x18; // ...XX
DelaylKTCYx ( DELAY) ;
PORTB = OxIC; // ..XXX
DelaylKTCYx(DELAY) ;
PORTB = OxIE; // .XXXX
DelaylKTCYx (DELAY) ;
PORTB = OxIF; // XXXXX
while ((PORTB & OxCO) != OxCO)
{
CIrWdtO; // сброс сторожевого таймера
if ( (PORTB & OxCO) == 0) // если прекращение
торможения;
)
)
else if ((PORTB & 0x80) == 0x80) // если ВПРАВО
{
PORTA = 0x10; // X....
DelaylKTCYx (DELAY) ;
PORTA = 0x18; // XX...
6elaylKTCYx (DELAY) ;
PORTA = OxIC; // XXX. .
DelaylKTCYx (DELAY) ;
PORTA = OxIE; // XXXX.
DelaylKTCYx(DELAY) ;
PORTA = OxIF; // XXXXX
while ((PORTB & OxCO) != OxCO)
{
CIrWdtO; // сброс сторожевого таймера
if ((PORTB & OxCO) == 0) // если прекращение
торможения;
)
)
else // если ничего не происходит
{
PORTA = OxFF; // все светодиоды выкл.
PORTB = OxFF;
12 V
27 pF
R12
3.9К
1.0 uF
R11
10К
U2 q
D1
77*
D2
77*
270
От левой задней
лампы тормоза
От правой задней
лампы тормоза
С1
100 uF
U1
2
4
6
8
13
15
17
19
2
"6
T
T
16
15
Srbo
RAO tnDM
RAI SRB1
RA2
RA3
RA4
HMCLR
OSC1 “RB6
OSC2 >RB7
PIC 18F1220
RB2
RB3
RB4
RB5
8
9
T7
18
IT
R13
Q1
2N2222
R14 1К
5. IV
D21
А1
А2
АЗ
А4
А5
А6
А7
А8
Y2
Y3
IB
16
14
D3
D4
Y5b—
Y6
D6
Y8
7
T
3
1ОЕ
^10
ewb
74LS244
10 uF
2
C4
LM7805
U5
VOUT VIN
I
U3 g
Q2
2N2222
Т5"
D5
D8
77*
3
левые
D9
77*
D10
77*
D11
77*
D12
77*
А1
А2
АЗ
А4
А5
АВ
А7
АВ
Y1
Y2
Y3
Y4
Y5
Y6
Y8
2О£,0
74LS244
18
16
IT
12
5
т
-емЬ
D13
D14
D16
правые
D15
D18
77*
D19
77*
D20
77*
Рис. 7.7. Схема световых сигналов тормоза и поворота
Применение микроконтроллеров PIC18
Глава 7. Базовый ввод-вывод
265
7-сегментные светодиодные индикаторы
Другой распространенный тип индикатора - это 7-сегментный светодиодный ин-
дикатор. Эти устройства используются в тех случаях, когда индикатор должен быть до-
вольно большим и обеспечивать хорошую наблюдаемость. Пример этого может быть
оборудование для физической терапии лиц пожилого возраста, которые часто имеют
недостаточное зрение. 7-сегментные светодиодные индикаторы доступны с размера-
ми в пределах от 0.25 до 5.0 дюйма (смотрите сайт фирмы Lite-on http:/
www.liteon.com). Рис. 7.8 иллюстрирует один такой светодиодный индикатор. Доступны
версии светодиодных индикаторов с общим анодом и общим катодом. В версии с об-
щим анодом все аноды светодиодов подключены к 5,0 В, при этом свечение сегмента
вызывается логическим нолем. В версии с общим катодом все катоды светодиодов
подключены к земле, при этом свечение сегмента вызывается логической единицей.
Оба типа светодиодных индикаторов широко используются в приложениях. Рассматри-
ваемый светодиодный индикатор содержит семь сегментов, помечаемых буквами от а
до д. Некоторые индикаторы также содержат десятичную точку, обозначаемую как dp.
Рис. 7.9 иллюстрирует 7-сегментный индикатор, подключенный к PIC18F1220. К
микроконтроллеру подключен также один кнопочный переключатель. Переключатель
связан с выводом RAO, а 7-сегментный индикатор подключен к порту В. Этот индикатор
управляется буферной схемой 74LS244, обеспечивающей ток в 10 мА на сегмент, кото-
рый требуется индикатору. Программа, управляющая индикатором, показана в приме-
ре 7.5. Эта программа устраняет дребезг контактов кнопки так, чтобы при каждом ее
нажатии число на 7-сегментном индикаторе увеличивалось бы на единицу. Обратите
внимание, как поисковая таблица в памяти программ используется для того, чтобы оп-
ределить 7-сегментный код для индикатора.
abed е f g
Общий катод
g '
Рис. 7.8. 7-сегментный светодиодный индикатор
266
Применение микроконтроллеров PIC 18
Пример 7.5
/*
* демонстрационный пример использования 7-сегментного индикатора, написанный
для PIC18F1220
*/
#include <pl8cxxx.h>
♦include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
♦pragma config OSC = RC
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
#pragma config MCLRE = ON
// *************** данные В ПАМЯТИ ПРОГРАММ ***
rom near char look7[] = // поисковая таблица для 7-сегментного индикатора
0x40, // 0 сигналы с активным логическим нулем
0x79, // 1 xgfedcba
0x24, // 2
0x30, // 3
0x19, // 4
0x12, // 5
0x02, // 6 ✓
0x78, // 7
0x00, // 8
0x10 // 9
***** ДАННЫЕ В ПАМЯТИ ДАННЫХ ********
int count;
♦pragma code
// *************** функции ************************************
void Switch (char bit)
{
do // ожидание отпускания
{
while ((PORTA & bit) != bit);
DelaylKTCYx (30); // 15-ms delay
Jwhile ((PORTA & bit) != bit);
do // ожидание нажатия
{
while ((PORTA & bit) == bit);
Глава 7. Базовый ввод-вывод
267
DelaylKTCYx (30);
}while ((PORTA & bit) == bit);
}
// ***************ГЛАВНАЯ ПРОГРАММА *********************************
void main (void)
ADCON1 = 0x7F; // порты А и В - цифровые
TRISA = 1; // порт А, бит 0 - вход
TRISB = 0; // порт В - выход
count = 0; // начало отсчета с нуля
whi le (1) // главный цикл
t PORTB = loo k7[count]; // отображение числа
Switch (1); // ожидание нажатия кнопки
count++;
if (count >= 10)
count = 0;
Иногда необходимо использовать более одного индикатора. Предположим, что нам
требуется система, которая будет отображать 4-разрядные числа на 4-разрядном светоди-
одном индикаторе. Если будет применяться та же самая методика, которая реализована в
схеме, приведенной на рис. 7.9, то потребуется использовать много выводов ввода - вывода,
а также много буферных схем и резисторов. Чтобы уменьшить количество компонентов и
' требуемых выводов ввода - вывода, индикаторы обычно мультиплексируются. Все индика-
торы мультиплексного многоразрядного индикатора совместно используют одну схему
управления, при этом одновременно информация отображается только в одном разряде
индикатора. Вследствие инерционности человеческого зрения, глаз и сетчатка 3ai iomhi iaioi
вспышку света примерно на 20 мс. Если свет будет мигать быстрее, чем 50 раз в секунду, то
наблюдателю будет казаться, что он светит постоянно. Если каждая цифра индикатора будет
высвечиваться по крайней мере 50 раз в секунду, то будет казаться, что все четыре цифры
светятся одновременно.
Тот же самый эффект используется при просмотре кинофильма в кинотеатре. На
пленке имеются 24 неподвижных кадра, которые все проектируются на протяжении
одной секунды. Каждый кадр высвечивается на экране дважды. Частота мелькания кад-
ров кинофильма равна 48 Гц, при этом никакое мигание не заметно - наблюдается
только гладкое движение. В более старых немых кинофильмах использовалась частота
смены кадров 18 кадров секунду, они также подсвечивались два раза в секунду, обес-
печивая частоту мигания кадров 36 Гц. Все знают, что мигание в этих фильмах было
заметно. Американское аналоговое телевидение имеет частоту регенерации кадров,
равную 60 Гц, при частоте смены кадров, равной 30 кадров в секунду.
SW1
O-
счет
C2 x
30 pF
+5V
Q
to
oo
R3 ? R2 > R1
3.9K> 10K> 10K
Д.
2.
6.
_7
3
16
15
U1
RAO
RA1
RA2
RA3
RA4
#MCLR
OSC1 <gRB6
OSC2 >RB7
§RBO
> RB1
RB2
RB3
RB4
RB5
PIC18F1220 ю
C1
1.0 uF
C3
0.1 uF
U2
Общий
анод
8
9
17
18
10
11
12
13
2
4
6
8
11
13
15
17
1
19
A1
A2
A3
A4
A5
A6
A7
A8
Y1
Y2
Y3
Y4
Y5
Y6
Y8
18
16
14
12
9
7
5
3
330
й:
WF
2OE
О
Применение микроконтроллеров PIC18
74LS244
Рис. 7.9. Простая система управления 7-сегментным светодиодным индикатором
Глава 7. Базовый ввод-вывод
269
Рис. 7.10 иллюстрирует мультиплексный индикатор, связанный с PIC18F1220. Эта
схема функционирует как простой вольтметр и отображает на 4-разрядном индикаторе
напряжение, которое прилагается к выводу RA0. Поскольку никакое масштабирование
входного напряжения не используется, то диапазон входных напряжений лежит в пре-
делах 0...5 В. Расположенная на втором индикаторе слева от цифры десятичная точка
соединена с землей. Смотрите описание простого аналогового входа, связанного с
АЦП, в главе 6.
Эта схема использует в качестве управляющего контура усилитель на паре со-
ставных транзисторов Дарлингтона DS2003, обеспечивающий необходимый ток для
индикаторных сегментов. (Фирма National Semiconductor через сайт www.national.com
предоставляет студентам бесплатные образцы своих изделий с оплатой только стои-
мости доставки.) Поскольку усилители на паре Дарлингтона инвертируют входной сиг-
нал, 7-сегментная поисковая таблица должна быть откорректирована на 7-сегментные
коды с активными единичными уровнями. Каждый сегмент индикатора потребляет ток в
40 мА. Номинальный ток сегмента на цифру индикатора составляет 10 мА, однако по-
тому что каждая цифра включена только 1/4 всего времени, ток увеличивается на ко-
эффициент, равный четырем в случае 4-разрядного индикатора с целью поддержания
среднего или номинального тока в 10 мА на сегмент. (Человеческий глаз усредняет
уровни яркости.) Последовательно включенный токоограничивающий резистор рассчи-
тывается с использованием значения падения напряжения на резисторе, равного 3 В, и
величины текущего через него тока, равного 40 мА, что дает величину сопротивления,
равную 75 Ом. Падение напряжение на светодиодном индикаторе приблизительно рав-
но 2 В. Управляющим элементом в цепи анода является PNP транзистор 2N2907 с ми-
нимальным коэффициентом усиления по току, равным 100. Поскольку время от време-
ни отображается цифра 8, подсвечивая все семь сегментов индикатора, сила тока, ко-
торый должен пропускаться управляющим элементом в цепи анода, равна 7 раз по
40 мА, или 280 мА. Ток базы при этом будет равен 2,8 мА, при падении напряжения в
4,3 В на резисторе базы, имеющем номинал в 1,5 кОм.
Программное обеспечение этой системы иллюстрируется примером 7.6. Пакет
инструментальных средств языка С не содержит функцию, которая преобразовывает
числа с плавающей запятой в последовательность цифр. Цикл for, приведенный в этом
примере, выполняет это преобразование, получая целочисленную часть напряжения,
выраженного как цифра в формате с плавающей запятой, в виде цифры, которая вычи-
тается из значения напряжения. Затем перед следующей итерацией, напряжение ум-
ножается на 10, в результате чего цифра, расположенная непосредственно справа от
десятичной точки, становится доступной как целое число. Этот процесс продолжается
до тех пор, пока не будут определены все четыре цифры, отображаемые на индикаторе.
+5V
О
R9
10K
PIC18F1220
Аналоговый вход
(0 - 5 В)
U1
C3
33 pF
4 MHz
C2
33 pF
C1
1.0 uF
U2 DS2003
16
2N2907
Srbo
15 .
COM
RB2
RB3
RB4
RB5
2
3
12
13
8
9
17
18
10
RAO fitTDV
RA1 >RB1
RA2
RA3
RA4
#MCLR
OSC1 WRB6
OSC2 •> RB7 I"——
5
6
INA
INB
INC
IND
INE
INF
ING
OU TA
OU ТВ
OUTC
OUTD
OUTE
OUTF
OUTG
Применение микроконтроллеров PIC18
Рис. 7.10. Многоразрядный цифровой индикатор, который работает как вольтметр
Глава 7. Базовый ввод-вывод
Рис. 7.11. Цифровой вольтметр с тремя пределами измерения напряжения
272
Применение микроконтроллеров PIC 18
Пример 7.б
/*
* программа вольтметра, написанная для PIC18F1220 и
* используемая тактовая частота 4 МГц
*/
#include <pl8cxxx.h>
#include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
ttpragma config BOR = OFF
#pragma config MCLRE = ON
// данные в памяти программ
rom near char look7 [] = // 7-сегментная поисковая таблица
t 0x3F, // 0 сигналы с активной логической 1
0x06, // 1 xgfedcba
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// данные в памяти данных
float volts;
#pragma code
// главная программа
float getVoltage (void)
{
ADCONObits.GO = 1; //начало преобразования
while (ADCONObits.GO == 1); // ожидание завершения
return (ADRESL + (ADRESH «8)) * 0.00489;
}
void main (void)
Глава 7. Базовый ввод-вывод
273
char а;
char selectPattern;
ADCONO ADCON1 ADCON2 TRISA TRISB = 1; = ОхОе; = 0х8С; = 0; = 0; // // // // // // выбор входа ANO, активирование АЦП ANO - аналоговый сигналд, VDD и VSS - опорные напряжения все другие выводы порта А и В являются цифровыми преобразование с использованием 1 мГц порт А - выход порт В - выход
while { (1) // главный цикл
volts = getVoltage(); // получение напряжения
selectPattern = OxFC;
for (a { = 0; a PORTA , 4; а++) Ц // = selectPattern; преобразование в цифры и отображение их // задание цифры
PORTB = look?[ (int) volts ];
volts -= (int) volts;
volts *= 10;
selectPattern = (selectPattern << 1) I 2;
DelaylKTCYx (3);
)
)
// задержка в 3 мс
г
Временная задержка используется для того, чтобы отображать каждую цифру
один раз каждые 3 мс. Это обеспечивает частоту вспышек, равную 83.3 Гц для четырех
цифр индикатора, что является вполне достаточным для того, чтобы предотвратить
мерцание. Частота вспышек не должен быть равной 50 или 60 Гц, либо любому числу,
кратному указанным значениям. В США частота электрической сети равна 60 Гц, что
заставляет флуоресцентные лампы мерцать с частотой в 120 Гц. (Флуоресцентная лам-
па зажигается только тогда, когда напряжение на ней равно 90 В или выше, поэтому она
включается и выключается 120 раз в секунду, один для каждого изменения знака на-
пряжения.) Если частота вспышек индикатора будет кратна 120 Гц, то возникнут про-
блемы при наблюдении индикатора в условиях флуоресцентного освещении. Тот же
самый истинно в отношении 100 Гц в других странах, потому что в них используется
частота электрической сети, равная 50 Гц. Частота вспышек может иметь любое значе-
ние - вплоть до приблизительно 30 кГц. Если будет использоваться более высокая час-
тота вспышек, то возникающий электромагнитный сигнал начнет создавать помехи для
радиосвязи - в силу того FCC (Федеральный Комитет по Связи) не пропустит соответ-
ствующую систему в широкую продажу. Цифровые данные содержат значительное ко-
личество гармоник - вплоть до 15-ой гармоники. Частота вспышек в 30 кГц, умноженная
на 15 даст частоту в 450 кГц. FCC регулирует и лицензирует спектр радиочастот от 450 кГц и
выше. Если какое-либо цифровое устройство создает радиопомехи, то FCC не сможет
274
Применение микроконтроллеров PIC 18
выдать лицензию на соответствующий участок спектра, поэтому все цифровые устрой-
ства должны быть приняты и одобрены FCC.
Если должно измеряться напряжение, большее, чем 5 В, то на входе должен ис-
пользоваться делитель напряжения, понижающий напряжение до значений 0-5 В. На-
пример, чтобы отмасштабировать входной сигнал с коэффициентом 10 (0-50 В), вклю-
чите последовательно резисторы 9 кОм и 1 кОм между входом и землей, сняв входное
напряжение с резистора в 1 кОм. Для деления входного сигнала на коэффициент 100,
используйте резисторы 91 кОм, 9 кОм и 1 кОм, включенные последовательно, и сни-
майте входное напряжения с резистора в 1 кОм. Для этой цели нужно использовать
резисторы 91 кОм, 9 кОм и 1 кОм, точность номинала которых составляет +/-1 %. Рис. 7.11 ил-
люстрирует соответствующее подключение к микроконтроллеру с переключателем,
установленным на диапазон 0-500 В. Двусторонняя переключательная схема может
использоваться для выбора входа, заменяя механический переключатель. К сожале-
нию, в этом случае, аналоговые входы микроконтроллера будут ограничены логически-
ми уровнями TTL, так что все три входы не могут непосредственно подключаться к мик-
роконтроллеру для считывания напряжения.
ЖК-индикаторы
ЖКИ (жидкокристаллические индикаторы) заменили светодиодные индикаторы
во многих приложениях. Однако, ЖК-индикаторы (ЖКИ) трудно наблюдать в ситуациях
слабой освещенности, при этом размеры индикатора демонстрируют тенденцию к то-
му, чтобы быть довольно небольшими, так что светодиодные индикаторы все еще ис-
пользуются в ряде применений. Многие изготовители жидкокристаллических индика-
торов начали продавать ЖКИ с яркой подсветкой, чтобы преодолеть названную про-
блему наблюдаемости. Однако, если цена OLED (органические светодиоды) будет дос-
таточно низкой, то и ЖК-индикаторы, и стандартные светодиодные индикаторы просто
исчезнут.
Рис. 7.12 иллюстрирует подключение ЖК-индикатора Optrex DMC-20481 к микро-
контроллеру PIC18F1220. DMC-20481 - это 4-строчный индикатор, обеспечивающий
отображение 20 символов в строке, который принимает ASCII- коды как входные дан-
ные. Он также принимает команды, которые инициализируют его и управляют работой
индикатора. Как можно видеть из рис. 7.12, ЖКИ имеет только несколько подключений.
Информационные и управляющие подключения, соединенные с портом В, используют-
ся для того, чтобы ввести данные в индикатор и считать информацию из индикатора.
ЖКИ функционируют при 8-разрядном либо 4-разрядном интерфейсе данных. В дан-
ном примере использован 4-разрядный интерфейс данных с тем, чтобы уменьшить
число используемых штырьков - это распространенный способ подключения ЖКИ к
микроконтроллеру. При использовании 4-разрядного интерфейса данных, биты данных
от D4 до D7 используются в ЖКИ и передаются, биты от D0 до D3 не используются и не
подключаются.
Глава 7. Базовый ввод-вывод
275
Индикатор имеет четыре вывода управления. Вывод VEE корректирует контраст-
ность ЖКИ и обычно соединяется с потенциометром на 10 кОм. Вход RS (выбор регист-
ра) выбирает данные (RS = 1) или команды (RS = 0). Вход Е (разрешение) должен быть в
состоянии логической единицы для DMC-20481, чтобы считывать или записывать ин-
формацию, а также функционировать в качестве стробирующего входа, активного по
единичному импульсу. И, наконец, вывод R/W выбирает операцию чтения или записи.
Обычно вывод RS устанавливается в 1 или 0, вывод R/W устанавливается в 1 или 0, дан-
ные помещаются на выводы ввода данных, а затем подается импульс на вывод Е - либо
с целью занесения данных в DMC-20481, либо считывания данных из него. Этот инди-
катор также имеет два входа (LEDA [анод] и LEDK [катод)] для управления светодиода-
ми подсветки. Подсветка требует тока в 240 мА, который формируется при использова-
нии последовательно включаемого токоограничивающего резистора. Некоторые инди-
каторы имеют электролюминисцентную подсветку, которая для своей правильной ра-
боты требует 120 ВА для своей правильной работы. Электро-люминисцентная подсвет-
ка обеспечивается флуоресцентной трубкой. Некоторые индикаторы, которые исполь-
зуют светодиодную подсветку, имеют токоограничивающий резистор, встроенный не-
посредственно в индикатор.
С целью программирования и использования DMC-20481 в системе, он должен
быть инициализирован. Это относится к любым индикаторам, которые используют схе-
му управления индикатором HD44780 (фирма Hitachi), встроенную в индикатор или ее
эквивалент. Вся линия малых индикаторных панелей от фирмы Optrex и большинства
других изготовителей программируется аналогичным образом. Когда выполняется
первичное включение ЖК-индикатора, HD44780 выполняет последовательность команд
самопроверки, которая отображает последовательность символов черных квадратов
(ASCII код 0x7F) в первой строке индикатора. Перед тем, как индикатор сможет быть
использован в системе, упомянутые квадраты должны быть стерты, а индикатор должен
быть инициализирован выполнением нижеописанных шагов.
1. Подождать по крайней мере 15 мс после того, как напряжение на входе VCC
поднимется до 5 В.
2. Выдать команду установки функции (0x30 [8-битная] или 0x20 [4-битная]) и по-
дождать по крайней мере 4,1 мс.
276
Применение микроконтроллеров PIC 18
3. Выдать команду установки функции (0x30 или 0x20) еще раз и подождать по
крайней мере 100 мкс.
4. Выдать команду установки функции (0x30 или 0x20) третий раз и подождать по
крайней мере 40 мкс.
5. Выдать команду установки функции четвертый раз (0x38 для 8-битного интер-
фейса или 0x28 для 4-битного интерфейса) и подождать по крайней мере 40 мкс.
6. Выдать 0x01 для вывода курсора в исходную позицию и очистки индикатора,
подождать по крайней мере 1,64 ms.
7. Выдать команду активирования дисплея при выключенном курсоре (ОхОС), по-
дождать по крайней мере 40 мкс.
8. Выдать 0x06 для выбора автоматического инкрементирования, которое сдви-
гает курсор вправо всякий раз, когда на индикатор посылается символ, and wait at least
40 мкс.
Программа, выполняющая инициализацию Жк- индикатора, показана в примере 7.7. Она
достаточно длинна, однако контроллер индикатора требует такого длинного диалога
инициализации. Различные команды, посылаемые на ЖК-индикатор, предъявляют раз-
личные требования к временным задержкам. В табл. 7.1 перечислены временные за-
держки, требуемые для команд. Эта программа передает и принимает данные через
порт В. Для выдачи команды сброса 0x20, сначала выдается 2, а затем 0 через четы-
рехбитный интерфейс данных.
Пример 7.7
// предполагаемая тактовая частота равна 2 МГц
// при командном цикле в 2 мкс
#define LCD PORTB // определение порта данных
#define RS PORTBbits.RB5 // определение RS
#define E PORTBbits.RB4 // определение E
void SendLCDdata (char data, char rs)
{
LCD = data >: > 4; // передача левого полубайта
RS = rs; // управление RS
E = 1; // импульс Е
E = 0;
DelaylOTCYx (2) ; // задержка 40 мс
LCD = data & OxOF; // передача правого полубайта
RS = rs; // управление RS
E = 1; // импульс Е
E = 0;
DelaylOTCYx (2) ; // задержка 40 мс
)
void InitLCD (void)
{
char a;
DelaylKTCYx (10); // ожидание 20 мс (смотрите текст)
for (а =0; а < 3; а++)
{
SendLCDdata (0x20, 0); // выдача 0x20
DelaylKTCYx (3); // ожидание 6 мс
Глава 7. Базовый ввод-вывод
277
}
SendLCDdata (0x28, 0); // выдача 0x28
SendLCDdata (0x01, 0); // выдача 0x01
DelaylKTCYx (1); // ожидание 2 мс
SendLCDdata (ОхОС, 0); // выдача ОхОС
SendLCDdata (0x06, 0); // выдача 0x06
}
Таблица 7.1. Команды для большинства ЖК- индикаторов.
Команда Код Описание Время
Очистка индикатора 0000 0001 Очищает индикатор и выводит курсор в исходную позицию 1.64 мс
Вывод курсора в исходную позицию 0000 0010 Выводит курсор в исходную позицию 1.64 мс
Установка режима ввода 0000 01AS Устанавливает направление перемещения курсора (А = 1, инкрементирование) и сдвига (S = 1, сдвиг индикации) 4 0 мкс
Индикатор вкл/выкл 0000 1DCB Включает/выключает индика- тор (D = 1, вкл.) (С = 1, курсор вкл.) (В = 1, мига- ние курсора) 4 о мкс
Сдвиг курсора/индикации 0001 SR00 Устанавливает перемещение курсора и сдвиг индикации (S = 1, сдвиг индикации) (R = 1, вправо) 4 0 мкс
Задание функции 001L NFXX Программирует цепи ЖК- индикатора (L = 1, 8-битный интерфейс) (N = 1, 2 стро- ки) (F = 1, символы 5x10) (F = 0, символы 5x7) 4 0 мкс
Установка адреса ГСЗУПВ 01XX XXXX Устанавливает адрес ЗУПВ генератора символов 4 о мкс
Установка адреса ПОЗУПВ 10XX XXXX Устанавливает адрес ЗУПВ памяти отображения 4 0 мкс
Считывание флага занятости вооо 0000 Считывает флаг занятости (В = 1, занят) 0
Запись данных Данные Записывает данные в память отображения ЗУПВ или же ЗУПВ генератора символов 4 0 мкс
Считывание данных Данные Считывает данные из памяти отображения ЗУПВ или ЗУПВ генератора символов 4 0 мкс
Задержки, отрабатываемые в программе, являются несколько более длинными, чем
требуемые вследствие того, что имеется временная задержка в функции SendLCD, гаранти-
рующая, что отводимое время будет достаточным. Генератор, используемый в этом примере,
является RC-генератором, частота которого может изменяться. Как и в случае с другими при-
мерами, временные задержки могут настраиваться, если частота генератора (2 МГц) не будет
той же, которая используется в рассматриваемой схеме. Обратите внимание на то, что не-
большая временная задержка может оказаться необходимой перед и после каждого измене-
ния сигнала Е с целью снижения уровня электромагнитных помех для оборудования, которое
должно быть одобрено Федеральной Комиссией Связи.
278
Применение микроконтроллеров PIC 18
Как только ЖК-индикатор будет инициализирован, понадобятся несколько процедур,
необходимых для отображения информации и управления индикатором. После инициализа-
ции временная задержка в 40 мкс отрабатывается в функции SendLCDData, которая исполь-
зуется при посылке данных или ряда команд на индикатор. Команда очистки индикатора
также нуждается во временной задержке, потому что флаг занятости не используется с ко-
мандами в функциях по примеру 7.7. Вместо использования временных задержек может
проверяться состояние флага занятости с целью определения того, завершил ли индикатор
выполнение требуемой операции. Если используется флаг занятости, то вывод R/W подклю-
чается к биту 6 порта В в этом примере, он управляется при считывании ЖК-и иди катера.
Процедура проверки состояния флага занятости показаная в примере 7.8. Процедура BUSY
проверяет состояние ЖК-индикатора; при этом возврат из нее отрабатывается только
тогда, когда индикатор завершил выполнение предыдущей команды.
Пример 7.8
#define LCD PORTB // определяет порт данных
#define RS PORTBbits.RB5 // определяет RS
#define E PORTBbits.RB4 // определяет Е
#define RW PORTBbits.RB6 // определяет RW
#define LCD_TRIS TRISB // определяет LCD_TRIS
void SendLCDdataWbusy (char data, , char rs)
{
RW = 0; // выбирает режим записи
LCD = data >: RS = rs; E = 1; E = 0; > 4; // посылает левый полубайт // устанавливает RS // импульс Е
DelaylOTCYx (2) ; // задержка 40 мкс
LCD = data & RS = rs; E = 1; E = 0; OxOF; // посылает правый полубайт // устанавливает RS // импульс Е
DelaylOTCYx RW = 1; RS = 1; (2) ; // задержка 40 мкс // выбирает режим чтения // устанавливает R/W
LCD_TRIS = OxOF; RS = 0; E = 1; E = 0; data = LCD; // устанавливает RB0-RB4 как входы // команда считывания флага занятости // посылает старший полубайт // считывает бит занятости
while ((data { & 8) == 8)
E = 1; E = 0; // считывает младший полубайт
E = 1; // импульс Е
E = 0; // считывает старший полубайт
data = LCD; // считывает ЖК-индикатор
1 LCD_TRIS = 0 // программирует PORT В как выходной
Глава 7. Базовый ввод-вывод
279
Если эта новая процедура будет доступна, то данные могут посылаться на инди-
катор с выполнением операции записи без временных задержек в любое время. Диалог
инициализации установил курсор на автоматическое инкрементирование, поэтому,
если процедура WRITE будет вызываться более одного раза, то символы, записывае-
мые в индикатор, будут отображаться один рядом с другим, - так же, как на экране ком-
пьютерного дисплея.
Единственной другой процедурой, необходимой для базового использования ин-
дикатора, является процедура с именем CLS, выполняющая очистку индикатора и вы-
вод его курсора в исходное положение. Эта процедура показана в примере 7.9. Она
использует макрокоманду SEND из программы инициализации для того, чтобы послать
команду очистки индикатора. Используя процедуру CLS, а также процедуры, описанные
к данному времени, на индикатор можно вывести любое сообщение, очистить его, а
затем отобразить другое сообщение, выполняя базовые операции управления индика-
тором. Как упоминалось ранее, команда очистки индикатора требует для своего выпол-
нения временной задержки (по крайней мере равной 1,64 мс).
Пример 7.9
void CLS (void)
SendLCDdata (0x01, 0); // выдача 0x01
DelaylKTCYx (1); // ожидание 2 мс
Среди дополнительных процедур, которые могут быть разработаны, может быть
процедура выбора позиции в ЗУПВ отображения. Адреса ЗУПВ памяти отображения
начинаются с 0 и возрастают по мере загрузки индикатора символами - вплоть до ад-
реса последнего символа первой строки, равного 19. Как только адрес курсора или
=щрес отображения будет изменен, индивидуальные символы на индикаторе могут
быть изменены или считаны, при этом данные могут читаться с индикатора.
Байты, не используемые для памяти отображения, могут использоваться для хра-
нения данных. Поскольку микроконтроллер имеет ограниченное количество ячеек ЗУПВ
данных, то неиспользуемые ячейки памяти данных могут их дополнять. ЖК-индикагор
содержит 128 байтов памяти, адресуемой от 0x00 до 0x7F. Не вся эта память всегда
используется. Например, однострочный 20-символьный индикатор использует только
первые 20 байтов памяти (0x00-0x13). Первая строка любого из этих индикаторов все-
гда начинается с адреса 0x00. Вторая строка любого индикатора, управляемого
HD44780, всегда начинается с адреса 0x40. Например, двустрочный х40-символьный
индикатор использует адреса 0x00-0x27 для хранения ASCII-кодированных данных для
первой строки. Вторая строка в этом индикаторе сохраняется по адресам 0x40-0x67. В
четырехстрочных первая строка сохраняется, начиная от адреса 0x00, вторая - от адре-
са 0x40, третья - от адреса 0x14 и последняя строка - о г адреса 0x54. Самое большое
индикаторное устройство, которое использует HD44780, - это двустрочный х40-
символьный индикатор. Четырехстрочные х40-символьные индикаторы используют
М50530 или пару HD44780S. Информация, касающаяся этих устройств, может быть
найдена в Internet, поэтому она не приводится в этой книге.
Программа, приведенная в примере 7.10, отображает сообщение “Hello” (Привет)
в строке 1 индикатора 4x20, а во второй строке сообщение “I’m PIC18” (Я - PIC18). Этот
пример включает одну дополнительную функцию, отображающую пустую строку С-
стиля. Когда адресуется ячейка памяти, самый левый бит адреса должен быть в со-
280
Применение микроконтроллеров PIC 18
стоянии логической единицы (см. таблицу 7.1 для задания адреса ЗУПВ индикатора).
Например, для адресации первого символа в строке 1 используйте адрес 0x80. Анало-
гично, чтобы адресовать первый символ в строке 2 следует использовать адрес ОхСО
(0x40 + 0x80).
Пример 7.10
/*
* LCD example written for a PIC18F1220
* for a 2-MHz internal RC clock
*/
#include <pl8cxxx.h>
#include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
ftpragma config OSC = RC
#pragma config WDT = OFF
#pragma config LVP = OFF
ttpragma config BOR = OFF
#pragma config MCLRE = ON
#pragma code
char strl[] = "Hello";
char str2[] = "I'm the PIC18";
// главная программа
#define LCD PORTB
#define RS PORTBbits.RB5
#define E PORTBbits.RB4
// определение порта данных
// определение RS
// определение Е
void SendLCDdata (char data, char rs)
{
LCD = data >: > 4; // выдача левого полубайта
RS = rs; // управление RS
E = 1; E = 0; // импульс Е
DelaylOTCYx (2) ; // задержка 40 мс
LCD = data & OxOF; // выдача правого полубайта
RS = rs; // управление RS
E = 1; E = 0; // импульс Е
DelaylOTCYx (2) ; // задержка 40 мкс
}
void InitLCD (void)
Глава?. Базовый ввод-вывод
281
char az-
DelaylKTCYx (10); for (a =0; a < 3; a++) { SendLCDdata (0x20, 0); DelaylKTCYx (3); } SendLCDdata (0x28, 0); SendLCDdata (0x01, 0); DelaylKTCYx (1); SendLCDdata (OxOC, 0); SendLCDdata (0x06, 0); } void CLS (void) { SendLCDdata (0x01, 0); DelaylKTCYx (1); ) void String (char *str, char position) { int ptr = 0; SendLCDdata (position, 0); while (str(ptr) != 0) SendLCDdata (strfptr+t], ) void main (void) { ADCON1 = OxOF; сигналов TRISB = 0; PORTB = 0; InitLCD(); while (1) // ожидание 20 мс (см. текст) // выдача 0x20 // ожидание 6 мс // выдача 0x28 // выдача 0x01 // ожидание 2 ms // выдача ОхОС // выдача 0x06 // выдача 0x01 // ожидание 2 мс // выдача позиции , 1);// выдача символа // выбор всех цифровых // порт В - выход // все выводы порта В = 0 // инициализация ЖКИ
String (strl, 0x80);
String (str2, OxCO);
282
Применение микроконтроллеров PIC 18
Предположим, что данные на индикаторе должны смещаться слева направо, по-
добно индикатору “бегущей строки’’. Функция, которая посылает данные в строку 1 ЖК-
индикатора этим способом, показана в примере 7.11. Это выполняется посредством
передачи четырех символов в секунду на индикатор. Данная функция предполагает, чго
строка была очищена перед ее вызовом. Счетчик циклов в цикле for имеет тип char.
Если тип char используется вместо типа integer, то объем памяти, требуемый для цикла,
значительно снижается. Это важный момент при разработке программ для PIC.
Пример 7.11
void scroll (char *str)
(
char a;
char b;
for (a =0; a < strlen (str); a++)
(
for (b = 0; b <= a; b++)
{
SendLCDdata (0x80 | a-b, 0); // позиционирование в строке 1
SendLCDdata (str[ strlen (str) - b], 1);
}
DelaylKTCYx (125); // ожидание 1/4 секунды
}
)
Если число выводов, доступных на PIC ограничено числом, меньшим, чем шесть,
то следует использовать либо последовательный ЖК-индикатор, либо схему, приве-
денную на рис. 7.13. Эта схема использует только два вывода микроконтроллера для
управления ЖК-индикатором, однако требует один дополнительный компонент. В схе-
ме используется сдвиговый регистр, для получения данных от микроконтроллера. Один
вывод порта является входом данных для сдвигового регистра, а второй - источником
сигнала тактовой частоты. Посредством управления линией данных и линией сигнала
тактовой частоты, число посылается в сдвиговый регистр и далее в виде параллельного
кода - на ЖК-индикатор.
Эта схема разработана таким образом, чтобы, когда сигнал данных из микрокон-
троллера будет нулевым или значение Q5 будет нулевым, то сигнал Е также будет в ну-
ле. Чтобы получить сигнал тактовой частоты Е, поступающий на ЖКИ, как Q5, так и RB0
оба должны быть в состоянии логической единицы. Два диода и резистор номиналом в
1 кОм формируют логическую схему И. Диодные логические элементы все еще иногда
используются в современных цифровых электронных схемах, чтобы сэкономить затра-
ты, не вводя дополнительную интегральную схему.
В примере 7.12 приведена программа, требуемая для того, чтобы передавать
данные на ЖКИ. Поскольку данные являются последовательными, большинство вре-
менных задержек, требуемых для управления ЖК-индикатором, уже включены в саму
функцию, передающую данные на ЖК-индикатор. Единственная часть программы, ко-
торая является принципиально новой - это функция очистки сдвигового регистра
74НСТ164.
Глава 7. Базовый ввод-вывод
Рис. 7.13. 2-проводное подключение микроконтроллера к ЖКИ
284
Применение микроконтроллеров PIC 18
Пример 7.12
/*
* пример последовательного ЖКИ, написанный для PIC18F1220
*/
♦include <pl8cxxx.h>
♦include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
♦pragma config OSC = RC
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
♦pragma code
// main program
void clockShiftReg (void) i
PORTBbits.RB3 = 1; PORTBbits.RB3 = 0; // // И тактовый импульс на линия данных = 0 передача 6 тактовых RB3 импульсов
i void { i clearShiftReg (void) char a; PORTBbits.RBO = 0; for (a = 0; a < 6; a++) clockShiftReg () ;
J void { sendNibble (char nib, char RS) char a;
clearShiftReg(); // очистка сдвигового регистра
PORTBbits.RBO = 1; clockShiftReg(); // выдача Е
PORTBbits.RBO = RS; clockShiftReg(); for (a = 0; a < 4; a++) { PORTBbits.RBO = nib & clockShiftReg(); nib »= 1; // 1; выдача RS
Глава 7. Базовый ввод-вывод
285
}
void SendLCDdata (char data, char RS)
sendNibble (data » 4, RS);
// выдача левого полубайта
sendNibble (data, RS);
// выдача правого полубайта
void initLCD (void)
DelaylKTCYx (10) ; // ожидание 20 мс (смотрите текст)
SendLCDdata (0x20, 0); И выдача 0x20
DelaylKTCYx (3) ; // ожидание 6 мс
SendLCDdata (0x20, 0); // выдача 0x20
DelaylOTCYx (1) ; // ожидание 100 мкс
SendLCDdata (0x20, 0); И выдача 0x20
SendLCDdata (0x28, 0); И выдача 0x28
SendLCDdata (0x01, 0); И выдача 0x01
DelaylKTCYx (1) ; И ожидание 2 мс
SendLCDdata (OxOC, 0); И выдача ОхОС
SendLCDdata (0x06, 0); И выдача 0x06
void main (void)
1 ADCON1 = OxOF; И установ всех сигналов каь с цифровых
TRISB = 0; и порт В - выход
PORTB = 0; и все выводы порта В - = 0
initLCD(); и инициализация ЖКИ
// здесь вводятся данные для отображения
Таблица 7.2. Функции для работы с ЖК-индикатором
в расчете на использование контроллера HD44780
Функция Пример Примечание
BusyXLCD (void) while (BusyXLCD()); Проверка занятости ЖКИ
OpenXLCD (unsigned OpenXLCD (FOUR_BIT & Инициализирует ЖКИ на 4 бита
char init) LINES_5X7); данных и режим множественных строк символов FOUR_BIT на 4 линии данных EIGHT_BIT на 8 линий данных LINE_5X7 для одной линии LINE _5Х10 для одной линии LINES 5X7 для нескольких линий
putcXLCD (char data) See WriteDataXLCD Same as WriteDataXLCD
putsXLCD (char *buffer) putsXLCD (buffer); Отображает содержимое буфера в памяти данных, который содер- жит строку с нулевым раздели- телем
putrsXLCD (const rom char *buffer) putrsXLCD (buffer); Отображает содержимое буфера в памяти программ, который со- держит строку с нулевым разде- лителем
286
Применение микроконтроллеров PIC 18
Функция Пример Примечание
unsigned char addr = Считывает адрес в ЗУПВ индика
ReadAddrXLCD (void) ReadAddrXLCD(); тора из ЖКИ
char ReadDataXLCD data = Read- Считывает байт данных из ЖКИ
(void) DataXLCDO ;
SetCGRamAddr (un- SetCGRamAddr (0x40); Адресует символ @ в генераторе
signed char addr) символов
SetDDRamAddr (un- SetDDRamAddr (0x80); Адресует позицию символа
signed char addr) данных
WriteCmdXLCD (un- WriteCmdXLCD Записывает команду в ЖКИ
signed char cmd) (BLINK_ON); DON - идикатор вкл. DOFF - идикатор выкл. BLINK_ON - мигание курсора BL1NK_OFF • курсор но мигает CURSOR_OFF курсор выкл. SHIFT_RIGHT_CUR SHIFT_LEFT_CUR SHIFT_DISP_RIGHT SHIFT DISP LEFT
WriteDataXLCD (char WriteDataXLCD ('A'); Запись байта данных в ЖКИ
data)
Поддержка работы с ЖКИ в трансляторе С18
Транслятор С18 с языка С обеспечивает поддержку работы с ЖК-индикаторами через
функции, перечисленные в табл. 7.2. Эти функции собраны в файле заголовков xlcd.h. В приве-
денной таблице перечислен полный набор функций для работы с ЖК-индикаторами, включая
изменение данных в символьном генераторе, так что могут отображаться специальные
символы.
Чтобы использовать xlcd.h и его функции, должны быть обеспечены три времен-
ные задержки: DelayFor18TCY (для задержки в 18 командных циклов), DelayPorXLCD
(для задержки 15 мс) и DelayXLCD (для задержки 5 мс). Если файл заголовков оставить
без изменений, то вывод RB4 будет использоваться для сигнала Е, вывод RB5 - для
сигнала RS, вывод RB6 - для сигнала RW, а выводы от RB0 до RB3 будут использовать-
ся как 4-разрядный интерфейс данных индикатора. Простой пример, иллюстрирующий
использование файла заголовков xlcd, показан в примере 7.13. Вследствие того, что
вывод R/W должен использоваться для того, чтобы данные функции работали правиль-
но, что требует использования дополнительного вывода ввода-вывода, на практике эти
функции используются редко.
Пример 7.13
/*
* Пример последовательного ЖК-индикатора, написанный для PIC18F1220
*/
#include <pl8cxxx.h>
^include <delays.h>
#include <xlcd.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
Глава 7. Базовый ввод-вывод
287
- отключение сброса по частичной потере питания
- разрешение общего сброса
^pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
^pragma config BOR = OFF
^pragma config MCLRE = ON
// ROM DATA
near rom char strl[] = "I am PIC18F";
near rom char str2 [ ] = "How are you?'';
#pragma code
// главная программа
void DelayForl8TCY (void) //
{
DelaylOTCYx (2); //
}
void DelayPORXLCD (void)
DelaylKTCYx (15); //
}
void DelayXLCD (void)
(
DelaylKTCYx (5); //
}
void main (void)
{
ADCON1 = OxOF; //
/ / инициализация ЖКИ
OpenXLCD (FOURJ3IT & //
LINES_5X7);
while (1)
{
SetDDRamAddr (0x80); //
putrsXLCD (strl);
SetDDRamAddr (OxCO); //
putrsXLCD (str2);
для тактовой частоты, равной 4 мГц
20 мкс
задержка в 15 мс
задержка в 5 мс
выбор всех цифровых сигналов
открытие ЖКИ
строка 1
строка 2
Вакуумные флуоресцентные индикаторы
Вакуумные флуоресцентные индикаторы (ВФИ) наиболее часто используются в
сигнальных часах, а также в автомобильных радиочасах. Эти индикаторы обычно харак-
теризуются их сине-зеленым цветом, который является видимым во многих различных
ситуациях освещения, хотя следует отметить, что имеются ВФИ и с другим цветом све-
чения. ВФИ были первыми доступными электронными индикаторными устройствами,
которые предшествовали светодиодам. Эти модули (обычно вставные) часто встреча-
288
Применение микроконтроллеров PIC 18
ются во многих потребительских электронных устройствах, их срок службы составляет
до 80000 часов. Рис. 7.14 иллюстрирует внутреннюю конструкцию ВФИ. ВФИ работает
подобно триодной электронной трубке, за исключением того, что напряжение анода
ВФИ составляет от 10 до 15 В вместо сотен вольт, используемых в электронной трубке.
Нить накала (катод) связана с 1,5 В, ток через нее заставляет нить нагреваться и гене-
рировать облако электронов. Если к аноду прикладывается положительное напряже-
ние, то электроны притягиваются к аноду и когда они соударяются с ним, то производят
фотон света, который является видимым. Анод покрыт фосфором, который и опреде-
ляет окраску излучаемого света. Управляющая сетка, расположенная между анодом и
нитью накала, может быть подключена к небольшому отрицательному напряжению с
тем, чтобы оттолкнуть некоторые электроны, уменьшив тем самым яркость индикато-
ра. Обычно с управляющей сеткой связан переключатель, соединяющий ее либо с зем-
лей, либо с - 1 В. Если управляющая сетка заземлена, то индикатор светится ярко, а
если на нее подан -1 В, то индикатор не светится.
В силу того, что это устройство хорошо работает при напряжении 12 В, обеспечи-
вая достаточную яркость, в большинстве автомобилей оно используется в одометрах, а
также в индикаторах радиоприемников и часов. Что касается его программирования, то
это устройство доступно в последовательной версии, которая программируется по-
добно ЖК-индикаторам, поэтому соответствующий пример здесь не приводится.
Рис. 7.14. Внутренняя конструкция вакуумного флуоресцентного индикатора (ВФИ)
Глава 7. Базовый ввод-вывод
289
7.3. Управления электромоторами
В этом разделе обсуждается управления электромоторами. Несколько базисных
типов электромоторов управляются встроенными системами, включая шаговые элек-
тромоторы и электромоторы постоянного тока. В этом разделе рассматривается фор-
мирование интерфейса и программные примеры для каждого из упомянутых типов
электромоторов.
Шаговые электромоторы
Устройством, которое часто подключается к встроенной системе, является шаго-
вый электромотор. Шаговый электромотор обычно рассматривается как дискретный
электромотор, потому что он перемещает вал дискретными шагами, переходя через
360°. Обычный шаговый электромотор имеет передаточный механизм, обеспечиваю-
щий угол поворота приблизительно от 15° до Г на шаг в прецизионных шаговых элек-
тромоторах. Во всех случаях, эти шаги обеспечиваются через использование несколь-
ких полюсов магнита и (или) использование передаточных механизмов. Обратите вни-
мание, на то, что две противоположные катушки, показанные на рис. 7.15, возбуждают-
ся одновременно. Это называется полношаговым режимом и заставляет ротор повора-
чиваться на 0 °, 90 °, 180 ° и 270 °. С целью экономии мощности, одновременно может
возбуждаться только одна катушка, однако это снижает силу поворота.
На рис. 7.15 приводится четырехкатушечный шаговый мотор, в котором исполь-
зуется ротор с одним полюсом. Шаговый мотор показан в четырех состояниях с рото-
ром (постоянно намагничен), находящимся в четырех дискретных состояниях. Соответ-
ствующий поворот ротора достигается посредством запитывания пары катушек, как
показано на рисунке. Это иллюстрирует полношаговый режим. Шаговый мотор управ-
ляется с использованием N-канального полевого МОП-транзистора для обеспечения
значительного тока на каждую катушку. Усилитель на полевых МОП-транзисторах мо-
жет быть заменен усилителем на составном транзисторе Дарлингтона. Такой усилитель
5 содержит внутренние демпферные диоды, предназначенные для шунтирования любых
выбросов обратного индуктивного напряжения, генерируемых коллапсом магнитного
поля вокруг полевого МОП-транзистора.
Цепь управления шаговым мотором иллюстрируется рис. 7.16, на котором пока-
заны четыре катушки шагового электромотора. В этой цепи используется микрокон-
троллер, который формирует сигналы управления, используемые для поворота ротора
мотора либо по либо против часовой стрелки.
290
Применение микроконтроллеров PIC 18
Рис. 7.15. Шаговый электромотор
RBO
RB2
Информационные вхо/
RBI
RB3
Рис. 7.16. Схема управления шаговым электромотором
Глава 7. Базовый ввод-вывод
292
Применение микроконтроллеров PIC 18
Простая процедура на языке С, которая управляет электромотором (принимая,
что порт В запрограммирован как выходной порт), показана в примере 7.14. Эта функ-
ция вызывается с параметром шага, который содержит число шагов и направления
вращения. Если значение параметра шага больше, чем 0x8000, то мотор поворачивает-
ся в направлении вращения часовой стрелки; если значение параметра шага меньше,
чем 0x8000, то мотор поворачивается в направлении против вращения часовой стрел-
ки. Например, если значение параметра шага равно 0x0003, то мотор поворачивает
ротор против часовой стрелки на три шага, а если параметр шага равен 0x8003, то он
повернет ротор на три шага в направлении движения часовой стрелки. Крайний левый
разряд параметра шага удаляется, при этом остальные 15 разрядов содержат число
шагов. Обратите внимание, что в показанной процедуре используется временная за-
держка, равная 1,0 мс. Эта временная задержка требуется для того, чтобы дать ротору
шагового электродвигателя время на выход в следующую позицию.
Пример 7.14
char currentposition = 0x33;
void movestepper (int steps)
{
unsigned int a;
if ((steps & 0x8000) == 0x8000)
{
for (a =0; a < steps & 0x7FFF; a++)
(
_asm RLNCF currentposition, 1, BANKED _endasm
PORTB = currentposition;
}
)
else
{
for (a =0; a < steps; a++)
{
_asm RRNCF currentposition, 1, BANKED _endasm
PORTB = currentposition;
}
}
}
Текущая позиция ротора сохраняется в ячейке памяти currentposition, которая
должен быть инициализирована значением 0x33, 0x66, ОхЕЕ или 0x99. Это позволяет
при помощи простых команд RRNCF (шаг вправо) или RLNCF (шаг влево) формировать
двоичные битовые структуры для следующего шага посредством циклического сдвига.
При использовании Ассемблера в программе на языке С, должны быть включены все
поля команд, как это иллюстрируется в примере 7.14. Почему использовался Ассемб-
лер для того, чтобы осуществлять циклический сдвиг числа в ячейке памяти
Глава 7. Базовый ввод-вывод
293
currentPosition? В языке С имеется только команда сдвига, поэтому реализация цикли-
ческого сдвига на С будет намного более сложной - она будет сопряжена с расходова-
нием намного большего объема памяти и времени.
Шаговые электродвигатели также функционируют в режиме половинного шага,
который позволяет выполнять восемь шагов на одну последовательность. Это выпол-
няется при использовании описанной полношаговой последовательности, и формиро-
вании половинного шага за счет возбуждения только одной катушки из числа установ-
ленных между полными шагами. Режим половинного шага позволяет ротору позицио-
нироваться на 45°, 135°, 225° и 315° в дополнение к позициям режима полного шага.
Коды позиций режима половинного шага - это 0x11,0x22, 0x44 и 0x88. Полная последо-
вательность из восьми шагов, включающая половинные и полные шаги, имеет вид:
0x11, 0x33, 0x22, 0x66, 0x44, ОхСС, 0x88, и 0x99. Эта последовательность должна либо
извлекаться из поисковой таблицы, либо генерироваться программно.
На рис. 7.15 иллюстрируется 6-проводный шаговый электродвигатель. Также мо-
жет использоваться 4-проводный шаговый электродвигатель, в котором имеются по-
следовательно соединенные катушки с четырьмя проводами. Его основным недостат-
ком является то, что при управлении им должен использоваться двухполярный источ-
ник питания либо схема Н-образного моста.
Электромоторы постоянного тока
Электромотор постоянного тока является - это устройство, работающее либо в
релейном режиме (режим включения/выключения), либо в режиме, когда выполняется
управление, как его скоростью, так и направлением вращения. Названное управления
выполняется посредством изменения напряжение на электромоторе, либо посредст-
вом изменения продолжительности импульса, приложенного к электромотору. Здесь
рассматривается последняя методика, потому что она реализует наиболее распро-
страненный в настоящее время метод управления скоростью вращения электромото-
ров постоянного тока. В этом подразделе рассматривается управление электромото-
рами постоянного тока с использованием широтно-импульсного модулятора (ШИМ),
размещенного внутри микроконтроллера.
На рис. 7.17 приведены схемы управления, требуемые для того, чтобы управлять
электромотором постоянного тока как однонаправленным, так и двунаправленным уст-
ройством. На этой иллюстрации используются схемы управления на полевых МОП-
транзисторах, потому что в этом случае стоимость схем подобна стоимости схем на
биполярных переключательных транзисторах, кроме того в случае использования ин-
терфейса на полевых МОП-транзисторах требуется меньше деталей. Двунаправленная
схема управления оптически изолирована от схемы управления электромотором на Н-
образном мосте. Это распространенная практика, имеющая целью предотвращение
проблем и изоляцию микроконтроллера от схемы управления электромотором. С це-
лью управления электромотором управляющий вход Н-образного моста включает пару
противоположно включенных полевых МОП-транзисторов. Пороговое напряжение
большинства мощных полевых МОП-транзисторов является приблизительно равным
3.0 В. Для включения полевого МОП-транзистора на вход подается положительное на-
пряжение, превышающее порог, а для его выключения - напряжение, являющееся бо-
лее низким, чем пороговое. Поскольку полевые МОП-транзисторы - это устройства,
управляемые по напряжению, то можно было бы предположить, что ток затвора являет-
ся очень небольшим. Это истинно в случае мощного полевого МОП-транзистора, рас-
сматриваемого как отдельное устройство, однако на рис. 7.17 не показано то, что ты-
сячи полевых МОП-транзисторов включены в параллель внутри корпуса микросхемы с
294
Применение микроконтроллеров PIC 18
целью управления большими токами. Так как затвор полевого МОП-транзистора пред-
ставляет собой конденсатор, а когда конденсаторы включаются параллельно, то их
емкости складываются, то вход имеет довольно большую емкость. Заряд или разряд
емкости затвора может потребовать значительного тока. Например, довольно типично,
что переключение тока в 1 А при помощи мощного полевого МОП-транзистора требует
тока затвора, равного 1,5 мА. Однако, переключение тока в 12А потребует уже 150 мА
тока затвора. Таким образом, схемы управления для сильноточных применений требу-
ются для организации интерфейса микроконтроллера с мощными полевыми
МОП-транзисторами.
Чтобы изменить скорость вращения электромотора используется ШИМ-модулягор
микроконтроллера с тем, чтобы обеспечить схеме управления сигнал с переменной
шириной импульса. ШИМ использует таймер 2 и функционирует как схема управления
с одним выходом, или как схема управления с двумя выходами для половины 14-
образного моста, или же как схема управления с четырьмя выходами для управления
полным Н-образным мостом. Различные члены семейства имеют один или большее
количество ШИМ-модуляторов с целью управления более, чем одним электромотором.
Сигнал, подаваемый на электромотор, должен быть выше диапазона слышимых частот,
ибо в противном случае электромотор будет “петь” на частоте модуляции. Основная
частота ШИМ должна быть по крайней мере равной 5 кГц. (Большинство электромото-
ров механически не смогут вибрировать на частоте в 10 кГц, которая является слыши-
мой). Она должна также быть меньше, чем приблизительно 30 кГц, иначе могут возник-
нуть проблемы, если для изделия потребуется одобрение FCC. В большинстве случаев
8-разрядная ШИМ будет достаточна для управления большинством однонаправленных
электромоторов постоянного тока. Она обеспечивает 256 разных значений скорости.
Если будет производиться управление двунаправленны электромотором, то такая
ШИМ обеспечит 128 значений скорости для каждого направления, что может быть, а
может и не быть достаточным скоростей для полноценного управления. Чтобы генери-
ровать большее количество приращений скорости, требуется использование ШИМ
большей разрядности. К счастью, ШИМ в микроконтроллере имеет разрядность в 10
битов, что позволяет использовать вплоть до 1024 значений скорости. Вероятно, что
это более, чем достаточно для большинства применений.
В главе 6 был изложен вводный материал о таймерах, однако в ней не рассматривалась
работа таймера 2. Блок схема таймера 2 показана на рис. 7.18. Таймер 2 - это 8-разрядный
счетчик, обозначенный на рисунке как TMR2. Входом модуля таймера является системная
тактовая частота, разделенная 4, - она может дополнительно делиться предварительным де-
лителем на 1,4 или 16, как это программируется битами T2CKPS1 и T2CKPS0 регистра управ-
ления (T2CON) таймера 2. Например, если система использует тактовый генератор на 4 МГц, а
предварительный делитель установлен на коэффициент деления 4, то таймер будет инкремен-
тироваться один раз каждые 4 мкс (4 мГц/16 = 250 кГц). Регистр периода (PR2) определяет
значение отсчета, которое сбросит TMR2. Таймер 2 инкрементируется по каждому входному
тактовому импульсу, а затем, если PR2 равен TMR2, выполняется сброс таймера по приходу
следующго импульса тактовой частоты. Вход TMR2 делится на PR2 + 1. Например, если пред-
варительный делитель установлен на коэффициент деления, равный 4, входная тактовая час-
тота равна 4 МГц, a PR2 запрограммирован на 9, то выходная частота таймера 2 частота будет
равна 25 кГ ц.
Таймер 2 имеет два выхода: один используется для схемы ШИМ внутри микро-
контроллера, а другой устанавливает бит флага прерывания (TMR2IF), вызывающий
прерывание от таймера 2. Частота сигнала на флаг прерывания делится на коэффици-
ент, установленный для постделителя, который может программироваться на деление
сигнала от таймера 2 на любое целое число от 1 до 16.
Одно направление
Два направления
Глава 7. Базовый ввод-вывод
Управляющий вход
обратная цепь 12 В
Рис. 7.17. Схемы управления электромотором постоянного тока
цифровая земля
296
Применение микроконтроллеров PIC 18
TMR2
выход
уставов
TMR21F
T2CON
TOUTPS3 TOUTPS2 TOUTPSI TOUTPS0 TMR2ON T2CKPS1 T2CKPS0
TOUTPS3-TOUTPSO = постделитель (0000= 4-1,0001 = 4-2 to 1111 = 4-16)
TMR2ON = включение/выключение таймера 2 (0-выкл.; 1=вкл.)
T2CKPS1-T2CKPS0 = предварительное деление (00 = 4-1,01 = 4-4,1Х = 4-16)
Рис. 7.18. Блок-схема таймера 2 и его регистра управления
Перед тем, как начать рассмотрение программного обеспечения, предназначен-
ного для управления ШИМ и генерирования широтно-импульсно модулированного сиг-
нала управления электромотором, необходимо понять функционирование ШИМ. Мо-
дуль ССР (сбор данных/сравнение/ШИМ) включает широтно-импульсный модулятор,
имеющий до четырех выходов. В режиме сбора данных ССР регистрирует содержание
таймера 1 или таймера 3, когда на штырьке RB3 происходит событие. Событием может
быть нарастающий фронт сигнала, ниспадающий край, каждый четвертый нарастаю-
щий фронт сигнала или каждый 16-ый нарастающий фронт. Эти события используются
для того, чтобы измерить время между фронтами сигнала, отсчитываемое по таймеру 1
или таймеру 3. В режиме сравнения таймер 1 или таймер 3 сравнивается с CCPR1 (16-
разрядный регистр). Если имеет место соответствие, то RB3 устанавливается в со-
стояние логической единицы, нуля, переключается или вырабатывается запрос преры-
вания. Этот режим полезен для генерирования сигнала по истечении некоторого коли-
чества периодов тактовой частоты. Режим ШИМ, который является основной темой
данного подраздела, использует таймер 2 и функцию сравнения ССР для того, чтобы
генерировать выходной широтно-импульсный модулированный сигнал на штырьке Р1А,
который называется RB3 в большинстве версий микроконтроллеров. Это выходной
сигнал, предназначенный для управления однонаправленным электромотором. Если
половинный или полный Н-образный мост используется для того, чтобы управлять дву-
направленным электромотором, то используются выводы Р1А, Р1В или Р1А, Р1В, Р1С и
Р1D. Некоторые версии микроконтроллеров имеют более одного модуля ШИМ.
Глава 7. Базовый ввод-вывод
297
Рис. 7.19 иллюстрирует блок-схему ШИМ для случая 8-разрядного режима рабо-
ты и выходной сигнал, демонстрирующий рабочий цикл, равный 50%. (Рабочий цикл -
это время высокого состояния сигнала, поделенное на время его низкого состояния.)
Таймер 2 определяет период следования сигнала, a CCPR1L выбирает время высокого
состояния выходного сигнала, которое определяет рабочий цикл выхода ШИМ. Когда
TMR2 (таймер 2) досчитает до отсчета, предварительно запрограммированного PR2, то
выходной сигнал устанавливается в единицу и содержимое CCPR1L загружается в
CCPR1Н, при этом таймер 2 сбрасывается в ноль. Когда таймер 2 досчитывает до зара-
нее определенного отсчета, запрограммированного CCPR1L, то выходной сигнал сбра-
сывается. Например, для генерирования рабочего цикла в 50%, если PR2 запрограм-
мирован на 100, в CCPR1L нужно загрузить 50. Это приведет к установке выходного
сигнала каждый раз при очистке TMR2, а затем, когда TMR2 досчитает до 50, выходной
сигнал сбрасывается и остается в состоянии логического нуля до тех пор, пока отсчет
не достигнет 100, где выходной сигнал устанавливается снова. Рабочий цикл в 25%
будет получен, например, если PR2 запрограммирован на 100, a CCPR1L- на 25.
Предположим, что электромотор постоянного тока подключен к выводу Р1А
(RB3), см. рис. 7.20. Электромотор управляется только в одном направлении, так что
схема схемы управления электромотором не должна быть сложной. Этот интерфейс
использует кварцевый резонатор на 4 МГц для синхронизации и две кнопки, подклю-
ченные к РАО и РА1 для управления скоростью. Одна из этих кнопок обозначена как UP
(увеличить), а другая - DOWN (уменьшить). Кнопка UP увеличивает скорость вращения
электромотора, а кнопка DOWN - уменьшает ее. Если ШИМ генерирует сотни рабочих
циклов выходного сигнала, то много работы нужно для того, чтобы изменить скорость
вращения от остановки до полной скорости, поэтому пример 7.15 использует только 10
различных скоростей. Электромотор в этом примере мог бы быть электромотором по-
толочного вентилятора.
Пример 7.15
период ШИМ = (PR2 +1) х TMR2PS х 4 х Tosc
период ШИМ = (10+1) х4х4х1/4 мкс
= 11 х 4 х 1 мкс
= 44 мкс
период ШИМ = 1/44 мкс = 22,7 кГц
Примечание: TMR2PS содержит коэффициент предварительного деления
для таймера 2)
Системная программа, показанная в примере 7.16, программирует ШИМ на пе-
риод в соответствии с уравнением по примеру 7.15. В этом примере частота ШИМ рав-
на 22,7 кГц. Тактовая частота таймера 2 - это всегда частота тактового генератора, раз-
деленная на 4. В этом случае тактовая частота таймера 2 равна 1 МГц, потому что в сис-
теме используется тактовый генератор на 4 МГц. Вследствие того, что предваритель-
ный делитель таймера 2 настроен на коэффициент деления, равный 4, то таймер 2 бу-
дет работать на частоте 250 кГц. Таймер 2 запрограммирован на сброс после того, как
досчитает от 0 до 10 (PR2). Таймер 2 считает от нуля до 10, а затем сбрасывается, деля
вход тактовой частоты в 250 кГц на 11 (250 кГц/11 = 22,7 Гц). Эта частота не является
слышимой.
298
Применение микроконтроллеров PIC 18
ПерИОД (PR2+1)
-«-рабочий цикл(ссрк1Т)
Выходной сигнал ШИМ
Рис. 7.19. Структурная схема ШИМ и форма выходного сигнала
Начальный отсчет CCPR1L равен 11. Это заставляет вывод выходного сигнала
ШИМ (RB3) устанавливаться в состояние логической единицы, потому что выходной
сигнал компаратора ССР никогда не сбрасывает внутренний RS- триггер. Аналогично,
если CCPR1L будет запрограммирован нулем, то выходной сигнал станет постоянным
логическим нулем, потому что выходная фиксирующая схема будет постоянно сброше-
на. Логическая 1, поданная на вход схемы управления электромотором, связанный с
RB3, заставляет схему управления КМОП выключиться, потому что нет никакого вход-
ного напряжения. Это останавливает электромотор. Если кнопка UP будет нажата, то
содержимое CCPR1L декрементируется на 10. Это заставляет выход ШИМ сгенериро-
вать сигнал, который будет в состоянии логической 1 на протяжении 10 отсчетов и в
состоянии логического 0 на протяжении 1 отсчета. Схема управления КМОП будет
включена для 1 отсчета и выключена для 10 отсчетов. Рис. 7.21 показывает несколько
сигналов для нескольких различных установок CCPR1L.
U1
PIC18F1220
UP
C2-T
22 pF
16
15
RAO
RA1
RA2
RA3
RA4
#MCLR
0SC1 $RB6
0SC2 >RB7
>RB1
RB2
RB3
RB4
RB5
9
17
18
C1
1.0 uF
12
13
Глава?. Базовый ввод-вывод
8
Or 80 -~~
Рис. 7.20. Управление однонаправленным электромотором постоянного тока
300
Применение микроконтроллеров PIC 18
1-------------------------------------------------------------
о
останов (CCPR1L = 11)
1
о_____________________________________________________________
полная скорость (CCPR.1L = 0)
1
45%(CCPR1L = 6)
I
0
18%(CCPRIL = 9)
Рис. 7.21. Несколько сигналов для пояснения схемы (см. рис. 7.19)
и программы в примере 7.14
Пример 7.16
/*
* Управление скоростью электромотора для PIC18F1220
*/
♦include <pl8cxxx.h>
♦include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
♦pragma code
// главная программа
void Switch (char bitP)
// устранение дребезга контактов
// переключателей
Глава 7. Базовый ввод-вывод
301
{
do //ожидание отпускания (биты =- 3)
{
while ((PORTA & bitP) != bitP);
DelaylKTCYx (15);
}while ((PORTA & bitP) != bitP);
do // ожидание нажатия (биты 1= 3)
while ((PORTA & bitP) == bitP); DelaylKTCYx (15); Jwhile ((PORTA & bitP) == bitP); )
void main (void) {
ADCON1 = OxOF; // объявление всех сигналов
// цифровыми
TRISB = 0; // порт В - выход
TRISA = 3; // биты 0 и 1 порта А - входы
T2CON = 1; // настройка предварительного
// делителя на коэффициент деления 4
CCP1CON = OxOC; // модуль ССР выкл, выход с
// активным высоким уровнем
TMR2 = 0; // очистка таймера 2
PR2 = 10; // таймер 2 сбрасывается на 10;
CCPR1L = 11; // останов электромотора (11)
T2CONbits.TMR2ON = 1; while (1) { //запуск таймера 2 и ШИМ
Switch (3); контактов // проверка и устранение дребезга
if (PORTAbits.RAO == 0) if (CCPR1L != 0) CCPR1L— ; else И нажатие кнопки UP (быстрее)
if (CCPR1L != 11) CCPR1L++; и нажатие кнопки DOWN (медленее)
В этой программе CCP1CON (регистр управления ССР) программируется для то-
го, чтобы выбрать режим работы регистра модуля ССР. Рисунок 7.22 иллюстрирует
содержимое регистра управления ССР модуля. В этом примере CCP1CON программи-
руется на ОхОС, что обеспечивает выбор одного выход (Р1 А), который является актив-
ным по логической единице. Различные режимы работы и сигналы, доступные на Р1А
через выводы P1D иллюстрируются на рисунке 7.23. Выходы Р1А и Р1С предназначены
для активирования одного из нагрузочных полевых МОП-транзисторов в Н-образном
мосте, в то время как сигнал перемещения электромотора поступает на выходные вы-
воды Р1D или Р1В для формирования результирующего выхода моста.
302
Применение микроконтроллеров PIC 18
CCP1CON
P1MI Р1М0 DC1B1 DC1B0 ССР 1 М3 ССР 1 М2 ССР! Ml ССР! МО
Р1М1 — Р1 МО Биты конфигурирования выхода ШИМ
00 = один выход Р1А
01 = полномосговой выход - вращение вперед
10 = полумостовой выход
11 = полномостовой выход - вращение назад
DC1В1 — DC1 ВО Биты расширения ШИМ
Младшие биты 10-битного сигнала ШИМ
ССР1 М3—ССР1 МО Биты выбора режима
0000 = сброс ССР
. 0001 = не используется
0010 = режим сравнения, переключение по соответствию
0011= не используется
0100 = режим регистрации, по каждому срезу
0101 = режим регистрации, по каждому нарастающему фронту
0110= режим регистрации, по каждому 4му нарастающему фрош у
0111= режим регистрации, по каждому 16му нарастающему фронту
1000 = режим сравнения, установ по соответствию
1001 = режим сравнения, сброс по соответствию
1010 = режим сравнения, генерирование прерывания по соответствию
1011= режим сравнения, переключение по специальному событию
1100 = режим ШИМ, Р1А, Р1С активен по логической единице, Р1 В, P1D активен по логи-
ческой единице
1101= режим ШИМ, Р1 А, Р1С активен по логической единице, Р1 В, Р1D активен по ло1 и-
ческому нулю
1110= режим ШИМ, Р1 А, Р1С активен по логическому нулю, Р1В, Р1D акшвен по логиче-
ской единице
1111= режим ШИМ, Р1А, Р1С активен по логическому нулю, Р1 В, Р1D аюивен по логиче-
скому нулю
Рис. 7.22. Регистр управления ССР
Глава 7. Базовый ввод-вывод
303
Р1А
Р1В
Полумост
Р1А 1
о
Р1В --------------------------------
Р1С о______________________________
P1D | |
Полный мост, вперед
Р1А
0
Р1В | |
Р1С _______________________________
1
РШ о_______________________________
Полный мост, назад
Рис. 7.23. Полу- и полномостовой выход блока ШИМ
Предположим, что электромотор должен управляться от устройства типа джой-
стика, которое содержит потенциометр. Потенциометр задает напряжение, по мере
того, как ручка джойстика перемещается от одного крайнего положения к другому. По-
скольку микроконтроллер содержит АЦП, выход джойстика используется как вход для
этого АЦП, генерируя дискретное число, которое соответствует установке ручки джой-
стика. АЦП генерирует 8-разрядное значение, которое используется как вход для ШИМ
с целью управления скоростью и направлением вращения электромотора, связанного с
микроконтроллером как Н-образный мост, управляемый полевым МОП-транзистором.
Такая система изображена на рис. 7.24. В этой схеме четыре IRF540N управляют током,
который может достигать вплоть до 33 А, так что этой схемой может управляться до-
вольно большой электромотор. В этой схеме также используются оптические развязки,
изолирующие схему управления электромотором от микроконтроллера. Схемы управ-
ления для полевых МОП-транзисторов требуются в случае управления электромотора-
ми, потребляющими большие токи.
о
R11
ДЖОЙСТИК
R10
10K
U1
---5- RAO °RBO -!------
---f- RA1 >RB1 -77—
---7~ RA2 RB2 -Tfg—
18
10
3
---s- RA3
---iH RA4
#MCLR
PIC 18F1220 из
C2
-O
CRYSTAL
C3
22 pF
1.0 uF
C1
22 pF
RB3
RB4 Hr?
RB5
RB6
RB7
11
12
13
12V
батарея
Применение микроконтроллеров PIC18
Рис. 7.24. Управление электромотором от джойстика
Глава 7. Базовый ввод-вывод
305
Полномостовые сигналы используются для того, чтобы управлять электромото-
ром в рассматриваемой схеме . В прямом направлении логическая единица на Р1А
(RB3) включает полевой МОП-транзистор Q3. Логический ноль на Р1С (RB6) выключает
полевой МОП-транзистор Q1. Прямой сигнал от ШИМ прикладывается к P1D (RB7) и к
Q2. В режиме прямого вращения электромотора пара Q2 и SQ3 активна, что позволяет
току течь от вывода “+” на электромоторе к выводу вращая ротор электромотора в
прямом направлении. В режиме обратного вращения электромотора Q3 выключается, а
Q1 - включается, при этом сигнал от ШИМ поступает на Р1В (RB2), управляя Q4. В ре-
жиме обратного вращения электромотора Q1 позволяет току течь через электромотор
от вывода к выводу “+” через Q4, вращая ротор электромотора в обратном направ-
лении.
Джойстик подключен к штырьку RA0 или аналоговому входу номер ноль АЦП. Про-
грамма по примеру 7.17 считывает напряжение с джойстика и генерирует цифровой
вход ШИМ с целью управления скоростью и направлением вращения ротора электро-
мотора.
Пример 7.17
* Программа управления электромотором от джойстика, написанная для PIC18F1220
’/
♦include <pl8cxxx.h>
* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
’ - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
♦pragma code
' main program
dnar getJoy (void)
ADCONObits.GO = 1; //начало преобразования
while (ADCONObits.GO == 1); // ожидание завершения
return (ADRESL » 2 | (ADRESH « 6) ;
void main (void)
ADCONO = 1;
ADCON1 = OxOe;
напряжения
// выбор входа ANO, активирование АЦП
// ANO - аналоговый вход, VDD и VSS - опорные
306
Применение микроконтроллеров PIC 18
ADCON2 = 0х8С; TRISA = 1; TRISB = 0; // преобразование с использованием 1 мГц
// бит 1 порта А = выход
// порт В - выход
T2CON = 0; // выбор предвар. Делителя или деление на 1
CCP1CON = 0х4С; TMR2 = 0; PR2 = Oxff; while (1) { // модуль ССР выкл, полный мост, выходной сигнал // активен по логической единице // сброс таймера 2 // таймер 2 сбпрасывается на 255;
CCPR1L = getJoyO // считывание джойстика; изменение скорости
7.4. Реле, соленоиды и датчики
В данном подразделе рассматривается то, как нужно организовывать интерфейс
и осуществлять управление различными приборами, включая реле, соленоиды и раз-
нообразные датчики.
Реле
Реле используются для переключения нескольких сигналов или напряжений од-
новременно, они имеют много применений. Имеются электромеханические, а также
интегральные реле. Наработка электромеханических реле на протяжении их срока
службы составляет от 10000 до 100000 циклов. Интегральные реле имеют более длин-
ные сроки службы.
Рис. 7.25. Подключение небольшого реле к микроконтроллеру
Глава 7. Базовый ввод-вывод
307
Подключение электромеханического реле к микроконтроллеру обычно требует использо-
вания схемы управления, потому что ток обмотки реле обычно выше, чем 3 мА (логическая еди-
ница), доступный на выходном выводе. Рис. 7.25 иллюстрирует подключение реле к выводу RB0
микроконтроллера. В этом примере реле используется для того, чтобы управлять лампочкой
можностью 25 Ватт, подключенной к сети 120 В. Этот рисунок также иллюстрирует простую схе-
му управления на одном транзисторе, используемую для включения реле. Данное реле требует
ток обмотки 60 мА. Усиление транзистора 2N2222A, как минимум, равно 100, поэтому базовый
ток будет равен 60 мА/100 или 0,6 мА. Так как минимальное напряжение логической единицы,
снимаемое со вывода порта микроконтроллера, равно 4,2 В, то падение напряжения на резисто-
ре базы будет равно 3,5 В. Значение резистора в цепи базы определяется как 3,5 В/0,6 мА или
5833 Ом. Самое близкое стандартное значение номинала резистора равно 5,6 кОм. Диод защи-
щает транзистор от бросков индуктивного напряжения, возникающих во время возмущения маг-
нитного поля вокруг обмотки реле. Без этого диода транзистор был бы выведен из строя сразу
же после первого выключения реле, потому что падение напряжения на транзисторе при этом
будет приблизительно равным 12000 В, (6 мА х 20 кОм, которое является сопротивлением запер-
того состояния транзистора).
Рис. 7.26. Управление интегральным реле
Рис. 7.26 иллюстрирует то же самое применение реле, что и на предыдущем, од-
нако используется реле в интегральном исполнении (твердотельное реле). В данном
случае используется интегральное реле фирмы Clare, рассчитанное на ток величиной
10 А. Ток, протекающий через встроенный светодиод, должен быть по крайней мере
равным 10 мА, поэтому необходим транзисторный ключ для усиления тока от микро-
контроллера. Падение напряжения на светодиоде равно 1,2 В. Резистор базы в этом
примере обеспечивает намного больший ток, чем требуемый для включения инте-
грального реле.
308
Применение микроконтроллеров PIC 18
Соленоиды
Соленоиды управляются абсолютно аналогичным способом, однако они не имеют
контактной группы. Соленоиды используются для того, чтобы переместить объекты на
короткое расстояние. Например, соленоид используется в кассовом аппарате, чтобы
открыть выдвижной кассовый ящик, перемещая арретир приблизительно на 5 мм
(1/4"). Как только арретир будет сдвинут, пружина продвигает ящик. Соленоид в кассо-
вом аппарате требует ток, приблизительно равный 0,5 А, при своем срабатывании от
12 В. Для того, чтобы гарантировать, что ящик прошел арретир, соленоид запитывается
приблизительно в течении 500 мс. Схема управления для соленоида иллюстрируется
на рис. 7.27, а программа, которая использует таймер 3 микроконтроллера и прерыва-
ния, показана в примере 7.18. Таймер настраивается таким образом, чтобы микрокон-
троллер мог делать другие операции в течение 500 мс, требуемых для подключения
питания к соленоиду. Усилитель на паре Дарлингтона MPSA13 имеет усиление 10000 и
обеспечивает максимальный непрерывный ток в 500 мА.
Рис. 7.27. Схема управления соленоидом
Пример 7.18
#include <timers.h>
void
OpenDrawer (void)
открытие ящика
WriteTimerO (64560);
программирование таймера О
для деления на 976
OpenTimerO (TIMER_INT_ON &
T0_16BIT &
TO_SOURCE_INT &
T0_PS_l_256);
// вкл. прерывания от таймера О
// таймер 0 - 16-битный
// внутренняя синхронизация таймера О
// предварительный делитель таймкера 0 на 256
PORTBbits.RBO = 1;
// настройка RB0
Глава 7. Базовый ввод-вывод
309
TimerOInt (void) // процедура обслуживания прерывания
INTCON.TMROIF = 0; // сброс прерывания
PORTBbits.RBO = 0; // сброс RB0
CloseTimerO(); // отключение таймера 0
Пример 7.18 использует две функции. Программа, требуемая, чтобы активировать
структуру прерываний микроконтроллера, не показана. Одна функция открывает выдвижной
ящик, помещая логическую единицу на вывод RB0 и запуская таймер 0, так что он вызывает
прерывание по 500 мс. Другая - это процедура обслуживания прерывания для таймера 0,
которая помещает логический ноль на вывод RB0 и останавливает таймер. В этом примере
предполагается, что используется тактовая частота RC-генератора, равная 2 МГц. Так как
тактовая частота делится на 4 прежде, чем поступает на предварительный делитель
Таймера 0, то на вход таймера после предварительного делителя будет поступать сиг-
нал с частотой 500 кГц (2 мкс), разделенный на 256, или 1953 Гц (512 мкс). Если таймер
установлен таким образом, чтобы переполняться через 976 тактовых циклов, то он бу-
дет выставлять прерывания от Таймера 0 через 499,7 мс после того, как будет запущен
дли открыт. Функция WriteTimerO (64560) программирует таймер 0 так, что он вызывает
прерывание по переполнению через 976 периодов тактовой частоты. Вызов этой функ-
ции может быть также записан как WriteTimerO (-976), что может быть немного более
понятно. Разрешение прерываний здесь не показано, не отражено оно и в процедуре
обслуживания прерывания - единственной функции, которая вызывается в данном
примере, когда происходит прерывание от таймера 0.
В этом примере используется включаемый файл timers.h, чтобы обеспечить
функции, которые управляют таймером. Когда таймер прерывает микроконтроллер,
вывод RB0 переводится обратно в состояние логического нуля и прерывание от тайме-
ра 0 будет запрещено, пока выдвижной ящик не будет еще раз открыт вызовом функции
OpenDrawer. Этот процесс генерирует импульс на RB0 продолжительностью в 500 мс.
Более подробная информация о файле timers.h приведена в главе 8 при обсуждении
ввода - вывода с управлением по прерываниям.
Почему временная задержка не использовалась для задания времени срабатыва-
ния соленоида? Если используется временная задержка, то ничто иное в системе не
будет работать на протяжении времени отработки этой задержки. Другими словами,
система не будет доступной в течении 500 мс, т.е. то время, когда отрабатывается
временная задержка. Для временных задержек порядка нескольких миллисекунд это не
составляет никаких проблем, но для длительных временных задержек системе может
все же потребоваться делать что-то еще. Таймер и прерывания - это часто самый луч-
ший подход к организации временных задержек, длительность которых превосходит
несколько миллисекунд.
Датчики
Имеется множество типов датчиков. Некоторые рассматриваются здесь, а другие
- в последующих главах. Не все датчики рассматриваются, потому что имеется очень
много разных типов датчиков. В этом учебнике представлена только иллюстративная
выборка датчиков.
Один распространенный тип датчика - это датчик температуры. Рис. 7.28 иллюст-
рирует датчик LM70 от фирмы National Semiconductor, подключенный с помощью ин-
310
Применение микроконтроллеров PIC 18
терфейса к микроконтроллеру. Само по себе данное устройство - это достаточно ма-
ленький датчик температуры, который может устанавливаться почти в любом месте.
LM70 имеет вход выбора микросхемы, разрешающий операцию чтения или записи,
вывод SI/O для последовательных данных и вход SC, который функционирует как по-
следовательный сигнал тактовой частоты. Чтобы читать температуру, нужно поместить
логический ноль на вход выбора микросхемы, а затем подать импульс на вход SC. По-
сле подачи импульса на вход SC, считывается бит значения температуры с вывода SI/O.
Единственная причина обеспечения возможности передачи данных в LM70 состоит в
том, чтобы иметь возможность считать код изделия изготовителя, который обычно не
требуется в большинстве систем. Первый бит данных будет доступен, когда вход выбо-
ра микросхемы будет заземлен; второй и последующие биты данных появляются через
70 нс после среза импульса на входе SC.
Температура
1 1 1 X X
9-бит целая часть 2-бита дробная часть
Рис. 7.28. Пример подключения датчика температуры
Глава 7. Базовый ввод-вывод
311
Данные значения 16-разрядной температуры появляются на штырьке Sl/О по од-
ному биту одновременно, начиная с самого старшего бита. Сама температура считыва-
ется, как это иллюстрируется на рис. 7.27, таким образом, что формируется
11-разрядное значение температуры, которое в случае своей отрицательности имеет
форму дополнения до двух. Даже при том, что самые правый пять битов не содержал
никаких данных, они должны считываться каждый раз, когда значение температуры
получается от LM70. Программа считывания температуры показана в примере 7.19.
LM70 выдает только температуру в градусах Цельсия, однако в показанном примере
температура по шкале Фаренгейта возвращается как округленное целое число со зна-
ком из функции getTemp.
Пример 7.19
* Пример программы получения температуры, написанный для PIC18F1220
*/
«include <pl8cxxx.h>
’* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
’/
^pragma config OSC = RC
^pragma config WDT = OFF
♦pragma config LVP = OFF
«pragma config BOR = OFF
♦pragma config MCLRE = ON
♦pragma code
1 главная программа
♦define SC PORTBbits.RB2
♦define CS PORTBbits.RBO
♦define SIO PORTBbits.RBI
void sendClock (void)
SC = 0;
SC = 1;
// SC = 0
// SC = 1
_nt getTemp (void)
int temp;
int b;
char a
CS = 0;
for (a = 0; a < 16; a++)
// #CS = 0;
// получение 16 битов
312
Применение микроконтроллеров PIC 18
temp «= 1;
temp != SIO » 1;
sendClock();
1
a = 0;
CS = 1; // #CS = 1
if ((temp & 0x8000) == 0x8000) // проверка знака
{
а = 1; temp = -temp; //
преобразование в положительное
J b = temp; temp »= 7 ; if ((b & 1) == 1) // округление результата
temp++; temp = (9 * temp) / 5 + 32; // преобразование в градусы Фаренгейта
if (a) temp = -temp; return temp; // возврат с температурой
J void main (void) { ADCON1 = OxOf; // все выводы порта цифровые
TRISB = 0x02; // программирование порта В
PORTB = 0x05; // #CS = 1 и SC = 1
// здесь выполняется другая работа
Устройства кодирования угла поворота вала
Устройства кодирования угла поворота - устройства, которые обычно содержат
оптические датчики, сообщающие о позиции вала. Эти датчики выдают выходные сиг-
налы самой различной разрядности - от 2 битов, указывающих позицию вала шагами по
90°, до устройств кодирования, которые производят тысячи импульсов на один оборот
вала. Некоторые из названных устройств формируют двоичный выходной сигнал, а не-
которые - только импульс на сигнальной линии. Устройства кодирования угла поворота
вала, кодирующие выходные данные, выдают информацию в виде кода Г рея или есте-
ственного двоичного кода. Код Грея в случае 3-разрядного устройства кодирования
соответствует следующей последовательности: ООО, 001,011, 111, 110, 100. Обратите
внимание, что только один разряд изменяется одновременно от одного значения кода
до следующего. 3-разрядный код Грея имеет шесть состояний, 4-разрядный код Грея
имеет восемь состояний и т.д.
Рис. 7.29 иллюстрирует устройство кодирования угла поворота вала, связанное с мик-
роконтроллером. Здесь устройство кодирования угла поворота вала S4 от фирмы US Digital
Глава 7. Базовый ввод-вывод
313
подключено к микроконтроллеру. Это устройство кодирования угла поворота вала использует
интерфейсный кабель с 4 проводами, который содержит + 5 В (вывод 1), землю (вывод 3),
сигнал А (вывод 2) и сигнал В (вывод 4). Линии сигнала А (самый младший бит) и сигна-
ла В формируют коды 00, 01, 11, 10 (код Грея) по мере вращения вала в прямом на-
правлении и коды 10, 11,01,00, когда вал вращается в обратном направлении.
Рис. 7.29. Устройство кодирования угла поворота вала,
подключенное к PIC18F1220
Предположим, что устройство кодирования угла поворота вала используется для
того, чтобы измерить скорость вращения вала электромотора. Электромотор вращает-
ся со скоростью вплоть до 4000 оборотов в минуту. Он вращается до 67,7 раз за секун-
ду, при этом выход устройства кодирования угла поворота вала изменяется вплоть до
267 раз в секунду. Чтобы измерить эту скорость, входы микроконтроллера должны дискрети-
зироваться, по крайней мере, каждые 3,75 мс. Образец программы (см. пример 7.20) про-
веряет входы RB0 и RB1 через каждые 1,024 мс с тем, чтобы обнаружить соответст-
вующие изменения. Прерывание используется для того, чтобы выполнить проверки и
определить, вращается ли электромотор по часовой стрелке или против часовой
стрелки, а также регистрировать скорость в оборотах в минуту в целочисленной ячейке
памяти с именем speedRPM. Значение скорости будет точным в диапазоне от 15 обо-
ротов в минуту до 4000 оборотов в минуту. Если необходимо определить более мед-
ленную скорость, то частота прерываний должна быть уменьшена от одного на каждую
1,024 мс. Например, если эта частота будет снижена до одного прерывания каждые
10,24 мс, то значение скорости будет точным в диапазоне от 1,5 оборота в минуту до
4000 оборотов в минуту.
314
Применение микроконтроллеров PIC 18
Пример 7.20
/*
* Пример определения скорости и направления вращения для PIC18F1220
*/
#include <pl8cxxx.h>
#include <timers.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
#pragma config OSC = HS #pragma config WDT = OFF // предполагает тактовую частоту в 4 мГц
#pragma #pragma #pragma config LVP = OFF config BOR = OFF
config MCLRE = ON
void MyHighlnt (void); // прототипы для прерываний
#pragma interrupt MyHighlnt // MyHighlnt - это прерывание
#pragma code high_vector=0x08 void high_vector (void) // high_vector - это вектор по адресу 0x08
_asm GOTO MyHighlnt _endasm
1
// данные в памяти данных
int speedRPM; // скорость в оборотах за минуту
char direction; // направление: 1 = вперед
// 0 = назад
char lastcount; // здесь должна храниться самая последняя позиция
int timer; // значение отсчета
// высокоприоритетное прерывание
#pragma code
void TimerO (void)
{
char temp = PORTB & 3;
WriteTimerO (OxFC); // таймер 0 на 252
OpenTimerO (TIMER_INT_ON & T0_8BIT & TO_SOURCE_INT & T0_PS_l_256) ; if (lastCount != temp) // включение прерывания от таймера 0 // таймер 0 - 16-разрядный // синхронизация таймера 0 - внутренняя // предварительный делитель таймера 0 на 256
switch (lastcount)
Глава 7. Базовый ввод-вывод
315
(
case 0:
{
if (temp == 1)
direction = 1;
else
direction = 0;
break;
1
case 1:
(
if (temp == 2)
direction = 1;
else
direction = 0;
break;
1
case 2:
{
if (temp == 0)
direction = 1;
else
direction = 0;
break;
1
case 3:
{
if (temp == 2)
direction = 1;
else
direction = 0;
break;
1
1
speedRPM = timer / 1.024 * 15; // количество прерываний для 90
градусов
timer = 0;
}
else
timer++;
void MyHighlnt (void)
(
if (INTCONbits.TMROIF == 1)
TimerO () ;
// main program
void main (void)
(
ADCON1 = OxOf; 11 все выводы порта - цифровые
TRISB = 0x00; // программирование порта В
316
Применение микроконтроллеров PIC 18
lastCount = timer = 0;
WriteTimerO (OxFC);
OpenTimerO (TIMER_INT_ON &
T0_8BIT &
TO_SOURCE_INT &
T0_PS_l_256);
RCONbits.IPEN = 1;
INTCONbits.GIEH = 1;
// здесь выполняется другая работа
// таймер 0 на 252
// вкл. Прерываний от таймера 0
// таймер 0 - 16-разрядный
// синхронизация таймера 0 - внутренняя
// предварительный делитель таймера 0 на 256
// IPEN = 1
// разрешение высокоприоритетных прерываний
Рис. 7.30. Датчик расхода, подключенный к микроконтроллеру
Датчики расхода
Датчики расхода формируют импульсы по мере того, как поток жидкостей прохо-
дит сквозь них. Предположим, что в системе должны измеряться расход и потребление
топлива. Это может быть выполнено посредством использования датчик расхода типа
датчика FT-110 от фирмы Gems. Это устройство (модель 173934) производит 8300 им-
пульсов на галлон потока жидкости. Измеряется расход от 0,07 до 5,3 галлонов в мину-
ту. Рис. 7.30 иллюстрирует подключение такого датчика расхода к микроконтроллеру.
Это устройство просто в подключении - его интерфейс состоит из трех проводов и од-
ного нагрузочного резистора.
Соответствующая программа показана в примере 7.21. Эта программа обеспечи-
вает снятие мгновенной скорости потока жидкости через датчик и занесение его в
Глава 7. Базовый ввод-вывод
317
ячейку памяти flowRate с использованием формата с плавающей запятой. Число в этой
ячейке памяти означает скорость потока жидкости, выраженную в галлонах за минуту.
Это значение обновляется 10 раз в секунду.
Пример 7.21
/*
* Пример замера расхода жидкости, написанный для PIC18F1220
*/
((include <pl8cxxx.h>
((include <timers.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
# pragma config OSC = HS
# pragma config WDT = OFF
# pragma config LVP = OFF
# pragma config BOR = OFF
((pragma config MCLRE = ON
void MyHighlnt (void); // прототипы для прерываний
#pragma interrupt MyHighlnt // MyHighlnt - это прерывание
#pragma code high_vector=0x08 // high_vector - это вектор
// по адресу 0x08
void high_vector (void)
asm GOTO MyHighlnt _endasm
I/ данные в памяти данных
float flowRate;
11 высокоприоритетные прерывания
#pragma code
void Timerl (void)
// каждую 1/10 секунды
// повторное активирование таймера 1
PIRlbits.TMR1IF =0; // повторное акт!
flowRate = ReadTimerOO * 10.0 * 60 / 8300;
WriteTimerO (0); // сброс отсчета
void MyHighlnt (void)
if (PIRlbits.TMR1IF == 1)
Timerl();
318
Применение микроконтроллеров PIC 18
// main program
void main (void)
{
ADCON1 = OxOf;
TRISA = 0x10;
WriteTimerO (0);
OpenTimerO (TIMER_INT_OFF &
T0_16BIT &
TO_SOURCE_EXT &
T0_EDGE_FALL &
TO_PS_1_1);
WriteTimerl (5303);
OpenTimerl (TIMER_INT_ON &
T1_16BIT_RW &
T1_SOURCE_INT &
T1_PS_1_8 &
T1_OSC1EN_OFF);
RCONbits.IPEN = 1;
INTCONbits.GIEH = 1;
// все выводы порта цифровые
// программирование порта А
// таймер 0 на 0
// вкл. Прерываний от таймера 0
// таймер 0 16-разрядный
// синхровход таймера 0 вывод RA4
// вывод RA4 по срезу
// предварительный делитель
// таймера 0 на 1
// таймер 1 на 5303
// вкл. прерываний от таймера 1
// таймер 1 16-разрядный
// внутренняя синхронизация
//таймера 1
// предварительный делитель
// таймера 1 на 8
// IPEN = 1
// разрешение высокоприоритетных
// прерываний
// здесь выполняется другая работа
Инфракрасные устройства дистанционного управления
Инфракрасные устройства дистанционного управления чрезвычайно распро-
странены и имеют много применений во встроенных системах. В качестве излучающего
датчика используется инфракрасный светодиод или несколько светодиодов для рас-
стояний, превышающих несколько метров. В качестве приемника на противоположном
конце, используется обычно инфракрасный фотодиод или фототранзистор. Сигнал во
многих устройствах дистанционного управления часто передается на относительно
низкой частоте (36 кГц, 38 кГц и 40 кГц.), что делает интерфейс с ними особенно подхо-
дящим для микроконтроллеров.
Полезное устройство, которое иллюстрирует принцип инфракрасных датчиков -
это схема расширителя диапазона дистанционного управления, созданная с примене-
нием микроконтроллера. Схема использует недорогой PIC18F1220 и несколько допол-
нительных компонентов. В качестве источника электропитания в ней используется ба-
тарейный комплект, состоящий из четырех батареек типа АА. Кроме того, в схеме ис-
пользуется интегральный стабилизатор с малым падением напряжения между входом
и выходом МАХ603. Это превосходная ИС, предназначена для использования в устрой-
ствах с батарейным питанием. Рис. 7.31 показывает схему инфракрасного расширите-
ля диапазона.
U4 МАХБОЗ
IN _„OUT
Q Q Q Q
OFF 0 0 0 0 SET
C1
10 uF
R5
10K
PIC18F1220
U1
— BT1
nr" 4 x AA
2
6
7
3
4
16
15
C4
1.0 uF
C3
0.1 uF
RAO
RA1
RA2
RA3
RA4
#MCLR
OSC1 «RB6
OSC2 >RB7
gRBO
>RB1
RB2
RB3
RB4
RB5
8
9
17
18
10
11
12
13
Глава 7. Базовый ввод-вывод
Рис. 7. 31. Инфракрасное ДУ
320
Применение микроконтроллеров PIC 18
Данные посылаются в форме импульсных пакетов на частоте 36 кГц с использо-
ванием двухфазного кода, который иногда называют манчестерским кодом. Информа-
ционный пакет состоит из 14 битов, которые включают две стартовых бита, находящих-
ся в состоянии логической 1, за которыми следует бит управления, который переклю-
чается каждый раз, когда нажимается кнопка на передатчике. После бита управления
следует 5-разрядный адрес. И, наконец, последние шесть битов задают команду, по-
сылаемую на устройство. Импульс бита имеет ширину в 1,728 мс и через каждые 30 мс
выполняется повторная передача кода, если кнопка на пульте дистанционного управ-
ления нажата. Манчестерский код посылается таким образом, что логическая единица
изменяет выход на ноль из единицы на среднем бите, а логический ноль изменяет вы-
ход из логической единицы в логический ноль на среднем бите. Сигнал, посылаемый на
инфракрасный диод, имеет частоту 36 кГц, если манчестерский код отражает логиче-
скую единицу. Наша система не должна генерировать эти коды, - она должна только
обнаруживать их, принимать и вновь передавать. Рисунок 7.32 иллюстрирует формат
кода дистанционного управления RC5, используемого фактически всеми соответст-
вующими электронными устройствами.
Полученный сигнал подается на вывод RB1, который является также входом пре-
рывания, ибо, когда сигнал не приходит в течении длительного периода времени, то
микроконтроллер входит в режим бездействия с целью экономии электропитания. Из
главы 6 вы, возможно, помните, что из режима бездействия микроконтроллер выходит
по любому прерыванию. Как только сигнал получен, отрабатывается программа, кото-
рая выполняет оценку входа и передачу команды на передатчик. Модуль ШИМ, как это
уже обсуждалось для случая управления скоростью вращения электромотора, исполь-
зуется для того, чтобы сгенерировать сигнал частотой в 36 кГц для передающего све-
тодиода. Пример 7.22 показывает расчет выходной частоты ШИМ. Как можно видеть из
приведенных расчетов, ближайшей к найденной, при использовании внутреннего син-
хрогенератора на 4 МГц, будет частота'равная 37 кГц. Эта частота достаточно близка с
тем, чтобы система функционировала корректно. В данном случае в регистр РМ2 за-
гружается значение, равное 26.
Рис. 7.32. Код дистанционного управления RC5
Глава 7. Базовый ввод-вывод
321
Пример 7.22
Период ШИМ = (PR2 +1) х TMR2PS х 4 х Tosc
Период ШИМ = (26 + 1) х 1 х 4 х 1/4 мкс
= 21 х 1 х 1 мкс
= 21 мкс
Частота ШИМ = 1/27 мкс = 37 кГц
(Примечание: TMR2PS - это значение коэффициента предварительного делителя тай-
мера 2)
Полный листинг программы для этого приложения показан в примере 7.23. Обра-
тите внимание, что когда вход RB1 изменяется, это вызывает прерывание, которое ак-
тивирует микроконтроллер. В процедуре облуживания прерывания включается выход-
ной сигнал светодиода, имеющий частоту 36 кГц к и так долго, пока входной сигнал от
детектора поступает один раз каждые 35 мкс (этот период отсчитывается таймером 0),
выход остается на частоте 36 кГц. Таймер 0 очищается через каждую половину периода
входного сигнала от детектора. Если посмотреть на манчестерский код и выходные
сигналы, показанные на рис. 7.31, то можно видеть, что самый длинный период време-
ни, когда сигнал падает до нуля, равен периоду тактовой частоты или 27 мкс. Програм-
ма обнаруживает прекращение изменения сигнала на протяжении 35 мкс, - этот период
достаточно длинен, чтобы обнаружить факт отсутствия изменения сигнала. Когда вход
перестает изменять свое состояние, выходная частота в 36 кГц выключается, прерыва-
ния вновь разрешаются и возврат из подпрограммы обслуживания прерывания пере-
дает управление вновь к основному бесконечному циклу - при этом система вновь вхо-
дит в режим бездействия, экономя электроэнергию.
Пример 7.23
★
* Расширитель диапазона пульта дистанционного управления
*/
♦include <pl8cxxx.h>
* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
’/
♦pragma config
♦pragma config
♦pragma config
♦pragma config
♦pragma config
OSC = INTIO2
WDT = OFF
LVP = OFF
BOR = OFF
MCLRE = ON
I ********* переменные в памяти данных
void MyHighlnt (void);
♦pragma interrupt MyHighlnt
♦pragma code high_vector=0x08
// прототипы для прерываний
// MyHighlnt - это прерывание
// high_vector - это вектор
322
Применение микроконтроллеров PIC 18
// vector at 0x08
void high_vector (void)
(
_asm GOTO MyHighlnt _endasm
}
#pragma code
// процедура обслуживания прерывания,
// возникающего по любому положительному фронту сигнала на INTI (RB1)
И
void MyHighlnt (void) i
INTCON3bits.INTIIF = 0; // сброс запроса прерывания
char state = PORTBbits.RBI;
T2CONbits.TMR2ON = 1 do f // запуск выхода 36 кГц output
t TMROL = 0; // очистка таймера 0
while (state == PORTBbits.RBI &&
TMROL < 20) ; // ожидание изменения либо таймаута
state = PORTBbits.RBI;
while (TMROL < 20);
} T2CONbits.TMR2ON = 0 // 36 кГц выкл.
void main (void)
t OSCCON = 0x63 // внутренний генератор на 4 мГц
ADCON1 = 0x0F; // порты цифровые
TRISB = 2; PORTB = 0; // программирование портов
T2CON = 0; // установ предварительного дели-
теля на 1 CCP1CON = 0x0C; // модуль ССР выкл, выход активен
по высокому TMR2 = 0; // очистка таймера 2
PR2 = 26; // таймер 2 очищается по 10;
CCPR1L = 14; // установ на квадратный сигнал
// (заполнение 50%)
TOCON = 0xC8; // таймер 0 считает в мкс
RCONbits.IPEN = 0; // вкл. Только высокоприоритетные
и прерывания
INTCON2bits.INTEDG1 = 1; // установ переключения INT1 по
положительному фронту
INTCON3bits.INT1IE = 1; // разрешение INT1
INTCONbits.GIE = 1; // разрешение прерываний
while (1)
Глава 7. Базовый ввод-вывод
323
Sleep (); // переход в неактивное состояние
}
}
Предположим, что эта система также должна функционировать, декодируя сиг-
налы от внешнего пульта дистанционного управления. Входной сигнал в этом случае
будет обнаруживаться в процедуре обслуживания прерывания, однако ни время высо-
кого значения сигнала, ни время его низкого значения замеряться не будут. В про-
грамме из примера 7.23 таймер 0 может использоваться для замера времен для вход-
ного сигнала, он может также определять, когда начинать и прекращать декодирование
манчестерского кода, передаваемого из пульта дистанционного управления. Эта часть
программы здесь не приводится, однако она будет разработана в более поздних главах
для других приложений, которые используют манчестерский код.
Газовые датчики
Имеется множество датчиков, предназначенных для измерения количества неко-
торых газов в атмосфере. Этот подраздел представляет один из них, предназначенный
для измерения содержания двуокиси углерода. Имеется также много других датчиков,
которые замеряют содержание кислорода, метана, алкоголя, водорода, сульфата во-
дорода и т.д.
Предположим, что нам необходим прибор для того, чтобы измерить концентра-
цию двуокиси углерода в воздухе. Имеется большое количество различных датчиков
двуокиси углерода, например TGS-2442 от фирмы Figaro Corporation. Это устройство
содержит нагреватель и датчик. Нагреватель активизирует датчик, чье сопротивление
изменяется в зависимости от концентрации двуокиси углерода. Чтобы контролировать
количество двуокиси углерода, нагреватель активируется на 14 мс, а сопротивление
датчика измеряется на протяжении 5 мс в цикле нагрева. Этот цикл нагрева/контроля
повторяется каждую секунду на протяжении периода измерения. Данный датчик может
измерять концентрацию СО2 в диапазоне от 30 до 1000 частей на миллион (промиллей).
Нагреватель требует напряжения в 5 В при токе в 200 мА на протяжении 14 мс на
каждые 1000 мс, так что в среднем потребляется только ток в 2,8 мА. Датчик темпера-
туры производит напряжение, которое может контролироваться АЦП в микроконтрол-
лере и отображаться как значение концентрации СО2 или использоваться любым дру-
гим способом. Рис. 7.33 иллюстрирует датчик и схему, используемую для того, чтобы
контролировать концентрацию СО2.
324
Применение микроконтроллеров PIC 18
Здесь выполняется выборка Vout
Рис. 7.33. Датчик СО2
Выходное напряжение, обозначаемое как Vout определяется переменным сопро-
тивлением датчика RS. Версия TG-2442A1 имеет значение RS в диапазоне от 6,81 до
21,5 кОм. Эти устройства должны калиброваться с тем, чтобы снимаемые ими отсчеты
были точными, - именно поэтому потенциометр на 50 кОм используется в цепи коллек-
тора 2N2222.
Рис. 7.34 показывает датчик, подключенный к микроконтроллеру PIC18F1220. В
схему также включен ЖК-индикатор 1x16, предназначенный для индикации значения
Глава 7. Базовый ввод-вывод
325
концентрации СО2 в промиллях. Для того, чтобы быть точным, датчик помещается в
среду с известной концентрацией СО2, затем состояние потенциометра корректирует-
ся с целью получения правильного отсчета на ЖК-индикаторе. Датчик имеет линейную
характеристику, так что, будучи однажды откалиброванным, он в дальнейшем будет
обеспечивать точные показания. Датчик также требует 2-дневного периода прогрева
прежде, чем он будет калиброваться.
Программа для данной системы приведена в примере 7.24. Коэффициент умно-
жения используется для того, чтобы отобразить по полученным отсчетам в промиллях
индикацию, учитывающую шкалу прибора. Этот коэффициент должен настраиваться с
тем, чтобы соответствовать характеристикам реального датчика. Соответствующая
настройка выполняется калибровочным потенциометром.
Рис. 7.34. Интерфейс датчика СО2
326
Применение микроконтроллеров PIC 18
Пример 7.24
/*
* приоритет множественных прерываний
*/
♦include <pl8cxxx.h>
♦include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора RC
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
♦pragma config OSC = INTIO2
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
/7 ********* переменные в памяти данных
void MyHighlnt (void); // прототипы для прерываний
♦pragma interrupt MyHighlnt // MyHighlnt - это прерывание
♦pragma code high_vector=0x08 // high_vector - это вектор по адресу 0x08
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
}
♦pragma code
char strlf] = "CO2 =
char str2[] = " ppm";
// процедура обслуживания прерывания,
// возникающего каждую секунду
//
void SendLCDdata (char data, char rs)
{
PORTB = (PORTB & 0xC3) I ((data >> 2) & ОхЗС) ; // передача левого
PORTBbits.RB6 = rs; // установ RS
PORTBbits.RB7 =1; // импульс E
PORTBbits.RB7 = 9;
DelaylOTCYx (1); // задержка 40 мкс
PORTB = (PORTB & ОхСЗ) I ((data << 2) & ОхЗС); // передача правого
PORTBbits.RB6 = rs; // установ RS
PORTBbits.RB7 =1; // импульс E
PORTBbits.RB7 = 0;
DelaylOTCYx(1); // задержка 40 мкс
}
void initLCD (void)
Глава 7. Базовый ввод-вывод
327
DelaylKTCYx (5); // ожидание 20 мкс (смотрите текст)
SendLCDdata (0x20, 0); // посылка 0x30
DelaylKTCYx (2) ; // ожидание 8 мкс
SendLCDdata (0x20, 0); // посылка 0x30
DelaylOTCYx (5) ; // ожидание 100 мкс
SendLCDdata (0x20, 0); // посылка 0x30
SendLCDdata (0x08, 0); // посылка 0x28
SendLCDdata (0x01, 0); // посылка 0x01
DelaylOOTCYx (5); // ожидание 2 ms
SendLCDdata (OxOC, 0); // посылка ОхОС
SendLCDdata (0x06, 0); // посылка 0x06
void string (char *str, char position)
int ptr = 0;
SendLCDdata (position, 0); // передача позиции
while (str[ptr] != 0)
SendLCDdata(str[ptr++], 1); // посылка символа
}
void MyHighlnt (void)
i
float analog;
PIRlbitS.TMR1IF = 0; // повторное разрешение прерываний
TMR1L = ОхЕЕ; // загрузка таймера 1 значением -31
250
TMR1H = 0x85; // для прерывания каждую секунду
PORTBbits.RB0 = 0; // запитка датчика и нагревателя
PORTBbits.RBI = 1;
DelaylKTCYx(1); // ожидание 4 мс
DelaylOOTCYx(2); // ожидание ,8 мс
DelaylOTCYx (5); // ожидание ,2 мс
// take sample
ADCONObits.GO =1; // запуск преобразования
while (ADCONObits.GO == 1); // ожидание завершения
analog = (ADRESL + (ADRESH «8)) * 0.489;
// масштабирование на
// максимум 500 промиллей
PORTBbits.RBI = 0;
DelaylKTCYx (2); // oe 8 мс
PORTBbits.RBO = 1;
string (strl, 0x80); // отображение "CO2 = "
str2[0] = analog / 100 + 0x30;
analog - (int) analog % 100;
str2[l] = (int) analog / 10 + 0x30;
str2[2] = (int) analog % 10 + 0x30;
string (str2, 0x86);
)
void main (void)
{
OSCCON = 0x43; // внутренний генератор устанавливается
//на 1 мГц
328
Применение микроконтроллеров PIC 18
ADCON1 = 0х7Е; // выбор входа ANO, активирование АЦП
ADCON1 = ОхОе; // ANO - аналоговый, VDD и VSS - опорные
ADCON2 - 0x84; // напряжения
TRISA = 1; // бит 1 порта А = вход
TRISB = 0; // порт В = выход
PORTB = 1; initLCD(); // выкл. датчика
T1CON = 0xF9; // таймер 1 считает 32 мкс на отсчет
TMR1L = OxEE; // загрузка таймера 1 значением -31, 250
TMR1H = 0x85; // для прерывания каждую секунду
RCONbits.IPEN = 0; // вкл. Только высокоприоритетных // прерываний
PIElbits.TMR1IE = 1; // разрешение прерывания от таймера 1
INTCONbits.GIE = 1; while (1) { // nothing // разрешение прерываний
7.5. Резюме
1. Дребезг контактов переключателей происходит приблизительно в течении 10 мс - он
должен быть компенсирован для правильной работы многих приложений. Устранение
дребезга контактов лучше всего достигается программно.
2. Вспомогательные клавиатуры часто подключаются к микроконтроллерам для
ввода различных типов данных. Вспомогательные клавиатуры наиболее часто создают-
ся как матрицы, - при нажатии клавиши строка матрицы соединяется со столбцом.
3. Светодиоды, которые подключаются к микроконтроллеру, часто требуют ис-
пользования схемы управления, формирующей ток, сила которого достаточна для све-
чения светодиода. Числовые индикаторы используют светодиоды в 7-сегментной кон-
фигурации, для управления ими используются 7-сегментные коды.
4. Жидкокристаллические индикаторы (ЖК-индикаторы) часто подключаются к
микроконтроллерам для того, чтобы отображать алфавитно-цифровые данные. Дос-
тупны различные размеры панелей ЖК-индикаторов - от однострочных до 4-строчных.
При этом в строке могут размещаться от 16 до 40 символов.
5. Вакуумные флуоресцентные индикаторы (ВФИ) - это яркие сине-зеленые ин-
дикаторы, используемые во многих изделиях широкого потребления с целью отобра-
жения алфавитно-цифровых данных.
6. Электромоторы в форме электромоторов постоянного тока или шаговых элек-
тродвигателей часто используются для того, чтобы позиционировать или переместить
устройства. Они часто подключаются к микроконтроллерам.
7. Электромоторы часто управляются с использованием мощных полевых МОП-
транзисторов. Распространенной конфигурацией схемы управления на полевых МОП-
транзисторах является Н-образный мост.
8. Модуль ШИМ микроконтроллера часто используется для того, чтобы управлять
скоростью и направлением вращения ротора электромотора постоянного тока. Изме-
Глава 7. Базовый ввод-вывод
329
няя коэффициент заполнения сигнала на выходе ШИМ, можно изменять скороегь рабо-
ты электромотора, потому что средний ток через электромотор будет изменяться.
9. Реле - как электромеханические, так и интегральные используются для того,
чтобы включать высокие напряжения или несколько контактов одновременно. Боль-
шинство релейных схем требуют применения схем управления, формирующих токи,
необходимые для подачи на обмотку реле.
10. Соленоиды - это электромеханические устройства, которые используются для
того, чтобы переместить устройство на короткое расстояние. Соленоиды должны воз-
буждаться в течении определенного отрезка времени, что требует применения про-
граммных временных задержек. Соленоиды также требуют больших токов и наличия
схемы управления.
11. Датчики - это устройства, которые преобразовывают движение или какие-
либо иные физические явления в электрический сигнал, который обрабатывается мик-
роконтроллером. Эти явления включают вращательное движение, давление, темпера-
туру, поток жидкости и т.д.
12. Код RC5 наиболее часто используется в инфракрасных устройствах дистан-
ционного управления для того, чтобы посылать сигналы на частоте 36 кГц.
7.6. Вопросы и задания
1. Какие проблемы могут иметь место в механических переключателях?
2. Как долго длится механический дребезг в переключателях?
3. Какая программа используется для того, чтобы устранить дребезг контактов
переключателя?
4. Напишите обращение к функции, используя функцию Switch из примера 7.1,
для устранения дребезга контактов в двух переключателях, связанное с битами 0 и 7
порта А.
5. В чем различие между переключателями типов SPST и SPDT?
6. Почему необходим нагрузочный резистор при соединении переключателя с
микроконтроллером?
7. Опишите конструкцию матрицы вспомогательной клавиатуры
8. Измените программу в примере 7.2 таким образом, чтобы она могла использо-
вать вспомогательную клавиатуру 4x6.
9. Поскольку программа в примере 7.2 использует порт А, как входной, сколько
максимально строк могло бы быть подключено к порту А в PIC18F1220?
10. Предположим, что белый светодиод подключен к бигу RB0 порта В микрокон-
троллера PIC. Светодиод требует напряжения 2,5 В и тока 30 мА для того, чтобы полно-
стью светиться. При использовании транзистора 2N2222, разработайте соответствую-
щий интерфейс.
11. Повторите вопрос 10 для красного яркого светодиода, который требует на-
пряжения в 2,0 В и тока в 20 мА.
12. Подключите пару красных светодиодов к битам RB0 и RB1 порта В. Эти свето-
диоды требуют 10 мА тока и напряжения в 1,65 В. Разработайте функцию для PIC, кото-
рая поочередно будет зажигать два светодиода с частотой 2 Гц в течение 10 секунд при
вызове функции flashLeds. Примите, что тактовая частота микроконтроллера равна 4
МГц.
13. Существую! трехцветные светодиоды. Эти устройства имеют четыре подключения:
(1) общее подключение анода, (2) красный катод светодиода, (3) зеленый катод светодиода и
(4) синий кагод светодиода. Подключите это устройство к PIC - к выводам RBO, RB1, и RB2.
330
Применение микроконтроллеров PIC 18
Красные и зеленые секции требуют напряжения 1,65 В и тока 10 мА, а синяя секция требует
напряжения в 2,5 В и ток в 20 мА. Разработайте функцию, которая будет высвечивать произ-
вольные цвета с частотой 3 Гц в течении 20 секунд всякий раз, когда на вход RA0 поступает
логическая единица. Произвольные цвета - это числа от ООО до 111, посылаемые на три бита
порта В. Примите, что тактовая частота равна 4 МГц.
14. Когда светодиоды мультиплексированы, они включаются индивидуально
только часть времени, но создается впечатление, что они светятся постоянно. Почему?
15. Какова минимальная и максимальная частота вспышек для мультиплексных
индикаторов?
16. Когда шесть светодиодных индикаторов мультиплексированы, пиковый ток
для каждого индикатора должен быть увеличен на какой коэффициент?
17. Как устанавливается частота вспышек в примере 7.6?
18. Панель ЖК-индикатора имеет вывод VEE, используемый для установки кон-
траста. Что обычно соединяется с VEE?
19. Каково назначение входа RS панели ЖК-индикатора? <
20. Каково назначение входа Е н ЖК-индикатора?
21. Опишите процесс, требуемый для того, чтобы инициализировать ЖК-
индикатор.
22. Как курсор перемещается в панели ЖК-индикатора?
23. Каков будет адрес отображения для строки 1 ЖК-индикатора 24 х 1 ?
24. Разработайте функцию с именем cursor, которая перемещала бы курсор в лю-
бую доступную позицию ЖК-индикатора. Прототип этой функции будет иметь вид void
cursor (позиция символа). Примите, что Е связан с RB4, RS связан с RB5, а 4-разрядные
данные подаются на RB0-RB3.
25. Дан ЖК-индикатор 2x16. Разработайте функцию, которая стирает только
строку номер 1 на индикаторе. (Выдача пробела стирает символ.)
26. Какая команда посылается на ЖК-индикатор, чтобы очистить весь экран? На-
пишите функцию очистки экрана с именем Clear.
27. Вакуумный флуоресцентный индикатор работает как___________вакуумная
трубка.
28. Что является основным преимуществом ВФИ?
29. Какой цвет обычно отображается ВФИ?
30. Почему шаговый электродвигатель называют “шаговым" ?
31. Что является основным преимуществом шагового электродвигателя?
32. Объясните, в чем различие между полным шагом и половинным ша1 ом в ша-
говом электродвигателе.
33. Что такое Н-образный мост?
34. Объясните, как изменение ширины импульса, приложенного к электромотору
постоянного тока, может изменять скорость электромотора.
35. На что указывает "пение электромотора" и как его предотвратить?
36. Что такое отдача демпферного диода и как ее предотвратить?
37. Как быстро будет вращаться электромотор постоянного тока, связанный с Н-
образным мостом, если импульсный широтно-модулированный сигнал имеет коэффи-
циент заполнения в 50%?
38. Приблизительно, как быстро электромотор постоянного тока будет вращать-
ся, если он управляется одним полевым МОП-транзистором, а его входной сигнал
ШИМ имеет коэффициент заполнения в 50%?
39. Предположим, что реле подключено микроконтроллеру и требует ток в 100
мА. Разработайте схему управления реле, использующую транзистор 2N2222.
40. Подключите соленоид к микроконтроллеру, приняв, что соленоид требует ток
Глава 7. Базовый ввод-вывод
331
600 мА и напряжение 12 В. Разработайте программу, возбуждающую соленоид в тече-
нии 700 мс каждый раз, когда вызывается функция Fire. Примите, что тактовая частота
равна 4 МГц, а соленоид подключен к RB3.
41. Как код Грея используется в устройствах кодирования угла поворота вала ?
42. Напишите код Грея для 4-разрядного устройства кодирования угла поворота
вала.
43. Каково назначения устройства кодирования угла поворота вала?
44. Датчик температуры LM70 имеет разрешающую способность в
градусах Цельсия.
45. Датчик температуры LM70 выдает___разрядное двоичное число в качестве
отсчета температуры.
46. Объясните, как программа из примера 7.19 округляет температуру.
47. Какую информацию индицирует датчик расхода?
48. Зайдите в Internet и составьте список из трех датчиков, которые не рассмат-
ривались в тексте. Также опишите выходные сигналы этих датчиков.
49. Имеется ли датчик, предназначенный для оценки количества кислорода в ат-
мосфере? (Опять-таки, выполните поиск в Internet).
50. Поскольку имеется множество типов газовых датчиков, можно ли разработать
устройство, которое обнаруживало бы практически все, что имеет характерный запах?
Если да, то составьте список, по крайней мере, из трех позиций, что можно было бы
обнаруживать?
51. Сколько битов включают один код RC5?
52. Какая частота используется для передачи инфракрасного сигнала, исполь-
зующего код RC5?
332
Применение микроконтроллеров PIC 18
Глава 8. Прерывания
Прерывания уже представлялись ранее в этой книге, но ввиду их важности вся эта
глава посвящена использованию прерываний в прикладных программах. Почти все
системы используют прерывания. Прерывания разрешают приложениям эффективно
коллективно использовать микроконтроллер, - без них было бы чрезвычайно трудно
реализовать много прикладных программ. Однако прерывания весьма трудны при по-
иске и устранении ошибок, а также в отладке.
После завершения изучения этой главы вы сможете:
1. Эффективно использовать прерывания при программировании приложений
для микроконтроллеров.
2. Использовать в программах как низко- так и высокоприоритетные прерывания.
3. Программировать USART на работу в режиме прерываний.
4. Программировать, используя прерывания, изменяющие состояния битов.
5. Понять, как функционируют малые сети, используя прерывания.
6. Программировать и использовать устройства чтения штрих-кодов.
8.1. Повторное знакомство с прерываниями
Микроконтроллер имеет два уровня прерываний: высокоприоритетное прерыва-
ние и низкоприоритетное прерывание. Уровни приоритета имеют значения только то-
гда, когда оба прерывания происходят одновременно. Когда активны оба вида преры-
ваний, то сначала микроконтроллером отрабатывается высокоприоритетное прерыва-
ние. Приоритет также играет роль в случае, если при отработке низкоприоритетного
прерывания возникнет высокоприоритетное прерывание, - в этом случае высокопри-
оритетное прерывание прервет отработку низкоприоритетного прерывания. Некоторые
прикладные программы используют только высокоприоритетные прерывания, в то
время как другие используют оба уровня прерываний. Выбор того, какой уровень или
какие уровни прерываний использовать всецело относится к компетенции разработчи-
ка программного обеспечения, но в общем случае можно сказать, что высокоприори-
тетные прерывания используется для обработки событий, которые должны обслужи-
ваться быстро, а низкоприоритетные прерывания используются для обработки менее
срочных событий. Бит IPEN в регистре управления сбросом (RCON) выбирает либо вы-
сокоприоритетное прерывание (IPEN = 0), либо высоко- и низкоприоритетные преры-
вания (IPEN = 1).
Например, предположим, что система использует таймер, который прерывает
микроконтроллер один раз каждые 100 мс с тем, чтобы обновить состояние таймера
реального времени. Второе прерывание при этом используется для того, чтобы кон-
тролировать внешнее событие отдатчика расхода. Сигнал отдатчика расхода возника-
ет в интервале времени между 1 мс и 40 мс. По причине того, что сигнал от датчика
расхода приходит более часто, чем прерывания таймера реального времени, сигналу
от датчика расхода присваивается более высокий приоритет, а прерыванию таймера
реального времени - более низкий приоритет. В общем случае, событиям, которые
происходят более часто, присваивается более высокий приоритет, но не всегда. Высо-
коприоритетное прерывание должно обычно обслуживаться в первую очередь, потому
что в случае, если они не будут обслужены первыми, произойдет потеря данных.
Как уже упоминалось в главе 6, высокоприоритетные векторы прерываний долж-
ны программироваться на ячейку памяти с адресом 0x0008, а низкоприоритетные век-
Глава 8. Прерывания
333
торы прерываний - на ячейку памяти с адресом 0x0018 для вызова соответствующих
процедур обслуживания прерываний. Так как объем памяти по адресам этих векторов
ограничен, то ячейка по адресу вектора прерывания обычно содержит команду GOTO,
передающую управление на процедуру обслуживания прерывания. На сегодняшний
день большинство прикладных программ пишутся на языке С, потому что это значи-
тельно снижает количество времени, требуемого для программирования приложения.
Схема реализации структуры прерываний на языке С иллюстрируется примером 8.1.
Размещение векторов прерываний является критически важным моментом, при этом
большая часть приведенной программы должна кодироваться именно в приведенном
порядке. Программный код, который следует за объявлением двух векторов прерыва-
ний, должен отделяться оператором псевдокомментария #pragma. Функция main в
этом примере разрешает оба прерывания после выбора обоих приоритетов прерыва-
ний битом IPEN регистра RCON. Если IPEN будет в состоянии логического нуля, то это
будет означать, что разрешено только высокоприоритетное прерывание. Другими сло-
вами, могут быть разрешены либо оба уровня прерываний, либо только высокоприори-
тетные прерывания.
Пример 8.1
* Пример использования прерываний
*/
^include <p!8fxxx.h>
* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
* /
♦pragma config OSC = RC
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
// ******** ПРОТОТИПЫ И ВЕКТОРЫ
ПРЕРЫВАНИЙ ****************
void MyHighlnt (void); // прототипы для прерываний
void MyLowInt (void); // сервисные процедуры
♦pragma interrupt MyHighlnt // MyHighlnt - прерывание
♦pragma code high_vector=0x08 // high_vector - по адресу 0x0008
void high_vector (void) // высокоприоритетный вектор
{
_asm GOTO MyHighlnt _endasm // переход на функцию обработки
// высокоприоритетного прерывания
)
♦pragma interruptlow MyLowInt // MyLowInt - прерывание
♦pragma interruptlow MyLowInt // низкоприоритетный вектор -
// по адресу 0x0018
334
Применение микроконтроллеров PIC 18
void low_vector (void) / // низкоприоритетный вектор
_asm GOTO MyLowInt _endasm // переход на функцию обработки // низкоприоритетного прерывания
// ******************* ПРОГРАММНЫЙ код *******************
// Программный код должен быть помещен здесь после
// того, как векторы прерываний будут определены
//
#pragma code //начало программного кода
void MyHighlnt (void)
(
// Высокоприоритетное прерывание переходит сюда
}
void MyLowInt (void)
{
// Низкоприоритетное прерывание переходит сюда
}
// главная программа
void main (void)
{
RCONBITS.IPEN = 1; // IPEN = 1 для разрешения приоритетов прерываний
INTCONBITS. GIEH =1; // разрешает высокоприоритетное прерывание
INTCONBITS. GIEL =1; // разрешает низкоприоритетное прерывание
// Прерывания теперь включены, выполнение других программных действий
}
Процедуры обслуживания прерываний
Программа по примеру 8.1 - это все, что необходимо, чтобы настроить и разре-
шить как низко, так и высокоприоритетные прерывания. Процедуры обслуживания пре-
рываний, которые обрабатывают как низко, так и высокоприоритетные прерывания, не
включены в этот пример. В него включены только оболочки процедур обслуживания
прерываний.
Процедура обслуживания прерывания, иногда называемая хэндлером прерыва-
ний, должна правильно обслужить прерывание. В противном случае система зависнет
или заблокируется, что сделает поиск и устранение ошибки очень трудным или невоз-
можным. С каждым устройством, которое выставляет прерывания микроконтроллеру,
связано три бита управления:
• бит приоритета прерывания (IP)
• бит разрешения прерывания (IE)
• бит флага прерывания (IF)
Бит приоритета прерывания (IP) выбирает либо высоко-, либо низкоприоритет-
ное прерывание для устройства. Логическая 1 в бите IP для данного входа прерывания
выбирает высокоприоритетное прерывание, а логический ноль выбирает низкоприори-
тетное прерывание. Бит разрешения прерывания (IE) разрешает прерывания от уст-
Глава 8. Прерывания
335
ройства, когда устанавливается в состояние логической единицы. Бит флага прерыва-
ния (IF) устанавливается для того, чтобы указать, что устройство вызвало прерывание.
Бит IF опрашивается программно в процедуре обслуживания прерывания с тем, чтобы
определить, какое устройство вызвало прерывание. Флаг прерывания должен быть
очищен программой обработки прерывания, когда прерывание будет обслужено. Если
этот бит не будет сбрасываться внутри программы обработки прерывания, то другое
прерывание никогда не сможет произойти.
Предположим, что таймер 0, таймер 1, а также вывод входа прерывания INT1 ис-
пользуются приложением. Прерывание от таймера 0 является высокоприоритетным
прерыванием, а прерывания от таймера 1 и входа INT1 являются низкоприоритетными
прерываниями. Пример 8.2 иллюстрирует программу, необходимую для того, чтобы
реализовать соответствующую структуру. В этом примере не показано, как процедуры
обслуживания прерываний завершаются возвратом по команде возврата из подпро-
граммы обработки прерывания (RETFIE). Соответствующее завершение подпрограммы
обработки прерываний по команде RETFIE обеспечивается операторами #pragma
interrupt и #pragma interrflow программы. Эти операторы псевдокомментариев иден-
тифицируют функции, используемые для того, чтобы обработать как высоко-, так и низ-
коприоритетные прерывания. Команда RETFIE (возврат из функции с разрешенными
прерываниями) автоматически повторно разрешает будущие прерывания в конце
функции обработки прерываний. Содержимое регистров управления прерываниями
описано в главе 6.
Пример 8.2
/*
* Пример использования высоко- и низкоприоритетных прерываний
*/
♦include <p!8cxxx.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
* /
♦ pragma config OSC = HS
♦ pragma config WDT = OFF
♦ pragma config LVP = OFF
♦ pragma config BOR = OFF
♦ pragma config MCLRE = ON
/I ********* прототипы и вектора
прерываний ***************
void MyHighlnt (void); //
void MyLowInt (void); //
♦pragma interrupt MyHighlnt //
♦pragma code high_vector=8 //
void high_vector (void) //
{
_asm GOTO MyHighlnt _endasm
прототипы процедур
обслуживания прерываний
MyHighlnt - это прерывание
high_vector по адресу 0x0008
высокоприоритетный вектор
// переход на подпрограмму обработки
336
Применение микроконтроллеров PIC 18
) // высокоприоритетных прерываний
#pragma interruptlow MyLowInt // MyLowInt - это прерывание
#pragma code low_vector=0xl8 // низкоприоритетный вектор
// по адресу 0x0018
void low_vector (void) I // низкоприоритетный вектор
t _asm GOTO MyLowInt _endasm // переход на подпрограмму обработки
низкоприоритетных прерываний
}
// ******************** программный код ******************
#pragma code // здесь начинается программный код
// высокоприоритетное прерывание
void MyHighlnt (void)
{
INTCONbits.TMROIF = 0; // сброс запроса от таймера 0
// обработка прерывания от таймера 0
}
// низкоприоритетное прерывание
void MyLowInt (void)
{
if (INTCON3bits.INT1IF == 1) // это INTI?
{
INTCON3bits.INT1IF = 0; // сброс запроса
//обработка прерывания INTI
}
else if (PIRlbitS.TMR1IF == 1) // это таймер 1?
{
PIRlbitS.TMR1IF = 0; // сброс запроса
// обработка прерывания от таймера 1
)
)
// main program
void main (void)
{
// программирование таймера 0, таймера 1 и INTI
INTCON2bits.TMR0IP = 1; INTCONbits.TMR0IE = 1; IPRlbits.TMR1IP = 0; PIElbits.TMR1IE = 1; INTCON3bits.INT1IP = 0; INTCON3bits.INT1IE = 1; RCONbits.IPEN = 1; INTCONbits.GIEH = 1; INTCONbits.GIEL = 1; // таймер 0 имеет высокий приоритет // разрешение прерывания от таймера 0 // таймер 1 имеет низкий приоритет // разрешение прерывания от таймера 1 // INT1 имеет низкий приоритет // разрешение INT1 // IPEN = 1 для разрешения приоритетов // прерываний // разрешение высокоприоритетных // прерываний // разрешение низкоприоритетных
Глава 8. Прерывания
337
// прерываний
// прерывания теперь включены, выполнение других задач
Для иллюстрации типовой системы, предположим, что некоторый банк нуждается
в установке индикатора времени и температуры. Он поручил нам разработать такой
индикатор. При разработке этой системы нам понадобится большой индикатор, поэто-
му для отображения информации в нашей системе мы будем использовать имеющие
5-дюймов в высоту светодиодные индикаторы от фирмы Liteon (Liteon 50801 HRB). Че-
тыре таких светодиодных индикатора используются для отображения значения време-
ни, а четыре других - для отображения значения температуры. Рис. 8.1 показывает
конфигурацию такого индикатора, отображающего значение времени в 11:03 и темпе-
ратуры в 104’ F. (По-видимому, это жаркий день.) Один 8-миллиметровый светодиод
используется для представления символа градуса и один - для отображения символа
двоеточия между часами и минутами. Восемь индикаторов обозначаются от D0 до D7 с
тем, чтобы можно было создать схему электрическую системы.
D3 D2 DI DO
D7 D6 D5 D4
Рис. 8.1. Индикатор Liteon 50801 HRB
Поскольку индикаторы мультиплексированы и требуют использования 15 выво-
дов ввода - вывода микроконтроллера, PIC18F1220 не подходит для подобного приме-
нения. Таким образом, для реализации системы необходимо выбрать больший микро-
контроллер. В данном случае применен микроконтроллер PIC18F2220 в корпусе типа
SPDIP, имеющий 28 выводов. Пятидюймовые 7-сегментные светодиодные индикаторы
фирмы Liteon требуют 4 В на сегмент при токе в 30 мА. 8-миллиметровыые светодиод-
ные индикаторы требуют напряжения в 2 В при токе в 20 мА.
oo
♦5V
Рис. 8. 2. Индикация времени и температуры
Применение микроконтроллеров PIC18
Глава 8. Прерывания
339
Входами микроконтроллера (см. рис. 8.2) является кнопка установки времени и датчик
температуры LM70. Эти устройства используют штырьки RA0-RA2 микроконтроллера. В ка-
честве схемы управления сегментами используется микросхема ULN2003 (7 буферных ин-
вертирующих каскадов), связанная с битами RC0-RC6 порта С. В качестве анодных ключей
используется пара микросхем управления с высокой нагрузочной способностью от фирмы
Texas Instruments (754410). Микросхема ULN2003 - это инвертирующий усилитель, поэтому в
случае использования 7-сегментного кода с активной логической единицей и неинверти-
рующих анодных ключей, логическая единица будет задавать свечение сегмента. Анодные
ключи используют все восемь битов порта В.
Программа для данного применения написана так, что для управления всей сис-
темой она использует одно прерывание от таймера 1. Прерывание от таймера 1 ин-
крементирует таймер реального времени. Один раз в минуту процедура обслуживания
прерывания от таймера 1 извлекает значение температуры из LM70, а также выполняет
отображение времени дня. Главная программа в этой системе не делает ничего, поми-
мо считывания состояния кнопочного переключателя в случае, если время должно быть
изменено. Если говорить о том, как написана программа установки времени, то следует
отметить, что одна кнопка используется для того, чтобы установить как часы, так и ми-
нуты. (Возможно, что изготовители цифровых часов примут эту методику установки
времени).
Последовательность операций при использовании кнопки установки времени яв-
ляется следующей:
- если кнопка нажата, то программа входит в режим установки времени, а самый
правый индикатор температуры отображает символ Н для установки часов;
- если кнопка нажимается в течении периода времени, меньшего, чем 3 секунды,
то значение часов будет инкрементироваться по каждому нажатию кнопки;
- если кнопка нажимается в течении периода времени, большего, чем 3 секунды,
то программа входит в режим установки минут, а самый правый индикатор температу-
ры отображает символ М для установки минут;
- если кнопка нажимается в течении периода времени, меньшего, чем 3 секунды,
то значение минут будет инкрементироваться по каждому нажатию кнопки, а если это
не так, то программа входит в режим установки секунд, а самый правый индикатор тем-
пературы будет отображать символ S для установки секунд;
- если кнопка нажимается в течении периода времени, меньшего, чем 3 секунды,
то значение секунд будет инкрементироваться по каждому нажатию кнопки, а если это
не так, то программа восстанавливает обычный режим работы работу и отображает
новое время и температуру.
Пример 8.3 иллюстрирует полную программу для этой системы. Система написа-
на в языке С, потому что Ассемблер сгенерировал бы очень большой файл листинга, а
программа была бы очень трудна в прочтении и отладке. Общий объем памяти, исполь-
зуемой этой системой, составляет 1044 слова (только приблизительно половину дос-
тупного объема) памяти программ и 432 байта памяти данных. Эта программа, в основ-
ном, составлена из других примеров программ, приведенных в более ранних главах.
Самое большое изменение в программе - это коррекция функции Switch. Так как пози-
ция разряда известна, то она не передается функции Switch в вызове. Другое измене-
ние функции Switch связано с тем, как в ней отрабатывается таймаут по истечении 3
секунд. Если возвращается 0, то это означает, что кнопка была нажата, а если возвра-
щается 1 то это значит, что к кнопке не прикасались по крайней мере в течении 3 се-
кунд. Эти изменения необходимы для использования кнопки с целью установки време-
ни дня.
340
Применение микроконтроллеров PIC18
Пример 8.3
/*
* Пример отображения времени и температуры
* /
#include <pl8cxxx.h>
#include <timers.h>
#include <delays.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* -- выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
* /
# pragma config OSC = HS
# pragma config WDT = OFF
# pragma config LVP = OFF
# pragma config BOR = OFF
# pragma config MCLRE = ON
void MyHighlnt (void); // прототипы для процедур обслуживания
void MyLowInt (void); // прерываний
void timeTemp (void);
int getTemp (void);
# pragma interrupt MyHighlnt // MyHighlnt - прерывание
# pragma code high_vector=0x08 // high_vector - в 0x0008
void high_vector (void) // высокоприоритетный вектор
{
_asm GOTO MyHighlnt _endasm // переход на подпрограмму обработки
// высокоприоритетного прерывания
}
# pragma interruptlow MyLowInt // MyLowInt - прерывание
# pragma code low_vector=0xl8 // низкоприоритетный вектор - в 0x0018
void low_vector (void) // низкоприоритетный вектор
{
_asm GOTO MyLowInt _endasm // переход на подпрограмму обработки
// низкоприоритетных прерываний
}
// Данные в памяти программ
rom near char look7[] = // 7-сегментная поисковая таблица
{
0x3F, // 0 сигналы с активной логической единицей
0x06, // 1
0x5В, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, H 7
0x7F, H 8
0x6F и 9
Глава 8. Прерывания
341
} ;
// Переменные в памяти данных
char tenths; char tenths; char minutes;' char hours; // хранение времени // отображение информации // установка флага времени
char char char char displayRAM[8]; setTimeFlag; select; pointer;
// И отображение кода выбора отображение указателя
((pragma code // здесь начинается программный код
void ( MyHighlnt (void)
i INTCONbits.1MR0IF = 0; // сброс запроса от таймера 0 PORTB = select;
PORTC = displayRAM[pointer++];
select <<= 1;
if (pointer == 8)
{
pointer = 0;
select = 1;
1
)
void MyLowInt (void)
{
PIRlbits.TMR1IF = 0; // сброс запроса от таймера 1
WriteTimerl (53000); // перезагрузка счетчика минус смещение (36)
tenths++; // инкрементирование таймера
if (tenths == 10)
{
tenths = 0;
seconds++;
if (seconds == 60)
{
seconds = 0;
minutes++;
if (minutes == 60)
{
minutes = 0;
hours++;
if (hours == 13)
hours = 1;
)
)
)
if ((tenths|seconds) == 0) // один раз в минуту
timeTemp();
)
void timeTemp (void)
{
int temp;
if (setTimeFlag == 0)
342
Применение микроконтроллеров PIC 18
displayRAM[4] = 0x71; // F для температуры
displayRAM[0] = look7[minutes % 10];
displayRAM[l] = look*? [minutes / 10];
displayRAM[2] = look7[hours % 10];
displayRAM[3] = look7[seconds / 10];
temp = getTempO;
displayRAM[7] = 0;
if (temp < 0)
{
temp = -temp;
displayRAM[7] = 0x40;
)
else
if (temp >= 100)
{
temp -= 100;
displayRAM[7] = 6;
}
displayRAM[4] = look7[temp % 100];
displayRAM[5] = look7[temp / 10];
void sendClock (void) = 0; = 1; // // SC = 0 SC = 1
I PORTAbits.RAI PORTAbits.RAI
J int i getTemp (void)
i int temp = 0; char a; PORTAbits.RA3 for (a = 0; a i = 0; < 16; a++) // // #CS = 0; получение 16 битов
temp «= 1; temp |= PORTAbits.RA2 » sendClock(); 1;
a = 0; if ((temp & 0x8000) == 0x8000) I // проверка знака
a = 1; temp = i -temp; П формирование положительного числа
temp »= 7; if (STATUSbits.C = 1) temp++; temp = (9 * temp) /5+32; if (a) temp = - temp PORTAbits.RA3 = 1 // // по Фаренгейту #CS = 1
\ return temp; // возврат с температурой
j int / Switch (void)
t int delay = 1500; // для 3-секундной задержки
Глава 8. Прерывания
343
do // ожидание отпускания
t while ((PORTA & 1) != 1); DelaylKTCYx (15); }while ((PORTA & 1) != 1); do // ожидание нажатия
t =while ((PORTA & 1) == 1) { DelaylKTCYx (2); delay—; if (delay == 0) return 1; 1 // если таймаут
J DelaylKTCYx (15); }while ((PORTA & 1) == 1); return 0; // если кнопка нажата
/ главная программа
oid main (void)
ADCON1 = OxOF; // все порты цифровые
TRISA = 0x05; // программирование порта А
TRISB =0; // программирование порта В
TRISC =0; // программирование порта С
PORTB =0; // все индикаторы выкл.
PORTA = 0х0А; // #CS и SC = 1
tenths = seconds = minutes = setTimeFlag = pointer = 0;
select = 1;
hours = 12;
timeTemp(); // инициализация индикатора
INTCON2bits.TMR0IP = 1; // таймер 0 высокоприоритетный
IPRlbits.TMR1IP = 0; // таймер 1 низкоприоритетный
WriteTimerO (0) ;
OpenTimerO (TIMER_INT_ON & // каждые 1024 мкс
T0_8BIT &
T0_SOURCE_INT &
T0_PS_l_4);
WriteTimerl (53036); // каждые 100 мс
OpenTimerl (TIMER_INT_ON &
T1_8BIT_RW &
T1_SOURCE_INT &
T1_PS_1_8);
RCONbits.IPEN =1; // IPEN = 1 для разрешения
// приоритетов прерываний
INTCONbits.GIEH =1; // разрешает высокоприоритетные
// прерывания
INTCONbits. GIEL =1; // разрешает низкоприоритетные
// прерывания
while (1) // главный цикл
344
Применение микроконтроллеров PIC 18
while (Switch!) == 1);
setTimeFlag = 1;
displayRAM[4] = 0x76;
timeTemp();
while (Switch () == 0)
{
hours++;
if (hours == 13)
hours = 1;
timeTemp();
}
displayRAM[4] = 0x6D;
timeTemp();
while (Switch () == 0)
{
minutes++;
if (minutes == 60)
minutes = 0;
timeTemp();
}
setTimeFlag = 0;
timeTemp();
// ожидание нажатия кнопки
// не отображать F
// отображать Н
// отображать S
Эта программа использует два прерывания: высокоприоритетное прерывание,
мультиплексирующее индикаторы и низкоприоритетное прерывание, которое происхо-
дит каждые 100 мс с тем, чтобы инкрементировать таймер реального времени. Низко-
приоритетное прерывание также изменяет содержимое оперативной памяти отобра-
жения один раз в минуту, когда изменяется время через вызов функции timeTemp.
Эта взятая в качестве примера система использует два таймера, которые явля-
ются важными для функционирования таймера реального времени и индикаторов.
Таймер 0 используется для того, чтобы мультиплексировать индикаторы - каждый раз
при его переполнении генерируется высокоприоритетное прерывание. Таймер 0 на-
страивается таким образом, что он использует коэффициент деления предварительно-
го делителя, равный 4. При этом входной сигнал таймера, частота которого равна 1
МГц (тактовая частота системы равна 4 МГц) преобразуется в сигнал с частотой, рав-
ной 250 кГц (4 мкс). В регистр таймера заносятся нули, поэтому прерывания буду! вы-
зываться через каждые 256 4-микросекундных входных тактовых импульсов или один
раз каждые 1024 мкс. Это заставляет частоту мигания каждого индикатора быть при-
близительно равной 125 Гц.
Таймер 1 используется для того, чтобы сгенерировать низкоприоритетное пре-
рывание один раз каждые 100 мс, используя коэффициент предварительного делителя
8 с тем, чтобы сформировать период тактовой частоты на входе таймера 1, равный 8
мкс. Таймер 1 программируется отсчетом, равным 53036, который обеспечивает при-
ход 12500 тактовых импульсов перед переполнением таймера. 12500 раз по 8 микросе-
кунд будет равно 100 миллисекунд, поэтому низкоприоритетное прерывание возникает
через каждые 100 миллисекунд, таймер реального времени делит 100-миллисекундные
импульсы на 10, получая отсчеты в секундах и формируя остаток отсчета времени.
Таймер реального времени отсчитывает время в 12-часовом формате с индикацией
букв AM (до полудня) или РМ (после полудня), которая широко распространена в инди-
каторах времени такого типа. Обратите внимание на то, что альтернативой использо-
Глава 8. Прерывания
345
ванию начального отсчета в 53036 может быть загрузка числа -12500, которая и долж-
на, вероятно, использоваться, ибо смысл этого числа проще понимается. 53036 - это
16-разрядное число 0xCF2C, а -12500 - также 0xCF2C, поэтому любой из названных
предварительных отсчетов может использоваться в программе.
Пример 8.3 использует файл заголовка timers.h для того, чтобы упростить про-
граммирование таймера. Файл заголовка timers.h содержит четыре функции для каж-
дого таймера: OpenTimer, CloseTimer, ReadTimer и WriteTimer. В данном примере ис-
пользуются только функции OpenTimer и WriteTimer. Для получения полного списка этих
функций, а также детальных сведений по ним, обращайтесь к вебсайту фирмы
Microsoft, а также смотрите PDF-файл библиотеки MPLAB-C18 и приложение В, в кото-
ром приведен сжатый перечень библиотечных функций.
8.2. USART и прерывания
USART (универсальный синхронно-асинхронный приемопередатчик) генерирует
и получает как синхронные, так и асинхронные последовательные данные. Как и боль-
шинство устройств микроконтроллера, это устройство также использует прерывания во
время своей нормальной работы с тем, чтобы повысить эффективность системы.
USART может эксплуатироваться и без прерываний, если это необходимо, но в боль-
шинстве случаев его работа в режиме прерываний является более эффективной. В
библиотеке С18 имеется программное обеспечение работы с UART (универсальный
асинхронный приемопередатчик) которое работает с асинхронными последовательны-
ми данными. UART рассматривается в более поздних подразделах этой книги.
Последовательные данные
Последовательные данные, могут быть как синхронными, так и асинхро! 1ными. Синхрон-
ные данные передаются с синхроимпульсом для синхронизации, а асинхронные данные пере-
даются без синхроимпульса. Большинство данных сегодня - это асинхронные данные. В до-
полнение к этим двум базисным типам последовательных данных, данные могут посылаться в
симплексном режиме, а также полудуплексном или полнодуплексном (который обычно назы-
вают просто дуплексным) режиме. Симплексный режим означает информацию, которая все-
гда посылается в одном направлении, - типа радиосигнала от спутникового передатчика. Ни-
какая информация никогда не посылается на спутник, она только принимается. Полудуплекс-
ный режим означает информацию, которая может быть послана или получена, но одновремен-
но только в одном направлении. Примером полудуплексной системы является СВ (граждан-
ская полоса) в радиосвязи или интерфейс USB (универсальная последовательная шина) в
компьютере. В СВ-радиосвязи передаваемое сообщение заканчивается словом “over” (конец),
чтобы информировать слушателя о том, что сейчас его очередь выполнять передачу. В USB-
системе, которая является полудуплексной системой, протокол требует, чтобы устройсгво-
приемник ждало момента, когда последовательная линия станет доступной перед передачей
информации. В полнодуплексной системе информация передается и принимается одновре-
менно. Примером полнодуплексной системы является телефонная система.
На рис. 8.3 представлены асинхронные данные, когда они передаются USART или
UART. Фрейм последовательных асинхронных данных содержит в большинстве случаев
10 битов и начинается стартовым битом. Заканчивается фрейм, по крайней мере одним
стоповым битом, хотя могут присутствовать и много стоповых битов, сколько это необ-
ходимо для того, чтобы выполнить разделение информации. Логический ноль часто
называют пробелом, а логическую единицу - меткой. Данные, которые заключены меж-
ду стартовым и стоповыми битами, это обычно восемь битов, при этом первым переда-
346
Применение микроконтроллеров PIC 18
ется младший бит. Данные могут быть успешно получены вследствие того, что частота
передачи или время передачи бита являются известными. Большинство систем толе-
рантны к колебаниям в значении периода передачи бита порядка +/- 5%. Например,
если данные передаются со скоростью 9600 бит/сек (битов в секунду), то это означает,
что 960 символов или байтов передается за секунду. Каждый символ требует для своей
передачи 10 периодов передачи бита. Данные передаются со скоростью 960 бай-
тов/секунду. Скорость передачи битов составляет (часто называемая скоростью в бо-
дах) будет равна 1/9600 или 104,2 мкс на бит. Обратите внимание на то, что скорость
передачи битов - это не есть скорость информационного обмена в бодах. Скорость
информационного обмена в рассматриваемом случае равна 960 бит/секунду, а ско-
рость передачи битов или скорость в бодах будет равна 9600 бит/сек. Скорость пере-
дачи битов была названа в честь Эмиля Бода, который создал код, называемый кодом
Бода. Этот код использовался в телеграфии на протяжении XIX века. Код Бода исполь-
зует стартовый бит, 5 битов данных и полтора стоповых бита, он был популярен вплоть
до недавних 1960-ых и использовался национальными поставщиками новостей. Сего-
дня стандартные асинхронные последовательные данные почти всегда используют
стартовый бит, 8 битов данных и 1 столовый бит.
Можно было бы легко генерировать этот тип данных программно, однако это при-
вело бы к почти полной загрузке микроконтроллера данной задачей. В силу этого схе-
ма, называемая USART, была включена в состав микроконтроллера с тем, чтобы пере-
давать и получать как синхронные, так и асинхронные последовательные данные.
USART был первой коммерчески доступной БИС (большой интегральной схемой), про-
изведенной в 1968 фирмой Texas Instruments.
Синхронные данные, которые не очень распространены сегодня, используют ли-
нию передачи сигналов и линию тактовой частоты. Рис. 8.4 иллюстрирует вид синхрон-
ных последовательных данных. Они не содержат никакого стартового или стопового
импульса, что повышает скорость передачи данных, потому что взамен использования
10 битов на байт данных при синхронной передаче данных используются только 8 битов
на байт данных. Этот тип данных вышел из широкого употребления ввиду необходимо-
сти использования дополнительного провода для передачи тактовой частоты. Если
сравнить два рисунка (см. рис. 8.3 и рис. 8.4), то можно увидеть, что в обеих случаях
передаются те же самые данные (символ А, за которым следует символ В), однако при
синхронной передаче данных на передачу тех же данных уходит меньшее количество
времени. Что не показывает рисунок 8.4, - так это то, что синхронные данные обычно
передаются пакетами. Пакет содержит фиксированное число байтов, при этом первым
идет байт, который указывает на начало пакета, а последним - байт, указывающий на
конец пакета. Время, требуемое на передачу этих двух байтов, снижает скорость ин-
формационного обмена. Эта книга концентрируется главным образом на асинхронной
передаче последовательных данных.
Управление USART
USART, находящийся внутри PIC18, содержит программируемый генератор ско-
рости информационного обмена, устанавливающий скорость обмена данными. Гене-
ратор скорости информационного обмена программируется посредством загрузки
численного значения в регистр, который называется SPBRG. Этот регистр программи-
рует внутренний таймер таким образом, что системная тактовая частота делится на
число, загруженное в SPBRG. Пример 8.4 показывает уравнения, используемые для
того, чтобы вычислить значение числа, загружаемые в SPBRG с тем, чтобы генериро-
вать нужную скорость в бодах. Так как таймер скорости информационного обмена
Глава 8. Прерывания
347
представляет собой 8-разрядный таймер, то самое большое число, которое может в
него заноситься, равно OxFF (255) или, если используется нулевое значение, 256. Пока-
занные три уравнения используются для того, чтобы вычислить значение, которое нуж-
но загрузить в SPBRG для изменения рабочих условий типа тактовой частоты и жела-
тельной скорости информационного обмена. Единственное различие между приведен-
ными уравнениями связано с использованием констант 64 (называется “медленной”),
16 (называется “высокоскоростной”) и 4 (для работы в синхронном режиме), которые
устанавливают внутренний предварительный делитель через таймер скорости инфор-
мационного обмена.
Пример 8.4
-’-.синхронный режим, скорость информационного обмена низкая (X программируется
= SPBRG)
скор.инф.обм.J
Асинхронный режим, скорость информационного обмена высокая (X программируется
з SPBRG)
( Fosc 1-1А 1
х = ----------— -16 -1
скор.инф. o6m.J
Синхронный режим (X программируется в SPBRG)
( Fosc 'I г л л
х - ----------—— Н- 6 4 -1
^скор.инф.обм.J
’Примечание: Fosc = тактовой частоте
Например, для того, чтобы USART работал в асинхронном режиме при скорости в
бодах, равной 9600, можно использовать как уравнение для медленной скорости, так и
уравнение для высокой скорости с тем, чтобы определить значение, загружаемое в
SPBRG. При использовании тактовой частоты, равной 16 МГц, значение для медленной
скорости будет равно 25, а значение для высокой скорости будет равно 103. Чтобы вы-
брать высокую скорость, бит BRGH в регистре TXSTA устанавливается в состояние ло-
гической единицы. USART использует вывод RC6 для передачи данных (ТХ) и вывод RC7
для приема данных (RX) на микроконтроллере PIC18F2220. Другие члены семейства PIC
могут использовать другие выводы, поэтому необходимо сверяться со спецификация-
ми выбранного устройства. Рис. 8.5 иллюстрирует подключение PIC18F2220 к после-
довательному интерфейсу с использованием микросхемы управления линией DS275.
Эта ИС обеспечивает преобразование уровней TTL в стандартные уровни интерфейса
RS-232. Стандартные логические уровни интерфейса RS-232C определяются как от 3
до 25 В для логического нуля и от -3 до -25 В для логической единицы. Практически при
использовании DS275, напряжения логических уровней будут равны +/-12 В. Соедини-
тельный разъем DB9 (9-выводной разъем типа D) используется для подключения к по-
следовательному COM-порту ПК. Показанное на рисунке 8.5 подключение предназна-
чено для стандартного последовательного кабеля (это не кабель нуль-модема). Как
соединительный разъем показанной схемы, так и соединительный разъем СОМ-порта
ПК являются ответными разъемами. Соединительный кабель должен иметь с обеих
сторон вставные разъемы.
Кадр символа
стоп-биты
DO Dl D2 D3 D4 D5 D6 D7
t
стартовый бит
стоп-биты
Пример передачи символа “А”, за которым следует символ “В”
стоп-биты стартовый бит
стоп-биты
стоп-биты стартовый
Л бит
Применение микроконтроллеров PIC 18
А = 0x41
В = 0x42
Рис. 8.3. Асинхронные последовательные данные, использующие
восемь информационных битов и один стоп-бит.
Глава 8. Прерывания
349
Дата
Время
А = 0x41
В = 0x42
Рис. 8.4. Синхронная передача данных
Программа для этого интерфейса приведена в примере 8.5. Последовательный
интерфейс программируется на асинхронный режим работы с 8 битами данных при
скорости информационного обмена в бодах, равной 9600. Это обычно устанавливаемая
по умолчанию скорость информационного обмена ПК. Функция OpenllSART програм-
мирует USART в данном случае так, чтобы он работал в режиме прерываний как от при-
емника, так и от передатчика, который разрешается установкой в состояние логиче-
ской единицы бита BRGH. Для скорости информационного обмена в 9600 бод, расчет-
ное значение для SPBRG равно 25. Приведенный пример программы реагирует на две
команды, посылаемые из ПК: символ “С” для соединения и символ “G” для отсоедине-
ния. Если микроконтроллер получает символ С, оно возвращает символьную последо-
вательность со словом ’’Hello” (Привет) назад в ПК в форме стандартной строки симво-
лов ASCII. Стандартные строки символов ASCII завершаются символом “возврат карет-
ки" (0x0D), который сопровождается символом “перевод строки” (ОхОА). Если микро-
контроллер получает символ G от ПК, то он посылает в ПК строку символов ASCII, со-
держащую слово “Goodbye” (До свидания). Эта программа может служить основой ор-
ганизации связи между ПК и микроконтроллером. Микроконтроллер использует две
очереди для того, чтобы буферизовать информационный обмен с ПК. Он также исполь-
зует прерывания для того, чтобы обрабатывать как передаваемые, так и получаемые
данные.
350
Применение микроконтроллеров PIC 18
+5V
О
Разъем DB9
R1
ЮК
4 MHz
VDRV 5
04
DS275
U2
С2
0.1 uF
сэ
1.0 uF
RXN ft RXOUT
DON >Q TOUT
7.
3
Y1
d[]h
PIC18F2220
U1
22
27 pF
2
3
4
5.
в
7
O'
10
j- RAO
г- RA1
Г RA2
- RA3
Г RA4
Г RA6
£ MCLR
г OSC1
- OSC 2
RBO
RBI
RB2
RB3
OR
RB5
25
26
27
28
16
18
RC5
RC6«g
RC7 >
RB7
RCO
RCiHr-
RC2
gScJ
12
13
14
С5
27 pF
О
§
Рис. 8.5. USART, подключенный к стандартному разъему DB9, с целью организации
информационного обмена через интерфейс RS-232C
Пример 8.5
/*
* пример использования прерываний при работе USART
*/
#include <pl8cxxx.h>
#include <usart.h>
/* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
♦pragma config OSC = HS
#pragma config WDT = OFF
♦pragma config LVP = OFF
Глава 8. Прерывания
351
((pragma config BOR = OFF ((pragma config MCLRE = ON
void MyHighlnt (void); // прототипы процедур
void MyLowInt (void); // обслуживания прерываний
((pragma interrupt MyHighlnt // MyHighlnt - это прерывание
#pragma code high_vector=8 // high_vector по адресу 0x0008
void high_vector (void) 1 // высокоприоритетный вектор
1 _asm GOTO MyHighlnt _endasm // переход на подпрограмму обработки
// высокоприоритетных прерываний
((pragma interruptlow MyLowInt // MyLowInt - это прерывание
((pragma code low_vector=0xl8 // низкоприоритетный вектор
// по адресу 0x0018
void low_vector (void) { // низкоприоритетный вектор
_asm GOTO MyLowInt _endasm // переход на подпрограмму обработки
// низкоприоритетных прерываний
' / данные в памяти данных
char inQueue[16];
char outQueue[16]
char inPi;
char inPo;
char outPi;
char outPo;
tpragma code // здесь начинается программный код
int outlnQueue (void)
int temp;
if (inPi == inPo)
return 0x100; // если пусто
temp = inQueue[inPo]; // получение данных
inPo = (inPo + 1) & OxOF;
return temp;
int inlnQueue (char data)
{
if (inPi == ( (inPo + 1) & OxOF) )
return 0x100; // если заполнено
inQueue[inPi] = data;
inPi = (inPi + 1) & OxOF;
return 0;
}
int outOutQueue (void)
352
Применение микроконтроллеров PIC 18
(
int temp;
if (outPi == outPo)
return 0x100; // если пусто
temp = outQueue[outPo]; // получение данных
outPo = (outPo +1) & OxOF;
return temp;
}
int inOutQueue (char data)
{
if (outPi == ((outPo + 1) & OxOF))
return 0x100; // если заполнено
outQueue[outPi] = data;
outPi = (outPi + 1) & OxOF;
PIElbits.TXIE =1; // передатчик вкл.
return 0;
}
void MyHighlnt (void)
{
int temp;
if (PIRlbits.RCIF == 1)
(
PIRlbits.RCIF = 0; // сброс прерывания
inlnQueue (RCREG); // сохранение принятых данных
// в очереди
}
else if (PIRlbits.TXIF == 1 && PIElbits.TXIE == 1)
{
PIRlbits.TXIF = 0; // сброс прерывания
temp = outOutQueue();
if (temp == 0x100)
(
while (TXSTAbits.TRMT == 0) ;
PIElbits.TXIE = 0; // передатчик выкл.
}
else
TXREG = temp; // передача данных
}
}
void MyLowInt (void)
{
// в данном примере здесь ничего не делается
}
// главная программа
void main (void)
(
int temp;
ADCON1 = 0x0F; // все порты цифровые
TRISC = 0x80; // программирование порта С
IPRlbits.TXIP =1; // выбор высокого приоритета
IPRlbits.RCIP = 1;
inPo = inPi = outPo = outPi = 0; // настройка очередей
OpenUSART (USART_TX_INT_ON & // USART работает на скорости 9600 бод
USART_RX_INT_ON &
USART_ASYNCH_MODE &
Глава 8. Прерывания
353
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH,
25) ;
RCONbitS.IPEN = 1;
INTCONbits.GIEH = 1;
прерывания
INTCONbits.GIEL = 0;
while (1)
{
temp = outlnQueue();
if (temp != 0x100)
{
if (temp == 'C' )
{
inOutQueue('H');
inOutQueue('e');
inOutQueue( '!' ) ;
inOutQueue ('!');
inOutQueue('o') ;
inOutQueue(13);
inOutQueue(10);
// IPEN = 1 для разрешения
// приоритетов прерываний
// разрешение высокоприоритетного
// разрешение низкоприоритетного
// прерывания
// получение данных от ПК из InQueue
// если данные обнаружены
else if (temp == 'G')
{
inOutQueue('G');
inOutQueue('o' ) ;
inOutQueue('o');
inOutQueue('d');
inOutQueue('b');
inOutQueue ('y');
inOutQueue('e');
inOutQueue(13);
inOutQueue(10);
// если код С (соединение)
// передача Н
// передача е
// передача 1
// передача 1
// передача о
// передача символа
// "возврат каретки"
// передача символа
// "перевод строки"
// если код G (отсоединение)
// передача G
// передача о
// передача о
// передача d
// передача b
// передача у
// передача е
// передача символа
// "возврат каретки"
// передача символа "перевод строки"
Для того, чтобы эта программа работала с ПК, необходимо, чтобы в ПК работало
соответствующее приложение. Для этой цели может использоваться приложение
Hyperterminal, или же для этой цели может быть написана короткая программа на Visual
C++. Рис. 8.6 показывает снимок экрана приложения на Visual C++, написанного для
тестирования микроконтроллера и программы из примера 8.5.
354
Применение микроконтроллеров PIC 18
Рис. 8.6. Снимок экрана. Visual C++
Программа на Visual C++ с или без управления Active-X, требуемая для выполне-
ния названной задачи, показана в примере 8.6. Эта программа работает с любой вер-
сией Windows, начиная Windows 98 и вплоть до Windows ХР. Все, что необходимо - это
Visual Studio любой 32-разрядной версии (Visual С версии 5.0 или более новой), а также
знание того, как создаются приложения на Visual C++. Это приложение (пример 8.6 (а))
использует объект Active-X с именем mscomm для управления последовательным ин-
терфейсом, он создан в Visual Studio.net 2003. Для того, чтобы это приложение функ-
ционировало в других версиях Visual Studio, может потребоваться некоторая его моди-
фикация, поскольку Microsoft постоянно изменяет некоторые аспекты этого пакета.
Объект mscomm Active-X находится либо в самом вашем пакете Visual Studio, либо его
можно выгрузить из Internet. Скорость и другие параметры устанавливаются в окне
управления свойствами Visual С. Приводимая здесь программа - это просто добавле-
ние к простому диалоговому приложению, которое использует Buttonl для соединения,
Button2 для разъединения и Listl для выдачи списка, в котором отображаются ответы
микроконтроллера. Чтобы добавить хэндлер кнопки в Visual Studio.net 2003, щелкните
на иконке желтого светящегося болта. Две функции коммуникационного порта добав-
лены к классу диалога, используя мастер добавления функций. Для того, чтобы эта
программа функционировала правильно, микроконтроллер должен быть включен до
того, как эта программа на Visual С начнет выполняться. Также нужно удостовериться в
том, что порт СОМ1 подключен к микроконтроллеру.
Глава 8. Прерывания
355
Пример 8.6 (Ь) показывает, как обратиться непосредственно к ядру Windows с
тем, чтобы связаться с СОМ- портом. Если управление Active-X доступно, то используй-
те его, потому что в этом случае программа будет немного короче, кроме того, будет
иметься вероятность того, подпрограмма работы с ядром сможет работать и с буду-
щими версиями Windows.
Пример 8.б (а)
void OpenComPort()
mscomml.put_CommPort(1); // выбор COMI
mscomml.put_InputLen(1);
mscomml.put_RThreshold(1); // выполнение OnComm для каждого
// принятого символа
mscomml.put_PortOpen(true); // открытие СОМ1
void CPICCDlg::OnBnClickedButtonl() // кнопка соединения
int temp;
CString message;
WriteComPort ("C");
// передача "C"
void CPICCDlg::OnBnClickedButton2() // кнопка разъединения
int temp;
CString message;
WriteComPort ("G");
// передача "G"
void CPICCDlg::WriteComPort (CString data)
mscomml.put_Output(COleVariant(data)); // передача строки
void CPICCDlg::OnCommMscomml()
CString temp;
if (comm.get_CommEvent() == 2) // 2 = принятый символ event
{
do
{
temp += comm.get_Input() ;
}while (comm.get_InBufferCount() > 0);
}
Lisi.AddString (temp);
356
Применение микроконтроллеров PIC 18
Пример 8.6 (б)
HANDLE hPort; // определение хэндлера
DCB deb; // определение блока управления
void CPICCDlg::OpenCom (CString port, DWORD baudrate)
(
COMMTIMEOUTS Timeout; // структура таймаута
hPort = CreateFile ( // создание хэндлера для COM-порта
port,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
GetCommState (hPort,&dcb); u установ состояния COM-порта
deb.BaudRate = baudrate; // скорость инф.обмена
deb.ByteSize = 8; H 8 информационных битов
deb.Parity = NOPARITY; // без паритета
deb.StopBits SetCommState = ONESTOPBIT; (hPort,&dcb); // 1 стоп-бит
GetCommTimeouts (hPort, &Timeout); // установка таймаута COM-порта
Timeout.ReadlntervalTimeout = 500;
Timeout.ReadTotalTimeoutConstant = 500;
Timeout.ReadTotalTimeoutMultiplier = 100;
Timeout.WriteTotalTimeoutConstant = 500;
Timeout.WriteTotalTimeoutMultiplier = 100;
SetCommTimeouts (hPort, &Timeout);
)
void CPICCDlg::SendPort (CString str)
{
DWORD byteswritten;
WriteFile (hPort, str, 1, &byteswritten, 0);
return;
CString CPICCDlg::ReadPort (void)
{
char mes[100];
DWORD transferred;
DWORD error;
COMSTAT status;
do
{
ClearCommError (
hPort, // хэндлер Сот-порта
&error, // указатель на коды ошибок
&status); // указатель на состояние
mes[status.cblnQue] = 0;
ReadFile (hPort, &mes, status.cblnQue, &transferred, 0);
} while (status.cblnQue == 0); // пока данные не будут приняты
return mes;
Глава 8. Прерывания
357
8.3. Прерывания по изменению состояния
Входами прерываний по изменению состояния являются биты от RB4 до RB7 пор-
та В. Если прерывание по изменению состояния разрешено, и порт В запрограммиро-
ван как входной порт, то прерывание будет происходить в случае изменения состояния
любого из названных четырех выводов. Это свойство может быть полезно во многих
приложениях. Если происходит изменение состояния любого из названных выводов, то
происходит прерывание по изменению состояния, поэтому не забудьте проверять эти
четыре штырька в процедуре обслуживания прерывания с тем, чтобы определить точ-
но, какой точно вывод изменил свое состояние, если приложение использует более
одного штырька.
В главе 5 обсуждалось программное обеспечение системы DCC (управление при
помощи цифровых команд (макетом железной дороги)), а также опрос входного штырь-
ка с тем, чтобы измерить ширину импульса. Однако лучший способ измерения ширины
импульса связан с использованием прерывания по изменению состояния, а также тай-
мера. При таком подходе микроконтроллер может заниматься другими делами, изме-
ряя в то же время ширину импульсов сигналов. Из главы 5 вы узнали, что сигнал DCC
использует сигнал логической единицы, который имеет ширину импульса между высо-
ким и низким состоянием сигнала, равную от 52 до 64 мкс. Бит логического нуля намно-
го более широкий и имеет ширину импульса между высоким и низким состоянием сиг-
нала, равную от 90 мкс до 10000 мкс. Предположим, что схема, изображенная на рис.
8.7, подключена к рельсам в системе DCC. Силовая микросхема 754410 обеспечивает
ток вплоть до 1 А, при напряжении в 12 В на каждом из выходных выводов, когда она
активирована сигналом управления, который передается по рельсам и обнаруживается
микроконтроллером. Восемь выходных выводов управляют любой комбинацией из
восьми отдельных устройств или же четырьмя двунаправленными устройствами типа
стрелочных приводов.
Как и описывалось в главе 5, сигнал на рельсах электрически изолирован от схе-
мы оптической развязкой. Сигнал на рельсах показан на рис. 5. 4, после его кондицио-
нирования он приобретает вид ТТЛ- сигнала, приложенного к выводу RB7 микрокон-
троллера. Программа, написанная для этой схемы, приведена в примере 8.7. Каждый
раз при изменении состояния RB7 происходит прерывание. Очень важно, чтобы PORTB
считывался перед очисткой бита флага RBIF в процедуре обслуживания прерывания.
Если PORTB не будет считан перед очисткой бита флага RBIF, то условие изменения
останется истинным и бит RBIF будет немедленно установлен после его сброса. В про-
цедуре обслуживания прерывания переключение из нуля в единицу сбрасывает таймер
0, эту же операцию выполняет и переключение из единицы в ноль - разница заключает-
ся в том, что когда вход изменяется из единицы в ноль, то исследуется содержимое
таймера 0. Таймер 0 отсчитывает интервалы, равные одной четвертой части микросе-
кунды, при этом, если его отсчет будет находиться между 52*4 или 208 (52 мкс) и 64*4
или 256 (64 мкс), то содержимое ячейки памяти переменной изменится на 0x01 и флаг
ячейки памяти будет установлен, указывая на актуальные данные. Аналогичным обра-
зом, если таймер 0 будет содержать число между 90*4 или 360 (90 мкс) и 10000*4 или
40000 (10 мс), то переменная сбрасывается в ноль, флаг устанавливается, указывая на
распознанный логический ноль. Данная система замеряет только время высокого со-
стояния входного сигнала, поэтому она реально отображается данные, полученные с
рельсов. Система, описанная в главе 5, замеряла как время высокого, так и низкого
состояния сигнала.
L/l
oo
Рис. 8. 7. Восьмивыходной контроллер периферийных устройств системы DCC
Применение микроконтроллеров PIC18
Глава 8. Прерывания
359
Рис. 5. 6 иллюстрирует реальные данные, посылаемые, на устройство управле-
ния. Программа по примеру 8.7 распознает актуальные значения данных в бесконечном
цикле while главной программы. Эта программа должна быть способна распознавать
два типа пакетов: пакеты, управляющие состояниями восьми выходов и другие пакеты,
программирующие устройство. Программирование устройства ограничено установкой
адреса контроллера вспомогательного устройства. Адрес вспомогательного устройст-
ва сохраняется в ячейках памяти данных ЭСППЗУ CV513 (управляющая переменная
513) и CV521, где CV513 содержит младшую часть адреса устройства (А5-А0), a CV521
содержит старшие три бита адреса устройства (А8-А6). Три старшие бита адреса ин-
вертированы. Таким образом, при записи адреса вспомогательного устройства 0x074
значение в CV513 будет равно 0x34, а значение в CV521 - 0x06. Начальные значения в
CV513 и CV521- 0x00. Это означает, что первоначально адрес вспомогательного уст-
ройства равен 0x1 СО или 448 в десятичной системе счисления. Этот адрес изменяется
передачей команд CV на блок командного управления системы. Вспомогательное уст-
ройство может быть сброшено на заводские установки командами CV513 и CV521 =
0x00. Повторный сброс выполняется удержанием кнопки при включении системы. Биты
ааа команды, изображенные на рисунке 5-6, используются для того, чтобы выбрать
один из восьми выходов системы. В данном случае 000 выбирает выход 0, 001 выбира-
ет выход 1 и т.д. Бит С - это данные, посылаемые на выход. В этой системе, если С = 1,
то на выход подается 12 В при токе до 1 А, а если С = 0, выход не обеспечивает никакого
тока. Эти команды генерируются блоком командного управления типа, которые пред-
лагаются такими фирмами, как Digitrax или Lenz. Проектирование также может быть
выполнено с использованием другой микроконтроллерной системы.
Пример 8.7
* Пример декодера вспомогательного устройства DCC
*/
♦include <pl8cxxx.h>
♦include <timers.h>
* Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
’ - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
’ - разрешение общего сброса
’/
♦pragma config OSC = HS
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
void MyHighlnt (void);
void MyLowInt (void);
♦pragma interrupt MyHighlnt
♦pragma code high_vector=8
void high_vector (void)
// прототипы процедур
// обслуживания прерываний
// MyHighlnt - это прерывание
// high_vector по адресу 0x0008
// высокоприоритетный вектор
360
Применение микроконтроллеров PIC 18
_asm GOTO MyHighlnt _endasm // переход на подпрограмму обработки
высокоприоритетных прерываний
}
#pragma interruptlow MyLowInt // MyLowInt - это прерывание
^pragma code low_vector=0xl8 // низкоприоритетный вектор по адресу 0x0018
void low_vect.or (void) // низкоприоритетный вектор
(
_asm GOTO MyLowInt _endasm // переход на подпрограмму обработки
// низкоприоритетных прерываний
}
// память данных
char flag; // флаг доступности данных
char data;
// ******** присвоение адресов данных в памяти данных ЭСППЗУ ********
#define CV513 0 // младшая часть адреса
f define CV521 1 // старшая часть адреса
tfpragma code // здесь начинается программный код
// считывание из адреса местоположения ячейки в памяти данных ЭСППЗУ
char eeRead (char address)
{
EECONlbits.EEPGD = 0;
EEADR = address;
EECONlbits.RD = 1;
return EEDATA;
// запись данных в ячейку памяти данных ЭСППЗУ по адресу
void eeWrite (char address, char data)
(
INTCONbits.GIEH = 0;
INTCONbits.GIEL = 0;
EECONlbits.EEPGD = 0;
EECONlbits.WREN = 1;
EEADR = address;
EEDATA = data;
EECON2 = 0x55;
. EECON2 = OxAA;
EECONlbits.WR = 1;
while (PIR2bits.EEIF == 0);
PIR2bits.EEIF = 0;
EECONlbits.WREN = 0;
INTCONbits.GIEH = 1;
INTCONbits.GIEL = 1;
void MyHighlnt (void)
Глава 8. Прерывания
361
if (INTCONbits.RBIF == 1)
1
int temp = PORTB; // нужно считать PORTB для сброса изме-
нения
INTCONbits.RBIF = 0; // сброс прерывания
if (PORTBbits.RB7 == 0)
1
if (ReadTimerO() == 0) // первичное
{
OpenTimerO (TIMER_INT_OFF &
T0_16BIT &
TO_SOURCE_INT &
T0_PS_l_256);
}
else if (ReadTimerO() < 4 * 52)
WriteTimerO(0); // неверное значение, сброс таймера
else if (ReadTimerO() >= 4 * 52 &&
ReadTimerO() <= 4 * 64)
(
WriteTimerO(0); // корректная 1, сброс таймера 0
data = 1;
flag = 1;
}
else if (ReadTimerO() >= 4 * 90 &&
ReadTimerO() <= 4 * 10000)
{
WriteTimerO (0); // корректный 0, сброс таймера 0
data = 0;
flag = 1;
}
else // bad data
WriteTimerO (0); // сброс таймера 0
}
else
WriteTimerO (0); // сброс по единичному переключению
void MyLowInt (void)
// в этом примере здесь ничего не выполняется
char wait4Bit (void)
while (flag == 0); // ожидание бита
flag = 0;
return data;
char getByte (void) // прием байта
char temp = 0;
int a;
for (a = 0; a < 8; a++)
{
temp
1;
362
Применение микроконтроллеров PIC 18
temp |= wait4Bit();
}
return temp;
// главная программа
void main (void)
(
char check;
char count;
char packetBytes[6];
int a;
char mask;
ADCON1 = OxOF;
TRISA = 0;
TRISB = 0x80;
PORTA = PORTB = flag = 0;
if (PORTAbits.RA4 == 0)
(
eeWrite (CV513, 0);
eeWrite (CV521, 0);
}
INTCON2bits.RBIP =1; //
INTCONbits. RBIE =1; //
WriteTimerO (0); //
RCONbits.IPEN =1; //
INTCONbits.GIEH = 1; //
INTCONbits.GIEL =0; //
while (1)
(
count = 0;
while (count != 10)
{
if (wait4Bit() == 1)
count++;
else
count = 0;
// все порты цифровые
// программирование направления
//
если выполняется реконфигурирование
высокий приоритет
разрешение прерывания по изменению бита
инициализация таймера 0
IPEN = 1 для разрешения приоритетов
прерываний
разрешение высокоприоритетного прерывания
разрешение низкоприоритетного прерывания
// распознавание заголовка, состоящего
// по крайней мере из 10 единиц
while (wait4Bit() == 1); 11 ожидание дополнительных единиц
// пропуск заголовка в этой точке
count = 0;
do // получение всех байтов пакета
{
packetBytes[count++] = getByte();
}
while (wait4Bit == 0) ;
// получение всех байтов пакета count = количеству байтов
for (а =0; а < count; а++)
check Л= packetBytes[а];
Глава 8. Прерывания
363
if (check == 0) // правильная контрольная сумма
{
if ((packetBytes[0] & 0x3F) == eeRead(CV513) &&
(((packetBytes[1] >> 4) & 0x07) Л 0x07)
== eeRead (CV521)) // соответствие адреса
(
if (count == 3) // если команда
{
mask = 1;
mask <<= packetBytes[1] & 3;
if ((packetBytes[1] & 4) == 0 &&
(packetBytes[1] & 8) == 0)
PORTB &= mask Л OxFF;
else if ((packetBytes[1] & 4) == 0 &&
(packetBytes[1] & 8) == 8)
PORTB |= mask;
else if ( (packetBytes [1] & 4) == 4 &&
(packetBytes[1] & 8) == 0)
PORTA &= mask л OxFF;
else
PORTA |= mask;
}
else if (count == 5) // если команда программирования CV
(
if ( (packetBytes[1] & 3) == 2 &&
packetBytes[2] == 0) // if CV513
eeWrite(CV513, packetBytes[3]);
else if ( (packetBytes[1] & 3) == 2 &&
packetBytes[2] == 8) // if CV521
eeWrite(CV521, packetBytes [ 3 J);
111111111 0
10AAAAAA 0 0AAA11 aa 0 aaaaaaaa 0
DDDDDDDD0 XXXXXXXX 1
preamble
Data for CV
CV address
Рис. 8.8. Вспомогательная команда для программирования регистра CV
Форматы пакетов программирования адресов вспомогательных устройств в
CV513 (адрес 0x200) и CV521 (адрес 0x208) показаны на рис. 8.8. Эти пакеты содержат
пять байтов вместо трех байтов в случае команд декодера вспомогательных устройств.
Адреса CV начинаются от CV1 (0x000), таким образом, CV513 программируется на ад-
рес 512 (0x200).
364
Применение микроконтроллеров PIC18
8.4. Примеры систем, работающих с прерываниями
Этот подраздел представляет несколько систем, работающих с прерываниями с
тем чтобы вы могли использовать их либо в качестве практических примеров, либо в
качестве образцов решений. Чем большее количество систем вы изучите, тем более
опытными вы станете в программировании и организации интерфейсов.
Пример системы 1
Первой системой, которую мы рассмотрим, будет система, о которой мы уже го-
ворили в главе 2. Эта система регистрировала информацию из идентификационных
карточек и передавала ее по последовательной линии связи в центральную регистри-
рующую компьютерную систему. Эта система содержит последовательный интерфейс,
ЖК-индикатор и вспомогательную клавиатуру. Эта система могла бы использоваться
либо как система табелирования, регистрирующая рабочие часы работника, либо как
система регистрации посещаемости учеников в школе. Однако, как бы она не исполь-
зовалась, эта система нуждается в прерываниях для работы таймера реального време-
ни, обработки чисел, считанных с идентификационной карточки, а также для обработки
данных, передаваемых по последовательной линии связи. Эта система использует
много прерываний - она заслуживает более подробного исследования.
Теперь, когда вы имеете концептуальное видение системы, следует выбрать ее
компоненты перед тем, как приступить к разработке. В этой системе необходимы сле-
дующие компоненты:
1. Микроконтроллер (тип которого будет определен позже).
2. ЖКИ на две строки по 40 символов в строке. Две строки необходимы для того,
чтобы отобразить идентификационный код служащего и его имя, а также сообщение,
адресованное ему.
3. Оптический считыватель карточек. Мог бы быть выбран магнитный считыватель
карточек, однако он потребовал бы использования специального оборудования, пред-
назначенного для изготовления магнитных идентификационных карточек. В то же вре-
мя оптические идентификационные карточки могут быть созданы на обычных совре-
менных принтерах, единственное специальное оборудование, которое необходимо в
этом случае - это устройство для ламинирования карточек.
4. Простой совместимый с ПК последовательный интерфейс, который использует
витую пару проводов. Может потребоваться, чтобы линии этого интерфейса были дос-
таточно длинными, поэтому использование USB является неприемлемым, ибо он до-
пускает длину провода всего лишь в несколько метров. Выбор интерфейса будет обсу-
ждаться позже в этом подразделе.
5. Клавиатура. Поскольку данная система должна быть легка в использовании без
применения каких-либо специальных кодов, малая клавиатура телефонного стиля не
рекомендуется, так как она не имеет достаточного количества клавиш. Необходимое
число клавиш и их функции будут обсуждаться позже в этом подразделе.
6. Источник электропитания. Если используется источник электропитания, уста-
новленный на расстоянии, то используйте две витые пары проводов, - одну для подво-
да электропитания к блоку, а другую - для передачи последовательных данных. Две
пары телефонных проводов или провод типа САТ5 (категория 5) могли бы быть хоро-
шим выбором для кабеля. Кабель САТ5 широко распространен и содержит четыре пары
проводов, что более, чем достаточно для данного применения. В качестве соедини-
тельных разъемов должны использоваться разъемы типа RJ-45.
Рис. 8.9. Система считывания идентификационных карточек. Схемотехническое решение
Глава 8. Прерывания
366
Применение микроконтроллеров PIC 18
Микропроцессоры PIC с 18 выводами, вероятно, не смогут обеспечить количест-
во выводов, достаточное для этого применения. Необходимо, следовательно исполь-
зовать микроконтроллер с 28 штырьками. ЖК-индикатор требует использования шести
подключений, а клавиатура, вероятно, потребует девяти подключений, если принять,
что вспомогательная клавиатура 5x4 будет достаточна. Если учесть, что несколько
выводов потребуются для последовательного подключения и несколько - для оптиче-
ского считывателя карточек, то можно предположить, микроконтроллер с 28 штырька-
ми будет приемлемым выбором для того, чтобы управлять этой системой. Вебсайт
фирмы Microchip рекомендует микропроцессор PIC18F2580, который имеет 32кб памя-
ти программы, 1536 байт СЗУПВ, и 256 байтов ЭСППЗУ, что должно обеспечить доста-
точный объем памяти для этой системы. Предположим, что идентификационные номе-
ра служащих ограничены в длину 10 алфавитно-цифровыми символами. Если 412 бай-
тов СЗУПВ используются для резервного хранение идентификационных номеров, то
это означает, что имеется место для сохранения 41 идентификационного номера. В
редких случаях, когда связь с ПК нарушается, идентификационные номера должны
временно сохраняться в системе. Остающиеся байты СЗУПВ дают объем памяти, более
чем достаточный для решения любой задачи, которая должна выполниться в данной
системе.
В качестве оптического считывателя карточек в этой системе выбран сканирую-
щий модуль Opticon LCO SR, который имеет выходной сигнал ТТЛ-уровня. Выход этого
модуля подается на 5-выводной разъем типа DIN, на вывод 1 которого подается 5 В, на
вывод 2 - выходной TLL и на вывод 3 - земля. Рис. 8.9 иллюстрирует принципиальную
схему системы, включая подключение считывателя карточек.
Кабель САТ5 использует 7 из 8 проводов, если только в системе не используются
повторители, - в этом случае потребуется одна дополнительная линия. При этом самые
крайние проводники разъема (выводы 1, 2, 7 и 8) используются для подачи электропи-
тания от блока питания ведущего ПК на каждый из 16 считывателей идентификацион-
ных карточек, подключенных к системе. Более 16 отводов могут использоваться, если
на линии установлен повторитель. Система использует стандартный интерфейс RS-
422, длина кабеля которого может достигать вплоть до 4000 футов, т.е. иметь в длину
почти милю. Дифференциальный сигнал данных передается по центральным проводам
(выводы 4 и 5). Остающиеся подключения, за исключением вывода 3, который идет от
модуля питания и включает линию на повторителях, не используются. Эта система
сконфигурирована как полудуплексная система, что означает, что одновременно толь-
ко одно устройство может передавать данные, в то время как все другие устройства
системы будут принимать данные. МАХ 1483 - это микросхема драйвер ли-
нии/приемник, выбранная для этой системы. Режим ее работы (драйвер ли-
нии/приемник), определяется состоянием вывода DR/RE. Если он находится в состоя-
нии логической единицы, то активируется драйвер линии, и модуль посылает данные в
ПК или на центральный пульт. Если вывод DR/RE переводится в состояние логического
нуля, то приемник линии становится активным и система получает данные из ПК. Вывод
RA6 управляет направлением переноса данных от МАХ 1483.
Рис. 8.10 иллюстрирует работу ПК и каждого ее отвода или систем считывания
идентификационных карточек, подключенных к одному кабелю. Фактически, имеется
один дополнительный компонент системы, который объясняется в примере системы 2,
который приводится далее в этом подразделе. Центральный пункт также требует ис-
пользования системы, обеспечивающей связь между ПК и сетью RS-422. Эта другая
система, называемая силовой системой, с одной стороны обеспечивает электропита-
ние сети, а с другой - формирует интерфейс между ПК и сетью. Минимальный вариант
системы требует наличия двух частей: силовой системы, которая соединяется с ПК, и
Глава 8. Прерывания
367
системы считывания идентификационных карточек. Эта система может масштабиро-
ваться почти до любых размеров, однако излагаемый вариант программного проекта
ограничен обслуживанием до 1000 считывателей идентификационных карточек. Это
должно обеспечить возможность установки такого числа блоков, которое должно быть
достаточно почти для любого приложения.
Каждая секция системы может иметь до 15 считывателей идентификационных
карточек плюс повторитель. Что не отображено на приведенной схеме, так это то, что в
случае наличия повторителей нужно использовать дополнительную сигнальную линию,
контролирующую направление работы повторителя. Более подробно этот вопрос будет
анализироваться позже в данном подразделе при рассмотрении силовых систем. ПК,
подключенный к силовой системе, обычно находится в режиме передачи информации,
а все повторители и считыватели идентификационных карточек обычно находятся в
эежиме приема информации. Когда ПК опрашивает считыватель идентификационных
карточек, то линия реверсируется и ПК становится приемником данным, - линией при
этом управляет один из считывателей идентификационных карточек. Это полудуплекс-
ный режим работы.
Таблица 8.1. , Команды системы считывания идентификационных карточек
Байт Команда Комментарий
л 06 АСК Подтверждение приема
л21 NAK Негативное подтверждение приема
л 17 TIME НН ММ SS ММ DD YY YY сгс Трансляция даты и времени от ПК в считыватели информацион- ных карточек (YY YY) передается как 20 06 (посылается NoACK/NAK)
л 18 READ address ere Запрос данных из считывателя информационных карточек Адрес равен (LL НН) (передается ACK/NAK)
л19 SEND packet ere Передает номер идентификационной карточки в форме пакета на ПК
л 1а SETID address newaddress ere Программирует номер идентификационной карточки Адрес равен (LL НН) (передается No ACK.NAK)
л1Ь SETIDL length ere Установка длины идентификационного номера (No ACK/NAK)
Примечания: сгс - контрольная сумма; address = адрес; packet = пакет; new address = новый адрес; length =
длина.
Чтобы управлять передачей данных, в этой сети необходим набор команд, а также
дополнительные средства управления потоком данных в случае возникновения ошибки.
Эта система использует методику управления потоком данных ACK/NAK (подтвержде-
чие/негативное подтверждение) для подтверждения корректности данных и управле-
ния потоком данных. Табл. 8.1 перечисляет команды, используемые в этой системе.
Применение микроконтроллеров PIC18
Рис. 8.10. Система считывания идентификационных карточек
Глава 8. Прерывания
369
Является ли сеть этого типа надежной? Да, если в нее встроены определенные
средства защиты. Аппаратный сбой приведет к краху системы, однако его практически
невозможно предотвратить, если только в систему не будет введена некоторая избы-
точность. После включения любого считывателя идентификационных карточек, его
приемо-передатчик шины (МАХ 1483) устанавливается в режим приема данных. Если
считыватель идентификационных карточек зависнет, то сторожевой таймер (WDT) вы-
полнит его перезагрузку и установит считыватель идентификационных карточек в ре-
жим получения данных. Это предотвращает любые проблемы со считывателями иден-
тификационных карточек. ПК также должен обладать способностью распознавать факт
того, что считыватель идентификационных карточек отказал в процессе передачи дан-
ных. Это возможно, если сторожевой таймер будет использоваться также и в програм-
ме, которая выполняется в ПК. Использование сторожевых таймеров предотвращает
зависание системы.
Каждое устройство в системе имеет свой адрес. Так, ПК имеет адрес 0x0000, а
каждый считыватель идентификационных карточек после первичной установки в сис-
теме имеет адрес 0x0001. Программа ПК периодически опрашивает систему на нали-
чие новых считывателей идентификационных карточек и в случае их обнаружения при-
сваивает им уникальные идентификационные номера. Оператор ПК может позже вве-
сти адрес модуля в банк данных. Программа ПК должна опрашивать сеть для обнару-
жения нового считывателя идентификационных карточек один раз в минуту. При этом
имеется невысокая вероятность того, что два считывателя будут установлены одно-
временно и оба получат один и тот же адрес. Это может произойти, поэтому программа
в считывателе идентификационных карточек позволяет выполнять изменение адреса
непосредственно со считывателя идентификационных карточек. Обратите внимание на
то, что идентификационный номер сохраняется в ЭСППЗУ с тем, чтобы в случае отказа
модуля электропитания, считыватель идентификационных карточек все продолжал
хранить свой идентификационный номер. Возможно, что было бы полезным иметь в
этой системе запасной модуль питания.
Программа считывания идентификационных карточек показана в примере 8.9.
Так как это программа для целой системы, то она длиннее, чем все другие рассмотрен-
ные к настоящему времени прикладные программы. Для того, чтобы эта программа
смогла выполняться, одно изменение должно быть сделано в файле компоновщика:
если массив по объему превосходит 256 байтов, то файл компоновщика должен быть
модифицирован так, чтобы быть способным адресовать этот массив. В данном приме-
ре используются 412 байтов памяти для локального сохранения идентификационных
номеров. Чтобы выполнить нужную модификацию, файл компоновщика изменяется так,
как показано в примере 8.8. Два оператора добавлены и несколько удалены. Подчерк-
нутые операторы были добавлены. Один из этих операторов определяет “queue” име-
нем, использующим большую модель памяти ("big"), а другой определяет SECTION как
RAM (ОЗУ). Что здесь не показано, так это то, что банки grp4 и grp5 были удалены. Если
просмотреть файл компоновщика из примера 8.9, то #pragma udata определяет место,
где сохраняется массив dataQueue.
370
Применение микроконтроллеров PIC 18
Пример 8.8
// $Id: 18f2580.Ikr,v 1.2 2004/08/22 23:40:54 curtiss Exp $
// Файл: 18f2580.1kr
// Пример сценария компоновки для процессора PIC18F2580
LIBPATH .
FILES c018i.o
FILES clib.lib
FILES pl8f2580.1ib
CODEPAGE NAME=vectors START=0x0 END=0x29 PROTECTED
CODEPAGE NAME=page START=0x2A END=0x7FFF
CODEPAGE NAME=idlocs START=Ox200000 END=0x2000Q7 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=OxFOOOOO END=0xFO00FF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gprl START=0xl00 END=0xlFF
DATABANK NAME=grp2 START=0x200 END=0x2FF
DATABANK NAME=grp3 START=0x300 END=0x3FF
DATABANK NAME=big START=0x400 END=0x5FF PROTECTED
DATABANK NAME=sfrl3 START=0xDO0 END=0xDFF PROTECTED
DATABANK NAME=sfrl4 START=OxE00 END=0xEFF PROTECTED
DATABANK NAME=sfrl5 START=OxF00 END=0xF5F PROTECTED
ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
SECTION NAME=CONFIG ROM=config
SECTION NAME=queue RAM= =big
STACK SIZE= 0x100 RAM=grp3
Эта система использует штрих-код, который называется "код 128”. Это очень распро-
страненный штрих-код, введенный в 1981 для кодирования алфавитных и числовых данных.
Преимущество данного штрих-кода заключается в том, что при использовании Windows и
набора шрифтов Truetype, идентификационные карточки могут печататься в Microsoft Word
без применения каких-либо специальных программных пакетов. В рамках кода 128 имеются
фактически три набора штрих-кодов: А, В и С. Штрих-коды версии А кода 128 включают час-
тичный набор кодов ASCII, штрих-коды версии В кода 128 включают полный набор кодов
ASCII, штрих-коды версии С кода 128 включают только числа от 0 до 9. Рис. 8.11 иллюстриру-
ет пример этого штрих-кода. В таблице 8.2 приведен полный список штрих-кодов, входящих
в состав кода 128. Структура каждого кода указывается как последовательность символов b
и s, где b означает полосу, as- пробел, bb означает полосу двойной ширины, a ss - пробел
двойной ширины. Каждый символ в данном коде составляется из трех полос и трех пробелов
переменной ширины.
Глава 8. Прерывания
371
PIC18F2580
Рис. 8.11. Пример штрих-кода кода 128.
Таблица 8.2. Штрих-коды набора символов “Код 128”
Код А Код В КодС Значение Структура
Пробел Пробел 00 0 bbsbbssbbss
I I 01 1 bbssbbsbbss
02 2 bbssbbssbbs
# # 03 3 bssbssbbsss
$ $ 04 4 bssbsssbbss
% % 05 5 bsssbssbbss
& & 06 6 bssbbssbsss
( 07 7 bssbbsssbss
( ) 08 8 bsssbbssbss
) * 09 9 bbssbssbsss
* * 10 10 bbssbsssbss
+ + 11 11 bbsssbssbss
12 12 bsbbssbbbss
- - 13 13 bssbbsbbbss
14 14 bssbbssbbbs
/ / 15 15 bsbbbssbbss
0 0 16 16 bssbbbsbbss
1 1 17 17 bssbbbssbbs
2 2 18 18 bbssbbbssbs
3 3 19 19 bbssbsbbbss
4 4 20 20 bbssbssbbbs
5 5 21 21 bbsbbbssbss
6 6 22 22 bbssbbbsbss
7 7 23 23 bbbsbbsbbbs
8 8 24 24 bbbsbssbbss
9 9 25 25 bbbssbsbbss
26 26 bbbssbssbbs
27 27 bbbsbbssbss
< < 28 28 bbbssbbsbss
372
Применение микроконтроллеров PIC 18
Код А Код В КодС Значение Структура
Равно Равно 29 29 bbbssbbssbs
> > 30 30 bbsbbsbbsss
? 9 31 31 bbsbbsssbbs
@ @ 32 32 bbsssbbsbbs
А А 33 33 bsbsssbbsss
В В 34 34 bsssbsbbsss
С С 35 35 bsssbsssbbs
D D 36 36 bsbbsssbsss
Е Е 37 37 bsssbbsbsss
F F 38 38 bsssbbsssbs
G G 39 39 bbsbsssbsss
Н Н 40 40 bbsssbsbsss
I I 41 41 bbsssbsssbs
J J 42 42 bsbbsbbbsss
К К 43 43 bsbbsssbbbs
L L 44 44 bsssbbsbbbs
М М 45 45 bsbbbsbbsss
N N 46 46 bsbbbsssbbs
О О 47 47 bsssbbbsbbs
Р Р 48 48 bbbsbbbsbbs
Q Q 49 49 bbsbsssbbbs
R R 50 50 bbsssbsbbbs
S S 51 51 bbsbbbsbsss
Т Т 52 52 bbsbbbsssbs
U’ и 53 53 bbsbbbsbbbs
V V 54 54 bbbsbsbbsss
W W 55 55 bbbsbsssbbs
X X 56 56 bbbsssbsbbs
Y Y 57 57 bbbsbbsbsss
Z Z 58 58 bbbsbbsssbs
[ [ 59 59 bbbsssbbsbs
\ \ 60 60 bbbsbbbbsbs
] ] 61 61 bbssbssssbs
Л Л 62 62 bbbbsssbsbs
.. 63 63 bsbssbbssss
NUL 9 64 64 bsbssssbbss
SOH а 65 65 bssbsbbssss
Глава 8. Прерывания
373
Код А Код В КодС Значение Структура
STX b 66 66 bssbssssbbs
ЕТХ с 67 67 bssssbsbbss
EOT d 68 68 bssssbssbbs
ENQ е 69 69 bsbbssbssss
АСК f 70 70 bsbbssssbss
BEL g 71 71 bssbbsbssss
BS h 72 72 bssbbssssbs
НТ i 73 73 bssssbbsbss
LF j 74 74 bssssbbssbs
VT k 75 75 bbssssbssbs
FF 1 76 76 bbssbsbssss
CR m 77 77 bbbbsbbbsbs
SO n 78 78 bbssssbsbss
SI 0 79 79 bsssbbbbsbs
DLE P 80 80 bsbssbbbbss
DC1 q 81 81 bssbsbbbbss
DC2 r 82 82 bssbssbbbbs
DC3 s 83 83 bsbbbbssbss
DC4 t 84 84 bssbbbbsbss
NAK u 85 85 bssbbbbssbs
SYN V 86 86 bbbbsbssbss
ETB w 87 87 bbbbssbsbss
CAN X 88 88 bbbbssbssbs
EM У 89 89 bbsbbsbbbbs
SUB z 90 90 bbsbbbbsbbs
ESC { 91 91 bbbbsbbsbbs
FS 1 92 92 bsbsbbbbsss
GS } 93 93 bsbsssbbbbs
RS — 94 94 bsssbsbbbbs
US DEL 95 95 bsbbbbsbsss
FNC3 FNC3 96 96 bsbbbbsssbs
FNC2 FNC2 97 97 bbbbsbsbsss
верхн.рег. верхн.рег. 98 98 bbbbsbsssbs
Код переключения С Код переключения С 99 99 bsbbbsbbbbs
Код переключения В FNC4 Код переключения В 100 bsbbbbsbbbs
FNC4 Код переключения А Код переключения А 101 bbbsbsbbbbs
FNC1 FNC1 FNC1 102 bbbbsbsbbbs
374
Применение микроконтроллеров PIC 18
Код А Код В Код С Значение Структура
Старт-код А Стар т-код Л Старт-код А ЮЗ bbsbsbbbbss
Старт-код В Старт-код В Старт-код В 104 bbsbssbssss
Старт-код С Старт-код С Старт-код С 105 bbsbssbbbss
СТОП-код СТОП-код СТОП-код 106 bbsssbbbsbsbb
Штрих-код всегда посылается, начиная со стартового символа (в нашем примере
- “А”), за которым следуют символы тела кода. После передачи тела кода передается
байт контрольной суммы modulo103, после чего следует стоп-код. Рисунок 8.12 пока-
зывает передачу сообщения “W0W3”. Код контрольной суммы генерируется так, как
показано на рисунке. Датчик оптического считывателя идентификационной карточки
генерирует логический ноль для темной полосы и логическую единицу для светлой по-
лосы. Программа по примеру 8.9 использует функцию прерывания по изменению со-
стояния при распознавании штрих-кода и преобразовывает его в число, которое со-
храняется в очереди для последующей передачи его через сеть после соответствующе-
го запроса.
Start A W О W 3 Проверка Стоп
Проверка = 1(55) + 2 (47) + 3(55) + 4(19) = 390
TTL уровни
390:103=3. Остаток 81 проверяется
Рис. 8.12. Передача сообщения W0W3
Глава 8. Прерывания
375
Пример 8.9
// Пример системной программы
И
([include <pl8cxxx.h>
#include <timers.h>
([include <delays.h>
([include <usart.h>
^include <string.h>
Установка битов конфигурации
* - установка режима генератора HS
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
#pragma config OSC = IRCIO67
^pragma config WDT = ON
^pragma config WDTPS = 256 // один раз в секунду
#pragma config LVP = OFF
[pragma config BOR = OFF
[pragma config MCLRE = ON
// ********* ПЕРЕМЕННЫЕ В ПАМЯТИ ДАННЫХ ************
^pragma udata queue 11 большие буфера (смотрите, текст)
char dataQueue[312]; // очередь идентификаторов
char cardBuffer[200]; 11 буфер номера карточки
#pragma udata
char inQueue[16]; // очередь USART
char outQueue[16];
char inPi;
char inPo;
char outPi;
char outPo;
int dataQueuePtr;
char dataQueueBusy;
char cardBufferPtr;
char cardBufferTimeOut;
int oneBits;
short : long time; // время
char day =1; // дата
char month = 0;
int } rear = 2225;
char flag; // флаг доступности данных
char dataL;
char dataH;
char alpha; // режим альфа-чисел
char dirty; // флаг нечитаемости
char idNumberCount;
376
Применение микроконтроллеров PIC 18
char idBuffer[10];
char state; // 6yi>ep пакета
char packetBuffer[10];
char packetPtr;
// *********** статические данные в памяти программ ********
rom near char *mesl = "Welcome--just swipe your card.";
rom near char *mes2 = "Alpha A-I";
rom near char *mes3 = "Numeric";
rom near char *mes4 = "ID Number = ";
rom near char *mes5 = "
rom near char *mes6 = "Alpha J-R";
rom near char *mes7 = "Alpha S-Z";
rom near char *mes8 = "ID Number is too short! Reenter it.";
rom near char *monthName[] =
{
"January ",
"February ",
"March ",
"April ",
"May ",
"June ",
"July ",
"August ",
"September ",
"October ",
"November ",
"December "
};
rom near char lookupKey[] =
I
1, 4, 7, 10, И левый столбец
2, 5, 8, 0,
3, 6, 9, 11,
12, 13, 14, 15,
16, . 17, 18, 19 // правый столбец
};
rom near int codel28[] = // поисковая таблица кода 128
{
ObllOllOOllOO, // пробел 0
0Ы1001101100, // 1 1
ObllOOllOOllO, // 2
0Ы0010011000, // # 3
0Ы0010001100, // $ 4
OblOOOlOOllOO, // о о 5
OblOO11001000, // & 6
0Ы0011000100, // \ 7
OblOOOllOOlOO, // ( 8
ObllOOlOOlOOO, // ) 9
0Ы1001000100, // ★ 10
ObllOOOlOOlOO, // + 11
0Ы0110011100, // 1 12
0Ы0011011100, // - 13
0Ы0011001110, // 14
Глава 8. Прерывания
377
0Ы0111001100, // / 15
0Ы0011101100, // 0 16
0Ы0011100110, // 1 17
0Ы1001110010, // 2 18
0Ы1001011100, // 3 19
0Ы1001001110, // 4 20
0Ы1011100100, // 5 21
0Ы1001110100, // 6 22
0Ы1101101110, // 7 23
0Ы1101001100, // 8 24
0Ы1100101100, // 9 25
0Ы1100100110, // 26
0Ы1101100100, // 27
0Ы1100110100, // < 28
0Ы1100110010, // 29
0Ы1011011000, // > 30
0Ы1011000110, // 2 31
0Ы1000110110, H @ 32
0Ы0100011000, H А 33
ОЬЮООЮ11000, // В 34
0Ы0001000110, // С 35
0Ы0110001000, // D 36
0Ы0001101000, // Е 37
0Ы0001100010, // F 38
0Ы1010001000, // G 39
0Ы1000101000, // Н 40
0Ы1000100010, // I 41
0Ы0110111000, // J 42
0Ы0110001110, // К 43
0Ы0001101110, // L 44
0Ы0111011000, H М 45
0Ы0111000110, // N 46
0Ы0001110110, H 0 47
0Ы1101110110, // Р 48
0Ы1010001110, // Q 49
0Ы1000101110, // R 50
0Ы1011101000, H S 51
0Ы10111000Ю, и Т 52
ObllO11101110, и и 53
0Ы1101011000, // V 54
0Ы1101000110, // W 55
0Ы1100010110, // X 56
0Ы1101101000, // Y 57
OblllOllOOOlO, // Z 58
OblllOOOllOlO, // [ 59
OblllOllllOlO, и \ 60
0Ы1001000010, и 1 61
0Ы1110001010, II А 62
OblOlOOllOOOO, и 63
OblOlOOOOllOO, и nul 64
0Ы0010110000, и soh 65
0Ы0010000110, и stx 66
0Ы0000101100, и etx 67
0Ы0000100110, и eot 68
0Ы0110010000, и enq 69
0Ы0110000100, и ack 70
0Ы0011010000, и bel 71
0Ы0011000010, и bs 72
378
Применение микроконтроллеров PIC 18
0Ы0000110110, и ht 73
0Ы0000110010, // If 74
0Ы1000010010, и vt 75
0Ы1001010000, и ff 76
0Ы1110111010, и cr 77
0Ы1000010100, и so 78
0Ы0001111010, и si 79
0Ы0100111100, и die 80
0Ы0010111100, и del 81
0Ы0010011110, и dc2 82
0Ы0111100100, // dc3 83
ОЫ 0011110100, // dc4 84
0Ы0 011110010, // nak 85
0Ы1110100100, // syn 86
0Ы1110010100, и etb 87
Obll110010010, и can 88
0Ы1011011110, и em 89
0Ы1011110110, и sub 90
0Ы1110110110, и esc 91
0Ы0101111000, и f s 92
0Ы0100011110, и gs 93
0Ы0001011110, // rs 94
0Ы0111101000, // US 95
0Ы0111100010, и fnc3 96
0Ы1110101000, и fnc2 97
0Ы1110100010, // shift 98
0Ы0111011110, // switch С 99
0Ы0111101110, и switch В 100
0Ы1101011110, и fnc4 101
0Ы1110101110, и f ncl 102
0Ы1010111100, и старт А 103
0Ы1010010000, и старт В 104
0ЫЮ1ОО11ЮО, и старт С 105
0Ы100011101011 и останов 106
// ******** распределение адресов данных в
памяти данных ЭСППЗУ
#define timeMode О //О
#define unitAddressL 1
#define unitAddressH 2
#define passWordO 3
#define passWordl 4
#define passWord2 5
# define passWord3 6
# define passWord4 7
♦ define idLength 8
12 час; 1 = 24 час
// ********* определения прерываний ************
II ********* прототипы ***********
void MyHighlnt (void);
void MyLowInt (void);
void timeTemp (void);
int getTemp (void);
void DoClock (void);
int GetlnQueue (void);
11 прототипы процедур
// обслуживания прерываний
Глава 8. Прерывания
379
int SavelnQueue (char data);
int GetOutQueue (void);
int SaveOutQueue (char data);
void abortCard (void);
I/ ********** настройка векторов прерываний ****************
1/ *** специальные примечания для PIC18F2580:
// *** необходимо, чтобы высокоприоритетное прерывание
// *** определялось как низкоприоритетное (смотрите листок
// *** изменений для данного микроконтроллера).
#pragma interruptlow MyHighlnt
#pragma code high_vector=0x08
high_vector по адресу 0x0008
void high_vector (void)
высокоприоритетный вектор
_asm GOTO MyHighlnt _endasm
// переход на подпрограмму обработки
// высокоприоритетных прерываний
tfpragma interruptlow MyLowInt
tfpragma code low_vector=0x!8
MyLowInt - это прерывание
низкоприоритетный вектор по адресу 0x0018
void low_vector (void)
низкоприоритетный вектор
_asm GOTO MyLowInt _endasm
tfpragma code
переход на подпрограмму обработки
низкоприоритетных прерываний
здесь начинается программный код
// процедура обслуживания высокоприоритетного прерывания
// -- прерывание по изменению для считывателя идентификационных карточек
void MyHighlnt (void)
(
if (INTCONbits.RBIF == 1)
{
int temp = PORTB; // необходимо считать PORTB для сброса
изменения
INTCONbits.RBIF = 0; // сброс прерывания
if (ReadTimerO() == 0) // начальное состояние
{
OpenTimerO (TIMER_INT_OFF &
T0_16BIT &
T0_SOURCE_INT &
T0_PS_l_256); // период 128 мкс
cardBufferPtr = 0;
cardBufferTimeOut = 10;
}
else
{
cardBuffer[cardBufferPtr++] = ReadTimerO();
cardBuffer[cardBufferPtr++] = ReadTimerO() >> 8;
cardBuffer[cardBufferPtr] = PORTBbits.RB7;
cardBuf fer [cardBuf ferPtr++ Л= 0x01; // инвертирование бита
if (cardBufferPtr >= (idLength +3) * 6)
abortCard();
380
Применение микроконтроллеров PIC 18
}
}
}
11 процедура обслуживания низкоприоритетного прерывания
// — приемник USART (самое высокоприоритетное)
// — передатчик USART
// — таймер 1 (RTC) (самое низкоприоритетное)
void MyLowInt (void)
{
int temp;
if (PIRlbits.RCIF == 1) 11 это приемник USART?
{
PIRlbits.RCIF = 0; // сброс прерывания
SavelnQueue (RCREG); // сохранение принятых данных в очереди
}
else if (PIRlbits.TXIF == 1 && PIElbits.TXIE == 1)// это передатчик?
{
PIRlbits.TXIF = 0; Il сброс прерывания
temp = GetOutQueue() ; // получение данных из очереди
if (temp == 0x100)
{
while (TXSTAbits.TRMT == 0);
PIElbits.TXIE = 0; // передатчик выкл
}
else
TXREG = temp; // передача данных
)
else if (PIRlbits.TMR1IF == 1) // это 100 мс от таймера реального времени?
{
if (cardBufferTimeOut == 0 && ReadTimerOO != 0)
abortCardO; // если таймаут
else if (cardBufferTimeOut != 0)
cardBufferTimeOut—;
DoClock(); // взвод таймера
)
)
// ************** функции ***************
11 таймаут считывателя идентификационных карточек
void abortCard (void)
{
CloseTimerO();
cardBufferTimeOut = 0;
WriteTimerO(0);
if (cardBufferPtr >= (idLength + 3) + 6)
flag = 1;
)
// считывание местоположения ячейки ЭСППЗУ из переменной адреса
char eeRead (char address)
{
EECONlbits.EEPGD = 0;
EEADR = address;
Глава 8. Прерывания
381
EECONlbits.RD = 1;
return EEDATA;
11 Запись ячейки ЭСППЗУ с данными по адресу
void eeWrite (char address, char data)
{
INTCONbits.GIEH = 0;
INTCONbits.GIEL = 0;
EECONlbits.EEPGD = 0;
EECONlbits.WREN = 1;
EEADR = address;
EEDATA = data;
EECON2 = 0x55;
EECON2 = OxAA;
EECONlbits.WR = 1;
while (PIR2bits.EEIF == 0);
PIR2bits.EEIF = 0;
EECONlbits.WREN = 0;
INTCONbits.GIEH = 1;
INTCONbits.GIEL = 1;
// считывание InQueue, 0x100 означает пустую ячейку
int GetlnQueue (void)
(
int temp;
if (inPi == inPo)
return 0x100; // если пусто
temp = inQueue[inPo]; // получение данных
inPo = (inPo + 1) & OxOF;
return temp;
)
// сохранение данных в InQueue, 0x100 означает заполнение
int SavelnQueue (char data)
(
if (inPi == ((inPo + 1) & OxOF))
return 0x100; // если заполнено
inQueue[inPi] = data;
inPi = (inPi + 1) & OxOF;
return 0;
// считывание из OutQueue, 0x100 означает пусто
int GetOutQueue (void)
1
int temp;
if (outPi == outPo)
return 0x100; // если пусто
temp = outQueue[outPo]; // получение данных
outPo = (outPo + 1) & OxOF;
return temp;
382
Применение микроконтроллеров PIC 18
// сохранение данных OutQueue, 0x100 означает заполнение
int SaveOutQueue (char data)
{
if (outPi == ((outPo + 1) & OxOF))
return 0x100; // если заполнено
inQueue[outPi] = data;
outPi = (outPi + 1) & OxOF;
PIElbits.TXIE = 1; // передатчик вкл.
return 0;
)
// Передача байта данных на ЖК-индикатор при RS = rs
void SendLCDdata (char data, char rs)
PORTA = data » 4; // передача левого 1 полубайта
PORTAbits.RA5 = rs f // установка RS
PORTAbits.RA4 = 1; // импульс E
PORTAbits.RA4 = 0; DelaylOTCYx (8); // ожидание 40 мкс
PORTA = data & OxOF; // передача правого полубайта
PORTAbits.RA5 = rs f // установка RS
PORTAbits.RA4 = 1; // импульс Е
PORTAbits.RA4 = 0; DelaylOTCYx (8); } // ожидание 40 мкс
// инициализация ЖК-индикатора
void InitLCD (void) // инициализация ЖК -индикатора
DelaylKTCYx(40); // ожидание 20 мкс
SendLCDdata(0x20, 0); // передача 0x20
DelaylKTCYx(12); // ожидание о мс
SendLCDdata(0x20, 0); // передача 0x20
DelaylOTCYx(20); // ожидание 100 мкс
SendLCDdata(0x20, 0); // передача 0x20
SendLCDdata(0x08, 0); // передача 0x28
SendLCDdata(0x01, 0); // передача 0x01
DelaylKTCYx (4); // ожидание 2 мс
SendLCDdata(OxOC, 0) ; // передача ОхОС
SendLCDdata(0x06, 0); // передача 0x06
// отображение строки данных (str) по адресу ЗУПВ данных
// Строка 1 находится в позициях от 0x80 до 0хА7
// Строка 2 находится в позициях от ОхСО до 0хЕ7
void DisplayStringRam (char position, char *str)
{
char ptr = 0;
SendLCDdata (position, 0); // передача позиции
while (str[ptr] != 0)
SendLCDdata (str[ptr++], 1); // передача символа
}
// отображение строки (str) по адресу памяти программ
Глава 8. Прерывания
383
zoid DisplayStringPgm (char position, rom char *str)
char ptr = 0;
SendLCDdata(position, 0); // передача позиции
while (str[ptr| != 0)
SendLCDdata (str[ptr++], 1); // передача символа
I отображение времени и даты в правой части строки 2
void DisplayTimeDate (void) // один раз в секунду
char timedatestring[19];
int а;
char Mode;
char ptr = 0;
int hours = time / 36000; // получаем часы
char amPM = 'A';
int minutes = (time % 36000) / 600; // получаем минуты
int seconds = ((time % 36000) % 600) I 10; // получаем секунды
int yearl = year;
Mode = eeRead (timeMode); // получаем timeMode из ЭСППЗУ
7 display time
if (Mode == 1) // 12-часовый режим
{
if (hours >= 12)
{
hours -= 12;
amPM = 'P';
)
if (hours == 0)
hours = 12;
}
if ( (hours I 10) == 0)
timedatestring[ptr++] = ' ' ;
else
timedatestring[ptr++] = hours / 10 + 0x30;
timedatestring[ptr++] = hours % 10 + 0x30;
timedatestring[ptr++] =
timedatestring[ptr++] = minutes / 10 + 0x30;
timedatestring[ptr++] = minutes % 10 + 0x30;
timedatestring[ptr++] =
timedatestring[ptr++] = seconds / 10 + 0x30;
timedatestring[ptr++] = seconds % 10 + 0x30;
if (Mode == 1)
{
timedatestring[ptr++] = ' ';
timedatestring[ptr++] = amPM;
timedatestring[ptr++] = 'M';
}
timedatestring[ptr] = 0;
DisplayStringRam (OxeO, timedatestring);
/ display date
ptr = strlenpgm (monthName[month]);
384
Применение микроконтроллеров PIC 18
strcpypgm2ram (timedatestring, monthName[month]) ;
if (day / 10 == 0)
timedatestring[ptr] = '
else
timedatestring[ptr++] = day / 10 + 0x30;
timedatestring[ptr++] = day % 10 + 0x30;
timedatestring[ptr++] =
timedatestring[ptr++] = '
for (a = 1000; a > 0; a /= 10)
{
timedatestring[ptr++] = yearl / a + 0x30;
yearl -= yearl / a * a;
)
timedatestring[ptr] = 0;
DisplayStringRam (Oxcc, timedatestring);
)
// Increment the RTC clock
II do not incrment date
void DoClock (void) таймера 1 j И подпрограмма обработки прерывания от
PIRlbitS.TMR1IF = 0; WriteTimerl (-25000); И И сброс запроса перезагрузка от таймера 1
time++; И инкрементирование времени
if (time == 864000) // если новый день time =0; // сброс в if ((time % 10) == 0) DisplayTimeDate(); ) I/ считывание клавиши с клавиатуры unsigned char GetKey (void) { int a; unsigned char keyCode; PORTC = 0x00; // выбор всех столбцов клавиш do // ожидание освобождения клавиши (864000∼1/10 sec) 0:00:00:0
while ((PORTB & OxOF) != OxOF)
ClrWdt () ; DelaylKTCYx(30); H сброс сторожевого таймера
Jwhile ((PORTB & OxOF) != OxOF); do // ожидание нажатия i
while ((PORTB & ClrWdt () ; DelaylKTCYx (30); Jwhile ((PORTB & OxOF) PORTC = OxFE; while ((PORTB & OxOF) I OxOF) == == OxOF) == OxOF) 0x0F) // H H сброс выбор пока сторожевого таймера самого левого столбца клавиша не обнаружена
i PORTC = (PORTC < keyCode += 4; I < 1) 1 1; // выборка следующего столбца // прибавление 4 к коду клавиши
/ for (a = 1; a != 0; a «= 1)
Глава 8. Прерывания
385
{
if ((PORTB & а) == 0)
break;
keyCode++;
)
return lookupKey[keyCode];
хода клавиши
// нахождение строки
// поиск в баблице корректного
char GetCode (int ptr)
int a;
int currentTime;
int temp = 0;
int oneHalfBits = oneBits / 2;
int oneAndOneHalfBits = oneBits + oneBits I 2;
for (a = 0; a < 6; a++)
{
currentTime = cardBuffer[ptr] + cardBuffer[ptr + 1] << 8;
if (currentTime > oneHalfBits &&
currentTime < oneAndOneHalfBits)
{
temp <<= 1;
if (cardBuffer[ptr+2] == 1)
temp |= 1;
)
else if (currentTime > oneAndOneHalfBits &&
currentTime < (oneAndOneHalfBits + oneBits))
{
temp <<= 2;
if (cardBuffer[ptr+2] == 1)
temp |= 3;
}
else if (currentTime > (oneAndOneHalfBits + oneBits) &&
currentTime < (oneAndOneHalfBits + oneBits * 2))
{
temp <<= 3;
if (cardBuffer[ptr+2] == 1)
temp |= 7;
}
else if (currentTime > (oneAndOneHalfBits + oneBits * 2) &&
currentTime < (oneAndOneHalfBits + oneBits * 3))
{
temp <<= 4;
if (cardBuffer[ptr+2] == 1)
temp |= OxOF;
}
ptr += 3;
)
for (a =0; a < 107; a++)
if (codel28[a] == temp)
break;
return a;
char GetCodeB (int ptr)
386
Применение микроконтроллеров PIC 18
int а;
int currentTime;
int temp = 0;
int oneHalfBits = oneBits / 2;
int oneAndOneHalfBits = oneBits + oneBits I 2;
for (a =0; a < 6; a++)
{
currentTime = cardBuffer[ptr] + cardBuffer[ptr + 1] << 8;
if (currentTime > oneHalfBits &&
currentTime < oneAndOneHalfBits)
{
temp >>= 1;
if (cardBuffer[ptr+2] == 1)
temp |= 0x8000;
}
else if (currentTime > oneAndOneHalfBits &&
currentTime < (oneAndOneHalfBits + oneBits))
{
temp >>= 2;
if (cardBuffer[ptr+2] == 1)
temp |= 0x0000;
)
else if (currentTime > (oneAndOneHalfBits + oneBits) &&
currentTime < (oneAndOneHalfBits + oneBits * 2))
{
temp >>= 3;
if (cardBuffer[ptr+2] == 1)
temp |= OxEOOO;
)
else if (currentTime > (oneAndOneHalfBits + oneBits * 2) &&
currentTime < (oneAndOneHalfBits + oneBits * 3))
{
temp >>= 4;
if (cardBuffer[ptr+2] == 1)
temp |= OxFOOO;
)
ptr += 3;
}
temp »= 5 ;
for (a =0; a < 107; a++)
if (codel28[a] == temp)
break;
return a;
void ProcessCard (void)
{
int ptr = 0;
char check;
char temp;
int modl03 = 0;
char count = 0;
char buffer[10];
oneBits = cardBuffer[4] << 8 + cardBuffer[3];
flag = 0;
if (cardBuffer[2] == 0 && cardBuffer[5] == 1)
{ // could be good start
temp = GetCode(ptr);
Глава 8. Прерывания
387
if (temp ==103) // если стартовый код
{
while (count != eeRead (idLength))
{
ptr += 18;
buffer[count] = GetCode(ptr);
modl03 - buffer[count] * (count + 1);
buffer [count] += 32;
count++;
)
ptr += 18;
if ((modl03 % 103) == GetCode (ptr)) // good
check
{
for (ptr = 0; ptr < eeRead(idLength); ptr++)
{
dataQueue[dataQueuePtr++] = buffer[ptr];
dataQueue[dataQueuePtr++] = time / 36000;
dataQueue[dataQueuePtr++] = (time % 36000) /
600;
)
)
)
else if (temp == 107) // если стоп-код
{
ptr += 3; // пропуск остальной части стоп-кода
check = GetCodeB(ptr);
while (count != eeRead(idLength))
{
ptr += 18;
buffer[count] = GetCodeB(ptr);
modl03 = buffer[count] * (count + 1);
buffer[count] += 32;
count++;
)
ptr += 18;
if ((modl03 % 103) == check) // good check
{
for (ptr = 0; ptr < eeRead(idLength); ptr++)
{
dataQueue[dataQueuePtr++] = buffer[ptr];
dataQueue[dataQueuePtr++] = time I 36000;
dataQueue[dataQueuePtr++] = (time % 36000) I
600;
)
)
)
)
)
void ProcessNetData (char data)
{
int a, checksum, tempPtr;
if (state == 0) // обработка всех команд
{
packetPtr = 0;
if (data == 0x17)
state = 1;
388
Применение микроконтроллеров PIC 18
else if (data == OxlA)
state = 2;
else if (data == 0x18)
state = 3;
else if (data == Oxlb)
state = 4;
}
else if (state == 1) // обработка команда 0x17 (установка времени и даты)
{
packetBuffer[packetPtr++] = data;
if (packetPtr == 8)
{
checksum = 0;
for (a = 0; a < 8; a++)
checksum Л= packetBuffer[a];
if (checksum == 0) // good crc
{
time = packetBuffer[0] * 36000 + packetBuffer[1] *
600 + packetBuffer[2] * 10;
day = packetBuffer[3];
month = packetBuffer[4] ;
year = packetBuffer[5] * 100 + packetBuffer[6];
}
state =0; // ожидание следующей команды
}
)
else if (state == 2) // процесс изменяет адрес идентификатора
{
packetBuffer[packetPtr++] = data;
if (packetPtr == 5)
{
checksum = 0;
for (a = 0; a < 8; a++)
checksum Л= packetBuffer[a];
if (checksum == 0) // правильная контрольная сумма
{
if (eeRead(unitAddressL) == packetBuffer [0] &&
eeRead(unitAddressH) == packetBuffer [1])
{
eeWrite(unitAddressL, packetBuffer[2]);
eeWrite(unitAddressH, packetBuffer[3]);
}
}
state = 0;
)
}
else if (state == 3) // обработка запроса чтения
{
packetBuffer[packetPtr++] = data;
if (packetPtr == 3)
{
checksum = 0;
for (a = 0; a < 8; a++)
checksum Л= packetBuffer[a];
if (checksum == 0) // правильная контрольная сумма
{
PORTAbits.RA6 =1; // настройка передачи
if (eeRead(unitAddressL) == packetBuffer [0] &&
Глава 8. Прерывания
389
eeRead(unitAddressH) == packetBuffer[1])
{
while (SaveOutQueue(0x06) == 0x100) //
передача подтверждения
ClrWdt() ;
while (TXSTAbits.TRMT == 0); // ожидание
завершения
if (dataQueuePtr != 0)
{
checksum = 0;
tempPtr = 0;
while (tempPtr != dataQueuePtr)
{
checksum Л= dataQueue[tempPtr];
while (SaveOutQueue(
dataQueue[tempPtr]) == 0x100)
ClrWdt();
tempPtr++;
)
while (SaveOutQueue(OxFF) == 0x100)
//передача конца сообщения
ClrWdt () ;
while (SaveOutQueue(checksum) == 0x100
) //передача контрольной суммы
ClrWdt () ;
dataQueuePtr = 0;
)
)
SaveOutQueue (0X21) ; // передача отсутствия подтверждения
PORTAbits. RA6 =0; // настройка приема
state = 0;
)
)
)
else if (state == 4)
{
packetBuffer[packetPtr++] = data;
if (packetPtr == 1)
{
eeWrite (idLength, packetBuffer[0]);
state = 1;
)
)
void SaveBigQueue (char data)
if (data == OxFE)
dataQueueBusy = 1;
else if (data == OxFF)
{
dataQueue[dataQueuePtr++] = time I 36000;
dataQueue[dataQueuePtr++] = (time % 36000) / 600;
dataQueueBusy = 0;
}
else
dataQueue[dataQueuePtr++] = data;
390
Применение микроконтроллеров PIC 18
void ProcessKey (void)
{
int a;
char temp = GetKeyO;
if (temp == 0 && idNumberCount < eeRead (idLength) &&
idNumberCount == 0)
{
DisplayStringPgm (0x84, mes4);
idBuffer[idNumberCount] = temp;
SendLCDdata (0x8C + idNumberCount++, 0);
SendLCDdata (temp + 0x30, 1) ;
}
else if (temp >= 1 && temp <= 9 && idNumberCount < eeRead(idLength))
{
if (idNumberCount == 0)
DisplayStringPgm (0x84, mes4);
if (alpha == 0)
{
idBuffer[idNumberCount] = temp;
SendLCDdata (0x8C + idNumberCount++, 0);
SendLCDdata (temp + 0x30, 1);
}
else
{
idBuffer[idNumberCount++] = alpha * 10 + temp;
SendLCDdata (0x8C + idNumberCount++, 0);
SendLCDdata (alpha * 10 + temp + 0x40, 1);
}
}
else if (temp == 10) // выбор возрастания для переменной alpha
{
if (alpha != 0 && alpha 1= 3)
alpha++;
if (alpha == 1)
DisplayStringPgm (OxCO, mes2);
else if (alpha == 2)
DisplayStringPgm (OxCO, mes6);
else if (alpha == 3)
DisplayStringPgm (OxCO, mes7);
}
else if (temp == 11) // выбор уменьшения для переменной alpha
{
if (alpha != 0 && alpha != 1)
alpha--;
if (alpha == 1)
DisplayStringPgm (OxCO, mes2);
else if (alpha == 2)
DisplayStringPgm (OxCO, mes6);
else if (alpha == 3)
DisplayStringPgm (OxCO, mes7);
}
else if (temp == 12) // нажата Fl
{
if (idNumberCount - 1 == eeRead(idLength))
{
SaveBigQueue (OxFE);
Глава 8. Прерывания
391
for (а = 0; а < idNumberCount; а++)
{
if (idBuffer[a] >= 10 && idBuffer[a] <= 18)
idBuffer[a] += 0x31;
else if (idBuffer[a] >= 19 && idBuffer[a] <= 27)
idBuffer[a] += 0x27;
else if (idBuffer[a] >= 28)
idBuffer[a] += 0x37;
SaveBigQueue (idBuffer[a]);
SaveBigQueue (OxFF);
)
DisplayStringPgm (0x84, mesl);
else
{
DisplayStringPgm (0x82, mes2);
idNumberCount = 0;
)
)
else if (temp == 13) // клавиша F5 - "шаг назад"
{
if (idNumberCount ! = 0)
{
SendLCDdata (0x8C + idNumberCount—, 0);
SendLCDdata (' ' , 1);
)
)
else if (temp == 14)
{
}
else if (temp == 15) // клавиша численного выбора F7
alpha = 0;
DisplayStringPgm (0xC0, mes3);
}
else if (temp ==16) // клавиша очистки F2
DisplayStringPgm (0x84, mesl);
idNumberCount = 0;
}
else if (temp == 17)
{
}
else if (temp == 18)
{
)
else if (temp == 19) // клавиша F8 - выбор символов
{
alpha = 1;
DisplayStringPgm (0xC0, mes2);
)
.-aid main (void)
главная программа
int temp;
392
Применение микроконтроллеров PIC 18
// настройка выводов порта
OSCCON = 0x72; ADCON1 = OxOF; TRISA = 0x00; // выбор внутренней тактовой частоты 8 мГц // порты - цифровые // порт А - выход
PORTA = 0x00; онных карточек TRISB = OxFF; // сеть является входом считывателя информаци- // порт В - вход
TRISC = OxAO; // порт С - выход, за исключением штырька RC7
PORTC = 0x00; // выбор всех столбцов матрицы клавиатуры
// проверка установки перемычки сброса по умолчанию
if (PORTCbits.RC5 == { eeWrite eeWrite eeWrite eeWrite eeWrite eeWrite eeWrite eeWrite eeWrite 0) // при аппаратной инициализации // сброс установок по умолчанию (timeMode, 1); // установка режима АМ/РМ (unitAddressL, 0); // установка адреса блока на 0x0000 (unitAddressH, 0); // адрес установлен на 0x0000 (passWordO, 0); // пароль установлен на 00411 (passWordl, 0); (passWord2, 4); (passwords, 1); (passWord4, 1); (idLength, 10); // принимаемая по умолчанию длина // идентификатора = 10
// настройка таймера реального времени
time = 0;
IPRlbits.TMR1IP = 0;
WriteTimerl (-25000) ;
OpenTimerl (TIMER_INT_ON &
T1_16BIT_RW &
T1_SOURCE_INT &
T1_PS_1_8);
// настройка USART кэш-памяти
IPRlbits.TXBIP = 0;
IPRlbits.RCIP = 0;
inPo = inPi = outPo = outPi = 0;
state = 0;
dataQueuePtr = dataQueueBusy = 0;
OpenUSART (USART_TX_INT_OFF &
USART_RX_INT_OFF &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_SINGLE_RX &
USART_BRGH_HIGH,
51) ;
и прерываний
//. инициализация времени до полуночи
// таймер 1 имеет низкий приоритет
// каждые 100 мс
// установка низкого приоритета
// TXBIP = ошибка
// настройка очередей
// установка USART в 0
// USART будет работать со
// скоростью 9600 бод
// настройка прерывания по изменению для оптического считывателя идентификаци-
онных карточек
flag = alpha = 0; // отсутствие данных
INTCON2bits.RBIP =1; // высокий приоритет
INTCONbits.RBIE =1; // разрешение прерывания по изменению
// состояния бита
WriteTimerO (0); // инициализация таймера 0
// запуск системы прерываний
Глава 8. Прерывания
393
RCONbits.IPEN = 1; // IPEN = 1 для разрешения приоритетов
// прерываний
INTCONbits.GIEH =1; // разрешение высокоприоритетного
// прерывания
INTCONbits.GIEL =1; // разрешение низкоприоритетного прерывания
// единственная главная программа системы
InitLCDO; // инициализация ЖК-индикатора
DisplayStringPgm (0x84, mesl); // установка связи с сообщением
DisplayStringPgm (OxCO, mes3);
DisplayTimeDate (); // инициализация отображения даты и времени
while (1) // главный цикл
{
CIrWdtO; // сброс сторожевого таймера
if ((PORTB & OxOF) != OxOF) // если нажата любая клавиша
ProcessKey() ;
if (flag != 0)
ProcessCardO; // если код карточки
temp = GetlnQueue();
if (temp != 0x100) // не пуст
ProcessNetData(temp); // обработка сетевых данных
)
Пример системы 2
Пример 2 - это продолжение примера 1. Пример 2 посвящен организации систе-
мы питания, для примера 1. Для того, чтобы система считывания идентификационных
карточек работала, она должна быть организована в сеть. Сеть, рассматриваемая
здесь - это сеть RS-422 сеть, которая требует использования специальной вставной
карты ПК, который является хост-компьютером сети. Чтобы сохранить систему на-
столько простой, насколько это возможно, в ее состав включен блок питания, который
подает электропитание на все считыватели карточек. Дополнительная функция, кото-
рую выполняет блок питания, - это преобразование уровней сигналов из RS-232C (ПК)
в RS-422 (сеть). Все, что необходимо от хост-компьютера - это разъем последователь-
ного COM-порта или USB адаптер с целью управления системой от USB порта ПК. В
любом случае никакая модификация ПК не требуется. Рис. 8.13 показывает схему
принципиальную блока электропитания, необходимого для системы считывания иден-
тификационных карточек.
Обратите внимание, что в блоке электропитания использован микроконтроллер,
управляющий двумя последовательными портами. Один из этих портов связан с СОМ-
портом RS-232C на хост-компьютере, а другой подключен к считывателям идентифика-
ционных карточек в сети RS-422. Микроконтроллер также управляет очередностью ин-
формационного обмена в сети RS-422, которая работает в полудуплексном режиме.
Программа для блока электропитания намного короче, чем программа для модуля считыва-
ния идентификационных карточек, потому что все блок электропитания должен делать - это
переключать линию или ретранслировать данные между ПК и сетью RS-422. Эта ретрансля-
ция данных выполняется двумя последовательными интерфейсами: программно UART
и аппаратно USART в микроконтроллере. Программа UART по умолчанию установлена
на использование выводов RB4 и RB5 порта В, а аппаратные средства USART исполь-
зуют штырьки RC6 и RC7. В примере 8.10 приведена программа для блока электропи-
тания.
C1 x-
1.0 uF
R2
ЮК
R1
3.9K
PIC18F2220
U1
C2
30 pF
L7805/T0220
U2
2
Vout § Vin
0
1
C4 x-i
100 uF
Источник
электропитания 12 В
10 А
C3
0.1 uF
2
3
4
5
6
7
10
16
17
18
RAO
RA1
RA2
RA3
RA4
RA5
MCLR
OSC1
OSC2
0
5
RC5
RC6 w
RC7 >
RBO
RB1
RB2
RB3
RB4
RB5
RB6
RB7
RCO
RC1
RC2
cgRC3
>RC4
Рис. 8.13. Организация
системы питания
21
22
23
24
25
26
27
28
11
12
13
14
15
2
C5
0.1 uF
из
R4 1К
R5
220
л
RO
DI
RE
R3
120
MAX1483
U4
RXOut
TXOut
о
Д.
5
2
6
ч
Q2
2N222;
_____5
____6
_____7
m
RJ-45
Применение микроконтроллеров PIC18
RXIn
TXIn
VDRV
0
DS275 v
СОМ-порт,
подключаемый к
ПК
Глава 8. Прерывания
395
Пример 8.10
/ Пример программы для блока электропитания
/
include <pl8cxxx.h>
♦include <sw_uart.h>
♦include <delays.h>
♦include <usart.h>
* Установить биты конфигурации
* - Установить RC генератор
* - Отключить сторожевой таймер
* - Отключить низковольтное программирование
* - Отключить сброс по частичной потере питания
* - Разрешить общий сброс
*/
♦pragma config OSC = RC
♦pragma config WDT = OFF
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
'/ ********* переменные в памяти данных ********
♦pragma udata
char readQueue [32] ;
char writeQueue[32] ;
char readlnPtr;
char readOutPtr;
char writelnPtr;
char writeOutPtr;
// **************** функции ******************
void MyHighlnt (void);
♦pragma interrupt MyHighlnt
♦pragma code high_vector=0x08
void high_vector (void)
{
asm GOTO MyHighlnt _endasm
♦pragma code
int GetWriteQueue (void)
int temp;
if (writelnPtr == writeOutPtr)
return 0x100; Il если пусто
temp = writeQueue[writeOutPtr]; // получить данные
writeOutPtr = (writeOutPtr + 1) & OxIF;
return temp;
396
Применение микроконтроллеров PIC 18
int SaveWriteQueue (char data)
{
if (writelnPtr == ((writeOutPtr + 1) & OxIF))
return 0x100; // if full
writeQueue[writelnPtr] = data;
writelnPtr = (writelnPtr + 1) & OxIF;
return 0;
inL GetReadQueue (void)
{
int temp;
if (readlnPtr == readOutPtr)
return 0x100; // если пусто
temp = readQueue[readOutPtr]; // получить данные
readOutPtr = (readOutPtr + 1) & OxlF;
return temp;
}
int SaveReadQueue (char data)
I
if (readlnPtr == ((readOutPtr + 1) & OxIF))
return 0x100; // если заполнение
readQueue[readlnPtr] = data;
readlnPtr = (readlnPtr + 1) & OxIF;
return 0;
}
void MyHighlnt (void)
{
int temp;
if (PIRlbits.RCIF == 1) // это приемник USART?
{
PIRlbits.RCIF = 0; // сброс прерывания
SaveWriteQueue (RCREG);
}
else if (PIRlbits.TXIF == 1 && PIElbits == 1)// это передатчик USART?
{
PIRlbits.TXIF =0; // сброс прерывания
temp = GetReadQueue(); // получение данных из очереди
if (temp == 0x100)
{
while (TXSTAbits.TRMT == 0);
PIElbits.TXIE = 0; // передатчик выкп.
}
else
TXREG = temp; // передача данных
)
}
//
// ************ временные задержки для программы UART ******************
// Эти задержки должны вводиться с целью
// обеспечения возможности использования программы
// UART библиотеки С18
//
void DelayRXHalfBitUART (void)
{
DelaylOTCYx(1);
Глава 8. Прерывания
397
DelaylTCYO ;
DelaylTCYO; '
DelaylTCY ();
DelaylTCY ();
DelaylTCY () ;
DelaylTCYO ;
DelaylTCY ();
DelaylTCYO ;
i
void DelayRXBitUART (void)
DelaylOTCYx (3);
DelaylTCY();
DelaylTCY();
DelaylTCYO ;
DelaylTCY ();
DelaylTCY () ;
DelaylTCYO ;
DelaylTCY О;
DelaylTCY();
DelaylTCY();
void DelayTXBitUART (void)
DelaylOTCYx (4);
DelaylTCYO ;
7 ****************
главная программа
void main (void)
char temp;
char count = OxFF;
ADCON1 = OxOF; // объявление выводов порта цифровыми
TRISC = 0x80; // программирование портов
TRISB = 0x20;
PORTB =1; // настройка передачи в сеть
RCONbits.IPEN =0; // только высокоприоритетное прерывание
7 настройка USART и очереди
IPRlbits.RCIP =0; // TXBIP - бит ошибки
readlnPtr = readOutPtr = writelnPtr = writeOutPtr = 0;
OpenUSART (USART_TX_INT_OFF & //USART работает на скорости 9600 бод
USART_RX_INT_OFF &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_SINGLE_RX &
USART_BRGH_HIGH,
12) ;
' / открытие программы UART
OpenUART();
while(1)
398
Применение микроконтроллеров PIC 18
if (PORTBbits.RBO == 1)
{
INTCONbits.GIE =1; // разрешение высокоприоритетных
// прерываний
temp = GetWriteQueue(); // получение данных от COM-порта
if (temp != 100)
{
INTCONbits.GIE =0; // запрет
WriteUART (temp); // записи в сеть
if (count != OxFF)
{
count—;
if (count == 0)
{
count = OxFF;
PORTBbits.RBO =0; Il реверс линии
}
}
if (temp == 0x18)
count = 3;
}
}
else
{
INTCONbits.GIE = 0;
temp = ReadUART();
SaveReadQueue (temp);
PIElbits.TXIE = 1; // передатчик вкл.
INTCONbits.GIE = 1;
if (temp == OxFF || temp == 6 || temp == 0x21)
PORTBbits.RBO =1; // реверс линии
)
И, наконец, последняя рассматриваемая нами часть взятой в качестве примера
системы, не имеет ни программы, ни микроконтроллера (см. рис. 8.14). Модуль расши-
рения имеет два приемопередатчика RS-422, управляемые сигналом с вывода 3 сете-
вой шины. Данный повторитель - это недорогое устройство. Питание для него берется
с сетевой шины и подается на вход стабилизатора L7805. Напряжение +5 В с выхода
стабилизатора, подается на выводы питания ИС МАХ1483.
Глава 8. Прерывания
399
Power
Station
Side
RJ-45
U3 L7805/TO3
2.
DI
2_
DE
re5
MAX1483
U1
8
_2____,
3____
4____
5____
6___
7____
8____
C1
0.1 uF
vee-
RO
J4
R2
120
2.
3
_6
r±
Out
Expansion Side
Рис. 8.14. Повторитель
8.5. Резюме
1. Структура прерываний микроконтроллера может включать как высоко, так и
низкоприоритетные прерывания или же только высокоприоритетные прерывания, как
это определяется битом IPEN регистра управления сбросом (RCON).
2. Приоритеты прерываний становятся активными только тогда, когда оба типа
прерываний происходят одновременно, - в этом случае высокоприоритетное прерыва-
ние имеет приоритет.
3. Индивидуальные прерывания управляются тремя битами: IP, IE и IF. Бит IP
(приоритет прерывания) выбирает низкий (0) или высокий (1) приоритет прерывания,
бит IE (разрешение прерывания) выбирает разрешенное (1) или заблокированное (0)
состояние прерывания, а бит IF (флаг прерывания) указывает, есть ли запрос прерыва-
ния (1) или нет (0).
4. Процедура обслуживания прерывания устанавливается в программу из биб-
лиотеки С18: (а) определением прототипа прерывания, (Ь) определением псевдоком-
ментария #pragma для высокоприоритетного (high) или низкоприоритетного (low) пре-
рывания, (с) размещение команды Ассемблера GOTO по адресу вектора прерывания и
(d) установкой процедуры обслуживания прерываний по адресу вектора прерывания.
5. Процедура обслуживания прерываний должна распознать, какое из устройства
вызвало прерывание, проверяя состояние бита IF для прерывания, - этот бит должен
400
Применение микроконтроллеров PIC 18
сбрасываться перед завершением выполнения процедуры обслуживания прерываний.
6. USART - это аппаратный компонент микроконтроллера, который осуществляет
преобразование между последовательными и параллельными данными, используя
синхронный или асинхронный формат. Как и в случае других программируемых уст-
ройств внутри PIC, это устройство генерирует прерывания. Когда приемник принимает
последовательные данные, приемник вызывает прерывание, а когда передатчик готов
передать данные, то передатчик вызывает прерывание. Как приемник, так и передатчик
имеет биты управления IP, IE и IF. Скорость информационного обмена USART програм-
мируется.
7. Специальный тип прерывания, называемый прерыванием на изменению со-
стояния, обнаруживает, изменил ли свое состояние любой из битов RB4-RB7 порта В.
Когда обнаружено изменение состояния любого из названных четырех выводов, то
происходит прерывание по изменению состояния. Это свойство чрезвычайно полезно,
наряду с таймером, для обнаружения входного импульса или импульсов и измерения
ширины входных импульсов, поскольку много типов данных используют широтно-
импульсное кодирование информации.
8. Многие системы в своей работе используют множественные прерывания, на-
пример система считывания идентификационных карточек, рассмотренная в этой гла-
ве. Система считывания идентификационных карточек использует прерывания по тай-
меру реального времени, прерывания по изменению состояния, прерывания от оптиче-
ского считывателя штрих-кода и два прерывания от USART, который осуществляет ин-
формационный обмен через сеть. Все эти прерывания координируются через два при-
оритетных вектора прерываний в микроконтроллере.
9. В этой главе был рассмотрен штрих-код “Код 128”, поскольку он является од-
ним из наиболее распространенных штрих-кодов, используемых при контроле покупок
и в других приложениях. Процесс сканирования штрих-кода и декодирования отскани-
рованной информации был рассмотрен в рамках примера использования прерывания
по изменению состояния.
10. Малая полудуплексная сеть была использована для организации информационно-
го обмена между встроенной системой и ПК. При организации интерфейса использовался
как протокол RS-232C, так и протокол RS-422 (RS-485) протоколы для интерфейса. Также
детально рассматривалось преобразование сигналов между интерфейсом RS-232C и сетью
RS-422. RS-422 был выбран здесь по той причине, что данный стандарт допускает использо-
вание кабеля, длина которого может достигать 4000 футов.
8.6. Вопросы и задания
1. Вектор прерывания, используемый высокоприоритетным прерыванием, рас-
положен в ячейке памяти.
2. Вектор прерывания, используемый низкоприоритетным прерыванием, распо-
ложен в ячейке памяти."
3. Если приоритетные прерывания заблокированы битом IPEN, какой вектор ис-
пользуется для всех прерываний?
4. Где размещается бит IPEN?
5. Опишите назначение битов управления IP, IE и IF в связи с прерываниями.
6. Если подпрограмма обслуживания высокоприоритетных прерываний должна об-
служить прерывание по изменению состояния, за которым следует прерывание от приемни-
ка USART, то какое из этих прерываний будет иметь самый высокий приоритет?
7. Опишите значение очистки бита IF изнутри процедуры обслуживания прерываний.
Глава 8. Прерывания
401
8. Что выполняет оператор INTCONBITS.GIEH = 1; в программе?
9. Что выполняет оператор IPR1 BITS.TMR1 IP = 0; в программе?
10. Что выполняет оператор INTCON3BITS.INT 11E = 1; оператор в программе?
11. Напишите оператор, который устанавливает прерывание от входа таймера 2
на низкоприоритетный уровень.
12. Напишите команду, которая разрешает прерывание от таймера 2.
13. Каково назначение регистра RCON?
14. В каком регистре размещается бит флага прерывания (IF) для прерывания по
изменению состояния?
15. Почему команда RETFIE не используется в процедуре обслуживания прерыва-
ния?
16. Что делает команда RETFIE?
17. Почему программа из примера 8.3 использование два таймера, и что исполь-
зует каждый из этих таймеров при выполнении программы?
18. Каково назначение низкоприоритетной процедуры обслуживания прерываний
из примера 8.3?
19. Опишите, как устанавливается время в программе из примера 8.3.
20. Пример 8.3 использует мультиплексированные индикаторы; как часто вклю-
чается позиция индикатора в этой программе?
21. Объясните, как считывается температура в примере 8.3.
22. Что такое асинхронные последовательные данные?
23. Каково назначение стартового и стопового битов в асинхронно-кодированном
потоке данных?
24. Наиболее современные форматы асинхронных последовательных данных
включают стартовый бит,битов данных и стоповых битов.
25. Что такое скорость информационного обмена при последовательной переда-
че данных?
26. Какое устройство используется для того, чтобы выполнять преобразование
между асинхронными последовательными данными и параллельными данными?
27. USART генерирует два типа прерываний, что это за прерывания?
28. Если имеется выбор, то какому из двух типов прерываний, вызванных USART,
вы бы назначили более высокий приоритет и почему?
29. Напишите короткую последовательность операторов на языке С, которые ус-
тановили бы низкий приоритет прерываний как для передатчика, так и для приемника
USART. Не используйте функцию OpenUSART - взамен непосредственно адресуйте ре-
гистры управления.
30. Как USART запрограммировать на скорость информационного обмена, рав-
ную 1200 бод? Определите значение, которое нужно занести в регистр скорости в ин-
формационного обмена, если тактовая частота равна 4 МГц.
31. Почему часто с устройствами ввода-вывода используются очереди?
32. Каков размер очередей, использованных в примере 8.5?
33. Почему и когда прерывание от передатчика выключается в процедуре обслу-
живания высокоприоритетных прерываний из примера 8.5?
34. В примере 8.5 прерывание от приемника обрабатывается в процедуре обслу-
живания высокоприоритетных прерываний; что выполняется при его обслуживании?
35. Пример 8.6 изображает программу для ПК, написанную на Visual C++. Каково
назначение DCB (блока управления данными) в функции WriteComPort?
36. Можно ли изменить функцию WriteComPort из примера 8.6 таким образом,
чтобы она записывала более одного байта данных? Если да, то объясните как.
37. Объясните, как в примере 8.7 замеряется ширина входного импульса системы
402
Применение микроконтроллеров PIC 18
DCC?.
38. Что является заголовком пакета системы DCC и какова его длительность?
39. Что такое управляющая переменная (CV) системы DCC?
40. Объясните, как выполняется доступ к ЭСППЗУ данных в примере 8.7.
41. Какие прерывания используются в программе из примера 8.7?
42. Объясните, как функция wait4Bit работает в программе из примера 8.7.
43. Объясните работу функции getByte в примере 8.7.
44. Для чего используется таймер 0 в примере 8.7?
45. Объясните, как реконфигурирующая кнопка используется в примере 8.7 и что
она делает.
46. Почему файл сценария компоновщика приведен в примере 8.8 и какие его
изменения были выполнены?
47. Что такое интерфейс RS-422 и почему он выбран в примере системы, приве-
денном на рисунке 8.9?
48. Что такое МАХ1483?
49. Что представляет собой кабель САТ5?
50. Что представляет собой соединительный разъем RJ-45?
51. Что представляет собой набор штрих-кодов “Код 128”?
52. Можно ли использовать набор штрих-кодов “Код 128” для того, чтобы помес-
тить ваше имя в соответствующую позицию идентификационной карточки?
53. Определите и выведите штрих-коды набора "Код 128” для строки W4A.
54. Выполните поиск в Internet и составьте список по крайней мере из трех других
наборов штрих-кодов, используемых с оптическими считывателями штрих-кодов.
55. Почему оптические штрих-коды намного более распространены, чем магнит-
ные коды?
56. Что означает “по модулю 103”?
57. Какая информация сохраняется в ЭСППЗУ данных программой из примера 8.9?
58. Объясните, где и как дата и время отображаются на ЖК-индикаторе в приме-
ре 8.9.
59. Какие прерывания используются в примере 8.9? Какое из прерываний, имеет
самый высокий приоритет, какое - самый низкий?
60. Объясните, что выполняет основной цикл в примере 8.9.
61. Каково назначение переменной idNumberCount в функции ProcessKey из при-
мера 8.9?
62. Как программа из примера 8.9 определяет, какая команда поступила из сети?
63. Какие дополнительные команды рекомендуется использовать для того, чтобы
повысить полезность считывателя идентификационных карточек согласно рис. 8.9?
64. Каково назначение интегральной схемы DS275 (см. рис. 8.13)?
65. Каково назначение микросхемы L7805 (см. рис. 8.13)?
66. Каково назначение транзистора 2N2222 (см. рис. 8.13)?
67. Программа из примера 8.10 использует как USART, так и UART; каково назна-
чение каждого из этих двух устройств?
68. Каково назначение блока электропитания, приведенного на рис. 8.13?
69. Как работает повторитель, показанный на рис. 8.14?
Глава 9. Системы управления
403
Глава 9. Системы управления
Многие системы, которые содержат микроконтроллеры - это системы управле-
ния, управляющие некоторым технологическим процессом или процессами. Эта глава
представляет методику проектирования систем управления технологическими процес-
сами, в ней также описаны несколько прикладных программ. Примерами оборудова-
ния, которое использует системы управления техпроцессом, могут быть стиральная
машина, посудомоечная машина, сборочная линия на фабрике, система управления
светофорами и т.д. Перечисленные устройства после своего включения отрабатывают
один и тот же процесс, при этом существует метод проектирования систем управления
подобными процессами.
После завершения изучения этой главы вы сможете:
1. Объяснить, как нужно формализовать процесс для системы управления.
2. Описать несколько простых систем управления.
3. Разработать систему управления светофорами.
4. Разработать систему, которая подобна системе управления санитарным ящи-
ком для котов, продаваемым фирмой Litter Maid.
5. Управлять домашней системой обогрева/вентиляции.
9.1. Формализация системы управления
Чтобы упростить проектирование системы управления, следует формализовать
задачу, используя простую временную диаграмму событий. После этого система может
быть разработана и может быть написано ее программное обеспечение. Предположим,
что микроконтроллерная система управления должна использоваться в посудомоечной
машине. Чтобы ограничить трудоемкость ее разработки, предположим, что это должна
быть максимально простая базовая система.
Система посудомоечной машины имеет только несколько компонентов, являю-
щихся объектами управления:
1. Клапан заполнения, который позволяет воде заполнить бак посудомоечной
машины. Это обычно механический поплавковый клапан, останавливающий поток во-
ды, когда бак заполнен.
2. Электромотор насоса, прогоняющего воду через посудомоечную машину с
тем, чтобы ополаскивать и мыть посуду. Он также выкачивает воду из посудомоечной
машины через дренажный патрубок.
3. Перепускной клапан, который управляется для того, чтобы выбрать, работает
ли электромотор насоса на мойку посуды или откачивает воду из посудомоечной ма-
шины через дренаж.
4. Нагревательный элемент, который сушит посуду, а в более дорогих моделях
нагревает воду, чтобы стерилизовать посуду.
5. Соленоид распределителя моющего средства, который открывается мойке по-
суды и подает моющее средство в моющую воду.
6. Некоторые посудомоечные машины имеют также небольшой вентилятор, кото-
рый прогоняет воздух сквозь посуду для ускорения высыхания.
404
Применение микроконтроллеров PIC 18
Соленоид
заполнения
Электромотор
насоса
Дренажный
перепускной
клапан
Распределитель!
моющего !
средства [
Нагреватель-
ный элемент
0 5 10 15 20 25 30 35 40 45 50 минуты
Рис. 9.1. Диаграмма управления технологическим процессом
для простой посудомоечной машины
Рис. 9.1 иллюстрирует временную диаграмму событий или диаграмму технологи-
ческого процесса, предназначенную разработки программного обеспечения системы
управления посудомоечной машиной. На этой диаграмме указаны все устройства, ко-
торые должны управляться, а также моменты времени, когда события должны происхо-
дить. Эта диаграмма представляет собой план системы и отражает зависимость всех
событий от времени. После того, как эта диаграмма разработана, как программное
обеспечение, так и систему будет разработать намного проще.
Из этой диаграммы может быть получена следующая информация:
1. 1 -минутная временная задержка необходима для того, чтобы заполнить бак.
2. 4-минутная временная задержка необходима для того, чтобы поработал элек-
тромотор насоса.
3. 30-минутная временная задержка необходима для работы нагревательного
элемента.
4. Короткая временная задержка необходима для того, чтобы открыть распреде-
литель моющего средства (200 мс).
Это устройство имеет только одну кнопку, запускающую цикл мытья посуды.
Единственный дополнительным переключателем является переключатель открытия
дверцы, который распознает, когда дверца машины открывается, и приостанавливает
цикл мытья посуды. Эта машина выполняет цикл предварительного мытья посуды, за
которым следует цикл мытья посуды с моющим средством, после которого следуют
два цикла полоскания и цикл сушки. Электромотор насоса, нагревательный элемент,
дренажный перепускной клапан и соленоид распределителя моющего средства - это
все выходы, управляемые интегральными реле. Эта система имеет два входа: кнопка
запуска и блокировка дверцы. Микроконтроллер, необходимый для управления этой
системой, имеющей два входа и пять выходов, может быть любым микроконтроллером
семейства PIC18, поэтому был использован самый дешевый из них - P1C18F1220.
Схемное решение системы показано на рис. 9.2. Кнопочный переключатель открытия
дверцы формирует сигнал логической единицы, когда дверца закрыта и сигнал логиче-
ского нуля, когда дверца открыта.
Black
Примечание: блокировка дверцы формирует логическую единицу, когда дверца закрыта и ноль, когда открыта
Рис. 9. 2. Посудомоечная машина, управляемая микроконтроллером PIC18F1220
Глава 9. Системы управления 405
406
Применение микроконтроллеров PIC 18
Программа этой системы использует прерывание от переключателя открытия
дверей с тем, чтобы прервать работу посудомоечной машины, если ее дверца будет
открыта в течение рабочего цикла. Во всех остальных отношениях программа системы
довольно проста, - она отрабатывает схему пос. „довательности операций процесса
мытья посуды, приведенную на рис. 9.1. В примере 9.1 приведена полная программа
упразления посудомоечной машиной. Единственным тонким моментом является пере-
ключатель открытия дверцы, который должен останавливать машину в любой момент,
когда ее дверца будет открыта. Когда дверца будет закрыта, посудомоечная машина
должна продолжить свою работу из точки прерывания. Здесь используется прерывание
для того, чтобы сигнализировать об открытом состоянии дверцы машины. Всякий раз,
когда дверца открывается, на вход прерываний INTO на RB0 поступает отрицательный
фронт сигнала. Это вызывает процедуру обслуживания прерывания в функции
MyHighlnt. В этой функции сохраняется текущее состояние машины и разрешается бу-
дущее прерывание INTO, после чего функция ожидает закрытия дверцы. Когда дверца
будет закрыта (обратите внимание на устранение дребезга контактов переключателя
открытия двери), состояние машины восстанавливается так, что ее работа может про-
должиться точно с того момента, когда была открыта дверца.
Пример 9.1
/*
* Программа посудомоечной машины
*/
tfinclude <pl8cxxx.h>
ttinclude <delays.h>
/* Установка битов конфигурации
* - установка внутренней синхронизации
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
#pragma config OSC = INTIO2
tfpragma config WDT = OFF
#pragma config LVP = OFF
tfpragma config BOR = OFF
tfpragma config MCLRE = ON
void MyHighlnt (void); // прототипы процедур обслуживания прерываний
#pragma interrupt MyHighlnt // MyHighlnt - это прерывание
#pragma code high_vector=8 // high_vector по адресу 0x08
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
}
#pragma code
// Interrupt service procedure
// occurs anytime door is opened
//
Глава 9. Системы управления
407
void MyHighlnt (void)
char a;
a = PORTB;
PORTB = 0;
do
{
while (PORTBbits.RBO
DelaylOOTCYx (10);
Jwhile (PORTBbits.RBO == 0);
INTCONbits.INTOIF = 0;
PORTB = a;
// сохранение текущего состояния
// останов машины
== 0); // пока дверца открыта
// устранение дребезга - 16 мс
// сброс флага INTOIF
// дверца закрыта
/
/ системная тактовая частота равна 250 кГц т.е. ее период равен
! 4 мкс, что дает командный цикл в 16 мкс
.-oid Wait200ms (void)
DelaylOOTCYx(125);
// 16 * 125 * 100 = 200 мс
void WaitMinute (char howmany)
int a, b; // 300 * .2 sec = 1 минута
for (a =0; a < howmany; a++) •
for (b = 0; b < 300; b++)
Wait200ms();
.aid DoCycles (void)
char a;
for (a = 0; a < 4; a++)
{
PORTBbits.RB2 = 1;
WaitMinute (1);
PORTBbits.RB2 = 0;
PORTBbits.RBI = 1;
if (a == 1)
{
PORTBbits.RB3 = 1;
Wait200ms();
PORTBbits.RB3 = 0;
}
WaitMinute (3);
PORTBbits.RB4 = 1;
WaitMinute(1);
PORTB = 0;
}
PORTBbits.RB5 = 1;
WaitMinute(30);
PORTB = 0;
// повторить 4 раза
// клапан заполнения вкл.
// ожидание 1 минута
// клапан заполнения выл.
// мотор насоса вкл.
// мытье с моющим средством
// ожидание 3 минуты
// соленоид стока воды вкл.
// ожидание 1минута
// все выкл
// нагреватель вкл
// сушка в течении 30 минут
// все выкл.
-oid main (void)
408
Применение микроконтроллеров PIC 18
OSCCON = 0x2 3; // внутренний тактовый генератор на 250 кГц
ADCGN1 = OxOF; // все входы цифровые
I’RISA = 2; // порт А, б:ь х -- вход
TRISB = 1; // порт В, бит 0 -= вход
PORTB = 0; // выключение системы
RCONbit s.IPEN = 0; // только высокоприоритетное прерывание вкл
INTCON2bits.INTEDGO = 0; // активен отрицательный фронт INTO
INTCONb its.INTOIE = 1; // разрешение INTO
INTCONb its.GIE = 1; // разрешение прерываний
while (1)
{
while (PORTAbits.RAI == 1); // ожидание цикла мойки
DoCycles();
Другие циклы могут быть добавлены в систему без необходимости написания
большой дополнительной программы. Например, может быть добавлен интенсивный
цикл мойки кастрюль, посредством добавления сигнала от второго распределителя
моющего средства на RB6 и сигнала от кнопочного переключателя блокировки на RA0.
Этот переключатель мог бы быть обозначен как “норма/кастрюли”. В положении этого
переключателя “кастрюли” второй цикл мойки со вторым распределителем моющего
средства обеспечил бы мытью кастрюль с использованием немного большего количе-
ства моющего средства. Много дополнительных функций могло бы быть добавлено в
посудомоечную машину при минимальных расходах, и больше денег можно было бы
заработать при ее продаже. Каждая новая функция требует использования дополни-
тельной схемы операций, которая иллюстрировала бы работу системы и облегчала бы
разработку программного обеспечения.
9.2. Примеры системы
В этом подразделе описана разработка нескольких последовательных систем
управления с использованием методики, описанной в подразделе 9.1.
Пример 1
Другим рассматриваемым нами примером системы является система управле-
ния дорожным движением. Система, разработанная здесь, предназначена для управ-
ления одним перекрестком, однако она имеет входы, используя которые, ее можно
расширить для сети перекрестков, которые будут осуществлять информационный об-
мен между собой. Кроме того, могут быть введены правила, которые будут изменять
характер базовых циклов для каждого перекрестка в некоторых обстоятельствах.
Рис. 9.3 показывает диаграмму процесса управления перекрестком. Направле-
ния обозначены как NS (север/юг) и EW (восток/запад). Времена указывают, когда кон-
кретное направление активизируется и может программироваться. Диаграмма следует
стандартной практике включения красного света в обоих направлениях в течение ко-
роткого времени с тем, чтобы предотвратить коллизии. Времена на диаграмме не про-
ставлены, потому что они могут программироваться.
Глава 9. Системы управления
409
Север-юг
красный
Север-юг
желтый
Север-юг
зеленый
Восток-запад
красный
Восток-запад
желтый
Восток-запад
зеленый
Рис. 9.3. Технологическая карта одного цикла управления дорожным движением
Система использует микроконтроллер PIC18F4220, малую клавиатуру телефон-
ного стиля 2x16, ЖК-индикатор для целей программирования, входы отдатчиков пото-
ка дорожного движения и кнопок пешеходов, выходы управления шестью лампами, а
также последовательный интерфейс для случаев, когда взаимосвязаны несколько пе-
реходов. Межсоединения переходов требуют использования некоторого стандарта
интерфейса, который может обслуживать довольно большие расстояния. Интерфейс
RS-422 или RS-485 работает на расстоянии до 4000 футов, что почти равно миле, так
чго любой этих стандартов может быть использован. Электронные схемы системы ил-
люстрируются двумя схемными решениями: рис. 9.4 показывает основную печатную
плату контроллера системы, а рис. 9.5 показывает схему управления, кнопку перехода
и переходную плату (которые могут располагаться на той же самой основной печатной
плате). Система использует те же самые 4-выводные соединительные разъемы для
подключения всех ламп, датчиков и кнопок перехода. Эта система разработана для
того, чтобы, чтобы управлять новым светофором светодиодного стиля и пешеходными
светофорами. Более новые лампы потребляют мощность от 13 до 25 Ватт, при этом
использованные схемы управления обеспечивают достаточный ток для двух наборов
ламп. Красные и зеленые лампы потребляют 13 Ватт мощности, а желтые - 25 Ватт.
Программа для этой системы иллюстрируется в примере 9.2. Эта система реали-
зует большинство необходимых функций, однако только команды синхронизации све-
тофоров передаются по сети. Программа кажется довольно длинной, однако все же она
компилируется всего только в 2605 ячеек памяти программ, так что почти 2000 ячеек
остаются для дополнительных задач.
+5V
MS = 1 Master
Рис. 9.4. Схемотехническое решение системы управления дорожным
движением. Плата контроллера
Применение микроконтроллеров PIC18
Рис. 9.
412
Применение микроконтроллеров PIC 18
Пример 9.2
/*
* Программа системы управления дорожным движением
*/
#include <pl8cxxx.h>
#include <delays.h>
#include <timers.h>
#include <usart.h>
/* Установка битов конфигурации
* - установка внутренней синхронизации
* выключение сторожевого таймера
* - выключение низковольтного программирования
* отключение сброса по частичной потере питания
* - разрешение общего сброса
#pragma config
#pragma config
#pragma config
#pragma config
#pragma config
OSC = INTIO2
WDT = OFF
LVP = OFF
BOR = OFF
MCLRE = ON
// ********* переменные в памяти данных
void MyHighlnt (void); // прототипы процедур
void MyLowInt (void); // обслуживания прерываний
ttpragma interrupt MyHighlnt // MyHighlnt - это прерывание
#pragma code high_vector=8 // high_vector по адресу 0x08
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
}
#pragma interruptlow MyLowInt
#pragma code low_vector=0x!8
// MyLowInt - это прерывание
// низкоприоритетный вектор по адресу 0x0018
void low_vector (void) // низкоприоритетный вектор
{
_asm GOTO MyLowInt _endasm // переход на подпрограмму обработки
низкоприоритетных прерываний
)
//
// переменные в ЭСППЗУ данных
//
# define BlinkStartHours 0
# define BlinkStartMinutes 1
# define BlinkStopHours 2
# define BlinkStopMinutes 3
# define EWYellowTime 4
# define NSGreenTime 5
# define NSYellowTime 6
tfdefine EWGreenTime 7
Глава 9. Системы управления
413
//
/ / Program memory data
11
rom near char lookupKey]] =
1, 4, 7, ю, // левый столбец
2, 5, 8, 0, // средний столбец
з, 6, 9, 11 // правый столбец
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
rom near char
strl [ ]
str2 []
str3[]
str4[]
str5[]
str6[]
str7[]
str8[]
str9[]
strlO []
strll[]
strl2[]
strl3[]
strl4[]
strl5[]
strl6[]
strl7[]
strl8[)
strl9[]
=- "Ready to control";
= " the traffic!
= " Enter the time ";
= "Set blink start ";
= "Set blink stop
= " Set EW yellow ";
= " Set EW green
= " Set NS yellow ";
- " Set NS green ";
= "The current time";
= " Blink start
= " BlinK stop
= " EW yellow ";
= " EW green ";
= " NS yellow
= " NS green
= "Enter a command ";
= " 1 — 8
/ переменные в памяти данных
♦pragma udata
char transmitQueue[16];
char receiverQueue[16];
mar inTrans;
mar outTrans;
mar inRecv;
mar outRecv;
mar seconds;
char minutes;
mar hours;
char NSGreen;
mar EWGreen;
mar state;
char buffer[4];
mt ptr;
♦pragma code
процедура обслуживания прерываний
возникающих каждую секунду
/ считывает по адресу ячейку ЭСППЗУ данных
414
Применение микроконтроллеров PIC 18
char eeRead (char address)
(
EECONlbits.EEPGD = 0;
EEADR = address;
EECONlbits.RD = 1;
return EEDATA;
// Записывает ячейку ЭСППЗУ данных по адресу с данными
void eeWrite (char address, char data)
(
INTCONbits.GIEH = 0;
INTCONbits.GIEL = 0;
EECONlbits.EEPGD = 0;
EECONlbits.WREN = 1;
EEADR = address;
EEDATA = data;
EECON2 = 0x55;
EECON2 = OxAA;
EECONlbits. WR = 1;
while (PIR2bits.EEIF == 0) ;
PIR2bits.EEIF = 0;
EECONlbits.WREN = 0;
INTCONbits.GIEH = 1;
INTCONbits.GIEL = 1;
)
void SendLCDdata (char data, char rs)
{
PORTC = data >> 4; // передает левый полубайт
PORTCbits.RC5 = rs; // проверка RS
PORTCbits.RC4 =1; // импульс E
PORTCbits.RC4 = 0;
DelaylTCY(); // задержка 48 мкс
DelaylTCY();
DelaylTCY();
PORTC = data & OxOF; // передает правый полубайт
PORTCbits.RC5 = rs; // проверяет RS
PORTCbits.RC4 =1; // импульс E
PORTCbits.RC4 = 0;
DelaylTCY (); // задержка 48 мкс
DelaylTCY();
DelaylTCY();
PORTC = 0;
}
void initLCD (void)
{
int a;
DelaylKTCYx (2); // ожидание 32 мс
for (a = 0; a < 3; a++)
{
SendLCDdata (0x20, 0); // передача 0x20
DelaylKTCYx (1); // ожидание 16 мс
)
SendLCDdata (0x28, 0); // передача 0x28
SendLCDdata (0x01, 0); // передача 0x01
DelaylKTCYx (1); // ожидание 16 мс
Глава 9. Системы управления
415
SendLCDdata (ОхОС, 0); // передача ОхОС
SendLCDdata (0x06, 0); // передача 0x06
/ Отображает в заданной позиции строку символов из памяти программ (str)
' / строка 1 имеет позиции от 0x8 0 до 0хА7
'/ строка 2 имеет позиции от ОхСО до 0хЕ7
Ч Отображает в заданной позицииа строку символов из памяти программ (sLr)
void DisplayStringPgm (char position, rom char *str)
char ptr = 0;
SendLCDdata(position, 0); // передача позиции
while (str[ptr] != 0)
SendLCDdata(str[ptr++], 1); // передача символа
void getNumb (char count, char temp)
if (ptr < count)
1
if (temp >= 0 && temp <= 9)
{
SendLCDdata (0xC6 + ptr, 0);
SendLCDdata (temp + 0x30, 1);
buffer[ptr++] - temp;
1
else if (temp == 10) // шаг назад (*)
if (ptr != 0)
ptr--;
SendLCDdata (0xC6 + ptr, 0);
SendLCDdata (' ', 1);
1
void Disp3 (char temp)
SendLCDdata (temp / 100 + 0x30, 1)
temp %= 100;
SendLCDdata (temp / 10 + 0x30, 1);
SendLCDdata (temp % 10 + 0x30, 1);
void Disp4 (char first, char second)
SendLCDdata (first / 10 + 0x30, 1);
SendLCDdata (first % 10 + 0x30, 1);
SendLCDdata (':', 1);
SendLCDdata (second / 10 + 0x30, 1) ;
SendLCDdata (second % 10 + 0x30, 1) ;
int outTransQueue (void)
int temp;
416
Применение микроконтроллеров PIC18
if (inTrans == outTrans)
return 0x100; // если пусто
temp = transmitQueue[outTrans]; // получение данных
outTrans = (outTrans +1) & OxOF;
return temp;
}
int inTransQueue (char data)
{
if (outTrans == ((inTrans 4- 1) & OxOF))
return 0x100; // если заполнено
transmitQueue[inTrans] = data;
inTrans = (inTrans 4 1) & OxOF;
PiElbits.TXIE =1; // передатчик вкл
return 0;
)
int outRecvQueue (void)
{
int temp;
if (inRecv == outRecv)
return 0x100; //если пусто
temp = receiverQueue[outRecv]; // получение данных
outRecv = (outRecv 4-1) & OxOF;
return temp;
}
int inRecvQueue (char data)
{
if (outRecv == ((inRecv 4- 1) & OxOF) )
return 0x100; // если заполнен
receiverQueue[inRecv] = data;
inRecv = (inRecv 4-1) & OxOF;
return 0;
}
void MyHighlnt (void)
{
char a, temp;
if (INTCONbits.INTOIF == 1)
{
INTCONbits.INTOIF = 0; // очистка флага INTOIF
if (NSGreen > 10)
NSGreen = 10;
}
else if (INTCON3bits.INT1IF == 1)
{
INTCON3bits.INT1IF = 0;
if (EWGreen > 10)
EWGreen = 10;
}
else if (INTCONbits.RBIF == 1)
{
DelaylKTCYx (1);
temp = 0;
if (PORTB & OxFO != OxFO) //корректная клавиша
{
// выбор самого левого столбца
OxEF;
PORTC
Глава 9. Системы управления
-117
while ((PORTB & OxFO) == OxFO) // клавиша не распознана
{
PORTC = (PORTC << 1) | 1; // взятие следующего столбца
temp += 4; // добавление строки к коду клавиши
}
for (а = 0x10; а != 0; а <<= 1)
{ // нгахождение строки
if ((PORTB & а) == 0)
break;
temp++;
}
temp = lookupKey[temp];
switch (state)
{
case 0:
{
if (temp ==10) // любая команда
DisplayStringPgm (0x80, strl8);
DisplayStringPgm (OxCO, strl9);
state = 1;
break;
}
case 1:
{
if (temp >= 1 && temp <= 8)
{
ptr = 0;
DisplayStringPgm (0x80, str4 +
(state - 1)* 17) ;
DisplayStringPgm (0x00, str3);
state = temp + 1;
}
else
{
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
)
break;
)
case 2: // "установка текущего времени" (команда *1)
{
getNumb (4, temp);
if (temp ==11) // вводится #
{
hours = bufferfO] * 10 + buffer[l];
minutes = buffer[2] * 10 + buffer[3];
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
)
break;
)
case 3: // "установка мигающего старта" (команда *2)
{
getNumb (4, temp);
if (temp == 11)
418
Применение микроконтроллеров PIC 18
eeWrite (BlinkStartHours, buffer[0] *
10 + buffer LI J);
eeWrite(BlinkStartMinutes, buffer|2J *
10 + buffer L3|);
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str?);
state = 0;
1
break;
}
case 4: // "установка мигающего останова"
(команда *3)
{
getNumb (4, temp);
if (temp -= 11)
(
eeWrite (BlinkStopHours, buffer [0] *
10 + buffer[ 1 ] ) ;
eeWrite (BlinkStopMinutes, buffer[2| *
10 + buffer[ 3 J ) ;
DisplayStringPgm (0x80, str]);
DisplayStringPgm (OxCO, str2);
state = 0;
1
break;
}
case 5: // "установка желтого восток-запад"
(команда *4)
{
getNumb (3, temp);
if (temp == 11)
(
if (buffer[0] * 100 + buffer[l] *
10 + buffer[2] > 255)
(
buffer[0] = 2;
buffer[l] = buffer[2] = 5;
1
eeWrite (EWYellowTime, buffer[0) *
100 + buffer[l] *
10 + buffer[1]);
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
}
break;
}
case 6: 11 "установка зеленого восток-запад"
(команда *5)
{
getNumb (3, temp);
if (temp == 11)
(
if (buffer[0] * 100 + buffer[l] *
10 + buffer[2] > 255)
(
buffer[0] = 2;
bufferfl] = buffer[2] = 5;
Глава 9. Системы управления
419
1
case 7:
{
1
case 8:
(
1
case 9:
(
1
eeWrite (EWGreenTime, buffer [0] *
100 + buffer[lj *
10 + buffer[1]);
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
1
break;
// "установка желтого север -юг" (команда *6)
getNumb (3, lemp);
if (temp == 11)
(
if (buffer[0] * 100 + buffer[l]
* 10 + buffer[2] > 255)
(
buffer[0] = 2;
buffer[l] = buffer[2] = 5;
}
eeWrite (NSYellowTime, buffer[0] *
100 + buffer[l] *
10 + buffer[1]);
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
)
break;
// "Установка зеленого север-юг" ( команда *7)
getNumb (3, temp);
if (temp == 11)
{
if (buffer[0] * 100 + buffer[l] *
10 + buffer[2] > 255)
(
buffer[0] = 2;
buffer[l] = buffer[2] = 5;
1
eeWrite (NSGreenTime, buffer[0] *
100 + buffer[l] *
10 + buffer[1]);
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
1
break;
// "Отобразить все" (команда *8)
DisplayStringPgm (0x80, strll + ptr * 17);
DisplayStringPgm (OxCO, str3);
SendLCDdata (0xC5, 0);
if (ptr == 0)
Disp4(hours, minutes);
else if (ptr == 1)
420
Применение микроконтроллеров PIC 18
Disp4(eeRead(BlinkStartHours) ,
eeRead(BlinkStartMinutes));
else if (ptr == 2)
Disp4 (eeRead(BlinkStopHours),
eeRead (BlinkStopMinut.es) ) ;
else if (ptr == 3)
Disp3 (eeRead(EWYellowTime));
else if (ptr == 4)
Disp3 (eeRead(EWGreenTime));
else if (ptr == 5)
Disp3 (eeRead (NSYellowTime) ) ;
else if (ptr == 6)
Disp3 (eeRead(NSGreenTime));
ptr++;
if (ptr == 7)
state = 10;
break;
}
case 10:
{
DisplayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
state = 0;
break;
}
}
}
PORTC = 0;
temp = PORTB; // нужно считать PORTB для
// сброса изменения
INTCONbits.RBIF =0; // сброс прерывания
void MyLowInt (void)
{
int temp;
if (PIRlbits.TMR1IF == 1) //
{
PIRlbits.TMR1IF = 0;
WriteTimerl (-15625);
seconds++;
if (seconds == 60)
{
seconds = 0;
minutes++;
if (minutes == 60)
{
minutes = 0;
hours++;
if (hours == 24)
hours = 0;
1
}
}
else if (PIRlbits.RCIF == 1)
{
PIRlbits.RCIF = 0; //
установ таймера реального времени
// на 24-часовой режим
сброс прерывания
Глава 9. Системы управления
421
inRecvQueue (RCREG); // сохранение очереди принятых данных
1
else if (PIRlbits.TXIF == 1)
{
PIRlbits.TXIF = 0; // сброс прерывания
temp = outTransQueue();
if (temp == 0x100)
PIElbits.TXIE =0; // передатчик выкл
else
TXREG = temp; // передача данных
1
char HalfSecond (char count)
int a, temp;
for (a = 0; a < count; a++)
{
temp = outRecvQueue();
if (temp != 0x100 &&
PORTDbits.RD7 == 0 && //если ведомое устройство
((PORTD & OxFO) >> 4) == (temp & 7) &&
temp & 0xF7 == 0)
return 1;
DelaylKTCYx (31);
DelaylOTCYx (25);
1
return 0;
void DoLights (void)
if ((hours >= eeRead(BlinkStartHours) && // мигание
hours <= eeRead(BlinkStopHours)) && (
minutes >= eeRead(BlinkStartMinutes) &&
minutes <= eeRead(BlinkStopMinutes)))
PORTAbits.RAI = 1;
PORTAbits.RA5 = 1;
PORTDbits.RD1 = 1;
PORTDbits. RD3 = 1;
HalfSecond(1);
PORTAbits.RAI = 0;
PORTAbits.RA5 = 0;
PORTDbits.RD1 = 0;
PORTDbits.RD3 = 0;
HalfSecond(1);
)
else
{
do
11 север-юг желтый
I/ восток-запад зеленый
// север-юг, стоп
// восток-запад, стоп
// ожидание 1/2 секунды
// нормальный цикл
// синхронизация
do
{
do
{
do
{
422
Применение микроконтроллеров PIC 18
do
{
do
{ NSGreen - eeRead (NSGteenTime);
EWGreen - eeRead (EWGreenTime) ;
PORTAbits.RA4 =1; // восток-запад желтый
PORTAbits.RA5 = 0;
)
white (HalfSecond (eeRead(EWYellowTime)) == 1);
PORTAbits.RA4 = 0;
PORTAbits.RA3 = 1; // восток-запад красный
PORTAbits.RAO = 0;
PORTAbi ts.RA2 - 1 ; // север юг зеленый
PORTDbits.RD2 = 1; // восток-запад переход
PORTDbiLs.RD1 = 1; // север юг стон
)
while (HalfSecond (eeRead(NSGreen/2) ) == 1);
PORTDbits.RD2 = 0;
PORTDbits.RD3 = 1;
)
while (HalfSecond (eeRead(NSGreen/2)) == 1);
PORTAbits.RAI =1; // север-юг желтый
PORTAbits.RA2 = 0;
)
while (HalfSecond (eeRead(NSYellowTime)) == 1);
PORTAbits.RAI = 0;
PORTAbits.RAO = 1; // север-юг красный
PORTAbits.RA5 = 1; // восток-запад зеленый
PORTAbits.RA3 = 0;
PORTDbits.RD3 = 1; // восток-запад стоп
PORTDbits.RD0 = 1; // север-юг переход
)
while (HalfSecond (eeRead(EWGreen/2)) == 1) ;
PORTDbits.RD0 = 0;
PORTDbits.RD1 = 1;
)
while (HalfSecond (eeRead(EWGreen/2)) == 1);
)
void main (void) ।
t int a;
OSCCON = 0x22; // внутренняя синхронизация 250-кГц
ADCON1 = OxOF; // все входы цифровые
TRISA = 0; // все штырьки порта А - выходы
TRISB = OxFF; u все штырьки порта В - входы
TRISC = 0x80; // все штырьки порта С - выхода, за исключением RC7
TRISD = OxFO; // Штырьки 0-3 порта D - выходы, 4-7 - входы
TRISE = 0; // все штырьки порта Е - выходы
if (PORTDbits.RD7 == 0)
PORTEbits.REl = 0; // ведомое устройство
e 1 se
PORTEbits.REl = 1; // ведущее устройство
Глава 9. Системы управления
423
PORTA =0; // все лампы выкл
PORTC = 0;
PORT’D = 0;
state = 0;
initl.CD () ;
D i.splayStringPgm (0x80, strl);
DisplayStringPgm (OxCO, str2);
INTCONPbits.RBPU - 0; // Нагрузки порта В вкл.
OpenTimer! (TIMER_INT_ON &
T1_8BIT_RW &
T1_SOURCE_INT &
T1_PS_1_4);
WriteTimerl (-15625); // каждую секунду
IPRlbits.TMR1IP = 0; // таймер 1 низкий приоритет
PIElbits.TMR1IE =1; // прерывание от таймера 1 вкл
1NTCON3bits.INT11P = 1; // INTI имеет высокий приоритет
INTCON3bits.INTI IE = 1; // разрешение
INTCON2bits.INTEDGO = 0; // объявление INTO переключаемым no
// отрицательному фронту
INTCONbits.INT0IE = 1; 11 разрешение INTO
INTCON2bits.RBIP = 0; // низкий приоритет
INTCONbits.RBIE = 1; // разрешение прерывание по изменению бита
IPRlbits.TXIP = 0; // выбор низкого приоритета
IPRlbits.RCIP = 0; // для USART
OpenUSART (USART_TX_INT_ON & 11 USART работает на скорости 1200 бод
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
usart2cont_rx &
USART_BRGH_HIGH,
3) ;
inRecv = outRecv = inTrans = outTrans = 0;
RCONbits.IPEN =1; // оба приоритетные прерывания вкл.
INTCONbits.GIEH = 1; // разрешение прерываний
INTCONbits.GIEL = 1;
// Synchronize all slaves
//
for (a = 0; a < 8; a4+)
{
while (in'fransQueue (a) -== 0x100); // посылка адреса
// все ведомые устройства посылают 0000 Оааа для
// синхронизации
// их таким образом, что их циклы будут синхронны
// 0000 0 - это команда синхронизации
)
while (1)
424
Применение микроконтроллеров PIC18
DoLights ();
)
Пример 2
Сейчас мы рассмотрим систему управления снискавшим популярность сани гар-
ным ящиком для котов. Подобное изделие производится фирмой Litter Maid. Никто не
любит чистить санитарный ящик кота, однако все, что пользователь должен делать в
случае санитарного ящика - это приблизительно один раз в неделю устанавливать в
нем сменный одноразовый контейнер - устройство автоматически будет загружать в
него то, что остается после кота. Никакого запаха, никаких забот.
Эта система довольно проста. Она содержит сенсорные переключатели, которые
указывают, когда перемещаемый совок позиционирован в каком либо конце ящика,
электромотор, перемещающий совок, устройство звуковой сигнализации для про-
блемных ситуаций, а также пару фотодатчиков, определяющих, находится ли кот в са-
нитарном ящике. Если кот зашел в санитарный ящик, то совок стопорится в пластмас-
совом блоке и остается в этом состоянии еще по крайней мере 10 минут после того, как
кот покинет ящик. (Мы, конечно, не хотим травмировать кота!) Это простая система, ее
схемное решение показано на рис. 9.6. Небольшое реле (выдерживает приблизительно
40000 циклов срабатывания) используется для переключения направления вращения
электромотора, потому что стоимость однонаправленного электромотора значительно
ниже, чем двунаправленного. Направление вращения также может быть изменено ме-
ханически. Фотодатчики включены последовательно, поэтому, когда кот перекрывает
один либо оба датчика, микроконтроллер получает на выводе RB4 сигнал логической
единицы. Это последовательное включение выполняет ту же функцию, что и логиче-
ская схема И. Зуммер, показанный на схеме, представляет собой сигнализатор Мело-
ри, который совместим с компонентами схемы без использования каких-либо дополни-
тельных деталей.
Программа для рассматриваемой системы короче, чем какие либо другие про-
граммы, приведенные в этой главе. Пример 9.3 показывает программу управления са-
нитарным ящиком кота. Одним из ее свойств является то, что в случае, когда совок
пытается поднять большой объем вещества, он движется вперед и назад, имея целью
протолкнуть его к задней стенке ящика, где расположен контейнер. Если после 30 по-
пыток успех не достигнут, то совок арретируется и система будет ожидать следующего
прихода кота. Это одна из немногих систем, которая не требует вмешательства чело-
века во время своей работы.
Зуммер
Инфракрасные передатчики
R1
ЮК
+5V
О
PIC18F1220
U1
С2
0.1 uF
R2
330
? R3
Инфракрасные / 47K
приемники f
Q1
1
2
6
7
3
4
16
15
С1
1.0 uF
RAO
RA1
RA2
RA3
RA4
#MCLR
OSC1 »RB6
OSC2 >RB7
°RBO
5RB1
RB2
RB3
RB4
RB5
8
9
17
18
10
11
12
13
R5
1К
Глава 9. Системы управления
Q2
Исходная позиция
Q4
ПР120
LS2
Реле
Мотор
Q3
2N2222
R4 Конец
Рис. 9. 6. Схема управления «санитарным ящиком
426
Применение микроконтроллеров PIC 18
Пример 9.3
/*
* Санитарный ящик кота
*/
flinclude <pl8cxxx.h>
flinclude <delays.h>
/* Установка битов конфигурации
* установка режима генератора RC
* выключение сторожевого таймера
* - выключение низковольтного программирования
* отключение сброса по частичной потере питания
* разрешение общего сброса
’/
#pragma config OSC = INTIO2
#pragma config WDT = ON
flpragma config WDTPS = 256 // одна минута
flpragma config LVP = OFF
flpragma config BOR = OFF
flpragma config MCLRE = ON
flpragma code
void main (void)
{
unsigned int count, countl;
OSCCON = 0x22; // внутренняя синхрочастота 250 кГц
ADCON1 = 0x7F; // все входы цифровые
TRISA = 0;
TRISB = 0x3F; // программирование порта В
PORTB = PORTA =0; // останов электромотора
while (1)
{
while (PORTBbits.RBI == 1)
{
PORTB = 0x80; // совок в исходное положение
ClrWdt();
)
PORTB = PORTA = 0; // останов электромотора и звукового сигнала
while (PORTBbits.RB4 == 0) // ожидание прихода кота
ClrWdt () ;
while (PORTBbits. RB4 == 1) // ожидание выхода кота
ClrWdt();
count = 0;
do
{
count++;
ClrWdt();
DelaylKTCYx(3); // 12 мс
if (PORTBbits.RB4 == 0)
count = 0;
}
while (count != 50000); // 10 минут
count = countl = 0;
while (PORTBbits.RB3 == 1)
{ // продвижения совка к стенке
Глава 9. Системы управления
427
count»г;
PORTB = OxCO;
De 1aylKTCYx(3);
ClrWdt () ;
if (count == 41'7) //5 секунд (должен остановиться)
(
PORTB = 0x80;
count = 0;
countl++;
DelaylKTCYx(2b5); // задержка
}
if (countl ==30) // выключение зуммера
{
PORTA =1; //30 попыток
break; // затем подъем
)
)
PORTB =0; // останов электромотора
Пример 3
Еще одним примером простой системы управления, которая может быть запро-
граммирована в микроконтроллере, является домашняя система клима г-контроля. Эта
система должна контролировать температуру в комнате и управлять подачей перемен-
ного напряжения в 24 В, которое запитывает обогреватель и/или установку кондицио-
нирования воздуха.
Предположим, что эта система нуждается в некотором интеллектуальном потен-
циале с тем, чтобы она могла автоматически переключаться от нагрева к кондициони-
рованию - эта функция отсутствует в большинстве домашних систем. Реализация этой
функции требует использования датчика наружной температуры какого-либо типа. Что-
бы разработать эту систему, мы должны точно определить, чем мы будем управлять и
что будем замерять. Входами этой системы будут сигналы от панели управления,
имеющей клавиатуру для программирования, двух датчиков температуры (один - для
термостата и один - для внешней температуры) и двух небольших реле включения на-
гревателя или кондиционера воздуха.
Пользовательский программный интерфейс обеспечивает способ ввода времени
дня и набора значений времени включения и выключения системы, благодаря чему
система может программироваться на выключение (или в качестве опции - на пониже-
ние температуры), когда дома никого не будет продолжительное время. Также можно
создать график работы системы в рабочие и выходные дни (этот график позволяет
пользователю, в частности, ввести расписание выходных дней, потому что не у всех
суббота и воскресенье - выходные дни).
Панель управления этой системы, открывающаяся при открытии дверцы, показа-
на на рис. 9.7. Число кнопок на ней минимизировано, однако их достаточно для про-
граммирования системы, которое интуитивно понятно почти для всех пользователей.
Вся система для простоты работы с ней сформирована на основе использования всею
только трех кнопок (UP (Вверх), DOWN (Вниз) ENTER (Ввод)), а также ЖКИ, который
подсвечивается, когда дверца, закрывающая кнопки, открыта. (Некоторые термостаты
размещены в темных местах и ночью их трудно видеть при программировании). ЖКИ
представляет собой ЖК-панель 2x24, достаточную, для индикации температуры и ре-
жима программирования. При нормальной работе системы температура в помещении
428
Применение микроконтроллеров PIC 18
отображается в строке 1, а наружная температура отображается в строке 2. Если поль-
зователь выполнил монтаж наружных проводов и не выполнил их подключение к датчи-
ку наружной температуры, то функция нагрева/кондиционирования воздуха не будет
работать, и наружная температура не будет отображаться. Рис. 9.8 иллюстрирует пол-
ную электрическую схему системы. Подключения к системе обогрева в большинстве
случаев стандартны, однако в некоторых системах может использоваться отличная от
показанной на схеме цветовая кодировка. Обычно используется подключение, которое
с одной стороны выходит на 24-вольтовый трансформатор, а с другой имеет три сиг-
нальные линии, передающие сигналы напряжения на реле, которые управляют нагре-
вателем, воздушным кондиционером и электромотором вентилятора. Управляющее
напряжение, равное 24 Вольт переменного тока, почти всегда используется в системах
обогрева, вентиляции и кондиционирования воздуха (HVAC).
Электромотор вентилятора управляется переключателем, который выбирает ав-
томатический режим (вентилятор включается только тогда, когда выполняется обогрев
или кондиционирование воздуха) или же режим ON (Вкл.), когда электромотор венти-
лятора будет работать непрерывно. Переключатель на приведенной схеме показан в
положении, соответствующем автоматическому режиму.
Программа для этой системы показана в примере 9.4. К этой программе многое
могло бы быть добавлено. Она обеспечивает только установку одной ночной темпера-
туры и одной температуры для рабочих дней. Дополнительные точки установки темпе-
ратуры могли бы быть добавлены в случае необходимости посредством ввода допол-
нительных состояний в функцию GotKey. Чтобы эта программа работала, к системе
должны быть подключены как внутренние, так и наружные датчики. Программа исполь-
зует 2841 слова из 4096 доступных ячеек памяти, так что намного больше функций мо-
гут быть легко добавлены без полного использования всего пространства памяти.
ЮК
Рис. 9.8. Электрическая схема системы
красный - общий
зеленый - вентилятор
белый - Hai-рев
430
Применение микроконтроллеров PIC 18
Пример 9.4
/*
* программа домашней системы обогрева/кондиционирования воздуха
*/
♦include <pl8cxxx.h>
♦include <delays.h>
♦include <timers.h>
♦include <string.h>
/* Установка битов конфигурации
* установка режима генератора RC
* -- выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
♦pragma config OSC = INTIO2
♦pragma config WDT = ON
♦pragma config WDTPS = 256
♦pragma config LVP = OFF
♦pragma config BOR = OFF
♦pragma config MCLRE = ON
// одна секунда
уу****************** векторы прерываний
void MyHighlnt (void);
♦pragma interrupt MyHighlnt
♦pragma code high_vector=8
I/ прототипы процедур
// обслуживания прерываний
// MyHighlnt - это прерывание
// high_vector по адресу 0x08
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
)
у у****************** переменные в памяти данных ********************
short long time;
char hours;
char minutes;
char day;
char displayTimeFlag;
char indoor;
char outdoor;
char setPoint;
char timeOut;
char state;
переменные в памяти программ
char near rom days[][10] = {
"Sunday
"Monday ",
"Tuesday ",
"Wednesday",
"Thursday ",
Глава 9. Системы управления
431
"Friday "
"Saturday "
char near rom strl[] = "Indoor ";
char near rom str2[] = "Outdoor ";
char near rom str3[] = " Set time of day ";
char near rom str4[] = t
char near rom str5[] = " Set day of week ";
char near rom Str6[] = " Is a work day (M-F)? ";
char near rom str7[] = " Up = yes, Down = no ";
char near rom str8[] = "Is
ana r near rom str9U - " a work day? "; // примеры нескольких случаев
char near rom strl0[) -- " Normal temperature
char near rom s t r 1 1 [ ] - " Setback temerature ";
char near rom strl2[] = " Work day ON 1 time ";
char near rom strl3[] = " Work day OFF 1 time
char near rom strl4[] = " Night OFF time ";
char near rom strl5[] = " Morning ON time
//***************** ЭСППЗУ
ДАННЫХ ************************************
«define
♦define
♦define
-def i ne
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
♦define
temperature 0
workday 1
dayO 2
dayl 3
day2 4
day3 5
day4 6
day5 7
day6 8
normaltemp 9
setbacktemp 10
workdayOnlh 11
workdayOnlm 12
workdayOfflh 13
workdayOfflm 14
nightOffh 15
nightOffm 16
mornOnh 17
mornOnm 18
7****************о***
функции
// установка температуры термостата
// рабочий день (ПН-ПТ) = 1
// рабочий день = 1, иначе = 0
♦pragma code
//считывание из адреса местоположения ячейки в памяти данных ЭСППЗУ
char eeRead (char address)
<
EECONlbits.EEPGD = 0;
EEADR = address;
EECONlbits.RD = 1;
return EEDATA;
// запись данных в ячейку памяти данных ЭСППЗУ по адресу
432
Применение микроконтроллеров PIC 18
void eeWrite (char address, char data)
{
INTCONbits.GIEH = 0;
EECONlbits.EEPGD = 0;
EECONlbits.WREN = 1;
EEADR = address;
EEDATA = data;
EECON2 = 0x55;
EECON2 = OxAA;
EECONlbits.WR = 1;
while (PIR2bits.EEIF == 0) ;
PIR2bits.EEIF = 0;
EECONlbits.WREN = 0;
INTCONbits.GIEH = 1;
)
void sendNib (char data, char rs)
(
PORTB = data; // передача полубайта
PORTAbits.OSC2 = rs; // проверка RS
PORTBbits.RB7 =1; // импульс E
PORTBbits.RB7 = 0;
DelaylTCY (); // задержка 64 мкс
DelaylTCY ();
void SendLCDdata (char data, char rs)
{
sendNib (data » 1, rs);
sendNib (data << 3, rs);
void initLCD (void)
int a; DelaylKTCYx (1); // ожидание 32 мс
for (a = 0; a < 3; a++)
i SendLCDdata (0x20, 0); // передача 0x20
DelaylOOTCYx (2) ; // ожидание 6.4 мс
j SendLCDdata (0x28, 0) ; // передача 0x28
SendLCDdata (0x01, 0); // передача 0x01
DelaylOOTCYx (1) ; // ожидание 3.2 мс
SendLCDdata (OxOC, 0) ; // передача ОхОС
SendLCDdata (0x06, 0); // передача 0x06
// Отображение строки из памяти программ (str) в указанной позиции
// строка 1 занимает позиции от 0x80 до 0x97
// строка 2 занимает позиции от ОхСО до 0xD7
// Отображение строки из памяти программ (str) в указанной позиции
void DisplayStringPgm (char position, rom char *str)
{
char ptr = 0;
SendLCDdata (position, 0); // передача позиции
while (str[ptr] != 0)
Глава 9. Системы управления
433
I
SendLCDdata(str[ptr++], 1); // передача
символа
void GetTemp (void)
char a; char b, c; PORTAbits.OSC1 = 0; for (a = 0; a < 9; a4+) i // CS = 0
t b «= 1; c <<= 1;
PORTAbits.RA2 = 1; b |= PORTAbits.RA3; c |= PORTAbits.RA4; // SC = 1
PORTAbits.RA2 = 0; ) for (a = 0; a < 7; a++) I // SC - 0
t PORTAbits.RA2 = 1; // SC = 1
PORTAbits.RA2 = 0; г // SC = 0
i PORTAbits.OSC1 = 1; if (c == Oxff) c = 0x80; indoor = b; outdoor = b; // CS = 1
void GetTime (short long *temp)
day = *temp / 86400;
hours = (*temp % 86400) / 3600;
minutes = ((*temp % 86400) % 3600) / 60;
void PutTime (char place)
(
char temp;
SendLCDdata (place, 0);
temp = hours;
if (hours >= 12)
hours -= 12;
if (hours == 0)
hours = 12;
if (hours < 10)
SendLCDdata (' ', 1);
else
SendLCDdata (hours / 10 + 0x30, 1);
SendLCDdata (hours % 10 + 0x30, 1);
SendLCDdata (':', 1);
SendLCDdata (minutes / 10 + 0x30, 1);
SendLCDdata (minutes % 10 + 0x30, 1);
SendLCDdata (' ', 1);
if (temp > 11)
SendLCDdata ('P', 1);
else
SendLCDdata ('A', 1);
434
Применение микроконтроллеров PIC 18
void PutTemp (char where, char temp)
{
SendLCDdata (where, 0);
if (temp < 0)
{
temp = -temp;
SendLCDdata ('-', 1);
)
if (temp >= 100)
{
SendLCDdata (temp / 100 + 0x30, 1);
temp -= 100;
)
SendLCDdata (temp / 10 + 0x30, 1);
SendLCDdata (temp % 10 + 0x30, 1);
SendLCDdata (OxDF, 1);
void DisplayTimeDate (void)
(
GetTemp ();
GetTime (&time);
DisplayStringPgm (0x80, strl);
PutTime (OxDO);
PutTemp (0x87, indoor);
if (outdoor != -128)
1
DisplayStringPgm (OxCO, str2);
PutTemp (0xC8, outdoor);
)
else
DisplayStringPgm (OxCO, str4);
void DoThermostat (void)
(
GetTime (&time);
if (eeRead(nightOffh) == hours &&
eeRead (nightOffm) == minutes)
setPoint = eeRead(setbacktemp);
else if (eeRead(mornOnh) == hours &&
eeRead(mornOnm) == minutes)
setPoint = eeRead (normaltemp);
else if (eeRead(dayO + day) == 1 &&
eeRead(workdayOnlh) == hours &&
eeRead(workdayOnlm) == minutes)
setPoint = eeRead(setbacktemp);
else if (eeRead(dayO + day) == 1 &&
eeRead (workdayOffIh) == hours &&
eeRead (workdayOffIm) == minutes)
setPoint = eeRead (normaltemp);
else
setPoint = eeRead (normaltemp);
if (outdoor < 65)
{
if (indoor < setPoint)
Глава 9. Системы управления
435
{
PORTAbits.RAO = 1;
PORTAbits.RAl = 0;
)
else
{
PORTAbits.RAO = 0;
PORTAbits.RAl = 0;
}
else
(
if (indoor > setPoint)
{
PORTAbits.RAO = 0;
PORTAbits.RAl = 1;
}
else
(
PORTAbits.RAO = 0;
PORTAbits.RAl = 0;
}
)
// нагрев вкл.
// нагрев выкл.
// воздух вкл.
// воздух выкл.
void MyHighlnt (void)
(
if (PIRlbits.TMR1IF == 1) // объявление 24-режима
{ // для таймера реального времени
PIRlbits.TMR1IF = 0;
WriteTimerl (-31250);
time++;
if (timeOut != 0)
timeOut—;
if (time == 604800)
time = 0;
if (displayTimeFlag == 1 && time % 60 == 0)
I
DisplayTimeDate();
DoThermostat ();
}
}
)
char GetKey (void)
{
do
{
while ((PORTB & 7) 1=7)
{
ClrWdt () ;
DelaylOOTCYx (5);
if (timeOut == 0)
return 7;
)
}
while ((PORTB & 7) 1= 7);
do
{
436
Применение микроконтроллеров PIC 18
while ((PORTB & 7) == 7)
{
ClrWdt () ;
DelaylOOTCYx (5);
if (timeOut == 0)
return 7;
}
while ((PORTB & 7) == 7);
return 0;
void GotKey (void)
{
i, n t a ;
short long b;
DelaylOOTCYx (5); // 16 мс
if ((PORTB & 7) != 3)
return; //игнорирование всего, кроме выборки
displayTimeFlag = 0;
DisplayStringPgm (0x80, str3);
DisplayStringPgm (OxCO, str4);
timeOut = 5;
while (GetKeyO == 0)
{
timeOut = 5;
switch (state)
(
case 0:
{
GetTime (&time);
PutTime (0xC8);
if (PORTBbits.RBO == 0)
{
time++;
if (time > 604800)
time = 0;
}
else if (PORTBbits.RBI == 0)
{
time--;
if (time < 0)
time = 604799;
}
else if (PORTBbits.RB2 == 0)
(
state = 1;
DisplayStringPgm (0x80, str5);
DisplayStringPgm (OxCO, str4);
a = 0;
)
break;
}
case 1:
{
a &— 7;
DisplayStringPgm (0xC9, days[a]);
if (PORTBbits.RBO == 0 )
Глава 9. Системы управления
437
}
case
{
)
case
{
)
case
{
а++;
else if (PORTBbits.RBI == 0)
a - • ;
else if (PORTBbits.RB2 == 0)
{
time = time % 86400 + a * 86400;
state = 2;
DisplayStringPgm (0x80, str6);
DisplayStringPgm (OxCO, str7);
}
break;
2 :
if (PORTBbits.RBO == 0)
{
eeWrite (workday, 1);
state = 4;
DisplayStringPgm (0x80, strlO);
DisplayStringPgm (OxCO, str4);
a = indoor;
}
else if (PORTBbits.RBI == 0)
{
eeWrite (workday, 0);
state = 3;
a = 0;
DisplayStringPgm (0x80, str8);
DisplayStringPgm (OxCO, str7);
)
break;
3 :
DisplayStringPgm (0x83, days[a]);
DisplayStringPgm (0x83 + strlenpgm (days[a]),
str9);
if (PORTBbits.RBO == 0)
eeWrite (dayO + a, 1);
else if (PORTBbits. RBI == 0)
eeWrite (dayO + a, 1);
else
a—;
a++;
if (a == 8)
(
state = 4;
DisplayStringPgm (0x80, strlO);
DisplayStringPgm (OxCO, str4);
a = indoor;
}
break;
4 :
PutTemp (OxCA, a);
if (PORTBbits.RBO == 0)
438
Применение микроконтроллеров PIC 18
а++;
if (а >= 100)
а—;
!
else if (PORTBbits.RB? -- 0)
{
a--;
if (a <= 49)
a++;
}
else if (PORTBbits.RB2 == 0)
{
eeWrite (normaltemp, a);
state = 5;
DisplayStringPgm (0x80, strll);
DisplayStringPgm (OxCO, str4);
}
break;
}
case 5:
{
PutTemp (OxCA, a);
if (PORTBbits.RBO == 0)
{
a++;
if (a >= 100)
a--;
)
else if (PORTBbits.RBI == 0)
{
a—;
if (a <= 49)
a++;
}
else if (PORTBbits.RB2 == 0)
{
eeWrite (setbacktemp, a);
state = 6;
DisplayStringPgm (0x80, strl2);
DisplayStringPgm (OxCO, str4);
b = 0;
)
break;
)
case 6:
{
GetTime (&b);
PutTime (0xC8);
if (PORTBbits.RBO == 0)
{
time++;
if (time > 604800)
time = 0;
}
else if (PORTBbits.RBI == 0)
{
time--;
if (time < 0)
Глава 9. Системы управления
439
time = 604799;
}
else if (PORTBbits.RB2 == 0)
{
state = 7;
DisplayStringPgm (0x80, strl3);
DisplayStringPgm (OxCO, str4);
eeWrite (workdayOnlh, hours);
eeWrite (workdayOnlm, minutes);
!
break;
}
case 7:
{
GetTime (&b);
PutTime (0xC8);
if (PORTBbits.RBO == 0)
{
time++;
if (time > 604800)
time = 0;
)
else if (PORTBbits.RBI == 0)
{
time--;
if (time < 0)
time = 604799;
}
else if (PORTBbits.RB2 == 0)
{
state = 8;
DisplayStringPgm (0x80, strl4);
DisplayStringPgm (OxCO, str4);
eeWrite (workdayOfflh, hours);
eeWrite (workdayOffIm, minutes);
}
break;
}
case 9:
{
GetTime (&b);
PutTime (0xC8);
if (PORTBbits.RBO == 0)
{
time++;
if (time > 604800)
time = 0;
}
else if (PORTBbits.RBI == 0)
{
time—;
if (time < 0)
time = 604799;
}
else if (PORTBbits.RB2 == 0)
{
state = 9;
DisplayStringPgm (0x80, strlb);
440
Применение микроконтроллеров PIC 18
DisplayStringPgm (OxCO, str4);
eeWrite (mornOnh, hours);
eeWrite (mornOnm, minutes);
displayTimeFlag - 1;
DisplayTimeDate();
return;
}
break;
}
)
)
displayTimeFlag = 1;
DisplayTimeDate();
}
//************************ главный код запуска *************
void main (void)
{
OSCCON = 0x02; // внутренняя тактовая частота 32 мкс
ADCON1 = 0x0F; // все входы цифровые
TRISA = 0x18; // программирование порта А
TRISB = 0x07; // программирование порта В
PORTA = 0x80;
PORTB = 7;
initLCDO ;
displayTimeFlag = 1;
DisplayTimeDate();
INTCON2bits.RBPU = 0; // включение слабых нагрузок порта В
OpenTimerl (TIMER_INT_ON &
T1_8BIT_RW &
T1_SOURCE_INT &
T1_PS_1_1);
WriteTimerl (-31250 ); // каждую секунду
INTCONbits.GIEH =1; // разрешение прерываний
while (1) // остаемся здесь до нажатия ключа
{
ClrWdt();
state = 0;
if ((PORTB & 7) != 7)
GotKey ();
)
9.3. Резюме
1. Технологическая карта процесса помогает специфицировать проект системы
управления, устанавливая зависимость между событиями и моментами времени, когда
эти события должны произойти.
2. В примере системы посудомоечной машины прерывания используются для
приостановки работы машины.
3. В примере системы управления светофорами используется последовательный
интерфейс RS-422 для того, чтобы осуществлять информационный обмен с системами
управления светофорами на других перекрестках с тем, чтобы работа светофоров была
синхронной.
Глава 9. Системы управления
441
4. Контроллер светофоров использует целый ряд входов, включая: кнопки пере-
хода и переходные панели, а также современные светофорные лампы светодиодного
типа.
5. Для того, чтобы сохранить себестоимость и количество деталей на минималь-
ном уровне, в примере системы санитарного ящика для котов используется реле,
управляющее направлением вращения электромотора вместо более дорогой двуна-
правленной схемы управления электромотором.
6. Система обогрева/кондиционирования воздуха использует микроконтроллер
PIC18 для того, чтобы управлять как обогревом помещения, так и кондиционированием
воздуха в домашней системе обогрева/кондиционирования воздуха.
9.4. Вопросы и задания
1. Перечислите все входы и выходы системы посудомоечной машины, описанной
в этой главе.
2. Что является целью использования прерываний в системе посудомоечной ма-
шины?
3. Если дверца посудомоечной машины будет открыта в процессе мытья посуды,
что произойдет с временными задержками?
4. Модифицируйте диаграмму управления процессом, приведенную на рис. 9.1
так, чтобы посудомоечная машина имела бы настройку цикла стерилизации, выбирае-
мого еще одним переключателем, подключенным к штырьку RA2. Этот тумблер выби-
рает цикл стерилизации, подавая на RA2 сигнал логической единицы, и отключает его,
подавая на этот вывод сигнал логического нуля. Для выполнения этого обычно исполь-
зуются две диаграммы, одна - для цикла без стерилизации и вторая - для цикла со сте-
рилизацией.
5. Измените программу из примера 9.1 таким образом, чтобы как цикл стерили-
зации, так и соответствующий переключатель правильно работали бы в системе.
6. Допустим, что имеется стиральная машина, которая имеет два цикла стирки —
один для нежной стирки в теплой воде и один - для нормальной стирки в горячей воде.
Разработайте технологическую карту, которая описывает работу этой машины. Эле-
ментами управления являются: электромотор насоса/активатора, заполни тельный
клапан для горячей воды, заполнители !ый клапан для холодной воды, высокоскорост-
ной передаточный механизм для цикла отжима, управляемый соленоидом, а также
дренажный соленоид для отвода воды из бака. Имеется также механизм блокировки
дверцы, который останавливает машину, но только в цикле сушки. Цикл стирки должен
включать стирку с предварительным отжимом, а затем полоскание и окончательный
01 жим.
7. Разработайте схему электрическую системы стиральной машины, используя
микроконтроллер PIC18 по вашему выбору.
8. Напишите программу управления для системы стиральной машины, разрабо-
танной в рамках выполнения последних двух заданий.
9. Предположим, что нам нужна система, управляющая блокировкой дверей авю-
мобиля. Когда автомобиль достигнет скорости, равной 15 миль в час, двери должны
блокироваться. Новый моментом в этой системе должно быть то, что когда автомобиль
останавливается и выключается зажигание, то двери должны разблокироваться. Если
автомобиль будет все еще в движении, когда зажигание будет выключено, то двери не
должны разблокироваться до тех пор, пока автомобиль полностью нс остановится.
Единственным элементом управления в системе является небольшой электромотор,
используемый для того, чтобы отпереть двери. Имеются два входа: сигнал зажигания
442
Применение микроконтроллеров PIC 18
(логический ноль, когда зажигание включено) и от датчика скорости на коробке пере-
дач. Датчик скорости генерирует импульсы по мере того, как поворачивается ведущий
вал коробки передач. Соотношение задается как 10 импульсов на один поворот шины.
Если используется 16-дюймовое колесо, то это значит, что датчик генерирует 39610
импульсов на милю (5280/1,333 х 10). Блок датчика производит 11,0028 импульса в
секунду (36610/3600) для каждой мили в час скорости. Таким образом, пороговому
значению 15 миль в час соответствует 165 импульсов в секунду. Полная остановка оз-
начала бы что-нибудь ниже 0,09 миль в час. Разработайте схемное решение для этой
системы и технологическую карту процесса в случае необходимости.
10. Сколько прерываний необходимо использовать для того, чтобы разработать
программу в задании 9?
11. Разработайте программу системы для задания 9.
12. Какая мощность потребления требуется для красного светодиодного индика-
тора светофора?
13. Каков срок службы красного светодиодного индикатора светофора?
14. Какой стандарт интерфейса используется для того, чтобы подключить один
контроллер светофора к другим в примере, рассмотренном в данной главе?
15. Какие входные сигналы используются в системе управления светофорами,
рассмотренной в данной главе?
16. Какая команда от ведущего устройства к подчиненным устройствам иллюст-
рируется в системе управления светофорами, рассмотренной в этой главе?
17. Опишите, какие другие команды должны быть использованы в реальной мно-
гоперекрестной системе управления дорожным движением.
18. Почему используется реле для того, чтобы изменить направление вращения
электромотора в санитарном ящике для котов, описанном в этой главе?
19. Как реагирует программа, когда совок в санитарном ящике для котов стопо-
рится большим объектом?
20. Предложите дополнительные функции, которые могли бы быть реализованы в
системе управления санитарным ящиком для котов, описанной в данной главе.
21. Детализируйте, как сигналы в домашней системе обогрева/кондиционирования воз-
духа управляют нагревателем, кондиционером воздуха и электромотором вентилятора циркуля-
ции воздуха.
23. Поскольку сигналы управления в вышеупомянутой системе представляют со-
бой сигналы 24 В переменного тока, для их контроля используются реле. Имеется ли
альтернативный дешевый и надежный метод управления этими сигналами?
24. Если значение наружной температуры в системе обогрева/кондиционирования возду-
ха недоступно, то возможно ли управлять как нагревом, так и кондиционированием воздуха без
ручной настройки? Аргументируйте ваш ответ.
25. Полезно ли в некоторых случаях вводить наружный воздух в систему обогре-
ва/кондиционирования воздуха? Если да, то объясните ваш ответ, рассмотрев не-
сколько случаев.
26. Какая роль отводится ЭСППЗУ данных в системе обогрева/кондицио! 1ирова> 1ия возду-
ха, описанной в данной главе?
Глава 10. Вопросы повышенной сложности
443
ГЛАВА 10. Вопросы повышенной сложности
В этой главе рассматриваются вопросы, которые не всегда связаны с ежеднев-
ным применением микроконтроллеров. Примером такого вопроса может быть исполь-
зование дополнительной памяти. Из предшествующих глав вы уже знаете, что микро-
контроллер имеет ограниченное количество памяти, однако до сих пор очень мало го-
ворилось о возможностях расширения памяти микроконтроллерной системы. Кроме
того, поскольку встречаются случаи, когда встроенных устройств ввода-вывода недос-
таточно, го в этой главе рассматривается на примерах то, как нужно использовать ин-
терфейс CAN (управляющая локальная сеть) и интерфейс USB (универсальная после-
довательная шина) для расширения возможностей ввода-вывода микроконтроллерной
системы.
После завершения изучения данной главы вы сможете:
1. Расширять объем памяти микроконтроллерной системы;
2. Использовать код UPC в системе управления складскими запасами;
3. Программировать микроконтроллер с использованием загрузочного блока;
4. Создавать программу начальной загрузки;
5. Расширять ввод-вывод микроконтроллера;
6. Использовать интерфейс CAN для объединения микроконтроллеров в сеть;
7. Программировать и подключать USB к персональному компьютеру;
8. Детализировать расширенный набор команд PIC18.
10.1. Расширение памяти
Одной из проблем, связанных с использованием микроконтроллеров, является
то, что они содержат ограниченный объем памяти. Это особенно справедливо в случае
СЗУПВ, объем которого часто находится в диапазоне от 256 до 512 байтов. Некоторые
исполнения микроконтроллеров имеют больший объем внутреннего СЗУПВ, но и эти
устройства имеют не более, чем 3698 ячеек памяти. Объем памяти программ также
может ограничить возможности приложений. Микроконтроллер может иметь только 2
или 4К ячеек памяти программ, что часто является достаточным для многих систем,
однако если системная программа очень велика, или же имеется большой объем ста-
тичных данных, то может потребоваться расширение памяти. В данном подразделе
исследуется вопрос расширения памяти с использованием последовательного
ЭСППЗУ, которое является единственным типом последовательных ЗУ, которые могут
использоваться для расширения памяти в микроконтроллерных системах.
Добавление последовательного ЭСППЗУ
Микросхемы последовательного ЭСППЗУ предлагаются фирмой Microchip для
расширения объема памяти микроконтроллеров. Это не СЗУПВ и эти микросхемы
имеют ограниченный срок службы. ЭСППЗУ обычно обеспечивает один миллион циклов
считывания-записи, что часто достаточно для многих применений. Для подключения
последовательного ЭСППЗУ необходимо использовать интерфейс 12С или SPI. Может
быть написано программное обеспечение, использующее выводы ввода-вывода непо-
средственно, однако намного эффективнее будет, если интерфейсными точками будуг
устройства 12С или SPI, ибо в этом случае будет требоваться использование меньшего
количества выводов микроконтроллера для организации интерфейса.
444
Применение микроконтроллеров PIC 18
Фирма Microchip производит весьма широкий диапазон микросхем ЭСППЗУ - от
тонких 128-битных (16 байтов) до микросхем на 512 килобит (64К байт). Еще одна фир-
ма - Atmel производит устройства флэш-памяти, которые могут хранить 4 мегабита
информации (512К байт). Фирма Philips Semiconductors также производит серию по-
следовательных запоминающих устройств.
PDIP/SOIC TSSOP/MSOP * TSSOP DFN
АО Е 1 м 8 □ Vcc AOdZ 1 KJ 8 Zbvcc AO tf A1 tf 1 2 KJ 14 13 Ti VCC Ъ WP AO 1 • KJ 8 VCC
А1£ 2 X X 7 J WP Ald= 2 X 7 Zbwp NC 3 X X 12 Ъ NC A1 2 X X 7 WP
А2Е 3 ut а> 6 □ SCL A2£ 3 KJ СЯ O) 6 Zb SCL NC tf NC cf 4 5 KJ СЛ 0) 11 10 tj NC Ъ NC A2 [3 KJ (Л a> 6 SCL
VssE 4 5 □ SDA VsscT 4 5 Zb SDA A2 ci- 8 9 41 SCL Vss [4 5 SDA
vss cT ~7 8 Tj SDA
Примечание: выводы АО и А1 не подключены только в корпусах MSOP.
Рис. 10.1. Цоколевка выводов микросхем последовательных ЭСППЗУ
Микросхемы последовательных ЭСППЗУ иллюстрируются на рис. 10.1. Эти при-
боры представляют собой 8-разрядных ИС, и не занимают много места на плате. На
упомянутом рисунке показаны корпуса устройств емкостью 256К бит, однако все дру-
гие устройства имеют аналогичную цоколевку выводов. Входы А - это не входы адреса;
это входы выборки микросхемы. Они называются A-входами потому, что могут исполь-
зоваться для того, чтобы выбрать более одного последовательного ЭСППЗУ, следова-
тельно, они выбирают различные устройства.
Рис. 10.2 иллюстрирует два таких устройства, подключенных к микроконтроллеру
PIC18F1220 с использованием АО в качестве входа адреса для выбора одной или другой
микросхемы ЭСППЗУ. Активизация A-входов происходит путем подключения их на об-
щий провод либо на шину питания + 5 В. Три адресных входа позволяют подключать к
микроконтроллеру системы вплоть до восьми устройств. Однако на самом деле, по
причине ограничений, связанных с внутренней нагрузочной способностью последова-
тельных ЭСППЗУ, могут быть подключены только два устройства (см. рис. 10.2). Если
нужно подключить еще устройства, то их нужно буферизовать. В этой схеме микросхе-
ма памяти U4 выбирается, когда АО = 0, а микросхема U5 выбирается, когда АО = 1, при
этом на А1 и А2 должен быть нулевой сигнал. Вывод RB6 - это последовательное под-
ключение данных между выводами SDA на обоих микросхемах памяти и микроконтрол-
лером, а вывод RB7 подает сигнал тактовой частоты на выводы SCL обеих микросхем
памяти. Если к микроконтроллеру подключается только одна микросхема памяти, то
тогда вход АО подключается на землю. В любом случае необходим нагрузочный рези-
стор в 10 кОм, чтобы память работала на рекомендуемой частоте, равной 100 кГц.
Последовательный интерфейс, используемый микросхемами последовательного
ЭСППЗУ, во многом подобен многим другим последовательным интерфейсам, которые
уже обсуждались нами в более ранних главах. При применении PIC18F1220, должна
использоваться программа, генерирующая тактовую частоту для ЭСППЗУ, а также по-
сылающая или получающая информацию из него. ЭСППЗУ обычно функционирует на
частоте 100 кГц. Перед обсуждением скорости информационного обмена, мы сначала
рассмотрим работу ЭСППЗУ. Микросхема память отвечает на передаваемый ей байт,
который называется байтом органа управления (см. рис. 10.3). Управляющий байт со-
стоит из стартового бита, битов состояний трех адресных входов, бита чтения/записи и
бита подтверждения.
Глава 10. Вопросы повышенной сложности
445
Стартовый бит - это отрицательный фронт сигнала, выдаваемого на микросхему
памяти в момент, когда сигнал тактовой частоты находится в состоянии логической
единицы. После этого передается битовая схема 1010, а затем состояния адресных
входов, выбирающих устройство. Как только команда будет послана, за ней следует
адрес памяти. Эта последовательность битов заносит адрес в память. Второй старто-
вый импульс посылается для считывания данных. Если данные записываются в память,
то второй импульс записи не передается в память, передаются только данные. Сигнал
АСК принимается после передачи или считывания каждого байта из памяти, однако
этот сигнал учитывается только после выполнения операции записи в память. Память
требует времени для того, чтобы завершить операцию записи. После выполнения опе-
рации записи в память, сигнал АСК контролируется для того, чтобы убеди 1ься в том,
что данные записаны в память. Если подтверждение не получено, то программа должна
ожидать до тех пор, пока оно не будет получено от памяти. Рис. 10.4 иллюстрирует об-
мен данными, который происходит между последовательным ЭСППЗУ и микроконтрол-
лером. При использовании 256-килобитного устройства, обсуждаемого здесь, адрес
будет 15-разрядным (32 кбайт). При этом данные будут адресоваться двумя байтами, а
бит А15 не будет использоваться. Первый байт адреса содержит биты адреса А15-А8, а
второй байт адреса - биты адреса А7-А0.
Рис. 10.2. Пара микросхем последовательного ЭСППЗУ,
подключенных к микроконтроллеру PIC18F1220
446
Применение микроконтроллеров PIC 18
Страничное считывание или запись также возможны при выполнении чтения или
записи более одного байта. Адрес памяти, который автоматически инкрементируется
после каждого чтения или записи, позволяет передавать много байтов без повторной
передачи адреса. Страница этой памяти по определению - это 64 байта. Страницы на-
чинаются с адресов, соответствующих нулевым значениям самых правых 6 битов адре-
са. Так, страница 0 расположена в диапазоне адресов 0x0000-0x003F, страница 1 - в
диапазоне адресов 0x0040-0x007F и т.д. При считывании более одного байта, адрес
переключается на начало страницы в конце страницы. Например, если памяти послан
адрес 0x007F и считываются 2 байта, то первым байтом будет содержимое ячейки по
Запись адреса
S 1 0 1 0 А 2 А 1 А 0 0 А С К X А 1 4 А 1 3 А 1 2 А 1 1 А 1 0 А 9 А 8 А С К А 7 А 6 А 5 А 4 А 3 А 2 А 1 А 0 А С К
за которым следует считываемый байт
S 1 0 1 0 А 2 А 1 А 0 1 А С к D 7 D 6 D 5 D 4 D 3 D 2 D I D 0 А С К Р
или за ко торым следует записываемый байт
D 7 D 6 D 5 D 4 D 3 D 2 D 1 D 0 А С К Р
S = старт-бит
Р = стоп-биг
АСК=подтверждение
Рис. 10.4. Сигналы на считывание или запись последовательного ЭСППЗУ
Программные функции, требуемые для того, чтобы читать или записать байты в
память, показаны в примере 10.1. Функции, которые читают или записывают блок па-
мяти, в данном программном примере не приводятся. В этой программе операторы
#define используются с тем, чтобы выводы порта, используемые для связи с памятью,
можно было легко изменять. Здесь RB7 используется для сигнала SCK и RB6 использу-
Глава 10. Вопросы повышенной сложности
447
ется для сигнала SDA. Для того, чтобы интерфейс функционировал правильно, направ-
ление переноса для сигнала SDA изменяется на вход, когда память посылает сигнал
логической единицы. Это выполняется потому, электронная схема памяти требует ис-
пользования резистора нагрузки в 10 кОм на подключении SDA с тем, чтобы правильно
выполнялась запись логической единицы. При переключении направления штырька
RB6 на вход при передаче логической единицы на вывод SDA, схема будет соответст-
вовать требованиям устройства памяти. Когда упомянутый вывод включен как выход, на
SDA устанавливается сигнал логического нуля; когда же он включен как вход, SDA ста-
новится штырьком ввода - вывода.
Пример 10.1
// ***************** константы
#define SCL PORTBbits.RB7 // RB7 = SCL
#define SDA PORTBbits.RB6 // RB6 = SDA
#define SDA TRIS TRISBbits.TRISB6
//*************** функции работы с последовательным ЭСППЗУ
void { } SendStart SDA_TRIS SCL = 1; SDA_TRIS SCL = 0; (void) = 1; = 0; // посылка старт-бита // SDA = 1 // SCL = 1
// // SDA = 0 SCL = 0
void SendStop (void) // передача стоп-бита
i } SCL = 0; SDA_TRIS SCL = 1; SDA_TRIS = 0; = 1; // SCL = 0 // SDA = 0 // SCL = 1 // SDA = 1
char SendSM (char data) // передача байта
char а, Ь, с;
с = for 1 0;
(a = 0; a , 8; a++)
t SCL = 0; // SCL = 0
if ((data & 0x80) == 0x80) // самый левый информационный бит
SDA_TRIS = 1; else // SDA = 1
SDAJIRIS = 0; // SDA = 0
data ,,= 1; // левый сдвиг данных
SCL = 1; // SCL = 1
J SCL = 0; // SCL = 0
SDA, _TRIS = 1;
scl’ = 1; // SCL = 1
if (SDA == 1) c = 1 ; // контроль SDA на ACK
SCL = 0; // SCL = 0
return c; // возврат ACK
448
Применение микроконтроллеров PIC 18
char ReadSM (void) // чтение байта
char a;
char b = 0;
SDA_TR1S = I; // установ SDA для чтения
SCL = 0; for (a = 0; r a , 8; a++) // SCL = 0
i b , , = 1; // левый сдвиг для следующего бита
SCL = 1; // SCL = 1
if (SDA == 1)
b 1=1; // добавление SDA, если 1
SCL I = 0; // SCL = 0
1 SDA__TR1S - 0; // SDA = 0
return b; // возврат извлеченных данных
void Ack (char control) // проверка ACK
{
char a = 1;
do
(
SendStart() ;
a = SendSM (control); // вывод управляющего байта
)
while (a == 1); #
SendStop ();
// Read a byte from memory
// address is 0x0000 -- OxFFFF
char ReadByte (int address)
{
char a = 0;
SDA = 0; // установ SDA = 0
SendStart ();
if ((address & 0x8000) == 0x8000)
a = 2 ;
else
a = 0;
SendSM (OxAO + a); // команда (запись адреса)
SendSM (address >> 8);
SendSM (address);
SendStart ();
SendSM (OxAl | a); // команда (чтение данных)
a = ReadSM ();
SendStop ();
return (a);
)
void WriteByte (int address, char data)
{
char a = 0;
SDA = 0; 11 установ SDA = 0
SendStart ();
Глава 10. Вопросы повышенной сложности
449
if ((address & 0x8000) == 0x8000)
а = 2;
SendSM (0хА0 | а);
SendSM (address >> 8);
SendSM (address);
SendSM (data);
SendStop ();
Ack (OxAO | a); // ожидание ACK
j
Приложение, использующее дополнительную память
Теперь, когда мы можем легко добавлять дополнительное пространство памяти к
микроконтроллеру, мы нуждаемся в приложении, которое использовало бы эту память.
Предположим, что нам необходима система, предназначенная для регистрации и со-
хранения данных с целью доступа к ним в будущем. Данные, которые регистрируется,
предназначены для системы управления товарно-материальными ценностями в гас-
трономе. Модуль, разработанный здесь, - это калькуляторо-подобное устройство, ко-
торое находится у кассира. Кассир сканирует код цены единицы товара (код UPC) на
покупке оптическим считывателем и вводит количество единиц товара в устройство
контроля товарно-материальных ценностей. Количество единиц товара и соответст-
вующие UPC-коды позднее загружаются в ПК для обновления базы данных товарно-
материальных ценностей. Если бы наше общество было абсолютно честным, то не было
бы столь уж большой потребности в ведении сложного учета товаров. Однако некото-
рые оценки указывают на потери вплоть до 10% товара в гастрономических магазинах.
Это означает, что вплоть до 10% товара никогда не оплачивались через кассу. Спроек-
тированная здесь система, по крайней мере, позволяет владельцу магазина опреде-
лить, что, собственно, пропадает и переместить наиболее часто похищаемые товары в
более оживленные места торгового зала.
В качестве устройства ввода данных, данная система нуждается во вспомога-
тельной клавиатуре для ввода количества единиц товара и оптическом считывателе для
сканирования стоимости. Она также нуждается в связи с ПК с тем, чтобы количество
единиц товара могло быть передано в ПК для контроля товарно-материальных ценно-
стей. Небольшой экран используется для того, чтобы отобразить UPC-код и количество
единиц товара, введенное кассиром. Устройство подобного типа не имеет достаточно-
го объема внутреннего ЭСППЗУ с тем, чтобы сохранять позиции, которые были проска-
нированы на протяжении 8-часового рабочего дня, так что необходима дополнительная
память. При использовании одной микросхемы последовательного ЭСППЗУ 24АА256
добавляется 32 килобайт памяти для хранения кодов позиций и количества единиц то-
вара. Является ли этот объем памяти достаточным? Предположим, что кассир может
сканировать, а затем считать единицы товара со скоростью 1 вид товара в минуту. За
8-часовый промежуток времени, работая без каких-либо перерывов, кассир может
учесть 480 видов товаров. UPC-код является либо 6-разрядным, либо 10-разрядным
кодом. Предположим, что все единицы товара имеют 10-разрядный UPC-код. Для хра-
нения всех кодов этом случае потребуется память объемом 4800 байт. Дополнительные
480 байтов, необходимы для сохранения количеств единиц товара, если предположить,
что это количество будет ограничено 255 единицами. Память объемом в 32 килобайта
достаточно велика для того, чтобы функционировать без выгрузки кодов и количеств
единиц товара в течении трех рабочих смен плюс еще имеется хороший запас для
чрезвычайно быстрых работников.
450
Применение микроконтроллеров PIC18
Штрих-коды уже обсуждались в главе 8 в связи с использованием штрих-кодов
кодировки “Код 128”, которая распространена в производственных системах управле-
ния складскими запасами. Штрих-коды, используемые в случае учета товаров, прода-
ваемых в гастрономах, являются другими. Они используют либо формат UPC-А, либо
формат UPC-Е. Версия формата UPC-Е обычно используется для более мелких единиц
товара. Формат UPC-А -это 10-разрядный код, а формат UPC-E - 6-разрядный код.
Рис. 10.5 приводит примеры обоих форматов кодов. Основное различие между кодом-
128 и форматами UPC-А и UPC-E - это то, что UPC-коды позволяют отображать только
числовые данные, в то время как код -128 обеспечивает возможность отображения как
алфавитных, так и числовых данных.
В форматах UPC-А и UPC-Е число всегда окружается битами синхронизации 101
(bsb, где b - черная полоса, a s - белое пространство). В формате UPC-А первый код,
который появляется справа от крайних левых битов синхронизации - это код системы
счисления (NS), за которым следует 5-разрядный код изготовителя. Справа от кода
изготовителя располагаются средние биты синхронизации, которые имеют структуру
0101 (sbsb). Справа от средней битовой структуры синхронизации располагается 5-
разрядный код продукта. И, наконец, слева от самых правый битов синхронизации на-
ходится контрольный разряд. Для получения более ясного представления об описан-
ной структуре кода, обращаемся к рис. 10.6. Код UPC-Е является другим, потому что он
содержит подразумеваемое значение NS = 0, за которым следует 6-разрядный код,
содержащий как код изготовителя, так и код продукта. После этого кода контрольный
разряд не следует. Этот формат кода также иллюстрируется на рис. 10.6. Формат
UPC-А использует кодировку ОООООО, за которой следует RRRRRR для отображения
12-разрядных чисел (О = нечетное, R = правый код и Е = четное, как показано в
табл. 10.1). Формат UPC-Е использует кодировку ЕЕЕООО из таблицы 10.1 для кодиро-
вания 6 цифр. В формате UPC-Е правое поле синхронизации содержит 0101 (sbsb)
вместо 101 (bsb), как это имеет место в формате UPC-A.
Преобразование здесь выполняется подобно преобразованию кода-128 в главе
8. Различие заключается в том, что имеется 6 поисковых таблиц - 3 прямых и 3 обрат-
ных для кодов UPC-А и UPC-Е. Как в главе 8, функция прерывания по изменению со-
стояния вместе с таймером используются для того, чтобы измерить ширину каждого
импульса.
Рис. 10.7 иллюстрирует полную схему электрическую этой системы. Система ис-
пользует программное обеспечение UART для связи с ПК схему управления на микро-
схеме DS-275. Оптический считыватель подключен к системе через программный по-
следовательный интерфейс, который использует функцию прерывания по изменению
состояния микроконтроллера. Внешняя память представляет собой одну микросхему
на 32 килобайта, которая хранить данные об операциях, если система используется для
регистрации и подсчета позиций товара в магазине. В конце рабочего дня содержание
ЭСППЗУ системы передается в ПК через последовательный интерфейс. Пример 10.2
показывает полную программу для этой системы.
Глава 10. Вопросы повышенной сложности
451
UPC-E
Рис. 10.5. Штрих коды цены единицы товара (UPC)
452
Применение микроконтроллеров PIC 18
UPC-A
Сигнал TIT
UPC-E
llllllllllll
2 8 8 1 9 2
Таблица 10.1. Кодировка UPC-A и UPC-E.
Цифра Нечет./Левый код Четный код Правый код
0 sssbbsb sbssbbb bbbssbs
1 ssbbssb sbbssbb bbssbbs
2 ssbssbb ssbbsbb bbsbbss
3 sbbbbsb sbssssb bssssbs
4 sbsssbb ssbbbsb bsbbbss
5 sbbsssb sbbbssb bssbbbs
6 sbsbbbb ssssbsb bsbssss
7 sbbbsbb ssbsssb bsssbss
8 sbbsbbb sssbssb bssbsss
9 sssbsbb ssbsbbb bbbsbss
контрастность
ЮК
PIC18F1320
U1
2
3
6
5
8
9
О
#
R1
10K
C2
0.1 UF
16
J5
gRBO
>RB1
RB2
RB3
RB4
RB5
RAO
RA1
RA2
RA3
RA4
#MCLR
OSC1 KRB6
OSC2 > RB7
8
9
17
18
10
11
12.
13
D7 VDD
D6
D5
D4
E
VEE
R/W VSS
RS
1 X 20 LCD
Оптический
P1
DS275 U3
RXIN
TXIN
VDRV
RXOUT
TXOUT
5.
C1____
1.0 uF
разъем DB9
C4
0.1 uF
« C3
0.1 uF
считыватель
R2
10K
2
3
U2 24AA256
AO
A1
A2
SDA
>SCL
6
WP
vcc
Глава Ю. Вопросы повышенной сложности
Рис. 10.7. Система управления товарно-материальными ценностями
454
Применение микроконтроллеров PIC 18
Пример 10.2
".'истема управления товарно-материальными запасами"
(( I нс I ude <d. । me rs . h>
(ItncJude <delays.h>
((include <sw uart.h>
/* Установка битов конфигурации
* установка внутренней синхронизации
* выключение сторожевого таймера
* выключение низковольтного программирования
* отключение сброса по частичной потере питания
* разрешение общего сброса
*/
((pragma config
((pragma config
((pragma config
((pragma config
OSC = INTIO2
WDT = OFF
LVP = OFF
MCLRE = ON
// program memory data
rom near char strl[]
rom near char str2[]
rom near char str3[]
"Uploading to the PC.";
"Ready to swipe code.";
" Ct=
rom near char odd[] =
0Ы0010000,
ObOlOlOlOO,
ObOlOOOlOl,
ObOOllOOOO,
ObOOOOlOOl,
ObOOOllOOO,
ObOOOOOOll,
ObOOlOOOOl,
ObOOOlOOlO,
0Ы0000001
// двоичные данные Obxxxxxxxx
rom near char oddbw[]
{
ObOOOOOllO,
ObOOOlOlOl,
ObOlOlOOOl,
ObOOOOllOO,
ObOllOOOOO,
ObOOlOOlOO,
Obll000000,
ObOlOOlOOO,
0Ы0000100,
ObOlOOOOlO
Глава 10. Вопросы повышенной сложности
455
rom near char even[] =
ObOOOOOllO,
ObOOOlOlOl,
ObOlOlOOOl,
ObOOOOllOO,
ObOllOOOOO,
ObOOlOOlOO,
0Ы1000000,
ObOlOOlOOO,
0Ы0000100,
ObOlOOOOlO
rom near char evenbw[] =
0Ы0010000,
ObOlOlOlOO,
ObOlOOOlOl,
ObOOllOOOO,
ObOOOOlOOl,
ObOOOllOOO,
ObOOOOOOll,
ObOOlOOOOl,
ObOOOlOOlO,
OblOOOOOOl
} ;
rom near char right[] =
{
0Ы0010000,
ObOlOlOlOO,
ObOlOOOlOl,
ObOOllOOOO,
ObOOOOlOOl,
ObOOOllOOO,
ObOOOOOOll,
ObOOlOOOOl,
ObOOOlOOlO,
OblOOOOOOl
};
rom near char rightbwf] =
{
ObOOOOOllO,
ObOOOlOlOl,
ObOlOlOOOl,
ObOOOOllOO,
ObOllOOOOO,
ObOOlOOlOO,
0Ы1000000,
ObOlOOlOOO,
0Ы0000100,
ObOlOOOOlO
);
rom near char lookupKeyf] =
456
Применение микроконтроллеров PIC 18
1, 4, 7, 10, // левый столбец
2, 5, 8, 0, // средний столбец
3, 6, 9, 11 // правый столбец
};
/ ' Определение адресов EEPROM
#define addrl 0
ildei ine addrh 1
// переменные в памяти данных
char goodUPC;
char timeOut;
char pulse;
int halfPulseWidth;
char UPC[14];
char UPCptr;
char type;
#pragma interrupt MyHighlnt save=PROD
#pragma code high_vector=0x08 // high_vector по адресу 0x0008
void high_vector (void) // высокоприоритетный вектор
{
_asm GOTO MyHighlnt _endasm // переход на подпрограмму обслуживания
//высокоприоритетного прерывания
}
ttpragma code
// считывания ячейки ЭСППЗУ данных по адресу
char eeRead (char address)
(
EECONlbits.EEPGD = 0;
EEADR = address;
EECONlbits.RD = 1;
return EEDATA;
}
11 запись ячейки ЭСППЗУ данных по адресу с данными
void eeWrite (char address, char data)
{ char temp;
temp = INTCONbits.GIEH;
INTCONbits.GIEH = 0;
EECONlbits.EEPGD = 0;
EECONlbits.WREN = 1;
EEADR = address;
EEDATA = data;
EECON2 = 0x55;
EECON2 = OxAA;
EECONlbits,WR = 1;
while (PIR2bits.EEIF == 0);
PIR2bits.EEIF = 0;
EECONlbits.WREN = 0;
if (temp == 1)
INTCONbits.GIEH = 1;
Глава 10. Вопросы повышенной сложности
457
// Передача байта данных на ЖК-индикатор с RS = rs
#define RS PORTAbits.OSC1
tfdefine E PORTAbits.RAO
void SendLCDdata (char data, char rs)
{
PORTB = (data >: > 4) | 0x80 ; // передача левого полубайта
RS = 1; // установка RS
E = 1; // импульс E
E = 0;
DelaylOTCYx (4); // ожидание 40 мкс
PORTB = (data & OxOF) I 0x80; // передача правого полубайта
RS = 1; // установка RS
E = 1; // импульс Е
E = 0;
DelaylOTCYx (4); // ожидание 40 мкс
// Инициализация ЖК-индикатора
void
InitLCD (void) // инициализация ЖКИ
DelaylKTCYx (20); // ожидание 20 мс
SendLCDdata (0x20, 0) ; // передача 0x20
DelaylKTCYx (6); // ожидание 6 мс
SendLCDdata (0x20, 0) ; // передача 0x20
DelaylOTCYx (10); // ожидание 100 мкс
SendLCDdata (0x20, 0) ; // передача 0x20
SendLCDdata (0x2 8, 0) ; // передача 0x28
SendLCDdata (0x01, 0); // передача 0x01
DelaylKTCYx (2); // ожидание 2 мс
SendLCDdata (OxOC, 0); // передача ОхОС
SendLCDdata (0x06, 0); u передача 0x06
// Отображение в заданной позиции строки символов из памяти программ (str)
void DisplayStringPgm (char position, rom char *str)
{
char ptr = 0;
SendLCDdata (position, 0); // передача позиции
while (str[ptr] != 0)
SendLCDdata(str[ptr++], 1); // передача символа
char lookup (rom char* table, char temp)
{
char a;
for (a =0; a < 10; a++)
if (table [a] == temp)
break;
return a;
void Abort (void)
458
Применение микроконтроллеров PIC 18
char temp = UPC[0];
char a;
char count = 0;
CloseTimerO ();
WriteTimerO (0);
if (UPCptr > 5 && UPCptr < 7) // обычный UPC-E
if (Lype 1) // обратный UPC-E
(
for (count = 0; count < 3; count++)
UPC[count] = lookup(oddbw, UPC[count]);
for (count = 3; count < 6; count++)
UPC[count] = lookup(evenbw, UPC[count]);
for (count = 0; count < 3; count++)
(
temp = UPC[5 - count];
UPC[5 - count] = UPC[count];
UPC[count] = temp;
}
goodUPC = 1;
}
else // прямой UPC-E
(
for (count = 0; count < 3; count++)
UPC[count] = lookup(even, UPC[countJ);
for (count = 3; count < 6; count++)
UPC[count] = lookup(odd, UPC [count]);
goodUPC = 1;
)
)
else if (UPCptr > 7)
<
for (a = 0; a < 4; a++)
{
count += temp & 3;
temp »= 2;
}
if ((temp & 1) == 0)
( // обратный UPC-A
for (count = 0; count < 6; count++)
UPC[count] = lookup(rightbw, UPC[count]);
for (count = 7; count < 13; count++)
UPC[count - 1] = lookup(oddbw, UPC[count]);
for (count = 0; count < 6; count++)
{
temp = UPC[11 - count];
UPC[11 - count] = UPC[count];
UPC[count] = temp;
)
goodUPC = 2;
)
else
( //обычный UPC-A
for (count = 0; count < 6; count++)
UPC[count] = lookup(odd, UPC[count]);
for (count = 7; count < 13; count++)
UPC[count - 1] = lookup(right, UPC[countj);
Глава 10. Вопросы повышенной сложности
459
goodUPC = 2;
}
}
void MyHighlnt (void)
{
int temp;
if (PIRlbits.TMR1IF == 1)
{
PIRlbits.TMR1IF = 0;
WriteTimerl(-12500 );
if (timeOut != 0)
timeOut--;
if (timeOut -= 0)
Abort();
}
}
else if (INTCONbits.RBIF == 1 )
{
temp = PORTB; // необходимо считать PORTB для
// сброса изменения
INTCONbits.RBIF = 0; // сброс прерывания
if (ReadTimerO() == 0) //инициализация
(
OpenTimerO(TIMER_INT_OFF &
T0_16BIT &
TO_SOURCE_INT &
T0_PS_l_64) ; // период 64 мкс
WriteTimerO (1);
timeOut = 3;
pulse = UPCptr = type = 0;
)
else if (pulse == 0)
(
halfPulseWidth = ReadTimerO() I 2;
WriteTimerO (1);
pulse++;
timeOut = 3;
WriteTimerO (1) ;
}
else if (pulse < 3)
{
halfPulseWidth - (halfPulseWidth + ReadTimerO() / 2 ) / 2;
WriteTimerO (1);
pulse++;
timeOut = 3;
}
else
(
temp = ReadTimerO ();
WriteTimerO (1) ;
if (temp <= halfPulseWidth * 3)
temp = 0;
else if (temp <= halfPulseWidth * 5)
temp = 1;
else if (temp <= halfPulseWidth * 7)
460
Применение микроконтроллеров PIC 18
t emp = 2;
else
temp = 3;
UPCfUPCptr] = UPCfUPCptr] « 2 | temp;
pulse++;
timeOut = 3;
if (pulse % 4 == 3)
{
if (pulse == 7)
(
if ((UPCfUPCptr] & 0x3F) == 0) // UPC-E обратный
(
type = 1;
pulse -= 3;
UPCfUPCptr] >= 6;
UPCptr--;
}
}
UPCptr++;
}
}
II ***************** константы
#define SCL PORTBbits.RB6 #define SDA PORTAbits.OSC1 #define SDA_TRIS TRISAbits.TRISA7 // RB6 = SCL // OSC1 = SDA
//*************** фуНКцИИ работы с последовательным ЭСППЗУ **********
void SendStart (void) ( // передача стартового бита
SDA_TRIS = 1; // SDA = 1
SCL = 1; // SCL = 1
SDA_TRIS = 0; // SDA = 0
SCL = 0; } // SCL = 0
void SendStop (void) // передача стоп-бита
SCL = 0; // SCL = 0
SDA—TRIS = 0; // SDA = 0
SCL = 1; // SCL = 1
SDA TRIS = 1; ) // SDA = 1
char SendSM (char data) ( char a, b, c; c = 0; for (a = 0; a < 8; a++) i // передача байта
i SCL = 0; // SCL = 0
if ((data & 0x80) == 0x80) // самый левый бит данных
SDA_TRIS = 1; // SDA = 1
else
Глава 10. Вопросы повышенной сложности
461
SDA_TRIS = 0; // SDA = 0
data <<= 1; // левый сдвиг данных
SCL = 1; // SCL = 1
j SCL = 0; // SCL = 0
SDA_TRIS = 1; SCL = 1; // SCL = 1
if (SDA == 1) // проверка SDA на ACK
c = 1 ;
SCL = 0; // SCL = 0
return c; // возврат ACK
char ReadSM (void) // считывание байта
char a; char b = 0;
SDA_TRIS = 1; // установка SDA на считывание
SCL = 0; for (a = 0; a < 8; a++) / // SCL = 0
t b «= 1; // левый сдвиг для следующего бита
SCL = 1; if (SDA == 1) // SCL = 1
b |= 1; // добавление SDA, если 1
SCL = 0; // SCL = 0
) SDA_TRIS = 0; // SDA = 0
return b; ) // возврат извлеченных данных
void Ack (char control) f // проверка АСК
t char a = 1; do
SendStart ();
а = SendSM ( control); // выдача управляющего байта
1
while (а == 1) ;
SendStop ();
)
// считывание байта из памяти
// адреса в диапазоне 0x0000 -- OxFFFF
char ReadByte (int address)
{
char a = 0;
SDA = 0; // установка SDA = 0
SendStart();
if ((address & 0x8000) == 0x8000)
a = 2;
else
a = 0;
SendSM (OxAO + a); // команда (адрес записи)
SendSM (address » 8);
SendSM (address);
462
Применение микроконтроллеров PIC 18
SendStart ();
SendSM (OxAl | a);
a = ReadSM ();
SendStop ();
return (a);
// команда (чтение данных)
void WriteByte (int address,
char a = 0;
SDA = 0;
SendStart ();
if ((address & 0x8000)
a = 2;
SendSM (OxAO | a);
SendSM (address » 8);
SendSM (address);
SendSM (data);
SendStop ();
Ack (OxAO | a);
}
char data)
// установка SDA = 0
== 0x8000)
#define KEYPORT PORTA
#define DELAY 15
//ожидание ACK
// изменить для соответствия
// фактическому порту
// изменить в случае необходимости для
// временной задержки
void Switch (char bit)
(
do // ожидание освобождения
(
while ((KEYPORT & bit) != bit);
DelaylKTCYx(DELAY);
}whiien ((KEYPORT & bit) != bit);
do /I ожидание нажатия
<
while ((KEYPORT & DelaylKTCYx(DELAY) bit) == bit) ;
(while ((KEYPORT & bit) i == bit)
unsigned char Key (void)
t #define MASK OxlE // установка маски
#define ROWS 4 int a; // задание количества строк
unsigned char keyCode; keyCode = 0; // очистка порта В и keyCode
PORTB = PORTB & 0xF8; Switch (MASK); // компенсация дребезга контактов
// и ожидание нажатия какой-либо клавиши
PORTB = PORTB & OxFE; // выбор самого левого столбца
while ((PORTA & MASK) == = MASK) // пока никакой ключ
// не найден
{
PORTB = (PORTB « 1) | 1; // берем следующий столбец
keyCode += ROWS; // добавление строки к коду клавиши
)
for (а = 1; а != 0; а <<= 1)
Глава 10. Вопросы повышенной сложности
463
{ // нахождение строки
if ((PORTA & а) 0)
break;
keyCode++;
}
return lookupKey[keyCode]; // нахождение корректного
// кода клавиши
int GetCount (void)
{
char number[3];
int retval = 0;
char count = 0;
char temp Key();
while (temp != 11)
if (temp == 10 && count != 0)
(
count--;
SendLCDdata (0x90 I count + 1, 0);
SendLCDdata ( ' ' , 1);
SendLCDdata (0x90 I count + 1, 0);
}
else
{
number[count] = temp;
if (count != 2)
count++;
}
temp = Key();
}
for (temp = 0; temp < count; temp++)
retval = retval * 10 + number[temp];
return retval;
}
void SendPC (void)
<
int addr;
int addrl = 0;
addr = eeRead (addrl);
addr = (int) eeRead(addrh) << 8;
while (ReadUART() != 1);
WriteUART(1);
while (addr != addrl)
WriteUART(ReadByte(addrl++));
eeWrite (addrl, 0);
eeWrite (addrh, 0);
)
void GetUPC (void)
<
int addr;
int count;
DisplayStringPgm (0x80, str3);
SendLCDdata (0x80, 0);
for (count = 0; count < 6; count++)
SendLCDdata ( UPC[count] + 0x30, 1);
464
Применение микроконтроллеров PIC 18
if (goodUPC == 2)
{
SendLCDdata ('-', 1);
for (count = 6; count < 12; count++)
SendLCDdata (UPC[count] + 0x30, 1);
}
count = GetCount();
if (count != 0)
addr eeRead(addrl);
addr = (int) eeRead(addrh) « 8;
if (goodUPC = 1)
(
WriteByte (addr++, 1);
for (count = 0; count < 6; count++)
WriteByte (addr++, UPC[count]);
)
else
{
WriteByte (addr++, '2);
for (count = 0; count < 12; count++)
WriteByte(addr++, UPC[count]);
}
WriteByte (addr++, count);
WriteByte (addr++, count » 8);
eeWrite (addrl, addr);
eeWrite (addrh, addr » 8) ;
}
goodUPC = 0;
DisplayStringPgm (0x80, str2);
void DelayTXBitUART (void)
{
DelaylOTCYx (9);
DelaylTCY ();
DelaylTCY ();
DelaylTCY ();
void DelayRXHalfBitUART (void)
(
DelaylOTCYx (4);
DelaylTCY ();
DelaylTCY ();
DelaylTCY();
DelaylTCY ();
void DelayRXBitUART (void)
(
DelaylOTCYx(9);
DelaylTCY();
void main (void)
(
OSCCON = 0x62;
// внутренняя тактовая частота 4 МГц
Глава 10. Вопросы повышенной сложности
465
ADCON1 = OxOF; // цифровой ввод-вывод
TRISA = 0х7Е;
TRISB = ОхАО;
PORTA = 0x8 0;
PORTB = ОхАО;
InitLCD();
goodUPC = timeOut = 0;
WriteTimerO (0);
OpenTimerl (TIMER_INT_ON & // каждые 8 мкс
T1_16BIT_RW &
T1_SOURCE_INT &
T1_PS_1_8);
WriteTimerl (-12500);
OpenUART() ;
INTCONbits.RBIE = 1;
PIElbits.TMR1IE = 1;
INTCONbits.GIEH = 1;
if (eeRead(addrl) == OxFF && eeRead(addrh) == OxFF)
{
eeWrite (addrl, 0);
eeWrite (addrh, 0) ;
}
if ((PORTA & 6) == 0 &&
eeRead--(addrl) != 0 && eeRead(addrh) 1= 0 )
(
DisplayStringPgm (0x80, strl);
SendPC();
}
DisplayStringPgm (0x80, str2);
while (1)
if (goodUPC != 0)
GetUPC () ;
}
}
10.2. Загрузочный блок
Микроконтроллеры семейства PIC18 содержат блок начальной загрузки, который
позволяет микроконтроллеру самому перепрограммироваться в рамках системы. Это
свойство очень полезно в тех системах, которые требуют применения программных
обновлений после сдачи системы в эксплуатацию. Иногда это называют флэшингом
системы или самопрограммированием. Если вы когда-либо приобретали материнскую
плату для компьютера, вы, вероятно, уже знакомы с флэшингом системы при помощи
BIOS.
Программа начальной загрузки
Блок начальной загрузки - это область памяти объемом 512 байт, которая начи-
нается с адреса 0x0000 и заканчивается адресом 0x1 FF. (Некоторые микроконтролле-
ры семейства PIC18 имеют большую область блока начальной загрузки, так что адрес
конца блока может быть отличным от указанного). Блок начальной загрузки содержит
защищенный код, который не может быть перезаписан, когда устройство программи-
руется. Код блока начальной загрузки, который загружает новую программу в свобод-
466
Применение микроконтроллеров PIC 18
ную часть памяти, часто называют программой начальной загрузки или начальным за-
грузчиком. Программа начальной загрузки загружает, когда это требуется, новую опе-
рационную систему в устройство. Таким образом устройство самопрограммируется.
Для того, чтобы начальный загрузчик функционировал, он должно иметь последова-
тельное соединение с внешним миром с тем, чтобы в случае необходимости новая про-
грамма могла быть загружена в микроконтроллер. Существенной частью программы
начальной загрузки является программное обеспечение, которое управляет упомяну-
тым последовательным интерфейсом. Рис. 10.8 показывает блок начальной загрузки,
размещенный в памяти программ системы. Выбор микроконтроллера для проекта оп-
ределяет общий объем памяти, но во всех случаях, по крайней мере первые 512 байтов
памяти резервируются под блок начальной загрузки.
0x3FFF
Остальная часть
памяти программ
0x0200
OxOlFF
Блок начальной
загрузки
0x0000
Примечание: верхний адрес памяти в устройствах семейства PIC18 изменяется.
Рис. 10.8. Карта памяти, иллюстрирующая размещение блока начальной загрузки
Блок начальной загрузки находится в защищенной области памяти, - это означа-
ет, что он не перезаписывается при программировании устройства. Программирова-
ние внутренней памяти программ подобно программированию внутреннего ЭСППЗУ
данных, которое обсуждалось в главе 6. Основное различие между ЭСППЗУ данных и
флэш-памятью программ заключается в том, что флэш-память программ защищена
поблочно, при этом первый ее блок называется блоком начальной загрузки. ЭСППЗУ
данных не имеет такого механизма защиты. Размеры и число других защищенных бло-
ков определены членом семейства микроконтроллера. Так, например, PIC18F1220
имеет блок начальной загрузки размером 512 байтов и два других защищенных блока,
которые размещены по адресам 0x0200-0x07FF и 0x0800-0x0FFF. Два блока помимо
блока начальной загрузки называются блоком 0 и блоком 1 соответственно. Другим
Глава 10. Вопросы повышенной сложности
467
примером может быть PIC18F4550, который имеет блок начальной загрузки объемом 2
килобайта (0x0000-0x07FF) и четыре других блока по адресам 0x0800-0x1 FFF (блок 0),
0x2000-0x3FFF (блок 1), 0x4000-0x5FFF (блок 2) и 0x6000-0x7FFF (блок 3). Обращайтесь
к спецификации технических данных на микроконтроллер, выбранный для использова-
ния в проекте, с тем, чтобы получить информацию о точном месторасположении и раз-
мерах блоков памяти программ. Эти блоки защищены через использование битов,
размещенных в регистрах конфигурации, включая блок начальной загрузки. Пример
10.3 показывает оболочку программы на языке С, которая работает как пространство
блока начальной загрузки. Эта программа использует последнюю ячейку ЭСППЗУ дан-
ных для того, чтобы определить, был ли выполнен обычный сброс, или же происходит
начальная загрузка памяти программ, начиная с адреса 0x0200. Оператор #pragma
code MainCode = 0x0200 устанавливает адреса вектора прерывания и вектора запуска
программы. Этот образец программы подходит для использования в любых микрокон-
троллерах семейства PIC18 при условии, что адрес блока MainCode будет изменен так,
чтобы соответствовать карте памяти выбранного микроконтроллера. Например, для
PIC18F4550 изменение будет носить следующий характер: #pragma code MainCode =
0x0800.
Пример 10.3
/*
* Это пример загрузочного блока
*/
^include <pl8cxxx.h>
/* Установка битов конфигурации
* • установка внутренней синхронизации
* -- выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
*/
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
// Define EEPROM addresses
#define bootcontrol OxFF
void MyHighlnt (void);
void MyLowInt (void);
#pragma interrupt MyHighlnt
#pragma code high_vector=0x08
void high_vector (void)
_asm GOTO MyHighlnt _endasm
}
#pragma interruptlow MyLowInt
#pragma code low_vector=0xl8
// прототипы
save=PROD
// high_vector по адресу 0x0008
// высокоприоритетный вектор
// переход нак подпрограмму обслуживания
// высокоприоритетный прерываний
// MyLowInt - это прерывание
// low_vector - это вектор по адресу 0x18
468
Применение микроконтроллеров PIC 18
void low_vector (void)
{
asm GOTO MyLowInt _endasm
}
#pragma code BootBlock
void NormalReset (void);
void main (void)
(
EECONlbits.EEPGD = 0; // проверка загрузочного кон
трольного байта
EEADR = bootcontrol;
EECONlbits.RD = 1;
if (EEDATA != OxFF) // отработать нормальный сброс
{
_asm GOTO NormalReset _endasm
)
// сюда переходит программа начальной загрузки
_asm GOTO NormalReset _endasm
)
#pragma code Main=0x0200
// не модифицируйте ничего от MyHighlnt до NormalReset
void Highlnt (void); // прототипы
void Lowlnt (void);
void MyHighlnt (void) // новый фиксированный вектор
// высокоприоритетного прерывания
{
_asm GOTO Highlnt _endasm
}
void MyLowInt (void) // новый фиксированный вектор
// низкоприоритетного прерывания
(
_asm GOTO Lowlnt _endasm
)
void NormalReset (void) 11 новый фиксированный вектор сброса
{
)
void Highlnt (void)
{
}
void Lowlnt (void)
{
)
Запись во флэш-память программ
Для выполнения записи во флэш-память используется практически ю же самое
программное обеспечение, которое анализировалось в главе 6 для случая записи дан-
ных в ЭСППЗУ данных. Основное отличие заключается в том, что блоки в памяти про-
грамм должны быть разблокированы для записи в них с использованием бита СР (за-
Глава 10. Вопросы повышенной сложности
469
щша кода), бита WRT (защита от записи) и бита EBTR (табличное считывание внешнего
блока). Эти биты защиты кодов размещены в регистре конфигурации по адресу
0x300008. Эта ячейка записывается точно так же, как другие ячейки памяти программ.
Биты защиты от записи размещены в регистре конфигурации по адресу ОхЗООООА а
биты EBTR - в ячейке по адресу ОхЗООООС. Это справедливо для микроконтроллера
PIC18F1220. Другие версии микроконтроллеров используют также используют эти
ячейки, а некоторые используют и другие ячейки. Обращайтесь к спецификации техни-
ческих данных на микроконтроллер, выбранный для использования в проекте.
Программа, показанная в примере 10.4, иллюстрирует программу блока начальной за-
грузки, обеспечивающую загрузку или выгрузку содержимого памяти программ. Эта про-
[рамма использует другую версию программы запуска, которая поставляется совместно
компилятором С18. Эта версия использует меньшее количество памяти, благодаря чему
блок начальной загрузки помещается в 512 байтах. (Программа требует 508 байт.) Програм-
ма, иллюстрируемая в этом примере, реагирует только натри команды, передаваемые через
последовательный интерфейс. Поскольку не все версии PIC18 имеют аппаратный USART, эта
программа использует программные функции UART, размещенные в файле заголовка
sw uart.h. Команда 0x01 позволяет осуществлять считывание памяти программ для выгрузки
кодов в ПК, команда 0x02 позволяет осуществлять запись в память программ или загрузку
кодов ПК, а команда 0x03 разрешает нормальную начальную загрузку. Единственный пугь
возврата в программу начальной загрузки состоит в том, чтобы записать значение OxFF в
ячейку ЭСППЗУ с адресом OxFF, - этот путь не иллюстрируется в данном примере. Встроен-
ный ассемблер, который является частью компилятора С18, использует немного другой
формат команд для табличных команд, отличающийся от формата команд обычного ассемб-
лера, который детально рассматривался в более ранних главах, а также освещается в доку-
ментации, предоставляемой фирмой Microchip. Смотрите детали изменений в листи! ire про-
граммы. Необходимо использовать программный код встроенного ассемблера для того,
чтобы программа начальной загрузки поместилась в 512 байтов доступной памяти.
Пример 10.4
* Начальный загрузчик для PIC18F1220
-/
'/ Для того, чтобы этот программный код мог вписаться в блок начальной загрузки
/ файл компоновщика был изменен с тем, чтобы использовать файл инициализации с018.о
// вместо файла С0181.0
' /
'/ Эффект от этого заключается в том, что в программе будет
// отсутствовать инициализируемая область памяти.
// Это не очень важное свойство для большинства систем.
«include <pl8cxxx.h>
«include <sw_uart.h>
^include <delays.h>
'' * Установка битов конфигурации
* -- установка внутренней синхронизации
* - выключение сторожевого таймера
* -- выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
-/
470
Применение микроконтроллеров PIC 18
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
((pragma config MCLRE = ON
// Define EEPROM addresses
((define bootcontrol OxFF
// Data memory variable
void MyHighlnt (void);
void MyLowInt (void);
((pragma interrupt MyHighlnt
((pragma code high_vector=0x08
void high_vector (void)
{
_asm GOTO MyHighlnt _endasm
}
((pragma interruptlow MyLowInt
((pragma code low_vector=0xl8
void low_vector (void)
{
_asm GOTO MyLowInt _endasm
)
((pragma code BootBlock
void NormalReset (void);
void DelayTXBitUART (void)
{
DelaylOTCYx (9);
DelaylTCY();
DelaylTCY();
DelaylTCY();
)
void DelayRXHalfBitUART (void)
{
DelaylOTCYx (4);
DelaylTCY();
DelaylTCY();
DelaylTCY();
DelaylTCY();
)
void DelayRXBitUART (void)
{
DelaylOTCYx(9);
DelaylTCY () ;
}
void main (void)
// внешняя тактовая частота 4 Ml’n
// прототипы
save=PROD
// high_vector по адресу 0x0008
// высокоприоритетный вектор
// переход на подпрограмму обслуживания
// высокоприоритетного прерывания
// MyLowInt - это прерывание
// low_vector - это вектор
// по адресу 0x18
// прототип
// 93 мкс для UART
// 44 мкс для UART
// 91 мкс для UART
Глава 10. Вопросы повышенной сложности
471
char temp;
char command;
char length;
char addrl;
char addrh;
char addru;
EECONlbits . EEPGD = 0; // проверка контрольно;’© байта
// загрузочного блока
EEADR =- bootControl;
EECONlbi t.S.RD - 1;
If (EEDATA != OxFF) // выполнение нормального сброса
1
_asm GOTO NormalReset _endasm
1
OpenUART();
do
{
command = ReadUARTO;
length = ReadUARTO;
addrl = ReadUARTO;
addrh = ReadUARTO;
addru = ReadUARTO;
_asm
MOVFF addrl,TBLPTRL
MOVFF addrh,TBLPTRH
MOVLW 0
MOVFF WREG,TBLPTRU
_endasm
// read program memory
// <01> <len> <addrl> <addrh> <addru>
// <data byte (s)>
if (command == 1)
{
while (length 1= 0)
{
asm // считывание памяти программ
TBLRDPOSTINC
MOVFF TABLAT,temp
_endasm
WriteUART(temp);
length--;
}
1
// запись в память программ
// <02> <len> <addrl> <addrh> <addru>
// <data byte(s)>
else if (command == 2)
{
while (length != 0)
{
temp = ReadUARTO;
_asm
MOVFF temp,TABLAT
TBLWTPOSTINC
_endasm
EECONlbits.EEPGD = 1; // выбор ЭСППЗУ программ
EECONlbits.WREN =1; // снятие защиты от записи
472
Применение микроконтроллеров PIC 18
EECON2 = 0x55; // стирание текущего байта
EECON2 = ОхАА;
EECONlbits.WR =1; // выбор записи
}
}
// управление нормальной загрузкой
// <03> <data> <dummy> <dummy> <dummy>
else if (command == 3)
{
EECONlbits.EEPGD = 0; // выбор ЭСППЗУ данных
EECONlbits.WREN = 1; // снятие защиты от записи
EEADR = bootcontrol; // задание адреса ЭСППЗУ
EEDATA = 0; // задание данных для ЭСППЗУ
EECON2 = 0x55; // стирание текущего байта
EECON2 = OxAA;
EECONlbits.WR = 1; // выбор операции записи
while (PIR2bits.EEIF == 0); // ожидание завершения
1
}
while (command != 0);
)
// Любой дополнительный код помещается после программы блока начальной загрузки!
// Следующий блок кода имеет имя Main.
#pragma code Main=0x200
void Highlnt (void);
void Lowint (void);
void MyHighlnt (void)
{
asm GOTO Highlnt _endasm
void MyLowInt (void)
(
asm GOTO Lowint endasm
void NormalReset (void)
(
_asm GOTO MAIN _endsasm
// place no code before this point!
void { I MAIN (void) // новая функция Main
void ( } Highlnt (void) // высокоприоритетное прерывание
void Lowint (void) // низкоприоритетное прерывание
Глава 10. Вопросы повышенной сложности
473
10.3. Расширение ввода-вывода
Хотя во многих случаях ввод-вывод, в выбранной версии микроконтроллера, яв-
ляется адекватен, имеются случаи, когда требуется дополнительный ввод-вывод, при
этом доступный ввод-вывод должен быть расширен. Этот подраздел иллюстрирует
несколько методов расширения структуры ввода-вывода микроконтроллеров.
Дополнительные выходные подключения
Дополнительные выходные цифровые подключения могут быль получены, если
использовать сдвиговый регистр для увеличения количества выходных битов. В схеме,
показанной на рис. 10.9, использован сдвиговый регистр для того, чтобы обеспечить 8-
разрядный выходной порт на микроконтроллере PIC18F1320. Три вывода ввод - вывод
микроконтроллера, используются для того, чтобы управлять этим интерфейс, поэтому
чистый выигрыш составляет только пять дополнительных выходов. Программа, управ-
ляющая этим простым интерфейсом, является достаточно короткой - она приведена в
примере 10.5. Этот пример иллюстрирует только функции инициализации интерфейса
и вывода одного байта через этот дополнительный выходной порт.
VCC
о
PIC18F1320
U2 -
1
2
6
7
3
4
16
15
RAO gRB0
RA1 > RB1
RA2 RB2
RA3 RB3
RA4 RB4
#MCLR RB5
OSC1 «RB6
OSC2 >RB7
8
9
17
18
10
11
12
13
74НС594
U1
14
12
11
13
10
Рис. 10.9. Применение расширения. 8-разрядный выходной порт
474
Применение микроконтроллеров PIC 18
Пример 10.5
void InitPort (void)
TRISB = TRISB & 0xF8; // программирует RBO, RBI и RB2
PORTB = PORTB & 0xF8; // очистка RBO, EB1, RB2
}
void OutPort (char data)
(
char a;
for (а = 0x80; а != 0; а >> / 1) // сдвиг позиции бита
t if ( (а & data) == а) // передача SER
PORTBbits.RB0 = 1;
else
PORTBbits.RBO = 0;
PORTBbits.RB2 = 1; // синхронизация SRCLK
PORTBbits.RB2 = 0; 1
J PORTBbits.RBI = 1; // синхронизация RCLK
PORTBbits.RBI = 0;
Микросхема 74HC594 имеет три входа. Первый из них, называемый SER, - это
вход последовательных данных, связанный в рассматриваемой схеме со выводом RB0
микроконтроллера. Вход SRCLK - это последовательный вход тактовой частоты, а вход
RCLK - это вход тактовой частоты регистра. Внутри устройства имеется сдвиговый ре-
гистр и буферный регистр. Чтобы обеспечить свободную от сбоев работу устройства,
данные заносятся в сдвиговый регистр. После этого буферный регистр по сигналам
тактовой частоты переносит данные из сдвигового регистра на выходные выводы, ко-
торые связаны с буферным регистром. Функция InitPort инициализирует порт В, а
функция OutPort используется для того, чтобы выдавать данные в порт. Обратите вни-
мание на то, что данные заносятся в сдвиговый регистр таким образом, что первым
идет самый старший бит.
Сдвиговый регистр является расширяемым, как это иллюстрируеюя на
рис. 10.10. Выход ОН при этом подключается ко входу SER следующей микросхемы
схемы, а входы тактовой частоты обеих микросхем объединяются, формируя 16-
разрядный выходной порт. Если необходим двухпроводный интерфейс, то можно ис-
пользовать устройства, выпускаемые Microchip и другими изготовителями, которые
подключаются к интерфейсу I2C микроконтроллера. При этом экономится один вывод,
но программа будет намного длиннее, чем та, которая показана в примере 10.5.
Глава 10. Вопросы повышенной сложности
475
VCC
о
PIC18F1320
U2
1
2
6
7
3
4
16
15
RAO
RA1
RA2
RA3
RA4
#MCLR
OSC1 $2 RB6
OSC2 >RB7
gRBO
> RB1
RB2
RB3
RB4
RB5
8
9
17
18
10
11
12
13
ю
R1
10K
74HC594
U1
16
УСС
14
SER
12
4f~>RCLK
J—>SRCLK
13
10
8
RCLR
SRCLR
GND
74HC594
U3
16
14
SER
12
11
>RCLK
>SRCLK
13
10
8
RCLR
SRCLR
GND
QA
QB
QC
QD
QE
QF
QG
QH
QH'
УСС
QA
QB
QC
QD
QE
QF
QG
QH
QH'
15
1
2
3
4
5
6
7
9
15
1
2
3
4
5.
6
7
9
Рис. 10.10. 16-разрядный выходной порт
476
Применение микроконтроллеров PIC 18
Рис. 10.11. Добавление 8-ми входных выводов
Дополнительные входные подключения
Та же самая методика, которая используется для добавления дополнительных
выходных выводов, может быть применена для того, чтобы добавить дополнительные
входные выводы. Единственное различие заключается в том, что вместо того, чтобы
использовать последовательный сдвиговый регистр, связанный с буфером, как в
74НС594, используется другой сдвиговый регистр, который внутренне связан с буфе-
ром, загружающим сдвиговый регистр с тем, чтобы последовательные данные могли
быть сгенерированы из входных битов. Рис. 10.11 иллюстрирует подключение, которое
добавляет 8 дополнительных входных битов данных для микроконтроллера. В этом
примере вывод микросхемы RBO - это последовательный вход данных микроконтрол-
лера, вывод RB1 - это вход тактовой частоты сдвигового регистра 74НС7595, a RB2 -
это параллельный вход нагрузки. Функция, инициализирующая и считывающая байт
данных от входных выводов, иллюстрируется примером 10.6. Показанная в этом при-
мере программа похожа на программу работы с выходным портом, которая была рас-
смотрена ранее.
Глава 10. Вопросы повышенной сложности
477
Пример 10.6
void InitPort (void)
{
TRISB = TRISB & 0xF8;
TRISBbits.TRISB0 = 1;
PORTB = PORTB & 0xF8;
PORTB - PORTB | 1;
// программирует RBO, RBI и RB2
char InPort (void)
{
char a, b;
PORTBbits.RBI = 0;
PORTBbits.RBI = 1;
for (a = 0; a <8; a++)
{
b «= 1;
b |= PORTBbits.RBO;
PORTBbits.RB2 = 1;
PORTBbits.RB2 = 0;
}
return (b);
// загрузка сдвигового регистра
// получаем все 8 битов
Использование 2-проводного интерфейса
Хотя уже рассмотренные методы расширения ввода-вывода часто вполне прием-
лемы, они требуют трех подключений к микроконтроллеру. В некоторых случаях требу-
ется 2-проводный интерфейс. Хотя его использование и связано с повышением слож-
ности управляющей программы, однако оно позволяет сэкономить один вывод микро-
контроллера.
Рис. 10.12 иллюстрирует пару микросхем PCF8574S, подключенных к микрокон-
троллеру PIC18F1320 с тем, чтобы увеличить число выводов ввода-вывода. Микросхе-
мы PCF8574S от фирмы Texas Instruments используют 2-проводный интерфейс I2C. В
отличие от других устройств расширения порта, эти устройства являются двунаправ-
ленными и играют роль как входного, так и выходного интерфейса. Устройство форми-
рует 8-разрядный квази-двунаправленный порт ввода- вывода (выводы Р0-Р7), вклю-
чая триггерные выходы с высокой токовой нагрузочной способностью, обеспечиваю-
щие возможность непосредственного управления светодиодами. Максимальный вы-
ходной ток логического нуля на штырьке порта равен 25 мА, а максимальной выходной
ток логической единицы равен 300 мкА. Указанные значения тока являются достаточ-
ными для управления большинством светодиодов. Каждый квази-двунаправленный
вывод ввода-вывода используется как вход или выход без применения регистра TRIS,
программирующего направление. Устройство U3 включено так, чтобы реагировать на
адрес 100, a U1 - на адрес 000. Программа двухпортового режима для этих устройств
использует файл заголовка sw_i2c.h из библиотеки, поставляемой совместно с компи-
лятором С18. В двух функциях, приведенных в примере 10.7, используется адрес 0 или
4 для устройств U1 и U3 соответственно. Выводы RB3 (тактовая частота) и RB4 (данные)
должны использоваться, если только файл sw_ic2.h не был перекомпилирован под дру-
гие выводы.
478
Применение микроконтроллеров PIC 18
PCF8574_P
Рис. 10.12. Применение 2-проводного интерфейса
Пример 10.7
//не забывайте #include <sw_i2c.h>
char ReadPort (char address)
{
char temp;
SWStartI2C () ;
SWWriteI2C (OxAO | address); // управляющий байт
SWAckI2C();
temp = SWReadI2C(); // считывание из U1 или U3
SWAckI2C();
SWStopl2C();
return temp;
void WritePort (char address, char data )
{
SWStartl2C ();
SWWriteI2C (OxAO | address); // управляющий байт
SWAckI2C();
SWWriteI2C (data); // запись в U1 или U3
SWAckI2C () ;
Глава 10. Вопросы повышенной сложности
479
SWStopI2C();
)
Цифро-аналоговые преобразователи
В микроконтроллерах PIC цифро-аналоговый преобразователь (ЦАП) отсулсгву-
ет, в то же время эта функция иногда требуется. Фирма Microchip предлагает cooiboi-
ствующее периферийное устройство, которое преобразует цифровое значение в ана-
логовое напряжение. Это устройство является недорогим и простым при подключении
и управлении со стороны микроконтроллера.
Фирма Microchip выпускает несколько микросхем ЦАП с последовательными вхо-
дами, которые доступны в 8-выводных корпусах типа PDIP. В качестве примера можно
назвать 8-разрядный ЦАП ТС1320. Рис. 10.13 иллюстрирует цоколевку выводов
ТС1320. В дополнение к подключениям VDD и VSS, вход Vref устанавливает полномас-
штабное выходное напряжение на выводе Vout вход SCL служит для сигнала последова-
тельной синхронизации, а вход SDA - для ввода последовательных данных. Вывод DAC-
OUT обеспечивает выход непосредственно из ЦАП, но обычно для снятия выходного
сигнала используется вывод Vout. Вывод DACJDUT используется тогда, когда в системе
применяется внешний операционный усилитель. Это бывает довольно редко, потому
что внутренний усилитель и усиленный выходной сигнал, доступный на Vout, обычно
обеспечивает нагрузочную способность, достаточную для большинства приложений.
U1
3
Vref Vout
SDA DAC-OUT
SCL
TC1320
Рис. 10.13. ЦАП ТС1320
Выходное напряжение ТС1320 дается первым уравнением из примера 10.8. Если
на вход Vref подается опорное напряжение, равное 5 В, то шаг выходного напряжения
будет равен 0,00196 В, а максимальное выходное напряжение будет равно 5 В. Для
регулирования шага выходного напряжения и максимального выходного сигнала может
использоваться другое опорное напряжение Vref. Второе уравнение из примера 10.8
может использоваться для того, чтобы вычислить значение цифровых данных, подан-
ных на АЦП с тем, чтобы сгенерировать конкретное выходное напряжение.
Пример 10.8
vout = vref (данные/256)
Данные = (Vout х 256)/Vref
Программный интерфейс ТС1320 обычно ориентирован на SPI (последователь-
ный периферийный интерфейс). При этом используется либо соответствующая функ-
ция из библиотеки компилятора С18, или аппаратные средства SPI, предоставляемые
внутренним интерфейсом MSSP. Схема, показанная на рис. 10.14, использует
PIC18F1220, который не имеет блока MSSP, поэтому используется программная фупк-
480
Применение микроконтроллеров PIC 18
ция SPI, добавляемая файлом заголовка swspi.h, который имеется в библиотеке ком-
пилятора С18.
Работа ЦАП требует, чтобы он был переведен в нормальный режим посредством
передачи в него значений 0x90 и 0x01, за которыми следует 0x00. Адрес подчиненного
устройства при этом запрограммирован на предприятии-изготовиюле как 1001 000w,
при этом правый бит (w) равен нулю для операции записи. Если необходим другой ад-
рес подчиненного устройства, то Microchip может обеспечить до восьми различных
адресов подчиненных устройств за отдельную плату. Последовательность значений
0x90, 0x01 и 0x00 программирует ЦАП на работу в нормальном режиме. С целью эконо-
мии электропитания ЦАП переводится в режим бездействия передачей в него последо-
вательности значений 0x90, 0x01 и 0x01. Чтобы преобразовать цифровое значение в
аналоговое напряжение на ЦАП передается последовательность значений 0x80, 0x00,
которая сопровождается данными, подлежащими преобразованию. Например, если Vrct
равно 5 В, а вывод Vout установлен на 3 В, то последовательность 0x90, 0x00 сопровож-
дается значением 0х9А. 0х9А вычисляется из второго уравнения примера 10.8.
Программа управления интерфейсом по рисунку 10.14 приведена в приме-
ре 10.9. Схема демонстрирует электромотор постоянного тока на 3 В, связанный с вы-
ходом ЦАП. Скорость электромотора управляется ЦАП и функцией Speed, включенной в
программу. Иногда электромотор может управляться этим способом, потому что он
может не запуститься надежно при использовании схемы широтно-импульсный моду-
лятора, рассмотренной главе 7. TIP120 - это усилитель на паре Дарлингтона (падение
напряжения "база-эмиттер" равно 1,4 В), поэтому выходной сигнал ЦАП должен лежать
между 1,4 В и 4,4 В, чтобы управлять электромотором с подачей на него от 0 до 3 В по-
стоянного тока. TIP120 используется как усилитель на эмиттерном повторителе. В спе-
цификациях выход ЦАП указывается для максимального тока, равного 3 мА. Минималь-
ный коэффициент усиления TIP120 равен 1000. Это означает, что самый мощный элек-
тромотор, которым эта схема может управлять - это электромотор на 3 А. Функция
Глава 10. Вопросы повышенной сложности
481
Speed использует скорости электромотора от 0 до 152, где 0 означает останов элек-
тромотора, а 152 - его максимальную скорость. Эти 153 приращения скорости должны
обеспечить достаточный уровень контроля скорости электромотора для большинства
приложений.
Пример 10.9
* Пример программы управления электромотором постоянного тока
*/
tfinclude <p!8cxxx.h>
^include <sw_spi.h>
/ * Установка битов конфигурации
* установка внутренней синхронизации
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
* /
ipragma config OSC = INTIO2
tfpragma config WDT = OFF
# pragma config LVP = OFF
# pragma config BOR = OFF
tfpragma config MCLRE = ON
'/ function to control the speed of the motor
'/ through the DAC. Speeds are 0 through 152
void Speed (unsigned char speed)
t
if (speed >= 0 && speed <= 152)
{
speed += 72; // смещение скорости на by 1,4 Вольта
WriteSWSPI (0x90); // передача скорости
WriteSWSPI (0x00);
WriteSWSPI (speed);
)
#pragma code
// основная программа
void main (void)
{
ADCON1 = OxOF; // цифровые выводы ввода-вывода
TRISB =0; // Порт В = выход
OSCCON = 0x73; // внутренняя синхронизация 8 мГц internal clock
OpenSWSPIO; // конфигурирование штырьков порта SPI
WriteSWSPI (0x90); // установ нормального режима
WriteSWSPI (0x01);
WriteSWSPI (0x00);
while (1)
{
482
Применение микроконтроллеров PIC 18
// выполнение других работ
)
)
10.4. Интерфейс CAN
CAN - это управляющая локальная сеть, используемая для того, чтобы связать
микроконтроллеры вместе в системе, в которой микроконтроллеры должны обмени-
ваться данными друг с другом. Этот интерфейсный модуль называется модулем CAN
или ECAN (расширенный CAN) имеется не во всех микроконтроллерах семейства
PIC18F. Первоначально CAN был разработан для автомобильной промышленности,
однако он нашел много применений в различных областях, в которых множественные
микроконтроллеры должны связываться друг с другом.
Структура CAN
CAN очень похожа на любую иную локальную сеть, в которой данные посылаются
и получаются между компьютерами и любыми устройствами, которые содержат интер-
фейс. Основное отличие CAN заключается в том, что он разработан для того, чтобы
осуществлять информационный обмен между микроконтроллерами в локальной облас-
ти в зашумленной среде, которая была бы подобна сетям ПК, если бы не высокий уро-
вень помех. CAN разработан для работы в зашумленных средах, которые встречаются в
автомобильных и иных подобных применениях. Модуль CAN содержит устройство от-
работки протокола, блок передачи сообщений и блок управления, он полностью интег-
рирован в различных микроконтроллерах семейства PIC18. Как и другие последова-
тельные сети, CAN формирует сеть, которая для своей работы требует использования
двух выводов микроконтроллера. Компилятор С18 поддерживает работу этого интер-
фейса на языке С, за счет чего достигается эффективность разработки соответствую-
щего программного обеспечения.
Вывод RB2 используется для передачи даш jx (CANTX) и вывод RB3 использует-
ся для приема данных (CANRX). Эти два вывода являются единственными подключе-
ниями микроконтроллера к данному интерфейсу, они связаны со внешней схемой
управления шиной, которая управляет CAN. CAN выполняет информационный обмен
между микроконтроллерами в любом направлении. Микроконтроллер может быть при-
емником сообщений или источником/приемником сообщений, что позволяет выпол-
нять взаимную связь через CAN между несколькими микроконтроллерами. Рис. 10.15
иллюстрирует типовое подключение микроконтроллеров через CAN. Длина шины CAN
может достигать 1000 метров без использования специальных схем управления при
скорости информационного обмена в 40 кбит/с. Если длины шины будет менее 40 мет-
ров, то скорость информационного обмена на шине будет равна 1 мбит/с. Эта скорость
является достаточной для большинства приложений, требующих использования сети.
Глава 10. Вопросы повышенной сложности
483
Рис. 10.15. Микроконтроллеры, соединенные между собой через шину CAN
Узлы шины связываются между собой витой парой проводов (САТ5) как и в боль-
шинстве сетей. Узлы могут подключаться и отключаться от сети при включенном на-
пряжении питания без каких-либо повреждений системы. К CAN может подключаться
вплоть до 20 узлов без дополнительной буферизации. На каждом своем конце шина
CAN должна заканчиваться резистором на 120 Ом. Этот резистор предотвращает от-
ражение сигналов на шину - в большинстве применений он обычно включается между
шинной парой на каждом узле. Рис. 10.16 иллюстрирует типовой узел с микроконтрол-
лером PIC18F2580 и микросхемой интерфейса шины CAN МРС2551 от фирмы
Microchip. Значение для RS выбирается таким образом, чтобы снизить уровень элек-
тромагнитных помех. Чем больше его значение, тем более длинный спадающий фронт
будет иметь сигнал шины CAN и тем ниже будет уровень электромагнитных помех.
+5V
о
PIC18F2580
о
U1 w
___2
___3.
___4_
___5_
___6_
___7
RA0
RA1
RA2
RA3
RA4
RA5
MCLR
OSC1
OSC2
16
17
18
RC5
RC6<g
RC7 >
RBO
RB1
RB2
RB3
RB4
RB5
RB6
RB7
RCO
RC1
RC2
SrcJ
21
23
24
25
26
27
28
13
14
15
MPC2551
R1
10K
g CANH
ТО g CANH
RXD 5 CANL
VREF
RS
ОТ
от
Рис. 10.16. Узел CAN
шина CAN
0
9
1
8
U2 «
484
Применение микроконтроллеров PIC 18
Приложение, использующее CAN
Гипотетическим приложением для CAN может быть система управления лифтом.
В этой системе нужно использовать какой-либо индикатор на каждом этаже, показы-
вающий, где находится кабина лифта, а также кнопки с тем, чтобы пассажир мог вызы-
вать кабину лифта, двигающуюся вверх либо вниз. В кабине лифта должна быть панель
управления, чтобы пассажир мог вводить требуемый этаж, кроме того должна иметься
система управления, управляющая перемещением кабины лифта вверх и вниз в шахте.
Система, иллюстрируемая рис. 10.17, предназначена для работы в зданиях, число эта-
жей которых достигает 10, однако она легко может быть модифицирована для любого
количества этажей. Наиболее значительным изменением в этом случае будет исполь-
зование развязывающих схем, поскольку количество подключений к CAN ограничено
20. Каждый этаж требует наличия своего собственного узла сети, что ограничивает
этажность здания в случае отсутствия дополнительных развязывающих схем.
Каждый этаж нуждается в блоке управления, который является точно таким же,
как на любом другом этаже, за исключением номера этажа. Блок управления имеет две
кнопки: одну, обозначенную как UP (Вверх), и другую, обозначенную как DOWN (Вниз), а
также внутренние диодные ключи, позволяющие устанавливать номер этажа. Единст-
венные исключения заключаются в том, что самый верхний этаж не имеет кнопки UP
(Вверх), а самый нижний этаж не имеет кнопки DOWN (Вниз). Блок управления также
имеет большие светодиодные индикаторы стреловидной формы, которые указывают
направление движения кабины лифта. Над входом в лифт имеется столбец больших
светодиодных индикаторов с цифрами, которые указывают текущее положение кабины
лифта. Рис. 10.17 иллюстрирует компоненты системы, включительно с микроконтрол-
лером, которые расположены на каждом этаже.
Рис. 10.18 иллюстрирует микроконтроллер и компоненты контроллера, исполь-
зуемого в системе управления лифтом на каждом этаже. На плате установлены четыре
интегральных схемы: микроконтроллер PIC18F2580, интерфейс CAN и две схемы
управления светодиодами. Набор четырех переключателей с двойным рядом выводов
используется для того, чтобы программировать номер этажа в контроллере. Здания с
большей этажностью требуют использования переключателей с большим количеством
выводов. Внутренние слабые нагрузки используются в порте В для двух кнопок - UP
(Вверх) и DOWN (Вниз), а также для четырех переключателей с двойным рядом выво-
дов, предназначенных для установки номера этажа. Используемая плата достаточно
мала для того, чтобы разместить ее позади кнопок или информационной панели, со-
держащей индикаторы этажей.
Программа для этой системы использует библиотеку ECAN, предоставляемую на
вебсайте фирмы Microchip. Благодаря копированию файлов ECAN.H, ECAN.DEF и
ECAN.C в каталог проекта и добавлению оператора #include <ECAN.H> в файл про-
граммы, система сможет программировать и использовать модуль ECAN, встроенный
в микроконтроллер. Программа контроллера этажа лифта приведена в примере 10.10.
Эта система передает сообщение всякий раз, когда нажата кнопка UP (Вверх) или
DOWN (Вниз) с тем, чтобы сообщить контроллеру кабины лифта (обсуждается позже),
что пассажир ожидает на указанном этаже. Программа также прослушивает шину CAN
на наличие сообщений от контроллеров этажей для контроллера кабины лифта, в ре-
зультате чего правильный номер этажа может индицироваться на информационной
панели, расположенной над дверью.
Глава 10. Вопросы повышенной сложности
485
Рис, 10.17. Лифт и органы управления им, расположенные
на каждом этаже 5-этажного дома.
Пример 10.10
/*
* Контроллер этажа системы управления лифтом
*/
^include <pl8cxxx.h>
#include <delays.h>
#include <ECAN.h>
/* Установка битов конфигурации
* - установка внутренней синхронизации
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
* /
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOR = OFF
486
Применение микроконтроллеров PIC 18
#pragma config MCLRE = ON
unsigned char floorfl];
char fired;
unsigned long id;
unsigned long iD;
unsigned char data[l];
char dataLen;
#pragma code
// основная программа
void checkButton (void)
if (PORTB & OxCO != OxCO)
{
if (fired == 0)
{
DelaylKTCYx(15); // компенсация дребезга контактов
if (PORTB & OxCO != OxCO)
{
fired = 1;
if (PORTBbits.RB7 == 0)
{
PORTCbits.RC6 =1; // вверх
floor[0] 1= 0x80;
}
else // вниз
{
PORTCbits.RC7 = 1;
floor[0] &= 0x7F;
)
while (!ECANSendMessage(iD,
floor,
1,
ECAN_TX_STD_FRAME));
}
}
else
fired = 0;
}
)
void main (void)
{
ECAN_RX_MSG_FLAGS flags;
ADCON1 = OxOf; // все выводы порта цифровые
TRISA = 0; // программирование портов
TRISB = OxFB;
TRISC = 0;
fired = PORTA = PORTC = iD = 0; // светодиоды выкл
floor[0] = (PORTB & 3) | ((PORTB & 0x30) « 2);
ECANInitialize(); // инициализация CAN
while (1)
{
checkButton ();
if (ECANReceiveMessage (&id, data, &dataLen, &flags))
Глава 10. Вопросы повышенной сложности
487
if (id == 1) // если от контроллера кабины
{
PORTA =1; // изменение индикации этажа
PORTA <<= data[0];
if (data[0] == (floor[0] ь 0x71-'))
PORTC = PORTC & 0x31"; // ВВЕРХ и ВНИЗ выкл.
)
Кабина лифта также нуждается в контроллере. Этот контроллер должен позво-
лить пассажиру выбрать этаж, он также должен выравнивать кабину лифта, когда она
останавливается на этаже, перемещать ее от одного этажа к другому, а также и пере-
давать текущий номер этажа всем контроллерам этажей, подключенным к CAN с тем,
чтобы они могли отображать текущую позицию кабины лифта. Контроллер кабины так-
же объявляет номер этажа и любую другую информацию через динамик в кабине лиф-
та. Это придает системе “человеческое лицо". Для выдачи этих голосовых сообщений
используется ЦАП, подающий на динамик человеческий голос, дискретизованный с
частотой в 2 кГц и сохраненный в памяти. Рис. 10.19 иллюстрирует панель управления,
находящуюся в кабине лифта. Данная панель используется пассажирами для того, что-
бы выбрать требуемый этаж и содержит кнопки, которые при нажатии подсвечиваются
светодиодами. Что не показано на этой иллюстрации, - так это динамик, через который
объявляются этажи, а также стрелки “вверх/вниз” в кабине лифта, которые отображают
направление движения. Механизм выравнивания лифта и система управления элек-
тромотором здесь также не рассматриваются.
Рис. 10.20 иллюстрирует принципиальную схему контроллера кабины лифта.
Электромотор лифта, установленный на крыше здания, управляется через подачу на
нею управляющих сигналов напряжения 24 В переменного тока. Эти сигналы активи-
руются интегральными реле, расположенными на плате управления кабины лиф1а.
Имеются два сигнала: один запускает электромотор так, что кабина лифта движется
вверх, а другой запускает электромотор так, что кабина лифта движется вниз. Вырав-
нивание выполнятся фотодетектором по меткам синхронизации, которые имеются в
шахте лифта. Сигналы с фотодетектора распознаются контроллером, в результате чего
лифт останавливается на этаже в правильной позиции.
ЦАП используется, чтобы генерировать речь через динамик, который управляется
TIP120. TIP120 может формировать очень большие токи, достаточные для управления
мощными динамиками, поэтому в схему включен резистор управления громкостью,
ограничивающий ток, проходящий через динамик, а следовательно и громкость рече-
вых сообщений. В форме массива, расположенного в памяти программ, хранится де-
сять речевых сообщений. Эти сообщения здесь не рассматриваются - они должны ге-
нерироваться пользователем с использованием другого PIC-устройства (здесь но по-
казано) и АЦП, генерирующего битовый поток для произнесенных слов. Амплитуда сиг-
налов этого потока должна лежать между 1,4 В и 3,6 В для правильной работы системы.
оо
оо
5 В от светодиодов
120
+5V
О
вверх
вниз
В
1
2
3
4
5
16
15
14
13
12
11
10
OUTA
OUTB
OUTC
OUTD
OUTE
OUTF
OUTG
16
IS
14
13
12
11
10
OUTA
OUTB
OUTC
OUTD
OUTE
OUTF
OUTG
из
4 MHz
R2
10K
PIC18F2S8O
U1
INA
IN В
INC
IND
INE
INF
ING
СОМ
DS2003
U4
INA
INB
INC
IND
INE
INF
ING
COM
DS2003
1.0 uF
C4 x
27 pF
2_
3
5
6
7
10
16
17
18
RAO
RA1
RA2
RA3
RA4
RAS
MCLR
OSC1
OSC 2
§
RC5
RC6<g
RC7 >
RBO
RB1
RB2
RB3
RB4
RB5
RB6
RB7
RCO
RC1
RC2
<gRC3
>RC4
C3
27 pl
21
22
23
24
25
26
27
28
11
12
13
14
15
Up
-о
Down
•О
MPC2S51
1
4
5
8
TXD 9 CANH
RXD > CANL
VREF g
RS >
шина
CAN
R1
10K
Применение микроконтроллеров PIC 18
этаж
Рис. 10.18. На каждом этаже имеется контроллер системы управления лифтом
Глава 10. Вопросы повышенной сложности
489
Рис. 10.19. Панель управления в кабине лифта
Выравнивание кабины лифта и индикация этажей иллюстрируются на рис. 10.21.
Для целей указания этажей используются сообщения, закодированные штрих-кодами
на пленке, которая клеится к стенке шахты лифта. Штрих-коды считываются, когда ка-
бина лифта движется вверх и вниз по шахте. Штрих код позволяет кабине лифта опре-
делять номера этажей, а также останавливать кабину лифта, так что она будет на одном
уровне с полом этажа. Используемый штриховой код кодирует номер этажа в двоичной
системе счисления, при этом имеется та же центральная отметка, которая позволяет
системе определять уровень этажа.
Пример 10.11 показывает программу контроллера кабины лифта. Обратите вни-
мание на то, что поскольку выводы порта С используются аппаратными средствами для
управления ЦАП, файл заголовка sw_spi.h, должен быть модифицирован таким обра-
зом, чтобы выводы порта С использовались для последовательной тактовой частоты и
передачи последовательных данных на ЦАП. Для того, чтобы эта программа работала, с
вебсайта Microchip.com должен быть загружен библиотечный файл ECAN.
120
чО
О
+5V
О
нормально-разомкнутое реле
нормально-замкнутое реле
реле "вниз
8 MHz
реле “вверх
PIC18F4580
U1
С2
фотодетектор |-
C3
0.1 uF
:ci
1.0 uF
чС5
22 pF
22 pF
U4
16
3E
14
13
12
11
10
на светодиоды
OUTA
OUTB
OUTC
0U7D
ОПТЕ
OUTF
OUTG
INA
INB
INC
IND
INE
INF
ING
JL
2
3
5
6
T
СОМ
9
DS2003
_1±
J9.
22.
21
22
27
28
29
8
C MCLR
RAO
RAI
RA2
RA3
RA4
RAS
0SC1
0SC2
RDO
RD1
RD2
RD3
RD4
RD5
RD6
RD7
REO
MPC2S51
лимит закрытия
33
U2
gg
° CANH
COCO
gg
R3
1К
LS1
SDO
RC6
RE1
RE2
Q1
Т1Р120
4
J
8
TXD ° CANH
RXD g CANL
7
8
4
TC1320
U3
лимит открытия
DAC-OUT
громкость
динамик
Vref g Vout
SDA
SCL g
2
3
шина
CAN
RBO
RB1
CANTX
CANRX
RB4
RB5
RB6
RB7
RCO
RC1
RC2 -Й—
SCK
SDI Mr—
35
38
37
38
Jg.
16
Л
R2
10К
Применение микроконтроллеров PIC 18
Рис. 10.20. Электрическая схема блока управления кабины лифта
Глава 10. Вопросы повышенной сложности
491
Вид спереди
Вид спереди
ШТИТэГШ
п
ТзГПЛ
Рис. 10.21. Соединительные разъемы USB
Пример 10.11
/*
* Программа контроллера кабины лифта
* /
^include
^include
#include
^include
^include
<pl8cxxx.h>
<delays.h>
<ECAN.h>
<spi.h>
<timers.h>
/* Установка битов конфигурации
* - установка внутренней синхронизации
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* разрешение общего сброса
^pragma config OSC = HSPLL // 32 мГц
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOR = OFF
ttpragma config MCLRE = ON
// // речевые сообщения в памяти программ частотой 2048 Гц
место для 10 односекундных речевых сообщений, дискретизованных с
// // Дискретизация аудиосигналов должна выполняться при минимальном уровне 1,4 В и
// максимальном уровне 3,6 В, чтобы ЦАП функционировал правильно.
// Аудиофайл должен быть сформирован пользователем как речевой массив
и // // // // и и и // // // 0 = подвал" 1 = "первый этаж" 2 = "второй этаж" 3 = "третий этаж" 4 = "четвертый этаж" 5 = пятый этаж" 6 = "закройте дверь" 7 = "лифт идет вверх" 8 = "лифт идет вниз" 9 = "инициализация"
492
Применение микроконтроллеров PIC 18
rom near char speech[10] [2048]
rom near ( char keyt[] =
5, 3, 1, 6, 4, 2, 0, 7
);
void MyHighlnt (void); // прототипы
// переменные в памяти данных
unsigned char fifo[16];
unsigned char fifoINP;
unsigned char fifoOUTP;
unsigned char SPIbusy;
unsigned char speak;
unsigned int speechcounter;
unsigned int timeDelayCounter;
unsigned char door;
unsigned char callFloor[6];
unsigned char data[l];
unsigned char dataLen;
unsigned currentFloor;
unsigned int barcode[6];
unsigned char barcodePtr;
unsigned char carMoving; // 1 = вверх, 2 = вниз, 0 = останов
char callDirection; // 1 = вверх, 2 = вниз, 0 = ожидание
char state;
#pragma interrupt MyHighlnt save=PROD
#pragma code high_vector=0x08 // high_vector по адресу 0x0008
void high_vector (void) // высокоприоритетный вектор
{
_asm GOTO MyHighlnt _endasm // переход на подпрограмму
// обработки
// вьсокоприоритетного прерывания
)
#pragma code
void DoOptical (void);
void DoTimerl (void);
void DoSPI (void);
void MyHighlnt(void) // новый фиксированный вектор
// высокоприоритетного прерывания
if (INTCONbits.INTOIF = 1) // если оптический считыватель
DoOptical();
else if (PIRlbits.TMR1IF == 1) DoTimerl(); И если таймер 1
else if (PIRlbits.SSPIF == 1) // если интерфейс SPI
DoSPI () ;
void SendFloor (void)
Глава 10. Вопросы повышенной сложности
493
unsigned char floor[l];
floor[0] = currentFloor;
while (!ECANSendMessage(1,
floor,
1,
ECAN_TX_STD_FRAME));
t
void WriteFifo (unsigned char data)
if (fifoINP == fifoOUTP && SPIbusy == 0)
{
SPIbusy = 1;
WriteSPI (data);
)
else
(
fifo[ fifoINP++ ] = data;
fifoINP &= 15;
}
unsigned int ReadFifo (void)
(
unsigned int retval = 0x100;
if (fifoINP != fifoOUTP)
(
retval = fifo[ fifoOUTP+4- ];
fifoOUTP &= 15;
}
return retval;
void DoSPI (void)
(
unsigned int data = ReadFifo();
PIRlbits.SSPIF == 0;
if (data != 0x100)
WriteSPI(data);
void DoOptical (void)
{
INTCONbits.INTOIF = 0;
if (barcodePtr != 0)
barcode[barcodePtr] = ReadTimerO() ;
WriteTimerO (0);
barcodePtr++;
void DoTimerl (void)
{
PIRlbits. TMR1IF == 0;
WriteTimerl (-488);
if (speak != 0)
{
WriteFifo (0x90); // речевое сообщение
WriteFifo (0x00) ;
494
Применение микроконтроллеров PIC 18
WriteFifo (speech [ speak
if (speechcounter == 2047
speak = speechCount'
}
if (timeDelayCounter != 0)
timeDelayCounter—;
if (door == 1 && PORTBbits.RBI
{
PORTAbits.RA2 = 0;
door = 0;
}
else if (door == 2 && PORTEbits
{
PORTAbits.RAI = 0;
door = 0;
}
[ speechCounter++ J);
ir = 0;
// шаг инкрементирования -- 1/2048 I'ti,
== 0)
RE2 == 0)
void CloseDoor (void)
{
while (door != 0);
PORTAbits.RA2 = 1;
door = 1;
// ожидание остановки двери
// закрытие двери
void OpenDoor (void)
{
while (door != 0);
PORTAbits.RAI = 1;
door = 2;
// ожидание остановки двери
// открытие двери
void CheckButtons (void)
{
char but = 0;
char mask = 0x10;
PORTC &= OxFC;
if ((PORTC & OxFO) != OxFO)
{
DelaylKTCYx(140);
if ((PORTC & OxFO) != OxFO)
{
PORTC != 1;
if ((PORTC & OxFO) ==
{
PORTC != (PORTC
but += 4;
}
while ((PORTC & mask)
{
mask «= 1;
but++;
}
but = keyt[but];
if (but == 6)
{
OpenDoor();
timeDelayCounte
OxFO)
& OxFC) | 2;
== mask)
= 2048 * 5; // 5 sec
Глава 10. Вопросы повышенной сложности
495
)
else if (but == 7)
CloseDoor () ;
else
callFloorf but ] |= 4;
)
)
)
// данные вызова этажа:
II 0 = вызова нет
// 1 = дистанционный вызов вверх
// 2 = дистанционный вызов вниз
// 4 = локальный вызов
void CheckCAN (void)
{
ECAN_RX_MSG_FLAGS flags;
if (ECANReceiveMessage (0, data, &dataLen, &flags))
{
if ((data[0] & 0x80) == 0x80)
callFloor[ data[0] & 0x7F ] |= 1;
else
callFloor[ data[0] ] 1= 2;
)
void LevelCar (void)
{
if (carMoving == 1)
{
barcodePtr = 0;
PORTAbits. RA3 = 1;
while (barcodePtr == 0);
PORTAbits.RA3 = 0;
barcodePtr = 0;
PORTAbits.RA4 = 1;
while (barcodePtr == 0);
PORTAbits.RA4 = 0;
barcodePtr = 0;
PORTAbits.RA3 = 1;
while (barcodePtr -= 0);
PORTAbits.RA3 = 0;
}
else
{
barcodePtr = 0;
PORTAbits.RA4 = 1;
while (barcodePtr == 0);
PORTAbits.RA4 = 0;
barcodePtr = 0;
PORTAbits.RA3 = 1;
while (barcodePtr == 0);
PORTAbits.RA3 = 0;
barcodePtr = 0;
PORTAbits.RA4 = 1;
while (barcodePtr == 0);
PORTAbits.RA4 = 0;
496
Применение микроконтроллеров PIC 18
unsigned char ReadBarcode (void)
1
char a;
unsigned int b = OxFFFF;
for (a = 0; a < 3; a++)
if (barcodefa] < b)
b = barcode[a] ;
b *= 3;
a = 0;
if (barcode[0] > b)
a | = 4 ;
if (barcode[1] > b)
a |= 2;
if (barcode[2] > b)
a |= 1;
a--;
return a;
void DoElevator (void)
{
char a;
if (state == 0)
{
for (a =0; a < 6; a++)
if (callFloor[a] != 0)
break;
if (a != 6)
{
if (currentFloor < a)
{
PORTAbits.RA4 = 1;
callDirection = 1;
speak = 7;
}
else
{
PORTAbits.RA3 = 1;
callDirection = 2;
speak = 8;
)
state = 1;
timeDelayCounter = 4092;
1
1
else if (state == 1)
{
barcodePtr = 0;
state = 2;
1
else if (state == 2)
{
if (barcodePtr == 4)
{
if (ReadBarcode() == a)
// перемещение кабины вверх
// сказать "вверх"
// перемещение кабины вниз
// сказать "вниз"
Глава 10. Вопросы повышенной сложности
497
(
currentFloor = а;
callFloor[a] = 0;
PORTAbits.RA4 = 0;
PORTAbits.RA3 = 0;
LevelCar();
OpenDoor();
speak = a; // сказать номер этажа
)
else
state = 3;
)
1
else if (state == 3);
{
state = 1;
timeDelayCounter = 4096;
1
void FindFloor (void)
unsigned char flr[l];
PORTAbits.RA4 = 1; И перемещение кабины вверх
timeDelayCounter = 4096; // 2 секунды
while (timeDelayCounter != 0); // ожидание
PORTAbits.RA4 = 0; // останов кабины
barcodePtr = 0;
PORTAbits.RA3 = 1; и перемещение кабины вниз
while (barcodePtr != 4); и ожидание штрих-кода
flr[0] = ReadBarcode();
while (!ECANSendMessage(0,
fir,
1,
ECAN_TX_STD_FRAME)) ;
PORTAbits.RA3 = 0; // останов кабины
carMoving = 2;
LevelCar();
speak = flr[0]; // сказать номер этажа
currentFloor = flr[0];
carMoving = 0;
void main (void)
(
char a;
ADCON1 = TRISA = TRISB = TRISC = TRISD = TRISE = = OxOF; 0; OxFB; 0; 0; 4; // И И И И И выбор цифрового 1 программирование программирование программирование программирование программирование звода-вывода порта А порта В порта С порта D порта Е
PORTA = PORTC = PORTD = SPIbusy = speak = 0;
timeDelayCounter = speechcounter = door = 0;
barcodePtr = carMoving = state = callDirection = 0;
for (a = 0; a < 6; a++)
callFloorfa] = bar codefa] = 0;
498
Применение микроконтроллеров PIC 18
ECANInitialize(); // инициализация CAN
INTCON2bits.RBPU =0; // включение нагрузок порта В
OpenTimerl (TIMER_INT_ON & // таймер на 1 мкс timer
T1_16BIT_RW &
T1_SOURCE_INT &
T1_PS_1_8);
WriteTimerl (-488); // срабатывание каждые 488 мкс
// 1/2048 Гц для аудио
OpenTimerO (TIMER_INT_OFF & // 32 мкс
ТО_16В1Т &
TO_SOURCE_INT &
T0~PS_1 256);
PIElbits.SSPIE = 1; // разрешение прерывания от SPI
RCONbits . IPEN = 0; // только высокоприоритетные прерывания вкл.
INTCON2bits.INTEDG0 =0; // объявление INTO переключаемым по
// отрицательному фронту
INTCONbits.INTOIE = 1; // разрешение INTO
INTCONbits.GIE =1; // разрешение прерываний
OpenSPI (SPI_FOSC_16, MODE_00, SMPEND); // конфигурирование штырьков
// порта SPI
WriteFifo (0x90); // установка нормального режима
WriteFifo (0x01);
WriteFifo (0x00);
WriteFifo (0x90); // динамик выкл.
WriteFifo (0x00);
WriteFifo (0x00);
speak = 9; // сказать "инициализация"
CloseDoor();
while (door != 0); // ожидание закрытия дверей
FindFloor();
OpenDoor();
timeDelayCounter = 2048 * 5; //5 секунд
while (1)
(
CheckButtons (); // проверка нажатия локальной кнопки
CheckCANO; // проверка CAN
if (timeDelayCounter == 0)
{
CloseDoor();
DoElevator(); // запуск лифта
Глава 10. Вопросы повышенной сложности
499
10.5. Интерфейс USB
Универсальная последовательная шина (USB) часто способна решить проблему
связи как для персонального компьютера, так и для многих встроенных приложений.
Эта шина обеспечивает скоростной последовательный информационный обмен, при
этом она подает электропитания на все подключенные к ней устройства. Другие пре-
имущества USB: легкость подключения устройств и доступ к вплоть до 127 различным
подключенным устройствам через последовательный кабель с четырьмя выводами.
Этот интерфейс идеален для внедренных микроконтроллеров, клавиатур, звуковых
плат, простых видеовоспроизводящих устройств и модемов. Скорость передачи дан-
ных равна 480 мбит/с в случае работы на полной скорости по стандарту USB 2.0,
11 мбит/с для информационного обмена в соответствии со стандартом USB 1.1 и
1,5 мбит/с при работе на минимальной скорости. В зависимости от версии PIC, ско-
рость передачи данных может устанавливаться либо в соответствии с USB 1.0, либо в
соответствии с USB 2.0.
Длина кабеля ограничена тремя метрами для полноскоростного интерфейса и
пятью метрами для медленного интерфейса. Максимальная мощность, доступная че-
рез эти кабели, может быть оценена как максимальный ток в 100 мА при напряжении 5
В. Если сила тока превысит 100 мА, то Windows отобразит желтый восклицательный
знак рядом с устройством, указывая этим состояние перегрузки устройства.
Соединительный разъем USB
Рис. 10.21 иллюстрирует разводку выводов соединительных разъемов USB. Оп-
ределены два типа соединительных разъемов USB и оба они используются. В каждом
случае в каждом соединительном разъеме имеется четыре штырька, на которые пода-
ются сигналы, указанные в табл. 10.2. Как уже упоминалось, +5 В и земля могут исполь-
зоваться для электропитания устройств, подключенных к шине, если только сила тока
не превысит 100 мА на устройство. Сигналы данных - это двухфазные сигналы. Когда
шина “+данные” находится в состоянии 3,3 В, шина “-данные” находится в состоянии 0
В и наоборот.
ТАБЛИЦА 10.2 . Цоколевка выводов USB
Номер вывода Сигнал
1 5.0 В
2 Данные
3 Данные
4 Земля
500
Применение микроконтроллеров PIC 18
Передача данных через USB
Сигналы данных - это двухфазные сигналы, которые генерируются с использова-
нием схемы типа, иллюстрируемого на рисунке 10.22. Приемник линии также иллюст-
рируется на рис. 10.22. К паре передающих проводов подключена схема шумоподав-
ления, изготовленная фирмой Texas Instruments (SN75240). После установки приемо-
передатчика, формирование интерфейса USB завершается. Интегральная схема 75773
от Texas Instruments в приведенной схеме может использоваться как дифференциаль-
ная схема управления линией и как приемник.
Теперь рассмотрим, как сигналы взаимодействуют на USB. Эти сигналы позво-
ляют передавать и получать данные из хост-компьютера. При передаче информацион-
ных пакетов USB использует кодировку сигналов NRZI (без возврата в ноль, инвертиро-
ванные). Этот метод кодирования не изменяет уровень сигнала при передаче логиче-
ской единицы, но уровень сигнала инвертируется при каждом изменении сигнала в
логический ноль. Рис. 10.23 иллюстрирует поток цифровых данных и соответствующие
сигналы USB при использовании названного метода кодирования.
Фактически передаваемые данные включают биты синхронизации, при этом ис-
пользуется метод, называемый вставкой битов. Если логическая единица передается
на протяжении более, чем шести битов в строке, то согласно методики вставки битов,
после шести непрерывных единиц вставляется дополнительный бит (логический ноль).
Поскольку это удлиняет поток данных, то этот метод называется вставкой битов. Рис.
10.24 показывает последовательный поток данных со вставленными битами, а также
алгоритм, используемый для того, чтобы создать этот поток из необработанных цифро-
вых последовательных данных. Методика вставки битов гарантирует, что приемник
сможет сохранять синхронизацию в случае длинных последовательностей единиц. Эта
же методика подразумевает вставку одного единичного бита в поток данных после
шести непрерывных нулей в строке. Данные всегда передаются последовательно, на-
чиная с младшего бита.
Команды USB
Для того, чтобы начать информационный обмен, сначала передается байт син-
хронизации (80Н), за которым следует байт идентификации пакета (PID). PID содержит
восемь битов, однако только самые правые четыре бита указывают тип пакета, который
будет следовать. Левые четыре бита PID - это биты, дополняющие правые четыре бита
до единиц. Например, если передается команда 1000, то фактически в PID будет пере-
дан байт 0111 1000. Табл. 10.3 демонстрирует доступные 4-битные PID и соответст-
Глава 10. Вопросы повышенной сложности
501
вующие им 8-битные коды. Обратите внимание на то, что PID используются в качестве
индикаторов лексем, индикаторов данных, а также для квитирования связи.
1101001100010
цифровые
данные
NRZI
Рис. 10.23. Данные в формате NRZI
Таблица 10.3. Коды PID (идентификации пакетов)
Код идентифи кассии Имя Тип Описание
Е1 OUT Лексема Хост-компьютер -->
—> функциональная операция
D2 АСК Квитирование связи Приемник квитирует пакет
СЗ DataO Данные Пакет данных (PID четный)
А5 SOF Лексема Начало фрейма
69 IN Лексема Функциональная операция--> хост-
компьютер
5А NAK Квитирование Приемник не принимает пакет
4В Datal Данные Пакет данных (PID нечетный)
ЗС PRE Специальный Преамбула хост-компьютера
2D Setup Лексема Команда настройки
1Е Stall Лексема Замедление
502
Применение микроконтроллеров PIC 18
Исходные и передаваемые данные
Начало
Рис. 10.24. Информационный поток и блок-схема алгоритма,
используемого для генерирования USB-данных.
Глава 10. Вопросы повышенной сложности
503
Рис. 10.25 иллюстрирует форматы данных, лексем, а также пакетов подтвержде-
ния связи и пакетов начала фрейма, передаваемых через USB. В пакете лексемы ADDR
(поле адреса) содержит 7-разрядный USB-адрес устройства. Как уже упоминалось ра-
нее, до 127 устройств могут присутствовать на USB одновременно. ENDP (терминаль-
ная точка) - 4-разрядное число, используемое USB. Терминальная точка 0000 исполь-
зуется /для инициализации, в то время как другие значения терминальных точек уни-
кальны для каждого USB-устройства.
Имеются два типа CRC (контроль циклическим избыточным кодом), используе-
мых при передаче данных через USB: 5-битный CRC и 16- битный CRC (используемый
для пакетов данных). 5-разрядный CRC генерируется согласно многочлена Х5 + Х2 + 1;
16-разрядный CRC генерируется согласно многочлена Х16 + Х15 + Х2 + 1. При форми-
ровании электронных схем, генерирующих или обнаруживающих CRC, знаки "+" пред-
ставляют логическую схему "исключающие ИЛИ". CRC- схема или программа - это по-
следовательный механизм проверки. При использовании 5-битного CRC остаточный
результат 01100 получается для случая отсутствия ошибок во всех пяти битах CRC и
битах данных. При использовании 16-битного CRC в случае отсутствия ошибок получа-
ется остаточный результат 1000000000001101.
USB использует лексемы АСК и NAK для координирования обмена информацион-
ными пакетами между хост-системой и USB-устройством. После того, как пакет данных
передан от хост-компьютера на USB устройство, USB устройство передает обратно на
хост-компьютер либо лексему АСК (подтверждение), либо лексему NAK (отсутствие
подтверждения). Если данные и CRC получены правильно, посылается АСК; если не-
правильно, то посылается NAK. Если хост-компьютер получает лексему NAK, то он бу-
дет повторно передавать пакет данных до тех пор, пока приемник в конце-концов не
получит его правильно. Этот метод передачи данных часто называют методом управле-
ния потоком данным с остановом и ожиданием. Хост-компьютер должен ожидать, пока
устройство-клиент не передаст АСК или NAK перед передачей последующих пакетов
данных.
504
Применение микроконтроллеров PIC 18
Пакет лексемы
8 битов 7 битов 4 битов 5 бигов
PID ADDR ENDP j CRC5
Начало пакета фрейма
8 битов
11 битов
5 битов
PID Frame Number CRC5
Пакет данных
8 битов от 1 до 1023 байт 1 б битов
PID Data CRC16
Пакет подтверждения связи
8 битов
PID
Рис. 10,25. Пакеты USB
PIC18 и USB
USB непосредственно поддерживается несколькими из микроконтроллеров
PIC18. Это позволяет микроконтроллерам подключаться к ПК и USB фактически для
любого применения, при котором необходима связь этого типа. Предусмотрена соот-
ветствующая библиотека для компилятора С18, однако она должна быть загружена с
вебсайта фирмы Microchip. Эта библиотека имеет имя MCHPFSUSB и находится в сек-
ции работы с высокоскоростной USB для стенда PicDem. Эта секция предполагает, что
необходимый файл уже загружен и установлен, так что иллюстрируемое программное
обеспечение может использоваться для программирования микроконтроллера
PIC18F4550, который включает быстродействующий интерфейс USB. Пакет содержит
библиотечные файлы для компилятора С18, а также драйвер, устанавливаемый в ПК с
тем, чтобы сделать возможным информационный обмен с микроконтроллером. Эти
функции, а также драйвер используются как основа любого USB-интерфейса между ПК
и микроконтроллером.
PIC18FX455/X550 Family
"1
VREGEN
EN
стабилизатор
3,3 в
f—13 vuse
! Внешний
источник 3,3 В
FSEN
UPUEN
LJTRDIS —
Тактовая частота
USB от модуля
генератора
конфигурирование
USB
USB
SIE
ЗУПВ
1 кбайт
нагрузки
L FS
полная
I
! CKOpOCTb
SPP7:SPP0
CKISPP
CK2SPP
CSSPP
OESPP
VMOW
ppo<1L
□ “♦И ОЕП)
| <-ЁЗ vmW
Внутренние
нагрузки
приемо-передатчик
Дополнительные
внешние
низкая
шина USB
Внешний приемо-передатчик
шина USB
Глава 10. Вопросы повышенной сложности
Примечания:
1. Этот сигнал может быть получен только при условии блокировки внутреннего приемо-передатчика (URDIS =1).
2. Внутренние нагрузочные резисторы должны быть отключены (UPUEN = 0), если используются внешние нагрузочные рези-
сторы.
3. Не активируйте внутренний стабилизатор, когда используется внешнее питающее напряжение 3,3 В.
Рис. 10.26. Внутренняя структура USB (с оазоешения Фирмы Microchip)
506
Применение микроконтроллеров PIC 18
Рис. 10.26 иллюстрирует внутреннюю структуру интерфейса USB в микрокон-
троллере PIC18F4550. Интерфейс USB PIC18 используется в этом подразделе для ор-
ганизации связи ПК через usbser.sys, который является драйвером, включенным в опе-
рационную систему Windows ХР (он также доступен в Windows 98SE и Windows 2000).
Благодаря использованию этого драйвера, отпадает необходимость в написании ново-
го драйвера для Windows.
Далее рассматриваются шаги, требуемые для того, чтобы проиллюстрировать
работу этого простого интерфейса с USB, а также то, как сконфигурировать программу,
как для микроконтроллера, так и ПК. Чтобы объяснить работу этого интерфейса ис-
пользуется эмуляция USB на RS-232C, ибо она наиболее проста в понимании и приме-
нима к интерфейсу между ПК и микроконтроллером. Microchip на своем вебсайте пре-
доставляет драйвер как для ПК, так и для PIC18, наряду с файлами работы с высоко-
скоростной USB для стенда PicDem. Программа, представленная здесь, предполагает,
что упомянутое программное обеспечение уже загружено, и драйвер для ПК установ-
Глава 10. Вопросы повышенной сложности
507
лен. Находясь в интегрированной среде разработки (IDE), загрузите рабочую область
(MCHPUSB.MCP) в папке C:\MCHPFSUSB\fw\Cdc, если пакет, полученный от Microchip,
установлен. Откройте файл user.c, в котором предусмотрено место для ввода про-
граммы пользователя, использующей USB и его подключение к ПК. Эта программа на-
писана для микроконтроллера PIC18F4550. Файл user.c приведен в примере 10.12.
Рис. 10.27 иллюстрирует PIC18F4550, связанный с ПК при помощи соединитель-
ного разъема интерфейса USB. Обратите внимание на то, что очень немного компонен-
тов требуются для формирования этого интерфейса, при этом микроконтроллер
PIC18F4550 может быть запитан от соединительного разъема USB, при условии, что вся
встроенная система не потребует тока, превосходящего 100 мА. В приведенной схеме
для питания USB используется напряжение внутреннего источника 3,3 В(вывод VUSB).
Пример 10.12
Программно- аппаратное обеспечение USB С18, Microchip версия 1.0
имя файла user.с
ссылки: смотрите секцию INCLUDES,приведенную ниже
процессор: PIC18
компилятор: С18 2.30.01+
оирма: Microchip Technology, Inc.
’ Лицензионное соглашение о программном продукте
’Программа, предоставляемая настоящим Microchip Technology
’Incorporated ("Компания") для ее микроконтроллера PICMICRO'
* предназначена и предоставляется Вам, клиенту Компании, для
'ее использования единственно и исключительно с
*микроконтроллерами PICMICRO0 Microchip. Эта программа
•’принадлежит Компании и-или ее поставщику и защищена согласно
'применимым законам об авторском праве. Все права
’зарезервированы. Любое использование в нарушении
’предшествующих ограничений может подвергнуть пользователя
'уголовному преследованию согласно применимых законов, а
’также сделать его объектом гражданской ответственности за
'нарушение условий и ограничений этой лицензии.
‘ЭТА ПРОГРАММА ПОСТАВЛЯЕТСЯ НА УСЛОВИЯХ "КАК ЕСТЬ". НИКАКИЕ
’ГАРАНТИИ НЕ ПРЕДОСТАВЛЯЮТСЯ, - ТО ЛИ ЯВНЫЕ, ТО ЛИ
'ПОДРАЗУМЕВАЕМЫЕ, ТО ЛИ УСТАНОВЛЕННЫЕ ЗАКОНОМ, ВКЛЮЧАЯ, НО НЕ
'ОГРАНИЧИВАЯСЬ, ПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ ПРИГОДНОСТИ ЭТОЙ
'ПРОГРАММ! ДЛЯ КОНКРЕТНЫХ ЦЕЛЕЙ. КОМПАНИЯ НЕ ДОЛЖНА В ЛЮБЫХ
'ОБСТОЯТЕЛЬСТВАХ НЕСТИ ОТВЕТСТВЕННОСТЬ ЗА НАМЕРЕННЫЕ, 'СЛУЧАЙНЫЕ ИЛИ
РЕЗУЛЬТИРУЮЩИЕ ПОВРЕЖДЕНИЯ, ВОЗНИКШИЕ ПО ЛЮБОЙ
’ПРИЧИНЕ.
Дата
Комментарий
' Рейзин Ройванит
11/19/04 Оригинал.
* * ж * > ж х Аг х ж А***АО***О******Х*****************'* AiAxitA + AAXX'AA'AAAAA'A' /
508
Применение микроконтроллеров PIC 18
* Указания по использованию эмуляции CDC RS-232
* Обращайтесь к указаниям по применению AN956 для CDC class.
* прежде всего обратитесь к Exercise_Example() и изучите, как вызываются функции.
* Имеются пять упражнений, каждое имеет решение в файле CDC\user\solutions.
’ Переместите экран вниз и найдите Exercise_01,_02,_03,_04 и _05.
* Рекомендации о том, что делать приведены внутри каждой функции.
/** включаемые файлы ********************************************************/
#include <pl8cxxx.h>
^include <usart.h>
#include "system\typedefs.h"
#include "system\usb\usb.h"
#include "io_cfg.h" // отображение штырьков ввода-вывода
#include "user\user.h"
#include "user\temperature.h"
/* * переменные ********************************************************/
#pragma udata
byte old_sw2,old_sw3;
char input_buffer[64];
char output_buffer[64];
rom char welcome[]={"PIC18F4550 Full-Speed USB - CDC RS-232 Emulation
Derno\r\n\r\n" } ;
rom char ansi_clrscr[]={"\xlb[2J"}; // Команда очистки экрана ANSI
/** прототипы класса private ***************************************/
void InitializeUSART (void);
void BlrnkUSBStatus (void);
BOOL Switch2IsPressed (void);
BOOL Swltch3lsPressed (void);
void Exercise_Example (void);
void Exercise_01 (void);
void Exercise_02 (void);
void Exercise_03 (void);
void Exercise_04 (void);
void Exercise_05 (void);
/* * объявления **************************************************I
#pragma code
void Userlnit (void)
{
mlnitAHLEDs () ;
mlnitAllSwitches();
old_sw2 = sw2;
old_sw3 = sw3;
InitTempSensor() ;
InitializeUSART() ;
)//end Userlnit
void InitializeUSART (void)
Глава 10. Вопросы повышенной сложности
509
TRISCbits.TRISC7=1;
TRISCbits.TRISC6=0;
SPBRG = 0x71;
SPBRGH = 0x02;
TX3TA = 0x24;
RC3TA = 0x90;
BAUDCON = 0x0 8;
P/en.a I.nitializeUSART
// прием
// передача
// 0x0271 для 48мГц -> 19200 бод
// активирование передачи BRGH=1
// непрерывный прием
// BRG16 = 1
/ к * ★х***-*-*****-*-'* **Л*********^***********************************
я функция:
void ProcessIO (void)
предварительные условия:
отсутствуют
вход:
выход:
отсутствует
отсутствует
побочные эффекты: отсутствуют
’ общая характеристика: эта функция является "держателем места" для
других пользовательских подпрограмм.
• Это комбинация задач, как связанных с USB, так и несвязанных с нею
* Примечания: нет
* л->*************************************************************!
void ProcessIO (void)
(
BlinkUSBStat_s();
/ ' пользовательские прикладные USB-задачи
if ((usb_device_state < CONFIGURED_STATE)||(UCONbits.SUSPND==1)) return;
Exercise_Example ();
Exerci se_01 ();
Exercise_02();
Exerci se_C3();
Exercise_04();
Exercise 05 ();
}//end ProcessIO
void ExerciseJExample (void)
(
static byte start_up_state = 0;
if (start_up_state == 0)
{
if (Switch2IsPressed())
start_up_state++;
else if (start_up_state == 1)
{
if (mUSBUSARTIsTxTrfReady())
{
putrsUSBUSART(ansi_clrscr);
start_up_state++;
}
)
else if (start_up_state == 2)
510
Применение микроконтроллеров PIC 18
(
if (mUSBUSARTIsTxTrfReady())
{
putrsUSBUSART("\rMicrochip Technology Inc., 2004\r\n");
start_up_state++;
)
)
else if (start_up_state == 3)
if (mUSBUSARTIsTxTrfReady())
{
putrsUSBUSART(welcome);
start_up_state++;
)
)
)//end Exercise_Example
void Exercise_01 (void)
{
/*
* Внесите в эту функцию код, посылающий литеральную строку с нуль-
ограничителем
* строка текста ("Hello World!\r\n") передается в ПК, когда нажат пере-
ключатель 2
* Полезные функции:
* Switch21 stressed() возвращает '1', когда нажат переключатель 2.
* putrsUSBUSART(...);
* Смотрите примеры в Exercise_Example();
* Помните, что вы должны контролировать готовность cdc_trf_state для
выполнения следующей операции переноса данных
* Когда готовность есть, значение должно Рыть равно CDC_TX_READY,
* или используйте макрос: mUSBUSARTIsTx.TrfReady ()
*/
/ * вставьте здесь код - 3 строки */
/* End */
}//end Exercise_01
rom char ex02_string[]={"Type in a string here.\r\n");
void Exercise_02 (void)
{
/*
* Напишите в этой функции код, который передает в ПК
*после нажатия переключателя 3 строку с нуль-ограничителем
*символов текста, сохраняемого в памяти программ, начиная от
*адреса, на который указывает указатель ex02_string.
* ex02_string объявляется непосредственно перед этой функцией.
* полезные функции:
* Switch3IsPressed() возвращает когда переключатель 3 нажат.
* putrsUSBUSART(...);
смотрите примеры в Exercise_Example();
Глава 10. Вопросы повышенной сложности
511
* Помните, что вы должны контролировать готовность cdc_trf_state для
выгод нения следующей операции переноса данных.
* Когда готовность есть, значение должно быть равно CDC_TX_READY,
* или используйте макрос: mUSBUSARTIsTxTrfReady()
* /
/* вставьте здесь код - 3 строки */
/* End */
}z/end Exercise_C2
void Exercise_03(void)
/*
* Напишите код в этой функции, который считывает данные с USB и
* переключает состояние светодиода D4, когда считывается значение дан-
ных, равное символу ASCII '1' (0x31)0
* Полезные функции:
* bytegetsUSBUSART (char *buffer, byte len) За деталями обращайтесь к
файлу cdc.c
* mLED_4_Toggle ();
* Используйте input_buffer[] для хранения данных, считанных с USB.
*/
/* вставьте здесь код - 3 строки */
'* 3rd */
; ''/end Exercise_03
v ла Ex.ercise_04 (void)
/ *
* Перед запуском Exercise__04 () , раскомментируйте обращение к
tnercise 01()
* в Process IO(); эта функция понадобиться при контроле
Switch2IsPressed().
* Вставьте код в эту функцию, который посылает следующие четыре байта
* данных: 0x30,0x31,0x32,0x33, когда переключатель 2 нажат.
* Обратите внимание на то, что эти данные не завершаются символом нуля.
Они размещены в памяти данных.
* полезные функции:
* Switch2IsPressed() возвращает '1', когда переключатель 2 нажат.
* mUSBUSARTTxRam(byte *pData, byte len) За деталями обращайтесь к файлу cdc.h.
* *
* Используйте output_buffer[] для хранения четырех байтов данных.
* Помните, что вы должны контролировать готовность cdc_trf_state для
выполнения следующей операции переноса данных
* Когда готовность есть, значение должно быть равно CDC_TX_READY,
* или используйте макрос: mUSBUSARTIsTxTrfReady()
*/
Применение микроконтроллеров PIC 18
'* вставьте здесь код - 7 строк */
/* End */
}//end Exercise_04
void Exercise_05 (void)
(
/*
* Деьюнстрационный стенд PICDEM для полноскоростной USB оборудован датчиком
* температуры. За деталями обращайтесь к файлам temperature.с и .h.
* Вызываются все функции, необходимые для сбора данных о температуре
* Эти функции обновляют данные несколько раз в секунду.
* В данном варианте программа выдает данные о температуре в ПК через UART.
* Вы можете проверить это, подключив последовательный кабель и настроив
* последовательный порт
* на 19200 бод, 8 битов данных, 1 стоп-бит,
* без паритета.
* Программа предполагает, что частота ЦП равна = 48 мГц
* для генерирования
* корректного значения SPBRG для передачи на скорости 19200 бод.
* Модифицируйте код для передачи строки символов ASCII, хранимой в
* cempString в ПК через USB вместо UART.
* Данные о температуре хранятся в массиве tempString
* з формате ASCII с нулевым ограничителем.
* полезные функции:
* putsUSBUSART(...);
* Помните, что вы должны контролировать готовность cdc_trf_state для
* выполнения следующей операции переноса данных
* Когда готовность есть, значение должно быть равно CDC_TX_READY,
* или используйте макрос: mUSBUSARTIsTxTrfReady!)
*/
static word ex05_count;
if (ex05_count == 0)
I
AcquireTemperature(); //считывание температуры от датчика
UpdateCelsiusASCII () ; // преобразование в ASCII-строку, сохраняемую в
// "tempString", смотрите файл temperature.с
/* модифицируйте код ниже - 3 строки */
putsUSART (tempString);
ex05_count = 10000;
/* End */
}
else
ex05_count-~;
}//end Exercise_05
A Функция:
void BlinkUSBStatus (void)
предварительные условия:
отсутствуют
Глава 10. Вопросы повышенной сложности
513
вход:
* выход:
отсутствует
отсутствует
побочные эффекты: отсутствуют
Назначение: BlinkUSBStatus включает и выключает светодиоды
в соответствии с состоянием
USB-устройства.
Примечание: макрос mLED находится в файле заголовка io_cfg.h
usb_device_state объявляется в usbmmap.c и модифицируется в
usbdrv.c, usbctrltrf.c и usb9.c
***************************************************************!
void BlinkUSBStatus (void)
(
static word led count=0;
if (led_count == 0)led_count =
led_count--;
#define mLED_Both_Off()
ftdefine mLED_Both_On()
#define mLED_Only_l_On()
ftdefine mLED_Only_2_On()
if (UCONbits.SUSPND == 1)
1
if (led_count==0)
1
mLED_l_Toggle();
mLED_2 = mLED_l;
)//end if
)
else
10000U;
{mLED_l_Off();mLED_2_Off();}
{mLED_l_On();mLED_2_On();)
{mLED_l_On();mLED_2_Off();)
{mLED_l_Off();mLED_2_On();}
//оба мигают одновременно
if (usb_device_state == DETACHED_STATE)
1
mLED_Both_Off();
else if (usb_device_state == ATTACHED_STATE)
1
mLED_Both_On();
}
else if (usb_device_state == POWERED_STATE)
{
mLED_Only_l_On();
else if (usb_device_state == DEFAULT_STATE)
1
mLED_Only_2_On();
else if (usb_device_state == ADDRESS_STATE)
1
if (led_count == 0)
{
mLED_l_Toggle ();
mLED_2_Off () ;
)//end if
)
else if (usb_device_state == CONFIGURED_STATE)
514
Применение микроконтроллеров PIC 18
if (led_count==0)
{
mLED_l_Toggle();
mLED_2 = ImLED
)//end if
}//end if (...)
)//end if (UCONbits.SUSPND. .. )
P/end BlinkUSBStatus
BOOL 5witch2lsPressed (void)
{
if (sw2 != old_sw2)
old_sw2 = sw2;
if (sw2 == 0)
return TRUE;
}//end if
return FALSE;
}//end Switch2IsPressed
BOOL Switch3lsPressed(void)
{
if (sw3 != old_sw3)
{
old_sw3 = sw3;
if (sw3 == 0)
return TRUE;
)//end if
return FALSE;
)//end Switch3lsPressed
// альтернативное мигание
// сохранение нового значения
// если нажато
// было нажато
// не было нажатия
// сохранение нового значения
// если нажато
// было нажато
// нажатие не было
/*‘ EOF user.с **************************************************************/
Чтобы проиллюстрировать использование этой оболочки, сначала удалим все
строки программного кода, за исключением тех, которые показаны в примере 10.13.
Это удалит все примеры, которые не относятся к приложению, разработанному в тек-
сте, и сформирует рабочую оболочку для разработки USB- программ, осуществляющих
связь с ПК. Как можно видеть, большая часть программного кода удаляется, обеспечи-
вая рабочую оболочку для USB-приложений.
Пример 10.13
** Оболочка приложений USB версии 2.0 ***********************/
Должна использоваться с файлами, предоставляемыми Microchip для USB
/** включаемые файлы **************************’*****************************/
#irelude <pl8cxxx.h> // добавьте эту строку
((include "system\typedefs.h"
((include "system\usb\usb.h"
((include "user\user.h"
/*’ переменные
((pragma udata
********************************************************/
Глава 10. Вопросы повышенной сложности
515
// здесь объявляются переменные
объявления ****-***************’************»*****************/
it р 1 ciCJ-Tici СОСсЭ
v j i d Userinit
(
// здесь выполняется инициализация
///end Userlnit
void ProcessIO (void)
{
// здесь выполняются любые задачи ввода-вывода
}//end ProcessIO
Другой способ управления USB состоит в том, чтобы создать оболочку, которая
использует включаемые файлы пакета и главную функцию main.с. Эта методика ис-
пользуется здесь для того, чтобы разработать простое приложение, а оболочка для
main.с показана в примере 10.14. К программе из примера 10.14 добавлены включае-
мые файлы, иллюстрируемые на рис. 10.28.
Пример 10.14
Пример оболочки, которая использует USART-эмуляцию USB
rinclide ,р18сххх.'г.
^rcl-de "systemxtypedefs.h"
#ir!C±_ide "system\usb\usb.h"
«ir.cljde "io_cfg.h"
// Необходим
// Необходим
// Необходим
* Установка битов конфигурации
’ - установка внутренней синхронизации
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
- разрешение общего сброса
/
^pragma config FOSC = HSPLL_HS
tfpragma config PLLDIV = 1
tfpragma config VREGEN = ON
tfpragma config WDT = OFF
tfpragma config LVP = OFF
«pragma config BOR = OFF
*t pragma config MCLRE = ON
void MyHighlnt (void);
11 прототипы
tfpragma interrupt MyHighlnt
«pragma code high_vector=0x08
void high_vector (void)
save=PROD
// high_vector по адресу 0x0008
// высокоприоритетный вектор
asm GOTO MyHighlnt endasm
// переход на подпрограмму
516
Применение микроконтроллеров PIC 18
обработки высокоприоритетных прерываний
#pragma code
void MyHighlnt (void)
)
// main program
void main (void)
{
mlnitializeUSBDriver() ;
)
// смотрите usbdrv.h
m4550.mcp
3 Source Files
< cdc.c
example l.c
usb9.c
usbctrltrf.c
usbdrv.c
• usbdsc.c
usbmmap.c
S Header Files
io_cfg.h
p!8f455O.h
typedefs.h
usb.h
usbcfg.h
usbdrv.h
usbmmap.h
Object Fites
; Library F8es
S Linker Scripts
18f4550.lkr
Other Files
Рис. 10.28. Снимок экрана файлов проекта
(главная программа находится в файле 1 .с)
Теперь, когда мы имеем оболочку для программирования USB, нам нужно распо-
лагать примером интерфейса с тем, чтобы проиллюстрировать работу USB с персо-
нальным компьютером. Предположим, что нам необходима система для того, чтобы
проверять блоки питания ПК в исполнении АТХ. Рассматриваемая далее система раз-
работана для того, чтобы проверять блоки питания мощностью 250 Вт, однако она мо-
Глава 10. Вопросы повышенной сложности
517
жет проверять и более мощные блоки питания ПК в режиме частичной нагрузки, Более
новые блоки питания имеют 24-штырьковый соединительный разъем, поэтому для их
подключения при проверке необходимо использовать соответствующий ответный
разъем. После того, как оператор подключает блок электропитания, система проверяет
его и отображает значения напряжения, подаваемые на ПК. Чтобы сформировать эту
систему, используется микроконтроллер для того, чтобы контролировать напряжения,
кроме того написано приложение на Visual С, отображающее напряжения на ПК. При-
ложение на Visual С трактует PIC как последовательный СОМ порт, поэтому нет необхо-
димости в использовании специального драйвера, чтобы завершить приложение со
стороны ПК. Единственное, что страдает при использовании этой методики - так это
скорость передачи, которая ограничена установкой скорости передачи для СОМ порта
в программе на Visual С. Во многих приложениях это не вызывает никаких проблем.
Рис. 10.29 иллюстрирует подключение PIC18F4550 для этого применения, а
табл. 10.4 показывает цоколевку выводов разъема блока электропитания ПК исполне-
ния АТХ. Блок питания АТХ имеет четыре выходных напряжения: + 12 В, -12 В, + 5 В и
+ 3,3 В. Каждый из этих выходов нагружается средней нагрузкой и контролируется АЦП
внутри микроконтроллера. АЦП может принимать максимум только 5 В, так что входное
напряжение уменьшается, используя делитель напряжения. В случае напряжения -12 В
операционный усилитель изменяет полярность и снижает напряжение. Сигнал +12 В
снижается с использованием коэффициента деления, равного 4, сигнал -12 В снижает-
ся с использованием коэффициента деления, равного 3 и инвертируется, сигнал +5 В
снижается с использованием коэффициента деления, равного 2, а сигнал 3,3 В не сни-
жается. Это дает предельные напряжения, равные 3 В, 4 В, 2,5 В и 3,3 В для напряже-
ний электропитания контролируемых микроконтроллером — все они попадают в при-
емлемые границы значений входных сигналов АЦП.
Программа, которая считывает напряжения блока питания АТХ и посылает их че-
рез USB в ПК показана в примере 10.15. Эта программа посылает в ПК символьную
строку с числом 1 в коде ASCII в качестве первого символа строки для необработанного
отсчета по каналу 12 В, считанного с АЦП. Необработанный отсчет по каналу 3,3 В по-
сылается в ПК, начиная с ASCII-кода цифры 2, необработанный отсчет по каналу -12 В,-
начиная с ASCII-кода цифры 3, а необработанный отсчет по каналу +5V, - начиная с
ASCII-кода цифры 4. Программа, выполняющаяся в ПК, должна преобразовать считан-
ные с АЦП необработанные отсчеты в фактические значения напряжения. В этом при-
мере напряжения считываются и посылаются в ПК один раз каждую половину секунды.
Таблица 10.4. Цоколевка выводов разъема блока питания АТХ.
Номер штырька Напряжение Номер штырька Напряжение
1 + 3,3 В 13 +3, 3 В
2 + 3, 3 В 14 -12 В
3 Земля 15 Земля
4 + 5 В 16 #PS ON
5 Земля 17 Земля
б +5 В 18 Земля
7 Земля 19 Земля
8 PWR ОК 20 Не используется
9 +5 В (дежурный 21 + 5 В
режим)
10 + 12 В 22 + 5 В
11 + 12 В 23 + 5 В
12 + 3, 3 В 24 Земля
518
Применение микроконтроллеров PIC 18
Пример 10.15
/ '
' Систем 1 контроля напряжений,
' с использованием USB
снимаемых с блока литания АТХ,
Иinclude
tf tnclude
ft lr.clade
ft include
if include
ft include
#include
<d18cxxx. >
"system\typedets.h"
"system\usb\usb. hzz
"io_cfg.h"
<timers.h>
<adc.h>
<stdlib.h>
/* Установка битов конфигурации
* ' - установка режима синхронизации HS (4 мГц)
* - выключение сторожевого таймера
* - выключение низковольтного программирования
* - отключение сброса по частичной потере питания
* - разрешение общего сброса
* /
tfpragma config FOSC = HSPLL_HS
tfpragma config PLLDIV = 1
tfpragma conf ig VREGEN = ON
I ox agma config WDT = OFF
*fpr agma config LVP = OFF
or agma config BOR = OFF
•i oi agma config MCLRE = ON
слаг buffer [4] [20];
слаг stace = 4;
vozd MyHighlnt (void);
// прототипы
tfpragma interrupt MyHighlnt
tfpragma code high_vector=0x08
save=PROD
// high_vector по адресу 0x0008
void high_vector (void)
_asm GOTO MyHighlnt _endasm
// высокоприоритетный вектор
// переход на подпрограмму обслуживания
// высокоприоритетного прерывания
tfpragma code
void USBTasks (void)
{
/*
* обслуживание аппаратных средств
*/
USBCheckBusStatus (); // должен использоваться метод опроса
if (UCFGbits.UTEYE!=1)
USBDri'. erService () ; // прерывание или метод опроса
tfif defined(USB_USE_CDC)
CDCTxService() ;
tfeadif
i end JSBTasks
Глава 10. Вопросы повышенной сложности
519
void GetADC (char channel, char number)
(
char a;
SetChanADC (channel);
ConvertADC();
for (a = 0; a < 20; a + + )
buffer[number][a] = 0;
while (BusyADCO);
buffer[number][0] = number + 0x31;
itoa(ReadADC(), buffer[number] + 1) ;
vjid MyHighlnt (void)
char a;
if (PIRlbits.TMR1IF == 1)
{
PIRlbits.TMR1IF = 0;
WrrteTimer1 (-62500 )
GetADC (ADC_CH0, 0);
GetADC (ADC_CH1, 1);
GetADC (ADC_CH2Z 2);
GetADC (ADC_CH3, 3);
state " 0;
)
// начало передачи
I/ main program
void main (void)
i
OpenTimerl (TIMER_INT_ON &
T1_8BIT_RW &
T1_SOURCE_INT &
T1_PS_1_8);
WriteTimerl (-62500 );
OpenADC (ADC FOSC_2 &
ALC_RIGHT_JUST &
ADC_0_TAD,
;-.dc_cho &
ADC_INT_OFF,
?x3E);
Z MTCONoil c.G1E H — 1;
mi.’ucial izeU^BDriver () ;
w n i L e (1)
i
JSBTasks();
if (mUGBUSARTIsTxTtfReady()
// настройка таймера 1
// каждую половину секунды
// смотрите Lsbdrv.h
// необходимо обеспечивать подкачку
&& state != 4)
.?utsUSBUSAR'i (buffer [state] ) ;
£tate++;
Рис 10.29. Система проверки напряжений, снимаемых с блока питания АТХ
Применение микроконтроллеров PIC18
Глава 10. Вопросы повышенной сложности
521
Драйвер для ПК устанавливается, когда ПК обнаруживает, что USB-устройство
подключено к USB-порту. На экране появится сообщение о новом оборудовании, когда
будет подключена система, описанная здесь. В диалоговом окне Add new hardware
(Добавление новых аппаратных средств) выберите папку.
C:\MCHPFSUSB\Pc\MCHPUSB Driver\Release и установите драйвер интерфейса USB со
стороны ПК. Как только драйвер будет установлен, написанная программа будет счи-
тывать напряжения из системы проверки блоков электропитания АТХ и отображать их
на экране дисплея ПК. Пример соответствующего приложения, написанного на
Microsoft Visual С, приведен в примере 10.16, а диалоговое окно, используемое для
отображения значений напряжения, показано на рис. 10.30. Этот пример использует
интерфейс HID (человеко-машинный интерфейс), который является частью Windows и
не требует никакого специального драйвера для ПК и Windows. HID эмулирует USB как
COM-порт и обеспечивает максимальную скорость передачи данных в 64 кбит/с, что
является адекватным для большинства микроконтроллерных приложений. Единствен-
ная программа, которую нужно предоставить Windows - это файл .inf, который разме-
щен в пакете от Microchip, - он должен быть установлен как описано выше. Когда .inf
файл будет установлен в процессе добавления новых аппаратных средств, сообщение
о которых появляется, когда PIC-система подключается к порту USB, ПК выбирает сле-
дующий доступный СОМ порт для подключения USB.
Программа, используемая в персональном компьютере показана в примере
10.16. Эта программа формирует диалоговое окно, показанное на рис. 10.30. Приве-
денный листинг программы показывает только ту ее секцию, которая добавляется к
стандартному диалоговому приложению. Единственным исключением является то, что
одна строка кода — SetTimer (1, 10, 0); — добавлена к функции OnlnitDialog после опе-
ратора TODO:. Это запускает программу, показанную в примере 10.16 таким образом,
что по истечении 600 миллисекунд выполняется считывает через USB из системы кон-
троля напряжений блока электропитания, описанной в этом подразделе. Программа
предполагает, что COM3 поставлен в соответствие устройству аппаратным нумерато-
ром Windows. Для того, чтобы эта система функционировала правильно, микроконтрол-
лер должен быть подключен к USB перед запуском программы в персональном компью-
тере.
Рис. 10.30. Снимок экрана.
Проверка величин напряжений источников питания
522
Применение микроконтроллеров PIC 18
Пример 10.16
nd DpicusbDlg::OnTimer(UINT nIDEvent)// управление передается сюда через
каждые 600 мс
(
спаг number;
doable actualReading;
inc placeholder;
int rawReading;
char buf fer[2 0];
if (nIDEvent == 1)
KillTimer (1); // блокировка таймера
number = ReadByte ("COM3"); // считывание байта идентификации
placeHolder = 0;
do // получение целого значения в коде
ASCII
buffer[placeHolder] = ReadByte ("COM3");
while (buffer[placeHolder++] != 0 );
rawReading = atoi (buffer);
if (number = '1') // обработка напряжения питания +12 В
{
actualReading = rawReading * 4 * 0.00488759;
gcvt (actualReading, 5, buffer);
Labell.put_Caption (buffer);
}
else if (number == '2')/ // обработка напряжения питания 3,3 В
actualReading rawReading * 0.00488759;
gcvt (actualReading, 5, buffer);
Label 4.put_Caption (buffer);
else iC (number == '3') // обработка напряжения питания -12 В
actualReading = -rawReading * 3 * 0.00488759;
gcvt (actualReading, 5, buffer);
Label2.put_Caption (buffer);
else // обработка напряжения питания 5 В
{
actualReading = rawReading * 2 * 0.00488759;
.gcvt (actualReading, 5, buffer) ;
Label3.put_Caption (buffer);
Setlimer (1, 600, 0); // таймер перезапуска
)
CDialog:iGnTimer (nIDEvent);
}
int CpicusbDlg::ReadByte (CString Portspecifier)
(
DCB deb;
inc retVal;
BYTE Byte;
DWORD dwBytesTransferred;
DWORD dwCommModemStatus;
HANDLE hPort CreateFile (
ForcSpec i fie. ,
GENERIC_READ,
0,
Глава 10. Вопросы повышенной сложности
523
NULL,
OPEN_EXISTING,
0,
NULL
) ;
if (IGetCommState(hPort,&dcb))
return 0x100;
dcb.BaudRate = CBR_9600; //9600 baud
deb.ByteSize = 8; //8 data bits
deb.Parity = NOPARITY; //no parity
dcb.StopBits = ONESTOPBIT; //1 stop
if (!SetCommState(hPort,&dcb))
return 0x100;
SetCommMask (hPort, EV_RXCHAR I EV_ERR); //событие приема символа
WaitConunEvent (hPort, &dwCommModemStatus, 0); //ожидание символа
if (dwCommModemStatus & EV_RXCHAR)
ReadFile (hPort, &Byte, 1, SdwBytesTransferred, 0); //read
else if (dwCon,inModemStatus & EV_ERR)
retVal - 0x101;
recVal - Byte;
CloseHandle (hPort);
return retVal;
Таблица 10.5 Команды расширенного набора команд PIC18
Код опера- 16-разрядное Воздей- ствуе-
ПИИ, Описание Циклы командное мое Прим.
операнды слово состоя-
ние
ADDFSR f, к Прибавляет к к FSR 1 1110 1000
ffkk кккк
ADDULNK к Прибавляет and return к к FSR2 2 1110 1000 11кк кккк
CALLW Вызывает подпро- грамму, используя WREG 2 0000 0000 0001 0100
MOVSF z fd Перемещает z.3 з fd 2 1110 1111 ffff 1011 ffff Ozzz zzzz ffff
MOVSS z zd Перемещает z.5 в zrJ 2 1110 1111 1011 xxxx Izzz xzzz zzzz zzzz
PUSHL к Сохраняет к по ад- ресу FSR2, декре- ментирует FSR2 1 1110 1010 kkkk kkkk
SUBFSR f, к Вычитает к из FSR 1 1110 1001 ffkk kkkk
SUBUNLK : к Вычитает к из FSR2, retz rn 2 1110 1001 llkk kkkk
f - 8-разрядная ячейка регистрового файла данных (от 0x00 до OxFF)
к - литеральное значение
zs - 7-разрядное значение смещения адреса при косвенной адресации для источника
Zo - 7-разрядное значение смещения адреса при косвенной адресации для приемника
524
Применение микроконтроллеров PIC 18
10.6. Расширенный набор команд PIC18
Команды расширенного набора команд используются с версией компилятора
С18, которая может быть приобретена отдельно. Бесплатная версия компилятора не
использует команды расширенного набора команд. Расширенный набор команд вклю-
чает восемь новых команд, которые перечислены в таблице 10.5. Эти команды по умол-
чанию заблокированы и чтобы их использовать, они должны быть разрешены установ-
кой бита конфигурации XINST. Поскольку бесплатная версия компилятора не поддер-
живает эти команды, то чтобы их использовать без покупки компилятора программа
должна быть написана на Ассемблере.
Как можно видеть из табл. 10.5, расширенные команды имеют дело главным об-
разом с регистром FSR2. Основная цель расширенных команд состоит в том, чтобы
обеспечить эффективный метод адресации программного стека данных. Возможно, что
вы помните из главы 4, что в примерах на применение стека данных использовался
FSR2 в качестве указателя стека. При этом программа, работавшая со стеком данных,
для занесения числа в стек должна была выполнить две команды: литеральную коман-
ду, а затем команду move. Расширенный набор команд содержит команду PUSHL, кото-
рая выполняет ту же самую задачу, что и две команды из главы 4. Пример 10.17 иллю-
стрирует оба метода занесения числа 6 в программный стек данных, адресуемый через
FSR2. Обратите внимание, что при использовании команды PUSHL в программе эконо-
мится одна команда.
Пример 10.17
; код, который использует стандартные команда! для занесения числа 6 в стек данных:
MOVLW 6 ;заносит 6 в стек
MOVWF POSTDEC2
; код, который использует расширенные команда! для занесения числа 6 з стек данных:
PUSHL 6
; код для извлечения числа 6 из стека:
MOVF PREINC2, 0 /извлекает 6 из стека
;и сохраняет его в ячейке О
Расширенный набор команд также содержит две новые индексные команды
move. Обе эти команды используют содержимое FSR2 с тем, чтобы индексировать па-
мять, и обе позволяют выполнять операцию перемещения данных типа “память-
память”. Команда MOVSS перемещает данные из одной индексированной ячейки памя-
ти в другую. Команда включает оба смещения от ячейки памяти, адресуемой FSR2. Ко-
манда MOVSF перемещает содержимое ячейка памяти, адресуемой FSR2 плюс смеще-
ние, в ячейку памяти данных.
Команды ADDFSR и SUBFSR позволяют 6-разрядному литералу складываться или
вычитаться из любого регистра FSR. Хотя эта конструкция не имеет никакого специфи-
ческого использования, она позволяет добавлять маленькие числа к регистру FSR для
поиска данных в базе данных или же для иных подобных целей.
Команды ADDUNLK и SUBUNLK фактически представляют собой команды воз-
врата, которые модифицируют содержимое регистра FSR2 с использованием 6-
разрядного литерала. Эти команды (особенно команда SUBUNLK) позволяют выпол-
нить при возврате автоматическое извлечение данных, занесенных в стек. Пример
Глава 10. Вопросы повышенной сложности
525
10.18 иллюстрирует, как команда SUBUNLK используется для того, чтобы удалить из
функции данные, занесенные в стек.
Пример 10.18
; функция, которая заносит три значения в стек данных, а затем восстанавливает
их командой SUBUNLK
MyFunc:
.PUSHL б
PUSHL 8
PUSHL 3
; do things
SUBUNLK 3 ; возврат и разгрузка стека
Последняя команда расширенного набора команд - это команда CALLW, которая
подобна CALL, но заменяет значение в PCL значением из WREG вместо того, чтобы ис-
пользовать адрес функции, как команда CALL. Эта команда позволяет использовать
различные функции или адреса перехода с обращением к ним из таблицы. Пример
10.19 иллюстрирует соответствующее приложение. В этом примере значение из WREG
задает адрес функции в поисковой таблице. Программа использует 0, чтобы выбрать
functionO, 1, чтобы выбрать functionl и т.д. Эта программа имеет некоторые ограниче-
ния. Начальный адрес должен быть установлен на ячейку памяти, адрес которой закан-
чивается на 0x00, а значение во WREG при вызове Sfunc должно находиться между 0 и
0x3F. Максимальное число функций для этой программы равно 64. Команда CALLW ко-
пирует команду вычисляемого GOSUB, имеющуюся в языке Basic. Можно также имити-
ровать команду вычисляемого GOSUB, заменив команду CALL командами GOTO.
Пример 10.19
ORG 0x1000 /необходимо использовать начальный адрес, который
заканчивается на 00
; функция sfunc может быть использована для системных вызовов
; содержимое WREG должно быть меньшим, чем 64
S func;
RLNCF WREG /умножает WREG на 4
RLNCF WREG
ADDLW 10 /смещает WREG на 8
CALLW /функция вызова
CALL FunctionO /для WREG = 0
CALL Functionl / для WREG = 1
CALL Funct ion2 / для WREG = 2
здесь вставляются дополнительные вызовы
526
Применение микроконтроллеров PIC 18
10.7. Резюме
1. В PIC18 память расширяется посредством подключения последовательного
ЭСППЗУ к нескольким выводам порта. Интерфейс ЭСППЗУ управляется программой,
которая генерирует последовательные данные для этого интерфейса.
2. В редких случаях, когда два дополнительных запоминающих устройства недос-
таточны, формируется второй последовательный интерфейс, предназначенный для
работы с третьим и четвертым запоминающим устройством. Память может добавлять-
ся как отдельными запоминающими устройствами, так и парами этих устройств, управ-
ляемых одним последовательным интерфейсом.
3. Наиболее распространенными штрих-кодами, используемыми в универсаль-
ных магазинах, являются коды UPC-А или UPC-Е. Код UPC-А кодирует товары с исполь-
зованием 12-разрядных цифр, а код UPC-Е кодирует товары с использованием 6-
разрядных цифр.
4. Функция прерывания по изменению состояния, наряду с таймером, использу-
ется с UPC-кодами, полученными от оптического считывателя.
5. Блок начальной загрузки - это секция памяти программ (по крайней мере 512
байтов), которая защищена от перезаписи при перепрограммировании микроконтрол-
лера. Блок начальной загрузки содержит программу, называемую начальным загрузчи-
ком, которая загружает память новой программой при перепрограммировании.
6. Память программ внутри микроконтроллера размещена в ЭСППЗУ, которое
программируется во многом так же, как и ЭСППЗУ данных. Основное различие состоит
в том, что несколько битов в регистрах конфигурации разрешают или запрещают про-
граммирование. Это обеспечивает защиту памяти программ.
7. Ввод-вывод расширяется в тех случаях, когда ввод-вывод микроконтроллера
является недостаточным. Такое расширение требует использования нескольких
штырьков ввода-вывода, формирующих последовательный интерфейс с устройствами
расширения ввода-вывода, производимыми фирмой Microchip или одной из многих
других компаний. Как правило, более эффективно приобрести больший микроконтрол-
лер, чем применять расширение ввода-вывода, как описано в данной книге. Однако
некоторые ситуации требуют, чтобы было доступно большее количество устройств вво-
да-вывода, чем обеспечивается любой версией микроконтроллера, - в этих случаях
следует использовать расширение ввода - вывода.
8. Интерфейс CAN (управляющая локальная сеть) функционирует во многом так
же, как локальная сеть Ethernet, однако CAN спроектирован для работы в зашумленных
средах.
9. Программный слой управления CAN обеспечивается файлом заголовка от
Microchip, который называется ECAN.H. Этот файл обеспечивает все обычные функции
управления и функции передачи данных, необходимые для использования CAN.
10. USB (универсальная последовательная шина) была разработан для того, что-
бы заменить порты СОМ и LPT в ПК USB-портами, которые функционируют со скоро-
стями в 1 мбит/с, 11 мбит/с и 480 мбит/с. Последняя версия USB 2.0 функционирует
на скорости в 480 мбит/с, что достаточно для приема видеопотоков, а также одновре-
менного выполнения ряда других функций. USB допускает подключение к одной шине
вплоть до 127 устройств.
11. USB управляется программой, поставляемой Microchip, она весьма просто
подключается к ПК. ПК требует либо наличия драйвера, либо же он может обращаться к
USB, как будто это СОМ-порт, - этот метод рассматривался в этой книге. Поскольку
применения микроконтроллера обычно не связаны в быстродействующем канале связи
с ПК, то в большинстве случаев - это самый лучший метод связи микроконтроллера с
Глава 10. Вопросы повышенной сложности
527
ПК через USB. Это особенно справедливо в силу того, что не нужно писать никаких
драйверов, обеспечивающих связь ПК с микроконтроллером через этот интерфейс.
12. Команды расширенного набора команд для PIC18 добавляют дополнительную
функциональность индексным регистрам FSRO, FSR1 и FSR2 и, в особенности, - FSR2.
Представляет интерес команда PUSHL, которая обеспечивает создание стека данных с
меньшей программной избыточностью.
13. Команды расширенного набора команд доступны для использования на языке
С только в случае, когда приобретена полная версия компилятора С18.
10.8. Вопросы и задания
1. Какая память может быть использована для расширения памяти микрокон-
троллера PIC18?
2. Поскольку ЭСППЗУ является последовательным устройством, какая интер-
фейсная программа должна использоваться для связи ЭСППЗУ с микроконтроллером?
3. Какие объемы ЭСППЗУ доступны для расширения памяти?
4. Для какой цели в системе используются A-входы последовательного ЭСППЗУ?
5. Сколько последовательных ЭСППЗУ могут подключаться к одному последова-
тельному интерфейсу без буферизации?
6. Какова скорость передачи последовательного интерфейса ЭСППЗУ?
7. ЭСППЗУ содержит управляющий байт. Каково его назначение?
8. Опишите функцию импульса АСК последовательного ЭСППЗУ.
9. Каково назначение функции АСК в примере 10.1?
10. Для примера 10.1 опишите, как адрес выбирает одно устройство памяти или
другое.
11. Каково различие между UPC-А и UPC-E?
12. Выведите на принтер UPC-Е код, полученный из числа 123456.
13. Какая микросхема серии DS275 используется в качестве схемы управления в
интерфейсе, показанном на рисунке 10.7?
14. Основной цикл программы по примеру 10.2 чрезвычайно короток. Каково его
назначение в системе?
15. Как в программе из примера 10.2 читается UPC-код из оптического считывателя?
16. Какие операции используются функцией GetUPC в программе из примера 10.2?
17. Как информация, сохраненная в буфере UPC-кодов, посылается в ПК в при-
мере 10.2?
18. Что представляет собой блок начальной загрузки, имеющийся во многих мик-
роконтроллерах PIC18?
19. Каково назначение программы начальной загрузки?
20. Почему важно иметь возможность перепрограммировать микроконтроллер?
21. Опишите, как защищен блок начальной загрузки в микроконтроллере.
22. Опишите, как в примере 10.3 перемещены векторы сброса, высокоуровневого
прерывания и низкоуровневого прерывания.
23. Каково назначение бита СР (защита кода), бита WRT (защита от записи) и бита
EBTR (табличное считывание внешнего блока).
24. Объясните различие между табличной командой языка встроенного Ассемб-
лера с ее формой для стандартного Ассемблера в случае примера 10.4.
25. Кратко объясните, как расширяется ввод-вывод в семействе микроконтрол-
леров PIC18.
26. Что представляет собой интегральная микросхема 74НС594?
528
Применение микроконтроллеров PIC 18
27. Сколько выводов ввода-вывода микроконтроллера требуется для подключе-
ния 74НС594?
28. Что представляет собой двухпроводный интерфейс, предназначенный для
расширения ввода-вывода?
29. Каково назначение ТС1320?
30. Объясните, как работает программа, приведенная в примере 10.9.
31. Что такое CAN?
32. Какова максимальная длина шины CAN для работы на скорости 40 кбит/с?
33. Какова максимальная длина шины CAN для работы на скорости 1 мбит/с?
34. Сколько узлов могут быть подключены к шине CAN до того, как понадобится
буферизация?
35. Каков номинал оконечных резисторов, используемых на шине CAN, и каково
их назначение?
36. Какой библиотечный файл заголовка используется для того, чтобы управлять
шиной CAN?
37. Каково назначение узлов шины CAN, используемых в системе управления
лифтом, описанной в этой главе?
38. Дайте общее описание работы программы контроллера этажа, приведенную в
примере 10.10.
39. Дайте общее описание работы программы контроллера кабины лифта, приве-
денную в примере 10.11.
40. Что такое USB и каковы значения скорости информационного обмена в
имеющихся ее версиях?
41. USB обеспечивает напряжение питания для любого устройства, которое к ней
подключено, однако потребление тока ограничено значением в мА.
42. USB подключается через-проводной кабель.
43. Каков самый простой интерфейс с портом USB, если рассматривать его с точ-
ки зрения разработки программ для ПК?
44. Опишите работу программы интерфейса, приведенной в примере 10.15.
45. При использовании с USB эмуляции RS-232 и программы драйвера Windows в
ПК, какой COM-порт будет использоваться? Объясните ваш ответ.
46. Приложение со стороны ПК в примере 10.16 активизируется каждые 600 мс
при переполнении таймера. Что делает функция OnTimer каждый раз, когда это проис-
ходит?
47. Какова скорость передачи для подключения через RS-232 к USB?
48. Как в ПК устанавливается файл .inf для интерфейса USB?
49. Команды расширенного набора команд микроконтроллеров семейства PIC18
доступны на Ассемблере. Как они могут использоваться в компиляторе С18?
50. С каким FSR-регистром работают многие из команд расширенного набора
команд?
51. Каково назначение команды PUSHL?
52. Каково назначение команды CALLW?
53. Каково назначение команды SUBUNLK?
Приложения
529
ПРИЛОЖЕНИЕ А
Набор команд семейства PIC18
Код операции, операнды Описание Циклы 16-битное командное слово Status Affected Notes
Байтово-ориентированные команды работы с регистровым файлом
ADDWF f, d,a СкладываетМПЕС и f 1 0010 01 da ffff ffff CDCZOVN 1,2
ADDWFC f, d, a CKnaflbiBaeTWREG и f cC 1 0010 OOda ffff ffff CDCZOVN 1,2
ANDWF f, d, a MWREGcf 1 0001 01 da ffff ffff ZN 1,2
CLRF f, a Очищает f (0x00) 1 0110 101а ffff ffff z 2
COMF f, d, a Дополнение f (Д01) 1 0001 11da ffff ffff 4
CPFSEQ f, a Сравнение f c WREG, пропуск = 1-3 0110 001а ffff ffff 4
CPFSGT f, a Сравниваетfc WREG, пропуск > 1-3 0110 010а ffff ffff 4
CPFSLT f, a Сравниваетfc WREG, пропуск < 1-3 0110 000а ffff ffff 4
DECF f, d, a Декресментмрует! 1 0000 01 da ffff ffff CDCZOVN 1,2,3,4
DECFSZ f, d,a Декресментмрует f, пропуск, если 0 1-3 0010 11da ffff ffff 1,2,3,4
DCFSNZ f, d, a Декресментмрует f, пропуск, если*0 1-3 0100 11da ffff ffff 1,2
INCF f, d, a Инкресментирует! 1 0010 10da ffff ffff CDCZOVN 1,2,3,4
INCFSZ f, d, a Инкресментирует f, пропуск, если 0 1-3 0011 11da ffff ffff 4
INFSNZ f, d, a Инкресментирует f, пропуск, если *0 1-3 0100 10da ffff ffff 1,2
' IORWF f, d, a Исключающее ИЛИ WREGсf 1 0001 OOda ffff ffff ZN 1,2
! MOVF MOVFF f, d, a Перенос! 1 0101 OOda ffff ffff ZN 1
fe,fd Перенос f, в fd Источник Приемник-^ 2 1100 ffff ffff ffff
1111 ffff ffff ffff
MOVWF f, a Перенос WREG в f 1 0110 111a ffff ffff
MULWF f, a VMHO^eweWIEGHaf 1 0000 001a ffff ffff
NEGF f,a Отрицательное число отf (дополне- ние до 2) 1 0110 110a ffff ffff CDCZOVN 1,2
RLCF f, d, a Циклический пере- нос f через С левый 0011 01da ffff ffff CZN
RLNCF f, d, a Циклический пере- нос f левый 1 0100 01 da ffff ffff ZN 1,2
RRCF f, d, a Циклический пере- нос f через С правый 1 0011 OOda ffff ffff CZN
RRNCF f, d, a Циклический пере- нос f правый 1 0100 OOda ffff ffff ZN
SETF f, a Установ! (OxFF) 1 0110 100a ffff ffff
SUBFWB f, d, a Вычитание f из WREG с заимствованием 1 0101 01 da ffff ffff CDCZOVN 1,2
SUBWF f, d, a Вычитание f из WREG 1 0101 11da ffff ffff CDCZOVN
SUBWFB f, d, a Вычитание WREG из f с заимствованием 1 VI01 10da ffff ffff CDCZOVN 1,2
SWAPF f, d, a Своппинг полубайтов в! 1 0011 10da ffff ffff 4
TSTFSZ f, a Проверка f, пропуск, если 0 1-3 0110 011a ffff ffff 1,2
530
Применение микроконтроллеров PIC 18
Код операции, операнды Описание Циклы 16-битное командное слово Status Affected Notes
XORWF f, d, a Исключающее ИЛИ WREGcf 1 0001 10da ffff ffff ZN
BCF f, d, a Очистка бита f 1 1001 bbba ffff ffff 1,2
BSF f, d, a Установка бита f 1 1000 bbba ffff ffff 1,2
BTFSC f, d, a Проверка битаТ, пропуск, если 0 1-3 1011 bbba ffff ffff 3,4
BTFSS f, d, a Проверка бита!, пропуск, если 1 1-3 1010 bbba ffff ffff 3,4
BTG f, d, a Переключение бита f 1 0111 bbba ffff ffff 1,2
КОМАНДЫ УПРАВЛЕНИЯ
ВС n Переход, если пере- нос 1-2 1110 0010 nnnn nnnn
BN n Переход, если отри- цательное значение 1-2 1110 0110 nnnn nnnn
BNC n Переход,если нет переноса 1-2 1110 0011 nnnn nnnn
BNN n Переход, если поло- жительное значение 1-2 1110 0111 nnnn nnnn
BNOV n Переход,если нет переполнения 1-2 1110 0101 nnnn nnnn
BNZ n Переход, если нену- левое значение 1-2 1110 0001 nnnn nnnn
BOV n Переход, если пере- полнение 1-2 1110 0100 nnnn nnnn
BRA n Переход всегда 2 1101 Onnn nnnn nnnn
BZ n Переход по нулю 1-2 1110 0000 nnnn nnnn
CALL n, s Вызов подпрограм- мы 2 1110 110s kkkk kkkk
1111 kkkk kkkk kkkk
CLRWDT Очистка сторожевого таймера 1 0000 0000 0000 0100 TO PD
DAW Десятичная настрой- ка WREG 1 0000 0000 0000 0111 CDC
GOTO n Переход по адресу 2 1110 1111 kkkk kkkk
1111 kkkk kkkk kkkk
NOP Нетоперации 1 0000 0000 0000 0000
NOP Нетоперации 1 1111 xxxx xxxx xxxx 4
POP Извлечение верхнего адреса стека возвра- та 1 0000 0000 0000 0110
PUSH Занесение адреса на вершину стека возврата 1 0000 0000 0000 0101
RCALL n Относительный ВЫЗОВ (CALL) 2 1101 1nnn nnnn nnnn
RESET Программный сброс (RESET) 1 0000 0000 1111 1111 All
RE1TFIE s Возврате разрешен- ными прерываниями 2 0000 0000 0001 000s
GIE/GIEH, PEIE/GIEL
RETLW k Возврат с литералом boWREG 2 0000 1100 kkkk kkkk
RETURN s Возврат из подпро- граммы 2 0000 0000 0001 001s
SLEEP Вход в режим без- действия 1 0000 0000 0000 0011 TO PD
Приложения
531
Код операции, операнды Описание Циклы 16-битное командное слово Status Affected Notes
ЛИТЕРАЛЬНЫЕ КОМАНДЫ
ADDLW к Складывает к с WREG 1 0000 1111 кккк кккк CDCZOVN
ANDLW к HkcWREG 1 0000 1011 кккк кккк ZN
IORLW к Включающее ИЛИ к с WREG 1 . 0000 1001 кккк кккк ZN
LSFR f,k Перенос к в FSR f 2 1110 1110 OOff кккк
1111 0000 кккк кккк
MOVLB к Перенос к в BSR 1 0000 0001 0000 кккк
MOVLW к Перенос к во WREG 1 0000 1110 кккк кккк
MULLW к Умножение WREG на к 1 0000 1101 кккк кккк
RETLW к Возврат с к во WREG 2 0000 1100 кккк кккк
SUBLW к Вычитание WREG из к 1 0000 1000 кккк кккк CDCZOVN
XORLW к Исключительное ИЛИ к с WREG 1 0000 1010 кккк кккк ZN
ТАБЛИЧНЫЕ КОМАНДЫ
TBLRD* Табличное считывание 2 0000 0000 0000 1000
TBLRD*+ Табличное считывание с постинкресментиро- ванием 2 0000 0000 0000 1001
TBLRD*- Табличное считывание с постда<щ>лентирсвани- ем 2 0000 0000 0000 1010
TBLRD+* Табличное снитьваниес предтркресментировани- ем 2 0000 0000 0000 1011
TBLWR* Табличная запись 2 0000 0000 0000 1100 5
TBLWR*+ Табличная запись с постинкрементирова- нием 2 0000 0000 0000 1101 5
TBLWR*- Табличная записьс постдекрементиро- ванием 2 0000 0000 0000 1110 5
TBLWR+’ табличная запись с преддекрементирова- нием 2 0000 0000 0000 1111 5
КОМАНДЫ РАСШИРЕННОГО НАБОРА КОМАНД
ADDFSR f, к Складывает k с FSR 1 1110 1000 ffkk кккк
ADDULNK к Складывает k с FSR2 и возврат 2 1110 1000 11кк кккк
CALLW Вызов подпрограммы с использованием WREG 2 0000 0000 0001 0100
MOVSF f„ Перенос z. в f„ 2 1110 1011 Ozzz ZZZZ
1111 ffff ffff ffff
MOVSS Z., Z, Перенос z.bz„ 2 1110 1011 1zzz ZZZZ
1111 хххх xzzz 7717.
PUSHL к Сохраняет к в FSR2, декрементирует FSR2 1 1110 1010 кккк кккк
SUBFSR f, к Вычитает к из FSR 1 1110 1001 ffkk кккк
SUBUNLK к Вычитает к из FSR2, возврат 2 1110 1001 11kk кккк
532
Применение микроконтроллеров PIC 18
Примечания:
1. Когда регистр порта изменяется как функция от своего состояния (например,
MOVF PORTB, 1, 0), используемым значением будет значение, представленное непо-
средственно на штырьках.
2. Если эта команда выполняется с регистром TMR0 (и где это применимо, d = 1),
то предварительный делитель будет очищаться, если он используется.
3. Если счетчик команд изменяется или проверка условия истинна, то команда
требует двух циклов. Второй цикл выполняется как команда NOP.
4. Некоторые команды состоят из двух слов. Второе слово выполняется как NOP,
если только первое слово не извлекает информацию, включенную во второе слово. Это
гарантирует, что во всех ячейках памяти программы имеются корректные команды.
5. Если операция табличной записи инициализирует цикл записи во внутреннюю
память, то запись будет продолжаться до завершения операции.
Обозначения в таблице:
f - 8-разрядная ячейка регистрового файла данных (0x00 через OxFF)
d - бит приемника (0 = сохранение результата boWREG, 1 = сохранение результа-
та в f)
а - бит доступа (0 = доступ к ячейке ЗУПВ, 1 = банк ЗУПВ, специфицируемый BSR)
С - перенос (перенос из крайнего левого разряда)
DC - половинный перенос (перенос между правым и левым полубайтами)
Z - нулевой результат (0 = не ноль, 1 = ноль)
OV - переполнение (0 = нет переполнения, 1 = арифметическое переполнение)
N - отрицательный результат (0 = положительный, 1 = отрицательный)
fs - 12-битный адрес источника регистрового файла данных (от 0x000 до OxFFF)
fd - 12-битный адрес приемника регистрового файла данных (0x000 через OxFFF)
п - относительный адрес для команд перехода, непосредственный адрес для ко-
манд CALL/BRA и команд возврата
s - бит выбора быстрого вызова (CALL) (0 = не обновлять теневые регистры, 1 =
обновлять теневые регистры)
bbb - выбор битовой позиции (от 0 до 7)
к - литеральное значение (может быть 8 -, 12 -, или 20-разрядным)
ТО - бит таймаута
Т© - бит отключения электропитания
GIE - бит глобального разрешения прерывания
GIEH - бит глобального разрешения прерывания (высокоприоритетное прерыва-
ние)
GIEL - бит глобального разрешения прерывания (низкоприоритетное прерыва-
ние)
PEIE - бит разрешения прерываний от периферийных устройств
zs - 7-разрядное значение смещения адреса источника при косвенной адресации
zd - 7-разрядное значение смещения адреса приемника при косвенной адреса-
ции
х - бит, состояние которого не учитывается
Приложения
533
ПРИЛОЖЕНИЕ В
Обычно используемые библиотечные функции языка С
Это приложение содержит сжатый список обычно используемых аппаратных и про-
граммных функций библиотеки языка С, поставляемой совместно с компилятором С18. Это
хорошая основа написания программного обсеспечения для микроконтроллерных систем.
Каждая из перечисленных функций сопровождается одним либо двумя примерами ее ис-
пользования. Параметры некоторых функций будут изменяться для различных версий PIC18,
поэтому их необходимо сверять с документацией, поставляемой фирмой Microchip.
#include <adc.h> // аппаратный аналого-цифровой преобразователь
Функция Параметры Назначение Пример
char BusyADC (void) Возвращает 1, если АЦП занят Проверяет АЦП на занятость while (BusyADC());
void CIoseADC (void) Закрывает АЦП и запре- щает прерывания от него CloseADC();
void ConvertADC (void) — Запускает новое преобразование ConvertADC();
void OpenADC (char configl, char config2) Configl: Источник тактовой час- тоты аналого-цифрового преобразования: ADC_FOSC_2 ADC_FOSC_4 ADC_FOSC_8 ADC_FOSC_16 ADC_FOSC_32 ADC_FOSC_64 ADC_FOSC_RC Выравнивание резуль- тата АЦП- преобразования: ADC_RIGHT_JUST ADC.LEFTJUST Источник опорного напряжения АЦП: ADC_8ANA_0REF ADC 7ANAJREF ADC_6ANA_2REF ADC_5ANA 1REF ADC_5ANA_0REF ADC_4ANA_2REF ADC_4ANA_1 REF ADC_3ANA_2REF ADC_3ANA_0REF ADC_2ANA_2REF ADC_2ANA1REF ADC_1ANA_2REF ADC_1ANA_0REF ADC_0ANA_0REF Config2: канал: ADC.CH0 ADCCH1 ADC_CH2 ADC_CH3 ADC.CH4 ADC CH5 Конфигурирует АЦП Open ADC (ADC_FOSC_16& ADC_8ANA_0REF,^DC _CH0 &ADC INT_ON);
534
Применение микроконтроллеров PIC 18
Функция Параметры Назначение Пример
ADC_CH6 ADC_CH7 Прерывания АЦП: ADCJNTON ADC INT OFF
;n* ReadADC (void) Считывает результат преобразования result = ReadADCQ;
void SetChanADC ;char channel) Channel: ADC-CHO ADCCH1 ADC_CH2 ADC_CH3 ADC_CH4 ADCCH5 ADCCH6 ADC_CH7 Изменяет канал SetChanADC (ADC.CH3);
#include <capture.h> // Аппаратный блок ССР
Функция Параметр Назначение Пример
void CloseCapturex (void) или void CloseECapture (void) — Закрывает блок ССР x или блок расширения CloseCapture1();
void OpenCapturex (char config) Config: Открывает блок OpenCapturel
или разрешает прерывания ССР х или блок (CAPTUREJNT.0
void OpenECapture (char config) от ССР: CAPTURE_INT_ON CAPTUREJNTOFF включает прерывания по: Cx_EVERY_FALL_EDGE Cx_EVERY_RISE_EDGE Cx_EVERY_4_RISE_EDGE Cx_EVERY_16_RISE_EDGE EC1_EVERY_FALL_EDGE EC1_EVERY_RISE_EDGE EC1_EVERY_4_RISE_EDGE EC1 EVERY 16 RISE EDGE расширения N & C1_EVERY_RIDE_ EDGE);
unsigned int ReadCapturex (void) или unsigned int ReadECapture (void) Считывает триг- гер блока ССР х или дополни- тельного блока value = ReadCap- turel ();
#include <ic2.h> // Аппаратный модуль 12С
Функция Параметры Назначение Пример
void Ackl2C (void) или void Ackl2Cx (void) — Генерирует сигнал кви- тирования шины (АСК) Ackl2C(); или Аск!2С2();
void Closel2C (void) или void Closel2Cx (void) Закрывает блок SSP Closel2C(); или Closel2C1();
unsigned char DataRdyi2O Возвращает 1, если в Проверяет буфер на if (DataRdyl2C())
,void) или unsigned char DataRdyl2Cx ;void) буфере есть данные наличие данных { // Получение данных
unsigned char getci2C (void) или unsigned char getcI2Cx (void) Возвращает байт из буфера Считывает буфер dat = getcl2C();
Приложения
535
#include ic2.h // Аппаратный блок l2C
Функция Параметры Назначение Пример
unsigned char getsl2C (un- Считывает строку символов с Reads a string getsl2C1( bob, 6);
signed char ‘ptr, unsigned char length) или unsigned char getsl2Cx (unsigned char *ptr, un- signed char length) шины I2C и сохраняет ее в ячейках памяти данных, адре- суемых ptr; возвращает 0, если все байты были перенесены from the I2C bus
void ldlel2C (void) bkb void ldleI2Cx (void) Ожидание, пока шина l2C не бу- дет свободна ldle!2C();
void NotAckl2C (void) или void NotAckl2Cx (void) Генерирует сигнал отсутст- вия подтвержде- ния (NAK) NotAckl2C();
void 0penl2C (unsigned Sync: Открывает под- Openl2C (MASTER,
char sync, unsigned char SLAVE_7 ключение I2C как SLEWOFF);
slew) SLAVE_10 ведущее или
или void 0penl2Cx (unsigned char sync, unsigned char slew) MASTER Slew: SLEWOFF SLEW ON ведомое
unsigned char putcl2C (un- Возвращает 0, если запись Записывает байт putcl2C(0x31);
signed char data) или unsigned char putci2Cx (unsigned char data) успешна на шину ГС
unsigned char putsl2C (un- Возвращает 0, если запись Записывает putsl2C(fred, 3);
signed char ‘ptr, unsigned char length) или unsigned char putsl2Cx (unsigned char *ptr, un- signed char length) успешна строку симвоолв на шину I2C
void RestartI2C (void) или void Restartl2Cx (void) Генерирует условия перезапуска Restartl2C();
void Startl2C (void) или void Startl2Cx (void) Генерирует условия запуска Startl2C1 (),
void Stopl2C (void) или void Stopl2Cx (void) Генерирует условия останова Stop2C2();
Wruel2C или Writel2C Смотрите функции putcl2C()n putcl2Cx()
Readl2C Смотрите функции getcl2C() и getcl2CCx() — —
536
Применение микроконтроллеров PIC 18
Функция Параметры Назначение Пример
или ReadI2Cx
unsigned char EEAckPolling Параметр управления OxAO Генерирует pol = EEAckPolling
(unsigned control) логически умножается с адре- последователь- (OxAO);
or сом устройства; возвращается ность подтвер-
unsigned char EEAck- Pollingx (unsigned control) 0 в случае отсутствия ошибок ждения опрос для памяти ЕЕ Microchip
unsigned char EEByteWrite Записывает байт EEByteWrite (OxAO,
(unsigned char control, unsigned char address, unsigned char data) or unsigned char EEByteWritex ^unsigned char control, unsigned char address, unsigned char data) по адресу ЭСППЗУ, опре- деленному в функции 0x10, 0x1A);
unsigned char EECurren- Считывает один EECurrentAddRead
tAodRead (unsigned char control) or unsigned char EECurren- tAddReadx (unsigned char control) байт из ЭСППЗУ по текущему адресу (OxAO);
unsigned char EEPageWrite Записывает EEPageWrite 1 (OxAO,
(unsigned char control, unsigned char address, unsigned char *ptr) or unsigned char EEPage- Writex (unsigned char con- trol, unsigned char address, unsigned char ‘ptr) страницу памяти данных ЭСППЗУ, адресованную ptr, начиная от текущего адреса 0x10, buffer);
unsigned int EERandom- Считывает один EERandomRead
Read (unsigned char con- trol, unsigned char address) or unsigned int EERandom- Readx (unsigned char con- trol, unsigned char address) байт из памяти ЭСППЗУ, требу- ет однобайтовый адрес (OxAO, 0x20);
unsigned charEESequen- Считываетстро- EESequentialRead
tialRead (unsigned char ку данных из (OxAO, 0x30, buffer,
control, unsigned char ad- dress, unsigned char ‘ptr, unsigned char length) or unsigned charEESequen- tialRead (unsigned char control, unsigned char ad- dress, unsigned char *ptr, unsigned char length) ЭСППЗУ 5);
Приложения
537
#include <pwm.h> // Аппаратный модуль ШИМ
Функция Параметры Назначение Пример
void ClosePWMx (void) Закрывает ШИМ- канал ClosePWM1();
void OpenPWMx (char period) Период ШИМ = (период +1) х 4 х TOSC х предварительный делитель TMR2. (Таймер 2 должен также быть открыт и запрограммирован перед открытием модуля ШИМ). Открывает ШИМ- модуль и задает его период OpenPWMI (10);
void SetDCPWNx (int duty_ cycle) Изменяется коэффициент заполнения для выбранного ШИМ-модуля Сизменяет коэффи- циент заполнения ШИМ-модуля SetDCPWMI (500);
void Config: Конфигурирует вы- SetOutputPWMI
SetOutputPWMx (unsigned char config, unsigned char mode) выход ШИМ: SINGLEJ3UT FULL_OUT_FWD HALF_OUT FULL OUT_REV Mode: PWM_MODE_1 PWM_M0DE_2 PWM_MODE_3 PWM MODE 4 ход ШИМ (SINGLEJDUT, PWM_MODE_1);
#include <spi.h>
Функция Параметры Назначение Пример
void CloseSPI (void) or void CLoseSPIx (void) — Закрывает блок SPI unit CloseSPK);
unsigned char Возвращает 1, если име- Проверяет буфер SPI if (DataRDYSPIO)
DataRDYSPI (void) or unsigned char DataRDYSPIx (void) ются доступные данные. на наличие доступ- ных данных { //обработка данных }
unsigned char getcSPI (void) or unsigned char getcSPIx (void) Пвозвращает данные с шины SPI (Инициализирует считывание SPI и возвращает данные dat = getc(SPI);
void getsSPI (unsigned char *ptr, unsigned char length) или void getsSPIx (unsigned char *ptr, unsigned char length) void OpenSPI (unsigned char sync, unsigned char bus, unsigned char snip) или void OpenSPIx (unsigned char sync, unsigned char bus, unsigned char smp) Считывает данные с шины SPI в буфер, адресуемый ‘ptr для числа битов, ука- занных параметром length Sync: SPI_FOSC_4 SPI_FOSC_16 SPI_FOSC_64 SPI_FOSC_TMR2 SLVSSON SLVSSOFF SPI Bus: MODE_00 MODE_01 MODE_10 MODE_11 Snip: SMPEND SMPMID Считывает строку данных с SPI getsSPI (buffer, 10);
538
Применение микроконтроллеров PIC 18
Функция Параметры Назначение Пример
unsigned char putcSPI (unsigned char data) Или Unsigned char putcSPix (unsigned char data) void putsSPI (unsigned char *ptr) или void putsSPIx (unsigned char *ptr) unsigned char ReadSPI (void) или unsigned char ReadSPix (void) unsigned char WriteSPI (unsigned char data) или unsigned char WriteSPIx (unsigned char data) Возвращаемое значение равно 0 для случая колли- зии, приведшей к невы- полнению записи Записывает содержимое буфера, адресуемого *ptr, на шину SPI Смотрите getcSPI или getcSPIx Смотрите putcSPI или putcSPix Открывает шину SPI и конфигурирует ее Выдает символ на шину SPI Записывает сим- вольную строку на SPI Считывает байт с SPI Записывает байт данных на шину SPI OpenSPI (SPI_FOSC_4, MODE_00, SMPMID); putcSPI (0x2A); putsSPI (buffer); x = ReadSPIQ; WriteSPI( 0x10 );
#include <timers.h> //Управление аппаратным таймером
Функция Параметры Назначение Пример
void CloseTimerx (void) void OpenTimerO (un- signed char config) Config: Interrupt: (Конфигурация) TIMER_INT_ON TlMER_INT_OFF Width: (Ширина) T08BIT T0.16BIT Clock Source: (Источник синхроимпуль- сов) TOSOURCEEXT TO_SOURCE_INT External Clock Trigger: (Вид переключения no внешнему синхроимпуль- су) TO_EDGE_FALL TO_EDGE_RISE Prescaler Value: (Коэффициент предвари- тельного деления) T0_PS_1_1 T0_PS_1 2 TO PS 1 4 Закрывает вы- бранный таймер Открывает таймер 0 и конфигурирует его CloseTimer20; OpenTimerO (TIMERJNT.ON & T0J6BIT& TO_SOURCE_INT & T0_PS_1_16);
Приложения
539
Функция Параметры Назначение Пример
void OpenTimerl (un- signed char config) T0_PS_1_8 T0_PS_1_16 T0_PS_1_32 T0_PS_1_64 T0_PS_1_128 T0_PS_1_256 Config: (Конфигурация) Interrupt: (Прерывание) TIMERINTON TIMERJNTJDFF Width: (Ширина) T1_8BIT_RW T1_16BIT_RW Clock Source: (Источник синхроимпульсов) T1_SOURCE_EXT T1_SOURCE_INT Prescaler Value: (Коэффициент предвари- тельного деления) T1_PS_1_1 T1_PS_1_2 T1_PS_1_4 T1_PS_1_8 Открывает Таймер 1 и конфигурирует его OpenTimerl (TIMERJNT_ON & T1_16BIT_RW& T1SOURCEJNT & T1_PD_1_1);
void OpenTimer2 (un- signed char config) Oscillator: (Генератор) T1_OSC1ENON T1_OSC1ENOFF Synchronize Clock (Синхронизация таймера) Input: (Вход) T1_SYNC_EXT_ON T1_SYNC_EXT_OFF Use With 1 или 2 CCPs: (Использоватьc 1 либо 2 блоками ССР) T3_SOURCE_CCP T1_CCP1_T3_CCP2 T1_SOURCE_CCP For devices with more Than 2 CCPs: (Для устройств с более, чем 2 ССР) T34_SOURCE_CCP Т12_ССР12_Т34_ССРЗ 45 Т12ССР1Т34ССР23 45 T12_SOURCE_CCP Config: (Конфигурация) Interrupt: (Прерывания) Открывает таймер 2 и конфигурирует его OpenTimer2 (TIMER INT ON &
540
Применение микроконтроллеров PIC 18
Функция Параметры Назначение Пример
TIMER INTJDN TIMER INTJDFF Prescaler Value: (Коэффициент предвари- тельного деления) T2_PS_1_1 T2_PS_1_4 T2_PS_1_16 Postscaler Value: (Коэффициент постделе- ния) T2_POST_1_1 T2_POST_1_2 T2_PS_1_1 & T2_POST_1_1);
T2_POST_1_15 T2_POST_1_16 1:16 Use With 1 или 2 CCPs: (Использовать c 1 либо 2 блоками ССР) T3_SOURCE_CCP T1_CCP1_T3_CCP2
void OpenTimer3 (un- signed char config) T1 _SOURCE_CCP More than 2 CCPs: (Более, чем 2 ССР) T34_SOURCE_CCP T12CCP12T34CCP3 45 T12_CCP1_T34_CCP23 45 T12_SOURCE_CCP Config: (Конфигурация) Interrupt: (Прерывание) TIMERJNTON TIMERJNTOFF Width: (Ширина) T3_8BIT_RW T3J6BITRW Clock Source: (Источник синхроимпуль- сов) T3JSOURCEEXT T3.SOURCEJNT Prescaler Value: (Коэффициент предвари- тельного деления) T3_PS_1_1 T3_PS_1_2 T3_PS_1_4 T3_PS_1_8 Synchronize Clock (Синхронизация таймера) Input: (Вход) T3_SYNC_EXT_ON T3_SYNC_EXT_OFF Открывает таймер 3 и конфигурирует его OpenTimer3 (TIMERJNTOFF & T3_8BIT_RW& T3JSOURCEJNT & T3_PS_1_1);
Приложения
541
Функция Параметры Назначение Пример
Use With 1 or 2 CCPs: (Использовать c 1 или 2 ССР) T3_SOURCE_CCP T1_CCP1_T3_CCP2 T1_SOURCE_CCP More than 2 CCPs: (Более, чем 2 ССР) T34_SOURCE_CCP T12_CCP12_T34_CCP3 45 T12_CCP1_T34_CCP23 45 T12_SOURCE_CCP
void OpenTimer4 (un- signed char config) Config: (Конфигурация) Interrupt: (Прерывание) TIMERJNTJDN ER_INT_OFF Prescaler Value: (Коэффициент предвари- тельного деления) T4_PS_1_1 T4_PS_1_4 T4_PS_1_16 Postscaler Value: (Коэффициент постделе- ния) T4_POST_1_1 T4_POST_1_2 Открывает таймер 4 и конфигурирует его OpenTimer4 (TIMERJNTJDN & T4_PS_1_1 & T4_POST_1_1);
unsigned int ReadTimerx (void); void WriteTimerx (un- signed int) T4_POST_1_15 T4_POST_1_16 1:16 Возвращает значение выбранного таймера. Считывает отсчет таймера Записывает в выбранный таймер x = ReadTimer2(); WriteTimer1(-12500);
542
Применение микроконтроллеров PIC 18
#include <usart.h> // Аппаратный USART
Функция Параметры Назначение Пример
void Config: Устанавливает baudUSART
baudUSART (unsigned (Конфигурация) скорость информа- (BAUD IDLE CLKHIGH
config) Clock Idle State: ционного обмена &
или void baudxUSART (un- signed config) (Синхронизация состояния паузы) BAUD_IDLE_CLK_HIGH BAUD_IDLE_CLK_LOW Baud Rate Generation: (Генерация скорости ин- формационного обмена) BAUD_16_BIT_RATE BAUD_8_BIT_RATE RX Pin Monitoring: (Контроль состояния штырь- ка RX) BAUD_WAKEUP_ON BAUD_WAKEUP_OFF Baud Rate Measurement: (Замер скорости информа- ционного обмена) (BAUD_AUTO_ON BAUD AUTO OFF USART BAUD_16_BIT_RATE & BAUD_WAKEUP_ON& BAUD_AUTO_ON);
char BusyUSART (void) Возвращает 1, если Проверяет while (BusyUSARTO);
или char BusyxUSART (void) передатчик занят передатчик USART или while (Busy2USART());
void CloseUSART (void) или void ClosexUSART (void) — Закрывает USART CloseUSARTO; Или Closet USART();
char DataRdyUSART Возвращает 1, если были Проверяет while (!Da-
(void) Или char DataRdyx- USART (void) приняты данные приемник USART taRdyUSARTO);
char getcUSART (void) или char getcxUSART (void) Возвращает символ, принятый USART Считывает символ из USAFil x = getcUSART();
void getsUSART (un- signed char ‘ptr, un- signed char length) или void getsxUSART (un- signed char ‘ptr, un- signed char length) Считывает символьную стро- ку из USART и сохраняет ее в ячейке памяти, адресуемой ‘ptr для количества байтов, специфицированного пара- метром длины строки (length). Считывает сим- вольную строку из USART getsUSART (buffer, 4);
void OpenUSART (un- Config: Открывает и OpenUSART
signed char config, (Конфигурация) конфигурирует ( USART TX INT ON &
unsigned int brg) или void OpenxUSART (un- signed char config, unsigned int brg) Interrupts: (Прерывания) USART.TXJNTJDN USART_TXJNT_OFF USART_RX_INT_ON USART_RX_INT_OFF Mode: (Режим) USARTASYNCHMODE USARTSYNCHMODE Width: (Ширина) USARTEIGHTBIT USART_NINE_BIT USART USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_SYNC_MASTER & USART_CONT_RX & USART_BRGH_HIGH, 25);
Приложения
543
Функция Параметры Назначение Пример
char ReadUSART (void) или char ReadxUSART (void) void WriteUSART (char data) или void WritexUSART (char data) Slave/Master: (Подчиненное/Ведущее) USART_SYNC_SLAVE USART_SYNC_MASTER Reception mode: (Режим приема) USART_SINGLE_RX USART_CONT_RX Baud rate: (Скорость информационного обмена) USART_BRGH_HIGH USART_BRGH_LOW BRG: (Генератор скорости инфор- мационного обмена) Определяет скорость информационного обмена Смотрите getcUSART() или getCxUSARTO Смотрите putcUSART() или putcxUSART() Считывает USART Записывает в USART х = ReadUSARTO; WriteUSART( 0x10);
#include <sw_i2c.h>// Программный интерфейс l2C
По умолчанию, программный интерфейс 12С использует RB3 для тактовой частоты
и RB4 для данных. Эти номера штырьков могут быть модифицированы посредством
изменения файла swJ2c.h с последующей повторной компиляцией функций.
Функция Параметры Назначение Пример
char Clock_test (void) Возвращает 0 в слу- чае отсутствия оши- бок Используется для растягивания во вре- мени импульсов так- товой частоты на ведомом устройстве if (Clock_test()) { // handle error }
char SWAckl2C (void) Возвращает 0, если Генерирует сигнал if (SWAckl2C())
or char SWNotAckl2C (void) ведомое устройство подтверждает выпол- нение операции АСК или NAK { // handle error }
char SWGetcl2C (void) Возвращает байт данных из I2C или -1 в случае ошибки Считывает шину I2C x = SWGetcl2C();
char SWGetsl2C (un- signed char *ptr, un- signed char length) Считывает шину I2C и сохраняет символы в буфере, адресуемом ’ptr; количество счи- танных байтов опре- деляется параметром длины (length). В случае ошибки возращается -1 Считывает строку символов с шины I2C SWGetsl2C (buffer, 5);
544
Применение микроконтроллеров PIC 18
Функция Параметры Назначение Пример
char SWPutcl2C (un- signed char data) char SWPutsl2C (un- signed char *ptr, un- signed length) Посылает данные на шину I2C, возвращает 0, если запись успеш- на Передает содержи- мое области памяти, адресуемой *ptr, на шину I2C. Параметр длины (length) указы- вает количество пе- редаваемых байтов; в случае отсутствия ошибки возвращается 0 Посылает байт на шину I2C Передает символьную строку на шину I2C SWPutcl2C(0x8A); SWPutsl2C (buffer, 10);
Функция Параметры Назначение Пример
char SWReadl2C (void) void SWRestartl2C (void) void SWStartl2C (void) void SWStopl2C (void) char SWWritel2C (unsigned char data) Смотрите SWGetcl2C() Смотрите SWPutcl2C() Считывает байт с шины 12С Перезапускает шину 12С Запускает шину 12С Останавливает шину 12С Записывает байт на шину 12С х = SWReadl2C(); SWRestartl2C(); SWStartl2C(); SWStopl2C(); SWWritel2C (0x22);
# include <sw_spi.h> // Программный интерфейс SPI
По умолчанию, программный интерфейс SPI использует RB2 как штырек GS,
RB3 как входной штырек данных, RB7 как выходной штырек данных и RB6 - как штырек
тактовой частоты. Эти номера штырьков могут быть модифицированы посредством
изменения файла sw_spi.h с последующей повторной компиляцией функций.
Функция Параметры Назначение Пример
void ClearCSSWSPI (void) void OpenSWSPI (void) char putcSWSPI (char data) void SetCSSWSPI (void) char WriteSWSPI (char data) Возвращает байт, сччитанный с SPI Смотрите putc- SWSPI» Сбрасывает штырек выбора микросхемы Открывает интерфейс SPI Записывает байт на шину SPI Устанавливает штырек выбора микросхемы Записывает байт на шину SPI ClearCSSWSPI»; OpenSWSPI»; х = putcSWSPI (Ox 66); SetCSSWSPI»; x = WriteSWSPI (0x33);
Приложения
545
#include <sw_uart.h> // программный интерфейс UART
По умолчанию, программное обеспечение UART использует штырек RB4 как штырек
передачи данных, а штырек RB5 - как штырек приема данных. Эти номера штырьков
могут быть модифицированы посредством изменения файла sw_uart.h с последующей
повторной компиляцией функций. Кроме того, следующие временные задержки для
передачи и приема должны быть определены в программе как функции:
DelayTXBitUART, DelayRXHalfBitUART и DelayRXBitUART. Функция DelayTXnitUART функ-
ция должна иметь время задержки, равное:
[(Fosc/(Baud х 2))+1] х 0.5 - 12, функция DelayRXHalfBitUART функция должна иметь
время задержки, равное:
[(Fosc/(Baud х 4))+1 ] х 0.5 - 9, а функция DelayRXBitUART должна иметь время задержки,
равное:
[(Fosc/(Baudx2))+1] х0.5 - 14
Функция Параметры Назначение Пример
char getcUART (void) void getsUART (char *ptr, unsigned char length) — Считывает байт из UART Считывает строку символов из UART х = getcUARTO; getsUART (buffer, 10);
Функция Параметры Назначение Пример
void OpenUART (void) void putcUART (char data) void putsUART (char *ptr) char ReadUART (void) void WriteUART (char data) Записывает в UART строку символов, за- канчивающуюся нулем Смотрите getcUARTO Смотрите put- cUART(data) Открывает UART Передает байт из UART Записывает строку символов в UART Считывает байт из UART Записывает байт в UART OpenUARTO; putcUART (0x33); putsUART (string 1); x = ReadUARTO; WriteUART (OxOD);
#include <delays.h> // Программные временные задержки
функция Параметры Назначение Пример
void DelaylTCY (void) — Вводит задержку на 1 командный цикл DelaylTCYO;
void DelaylOTCYx (un- signed char count) Параметр count - это значение между 0 и 255, при этом 0 соответству- ет 256. Задержка равна 10 х count х длительность командного цикла DelaylOTCYx (10);
void DelaylOOTCYx (unsigned char count) Параметр count - это значение между 0 и 255, при этом 0 соответству- ет 256 Задержка равна 100 х count х длительность командного цикла DelaylOOTCYx (12);
void DelaylKTCYx (unsigned char count) Параметр count - это значение между 0 и 255, при этом 0 соответству- ет 256 Задержка равна 1000 х count х длительность командного цикла DelaylKTCYx (10);
void DelaylOKTCYx (unsigned char count) Параметр count - это значение между 0 и 255, при этом 0 соответству- ет 256 Задержка равна 10000 х count х длительность командного цикла DelaylOKTCYx (1);
546
Применение микроконтроллеров PIC 18
ПРИЛОЖЕНИЕ С
Ответы на избранные вопросы и задания с четными номерами
ГЛАВА 1
2. Фирма “Intel Corporation”
4. Машина фон Неймана представляет собой стандартную архитектуру, используемую
в компьютерных системах.
6. Компьютер с полным набором команд
8. Единица или ноль
10. 1024К
12.Полубайт - это половина байта или 4 бита
14. Адрес, управление и данные
16. Сигнал считывания или RD
18.ППЗУ стирается ультрафиолетовыми лучами вне системы, в то время как ЭСППЗУ
стирается электрически в системе.
20. 4К или 4096
22. СЗУПВ или ДЗУПВ
24. (a) char резервирует байт памяти со знаком, (b) short резервирует 16-разрядную
ячейку памяти со знаком, (с) int резервирует 16- разрядную ячейку памяти со зна-
ком, (d) float резервирует 24- разрядную ячейку памяти для числа с плавающей точ-
кой и (е) double резервирует 24- разрядную ячейку памяти для числа с плавающей
точкой.
26. (а) 13.25, (Ь) 57.125, (с) 43.3125 и (d)
28. (а) 163.1875, (Ь) 297.75, (с) 172.859375, (d) 4011.1875 и (е) 3000.05078125
30. (а) 0.1012 0.58 О.А16, (Ь) 0.000000012 0.0028 0.0116, (с) 0.101000012 0.5028 О.А1,6, (d)
0.1 12 0.68 О.С16 и (е) 6.11112 0.74g O.F16
32. (а) С2, (b) 10FD, (с) ВС, (d) 10 и (е) 8ВА
34. (а) 0111 1111, (Ь) 0101 0100, (с) 0101 0001 и (d) 1000 0000
36. (a) DATA “FROG”, 0 (b) DATA “Arc”, 0 (c) DATA “Water”, 0 (d) DATA “Well”, 0
38. DATA “What time is it?”, 0
40. (a) 0000 0011 1110 1000, (b) 1111 1111 1111 0100, (c) 0000 0011 0010 0000, (d) 1111
0011 0111 0100
42. char Fredl = -34;
44. Формат с обратным порядком данных сохраняет младший байт в байтовой ячейке
памяти с минимальным адресом, а формат с прямым порядком данных сохраняет
старший байт в ячейке памяти с минимальным адресом.
46. (а) упакованный: 0000 0001 0000 0010, неупакованный: 0000 0001 0000 0000 0000
0010, (Ь) упакованный: 0100 0100, неупакованный: 0000 0100 0000 0100, (с) упако-
ванный: 0000 0011 0000 0001, неупакованный: 0000 0011 0000 0000 0000 0001 и (d)
упакованный: 0001 0000 0000 0000, неупакованный: 0000 0001 0000 0000 0000 0000
0000 0000
48. (а) 89, (Ь) 9, (c)32n(d) 1
50. (а) +3.5 (Ь)-1.0 (с)-12.5
ГЛАВА 2
2. Гарвардская архитектура использует отдельное пространство памяти для программ
и отдельное - для данных.
4. Конвейерная обработка информации связана с тем, что извлечение команд выпол-
няется параллельно с выполнением команд, что позволяет в каждом командном
Приложения
547
цикле выполнять одну команду, за счет чего повышается эффективность выполнения
программ.
6. 8
8. 0x000000 (первое) и 0x1 FFFFF (последнее)
10. 12
12. ЭСППЗУ располагается в специальной отдельной области пространства памяти
данных, адресуемой специальными функциональными регистрами.
14. От 0x000 до 0x2FF
16.0X007FFF
18. Регистры TRIS, LAT и PORT
20. Рабочий регистр (W) или (WREG) - это место, в котором большинство арифметиче-
ских и логических команд размещают результат своего выполнения.
22. Регистр WREG размещается в ЗУПВ данных по адресу 0xFE8.
24. Регистры FSR используются для косвенной адресации памяти данных.
26. Регистр состояния.
28. Поскольку ноль выбирает выход, а единица - вход, то TRISB загружается OxFE.
30. 0x33 передается в порт А посредством загрузки WREG значением 0x33 с последую-
щей адресацией либо регистра LATA или регистра PORTA и дальнейшей выдачей
0x33 из WREG.
32. 3
34. IDE - это интегрированная система разработки, используемая для программирова-
ния микроконтроллеров PIC как на языке Ассемблера, так и на языке С, с последую-
щей имитацией работы программ. IDE может также управлять программатором и
внешним эмулятором.
36. Эмуляция и программирование.
38. Эмулятор - это программа, которая функционирует так же, как и микроконтрол-
лер.
40. (a) Start: - это метка, которая используется для ссылки на команду, GOTO - это
мнемоническое обозначение кода операции, a Heaven - это ячейка памяти , в кото-
рую команда GOTO передает управление в программе. Она называется операндом,
(b) ADDLW - это код операции, 0x29 - это операнд, за которыми следует коммента-
рий. (с) Loopy 1: представляет собой метку, MOVFF - это код операции, WREG и
0x145 являются операндами, за которыми следует комментарий.
42. Процесс ассемблирования заключается в том, что ассемблер берет исходный файл
и преобразует его в объектный файл.
44. Объектный файл - это файл, который содержит исходную программу на языке Ас-
семблера в ее двоичной машинной версии. Она является объектом процесса ас-
семблирования.
46. .Ikr файл - это файл компоновки, который содержит команды для программы ком-
поновщика.
48. Директива CODE определяет секции программного кода или команд.
50. Директива CODE 0x1000 информирует ассемблер о том, что команды, которые сле-
дуют далее в программе, должны быть размещены, начиная с ячейки памяти с адре-
сом 0x1000.
52. Этот оператор резервирует 2 байта памяти для метки DATA1.
ГЛАВА 3
2. WREG
4. (a) MOVLW 0x34 (b) ADDLW 3 (с) IORLW 6 (d) MOVLB 2 (е) SUBLW 9
548
Применение микроконтроллеров PIC 18
6. MOVLW 3
ADDLW 9
IORLW 5
8. (a) BCF WREG, 2 (b) BSF 0x11, 3, ACCESS (c) BTG 0x1 A, 5, ACCESS (d) BSF STATUS, 2
(e) BCF STATUS, N
10. Команда BTFSS позволяет проверять бит регистровой ячейки памяти данных. Если
при проверке окажется, что бит установлен (1), то следующая команда программы
пропускается.
12. Банк доступа содержит регистровые ячейки памяти данных в области от 0x000 до
OxO7F и от 0xF80 до OxFFF во многих версиях микроконтроллеров. Обратите внима-
ние на то, что в некоторых версиях микроконтроллеров используют другое разбие-
ние пространства памяти.
14. Литеральное сложение добавляет константу, в то время как байтовое сложение до-
бавляет переменную.
16. MOVLW 0х5А
MOVWF 0x10, ACCESS
MOVWF 0x20, ACCESS
MOVEF 0x30, ACCESS
18. MUVLW WREG
MOVF PRODL
20. Регистр состояния переноса содержит заимствование после вычитания.
22. MOVF 0x10, ACCESS
ADDWF 0x20, ACCESS
MOVWF 0x20, ACCESS
MOVF 0x11, ACCESS
ADDWFC 0x21, ACCESS
MOVWF 0x21, ACCESS
MOVF 0x12, ACCESS
ADDWFC 0x22, ACCESS
MOVWF 0x22, ACCESS
24. Декрементирует регистрировую ячейку памяти данных и пропускает следующую
команду, если результат не равен нулю.
26.Операнд POSTINC1 использует FSR1 для того, чтобы адресовать память, а затем
инкрементирует содержимое FSR1.
28. Содержимое WREG преобразуется в дополнение до одного, если выполняется ис-
ключающее ИЛИ этого регистра с OxFF.
30. Команда GOTO позволяет программе продолжаться по любому адресу в памяти
программ, в то время как команда BRA имеет ограниченную дистанцию перехода,
равную ±1024 от адреса следующей команды программы.
32. Эта команда обеспечивает только переход от +127 до -128 байтов от адреса сле-
дующей команды программы.
34. LFSR MOVLW 1,0x000 WREG
LOOP1: ADDWF POSTINCI
CPFSEQ FSR1L
BRA LOOP1
36. Когда выполняется команда CALL, содержимое счетчика команд заносится в стек.
Команда RETURN извлекает содержимое счетчика команд из стека. Так как команда
CALL сохраняет адрес следующей за ней команды программы в стеке, команда
Приложения
549
RETURN возвращает управление команде, следующей непосредственно после ко-
манды CALL.
38. Пример 3-17 использует команду DAW для того, чтобы выполнить преобразование
посредством добавления 6 к содержимому регистра WREG, если значение младшего
полубайта превосходит 9. Хотя к буквам должно прибавляться число 7, при добавле-
нии 6 командой DAW 7 получается инкрементированием значения boWREG, если его
значение равно 0x40 или больше, как в случае буквенных символов после прибавле-
ния к ним 6.
4Q. .*********** Поисковая таблица Prime ************
PRIMES CODE, _PACK OxlFOO
PRIME1 DB "1, 2 , 3, 4, 5, 7, 11 , 13 f
17,19
DB 23, 29, 31, 37 , 41, 43, 47, 53
DB 59, 61, 67, 71 , 73, 79, 83,
89, 97
DB 101, 103, 107, 109, 113, 127
DB 131, 137, 139, 149, 151, 157,
163
DB 167, 173, 179, 181, 191, 193,
197, 199
DB 211, 223, 227, 229, 233, 239,
241, 251
DB 0 ;конец таблицы
Функция
PRIME ***************
; Возвращает Carry = 1,
; Возвращает Carry = 0,
если WREG = prime
если WREG не равен prime
PRIME: MOVWF PRODL ;сохраняет число в PRODL
MOVLW 0 /адресует поисковую таблицу
MOVWF TBLPTRL
MOVLW OxIF
MOVWF TBLPTRH
MOVLW 0
MOVWF TBLPTRU
PRIME1: TBLRD*+ MOVLW 0 CPFSEQ TABLAT /получение первичного числа
BRA PRIME2 /если не конец таблицы
BCF STATUS, C /сброс переноса
MOVFF RETURN PRODL, WREG
PRIME2: MOVFF PRODL, WREG
CPFSEQ TABLAT
BRA PRIME1 /если не найдено
BSF STATUS, C /установка переноса для prime
550
Применение микроконтроллеров PIC18
MOVFF PRODL, WREG
RETURN
42. Память, требуемая при вызове макроса, равна объему памяти, необходимому для
хранения команд макроса без каких-либо дополнительных байтов для команд call
или return.
ГЛАВА 4
2. Программный стек - это область памяти внутри микроконтроллера, которая содер-
жит адрес возврата из функции или подпрограммы.
4. (a) MOVWF POSTDEC1 (b) MOVF PREINC1, 0 (с) MOVFF PRODL, POSTDEC1 и MOVFF
PRODH,POSTDEC1
6. PRODL извлекается первым, поскольку стек данных представляет собой запоми-
нающее устройство, работающее по принципу “первым вошел - последним вышел”.
8. Программное обеспечение работы с очередями должно распознавать состояние
пустой и заполненной очереди.
10. Область памяти, отведенная под очередь, используется программами вновь и
вновь, поэтому она рассматривается как цикличная память.
12. Упакованные BCD (двоично -кодированные десятичные числа) сохраняются как два
числа на байт, в то время как неупакованные'ВСО-числа сохраняются как одно число
на байт.
14. BCD-числа вычитаются при использовании сложения с дополнением до десяти, при
этом команда DAW может использоваться для коррекции результата.
16. BCD-числа используются в программах вместо двоичных для экономии времени,
необходимого для выполнения преобразований между двоичными и BCD-числами.
18. Команда умножения используется для 16-разрядного умножения согласно алго-
ритму перекрестного умножения, который рассматривался в главе 4 и иллюстриро-
вался примером 4-9.
20. ;************* функция MULTAB *************
Z
MULTAB MULWF TABLAT
MOVFF PRODL, WREG
RETURN
22. Чтобы умножить числа co знаком, эти числа сначала проверяются и в случае отри-
цательности они делаются положительными. Результат будет отрицательным, если
два числа, являющиеся множителями, имеют разные знаковые разряды. Изменение
знака выполняется с использованием двух дополнений.
24. Самый лучший метод деления на 4 заключается в сдвиге числа вправо на два раз-
ряда. При этом предполагается, что число является положительным или беззнаковым.
26. Да, используя алгоритм, описанный в тексте, хотя в этом случае операция и потре-
бует большего времени, чем в случае использования меньших делителей.
28. Единственное изменение, необходимое для того, чтобы выполнить восьмеричное преоб-
разование - это то, что команда MOVLW .10 должна быть изменена на MOVLW .8, благо-
даря чему программа будет генерировать восьмеричный результат.
30. Число преобразуется из десятичного в двоичное посредством умножения на 10
результата, который является первоначально нулем, с последующим добавлением
десятичной цифры к результату. Эти операции умножения и добавления повторя-
ются до тех пор, пока никакие дополнительные цифры не будут появляться в деся-
тичном числе.
Приложения
551
32. Команда между BinBCDs и BinBCDsl требует для своего выполнения 4,5 мкс, ко-
манда между BinBCDsl и BinBCDs2 требует для своего выполнения 4,5 мкс плюс
время, нужное для выполнения функции Div в рамках итераций, происходящих до
тех пор, пока число не станет нулевым. Функция Div требует для своего выполнения
54 мкс, так что требуемое время равно 59,5 мкс на итерацию. Время, требуемое для
выполнения команд между BinBCDs2 и оператором конца функции, равно 4,5 мкс.
Таким образом, общее время будет равно 9,0 мкс плюс 59,5, умноженное на число
итераций. Если требуются три итерации, то общее время будет равно 187,5 мкс.
34. 3.5 мкс
36. MyFunc:
CALL GetData
SUBLW 0x59
BZ MyFuncl /сдвиг вправо
ADDLW 0x59
SUBLW OxFO
BZ ;отпускание клавиши
RETURN
MyFuncl:
CLRF 0x10, ACCESS
REUTRN
MyFunc2:
SUBLW 0x59
BZ MyFunct3
RETURN
MyFunc3:
SETF 0x10, ACCESS
RETURN
ГЛАВА 5
2. Код Ассемблера в программах на языке С помещается между операторами _asm и
endasm. Коды ассемблера, используемые в программах на языке С, не должны со-
держать символов точки с запятой и должны включить все поля команд.
4. Оператор #pragma config используется для того, чтобы конфигурировать микро-
контроллер для его последующей работы.
6. Функция DelaylKTCYx вызывает временную задержку в 1000 командных циклов.
При тактовой частоте в 4 мГц, командный цикл занимает 1,0 мкс, так что функция
DelaylKTCYx вызывает временную задержку, равную 1,0 мс. Поскольку требуется
10 мс, то в программе используется команда DelaylKTCYx (10);.
8. while (1)
(
PORTBbits.RB0 л=1; // бит дополнения
DelaylOKTCYx (100); // ожидание одну секунду
}
10. char bitPattern = 0;
PORTBbits.RB3 - 1;
while (bitPattern != 16)
{
PORTB = PORTB & OxFO | bitPattern;
// выдача входных битов
if (bitPattern != OxOF && PORTAbits.RA4
'.= 1
552
Применение микроконтроллеров PIC18
I| bitPattern == OxOF &&
PORTAbits. RA4 != 0)
PORTBbits.RB3 = 0; // плохо
bitPattern++;
}
12. Директива rom near определяет данные в памяти программ по адресам от 0x0000
до OxFFFF (16-разрядныи указатель), а директива rom far определяет данные по ад-
ресам от 0x000000 до OxFFFFFF (24-разрядный указатель).
14. Каждый вход разделяется на две части. Самые правые три бита содержат значение
числа точек и тире, а крайние левые пять битов содержат структуру точек и тире ко-
да Морзе.
16. while (PORTBbits.RB2 == 1);
18.0x101
20. Переменная count используется для того, чтобы указать, сколько периодов по 20
мкс заключается в ширине импульса. Если переменная count равна 1 или 2, то это
значит, что импульс имеет состояние, соответствующее логической единице, а ес-
ли значение count превосходит 2, то это значит, что импульс имеет состояние, со-
ответствующее логическому нулю.
22. Оператор states [state] ()ссы лается на поисковую таблицу указателей на различные
функции и вызывает их, используя переменную state как ссылку.
24. float хс [11];
float cap = 0,000001;
int f;
char count = 0;
for (f = 100; f <= 1000; f += 100)
{
xc[count++] = 1 / (6.2832 * f * cap);
}
ГЛАВА 6
2. Корпус типа PDIP - это пластмассовый корпус с двойным рядом выводов, он наибо-
лее часто используется при изготовлении опытных образцов.
4. Корпус типа SSOP - это компактный корпус небольших размеров с рельефной
структурой.
6. Вывод VDD - это вывод, предназначенный для подключения положительного полюса
электропитания, которое часто равно 5 В, а вывод VSS это вывод для подключения
земли.
8. 12 мА
10. 8.5 мА
12. 15 мс
14. 0x0000
16. Сторожевой таймер используется для сброса микроконтроллера всякий раз, когда
он переполняется. Его назначением является перезапуск системы в случае, если
она “зависла" по каким-либо причинам.
18. 4.0 мс
20. Сброс стека происходит в случае, когда он переполняется либо делается попытка
извлечения данных из пустого стека, чего не происходит во время нормальной ра-
боты программного обеспечения, однако это может произойти, если микрокон-
троллер станет объектом воздействия помех.
Приложения
553
22. 40 МГц
24. 4
26. Код RCIO используется при работе микроконтроллера с тактовым RC-генератором.
В этом случае штырек OSC2 используется как штырек ввода-вывода.
28. Посредством использования оператора #pragmaconfig OSC = HSPLL.
32. Система электронной игры в кости выбирает случайные числа посредством инкре-
ментирования числа в то время как пользователь удерживает кнопку в нажатом со-
стоянии. Поскольку инкрементирование числа происходит с высокой скоростью,
пользователь не может влиять на значение числа, подсчитывая, как долго он удер-
живает кнопку.
34. Подсчитанное значение равно 475 Ом, однако поскольку это значение не является
стандартным номиналом резистора, то в цепи используется резистор на 470 Ом.
36. ADCON1 = 0x7f; // программа для цифровых штырьков
TRISB =0; // порт В - выходной
38. Прерывание - это аппаратно или программно-инициализированный вызов функ-
ции.
40. Эти операторы дают указание компилятору использовать вектор высокоприоритет-
ного прерывания по адресу 0x0008 для функции MyHighlnt.
42. Данная команда разрешает ввод высокоприоритетных прерываний.
44. Кварцевый генератор на 32,768 кГц подключен к штырьку тактового входа таймера
1, при этом таймер 1 программируется наделение отсчета на 32768, что вызывает
прерывания с частотой ровно 1 раз в секунду.
46. Если флаг прерывания (IF) для прерывания не сброшен, то прерывание возникнет
немедленно после выхода из процедуры обслуживания прерываний.
48. 0.00323 В
50. Бит GO регистра ADCON устанавливается в логическую единицу для запуска преоб-
разования.
52. Для считывания из ЭСППЗУ данных бит EEPGD сбрасывается, адрес посылается в
регистр EEADR, бит RD устанавливается, а данные затем считываются из регистра
EEDATA.
54. 4 мс
56. Вход ССР программируется на переключение по каждому положительному фронту
сигнала. Программа подсчитывает расстояние между двумя положительными
фронтами с шагом дискретности в 8 мс, затем по полученному отсчету определяет-
ся частота.
ГЛАВА 7
2. От 10 до 20 мс
4. Переключатель (0x81);
6. Нагрузочные резисторы являются необходимыми вследствие того, что разрыв цепи
не является допустимым состоянием входа микроконтроллера. “Висячий” вход яв-
ляется объектом воздействия помех.
8. //
// коды клавиш для клавиатуры с матрицей 4x6,
// сохраненные как константы в памяти программ
И
rom near char lookupKey[] =
{
1, 4, 7, 10, // левый столбец
2, 5, 8, 0,
554
Применение микроконтроллеров PIC 18
3, 6, 9, 11,
12, 13, 14, 15,
16, 17, 18, 19
};
//
// использует функцию Switch из примера 7-1
//
unsigned char Key (void)
{
#define MASK OxOf // установка маски
#define ROWS 6 // задание количества столбцов
int a;
unsigned char
keyCode;
PORTB = keyCode - 0; // очистка порта В и
keyCode
Switch (MASK) ; // компенсация дребезга контактов и ожидание
// нажатия какой-либо клавиши
PORTB = OxFE; // выбор самого левого столбца
while ((PORTA & MASK) // пока не будет обнаружена клавиша
== MASK)
{
PORTB = (PORTB // получение следующего столбца
« 1) I 1;
keyCode += ROWS; // добавление-строки к коду ключа
}
for (а = 1; а != 0; а <<= 1)
{ // нахождение строки
if ((PORTA & а) == 0)
break;
keyCode++;
}
return lookupKey // просмотр на нахождение правильного кода клавиши
[keyCode];
Приложения
555
10. (Смотрите рисунок С-1)
Рисунок С-1
12. (Смотрите рисунок С-2)
Рисунок С-2
556
Применение микроконтроллеров PIC 18
I I фу J-J КЦ14Я Fl 3 S И *******************
//
// использует delays.h
//
void Flash (void)
{
char a;
PORTB = 1;
for (a =0; a < 20; a++)
{
DelaylOKTCYx(50); // 1/2 секунды
PORTB A = 3;
}
}
14. Благодаря инерционности человеческого зрения, кажется, что они светятся посто-
янно.
16. 6
18. Вывод VEE ЖК-индикатора подсоединяется к отводу потенциометра на 10 кОм,
подключенному между 5В и землей.
20. Входной штырек Е ЖК-индикатора работает как вход тактовой частоты, стробирую-
щий ввод данных в ЖК-индикатор через щтырьки ввода данных.
22. Курсор перемещается посредством передачи в ЖК-индикатор его позиции с логи-
ческой единицей в битовой позиции 7. Эта позиция передается при состоянии сиг-
нала на штырьке RS, равном логическому нулю.
24. // ************ Функция Cursor ************
//
//
void Cursor (char position)
{
PORTB = position >> 4;
PORTBbits.RB4 = 1;
PORTBbits.RB4 - 0;
PORTB = position & OxOF;
PORTBbits.RB4 = 1;
PORTBbits.RB4 = 0;
}
26. 0x01, как показано в функции Clear.
// ************* функция Clear ************
//
//
void Clear (void)
{
PORTB = 0;
PORTBbits.RB4 = 1;
PORTBbits.RB4 = 0;
PORTB = 1;
PORTBbits.RB4 = 1;
PORTBbits.RB4 = 0;
}
28. Основным преимуществом ВФИ (вакуумных флуоресцентных индикаторов является
их яркость для любого типа освещения и их способность к снижению яркости све-
чения в случае необходимости.
Приложения
557
30. Шаговые электромоторы называются шаговыми вследствие того, что их вал пово-
рачивается дискретными шагами.
32. Полный шаг соответствует повороту вала шагового электромотора от одной полюс-
ной катушки до другой, в то время как половинный шаг соответствует повороту вала
до точки, расположенной посередине между полюсными катушками. Половинный
шаг выполняется посредством запитывания противоположных полюсных катушек
плюс соседних катушек.
34. Посредством изменения ширины импульса, можно изменять среднее количество
тока, протекающего через электромотор, за счет чего изменяется скорость враще-
ния вала электромотора.
36. Обратный или демпферный диод шунтирует ток, генерируемый возмущением элек-
тромагнитного поля электромотора, реле или индуктивностью, включенной парал-
лельно транзистору, с целью предотвращения выхода из строя элементов контура.
38. Примерно половинная скорость.
40. (Смотрите рисунок С-3)
// ************* функция Fire *************
//
// uses delays.h
//
void Fire (void)
{
PORTBbits. RB3 = 1;
DelaylOKTCYx(70);
PORTBbits.RB3 = 0;
}
42. 0000, 0001,0010, 0011,0101,0111,0110, 0100
44. 125
46. 1если самый правый бит b будет в состоянии логической единицы, то temp будет
инкрементироваться с целью округления.
52. 38 KHz
558
Применение микроконтроллеров PIC 18
ГЛАВА 8
2. 0x0018
4. Бит IPEN находится в регистре RCON.
6. Прерывание по изменению состояния обслуживается первым, поэтому оно имеет
высокий приоритет.
8. Высокоприоритетные прерывания разрешены.
10. Разрешение входа INT1.
12. PIE1 bits.TMR2IE = 1;
14. INTCON
16. Возврат из прерывания устанавливает бит флага GIE/GEIH джля повторного разре-
шения прерываний. Если выполняется команда RETFIE 1, то бит флага GEIL уста-
навливается для повторного разрешения низкоприоритетных прерываний.
18. Низкоприоритетное прерывание в примере 8-3 управляет таймером реального
времени.
20. Один раз каждые 1,024 мс.
22. Асинхронные последовательные данные - это данные, которые посылаются без
синхросигналов. Вместо синхроимпульсов используется передача стартового и
стопового бита в дополнение к информационным битам.
24. 8 информационных битов и 1 стоп-бит
26. UART или USART
28. Приемник выставляет прерывание, поэтому принимаемые данные не теряются.
30. Одно из уравнений из примера 8-4 используется для расчета значения, помещае-
мого в регистр SPBRG. Для установки скорости информационного обмена, равной
1200, SPBRG программируется на 51 для установки высокой скорости, для установ-
ки низкой скорости регистр SPBRG программируется на 207.
32. Каждая очередь имеет 16.
34. Флаг прерывания приемника сбрасывается, а данные из RCREG помещаются во
входную очередь.
36. Третий параметр в
bool retVal - WriteFile (hPort,Data,1,
&byteswritten,NULL);
изменяется - его значение должно быть равно длине строки при записи более од-
ного байта.
38. Преамбула состоит по крайней мере из последовательности десяти 10 битов, нахо-
дящихся в единичном состоянии.
40. К ЭСППЗУ обращаются функции EERead И EEWrite, приведенные в программе.
42. Функция wait4Bit проверяет состояние бита флага с тем, чтобы распознать факт
поступления с рельс в DCC-систему бита данных.
44. Таймер 0 используется для того, чтобы измерить ширину импульса в DCC-системе
с дискретностью в j мкс.
46. Всякий раз, когда используется массив, больший чем 256 байтов, сценарий компо-
новщика должен изменяться с тем, чтобы был объявлен больший массив.
48. МАХ1483 - это схема управления/приемника линии, которая поддерживает стан-
дарт интерфейса RS-422, обеспечивая последовательный информационный обмен
при длине линии вплоть до 4000 футов.
50. Соединительный разъем RJ-45 - это стандартный разъем, используемый с кабе-
лем типа САТ5, а также в сетях.
52. Да, - штрих-код “Код 128” поддерживает алфавитные данные.
56. Это проверка проверки правильности данных в штрих-коде кодировки “Код 128".
58. Время отображается слева от линии 2, а данные отображаются справа от линии 2.
Приложения
559
60. Основной цикл программы проверяет, нажата ли клавиша, есть ли данные в сети и
была вставлена ли карточка.
62. Она проверяет входную очередь с тем, чтобы видеть, прибыли ли данные из сети.
64. DS275 формирует интерфейс с последовательным COM-портом ПК. Уровни сигна-
ла COM-порта равны +/- 12 В, они должны быть преобразованы для микроконтрол-
лера в уровни ТТЛ.
66. Транзистор посылает сигнал, который реверсирует линию в полудуплексной сети.
68. Модуль электропитания обеспечивает электропитание системы, кроме того он
формирует интерфейс системы с COM-портом ПК и управляет сетью.
ГЛАВА 9
2. Прерывание используется для того, чтобы обнаружить факт открытия дверцы в
течение цикла мытья посуды.
4. (См. рис. С-4)
Заполните линяй
соленоид
Электромотор
насоса
Дренажный
клапан
Распределитель
моющего
средства
Нагревательный
элемент
0 5 10 15 20 25 30 35 40 45 50 минуты
Рис. С-4. Временная диаграмма цикла стерилизации; вода нагревается
10. Два - один отдатчика скорости вращения вала передаточного механизма и один от
задатчика времени или таймера.
12. 13 Ватт
14. RS-422 или RS-485
16. Синхронизация всех подчиненных устройств.
18. Реле используется только по причине стоимости системы. Контроллер электромо-
тора, который позволяет управлять вращением электромотора в обоих направлени-
ях, стоит больше.
22. Управление системой нагрева/кондиционирования воздуха (HVAC) осуществляется
сигналами 24 В переменного тока, которые формируются в данном приложении за
счет использования реле, которые управляются микросхемами управления TIP120.
24. Нет. Температура наружного воздуха должна быть известной для того, .чтобы опре-
делить, необходимо ли кондиционирование воздуха или его нагрев.
26. ЭСППЗУ используется для сохранения параметров настройки системы.
560
Применение микроконтроллеров PIC 18
ГЛАВА 10
2. Интерфейс с ЭСППЗУ является последовательным, поэтому программное обеспече-
ние SPI или 12С может использоваться для этого интерфейса.
4. A-входы программируются так, чтобы выбрать ЭСППЗУ.
6. 100 кГц
8. Сигнал АСК проверяется после записи в ЭСППЗУ - он указывает на то, что запись
завершена.
10. Первое ЭСППЗУ выбирается, если адрес меньше, чем 0x8000, а другое выбирается,
если адрес лежит в диапазоне от 0x8000 до OxFFFF.
14, Основной цикл программы проверяет, был ли введен правильный UPC- код.
16. Код отображается на экране ЖК-индикатора, пользователь запрашивается о коли-
честве единиц товара, введенное значение сохраняется в очереди ЭСППЗУ для по-
следующей его передачи в ПК через последовательный интерфейс.
18. Блок начальной загрузки - это защищенная область памяти, обеспечивающая про-
странство для хранения программы начальной загрузки.
20. Способность перепрограммирования памяти программ микроконтроллера обеспе-
чивает возможность обновления программных средств системы без извлечения
микроконтроллера.
22. Программное обеспечение использует команды goto для того, чтобы переориенти-
ровать вектор сброса и векторы прерываний на ячейки памяти, расположенные вы-
ше защищенного блока начальной загрузки.
24. Мнемонические обозначения кодов операций во встроенном ассемблере отлича-
ются от мнемонических обозначений кодов операций в стандартном Ассемблере.
26. Эта интегральная схема представляет собой сдвиговый регистр, содержащий параллель-
ный триггер, используемый как буфер для обеспечения надежной работы схемы.
28. Использование двухпроводного интерфейса 12С позволяет экономить один штырек
порта.
30. Программа передает измененное значение скорости на электромотор через ЦАП.
32. 1000 метров
34. 20
36. ECAN.H
38. Каждый контроллер этажа контролирует состояние кнопок UP (ВВЕРХ) И DOWN
(ВНИЗ) и посылает информацию о их нажатии в контроллер кабины лифта, если ка-
кая-либо из названных кнопок нажата. Контроллер этажа также отображает номер
этажа, на котором находится кабина лифта, - эта информация получается от кон-
троллера кабины лифта.
40. USB - это универсальная последовательная шина, доступная в версиях 1.0
(1 мбит/с), 1.1 (11 мбит/с) и 2.0 (480 мбит/с).
42. 4
44. Программа считывает напряжения с интерфейса через каждую половину секунды и
передает считанные значения в ПК через USB.
46. Функция OnTimer вычисляет напряжение по необработанным данным, полученным
через USB, и отображает результат в ярлыках Active-X, соответствующих каждому
напряжению.
48. Файл .inf устанавливается, когда микроконтроллер первый раз подключается к USB
на ПК. Установка производится автоматически, за исключением указания места, где
в ПК находится требуемый файл .inf.
50. FSR2
52. Команда CALLW используется для вызова функции, адресуемой счетчиком команд,
при этом самые правые 8 битов равны содержимому регистра WREG.
Приложения
561
Приложение D
PIC-система, использующая интерфейс USB
В этом приложении рассматривается схемное решение, а также программа для
реализации PIC-системы со встроенной программой начальной загрузки, которая со-
единяется с ПК через шину USB. Эта система может использоваться в лабораторной
среде для изучения микроконтроллеров PIC или же как недорогая система разработки
программных средств. Данная PIC-система стоит приблизительно от 30 до 40 долларов
США, что намного дешевле, чем что-либо подобное на рынке. Вместе с тем ее созда-
ние обеспечит ценный опыт формирования достаточно полной небольшой системы.
Конструкция может быть собрана либо с использованием метода скрутки (что несколь-
ко дороже) или же на базе коммутируемой панели ввиду относительно небольшого ко-
личества соединений, необходимых для создания системы. Поскольку эта система ис-
пользует интерфейс USB, а микроконтроллер PIC программируется по месту, то она
идеально подходит для какого-либо современного экспериментирования. Единствен-
ный раз, когда микроконтроллер должен быть установлен в PIC-программатор, - это
момент начального программирования, когда в PIC записывается программа началь-
ной загрузки. После этого первичного программирования, PIC-плата программируется
с использованием программы начальной загрузки, резидентной в блоке начальной за-
грузки. Это позволяет программировать систему по месту без использования PIC-
программатора.
Для системы был выбран микроконтроллер PIC18F4550I/P, имеющий пластмас-
совый корпус типа PDIP, поскольку он имеет встроенный быстродействующий интер-
фейс USB, который работает на скорости 1 мбит/с или 12 мбит/с (USB 2.0 согласно
Microchip). Система запитывается от ПК через кабель USB, который обеспечивает до
ток вплоть 500 мА, после чего уже потребуется дополнительное электропитание. Сам
по себе микроконтроллер PIC при полной нагрузке может выдавать только 200 мА, та-
ким образом к плате почти ничего нельзя подключить без использования дополнитель-
ного электропитания. Здесь рассматривается самая последняя версия программы сис-
тема. Она имеется также на вебсайте по адресу http://members.ee.net/brey в разделе
"Технические средства”. Программа включает небольшую операционную систему ре-
ального времени, а также начальный загрузчик.
Рисунок D-1 показывает схему принципиальную системы, которая полностью от-
лажена и будет работать, если собрана в соответствии с показанной схемой. Все неис-
пользуемые штырьки ввода-вывода (21 штырек) вставлены в 30-гнездный разъем типа
SIP (корпус с одним рядом выводов) разъем, который может быть обрезан до размера,
соответствующего 21 штырьку. Эти разъемы могут быть приобретены по адресу
http://www.elexp.com, так что будет довольно просто экспериментировать с данной
платой и подключать к ней почти все, что угодно, используя проводники, подключаемые
к штырькам SIP. Все детали этой системы могут быть приобретены где угодно, включая
http://www.mouser.com, http://www.digikey.com, http://www.allelectronics.com и
http://www.Elexp.com. На плате смонтирован соединительный разъем типа A USB, по-
скольку стандарт USB указывает, что при соединении компьютера с компьютером по
USB (если считать PIC компьютером), обе системы должны иметь соединительный
разъем типа А. Используется USB-кабель А-А, который имеет длину 6 футов (2 метра).
В системе может работать малая клавиатура телефонного стиля с матрицей 4x4 мат-
рицы либо с матрицей 3 х 4 - в последнем случае понадобится только незначительная
модификация программного обеспечения.
562
Применение микроконтроллеров PIC 18
5V г,
О С2
Максимум 500 мА
Reset
z 16 MHz
PIC18F4550
U1 ’
2
___5_
___6_
ДЗ.
19
20
21
21
27
28
29.
30
33
R80 [ад
R81
RB2
RB3
RB4
RB5
RB6
RB7H“-
36
RA0
RA1
RA2
RA3
RA4
. , RA5
fC MCLR
Г OSC1
П 0SC2
RD0
RD1
RD2
RD3
RD4
RD5
RD6
RD7
RE0
40
15
use
v> и>
V) V)
0
F
Е
3
6
9
2
5
8
В
С
D
клавиатура 4x4
RC1 17
*сгН£-
D-
D+
RC6
RC7
VUSB
RE1
RE2 '
23 ...
24 .
_25_
_26_
18
9____
10
С4
0.22
5VO
ЖКИ-индикатор
2
TOD
ТОЕ
ЮК
2.
2.
С1
0.1
Убедитесь в том, что используемые штырьки
соответствуют выводам ЖК-иидикатора. В данной схеме
используется разводка 2x20, однако при модификации
пршраммных средств может использоваться любая
другая.
Клавиша D используется как клавиша Enter (Ввод)
л
Е
Рисунок D-1
По причине простоты используемой схемы, печатная плата не является необхо-
димой. Непосредственный монтаж работает точно так же и стоит гораздо меньше.
Операционная система обслуживает ЖК-индикатор, малую клавиатуру и внутренний
таймер реального времени. Временные задержки в реальном масштабе времени могут
иметь диапазон от миллисекунд до секунд, так что синхронизация также выполняется
очень просто. Так как временные задержки задаются в реальном времени, то они точны
до +/- 1 мс, что достаточно хорошо для большинства приложений типа управляющих
программ. Так как микроконтроллер работает с тактовой частотой, равной 16 мГц, то он
выполняет 4000000 команд за секунду, что обеспечивает значительный запас мощно-
сти для любого микроконтроллерно-основанного приложения. Операционная система
загружает микроконтроллер, однако меньше, чем 1% его времени. Она также исполь-
зует приблизительно 10% доступной памяти (как памяти программ, так и памяти дан-
ных). Время дня может отображаться как в 24-часовом, так и в 12-часовом формате -
Приложения
563
4
эта индикация в любое время может быть отключена или включена программным пере-
ключателем.
Рисунок D-2
Рисунок D-2 показывает фотографию системной платы. Светодиоды трех цветов
подключены к штырькам порта RCO, RC1 и RC2 с использованием трех 150-Омных то-
коограничивающих резисторов. Эта система показала себя весьма эффективной.
Перечень компонентов: Цена:
1 микроконтроллер PIC18F4550 l/P PDIP $ 6.72
1 40 -штырьковая панель DIP $ .25
1 14 -штырьковая панель DIP (генератор) $ .15
1 30- штырьковая панель SIP для подключений ввода-вывода $ 1.90
1 ЖК-индикатор 2x16 $ 7.50
1 малая клавиатура с матрицей 4x4 $ 5.95
1 резистор на 10 кОм $ .06
1 потенциометр на 10 кОм $ .45
1 кварцевый генератор на 16 мГц $ 1.95
1 нормально разомкнутый кнопочный выключатель $ .50
3 конденсатора на 0,1 мкФ $ .30
1 конденсатор на 0,22 мкФ $ .15
1 USB-кабель длиной 2 метра типа А-А $ 3.50
1 соединительный разъем USB типа А $ .56
Итого $30.21
564
Применение микроконтроллеров PIC 18
Пример D-1 иллюстрирует тестовую программу этой системы. Она позволяет вы-
полнить тестирование системы перед активированием USB. Под управлением этой
программы система функционирует как простые часы, поскольку назначением данной
программы является исключительно тестирование аппаратных средств. Программа
использует файл заголовка blcd.h, который обеспечивает управление ЖК-индикатором
и реализует точные временные задержки. Данный файл заголовка доступен по адресу
http://members.eenet/brey, он также приведен в примере D-2.
Пример D-1
((include <pl8f4550.h>
#include <timers.h>
finclude <blcd.h>
/* Программа первичного тестирования для проекта ЕЕТ-387
Copyright (с) 2006, Barry В. Вгеу
Версия 1.1 ... 5/26/06
требует:
timers.h .. управление таймером
blcd.h .. клавиатура и временные задержки
компоновщик: 18f4550.1кг
// биты конфигурированы программы
#pragma config WDT = OFF //
#pragma config WDTPS = 32768 //
fpragma config BOR = ON //
((pragma config MCLRE = ON //
((pragma config PWRT = OFF //
((pragma config PBADEN = OFF //
((pragma config PLLDIV = 4 //
((pragma config FOSC = ECPLLIO_EC //
((pragma config CPUDIV = OSC1_PLL2 //
((pragma config USBDIV = 2 II
((pragma config VREGEN = ON //
((pragma config STVREN = ON II
((pragma config LVP = OFF //
((pragma config WRTB = ON II
void Highlnt (void);
((pragma interrupt Highlnt
((pragma code _HIGH_INTERRUPT_VECTOR
void _high_ISR (void)
включение сторожевого таймера
отсчет сторожевого таймера (131 секунда)
напряжение частичной потери питания
разрешение общего сброса
активирование таймера включения питания
порт В цифровой
тактовая частота для полноскоростной USB
тактовая частота USB PIC равна 48 мГц
внешний генератор с фазоблокирукшим контуром
высокая скорость USB
включение регулятора USB
сброс по переполнению стека
низковольтное программирование
защита от записи блока начальной загрузки
= 8
_asm goto Highlnt _endasm // переход на подпрограмму обработки
// высокоприоритетных прерываний
}
/* константы в памяти программ */
rom near char keyLookUp[] = { 0, 7, 4, 1, // может потребоваться изменение
15, 8, 5, 2,
14, 9, 6, 3,
13, 12, 11, 10 );
// это для индикатора 2x20
rom near char mesla[] = " The PIC 4550 Demo ";
rom near char meslbf] = " Test Program ";
rom near char mesic[] = " Enjoy the Project!
rom near char mesld[] = "(c) 2006 by B. Brey
rom near char meslf] = " Set Hours:
Приложения
565
rom near char mes2[] = " Set Minutes:
rom near char mes3[] = " 0=24hr or l=12hr
rom near char mes4[] = " The PIC4550 rules!
rom near char mes5[] = " ";
/* это для индикатора 2 x 16
rom near char mesla[] = " PIC 4550 Demo ";
rom near char meslb[] = " Test Program ";
rom near char meslc[] = " Enjoy!!
rom near char rnesld]] = "(c) 2006 by Brey ";
rom near char mesl[] = " Set Hours:
rom near char mes2[] = " Set Minutes:
rom near char mes3[] = "0=24hr or l=12hr
rom near char mes4[] = "The 4550 rules!
rom near char mes5[] = "
*/
/* глобальные переменные в памяти данных */
// время дня
int milli;
char seconds;
char minutes;
char hours;
char buffer [21]; // буфер строки ЖК-индикатора
char displayTimeFlag; // флаг времени отображения
char timeFormat; // 0 = 24-часовый, 1 = 12-часовый
#pragma code
void ShowTime (void)
(
char portDbuffer = PORTD;
char temph = hours;
if (displayTimeFlag != 0)
{
if (temph > 12 && timeFormat == 1) // формирование надписи
11 AM/PM (до полудня/после полудня)
temph -= 12;
else if (temph == 0 && timeFormat == 1)
temph = 12;
buffer[0] = temph/10 I 0x30;
if (buffer[0] == 0x30 )
buffer [0] = 0x20; // пробел в начальный ноль значения часов;
buffer[1] = temph % 10 1 0x30;
bu f f e r[2] = ':' ;
buffer[3] = minutes / 10 I 0x30;
buffer [4] = minutes % 10 I 0x30;
buffer[5] = ':'
buffer[6] = seconds / 10 I 0x30;
buffer]?] = seconds % 10 1 0x30;
if (timeFormat == 1)
{
buffer[8] = 0x20;
if (hours >= 12)
buffer [9] = 'P';
else
buffer[9] = 'A';
buffer[10] = 'M';
buffer[11] = 0;
566
Применение микроконтроллеров PIC 18
AddrLCD(Oxc); // отображение времени
)
else
{
buffer[8] = 0;
AddrLCD(Охсб) ;
}
putsLCD ffer) ;
}
PORTD = portDbuffer;
J
void DoTime (void)
{
milli++;
if (delayms != 0) // временная задержка в 1 мс
{
delayms--;
if (delayms == 0)
mflag = 0;
}
if (milli == 1000)
{
milli = 0;
seconds++;
if (delaySec != 0) // секундная временная задержка
{
delaySec—;
if (delaySec == 0)
sflag = 0;
)
if (seconds == 60)
{
seconds = 0;
minutes++;
if (minutes == 60)
{
minutes = 0;
hours++;
if (hours == 24)
hours = 0;
)
}
}
if (milli == 0) // проверка на новую секунду
{
INTCONbits . GIEH = 1; // разрешение высокоприоритетно прерываний
ShowTime();
}
)
void Highlnt(void) // прерывание
{
if (PIRlbits.TMR1IF == 1) Il режим 24 часов
{
PIRlbits . TMR1IF = 0; // повторное разрешение прерывания от таймера 1
WriteTimerl(-11810); // перепрограммирование смешенного отсчета (190)
DoTime();
Приложения
567
char ReadKey (void)
(
char select = Oxef;
char col = -4;
char mask = 1;
PORTD = 0;
do
(
while ((PORTD & OxOf) != OxOf)
ClrWdt () ;
DelayMs(15); // 15 мс
} while ((PORTD & OxOf) != OxOf);
do
{
while ((PORTD & OxOf) == OxOf)
ClrWdt () ;
DelayMs(15);
} while ((PORTD & OxOf) == OxOf);
do
{
PORTD = select;
select «= 1;
col += 4;
} while ((PORTD & OxOf) == OxOf);
while ((PORTD & mask) == mask)
(
col++;
mask <<= 1;
}
return keyLookUp[col];
void SetTime (char* clock, char maxTensDigit)
{
char temp;
do
(
*clock = 0;
ShowTime();
temp = ReadKey();
if (temp <= maxTensDigit)
*clock += temp * 10;
ShowTime();
temp = ReadKey();
if (temp < 10)
*clock += temp;
ShowTime();
temp = ReadKey();
} while (temp != 13);
AddrLCD(0x80);
putrsLCD(mes2);
J
void InitializeSystem (void)
(
ADCON1 = 0x3f; // все входы цифровые
PORTE = 0x80; // вклинение нагрузочных резисторов порта D
TRISD = OxOf; // настройка входов порта D
WDTCONbits.SWDTEN = 1; // активирование сторожевого таймера
milli = seconds = minutes = hours = 0; // время = 00:00:00
568
Применение микроконтроллеров PIC 18
displayTimeFlag = 0; //не отображать время
delayms = delaySec = 0; OpenTimerl (TIMER_INT_ON & // сброс задержек // программирование таймера 1
T1_16BIT_RW & T1_SOURCE_INT & T1_PS 1_1 & T1_OSC1EN_OFF & T1_SYNC_EXT_OFF); WriteTimerl (-12000); // установка отсчета таймера 1 (1,0 мс)
RCONbits.IPEN = 1; IPRlbits.TMR1IP = 1; // IPEN = 1 // объявление таймера 1
// высокоприоритетным
INTCONbits.GIEH = 1; // разрешение высокоприоритетных прерываний
OpenLCD(); // инициализация ЖК-индикатора
void ShowStrings (const rom char *linel, const rom char *line2, char delay)
AddrLCD (0x80); putrsLCD (linel); AddrLCD (OxcO); putrsLCD (line2);
DelaySec (delay);
}
void main (void)
char a; InitializeSystem(); ShowStrings (mesla, meslb, 5 ); ShowStrings (mesic, mesld, 5 ); AddrLCD (OxcO); putrsLCD (mes5); AddrLCD (0x80); putrsLCD (mesl); timeFormat = 0; displayTimeFlag = 1; // отобразить время
SetTime (&hours, 2); // установка часов
AddrLCD (0x80); putrsLCD (mes2); SetTime (&minutes, 5); // установка минут
AddrLCD (0x80); putrsLCD (mes3); AddrLCD (0x80); putrsLCD(mes3); a = ReadKeyO; if (a < 2) timeFormat = a; AddrLCD (0x80); putrsLCD (mes5); AddrLCD (OxcO); putrsLCD (mes5); ShowTime(); for (a = 0; a < 20; a++) { AddrLCD (0x80 I a); WriteLCD(mes4[a]); DelayMs(150); } for (a = 0; a < 5; a++)
Приложения
569
{
AddrLCD (0x80);
putrsLCD (mes5);
DelayMs (400);
AddrLCD (0x80);
putrsLCD (mes4);
DelayMs (400);
}
while (1)
{
ClrWdt();
}
// сброс сторожевого таймера
Пример D-2
/*
Временные задержки и управление ЖК-индикатором
(с) 2006, Barry В. Вгеу
содержит:
DelayMs (unsigned int count) // вызывает задержку от 1-К до 64-К миллисекунд
DelaySec (unsigned int count) // вызывает задержку от 1-К до 64-К секунд
OpenLCD()
AddrLCD()
putsLCD (char *buffer )
putrsLCD (const rom char buffer)
WriteLCD (char data )
*/
(fifndef __BLCD_H
((define __BLCD_H
unsigned int delayms;
char mflag;
unsigned int delaySec;
char sflag;
# pragma code
void ShortDelay (void)
(
Nop() ;
Nop();
Nop();
Nop () ;
Nop();
Nop();
Nop () ;
Nop();
Nop ();
Nop();
// открывает ЖК-индикатор для его использования
// адресует позицию индикатора
// 0x80 - это строка 1, ОхСО - это строка 2
// отображение строки символов из ЗУПВ
// отображение строки символов из ПЗУ
// отображение одного символа
// миллисекундная задержка
// секундная задержка
// ожидание бита
являются необходимыми вследствие того,
половинами целых чисел,
поэтому
// Переменные mflag и sflag далее
// что команда while (delaysm)
// будет иногда прерываться между
// что вызовет неверное функционирование системы,
// нужно использовать байтовые флаги.
void DelayMs (unsigned int count) // вплоть до 64K миллисекунд
{
delayms = count; // delayms изменяется в функции
DoTime()
mflag = 1;
570
Применение микроконтроллеров PIC 18
while (mflag);
}
void DelaySec (unsigned int count) // вплоть до 64K секунд
(
delaySec - count; // dalaySec изменилась в DoTime()
sflag = 1;
while (sflag);
void SendLCD (char command, char data ) // для внутреннего использования
{
char a;
PORTEbits.REO = command; // установ либо сброс бита RS
PORTD = data & OxfO; // d7 == d4 на ЖКИ
ShortDelay(); // короткая задержка
PORTEbits.RE1 =1; // установ E
ShortDelay(); // короткая задержка
PORTEbits.RE1 = 0; // сброс E
ShortDelay();
PORTD = data «4; // d3 - dO на ЖКИ
ShortDelay(); // короткая задержка
PORTEbits.RE1 = 1; H установ E
ShortDelay(); // короткая задержка
PORTEbits.RE1 = 0; H сброс Е
PORTE = 0x80; for (a = 0; a < 27; a++)
ShortDelay(); II ожидание 40 мкс
OpenLCD (void) H открытие ЖКИ
char a; char reset[] = { 0x28, 1, 12, 6}; // формирование команд
TRISE = TRISE & Oxfc; H RE0 и RE1 являются выходами
TRISD = TRISD & OxOf; H RD4 -- RD7 являются выходами
PORTEbits.RE1 = 0; / / сброс Е
DelayMs(16); // ожидание 16 мс (время включения)
for (a = 0; a < / 3; a++) И выдача команд сброса
i SendLCD(0, DelayMs(5) } 0x20); // ожидание 5 мс
for (a =0; a < 4; a++) H выдача команд настройки
{
SendLCD(0, reset[a]);
DelayMs(2);
}
void AddrLCD (char addr) // установка адреса индикатора
{ H строка 1 находится от 0x80 до 0x87
) SendLCD (0, addr); H строка 1 находится от ОхсО до Oxcf
void putsLCD (char *buffer) // отображение строки из памяти данных
while (*buffer)
{
SendLCD(1, *buffer);
buffer++;
Приложения
571
void putrsLCD (const rom char *buffer) // отображение строки из памяти программ
(
while (*buffer)
{
SendLCD(l, *buffer);
buffer++;
}
}
void WriteLCD (char data) // отображение одного символа
SendLCD (1, data);
flendif
Как только программа из примера D-1 будет перенесена в PIC, что потребует ис-
пользования программатора типа PICSTART PLUS, нужно запитать систему, подключив
ее к разъему USB ПК. Первое, что вы увидите на индикаторе - это фраза "Set Hours:"
(Установите часы). Введите время в 24-часовом формате, вводя данные с малой кла-
виатуры и нажимая клавишу ENTER (Ввод) (или любую другую клавишу, которая на ис-
пользуемой вами клавиатуре функционирует как клавиша ENTER (Ввод)). Малая кла-
виатура может иметь, а может и не иметь клавиши ENTER. (В схеме по рисунку D-1 в
качестве клавиши ENTER используется клавиша D.)
Следующий шаг заключается в разработке, или по крайней мере модификации,
программы начальной загрузки, которая доступна на сайте Microchip. Она может быть
выгружена с этого сайта, имеется также ее скомпилированная версия в шестнадцати-
ричных кодах. Перед использованием эта программа начальной загрузки должна быть
модифицирована с тем, чтобы она могла работать с вашими аппаратными средствами.
Система обращается к программе начальной загрузки всякий раз, когда нажимается и
удерживается в нажатом состоянии до момента сброса или включения системы. Если
система сбрасывается без удержания в нажатом состоянии клавиши клавиатуры, то
выполняется приложение, загруженное в PIC.
Единственный файл, необходимый для того, чтобы система функционировала
описанным способом, - это файл, приведенный в примере D-3. Откройте новый проект
и настройте его так, как это описано в примере D-3. Удостоверьтесь в том, что пере-
численные файлы загружены с сайта фирмы Microchip, а сценарий компоновщика из-
менен указанным образом, иначе результирующий код не поместится в пространстве
памяти загрузочного блока объемом 2К байт. Как только будут выполнены все настрой-
ки и программа будет написана, выполните компоновку программы (или выгрузите с
сайта фирмы Microchip ее скомпилированную шестнадцатиричную версию), а затем
запрограммируйте PIC, используя программатор типа PICSTART PLUS.
Пример D-3
/*
Для создания этой программы
1. Создайте новую программу, используя мастер проектов
2. Добавьте файл компоновщика 18f4550.1kr,
нужные файлы/папки находятся в папке MCHPFSUSB\fw\Boot
3. Скопируйте систему и папку autofile в ваш каталог
4. Скопируйте файл io_cfg.h в ваш каталог
5. Добавьте следующие исходные файлы в проект:
boot.с, usb9.c, usbctrltrf.с, usbdrv.c, usbdsc.c и usbmmap.c
572
Применение микроконтроллеров PIC 18
б. Добавьте к проекту следующие файлы заголовков:
boot.h, usb.h, usbcfg.h, usbdsc.h, usbmmap.h, io_cfg.h,
typedefs.h
7. В опциях компоновки выберите проект, затем выберите закладку MPLAB
С18, щелкните на позиции Alternate (Изменить), а затем введите -scs
Теперь выполните компоновку проекта.
*/
#include <pl8f4550.h>
#include "system\typedefs.h"
#include "system\usb\usb.h"
#include "io_cfg.h"
fpragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config BOR = ON
fpragma config MCLRE = ON
((pragma config PWRT = OFF
((pragma config PBADEN = OFF
#pragma config PLLDIV = 4
((pragma config FOSC = ECPLLIO_EC
#pragma config CPUDIV = OSC1_PLL2
((pragma config USBDIV = 2
((pragma config VREGEN = ON
((pragma config STVREN = ON
((pragma config LVP = OFF
I'pragma config WRTB = ON
// включение сторожевого таймера
// отсчет сторожевого таймера (131 секунда)
// напряжение частичной потери питания
// разрешение общего сброса
// активирование таймера включения питания
// порт В цифровой
// тактовая частота для полноскоростной USB
// тактовая частота USB PIC равна 48 мГц
// внешний генератор с фазоблокирукшим контуром
// высокая скорость USB
// включение регулятора USB
// сброс по переполнению стека
// низковольтное программирование
// защита от записи блока начальной загрузки
// вектора прерываний
((pragma code _HIGH_INTERRUPT_VECTOR = 0x000008
void _high_ISR (void)
_asm goto 0x808 _endasm // новый адрес вектора
}
((pragma code _LOW_INTERRUPT_VECTOR = 0x000018
void _low_ISR (void)
(
_asm goto 0x818 _endasm // новый адрес вектора
}
((pragma code
void main (void)
(
char temp; И сохранение состояния сброса
char tempi; char temp2; char temp3; temp2 = PORTE; PORTE = 0x80; // включение нагрузок порта D
temp = ADCON1; tempi = TRISD; temp3 = PORTD; ADCON1 != OxOF; //цифровой ввод-вывод
TRISD = OxOF; // настройка клавиатуры
PORTD = 0; // выборка всех клавиш клавиатуры
// проверка на режим начальной загрузки (нажатие любой
// клавиши клавиатуры для сброса))
if ((PORTD & OxOf) == OxOf) // если никакая клавиша не нажата,
// выбирается пользовательский режим
Приложения
573
PORTE = temp2; // восстановление значений сброса
TRISD = tempi;
ADCON1 = temp;
PORTD = temp3;
_asm goto 0x800 _endasm // новый адрес вектора сброса
}
// режим начальной загрузки
mlnitializeUSBDriver(); // смотрите usbdrv.h
USBCheckBusStatus(); // модифицировано для постоянного
// активирования модуля USB
while (1)
{
USBDriverService(); // смотрите usbdrv.c
BootService (); // смотрите boot.с
)
После записи программы начальной загрузки, система будет готова к програм-
мированию через USB-подключение к ПК. Имеется только одна проблема: программа
должна написана так, чтобы она начиналась по адресу 0x800 вместо 0x000. Это дости-
гается посредством такого изменения файла компоновщика, которое иллюстрируется
в примере D-4, хорошей идеей является также переименование этого файла, - напри-
мер назовем его boot18f4550.lkr вместо 18f4550.lkr. Первые две строки объявления
кодовых страниц (CODEPAGE) теперь будут новыми, а третья - закомментирована. Ко-
довая страница, названная boot, - это защищенная программа начальной загрузки, а
страница, названная vectors переопределяет стартовый адрес как 0x800.
Пример D-4
// $Id: 18f4550.Ikr,v 1.3 2004/08/23 18:08:22
// файл: 18f4550.1kr
// Пример сценария компоновщика для процессора PIC18F4550
LIBPATH .
FILES c018i.o
FILES clib. lib
FILES pl8f4 550.lib
CODEPAGE NAME=boot START=0x0 END=0x7FF PROTECTED
CODEPAGE NAME=vectors START=0x800 END=0x0x829 PROTECTED
// CODEPAGE : NAME=vectors START=0x0 END=0x29 PROTECTED
// CODEPAGE : NAME=page START=0x2A END=0x7FFF
CODEPAGE NAME=page START=0x82A END=0x7FFF
CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=0xF00000 END=0xF000FF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gprl START=0xl00 END=0xlFF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK . NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=usb4 START=0x400 END=0x4FF PROTECTED
DATABANK NAME=usb5 START=0x500 END=0x5FF PROTECTED
DATABANK NAME=usb6 START=0x600 END=0x6FF PROTECTED
DATABANK NAME=usb7 START=0x700 END=0x7FF PROTECTED
ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
SECTION NAME=CONFIG ROM=config
STACK SIZE= ;0xl00 RAM=gpr3
574
Применение микроконтроллеров PIC 18
После того, как показанные изменения будут проведены, любая написанная про-
грамма должна использовать boot 18f4550. Ikr файл из примера D-4 вместо файла
18f4550.lkr. Пример D-5 иллюстрирует изменения, проведенные в программе по при-
меру D-1 с тем, чтобы она функционировала в среде начальной загрузки. (Первый под-
раздел из D-1 удален и заменен вторым подразделом). Это изменяет адреса вектора
сброса и высокоприоритетного прерывания. В этой тестовой программе низкоприори-
тетный вектор прерывания не используется.
Пример D-5
// оригинал из примера D-1 (удален)
// должен использоваться модифицированный файл компоновщика
void Highlnt (void); // прототипы
((pragma interrupt Highlnt
((pragma code high_vector = 8
void high_vector (void) // высокоприоритетный вектор f
t _asm GOTO Highlnt _endasm // переход на подпрограмму обработки
// высокоприоритетных прерываний
// replaces original in Example D-1
void Highlnt (void);
extern void _startup (void); // смотрите c018i.c в каталоге
// компоновщика компилятора Cl8
((pragma code _RESET_INTERRUPT_VECTOR = 0x800
void _reset (void)
{
_asm goto _startup _endasm
((pragma interrupt Highlnt
((pragma code _HIGH_INTERRUPT_VECTOR = 0x808
void _high_ISR (void)
{
_asm goto Highlnt _endasm // переход на подпрограмму обработки
// высокоприоритетных прерываний
}
Шестнадцатеричный файл программы начальной загрузки (которая программи-
руется с использованием программатора типа PICSTART PLUS) называется boot.hex на
http://members.ee/net/brey, тестовая программа по примеру D-1 называется test.hex, а
тестовая программа, модифицированная для начальной загрузки, называется
boottest.hex. Они могут быть выгружены для проверки системы.
Содержание компакт-диска
575
Содержание компакт-диска
- Справочные данные на семейство микроконтроллеров PIC18
- Примеры программ
- Microchip MPLAB IDE версия 7-3
- Microchip MPLAB IDE версия 7-5
- Драйверы USB
- Компилятор C18
- Интерфейс USB. Программы