Вы находитесь на странице: 1из 259

О. М.

Кочуров

ПРОГРАММИРОВАНИЕ ВСТРАИВАЕМЫХ
СИСТЕМ НА ОСНОВЕ МИКРОКОНТРОЛЛЕРОВ
LPC214X
Учебное пособие
Министерство образования и науки РФ

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

Кафедра управления и информатики в технических


и экономических системах

Учебное пособие

ПРОГРАММИРОВАНИЕ ВСТРАИВАЕМЫХ СИСТЕМ


НА ОСНОВЕ МИКРОКОНТРОЛЛЕРОВ LPC214X

О. М. Кочуров

Владимир 2011
УДК 004.31
УДК 004.031.6

ББК 32.973–04
К75

Кочуров О. М., Программирование встраиваемых систем на основе


микроконтроллеров LPC214x. — Владимир: ВлГУ — 2011, 258 с.

Настоящее учебное пособие, состоящее из трех частей, предназначено


для изучения архитектуры и основных приемов программирования микро-
контроллеров LPC214x (производства NXP) семейства ARM7TDMI. В первой
части изложен справочный материал по аппаратным средствам микро-
контроллера. Вторая часть посвящена средствам разработки и отладки про-
грамм, прежде всего, среде Keil µVision на основе языка Си. Третья часть со-
держит описание решения типовых задач, представляющих интерес в прак-
тике разработки микропроцессорных систем.
Учебное пособие предназначено для широкого круга специалистов в
области электроники и микропроцессорной техники. Также может быть ре-
комендовано студентам бакалавриата и магистратуры, изучающим дисци-
плину «Микропроцессорная техника» и родственные дисциплины.
Перечень сокращений
АЛУ — арифметико-логическое устройство
АЦП — аналого-цифровой преобразователь
ЖК(И) — жидкокристаллический (индикатор)
МК — микроконтроллер
МП — микропроцессор
МПС — микропроцессорная система
МПУ — микропроцессорное устройство
ОЗУ — оперативное запоминающее устройство
ПД — память данных
ПЗУ — постоянное запоминающее устройство
ПК — персональный компьютер
ПП — память программ
ПУ — периферийное устройство
РОН — регистр общего назначения
РСФ — регистр специальных функций
СИФУ — система импульсно-фазового управления
УУ — устройство управления
ФАПЧ — фазовая автоподстройка частоты
ЦАП — цифро-аналоговый преобразователь
ШИМ — широтно-импульсный модулятор

3
Предисловие
Настоящее учебное пособие предназначено для изучения архитектуры
и основных приемов программирования встраиваемых однокристальных
микроконтроллеров серии LPC214x фирмы NXP. Материал изложен в трех
частях.
Первая часть преимущественно содержит материал справочного ха-
рактера — описание архитектуры и аппаратных средств микроконтроллера.
Предложенное описание, затрагивая важнейшие узлы LPC2148, не является
полным. Некоторые из аппаратных средств не рассмотрены. Изучив материал
настоящего учебного пособия читатель без труда дополнит свои знания с по-
мощью известных книг [1, 2] а также официальной документации компаний
ARM и NXP, ссылки на которые приведены в приложении.
Отметим, что первая часть не повторяет перевода официальной до-
кументации, а представляет собой авторское изложение материала. Каждый
раздел начинается с краткого описания основных возможностей одного из
узлов микроконтроллера, после чего следует основная справочная часть. В
конце разделов приводятся методические указания по настройке рассмотрен-
ных узлов и управлению ими.
Вторая часть посвящена программным и аппаратным средствам, кото-
рые необходимы для разработки программ. Здесь читатель найдет основы
представления числовой информации в памяти вычислительных устройств, а
также экскурс в программирование на языке Си. Привнести что-либо новое в
описание самого распространенного языка программирования трудно, кроме
краткости. Поэтому авторы касаются лишь наиболее важных вопросов, без
знания которых невозможна разработка ни одной программы. Авторы стре-
мились не обойти вниманием некоторые приемы программирования и кон-
струкции, которые часто возникают при программировании микроконтрол-
леров и редко в практике программирования для персональных ЭВМ. Для
углубленного изучения языка рекомендуем иметь под рукой один из извест-
ных учебников [3, 4]. Значительное внимание уделено описанию популярной
среды программирования Keil µVision 4. Авторы предложили методику от-
ладки программ.
Третья часть представляет собой методические указания по решению
практических задач. В каждом разделе дано описание алгоритмического ре-
шения очередной элементарной задачи. Аппаратной основой авторам послу-
жили учебные платы EA-EDU-001 и EA-EDU-011 фирмы Embedded Artists.
Схемотехнические узлы этих плат вполне могут считаться классическими и
легко заимствуются с помощью принципиальных схем, приведенных в при-
ложении. Тематика практических занятий охватывает весьма широкий круг
задач, возникающих в практике разработки микропроцессорных средств, та-
ких как ввод-вывод аналоговых и цифровых сигналов, опрос аналоговых,
дискретных и цифровых датчиков, индикация, обмен данными с другими
компонентами микропроцессорной системы и персональным компьютером.

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

5
Введение
Исторически первый четырехразрядный микропроцессор был разра-
ботан фирмой Intel в 1971 году для применения в настольных микрокальку-
ляторах. Микросхема i4004 выпускалась в корпусе PDIP16, выполняла
92,6 тысяч действий в секунду и адресовала всего 640 байт памяти. Система
команд первого процессора включала 46 инструкций. Давно известные прин-
ципы программного управления впервые были применены в интегральной
микросхеме. Это положило начало новому направлению микросхемотехники.
На протяжении сорока лет микропроцессорная техника может по пра-
ву считаться наиболее динамично развивающимся направлением микросхе-
мотехники. Постоянно повышаются тактовые частоты микропроцессоров,
увеличивается число полупроводниковых элементов на кристалле, усложня-
ются операционные узлы и система команд.
Универсальные микропроцессоры, предназначенные для решения ши-
рокого круга задач, связанных с обработкой цифровой информации, стали
основой для построения персональных компьютеров. Благодаря высокому
быстродействию, разрядности и объему адресуемой памяти такие микропро-
цессоры отличаются способностью выполнять громоздкие алгоритмы за при-
емлемое время.
Чрезвычайная гибкость микропроцессоров сделала их привлекатель-
ными для применения в составе разнообразных технических изделий от бы-
товых приборов до промышленных установок. По мере широкого распро-
странения микропроцессоров возникла необходимость в разработке эконо-
мичных, компактных и исключительно надежных микропроцессорных си-
стемы, причем, в кратчайшие сроки.
Высокопроизводительные универсальные микропроцессоры не удо-
влетворяют таким потребностям. Их ядро представляет собой набор взаимо-
действующих интегральных микросхем высокой степени интеграции с боль-
шим числом выводов. При этом требуется изготовление печатных плат высо-
кого класса плотности монтажа. Передача цифровых сигналов в микропро-
цессорных системах осуществляется в диапазоне высоких и ультравысоких
частот, что также выдвигает жесткие требования к технологии изготовления
аппаратуры. Кроме того, универсальные микропроцессоры не приспособле-
ны для непосредственного взаимодействия со средой, требуя еще и сложных
средств сопряжения.
Разрешить возникшие противоречия позволило создание микро-
контроллеров. Эти устройства представляют собой совмещение всех элемен-
тов микропроцессорной системы на одном кристалле.
Микроконтроллеры предназначены для решения задач управления
объектом в реальном времени. Помимо микропроцессорного ядра содержат
встроенные память для программы и данных, а также периферийные устрой-
ства для сопряжения с объектом. Как правило, микроконтроллеры обладают
меньшим быстродействием, разрядностью и объемом памяти, чем универ-

6
сальные микропроцессоры, но выделяются развитыми средствами для ввода
и вывода дискретных и аналоговых сигналов.
Первый микроконтроллер i8051 также был разработан фирмой Intel в
1980 году. Это был 8-разрядный микроконтроллер, выполненный в виде мик-
росхемы в корпусе PDIP40. Архитектура 8051 (или ее развитие 8052), реали-
зованная во множестве модификаций микроконтроллеров, чрезвычайно по-
пулярна до настоящего времени и будет оставаться популярной еще, по
меньшей мере, десять лет.
Число семейств микроконтроллеров, разработанных за тридцатилет-
нюю историю, по всей видимости, исчисляется сотнями, а в каждом семей-
стве насчитывается до нескольких десятков микросхем. Разнообразие дей-
ствительно огромно: от очень простых микросхем всего с шестью выводами
до сложных однокристальных систем ввода, вывода и обработки сигналов.
Сегодня микроконтроллеры чрезвычайно распространены, составляя
основу для построения так называемых встраиваемым систем, то есть микро-
процессорных систем, встроенных в какое либо изделие и управляющее им
или его узлами. С использованием микроконтроллеров конструируется со-
временное промышленное оборудование, контрольно-измерительные прибо-
ры, бортовые устройства транспортных средств, медицинские и бытовые
приборы. Знание архитектур распространенных микропроцессоров и микро-
контроллеров, владение приемами их программирования и отладки программ
необходимы инженеру, работающему в этих областях техники.

7
Часть 1. Архитектура и аппаратные средства
микроконтроллера LPC214x

1.1 Общие сведения о микроконтроллерах LPC214x


Рассматриваемый в настоящем учебном пособии микроконтроллер
LPC214x фирмы NXP построен на основе архитектуры ARM7. Архитектура
ARM7 создана в 1994 году компанией ARM (Advanced RISC Machines), спе-
циализирующейся на разработке процессорных ядер. ARM7 стоит в ряду
других разработок этой компании, среди которых наиболее известны ARM9,
Cortex-M0/M3/M4. Компания ARM предоставляет лицензии на использова-
ние архитектур процессоров ведущим мировым производителям, таким как
Atmel, NXP, STMicroelectronics, Texas Instruments, Analog Devices.
Микроконтроллеры на базе архитектуры ARM7 сегодня входят в чис-
ло лидеров по популярности среди 32-разрядных микроконтроллеров. Можно
ожидать, что в ближайшие годы архитектура ARM7 и родственные ей Cortex
будут постепенно заменять архитектуру 8051/8052, сохраняющую популяр-
ность на протяжении 30 лет. Об этом свидетельствует пример компании Ana-
log Devices, многие годы выпускавшей микроконтроллеры ADUC8xx со
встроенными прецизионными аналоговыми устройствами только на базе яд-
ра 8052. Сравнительно недавно (с 2004 г) Analog Devices начала выпуск мик-
роконтроллеров ADUC7xxx на базе ядра ARM7.
В данном учебном пособии рассматривается модификация
ARM7TDMI, отличающаяся поддержкой 16-разрядного режима Thumb,
наличием встроенного умножителя и поддержкой внутрисхемной отладки
через интерфейс JTAG. Перечислим основные характеристики ядра
ARM7TDMI:
а) 32-разрядный RISC процессор;
б) фон-неймановская архитектура; единое адресное пространство для
памяти программ и данных объемом 4 Гбайта;
в) 16 регистров общего назначения (в основном режиме);
г) обработка исключительных ситуаций;
д) устройство циклического сдвига и умножитель;
е) система команд, включающая 44 инструкции;
ж) поддержка 11 методов адресации;
е) 16-разрядный режим, позволяющий сократить объем программы.
Могут быть названы следующие основания для выбора микро-
контроллеров с архитектурой ARM7.
а) Открытая архитектура становится общепринятым стандартом.
Имеются исчерпывающие описания, в том числе на русском языке.
б) Поддержка ядра многими ведущими производителями гарантирует
широкую номенклатуру микроконтроллеров, облегчая выбор микросхемы,
удовлетворяющей заданным техническим требованиям.
в) Совместимость средств разработки и отладки со всеми микро-
контроллерами семейств ARM (в том числе Cortex) дает свободу выбора как
самих средств отладки, так и микроконтроллеров. Наиболее известны среды
8
разработки с интегрированным Си-компилятором: µVision фирмы Keil и Em-
bedded Workbench фирмы IAR. Внутрисхемная отладка обеспечивается таки-
ми средствами, как U-Link2 (фирмы Keil), J-Link (фирмы Segger), а также их
многочисленными дешевые аналогами.
В дальнейшем будем рассматривать микроконтроллер LPC2148 фир-
мы NXP (старший из серии LPC214x), который можно назвать типичным
представителем семейства ARM7. Приведем основные параметры и перечис-
лим наиболее важные встроенные аппаратные средства этой микросхемы.
а) Максимальная тактовая частота 60 МГц.
б) ПЗУ (FLASH-память) объемом 512 кбайт.
в) ОЗУ объемом 40 кбайт.
г) Два 32-разрядных таймера-счетчика, модуль ШИМ с отдельным
таймером, сторожевой таймер, часы реального времени с автономным пита-
нием и тактированием.
д) Два десятиразрядных АЦП с временем преобразования 2,44 мкс.
е) Десятиразрядный ЦАП с временем установления 1 мкс.
ж) Приемопередатчики интерфейсов: два UART, два I2C, SPI, SSP,
USB 2.0 в режиме Full Speed (12 МГц) с прямым доступом к памяти.
и) Гибкая система управления энергопотреблением.
Следующие разделы первой части настоящего учебного пособия по-
священы описанию архитектуры ARM7TDMI и аппаратных узлов микро-
контроллера LPC2148.

1.2 Программистская модель процессорного ядра ARM7TDMI


Составляя программу, программист в основном абстрагируется от
устройства аппаратных средств микропроцессора и имеет дело лишь с реги-
страми общего назначения, регистрами специальных функций и набором
ячеек памяти. Эти ресурсы будем называть программистской моделью мик-
ропроцессора или микроконтроллера. Схема программистской модели и ор-
ганизации памяти приведена на рисунке 1.2.1.
1.2.1 Режимы работы ядра ARM7
Процессорное ядро ARM7 имеет шесть режимов работы. От выбран-
ного режима зависит доступный набор регистров общего назначения. Смена
режима может происходить аппаратно или выполняться программно путем
записи кода в регистр состояния программы СPSR (раздел 1.2.2) командой
MSR. Ниже перечислены все режимы и даны краткие пояснения по поводу
назначения каждого из них (см. также раздел 1.6).
а) Режимы User и System предназначены для выполнения программы
пользователя или операционной системы; это основной режим работы ядра.
б) Supervisor — режим программного прерывания. Приход в этот ре-
жим происходит при сбросе, выполнении инструкции SWI или переполнении
счетчика команды.
в) Переход в режим Abort происходит при обращении к недопусти-
мому адресу памяти (исключительные ситуации PAbort и DAbort).

9
г) Переход в режим Undefined производится в случае попытки вы-
полнения неопределенной команды (исключительная ситуация Undefined).
д) IRQ — режим прерывания, классифицированного как IRQ.
е) FIQ — режим прерывания, классифицированного как FIQ (быстрое
прерывание).
Все режимы кроме User называются привилегированными. В этих ре-
жимах доступны некоторые функции управления ядром, которые не доступ-
ны в режиме User.
1.2.2 Система регистров
Арифметико-логическое устройство МК взаимодействует с 16 реги-
страми общего назначения, обозначаемыми R0–R15 (рисунок 1.2.1). Реги-
стры R0–R12 доступны для размещения данных. Регистр R13 (SP) служит
указателем стека; в нем хранится адрес вершины стека, организованного в
памяти данных. R14 (LR) — регистр связи, предназначенный для хранения
адреса возврата при вызове прерываний и подпрограмм. R15 (PC) — счетчик
команд, содержащий адрес следующей команды.
В каждом привилегированном (то есть кроме User/System) режиме
имеется своя пара регистров R13, R14. На схеме (рисунок 1.2.1) они обозна-
чены R13_xxx, R14_xxx, где xxx — идентификатор режима. При смене ре-
жима используются эти копии, а оригинальное содержимое R13, R14 основ-
ного режима User/System сохраняется неизменным. Это необходимо для пол-
ного восстановления состояния ядра при возврате в режим User/System.
Вполне очевидно, что счетчик команд R15 не должен ни сохраняться, ни вос-
станавливаться при смене режима, поэтому он не имеет копий. Для режима
быстрого прерывания FIQ предусмотрен второй набор регистров R8–R12.
Эти «дублеры» R8–R12 можно использовать в процедуре обработки быстро-
го прерывания, не затрачивая времени на сохранение в стек оригинальных
регистров режима User/System и на последующее их восстановление.
Регистр состояния программы CPSR содержит флаги результатов
арифметических операций и биты управления режимом ядра (раздел 1.2.3).
Изменение регистра CPSR программным путем возможно только в привиле-
гированных режимах. Для сохранения слова состояния программы имеются
регистры SPSR_xxx, где xxx — идентификатор режима.
1.2.3 Слово состояния программы
Схема флагов и управляющих битов слова состояния программы
CPSR показана на рисунке 1.2.1 (внизу).
Флаги результата арифметических операций, устанавливаются авто-
матически при обработке данных в АЛУ инструкциями, вызванными с моди-
фикатором {S} (раздел 1.4 и таблица 1.4.2). В таблице 1.2.1 даны примеры
влияния на флаги операции сложения. Рассмотрим назначение флагов слова
состояния программы CPSR.
● Бит 31 (N) — флаг устанавливается в единицу, если результат вы-
числений в АЛУ отрицательный, то есть если старший (31-ый) разряд ре-
зультата равен единице.
10
User/System FIQ Supervisor Abort IRQ Undefined 0xFFFFFFFF
Режимы: Выполнение Быстрое Программное Ошибка Прерывание Неопределен- Устройства AHB
0xF0000000
программы прерывание прерывание адреса ная команда 0xEFFFFFFF
R0 R0 Устройства VPB
R0 R0 R0 R0 0xE0000000
R1 R1 R1 R1 R1 R1
R2 R2 R2 R2 R2 R2 Загрузчик 0x7FFFFFFF

R3 R3 R3 R3 R3 R3 12 кбайт 0x7FFFD000
R4 R4 R4 R4 R4 R4
R5 R5 R5 R5 R5 R5 Буфер USB 0x7FD01FFF
Регистры
общего R6 R6 R6 R6 R6 R6 8 кбайт 0x7FD00000
назначения R7 R7 R7 R7 R7 R7
0x40007FFF
R8 R8_fiq R8 R8 R8 R8 Память данных
R9 R9_fiq R9 R9 R9 R9 ОЗУ
32 кбайта 0x40000000
R10 R10_fiq R10 R10 R10 R10
Порты 0x3FFFFFFF
R11 R11_fiq R11 R11 R11 R11
ввода-вывода 0x3FFF8000
R12 R12_fiq R12 R12 R12 R12
Указатель стека R13 (SP) R13_fiq R13_svc R13_abt R13_irq R13_und
0x0007FFFF
Адрес возврата R14 (LR) R14_fiq R14_svc R14_abt R14_irq R14_und Память программ
Счетчик команд R15 (PC) R15 R15 R15 R15 R15 Flash-ПЗУ
512 кбайт 0x00000040
Регистр состояния CPSR CPSR CPSR CPSR CPSR CPSR 0x0000003F
Резерв

(на примере микроконтроллера LPC2148)


Регистры сохраненного состояния SPSR_fiq SPSR_svc SPSR_abt SPSR_irq SPSR_und 0x00000020
Fast Int. Request 0x0000001C
Int. Request 0x00000018
31 30 29 28 27 8 7 6 5 4 3 0
Checksum 0x00000014
CPSR N Z C V I F T MODE Data Abort 0x00000010
Prefetch Abort 0x0000000C
Переполнение Разрешить прерывания IRQ Sowftware Int. 0x00000008
Thumb Режим
векторов прерываний
Отображаемая область

Перенос Разрешить прерывания FIQ

Рисунок 1.2.1 – Программистская модель и организация памяти ядра ARM7


Отрицатель- Undefined 0x00000004
ный результат Нулевой результат Reset 0x00000000

11
Таблица 1.2.1 – Примеры влияния операции сложения на флаги результата
Операция Результат C V N Z
1 0 0 0
0 1 0 0
0 0 1 0
1 1 0 0
1 0 0 1
0 1 1 0
1 0 1 0
● Бит 30 (Z) — флаг устанавливается в единицу, если результат вы-
числений в АЛУ равен нулю.
● Бит 29 (С) — флаг переноса, инверсный влаг заема. При сложении
беззнаковых чисел флаг устанавливается в единицу, если произошел перенос
из 31-го разряда, то есть если результат вычислений в АЛУ больше .
При вычитании беззнаковых чисел флаг сбрасывается в ноль, если произо-
шел заем из несуществующего 32-го разряда, то есть если результат вычис-
лений в АЛУ меньше нуля.
● Бит 28 (V) — флаг арифметического переполнения. При сложении и
вычитании чисел со знаком флаг устанавливается в единицу, если результат
вычислений в АЛУ больше или меньше . Такой результат приво-
дит к потере знака. Иными словами, флаг устанавливается в единицу, если
знаковый (31-ый) разряд обоих операндов одинаков и отличается от знаково-
го разряда результата.
● Бит 7 (I) — бит запрета прерываний IRQ. Устанавливается аппарат-
но в единицу в исключительных ситуациях Reset, SWI, IRQ, FIQ. Равенство
единице запрещает прерывания IRQ при сбросе и в одноименных режимах.
● Бит 6 (F) — бит запрета прерываний FIQ. Устанавливается в едини-
цу аппаратно в исключительных ситуациях Reset, FIQ. Равенство единицы
запрещает прерывания FIQ при сбросе и в режиме FIQ.
● Бит 5 (T) — бит перевода ядра в 16-разрядный режим Thumb ( ).
В режиме Thumb меняется программистская модель и система команд мик-
роконтроллера. Производительность в режиме Thumb снижается, но благода-
ря коротким 16-разрядным командам сокращается расход памяти программ.
Режим Thumb в настоящем учебном пособии не рассматривается.
Таблица 1.2.2 – Управление режимом работы ядра через регистр CPSR
Режим Mode (двоичные и шестнадцатеричные значения)
User 10000 (0x10)
FIQ 10001 (0x11)
Привилегир.

Исключ.

IRQ 10010 (0x12)


Supervisor 10011 (0x13)
Abort 10111 (0x17)
Undefined 11011 (0x1B)
System 11111 (0x1F)

12
● Биты 0–4 (Mode) — код управления режимом работы микро-
контроллера (раздел 1.2.1) в соответствии с таблицей 1.2.2.
1.2.4 Организация памяти
В состав системы памяти входит память программ, память данных и
массив управляющих регистров.
Ядро ARM7 основано на фон-неймановской архитектуре. Это значит,
что одна и та же шина используется для передачи команд и данных. Имеется
единое адресное пространство для памяти программ, данных и управляющих
регистров; обращение к этим областям памяти выполняется одними и теми
же командами (в основном LDR и STR). Шина адреса имеет разрядность
32 бита, соответственно объем адресного пространства составляет 4 Гбайта.
Единое адресное пространство и возможность размещения частей
программы в памяти данных делают неточными термины «память программ»
и «память данных». Поэтому далее будем чаще называть их ПЗУ и ОЗУ.
Схема распределения памяти показана на рисунке 1.2.1. На схеме вы-
делены области памяти данных, памяти программ, а также области портов
ввода-вывода и устройств AHB и APB.
Память программ предназначена для постоянного хранения про-
граммы и используемых ей констант. Память программ представляет собой
электрически перепрограммируемое ПЗУ (FLASH) объемом 512 кбайт. К
этой области относятся адреса 0x00000000–0x3FFF7FFF и 0x7FFFD000–
0x7FFFFFFF (загрузчик).
Адреса 0x00000000–0x0000003F в начальной области памяти (отделе-
ны пунктирной линией) принадлежат векторам исключительных ситуаций и
прерываний. В LPC2148 из них используются первые восемь 32-разрядных
ячеек с адресами 0x00000000–0x0000001С. При возникновении исключи-
тельной ситуации или прерывания управление передается команде, располо-
женной по одному из этих адресов. Подробнее вопросы обработки исключе-
ний рассматриваются в разделах 1.6 и 1.11. Здесь коснемся лишь ячейки с ад-
ресом 0x00000014 (Checksum). Ячейка предназначена для хранения
32-разрядной контрольной суммы остальных семи ячеек. Контрольная сумма
используется процедурой начальной загрузки (раздел 1.5).
Основное назначение памяти данных — хранение переменных, со-
здаваемых программой. Встроенная память данных является статическим
ОЗУ объемом 40 кбайт, из которых 8 кбайт служат буфером для приемопере-
датчика USB, хотя могут использоваться и для общих целей. ОЗУ занимает
адреса выше 0x40000000.
Управляющие регистры предназначенных для взаимодействия ядра
с периферийными устройствами микроконтроллера и системой прерываний.
Обмен данными с управляющими регистрами осуществляется через две
внутренние шины: шину высокого быстродействия (AHB — Advanced High-
performance Bus) и шину периферийных устройств (APB — ARM Peripheral
Bus). Через шину AHB ведется управление системой прерываний; остальные
регистры подключены к шине APB. Управляющим регистрам отведены адре-

13
са выше 0xE0000000. Отдельная область памяти 0x3FFF8000–0x3FFFFFFF
предназначена для регистров управления портами в быстром режиме.
Организация памяти в ARM7 байтовая. Это значит, что каждый адрес
указывает на ячейку размером 1 байт. В то же время хранимые в памяти дан-
ные выравниваются соответственно их разрядности. Поэтому при обращении
к 16-разрядному слову адрес должен быть четным; для 32-разрядного слова
адрес должен быть кратным четырем (закачиваться на шестнадцатеричные
цифры 0, 4, 8, С). Обращение в байтовом режиме возможно к любому адресу.
Данные, занимающие более одного байта, хранятся с обратным по-
рядком байт. Младший байт размещается по адресу с меньшим номером;
старший байт — по адресу с большим номером.

1.3 Система команд


Cведения системе команд и методах адресации (раздел 1.4) необходи-
мы программисту в ходе отладки, так как время от времени приходится при-
бегать к чтению дизассемблированной программы. Основы программирова-
ния на ассемблере рассмотрены в разделе 2.5. Там же читатель найдет при-
мер простой программы.
Система команд ядра ARM7 включает всего 44 инструкции (не считая
NOP). Отличительная особенность в том, что все инструкции являются услов-
ными. Каждая команда может быть выполнена или пропущена в зависимости
от флагов состояния программы. Для этого в коде команды предусмотрено
поле условия. На языке ассемблера условие обозначается двумя буквами
непосредственно после мнемоники команды (сливается с командой в одно
слово). Допустимые условия приведены в таблице 1.3.1.
Таблица 1.3.1 – Обозначения условных полей
Обознач. Условие Описание
EQ Равенство. Флаг нуля установлен
NE Неравенство. Флаг нуля сброшен
CS/HS Больше или равно (без знака). Перенос
CC/LO Меньше (без знака). Флаг переноса сброшен
MI Отрицательный результат
PL Положительный или нулевой результат
VS Флаг переполнения установлен
VС Флаг переполнения сброшен
HI Больше (без знака)
LS Меньше или равно (без знака)
GE Больше или равно (со знаком)
LT Меньше (со знаком)
GT Больше (со знаком)
LE Меньше или равно (со знаком)
AL Всегда (безусловное выполнение)
NV Никогда

14
Перечень команд, сгруппированных по выполняемым функциям, при-
веден в таблице 1.3.2 (см. также о псевдокомандах в разделе 2.5). Кратко рас-
смотрим каждую из групп.
1.3.1 Команды арифметической и логической обработки
Команды этой группы предназначены для выполнения арифметиче-
ских действий (сложение, вычитание) с целыми числами, а также логических
операций (конъюнкция, дизъюнкция, исключающее «ИЛИ»). Команды явля-
ются трехадресными и все имеют общий синтаксис:
Операция{Усл}{S} , ,
При этом Операция, определяемая мнемоническим обозначением, выполня-
ется над операндами и . Результат операции помещается в .
Здесь , любые регистры общего назначения (R0–R15). ,
занимающий 12 разрядов в коде команды, может быть адресован непосред-
ственным или регистровым методом (раздел 1.4.1 и таблица 1.4.1).
Операнд может отсутствовать или совпадать с . Эти случаи ин-
терпретируются одинаково — служит и первым операндом, и приемником.
Имеется необязательный модификатор «S», который указывает на
необходимость обновления флагов состояния программы. Без этого модифи-
катора обновление не происходит. Независимо от результата выполнения
команды флаги результат остаются неизменными.
Примеры:
ADD R0, R1, R2 ; R0 = R1 + R2
AND R0, R1, #0x80 ; R0 = R1 & 0x80
ADD R0, R1 ; R0 += R1
ADDEQ R0, R1, R2 ; if (Z) R0 = R1 + R2
1.3.2 Команды умножения
Команды выполняют умножение 32-разрядных целых чисел. Операн-
дами и приемником результата могут служат регистры общего назначения.
Имеются команды для умножения с накоплением. Результат может
быть 32- или 64-разрадным. Команды с 32-разрядным результатом отбрасы-
вают старшую часть. 64-разрядный результат размещается в паре регистров
общего назначения.
Примеры:
MUL R0, R1, R2 ; R0 = (long)(R1 * R2)
MLA R0, R1, R2, R3 ; R0 = (long)(R1 * R2 + R3)
Влияние команд на флаги состояния включается модификатором «S».
1.3.3 Команды регистровой пересылки
Команды пересылки предназначены для загрузки регистра короткой
константой или для копирования содержимого одного регистра в другой.
Команды двухадресные; второй операнд может быть задан непосредственно
(константа) или адресован регистровым способом. При копировании воз-
можна инверсия (команда MVN) или сдвиг.

15
Таблица 1.3.2 – Система команд процессорного ядра ARM7
Мнемоническое обозначение Операция Краткое описание
Команды арифметической обработки
ADD{Усл}{S} , , Арифметическое сложение
ADC{Усл}{S} , , Арифметическое сложение с переносом
SUB{Усл}{S} , , Вычитание
SBC{Усл}{S} , , Вычитание с учетом заема
RSB{Усл}{S} , , Обратное вычитание
RSС{Усл}{S} , , Обратное вычитание с учетом заема
Команды логической обработки
AND{Усл}{S} , , Логическое умножение (И)
ORR{Усл}{S} , , Логическое сложение (ИЛИ)
EOR{Усл}{S} , , Исключающее ИЛИ (сложение по модулю 2)
BIC{Усл}{S} , , Сброс битов в ноль
Команды регистровой пересылки
MOV{Усл}{S} , Копирование регистра или загрузка константы
Копирование регистра или загрузка константы
MVN{Усл}{S} ,
с инверсией
Команды сравнения и тестирования
CMN{Усл} , Сравнение с отрицательным числом
CMP{Усл} , Сравнение с положительным числом
TEQ{Усл} , Проверка равенства
TST{Усл} , Тестирование
Команды умножения c 32-разрядным результатом
MUL{Усл}{S} , , Умножение (с учетом знаков)
MLA{Усл}{S} , , , Умножение с накоплением (с учетом знаков)

16
Таблица 1.3.2 – Продолжение
Мнемоническое обозначение Операция Краткое описание
Команды умножения с 64-разрядным результатом
SMULL{Усл}{S} , , , Умножение учетом знака
SMLAL{Усл}{S} , , , Умножение с накопл. (с учетом знака)
UMULL{Усл}{S} , , , Умножение положительных чисел
UMLAL{Усл}{S} , , , Умножение полож. чисел с накоплением
Команды загрузки регистров из памяти
LDR{Усл} , Загрузка регистра
LDR{Усл}B , ; Загрузка регистра байтом
Загрузка регистра байтом
LDR{Усл}BT , ;
c эмуляцией режима User
LDR{Усл}H , ; Загрузка регистра двухбайтным словом
; Загрузка регистра байтом
LDR{Усл}SB ,
c дополнением знака
Загрузка регистра двухбайтовым словом
LDR{Усл}SH ,
c дополнением знака
Загрузка регистра
LDR{Усл}T ,
c эмуляцией режима User
Команды сохранения регистров в память
STR{Усл} , Сохранение регистра в память
STR{Усл}B , Сохранение в память мл. байта регистра
Сохранение в память младшего байта
STR{Усл}BT ,
регистра с эмуляцией режима User
STR{Усл}H , Сохранение в память мл. слова регистра
Сохранение регистра в память с эмуля-
STR{Усл}T ,
цией режима User
17
Таблица 1.3.2 – Продолжение
Мнемоническое обозначение Операция Краткое описание
Команды перестановки регистров и ячеек памяти
SWP{Усл} , ,[ ] ; Обмен между регистрами и памятью
SWP{Усл}B , ,[ ] Обмен байтов между регистрами и памятью
Команды пакетной пересылки
LDM{Усл}IA {!},
Загрузить блок памяти Методы адресации:
LDM{Усл}IB {!},
с базовым адресом равным IA (FD) — постинкрементный;
LDM{Усл}DA {!},
в список Регистров IB (ED) — преинкрементный;
LDM{Усл}DB {!},
DA (FA) — постдекрементный;
STM{Усл}IA {!},
Сохранить список Регистров DB (EA) — предекрементный.
STM{Усл}IB {!},
в блок памяти, Список регистров задается в фигурных скобах через
STM{Усл}DA {!}, запятую или тире, например, {R0–R3, R5}
начиная с адреса в
STM{Усл}DB {!},
Команды передачи управления
B{Усл} Передача управления по непосредственному адресу
BL{Усл} ; Передача управления с сохранением адреса возврата
Передача управления по адресу в регистре
BX{Усл}
со сменой режима ARM/Thumb
SWI{Усл} Вызов прерывания Software Interrupt; перевод процессора в режим ARM Supervisor
Команды обращения к слову состояния программы
MRS{Усл}{S} , CPSR
Сохранение или в регистр
MRS{Усл}{S} , SPSR
MSR{Усл} CPSR_Поля, #
MSR{Усл} SPSR_Поля, # Запись константы или регистра в разряды флагов в или .
MSR{Усл} CPSR_Поля, Поля задают копируемые байты: c — 0, x — 1, s — 2, f — 3
MSR{Усл} SPSR_Поля,
18
Ограниченная разрядность поля операнда не позволяет загружать
произвольную 32-разрядную константу. Непосредственно в коде команды
могут размещаться только 8-разрядные константы с 4-разрядным смещением
(раздел 1.4.1). Для загрузки 32-разрядных констант используются команды
обмена с памятью. Влияние команд пересылки на флаги состояния разреша-
ется или запрещается модификатором «S». Формат команд:
MOV{Усл}{S} ,
MVN{Усл}{S} ,
Операнд12 копируется в регистр-приемник (R0–R15).
Примеры:
MOV R0, #0x80 ; R0 = 0x80
MVN R0, R1, LSR #2 ; R0 = ~(R1 << 2)
Для загрузки «полноценных» 32-разрядных констант служит псевдо-
команда
LDR{Усл} ,=
При этом константа размещается в отдельной ячейке памяти программ, адрес
которой задается 12-разрядным кодом, обычно в виде смещения по отноше-
нию к счетчику команд.
1.3.4 Команды загрузки и сохранения регистров
Эти команды предназначены для загрузки в регистры общего назна-
чения содержимого ячеек памяти и сохранения в память содержимого реги-
стров. Команды двухадресные, имею общий формат
Команда{Усл} , /
Поддерживается косвенная или индексная адресация (раздел 1.4.2). Имеется
несколько модификаций команд этой группы (таблица 1.3.2) для пересылки
байтов и двухбайтных слов. Как указывалось выше, при передаче 16-
разрядного слова адрес обязательно должен быть четным, а при передаче 32-
разрядного слова — кратным четырем. На флаги состояния программы ко-
манды эти команды не влияют.
Примеры:
STR R1, [R2] ; *R2 = R1
LDR R1, [PC, #0x58] ; R1 = *(PC + 0x58)
К этой же группе относится команды SWP одновременно загружаю-
щую и сохраняющую регистры. С помощью SWP можно «перестановить ме-
стами» содержимое регистра и ячейки памяти.
1.3.5 Команды пакетного обмена с памятью
Основное назначение таких команд — сохранение регистров в стек и
последующем их восстановлении. В адресной части команды указывается ре-
гистр, содержащий базовый адрес блока памяти, перечень регистров общего
назначения, содержимое которых требуется сохранить в блок памяти или за-
грузить этим блоком, а также метод адресации. Поддерживается автоинкре-
ментный и автодекрементный виды адресации.

19
Пример:
STMDB SP!, {R1-R2} ; *(SP-=4) = R1; *(SP-=4) = R2
LDMIA SP!, {R3} ; *SP = R3; SP += 4
1.3.6 Команды передачи управления
Команды служат для безусловных и условных переходов (ветвлений)
и вызова подпрограмм. Поскольку все команды ARM7 являются условными,
достаточно всего трех команд B (перехода по непосредственному адресу) BL
(переход с сохранением адреса возврата в LR) и BX (переход по адресу в ре-
гистре).
Адрес перехода, заданный непосредственно, кодируется как 24-
разрядное смещение (включая знак), которое умножается на 4 и прибавляется
к текущему значению счетчика команд. Фактически реализуется операция

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


адрес, который при ассемблировании заменяется относительным.
Примеры:
BNE 0x380 ; if (Z == 0) PC = 0x380
BL 0x380 ; LR = PC + 4; PC = 0x380
1.3.7 Команды обращения к слову состояния программы
Команды этой группы предназначены для загрузки и сохранения сло-
ва состояния программы CPSR и его копии SPSP для текущего режима ядра.
Возможно загрузка 8-разрядной константой с 4-разрядным смещением ( )
или содержимым регистра общего назначения ( ). Копирование выполня-
ется с наложением маски. Примеры:
MRS CPSR, R0 ; R0 = CPSR
MSR CPSR_c, #0x10 ; Загрузить 0x10 в младший байт
MSR SPSR_cxsf, R0 ; SPSR = R0
Сюда же отнесем команду вызова программного прерывания SWI. Эта
команда переводит ядро в режим Supervisor и в режим ARM (если ядро нахо-
дилось в 16-разрядном режиме Thumb), после чего передает управление по
вектору программного прерывания.

1.4 Методы адресации


Адрес ячейки памяти или регистра общего назначения, к которым
производится фактическое обращение, называется исполнительным адресом.
Методом адресации называется способ формирования исполнительного ад-
реса. Методы адресации различаются в зависимости от того, где расположе-
ны операнды и каким образом их расположение задано в коде операции.
Ядро ARM7 поддерживает все наиболее распространенные в микро-
процессорной технике методы адресации кроме прямой. Прямая адресация,
предполагающая хранение адреса операнда в коде операции, не может быть
реализована. Длина всех команд ARM7 одинакова и составляет 32 бита. По-

20
этому длинные 32-разрядные адресе не могут размещаться в коде операции.
Ниже рассмотрены поддерживаемые методы адресации.
Важный материал далее представлен в форме таблиц (1.4.1–1.4.3). В
таблицах использованы следующие обозначения: текст, набранный шрифтом
Consolas, не допускает изменения, так как является мнемоническим обозна-
чением или элементами синтаксиса. Текст, оформленный наклонным шриф-
том Times, представляет собой операнды. Вместо него подставляются кон-
станты, адреса или имена регистров, содержащих обрабатываемые данные.
Элементы в фигурных скобках «{ }» не обязательны и могут быть опущены.
1.4.1 Непосредственная адресация
Непосредственная адресация наряду с регистровой применяется в ко-
мандах арифметической и логической обработки. Непосредственная адреса-
ция наиболее проста. Операндом является числовая константа располо-
женная непосредственно в коде операции.
Пример (третий операнд адресован непосредственно):
SUB R2, R0, #0x80000001 ; R2 = R0 - 0x80000001
Разрядность поля операнда ограничена 12 битами. Это поле состоит
из двух частей: восьмиразрядной , и четырехразрядной . Операнд фор-
мируется путем циклического сдвига вправо константы на разряда.
Допустимыми являются только числа, которые могут быть представлены та-
ким способом. Характерный пример — число 0x80000001 (шестнадцатерич-
ное), которое получается путем сдвига числа 6 (двоичная запись ) на два
разряда вправо. В то же время число , для записи которого в обычном
прямом двоичном коде требуется всего девять разрядов, недопустимо, так
как все эти разряды содержат единицы. Определить множество допустимых
чисел с помощью удобной математической формулы вряд ли возможно.
1.4.2 Регистровая адресация
Регистровая адресация (короткая прямая) — вторая разновидность ад-
ресации в арифметико-логических командах. При регистровой адресации
операнд расположен в одном из регистров .
Пример (все три операнда адресованы регистровым способом):
ORR R3, R3, R2 ; R3 = R3 | R2
Здесь примеры сопровождаются комментариями (через «;»), поясняющими
выполняемые командой действия. При этом использован синтаксис языка Си.
В коде команды номер регистра обозначается коротким 4-разрядным
полем. Это позволяет включить три адресных поля в сравнительно длинные
32-разрядные команды ARM7.
Кроме базового варианта поддерживается несколько видов сдвига ре-
гистрового операнда. Способ сдвига обозначается специальным ключевым
словом. Число разрядов сдвига обозначается непосредственно константой
или хранится в регистре общего назначения. Примеры:
ADD R0, R0, R1, LSR #4 ; R0 = R0 + R1 >> 4
ADD R0, R0, R1, LSR R2 ; R0 = R0 + R1 >> R2

21
Сдвиг применим только к последнему третьему операнду (в примере
это регистр R1). В таблице 1.4.1 приведены допустимые варианты регистро-
вой адресации со сдвигом.
Таблица 1.4.1 – Непосредств. и регистровая адресация (операнд типа )
Метод адресации Сдвиг операнда
Непосредственная # —
Регистровая —
, LSL # Логический влево на разрядов
Регистровая с , LSR # Логический вправо на разряд
непосредственным , ASL # Арифм. вправо на разряд
сдвигом , ROR # Циклич. вправо на разряд
, RRX Цикл. вправо через перенос на 1 разр.
, LSL Логический влево на разрядов
Регистровая с
, LSR Логический вправо на разрядов
регистровым
, ASL Арифм. вправо на разрядов
сдвигом
, ROR Циклический вправо на разрядов
1.4.3 Косвенная адресация
Косвенная адресация применяется только в командах обмена с памя-
тью. Предполагается, что 32-разрядный исполнительный адрес хранится в
одном из регистров общего назначения, в то время как в коде операции хра-
нится лишь короткая 4-разрядная ссылка на этот регистр, играющий роль
указателя. Пример:
LDR R0, [R1] ; R0 = *R1
Разумеется, регистр-указатель должен быть предварительно загружен нуж-
ным адресом.
1.4.4 Индексная адресация
Индексная адресация является развитием косвенной и так же как кос-
венная применяется в командах сохранения, загрузки и обмена с памятью.
При индексной адресации исполнительный адрес вычисляется как сумма или
разность базового адреса и смещения. Базовый адрес хранится в регистре
общего назначения ( ). Смещение может быть задано непо-
средственно числовой константой или тоже храниться в одном из регистров
общего назначения.
После выполнения операции исполнительный адрес может быть поте-
рян, либо сохранен. В последнем случае регистр, хранящий базовый адрес,
модифицируется, то есть увеличивается на величину смещения. Причем ба-
зовый адрес может модифицироваться на величину смещения до обращения
к памяти или после. По этому признаку различают преиндексную адресацию
и постиндексную.
Кроме того смещение, прибавляемое к базовому адресу или вычитае-
мое из него, может быть подвергнуто сдвигу. Поддерживается несколько ви-
дов сдвига (таблица 1.3.2).

22
Таблица 1.4.2 – Косвенная и индексная адресация (операнд типа )
Метод Исполн. Содержимое
Вид сдвига
адресации адрес после операции
Косвенная [ ] — — —
Непоср.
[ ], #± —
Постиндексная

смещ.
[ ], ± — —
Регистровое

со сдвигом
смещение

[ ], ± , LSL # Логический влево на разрядов


[ ], ± , LSR # Логический вправо на разрядов
[ ], ± , ASR # Арифметич. право на разрядов
[ ], ± , ROR # Циклический вправо на разрядов
Непоср.
[ , #± ]{!} —

модификатора {!}
Rn не меняется без
смещ.
Преиндексная

[ ,± ]{!} — —
Регистровое

Логический влево на разрядов


со сдвигом

[ ,± , LSL # ]{!}
смещение

[ ,± , LSR # ]{!} Логический вправо на разрядов


[ ,± , ASR # ]{!} Арифметич. вправо на разрядов
[ ,± , ROR # ]{!} Циклический вправо на разрядов
[ ,± , RRX]{!} — Цикл. вправо через перенос на 1 разр.
Таблица 1.4.3 – Косвенная и индексная адресация (операнд типа )
Метод адресации Исполн. адрес Содержимое после операции
Косвенная [ ] —
Постиндексная с непосредств. смещением [ ], #±
Постиндексная с регистровым смещением [ ], ±
Преиндексная с непосредств. смещением [ , #± ]{!} (с модификатором {!})
Преиндексная с регистровым смещением [ , #± ]{!} (с модификатором {!})
23
Преиндексная адресация с непосредственным смещением. Испол-
нительный адрес — сумма или разность содержимого регистра
и константы ( или ). В случае использовании модифи-
катора {!} вычисленный исполнительный адрес сохраняется в регистре
до обращения к памяти.
Примеры:
LDR R0, [R1, #32] ; R0 = *( R1 + 32 )
LDR R0, [R1, #32]! ; R0 = *( R1 += 32 )
Преиндексная адресация с регистровым смещением. Исполни-
тельный адрес — сумма или разность базового адреса в регистре
и смешения в регистре , которое может под-
вергаться сдвигу. В случае использования модификатора «!» вычисленный
исполнительный адрес сохраняется в регистре до обращения к памяти.
Примеры:
LDR R0, [R1, R2] ; R0 = *( R1 + R2 )
LDR R0, [R1, R2]! ; R0 = *( R1 += R2 )
LDR R0, [R1, –R2, LSL #4] ; R0 = *(R1 – (R2 << 4))
LDR R0, [R1, –R2, LSL #4]! ; R0 = *(R1 –= R2 << 4)
Постиндексная адресация с непосредственным смещением. Ис-
полнительный адрес хранится в регистре . После обращения
к памяти содержимое регистра изменяется путем прибавления или вычи-
тания 8- или 12-разрядной константы / .
LDR R0, [R1], #32 ; R0 = *R1; R1 + = 32
Постиндексная адресация с регистровым смещением. Исполни-
тельный адрес хранится в регистре . После обращения к па-
мяти содержимое регистра изменяется путем прибавления или вычитания
смещения , которое может подвергаться сдвигу.
LDR R0, [R1], #R2 ; R0 = *R1; R1 + = R2
LDR R0, [R1], #R2, LSR #2 ; R0 = *R1
; R1 + = ( R2 >> 2 )

1.5 Процедура начальной загрузки и режимы отображения памяти


Микроконтроллер LPC2148 имеет встроенную программу начальной
загрузки (загрузчик), которая размещается во встроенном ПЗУ. Запись кода
загрузчика производится при изготовлении микросхемы. Функции загрузчи-
ка: «прошивка» основной программы в ПЗУ через последовательный интер-
фейс, запуск основной программы, защита кода программы от несанкциони-
рованного считывания.
Размер области памяти, выделяемой загрузчику, составляет 12 кбайт.
Эта область расположена, начиная с адреса 0x7FFFD000 (рисунок 1.2.1).
Непосредственно после сброса область векторов прерываний (адреса
памяти 0x00000000–0x0000003F) отображается на начало области загрузчика
0x7FFFD000–0x7FFFD03F. Поэтому при сбросе управление передается на
физический адрес 0x7FFFD000, то есть запускается загрузчик.
24
Загрузчик проверяет контрольную сумму векторов прерываний. Вы-
числяется сумма содержимого первых восьми 32-разрядных ячеек памяти с
адресами 0x00000000–0x0000001C. Если сумма дает ноль (разряды старше
31-го отбрасываются), то контрольная сумма считается верной. Как правило,
для совпадения контрольной суммы в ячейку 0x00000014 следует записать
код 0xB9205F80. В общем случае для расчета этой величина программисту
необходимо сложить содержимое всех остальных семи ячеек памяти; выде-
лить младшие 32 разряда; поразрядно инвертировать и прибавить единицу.
Верная контрольная сумма служит признаком того, что память про-
грамм не пуста и содержит программу. В этом случае переотображение век-
торов прерываний прекращается, управление передается на команду по адре-
су 0x00000000, то есть первой команде основной программы.
При несовпадении контрольной суммы считается, что память не со-
держит программы. Загрузчик переходит в режим ожидания потока данных с
последовательного порта UART0 для загрузки кода программы.
Отметим, что имеется еще один режим отображения векторов преры-
ваний, в котором адресам 0x00000000–0x0000003F ставятся в соответствие
физические адреса оперативной памяти 0x40000000–0x4000003F.
При необходимости режим отображение памяти может быть изменен
программным путем с помощью регистра MEMMAP. Значения управляющих
кодов приведены в таблице 1.5.1.
Таблица 1.5.1 – Управление режимами отображения векторов прерываний
Физические адреса, на которые
MEMMAP Режим
отображаются вектора прерываний
0x00 0x7FFFD000–0x7FFFD03F Режим загрузчика
0x01 0x00000000–0x0000003F Режим программы
0x02 0x40000000–0x4000003F Режим ОЗУ

1.6 Обработка исключительных ситуаций


Исключительные ситуации или просто «исключения» — это события,
которые требуют немедленной реакции со стороны программы. Частным
случаем исключений являются прерывания, запрашиваемые периферийными
устройствами микроконтроллера. Другие исключения возникают в случае
ошибочных действий программы. Прерывания являются одним из основных
приемов программного управления вычислительным процессом. Обработка
исключений, вызванных ошибкой, направлена на повышение надежности
микропроцессорной системы.
Ядро ARM7 предоставляет возможность аппаратного диагностирова-
ния исключительных ситуаций. Возникновение исключения сопровождается
автоматическим переводом процессора из режима User в один из привилеги-
рованных режимов соответственно возникшему исключению (раздел 1.2.1).
Выполнение программы приостанавливается, и управление передается про-
цедуре обработки прерывания или исключения. Обработчик заканчивается

25
командой возврата в основную программу. При этом состояние программы
восстанавливается таким, каким оно было до возникновения исключения.
Исключения характеризуются разными приоритетами. Обработка ис-
ключения с меньшим приоритетом может быть приостановлена возникшим
исключением с более высоким приоритетом.
Исключительные ситуации, обработка которых предусмотрена аппа-
ратурой контроллера LPC2148, перечислены ниже (см. также раздел 2.4.1).
Reset — сброс. Исключение возникает в следующих случаях:
а) включение питания микроконтроллера или восстановление напря-
жения питания после провала до 1 В;
б) нарастающий перепад напряжения на контакте ;
в) сигнал сброса от сторожевого таймера;
г) сигнал от супервизора питания, свидетельствующий о снижении
напряжения до 2,6 В.
Undefined — неопределенная команда. Исключение возникает, если
на конвейер поступил код нераспознанной команды
Software interrupt (SWI) — программное прерывание. Вызывается
командой SWI.
Prefetch abort (PAbort) — ошибка адреса команды. Исключение возни-
кает при передаче управления по адресу памяти, не реализованному физически.
Data abort (DAbort) — ошибка адреса данных. Исключение возника-
ет при попытке обращения к ячейке памяти, не реализованной физически.
Interrupt request (IRQ) — прерывание. Поступил запрос прерывания,
разрешенного и классифицированного как zIRQ.
Fast interrupt request (FIQ) — быстрое прерывание. Поступил запрос
прерывания, разрешенного и классифицированного как FIQ.
В таблице 1.6.1 для каждого исключения указан приоритет, закреп-
ленный адрес памяти программ для передачи управления, режим, в который
будет переведен процессор на время обработки исключения, и инструкция,
завершающая обработку.
Общий порядок действий, выполняемых при возникновении исклю-
чения таков:
1. Cодержимое счетчика команд R15 (PC), указывающее на следую-
щую команду, сохраняется в регистр R14_xxx (LR), где xxx — идентификатор
Таблица 1.6.1 – Исключения, поддерживаемые ядром ARM7TDMI
Исключение Приор. Вектор I/F Режим Инструкция выхода
Reset 1 0x00000000 1/1 Supervisor —
Undefined 6 0x00000004 –/– Undefined MOVS PC, R14
SWI 6 0x00000008 1/– Supervisor MOVS PC, R14
PAbort 5 0x0000000C –/– Abort SUBS PC, R14, #4
SUBS PC, R14, #4
DAbort 2 0x00000010 –/– Abort
SUBS PC, R14, #8
IRQ 4 0x00000018 1/– IRQ SUBS PC, R14, #4
FIQ 3 0x0000001C 1/1 FIQ SUBS PC, R14, #4
26
режима, соответствующего возникшему исключению. Например, при воз-
никновении исключения Data Abort счетчик команд сохраняется в R14_abt.
Для Data Abort в R14_xxx помещается значение для остальных —
.
2. Содержимое слова состояния программы CPSR сохраняется в ре-
гистр SPSR_xxx режима, соответствующего исключению.
3. Изменяется режим работы процессора, а также устанавливаются
биты запрета прерываний (I и F) в слове состояния программы CPSR в соот-
ветствии с таблицей 1.6.1.
4. В счетчик команд R15 (PC) записывается адрес вектора исключения
в соответствии с таблицей 1.6.1, что приводит к немедленной передаче
управления команде, расположенной по этому адресу.
Общий порядок действий, производимых ядром ARM7 при возврате
из обработчика исключения:
1. Восстанавливается содержимое счетчика команд R15 (PC) путем
вычитания из R15_xxx смещения. Команды возврата приведены в таблице
1.6.1. Для Data Abort может использоваться возврат к команде, вызвавшей
исключение, а может к следующей ща ней команде (то есть с пропуском ко-
манды, приведшей к ошибке). Это достигается вычитанием смещения 8 или 4.
2. При выполнении команды возврата автоматически восстанавлива-
ется слово состояния программы CPSR из SPSR_xxx. При этом режим ядра
меняется на исходный, сбрасываются флаги запрета прерывания I и F, уста-
новленные в ходе обработки исключения.
Частный случай обработки прерываний IRQ и FIQ рассмотрен по-
дробней в разделе 1.11.2.

1.7 Система тактирования


1.7.1 Выбор тактовой частоты микроконтроллера
Основным источником тактирования микроконтроллера LPC2148 яв-
ляется встроенный тактовый генератор. Тактовая частота чаще всего задается
кварцевым резонаторам, подключенным к выводам XTAL1, XTAL2. Допу-
стимый диапазон частот резонатора МГц. Микроконтроллер
оснащен встроенным умножителем тактовой частота на основе ФАПЧ. До-
ступна сетка целочисленных множителей — . Частота ядра после
умножения не должна превышать 60 МГц.
В обратной связи системы ФАПЧ имеется управляемый током генера-
тор, работающий в диапазоне частот МГц. Эта частота за-
дается делителем, который может принимать значения .
На этапе настройки ФАПЧ тактового генератора выбирается множи-
тель , обеспечивающий требуемую тактовую частоту
МГц, (1.7.1)
а также делитель , так чтобы величина
(1.7.2)
принадлежала диапазону

27
(МГц). (1.7.3)
Например, при частоте кварцевого резонатора МГц значения
, дают МГц и МГц. Такие параметры си-
стемы тактирования можно рекомендовать разработчикам.
Имеется второй умножитель, предназначенный для тактирования при-
емопередатчика USB. Его настройка осуществляется аналогичным образом с
поправкой — выходная частота должна быть равна 48 МГц.
Значения и для ФАПЧ 0 и 1 задаются через регистры PLL0CON
и PLL1CON соответственно. Для выполнения настройки необходимо обра-
щаться еще к нескольким регистрам.
В учебном пособии настройка ФАПЧ через регистры специальных
функций не рассматривается. В большинстве случаев настройка системы так-
тирования выполняется однократно, ее не приходится выполнять повторно
во время выполнения программы. Поэтому предлагается воспользоваться ин-
струментом Configuration Wizard, среды Keil µVision 4. Инструмент автома-
тически генерирует необходимые команды настройки и внедряет их в файл
инициализации Startup.s, являющийся частью разрабатываемого проекта.
Значение выбирается в поле PLL Multiplier Selection, значение —
в поле PLL Divider Selection (рисунок 1.7.1).

Рисунок 1.7.1 – Настройка системы тактирования


с помощью инструмента Configuration Wizard
Заметим, что уменьшение тактовой частоты — одна из основных мер
по снижению энергопотребления микроконтроллера.
1.7.2 Настройка тактирования периферийных устройств
Внутренняя шина периферийных устройств APB (ARM Peripheral Bus)
работает при тактовой частоте , которая получается путем деления си-
стемной тактовой частоты
. (1.7.4)
Возможные значения делителя .

28
Особенно важно контролировать частоту при использовании
таймеров, поскольку именно этот сигнал поступает на их счетные входы.
Частота шины периферийных устройств APB, так же как и частота яд-
ра, связана с потребляемой микроконтроллером мощностью.
Делитель частоты периферийных устройств задается двумя младшими
разрядами регистра APBDIV (таблица 1.7.1).
Рассмотрим настройку делителя шины APB с помощью Configuration
Wizard (рисунок 1.7.1). По умолчанию флажок VPBDIV Setup снят и исполь-
зуется делитель 1:4. Установка флажка позволяет выбрать значение делителя
шины APB (опция VPBDIB: VPB Clock) согласно таблице 1.7.1.
Таблица 1.7.1 – Управление тактовой частотой шины APB
Двоичный код в регистре APBDIV Делителя частоты шины APB
00 (по умолчанию) 4 (по умолчанию)
01 2
10 1
11 зарезервировано

1.8 Модуль ускорения памяти


Быстродействие МК LPC2148, при тактовой частоте несколько десят-
ков мегагерц, ограничено временем доступа к Flash-памяти программ. Для
МК LPC2148 это время составляет 50 нс, что втрое превышает длительность
такта при частоте 60 МГц (16,67 нс). Для преодоления этого препятствия
служит модуль ускорения памяти (MAM — Memory Acceleration Module).
Модуль MAM представляет собой два буфера емкостью 16 байт. Каж-
дый буфер вмещает коды четырех команд. Логика управления обеспечивает
опережающую загрузку в буферы команд, которые предстоит выполнить в
следующих тактах. В то время как один буфер используется для чтения и ис-
полнения команд, во второй загружается очередной блок из Flash-памяти.
Это обеспечивает непрерывный поток команд без задержек.
Непрерывность нарушается при появлении команд передачи управле-
ния, как следствие появляются простои. Практически снижение производи-
тельности невелико (не превышает 5–10%).
Настройка модуля MAM осуществляется с помощью регистров спе-
циальных функций MAMCR и MAMTIM. Поскольку, как правило, настройка
выполняется однократно и в процессе выполнения программы не возникает
необходимость ее изменения, имеет смысл использовать инструмент Configu-
ration Wizard. Здесь ограничимся рассмотрением такого способа настройки.
Режим работы модуля MAM задается в поле MAM Control (рисунок
1.8.1). Модуль может быть полностью включен (опция Fully Enabled), вклю-
чен только для последовательно расположенных команд (Partially Enabled)
или полностью отключен (Disabled).
Эффективность работы модуля MAM зависит от числа тактов, выде-
ляемых для считывания команд из памяти (поле MAM Timing). Чем выше
тактовая частота, тем больше требуется тактов на обращение к памяти.
29
Рисунок 1.8.1 – Настройка модуля ускорения памяти (MAM)
с помощью инструмента Configuration Wizard
В техническом описании производителя утверждается, что длитель-
ность цикла обращения к памяти не должна быть меньше 50 нс. Соответ-
ственно при тактовых частотах до 20 МГц для обращения к памяти программ
рекомендуется выделять 1 такт; при тактовой частоте 20–40 МГц — 2 такта;
40–60 МГц — 3 такта. Однако авторы считают, что в большинстве случаев
следует выделять один такт при тактовых частотах до 40 МГц и два такта при
тактовых частотах 40 МГц и выше.
Можно рекомендовать подбирать настройку модуля MAM, опираясь
на экспериментально измеренное время выполнения фрагмента программы.
Для этого в начале и конце фрагмента следует включить отладочные коман-
ды, формирующие логический сигнал на одном из свободных выводов МК.
Для измерений необходим цифровой осциллограф.
В заключение отметим, что возможно выполнение фрагмента про-
граммы абсолютно без потерь производительности, если его разместить в
оперативной памяти (см. раздел 2.3.8).

1.9 Внешние выводы микроконтроллера


1.9.1 Служебные контакты
Микроконтроллер LPC2148 выпускается в корпусе LQFP размером
10×10 мм с 64 контактами (шаг 0,5 мм). Контакты микроконтроллера можно
разделить на две группы: служебного назначения, например, для подключе-
ния источника питания, и программно-управляемые линии ввода-вывода,
предназначенные для обмена цифровыми и аналоговыми сигналами с внеш-
ней средой. Краткое описание служебных контактов микроконтроллера
LPC214x приведено в таблице 1.9.1.
1.9.2 Программно-управляемые линии ввода-вывода
Контакты, не включенные в таблицу 1.9.1, предназначены для ввода и
вывода цифровых и аналоговых сигналов. Каждый из них может работать в
режиме двунаправленного цифрового входа-выхода. В связи с этим контакты
сгруппированы в два 32-разрядных параллельных порта, называемых

30
«порт 0» и «порт 1». В них не все разряды реализованы физически. Принято
порты обозначать «P0» и «P1», а номера линий порта указывать через точку,
например «P0.14» или «P1.23». Цифровые сигналы могут формироваться или
считываться с портов под управлением программы (раздел 1.10). Основные
электрические характеристики портовых линий приведены в таблице 1.9.2.
Таблица 1.9.1 – Назначение служебных контактов МК LPC2148
Обознач. Контакт Назначение
Vdd 23, 43, 51 Питание цифровой части (3,0–3,6 В)
Vdda 7 Питание аналоговой части (3,0–3,6 В)
Vss 6, 18, 25, 42, 50 Общая точка цифровой части
Vssa 59 Общая точка аналоговой части
Вход сброса. Низкий лог. уровень переводит
57 микроконтроллер в режим сброса. В рабочем
режиме должен быть подан высокий уровень
XTAL1 62 Контакты для подключения основного кварцево-
го резонатора. На контакт XTAL1 может быть
XTAL2 61 подан внешний тактовый сигнал
RTCX1 3 Контакты для подключения кварцевого резона-
RTCX2 5 тора для тактирования часов реального времени
D+ 10 Двунаправленная линия передачи данных ин-
D– 11 терфейса USB
Vref 63 Опорное напряжение АЦП и ЦАП (2,5–3,6 В)
Vbat 49 Питание часов реального времени (2,0–3,6 В)
Отметим, что реальные логические уровни, существенно отличаются
от предельных. Так в условиях, близких к нормальным, экспериментально
можно установить, что: В, В.
Таблица 1.9.2 – Электрические параметры цифровых портовых линий
Параметр Значение
Предельно допустимое напряжение в режиме входа, В
Выходной уровень логической единицы, В, не менее
Выходной уровень логического нуля, В, не более 0,4
Входной уровень логической единицы, В, не менее 2,0
Входной уровень логического нуля, В, не более 0,8
Ток в режиме входа, мкА, не более 3
Предельный выходной ток, мА 50
Предельный ток через каждый контакт Vdd и Vss, мА 100
1.9.3 Альтернативные функции линий ввода вывода
Портовые линии совмещают основную функцию (цифровой ввод-
вывод) с несколькими альтернативными функциями. Они служат входами
или выходами многочисленных периферийных устройств, встроенных в мик-
роконтроллер, таких как счетчики, АЦП и ЦАП.

31
PINSEL1 – настройка входов внешних прерыыаний
31 P0.30 27 24 23 20 19 16 15 12 11 P0.20 7 4 3 P0.16

0 1 1 1 0 1
EINT3 EINT3 EINT0

PINSEL0 – настройка входов внешних прерыыаний


P0.15 P0.14 27 24 23 20 P0.9 16 P0.7 12 11 8 P0.3 4 P0.1 0

1 0 1 0 1 1 1 1 1 1 1 1
EINT2 EINT1 EINT2 EINT2 EINT1 EINT0

PINSEL1 – настройка входов таймеров-счетчиков


31 P0.30 P0.29 P0.28 23 20 19 16 15 P0.22 P0.21 P0.20 P0.19 P0.18 P0.17 P0.16
1 0 1 0 1 0 0 1 0 1 0 1 1 0
1 1 1 1 1 1 1 1
1 1 0 1 1 1 1 1 1 1 1 1
CAP0.0 CAP0.3 CAP0.2 CAP0.0 CAP1.3 MAT1.3 MAT1.2 CAP1.3 CAP1.2 MAT0.2
MAT0.3 MAT0.2 MAT0.0 CAP1.2 MAT1.3 MAT1.2 CAP0.2
PINSEL0 – настройка входов таймеров-счетчиков
31 28 P0.13 P0.12 P0.11 P0.10 19 16 15 P0.6 P0.5 P0.4 P0.3 P0.2 3 0

1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
MAT1.1 MAT1.0 CAP1.1 CAP1.0 CAP0.2 MAT0.1 CAP0.1 MAT0.0 CAP0.0

PINSEL1 – настройка выходов ШИМ


31 28 27 24 23 20 19 16 15 12 P0.21 8 7 4 3 0

0 1
PWM5

PINSEL0 – настройка выходов ШИМ


31 28 27 24 23 20 P0.9 P0.8 P0.7 12 11 8 7 4 P0.1 P0.0

1 0 1 0 1 0 1 0 1 0
PWM6 PWM4 PWM2 PWM3 PWM1

Рисуноук1.9.1 – Схема регистров управления альтернативными функциями портов ввода-вывода

32
PINSEL1 – настройка входов АЦП
31 P0.30 P0.29 P0.28 23 20 P0.25 16 15 P0.22 P0.21 8 7 4 3 0

0 1 0 1 0 1 0 1 0 1 1 0
AD0.3 AD0.2 AD0.1 AD0.4 AD1.7 AD1.6

PINSEL0 – настройка входов АЦП


P0.15 28 P0.13 P0.12 23 P0.10 19 P0.8 15 P0.6 P0.5 P0.4 7 4 3 0

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
AD1.5 AD1.4 AD1.3 AD1.2 AD1.1 AD1.0 AD0.7 AD0.6

PINSEL1 – настройка линий SPI


31 28 27 24 23 20 19 16 15 12 11 P0.20 P0.19 P0.18 P0.17 0

1 0 1 0 1 0 1 0
SSEL1 MOSI1 MISO1 SCK1

PINSEL0 – настройка линий SPI


31 28 27 24 23 20 19 16 P0.7 P0.6 P0.5 P0.4 7 4 3 0

0 1 0 1 0 1 0 1
SSEL0 MOSI0 MISO0 SCK0

PINSEL0 – настройка линий UART


P0.15 P0.14 P0.13 P0.12 P0.11 P0.10 P0.9 P0.8 15 12 11 8 7 4 P0.1 P0.0

0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
RI DCD DTR DSR CTS RTS RxD1 TxD1 RxD0 TxD0

PINSEL0 – настройка линий I2С


31 P0.11 27 24 P0.11 20 19 16 15 12 11 8 P0.3 P0.2 3 0

1 1 1 1 0 1 0 1
SDA1 SCL1 SDA0 SCL0

Рисунок 1.9.2 – Схема регистров управления альтернативными функциями портов ввода-вывода

33
Выбор основной или альтернативной функции линий порта 0 осу-
ществляется путем записи управляющего кода в регистры PINSEL0 и PIN-
SEL1. Имеется также регистр PINSEL2, предназначенный для переключения
линий порта 1 в отладочный режим, который здесь не рассматривается.
Управляющие коды и соответствующие им альтернативные функции
портовых линий приведены в таблицах 1.9.3, 1.9.4. На рисунках 1.9.1 и 1.9.2
показаны схемы регистров PINSEL0 и PINSEL1, сгруппированы по перифе-
рийным устройствам.
Прежде чем использовать какое-либо встроенное периферийное
устройство, требующее взаимодействия с внешней средой, необходимо с по-
мощью таблиц 1.9.3, 1.9.4 или рисунков 1.9.1, 1.9.2 определить, какие кон-
такты МК могут использоваться для обмена сигналами с данным устрой-
ством и внедрить в программу команды перевода выбранных линий в аль-
тернативный режим.
Таблица 1.9.3 – Управление функциями внешних выводов через PINSEL0
Биты Конт. Код Функция Описание
0–1 19 00 Port 0.0
01 TxD0 (UART0) Выход передатчика UART0
10 PWM1 Выход 1 ШИМ
11 —
2–3 21 00 Port 0.1
01 RxD0 (UART0) Вход приемника UART0
10 PWM3 Выход 3 ШИМ
11 EINT0 Вход 0 внешнего прерывания
4–5 22 00 Port 0.2
01 SCL0 (I2C0) Тактовый сигнал I2C0
10 CAP0.0 (Timer 0) Вход 0 устр. захвата таймера 0
11 —
6–7 26 00 Port 0.3
01 SDA0 (I2C0) Линия передачи данных I2C0
10 MAT0.0 (Timer 0) Выход 0 устр. сравнения таймера 0
11 EINT1 Вход 1 внешнего прерывания
8–9 27 00 Port 0.4
01 SCK0 (SPI0) Тактовый сигнал SPI0
10 CAP0.1 (Timer 0) Выход 1 устр. сравнения таймера 0
11 AD0.6 Вход 6 АЦП 0
10–11 29 00 Port 0.5
01 MISO0 (SPI0) Вход ведущего, выход ведомого SPI0
10 MAT0.1 (Timer 0) Выход 1 устр. сравнения таймера 0
11 AD0.7 Вход 7 АЦП 0

34
Таблица 1.9.3 – Продолжение
Биты Конт. Код Функция Описание
12–13 30 00 Port 0.6
01 MOSI0 (SPI0) Выход ведущего, вход ведомого SPI0
10 CAP0.2 (Timer 0) Выход 2 устр. сравнения таймера 0
11 AD1.0 Вход 0 АЦП 1
14–15 31 00 Port 0.7
01 SSEL0 (SPI0) Выбор режима ведущий/ведомый SPI0
10 PWM2 Выход 2 ШИМ
11 EINT2 Вход 2 внешнего прерывания
16–17 33 00 Port 0.8
01 TxD1 (UART1) Выход передатчика UART1
10 PWM4 Выход 4 ШИМ
11 AD1.1 Вход 1 АЦП 1
18–19 34 00 Port 0.9
01 RxD1 (UART1) Вход приемника UART1
10 PWM6 Выход 6 ШИМ
11 EINT3 Вход 3 внешнего прерывания
20–21 35 00 Port 0.10
01 RTS (UART1) Выход запроса передачу (UART1)
10 CAP1.0 (Timer 1) Вход 0 устр. сравнения таймера 1
11 AD1.2 Вход 2 АЦП 1
22–23 37 00 Port 0.11
01 CTS (UART1) Вход готовности к передаче UART1
10 CAP1.1 (Timer 1) Выход 1 устр. сравнения таймера 1
11 SCL1 (I2C1) Тактовый сигнал I2C1
24–25 38 00 Port 0.12
01 DSR (UART1) Вход готовности к обмену UART1
10 MAT1.0 (Timer 1) Выход 0 устр. сравнения таймера 1
11 AD1.3 Вход 3 АЦП 1
26–27 39 00 Port 0.13
01 DTR (UART1) Выход готовности к обмену UART1
10 MAT1.1 (Timer 1) Выход 1 устр. сравнения таймера 1
11 AD1.4 Вход 4 АЦП 1
28–29 41 00 Port 0.14
01 DCD (UART1) Вход «связь установлена» UART1
10 EINT1 Вход 1 внешнего прерывания
11 SDA1 (I2C1) Линия данных (I2C1)
30–31 45 00 Port 0.15
01 RI (UART1) Вход входящего вызова UART1
10 EINT2 Вход 2 внешнего прерывания
11 AD1.5 Вход 5 АЦП 1

35
Таблица 1.9.4 – Управление функциями внешних выводов через PINSEL1
Биты Конт. Код Функция Описание
0–1 46 00 Port 0.16
01 EINT0 Вход 0 внешнего прерывания
10 MAT0.2 (Timer 0) Выход 2 устр. совпадения таймера 0
11 CAP0.2 (Timer 0) Вход 2 устр. захвата таймера 0
2–3 47 00 Port 0.17
01 CAP1.2 (Timer 1) Вход 2 устр. захвата таймера 1
10 SCK1 (SSP) Тактовый синел интерфейса SSP
11 MAT1.2 (Timer 1) Выход 2 устр. совпадения таймера 1
4–5 53 00 Port 0.18
01 CAP1.3 (Timer 1) Вход 3 устр. захвата таймера 1
10 MISO1 (SSP) Вход ведущего, выход ведомого SSP
11 MAT1.3 Выход 2 устр. совпадения таймера 3
6–7 54 00 Port 0.19
01 MAT1.2 Выход 2 устр. совпадения таймера 1
10 MOSI1 (SSP) Выход ведущего, вход ведомого SSP
11 CAP1.2 (Timer 1) Вход 2 устр. захвата таймера 1
8–9 55 00 Port 0.20
01 MAT1.3 (Timer 1) Выход 2 устр. совпадения таймера 3
10 SSEL1 (SSP) Выбор режима ведущий/ведомый SSP
11 EINT3 Вход 3 внешнего прерывания
10–11 1 00 Port 0.21
01 PWM5 Выход 5 ШИМ0
10 AD1.6 Вход 6 АЦП 1
11 CAP1.3 (Timer 1) Вход 3 устр. захвата таймера 1
12–13 2 00 Port 0.22
01 AD1.7 Вход 7 АЦП 1
10 CAP0.0 (Timer 0) Вход 0 устр. захвата таймера 0
11 MAT0.0 (Timer 0) Выход 0 устр. совпадения таймера 0
14–15 58 00 Port 0.23
01 Vbus Вход обнаружения питания USB
10,11 —
16–17 — — —
18–19 9 00 Port 0.25
01 AD0.4 Вход 4 АЦП 0
10 Aout (DAC) Выход ЦАП
11 —
20–23 — — —
24–25 13 00 Port 0.28
01 AD0.1 Вход 1 АЦП 0
10 CAP0.2 (Timer 0) Вход 2 устр. захвата таймера 0
11 MAT0.2 (Timer 0) Выход 2 устр. совпадения таймера 0

36
Таблица 1.9.4 – Продолжение
Биты Конт. Код Функция Описание
26–27 14 00 Port 0.29
01 AD0.2 Вход 2 АЦП 0
10 CAP0.3 (Timer 0) Вход 3 устр. захвата таймера 0
11 MAT0.3 (Timer 0) Выход 3 устр. совпадения таймера 0
28–29 15 00 Port 0.30
01 AD0.3 Вход 3 АЦП 0
10 EINT3 Вход 3 внешнего прерывания
11 CAP0.0 (Timer 0) Вход 0 устр. захвата таймера 0
30–31 17 00 Port 0.31 Только выход
01 UP_LED (USB) Выход индикатора связи через USB
10 CONNECT (USB) Вых. программного подключения USB
11 —

1.10 Цифровые порты ввода-вывода


В данном разделе рассматривается основная функция портов —
цифровой ввод-вывод. Для выбора основной функции достаточно оставить
без изменений нулевой управляющий код, которой содержится в PINSEL0–
PINSEL2 (раздел 1.9.3) по умолчанию.
Микроконтроллер поддерживает два режима управления портовыми
линиями: низкоскоростной и высокоскоростной. Последний отличается со-
кращенным временем реакции на команду и расширенными возможностями
управления. Осциллограммы сигнала на линии P0.9, управляемой в низко-
скоростном и высокоскоростном режиме (рисунок 1.10.1) позволяют оценить
разницу во времени реакции.

Рисунок 1.10.1 – Осциллограммы сигнала на линии P0.9, управляемой


в высокоскоростном и в низкоскоростном режимах
37
Осциллограммы записаны при тактовой частоте МГц.
Верхняя осциллограмма получена командами
FIO0SET=0x200; FIO0CLR=0x200;
А две нижние командами
IO0SET=0x200; IO0CLR=0x200;
Видно, что в низкоскоростном режиме задержки реакции при вводе-
выводе через порт зависят от делителя шины периферийных устройств: 1:1
или 1:4 ( МГц или МГц).
1.10.1 Управление портом через низкоскоростную шину
Направление ввода-вывода задается с помощью регистров IOxDIR,
где x — номер порта (0 или 1). Линии, соответствующие единицам двоично-
го кода, записанного в IOxDIR, переводятся в режим вывода. Нулям соответ-
ствуют линии в режиме ввода. По умолчанию регистр содержит нулевое зна-
чение, и все порты находятся в режиме ввода.
Установка в единицу одной выходной линии порта или нескольких
одновременно выполняется путем записи управляющего кода в регистр
IOxSET. На линиях, соответствующих единицам двоичного кода IOxSET,
установится уровень логической единицы. Линии порта, соответствующие
двоичным нулям, не меняют состояния. Аналогично сброс в ноль линий пор-
та осуществляется путем записи единиц в регистр IOxCLR. Такой способ
удобен, если требуется изменить уровень нескольких линий, не меняя уро-
вень остальных. Однако каждая такая операция установит на заданных лини-
ях только высокий или только низкий уровень. Невозможно одной командой
установить произвольное сочетание нулей и единиц.
Для вывода в порт произвольного двоичного кода одной командой
служит регистр IOxPIN. После записи этого регистра на выходных линиях,
соответствующих единицам установится высокий уровень, на линиях, соот-
ветствующих нулям — низкий. Для выборочного изменения нескольких ли-
ний применяют так называемое наложение маски (маскирование). Сначала
выполняют логическое умножение регистра IOxPIN на число, содержащее
нули в разрядах, соответствующих низкому логическому уровню. Затем при-
меняют логическое сложение. Рассмотрим несколько примеров.
Пример 1. Вывод 8-разрядной константы в порт. Команда
IO0PIN=(IO0PIN & 0xFFFF00FF) | 0x0000A500;
дает результат
,

где x — неизменившиеся разряды.


Пример 2. Вывод 8-разрядной переменной в порт. Команда
IO0PIN=(IO0PIN & 0xFFFFС03F) | Port << 6;
дает результат
,
где P — 8-разрядное содержимое переменной Port.

38
Пример 3. Вывод одного бита в порт. Команда
IO0PIN=(IO0PIN & 0xFFFFFFBF) | Bit << 6;
дает результат
.
Имеется в виду, что переменная Bit принимает только два значения: 0 или 1,
содержащееся в младшем разряде B.
Пример 4. Вывод произвольного бита переменной в порт. Команда
IO0PIN=(IO0PIN & 0xFFFFFFFD) | (Word & 0x1000) >> 11;
скопирует 12-ый разряд переменной Word в 1-ый разряд порта:
.
Фактически логика управления портом через регистры IOxPIN,
IOxSET, IOxCLR соответствует работе D-триггера, включенного так, как по-
казано на рисунке 1.10.2, а).
Чтение регистра IOxPIN дает двоичный код, соответствующий логи-
ческим уровням на контактах микроконтроллера (причем независимо от того,
настроены они на ввод или на вывод). Выборочное считывание одного или
нескольких бит выполняется с помощью логического умножения на маску.
Пример 5. Чтение состояния одной портовой линии
Bit=IO0PIN & 0x00000040;
дает результат
,
где бит равен 0 или 1 в зависимости от электрических уровнях на линии.
Пример 6. Чтение байта из порта
Byte=IO0PIN & 0x0000FF00;
дает результат:
,
где x — нули или единицы в зависимости от электрических уровней.
IOxSET.x S Q Px.x FIOxSET.x S Q Px.x
T FIOxMASK.x T
&
IOxPIN.x D D
FIOxPIN.x
IOxCLR.x R FIOxCLR.x R

а) б)
Рисунок 1.10.2 – Структурная схема выхода портовой линии:
а) в низкоскоростном режиме, б) в высокоскоростном режиме
Перечислим регистры управления портами в низкоскоростном режиме.
Регистр IOxDIR (IO0DIR, IO1DIR) устанавливает режим ввода или
вывода через порт. Единица в разряде IOxDIR переводит соответствующую
линию порта в режим цифрового выхода, ноль соответствует режиму входа.
Регистры IOxPIN (IO0PIN, IO1PIN) управляют электрическими
уровнями на портовых линиях, а также используются для чтения уровней,
действующих на линиях. Запись числа в эти регистры приводит к установке
уровней, советующих двоичному коду числа. Чтение регистров дает код, со-
ответствующий логическим уровням на портовых линиях.

39
Регистр IOxSET (IO0SET, IO1SET). Запись числа в эти регистры
приводит к установке высоких логических уровней на выходных линиях, со-
ответствующих двоичным единицам в IOxSET. Портовые линии, соответ-
ствующие логическим нулям не меняют состояния.
Регистр IOxCLR (IO0CLR, IO1CLR). Запись числа в эти регистры
приводит к установке низких логических уровней на выходных линиях, соот-
ветствующих двоичным единицам в IOxCLR. Портовые линии, соответству-
ющие логическим нулям не меняют состояния.
1.10.2 Управление портом через высокоскоростную шину
Высокоскоростной режим включается установкой единиц в нулевом и
первом разряде регистра SCS (рисунок 1.10.3). Нулевой разряд отвечает за
режим порта 0, первый — за режим порта 1.
SCS – режим управления цифровыми портами ввода-вывода
15 8 7 4 3 2 1 0

1M

0M
O

O
PI

PI
G

G
Порт 1 Порт 0

Рисунок 1.10.3 – Схема регистра управления высокоскоростным обменом


с цифровыми портами ввода-вывода
Логика управления портом в высокоскоростном режиме соответствует
схеме на рисунке 1.10.2 б).
Регистры управления портом в высокоскоростном режиме подключе-
ны к шине данных ядра МК. Помимо сокращения времени реакции на коман-
ду в этом режиме доступно маскирование, а также обращение в формате бай-
та и слова.
Использование регистров FIOxDIR, FIOxSET, FIOxCLR и FIOxPIN
полностью аналогично регистрам IOxDIR, IOxSET, IOxCLR и IOxPIN низко-
скоростного режима.
К 32-разрядным регистрам FIOxDIR, FIOxSET, FIOxCLR и FIOxPIN,
можно обращаться в формате 16-разрядного слова и в байтовом формате. В
таком случае к именам регистров добавляется еще один символ. Младшее
слово обозначается буквой «L», старшее — буквой «U». Байты нумеруются
цифрами от 0 до 3: FIOxSETL, FIOxCLRU, FIOxPIN0–FIOxDIR3.
Аппаратно поддерживается маскирование через регистр FIOxMASK, к
которому также можно обращаться в формате байта и слова. Запись двоич-
ных единиц в FIOxMASK блокирует изменение соответствующих портовых
линий любыми командами (логический элемент «И» на рисунке 1.10.1, б).
Пример 1 из предыдущего раздела (вывод 8-разрядной константы) в
режиме байтового доступа реализуется так:
FIO0PIN1=0xA5;
Пример 2 (вывод байтовой переменной):
FIO0MASKL=0xC03F;
FIO0PINL=(Port << 6);
Пример 3 (вывод младшего бита переменной в 6-ой бит порта):
40
FIO0MASK0=0xBF;
FIO0PIN0=Bit << 6;
Пример 4 (вывод 12-го бита переменной в 1-ый бит порта):
FIO0MASK0=0xFD;
FIO0PIN0=(Word & 0x1000) >> 11;
Регистры FIOxDIR, FIOxPIN, FIOxSET, FIOxCLR полностью ана-
логичны соответствующим регистрам для низкоскоростного режима.
Регистры FIOxPINL, FIOxPINU (FIO0PINL, FIO0PINU,
FIO1PINL, FIO1PINU) предназначены для чтения и записи порта в формате
16-разрядного слова. FIOxPINL связан с портовыми линиями Px.0–Px.15,
FIOxPINU — с линиями Px.16–Px.31 (рисунок 1.10.2).
Регистры FIOxPIN0–FIOxPIN3 (FIO0PIN0–FIO0PIN3, FIO1PIN0–
FIO1PIN3) предназначены для чтения и записи порта в байтовом формате.
FIOxPIN0 связан с портовыми линиями Px.0–Px.7, FIOxPIN1 — с линиями
Px.8–Px.15 и т. д. (рисунок 1.10.4).
Регистры FIOxMASK (FIO0MASK, FIO1MASK) предназначены для
наложения маски при всех операциях с портами. Установка единиц в некото-
рые разряды приводит к блокировке любых изменений соответствующих
портовых линий через FIOxPIN, FIOxSET и FIOxCLR.
31 0

FIOxPIN

15 0 15 0

FIOxPINU FIOxPINL

7 0 7 0 7 0 7 0

FIOxPIN3 FIOxPIN2 FIOxPIN1 FIOxPIN0

Рисунок 1.10.4 – Схема регистров управления портами в режимах


четырехбайтного слова, двухбайтного слова и в байтовом режиме
Примечание. Для управления портами в формате байта и 16-
разрядного слова кроме FIOxPINL/U и FIOxPIN0–3, все другие регистры
(FIOxDIR, FIOxSET, FIOxCLR, FIOxMASK) допускают использование в кон-
це имени номеров 0–3 и обозначений «L/U».

1.11 Система прерываний


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

41
Событие, требующее немедленной реакции и программной обработки,
называется прерывающим событием. Возникновение такого события сопро-
вождается специальным сигналом — запросом прерывания. Устройство, ге-
нерирующее этот сигнал, будем называть источником прерывания.
Упрощенно процесс обработки прерывания можно описать так:
а) источник прерывания формирует запрос прерывания;
б) система прерываний приостанавливает выполнение основной про-
граммы и передает управление процедуре обработки прерывания;
в) после завершения процедуры обработки прерывания управление
возвращается в основную программу.
Перечисленные действия могут быть организованы алгоритмически
(программным путем) без использования специальных аппаратных средств.
Однако для этого потребуется периодически опрашивать потенциальные ис-
точники прерываний в ожидании появления запросов. Программный опрос
приведет к усложнению алгоритма и неизбежным запаздываниям в реакциях
на прерывающие события. В то время как система прерываний обеспечит не-
прерывное слежение за всеми источниками и в случае появления запроса за-
пустит процедуру обработки прерывания с минимальной задержкой.
Архитектура ARM7 поддерживает три вида прерываний: векторное
IRQ, невекторное IRQ и быстрое FIQ. Одновременно поддерживается обра-
ботка не более 16 источников векторных прерываний, каждому из которых
может быть назначен произвольный адрес обработчика. Если необходимо
обеспечить поддержку более 16 источников прерываний, то используют не-
векторные прерывания с общим адресом обработчика. Процесс реакции на
векторные и невекторные прерывания один и тот же. Быстрое прерывание
FIQ имеет приоритет выше, чем IRQ и может прерывать обработку IRQ.
Предусмотрен только один обработчик всех запросов FIQ с единственным
адресом. Запрос от каждого источника может быть классифицирован как IRQ
или FIQ через регистр VICIntSelect (раздел 1.11.4).
1.11.2 Процесс обработки прерываний IRQ
Прерывания IRQ и FIQ являются частным случаем исключительных
ситуаций. Процесс обработки прерывания подчинен общему порядку для ис-
ключений, рассмотренному в разделе 1.6.
При возникновении прерывания, классифицированного как IRQ, вы-
полняются следующие действия:
1) содержимое счетчика команд , указывающее на следующую
команду, сохраняется в R14_irq (LR);
2) слово состояния программы CPSR сохраняется в SPSR_irq;
3) режим меняется на IRQ;
4) бит I в слове состояния программы CPSR устанавливается в едини-
цу, что запрещает все прерывания IRQ;
5) регистр VICVectAddr загружается адресом процедуры обработки
прерывания из регистра VICVectAddr0–15, где 0–15 — номер слота, c кото-
рым связан данный источник прерывания;

42
6) в счетчик команд R15 (PC) записывается адрес 0x00000018, что
приводит к немедленной передаче управления по этому адресу;
7) выполняется инструкция
LDR PC, [PC, #-0x0FF0]
расположенная по адресу 0x00000018, что приводит к записи в счетчик ко-
манд содержимого регистра VICVectAddr с адресом
;
8) управление получает процедура обработки прерываний, адрес ко-
торой был задан в регистре VICVectAddr.
Процедура обработки прерываний начинается с команды STM, сохра-
няющей в стек все используемые регистры общего назначения (R0–R12).
1.11.3 Процесс обработки быстрых прерываний FIQ
При возникновении прерывания, классифицированного как FIQ, вы-
полняются следующие действия:
1) счетчик команд , сохраняется в R14_fiq (LR);
2) слово состояния программы CPSR сохраняется в SPSR_fiq;
3) режим меняется на FIQ;
4) биты I, F в слове состояния программы CPSR устанавливается в
единицу, что запрещает все прерывания IRQ и FIQ;
5) управление передается команде по адресу 0x0000001С путем запи-
си этой константы в счетчик команд R15 (PC);
6) выполняется инструкция
LDR PC, [PC, #Смещение]
что приводит к загрузке в счетчик команд адреса обработчика быстрого пре-
рывания;
7) управление получает процедура обработки быстрого прерывания.
1.11.4 Регистры управления системой прерываний
Большинство регистров, предназначенных для управления системой
прерываний или слежения за ее состоянием, имеют структуру, схематично
показанную на рисунке 1.11.1. Каждый бит регистра соответствует одному из
источников прерываний.
Регистр VICRAWStatus. Единица в любом из разрядов информирует
о получении запроса прерывания от соответствующего источника, причем
независимо от того разрешено ли прерывание (см. также VICIntEnable).
Регистр VICIRQStatus. То же, что VICRAWStatus, но единицами от-
мечаются только источники, прерывания от которых разрешены и классифи-
цированы как IRQ (см. также VICIntSelect).
Регистр VICFIQStatus. То же, что VICIRQStatus, но для прерываний,
классифицированных как FIQ.
Регистр VICIntEnable. Установка единицы в любой из разрядов раз-
решает обработку запросов прерывания от соответствующего источника.
Сброс в ноль не имеет значения. Запрет обработки прерываний осуществля-
ется через регистр VICIntEnClear.

43
Регистр VICIntEnClear. Установка единицы в любой из разрядов за-
прещает обработку запросов прерывания от соответствующего источника.
Регистр VICIntSelect. Сброс в ноль любого из разрядов классифици-
рует соответствующий источник как IRQ. Адрес обработчика прерывания
должен храниться в одном из регистров VICVectAddr0–15 в зависимости от
слота, назначенного данному источнику. Установка единицы классифициру-
ет соответствующий источник как FIQ. Тогда адрес обработчика прерывания
задается инструкцией по вектору 0x0000001C.
Регистр VICSoftInt. Установка единицы в любой из разрядов вызы-
вает обработку прерывания от соответствующего обработчика программным
путем. Прерывание будет возникать циклически, пока данный регистр со-
держит единицы в разрядах, соответствующих разрешенным прерываниям.
Регистр VICSoftIntClear. Установка единицы в любой из разрядов
снимает программный запрос прерывания, выполненный через VICSoftInt.
Регистры VICVectCntl0–15 предназначены для того, чтобы распре-
делить используемые источники прерываний по 16 слотам. Структура реги-
стра показана на рисунке 1.11.1.
● Бит 5 (SlotEN) должен быть установлен в единицу.
● Биты 0–4 (IntRequest) назначают данному слоту номер источника
прерывания. Номера источников прерываний соответствуют номерам битов

VICVecCntl0-15 – управление слотами векторных прерываний


15 8 7 6 5 4 0
N

IntRequest
otE
Sl

Номер запроса прерывания


Включить слот

VICProtection – защита слотов


15 8 7 4 3 1 0
ac VIC
ss
ce

Запретить управление из режима User

Маска регистров управления системой прерываний


31 24 23 22 21 20 19 18 17 16
T3

T2
D

1
SB

0
C
AD

AD
BO

N
I2
U

EI

EI

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
C RM

C RM
SS PI1

T1

T0

0
0
T1

T0

T
I0

0
TC

er

er
M
L

e1

e0

D
C

AR

AR
P
PL
N

SP
S

A
PW

W
I2
R

or

or
EI

EI

Ti

Ti
U

22 – USB ― приемопередатчик USB 9, 19 – I2C0/1 ― приемопередатчики I2C


20 – BOD ― монитор питания 8 – PWM0 ― широтно-импульсный модулятор
18, 21 – AD0/1 ― аналого-цифровой преобразователь 6, 7 – UART0/1 ― приемопередатчики UART
14–17 – EINT0–EINT3 ― запрос внешним сигналом 4, 5 – Timer0/1 ― таймеры-счетчики
13 – RTC ― часы реального времени 2, 3 – ARM Core0/1 ― резерв
12 – PLL ― умножитель тактовой частоты 0 – WDT ― сторожевой таймер
10, 11 – SPI0/1 ― приемопередатчики SPI

Рисунок 1.11.1 – Структура основных регистров управления системой прерываний

44
на рисунке 1.11.1. Назначать один и тот же источник прерывания нескольким
слотам не рекомендуется, хотя практически это возможно и допустимо. Если
такое произошло, то использоваться будет слот с меньшим номером.
Регистры VICVectAddr0–15 задают адрес обработчика прерывания
для каждого слота.
Регистр VICVectAddr автоматически загружается адресом обработ-
чика из VICVectAddr0–15 при запросе прерывания. Содержимое регистра ис-
пользуется командой LDR по адресу 0x00000018 для передачи управления об-
работчику прерывания.
Регистр VICDefVectAddr — адрес обработчика невекторных преры-
ваний. Если прерывание разрешено через VICIntEnable, не классифицировано
как FIQ через VICIntSelect, но не ассоциировано ни с одним из 16 слотов че-
рез VICVectCntl0–15, оно считается невекторным. В этом случае управление
будет передано по адресу, записанному в VICDefVectAddr. Невекторные
прерывания используют, если все слоты заняты. При обработке невекторного
прерывания его источник идентифицируется через регистр VICIRQStatus.
Регистр VICProtection содержит единственный управляющий бит
(рисунок 1.11.1). Установка единицы разрешает управление прерываниями
только в привилегированных режимах. В режиме User управление прерыва-
ниями становится запрещено.
1.11.5 Порядок настройки прерывания IRQ
В ходе настройки системы прерываний рекомендуется придерживать-
ся следующего порядка действий.
1. Принять решение о том, какой из свободных слотов (0–15) будет
использоваться для данного источника прерывания.
2. Записать адрес обработчика прерывания в регистр VICVectAddr0–
15, соответствующий выбранному слоту, например для слота 0
VICVectAddr0 = (unsigned) Имя процедуры-обработчика ;
3. Назначить выбранному слоту источник прерывания
VICVectCntl0 = 0x20 | Номер источника ;
Под номером понимается десятичное число (номер источника или номер раз-
ряда на рисунке 1.11.1).
4. Настройка по пунктам 1–3 повторяется для каждого источника.
5. Включить прерывание от данного источника
VICIntEnable = Маска источника ;
Под маской понимается двоичный код с единицами в разрядах, соответству-
ющих разрешенным прерываниям (рисунок 1.11.1).
Отметим, что каждому из регистров может быть
поставлен в соответствие единственный источник прерывания, поэтому ука-
зывается его номер. В то же время через могут быть разрешены
несколько прерываний, поэтому каждому из них соответствует один бит.
Порядок настройки невекторного прерывания IRQ:
1. Аналогично пункту 2 для векторного прерывания поместить адрес
обработчика в регистр VICDefVectAddr.
45
2. Аналогично пункту 5 для векторного прерывания разрешить обра-
ботку прерывания от данного источника через регистр VICIntEnable.
1.11.6 Порядок настройки быстрого прерывания FIQ
1. Классифицировать прерывание от данного источника, как быстрое
прерывание FIQ. Установить единицу в разряд регистра VICIntSelect, соот-
ветствующий данному источнику
VICIntEnable = Маска источника ;
2. Включить прерывание от данного источника
VICIntEnable = Номер источника ;
3. Внести изменения в код инициализации Startup.s. Заменить строку
FIQ_Handler B FIQ_Handler
на
IMPORT FIQ_Handler
В дальнейшем использовать имя FIQ_Handler для процедуры-обработчика
прерывания. Заголовок процедуры-обработчика должен быть таким:
irq void FIQ_Handler ()
Имя подпрограммы может быть произвольным, но должно совпадать c име-
нем после директивы IMPORT.
1.11.7 Процедура обработки прерывания
Процедура обработки прерывания на языке Си, ориентированном на
использование компилятора RealView 4 создается по шаблону:
irq void Имя_функции()
{
...
Регистр = Код ; // Сброс флага запроса прерывания
VICVectAddr=0;
}
Строка «Сброс флага запроса прерывания» обращается к регистру
управления периферийным устройством, вызвавшим прерывание. Например,
для таймера 0 это
T0IR=1;
Если сброс флага не произвести, запрос прерывания останется активным и
обработка прерывания начнет повторяться циклически.
1.11.8 Задержка обработки прерывания
В микроконтроллерах семейства LPC21xx задержка при передаче
управления обработчику прерывания сравнительно велика. Минимальное
время от появления запроса прерывания до выполнения первой команды об-
работчика составляет 12 тактов для FIQ и 13 тактов для IRQ. Максимальное
время реакции на запрос на 20 тактов больше минимального. Дополнитель-
ные 20 тактов определяются временем, необходимым для завершения коман-
ды, с выполнением которой совпал запрос прерывания, такой как

46
LDMFA R0, {R0-R15}
Выполнение первой эффективной команды будет отложено еще на не-
сколько тактов, необходимых для сохранения в стек регистров общего назна-
чения такой командой, как
STMDB R13!, { ... }
Затраты времени на сохранение регистров зависят от их числа. На 13 реги-
стров R0–R13 уходит 14 тактов.
Таким образом, задержка обработки прерывания IRQ может варьиро-
вать от 13 до тактов; для FIQ задержка варьирует от 12 до
46 тактов.
В качестве подтверждения приведем результат простого эксперимен-
та. На вход запроса прерывания EINT3 поступают периодические импульсы
от генератора. Обработчик прерывания по внешнему сигналу в ответ форми-
рует короткий одиночный импульс. Интервал времени между фронтами им-
пульсов от генератора и ответного, формируемого микроконтроллером, соот-
ветствует задержке обработки прерывания.
Листинг программы приведен в приложении А. Отметим, что тактовая
частота микроконтроллера равна 12 МГц, умножитель отсутствует, обраще-
ние к портам выполняется через высокоскоростную шину.
На рисунке 1.11.2 приведено семейство осциллограмм, записанных
многократно в случайные моменты времени. Жирным пунктиром выделены
импульсы, соответствующие самой короткой и самой длинной задержкам.
Задержка в 21 такт для IRQ складывается из тринадцати базовых,
трех, затраченных на сохранение регистров R0–R1 и пяти на вывод в порт.

Рисунок 1.11.2 – Осциллограммы импульсов, показывающих


временную задержку обработки прерывания IRQ (вверху) и FIQ (внизу)

47
Вместе с тем можно предположить, что команда LDM, выполняемая до
20 тактов не встречается в программе, а самая «медленная» команда в про-
грамме выполняется 3 такта; команда STM сохраняет не все регистры и вы-
полняется 4–7 тактов. Основываясь на этих предположениях, можно считать,
что задержка от появления запроса IRQ до первой эффективной команды об-
работчика ориентировочно составляет от до так-
тов. Для FIQ задержка на 1 такт меньше.
Время реакции на прерывание FIQ можно существенно уменьшить,
приняв следующие меры:
а) В процедуре обработки прерывания использовать только регистры
R8–R12, отдельные для режима FIQ. Это даст возможность не сохранять и не
восстанавливать их командами LDM, STM.
б) Не оформлять обработчик быстрого прерывания как процедуру, а
размещать его команды, начиная с адреса 0x0000001С. Этот адрес последний
в таблице векторов исключительных ситуаций, поэтому все последующие
адреса свободны.
Компилятор RealView не содержит необходимых для этого средств,
поэтому потребуется для случая а) обработчик прерывания создавать с ис-
пользованием ассемблера (директива asm), а для случая б) включать код
обработчика прерывания непосредственно в стартовый код Startup.s.

1.12 Внешние прерывания


Запрос внешнего прерывания инициируется электрическим сигналом
на портовых линиях микроконтроллера. Входы внешних прерываний обозна-
чаются EINT0–EINT3. Внешнее прерывание способно вывести микроконтрол-
лер из режима отключения, когда почти все периферийные устройства не ра-
ботают и запросы прерываний от большинства источников невозможны.
1.12.1 Регистры управления блоком внешних прерываний
Схема управляющих регистров показана на рисунке 1.12.1.
Регистр EXTINT
● Биты 0–3 (EINT0–EINT3). Флаги запроса внешних прерываний.
Каждый из этих разрядов устанавливается в единицу при обнаружении за-
проса внешнего прерывания. Флаг сбрасывается путем записи в него единицы.
Регистр INTWAKE
● Биты 0–3 (EXTWAKE0–EXTWAKE3). Единица в каждом из разря-
дов разрешает вывод МК из режима отключения запросом внешнего преры-
вания с соответствующим номером.
● Биты 5 (USBWAKE). Установка бита в единицу разрешает вывод
МК из состояния отключения при появлении активности на шине USB.
● Биты 14 (BODWAKE). Установка бита в единицу разрешает вывод
МК из состояния отключения сигналом монитора питания (при падении
напряжения питания до 2,6 В).
● Биты 15 (RTCWAKE). Установка бита в единицу разрешает вывод
МК из состояния отключения сигналом от часов реального времени.

48
EXTINT – флаги запроса внешних прерываний
15 8 7 4 3 2 1 0
T3 T2 T1 T0
N N N N
EI EI EI EI
Флаги прерываний

INTWAKE – Разрешение выхода из отключенного режима


15 8 7 6 5 4 3 2 1 0
D T 3 T 2 T 1 T 0
TC SB EX KE EX KE EX KE EX KE
BO AKE R AKE U AKE A A A A
W W W W W W W
Монитор USB Внешние прерывания
Часы реального времени
питания
EXTMODE – Режим: перепад/уровень
15 8 7 4 3 2 1 0
T 3 T 2 T 1 T 0
EX DE EX DE EX DE EX DE
O O O O
M M M M
Уровень/перепад

EXTPOLAR – фронт/срез, низкий/высокий уровень


15 8 7 4 3 2 1 0
T 3 T 2 T 1 T 0
EX AR EX AR EX AR EX AR
L L L L
PO PO PO PO

Полярность/выбор фронта

Рисунок 1.12.1 – Схема регистров управления реакциями на внешние прерывания


Регистр EXTMODE
● Биты 0–3 (EXTMODE0–EXTMODE3). Установка единицы в каждый
разряд включает реакцию соответствующего входа прерывания на перепад
сигнала. Регистр EXTPOLAR (см. ниже) определяет спадающий или нарас-
тающий фронт. Сброс в ноль этих битов заставляет соответствующую линию
реагировать на статический логический уровень. Запрос прерывания посто-
янно вырабатывается, пока фиксируется активный логический уровень. Низ-
кий или высокий активный уровень определяется регистром EXTPOLAR.
Регистр EXTPOLAR
● Биты 0–3 (EXTPOLAR0–EXTPOLAR3). Сброс в ноль каждого раз-
ряда делает активным, спадающий фронт сигнала или на низкий логический
уровень в зависимости от значения EXTMODE. Установка единицы застав-
ляет линию прерывания реагировать на нарастающий перепад или высокий
логический уровень.
1.12.2 Порядок настройки блока внешних прерываний
1. Перевести в соответствующий режим портовые линии, которые ис-
пользуются для запроса внешних прерываний. Настройка производится через
регистры PINSEL0–PINSEL1 (раздел 1.9.3).
2. Выбрать реакцию на перепад напряжения или статический уровень
через регистр EXTMODE. По умолчанию выбрана реакция на уровень.
3. Выбрать активный уровень или фронт сигнала внешнего прерыва-
ния через регистр EXTPOLAR. По умолчанию выбран активный логический
ноль или спадающий фронт.

49
4. Если необходимо, разрешить «пробуждение» микроконтроллера по
запросу внешнего прерывания через регистр INTWAKE. Если режим отклю-
чения питания не используется, то настройка не производится.
5. Разрешить внешнее прерывание через регистры VICVectAddr0–15,
VICVectCntl0–15 и VICIntEnable.
Процедура обработки прерывания должна содержать команду сброса
флага путем записи единицы в соответствующий разряд регистра EXTINT.

1.13 Таймеры-счетчики
Таймеры-счетчики применяются для формирования и измерения ин-
тервалов времени или для подсчета числа внешних импульсов. Таймер-
счетчик представляет собой программируемый суммирующий счетчик с воз-
можностью выбора источника счетных импульсов. Микроконтроллер
LPC2148 оснащен двумя абсолютно идентичными по функциональным воз-
можностям 32-разрядными таймерами-счетчиками. Содержимое таймеров-
счетчиков доступно для чтения и записи через регистры TC0 и TC1.
1.13.1 Режим таймера и схема совпадения
В зависимости от источника счетных импульсов различают режим
таймера или счетчика. В режиме таймера ведется счет внутренних тактовых
импульсов микроконтроллера . При максимальной тактовой частоте
60 МГц разрядность позволяет продолжать счет без переполнения в течение
с. Формирования или измерение бóльших интервалов
времени возможно с использованием 32-разрядных предварительных счетчи-
ков-делителей c произвольным модулем счета в пределах разрядности (реги-
стры TxPC). Каскадное соединение таймера и предварительного делителя
практически бесконечно расширяет диапазон временных интервалов. При
тактовой частоте 60 МГц переполнение произойдет почти через 10 тысяч лет.
Временные интервалы формируются схемой совпадения, которая
сравнивает содержимое таймера с пороговыми регистрами TxMR0–TxMR3.
В момент равенства возможно выполнение следующих действий: сброс тай-
мера в ноль, остановка таймера, запрос прерывания, изменение логического
уровня на портовой линии. Четыре схемы совпадения позволяют выполнять
разные действия при достижении таймером каждого из четырех пороговых
значений.
Длительность временного интервала при увеличении таймера от 0 до
TxMRx без предварительно делителя ( ) составляет
. (1.13.1)
С предварительным делителем ( )
. (1.13.2)
Следовательно, значение порогового регистра, обеспечивающего за-
держку (без предварительного делителя) определяется выражением
. (1.13.3)
50
Здесь — ближайшее к целое, не превосходящее , а —
округленная до ближайшего целого величина .
1.13.2 Режим счетчика
В режиме счетчика подсчитываются импульсы напряжения, поступа-
ющие на портовые линии CAPx.0–CAPx.3. Максимальная частота на счетном
входе составляет 30 МГц.
1.13.3 Схема захвата
Схема захвата позволяет «запомнить» в регистрах TxCR0–TxCR3 те-
кущее состояние таймера-счетчика в момент появления сигнала на входных
портовых линиях CAPx.0–CAPx.3. Захват состояния осуществляется с мини-
мально возможной временной задержкой в один машинный цикл.
1.13.4 Управляющие регистры
Схема регистров управления таймерами-счетчиками приведена на ри-
сунке 1.13.1.
Регистры TxIR (T0TCR, T1TCR) содержат флаги прерываний от
схем совпадения и захвата. Установленный флаг должен сбрасываться в про-
цедуре обработки прерывания путем записи единицы в соответствующий
разряд. Запись нуля не оказывает влияния.
● Биты 0–3 (MR0I–MR3I) — флаги прерываний от выходов схемы
совпадения MAT0–MAT3.
● Биты 4–7 (CR0I–CR3I) — флаги прерываний от выходов схемы за-
хвата CAP0–CAP3. Регистры TxTCR (T0TCR, T1TCR) предназначены для
запуска и сброса таймеров-счетчиков МК. Каждый из них содержит только
два управляющих бита.
● Бит 0 (ENABLE). Установка единицы разрешает счет, сброс в ноль
запрещает счет.
● Бит 1 (RESET). Установка единицы приводит к сбросу таймера-
счетчика в ноль. Счет будет продолжен после сброса бита RESET в ноль.
Регистры TxCTCR (T0CTCR, T1CTCR) предназначены для
настройки режимов работы встроенных таймеров-счетчиков.
● Биты 0–1 (MODE). Отвечают за выбор режима работы таймера-
счетчика (таблица 1.13.1).
● Биты 2–3 (InputSelect). Отвечают за выбор линии CAPx.0–CAPx.3,
которая служит счетным входом или входом захвата. Номер линии (0–3) сов-
падает с двоичным кодом в InputSelect (00–11). Значение этих битов не важно
в режиме таймера ( ), когда внешние сигналы не используются.
Таблица 1.13.1 – Режимы работы таймеров-счетчиков МК LPC2148
MODE Режим таймера-счетчика
00 Режим таймера. Инкремент по фронту внутреннего сигнала PCLK
01 Режим счетчика. Инкремент по фронту внешнего сигнала CAP.
10 Режим счетчика. Инкремент по срезу внешнего сигнала CAP.
11 Режим счетчика. Инкремент по фронту и срезу сигнала CAP.

51
TxTCR – настройка таймеров-счетчиков
15 11 8 7 2 1 0
ET
ES EN
R
ВКЛ
Сброс

TxCTCR – настройка режима счета


15 8 7 4 3 2 1 0
Input
Select MODE
Режим
Выбор входа

TxMCR – настройка схемы совпадения


15 12 11 10 9 8 7 6 5 4 3 2 1 0
3S 3R 3I 2S 2R 2I 1S 1R 1I 0S 0R 0I
R R R R R R R R R R R R
M M M M M M M M M M M M

3 2 1 Сброс
Прерывание
Остановка
TxCCR – настройка схемы захвата
15 12 11 10 9 8 7 6 5 4 3 2 1 0
3 3 3 2 2 2 1 1 1 0 0 0
AP AP AP AP AP AP AP AP AP AP AP AP
C I C FE C RE C I C FE C RE C I C FE C RE C I C FE C RE

3 2 1 Срез
Фронт
Прерывание
TxEMR – настройка сигналов совпадения
15 12 11 10 9 8 7 6 5 4 3 2 1 0

EMC3 EMC2 EMC1 EMC0 EM3 EM2 EM1 EM0


Режим Режим Режим Режим Состояние

TxIR – флаги прерываний


15 8 7 6 5 4 3 2 1 0
3I 2I 1I 0I 3I 2I 1I 0I
R R R R R R R R
C C C C M M M M
Флаги прерываний Флаги прерываний
от схемы захвата от схемы совпадения

Рисунок 1.13.1 – Схема регистров управления таймерами-счетчиками


Регистры TxPR (T0PR, T1PR) содержат предельные 32-разрядные
значения предварительных счетчиков-делителей.
Регистры TxTC (T0TC, T1TC) содержат 32-х разрядный код, накоп-
ленный в таймере-счетчике.
Регистры TxPС (T0PС, T1PС) — содержимое 32-разрядных предва-
рительных счетчиков-делителей. Таймер-счетчик увеличивается на единицу
при достижении счетчиком-делителем TxPС предельного значения, заданно-
го в TxPR. Если , то в режиме таймера инкремент будет происхо-
дить каждый такт PCLK; если , каждый второй такт и т. д. (1.13.2).
Регистры TxMRx (T0MR0–T0MR3, T1MR0–T1MR3) — пороговые
регистры, с которыми сравнивается содержимое таймеров счетчиков. При
совпадении генерируются события, заданные регистром TxMCR.
Регистры TxMCR (T0MCR, T1MCR).

52
● Биты 0–11 (MR0I–MR3I, MR0R–MR3R, MR0S–MR3S) задают реак-
ции на совпадение таймера с каждым из пороговых регистров TxMR0–
TxMR3 (см. таблицу 1.13.2).
Таблица 1.13.2 – Реакции на совпадение таймера-счетчика с TxMR0–TxMR3
Управляющие биты Назначение
MR0I–MR3I Разрешить/запретить запрос прерывания
MR0R–MR3R Разрешить/запретить сброс таймера-счетчика в ноль
MR0S–MR3S Разрешить/запретить остановку счета
Регистры TxCRx (T0CR0–T0CR3, T1CR0–T1CR3) содержат состоя-
ния таймеров счетчиков, захваченные при событии CAP0–CAP3.
Регистры TxCCR (T0CCR, T1CCR) — настройка схемы захвата.
● Биты 0–3 (CAP0RE–CAP3RE, CAP0FE–CAP3FE, CAP0I–CAP3I) за-
дают событие, на которое реагирует каждая из четырех схем захвата, а также
указывают на необходимость прерывания по захвату (таблица 1.13.3).
Таблица 1.13.3 – Реакции на сигнал захвата CAPx.0–CAPx.3
Управляющие биты Назначение
CAP0RE–CAP3RE Захват по фронту сигнала CAPx.0–CAPx.3
CAP0FE–CAP3FE Захват по срезу сигнала CAPx.0–CAPx.3
CAP0I–CAP3I Запрос прерывания по событию захвата
Регистры TxEMR (T0EMR, T1EMR).
● Биты 0–3 (EM0–3) отражают состояние логических уровней на вы-
ходах MATx.0–MATx.3
● Биты 4–5 (EMC0–EMC3). Биты управляют формированием внешне-
го сигнала по совпадению таймера-счетчика с каждым из пороговых реги-
стров TxMR0–TxMR3 (в соответствии с таблицей 1.13.4).
Таблица 1.13.4 – Способы формирования внешнего сигнала совпадения
ECx Реакция на совпадение
00 Не изменять внешний сигнал MATx.0
01 Установить на выходе MATx.0 сигнал «логический ноль»
10 Установить на выходе MATx.0 сигнал «логическая единица»
11 Инвертировать сигнал на выходе MATx.0
1.13.5 Формирование интервалов времени через систему прерываний
Чаще всего формирование временного интервала осуществляется с
помощью процедуры обработки прерывания, вызываемой схемой совпаде-
ния. При этом рекомендуется придерживаться следующего порядка настрой-
ки аппаратуры микроконтроллера.
1. Настроить работу схемы совпадения через регистр TxMCR. Обычно
требуется включить сброс счетчика и запрос прерывания по совпадению с
одним из пороговых регистров, например, TxMR0. Для этого достаточно уста-
новить единицы в битах MR0R, MR0I регистра TxMСR. Запрос прерывания
необходимо разрешить, даже если предполагается программный опрос флага.

53
2. Задать значение выбранного порогового регистра TxMR0–TxMR3.
Расчет выполнить в соответствии с формулой (1.13.3).
3. Выбрать режим таймера в регистре TxCTCR. Если настройка про-
изводится после сброса, этот пункт можно опустить, поскольку при сбросе
регистр TxCTCR получит нулевое значение.
4. Разрешить счет путем записи единицы в регистр TxTCR.
Остановка счета осуществляется путем записи нуля в TxTCR. Если
требуется при этом сбросить таймер в ноль, то следует записать единицы в
нулевой и первый бит, то есть число 3.
Проверка окончания временного интервала выполняется путем опроса
флага либо с помощью прерывания.
Если разрешен запрос прерывания (регистр TxMCR), то окончание
временного интервала (совпадение TxMCR и TxMRx) будет сопровождаться
установкой бита, соответствующего пороговому регистру, в регистре TxIR.
Для программного опроса флага требуется внедрить в программу команды
проверки условия и ветвления.
Чаще вместо программного опроса флага используют прерывание от
схемы совпадения. Для этого необходимо разрешить прерывание с помощью
регистров VICVectAddr0, VICVectCntl0 и VICIntEnable (раздел 1.11.4). В
конце процедуры обработки прерывания сбросить флаг прерывания путем
записи единицы в соответствующий разряд регистра TxIR.
1.13.6 Измерение периода и длительности импульса с помощью
устройства захвата
Измеряемый временной интервал может быть определен как разность
двух значений таймера, захваченных в моменты начала и конца временного
интервала. Для настройки таймера и схемы захвата предлагается придержи-
ваться следующего порядка действий.
1. Перевести выбранную портовую линию в режим CAP путем записи
в регистры PINSEL0, PINSEL1 (таблицы 1.9.3, 1.9.4).
2. Настроить схему захвата через регистр TxCCR. При измерении дли-
тельности импульса необходимо включить реакцию на оба фронта; при из-
мерении периода — на передний или задний фронт. Рекомендуется также
разрешить прерывание.
3. Включить таймер путем записи единицы в регистр TxTCR.
4. Разрешить обработку прерывания по захвату с помощью регистров
VICVectAddr0–15, VICVectCntl0–15 и VICIntEnable (раздел 1.11.4).
5. В процедуре обработки прерывания требуется сохранить захвачен-
ное значение таймера, находящееся в одном из регистров захвата TxCC0–
TxCC3. Необходимо также хранить и предыдущее значение этого регистра.
6. Определить длительность измеряемого интервала времени по раз-
ности текущего ( ) и предыдущего ( ) значения регистра захвата
. (1.13.4)

54
Такой алгоритм необходим, если окончание одного временного ин-
тервала совпадает с началом следующего. С таким случаем имеем дело при
измерении периода прямоугольного сигнала, как интервала времени между
нарастающими или спадающими фронтами импульсов.
При измерении длительности импульса можно подключить сигнал
сразу к двум входам захвата и настроить реакцию одного из них (например,
CAP0.0) на нарастающий фронт, а другого — на спадающий (например,
CAP0.1). Прерывание разрешить только по спадающему фронту. Тогда нет
необходимости сохранять в памяти значения регистров захвата. Можно
определить длительность через разность текущих значений CAP0.1 и CAP0.0.
1.13.7 Подсчет числа импульсов в единицу времени
Для реализации частотомера потребуется два таймера-счетчика. Один
используется для формирования интервала счета (например, 1 с), другой
служит счетчиком внешних импульсов. Для определенности будем считать,
что TC0 — таймер, а TC1 — счетчик.
Тогда необходимо использовать один из выходов MAT0 (таймера-
счетчика 0), сигнализирующий об окончании интервала счета, в качестве
сигнала захвата CAP1 (таймера-счетчика 1). Потребуется внешнее электриче-
ское соединение соответствующих портовых линий MAT0 и CAP1.
Порядок настройки изложен ниже.
1. Перевести одну портовую линию в режим MAT0.x, и две в режим
CAP1.x и CAP2.x.
2. Через регистр T0MCR включить сброс таймера по совпадению.
3. Через регистр T0EMR включить инверсию выбранного выхода
MAT0.x.
4. Задать длительность формируемого интервала счета установкой по-
рогового регистра T0MRx. Опираться на формулу (1.13.3).
5. Запустить таймер через T0TCR.
6. Задать режим счетчика с инкрементом по одному из фронтов, вы-
брать счетный вход для TC1 через регистр T1CTCR.
7. В регистре T1CCR включить захват TC1 по обоим фронтам сигнала
на входе CAP1.x, соединенным с сигналом совпадения MAT0.x.
8. Разрешить счет через регистр T1TCR.
9. Разрешить прерывание от таймера 1 с помощью регистров
VICVectAddr0–15, VICVectCntl0–15 и VICIntEnable.

1.14 Широтно-импульсный модулятор


Широтно-импульсный модулятор (ШИМ) предназначен для формиро-
вания периодических последовательностей прямоугольных импульсов. Пе-
риод и длительность импульсов регулируются с шагом в один машинный
цикл (16,67 нс). Возможно формирование до шести последовательностей им-
пульсов одной частоты и разной скважности. Имеется режим, в котором за-
дается начальная фаза импульсов.

55
1.14.1 Основы функционирования
Упрощенная функциональная схема ШИМ показана на рисунке 1.14.1.
Основу модуля ШИМ составляет счетчик PWMTC (на схеме не показан),
семь пороговых регистров PWMMR0–PWMMR6 (также не показаны), набор
схем совпадения и D-триггеров, связанных с выходными портовыми линиями
МК PWM0–PWM6. Счетчик PWMTC инкрементируется в каждом такте .
PWMTC A ==
Y
PWMMR0 B
S Q PWM1
T

A ==
Y R
PWMMR1 B

D1 MX
D0 Y S Q PWM2
T
MWMSEL2 A
A ==
Y R
PWMMR2 B

D1 MX
D0 Y S Q PWM3
T
MWMSEL3 A
A ==
Y R
PWMMR3 B

D1 MX
D0 Y S Q PWM4
T
MWMSEL4 A
A ==
Y R
PWMMR4 B

D1 MX
D0 Y S Q PWM5
T
MWMSEL5 A
A
==
Y R
PWMMR5 B

D1 MX
D0 Y S Q PWM6
T
MWMSEL6 A
A
==
Y R
PWMMR6 B

Рисунок 1.14.1 – Упрощенная функциональная схема модуля ШИМ


С помощью схем совпадения счетчик PWMTC сравнивается с порого-
выми регистрами PWMMR0–6. При совпадении PWMTC и PWMMR0 фор-
мируется сигнал сброса счетчика в ноль (верхний график на рисунке 1.14.2).
Таким образом, пороговый регистр PWMMR0 используется для зада-
ния периода импульсов. При частота выходных импульсов
ШИМ определяется выражением
. (1.14.1)
Так как PWMMR0 — 32-разрядный регистр, диапазон изменения ча-
стоты весьма широк: от десятков мегагерц до сотых долей герц.
56
Рисунок 1.14.2 – Временные диаграммы работы ШИМ.
Управление начальной фазой отключено (PWMSEL2–6 = 0)
Остальные пороговые регистры служат для задания длительности им-
пульсов. D-триггеры, соединенные с выходными портовыми линиями МК
PWM0–PWM6, сбрасываются при совпадении счетчика PWMTC с соответ-
ствующим пороговым регистром PWMMR1–PWMMR6. Установка триггеров
может происходить двумя способами в зависимости от состояния мульти-
плексоров, управляемых сигналами PWMSEL2–6.
Если , установка осуществляется в начале каждого периода
ШИМ. При этом возможность регулировки начальной фазы отсутствует. По-
лучим шесть синхронных выходов с независимой регулировкой коэффициен-
та заполнения (рисунок 1.14.2). Коэффициент заполнения определяется сле-
дующим выражением:
. (1.14.2)
При установка триггеров PWM2, 4, 6 происходит при сбросе тригге-
ров PWM1, 3, 5. В этом случае пороговые регистры PWMMR1, 3, 5 исполь-
зуются для задания начальной фазы, а PWMMR2, 4, 6 для задания длитель-
ности импульсов. Данный режим задействует больше аппаратных ресурсов
(по два пороговых регистра на каждый выход), что приводит к сокращению
числа выходных сигналов. Получим три синхронных выхода PWM2, 4, 6 с
независимой регулировкой начальной фазы (угла включения) и коэффициен-
та заполнения (рисунок 1.14.3). В этом случае коэффициент заполнения (для
выхода PWM2)
. (1.14.3)
Для остальных выходов должны использоваться другие пары «четно-
го» и «нечетного» пороговых регистров.

57
Рисунок 1.14.3 – Временные диаграммы работы ШИМ
в режиме управления начальной фазой (PWMSEL2–6 = 1)

Начальная фаза
. (1.14.4)
Длительность импульса
. (1.14.5)

1.14.2 Дополнительные возможности


Имеется возможность деления входной тактовой частоты счет-
чика PWMTC предварительным счетчиком делителем PWMPC. Причем ко-
эффициент деления частоты задается в регистре PWMPR. Инкремент счетчи-
ка PWMTC осуществляется каждый PWMPR+1 такт . Таким образом,
действительная частота тактовых импульсов на входе счетчика PWMTC рас-
считывается по формуле
. (1.14.6)
Следовательно, частота выходных импульсов при
. (1.14.7)
Выше сказано, что сброс счетчика PWMTC осуществляется при сов-
падении его содержимого с пороговым регистром PWMMR0. На самом деле
есть возможность отслеживать его совпадение с любым из пороговых реги-
стров и выполнять одно из трех действий: сброс счетчика, остановка счета,
запрос прерывания.
Рассмотрим следующую ситуацию. Пусть счетчик ;
. Через 10 тактов их значения совпадут, что приведет к по-

58
явлению нового импульса. Если в этот момент увеличить частоту путем за-
писи в PWMMR0, например, числа 900, то PWMTC окажется больше
PWMMR0. Формирование нового импульса не произойдет до тех пор, пока
PWMTC не достигнет максимального значения , сбросится в ноль и
затем достигнет значения 800, что займет более 70 секунд. На это время ра-
бота ШИМ будет заблокирована.
Для предотвращения такого сбоя при изменении пороговых регистров
имеется система регистров-защелок. При этом сравнение счетчика осуществ-
ляется не с пороговыми регистрами, а с регистрами защелками, которые об-
новляются одновременно и только в начале каждого периода ШИМ. Подроб-
ней см. ниже (регистр PWMLER в разделе 1.14.3 и раздел 1.14.4).
1.14.3 Регистры управления ШИМ
Схема управляющих регистров показана на рисунке 1.14.4.
Регистры PWMTC, PWMPC — счетчик ШИМ и предварительный
делитель счетчика (соответственно). Как правило, ни в чтении, ни в записи
этого регистра необходимости не возникает.
Регистр PWMPR — регистр порогового значения для предваритель-
ного делителя, фактически, коэффициент деления частоты .
Регистр PWMTCR служит для управления счетчиком ШИМ.
● Бит 0 (CNTEN). Бит включения счетчика ШИМ. Для работы ШИМ
должен быть установлен в единицу.
● Бит 1 (RESET). Установка единицы приводит к сбросу счетчика
ШИМ. Счет блокируется, если бит равен единице.
● Бит 3 (PWMEN). Включение синхронного режима. В данном режи-
ме при изменении пороговых регистров (PWMMR0–PWMMR6) их содержи-
мое будет обновлено только в начале следующего периода. Изменение раз-
решается через регистр PWMLER (см. ниже).
Внимание! Запись в пороговый регистр PWMMR0 должна предше-
ствовать установке данного бита.
Регистр PWMMCR
● Биты 0–2 (MR0I–MR6I, MR0R–MR6К, MR0S–MR6S) задают реак-
цию на совпадение счетчика с каждым из пороговых регистров PWMMR0–
PWMMR6 (в соответствии с таблицей 1.14.1).
Регистр PWMPCR — управление начальной фазой.
● Биты 2–6 (PWMSEL2–6). Установка единицы в каждом разряде раз-
решает регулировку начальной фазы выходной линии ШИМ с тем же номе-
ром. На рисунке 1.14.1 выход Y соответствующего мультиплексора

Таблица 1.14.1 – Реакции на совпадение счетчика с PWMMRx


Управляющие биты Назначение
MR0I–MR6I Разрешить/запретить запрос прерывания
MR0R–MR6R Разрешить/запретить сброс таймера-счетчика в ноль
MR0S–MR6S Разрешить/запретить остановку счета

59
PWMTCR – настройка счетчика ШИМ
15 8 7 4 3 2 1 0
M ET N
T
PW EN ES C
EN
R
ВКЛ
Вкл. защелки пороговых регистров Сброс

PWMMCR – настройка схемы совпадения


23 21 20 19 18 17 16 15 14 13 12
6S 6R 6I 5S 5R 5I 4S 4R 4I
R R R R R R R R R
M M M M M M M M M

6 5 4
11 10 9 8 7 6 5 4 3 2 1 0
3S 3R 3I 2S 2R 2I 1S 1R 1I 0S 0R 0I
R R R R R R R R R R R R
M M M M M M M M M M M M

3 2 1 Сброс
Прерывание
Остановка
PWMPCR – настройка ШИМ
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
M M M M M M M M M M M
PW N6 PW N5 PW N4 PW N3 PW N2 PW N1 PW EL6 PW EL5 PW EL4 PW EL3 PW EL2
E E E E E E S S S S S
Включение каналов Вкл. управление начальной фазой

PWMLER – настройка регистров-защелок


15 8 7 6 5 4 3 2 1 0
T6 AT5 AT4 T3 AT2 AT1 AT0
LA L L LA L L L
Разрешение обновления регистров-защелок

PWMIR – флаги прерываний


15 11 10 9 8 7 4 3 2 1 0
6 5 4 3 1 2
0
M I M I M I M I M I M I M I
PW MR PW MR PW MR PW MR PW MR PW MR PW MR

Флаги прерываний от каналов ШИМ

Рисунок 1.14.4 – Схема регистров управления модулем ШИМ


соединяется с входом D1. Сброс данного бита в ноль отключает регулировку
начальной фазы соответствующего канала (начальная фаза равна 0 радиан),
выход Y соединяется с входом D0. Временные диаграммы работы ШИМ в
двух режимах показаны на рисунках 1.14.1 и 1.14.2.
Регистры PWMLER — синхронный режим.
● Биты 0–6 (LAT0–6). В синхронном режиме ( ) установ-
ка единиц разрешает копирование соответствующих программно доступных
пороговых регистров PWMMR0–6 в регистры защелки, воздействующие на
схемы совпадения. Изменение произойдет в начале следующего периода
ШИМ. Данный регистр необходим для обеспечения одновременного измене-
ния всех семи пороговых значений.
Регистры PWMIR — управление прерыванием.
● Биты 0–3, 8–10 (PWM0MRI–PWM6MRI). Флаги прерываний, уста-
навливаемые в единицу аппаратно при совпадении счетчика ШИМ с соответ-
ствующими пороговыми регистрами (PWMMR0–PWMMR6).

60
1.14.4 Порядок настройки ШИМ
1. Задать режим PWM для портовых линий, которые послужат выхо-
дами ШИМ через регистры PINSEL0, PINSEL1 (раздел 1.9.3).
2. Задать частоту импульсов путем записи в регистр PWMMR0 значе-
ния, рассчитанного по формуле (1.14.1) или (1.14.7).
3. Задать длительности импульсов и (или) начальные фазы с помощью
регистров PWMMR1–6. Необходимо устанавливать значения только тех ре-
гистров, которые связаны с задействованными выходами ШИМ. Использо-
вать выражения (1.14.2) при нулевой начальной фазе, выражения (1.14.3–
1.14.5) при регулируемой начальной фазе.
4. Произвести настройку счетчика модуля ШИМ через регистр
PWMTCR. Необходимо установить бит включения счетчика; рекомендуется
разрешить работу защелок. Следовательно, типовым значением является
.
5. Включить необходимые выходы ШИМ и выбрать режим управле-
ния начальной фазой для каждого канала через регистр PWMPCR.
После того как настройка произведена, генерирование прямоугольных
импульсов с заданными параметрами будет продолжаться, не требуя никако-
го участия со стороны программы. Изменение параметров сигнала (частоты,
начальной фазы, скважности) возможно в любой точке программы путем
следующей последовательности действий:
а) запись новых значений в регистры PWMMR0–6;
б) установка битов разрешения обновления защелок в регистре PWM-
LER. Запись единиц должна производиться одной командой.
Сброс регистра PWMLER в ноль выполняется автоматически.
Остановка ШИМ возможна путем сброса бита CNTEN в регистре
PWMTCR. Рекомендуется той же командой сбросить таймер установкой бита
RESET в том же регистре.
В разделе 3.6 приведены выражения для расчета пороговых значений,
позволяющие организовать ШИМ, частотное и фазовое управление.

1.15 Аналого-цифровые преобразователи


1.15.1 Краткие сведения о встроенных АЦП
Микроконтроллер LPC2148 оснащен двумя встроенными аналого-
цифровыми преобразователями (АЦП) поразрядного уравновешивания. Ос-
новные параметры встроенных АЦП приведены в таблице 1.15.1.
Каждый АЦП с помощью аналогового мультиплексора позволяет вы-
бирать один из нескольких сигналов, поступающих одновременно на анало-
говые входы. Для АЦП 0 таких входов шесть (AD0.1–4, AD0.6.–7), для АЦП
1 — восемь (AD1.0–7). В остальном АЦП идентичны.
Входы АЦП совмещены с цифровыми портовыми линиями. Как было
показано в разделе 1.9.3 выбор функции, выполняемой входом, осуществля-
ется через регистры PINSEL0 и PINSEL1.

61
Таблица 1.15.1 – Основные параметры АЦП МК LPC2148
Разрядность, бит 3–10
Мин. время преобразования при разрядности 10 бит, мкс 2,44
Макс. производительность при разрядности 10 бит, преобр./с 409 090
Мин. время преобразования при разрядности 3 бит, мкс 0,89
Макс. производительность при разрядности 3 бит, преобр./с 1 125 000
Число мультиплексируемых аналоговых входов (АЦП 0/1) 6/8
Диапазон измеряемого напряжения 0–3,3 В
Имеется рекомендация, в соответствии с которой для сохранения точ-
ности выходное сопротивление источника измеряемого напряжения не
должно превышать 40 кОм.
1.15.2 Общие рекомендации по использованию АЦП
Взаимодействие с аналого-цифровым преобразователем включает три
основных действия: запуск АЦП, ожидание готовности результата преобра-
зования, считывание и обработка результата. Существует несколько вариан-
тов алгоритмической реализации взаимодействия с аналого-цифровым пре-
образователем. Основное отличие состоит в способе запуска АЦП. Запуск
может осуществляться:
а) программным путем;
б) по совпадению счетчика с пороговым значением;
в) внешним электрическим сигналом;
г) окончанием предыдущего преобразования.
В таблице 1.15.2 дана краткая характеристика перечисленных спосо-
бов. Ниже будут рассмотрены все способы взаимодействия с АЦП, даны ре-
комендации по выбору каждого варианта, а также предложены шаблоны про-
граммного кода для их реализации.
Программный запуск АЦП реализуется командой, выполняемой при
наступлении некоторого события. Таким событием может быть нажатие
кнопки, получение команды от компьютера, истечение интервала времени и
т. п. Единственным преимуществом программного запуска является то, что
он не требует привлечения других ресурсов МК, таких как таймеры-
счетчики.
При решении большинства задач желательна строгая периодичность
запуска АЦП, а в некоторых случаях совершенно необходима. Могут быть
названы следующие причины. Во-первых, большинство методов цифровой
обработки сигналов разработаны для случая периодической дискретизации.
Для их применения необходимо, чтобы дискретные отсчеты напряжения бы-
ли получены через равные интервалы времени. Нарушение периодичности
неизбежно приведет к возникновению дополнительного шума квантования.
Во-вторых, одним из распространенных способов борьбы с некото-
рыми видами помех является синхронизация частоты квантования с частотой
измеряемого процесса или с частотой питающей сети.

62
Таблица 1.15.2 — Способы запуска АЦП в микроконтроллере LPC2148
Способ
Преимущества Недостатки Применение
запуска АЦП
Программный Не задействует ап- Непериодиче- Измерение посто-
паратных ская дискрети- янного или медлен-
узлов МК зация но меняющегося
напряжения с пери-
одом дискретиза-
ции от 0,1 с и выше
От таймера Периодическая дис- Задействован Широкий круг за-
кретизация; не тре- таймер дач цифровой обра-
бует участия про- ботки сигналов
граммы
Внешним Синхронизация Задействован Системы импульс-
сигналом внешним вывод МК; тре- но-фазового управ-
процессом бует источника ления, цифровая
синхросигнала обработка сигналов
Непрерывное Периодическая дис- Ограниченные Цифровая обработ-
преобразова- кретизация; не за- возможности ка сигналов с высо-
ние действует узлов выбора частоты кими частотами
МК; мин. задержки квантования квантования
между преобр.
Программный запуск АЦП практически не позволяет обеспечить
строгую периодичность запуска АЦП, а значит и периода дискретизации
сигнала. Причина заключается в том, что выполнение каждой итерации про-
граммы занимает различное время, например, из-за ветвлений с различным
числом команд в ветвях. Дополнительные временные задержки создают пре-
рывания от разных источников.
В связи с этим, программный запуск применять не рекомендуется.
Программный запуск допустим лишь в случаях, когда нет необходимости в
строгой периодичности дискретизации, например при измерении постоянно-
го или медленно меняющегося напряжения и притом, что нежелательно ис-
пользовать один из таймеров-счетчиков специально для формирования сиг-
нала запуска АЦП.
Отметим, что команда запуска АЦП, помещенная в процедуре обра-
ботки прерывания от таймера также не обеспечит строгой дискретизации.
Точнее обеспечит периодичность с некоторой погрешностью. Погрешность
возникает вследствие неизбежных временных задержек, которые имеют слу-
чайный характер (см. раздел 1.11.8).
Автоматический запуск при достижении таймером заданного по-
рогового значения. Этот способ можно назвать наиболее универсальным и
пригодным для решения большинства практических задач. Сигнал, формиру-
емый схемой совпадения таймера-счетчика, приведет к запуску без участия
программы. Запуск осуществляется строго периодически. Прерывание от

63
таймера при этом использовать не требуется. Это является еще одним пре-
имуществом — отсутствуют затраты процессорного времени на обработку
прерывания и команды запуска АЦП. Имеется единственный недостаток —
использование важного аппаратного ресурса — таймера-счетчика.
Считывание результата можно организовать путем программного опро-
са, либо с помощью прерывания от АЦП. Второй вариант предпочтителен.
Запуск внешним электрическим сигналом. Внешний пуск обеспе-
чивает синхронизацию процесса квантования с измеряемым процессом, что в
некоторых задачах совершенно необходимо, а в ряде других случаев, как
упоминалось выше, позволяет устранить некоторые составляющие случай-
ной погрешности. Использование одного из выводов МК, является несуще-
ственным недостатком. Существенную трудность составляет необходимость
построения аппаратной схемы синхронизации.
Непрерывная работа. В таком случае также обеспечивается строгая
периодичность, однако, доступна фиксированная сетка частот тактирования
АЦП и соответствующих частот квантования. При этом не предоставляется
возможность выбирать период квантования с шагом в один машинный цикл
МК. Доступный шаг гораздо больше. Следует отметить, что такой способ за-
пуска может гарантировать работу АЦП без простоев, то есть позволяет до-
биться наибольшей его производительности.
1.15.3 Управляющие регистры
Рассмотрим регистры, отвечающие за настройку аналого-цифровых
преобразователей (рисунок 1.15.1).
Регистры ADxCR
● Биты 0–7 (SEL) отвечают за выбор каналов АЦП. Каждому биту со-
ответствует канал с тем же номером AD0.0–AD0.7 (АЦП 0) или
AD1.0–AD1.7 (АЦП 1). Одновременная установка нескольких битов допус-
кается только в режиме автоматического сканирования каналов (см. ниже).
● Биты 8–15 (CLKDIV) служат для выбора тактовой частоты АЦП.
Тактовая частота определяется по формуле
, (1.15.1)
где — тактовая частота периферийных устройств, которая может быть
равна целой, половине или четверти тактовой частоты МК (раздел 1.7.2).
Значение не должно превышать 4,5 МГц.
● Бит 16 (BURST). Единица в данном разряде переводит АЦП в ре-
жим автоматического сканирования каналов. Производится поочередное
преобразование сигналов в каналах, выбранных битами SEL. В этом режиме
биты START (см. ниже) должны быть равны нулю.
● Биты 17–19 (CLKS) имеют значение только в режиме автоматиче-
ского сканирования каналов ( ). Эти биты определяют время пре-
образования и разрядность результата. Значению соответствует
время преобразования 11 тактов, разрядность 10 бит. С увеличением на еди-
ницу CLKCS, на единицу уменьшается время преобразования и разрядность.

64
ADxCR – настройка АЦП
31 28 27 26 24 23 22 21 20 19 17 16 15 8 7 0
E N ST
G START CLKS R CLKDIV SEL
ED PD BU
Способ запуска ВКЛ Число тактов Делитель частоты Выбор каналов АЦП ADx.7:0
Фронт/срез
в непр. режиме
Непрерывное преобразование
ADGSR – запуск всех АЦП
31 28 27 26 24 23 20 19 17 16 15 8 7 0
E ST
G START R
ED BU
Способ запуска
Фронт/срез
Непрерывное преобразование
ADxGDR – общий результат
31 30 29 28 27 26 24 23 16 15 8 7 6 5 0
-
E VE
N CHN RESULT
O O UN
D R
Готов Номер канала Результат аналого-цифрового преобразования
Потеря результата

ADxDRx – результат для канала


31 30 29 28 27 24 23 16 15 8 7 6 5 0
-
E VE
N RESULT
O O UN
D R
Готов Результат аналого-цифрового преобразования
Потеря результата

ADxSTAT – состояние
31 24 23 20 19 17 16 15 8 7 0
T
IN OVERUN7:0 DONE7:0
AD
Потеря результата каналов ADx.7:0 Готовность результата каналов ADx.7:0
Флаг прерывания
ADxINTEN – управление прерыванием
31 24 23 16 15 12 11 9 8 7 0
-
G N
AD TE ADINTEN7:0
IN
Разрешение прерываний от каналов ADx.7:0
Разр. прер. от всех каналов

Рисунок 1.15.1 – Схема регистров для управления аналого-цифровыми преобразователями

65
Таблица 1.15.3 – Режимы запуска АЦП
START Режим запуска АЦП
000 Преобразования не выполняются
001 Запустить преобразование немедленно
010 Запуск внешним сигналом на входе P0.16
011 Запуск внешним сигналом на входе P0.22
100 Запуск сигналом MAT0.1
101 Запуск сигналом MAT0.3
110 Запуск сигналом MAT1.0
111 Запуск сигналом MAT1.1
Значению соответствует время преобразования 4 такта, разряд-
ность 3 бита. При разрядность составляет 10 бит, преобразова-
ние занимает 11 тактов независимо от состояния CLKS.
Минимальное время преобразования определяется выражением
(мкс), (1.15.2)
где — разрядность АЦП.
● Бит 21 (PDN) включает (1) и отключает (0) АЦП. Должен быть
установлен в единицу.
● Биты 24–26 (START) служат для выбора способа запуска АЦП (таб-
лица 1.15.3). Эти биты должны быть равны нулю в режиме автоматического
сканирования каналов ( ).
Следует понимать принципиальное отличие запуска внешним сигна-
лом на входах P0.16 и P0.22 от запуска сигналами MATx.x, которые форми-
руются внутренней схемой совпадения встроенного таймера-счетчика и мо-
гут не быть подключенными к внешним выводам МК (раздел 1.13.1).
● Бит 27 (EDGE). Выбор нарастающего (0) или спадающего (1) фрон-
та сигнала запуска АЦП при .
Регистр ADGSR позволяет одновременно настроить запуск двух
АЦП. Значения битов BURST, START, EDGE абсолютно аналогичны реги-
страм ADxCR. Остальные биты должны задаваться отдельно для каждого
АЦП через регистр ADxCR.
Регистр ADxGDR. Результат аналого-цифрового преобразования счи-
тывается из регистров AD0GDR и AD1GDR (ADxGDR).
● Биты 6–15 (RESULT) содержат десятиразрядный результат аналого-
цифрового преобразования. Входное напряжение АЦП связано с результатом
АЦП и опорным напряжением, подключенным к входу Vref МК, выражением
. (1.15.3)
● Биты 24–26 (CHN) содержат двоичный номер канала АЦП от 0 (000)
до 7 (111), для которого получен результат, хранимый в разрядах RESULT.
● Бит 30 (OVERUN). Бит равен единице, если в режиме автоматиче-
ского сканирования каналов ( ) результат АЦП потерян, то есть не

66
был считан до того, как оказался перезаписан следующим результатом. Бит
очищается при чтении регистра ADxGDR.
● Бит 31 (DONE). Бит равен единице, если аналого-цифровое преобра-
зование завершено. Этот бит информирует о готовности результата. Бит
очищается при чтении РСФ ADxGDR.
Регистр ADxGDR. В то время как регистр ADGSR хранит результата
любого последнего преобразования, независимо от использованного канала,
регистры AD0DR0–7, AD1DR0–7 (ADxDRx) хранят результаты для каждого
канала в отдельности. Значения их битов идентичны битам регистра ADGSR,
за исключением отсутствующих битов CHN.
Регистр ADxSTAT. Флаги готовности и потери данных всех каналов
объединены в регистрах AD0STAT и AD1STAT (ADxSTAT).
● Биты 0–7 (DONE0–7). Биты готовности результата преобразования
сигналов в каналах 7–0. В отличие от своих копий в регистрах ADxDRx не
очищаются при чтении регистра.
● Биты 8–15 (OVERUN0–7). Биты потери результата преобразования
сигналов в каналах 0–7. При чтении регистра значение битов сохраняется.
● Бит 16 (ADINT). Флаг прерывания от АЦП. Данный разряд устанав-
ливается в единицу и инициирует прерывание в случае, если равен единице
один из битов готовности DONE0–7, при условии что прерывание для соот-
ветствующего канала разрешено (см. ниже регистр ADxINTEN).
Регистр ADxINTEN содержит биты разрешения прерывания по го-
товности результата АЦП.
● Биты 0–7 (ADINTEN0–7). Биты позволяют разрешить (1) или запре-
тить (0) прерывание, возникающее при завершении преобразования сигнала
на каждом из восьми каналов АЦП.
● Бит 8 (ADGNTEN). Установка этого бита в единицу разрешает пре-
рывание от АЦП независимо от того, для какого канала получен результат.
Для индивидуального выбора каналов следует записать ноль. При сбросе
этот бит установлен в единицу.
1.15.4 Порядок настройки АЦП
1. Выполнить настройку АЦП через регистр ADxCR. При установке
значений отдельных битов предлагается следующий порядок действий.
а) Выбрать способ запуска АЦП, принимая во внимание сведения в
таблицы 1.15.3. Записать значение битов START и BURST в соответствии с
выбранным способом запуска. Записать значение бита EDGE, если АЦП за-
пускается сигналом от таймера или внешним сигналом. Если используется
программный запуск, необходимо нулевое значение START.
б) Записать единицу в разряд PDN.
в) Если требуемое по заданию время преобразования меньше 2,44 мкс,
выбрать разрядность и время преобразования, с учетом выражения (1.15.2).
г) Выбрать тактовую частоту АЦП, так чтобы время преобразования
не превышало требуемого по заданию, но не более 4,5 МГц. Рассчитать зна-
чение битов CLKDIV по формуле (1.15.1).

67
д) Установить единицы в разряды SEL, соответствующие используе-
мым каналам. Если аппаратное сканирование каналов не используется, дол-
жен быть выбран единственный канал.
Приведем пример настройки аналого-цифрового преобразования.
AD0CR=0x00207F02;
Данная команда обеспечивает включение АЦП (бит 21), с делителем частоты
1:128 (биты 8–15), с использованием канала 1 (биты 0–7).
2. Если предполагается использование прерывания по готовности
АЦП, установить каналы, для которых будет вырабатываться прерывание
(регистр ADINTEN). Если выборочная настройка по каналам не требуется
или прерывание от АЦП не используется, оставить регистр ADINTEN без
изменений.
3. Подключить портовые линии МК, выполняющие функцию аналого-
вых входов, через регистры PINSEL0 и PINSEL1 (рисунки 1.9.1, 1.9.2).
4. Если необходимо прерывание от АЦП, настроить контроллер пре-
рываний через регистры VICVectAddr0–15, VICVectCntl0–15 и VICIntEnable.
1.15.5 Программный запуск аналого-цифрового преобразователя
Программный запуск АЦП осуществляется командой логического
сложения регистра ADxCR с числом 0x01000000. Это обеспечит установку
двоичного кода 001 в биты START, не влияя на остальные биты.
AD0CR|=0x01000000;
1.15.6 Запуск аналого-цифрового преобразователя по таймеру
Для периодического преобразования необходимо:
1. Настроить таймер и схему совпадения для формирования интерва-
лов времени, так как это было описано в разделе 1.13.5.
2. Разрешить формирование схемой совпадения установку одного из
сигналов EMC0–3 (регистр TxEMR, биты EMC0–3). При этом прерывание от
таймера разрешать не требуется.
3. При обнаружении готовности АЦП сбросить в ноль соответствую-
щий флаг в регистре TxEMR (биты EM0–3), например, командой (для тайме-
ра 0 и сигнала EMC1)
T0EMR&=0xFFFFFFFD;
1.15.7 Программный опрос готовности АЦП
Практически могут быть предложены два варианта. Отличие состоит в
том, что в первом случае программа МК «зависает» на время преобразова-
ния, что крайне нежелательно. Однако может считаться допустимым упро-
щением алгоритма в случаях, когда время преобразования пренебрежимо ма-
ло в данной конкретной специфической задаче.
Проверка готовности АЦП через опрос флага «с зависанием»
while ((AD0STAT & 0x00000002)==0) ;
ADRes=AD0DR0;
... // Обработка

68
или
do ADCRes=AD0DR0;
while ((AD0STAT & 0x00000002)==0) ;
... // Обработка
Проверка готовности АЦП без «зависания»
if ((AD0STAT & 0x00000002)!=0)
ADRes=AD0DR0;
...; // Обработка
или
ADCRes=AD0DR0;
if ((ADCRes & 0x00000002)!=0)
{
...; // Обработка
}
Подразумевается, что эти команды будут помещены в вечный цикл, чем
обеспечится их периодическое и частое выполнение.
Переменная ADRes должна быть объявлена как целое без знака.
unsigned int ADCRes;
1.15.8 Опрос готовности АЦП по прерыванию
Наиболее эффективным и универсальным можно считать считывание
и обработку результата, вынесенную в процедуру обработки прерывания.
Для разрешения прерывания по готовности АЦП необходимо:
1. Если требуется запрашивать прерывание по завершении преобразо-
вания для нескольких каналов выборочно, произвести соответствующую
настройку через регистр ADxINTEN. Если прерывание должно происходить
при каждом преобразовании, этот пункт пропустить.
2. Настроить систему прерываний с помощью регистров
VICVectAddr0–15, VICVectCntl0–15 и VICIntEnable.
3. Процедура обработки прерывания должна содержать команду сбро-
са в ноль сигнала EMCx, если прерывание вызвано схемой совпадения тай-
мера (раздел 1.15.4).
1.15.9 Считывание и масштабирование результата АЦП
Результирующий код аналого-цифрового преобразования может быть
считан из регистра ADxDRx путем наложения маски и сдвига на шесть раз-
рядов вправо:
N=(AD0DR0 & 0xFFC0) >> 6;
или
N=((AD0DR0 >> 6) & 0x3FF);
Наложение маски (логическое умножение на 0xFFC0) выделяет результат
АЦП, сбросив все остальные биты регистра ADxDRx в ноль. Сдвиг вправо
удаляет незначащие нули. При этом будет получен результат АЦП «как есть»
от 0 до 1023, который может быть сохранен в целочисленную переменную N.

69
На практике, обычно, требуется перейти от безразмерного результата
АЦП к физической величине, которой он соответствует. Для этого выполня-
ется масштабирование.
Код АЦП связан с напряжением, приложенным непосредственно к
входу формулой (1.15.3). Повторим ее с другими обозначениями
,
где — опорное напряжение, В; — входной код АЦП.
Соответственно, масштабирующий множитель
. (1.15.4)
Очевидно, что этот множитель при имеет смысл веса единицы
младшего разряда АЦП.
Теперь примем во внимание, что измерительный канал может иметь
не единичный коэффициент передачи . Тогда вес младшего разряда
. (1.15.5)
Заметим, что связывает входное напряжение АЦП с физической величи-
ной, возможно неэлектрической. Поэтому может иметь размерность.
Если числовое значение не равно степени двух, то вес младше-
го разряда оказывается «длинной» дробью. В то же время индицируемый ре-
зультат измерения должен быть округлен до разумного числа десятичных
разрядов. Практически это приводит к увеличению шума квантования.
Несмотря на то, что коэффициент является свойством аппаратных
узлов измерительного канала, обычно им можно варьировать. Имеется также
некоторая свобода в выборе величины источника опорного напряжения. Так
можно добиться того, что вес младшего разряда имеет вид
, где — цифра от 1 до 9, а — целое число. Тогда индикация в де-
сятичной системе счисления возможна без округления результата измерения.
Сохранение результата в формате с плавающей точкой может выпол-
няться командой, подобной следующей
N=(AD0DR0 & 0xFFC0)*Vref/С/65536.0;
Имеется в виду, что переменная N объявлена как float или double;
Vref — переменная или константа, равная опорному напряжению; C —
коэффициент передачи измерительного канала.
Поясним значение множителя Vref/65536.0. Результат оказывается
смещен на 6 разрядов влево, поскольку справа он дополнен шестью нулевы-
ми двоичными разрядами. С учетом этого обстоятельства и формулы (1.15.5)
находим масштабирующий множитель .

1.16 Цифро-аналоговый преобразователь


МК LPC2148 имеет встроенный 10-разрядный цифро-аналоговый
преобразователь (ЦАП) с временем установления выходного напряжения
1 мкс. Это позволяет формировать однополярные сигналы с переменной со-
ставляющей звуковой частоты (по крайней мере, до 20 кГц) при сравнитель-

70
но малом шуме квантования. Напряжение формируется на линии AOUT.
Диапазон выходного напряжения ЦАП от 0 В до опорного напряжения, под-
ключенного к контакту Vref.
1.16.1 Регистр управления ЦАП
Регистр DACR. Управление ЦАП осуществляется с помощью един-
ственного регистра (рисунок 1.16.1).
● Биты 6–15 (VALUE). Код выходного напряжения ЦАП. Значение
разрядов VALUE связано с напряжением на выходе AOUT выражением
. (1.16.1)
● Бит 16 (BIAS). Бит определяет время установления выходного
напряжения ЦАП (таблица 1.16.1).
Таблица 1.16.1 – Управления временем установления ЦАП
BIAS Время установления Ток, потребляемый модулем ЦАП
0 1 мкс 700 мкА
1 2,5 мкс 350 мкА
DACR – настройка ЦАП
19 17 16 15 8 7 6 5 4 3 0
AS

VALUE
BI

Время установки Код цифро-аналогового преобразования

Рисунок 1.16.1 – Схема регистров управления цифро-аналоговым преобразователем


1.16.2 Рекомендации по применению ЦАП
Настройка ЦАП сводится лишь к настройке режима работы порта че-
рез регистр PINSEL1 (код 01 в разрядах 18–19) и выбора времени установле-
ния ЦАП через бит BIAS. Осциллограммы, иллюстрирующие время установ-
ки ЦАП при изменении кода от нуля до максимума, показаны на рисунке
1.16.2. Изменение выходного напряжения выполняется путем записи кода в

Рисунок 1.16.2 – Осциллограммы сигнала ЦАП при изменении кода от нуля


до максимума. Вверху BIAS = 0, внизу BIAS = 1

71
разряды VALUE. Расчет кода выполняется в соответствии с выражением (1).
Средства, сигнализирующие о завершении переходного процесса, отсут-
ствуют. В программе следует предусматривать временные задержки, необхо-
димые для установления выходного напряжения.
О применении ЦАП для формирования аналоговых сигналов разной
формы см. раздел 3.7.

1.17 Последовательный синхронный приемо-передатчик SPI


1.17.1 Назначение и основы функционирования интерфейса SPI
Интерфейс SPI (Serial Peripheral Interface) представляет собой про-
стейший последовательный синхронный интерфейс, использующий три про-
водника:
а) тактовый сигнал SCK (Serial Clock);
б) MISO (Master In Slave Out) — вход ведущего, выход ведомого;
в) MOSI (Master Out Slave In) — выход ведущего, вход ведомого.
Основу приемопередатчика SPI составляет пара сдвиговых регистров
и генератор синхроимпульсов. SPI обеспечивает полнодуплексный режим, то
есть возможность одновременного приема и передачи данных. Интерфейс
характеризуется сравнительно высокой скоростью передачи данных (десятки
Мбит/с). Адресация не поддерживается, так же как и контроль ошибок.
Устройство, подключенное к интерфейсу SPI, может быть ведущим
(master) или ведомым (slave). Ведущее устройство является источником так-
товых импульсов, а ведомое синхронизируется тактовыми импульсами ве-
дущего. При соединении более двух устройств каждому ведомому поступает
сигнал выбора, имеющий активный низкий уровень.
Основное назначение — передача данных между цифровыми про-
граммируемыми микросхемами. Простой пример применения SPI — загрузка
данными сдвигового регистра. В этом случае МК работает в режиме ведуще-
го, а регистр является ведомым, поскольку не содержит генератора тактовых
импульсов. Здесь достаточно всего двух линий МК: синхронизация SCK и
выход ведущего MOSI.
Данный раздел посвящен модулю, обозначаемому в инструкции
«SPI0». МК LPC2148 оснащен также синхронным последовательным портом
SSP (Synchronous Serial Port), совместимым с интерфейсами SPI, SSP и Mi-
crowire (обозначается SPI1). Модуль SSP в данном разделе не рассматривается.
1.17.2 Управляющие регистры
Схема управляющих регистров показана на рисунке 1.17.1
Регистр S0SPCR — основной управляющий регистр.
● Бит 2 (BITEN). Установка данного бита в единицу разрешает управ-
ление разрядностью. Нулевое значение устанавливает разрядность 8 бит.
● Бит 3 (CPHA). При равенстве единице включает сдвиг фаз на один
такт между тактовым сигналом и данными. В большинстве случаев требуется
сохранить нулевое значение (по умолчанию). Влияние бита на передаваемый
сигнал показано на рисунке 1.17.2.
72
I2CxCONSET – установка состояния I2C
15 8 7 6 5 4 3 2 1 0

EN STA STO SI AA
Старт/Стоп Подтвержд.
ВКЛ
Флаг прерывания
I2CxCONCLR – сброс состояния I2C
15 8 7 6 5 4 3 2 1 0

EN STA SI AA
Старт Подтвержд.
ВКЛ
Флаг прерывания
I2CxSTAT – состояние I2C
15 8 7 3 2 0

STATUS
Состояние I2C

Рисунок 1.17.1 – Схема регистров управления приемопередатчиком SPI


● Бит 4 (CPOL). Задает активный логический уровень синхроимпуль-
сов на линии SCK. соответствует высокому активному уровню,
соответствует низкому активному уровню (рисунок 1.17.2).

Рисунок 1.17.2 – Осциллограммы двоичного сигнала 01010101 (0x55), передаваемого


по SPI, для разных режимов фазы (CPOL) и полярности синхроимпульсов (CPHA)
● Бит 5 (MSTR). Выбор режима: 0 — ведомый, 1 — ведущий.
● Бит 6 (LSBF). Определяет порядок передачи битов: 0 — первым пе-
редается старший бит; 1 — первым передается младший бит.
● Бит 7 (SPIE). Бит разрешения прерывания от модуля SPI. Установка
единицы разрешает формирование запроса прерывания при завершении при-
ема/передачи или обнаружении конфликта.
● Биты 8–11 (BITS). Биты настройки разрядности (числа передавае-
мых бит в пакете). Для настройки разрядности необходимо установить бит

73
. Число передаваемых бит совпадает с двоичным кодом BITS.
соответствует пакету 8 бит, — 15 бит,
— 16 бит.
Регистр S0SPDR. Двунаправленный регистр передачи данных. Запись
в регистр приводит к началу передачи данных по SPI. Повторная запись до-
пускается только после завершения передачи. На время передачи запись в ре-
гистр блокируется.
Чтение регистра дает принятые данные. Отсутствующие старшие раз-
ряды заполнены нулями.
Регистр S0SPCCR. Делитель частоты для синхросигнала SPI. Диапа-
зон допустимых значений 8–254. В режиме ведущего на линии SCK будет
установлена частота
. (1.17.1)
Внимание! Значение S0SPCCR должно быть четным и не менее восьми. По-
этому частота не может превысить МГц.
Частота равна битовой скорости передатчика (бит/с). Например,
популярный сдвиговый регистр 74HC595 допускает частоту синхроимпуль-
сов МГц (в зависимости от производителя).
Регистр S0SPSR отражает состояние приемопередатчика SPI.
● Бит 3 (ABRT). Отмена передачи. Бит устанавливается в единицу, ес-
ли в режиме ведомого передача прерывается переходом в пассивное состоя-
ние сигнала SSEL. Бит сбрасывается в ноль при чтении регистра.
● Бит 4 (MODF). Ошибка режима. Бит устанавливается в единицу, ес-
ли в режиме ведущего сигнал SSEL перешел в активное состояние, сигнали-
зируя о том, что на линии есть еще один ведущий. Бит сбрасывается в ноль
после чтения данного регистра и записи регистра S0SPCR.
● Бит 5 (ROVR). Потеря данных при чтении. Бит устанавливается в
единицу, если новый пакет был принят до того, как считан предыдущий из
регистра данных S0SPDR. Бит сбрасывается в ноль при чтении регистра.
● Бит 6 (WCOL). Конфликт записи. Бит устанавливается в единицу,
если новый пакет был записан в регистр данных S0SPDR во время передачи.
Бит сбрасывается в ноль после чтения данного регистра и доступа к регистру
данных S0SPDR.
● Бит 7 (SPIF). Значение 1 индицирует готовность после передачи.
Флаг сбрасывается в ноль после двух действий: чтения регистра S0SPSR и
обращению к регистру данных S0SPDR.
Регистр S0SPINT содержит единственный бит — запрос прерывания.
● Бит 0 (SPINT). Флаг запроса прерывания. Флаг сбрасывается в ноль
путем записи в него единицы.
1.17.3 Передача и прием данных в режиме ведущего
1. Настроить портовые линии на режим SPI через регистры PINSEL0,
PINSEL1. В простейшем случае потребуются лишь две линии SCK и MOSI.

74
2. Настроить скорость обмена данными, задав делитель тактовой ча-
стоты через регистр S0SPCCR (1.17.1). Требуется принимать во внимание
допустимую частоту для других устройств, подключенных к шине SPI.
3. Настроить модуль SPI через регистр S0SPCR. Обычно требуется
лишь включить режим ведущего (бит MSTR) и задать число передаваемых
бит (разряды BITEN и BITS).
4. При необходимости включить прерывание от модуля SPI через ре-
гистры VICVectAddr0, VICVectCntl0 и VICIntEnable.
Передача инициируется путем записи в регистр S0SPDR передавае-
мых данных.
Готовность приемопередатчика может быть проверена путем опроса
бита SPIF (бит 7) в регистре S0SPSR. Единица обозначает завершение пере-
дачи. Альтернатива — использование системы прерываний.
Передача данных приводит к формированию синхроимпульсов и од-
новременно сопровождается приемом последовательных битов с входа
MISO. Если прием задействован, то после распознавания готовности пере-
датчика принятый пакет может быть считан из того же регистра S0SPDR. В
режиме ведущего осуществить прием без передачи невозможно, поскольку
только передача сопровождается формированием синхроимпульсов.
1.17.4 Передача и прием данных в режиме ведомого
1. Настроить портовые линии на режим SPI через регистры PINSEL0,
PINSEL1. В простейшем случае потребуются лишь одна линия: MOSI (для
приема) или MISO (для передачи).
2. Настроить модуль SPI через регистр S0SPCR. Обычно требуется
лишь включить режим ведомого (бит MSTR) и задать число передаваемых
бит (биты BITEN и BITS).
3. При необходимости включить прерывание от модуля SPI через ре-
гистры VICVectAddr0, VICVectCntl0 и VICIntEnable.
Как и в режиме ведущего передача инициируется путем записи пере-
даваемых данных в регистр S0SPDR. Передача не является обязательной. Ес-
ли требуется только прием данных, то достаточно только контроля готовно-
сти приемопередатчика.
Готовность приемопередатчика может быть проверена путем опроса
бита SPIF (бит 7) в регистре S0SPSR (единица — обмен завершен) или через
прерывания.
После обнаружения готовности можно считать принятый пакет из ре-
гистра S0SPDR. В режиме ведущего может осуществляться только передача,
только прием или и то и другое.

1.18 Последовательный синхронный приемо-передатчик I2С


1.18.1 Назначение и основы функционирования интерфейса I2С
I2C — последовательный синхронный интерфейс, предназначенный
для передачи небольших объемов информации между микросхемами. Мик-
росхемы, поддерживающие I2C — АЦП, ЦАП, ПЗУ, датчики температуры,
75
драйверы дисплеев, порты ввода-вывода и др. Используется всего два про-
водника SCL — тактирование и SDA данные. Одновременно возможна пере-
дача только в одном направлении. Скорость передачи данных не велика — до
400 кбит/с или (реже) до 1 Мбит/с. В LPC2148 скорость не превышает
400 кбит/с.
Одно из устройств на шине I2C является ведущим, остальные —
ведомыми. Допускается подключение до 128 устройств. I2С предоставляет
аппаратную поддержку адресации.
Любая передача независимо от направления инициируется ведущим.
Интерфейсные выходы I2C любой микросхемы имеют открытые стоки, на
обеих линиях I2C устанавливаются подтягивающие резисторы. Таким обра-
зом реализуется операция монтажного логического «И», позволяющая любо-
му ведомому устройству захватить линию и заставить ведущего ждать.
Сопротивления подтягивающих резисторов рекомендовано [2] приближенно
рассчитывать по формуле
(кОм),
2
где — число устройств на шине I C.
Начало и конец пакета I2C обозначаются состояниями START и STOP,
которые формируются ведущим устройством. Состояние START представля-
ет собой спадающий фронт сигнала SDA при высоком уровне на SCL. Состо-
яние STOP генерируется нарастающим фронтом SDA также при высоком
SCL. Временные диаграммы сигналов на лини данных SDA показаны на ри-
сунке 1.18.1.
START STOP
Адрес A6-A0 R/W A Данные D7-D0 A A/A

START STOP
Адрес A6-A0 R/W A Данные D7-D0 A A

― Генерируется ведущим ― Генерируется ведомым

Рисунок 1.18.1 – Временные диаграммы сигнала SDA при передаче от ведущего


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

76
Микроконтроллер LPC2148 оснащен двумя идентичными модулями
2
I C (I2C0 и I2C1). Здесь будем рассматривать только работу в режиме веду-
щего. Режим ведомого может потребоваться только для организации переда-
чи данных между двумя или несколькими микроконтроллерами. Полное опи-
сание можно найти в литературе [1] или в документации к LPC214x.
1.18.2 Управляющие регистры
Схема регистров управления модулями I2C показана на рисунке 1.18.2.
Регистры I2CxCONSET и I2CxCONCLR — управляют состоянием
модулей I2C. Запись единицы в один из разрядов регистра xSET переводит
модуль в соответствующие состояние. Запись единица в xCLR снимает соот-
ветствующие состояние. Запись нулей в эти регистры не имеет значения.
● Бит 2 (AA) разрешает или запрещает генерирование подтверждения
в режиме приема данных. Во время передачи байтов пакета обычно требует-
ся устанавливать в единицу, при передаче последнего байта сбросить в ноль.
I2CxCONSET – установка состояния I2C
15 8 7 6 5 4 3 2 1 0

EN STA STO SI AA
Старт/Стоп Подтвержд.
ВКЛ
Флаг прерывания
I2CxCONCLR – сброс состояния I2C
15 8 7 6 5 4 3 2 1 0

EN STA SI AA
Старт Подтвержд.
ВКЛ
Флаг прерывания
I2CxSTAT – Состояние I2C
15 8 7 3 2 0

STATUS
Состояние I2C

Рисунок 1.18.2 – Схема регистров управления приемопередатчиками I2С


● Бит 3 (SI) — флаг запроса прерывания при завершении операции
приемопередатчиком I2C. Аппаратная установка единицы свидетельствует о
готовности модуля I2C. Сброс в ноль инициирует генерирование очередного
состояния или передачу данных.
● Бит 4 (STO). Запись единицы генерирует состояние STOP, прекра-
щая обмен по I2C. Отменить STOP нельзя, поэтому бит STO в регистре
I2CxCONCLR отсутствует.
● Бит 5 (STA). Устанавливает или сбрасывает состояние START,
начиная передачу пакета. После установи через I2CxCONSET бит должен
сбрасываться через I2CxCONCLR программным путем.
● Бит 6 (EN) включает или отключает приемопередатчик I2C. Прежде
чем использовать модуль необходимо установить этот бит в регистре
I2CxCONSET.
В таблице 1.18.1 приведены наиболее часто используемые кодовые
комбинации, записываемые в регистры I2CxCONSET/CLR.
77
Таблица 1.18.1 – Коды управления состоянием через I2CxCONSET/CLR
Код Описание
0x40 Включить/выключить приемопередатчик I2C
0x20 Сгенерировать состояние START
0x04 Разрешить/запретить подтверждение приема байта
0x10 Сгенерировать состояние STOP
Сбросить запрос прерывания (для I2CxCONCLR) прочитать
0x08
флаг запроса готовности (для I2CxCONSET)
Регистр I2CxSTAT необходим для чтения текущего стояния модуля
2
I C и принятия решения о следующем действии.
Биты 3–7 (STATUS) содержат код текущего состояния. Коды для ре-
жима ведущего приведены в таблице 1.18.2.
Таблица 1.18.2 – Коды состояния приемопередатчика I2C в режиме ведущего
Код Описание Направление
0x00 Ошибка передача/прием
0x08 Передано состояние START передача/прием
0x10 Передано повторное состояние START передача/прием
Передан адрес ведомого (SLA) и признак режима
0x18 передача
записи (W), подтверждение (ACK) получено
Адрес ведомого (SLA) и признак режима записи (W)
0x20 передача
НЕ переданы, подтверждение (ACK) НЕ получено
0x28 Данные переданы, подтверждение (ACK) получено передача
Данные НЕ переданы, подтверждение (ACK)
0x30 передача
НЕ получено
0x38 Арбитраж потерян передача/прием
Адрес ведомого (SLA) и признак режима чтения (R)
0x40 прием
переданы, подтверждение (ACK) получено
Адрес ведомого (SLA) и признак режима чтения (R)
0x48 прием
НЕ переданы, подтверждение (ACK) НЕ получено
0x50 Данные получены, подтверждение (ACK) отправлено прием
Данные получены, подтверждение (ACK)
0x58 прием
НЕ отправлено
0xF8 Простой передача/прием
Регистр состояния I2CxDAT предназначен для записи байта данных,
который предстоит передать. Передача будет сбросов запроса прерывания SI
в регистре I2CxCONCLR. При чтении регистр содержит принятый байт.
Регистры частоты I2CxSCLH, I2CxSCLL представляют собой дели-
тели частоты, определяющие длительности высокого (I2CxSCLH) и низкого
(I2CxSCLL) состояний на линии тактирования SCL. Учитываются 16 млад-
ших разрядов этих регистров. Частота определяется их суммой:
. (1.18.1)

78
Обычно скважность сигнала SCL равна 2 и эти регистры содержат равные
значения, хотя это не обязательно. Частота не должна превышать
кГц. Следовательно, для расчета значений регистров можно рекомендо-
вать следующее выражение:
, (1.18.2)
где частота задана в мегагерцах.
1.18.3 Настройка модуля I2C
Для настройки модуля I2C, как правило, достаточно:
а) выбрать режим портовых линий SDA и SCL через регистр
PINSEL0;
б) присвоить одинаковые значения регистрам выбора скорости
(I2CxSCLH, I2CxSCLL), рассчитанные по формуле 1.18.2;
в) включить модуль I2C, записав код 0x40 в регистр I2CxCONSET.
1.18.4 Типовые циклы обмена данными по шине I2C
На практике чаще всего встречаются три вида циклов обмена данны-
ми по шине I2C. Цикл содержит ожидание готовности I2C через регистры
I2CxCONSET и I2CxSTAT, установку и снятие состояний через регистры
I2CxCONSET и I2CxCONCLR, прием и передачу данных через регистр
I2CxDAT. Ниже приведены алгоритмы каждого цикла обмена.
Цикл «Адрес–Передача»
1. Установить START.
2. Дождаться состояния 0x08 (START передан); снять START; пере-
дать адрес и .
3. Дождаться состояния 0x18 (адрес передан); передать байт.
4. Дождаться состояния 0x28 (данные переданы); передать следующий
байт. Если передан последний (или единственный) байт, установить STOP.
Цикл «Адрес–Прием»
1. Установить START.
2. Дождаться состояния 0x08 (START передан); снять START; если
требуется принять больше одного байта, разрешить подтверждение; передать
адрес и . Если байт всего один, пункт 3 пропустить.
3. Дождаться состояния 0x50 (данные получены, подтверждение от-
правлено); сохранить принятый байт. Если получен предпоследний байт, за-
претить подтверждение (запретить сразу, если байта всего два).
4. Дождаться состояния 0x58 (данные получены, подтверждение НЕ
отправлено). Установить STOP.
Цикл «Адрес–Передача–Прием»
1. Установить START.
2. Дождаться состояния 0x08 (START передан); снять START; пере-
дать адрес и .
3. Дождаться состояния 0x18 (адрес передан); передать байт.

79
4. Дождаться состояния 0x28 (данные переданы); передать следующий
байт. Если передан последний (или единственный) байт, установить START.
5. Дождаться состояния 0x10 (повторный START передан); снять
START; если требуется принять больше одного байта, разрешить подтвер-
ждение; передать адрес и . Если байт всего один, пункт 4 пропустить.
6. Дождаться состояния 0x50 (данные получены, подтверждение от-
правлено); сохранить принятый байт. Если получен предпоследний байт, за-
претить подтверждение (запретить сразу, если байта всего два).
7. Дождаться состояния 0x58 (данные получены, подтверждение НЕ
отправлено). Установить STOP.
В качестве примера приведем шаблон реализации самого сложного
цикла «Адрес–Передача–Прием» через опрос флага готовности в регистре
I2C0CONSET.
I2C0CONSET=0x20;
while (!Finished)
if (I2C0CONSET & 0x08)
{
switch (I2C0STAT)
{
case 0x08: ... ; break;
case 0x18: ... ; break;
case 0x28: ... ; break;
case 0x10: ... ; break;
case 0x50: ... ; break;
case 0x58: ... ; Finished=1;
}
I2C0CONCLR=0x08;
}
Алгоритм упрощается с использованием прерываний. Требуется по-
местить в процедуру обработки прерывания конструкцию switch...case и
команду сброса флага в I2CxCONCLR.

1.19 Последовательный асинхронный приемопередатчик UART


1.19.1 Назначение и основы функционирования порта UART
Последовательный порт UART используется для обмена сообщениями
через интерфейсы RS-232 и RS-485, широко распространенные как в компь-
ютерной технике, так и в промышленных системах управления. Сопряжение
этих интерфейсов с портом UART обеспечивается соответствующими преоб-
разователями уровней, выпускаемыми в виде интегральных микросхем.
Универсальный асинхронный приемопередатчик (UART) представля-
ет собой асинхронный интерфейс, использующий две линии для передачи
данных в обоих направлениях. Скорость передачи данных ограничена
3,75 Мбит/c. Каждый символ может состоять из 5–8 битов, к которым может
добавляться бит контроля четности. Младший бит передается первым. Нача-

80
ло и конец символа обозначаются стартовым битом (логический ноль) и сто-
повым битом (логическая единица). Стоповых битов может быть один или два.
На рисунке 1.19.1 Показаны осциллограммы сигнала, передаваемого
по интерфейсу RS-232 персональным компьютером, а также эквивалентного
сигнала стандартных уровней ТТЛ/КМОП, полученного с помощью преобра-
зователя уровней MAX232.

Рисунок 1.19.1 – Осциллограммы сигнала RS-232 (вверху) и сигнала на входе RxD


микроконтроллера (внизу) при передаче символов 0x89 и 0x39. Параметры сигнала:
скорость 9600 бит/с, 8 бит, один стоповый бит, контроль нечетности.
Микроконтроллер LPC2148 оснащен двумя портами UART. Здесь
ограничимся рассмотрением только модуля UART0. Другой модуль (UART1)
отличается поддержкой полного модемного интерфейса.
Следует указать отличительные особенности портов UART в микро-
контроллерах LPC2148: 16-уровневые буферы приемника и передатчика,
действующие по принципу очереди; автоматический контроль четности при
приеме и формирование бита честности при передаче; развитые средства
контроля ошибок; поддержка автоматического определения битовой скорости.
1.19.2 Управляющие регистры
Схема управляющих регистров модуля UART0 показана на рисун-
ке 1.19.2.
Регистр U0RBR — вершина буфера-очереди приемника. Содержит
самый «старый» принятый байт. Если используется передача символа длиной
менее восьми бит, то неиспользуемые старшие разряды заполнены нулями.
При считывании байта из буфера через U0RBR бит доступа к делите-
лю частоты DLAB (см. ниже) должен быть сброшен в ноль.
Регистр U0THR — вершина буфера-очереди передатчика. Байт, за-
груженный в этот регистр, будет поставлен в очередь и передан после всех
байтов, загруженных в U0THR ранее. Запись возможна, если бит доступа к
делителю частоты DLAB сброшен в ноль.

81
U0TER – Включение передатчика
11 8 7 6 0
EN
TX
Вкл

U0LSR – состояние линии


11 8 7 6 5 4 3 2 1 0
E T E
XF M R BI FE PE OE RDR
R TE TH
Ошибка в ходе приема Данные в буфере приемника
Передача завершена Переп. буфера
Буфер передатчика пуст Ошибка четности
Поток прерван Потеря стопового бита

U0LCR – управление линией


11 8 7 6 5 4 3 2 1 0
B K R P
LA EA PARSEL PA N STO WLEN
D BR E

Разр. настр. скорости Блок. Чет/ Контр. Число бит


нечет чет.
Число стоповых
U0FCR – управление буфером
11 8 7 6 5 4 3 2 1 0
O
TRIGLEV TX S RX S IF
E E F EN
R R
Число байт до
Сбр. буф. TX Вкл. буферы
прерывания
Сбр. буф. RX
U0IIR – идентификация прерывания
11 10 9 8 7 6 5 4 3 2 1 0
EO BTO FIFOEN IDENT IP
AB A
Ошибка опр. скорости Буферы Идентиф. прер.
Флаг прерывания
включены события
Скорость определена

U0IER – управление прерывающими событиями


11 10 9 8 7 4 3 2 1 0
EO BTO
S E
AB A XL THR RBR
R
Ошибка опр. скорости
Ошибка в ходе приема Данные в буфере приемника
Скорость определена Буфер передатчика пуст

U0ACR – автоматическое определение скорости


11 10 9 8 7 4 3 2 1 0
EO lr TO lr to e t
AB tC AB tC Au tart od ar
In In S M St
Сброс флагов
Автоматический повтор Запуск
прерываний
Режим

Рисунок 1.19.2 – Схема регистров управления приемопередатчиками UART0


Регистры U0DLL, U0DLM задают делитель частоты, определяя би-
товую скорость приемопередатчика. См. выражения (1.19.1, 1.19.2).
Регистр U0FDR задает делитель частоты для точной настройки.
● Биты 0–3 (DivAddVal) — см. выражения (1.19.1, 1.19.2).
● Биты 4–7 (MulVal) — см. выражения (1.19.1, 1.19.2).

82
Таблица 1.19.1 – Оптимальные по точности настройки скорости UART
МГц МГц МГц
Стандартная

скорости, %

скорости, %

скорости, %
DivAddVal

DivAddVal

DivAddVal
Отн. погр.

Отн. погр.

Отн. погр.
скорость

U0DLM

U0DLM

U0DLM
U0DLL

U0DLL

U0DLL
MulVal

MulVal

MulVal
2400 226 4 4 1 0 113 2 4 1 0 23 1 5 2 0,006
4800 113 2 4 1 0 23 1 5 2 0,006 93 0 10 11 0,006
9600 23 1 5 2 0,006 93 0 10 11 0,006 71 0 8 3 0,032
19200 93 0 10 11 0,006 71 0 8 3 0,032 38 0 7 2 0,059
38400 71 0 8 3 0,032 38 0 7 2 0,059 19 0 7 2 0,059
57600 31 0 10 11 0,006 19 0 7 5 0,059 12 0 14 5 0,059
Битовая скорость определяется выражением
; (1.19.1)

или (что то же самое)


, (1.19.2)
где ; ; ; .
При настройке допустимое рассогласование скоростей приемника и
передатчика составляет 5%.
В таблице 1.19.1 приведены оптимальные значения величин, задаю-
щих скорость приемопередатчика для тактовых частот равных 60, 30
и 15 МГц, которые могут быть получены с кварцевым резонатором 12 МГц.
Приняв , практически при любой частоте
кварцевого резонатора можно получить рассогласование не более 2%. Тогда
упрощенный расчет можно проводить по формуле
, (1.19.3)
где обозначают 16-разрядный код, разбитый на два байта.
Заметим, что нередко в системах передачи данных используют квар-
цевый резонатор с частотой 11,0592 МГц, которая делится нацело на все
стандартные скорости RS-232. При этом в большинстве случаев погрешность
задания частоты отсутствует при .
Регистр U0FCR предназначен для управления буфером-очередью.
● Бит 0 (FIFO Enable). Запись единицы включает буферы приемника и
передатчика, а также открывает доступ к остальным битам регистра. Для ра-
боты приемопередатчика бит должен быть равен единице. Изменение бита
сбрасывает буферы.

83
● Бит 1 (RX FIFO Reset). Запись единицы приводит к очистке буфера
приемника, после чего бит автоматически будет сброшен в ноль.
● Бит 2 (TX FIFO Reset). Запись единицы приводит к очистке буфера
передатчика. Бит также сбрасывается в ноль автоматически.
● Биты 6–7 (RX Trigger Level) — порог буфера. Определяют число
принятых байт, при котором вырабатывается прерывание (см. таблицу
1.19.2). Биты должны быть установлены до включения прерывания.
Таблица 1.19.2 – Пороговое значение буфера приемника
RX Trigger Level Число приятных байт, вызывающих прерывание
00 1
01 4
10 8
11 14
Регистр U0LCR — регистр управления линией.
● Биты 0–1 (World Length Select) выбирают разрядность передаваемых
и принимаемых символов (см. таблицу 1.19.3).
Таблица 1.19.3 – Настройка числа принимаемых и передаваемых бит
World Length Select Число принимаемых и передаваемых бит
00 5
01 6
10 7
11 8
● Биты 4–5 (Parity Select). Настройка контроля четности (в соответ-
ствии с таблицей 1.19.4).
● Бит 2 (Stop Bit Select). Нулевое значение соответствует одному сто-
повому биту, единица — двум стоповым битам.
Таблица 1.19.4 – Настройка контроля четности
Parity Select Настройка бита честности
00 Число двоичных единиц в символе нечетно
01 Число двоичных единиц в символе четно
10 Бит четности всегда равен 1
11 Бит четности всегда равен 0
● Бит 3 (Parity Enable). Установка в единицу приводит к формирова-
нию бита четности при передаче и контролю четности при приеме.
● Бит 6 (Break Control). Запись единицы приводит к установке логиче-
ского нуля на выходе передатчика TxD. Низкий уровень на линии TxD будет
удерживаться пока этот бит равен единице.
● Бит 7 (DLAB). Установка единицы открывает доступ к регистрам
настройки скорости (см. выше).
Регистр U0LSR индицирует состояние линии.

84
● Бит 0 (RDR). Единица показывает, что буфер приемника содержит
принятые данные, готовые для считывания через U0RBR. Бит сбрасывается в
ноль, когда буфер опустеет.
● Бит 1 (OE). Единица устанавливается в случае переполнения буфера
приемника, то есть поступлении более 16 символов подряд без извлечения
данных из U0RBR. Бит сбрасывается в ноль при чтении регистра U0LSR.
● Бит 2 (PE). Единица обозначает возникновение ошибки контроля
четности. Значение бита относится к самому «старому» символу в буфере-
очереди. При извлечении очередного символа буфер сдвигается, и флаг PE
обновляется для очередного символа. Бит сбрасывается при чтении U0LSR.
● Бит 3 (FE). Единица показывает, что стоповый бит распознан как
логический ноль. При возникновении такой ошибки приемник будет пытать-
ся восстановить синхронизацию, считая стоповый бит пропущенным, а нуле-
вой уровень стартовым битом следующего символа. Значение бита также от-
носится к очередному символу в буфере, обновляется при чтении U0RBR и
сбрасывается в ноль при чтении U0LSR.
● Бит 4 (BI). Устанавливается в единицу, если на протяжении всего
символа состояние линии RXD0 неизменно и равно логическому нулю. Чте-
ние U0LSR сбрасывает бит в ноль.
● Бит 5 (THRE). Единица показывает, что буфер передатчика пуст и
готов принимать данные через U0THR. При записи в U0THR бит сбрасывает-
ся в ноль.
● Бит 6 (TEMT). Единица показывает, что свободны и буфер передат-
чика, и сдвиговый регистр передатчика. То есть в настоящий момент пере-
датчик простаивает. Ноль устанавливается, если в буфере или в сдвиговом
регистре появляются данные.
● Бит 7 (RXFE). Устанавливается в единицу, если в любой из ячеек
буфера имеется символ приятный с ошибкой (FE, PE или BI). Бит сбрасыва-
ется в ноль при чтении U0LSR при условии все байты, хранящиеся в буфере,
приняты без ошибок.
Регистр U0ACR — управление автоматической настройкой скорости.
● Бит 0 (Start). Установка в единицу запускает процедуру автоматиче-
ского определения скорости. По завершении бит автоматически будет сбро-
шен в ноль.
● Бит 1 (Mode). Режим 0 (скорость определяется по стартовому биту и
младшему биту данных) или режим 1 (скорость определяется только по стар-
товому биту).
● Бит 2 (Auto Restart). Установка единицы приводит к автоматическо-
му перезапуску процедуры в случае неудачи.
● Бит 8 (ABEOIntClr). Запись единицы сбросит соответствующий
флаг запроса прерывания в регистре U0IIR. Запись нуля не имеет значения.
● Бит 9 (ABTOIntClr). Запись единицы сбросит соответствующий
флаг запроса прерывания в регистре U0IIR. Запись нуля не имеет значения.
Регистр U0TER предназначен для запрета передачи. Содержит един-
ственный управляющий бит.
85
● Бит 7 (TXEN). По умолчанию бит равен единице. Запись нуля за-
прещает работу передатчика. Если бит сброшен в ноль во время передачи, то
она будет завершена, но следующий символ из буфера передаваться не будет
до тех пор, пока биту не будет присвоена единица.
Регистр U0IER предназначен для включения прерываний, связанных
с событиями в модуле UART0.
● Бит 0 (RBR) разрешает формирование запроса прерывания при нали-
чии данных в буфере приемника, которые не были считаны через U0RBR.
● Бит 1 (THREE) разрешает запрос прерывания при опустошении бу-
фера передатчика.
● Бит 2 (RX Line Status) разрешает прерывание при обнаружении
ошибки (OE, PE, FE, BI) в ходе прима данных. Подробней об ошибках см.
описание регистра U0LSR.
● Бит 8 (ABTO Int En) разрешает запрос прерывания по успешному
завершению процедуры автоматического определения скорости.
● Бит 8 (ABEO Int En) разрешает запрос прерывания по неудачному
завершению процедуры определения скорости.
Регистр U0IIR — идентификатор прерываний UART0. Все прерыва-
ющие события, священные с модулем UART0 считаются относящимися к
одному источнику. Поэтому требуется алгоритмически определять причину
прерывания с помощью следующих битов.
● Бит 0 (Interrupt Pending) Равенство единице показывает, что ни одно
из прерываний не запрошено.
● Биты 1–3 (Interrupt Identification) содержат идентификатор прерыва-
ния в соответствии с таблицей 1.19.5.
Таблица 1.19.5 – Идентификация прерываний приемопередатчика UART
U0IIR[0–3] Значение Условие сброса в ноль
0001 Прерывание не запрошено —
0110 Ошибка в ходе приема
Чтение U0LSR
(биты OE, PE, FE, BI в U0LSR)
0100 Чтение U0RBR или число байт,
Буфер приемника полон
в буфере, становится порога
1100 Буфер частично заполнен и
Чтение U0RBR
приемник простаивает
0010 Чтение U0IIR или запись
Буфер передатчика пуст
в регистр THR
● Бит 6–7 (FIFO Enable) Эти биты повторяют бит 0 регистра U0FCR.
● Бит 8 (ABEO Int). Единица показывает, что процедура автоматиче-
ского определения скорости завершена успешно.
● Бит 9 (ABTO Int). Единица показывает, скорость не удалось опреде-
лить автоматически.
Здесь необходимо дать некоторые пояснения. Идентификаторы 0100 и
1100 свидетельствуют о наличии необработанных данных в буфере приемни-
ка. Различие состоит в том, что код 0100 устанавливается, когда число байт в
86
буфере достигает порогового значения 1, 4, 8 или 14 (см. выше регистр
U0FCR). Код 1100 устанавливается, если в буфере есть хотя бы один байт, но
число принятых байт меньше порогового значения, и приемник простаивает
в течение интервала 3,5…4,5 символа. Этот интервал не может быть изменен
и зависит от нескольких настроек UART (см. техническое описание
LPC214x).
Необходимость различать эти события поясним на простом примере.
Пусть требуется принять и обработать пакет из 100 байт, следующих непре-
рывным потоком. Порог буфера установлен на 14 байт. То есть прерывание
запрашивается через каждые 14 принятых байт. После седьмого прерывания
из буфера будут извлечены байт. Последние 2 байта не дадут за-
полнения буфера. Однако прекращение непрерывного потока будет обнару-
жено и запрошено прерывание с идентификатором 1100.
Практически обработка этих событий может быть абсолютно одина-
ковой. Если порог буфера равен единице, всегда получаем код 0100.
Отметим также, что прерывания будут постоянно вырабатываться до
тех пор пока буфер приемника не опустеет, а буфер передатчика не будет за-
гружен хотя бы одним байтом.
1.19.3 Настройка порта UART
Для настройки можно рекомендовать следующий порядок действий.
1. Выбрать режим портовых линий RxD и (или) TxD через регистр
PINSEL0.
2. Установить в единицу бит DLAB в регистре U0LCR (необходимо
для настройки скорости).
3. Задать скорость приемопередатчика через регистры U0DLM,
U0DLL, и U0FDR. Воспользоваться таблицей 1.19.1 или выражениями
(1.19.2, 1.19.3).
4. Настроить параметры протокола обмена (число информационных и
стоповых битов, контроль четности) через регистр U0LCR. При этом седьмой
бит (DLAB) сбросить в ноль.
5. Включить буферы приемопередатчика (бит 0 регистра U0FCR) и
задать в том же регистре порог буфера — число накопленных принятых байт,
вызывающее прерывание. Если механизм прерываний применять не предпо-
лагается, то можно рекомендовать порог в один байт. При использовании
прерываний желательно, чтобы они возникали как можно реже, поэтому ре-
комендуем порог в 8 или 14 байт.
1.19.4 Прием байта с опросом флага
Команды приема байта с опросом флага могут быть размещены в про-
извольном месте программы. Необходимо обеспечить условия, при которых
частота опроса будет не менее 1/16 байтовой скорости.
1. Дождаться появления единицы в младшем разряде (RDR) регистра
U0LSR.
2. Считать принятый байт из U0RBR.

87
3. Повторять опрос флага RDR и чтение из U0RBR до тех пор пока
буфер не окажется пуст ( ).
1.19.5 Передача байта с опросом флага
1. Записать от 1 до 16 байт в регистр U0THR подряд.
2. Дождаться появления единицы в бите THRE регистра U0LSR.
3. После появления флага опустошения буфера THRE передача может
быть продолжена.
1.19.6 Прием и передача данных с использованием прерываний
1. Дополнить настройку UART разрешением формирования запросов
прерываний (регистр U0IER). Обычно можно установить три младших бита в
единицу, записав код 0x07.
2. Настроить систему прерываний через регистры VICVectAddr0–15,
VICVectCntl0–15 и VICIntEnable.
3. В процедуре обработки прерывания следует считать идентификатор
прерывания и состояние линии, например, командами:
IntID=U0IIR & 0x0F; // Выделение идентификатора прер.
LineStat=U0LSR; // Чтение состояния линии
4. Путем анализа идентификатора прерывания, сохраненного в пере-
менной IntID можно организовать ветвление, то есть выполнять либо прием,
либо передачу, либо обработку ошибок. При этом можно рекомендовать сле-
дующую конструкцию:
switch (IntID)
{
case 0x04:
case 0x0C:
while (U0LSR & 1)
{
... // Чтение из U0RBR байта и сохранение
}
break;
case 0x06:
if (LineStat & 0x02) ... ; // Обработка ошибок
... ;
break;
case 0x02:
... // Передача от 1 до 16 байт
}
Первая ветвь выполняется при наличии данных в буфере и содержит
команду циклического чтения до тех пока буфер не окажется пуст (фиксиру-
ется по флагу RBR в регистре U0LSR). Об обработке ошибок см. ниже. Пере-
дача может выполняться до 16 байт подряд.

88
1.19.7 Прием и передача пакетов данных
При работе с пакетами данных требуется обеспечить кадровую син-
хронизацию, то есть обозначить границы пакетов. Для этого в состав пакета
включают заранее известный заголовок (префикс) или постфикс. Это может
быть кодовая комбинация, которая не встречается в информационной части
пакета, так как это сделано в протоколе обмена с модемом (символы «AT»)
или в протоколе SCPI (Standard Commands for Programmable Instruments)
(символы «*» или «:» в начале и символ «?» в конце).
Если выбрать код, не встречающийся среди данных невозможно, то в
качестве заголовка используют любую достаточно длинную кодовую комби-
нацию (не менее 4-х байт). Высокая разрядность этой комбинации делает ма-
ловероятным случайное совпадение с фрагментов данных.
В состав пакета можно ввести поле для обозначения длины пакета,
что избавит от потребности в завершающей кодовой комбинации (постфик-
се). Может также потребоваться введение поля циклического кода контроля
ошибок, например, CRC32.
Стоит сказать, что обмен данными между персональным компьюте-
ром и встраиваемым микроконтроллером может быть организован по прин-
ципу «запрос-ответ». То есть МК будет отправлять пакет данных только в
ответ на соответствующую команду ПК. В таком случае синхронизация не
потребуется так же как и передача длины пакета.
1.19.8 Диагностика ошибок
Диагностика ошибок осуществляется путем анализа регистра U0LSR.
Следует учитывать, что большинство флагов этого регистра автоматически
сбрасываются при чтении. Поэтому прежде чем анализировать состояние
U0LSR его необходимо одной командой скопировать в специально создан-
ную переменную, а затем проверять ее значение.
Реакция на возникшую ошибку диктуется спецификой решаемой за-
дачи. Это может быть игнорирование ошибки, появление предупреждающего
сигнала или информирование об ошибке по линии UART. В то же время, об-
работка ошибки переполнения буфера всегда предполагает очистку буфера
путем многократного чтения из U0RBR или установкой бита RX FIFO Reset в
регистре U0FCR.
1.19.9 Автоматическая настройка скорости
Для автоматической настройки скорости необходимо установить еди-
ницу в младший бит (Start) регистра U0ACR. Скорость будет измерена во
время приема следующего символа. Необходимо чтобы нулевой (младший
разряд) этого тестового символа был равен единице, а следующий (первый)
бит — нулю. То есть первый символ, передаваемый после запуска процедуры
измерения скорости, должен иметь двоичный формат xxxxxx01. Если же
установить режим 1 (бит Mode регистра U0ACR), то достаточно только одно-
го единичного младшего бита. Этому правилу подчинены AT-команды (код
символа «A» — 0x41, символа «a» — 0x61).

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

1.20 Часы реального времени


1.20.1 Основные возможности часов реального времени
Часы реального времени предназначены для фиксации времени и да-
ты. Часы состоят из 15-разрадяного счетчика-делителя, предназначенного
для получения частоты 1 Гц, и восьми счетчиков времени и даты. Имеется
возможность формирования запросов прерывания по инкременту любого из
счетчиков и совпадению текущего времени с установкой «будильника».
Например, каждую минуту или в определенное время каждый понедельник.
Тактирование часов реального времени осуществляется либо от соб-
ственного тактового генератора с кварцем 32768 Гц, либо от основного так-
тового генератора (частота ).
Отметим, что часы реального времени LPC2148 используют упро-
щенный алгоритм определения високосного года. Високосный год определя-
ется по равенству нулю двух младших двоичных разрядов года. При этом
каждый 4-й год считается високосным. В то время как по григорианскому
календарю каждый 100-ый год не високосный, хотя и делится на 4, но каж-
дый 400-ый — високосный, хотя делится на 100. Впервые проблема даст о
себе знать лишь в 2100 году.
Соответствие дня недели (DOW) и дня в году (DOY) текущей дате не
контролируется. Например, можно установить дату 1 января 2010 г., при
этом сделав это число понедельником (хотя, на самом деле, пятница) и сотым
днем в году.
1.20.2 Управляющие регистры
Схема управляющих регистров показана на рисунке 1.20.1.
Регистры SEC, MIN, HOUR, DOW, DOM, MONTH, YEAR, DOY
содержат текущее время и дату. Назначение каждого из них и диапазоны
возможных значений приведены в таблице 1.20.1.
Регистры CTIME0–CTIME2 содержат текущее время, упакованное в
96-разрядный формат. Расшифровка формата (назначение разрядов) приве-
дено в таблице 1.20.1 Эта группа регистров позволяет считать время всего за
три операции, но не доступна для записи.
Регистры ALSEC, ALMIN, ALHOUR, ALDOW, ALDOM, AL-
MONTH, ALYEAR, ALDOY аналогичны регистрам времени. Содержат
установку «будильника». Совпадение всех или некоторых регистров времени
и «будильника» может вызвать прерывание (см. регистр AMR).

90
ILR – флаги запросов прерываний CCR – управление часами
11 8 7 4 3 2 1 0 11 8 7 5 4 3 2 1 0

L
T

F
C
C

R
R
CTTEST

IF
S

L
EN K

C TC

A TC
R TC

SR LK
Тест Вкл
«Будильник» Инкремент
Источник тактирования Сброс
AMR – управление запросами прерываний по «будильнику»
31 24 23 16 15 8 7 6 5 4 3 2 1 0
R

N
Y
M
C

A
A
A
A
A
AM
AM
A

AR
IN

O
O
O

O
O R
M
SE MR

D MR

M MR
D MR

D MR

YE MR
H

Месяц Д. нед. Часы Сек.


Год
День в году Число Минуты
CIIR – управление запросами прерываний по инкременту счетчиков
31 24 23 16 15 8 7 6 5 4 3 2 1 0
R
I
I

N
Y
M
C

W
U

AR
IN

O
O
O

O
O
M M
SE M

D IM

M IM
D IM

D IM

YE IM
H IM

Месяц Д. нед. Часы Сек.


Год
День в году Число Минуты
CTIME0 – упакованное время и дата
31 28 27 26 24 23 21 20 16 15 14 13 8 7 6 5 0

DOW HOUR MIN SEC


День недели (0–6) Часы (0–23) Минуты (0–59) Секунды (0–59)

CTIME1 – упакованное время и дата


31 28 27 24 23 16 15 12 11 8 7 6 5 4 0

YEAR MONTH DOM


Год (0–4095) Месяц (1–12) Число месяца (0–31)

CTIME2 – упакованное время и дата


31 24 23 16 15 12 11 8 7 0

YEAR
День в году (0–366)

Рисунок 1.20.1 – Схема регистров управления часами реального времени

91
Таблица 1.20.1 – Основные регистры-счетчики часов реального времени
Счетчики Объединенные Диапазон
Регистры
времени регистры Назначение возможных
будильника
и даты Регистр Биты значений
SEC ALSEC 0–5 Секунды 0–59
MIN ALMIN 8–13 Минуты 0–59
CTIME0
HOUR ALHOUR 16–20 Часы 0–23
DOW ALDOW 24–26 День недели 0–6
1–28, 1–29, 1–30 или
Число 1–31 в зависимости
DOM ALDOM 0–4
месяца от месяца и
CTIME1
високосного года
MONTH ALMONTH 8–11 Месяц 1–12
YEAR ALYEAR 16–27 Год 0–4095
1–365 или 1–366 для
DOY ALDOY CTIME2 0–11 День в году
високосного года
Регистр CCR управляет счетчиком часов реального времени.
● Бит 0 (CLKEN). Единица разрешает работу часов, ноль —
запрещает.
● Бит 1 (CTCRST). Запись единицы сбрасывает в ноль счетчик-
делитель. Сброс действует до тех пор, пока этот бит не будет очищен.
● Бит 2–3 (CTTEST). Биты должны быть сброшены в ноль.
● Бит 4 (CLKSRC). Если бит равен единице, источником тактового
сигнала для часов реального времени служит отдельный генератор с частотой
32768 Гц. Сброс в ноль приводит к тактированию сигналом с предваритель-
ного делителя, который в свою очередь тактируется сигналом .
Регистр CTCR — 15-разрядный счетчик-делитель часов реального
времени. Входная частота счетчика 32768 Гц, выходная — 1 Гц. Выход счет-
чика подключен к входу счетчика секунд.
Регистр ILR содержит флаги прерываний от часов реального време-
ни.
● Бит 0 (RTCCIF). Равенство единице свидетельствует о прерывании
по инкременту одного из счетчиков времени. Запись единицы приводит к
сбросу соответствующего флага прерывания (см. также регистр CIIR).
● Бит 1 (RTCALF). Равенство единице свидетельствует о прерывании
по «будильнику». Запись единицы приводит к сбросу флага прерывания (см.
также регистр CIIR).
Регистр CIIR управляет запросами прерывания по инкременту каж-
дого из счетчиков часов реального времени. В зависимости от битов, уста-
новленных в единицу, прерывания могут запрашиваться по инкременту се-
кунд (IMSEC), минут (IMMIN), часов (IMHOUR), числа месяца (IMDOM),
дня недели (IMDOW), числа года (IMDOY), месяца (IMMON) или года
(IMYEAR).

92
Регистр AMR управляет запросами прерывания от «будильника». Его
структура аналогична регистру CIIR — каждый бит (AMRSEC–AMRYEAR)
отвечает за определенный временной интервал от секунды до года. Установ-
ка единицы в каждый разряд запрещает запрос прерывания при совпадении
соответствующего счетчика с установкой будильника. Например, ежедневное
срабатывание будильника в 8:00 потребует установки всех битов кроме AM-
SEC, AMMIN и AMHOUR. Установка в единицу всех разрядов отключит
«будильник».
Регистры PREINT, PREFRAC задают предварительный делитель,
предназначенный для получения опорной частоты 32768 Гц из любой такто-
вой частоты периферийных устройств . Строго говоря, при этом такто-
вый сигнал не является колебаниями с частой 32768 Гц, а представляет собой
последовательность из 32768 неодинаковых по длительности импульсов, по-
вторяющуюся каждую секунду.
Расчет значений регистров выполняется по формулам:
; (1.20.1)
(1.20.2)
1.20.3 Рекомендации по применению
Настройка часов реального времени проста:
1. При необходимости присвоить начальные значения счетчикам вре-
мени SEC–YEAR.
2. Включить часы и тактирование от низкочастотного генератора (за-
пись кода 0x11 в регистр CCR).
Если необходимо тактировать часы от основного тактового генерато-
ра, потребуется присвоить регистрам и величины, рас-
считанные по формулам (1.20.1–1.20.2). Для частоты МГц
, . При МГц ,
. Тогда в регистр CCR записать код 0x01.
Настройка прерываний:
1) разрешить необходимые прерывающие события, записав маску в
регистры IIR и/или AMR;
2) разрешить прерывание от часов с помощью регистров
VICVectAddr0–15, VICVectCntl0–15 и VICIntEnable.

1.21 Управление питанием и идентификация источников сброса


1.21.1 Краткие сведения о мониторе питания
Микроконтроллер имеет развитые средства управления питанием.
Поддерживается два режима пониженного энергопотребления.
а) Режим ожидания (Idle Mode). В данном режиме тактирование ядра
микроконтроллера прекращается, в то время как работа периферийных
устройств продолжается. Любое прерывание выводит микроконтроллер из
режима ожидания.

93
б) Режим отключения (Power Down Mode). В отключенном состоянии
прекращается питание всех узлов микроконтроллера. Однако сохраняется со-
стояние регистров, оперативной памяти и электрические уровни на выводах.
Потребляемая мощность снижается до 40–100 мкА. Выход из режима отклю-
чения производится внешним прерыванием или сбросом.
Гибкое управление потребляемой мощностью возможно путем от-
ключения питания отдельных периферийных устройств.
Следует напомнить, что потребляемая мощность связана с тактовой
частотой ядра и шины периферийных устройств . Уменьшение
этих частот (раздел 1.7) приведет к снижению потребляемой мощности.
Микроконтроллер оснащен монитором контроля напряжения питания.
Монитор реагирует на два порога: 2,9 В и 2,6 В и предоставляет возможность
генерировать запрос прерывания при снижении напряжения до 2,9 В, а также
переводить микроконтроллер в состояние сброса при снижении напряжения
до 2,6 В.
1.21.2 Управляющие регистры
Схема управляющих регистров приведена на рисунке 1.21.1.
Регистр PCON — управление режимом энергопотребления.
Бит 0 (IDL). Установка единицы переводит микроконтроллер в режим
ожидания.
Бит 1 (PD). Установка единицы переводит МК в режим отключения.
RSIR – идентификация источника сброса
15 8 7 4 3 2 1 0
TR
R

TR

R
D

PO
D
BO

EX
W

Монитор питания ВКЛ питания


Сторожевой таймер Сброс
PCON – управление монитором питания
15 8 7 5 4 3 2 1 0
PD OD
D
R

PD
L
G
D

M
B

ID
BO

BO

Ожидание
Сброс от монитора питания Отлючение
ВКЛ монитор питания
ВКЛ монитор питания
в режиме отключения

PCONP – управление питанием периферийных устройств


31 28 27 24 23 21 20 19 16
1
SB

C
AD

I2
U

15 13 12 11 10 9 8 7 6 5 4 3 2 1 0
T1

T0

0
0
I1

I0

0
TC

er

er
0

M
C

AR

AR
AD

SP

SP

PW

m
I2
R

Ti

Ti
U

31 – USB ― приемопередатчик USB 9 – RTC ― часы реального времени


20, 12 – AD1 ― аналого-цифровые преобразователи 8 – PWM0 ― широтно-импульсный модулятор
19, 7 – I2C1 ― приемопередатчики I2C 4, 3 – UART0/1 ― приемопередатчики UART
10, 8 – SPI0/1 ― приемопередатчики SPI 1, 2 – Timer0/1 ― таймеры-счетчики

Рисунок 1.21.1 – Схема регистров управления питанием

94
Бит 2 (BODPDM). Установка единицы приводит к отключения мони-
тора питания. Это приводит к дополнительному снижению потребляемой
мощности, однако, в случае снижения напряжения питания выхода перехода
микроконтроллера в активный режим не произойдет. Соответственно не бу-
дет реакции на аварийную ситуацию.
Бит 3 (BOGD). Установка единицы отключает монитор питания.
Бит 4 (BORD). Установка единицы запрещает формирование сброса
при понижении напряжения до 2,6 В.
Регистр RSIR (только для чтения) предназначен для идентификации
источника сброса.
Бит 0 (POR). Единица в этом разряде свидетельствует о сбросе по
включению питания.
Бит 1 (EXTR). Сброс вызван внешним сигналом на входе RESET.
Бит 2 (WDTR). Сброс вызван сторожевым таймером.
Бит 3 (POR). Сброс вызван монитором питания вследствие падения
напряжения питания до 2,6 В.
Регистр PCONP предназначен для выборочного отключения питания
периферийных устройств микроконтроллера. Каждый разряд данного реги-
стра соответствует одному из периферийных узлов микроконтроллера. Схема
соответствия показана на рисунке 1.21.1. Сброс разряда в ноль приводит к
отключению питания связанного с ним устройства.

95
Часть 2. Разработка и отладка программ с помощью
современных инструментальных средств

2.1 Форматы представления чисел


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

Способы представления целых чисел различаются в зависимости от


кодирования знака («+» или «–»).
Прямой код. Для хранения знака выделяют старший разряд, называе-
мый знаковым. Остальные разряды называют значащими. Знаковый разряд
положительного числа всегда равен нулю, отрицательного — единице. Коли-
чество значащих разрядов при этом сокращается на 1, а наибольшее число,
которое можно записать в разрядной сетке, оказывается примерно вдвое
меньше и составляет . Формула меняется:
. (2.1.2)
Несмотря на простоту для понимания, реализация вычислений в пря-
мом коде затруднена, поэтому такой код практически никогда не применяет-
ся. Вычислительные машины используют для представления отрицательных
чисел дополнительный код.
В дополнительном коде, как и в прямом, старший разряд использует-
ся для хранения знака, но знак кодируется иначе:
. (2.1.3)
Число состоит из двух частей: отрицательной, кодируемой всего одним раз-
рядом ( ), и положительной, кодируемой всеми остальными разрядами.
Если знаковый разряд равен нулю, отрицательная часть отсутствует и число
становится положительным. Для положительных чисел прямой и обратный
код совпадают. По модулю отрицательная часть, по крайней мере, на едини-
цу больше положительного, так как, очевидно,
.
Поэтому если знаковый разряд равен единице, то число отрицательно.
Дополнительный код имеет несколько преимуществ перед прямым:
1) Только в дополнительном коде выполняется очевидное равенство
96
,
что позволяет применять общие правила для сложения положительных и от-
рицательных чисел.
2) В дополнительном коде существует единственное представление
нуля. Для сравнения, в прямом коде можно записать как , так и . Одно-
значность нуля освобождает одну кодовую комбинацию, которая по формуле
(2.1.3) относится к области отрицательных чисел. Поэтому в дополнительном
коде всегда диапазон представления отрицательных чисел на единицу боль-
ше, чем положительных. Наибольшее по модулю отрицательное число всегда
четное и равно . Наибольшее положительное число всегда нечетное и
равно .
Смена знака числа в дополнительном коде производится по формуле
. (2.1.4)
То есть инвертируются все разряды числа и к результату прибавляется еди-
ница. Эту формулу можно считать правилом перевода в прямой код и обратно.
Отметим, что правила машинной арифметики для положительных и
отрицательных чисел в дополнительном коде абсолютно одинаковы. По од-
ним и тем же правилам вычисления выполняются верно, независимо от того,
служит ли старший разряд для хранения знака (знаковый разряд) или это
значащий разряд, расширяющий вдвое диапазон представления только поло-
жительных чисел.
Программист субъективно интерпретирует старший разряд как знако-
вый или значащий в зависимости от того интересуют ли его в данной задаче
отрицательные числа.
Процессор, как правило, информирует программиста о принадлежно-
сти результата двум диапазонам: и . Выход за пре-
делы первого диапазона говорит о переполнении при работе с положитель-
ными числами, выход за пределы второго — о переполнении при обработке
чисел со знаком. О реализации контроля переполнения в архитектуре ARM7
см. раздел 1.2.3 (биты С и V слова состояния программы CPSR).
Смещенный код очень распространен для кодирования чисел в таких
устройствах как аналого-цифровые и цифро-аналоговые преобразователи.
Для смещенного кода можно использовать декодирующее выражение
. (1.2.5)
В таком коде 0 — наименьшее отрицательное число, все единицы —
наибольшее положительное число, а ноль находится в середине между ними.
Удобство применения именно такого кодирования связано с тем, что в
ЦАП и АЦП диапазон напряжения зависит от схемы включения. Возмож-
ность работы с двуполярным напряжением и сама полярность напряжения
задаются схемотехнически. Поэтому практически удобно независимо от зна-
ка наименьшее напряжения представлять наименьшим кодом (все нули), а
наибольшее — наибольшим кодом (все единицы).
Код Грея применяется для кодирования угла поворота ротора или фа-
зового угла несущего колебания модулированного сигнала. Любые два

97
смежных числа, записанные в коде Грея, отличаются только одним каким-
либо разрядом. Код Грея в отличие от рассмотренных выше является непози-
ционным, можно сказать, подобно римской системе записи чисел.
Преобразование из обычного позиционного двоичного кода в код Грея
и обратно выполняется с помощью операций сдвига и сложения по модулю
два. Для наглядности введем обозначение для операции сдвига вправо дво-
ичного кода на разрядов (младший разряд при сдвиге теряется, стар-
ший заменяется нулем)
.
Будем применять традиционное обозначение « » не только к разряду,
но и к коду, подразумевая при этом, что операция «сложение по модулю два»
(она же «исключающее ИЛИ», она же «неравнозначность») выполняется по-
разрядно. Тогда код Грея получается из позиционного двоичного кода
по формуле
. (2.1.5)
Обратное преобразование требует циклического повторения:

или короче
. (2.1.6)

2.1.2 Форматы представление целых чисел, приятные в языке Си


Некоторые весьма существенные моменты, касающиеся целочислен-
ных типов данных, могут отличаться в разных компиляторах. Здесь рассмат-
ривается компилятор RealView 4.
Целые положительные числа представляются в памяти в прямом дво-
ичном коде. Числа, занимающие более одного байта, размещаются в памяти в
нескольких последовательных байтах. Младший байт получает меньший ад-
рес, старший — больший. Отрицательные числа записываются в дополни-
тельном коде. В таблице 2.1.1 приведены доступные форматы представления
целых чисел.
Обратим внимание на то, что тип char без приставки unsigned счи-
тается беззнаковым. Восьмиразрядным числам со знаком соответствует тип
signed char. В то время как все остальные типы без приставки unsigned
хранят знак.
Поскольку ядро ARM7 32-х разрядное, основным типом целочислен-
ных данных является int или long. Причем по той же причине они являются
синонимами. Использование 8- или 16-разрядных чисел (соответственно
char и short) сократит объем расходуемой оперативной памяти, однако
может потребовать большего кода и снизить производительность. Это объяс-
няется тем, что в код программы будут внедрены команды, искусственно
ограничивающие разрядность. Использование 64-разрядных чисел (long
long) тоже снизит производительность, но уже из-за необходимости «нара-
щивания» разрядности.

98
Таблица 2.1.1 – Форматы представления целых чисел
Тип Си Объем
Диапазон представления чисел
(компилятор RealView 4) памяти
char и unsigned char
1 байт
signed char
unsigned short
2 байта
short
unsigned int и
unsigned long 4 байта
int и long
unsigned long long
8 байт
long long
Программисту полезно запомнить двоичные и шестнадцатеричные
представления всех чисел от 0 до 15, а также некоторых других положитель-
ных и отрицательных чисел (см. таблицу 2.1.2).
Таблица 2.1.2 – 2-чные и 16-ричные представления некоторых целых чисел
Двоичный Числа без знака Числа со знаком
и (прямой код) (дополнительный код)
16-ричный Числовое Пример Числовое Пример
коды значение для значение для

2.1.3 Форматы чисел c плавающей точкой стандарта IEEE754


Компилятор RealView 4 поддерживает два формата — одинарной
(float) и двойной (double) точности (см. таблицу 2.1.3).
Схемы, иллюстрирующие представления чисел в формате float и
double, показаны на рисунке 2.1.1.
Таблица 2.1.3 – Форматы представления чисел с плавающей точкой
Объем Пределы относит. Минимальное по
Тип Си Диапазон чисел
памяти погрешности модулю число
float 4 байта
double 8 байт

99
31 30 23 22 0

S P M
Знак Порядок Мантисса
8 разрядов 23 разряда

63 62 52 51 0

S P M
Знак Порядок Мантисса
11 разрядов 52 разряда

Рисунок 2.1.1 – Схемы предоставления чисел с плавающей запятой


согласно стандарту IEEE754: одинарной (вверху) и двойной (внизу) точности
23-разрядная (для float) и 52-разрядная (для double) мантисса
представлена в прямом коде и хранит дробную часть числа. Числа считаются
нормализованными кроме исключений, которое будет рассмотрено ниже. Это
значит, что целая часть принимается равной единице. Иными словами, деци-
мальная точка находится слева от мантиссы, а еще левее подразумевается
единица. Знаковый разряд отделен от мантиссы и помещен в старший раз-
ряд всего кода. Для отрицательных чисел .
8-разрядный (для float) и 11-разрядный (для double) порядок за-
писан в смещенном коде, то есть коду «все нули» соответствует максималь-
ное по модулю отрицательное число, «все единицы» — максимальное поло-
жительное.
Общее выражение для расчета числа одинарной точности, представ-
ленного в формате IEEE754:
;
.
Второе выражение используется для так называемых денормализованных чи-
сел (обозначаемых нулевым порядком ). Мантисса денормализованного
числа не имеет единичной целой части. Введение денормализации позволяет
расширить динамический диапазон представления чисел.
Общее выражение для расчета числа двойной точности, представлен-
ного в формате IEEE754:
;
.
Очевидно, что с помощью приведенных формул невозможно записать
ноль. Для нуля потребовалось исключительное обозначение. Еще несколько
исключений предназначены для обозначения бесконечности и неопределен-
ности (см. таблицу 2.1.4).
Бесконечность (Infinity) возникает при делении на ноль и в ре-
зультате выполнения некоторых функций, например, логарифм нуля. Не-
определенность (Not a Number) возникает при делении нуля на ноль,
бесконечности на бесконечность и в результате таких функций, как корень из
отрицательного числа и логарифм отрицательного числа.
100
Таблица 2.1.4 – Представление и неопределенности в формате IEEE754
Чисто в формате IEEE754 P P
Десятичное
(двоичный код, M одинарная двойная
число
одинарная точность) точность точность

0 0 0 0

0 0 0

0 255 1023

неопреде-
>0 255 1023
ленность

2.2 Основы программирования на языке Си


Си является основным языком программирования встраиваемых си-
стем. В настоящее время разработано множество Си-компиляторов для
большинства архитектур: от простейших 8-разрядных микроконтроллеров
PIC18 (Microchip) и AVR (Atmel), до развитых сигнальных процессоров Ana-
log Devices и Texas Instruments.
Программирование на ассемблере сегодня применяется реже. Си-
компилятор освобождает программиста от решения таких задач, как распре-
деление памяти программ и данных, обработка и хранение данных сложных
форматов, программирование типовых конструкций и реализация математи-
ческих функций. Программа, составленная на Си, легко воспринимается зри-
тельно. При этом временные затраты на составление программ существенно
сокращаются, возникает значительно меньше предпосылок для ошибок.
Применение одного языка при разработке программ для персонально-
го компьютера и встраиваемой системы облегчает их сопряжение благодаря
одинаковым форматам хранения данных.
Недостатком программирования на Си является некоторое снижение
производительности. Чаще всего это не создает проблем, из-за постоянно
растущего быстродействия современных микроконтроллеров. К тому же, как
правило, допускается внедрение в Си-программу блоков, составленных на
ассемблере (см. раздел 22).
В этом разделе будут коротко рассмотрены основы программирования
на Си. При этом, как было сказано выше, ориентируемся на компилятор
RealView 4. В то же время материал вполне соответствует стандарту ANSI и
в основном может использоваться при работе с другими компиляторами.
Для углубленного изучения языка авторы рекомендуют пользоваться
известными учебниками [3, 4].

101
2.2.1 Структура программы
Упрощено структуру программы на языке Си можно показать так:
Директивы компилятора
Объявление глобальных переменных
Объявление функций и процедур обработки прерываний
int main()
{
Объявление локальных переменных основной программы
Блок, выполняемый однажды
while (1)
{
Блок, выполняемый циклически
}
}
Программа обычно начинается с одной или нескольких директив ком-
пилятора, например, предназначенных для подключения стандартных биб-
лиотек. Далее следует раздел объявления глобальных переменных. Функции
и процедуры обработки прерываний включаются в программу до основной
программы. Основная программа и каждая функция может иметь раздел объ-
явления локальных переменных.
Комментарии обозначаются двумя способами. Однострочные коммен-
тарии начинаются с двух символов «слэш»
// Однострочный комментарий
Многострочный комментарий начинается символами «/*» и заканчивается
теми же символами в обратном порядке «*/»
/*
Многострочный комментарий
*/
Символы после «//» до конца строки, а также между «/* */» иг-
норируются компилятором.
2.2.2 Числовые константы
Целочисленные константы записываются в десятичной, восьмеричной
или шестнадцатеричной системе счисления. Восьмеричные числа начинаются
с нуля; шестнадцатеричные обозначаются предшествующими символами 0x.
Символьная константа (один символ, заключенный в апострофы) яв-
ляется тоже, на самом деле, является числовой. Вместо символа подставляет-
ся его ASCII-код размером 1 байт. Символ соответствует типу char.
Ниже предложены несколько примеров записи целочисленных кон-
стант, причем, идентичных с точки зрения машинного представления.
90 // Десятичное число 90
0132 // Число 90, представленное в 8-ричной форме
0x5A // Число 90, представленное в 16-ричной форме
'Z' // Символ Z, с кодом 90

102
Дробные (вещественные) числа записываются через точку, отделяю-
щую целую часть от дробной, либо в экспоненциальном формате. Например,
следующие две записи эквивалентны
0.00125
12.5E–4 // 12.5*10^(-4)=0.00125
2.2.3 Переменные и именованные константы
Любая переменная должна быть объявлена до того, как впервые упо-
минается в программе. Синтаксис объявления переменной следующий
Тип Имя1, Имя2, ... ;
или
Тип Имя1 = Значение1, Имя2 = Значение2, ... ;
Здесь Тип — один из типов данных, рассмотренных в разделах 2.1.2, 2.1.3;
Имя — идентификатор (имя переменной); Значение — значение, которое бу-
дет присвоено переменой по умолчанию (указывать не обязательно). Допус-
кается через запятую перечислять несколько однотипных переменных.
Имя переменной подчиняется правилам, общим для большинства
языков программирования: состоит из латинских букв, цифр и символа под-
черкивания, первый символ не должен быть цифрой. Внимание! В Си разли-
чаются малые и прописные буквы в именах переменных.
Пример объявления четырех переменных с именами Var1–Var4:
char Var1;
unsigned int Var2=0x80000000, Var3=0;
float Var4=7.5;
Блок объявления переменных может быть расположен:
1) до основной программы (объявление глобальных переменных);
2) в начале основной программы (первая запись после открывающейся
операторной скобки «{»);
3) в начале каждой функции.
В зависимости от того, где объявлены переменные, они являются гло-
бальными (доступны в любой функции) или локальными (доступны в преде-
лах функции или основной программы). Первый вариант размещения дает
глобальные переменные, второй и третий — локальные. Если локальных пе-
ременных немного, компилятор использует для их хранения регистры обще-
го назначения R0–R12. Это сокращает расход памяти и увеличивает быстро-
действие программы. Поэтому локальным переменным следует отдавать
предпочтение.
Помимо переменных могут также использоваться именованные кон-
станты. Объявляются они также, но с ключевым словом const.
const Тип Имя1 = Значение1, Имя2 = Значение2, ... ;
Пример:
const double pi=3.141592653589793238462643383;
Так можно создавать массивы данных, объем которых превышает
объем оперативной памяти. Константы при этом размещаются в ПЗУ.
103
2.2.4 Оператор присваивания, выражения и операции
Общая форма оператора присваивания такова
Переменная = Выражение ;
Допустимо присваивание нескольким переменным одного и того же
значения в одном операторе
Переменная1 = Переменная2 = ... = Выражение ;
Выражения конструируются с участием других переменных, число-
вых констант и знаков арифметических и логических операций. Выполнение
операций выполняется в порядке их приоритетов.
Основные операции с комментариями и примерами приведены в таб-
лице 2.2.1. В правой колонке указаны приоритеты операций (1 — самый вы-
сокий, 12 — самый низкий). Для изменения приоритета, как обычно, служат
круглые скобки «( )». Операции над выражениями в скобках имеют первый
(высший) приоритет.
Часто новое значение переменной рассчитывается с использованием
старого. Тогда одна и та же переменная оказывается и слева, и справа от зна-
ка присваивания. В этом случае удобна сокращенная форма записи оператора
присваивания, которая имеет следующий общий вид.
Переменная Операция = Выражение ;
Эта запись тождественна следующей привычной форме
Переменная = Переменная Операция (Выражение) ;
Здесь скобки показывают, что какой бы ни была Операция, Выражение вы-
числяется в первую очередь, потому что сокращенная форма имеет низший
14-ый приоритет. В качестве примера рассмотрим две команды, которые да-
дут одинаковый результат.
A=A*(B+С);
A*=B+С;
2.2.5 Условный оператор
Условный оператор предназначен для выбора одного из выражений в
зависимости от некоторого условия. Обычно с целью присваивания. Форма
записи условного оператора следующая
Условие ? Выражение1 : Выражение2 ;
Результатом является Выражение1, если Условие не равно нулю. В
противном случае, результат — Выражение2.
Приведем пример.
A=B+(C<0?-1:1);
Здесь переменной A будет присвоено значение B, увеличенное или умень-
шенное на единицу в зависимости от знака переменной C.
2.2.6 Приведение и преобразование типов
Если в выражении участвуют операнды разных типов, то они приво-
дятся к одному типу по следующим правилам:

104
Таблица 2.2.1 – Основные операторы языка Си
Опер. Описание Пример Примечание Приор.
* Обращение по адресу *A Обращение к данным, по адресу в указателе 2
& Взятие адреса &A Возвращает 32-разрядный адрес переменной или константы 2
! Логическое НЕ !A Результат 1, если операнд равен 0, иначе 0 2
~ Поразрядное НЕ ~A 2
++ Инкремент ++A или A++ Увеличение операнда на 1 до или после использования 2
–– Декремент ––A или A–– Уменьшение операнда на 1 до или после использования 2
* Умножение A*B 3
Для целочисленных операндов дает целую часть от деления,
/ Деление A/B 3
округленную до меньшего по модулю
% Остаток от деления A%B Только для целочисленных операндов 3
+ Арифметическое сложение A+B 4
– Арифметич. вычитание A–B 4
>> Сдвиг вправо A >> B 5
Второй операнд обозначает число разрядов сдвига
<< Сдвиг влево A << B 5
> Больше A>B 6
< Меньше A<B 6
Результат 1, если неравенство справедливо, иначе 0
>= Больше или равно A >= B 6
<= Меньше или равно A <= B 6
== Равно A == B Результат 1, если неравенство или равенство 7
!= Не равно A != B справедливо, иначе 0 7
& Поразрядное И A&B 8
^ Поразрядное исключ. ИЛИ A^B 9
| Поразрядное ИЛИ A|B 10
&& Логическое И A && B Результат 1, если оба операнда не равны 0, иначе 0 11
|| Логическое ИЛИ A || B Результат 1, если один из операндов не равен 0, иначе 0 12
105
1. Приведение типов выполняется попарно в порядке приоритетов
операций. То есть, сначала приводятся типы операндов связанных операцией
с наивысшим приоритетом.
2. Если в операции участвуют знаковые и беззнаковые операнды, ре-
зультат приводится к беззнаковому типу. Знак теряется.
3. Если в операции участвуют операнды разной длины, то результат
будет иметь длину наибольшего из операндов. Правило касается как чисел с
фиксированной точкой, так и с плавающей.
4. Если в операции участвуют операнды с фиксированной и с плава-
ющей точкой, результат приводится к формату с плавающей точкой.
Пример 1:
int A=75, B=10;
double C;
...
C=A/B; // C=7
Здесь операнды имеют один и тот же тип. Поэтому преобразование типов не
производится, несмотря на то, что для сохранения результата деления без по-
терь информации необходим формат с плавающей точкой.
Нередко это становится причиной ошибок даже с константами.
X=Y/2;
даст всегда целый результат, потому что 2 интерпретируется как целочис-
ленная константа, в то время как
X=Y/2.0;
дает дробный результат, если X вещественного типа (float или double).
Пример 2:
int A=–1;
unsigned int B=10;
double C=1, D;
...
D=A*B*C; // D=4294967286
Результат умножения A*B в соответствии с правилом 2 получает беззнаковый
тип. В то же время изменение порядка множителей даст другой результат.
int A=–1;
unsigned int B=10;
double C=1, D;
...
D=C*A*B; // D=–10
Результат умножения C*A в соответствии с правилом 4 сразу приводится к
формату с плавающей точкой, поэтому в дальнейшем потери знака не проис-
ходит.
В рамках выражения можно принудительно преобразовать тип одного
из операндов или части выражения, указав перед ним тип в скобках.
int A=–1;

106
unsigned int B=10;
double D;
...
D=(int)(A*B); // D=-10
И то же с примером 1:
int A=75, B=10;
double C;
...
C=(double)A/B; // C=7.5
C=A/(double)B; // C=7.5
2.2.7 Массивы
Массив — это совокупность однотипных элементов, которые иденти-
фицируются по индексу или нескольким индексам.
Одномерные массивы объявляются следующим образом
Тип Имя[Размерность]={Значениие1, ... ,ЗначениеN};
Массивы могут быть многомерными. Рассмотрим синтаксис для дву-
мерных массивов.
Тип Имя[Размерность1][Размерность2]=
{{Знач.11, ... ,Знач.1N}, ... ,{Знач.M1, ... ,Знач.MN}};
Начальные значения при объявлении присваивать не обязательно. В
то же время, если присваивание выполняется, можно не указывать размер-
ность, поставив две скобки подряд «[]». Тогда размерность автоматически
определяется числом элементов в фигурных скобках.
Обращение к элементам массива производится с указанием индексов
в квадратных скобках
A[5]
B[m][n]
В Си индексация элементов массива всегда начинается только с нуля.
Индекс является смещением относительно базового адреса.
Часто применяется компактная запись, сочетающая обращение к эле-
менту массива с изменением индекса:
A[k++]=...
...=B[m][++n]
В первом случае выборка элемента массива из памяти предшествует инкре-
менту индекса, во втором используется уже инкрементированный индекс.
2.2.8 Строки символов
Строка представляет собой одномерный массив элементов типа char,
последний из которых всегда равен нулю (обозначает конец строки). Строко-
вые константы записываются в двойных кавычках. Ниже приведены эквива-
лентные примеры
char S[7]="Превед";
char S[7]={'П','р','е','в','е','д',0};

107
Обратим внимание на то, что в основной программе строковую кон-
станту нельзя присвоить строковой переменной, также как нельзя одной ко-
мандой присвоить значение массиву. Это допустимо только в разделе объяв-
ления переменных. Вместе с тем строковые константы, заключенные в ка-
вычки могут быть параметрами функций.
Для символов, которые невозможно набрать с клавиатуры, преду-
смотрено специальное обозначение: «\xКод». Код используется шестнадца-
теричный. Например
"I \x01 ARM7" // Дает "I ♥ ARM7"
2.2.9 Структуры
Структура, в отличие от массива, — это совокупность разнотипных
данных, называемых полями, идентифицируемых по имени. Среди полей мо-
гут быть и массивы. Объявление структуры имеет вид
struct
{
Объявление1 ;
...
ОбъявлениеN ;
} Имя ;
При обращении к элементам структуры ее имя отделяется от имени
поля точкой, например
Structure1.Field2=...
Может быть задано начальное значение, например:
struct
{
int Header;
int CRC;
char Data[8];
} Frame={0x12345678,0,{1,2,3,4,5,6,7,8}};
2.2.10 Объединения
Объединения дают возможность обращаться к одной и той же области
памяти, как к данным разных типов.
union
{
Объявление1 ;
...
ОбъявлениеN ;
} Имя ;
Обычно (но не обязательно) все элементы объединения имеют одну и
ту же длину. Приведем пример записи области памяти как массива четырех
байтов и чтения той же области уже как числа с плавающей точкой, состоя-
щего из этих байтов.

108
union
{
float F;
char C[4];
} Buffer;
...
for (k=0; k<4; k++) Buffer.С[k]=...;
...=Buffer.F;
2.2.11 Указатели
Указатель представляет собой 32-разрядную величину, хранящую ад-
рес переменной произвольного типа. При объявлении указателя после типа
данных ставится символ «*», например,
float* F;
Фактически с помощью указателей в Си реализуется косвенная адре-
сация. Присваивание указателю числовой константы недопустимо, в принци-
пе возможно и осуществляется так.
Имя_указателя = ( Тип* ) Значение;
Например, в нашем случае
F=(float*)0x40000010;
Однако это изменит не данные, а адрес, на который ссылается указатель. При
программировании для ARM7 распределение памяти, как правило, полно-
стью доверяется компилятору. В таком случае с уверенностью сказать, что
конкретный адрес памяти свободен, — невозможно. Поэтому инициализация
(присваивание значения) указателя обычно выполняется так
F=&D;
Здесь D — имя переменной, а & оператор взятия адреса (таблица 2.2.1). Такая
команда приведет к тому, что указатель F будет ссылаться на переменную D.
Для обращения к самим данным используется такой синтаксис
*F=23; // Запись по адресу, хранящемуся в F
...=*F; // Чтение адреса, хранящегося в F
Здесь * — оператор обращения по адресу (таблица 2.2.1).
В нашем примере следующие операции будут идентичны.
*F=...;
D=...;
В сущности, массивы тоже являются указателями на нулевой элемент
(базовый адрес). Поэтому наряду с традиционным обращением к массиву
M[2]=100;
вполне допустимо
*(M+2)=100;
2.2.12 Ветвление
Конструкция ветвления имеет следующую структуру

109
if ( Выражение )
{
... ; // Блок операторов 1
}
else
{
... ; // Блок операторов 2
}
Здесь Выражение — любое арифметическое выражение целого типа.
Если это Выражение имеет ненулевое значение, выполняется блок операто-
ров 1, иначе — блок операторов 2. Такую форму записи можно назвать пол-
ной. Сокращенная форма записи не содержит ветви else.
Если блок операторов состоит лишь из одной команды, то оператор-
ные скобки { } можно опустить.
Пример 1
if ((A>0) && B) // Выполнить операторы 1–2, если
{ // A>0 и B≠0
Оператор 1 ;
Оператор 2 ;
}
Else // Иначе выполнить оператор 3
Оператор 3 ;
Отметим, что в Си допустимо совмещать вычисления и проверку
условия. Приведем несколько примеров.
Пример 2.
if (--k==0) // Декремент k, если результат
{ // равен нулю, то выполнять операторы
Операторы ;
}
Пример 3.
if (k++>100) // Если k>100, то выполнять операторы
{ // После проверки увеличить k на 1
Операторы ;
}
Пример 4.
if (A|=B) // Присвоить A поразрядное ИЛИ A и B
{ // Выполнять операторы, если результат ≠0
Операторы ;
}
2.2.13 Множественное ветвление
Конструкция множественного ветвления имеет следующую структуру
switch ( Выражение )

110
{
case Значение1:
... ; // Блок операторов 1
break;
case Значение3:
... ; // Блок операторов 3
break;
...
default
... ; // Блок операторов N
}
Выполняется условный переход на одно из Значений Выражения. Ес-
ли ни одно из указанных Значений не соответствует реальному значению, то
происходит переход на точку default. Заметим, что после выполнения лю-
бого блока операторов будет продолжено выполнение операторов всех дру-
гих блоков ниже, если в конце не дать команду выхода break.
2.2.14 Цикл со счетчиком
Конструкция цикла со счетчиком имеет вид
for (Команда1; Выражение; Команда2)
{
... ; // Операторы
}
Команда1 выполняется перед выполнением всего цикла; обычно со-
держит команду присваивания счетчику начального значения. Цикл повторя-
ется пока Выражение не равно нулю; как правило, Выражение имеет вид
операции отношения вида
Счетчик < Предельное_значение
Команда2, чаще всего представляет собой инкремент или декремент счетчи-
ка, например k++. Команда1 и Команда2 могут отсутствовать. В качестве
вечного цикла можно использовать конструкцию
for (;;)
{
... ; // Операторы
}
Оператор continue досрочно прекращает текущую итерацию и
начинает следующую; оператор break досрочно завершает весь цикл.
2.2.15 Циклы с предусловием и постусловием
Конструкция цикла с предусловием имеет вид
while (Выражение)
{
... ; // Операторы
}

111
Тело цикла выполняется по крайней мере один раз независимо от зна-
чения Выражения, а затем повторяется пока целочисленное Выражение не
равно нулю. Часто используется такая конструкция для вечного цикла
while (1)
{
... ; // Операторы
}
Конструкция цикла с предусловием имеет вид
do
{
... ; // Операторы
} while (Выражение)
Если Выражение равно нулю, тело цикла не выполняется ни разу.
Здесь также допустимо использование операторов continue и break.
2.2.16 Функции
Функция объявляется по шаблону
Тип Имя(Параметр1,...,ПараметрN)
{
... ; // Тело функции
return Выражение ;
}
Если не предполагается возврат результата и включение функции в
правую часть оператора присваивания, то в качестве типа указывается пустой
тип void и оператор return опускается. Список параметров также может
быть опущен.
Вызов функции осуществляется по ее имени, после которого в скоб-
ках перечисляются параметры. Скобки обязательны, даже если параметры
отсутствуют.
С сущности в Си не существует понятия выходных параметров. Ре-
зультат может присваиваться только самой функции. Разумеется, часто этого
недостаточно.
Для того чтобы функция могла возвращать измененные данные в ос-
новную программу, в качестве параметра функции передают указатель на пе-
ременную, массив или структуру. Сам параметр и в этом случае остается
неизменным, но функция получает возможность записи в область памяти, на
которую ссылается указатель и доступную для чтения в основной программе.
При объявлении функции такие параметры описывают как указатели
(с символом * перед именем), а при вызове функции передают не саму пере-
менную, а адрес (указывая перед именем символ взятия адреса &).
Ниже приведен пример функции, иллюстрирующий передачу не-
скольких параметров, в том числе массива С.
int Function(char A, int *B, char *C)
{

112
A+=10;
C[5]=*B+A;
*B=0;
return 1;
}
int main()
{
A=5; B=10; C[5]=20;
D=Function(A,&B,C); //A=5,B=0,C[5]=25,D=1
}
Здесь при вызове функции ей передается входной параметр A (без возможно-
сти изменения) и два выходных параметра (с возможностью изменения): це-
лое B и массив C. Видно, что в результате выполнения функции A не измени-
лась, несмотря на то, что внутри функции ей присвоено новое значение. В то
же время изменилась переменная B и пятый элемент массива C. Переменная D
получила единичное значение, возвращенное через команду return.
2.2.17 Некоторые директивы компилятора
Директивы не являются частью программы и не компилируются в ин-
струкции процессора, а управляют процессом компиляции. Здесь коснемся
лишь двух наиболее часто встречающихся директив
Директива присоединения файла.
#include "Имя_файла"
или
#include <Имя_файла>
В Си-программу будет «вшит» заданный файл. Это может быть файл заго-
ловков (*.h), в котором описаны переменные, константы или функции, а мо-
жет быть другая Си-программа (*.C).
Если имя указано в двойных кавычках, то поиск файла будет осу-
ществляться сначала в текущем каталоге, где находится проект, а затем, в
стандартных каталогах компилятора. Если использованы треугольные скобки
(знаки «больше» и «меньше»), то поиск в текущем каталоге будет пропущен.
Директива подстановки имеет следующий вид.
#define Имя Значение
Такая команда вводит символическое обозначение Имя для Значения.
Далее вместо имени будет подставляться присвоенное ему значение. В отли-
чие от переменной память для постоянного хранения данных при этом не
выделяется.
2.2.18 Библиотека математических функций MATH.h
Для использования в программе математических функций необходи-
мо в начале подключить библиотеку директивой
#include <math.h>
При этом станут доступны функции, приведенные в таблице 2.2.2.

113
Таблица 2.2.2 – Основные математические функции библиотеки MATH.h
Функция Объявление функции Описание Действие
Основные
abs(x) int abs(int x) модуль целого аргумента
cbrt(x) double cbrt(double x) кубический корень
exp(x) double exp(double x) экспонента
expm1(x) double expm1(double x) экспонента, уменьшенная на единицу
fabs(x) double fabs(double x) модуль вещественного аргумента
hypot(x,y) double hypot(double x, double y) корень из суммы квадратов аргументов
ldexp(x) double ldexp(double x, int n) возвращает значение , целое
log(x) double log(double x) натуральный логарифм
log10(x) double log10(double x) десятичный логарифм
log1p(x) double log1p(double x) натуральный логарифм
sqrt(x) double sqrt(double x) квадратный корень
pow(x,y) double pow(double x, double y) возводит в степень
Округление, остаток от деления, выделение целой и дробной части
ceil(x) double ceil(double x) округление до большего целого
floor(x) double floor(double x) округление до меньшего целого
fmod(x,y) double fmod(double x, double y) остаток от деления на
возвр. нормализованную мантиссу числа
frexp(x,&n) double frexp(double x, int *n)
и экспоненциальную часть , как степень 2
modf(x,&I) double modf(double x, double *I) возвр. дробную часть , — целая часть
Тригонометрические и обратные тригонометрические
asin(x) double asin(double x) арксинус
acos(x) double acos(double x) арккосинус
atan(x) double atan(double x) арктангенс

114
Таблица 2.2.2 – Продолжение
Функция Объявление функции Описание Действие
atan2(x) double atan2(double x, double y) арктангенс отношения
cos(x) double cos(double x) косинус
sin(x) double sin(double x) синус
tan(x) double tan(double x) тангенс
Гиперболические и обратные гиперболические
acosh double acosh(double x) гиперболический арккосинус
asinh double asinh(double x) гиперболический арксинус
atanh double atanh(double x) гиперболический арктангенс
cosh(x) double cosh(double x) гиперболический косинус
sinh(x) double sinh(double x) гиперболический синус
tanh(x) double tanh(double x) гиперболический тангенс
Специальные
erf(x) double erf(double x) функция ошибок
erfc(x) double erfc(double x) дополнительная функция ошибок
lgamma(x) double lgamma(double x) логарифм гамма-функции
Тестирование чисел в формате IEE754
возвращает единицу, если
isfinite(x) double isfinite(double x)
не равен бесконечности
возвращает единицу, если
isinf(x) double isinf(double x)
равен бесконечности
возвращает единицу, если
isnan(x) double isnan(double x)
равен неопределенности
signbit(x) int signbit(double x) возвращает знаковый разряд числа

115
2.2.19 Функция создания форматированных строк SNPRINTF
Функция snprintf входит в библиотеку STDIO.h, которая подключается
директивой
#include <STDIO.h>
Основное назначение функции — перевод двоичной числовой инфор-
мации в десятичную (или другую) систему счисления, представление в фор-
мате, удобном для восприятия человеком.
snprintf(S,L,"Формат",N1,N2,...);
Здесь S — переменная строкового типа (массив char), в которую сохраняется
результат; L — целочисленная константа, на единицу превышающая число
символов в строке S; «Формат» — строка, определяющая форматирование
(см. ниже), N1, N2 и т. д. — числовые переменные или константы.
Строка формата — это произвольный текст, в который внедрены спе-
циальные символы форматирования. Функция snprintf повторит этот текст в
переменной S, а в место символов форматирования подставит числа N1, N2
по порядку. Числа будут соответствующим образом отформатированы.
Каждое обозначение формата начинается с символа «%», за которым
следуют несколько необязательных символов и один обязательный указатель
типа (рисунок 2.2.1).
Необязательные

% F W .P L T

Флаги: Длина Точность Модиф. Тип:


–, + , #, (число) (число) длины: d, u, o,
пробел h, hh x, X, f, e

Рисунок 2.2.1 – Строка формата


В таблицах 2.2.3–2.2.4 приведены возможные значения полей «Тип»,
«Флаги» и «Модификатор длины». Флагов может быть указано сразу не-
сколько подряд.
Поле «Длина» (W) определяет число позиций, отводимых для пред-
ставления форматированного числа. Если число короче, оно дополняется
пробелами слева или справа в зависимости от флага «–». Если число длиннее,
то формат будет нарушен и длина строки увеличена.
Поле «Точность» (P), отделяемое от поля «Длина» точкой для дроб-
ных типов (f/F, e/E) устанавливает число точек после запятой для дробной
части числа (мантиссы). Если точность не указана, подразумевается 6 знаков
после запятой. Для целых чисел определяет число позиций, которое достига-
ется добавлением слева незначащих нулей.
Символ «x» или «X» определяет, малые или прописные буквы исполь-
зуются для обозначения шестнадцатеричных цифр («a»–«f» или «A»–«F»).
Малая или приписная буква f/F или e/E в поле формата определяет,
малые или прописные буквы (e/E) используются для отделения мантиссы от
порядка, а также обозначения бесконечности (inf/INF) и неопределенности
(nan/NAN).

116
Таблица 2.2.3 – Возможные значения поля «Тип»
Тип Пояснения
d Десятичное целое со знаком
u Десятичное целое без знака
o Восьмеричное целое
x, X Шестнадцатеричное целое
f, F Дробный формат
e, E Экспоненциальный формат
Таблица 2.2.4 – Возможные значения поля «Флаг»
Флаг Пояснения
Выравнивание по левому краю. Если длина строки (W) превышает
– фактическое число символов, строка дополняется нулями справа. По
умолчанию — слева (выравнивание по правому краю).
+ Отображать знак «+» для положительных чисел
Обозначать восьмеричные числа нулем слева, а шестнадцатеричные
#
символами «0x» или «0X» в зависимости от формата «x» или «X»
Дополнять слева пробелом положительные числа, резервируя пози-
пробел
цию под знак «–»
Таблица 2.2.5 – Примеры применения функции snprintf для форматирования
Числовая переменная Формат Результат
int N=123; snprintf(S,11,"%d V",N) –123˽V˽˽˽˽
int N=–123; snprintf(S,11,"%8d V",N) ˽˽˽˽–123˽V
snprintf(S,11,"%-8d V",N) 123˽˽˽˽˽˽V
int N=123; snprintf(S,11,"%8.8d V",N) 00000123˽V
snprintf(S,11,"% 8d V",N) ˽˽˽˽˽123˽V
snprintf(S,11,"% 8d V",N) ˽˽˽˽–123˽V
int N=–123;
snprintf(S,11,"%8.5d V",N) ˽˽–00123˽V
snprintf(S,11,"%+8d V",N) ˽˽˽˽+123˽V
int N=123;
snprintf(S,11,"%o",N) 710˽˽˽˽˽˽˽
snprintf(S,11,"%u",N) 4294968173
snprintf(S,11,"%x",N) ffffff85˽˽
snprintf(S,11,"%X",N) FFFFFF85˽˽
int N=–123;
snprintf(S,11,"%#x",N) 0xffffff85
snprintf(S,11,"%hX",N) FF85˽˽˽˽˽˽
snprintf(S,11,"%hhX",N) 85˽˽˽˽˽˽˽˽
snprintf(S,11,"%f",N) 3.141593˽˽
snprintf(S,11,"%8.4f",N) ˽˽3.1416˽˽
snprintf(S,11,"%.2рад",N) 3.14рад˽˽˽
float N=3.1415927; snprintf(S,11,"%-7.2fрад",N) 3.14˽˽˽рад
snprintf(S,11,"%+-7.2fрад",N) +3.14˽˽рад
snprintf(S,11,"%5.3e",N) 3.142e+00˽
snprintf(S,11,"%5.3E",N) 3.142E+00˽
117
Модификатор длины «h» заставляет считать число двухбайтным, а
«hh» — однобайтным независимо от истинного размера переменной.
Обращаем внимание на то, что функция snprintf не поддерживает тип
long long.
Таблица 2.2.5 содержит множество полезных примеров формирования
строки S из 10 символов, объявленной как char S[11].
2.2.20 Ассемблер в Си-программах
Раздел 2.6 посвящен составлению программы на ассемблере без уча-
стия Си-компилятора. Здесь речь пойдет о внедрении кода на ассемблере в
Си-программу.
Как известно, код, генерируемый Си-компилятором, в некоторой сте-
пени избыточен. Поэтому он неоптимален с точки зрения быстродействия и
(или) объема. С целью оптимизации в Си-программы внедряют фрагменты,
составленные на ассемблере. Компилятор RealView 4 поддерживает два спо-
соба, так называемые, «внедряемый ассемблер» (Embedded Assembler) и
«встраиваемый ассемблер» (Inline Assembler).
Блок внедряемого ассемблера имеет формат
asm
{
... ; // Инструкции ассемблера
}
Использование внедряемого ассемблера ограничено несколькими об-
стоятельствами:
а) вместо регистров используются «виртуальные регистры», то есть
компилятор вправе размещать данные, обозначенные как R0–R12 в произ-
вольных регистрах общего назначения;
б) доступ к регистрам R13–R15 невозможен;
в) если оптимизация кода в настройках компилятора включена, то она
будет применена и к коду внедряемого ассемблера; так что точное совпаде-
ние инструкций и исполнимого кода не гарантируется;
Фрагмент встраиваемого ассемблера всегда оформляется как функция:
asm void Имя_функции(Параметры)
{
... ; // Инструкции ассемблера
}
Ограничения, перечисленные выше для внедряемого ассемблера,
здесь не действуют. Отметим, что практически код повторяется в точности.
Так что даже команда возврата из подпрограммы (bx LR) автоматически не
будет сгенерирована компилятором.
Пример использования встраиваемого ассемблера для формирования
временной задержки рассмотрен в практическом занятии №2 (раздел 3.2.6).

118
2.3 Интегрированная среда разработки Keil µVision 4
Интегрированная среда Keil µVision — широко известное средство
разработки для микроконтроллеров. Причина ее популярности в поддержке
нескольких семейств микроконтроллеров: Intel MCS-51, Intel MCS-251, ARM
многих модификаций и Infineon XC166.
Keil µVision включает реактор исходных текстов программы; ассем-
блер; Си-компилятор; симулятор, моделирующий работу микроконтроллера;
поддержку нескольких внутрисхемных отладчиков и трассировщиков.
В данном разделе коротко рассмотрим основные приемы работы с ин-
тегрированной средой разработки Keil µVision 4.
Этот программный продукт является весьма дорогостоящим, однако в
учебных целях может свободно использоваться некоммерческая версия с
ограничением объема используемой памяти 32 кбайта. Этого вполне доста-
точно для полноценного обучения программированию.
2.3.1 Создание проекта
Стандартный ярлык для запуска среды Keil µVision изображен на ри-
сунке 2.3.1.

Рисунок 2.3.1 – Пиктограмма среды Keil µVision 4


Компоненты создаваемой программы объединяются в проект. Проект
хранит информацию о размещении файлов на диске, параметрах настройки
среды и других задействованных средств. Все файлы проекта должны раз-
мещаться в отдельном каталоге на диске. Поэтому прежде чем начинать со-
здание нового проекта, необходимо создавать для него каталог и в дальней-
шем следить, чтобы именно в него сохранялись все файлы.
Для создания нового проекта необходимо:
а) Воспользоваться пунктом меню Project  New μVision Project.
При этом откроется стандартное окно сохранения файла.
б) Перейти в папку проекта и сохранить проект.
в) Выбрать тип контроллера, для которого разрабатывается программа
(см. рисунок 2.3.2). В нашем случае — NXP (Founded by Philips) 
LPC2148. Внимание! На вопрос «Copy Philips LPC2000 Startup Code to
Project Folder and Add File to Project?» следует ответить «Да».
2.3.2 Создание файла программы
Файл программы представляет собой текстовый файл с расширением
*.С (программа на языке Си) или .S (программа на ассемблере). Для создания
файла необходимо выполнить следующие операции:
а) Создать новый файл командой меню File  New.
б) Сохранить файл командой File  Save. Сохранять файл необходи-
мо в папку проекта. Имя файла требуется вводить с расширением *.С.

119
Рисунок 2.3.2 – Диалоговое окно выбора типа микроконтроллера

Рисунок 2.3.3 – Контекстное меню группы Рисунок 2.3.4 – Состав


исходных текстов Source Group 1 исходных текстов проекта
в) Щелчком правой кнопки мыши по пункту Source Group 1 окна
проекта (рисунок 2.3.3) открыть его контекстное меню.
г) Воспользоваться пунктом Add Files to Group… и выбрать файл
программы (*.C) в открывшемся диалоговом окне. Имя файла программы
должно появиться в окне проекта (рисунок 2.3.4).
Созданный однажды проект в дальнейшем открывается командой ме-
ню Project  Open Project…
2.3.3 Настройка проекта
Доступ к настройкам проекта открывается из контекстного меню про-
екта (рисунок 2.3.5); пункт Options for Target…:

120
Рисунок 2.3.5 – Контекстное меню проекта
По умолчанию отладка программы производится в режиме симуля-
ции. Симулятор моделирует работу реального микроконтроллера. Можно
наблюдать за пошаговым выполнением программы, за состоянием регистров,
содержимым памяти и течением модельного времени.
Если вместо компьютерной имитации работы программы предполага-
ется загрузка кода в память микроконтроллера и внутрисхемная отладка, то
необходимо настроить взаимодействие с отладочной аппаратурой.
Выбор режима: симуляция или внутрисхемная отладка, производится
переключателем Use на вкладке Debug окна свойств проекта. Настройку
внутрисхемного отладчика рассмотрим на примере прибора J-Link.
Для перехода в режим аппаратной отладки следует установить пере-
ключатель Use в правое положение; в выпадающем списке выбрать J-LINK /
J-TRACE; включить опции Load Application at Startup и Run to main() (ри-
сунок 2.3.6).
Рекомендуется также вызвать диалог настройки отладчика кнопкой
Settings; в нем установить адаптивный выбор тактовой частоты опцией
Adaptive Clocking (рисунок 2.3.7) и режим сброса Hardware, halt after reset
using WP.
Внимание! Следует отметить еще одну опцию — флаг Use Memory
Layout from Target Dialog на вкладке Linker (рисунок 2.3.16). Эта опция
должна быть включена.
Отметим, что среда Keil µVision 4 не содержит средств для загрузки
программы в память микроконтроллера через последовательный интерфейс
RS-232, что поддерживается микроконтроллером LPC2148 наряду с интер-
фейсом отладки JTAG. Загрузки по RS-232 требует применения дополни-
тельных программ (см. раздел 1.5.3). Такие программы импортируют ском-
пилированный код через объектный файл в формате Intel HEX, предвари-
тельно созданный в Keil µVision. Для создания HEX-файла следует на вклад-
ке Output включить опцию Create HEX File.

121
Рисунок 2.3.6 – Выбор симулятора или отладчика

Рисунок 2.3.7 – Настройка внутрисхемного отладчика J-Link


2.3.4 Набор текста программы
Исходный текст программы на языке ассемблера или Си вводится в
окно текстового редактора (в соответствии с расширением имени файла).
Си программа начинается с директивы подключения h-файла, содер-
жащего описания регистров специальных функций микроконтроллера (в
нашем случае типа LPC214x).
#include <LPC214x.h>
Это позволяет обращаться ко всем регистрам специальных функций микро-
контроллера по стандартным именам, как к переменным.
Практически любая программа содержит вечный цикл, например,
оформленный в виде конструкции
while (1) { ... }

122
Простейшая программа, не содержащая функций, составляется по
следующему шаблону.
#include <LPC214x.h>
... // Объявление функций и глобальных переменных
int main(void)
{
... // Объявление локальных переменных и настройка
while (1)
{
... // Основной цикл программы
}
}
2.3.5 Компиляция программы
На этапе компиляции будет создан объектный код, готовый к записи в
память программ микроконтроллера. Компиляция выполняется нажатием
кнопки F7. При этом формируется отчет, который можно просмотреть в окне
Build Output в нижней части основного окна Keil µVision. В отчете, прежде
всего, следует обратить внимание на число ошибок (Errors) и предупрежде-
ний (Warnings). На рисунке 2.3.8 приведен пример отчета с ошибками, а на
рисунке 2.3.9 — без ошибок.

Рисунок 2.3.8 – Отчет о компиляции Си-программы, содержащей ошибки

Рисунок 2.3.9 – Отчет о компиляции Си-программы без ошибок и предупреждений


При наличии ошибок их необходимо исправить. Строка отчета, ин-
формирующая об ошибке, содержит имя файла, номер ошибочной строки,
код и описание ошибки. Ниже приведена сама строка, содержащая ошибку, в
которой символом «^» указана позиция ошибки. Двойным щелчком мыши по
сообщению об ошибке можно быстро переместиться на строку программы,
содержащую ошибку.
Предупреждения практически допустимы, но нежелательны. При
компиляции предложенной здесь простейшей программы их быть не должно.
Кроме информации об ошибках и предупреждениях в отчете приво-
дятся сведения о расходе памяти: программ (Code), констант, хранимых в
123
оперативной памяти (RO-data), переменных (RW-data), объем памяти, вы-
деленной под стек и динамически распределяемой памяти (ZI-data). Данная
программа не потребует памяти данных, поскольку для единственной пере-
менной k компилятор использует один из регистров общего назначения.
2.3.6 Отладка программы
Переключение между режимом редактирования программы и отладки
производится комбинацией клавиш Ctrl+F5. В случае внутрисхемной отладки
код программы при этом автоматически загружается в память программ мик-
роконтроллера, и выполняются все команды до входа в основную программу
main (см. раздел 2.2.3 и рисунок 2.3.6).
Общий вид окна среды Keil µVision 4 в режиме отладки показан на
рисунке 2.3.10.
Перечислим основные элементы интерфейса среды Keil µVision 4:
1. Панель инструментов управления трассировкой содержит кнопки
запуска, остановки и пошагового выполнения программы (см. таблицу 2.3.1).
2. Окно просмотра содержимого регистров общего назначения
R0–R15 и слова состояния программы CPSR.
3. Метки зеленого цвета видны только в режиме симуляции. Они от-
мечают строки программы, которые были выполнены, по крайней мере, один
раз. Большие фрагменты программы, оставшиеся неотмеченными даже после
длительной работы программы, нередко свидетельствуют об ошибке. Это
может значить, что в программе есть части, которые никогда не выполняют-
ся, например, из-за зависания программы.
4. Стрелка желтого цвета — программный курсор. Показывает коман-
ду Си-программы, которую предстоит выполнить на следующем шаге трас-
сировки.
5. Меткой темно серого цвета отмечены строки, содержащие скомпи-
лированную команду Си. Команда, не отмеченная темно серым цветом, чаще
всего говорит о распространенной среди начинающих ошибке —
программист внес изменения в программу и забыл скомпилировать.
6. Красный прямоугольник показывает точку останова. Выполнение
программы будет прекращено при достижении точки останова.
7. PC $ — значение счетчика команд. Содержит адрес команды, кото-
рую предстоит выполнить на следующем шаге трассировки. Совпадает с ре-
гистром R15 и соответствует положению программного курсора (4).
8. Mode — индикатор режима ядра микроконтроллера (см. раздел
1.2.1 и рисунок 1.2.1).
9. States — счетчик машинных тактов, прошедших с момента запуска
программы.
10. Sec — время выполнения программы в режиме симуляции (в се-
кундах). Равно отношению числа тактов к тактовой частоте, заданной в свой-
ствах проекта Options for Target `Target 1`  Target  Xtal (MHz).
11. Программный курсор окна дизассемблера. Показывает инструк-
цию ядра, которую предстоит выполнить на следующем шаге трассировки.

124
1
18
2
17
11
3 16
4
5
12
6

14 15

13
7
8
9
10

1 – панель управления трассировкой; 6 – точка останова; 12 – окно дизассемблера; 17 – логический анализатор и


2 – регистры общего назначения; 7 – счетчик команд; 13 – окно просмотра переменных; хронометраж;
3 – выполненные команда Си; 8 – режим ядра; 14 – окно редактора Си-программы; 18 – панель управления точками
4, 11 – программные курсоры; 9, 10 – число тактов и время 15 – отчет о компиляции; останова
5 – скомпилированная строка; выполнения программы; 16 – вкладка файла конфигурации;
Рисунок 2.3.10 – Основное окно Keil µVision 4 в режиме отладки
125
Таблица 2.3.1 – Основные команды отладчика Keil μVision 4
Сочетание
Операция Кнопка Пункт меню
клавиш
Компиляция F7 Project  Build target
Режим «Программи- Debug  Start/Stop Debug
Ctrl+F5
рование» / «Отладка» Session
Запуск программы F5 Debug  Run
Остановка программы Debug  Stop
Системный сброс Debug  Reset CPU
Пошаговое
выполнение с заходом F11 Debug  Step
в подпрограммы
Пошаговое
выполнение без захода F10 Debug  Step Over
в подпрограммы
Выполнение до выхо-
Ctrl+F11 Debug  Step Out
да из подпрограммы
Выполнение
Ctrl+F10 Debug  Run To Cursor Line
до позиции курсора
Debug 
Точка останова F9
 Insert/Remove Breakpoint
Удалить все точки Ctrl+
Debug  Kill All Breakpoints
останова +Shift+F9
Счетчик команд PC содержит адрес инструкции, на которую указывает этот
программный курсор.
12. Окно дизассемблера. Содержит инструкции ядра, сгенерирован-
ные компилятором на основе текста Си-программы (см. разделы 1.3, 1.4). Ли-
стинг оформлен в четыре колонки: адрес команды, код команды, мнемониче-
ское обозначение команды и список операндов. Темно красным цветом вы-
делена строка исходного текста программы, для которой ниже приведен ди-
зассемблированный код.
13. Окно просмотра переменных Watch служит для наблюдения за
значениями переменных и их редактирования. Добавление новой переменной
к списку осуществляется нажатием кнопки F2.
14. Окно редактора исходного текста программы.
15. В окно отчета о компиляции выводится информации об ошибках и
предупреждениях, а также о расходе памяти микроконтроллера.
16. Вкладка редактора файла конфигурации Startup.s, генерируемого
автоматически и содержащего команды ассемблера для инициализации мик-
роконтроллера.
17. Кнопка вызова отладочных инструментов хронометража (Perfor-
mance Analyzer) и логического анализатора (Logic Analyzer).
126
18. Панель инструментов для управления точками останова.
Назначение наиболее часто используемых пунктов меню и соответ-
ствующих кнопок приведены в таблице 2.3.1. Способы вызова диалоговых
окон, необходимых для слежения за состоянием микроконтроллера и его пе-
риферийных устройств приведены в таблице 2.3.2.
Таблица 2.3.2 – Основные диалоговые окна отладчика Keil μVision 4
Ячейки памяти View  Registers Window
Просмотр регистров View  Memory Window  Memory 1–4
Просмотр локальных переменных View  Watch Windows  Locals
Просмотр глобальных переменных View  Watch Windows  Watch 1–2
Окно дизассемблера View  Disassembly Window
View  Analysis Windows 
Хронометраж
 Performance Analyzer
View  Analysis Windows 
Логический анализатор
 Logic Analyzer
Периферийные устройства Peripherals  …
Остановимся на главных операциях отладки. После перехода в режим
отладки (Ctrl+F5) курсор устанавливается на первую строку основной про-
граммы. Программист может сразу начать пошаговое выполнение програм-
мы (F10/F11) или же установить точку останова (F9) на интересующей строке
и запустить программу (F5). При достижении этой точки выполнение про-
граммы будет приостановлено и управление передано программисту.
Отметим, что возможно пошаговое выполнение не только команд Си,
но и ассемблера. Для этого переместить фокус ввода (щелчок мышью) в окно
дизассемблера.
В ходе отладки программист просматривает и при необходимости мо-
дифицирует регистры процессора (2), а также локальные и глобальные пере-
менные через Watch-окно. Доступ к большинству управляющих регистров
периферии открывается через меню Peripherals  …. Многочисленные диа-
логовые окна настройки, связанные с периферийными устройствами будут
рассмотрены в разделе 2.4 «Методика отладки программ».
2.3.7 Основные отладочные инструменты среды Keil µVision 4
Окно просмотра переменных Watch (рисунок 2.3.11) служит для
наблюдения за значениями переменных или массивов и их редактирования.
Окно содержит таблицу из двух колонок: имена переменных (1) и значения
(2, 3), которые могут быть отображены в шестнадцатеричной или десятичной
форме. Добавление новой переменной к списку осуществляется нажатием
кнопки F2 или двойным щелчком по пустой строке (см. подсказку «double-click
or F2 to add»). Кроме окна Watch есть окно Locals, в котором отображен
список локальных переменных текущей функции.
Хронометраж позволяет измерить время выполнения участка про-
граммы и доступен только в режиме симуляции (рисунок 2.3.12). Здесь отоб-

127
ражается общее время выполнения программы (2), а также отдельных под-
программ (3). Время рассчитывается исходя из числа прошедших машинных
тактов и тактовой частоты, заданной в свойствах проекта Options for Target
`Target 1`  Target  Xtal (MHz). Сброс счетчика времени производится
кнопкой (1).
1 – имена переменных;
2 – элементы массива в
десятичном представ-
2 лении;
1
3 3 – шестнадцатеричное
значение переменной

Рисунок 2.3.11 – Окно просмотра переменных Watch


1 – кнопка сброса (обну-
ление счетчика време-
1 ни);
2 – общее время выпол-
2 нения программы;
3 3 – время выполнения
подпрограмм

Рисунок 2.3.12 – Окно хронометража Performance Analyzer


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

2 3

1 – кнопка вызова диалога настроек; 2 – выбор масштаба; 3 – экранный курсор


Рисунок 2.3.13 – Окно логического анализатора (Logic Analyzer)

128
1 – имена регистров или
переменных;
1 2–3 – кнопки добавления
3
или удаления сигнала;
4 – способ представления
2
сигнала (аналоговый,
двоичный, временная
диаграмма);
5 – выбор диапазона по ам-
4 5 плитуде;
6 – маска (через логическое
«И»);
7 – сдвиг право
6 7

Рисунок 2.3.14 – Окно настройки логического анализатора


Настройка осуществляется кнопкой Setup (1). В окне настройки (ри-
сунок 2.3.14) можно добавить сигнал кнопкой (2) или удалить кнопкой (3).
При добавлении вводится имя переменной или регистра. Для просмотра ос-
циллограммы логического уровня на портовой линии имя вводится по шаб-
лону «PortX.X».
Здесь же можно задать логическую обработку регистра —
маскирование (6) и смещение на несколько разрядов вправо (7). Это позво-
ляет выделить несколько интересующих разрядов «из середины» регистра.
Также задаются предельные значения по оси ординат (5).
Масштаб настраивается кнопками (3). Для автоматического выбора
масштаба служит кнопка All. Щелчком левой кнопки мыши по осциллограм-
ме вызывается экранный курсор (2) — передвижная временная метка.
2.3.8 Управление распределением памяти
Задачи распределения памяти решает реактор связей (Linker). Управ-
ляя его работой можно добиваться размещения данных и фрагментов про-
граммы по определенным адресам в оперативной или постоянной памяти.
В простейшем случае используется простая схема распределения па-
мяти: данные размещаются в ОЗУ, начиная с адреса 0x40000000; основная
программа, все функции и константы, объявленные через const, — в ПЗУ,
после векторов прерываний, то есть, начиная с адреса 0x00000040.
Для устранения задержек при обращении к ПЗУ можно перенести
часть кода в память данных. Для этого необходимо оформить фрагмент про-
граммы, как функцию, сохранить ее в отдельный файл и прикрепить файл к
проекту. Затем в окне проекта (рисунок 2.3.4) изменить свойства этого файла.
В поле Memory Assignment требуется задать диапазон адресов 0x40000000–
0x40007FFF, который по умолчанию обозначен IRAM1 (рисунок 2.3.15).

129
Рисунок 2.3.15 – Настройка размещение подпрограммы в оперативной памяти

1 2
3

1 – флаг отключения сценария; 2 – имя файла сценария; 3 – редактор файла сценария


Рисунок 2.3.16 – Окно настройки редактора связей (Linker)
После этого в программу будет автоматически внедрен код, копиру-
ющий данную функцию из ПЗУ в ОЗУ. Копирование будет производиться в
ходе инициализации микроконтроллера, а запускаться функция будет из опе-
ративной памяти.
Такой способ настройки распределения памяти не решает проблем с
быстродействием функций стандартных библиотек. Если пользовательская
функция, находящаяся в ОЗУ, вызывает стандартную функцию sqrt, то по-
130
следняя по-прежнему будет размещена в ПЗУ. Еще важнее то, что даже
умножение чисел с плавающей точкой при компиляции, реализуется с ис-
пользованием подпрограмм, которые тоже по умолчанию находятся в ПЗУ.
Для переноса подпрограмм и библиотечных функций в оперативную
память придется вручную править сценарий редактора связей (Linker scatter
file). Файл имеет расширение *.SCT.
Подключение сценария выполняется в свойствах проекта: Options for
Target…  Linker. Нужно снять флаг Use Memory Layout from Target Dia-
log и нажать кнопку Edit… (рисунок 2.3.16).
Приведем пример модифицированного сценария с небольшими ком-
ментариями. Добавленные строки выделены светло-серым цветом.
; **********************************************************
; ** Scatter-Loading Description File generated by uVision *
; **********************************************************

LR_IROM1 0x00000000 0x00080000 {


ER_IROM1 0x00000000 0x00080000 { ; Область ПЗУ
*.o (RESET, +First)
*(InRoot$$Sections)
*armlib/c_* (+RO) ; Библиотечные функции
.ANY (+RO)
}
RW_IRAM1 0x40000000 0x00008000 { ; Область ОЗУ
RAM_Func.o (+RO) ; Функция пользователя
*armlib* (+RO) ; Подпрограммы
.ANY (+RW +ZI)
}
}
В этом примере подпрограммы перенесены в ОЗУ, в то время как
библиотечные функции, занимающие гораздо больше места в памяти остав-
лены в ПЗУ.

2.4 Методика отладки программ


В этом разделе будут даны рекомендации по диагностике программ и
выявлению ошибок. Основным инструментом является среда разработки Keil
µVision и один из многочисленных внутрисхемных отладчик с интерфейсом
JTAG, например J-Link. Возможна работа и в отсутствии внутрисхемной от-
ладки, но симуляция не гарантирует выявление всех ошибок и не может за-
менить проверку программы в функционирующей системе. В то же время
некоторые возможности доступны только в режиме симуляции.
Для отладки программы в системе инженер должен иметь в своем
распоряжении базовый комплект лабораторных электроизмерительных при-
боров: осциллограф (желательно цифровой), вольтметр или мультиметр, ча-
стотомер, а также источник регулируемого постоянного напряжения и функ-

131
циональный генератор. Надо сказать, что в большой степени цифровой ос-
циллограф может заменить другие измерительные приборы, выполняя функ-
ции измерения напряжения, интервалов времени и частоты.
Прежде всего, предлагается выполнить процедуру, названную автора-
ми «быстрый поиск ошибок» (раздел 2.4.1). Эта процедура позволяет с ми-
нимальными затратами времени выявить самые грубые ошибки, которые ча-
сто встречаются на практике, причем делают совершенно неработоспособной
программу и систему, которой она управляет.
Быстрый поиск не позволяет выявить ошибки в настройках перифе-
рийных устройств. Диагностике периферии посвящены разделы 2.4.2–2.4.13.
2.4.1 Быстрый поиск ошибок
Алгоритм процедуры быстрой отладки показан на рисунке 2.4.2.
Напомним, что проверка программы выполняется нажатием Ctrl+F5 и F5.
Перед началом любой диагностической операции необходимо остановить
выполнение программы кнопкой Stop.
Ошибочный режим ядра. После запуска и остановки программы,
прежде всего, следует обратить внимание на режим работы ядра (см. рисунок
2.4.1). Если после остановки программы ядро находится в режиме Us-
er/System, это нормально. Любой другой режим, чаще всего, следствие гру-
бой ошибки, причины которых перечислены ниже.

Рисунок 2.4.1 – Индикация режима ядра


● Зависание в режиме Supervisor. При выполнении программы режим
Supervisor, скорее всего, возник, как следствие переполнения счетчика ко-
манд, потому что в программе отсутствует вечный цикл. Напомним, что
сброс кнопкой на панели инструментов (рисунок 2.3.10, 1) также переведет
ядро в режим Supervisor. Ошибкой это не является.
● Зависание в режиме Abort всегда говорит об ошибке. Переход в ре-
жим Abort возникает в двух исключительных ситуациях: Data Abort и
Prefetch Abort (см. раздел 1.6). Распознать возникшее исключение можно по
команде, на которой произошло зависание.
Ели программная обработка этих исключений не реализована, то при
Prefetch Abort зависание происходит на адресе 0x00000048, где размещена
команда вечного цикла (см. файл Startup.s)
PAbt_Handler B PAbt_Handler
Data Abort дает зависание на следующей строке (адрес 0x0000004С)
DAbt_Handler B DAbt_Handler

132
Начало

Остановить программу

User/System Supervisor
Режим ядра
1
Нет вечного цикла
Да
Зависание?
Нет Abort
2
Конец
Индекс массива вне
Нет Прерывание допустимого диапазона
используется? или
переполнение стека
Да
Всегда только Interrupt
Точка останова 3
в проц. обраб. прерыв.
Не сбрасывается флаг
Создать прерывающее
прерывания
событие

Да Нет
Остановка?
4
Ошибка в настройке
Возобновить работу системы прерываний
программы и повторить
прерывающее событие
5
Не включен запрос
Да Нет
Остановка? прерывания

7
Останов на команде Нет обнуления 6
ввода-вывода, VICVectAddr Нет прерывающего
выполнение команды события (ошибка в
ввода-вывода настройки периферии)

Ввод-вывод Да
верный? 8
Неверный режим
Нет
портовой линии

Проверка настроек 9
периферии.
Ошибка направления
Пошаговая проверка
портовой линии
алгоритма

10
Не выбрана
Конец
скорость порта

Рисунок 2.4.2 – Схема алгоритма диагностирования наиболее


распространенных ошибок в программах для микроконтроллера LPC2148

133
4
3
2
1

Рисунок 2.4.3 – Переход ядра в режим Data Abort при обращении


к недопустимому адресу памяти (смещение 0x60000000)
Режим Abort (Data Abort) чаще всего возникает из-за выхода за допу-
стимые границы индекса массива, которому ошибочно не присваивается
начальное значение или не контролируется принадлежность диапазону.
Необходимо внимательно проследить, верно ли назначена размер-
ность массивов, и всегда ли соответствуют ей индексы.
Если программа сложна настолько, что найти ошибку не удается,
придется выполнить следующую последовательность действий:
а) считать адрес ошибочной команды из регистра R14; на рисун-
ке 2.4.3 это адрес 0x00000244 (2);
б) найти в окне дизассемблера этот адрес (3), уменьшенный на 8
(0x0000023C);
в) щелчок в окне дизассемблера подсветит строку желтым цветом и
выделит синей стрелкой искомую Си-команду, приводящую к ошибке (4).
Исключения Prefetch Abort возникает при передаче управления ко-
манде по недопустимому адресу. Частая причина исключения —
переполнение стека. Проблема решается уменьшением числа вложенных
функций или увеличением области памяти, выделяемой под стек. Настройки
стека доступны через инструмент Configuration Wizard  Stack Configura-
tion (Stack Size in Bytes). Объем стека задается для каждого режима ядра в
отдельности. Скорее всего, переполнение возникает в режиме Interrupt или
Fast Interrupt. Для этих режимов, прежде всего, и следует менять объем стека.
● Зависание процедуры обработки прерывания (режим Interrupt). Сра-
зу заметим, что остановка могла произойти внутри процедуры обработки
прерывания случайно. Ошибкой считается только непрерывная работа ядра в
режиме Interrupt, когда бы ни остановили программу.
В процедуре обработки прерывания должна размещаться команда
присваивания, сбрасывающая флаг запроса прерывания. Если такая команда
отсутствует, прерывание будет выполняться циклически. В этом обычно и
состоит причина ошибки.
● Зависание в режиме User/System. Программа всегда содержит веч-
ный цикл. Если по прошествии нескольких секунд после запуска остановка

134
произошла в точке выше вечного цикла, это говорит о зависании программы.
Чаще всего такое зависание возникает в случае неудачной инициализации
внешних устройств. Например, когда ЖК модуль не отвечает на команды.
Ошибки, связанные с системой прерываний. Если прерывания не
используются, этот этап поиска ошибок следует пропустить.
Необходимо установить точку останова на любой команде внутри
процедуры обработки прерывания (рекомендуется на первой) и запустить
программу. Далее дождаться прерывающего события или создать его. Если
остановка не происходит или происходит лишь однажды, то можно предпо-
ложить возникновение одной из следующих ошибок.
● Ошибка в настройке системы прерываний. Открыть окно настройки
прерываний с помощью меню Peripherals  Vectored Interrupt Controller
(рисунок 2.4.4). Основную часть окна занимает таблица, в которой перечис-
лены все источники прерываний (1–2). Требуется убедиться, что:
а) прерывание от интересующего источника (1) разрешено (6);
б) обычно, классифицировано как IRQ (3);
в) ассоциировано с нужным слотом (3) (только для IRQ);
г) адрес обработчика задан (4), то есть не равен нулю.
● Отключен запрос прерывания. Запрос прерывания от каждого ис-
точника включается через управляющие регистры соответствующего пери-
ферийного устройства. Для проверки разрешено ли формирование запроса
требуется открыть окно периферийного устройства. О проверке этих битов
сказано ниже в разделах 2.4.2–2.4.13.
● Ошибка в настройке периферии. В том же окне можно обнаружить,
что периферийное устройство (источник прерывания) вообще отключено или
неверно настроено. Поэтому запросы прерывания не генерируются.

4
5
1
6
2

1 – прерывания от таймеров; 4 – адрес обработчика прерывания;


2 – вид прерывания (IRQ или FIQ); 5 – флаг разрешения прерывания;
3 – номер слота; 6 – флаг запроса прерывания
Рисунок 2.4.4 – Окно настройки системы прерываний
135
● Инициализация системы прерываний. Если оказывается, что преры-
вание возникает с появлением прерывающего события, но лишь однажды,
скорее всего, пропущена команда обнуления регистра VICVectAddr. Лучше
сделать эту команда в процедуре обработки прерываний последней. По не-
внимательности нередко обнуляют VICVectAddr0 вместо VICVectAddr.
Ошибки в настройке портовых линий. Возможно, программа рабо-
тает нормально, все периферийные устройства настроены верно, но ввод или
вывод не происходит из-за ошибки в настройке режима или направления
портовых линий.
● Неверная настройка режимов портовых линий. Все линии порта 0
кроме основной функции могут выполнять несколько альтернативных. Если
альтернативная функция не выбрана, то линия является дискретным входом-
выходом и отключена от периферийных устройств.
Для выявления ошибки следует воспользоваться окном Peripherals 
Pin Connection Block (рисунок 2.4.5). Окно представляет собой перечень ли-
ний порта 0 (1), напротив которых указан их текущий режим (2). По умолча-
нию установлен режим «GPIO Port 0.x» — это режим дискретного ввода-
вывода. В меню (3) выбирается один из четырех возможных режимов каждой
портовой линии. Нужно убедиться, что все необходимые альтернативные
функции есть в списке (2), и назначены они верным портовым линиям (1).
1 – обозначения линий;
2 – режимы линий;
3 – меню выбора режима
2
1

Рисунок 2.4.5 – Окно настройки режимов портовых линий


● Для линий дискретного вывода должно быть задано направление.
По умолчанию все линии настроены на ввод. Ошибка в настройке направле-
ния через IOxDIR или FIOxDIR приводит к тому, что дискретный сигнал на
ножке не появится.
Проверить настройку можно в окне Peripherals  GPIO Slow / Fast
Interface  Port 0/1 (рисунок 2.4.6). Верхний ряд флажков отвечает за
направление. Установленный флажок соответствует режиму вывода.

136
Внимание! Порт не будет функционировать, если обращение к нему
выполняется в высокоскоростном режиме (регистры FIOx…), а высокоско-
ростной режим отключен (регистр SCS). То же и наоборот. Следует убедить-
ся, что флажки GPIOxM в окне System Control Block  System Control &
Status установлены для высокоскоростного режима или сброшены для низ-
коскоростного.
2.4.2 Ввод и вывод дискретных сигналов
Для тестирования ввода дискретного сигнала рекомендуется:
1. Установить точку останова на команду обращения к порту. Коман-
да чтения обычно имеет формат:
Имя переменной = IOxPIN & Маска ;
Команда записи
IOxPIN/SET/CLR = Имя переменной & Маска ;
Маска может отсутствовать. В высокоскоростном режиме вместо IOx… ис-
пользуются FIOx….
2. При вводе добиться желаемого уровня на дискретном входе, вы-
полнив необходимые коммутации в аппаратуре. Желательно контролировать
электрический уровень на входе вольтметром или осциллограмм. При выводе
просто контролировать сигнал.
3. Открыть окно просмотра состояния портов ввода-вывода
Peripherals  GPIO Slow Interface  Port 0 или Peripherals  GPIO Fast
Interface  Port 0. На рисунке 2.4.6 показаны оба варианта.

1
2
3
4
5

1 – направление ввода-вывода; 4 – текущее состояние;


2 – установка единицы; 5 – моделирование ввода дискретных сигналов;
3 – сброс в ноль; 6 – маска
Рисунок 2.4.6 – Окна цифровых портов ввода-вывода
Каждый флажок соответствует разряду одного из регистров управле-
ния портами (имена регистров подписаны слева). Имеются также поля для
ввода 16-ричных кодов управления портами. Флажки Pins в нижнем ряду
137
предназначены для имитации ввода дискретных сигналов. В режиме внут-
рисхемной отладки они отсутствуют.
4. Нажать F11, выполнив команду обращения к порту. При чтении
проследить за изменением регистра IOxPIN (FIOxPIN) и переменной, в кото-
рую содержимое порта сохраняется (окно Watch). При записи проследить за
изменением электрического сигнала на портовой линии.
Если ввод-вывод выполняется с ошибкой, причины могут быть сле-
дующие:
а) из-за неверной маски обращение происходит не к той линии, к ко-
торой должно;
б) выбрано неверное направление линии через (F)IOxDIR;
в) линия настроена на выполнение альтернативной функции;
г) изменение линии запрещено аппаратным маскированием (регистр
FIOMASK равен единице);
д) выполняется обращение через регистры FIOx…, притом что высо-
коскоростной режим не включен (регистр SCS) или наоборот.
2.4.3 Таймер-счетчик. Формирование интервалов времени
1. Запустить программу (F5), затем остановить и убедиться, что блок,
отвечающий за настройку таймеров-счетчиков, выполнился. Иными словами,
убедиться, что программа не зависла, не доходя до блока настройки.
2. Открыть окно таймеров-счетчиков (Peripherals  Timer 
Timer 0/1) (рисунок 2.4.7).
3. Прежде всего, обратить внимание на бит разрешения счета (2) и
сброса счетчика (3). Первый должен быть единицей, второй нулем. Прове-
рить, что выбран верный источник тактирования, то есть режим таймера или
счетчика (17). Если что-то из перечисленного настроено неверно, то содер-
жимое таймера-счетчика (1), скорее всего, равно нулю. Если в поле (1) нену-
левое значение, значит, таймер-счетчик работает и нужно переходить к про-
верке схемы совпадения.
4. Следует убедиться, что, по крайней мере, одно из устройств совпа-
дения обеспечивает остановку и/или сброс таймера-счетчика, то есть хотя бы
один из флагов (6–7) установлен, а также что пороговое значение (4) не
слишком велико (соответствует длительности формируемого интервала вре-
мени) и не равно нулю.
5. Если используется прерывание по совпадению, формирование за-
проса прерывания должно быть разрешено (5). Если формируемый интервал
времени слишком длинный, полезно установить точку останова внутри про-
цедуры обработки прерывания, имитировать совпадение путем ввода вруч-
ную в окно (1) числа, равного пороговому значению (4) и запуска программы
(F5). При этом должен установиться флаг (10) и возникнуть прерывание.
6. Постоянно установленный флаг запроса прерывания (10, 16) и от-
сутствие самого прерывания, свидетельствует в пользу нормального функци-
онирования таймера и ошибочной настройки системы прерываний.

138
1
2
4
5
6
3
7
8
9
10
11
12
13
14
15 17
16
18

1 – содержимое таймера-счетчика; 11 – захваченное состояние;


2 – включение; 12–13 – разрешить захват по фронту и по
3 – сброс; срезу;
4 – пороговое значение; 14 – разрешить запрос прерывания по за-
5–7 – разрешить запрос прерывания, сброс хвату;
и остановку по совпадению; 15 – состояние входов CAPx.x;
8–9 – управление сигналом MATx.x и его 16 – состояние запроса прерывания по за-
текущее состояние; хвату;
10 – состояние запроса прерывания по сов- 17 – режим (таймер или счетчик);
падению; 18 – выбор входа счетчика
Рисунок 2.4.7 – Окно таймера-счетчика
2.4.4 Таймер-счетчик. Формирование внешних сигналов совпадения
1. Подключить осциллограф или вольтметр к линии порта, на которой
ожидается сигнал совпадения.
2. Убедиться, что таймер и устройство совпадения функционируют
нормально (см. выше).
3. Проверить разрешено ли формирование внешних сигналов совпа-
дения и верно ли выбрана реакция на совпадение: инверсия, положительный
или отрицательный перепад (8).
4. Если флаг (9) меняется верно, но уровень электрического сигнала
не меняется, следует искать ошибку в настройке режима портовой линии.
2.4.5 Таймер-счетчик. Счетчик внешних событий
1. Подключать источник прямоугольного сигнала амплитудой от 0 до
5 В и частотой не более 30 МГц к одному из счетных входов CAPx.x. Откры-
вать окно таймера следует после того, как внешний сигнал подан, так как
информация не обновляется в открытом окне.

139
2. Проверить выбор режима счетчика (17) и счетного входа (18).
3. Если счетчик при наличии внешнего сигнала не инкрементируется,
следует искать ошибку в настройке портовой линии.
2.4.6 Таймер-счетчик. Устройство захвата
1. Добиться нормального функционирования таймера.
2. Подключать источник дискретного сигнала амплитудой от 0 до 5 В
и к одному из входов CAPx.x. Открыть окно таймера.
3. Убедиться, что разрешен захват по фронту и/или срезу по крайней
мере одного из внешних сигналов (12–13).
4. Если ни один из флажков 15 не активен (закрашен серым цветом),
значит режим порта настроен неверно.
5. При изменении уровня внешнего сигнала захваченное состояние
таймера должно обновляться в окне (11). Обновление будет происходить
только при любой активности отладчика: открыть/закрыть окно таймера, вы-
полнить очередную команду (F10/F11) и т. д.
2.4.7 Широтно-импульсный модулятор
1. Во время тестирования ШИМ рекомендуется контролировать ос-
циллографом сигнал на выходах PWMx. Окно настроек вызывается пунктом
меню Peripherals  Pulse Width Modulator.
Верхняя часть окна (рисунок 2.4.8) аналогична окну настроек таймера.
Ниже расположена таблица, в которой показаны настройки каждого из семи
устройств совпадения.

2
3
4

5
7
8
9
6

1 – содержимое счетчика ШИМ; 6 – состояние запроса прерывания;


2 – включение счетчика; 7 – управление начальной фазой;
3 – сброс счетчика; 8 – включение канала;
4 – пороговые значения и настройки всех каналов; 9 – состояние выхода канала ШИМ
5 – разрешение запроса прерывания, сброса, и
остановки счета по совпадению (сверху вниз);
Рисунок 2.4.8 – Окно настройки ШИМ

140
2. Необходимо убедиться, что счетчик включен (2) и не сброшен (3).
После запуска программы содержимое счетчика (1) не должно быть нулевым.
3. Пороговые значения для каждого канала отображаются в таблице
(4). Нулевой порог должен быть наибольшим, далее, чаще всего, в порядке
возрастания.
4. Обычно остановка отключена (5), а сброс счетчика включен для ну-
левого порога (видно также и в таблице в столбцах Reset и Stop).
5. Убедиться, что все задействованные каналы ШИМ включены (8).
6. Установка бита PWMSELx (7) включает управление начальной фа-
зой каждого канала.
2.4.8 Аналого-цифровой преобразователь
На этапе тестирования следует подключить к АЦП источник постоян-
ного напряжения, величину которого контролировать вольтметром или ос-
циллографом. Окно настроек АЦП открывается через меню Peripherals 
A/D Converter  A/D Converter 0/1 (рисунок 4.2.9).

2 1
5
3
6
4 7
8
9
10
11

12

13

15
14

1 – включение; 9 – глобальный запрос прерывания;


2 – Выбор канала; 10 – результат АЦП;
3 – разрядность; 11 – номер канала, от которого получен результат;
4–5 – способ запуска; 12 – состояния каналов;
6 – тактовая частота; 13 – управление прерываниями;
7 – флаг завершения преобразования; 14 – опорное напряжение, В;
8 – флаг потери результата; 15 – результаты преобразования, В
Рисунок 2.4.9 – Окно настройки аналого-цифрового преобразователя

141
1. Убедиться, что настройки верны: АЦП включен (1); частота (6) не
превышает 4,5 МГц; разрядность соответствует желаемой (3).
2. Убедиться, что выбран верный канал АЦП (2) и притом только
один. Выбор нескольких каналов допускается только в режиме циклического
опроса (BURST = 1).
3. Проверить, верно ли выбран способ запуска АЦП (4).
4. Поместить точку останова после цикла ожидания результата АЦП;
создать условие, при котором АЦП запустится. Если остановка не произо-
шла, следует искать ошибки в настройке узлов, запускающих АЦП (таймер
или порт ввода-вывода).
5. Если результат получен, его следует сверить с ожидаемым, прини-
мая во внимание опорное напряжение.
2.4.9 Цифро-аналоговый преобразователь
Окно управления ЦАП доступно через меню Peripherals  D/A Con-
verter (рисунок 2.4.10). Ненулевое значение в поле (1) должно немедленно
приводить к установке на выходе AOUT соответствующего напряжения, ко-
торое можно измерить вольтметром или осциллографом. Если этого не про-
исходит, значит, выход P0.25 настроен неверно.
В режиме симулятора доступно поле (2) для величины опорного
напряжения. Симулятор автоматически рассчитывает выходное напряжение
(3) на основе кода и опорного напряжения.
1 – код управления напряжением;
2 – опорное напряжение, В;
3 – выходное напряжение
1

Рисунок 2.4.10 – Окно настройки ЦАП


2.4.10 Приемопередатчик SPI
1. Выполнив блок настройки, открыть окно настройки приемопере-
датчика SPI (Peripherals  SPI Interface  SPI0).
2. Как правило, должен быть выбран режим ведущего (5), биты по-
лярности и фазы (6–7) сброшены.
3. Проконтролировать, верно ли выбрана очередность передачи битов
(4). Установка флага (4) ведет к передаче, начиная с младшего бита.
4. Проверить настройку разрядности (1–2). Если используется разряд-
ность (2), отличная от 8 бит, флаг (1) должен быть установлен.
5. Проверить значение битовой скорости (9). Рекомендуются значения
от сотен килогерц до единиц мегагерц (не более 7,5 МГц).
6. Рекомендуется с помощью точки останова остановить программу на
команде передачи, то есть присваивания регистру S0SPDR. Подключить к

142
выходу SCK цифровой осциллограф в режиме однократной или ждущей раз-
вертки; выполнить команду передачи (F10/F11). На осциллографе должны
появиться тактовые импульсы, в окне должен установиться флаг SPIF (8).
Так же следует просмотреть сигналы на линиях MOSI, MISO.
Если при правильной настройке осциллографа осциллограмма не за-
фиксирована, значит, передача не выполнялась, вероятно, из-за ошибочного
выбора режима портовых линий.
1–2 – управление разрядностью;
3 3 – разрешение запроса прерывания;
4 4 – очередность (первый бит млад-
1 ший/старший);
5
2 5 – режим (ведущий/ведомый);
6
7 6–7 – управление полярностью и фа-
зой;
8 – диагностика;
8 9 – скорость бит/с;
10 – активность запроса прерывания
9

10

Рисунок 2.4.11 – Окно настройки приемопередатчика SPI


Внимание! Открытое окно SPI приводит к тому, что регистры S0SPSR
и S0SPDR время от времени считывается через интерфейс JTAG. Это дает
автоматический сброс флагов в S0SPSR. В частности сбрасывается флаг го-
товности SPIF. Поэтому при открытом окне цикл ожидания окончания пере-
дачи зависнет. Флаг готовности установится и сбросится на следующем же
шаге трассировки.
2.4.11 Приемопередатчик I2C
Окно настроек I2C доступно через меню Peripherals  I2C  I2C0/1
(рисунок 2.4.12). Во время отладки полезно наблюдать за сигналами SCL,
SCK с помощью цифрового осциллографа в режиме однократной разверстки.
1. Прежде всего, необходимо проверить, что модуль I2C включен (1) в
режиме ведущего (3). Убедиться, что скорость не превышает 400 кГц (5).
2. Установить точку останова на команде установки состояния
START; выполнить команду и убедиться что состояние (6) изменилось.
3. Установить точку останова на конструкции switch {...}, исполь-
зуемой для анализа нового состояния. Выполнить программу до этой точки, а
затем выполнять в пошаговом режиме (F10/F11), наблюдая за тем, как состо-
яния сменяют друг друга при сбросе флага готовности в регистре
I2CxCONCLR.
Возможные причины ошибок: неверная настройка режимов портовых
линий либо ошибочная последовательность чередования состояний I2C.
143
4
1

5
2
3
6

1 – включить; 4 – сброс состояний; 6 – текущее состояние;


2 – установка состояний; 5 – скорость, бит/с; 7 – данные
3 – режим (ведущий/ведомый);
Рисунок 2.4.12 – Окно настройки приемопередатчика I2C
2.4.12 Приемопередатчик UART
Рекомендуется наблюдать с помощью цифрового осциллографа сиг-
нал на линии RxD, TxD. Окно настроек приемопередатчика UART открыва-
ется через меню Peripherals  SPI Interface  UART  UART0 (рису-
нок 2.4.13).
1 – настройка разрядно-
сти, числа стоповых
6 бит и четности;
2 – включение;
1 3 – уровень буфера при-
емника, вызывающий
прерывание;
4 – настройка скорости;
5 – текущая скорость;
8 6 – текущее сосание и ди-
7
агностика;
2 7 – настройка прерыва-
3 ний;
8 – идентификация пре-
9 рываний;
9 – принятый или переда-
ваемый байт
5
4

Рисунок 2.4.13 – Окно настройки приемопередатчика UART

144
1. Убедиться, что приемопередатчик включен (2); проверить настрой-
ку разрядности, числа стоповых бит и четности (1).
2. В режиме симулятора доступна расчетная битовая скорость (5). Она
должна совпадать со скоростью COM-порта персонального компьютера с
ошибкой не более 5%.
3. Следует обратить внимание на число байт в буфере приемника,
накопление которых вызывает прерывание (3), а также биты разрешения пре-
рываний (7).
4. Установить точку останова внутри блока, отвечающего за обработ-
ку принятого байта и вызываемого только, если байт принят. Если ожидание
байта реализовано через прерывания, то установить точку останова внутри
процедуры обработки прерываний. Послать с персонального компьютера
один или несколько байт (не более 16) и проследить за реакцией программы.
5. Если остановки не произошло, значит либо настройки интерфейса
приемника и передатчика не соответствуют, либо неверно настроен режим
портовых линий, либо ошибка в настройке системы прерываний.
6. Если реакция есть, проверить принятый байт в поле (9).
7. Для диагностики приема рекомендуется поместить точку останова
на команду передачи (записи в UxTHR), и выполнить эту команду, наблюдая
за результатом на персональном компьютере и, по возможности, с помощью
цифрового осциллографа.
2.4.13 Часы реального времени
Окно настроек показано на рисунке (2.4.14.). Ниже даны рекоменда-
ции по проверки этих настроек.

1
3
2
6
5

4
7
8

1 – включение; 5 – маска прерывания по инкременту;


2 – источник тактирования; 6 – маска прерывания по будильнику;
3 – включение запросов прерывания; 7 – установка «будильника»;
4 – текущее время; 8 – делитель тактовой частоты
Рисунок 2.4.14 – Окно настройки часов реального времени

145
1. Счетчик часов реального времени должен быть включен (1); бит
выбора источника тактирования сброшен (2), если тактирование не осу-
ществляется от основного тактового генератора.
2. Один или оба бита выбора прерывающего события (3) должны быть
установлены. И выбрано, какие именно события будут вызывать запрос пре-
рывания (5).
3. Должны быть заданы маски прерывающих событий (4, 7).

2.5 О программировании ARM7 на ассемблере


Система команд ARM7 (раздел 1.4) включает всего 45 инструкций,
которые довольно сложны из-за многообразия методов адресации, условных
полей и модификаторов. Программа на ассемблере получается громоздкой и
с трудом читается. Поэтому ассемблер редко применяется в программирова-
нии для архитектуры ARM7.
Вместе с тем, язык высокого уровня Си скрывает от программиста
многие особенности архитектуры. Программист практически не касается та-
ких процедур, как выбор режима ядра, выделение памяти под стек и обработ-
ка прерываний. Для изучения этих процедур полезно составить хотя бы одну
простую программу на ассемблере.
Кроме того, даже при использовании Си к языку ассемблера все же
приходится прибегать.
1. Следует контролировать Си-компилятор, отслеживая, не исключил
ли он в ходе оптимизации важные команды, посчитав их ненужными. Не ге-
нерирует ли компилятор исключительно неэффективный код для сравни-
тельно простой операции, из-за недостаточной оптимизации. Чтобы убедить-
ся, что компилятор действительно задействует те аппаратные ресурсы, кото-
рые, призваны повысить эффективность конкретного алгоритма.
2. В ходе поиска ошибок или причин возникновения исключительных
ситуаций (раздел 2.4.1).
3. Для получения кода, абсолютно оптимального по быстродействию
или расходу памяти (разделы 2.2.20, 3.1.5).
Рассмотрим основные приемы составления программы на ассемблере
с целью продемонстрировать весь код исполняемый микроконтроллером, как
есть, и без посредничества Си-компилятора.
Порядок создания проекта на основе ассемблера почти тот же, что и
для Си-программ (разделы 2.3.1–2.3.3). Исключения лишь два:
а) файлу исходного текста присваивается расширение *.S;
б) здесь предполагается, что файл STARTUP.S к программе не под-
ключается.
2.5.1 Основные правила записи программ на ассемблере
Текст программы на ассемблере принято оформлять в четыре колон-
ки. Можно сказать, что каждая строка состоит из четырех полей, а именно:
поля меток, операций, операндов, комментариев. Поля отделяются друг от
друга символом «табуляция» или пробелами.

146
Основными являются поля операций и операндов. Допустимые опера-
ции и их синтаксис приведены в таблице (1.4.2)
Метка — это символьное обозначение адреса команды. Везде вместо
метки будет выполняться подстановка адреса команды, которой предшеству-
ет метка. Чаще всего метки используются в командах передачи управления.
Каждая метка должна быть уникальной и при этом является не обязательной.
В отличие от многих других версий, в ассемблере RealView метки не закан-
чиваются двоеточием («:»).
Комментарии по желанию помещаются в конце строки и отделяются
точкой с запятой («;»).
Приведем простой пример.
Label ADD R1, R1, R0, LSL #2 ; R1 = R1 + R0 << 2
...
BEQ Label ; Перейти по метке, если Z = 0
2.5.2 Псевдокоманды
Ассемблер RealView поддерживает так называемые псевдокоманды.
Псевдокоманда — это мнемоническое обозначение, которое на самом деле не
соответствует системе команд процессора, а заменяется одной или (реже) не-
сколькими командами. Псевдокоманды являются своего рода макросами и
служат для упрощения синтаксиса. Перечень поддерживаемых псевдокоманд
приведен в таблице (2.5.1).
2.5.3 Директивы ассемблера
В отличие от команд директивы не создают исполнимого кода, загру-
жаемого в память микроконтроллера. Директивы представляю собой лишь
предписания ассемблеру, управляют формированием исполнимого кода.
Рассмотрим часто используемые директивы ассемблера RealView 4.
Имя EQU Константа
Назначает Константе символьное обозначение Имя, которое стано-
вится синонимом константы. Основное назначение — введение имен управ-
ляющих регистров,
AREA Имя, Параметры
Определяет область памяти с заданным Именем. С помощью парамет-
ров указывается назначение области памяти, например, DATA (данные) или
CODE (код). От выбранного назначения зависят адреса определяемой области.
Область CODE размещается, начиная с адреса 0x00000000, область DATA — с
адреса 0x40000000. В программе обязательно должна существовать область
CODE c именем RESET. Константы, размещаемые в памяти программ, следует
объявлять в секции с парой параметров CODE, READONLY.
ENTRY
Обозначает точку входа в программу, показывает ее «начало». Одна
такая директива всегда должна присутствовать в программе. Обычно поме-
щается непосредственно после директивы AREA RESET, CODE.

147
Таблица 2.5.1 – Псевдокоманды, поддерживаемые ассемблером RealView 4
Мнемоническое обозначение
Операция Фактическая реализация
и синтаксис
Сложение или вычитание константы из PC ко-
ADR{Усл} , Загрузка адреса в регистр
мандами ADD или SUB
Загрузка адреса в регистр
ADRL{Усл} , Дважды ADD или SUB с участием PC
(расширенный диапазон адресов)
ASR{Усл}{S} , , Загрузка регистра командой MOV с использова-
Арифметический сдвиг вправо
ASR{Усл}{S} , , нием сдвигового операнда
Загрузка регистра командой LDR с косвенной
LDR{Усл} , Загрузка адреса в регистр
адресацией (PC + непосредственное смещение)
Размещение константы в памяти программ
Загрузка 32-разрядной константы в
LDR{Усл} ,= и загрузка с помощью LDR с индексной адреса-
регистр
цией. Смещением служит PC.
LSL{Усл}{S} , , Загрузка регистра командой MOV с использова-
Логический сдвиг влево
LSL{Усл}{S} , , нием сдвигового операнда
LSR{Усл}{S} , , Загрузка регистра командой MOV с использова-
Логический сдвиг вправо
LSR{Усл}{S} , , нием сдвигового операнда
Восстановление регистров командой
POP{Усл} Восстановить регистры из стека
LDMIA R13!,{...}
Сохранение регистров командой
PUSH{Усл} Сохранить регистры в стек
STMDB R13!,{...}
ROR{Усл}{S} , , Загрузка регистра командой MOV с использова-
Циклический сдвиг вправо
ROR{Усл}{S} , , нием сдвигового операнда
Циклический сдвиг вправо через Загрузка регистра командой MOV с использова-
RRX{Усл}{S} ,
перенос на 1 разряд нием сдвигового операнда

148
Имя SPACE Размер
Резервирует память для хранения данных заданного Размера. Имя
становится синонимом адреса зарезервированного пространства. Единство
адресного пространства позволяет применять эту директиву, как для посто-
янной, так и для оперативной памяти. Основное назначение — создание гло-
бальных переменных в оперативной памяти (в области DATA).
Метка DCB/DCW/DCD Константа
«Прошивают» данные (числовые Константы) в памяти программ.
Метка становиться синонимом адреса, по которому будут записаны данные.
Разные директивы (DCB, DCW и DCD) служат для данных разного размера:
байт, 16-разрядное слово, 32-разрядное слово (соответственно).
END
Служит признаком конца файла. Весь текст после этой директивы иг-
норируется ассемблером.
2.5.4 Макросы
Макрос представляет собой предопределенный фрагмент программы,
выполняющий какую-либо распространенную операцию. В отличие от под-
программ, вызываемых с помощью команд передачи управления, использо-
вание макросов не снижает быстродействия, но не снижает и расход памяти
программ. Потому что при каждом вызове макроса ассемблер внедряет в
программу полностью его текст.
Для объявления макроса служит следующая конструкция
MACRO
Имя $Параметр1, $Параметр2, ...
...
MEND
Параметры позволяют модифицировать текст макроса при каждом обраще-
нии к нему. Внутри (в теле) макроса параметры используются также с пред-
шествующим знаком «$». Вместо параметров в теле макроса подставляются
параметры, указанные при вызове.
Вызов макроса осуществляется так:
Имя Параметр1, Параметр2, ...
Имеется возможность организовать проверку условия и ветвление.
IF "$Параметр" == "Значение"
...
ELSE
...
ENDIF
Обращаем внимание на то, такая конструкция не приводит к про-
граммной проверке условия микроконтроллером. Проверку условия осу-
ществляет ассемблер в ходе формирования исполнимого кода.

149
2.5.5 Пример простой программы
В качестве наглядной иллюстрации предлагаем рассмотреть простую
программу, формирующую пачки из пяти прямоугольных импульсов. После
каждой пачки следует пауза, равная по длительности тем же пяти импульсам.
В программе используется прерывание от таймера 0 и глобальная пе-
ременная счетчик Counter. Вначале счетчику присваивается значение 20. При
каждом достижении таймером порога значение счетчика декрементируется,
формируется перепад на портовой линии P0.7. Генерирование импульсов не
производится, если счетчик больше десяти. При достижении счетчиком нуля
ему снова присваивается значение 20 и цикл повторяется.
IO0PIN EQU 0xE0028000
IO0DIR EQU 0xE0028008
T0IR EQU 0xE0004000
T0TCR EQU 0xE0004004
T0MCR EQU 0xE0004014
T0MR0 EQU 0xE0004018
VICIntEnable EQU 0xFFFFF010
VICVectAddr EQU 0xFFFFF030
VICVectAddr0 EQU 0xFFFFF100
VICVectCntl0 EQU 0xFFFFF200

MACRO
LoadConst $Val, $Reg, $Length
LDR R0, =$Reg
IF "$Length" == "Short"
MOV R1, #$Val
ELSE
LDR R1, =$Val
ENDIF
STR R1, [R0]
MEND

AREA STACK, DATA


StackBottom SPACE 1024

AREA Vars, DATA


Counter SPACE 4

AREA RESET, CODE


ENTRY

B Start

SPACE 16
150
DCD 0x77BFA08A
LDR PC, [PC, #-0x0FF0]
SPACE 4

Start
MSR CPSR_c, #0x12
LDR SP, =StackBottom+1024
MSR CPSR_c, #0x10

LoadConst 0x80, IO0DIR, Short


LoadConst 1000000, T0MR0, Long
LoadConst 0x03, T0MCR, Short
LoadConst 0x01, T0TCR, Short
LoadConst Timer0Int, VICVectAddr0, Long
LoadConst 0x24, VICVectCntl0, Short
LoadConst 0x10, VICIntEnable, Short
LoadConst 20, Counter, Short

Loop B Loop

Timer0Int
STMDB SP!, {R0-R3}

LDR R0, =Counter


LDR R1, [R0]
SUBS R1, R1, #1
MOVEQ R1, #20
STR R1, [R0]

CMP R1, #10


BGT Skip

LDR R0, =IO0PIN


LDR R1, [R0]
EOR R1, R1, #0x80
STR R1, [R0]

Skip LoadConst 0x01, T0IR, Short


LoadConst 0x00, VICVectAddr, Short

LDMIA SP!, {R0-R3}


SUBS PC, R14, #4

END
151
Дадим некоторые пояснения. Текст программы начинается с объявле-
ния имен регистров. Стандартным именам присваиваются соответствующие
адреса директивой EQU.
Далее объявлен макрос LoadConst, содержащий команды загрузки ко-
манды в управляющий регистр. Макрос имеет три параметра: загружаемая
числовая константа (Val), адрес регистра (Reg) и модификатор (Length). С
помощью директив IF…ELSE…ENDIF загрузка осуществляется либо командой
MOV, либо LDR. Если константа может быть предоставлена в виде сдвигового
12-разрядного операнда, передается параметр Length = Short и выполняется
команда MOV, иначе загрузка выполняется командой LDR.
Директива AREA…DATA определяет область памяти для стека. А SPACE
резервирует под стек 1024 байта. Начало этой области получает имя Stack-
Bottom.
Аналогично создается глобальная переменная Counter размером
4 байта.
Область кода программы объявляется директивой AREA…CODE.
Первой инструкцией программы является команда безусловного пере-
хода на точку входа, обозначенную ниже меткой Start.
В области векторов прерываний занята командой передачи управле-
ния процедуре обработки прерываний (LDR PC, [PC, #-0x0FF0]), а также
контрольной суммой (директива DCD). Директивы SPACE заполняют пустые
пространства.
Основная программа начинается после метки Start. Первые три стро-
ки: перевод ядра в режим IRQ; инициализация указателя стека (SP) режима
IRQ; перевод ядра в режим User. Здесь инициализация стека выполняется пу-
тем загрузки в него суммы базового адреса стека и объема стека (1024 байта),
зарезервированного ранее.
С помощью макроса LoadConst выполняется настройка портовой ли-
нии, таймера и системы прерываний; присваивается начальное значение пе-
ременной-счетчику Counter.
Основная программа завершается командой вечного цикла (переход
на метку Loop).
Ниже размещается подпрограмма обработки прерываний (метка
Timer0Int). Вначале сохраняются в стек регистры R0–R3 (команды STMDB).
Далее выполняется декремент счетчика и присваивание начального
значения (20) в случае равенства нулю.
Следующий блок пропускается (метка Skip), если счетчик больше 10.
Блок содержит команды инверсии портовой линии.
Далее выполняется обычная процедура возврата из прерывания: с по-
мощью макроса LoadConst снимается флаг запроса прерывания и обнуляется
регистр VICVectAddr. Регистры общего назначения восстанавливаются из
стека, выполняется возврат командой SUB с участием счетчика команд.

152
2.6 Распространенные средства разработки и отладки
2.6.1 Демонстрационные платы EA-EDU-001 и EA-EDU-011
Одной из наиболее удачных демонстрационных плат на основе мик-
роконтроллеров семейства LPC2000, по мнению авторов, является плата EA-
EDU-001 производства фирмы Embedded Artists. На рисунке 2.6.1 приведена
фотография платы, а на рисунке 2.6.2 схематично изображено размещение
основных электронных узлов с указанием линий микроконтроллера, управ-
ляющих ими.
Плата EA-EDU-001 сочетает разнообразие установленных устройств и
возможность расширения благодаря 50-контактому разъему, к которому под-
ключено большинство портовых линий микроконтроллера.
Причислим устройства, установленные на плате:
1) микроконтроллер LPC2148 с кварцевыми резонаторами 12 МГц и
32768 Гц;
2) восемь светодиодов, подключенных к порту ввода-вывода;
3) трехцветный светодиод, подключенный к трем каналам ШИМ;
4) кнопка, подключенная к входу запроса внешнего прерывания;
5) джойстик, состоящий из пяти кнопок;
6) два потенциометра, подключенных к входам АЦП;
7) динамик, подключенный к выходу ЦАП;
8) фильтр нижних частот, для получения постоянного напряжения с
помощью ШИМ;
9) символьный ЖК индикатор 16×2 символа (LMB162A);
10) светодиодная матрица 8×8 точек (LMD08088);
11) миниатюрный шаговый двигатель (20BY20L033);

Рисунок 2.6.1 – Фотография учебной платы EA-EDU-001

153
USB
Память EEPROM UART0 D–/D+ – прием/передача
SDA0 – данные TxD0 – передача P0.23 – Vbus
SCL0 – тактирование RxD0 – прием P0.31 – Connect

Трехцветный светодиод
P0.7/PWM2 – красный
P0.8/PWM4 – синий
Flash-карта MMС/SD
P0.9/PWM6 – зеленый
MOSI0 – передача
MISO0 – прием
SCK0 – тактирование
P0.11 – CS Жидкокристаллический
индикатор
Светодиодная матрица
P1.16–P1.23 – D0–D7 (данные)
MOSI0 – передача
P1.24 – RS (команда/данные)
MISO0 – прием
P0.22 – RW (чтение/запись)
SCK0 – тактирование
P1.25 – E (стробирование)
P0.15 – CS
P0.30 – подсветка
Динамик
AOUT

Регулятор громкости Джойстик


P0.16 – центр
P0.17 – вверх
Датчик температуры Шаговый двигатель Потенциометры Светодиоды Кнопка Сброс P0.18 – вправо
SDA0 – данные P0.12, P0.21 AD0.1, AD0.2 P0.8 – P0.15 P0.14 P0.19 – влево
SCL0 – тактирование (слева направо) (справа налево) P0.20 – вниз

154
Рисунок 2.6.2 – Схема размещения компонентов учебной платы EA-EDU-001 с указанием адресов каналов управления
Рисунок 2.6.3 – Фотография платы расширения EA-EDU-011

RS-232 Flash-карта microSD Акселерометр


TxD1, RxD1 MOSI0 – передача AD1.6 – канал X
RTS, CTS MISO0 – прием AD1.7 – канал Y
DSR, DTR SCK0 – тактирование AD0.3 – канал Z
DCD, RI P0.13 – CS P0.13 – gSelect1
P0.16 – Card Detect P0.14 – gSelect2

Ethernet
P0.14 – INT
MOSI0 – передача
MISO0 – прием
SCK0 – тактирование
P0.14 – CS

Джойстик
P0.8 – центр
P0.10 – вверх
P0.11 – вправо
P0.9 – влево
P0.12 – вниз

Параллельный порт Цветной ЖК дисплей


SDA0 – данные MOSI0 – передача
SCL0 – тактирование SCK0 – тактирование
(LED0–15 светодиоды; LED7, 8 – кнопки) P0.7 – CS
P0.15 – подсветка

155
Рисунок 2.6.4 – Схема размещения компонентов учебной платы EA-EDU-011
с указанием адресов каналов управления
12) электрически перепрограммируемое ПЗУ емкостью 2 кбита
(CAT1025);
13) цифровой датчик температуры (LM75);
14) разъем карт памяти MMS/SC;
15) мост USB/UART (FT232R);
16) интерфейс USB;
17) интерфейс JTAG.
Питание платы осуществляется либо от порта USB персонального
компьютера, либо от отдельного источника постоянного тока 9–15 В (не ме-
нее 200 мА).
50-штырьковый разъем может использоваться для расширения платы
с использованием любой аппаратуры, разработанной и сконструированной
пользователем. Фирма Embedded Artists выпускает плату расширения EA-
EDU-011, содержащая дополнительный набор устройств:
1) джойстик;
2) две кнопки и 16 светодиодов, подключенный через параллельный
порт (PCA9532);
3) цветной светодиодный экран 130×130 точек совместимый с
Nokia 6100 и контролером Philips PCF8833.
4) аналоговый трехосевой акселерометр (MMA7260QT);
5) разъем microSD;
6) интерфейс RS-232 с полным набором модемных сигналов;
7) интерфейс Ethernet 10 Мбит через мост SPI/Ethernet (ENC28J60).
Фотография платы показана на рисунке 2.6.3, на рисунке 2.6.4 приве-
дена схема размещения компонентов с указанием адресов подключения к
микроконтроллерной плате EA-EDU-001.
2.6.2 Внутрисхемный отладчик J-Link
При составлении и настоящего учебного пособия авторы использова-
ли внутрисхемный отладчик J-Link фирмы Segger. Фотография прибора и его
расширенной модификации J-Link Ultra, показаны на рисунках 2.6.5, 2.6.6.

Рисунок 2.6.5 – Отладчик J-Link Рисунок 2.6.6 – Отладчик J-Link Ulta


156
Отладчики подключаются к компьютеру через интерфейс USB (J-Link
Ultra также поддерживает Ethernet). Эксплуатация прибора не вызывает
трудностей. При первом подключении будет запрошена установка драйвера,
который находится на диске, входящем в комплект поставки. Среда Keil
µVision 4 поддерживает J-Link. Поэтому дополнительное программное обес-
печение не потребуется. Практически не требуется и никакая настройка,
кроме простейших действий, рассмотренных в разделе 2.3.3.
Программатор поддерживает большинство микроконтроллеров се-
мейств ARM7, ARM9, Cortex-M3, Cortex-M4.
2.6.3 Утилиты программирования ПЗУ LPC Flash Utility и FlashMagic
Микроконтроллеры семейства LPC200 поддерживают загрузку испол-
нимого кода программы через интерфейс UART. За эту возможность отвеча-
ет загрузчик, размещенный в ПЗУ на заводе-изготовителе. Связь UART с
персональным компьютером может обеспечиваться через RS-232 или USB
посредством микросхем, таких как MAX3232 или FT232R. Этот способ за-
грузки программы можно считать наиболее дешевым, потому что не требует-
ся JTAG-программатор.
Со стороны персонального компьютера «прошивкой» могут управлять
известные программы: LPC2000 Flash Utility и FlashMagic (рисунки 2.6.7,
2.6.8). Обе программы требуют сохранения исполнимого файла программы в
формате HEX (раздел 2.3.3).

10
11
1
3
6
7 4
9
8
2

Рисунок 2.6.7 – Окно программы Philips Flash Utility


Порядок работы с LPC Flash Utility таков:
1) выбрать HEX-файл, расположенный в папке проекта;
2) ввести реальную частоту кварцевого резонатора микроконтроллера
(в килогерцах);
3) выбрать последовательный порт, к которому подключен микро-
контроллер;
4) выбрать скорость передачи данных (не более 38400 бит/с);

157
5) считать идентификатор устройства (после этого шага в поле Device
должен появиться теп микроконтроллера);
6) если это необходимо установить флажок Execute Code after Upload
(запустить программу после загрузки);
7) нажать кнопку Upload to Flash; начнется процесс загрузки.
Помимо загрузки программы имеется возможность сравнения вы-
бранного HEX-файла с содержимым Flash-памяти микроконтроллера (8).
Сброс микроконтроллера можно выполнить кнопкой (9).
Программа Flash Magic позволяет «прошивать» микроконтроллеры и
других семейств производства NXP, например 8051. Для записи исполнимого
кода необходимы следующие действия: выбрать тип устройства кнопкой
Select Device (1); выбрать последовательный порт (2); выбрать скорость пе-
редачи данных (не более 38400 бит/с) (3); ввести частоту кварцевого резона-
тора в мегагерцах (4); выбрать загружаемый HEX-файл (5); нажать кнопку
Start (6).

1
2
3

Рисунок 2.6.8 – Окно программы Flash Magic


2.6.4 Программа-терминал 232Analyzer
Для взаимодействия с микроконтроллером по интерфейсу RS-232 по-
требуется программа-терминал. Простейший терминал, как известно, входит
в комплект поставки Windows, однако пользоваться им крайне неудобно.
Еще более простая и, тем не менее, удобная программа называется TTY.
Программа довольно старая и сегодня найти ее трудно.
Проведя обзор современных программ-терминалов, авторы рекомен-
дуют 232Analyzer (рисунок 2.6.9).
Выбор и настройка порта RS-232 выполняется меню (2), вынесенными
на панель инструментов программы. Для установки подключения нужно

158
нажать кнопку (1). Флаги (3–4) позволяют выбрать формат передаваемой и
принимаемой информации.
Для передачи символа, он или его код вводится в поле 5 и нажимается
кнопка Send (6). Если нужно передать несколько символов в формате ASCII,
они водятся подряд. Если передается последовательность кодов, то они раз-
деляются запятой. Причем запятая ставится и в конце последнего кода. Над
строкой (5) появляется подсказка с примером.
1 2 3 4 5 6

Рисунок 2.6.9 – Окно программы 232Analyzer


2.6.5 Низкоуровневый редактор диска DMDE
В разделе рассматривается взаимодействие с картами Flash-памяти
стандарта MMC/SD. Для тестирования программы необходима возможность
считывать и записывать информацию на карту на низком уровне с персо-
нального компьютера. Для этого удобен редактор дисков DMDE 2.0.
После запуска программы следует перейти в режим «Физические сек-
торы» с помощью одноименного пункта меню Редактор. Выбрать текущий
диск можно через меню Диск  Выбрать диск.
По умолчанию программа работает в режиме «только чтение». Изме-
нение информации на диске становится возможным после включения режима
Правка  Режим редактирования. Для сохранения всех внесенных изме-
нений служит меню Правка  Сохранить изменения.

159
Часть 3. Решение типовых задач локального управления

3.1 Формирование временной задержки с помощью цикла


3.1.1 Задание
Разработать программу, инвертирующую логический уровень на ли-
нии P0.7 через каждые 0,5 с. Задержку организовать с помощью цикла.
3.1.2 Общие рекомендации
Поставленная задача является простейшей с точки зрения программи-
рования и в тоже время чрезвычайно распространенной. Рассматриваемое
здесь решение важно для обучения программированию, но на практике при-
меняется ограниченно из-за своих недостатков. Алгоритм программы пока-
зан на рисунке 3.1.1. Предлагается включить в программу цикл задержки,
время выполнения которого примерно составляет 0,5 с. По окончании цикла
выполнить команду инверсии требуемой портовой линии. Единственный ап-
паратный узел МК, с которым приходится взаимодействовать программе —
это порт ввода-вывода.
Начало

1
Настройка портовых
линий P0.7–P0.9

Да 2 Нет
k=1; k<N; k++

3
Инверсия P0.7

Рисунок 3.1.1 – Алгоритм программы формирования дискретного сигнала


3.1.3 Алгоритм программы
Перед началом работы выполнить подготовку, как это было описано в
разделах 2.3.1–2.3.4.
В программе потребуется объявить одну переменную-счетчик целого
типа int.
int Имя_переменной ;
1. Настройка состоит в переводе портовых линий P0.7–P0.9 в режим
вывода путем записи единиц в соответствующие разряды регистра IO0DIR
(см. раздел 1.10.1); а также установке низких логических уровней на тех же
линиях путем записи единиц в соответствующие разряды регистра IO0CLR.
2. Команды блоков 2–3 помещаются в вечный цикл
while (1)
{
...
}

160
В начале вечного цикла организовать цикл задержки
for (k=0; k<N ; k++) ;
где N — число итераций, которое можно приближенно принять равным
100 000.
3. После цикла задержки инвертировать портовую линию с помощью
команды сложения по модулю два.
IO0PIN^= Код ;
где Код содержит единственную единицу в седьмом разряде (соответственно
разряду порта P0.7).
Провести компиляцию проекта (F7) исправить синтаксические ошиб-
ки, если они имеются.
3.1.4 Отладка
Поскольку это первое задание, несмотря на его исключительную про-
стоту подробно рассмотрим порядок отладки программы. Таким образом
продемонстрируем на конкретном примере приемы отладки, подробно рас-
смотренные в разделе 2.4. Итак, рекомендуется придерживаться следующего
порядка действий.
1. Перевести среду в режим отладки (Ctrl+F5). При этом работает си-
мулятор. Запись программы в память микроконтроллера не производится.
2. Проследить за пошаговым выполнением программы (F11).
3. Установить точку останова на команду инверсии порта (двойной
щелчок по серому полю слева). Открыть окно порта ввода-вывода (Periph-
erals  GPIO  Port 0).
4. Несколько раз запустить программу до точки останова (F5). Про-
следить периодическое изменение состояния портовой линии в окне.
5. Открыть окно логического анализатора (раздел 2.3.7). Получить ос-
циллограмму сигнала лини P0.7.
6. Определить время выполнения одной итерации с помощью окна
хронометража (раздел 2.3.7).
7. Вернуться в режим программирования (Ctrl+F5). Откорректировать
предельное значение счетчика так, чтобы время итерации составило 0,5 с.
Скомпилировать программу.
8. Вызвать свойства проекта. Выбрать в качестве инструмента внут-
рисхемный отладчик (раздел 2.3.3).
9. Перейти в режим отладки (Ctrl+F5). Переход будет сопровождаться
загрузкой кода программы в память микроконтроллера.
10. Запустить программу нажатием кнопки F5. Убедиться в работо-
способности программы.
3.1.5 Дополнительные сведения о формировании временной задержки
Несмотря на указанные недостатки, формирование временной за-
держки с помощью пустого цикла применяется в некоторых случаях (напри-
мер, практическое занятие №10).

161
В дальнейшем предлагается вместо пустого цикла for использовать
следующую функцию, составленную из инструкций ассемблера. Внедрение
кода на ассемблере позволяет получить наименьший возможный шаг в
настройке длительности импульса.
asm void Delay(int R0) // Параметр R0 -
{ // число повторов
subs R0, R0, #1 // Уменьшение счетчика на 1
bne {PC}-4 // Повтор, если не равен 0
bx LR // Возврат из функции
}
Обращаем внимание на то, что в строках ассемблера необходим от-
ступ хотя бы в один пробел.
С помощью такой функции последовательность прямоугольных им-
пульсов может быть сформирована так:
while (1)
{
FIO0SET= Маска ; // Высокий уровень
Delay( Числовая константа ); // Задержка
FIO0CLR= Маска ; // Низкий уровень
}
Заметим, что здесь используется управление портом ввода-вывода че-
рез высокоскоростную шину (раздел 1.10.2).

Рисунок 3.1.2 – Осциллограмма импульсов с временной задержкой,


полученной с помощью пустого цикла
Параметры импульса (период следования и длительность) могут быть
рассчитаны по следующим формулам:
; (3.1.1)

, (3.1.2)
где — длительность такта (по умолчанию нс),
— числовая константа, передаваемая функции Delay в качестве пара-
метра; — числа тактов, выделяемых для считывания команд из памяти,
которое по умолчанию равно 4 (о модуле ускорения памяти см. раздел 1.8).

162
Минимальный период, который может быть получен таким способом
нс, минимальная длительность импульса нс. Ми-
нимальный шаг настройки нс.
На рисунке (3.1.2) показана осциллограмма импульсов на одной из
портовых линий микроконтроллера, генерируемых приведенной выше про-
граммой. Использовались следующие параметры: нс, ,
, что с тактовой частой МГц приводит к периоду импуль-
сов нс и длительности нс.
Для сравнения приведем осциллограмму сигнала (рисунок 3.1.3),
формируемого кодом без временной задержки при нулевом уровне оптими-
зации кода.
while (1)
{
FIO0SET= Маска ;
FIO0CLR= Маска ;
}

Рисунок 3.1.3 – Осциллограмма импульсов без временной задержки


Параметры импульсов: период нс (частота МГц),
длительность нс (без учета длительности среза). Точный подбор
длительности импульса возможен вставкой между командами записи в порт
нескольких функций nop(), которые компилируется в команду NOP, вы-
полняемую 16,67 нс.

3.2 Формирование дискретного сигнала с помощью таймера


3.2.1 Задание
Разработать программу генератора напряжения формы меандра с
частой Гц. Обеспечить формирование сигнала на выводе P0.7. Задачу
решить с помощью прерывания от схемы совпадения таймера.
3.2.2 Общие рекомендации
Решение, примененное в предыдущей работе просто, но интересно
лишь для демонстрации основных операций программирования микро-
контроллера. Практической ценности такое решение не представляет, за ис-
ключением случая сравнительно небольших интервалов времени, например

163
долей миллисекунд. Недостаток в том, что программа «зависает» на 0,5 с и
не может выполнять никаких других задач, кроме «мигания светодиодом».
На практике формирование временной задержки производится с помощью
таймера, схемы совпадения и системы прерываний. Настройка таймера и
схемы совладения производится так, чтобы каждые 0,5 с вырабатывался за-
прос прерывания. Процедура обработки прерывания, вызываемая при этом
автоматически, содержит команду инверсии порта. В этом случае микро-
контроллер свободен для выполнения любого алгоритма, поскольку ожида-
ние обеспечивается аппаратурой микроконтроллера параллельно.
Отметим, что низкая частота сигнала, которую предстоит получить на
выводе P0.7 выбрана лишь для лучшей визуализации работы программы. Во-
обще предлагаемое решение можно применять при частотах сигнала до сотен
килогерц. Алгоритм решения задачи показан на рисунке 3.2.1.
Основная программа Процедура обработки прерывания

Начало Начало

1 7
Настройка портовых Инверсия
линий на вывод портовой линии
4
2 Настройка системы 8
Настройка таймера: прерываний Сброс флага
вкл. сброс и запроса прерывания
запрос прерывания 5
Запуск таймера 9
3 Инициализация
Задание порогового системы прерываний
значения для таймера 6
Пустая команда
Конец

Рисунок 3.2.1 – Алгоритм программы формирования дискретного сигнала


с помощью прерывания от таймера
Блоки 1–4 относятся к настройке МК и будут рассмотрены ниже. Веч-
ный цикл не содержит команд (блок 5). Выход из цикла ожидания осуществ-
ляется автоматически при появлении запроса прерывания. Тогда управление
получает процедура обработки прерывания, которая содержит команду ин-
версии портовой линии (блок 6), а также команды, необходимые для кор-
ректного возврата управления в основную программу (блок 7–8)
3.2.3 Алгоритм программы
1. Настройка портовой линии P0.7 на вывод производится через ре-
гистр IO0DIR (раздел 1.10.1).
2. Настройка схемы совпадения выполняется через регистр T0MCR
(раздел 1.13.4). Необходимо разрешить формирование запроса прерывания и
сброса таймера в ноль.
3. Рассчитать пороговое значение для таймера по формуле (1.13.3) для
с. Исходные данные для расчета: тактовая частота периферийных
устройств , тактовая частота ядра и частота кварцевого резона-
тора , по умолчанию связаны следующими соотношениями
164
МГц.
Записать команду загрузки рассчитанного значения в регистр T0MR0.
4. Настроить систему прерываний через регистры VICVectAddr0,
VICVectCntl0, VICIntEnable (раздел 1.11.5).
5. Включить таймер-счетчик в режиме таймера (регистр T0TCR).
6. Закончить программу пустым вечным циклом
while (1) ;
7. Перед основной программой поместить процедуру обработки пре-
рываний по шаблону, приведенному в разделе 1.11.7. Флаг прерывания сбра-
сывается записью единицы в регистр T0IR.
T0IR=1;
В теле процедуры должна находиться единственная команда инверсии порта.
Отладка программы осуществляется по «быстрому алгоритму», рас-
смотренному в разделе 2.4.1

3.3 Опрос дискретного датчика или кнопки


3.3.1 Задание
Разработать программу, инвертирующую логический уровень на ли-
ниях P0.7 при каждом спадающем фронте сигнала на линии P0.14. Имитация
сигнала дискретного датчика производится кнопкой.
3.3.2 Общие рекомендации
Для решения задачи необходимо периодически считывать содержи-
мое порта 0 и сохранять его в специально созданную переменную. Если те-
кущее состояние линии P0.14 изменится по отношению к предыдущему со-
стоянию, сохраненному в переменной с единицы на ноль, значит, кнопка
нажата и следует инвертировать линию P0.7. Алгоритм программы показан
на рисунке 3.3.1.
3.3.3 Алгоритм программы
В программе потребуется объявить две целочисленные переменные
NewPort и OldPort, предназначенные для хранения текущего и предыдущего
состояния порта.
int NewPort, OldPort;
1. Основная программа начинается с настройки линии P0.7 на вывод.
Команды, следующие далее (блоки 2–5), помещаются внутри вечного
цикла while (1) { ... }.
2. Считать содержимое порта 0 в переменную NewPort с наложением
маски, то есть с логическим умножением, обеспечивающим копирование
только интересующего 14-го разряда.
NewPort=IO0PIN & 0x00004000;

165
Начало 2
Скопировать порт
1 в NewPort
Настройка портовой
с наложением маски
линии на вывод

Да 3 OldPort>0 и
NewPort=0

4 Нет
Инверсия P0.7

5
OldPort=NewPort

Рисунок 3.3.1 – Алгоритм программы опроса дискретного датчика


3. Проверить одновременное выполнение условий и
(раздел 2.2.12 и пример 1). Выполнение условий говорит о том,
что кнопка сейчас нажата, а во время предыдущей проверки была отпущена.
4. Если условие выполнено, инвертировать логический уровень на
портовой линии P0.7.
5. После проверки требуется сохранить переменную NewPort в
OldPort, чтобы на следующей итерации с ней сравнивать состояние порта.
3.3.4 Отладка
Дадим некоторые рекомендации по поиску ошибок.
1. Установить точку останова непосредственно после команды чтения
порта, убедиться, что 14-ый бит NewPort равен единице, когда кнопка отпу-
щена, а когда нажата — NewPort равен нулю.
2. Установить точку останова на команде инверсии портовой линии.
Запустить программу и убедиться, что остановка происходит при нажатии на
кнопку P0.14. Если остановка происходит, ошибку снова следует искать в
команде настройки портовой линии на вывод, либо в самой команде инвер-
сии. Если точка останова не достигается, значит, ошибка в проверке условия.
Рекомендуется воспользоваться окном Watch для просмотра содержимого
переменных и прибегнуть к пошаговой трассировке программы.
3. Если состояние портовой линии меняется и при нажатии, и при от-
пускании кнопки. Проверить команду блока (5).

3.4 Опрос состояния механических контактов с подавлением


дребезга
3.4.1 Задание
Разработать программу, выполняющую инверсию логического сигна-
ла на линии P0.7 при нажатии кнопки, подключенной к линии P0.14. Схемы
подключения кнопки и светодиода показаны на рисунках 3.4.1, 3.4.2 Допол-
нительно требуется обеспечить программное подавление дребезга контактов
кнопки.
166
Рисунок 3.4.1 – Схема Рисунок 3.4.2 – Схема подключения
подключения кнопки трехцветного светодиода
3.4.2 Общие рекомендации
В нашем случае замкнутые контакты кнопки дают уровень логическо-
го нуля. На рисунке 3.4.3 показаны осциллограммы напряжения на портовой
линии при размыкании кнопки.
В момент времени мс отчетливо виден всплеск, пересекающий
уровень логического нуля, за которым следует провал напряжения. Такие ко-
лебания происходят до того, как контакт надежно разомкнется и напряжение
установится на уровне примерно 3,3 В. Из приведенной осциллограммы сле-
дует, что надежное размыкание контактов занимает более миллисекунды.
Причем, для кнопок и переключателей других конструкций это время может
быть больше.
Простейший способ опроса дискретных датчиков, рассмотренный в
предыдущей работе, не применяется для механических контактов из-за его
чувствительности к дребезгу. Программа выполняет опрос порта достаточно
часто, чтобы распознать колебания напряжения как повторное замыкание.

Рисунок 3.4.3 – Осциллограмма напряжения на контактах кнопки при размыкании

167
Броски напряжения, вызванные дребезгом, устраняются включением
конденсатора небольшой емкости параллельно контактам. Существует также
надежное программное решение, которое будет рассмотрено далее.
Идея состоит в том, чтобы, распознав однажды нажатие кнопки пре-
кратить опрос на 10–50 мс. Этого времени вполне достаточно, чтобы контак-
ты надежно замкнулись или разомкнулись, но слишком мало, чтобы пропу-
стить действительное нажатие кнопки.
Предлагается сформировать интервал времени для блокировки клави-
атуры с помощью таймера. Использование механизма прерываний здесь из-
лишне; проще организовать периодический опрос флага совпадения таймера
с пороговым значением.
Алгоритм решения поставленной задачи показан на рисунке 3.5.4.
Начало
5 Да
1 Совпадение
Настройка портовых 6
линий на вывод Скопировать порт
Нет
в NewPort
2 с наложением маски
Настройка таймера:
вкл. сброс, остановку,
запрос прерывания
7 Да
3 OldPort≠NewPort
Задание порогового 8
значения для таймера Сброс запроса
Нет
прерывания
4
Запуск таймера 9
Запуск таймера

10
Обработка реакций

11
OldPort = NewPort

Рисунок 3.4.4 – Алгоритм опроса кнопки или датчика


с механическими контактами с подавлением дребезга
Блоки 1–4 относятся к настройке и будут рассмотрены в инструкции к
составлению программы.
1. Интервал времени для блокировки клавиатуры формируется с по-
мощью таймера. Об окончание интервала времени сигнализирует флаг за-
проса прерывания, устанавливаемый автоматически аппаратурой МК при
совпадении таймера TCx с пороговым значением TxMRx. Блокировка опроса
кнопок обеспечивается условием 5. Через несколько миллисекунд после за-
пуска таймера блоком 4 флаг будет установлен и условие 5 станет истинно.
Выполнится ветка «Да», что приведет к чтению порта и копированию его со-
держимого в переменную NewPort (блок 6). Здесь с помощью маскирования
считываются только те биты, к которым подключены кнопки. В данном слу-
чае требуется чтение только одного бита. Остальные биты остаются нулевы-

168
ми. Заметим, что после установки флага обновление содержимого порта в
NewPort осуществляется периодически в каждой итерации главного цикла.
2. Условие 7 предназначено для распознавания изменения в состоянии
кнопок. Заметим, что это условие проверяется независимо от флага совпаде-
ния таймера, но пока NewPort не обновляется (блок 6), условие 7 всегда ложно.
3. Если состояние порта изменилось (контакты кнопок замкнулись
или разомкнулись), выполняются блоки 8–11. Сброс флага совпадения при-
ведет к тому, что при следующей проверке условие 5 будет ложно. Таким об-
разом, при любом изменении клавиатура окажется заблокирована снова. За-
пуск таймера гарантирует автоматическую установку флага совпадения через
несколько миллисекунд и разблокирование клавиатуры. Блок 10 содержит
ряд следующих одно за другим условий проверки каждого бита переменной
NewPort и выполнения требуемых действий.
4. Обновление переменной OldPort (блок 11) приведет к тому, что при
следующей проверке условие 7 окажется ложным. Повторной реакции на
нажатие кнопки не произойдет. Прежде чем блоки 8–11 будут выполняться
снова состояние кнопок должно измениться, причем не ранее чем через не-
сколько миллисекунд.
3.4.3 Алгоритм программы
Потребуется объявить переменные NewPort и OldPort типа int.
1. Настроить поровую линию P0.7 на вывод путем записи управляю-
щего кода в регистр IO0DIR0 (см. раздел 1.10.1).
2. Настроить схему совпадения одного из таймеров МК через регистр
TxMCR (раздел 1.13.4). Включить остановку таймера, сброс в ноль, форми-
рование запроса прерывания. Может быть выбран любой из двух таймеров
произвольно. Также произвольно выбирается номер устройства совпадения
(0–3). Однако для определенности далее будем считать, что используется
таймер 0 и устройство совпадения 0.
3. Рассчитать пороговое значение для таймера по формуле (1.13.3) так,
чтобы интервал времени, отводимый для прекращения дребезга контактов,
был от 10 до 50 мс. Напомним, чему равны тактовые частоты, необходимые
для расчета.
МГц.
4. Дать команду запуска таймера путем записи в регистр T0TCR.
Блоки 1–4 относятся к настройке узлов микроконтроллера и должны
выполняться лишь однажды при сбросе. Блоки ниже помещаются в тело
«вечного» цикла.
while (1)
{
...
}
5. Записать команду проверки флага совпадения таймера. Анализиро-
вать содержимое регистра с наложением маски.

169
6. Если обнаружено совпадение таймера с пороговым регистром, при-
своить переменной NewPort содержимое порта 0. При этом необходимо с по-
мощью операции логического умножения наложить маску, обеспечив копи-
рование единственного бита P0.14 (подробнее см. раздел 1.10.1).
7. Проверить неравенство переменных OldPort и NewPort. Команды,
соответствующие блокам (9–11) должны выполняться при неравенстве этих
переменных.
8. Сбросить флаг запроса прерывания через регистр T0IR. Напомним,
что сброс флага выполняется записью единицы, а не нуля.
9. Запустить таймер через регистр T0TCR.
10. Поместить блок реакции на нажатие кнопок, в данном случае со-
стоящий одного условия, проверяющего бит 14 регистра NewPort. Если бит
равен нулю дать команду инверсии линии P0.7. Для этого использовать сло-
жение по модулю два регистра IO0PIN с константой.
11. Обновить переменную OldPort.
3.4.4 Отладка
Ниже названы некоторые причина возможных ошибок.
1. Не работает таймер, флаг T0IR не устанавливается. Установить
точку останова на команде, соответствующей блоку (5). Запустив программу,
проверить, достигается ли периодически эта команда. Если нет, то просле-
дить за состоянием таймера в окне Peripherals  Timer  Timer 0. Убе-
диться, что таймер инкрементируется, все три события по совпадению (оста-
новка, сброс, запрос прерывания) разрешены, что модуль счета достаточно
мал для быстрого совпадения.
2. Порт не считывается или неверно маскирование. Установить точку
останова на команду блока 8; запустить программу; нажать кнопку на плате.
Ошибка диагностируется, если останова при этом не происходит. Проверить
маскирование (блок 6), условие (блок 7). Рекомендуется использовать про-
смотр переменной NewPort через окно Watch.
3. Неверно условие проверки битов переменной NewPort (блок 10).
Установить точку останова на команду инверсии линии P0.8. Если при нажа-
тии кнопки (притом что отладка по пунктам 1–3 ошибок не выявила) состоя-
ние портовой линии не меняется, искать ошибку в командах блока 10.
4. Дребезг сохраняется из-за неверной инициализации схемы совпаде-
ния. Проверить команды блоков 8 и 9.
5. Состояние портовой линии меняется и при нажатии, и при отпуска-
нии кнопки. Проверить команду блока 11.

3.5 Опрос клавиатуры с автоповтором


3.5.1 Задание
Задание. Разработать программу, инвертирующую логические уровни
на линиях P0.8, P0.9 при нажатии кнопок, подключенных к линиям P0.18 и
P0.19. Необходимо обеспечить защиту от дребезга контактов; инверсия
должна повторяться периодически при удерживании кнопки.
170
3.5.2 Общие рекомендации
Здесь предлагается воспроизвести реакцию на нажатие кнопок, зна-
комое пользователям персонального компьютера. Некое действие выполня-
ется однократно при нажатии кнопки, а затем повторяется периодически, ес-
ли кнопка удерживается в нажатом положении. Причем, задержка перед
началом повтора должна быть больше, чем период автоповтора. Разрабаты-
ваемый в данном практическом занятии алгоритм применяется при создании
интерфейса встраиваемой системы с пользователем. Например, при исполь-
зовании экранного меню для настройки прибора.
Может быть предложено несколько вариантов решения данной зада-
чи. Алгоритм, описанный ниже, представляется авторами наиболее рацио-
нальным.

Рисунок 3.5.1 – Временные диаграммы, показывающие изменение таймера


Начальное значение таймера задано таким, что потребуется секунд
для его совпадения с пороговым регистром (см. рисунок 3.5.1). Это время за-
держки перед повтором. Рекомендуется выбирать с.
После совпадения таймер автоматически сброшен в ноль и для следу-
ющего совпадения потребуется время , определяемое порогом T0MR1.
Как и в предыдущем случае, для подавления дребезга чтение порта
(блок 6) будет производиться только после завершения интервала
с после изменения порта. Блокировка клавиатуры осу-
ществлена блоком 5. Значение порогового регистра T0MR0 определяется от-
носительно начального значения T0TC.
3.5.3 Алгоритм программы
1. Настроить портовые линии P0.8, P0.9 на вывод, записав единицы в
соответствующие разряды регистра IO0DIR.
2. В предлагаемом решении используется две схемы совпадения. По-
ровый регистр T0MR0 определяет задержку для защиты от дребезга , поро-
говый регистр T0MR1 — задержки и для автоповтора.

171
Начало
5 Да
1 Совпадение 0
Настройка портовых 6
линий на вывод Скопировать порт
Нет
в NewPort
2 с наложением маски
Настройка схем
совпадения

3 7 Да
Загрузка таймера и Совпадение 1 или
OldPort≠NewPort
пороговых регистров 8
Сброс запроса
4 Нет
прерывания 1
Запуск таймера
9
Обработка реакций

10 Да
OldPort≠NewPort
11
Загрузка таймера
Нет
12
Сброс запроса
прерывания 0

13
OldPort = NewPort

Рисунок 3.5.2 – Алгоритм программы опроса клавиатуры с автоповтором


Необходимо включить запрос прерывания для совпадения MR0; для
совпадения MR1 включить запрос прерывания и сброс таймера-счетчика (ре-
гистр T0MCR).
3. Рассчитать значения пороговых регистров T0MR0, T0MR1 и тайме-
ра T0TC, которое в данном случае не будет нулевым.
Пороговое значение T0MR1, отвечающее за автоповтор, рассчитыва-
ется по формуле (1.13.3) для интервала . Повторим эту формулу упрощен-
но, опустив операцию округления:
.
Начальное значение таймера вычисляется по аналогичной формуле
таким образом, чтобы разность между ним и T0MR1 соответствовала за-
держке перед автоповтором . Отметим, что величина T0TC окажется отри-
цательной. Чтобы избежать предупреждений компилятора о возможной по-
тере знака при приведении типов, рекомендуется представить результат в до-
полнительном коде. Тогда
, (3.5.1)
или, что то же самое
,

172
Пороговое значение T0MR0 больше на величину, соответствующую
интервалу с. Вопрос выбора этого интервала обсуждался в
разделе 3.5.3.
. (3.5.2)
Рассчитав T0MR0, T0MR1, T0TC, включить в программу команды
присваивания значений этим регистрам.
4. Запустить таймер через регистр T0TCR.
5. Блоки 5–13 помещены в «вечный цикл». Проверить совпадение
MR0 путем сравнения с единицей флага MR0I в регистре T0IR. Для проверки
единственного бита необходимо выделить его наложением маски операцией
логического умножения.
6. Если совпадение произошло (флаг равен единице), обновить пере-
менную NewPort, скопировав в нее содержимое порта с наложением маски.
7. Последующие блоки выполняются при выполнении одного из усло-
вий: совпадение MR1 или неравенство переменных NewPort и OldPort.
8. В случае выполнения условия блока 7 необходимо сбросить запрос
прерывания и обеспечить обработку реакции на кнопку. В соответствии с за-
данием реакция состоит в инверсии линии порта P0.8 или P0.9 в зависимости
от нажатой кнопки P0.18 или P0.19.
9. При обнаружении изменения порта (блок 10) потребуется снова за-
грузить в таймер начальное значение, рассчитанное по формуле 3.5.1 (блок
11). Сбросить флаг совпадения 0 (блок 12), что обеспечит блокировку опроса
порта ложным условием 5. И обновить прежнее значение порта (блок 13), что
позволит обнаружить очередное изменение при следующем выполнении
блоков 7 и 10.
3.5.4 Отладка
1. Из-за неверной настройки таймера и схемы совпадения 0 нет об-
новления переменной NewPort (блок 6). Установить точку останова на ко-
манду блока 6 и, запустив программу, проверить достигается ли эта точка.
Если останова не происходит, проверить настройки таймера.
2. Из-за неверной настройки схемы совпадения 1 нет анализа измене-
ний порта. Установить точку останова на команду блока 8. Проверить дости-
гается ли она, запустив программу и нажав на кнопку учебной платы. Если
останова не происходит, проверить настройку схемы совпадения 1. Рекомен-
дуется также сопоставить содержимое порта и переменной NewPort.
3. После обработки реакции на изменение уровня таймеру не присева-
ется требуемого начального значения, в результате чего до порогового зна-
чения T0MR0 (см. рисунок) таймер доходит несколько минут. Проверить со-
держимое таймера, установив точку останова на команду блока 12.
4. Проверить команды, отвечающие непосредственно за реакцию на
изменения уровней (блок 9).
5. Состояние светодиода меняется и при нажатии и при отпускании
кнопки либо при удерживании кнопки они мигают с очень высокой частотой.
Проверить команды, отвечающие за реализацию блоков 10–13.

173
3.6 Формирование импульсного управляющего сигнала
с помощью модуля ШИМ
3.6.1 Задание
Разработать программу, генерирующую три последовательности пря-
моугольных сигналов, смещенных по фазе на 120º. Параметры сигналов: ча-
стота ; скважность (коэффициент заполнения задаются препо-
давателем). Пример осциллограммы сигнала показан на рисунке 3.6.1

Рисунок 3.6.1 – Осциллограммы сигнала на выходах ШИМ


3.6.2 Общие сведения
В импульсных системах управление объектом возможно путем регу-
лирования коэффициента заполнения (скважности) импульсов, начальной
фазы или частоты. В этой связи различают системы с широтно-импульсной
модуляцией (ШИМ), импульсно-фазового управления (СИФУ) или частотно-
го управления.
Система может быть как однофазной, так и трехфазной. Трехфазная
система состоит из трех каналов. Параметры импульсов во всех каналах
обычно одинаковы, но начальная фаза отличается на 120 градусов.
Ниже в таблицах 3.6.1–3.6.3 приводятся выражения для настройки
ШИМ в трехфазных системах тех типов. В случае однофазной системы нуж-
но повторить настройки для каналов 0 и 2 (а для СИФУ— 0–2).
В трехфазных системах управляющий импульсный сигнал формиру-
ется на выходах PWM2, 4, 6; в однофазных — PWM2. Считается, что предва-
рительный делитель частоты ШИМ не используется.
Частотное управление дает коэффициент заполнения . Если
требуется получить другой коэффициент управления, можно использовать
настройки для ШИМ (таблица 3.6.1).

174
Таблица 3.6.1 – Настройки для трехфазной системы ШИМ
Пороговые Значения пороговых регистров PWMSELx
регистры (переменная — )
PWMMR0 —
PWMMR1 0 (не имеет значения) —
PWMMR2 0
PWMMR3 0
PWMMR4 1
PWMMR5 0
PWMMR6 1
Таблица 3.6.2 – Настройки для трехфазной системы СИФУ
Пороговые Значения пороговых регистров PWMSELx
регистры (переменная — , град.)
PWMMR0 —
PWMMR1 —
PWMMR2 ¿ fP CLK + PWMMR1 1
PWMMR3 0
PWMMR4 1
PWMMR5 0
PWMMR6 1
Таблица 3.6.3 – Настройки для трехфазной системы частотного управления
Пороговые Значения пороговых регистров PWMSELx
регистры (переменная — )
PWMMR0 —
PWMMR1 0 (не имеет значения) —
PWMMR2 0
PWMMR3 0
PWMMR4 1
PWMMR5 0
PWMMR6 1
3.6.3 Алгоритм программы
Широтно-импульсных модулятор является одним из самых простых
узлов микроконтроллера. Для получения сигнала с неизменными параметра-
ми требуется однократно выполнить настройку модуля ШИМ. Алгоритм
настройки приведен на рисунке 3.6.2.
1. Перевести портовые линии P0.7–P0.9 в режим PWM2, 4, 6 соответ-
ственно (регистр PINSEL0).
2. Задать частоту ШИМ Гц (регистр PWMMR0). Восполь-
зоваться первой формулой в таблице 3.6.1.
3. Рассчитать и присвоить регистрам PWMMR1–6 значения, обеспе-
чивающие необходимую скважность (коэффициент заполнения и начальные
фазы). Начальная фаза канала PWM2 задается регистром PWMMR1, его ко-
175
эффициент заполнения — разностью PWMMR2 и PWMMR1. По аналогии
следующая пара регистров PWMMR3–PWMMR4 определяет параметры сиг-
нала PWM4, а пара PWMMR5–PWMMR6 — сигнала PWM6. Принять
начальную фазу второго канала нулевой, остальные в соответствии с задани-
ем смещены на 120º. Все необходимые формулы есть в таблице 3.6.1.
Основная программа 4
Настройка схемы
Начало
совпадения ШИМ
1
Настройка режимов 5
Включить счетчик
портовых линий
ШИМ в синхронном
P0.7–P0.9
режиме
2 6
Задание частоты ШИМ
Включить каналы с
3 управлением фазой
Задание коэфф.
заполнения
и начальные фазы 7
Пустая команда

Рисунок 3.6.2 – Алгоритм настройки ШИМ


4. Через регистр PWMMCR разрешить сброс счетчика ШИМ при сов-
падении с пороговым значением PWMMR0.
5. Включить счетчик ШИМ, включить защелки пороговых регистров
для синхронного режима (регистр PWMTCR).
6. Через регистр PWMPCR включить выходы каналов 2, 4, 6 и управ-
ление начальной фазой для каналов 4 и 6 (см. правую колонку таблицы 3.6.1).
7. Зациклить программу.
3.6.4 Отладка
Если полученный сигнал не соответствует осциллограммам на рисун-
ке 3.6.1, тщательно проверить настройку ШИМ. Практически верные
настройки ШИМ показаны на рисунке 2.4.8.
3.6.5 Синхронизация внешним сигналом
В системах импульсно-фазового управления обычно необходима син-
хронизация внешним сигналом, соответствующим напряжению питающей
сети 220/380 В, 50 Гц. Такой сигнал формируется с помощью устройства
синхронизации с трансформаторной или оптической развязкой.
С точки зрения программирования для синхронизации необходимо
обеспечить сброс счетчика ШИМ и начало нового цикла счета по фронту
внешнего синхросигнала. В этом случае частота станет равна частоте сети, а
фаза начнет отсчитываться от начала синхроимпульса (обычно совпадает с
началом периода сети).
Предлагается реализация с помощью прерывания по внешнему сигна-
лу (раздел 1.12). Нужно запретить автоматический сброс счетчика ШИМ по

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

3.7 Формирование сигналов специальной формы с помощью ЦАП


3.7.1 Задание
Разработать программу, формирующую на выходе AOUT сигнал за-
данной формы (прямоугольной, синусоидальной, треугольной или пилооб-
разной) с заданной амплитудой и частотой. Рекомендуемые параметры сиг-
нала: амплитуда от 0,1 до 2,2 В; частота от 20 Гц до 20 кГц.
3.7.2 Основы
Цифро-аналоговый преобразователь дает дискретный по уровню сиг-
нал. Поэтому здесь речь идет об аппроксимации аналогового сигнала дис-
кретным по уровню и по времени.
В простейшем случае аппроксимация выполняется разбиением перио-
да сигнала на равных интервалов длительностью . В течение
каждого интервала уровень сигнала постоянный. Так образуются характер-
ные «ступеньки» или «дискреты». На рисунке 3.7.1 приведены примеры та-
кой аппроксимации сигналов разной формы.

Рисунок 3.7.1 – Осциллограммы сигналов, различной формы,


полученные с помощью ЦАП

177
На частотах порядка 500 Гц быстродействия микроконтроллера недо-
статочно для вычисления дискретных отсчетов синусоидального сигнала в
реальном времени. То есть для вычисления одной точки синуса требуется
время, превышающее . Поэтому таблица синусов вычисляется заранее. В за-
висимости от того меняются ли параметры сигнала в ходе работы программы
или они постоянны, таблица рассчитывается либо на этапе разработки про-
граммы и «прошивается» в ПЗУ, либо рассчитывается по программе самим
микроконтроллером и хранится в ОЗУ. Здесь будем рассматривать только
второй случай. Если расчет таблицы выполняется микроконтроллером, то
вычисление тригонометрической функции связано с существенными времен-
ными затратами. Можно рекомендовать рассчитать шаблон синусоидального
сигнала фиксированной амплитуды и постоянно хранить в памяти в формате
с плавающей точкой. Будем обозначать этот шаблон . В таблице 3.7.1 при-
ведены выражения и соответствующие команды Си для расчета однополяр-
ного шаблонного сигнала разных форм в диапазоне .
Таблица 3.7.1 – Выражения для расчета шаблонных сигналов
Форма Математическое Реализация с помощью
сигнала выражение ( ) команды Си
Меандр u[k] = k<N/2? 0 : 2;

Пила u[k] = k*2.0/(N-1);

u[k] = k<N/2 ?
Треугольник
k*4.0/N : 4-k*4.0/N;
u[k] =
Синус
sin(6.283185307*k/N)+1;
Всякий раз, когда необходимо изменить амплитуду, на основе шабло-
на путем масштабирования, смещения и округления рассчитывается циф-
ровой сигнал . Этот сигнал должен быть представлен в формате с фиксиро-
ванной точкой. Он содержит отсчеты, готовые для записи в ЦАП.
Сигнал рассчитывается на основе по общей формуле (независи-
мо от формы):

, (3.7.1)

где — амплитуда сигнала, В; — опорное напряжение, В.


Дадим необходимые пояснения. Множитель 511,5 выбран исходя из
числа кодовых комбинаций 10-разрадного ЦАП ( ) и при
дает . Операция округления уже известна.
Умножение на 64 — это сдвиг на 6 разрядов влево (см. формат регистра
DACR в разделе 1.16.1).
Выражение (3.7.1) реализация на Си следующей командой.
v[k]=(int)floor(511.5*A/Vref*u[k]+0.5)<<6;
178
Для формирования временных интервалов используется таймер. В
процедуру обработки прерывания помещается команда обновления ЦАП вы-
численным заранее значением для очередной дискреты.
3.7.3 Алгоритм программы
Потребуется подключить директивой #include файл math.h.
На вкладке Configuration Wizard файла настройки Startup.s выбрать
опцию VPBDIV Setup и VPB Clock = CPU Clock.
В программе используется несколько глобальных констант и пере-
менных:
а) целочисленная константа N — число дискрет в периоде сигнала
(обычно несколько десятков или сотен, но не более 500 тыс./с);
б) вещественная константа Vref, равная величине опорного напряже-
ния (по умолчанию 2,2 В);
в) вещественные переменные A и f — амплитуда и частота сигнала,
которым здесь же следует присвоить значения из задания;
г) вещественный массив отсчетов сигнала u из N элементов;
д) целочисленный массив v из N элементов;
е) целочисленный счетчик .
Схема основной программы и процедуры обработки прерывания по-
казаны на рисунке 3.7.2
В основной программе потребуется локальная переменная — счетчик k.
Основная программа Процедура обработки прерывания

Начало Начало

1 1
K=0 Запись в ЦАП v[K]

2 2
Настройка режима K=K+1
линии P0.25
3 Да
K=N
Нет 3 Да 4
k = 0; k < N; k++ Нет K=0

4
6 Расчет u[k]
Настройка таймера: 5
5 Инициализация
задание порога, вкл.
Расчет v[k] системы прерываний
сброс и запрос прерывания

7 Конец
Настройка системы
прерываний

8
Пустая команда

Рисунок 3.7.2 – Алгоритм программы функционального генератора


179
1. Присваивание нулевого начального значения счетчику K реализует-
ся в разделе объявления.
2. Перевести линию P0.25 в режим аналогового выхода (PINSEL1).
3–5. В цикле заполнить массивы по одной из формул таблицы 3.7.1 и
формуле (3.7.1)
6. Настроить таймер:
а) задать пороговое значение, обеспечивающее необходимую дли-
тельность дискреты
;
в соответствии с выражением 1.13.3 пороговое значение
;
б) включить сброс и прерывание по совпадению (T0MCR);
в) включить таймер (T0TCR).
7. Настроить систему прерываний через регистры VICVectAddr0,
VICVectCntl0 и VICIntEnable (раздел 1.11.5).
Процедура обработки прерывания создается до основной программы
по шаблону, предложенному в разделе 1.11.7.
Прокомментируем алгоритм процедуры обработки прерываний.
1. Записать значение текущей дискреты в ЦАП (регистр DACR).
2. Увечить глобальный счетчик K на единицу.
3–4. Обнулить счетчик K, Если он равен N.
5. Выполнить инициализацию системы прерываний, сбросив флаг
совпадения (T0IR) и обнулив VICVectAddr.
3.7.4 Повышение точности генерирования частоты
Недостаток рассмотренного алгоритма в том, что равенство длитель-
ностей всех интервалов увеличивает погрешность частоты. Действительно,
очевидно, что пределы абсолютной погрешности длительности дискреты
.
Причем погрешности каждой дискреты одинаковы и имеют один и тот же
знак. Тогда предельная абсолютная погрешность периода пропорциональная
числу дискрет .
.
Избавиться от влияния можно, сделав разными для каждой дис-
креты, так чтобы погрешность периода не превышала половины такта. Реали-
зация такого подхода потребует внести следующие изменения в алгоритм:
1. Ввести глобальный целочисленный массив T из N элементов, кото-
рый будет хранить пороговые значения таймера для каждой дискреты.
2. Цикл (блоки 3–5) дополнить командой расчета длительностей дис-
крет по формуле
T[k]=floor(60E6/f/N*(k+1)+0.5)-1;
3. Присвоить пороговому значению (блок 6) величину T[0].

180
T0MR0=T[0];
4. Задать еще одно пороговое значение таймера, соответственно пери-
оду сигнала, например
T0MR1=60E6/f-1;
или (лучше) с округлением:
T0MR1=floor(60E6/f-0.5);
5. Настроить схемы совпадений таким образом, чтобы T0MR0 давало
только запрос прерывания, а переполнения давало T0MR1.
6. Процедуру обработки прерывания (непосредственно после блока 1)
дополнить командой задания нового порогового значения
T0MR0=T[K];
Теперь в начале каждой дискреты таймер не сбрасывается, а продол-
жает инкрементироваться. При этом самому пороговому значению T0MR0
дается приращение, соответствующее длительности очередной дискреты.
Сброс таймера в ноль осуществляется устройством совпадения T0MR1.
Сброс происходит одновременно с концом последней дискреты.
3.7.5 Выбор числа дискрет
Число дискрет стремятся сделать как можно больше. Чем выше ,
тем меньше шум квантования и выше его частота. Однако быстродействие
как цифроаналогового преобразователя, так и микроконтроллера ограничива-
ет число дискрет. Расход процессорного времени связан с обработкой преры-
ваний. С помощью микроконтроллера LPC2148 при практически не
удается получить частоту сигнала больше 20 кГц (длительность дискреты
около 1,6 мкс). В то же время на низких частотах есть возможность увели-
чить до сотен и тысяч.
Если требуется регулировать частоту сигнала в широких пределах,
можно рекомендовать динамическое изменение числа дискрет , увеличивая
его с уменьшением частоты и сохраняя малой длительность дискреты при
любой частоте.
Например, расчет числа дискрет можно производить по формуле:

, (3.7.2)

где — наибольшая частота сигнала; — число дискрет на наиболь-


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

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

. (3.7.3)

Пример реализации на Си
n=N >> (int)floor(log(20E3*16/f)/log(2));
if (n==0) n=1;
Условный оператор вводит ограничение .
Блок 2 процедуры обработки прерывания потребуется заменить на
K+=n;

3.8 Управление двухфазным шаговым двигателем


3.8.1 Задание
Разработать программу, которая обеспечит колебательные движения
ротора шагового двигателя в диапазоне углов 0–180°. Период колебания 10 с.
Двигатель должен поворачиваться на 10 шагов по часовой стрелке, затем на
10 шагов против часовой стрелки. Шаги повторяются через 0,5 с.
3.8.2 Общие сведения
Шаговый двигатель — это электрическая машина переменного тока,
ротор которой может устойчиво занимать несколько фиксированных поло-
жений. Ротор меняет положение, поворачиваясь на определенный угол (шаг)
при появлении импульса тока в обмотке.

Рисунок 3.8.1 – Схема подключения шагового двигателя к микроконтроллеру


На учебной плате EA-EDU-001 установлен миниатюрный двигатель
20BY20L033 производства фирмы Finespin Motors. Двигатель имеет две об-
мотки. Полный оборот ротора состоит из 20 шагов (одному шагу соответ-
ствует угол поворота 18º). Обмотки двигателя включены в диагонали транзи-
сторных мостов. Это обеспечивает смену направления тока в обмотках на
обмотках. Функции мостовых преобразователей выполняют драйверы
182
MIC4428 фирмы Micrel (рисунок 3.8.1). Драйверы управляется портовыми
линиями P0.12 и P0.21.Таблица 3.8.1 поясняет реакцию двигателя на импуль-
сы тока в обмотках.
Вращение по часовой стрелке обеспечивается сменяющими друг дру-
га состояниями 1, 6, 4, 7, против часовой стрелки — состояниями 5, 2, 8, 3.
Таблица 3.8.1 – Управление двухфазным шаговым двигателем
Направление поворота
P0.12 P0.21
ротора на один шаг (18º)
1 0 
2 1 
3 0 
4 1 
5 0 
6 1 
7 0 
8 1 
Чередующиеся кодовые комбинации 00–01–11–10 на P0.12, P021
представляет собой код Грея. Код, в котором запись любых двух смежных
чисел отличаются только одним двоичным разрядом.
Временные диаграммы, иллюстрирующие управление двигателем, по-
казаны на рисунке 3.8.2
P0.12 1 4 1 3 2

P0.21 6 7 6 8 5 8

Положение
ротора
Рисунок 3.8.2 – Временные диаграммы,
поясняющие управление шаговым двигателем
3.8.3 Алгоритм программы
Задача решается с помощью таймера, генерирующего прерывания
каждые 0,5 с. Процедура обработки прерываний содержит команды инверсии
портовых линий в соответствии с кодом Грея. Перевод позиционного двоич-
ного кода в код Грея рассматривается в разделе 2.1.
Поскольку здесь имеем дело лишь с четырьмя кодовыми комбинаци-
ями, проще заранее найти их, поместить в массив, а далее выводить в порт в
порядке, соответствующим направлению вращения.
Схема алгоритма показана на рисунке 3.8.3.
В программе потребуются следующие глобальные переменные:
а) целочисленный со знаком счетчик шагов ;
б) целочисленное со знаком приращение счетчика ;

183
Основная программа Процедура обработки прерывания

Начало Начало

1 1
Включение Вывод в порт кода
высокоскоростного P[n%4]
режима порта 0
2
2 n=n+D
Настройка на вывод
P0.12 и P0.21
Нет 3
n < 0 или n > 10
3
Задание маски
для порта 0 Да
4
4 n = n – 2D
Настройка таймера:
задание порога, вкл. 5
сброс и прерывание D = –D

5
Настройка системы 6
прерываний Инициализация
системы прерываний

6
Пустая команда Возврат

Рисунок 3.8.3 – Схема программы управления шаговым двигателем


в) целочисленный массив, содержащий все четыре возможные кодо-
вые комбинации, управляющие двигателем:
unsigned int P[]=
{0x00000000,0x00001000,0x00201000,0x00200000};
1. Следует включить высокоскоростной режим обмена для порта 0
(регистр SCS). Далее для обращения к порту будут использованы только ре-
гистры FIO0….
2. Настроить линии P0.12 и P0.21 на вывод (регистр FIO0DIR).
3. С помощью маскирования запретить изменение всех линий порта 0
кроме P0.12 и P0.21. Для этого записать в регистр FIO0MASK все единицы
кроме двух разрядов. Проще всего сделать это командой
FIO0MASK=~0x00201000;
4. Настроить таймер:
а) задать порог таймера (T0MR0) для получения интервала времени
0,5 с; расчет проводить по формуле (1.13.3), учитывая, что по умолчанию
МГц;
б) включить сброс таймера и формирование запроса прерывания по
совпадению (регистр T0MCR);
в) включить таймер (регистр T0TCR).
5. Включить прерывание от таймера через регистры VICVectAddr0,
VICVectCntl0, VICIntEnable (раздел 1.11.5).

184
6. Завершить программу вечным циклом.
Схема процедуры обработки прерывания показана на рисунке 3.8.3.
1. Вывести в порт очередную кодовую комбинацию. Индекс элемента
массива последовательно должен принимать значения 0, 1, 2, 3, 0, 1 и т. д. В
то время как счетчик шагов n будет меняться от 0 до 10 и обратно до 0. Оче-
видно, что индекс массива можно вычислить как остаток от деления n на 4.
Поэтому блок 1 реализуется командой
FIO0PIN=P[n%4];
2. Увеличить счетчик шагов n на величину приращения D.
3–5. Если n вышел за границы интервала [0; 10], сделать шаг в проти-
воположном направлении вычитанием удвоенного D; далее изменить знак D.
Это приведет к изменению порядка чередования кодовых комбинаций на
противоположный и реверсу двигателя.
6. Завершить процедуру обработку прерывания сбросом флага запроса
(T0IR) и обнулением VICVectAddr.

3.9 Применение ШИМ для формирования низкочастотных


аналоговых сигналов
3.9.1 Задание
Разработать программу, с помощью ШИМ формирующую на выходе
AOUT учебной платы гармонический сигнал частой 2 Гц.
3.9.2 Основные сведения
Если обработать ШИМ-сигнал фильтром нижних частот, частота сре-
за которого намного меньше частоты несущего колебания, то получим вос-
становленный модулирующий сигнал. Так ШИМ может использоваться для
формирования низкочастотного аналогового сигнала. На плате EA-EDU-001
выход PWM2 микроконтроллера подключен к RC-фильтру нижних частот
1-го порядка (см. рисунок 3.9.1 R83=3 кОм, C39=22 мкФ). Частота среза
фильтра примерно составляет 2,4 Гц (по уровню –3 дБ). Это позволит фор-
мировать лишь постоянное или медленно меняющее напряжение. Однако
ограничение вызвано именно аналоговым фильтром, а не возможностями
микроконтроллера. Практически возможно получить аналоговый сигнал с
частотой, по крайней мере, до 20 кГц.

Рисунок 3.9.1 – Схема фильтра нижних частот


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

185
му закону. Выше показана осциллограмма гармонического напряжения ча-
стотой 2 Гц, полученного путем фильтрации. В данном случае частота следо-
вания импульсов в 50 раз превышает частоту модулирующего колебания
( Гц). При этом отчетливо видна высокочастотная составляющая в
составе гармонического напряжения.
Осциллограмма для случая тысячекратного превышения ( кГц)
показана на рисунке 3.9.3.
Для реализации генератора предлагается использовать таблицу дис-
кретных отсчетов гармонического сигнала и изменение длительности моду-
лированных импульсов по таймеру (многократно за период).
Введем следующие обозначения: , Гц — частота гармонического
сигнала; — число модулированных импульсов, заключенных в периоде
гармонического сигнала. — коэффициент, связывающий частоту импуль-
сов и частоту модулирующего колебания.

Рисунок 3.9.2 – Осциллограммы ШИМ-сигнала (f0 = 100 Гц, M = 50, N = 50)


и гармонического сигнала, полученного с помощью его фильтрации

Рисунок 3.9.3 – Осциллограмма гармонического напряжения, полученного


с помощью фильтрации ШИМ-сигнала (f0 = 2 кГц, M = 1000, N = 50)

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

, (3.9.3)

3.9.3 Алгоритм основной программы


Схема алгоритма показана на рисунке 3.9.4. В программе использует-
ся функция расчета синуса, поэтому кроме привычного описания регистров,
файла LPC2148.h, необходимо подключить библиотеку математических
функций.
#include <math.h>
1. Для управления ШИМ будут использованы , , , смысл которых
был разъяснен выше. Объявить константы в Си-программе необходимо ди-
рективами
#define f 2.0 // Частота гармонического сигнала
#define M 100 // Число импульсов ШИМ в периоде
#define N 100 // Число градаций длительности в периоде
В программе потребуется объявить глобальные переменные: целочис-
ленные счетчик k, и массив u из N элементов.
int k, u[N];
2. Перевести линию P0.7 в режим PWM2 (регистр PINSEL0).
3. Задать частоту ШИМ через регистр PWMMR0 (3.8.1). Рекомендует-
ся выразить ее через объявленные константы, например
PWMMR0=15E6/f/M-1;
Здесь 15E6 обозначает входную частоту счетчика ШИМ по умолчанию.
4. Через регистр PWMMCR разрешить сброс счетчика ШИМ при сов-
падении с пороговым значением PWMMR0.

187
Основная программа 7 Процедура обработки
Расчеты таблицы прерывания
Начало
отсчетов сигнала
Начало
1 8
Ввод f0, M, N 1
k=0
PWMMR2=u[k]
2
Настройка режима 9
Настройка таймера: 2
портовой лини P0.7 Инкремент k
вкл. cброс и
3 запрос прерывания 3
Задание частоты ШИМ Стробирование
10 защелки ШИМ
4 Задание порогового
Настройка схемы значения для таймера
совпадения ШИМ 4 Да
11 k=N
5 Настройка системы
Вкл. cч. ШИМ в прерываний 5
Нет k=0
синхронном режиме
12
6 Запуск таймера
Включить канал PWM2 6
Инициализация
13 системы прерываний
Пустая команда
Конец
Рисунок 3.9.4 – Схемы алгоритмов основной программы
и процедуры обработки прерывания от таймера
5. Включить счетчик ШИМ в синхронном режиме (с использованием
защелок) через регистр PWMTCR.
6. Включить выход канала PWM2 (регистр PWMPCR). Управление
фазой для всех каналов оставить отключенной.
7. Расчет таблицы выполнить по формуле (3.9.3), которая реализуется
на Си следующим образом:
for (k=0; k<N; k++)
u[k]=floor((PWMMR0-1)/2*
(sin(2*3.1415927*k/N)+1)+0.5);
8. Значение счетчика будет использоваться в дальнейшем, поэтому
после цикла важно присвоить ему нулевое значение.
9–13. Блоки абсолютно идентичны соответствующим блокам про-
граммы генератора прямоугольного сигнала (практическое занятие №2). От-
метим лишь, что присвоить задать пороговое значение (3.9.2) удобно коман-
дой
T0MR0=15E6/f/N-1;
3.9.4 Алгоритм процедуры обработки прерывания
Оформление процедуры обработки прерывания от схемы совпадения
таймера рассматривалось в практическом занятии №2.
1–2. Загрузить новое значение в пороговый регистр PMWMR2. Оба
блока реализуются одной командой Си

188
PWMMR2=u[k++];
3. Разрешить обновление защелки пороговых значений в начале сле-
дующего периода. Для этого установить единицу в разряд регистра
PWMLER, соответствующий второму каналу ШИМ.
4–5. Реализовать проверку равенства счетчика предельному числу ,
обнулить k в случае равенства.
6. Сброс флага прерывания и инициализация адреса обсуждалась в
практическом занятии № 2.

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


3.10.1 Задание
Разработать библиотеку подпрограмм управления жидкокристалличе-
ским символьным индикатором. Библиотека должна содержать функции:
инициализации, очистки экрана, перемещения курсора, вывода строки сим-
волов. Программу необходимо протестировать путем отображения произ-
вольного текста на индикаторе.
3.10.2 Управление модулем жидкокристаллической индикации
На плате EA-EDU-001 установлен символьный жидкокристалличе-
ский индикатор типа LMB162A производства фирмы Topway. Индикатор со-
стоит из двух строк, в каждой из которых имеется 16 знакомест. Каждое зна-
коместо представляет собой матрицу из 5x7 точек. Индикатор является зна-
косинтезирующим. Это значит, что изображение символа формируется аппа-
ратными и программными средствами самого индикатора в соответствии с
кодом символа. Кодировка в основном соответствует стандарту ASCII. Име-
ется возможность программирования восьми произвольных символов.
Интерфейс взаимодействия с индикатором фактически стандартизо-
ван. Поэтому подпрограммы управления индикатором, которые предстоит
разработать, будут совместимы с множеством подобных жидкокристалличе-
ских модулей, в том числе, производства отечественной фирмы МЭЛТ. Здесь
будут рассмотрены только основные операции управления индикатором. Для
подробного изучения рекомендуется обратиться к русскоязычной докумен-
тации фирмы МЭЛТ.
Интерфейс (рисунок 3.10.1) состоит из 8-разрядной шины данных
DB0–DB7; сигнала RS, определяющего передается ли в настоящее время ко-
манда или данные; сигнала RW, задающего направление передачи данных по
шине; стробирующего сигнала E, по срезу которого индикатор воспринимает
остальные сигналы.
Система команд индикатора представлена в таблице 3.10.1. Индика-
тор имеет память для хранения кодов символов, поэтому сформированное
однажды изображение останется без изменения, если не поступит соответ-
ствующей команды от микроконтроллера.
Для подачи управляющей команды индикатору необходимо вывести
байт на шину данных и установить сигналы RS и RW в соответствии-с табли-
цей 1. Выполнение команды инициируется сигналом по спадающему фронту
189
Таблица 3.10.1 – Система команд символьного ЖКИ на основе контролера совместимого с KS0066
Команда ЖКИ RS RW DB7 – DB0 Комментарии
Clear Display
0 0 0 0 0 0 0 0 0 1 Очистить дисплей
Очистка дисплея
Return Home
0 0 0 0 0 0 0 0 1 x Установить курсор на нулевую позицию
Возврат курсора
— дисплей неподвижен/сдвигается
Entry Mode Set
0 0 0 0 0 0 0 1 ID S — сдвиг курсора (и дисплея)
Режим сдвига дисплея или курсора
вправо/влево
— дисплей выключен/включен
Display ON/OFF
0 0 0 0 0 0 1 D C B — курсор выключен/включен
Включение дисплея и режим курсора
1 0 0 — мигание курсора выкл./вкл.
Shift Display — сдвинуть курсор/дисплей
0 0 0 0 0 1 SC RL x x
Сдвиг дисплея или курсора — сдвинуть влево/вправо
— 4-/8-разрядный интерфейс
Function Set
0 0 0 0 1 DL N F x x — 1/2 строки
Настройка
1 1 0 — шрифт 5×8/5×11
Set CGRAM Address A0–A6 текущий адрес в таблице знакогене-
0 0 0 1 A5 A4 A3 A2 A1 A0
Установить адрес в таблице знакоген. ратора
Set DDRAM Address A0–A6 текущий адрес в памяти символов
0 0 1 A6 A5 A4 A3 A2 A1 A0
Установить адрес в памяти символов (позиция курсора)
Read Busy Flag and Address — модуль готов/занят;
0 1 BF A6 A5 A4 A3 A2 A1 A0
Чтение флага готовности и адреса A0–A6 текущий адрес
Write Data
1 0 D7 D6 D5 D4 D3 D2 D1 D0 D0–D7 данные
Запись данных
Read Data
1 1 D7 D6 D5 D4 D3 D2 D1 D0 D0–D7 данные
Чтение данных
190
импульса на линии E. Время выполнения команд очистки экрана (Display
Clear) и возврата курсора (Return Home) составляет 1,71 мс; остальных ко-
манд — 41 мкс. Эти характеристики приведены для модуля LMB162; для
других аналогичных устройств могут отличаться. Прежде чем подавать оче-
редную команду необходимо выдержать паузу или циклически опрашивать
флаг готовности модуля индикации. Взаимодействие с опросом флага слож-
нее в программной реализации, но минимизирует величину задержки и га-
рантирует работу с любым аналогичным модулем. Далее будет рассмотрены
оба способа взаимодействия.

Рисунок 3.10.1 – Схема подключения модуля ЖКИ к микроконтроллеру


Для инициализации индикатора в большинстве случаев достаточно
трех команд: Function Set, Display On и Clear Display (в таблице выделены се-
рым цветом). В дальнейшем необходимы еще две команды для перемещения
курсора (Set DDRAM Address) и вывода символа (Write Data).
Схема адресов символьных позиций показана на рисунке 3.10.2.
Поз. 0 Поз. 15
Строка 1 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F

Строка 2 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F

Рисунок 3.10.2 – Схема адресов символьных позиций ЖКИ


3.10.3 Разработка функции управления ЖКИ с ожиданием готовности
Рекомендуется все функции управления ЖКИ поместить в отдельный
файл с именем LCD.c. Кроме того, в библиотеку войдет функции формиро-
вания временной задержки, рассмотренную в разделе 3.1.5. В дальнейшем
при необходимости файл библиотеки будет подключаться к программам ди-
рективой #include.
Алгоритм функции вывода команды LCDWrite показан на рисунке
3.10.3, а).

191
Функция Функция вывода строки Функция
выполнения команды инициализации ЖКИ
Начало
Начало Начало
1
1 Ввод Sym, Pos 1
Ввод Data, RS Настроить режим и
2 направление
2 k=0
портовых линий
RW=0
3
Перевести курсор в 2
3 Вкл. подсветку
Вывод RS позицию Pos
(Set DDRAM Address) 3
4 Задержка 50 мс
Вывод Data
4
5 Нет 4 Function Set
Формирования Sym[k]>0 (DL=1, N=1, F=0)
импульса 575 нс
Да 5
6 Display On
Задержка 1,71 мс 5 (D=1, C=0, B=0)
Вывод символа Sym[k]
Возврат (Write Data) 6
Clear Display

Возврат
Возврат
а) б) в)
Рисунок 3.10.3 – Схемы алгоритмов функций управления модулем ЖКИ
1. Входные параметры функции: байт Data, выставляемый на шину
данных индикатора; сигнал RS, принимающий два значения 0 и 1. Оба пара-
метра должны иметь тип unsigned char.
2. Установить низкий уровень на линии RW, что соответствует режи-
му отправки данных. Рекомендуется использовать обращение к порту ввода-
вывода в режиме байта (регистр FIO0CLR2). Схема подключения входов ин-
дикатора к портовым линиям микроконтроллера показана на рисунке 3.10.4.
3. Установить на линии RS (регистр FIO1PIN3) логический уровень в
соответствии со значением одноименного параметра функции. Типовая зада-
ча вывода бита в порт рассмотрена в разделе 1.10.1 (пример 3).
4. Вывести байт Data на шину данных (регистр FIO1PIN2).
FIO1PIN3 – третий байт порта 1 FIO1PIN2 – второй байт порта 1
31 28 27 25 24 23 16
sy

E DB7:DB0
S

Bu
R

Строб Шина данных


Данные (1)

FIO0PIN3 – третий байт порта 0 FIO0PIN2 – второй байт порта 0


31 30 29 28 27 24 23 22 21 20 19 16
/W
BL

Подсветка Чтение (1)

Рисунок 3.10.4 – Схема портовых линий МК, используемых для управления ЖКИ

192
5. Сформировать строб на линии E — импульс длительностью не ме-
нее 575 нс. Для этого установить высокий уровень на линии E с помощью ре-
гистра FIO1SET3, вызвать процедуру задержки с параметром , предвари-
тельно рассчитав числовое значение N по формулам 3.1.2, затем установить
низкий уровень сигнала E через регистр FIO1CLR3.
6. Сформировать новую задержку, достаточную для завершения лю-
бой команды (не менее 1,71 мс).
3.10.4 Функция вывода строки символов
Основной функцией в библиотеке является подпрограмма вывода
строки символов. Обозначим функцию PrintSymbol. Ее алгоритм показан на
рисунке 3.10.3, б).
Функции передается два параметра: указатель Sym (строка символов)
и байт Pos (номер позиции индикатора для первого символа). Переменная k
служит счетчиком символов. Первый вызов функции LCDWrite обеспечивает
выполнение команды индикатора Set DDRAM Address, то есть перемещение
курсора в позицию Pos. Далее в цикле повторяется выполнение команды за-
писи кода символа в память модуля индикации. Переменная-счетчик k ис-
пользуется как индекс массива и при каждом обращении инкрементируется
([k++]). Выполнение цикла продолжается до тех пор, пока не встретится
символ конца строки — символ с кодом 0x00, обозначающий конец строки.
void PrintSymbol(char *Sym, char Pos)
{
char k=0;
LCDWrite(0x80 | Pos,0);
while (Sym[k]>0)
LCDWrite(Sym[k++],1);
}
3.10.5 Разработка функции инициализации модуля ЖКИ
Алгоритм функции инициализации показан на рисунке 3.10.3, в).
Объявить функцию пустого типа
void LCDInit()
1. Выбрать высокоскоростной режим обмена с портами ввода-вывода
через регистр SCS (раздел 1.10.2). Настроить на вывод все линии, задейство-
ванные для управления индикатором (по рисункам 3.10.1, 3.10.4). Можно ре-
комендовать использовать регистры FIO0DIRU и FIO1DIRU. Причем лучше
для установки у них единиц использовать не команду присваивания, а логи-
ческое сложение, например
FIO0DIRU|= Код ;
Это сохранит неизменными остальные разряды, что очень важно в дальней-
шем при сопряжении разрабатываемой библиотеки с другими программами.
2. Включить подсветку, установив высокий уровень на линии P0.30.
3. Обеспечить задержку не менее 50 мс, необходимую для начала ра-
боты модуля индикации.
193
5–6. С помощью функции LCDWrite подать на индикатор команды
Function Set, Display On и Clear Display. Значения управляющий битов указа-
ны в блок-схеме алгоритма.
3.10.6 Разработка тестовой программы
Тестовая программа должна содержать директиву подключения биб-
лиотеки функций управления ЖКИ
#include "LCD.C"
Блок-схема тестовой программы показана на рисунке 3.10.5, а).
1. Вызвать функцию инициализации ЖКИ
LCDInit();
2. Выполнить вывод одной или нескольких произвольных строк сим-
волов, вызывая функцию из библиотеки, например:
PrintSymbol("Preved, Medved!", Номер позиции );
Напомним, что позиции верхней строка индикатора нумеруются 0–15
(шестнадцатеричные значения 0x00–0x0F), а нижней — 64–79 (0x40–0x4F).
3.10.7 Управление ЖКИ с опросом флага готовности
Предлагается разработать полный аналог функции LCDWrite, рас-
смотренной в разделе 3.10.4, но вместо «слепого» ожидания готовности вос-
пользуемся опросом флага. Алгоритм функции показан на рисунке 3.10.5, б).
Блоки 1–4 полностью идентичны 3.10.3, а).
5. Здесь рекомендуется длительность строба 1,5 мкс. Это гарантирует,
что период следования импульсов будет не меньше допустимых 1,2 мкс.
6–7. После формирования строба необходимо подготовиться к цикли-
ческому опросу флага готовности: для этого настроить портовую линию, от-
вечающую за сигнал DB7 на ввод (регистр FIO0DIR2), и установить сигналы
, .
8–9. Реализовать повтор в цикле while (...) ... ; строба пока на
линии DB7 фиксируется низкий логический уровень. Строб формировать с
той же временной задержкой 1,5 мкс.
10. Восстановить режим вывода для линии DB7.
3.10.8 Программирование произвольных символов
Память знакосинтезатора имеет восемь свободных позиций символы с
кодами 0–7. Графическое изображение этих символов может быть запро-
граммировано произвольным образом. Для этого необходимо дать команду
Set CGRAM Address, после чего подать байт, задающий графическое изобра-
жение одного столбца таблицы знакогенератора. Каждый байт определяет
строку символа, причем старшие три бита не задействованы, поскольку сим-
вол состоит только из пяти столбцов. Полное изображение символа форми-
рую 8 байт. Таким образом, адреса памяти знакогенератора с 0x00–0x07 со-
ответствуют изображению символа с кодом 0x00, адреса с 0x08–0x0F —
символа с кодом 0x01 и т. д.

194
Функция программирования символов незначительно отличается от
функции вывода символов PrintSymbol. Предложим ее исходный текст.
void ProgSymbol(char *Mask, char Pos)
{
char k;
LCDWrite(0x40 | Pos,0);
for (k=0; k<8; k++) LCDWrite(Mask[k],1);
}
Функция выполнения команды

Начало 6
Настроить
1 линию DB7 на ввод
Основная программа Ввод Data, RS
7
Начало 2 RS=0, RW=1
RW=0
1
Инициализация 3
8
ЖКИ Вывод RS
Формирования
4 импульса 1,5 мкс
2
Вывод строки Вывод Data

5
9 Да
Формирования DB7=0
3
Пустая команда импульса 1,5 мкс
Нет
10
Восстановить режим
вывода для линии DB7

Возврат
а) б)
Рисунок 3.10.5 –Алгоритмы основной программы взаимодействия с модулем ЖКИ
(а) и функции выполнения команды с ожиданием флага готовности (б)
Адрес 0x00-0x07 0x08-0x0F 0x10-0x17 0x18-0x1F 0x20-0x27 0x28-0x2F 0x30-0x37 0x38-0x3F

Код 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07

Код символа - 0x00 Код символа – 0x01

0x00 0x08 0 0 0 0 0 = 0x00


Адреса памяти знакогенератора

Адреса памяти знакогенератора

0x01 0x09 0 1 0 1 0 = 0x0A


0x02 0x0A 1 1 1 1 1 = 0x1F
0x03 0x0B 1 1 1 1 1 = 0x1F
0x04 0x0C 0 1 1 1 0 = 0x0E
0x05 0x0D 0 0 1 0 0 = 0x04
0x06 0x0E 0 0 0 0 0 = 0x00
0x07 0x0F 0 0 0 0 0 = 0x00

Рисунок 3.10.6 – Схема адресов памяти знакогенератора (CGRAM)


195
Приведем также пример использования функции для программирова-
ния изображения символа с кодом 0x01 в соответствии с рисунком 3.10.6:
char NewSymbol[]=
{0x00,0x0A,0x1F,0x1F,0x0E,0x04,0x00,0x00};
...
ProgSymbol(NewSymbol,0x8);
Пример включения запрограммированного символа в выводимую на
индикатор строку
PrintSymbol("I \x01 ARM7",0x04);

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


3.11.1 Задание
Разработать программу, формирующую изображение произвольного
символа с помощью светодиодной матрицы 8x8 точек, управляемой динами-
чески через сдвиговые регистры по интерфейсу SPI.
3.11.2 Основные рекомендации
На учебной плате установлена светодиодная матрица 8×8 точек
LMD08088AG-15 производства фирмы Wenrun Optoelectronic. Матрица
предназначена для динамической индикации. Это значит, что одновременно
могут гореть несколько светодиодов только одного столбца. Светодиоды
подключены по схеме «общий катод» (рисунок 3.11.1). Подключая питание к
каждому из столбцов по очереди с высокой частой, создается зрительное
впечатление изображения. Полный цикл рекомендуется повторять не менее
100 раз в секунду.

Рисунок 3.11.1 – Схема управления светодиодной матрицей

196
Управление светодиодами осуществляется с помощью сдвиговых ре-
гистров типа 74HC595 производства фирмы NXP. Выходы регистра управле-
ния столбцами усилены p-n-p транзисторами, так как суммарный ток свето-
диодов превышает предельно допустимый ток выходов регистра и составляет
примерно 48 мА. Через каждую линию строк протекает ток только одного
светодиода (около 6 мА), поэтому строки (катоды светодиодов) подключены
к регистрам непосредственно.
Как видно из схемы, для управления как строками, так и столбцами
матрицы активным уровнем является логический ноль.
Для формирования символов предлагается использовать файл
Font_6x8.h, содержащий объявление массива — таблицы знакогенератора.
Файл имеет следующую структуру:
const char Font_6x8_Data[]=
{
...
0x00, 0x7f, 0x0