Название книги в оригинале: Барретт Стивен. Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С

A- A A+ White background Book background Black background

На главную » Барретт Стивен » Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С.





Читать онлайн Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С. Барретт Стивен Ф..

ВСТРАИВАЕМЫЕ СИСТЕМЫ

Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С

С. Ф. Баррет

University of Wyoming 

Д. Дж. Пак

United States Air Force Academy  

 Сделать закладку на этом месте книги

ПРЕДИСЛОВИЕ

 Сделать закладку на этом месте книги

В начале 2002 года наша первая книга «Микроконтроллеры семейства 68НС12: Теория и применение» была издано издательством Prentice Hall. Нашими целями были: представить основы программирования на ассемблере; проиллюстрировать работу отдельных блоков в составе микроконтроллера и представить методы сопряжения различных внешних устройств с микроконтроллерами. В качестве примера мы использовали автономный мобильный робот для иллюстрации совместной работы микроконтроллера во встраиваемой системе.

Наша вторая книга, посвященная встраиваемым микропроцессорным системам «Разработка и применение встраиваемых систем на основе микроконтроллеров семейства 68HC12 и HCS12», охватывает проблемы не раскрытые в первой книге. Нашей целью в ней было разработать учебное пособие по проектированию встраиваемых систем. Мы постарались провести читателя от основ системного программирования через применения операционных систем реального времени к решению задач распределенного управления. Вместо того, чтобы «нырнуть на глубину в бассейн» мы начали с обучения концепциям системного проектирования и программирования на языке С. Затем мы двинулись к обсуждению специфического аппаратного обеспечения, реализованного на кристаллах микроконтроллеров семейств 68HC12/HCS12. В начале этих глав мы придерживались идеологии «ходьбы перед бегом». Мы предполагали, что читатель имеет фундаментальные, но базовые знания по организации программно–аппаратного обеспечения микроконтроллеров. Мы считаем это правильным подходом, поскольку целевой аудиторией для книги являются студенты учебных заведений вовлеченные во второй цикл обучения разработки встраиваемых систем. Темы обучения в начальных главах книги могут быть пропущены инженерами с опытом. Однако мы получили много пожеланий от таких инженеров на включении этого материала в книгу.

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

Мы имели несколько целей при написании этой книги.

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

2. Изложить методические аспекты проектирования встраиваемых систем;

3. Представить функциональное аппаратное обеспечение микроконтроллеров;

4. Раскрыть методы сопряжения с микроконтроллерами различных периферийных устройств при создании встраиваемых систем;

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

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

Мы предприняли попытку практической ориентации книги с сильным упором на обучение и многочисленными практическими примерами. Основанные на реальных применениях, эти примеры сфокусированы на приобретение навыков по разработке встраиваемых систем, методов синхронизации и подавлению шумов, а также способов отыскания неисправностей. Книга представляет обзор языка программирования Си, методов структурного программирования, микроконтроллеров семейств 68HC12/HCS12, детальное обсуждение проблем RTOS, многопроцессорных систем и иллюстрацию концепций разработки встраиваемых систем.

Вначале книги мы представляем читателю концепции структурной разработки систем. Используя подход функционального разбиения системы сверху вниз, студенты будут в состоянии понять любые проблемы связанные со сложностью структуры встраиваемых систем. Мы коснулись некоторых принципов системного подхода к разработке, описанного Meilir Page–Jones в его классической книге «Practical Guide to Structured Systems Design». Эти методы работают в равной степени хорошо при разработке программного, аппаратного и программно–аппаратного обеспечения встраиваемых систем. Однажды их представив, мы их активно используем в дальнейшем во всей книге.

Структура книги

 Сделать закладку на этом месте книги

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

В первой главе мы представили понятие встраиваемых систем и специфические проблемы связанные с их разработкой и применением. Глава 2 описывает преимущества программирования на языках высокого уровня — High Level Language (HLL). Мы сбалансировали обсуждение методов программирования на языке ассемблер и HLL и показали, что программы для встраиваемых систем могут содержать оба подхода. Мы обсудили ключевые концепции структурного программирования, позволяющие разбить большие проекты на более понятные и легко реализуемые части. Затем мы применили эти понятия на этапах разработки, реализации и тестирования систем. Мы дали почувствовать читателю некую комфортность использования такого подхода на примерах простых систем прежде чем переходить к более сложным случаям.

В главе 3 мы рассматриваем процесс программной/компиляции/ассемблирования анализируя принципы программирования на языке С. В завершении главы рассматриваются методы и средства программирования и отладки программ. При рассмотрении проблем программирования мы намерено ушли от любых специфических особенностей компиляторов. На сегодняшний день существуют очень много доступных компиляторов для семейств 68НС12/HSC12. В четвертой главе мы описываем структуру семейств 68НС12/HSC12 и их отдельных представителей. В дальнейшем мы иллюстрируем их применение в реальных системах управления.

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

В главе 7 мы помещаем микроконтроллеры 68НС12/HSC12 в реальные системы. В каждом примере мы обеспечиваем сквозное описание проекта, алгоритм работы и код, необходимый для реализации системы. Мы скрупулезно подошли к подбору примеров так, чтобы все они были реализуемы на микроконтроллерах семейства 68НС12/HSC12. В восьмой главе мы рассмотрели проблемы применения операционных систем реального времени. Мы начали с определений RTOS, а затем перешли к обсуждению возможностей их реализации. В дальнейшем мы рассмотрели проблемы, связанные с реализацией RTOS. Мы предполагали, что читатель не имеет практического опыта работы с системами подобной сложности.

Глава 9 рассматривает распределенные системы. Такие системы содержат более одного микропроцессора в своей структуре. Мы представили методы и подходы, позволяющие сопрягать их в систему, используя встроенный CAN контроллер в семейства 68НС12/HSC12.

В дополнение к содержанию книги мы подготовили и поддерживаем справочный веб-сайт www.prenhall.com/pack. Он содержит справочную информацию по семействам 68НС12/HSC12, файлы программ на С, и программно–аппаратные средства поддержки микроконтроллеров семейства 68НС12/HSC12. Для преподавателей этот веб-сайт также содержит дополнительный материал включая лекционные слайды в Power Point и рекомендации как заказать информацию по всем решениям задач, представленных во всех домашних заданиях в каждой главе.

Учебные системы

 Сделать закладку на этом месте книги

Для иллюстрации системных принципов в главах с 1 по 9 мы рассматривали многочисленные примеры. Примеры были разработаны для двух учебных систем: отладочной платы M68HС912B32EVB (B32EVB) и для MC9S12DP256 или DP256. Мы выбрали отладочную плату В32EVB ввиду ее широкого распространения, разумной цены и что наиболее важно ее многими полезными функциями. EVB имеет интерфейс RS–232, работает от одного источника питания, имеет легкий доступ к основным контрольным точкам через четыре группы разъемов и монтажное поле для размещения дополнительной схемотехники при анализе систем. EVB также имеет хороший набор функций памяти, включающий в себя 32Кбайт электрически перепрограммируемой флэш памяти программ (EPROM), 1Кбайт ОЗУ и 768 байт побайтно стираемой EEPROM для записи данных. Во флэш памяти расположен резидентный монитор/отладчик программ D–Bug12. Мы опишем в деталях все отмеченные свойства в гл. 4. В32 является отличным учебным средством, но оно может быть также успешно использована для реализации прототипов отлаживаемых систем.

Читатели, которые не намерены использовать B32 EVВ, могут быть уверены, что большинство из рассмотренных в книге примеров могут быть реализованы на других вариантах отладочных средств семейств 68НС12/HSC12.

Поскольку базисные концепции и функциональные блоки различных микроконтроллеров практически идентичны друг другу, то полученные знания семейств 68НС12/HSC12 могут быть естественным образом применены и для других микроконтроллеров. В гл.7 и 9 мы используем микроконтроллер MC9S12DP256. HCS12 микроконтроллер имеет 256 К байт флэш память, несколько каналов msCAN интерфейсов с соответствующими контроллерами. Он также имеет большой объем ОЗУ. В распоряжении разработчиков имеются различные типы отладочных плат.

Целевая аудитория

 Сделать закладку на этом месте книги

Основной аудиторией для книги являются студенты университетов, изучающих курс вычислительные микропроцессорные системы. Поскольку все ABET (Acredittion Board for Engineering and Technology, Inc) требуют наличия такого курса в своих программах, мы надеемся, что преподаватели этих дисциплин будут активно использовать данную книгу в своей практике. Мы ожидаем также, что студенты первого года обучения языков программирования найдут эту книгу для себя также полезной. Владение темой языков программирование позволит студентам легко разобраться с приведенными в книге примерами. В идеале студенты будут имеет полный курс введения в микроконтроллеры. Однако ввиду экспериментальной направленности книги студенты должны будут самостоятельно заполнить пробелы в знаниях там где это будет необходимо.

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

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

Благодарности

 Сделать закладку на этом месте книги

Эта книга является совокупным трудом многих специалистов. Конечно же ни одна хорошая книга не может появится без выдающегося издателя и его команды. Мы благодарны Tom Robbins и Alice Dworkin из Prentice Hall за их веру в проект. Было большим удовольствием работать с Kevin Bradley и его сотрудниками из Sunflower Publishing Services. Мы благодарны им за их отличную редакторскую работу. Мы высоко оцениваем отзыв и обратную связь от Barry Mullins из Air Force Institute of Technology. В результате всех этих усилий содержание книги значительно улучшилось. Мы также высоко ценим дельные замечания и обратную связь, полученную по окончательной версии книги от Jerry Hamman из University of Wyoming; John Reece из Mercer College из Macom, Georgia и William Stapleton из University of Alabama. Мы также очень благодарны Karen Bosco из Motorola за ее помощь в получении разрешении от Motorola использовать рисунки в книге.

Мы признательны руководству нашего факультета за их поддержку. Colonel Alan Klayton (USAF Academy) постоянно поддерживал нашу работу и и осуществлял многостороннюю помощь. John Steadman (ранее работавший в University of Wyoming, а в настоящее время декан электротехнического факультета в University of South Alabama), активно воодушевлял нас на написание этой книги. Мы благодарны большому количеству студентов вовлеченных в учебный процесс по курсам микропроцессорной технике в отмеченных выше университетах. Их обратная связь оказала нам большую помощь в изложении материала книги. Abbie Wells, Scott Lewis, Joel Perlin, Carrie Hernanddez, Ted Dibble, Tom Schei, Charles Straley, Pamela Beavis и Austin Griffith из университета Wyoming написали ряд программ в примерах и оказали значительную помощь в переходе от семейства от семейства 68НС11 к семейству НС12. В дополнении к этому мы хотели бы поблагодарить многих наших коллег из Air Force Academy и University of Wyoming.

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

Я хотел бы еще отметить Glarence Zarn, очень дорогого друга семьи, из–за влияния которого я стал инженером. Когда я был еще ребенком, моя семья проводила много отпусков с семьей Zarns. Меня брали в офис Clarence, полный книг, справочников, схем и плакатов, иллюстрирующих многообразный мир техники. В то время Clarence работал инженером и был вице-президентом компании Pentzien Corporation of Omaha, Nebraska в течение долгого времени. Недавно он подарил мне свою логарифмическую линейку (1940), которой он пользовался долгие годы. Я буду хранить ее всегда. Он повторял, что инженерная работа была и всегда останется востребованной. Большое спасибо моим родителям. Спасибо моим бабушкам Eleonore и Jackie, а также дедушке Frank за постоянную веру в меня. Спасибо Young Shin и Rana и Sung Bock и Chong Kon за мотивацию и постоянную поддержку. Особая благодарность моему отцу за воодушевления меня на этот труд, в то время когда он сам боролся с раком. В заключении хочется отметить, что эта работа не могла бы осуществиться без поддержки членов нашей семьи: Cindy, Heidi, Hearther, Jon R., Christine, Jon B., Andrew и Graham. Примите нашу благодарность. 

Steven F. Barrett Daniel J. Pack

Глава 1

ПЕРВОЕ ЗНАКОМСТВО СО ВСТРАИВАЕМЫМИ СИСТЕМАМИ

 Сделать закладку на этом месте книги

ПОСЛЕ ИЗУЧЕНИЯ ГЛАВЫ ВЫ СМОЖЕТЕ:

• Дать определение термину «вычислитель»;

• Перечислить основные блоки вычислителя. Описать функции этих блоков;

• Объяснить значение терминов: встраиваемая система, микроконтроллер, компьютер общего применения;

• Привести примеры встраиваемых микропроцессорных систем управления;

• Перечислить основные проблемы, которые возникают в процессе разработки встраиваемых систем;

• Пояснить термин «работа в реальном времени» в контексте обсуждения встраиваемых систем;

• Описать основные функциональные блоки микроконтроллеров семейства 68HC12 и семейства HCS12.

• Перечислить основные различия между микроконтроллерами семейства 68НС12 и семейства НСS12.

В этой главе мы познакомим Вас с теми проблемами, которые возникают при проектировании, реализации и тестировании встраиваемых микропроцессорных систем. Мы начнем наше рассмотрение с достаточно общих понятий, однако в разделе 1.3 произойдет Ваше первое знакомство с системами на микроконтроллерах семейств 68HC12 и HCS12.

1.1. Что такое встраиваемая система?

 Сделать закладку на этом месте книги

Любая механическая или электрическая система, которая имеет в своем составе устройство управления, выполненное на основе вычислителя, называется встраиваемой системой (Embedded System). Перед тем, как мы продолжим, следует дать определение термину «вычислитель». Все вычислители обязательно состоят из следующих функциональных блоков: центрального процессора (ЦП), запоминающего устройства (ЗУ) устройств ввода/вывода (УВВ) и межмодульных магистралей. Центральный процессор содержит в себе арифметико–логическое устройство (АЛУ), устройство управления и некоторое количество регистров. АЛУ выполняет операции над данными, которые представлены в цифровом коде. Типовыми для АЛУ являются следующие арифметические и логические операции: сложение, вычитание, умножение, деление, логические операции И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ, НЕ (инверсия).

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

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

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

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

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

В настоящее время многие производители полупроводниковых компонентов, такие как Intel, Microchip, Hitachi, NEC, Atmel, Texas Instruments и др., выпускают микроконтроллеры различной сложности. Относительно простые МК находят применение в бытовой технике и игрушках. Наиболее сложные высокопроизводительные МК используются в коммуникационном оборудовании, для управления самолетами и военной техникой. В этой книге мы предлагаем Вам изучить два типа МК: семейства 68HC12 и HCS12 компании Motorola.

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

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

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



Рис. 1.1. Области применения встраиваемых систем

1.2. Особенности встраиваемых систем

 Сделать закладку на этом месте книги

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

1.2.1. Работа в реальном времени

 Сделать закладку на этом месте книги

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

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


убрать рекламу






возможно сокращенном виде.

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

1.2.2. Миниатюризация размеров и процесс тестирования

 Сделать закладку на этом месте книги

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

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

1.2.3. Минимизация энергии потребления

 Сделать закладку на этом месте книги

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

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

1.2.4. Интерфейс пользователя и интерфейс сопряжения с объектом

 Сделать закладку на этом месте книги

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



Рис. 1.2. Робот, способный двигаться сквозь лабиринт

1.2.5. Многозадачность

 Сделать закладку на этом месте книги

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

1.2.6. Минимизация стоимости

 Сделать закладку на этом месте книги

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

1.2.7. Ограничение объема памяти

 Сделать закладку на этом месте книги

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

1.2.8. Программно–аппаратный дуализм

 Сделать закладку на этом месте книги

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

1.3. Введение в микроконтроллеры семейства 68HC12 и HCS12

 Сделать закладку на этом месте книги

В предыдущем параграфе мы обсудили общие проблемы, связанные с разработкой и эксплуатацией встраиваемых микропроцессорных систем. В своем рассмотрении мы пока не касались той элементной базы, на основе которой выполняются встраиваемые системы, т.е. микроконтроллеров. Поскольку наша книга посвящена встраиваемым системам на микроконтроллерах семейства 68HC12/HCS12 компании Motorola/Freescale Semiconductor, то перейдем к знакомству с этой элементной базой.

Семейство микроконтроллеров 68HC12/HCS12 относится к группе 16–разрядных МК. Процессорное ядро 68HC12 унаследовало свою программно–логическую модель и систему команд от широко известного 8–разрядного процессорного ядра HC11. Начало семейству 68HC12 было положено в 1996 году выпуском двух базовых моделей: MC68HC12A4 и MC68HC912B32. Микроконтроллер MC68HC12A4 был предназначен для работы в расширенном режиме, т.е. с внешней памятью программ. Микроконтроллер MC68HC912B32 уже имел на кристалле многократно программируемое пользователем энергонезависимое запоминающее устройство, выполненное по технологии Flash. В 2002 году компанией Motorola/Freescale Semiconductor было предложено новое семейство HCS12, которое предназначалось для замены МК семейства 68HC12 на более высокопроизводительные, но полностью программно совместимые модели. На протяжении этой книги мы будем использовать в качестве базового микроконтроллер MC68HC912B32. Это простой МК низкой стоимости, доступный как для обучения, так и для относительно несложных разработок. Однако большая часть сведений, которые Вы почерпнете из данной книги, может быть легко распространена и на МК HCS12.

На основе базового МК MC68HC912B32 производителем был создан целый ряд моделей: MC68HC12BE32, MC68HC912BC32 и MC68HC12BC32. Основное отличие этих моделей друг от друга состоит в объеме размещенной на кристалле памяти программ и в наличии или отсутствии контроллера CAN сети.

На рис. 1.3 представлена структурная схема сразу двух МК: MC68HC912B32 и MC68HC12BE32. На рис. 1.4 дана цоколевка корпуса для этих микроконтроллеров. Далее на рис. 1.5 показана структура микроконтроллера MC68HC912BC32, на рис. 1.6 — цоколевка корпуса для него. В таблице рис. 1.7 перечислены основные функциональные блоки каждой из перечисленных моделей МК. Эта же таблица позволяет легко определить функциональные различия между рассматриваемыми МК.



Рис. 1.3. Структура микроконтроллеров MC68HC912B32 и MC68HC12BE32




Рис. 1.4. Цоколевка корпуса микроконтроллеров MC68HC912B32 и MC68HC12BE32


Микроконтроллеры семейства 68HC12 — это 16–разрядные МК, что означает, что центральный процессор может выполнять операции над 16–разрядными данными, а также то, что данные передаются внутри МК по 16–разрядной магистрали данных. МК 68HC12 имеют также 16–разрядную магистраль адреса, что позволяет им адресовать 65 536 ячеек памяти. Максимальная частота системной шины МК семейства 68HС12 равна 8 МГц, что обеспечивать значительное возрастание вычислительной производительности по отношению к предшественнику — МК HC11.

Система команд 68HC12 основана на системе команд HC11, однако число способов адресации и число выполняемых действий значительно расширены. Система команд 68HC12 включает 208 инструкций, в том числе пять команд деления с разрядностью данных 16/16 и 32/16 в целочисленном и дробном форматах, команды выбора максимального и минимального числа, команды нечеткой логики. Операции сложения или вычитания двухбайтовых чисел выполняются за 2 или 3 такта системной шины МК. Центральный процессор 68HC12 поддерживает 16 способов адресации, при этом исполнение каждой команды из группы арифметических или логических команд возможно с использованием по крайней мере 12 способов адресации. Центральный процессор 68HC12 имеет двухадресные команды, позволяющие выполнять пересылки 8–и 16–разрядных данных между двумя ячейками памяти или регистрами специальных функций минуя регистры центрального процессора. Четыре команды предназначены для реализации алгоритмов нечеткой логики (fuzzy logic): команда фаззификации MEM, команда обработки нечетких переменных REV, команда обработки нечетких переменных REVW и команда дефаззификации WAW.

Микроконтроллеры семейства 68HC12 обладают резидентной Flash-памятью программ, объемом до 32 Кб, оперативной памятью данных до 1 Кб, энергонезависимой памятью данных типа EEPROM объемом до 768 байт. Они имеют встроенный модуль отладки, который позволяет отлаживать программы, а также выполнять операции стирания/программирования Flash и EEPROM, взаимодействуя с персональным компьютером по однопроводному последовательному интерфейсу.



Рис. 1.5. Структура микроконтроллера MC68HC912BС32




Рис. 1.6. Цоколевка корпуса микроконтроллера MC68HC912BС32


Микроконтроллеры семейства 68HC12 имеют до семи многофункциональных двунаправленных портов ввода/вывода, модуль аналого цифрового преобразователя, модуль таймера с функциями входного захвата и выходного сравнения, 16–разрядный счетчик внешних событий, модуль широтно–импульсного модулятора и несколько контроллеров последовательных интерфейсов. Полный перечень возможных для МК семейства 68HC12 периферийных модулей приведен в таблице рис. 1.7.

Функциональные модули в составе МК MC68HC912B32 MC68HC12BE32 MC68HC912BC32 MC68HC12BC32
Центральный процессор CPU12 + + + +
Системная магистраль + + + +
Память программ Flash 32Кб +   +  
Память программ однократно программируемая 32Кб   +   +
EEPROM 768 байт + + + +
ОЗУ 1 Кб + + + +
Модуль таймера TIM + + + +
Модуль аналого–цифрового преобразования ATD + + + +
Усовершенствованный модуль таймера ECT + + + +
Модуль широтно–импульсного модулятора PWM + + + +
Модуль контроллера асинхронного последовательного обмена SCI + + + +
Модуль контроллера синхронного последовательного обмена SPI + + + +
Модуль контроллера последовательного обмена CAN     + +
Модуль контроллера последовательного обмена BDLC + + + +
Сторожевой таймер COP + + + +
Модуль отладки BDM + + + +
Модуль делителя для низкочастотной синхронизации + + + +

Рис. 1.7. Сравнительные характеристики микроконтроллеров семейства 68HC12B

1.4 Микроконтроллеры HCS12

 Сделать закладку на этом месте книги

Подобно семейству 68HC12, семейство HCS12 объединяет ряд микроконтроллеров с одинаковым процессорным ядром CPU HCS12, различающихся объемом резидентной памяти и набором периферийных модулей, интегрированных на кристалл МК. Различные модели МК в составе семейства имеют Flash память программ объемом до 512 Кб, оперативную память объемом до 12 Кб. Напряжение питания большинства моделей семейства — 5,0 В, что позволяет обеспечить электромагнитную совместимость в автомобильных применениях. Частота внутренней системной шины МК семейства HCS12 равна 25 МГц, что существенно увеличивает их производительность по сравнению с МК семейства 68HC12.

Все модели МК семейства HCS12 имеют в своем составе следующие функциональные блоки:

• Оперативное запоминающее устройство и постоянное запоминающее устройство трех типов: Flash, EEPROM, масочного типа;

• Порты с двунаправленными линиями ввода/вывода;

• Модуль таймера с 16–разрядным счетчиком временной базы и 8 каналами захвата/сравнения;

• Подсистему последовательного обмена с несколькими контроллерами ввода/вывода различных стандартов (SCI, SPI, CAN и др.);

• Модуль АЦП с 8–и или 10–разрядным представлением результата;

• Модуль ШИМ с разрешением 8 или 16 разрядов.

Структура МК MC9S12DP256B представлена на рис. 1.8. Обратите внимание, что большая часть периферийных модулей этого МК аналогична модулям микроконтроллеров семейства 68HC12. От ранее рассмотренного МК MC68HC912B32 микроконтроллер DP 256 отличает увеличенный до 256 кб объем Flash памяти программ, наличие в его составе модуля усовершенствованного таймера ECT, двух 8–канальных модулей аналого–цифрового преобразования ATD, пяти контроллеров интерфейса информационной сети в стандарте CAN.



Рис. 1.8. Структура микроконтроллера MC9S12DP256B

1.4.1. Семейство HCS12

 Сделать закладку на этом месте книги

Семейство HCS12 объединяет более 30 моделей МК. Однако мы не хотим концентрировать внимание читателя на изучении модельного ряда HCS12, поскольку детальное знание различных представителей семейства необходимо при профессиональной деятельности. А в процессе обучения мы наоборот, хотим использовать общность структуры и режимов работы функциональных модулей МК 68HC12 и HCS12. Поэтому в рамках этого первого знакомства с семейством HCS12 ограничимся рассмотрением системы условных обозначений МК и кратким обзором структуры некоторых МК семейства.

1.4.2. Обозначения МК

 Сделать закладку на этом месте книги

Каждая модель МК в составе семейства 68HC12/HCS12 имеет собственное сокращенное обозначение. Это обозначение используется для маркировки корпуса МК и при заказе ИС МК у производителя. Система сокращенных обозначений для МК семейства 68HC12 и HCS12 представлена на рис. 1.9. Обратите внимание, что каждое поле в сокращенной записи отражает определенную техническую характеристику изделия. В перечень технических характеристик входят не только структура МК и частота тактирования (функциональные характеристики), но и тип корпуса, диапазон рабочих температур, т.е. характеристики, связанные с конструктивным исполнением и условиями эксплуатации конечного изделия.



Рис. 1.9. Система обозначений МК семейства 68HC12/HCS12

1.4.3. Модельный ряд HCS12

 Сделать закладку на этом месте книги

В настоящее время компания Motorola/Freescale Semiconductor выпускает около 40 МК с процессорным ядром HCS12 (рис. 1.10[1]). Традиционно для Motorola/Freescale Semiconductor все МК одного семейства группируются в серии по схожести периферийных устройств. Внутри серии МК различаются объемом резидентной памяти и числом линий портов ввода/вывода. Все МК семейства HCS12 внутри одной серии совместимы по выводам корпусов, благодаря чему на печатную плату можно установить МК с большей памятью без изменения платы.

Тип МК ПЗУ FLASH, байты ОЗУ, байты EEPROM, байты Число линий ввода/вывода Контроллеры последовательных интерфейсов Таймер Число каналов/разрядность АЦП Число каналов/разрядность Модуль ШИМ Число каналов/разрядность Специальные модули *) Частота шины CPU, МГц Напряжение питания, В
Серия А
MC9S12A32 32000 4096 1024 91 IIC 2 SCI SPI 8/16 8/10 4/16  8/8    25 5
MC9S12A64 65536 4096 1024 59 91 IIC 2 SCI SPI 8/16 8/10 4/16 7/8 8/8   25 5
MC9S12A128 MC9S12A128B 131072 8192 2048 59 91 IIC 2 SCI SPI 8/16 8/10 4/16 8/8 EBUS 25 5
MC9S12A256B 26144 12288 4096 59 91 IIC 2 SCI SPI 8/16 2/10 3/10 8/10 4/16 8/8 EBUS 25 5
MC9S12A512 512000 4096 1024 59 IIC 2 SCI SPI 8/16 16/10 7/8   25 5
Серия С
MC9S12C32 32000 2000 нет 60 CAN SCI SPI 8/16 8/10 6/8 LVI 16 25 3,3 5,0
MC9S12C64 64000 4000 нет 60 CAN SCI SPI 8/16 8 6/8 LVI 25 3,3 5,0
MC9S12C96 96000 4000 нет 60 CAN SCI SPI 8/16 8 6/8 LVI 25 3,3 5,0
MC9S12C128 128000 4000 нет 60 CAN SCI SPI 8/16 8 6/8 LVI 25 3,3 5,0
Серия D
MC9S12D32 32000 4096




eft" valign="top">1024
91 CAN IIC 2 SCI SPI 8/16 8/10 4/16 8/8   25 5,0
MC9S12D64 65536 4096 1024 59 91 CAN IIC 2 SCI SPI 8/16 8/10 4/16 7/8 8/8   25 5,0
MC9S12DJ64 65536 4096 1024 59 91 CAN IIC J1850 2 SCI SPI 8/16 8/10 4/16 7/8 8/8   25 5,0
MC9S12DB128 131072 8192 2048 91 BYTE-FLIGHT 2 CAN 2 SCI 2 SPI 8/16 16/10 8/8 EBUS 25 5,0
MC9S12DB128B 131072 8192 2048 91 BYTE-FLIGHT CAN 2 SCI 2 SPI 8/16 16/10 8/8 EBUS 25 5,0
MC9S12DG128 MC9S12DG128B 131072 8192 2048 59 91 2 CAN IIC 2 SCI SCP 2 SPI 7/16 8/16 16/10 8/8 EBUS 25 5,0
MC9S12DG256B 26144 12288 4096 91 2 CAN IIC 2 SCI 2 SPI 8/16 16/10 4/16 8/8 EBUS LVI 25 5,0
MC9S12DJ128 MC9S12DJ128B 131072 8192 2048 59 91 2 CAN IIC J1850 2 SCI 2 SPI 7/16 8/16 8/10 4/16 8/8 EBUS 25 5,0
MC9S12DJ256B 262144 12288 4096 59 91 2 CAN IIC J1850 2 SCI 3 SPI 7/16 8/16 8/10 4/16 8/8 EBUS 25 5,0
MC9S12DP256B 262144 12288 4096 91 5 CAN IIC J1850 2 SCI 3 SPI 8/16 16/10 8/8 EBUS 25 5,0
MC9S12DP512 512000 12288 4096 91 5 CAN IIC J1850 2 SCI 3 SPI 8/16 16/10 8/8 EBUS 25 5,0
MC9S12DT128 MC9S12DT128B 131072 8192 2048 91 3 CAN IIC 2 SCI 2 SPI 8/16 8/10 4/16 8/8 EBUS 25 5,0
MC9S12DT256B 262144 12288 4096 91 3 CAN IIC 2 SCI 2 SPI 8/16 8/10 4/16 8/8 EBUS LVI 25 5,0
Серия E
MC9S12E64 65536 4096 8192  нет 59 91 IIC 3 SCI SPI 4/16 16/10 6/8 PWMF 2 DAC 25 5,0
Серия G
MC9S12GC16 16000 2000 нет 60 SCI SPI 8/16 8/10 6/8 LVI 16 25 3,3 5,0
MC9S12GC32 32000 2000 нет 60 SCI SPI 8/16 8/10 6/8 LVI 16 25 3,3 5,0
MC9S12GC64 64000 4000 нет 60 SCI SPI 8/16 8/10 6/8 LVI 25 3,3 5,0
MC9S12GC96 96000 4000 нет 60 SCI SPI 8/16 8/10 6/8 LVI 25 3,3 5,0
MC9S12GC128 128000 4000 нет 60 SCI SPI 8/16 8/10 6/8 LVI 25 3,3 5,0
Серия H
MC9S12H128 131072 6000 4096 99 2 CAN IIC 2 SCI SPI 8/16 16/10 4/16 8/8 EBUS LVI LCD 32×4 MC 24 16 5,0
MC9S12H256 262144 12288 4096 99 2 CAN IIC 2 SCI SPI 8/16 16/10 4/16 8/8 EBUS LVI 16 5,0
Разные МК
MC9S12NE64 64000 8000 нет 48 80 Ethernet IIC 2 SCI SPI 4/16 8/10 нет RTI 25 3,3 5,0
MC9S12T64 65536 2048 2048   SCI SPI 8/16 8/10 4/16 8/8     5,0
MC9S12UF32 32768 3584 нет 75 SCI USB 2.0 8/16       30 5,0

Рис. 1.10. Технические характеристики МК семейства HCS12

Примечание:

EBUS — модуль интерфейса внешней магистрали;

LVI — модуль контроля за пониженным напряжением питания;

RTI — модуль меток реального времени;

PWMF — модуль специализированного генератора для управления силовыми коммутаторами в электроприводе;

DAC — модуль одноканального ЦАП;

LCD 32×4 — контроллер управления ЖКИ-дисплеем (4 группы по 32 сегмента);

MC 24 — 24 выхода с повышенной токовой нагрузкой для управления маломощными шаговыми электродвигателями.


Сегодня в состав семейства HCS12 входят 6 серий. Серия А — МК общего применения с тремя типами относительно простых контроллеров последовательных интерфейсов. Серии С и CG — недорогие модели без EEPROM, способные работать при пониженном напряжении питания. Серия D, объединяющая наибольшее число МК, ориентирована на использование в CAN–приложениях. Отдельные модели содержат до 5 CAN–контроллеров на кристалле! Серия E — МК с встроенным ШИМ–генератором для управления электроприводом. Серия H — специализированные МК для управления приборными панелями автомобилей, содержат драйверы шаговых двигателей стрелочных индикаторов и контроллер управления ЖК–индикатором. Указанная производителем специализация не препятствует использованию этих МК в устройствах другого типа с многофункциональными приборными панелями. Три последних МК в таблице рис. 1.10 — родоначальники новых серий. Среди них особенно интересен МК HC9S12NE64 c контроллером 10/100 Ethernet на кристалле.

1.5. Заключение по главе 1

 Сделать закладку на этом месте книги

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

1.6. Вопросы и задания

 Сделать закладку на этом месте книги

Основные

1. Перечислите основные блоки вычислителя.

2. Какие функции выполняет центральный процессор в составе вычислителя?

3. Дайте определение термину компьютер.

4. Дайте определение термину микропроцессор.

5. Дайте определение термину микроконтроллер.

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

7. Какие функции может исполнять модуль ШИМ микроконтроллера 68HC12 в системе управления?

8. Перечислите, какие домашние встроенные системы не были упомянуты в этой главе?


Более сложные

1. Поясните, чем отличаются микроконтроллер и персональный компьютер.

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

3. Приведите примеры работы встроенных систем в реальном масштабе времени?

4. В каких случаях Вы, как разработчик встроенной системы, можете выбрать однокристальный режим работы МК, а в каких расширенный режим работы?

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


Исследовательские

1. Программно–аппаратный дуализм встраиваемой микропроцессорной системы?

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

Глава 2

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

 Сделать закладку на этом месте книги

ПОСЛЕ ИЗУЧЕНИЯ ГЛАВЫ ВЫ СМОЖЕТЕ:

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

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

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

• Понять важность документирования в процессе разработки.

• Перечислить правила ведения инженером рабочей тетради.

• Применить методы универсального языка моделирования к описанию функционирования встраиваемых систем.

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

2.1. Почему мы программируем микроконтроллеры на Си?

 Сделать закладку на этом месте книги

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

В предисловии мы адресовали данную книгу подготовленным читателям, которые знакомы с основами цифровой и микропроцессорной техники, имеют опыт программирования на языке ассемблера для какого либо типа МК. Не пугайтесь, если Вы чувствуете себя недостаточно образованным в перечисленных областях знаний. Мы постарались преподнести материал данной книги так, чтобы он легко усваивался учащимися. Для того чтобы восполнить недостающие знания в области цифровой техники, рекомендуем обратиться к книге [9] или к иным подобным изданиям. Для предварительного знакомства с архитектурой и системой команд микроконтроллеров 68HC12 Вы можете использовать книгу [6].

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

2.2. Преимущества программирования на языке ассемблер

 Сделать закладку на этом месте книги

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

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

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

2.3. Преимущества языков высокого уровня

 Сделать закладку на этом месте книги

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

Недавно один из авторов этой книги должен был выполнить разработку, в которой заказчик определил использование МК компании Atmel. Он никогда ранее не использовал 8-разрядные МК от компании Atmel, но был не прочь их освоить. Поэтому автор решил выполнять проект на Си. Это позволило ему быстрее завершить исполнение заказа. Если бы он решил выполнять проект на ассемблере, то ему потребовалось значительно больше времени не только для изучения архитектуры и алгоритмов работы периферийных модулей, но и системы команд, поскольку МК Atmel существенно отличаются от знакомых автору МК Motorola/Freescale Semiconductor. Кроме того, область применения устройства была такой, что он мог не беспокоиться о размере программы и времени ее выполнения. Поэтому в приведенных условиях выбор языка Си для проекта был логичным и естественным.

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

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

Языки высокого уровня обладают важным свойством переносимости программного кода. Это означает, что программа, написанная на языке высокого уровня для одного МК, затем может быть скомпилирована другим компилятором для МК с другим процессорным ядром. И эта программа тоже окажется работоспособной. Для того, чтобы программа обладала свойством переносимости, синтаксис языка высокого уровня для разных компиляторов должен быть абсолютно одинаков. В частности, таким свойством обладает язык Си стандарта ANSI (American National Standards Institute). Разработчики называют его просто «ANSI C». Основная цель стандартизации состоит в том, чтобы обеспечить разработчику возможность написания типовых функций управления один раз с последующим их многократным использованием в разных проектах и для разных микроконтроллеров.

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

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

TIMP  = (216×n ) + (Stop_count  − Start _count )

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

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

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

 Сделать закладку на этом месте книги

Проведя обзор в Internet, Вы обнаружите достаточно большое число разнообразных компиляторов различных языков высокого уровня для встраиваемых систем. Вы без труда найдете компиляторы Си, С++, Java. Ada, Fortran и некоторые другие. Каждый из этих языков имеет свои преимущества и недостатки. Часто выбор языка программирования может определяться специфическими особенностями задачи или просто пожеланиями заказчика. Детальное сравнение всех перечисленных языков выходит за рамки этой книги и вряд ли возможно.

Для этой книги мы выбрали язык Си, потому что именно он сейчас используется в организациях разработчиков, и он обеспечивает хороший доступ к аппаратным ресурсам микроконтроллеров. Язык Си известен как некоторый промежуточный язык, который объединяет в себе свойства языка высокого уровня и одновременно обеспечивает легкий доступ к регистрам и ячейкам памяти МК. Именно это свойство отмечал один из разработчиков Си господин Ричи (Ritchie).

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


убрать рекламу






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

2.3.2. Краткая история языка Си

 Сделать закладку на этом месте книги

Наш разговор о Си был бы неполным, если бы мы кратко не остановились на происхождении этого языка. Для более полного погружения в эту тему советуем обратиться к книге [8]. Ниже по тексту параграфа мы даем краткое изложение одного из разделов этой книги.

Первая версия языка Си была разработана в середине 60 ых годов для разработки операционной системы Unix в лаборатории Bell. Один из самых первых разработчиков этого языка, Кен Томсон (Ken Thompson), решил, что требуется язык для создания более сложных языков программирования. Он создал такой язык и назвал его «B». В процессе развития своего творения Томсон постоянно боролся с ограничением ресурсов памяти, что теперь очень похоже на встраиваемые системы. Деннис Ричи (Dennis Ritchie) решил расширить язык «B» свойством генерировать малый по объему код, который сможет соперничать с кодом, написанным на ассемблере. В 1973 году важнейшие свойства этого нового языка «C» были получены.

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

Американский национальный институт стандартизации (American National Standards Institute — ANSI) в 1982 году учредил комитет X3J11 для разработки стандарта языка Си. В 1989 доклад комитета был передан в Международную организации стандартизации (International Organization for Standardization — ISO) и международную электротехническую комиссию (International Electrotechnical Commission — IEC) и был утвержден в качестве стандарта ISO/IEC 9899-1990. За этим стандартом последовало неизбежное развитие языка, которое было узаконено в 1999 стандартом ISO/IEC 9899. И Си стал языком, который наиболее часто используется в компьютерной индустрии.

2.4. Оптимальная стратегия — программирование на Си и на ассемблере

 Сделать закладку на этом месте книги

Итак, мы установили, что предпочтительно программировать встраиваемые системы на языке высокого уровня. И в качестве такого языка мы обоснованно выбрали язык Си. Но и ассемблер имеет свои преимущества. Так на каком языке мы все таки будем программировать встраиваемые системы?

Практика применения языка Си и ассемблера показывает, что оптимальный результат, как с точки зрения экономии времени на разработку, так и по времени исполнения программы, можно получить, используя в одном проекте сразу два языка программировании: и Си, и ассемблер. Основная часть прикладной программы, в которой производятся преобразования данных, будет написана на СИ, в то время, как критичные по времени реализации фрагменты алгоритма, следует оформить на ассемблере. Кроме того, ассемблер иногда используют для программной поддержки некоторых внешних по отношению к МК периферийных ИС. Драйверы обмена с такими ИС обычно требуют многократного переключения отдельных линий портов МК, что в компиляторах Си для некоторых МК удобнее выполнить на ассемблере. Еще один случай обязательного включения ассемблерного фрагмента в текст основной программы на Си мы продемонстрируем на примере использования команд ассемблера 68HC12/HCS12 для преобразования данных по правилам нечеткой логики (см. гл. 7).

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

2.5. Структурное проектирование

 Сделать закладку на этом месте книги

Несколько следующих параграфов мы посвятим изложению основных идей метода структурного проектирования. Для создания этого раздела мы использовали материалы, изложенные в [1, 7], а также опыт собственных разработок. Метод структурного проектирования не гарантирует обязательного успешного завершения проекта. Однако этот метод значительно увеличивает вероятность создания за ограниченное время качественной системы, полностью совместимой с управляемым объектом.

2.5.1. Основные положения метода структурного проектирования

 Сделать закладку на этом месте книги

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

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

Применение. На протяжении всего этого параграфа мы будем иллюстрировать применение выдвинутых концепций на примере разработки системы управления стереоусилителем. Прототип нашего примера контроллер стереоусилителя, был разработан доктором Паррисом Нилом (Parris Neal) из Аэрокосмической Академии в Колорадо. Парис — превосходный инженер, разрабатывает стереоусилители мирового уровня. Любой из его проектов — это произведение искусства. Паррис разработал стереоусилитель, который может принимать звуковые сигналы от шести различных источников. Пользователь должен выбрать сигнал либо с помощью переключателей на передней панели корпуса усилителя (рис. 2.1), либо с дистанционного пульта управления, связанного со стереоусилителем по инфракрасному каналу. Паррис попросил первого автора этой книги разработать микропроцессорный контроллер для этого усилителя, используя 8 разрядный RISC МК компании Atmel. Ему было интересно на практике исследовать возможности МК Atmel в качестве низкостоимостного МК для следующих проектов.



а) Вид спереди



б) Плата с микроконтроллером



в) Вид сзади 

Рис. 2.1. Внешний вид стереоусилителя с дистанционным управлением


После первого обсуждения были выявлены следующие технические требования к проекту:

• Необходимо разработать микропроцессорный контроллер для управления стереоусилителем;

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

• При разработке устройства управления необходимо использовать МК компании Atmel.

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

• Что конкретно должен делать контроллер в ответ на выбор номера канала воспроизведения?

• Кто несет ответственность за интерфейс сопряжения между контроллером и стереоусилителем?

• Каковы электрические характеристики сигналов с передней панели усилителя и с удаленного пульта управления?

• Какие сигналы должен формировать контроллер для управления переключением каналов усилителя?

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

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

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

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

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

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

Применение. Структура программного обеспечения контроллера управления стереоусилителем показана на рис. 2.2. Блок схема алгоритма — на рис. 2.3. Проанализировав эти рисунки, можно увидеть, что структура программы управления показывает взаимосвязь отдельных модулей программы, в то время, как блок схема алгоритма является графическим описанием порядка функционирования этой программы. В этот момент, Вы можете подумать: «Наконец-то! Теперь можно кодировать программу!». Но нет, существует еще несколько обязательных этапов структурного проектирования, которые должны предшествовать написанию текста программы.



Рис. 2.2. Структура программы управления стереоусилителем




Рис. 2.3. Блок-схема алгоритма управления стереоусилителем


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

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

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



Рис. 2.4. Псевдокод программы управления стереоусилителем


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

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

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

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

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

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



Рис. 2.5. Функциональная схема имитатора для тестирования программы стереоусилителя


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

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

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

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

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

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

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

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

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

2.5.2. Документирование программ

 Сделать закладку на этом месте книги

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

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

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

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

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

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

2.5.3. Как язык Си соотносится со структурным проектированием

 Сделать закладку на этом месте книги

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

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

2.6. Рабочие тетради

 Сделать закладку на этом месте книги

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

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

2.6.1. Порядок ведения записей

 Сделать закладку на этом месте книги

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

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

2. Все записи должны делаться последовательно несмываемыми чернилами.

3. Страницы тетради должны быть последовательно пронумерованы.

4. Каждая запись должна сопровождаться датой. При этом дата не должна быть двояко трактуемой. Запись «09 мая 2004 г.» лучше, чем «9/5/2004».

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

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

7. Законченный материал должен быть помечен символами «X» или «Z» для уверенности, что ничего не было добавлено позже.

2.6.2. Содержание записей

 Сделать закладку на этом месте книги

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


убрать рекламу






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

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

2.7. Блок схемы алгоритмов

 Сделать закладку на этом месте книги

Теория. Универсальный язык моделирования (Unified Modeling Language — UML) — это язык для определения, представления, проектирования и документирования программных систем. Основными составляющими языка UML являются элементы, связи, механизмы расширения и диаграммы. Универсальный язык моделирования предоставляет разработчику метод графической иллюстрации и имитационного моделирования системы, которая основана на программном принципе управления. Этот язык позволяет стандартизировать графическое изображение операций в системе с целью моделирования ее алгоритма работы в общем виде, без составления исходного текста управляющей программы. Универсальному языку моделирования посвящены более 100 научных монографий. Мы рассмотрим лишь малую часть сведений об этом языке, которые будут использованы нами для проектирования встраиваемых систем на протяжении всей этой книги. Если Вас будет интересовать получение более широких сведений по этой теме, обратитесь к литературе, рекомендованной в конце главы.

Свою историю универсальный язык моделирования ведет с начала 90х годов. В 1994 году Грэйди Буч (Grady Booch), Джеймс Рэмбо (James Rambaugh) и Ивар Якобсон (Ivar Jacobson) начали объединять несколько методов объектно ориентированного моделирования в фирме Rational Software. Их целью была разработка методов сокращения времени реализации программных продуктов для промышленности. И уже в 1995 году была представлена спецификация метода, названного «Unified Method». Первая версия универсального языка моделирования была принята консорциумом OMG (Object Management Group) в январе 1997 года. Утвержденная же в сентябре того же года версия UML 1.1 была принята на вооружение основными компаниями — производителями программного обеспечения, такими, как Microsoft, IBM, Hewlett Packard.

Визуальные модели универсального языка моделирования широко используются в существующих технологиях управления проектированием систем, сложность, масштабы и функциональность которых постоянно возрастают. В практике эксплуатации программных информационных систем постоянно приходится решать такие задачи как перераспределение вычислений и данных, обеспечение проведения параллельных вычислений, обеспечение безопасности доступа к информационным системам, оптимизация балансировки нагрузки систем, устойчивость к сбоям и многое другое. Основные виды визуальных моделей UML (универсального языка моделирования): диаграммы сценариев, диаграммы взаимодействия объектов, диаграммы классов, диаграммы состояний, диаграммы модулей и компонентов, диаграммы действий [2,3]. Графические средства представления алгоритмов позволяют переводить модели UML в исходный код объектно-ориентированных языков программирования, что значительно ускоряет процесс разработки. Поэтому универсальный язык моделирования прекрасно зарекомендовал себя на множестве успешных программных проектов. Мы не будем касаться объектно ориентированного программирования в нашей книге. Поэтому мы используем лишь малую часть возможностей универсального языка моделирования для иллюстрации последовательности действий в проектируемых нами программ для встраиваемых систем.

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

Основные типы операторов представлены на рис. 2.6. Программа начинается с оператора начального запуска и заканчивается оператором останова. Множество различных действий совершается под управлением программы в процессе ее выполнения. Каждое действие отображается оператором процесса, который производит изменение значения, формы представления или расположения данных. Оператор процесса может иметь любое количество входов, но только один выход. Переход от одного оператора к другому обозначается стрелкой. Если в процессе выполнения очередного действия производится анализ некоторого внешнего сигнала или внутреннего состояния программы с последующим выбором, по какому пути продолжить исполнения программы, то такое действие отображается условным оператором (другое название — оператор решения). Условный оператор имеет один вход и несколько выходов. После выполнения действий условного оператора программа может «избрать» только один путь. Поэтому условия, по которым определяется направление выхода из оператора решения, должны быть взаимоисключающими. Оператор слияния (поглощения), в соответствие со своим названием, позволяет соединить несколько отдельных ветвей алгоритма в одну. В завершение мы включили два оператора, которые характерны для структурного программирования. Это операторы ветвления и объединения, которые предназначены для отображения работы систем с параллельными вычислителями [2,3]. В качестве первого примера использования условных графических обозначений UML мы представили средствами универсального языка моделирования процесс структурного проектирования, блок схема алгоритма которого приведена на рис. 2.7. На рис. 2.8 тот же процесс представлен с большей степенью подробности, что немедленно привело к усложнению блок схемы алгоритма.




Рис. 2.6. Условные графические обозначения операторов универсального языка моделирования UML




Рис. 2.7. Блок схема алгоритма структурного проектирования




Рис. 2.8. Блок схема алгоритма разработки и тестирования программного обеспечения встраиваемой системы

2.8. Пример применения

 Сделать закладку на этом месте книги

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

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



Рис. 2.9. Структура функций медицинского лазера

2.9. Заключение по главе 2

 Сделать закладку на этом месте книги

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

2.10 Что еще почитать?

 Сделать закладку на этом месте книги

1. Dale, Nell, and Susan С. Lilly. Pascal Plus Data Structures. 4th ed. Englewood Cliffs, NJ: Jones and Bartlett, 1995.

2. Douglass, Bruce Powel. Real Time UML Developing Efficient Objects for Embedded Systems. 2nd ed. Boston: Addison Wesley, 2000.

3. Fowler, Martin, with Kendall Scott. «UML Distilled A Brief Guide to the Standard Object Modeling Language. 2nd ed. Boston: Addison Wesley, 2000.

4. Kobryn, Chris. «UML 2001.» Communications of the ACM 42, no. 10, (October 1999): 29–37.

5. МсСоnnасk, J. В., R. K. Morrow, H. F. Bare, R. J. Bums, and R. L. Rasmussen «The Complementary Roles of Laboratory Notebooks and Laboratory Reports.» Paper presented at the annual meeting of the American Society for Engineering Educators Toronto, Canada, 1990.

6. Pack, Daniel, and Steven Barrett. 68HC12: Theory and Applications. Upper Saddle River, NJ: Prentice Hall, 2002.

7. Page Jones, Meilir. The Practical Guide to Structured Systems Design. 2nd ed. Upper Saddle River, NJ: Yourdon Press, 1988.

8. Ritchie, Dennis M. «The Development of the С Language.» Paper presented at а meeting of the Association for Computing Machinery, Second History of Programming Languages Conference, Cambridge, МА, 1993.

9. Wakerly, John F. Digital Design Principles and Practices. 3rd ed. Upper Saddle River, NJ: Prentice Hall, 2000.

2.11 Вопросы и задания

 Сделать закладку на этом месте книги

Основные

1. Проведите сравнение достоинств и недостатков применения языка Си и языка ассемблер для программирования встраиваемых микропроцессорных систем.

2. Опишите следующие свойства метода структурного проектирования: переносимость, устойчивость, читабельность.

3. Какие другие компиляторы с языков высокого уровня, кроме компиляторов Си, Вы знаете? Укажите их источники в Internet.

4. Каковы основные причины быстрого распространения языка Си для программирования встраиваемых систем?

5. Что такое «черный ящик»?

6. Каково различие между структурой и блок схемой алгоритма?


Более сложные

1. Преобразуйте блок схему алгоритма рис. 2.3 в диаграмму действия UML.

2. Что называют псевдокодированием?

3. Объясните различия между методами проектирования сверху вниз и снизу вверх?

4. Каковы различия между внешней и внутренней документацией?

5. Поясните необходимость ведения рабочей тетради.


Исследовательские

1. Программно аппаратный дуализм встраиваемой микропроцессорной системы?

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

 • Анемометром — прибором для измерения скорости ветра. Анемометр представляет собой колесо с лопастями, которое вращается со скоростью, пропорциональной скорости ветра. Будем считать, что электронная схема анемометра выдает один импульс амплитудой 5 В на один оборот колеса.

 • Барометром — прибором для измерения атмосферного давления. На аналоговом выходе электронного преобразователя сигнала барометра формируется напряжение в диапазоне 0…5,0 В. Давлению в 640 мм рт. ст. соответствует напряжение 0 В, давлению 810 мм рт. ст. — напряжение 5,0 В. Преобразователь обладает линейной передаточной характеристикой.

 • Гигрометром — прибором для измерения влажности воздуха. Гигрометр также оснащен электронным преобразователем сигнала с линейной передаточной характеристикой. Относительной влажности 0% соответствует напряжение 0 В, влажности 100% — напряжение 5,0 В.

 • Термометром — прибором для измерения температуры воздуха. Температуре 50°C соответствует напряжение 0 В, температуре +120°C — напряжение 5,0 В. Передаточная характеристика преобразователя сигнала — линейная.

 • Флюгером — прибором для определения направления ветра. Напряжение на выходе электронного преобразователя прямо пропорционально углу поворота флюгера. Напряжение 0 В формируется при положении стрелки «север», далее напряжение линейно возрастает, при положении стрелки «юг» напряжение равно 2,5 В, и на повороте в 180 град. эл. продолжает линейно возрастать до 5,0 В.

Проектируемая система должна уметь делать следующее:

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



Рис. 2.10. Портативная метеостанция


• Измеритель уровня осадков должен периодически очищаться.

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

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

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

4. Разработайте диаграмму действий UML для выбранного домашнего прибора.

Глава 3

ОСНОВЫ ПРОГРАММИРОВАНИЯ МИКРОКОНТРОЛЛЕРОВ НА СИ

 Сделать закладку на этом месте книги

ПОСЛЕ ИЗУЧЕНИЯ ГЛАВЫ ВЫ СМОЖЕТЕ:

• Описать основные конструкции языка Си;

• Написать на Си простые программы для встроенных систем на основе микроконтроллеров;

• Объяснять последовательность действий, необходимую для получения исполняемого фрагмента кодов для МК 68HC12 и HCS12;

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

В главе 3 рассматривается технология написания и отладки программ на языке Си для микроконтроллеров 68НС12 и HCS12. На протяжении всей главы мы не будем делать различия между этими двумя типами МК и, как следствие, будем использовать для ссылок общую аббревиатуру 68HC12. Основное наше внимание будет уделено технике программирования на языке Си. Однако это не означает, что программирование на языке ассемблера может быть полностью забыто. Включение в исходный текст Си-программы фрагментов на языке ассемблера позволяет создать эффективный исполняемый код в критичных по времени исполнения задачах. Вопросы объединения программных фрагментов, записанных на Си и на ассемблере, также рассматриваются в данной главе.

Мы покажем, как из исходного текста программы, записанного на Си, создать файл исполняемого кода для микроконтроллера, используя для этого программы компилятора, ассемблера, линковщика и загрузчика в составе программного пакета ICC12 от компании Imagecraft (https:/www.imagekraft.com). Программный продукт ICC12 — достаточно простой в управлении, недорогой, но обладающий всеми необходимыми типовыми функциями программный пакет класса «интегрированная среда разработки и отладки программ управления для встраиваемых систем». Технология создания программного обеспечения для встраиваемых микроконтроллерных систем с использованием перечисленных выше программ в составе интегрированной среды разработки IDE (Integrated Development Environment) обладает достаточной степенью универсальности. Поэтому навыки создания и отладки программ для МК 68HC12, полученные с использованием пакета ICC12, могут быть использованы читателем при программировании 68HC12 или иных типов микроконтроллеров с использованием других более развитых программных пакетов IDE, например Code Warrior от компании Metrowerks (https:/www.metrowerks.com).

В этой главе мы обсудим технологию отладки программы, написанной на языке Си, в процессе ее исполнения реальным микроконтроллером. Все МК семейства 68HC12 обладают специальным режимом отладки в реальном времени BDM (Background Debug Mode). Мы рассмотрим основные свойства режима BDM в этой главе. В заключение мы приведем подробный пример преобразования исходного текста программы на Си в файл исполняемого кода для выбранного типа МК средствами программ, входящих в пакет интегрированной среды разработки IDE ICC12.

3.1. Введение в программирование на Си

 Сделать закладку на этом месте книги

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

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

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

3.1.1. Глобальные и локальные переменные

 Сделать закладку на этом месте книги

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

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

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

В микроконтроллерах семейства 68НС12, переменные размещаются в ячейках памяти ПЗУ или ОЗУ. Переменная, которая не изменяет своего значения в течение выполнения программы, именуется константой и хранится в ПЗУ. Переменная, значение которой изменяется в процессе исполнения программы, должна храниться в ОЗУ. Например, предположим, что некоторый контроллер связан с датчиком температуры посредством аналого цифрового преобразователя. Прикладная программа должна постоянно обновлять значение температуры в памяти контроллера. Для этого объявим переменную с именем temp (от слова temperature — температура) и разместим ее в ОЗУ МК. Приведенный ниже фрагмент программы на Си демонстрирует, как обратиться к размещенной в ОЗУ переменной temp и отобразить ее значение на дисплее. Заметим, что номера строк в приводимых фрагментах программ не являются частью записи операторов языка Си и не должны присутствовать в исходном тексте программы, подлежащем компиляции. Они введены искусственно для ссылки на отдельные операторы при обсуждении конструкций языка Си.

1 while (1)

2 {

3  temp = *(unsigned char volatile*)(0х1000);

4  printf(The current temperature is %d\n, temp);

5 }

Данный фрагмент кода предполагает, что переменная с именем temp создана (объявлена) ранее, и также ранее реализован фрагмент кода на Си для опроса аналого цифрового преобразователя с целью обновления значения температуры. Для определенности в строке 3 мы сами присваиваем этой переменной значение $1000 в шестнадцатеричном коде (или 4096 в десятичной системе счисления). Префикс 0x служит в Си для обозначения шестнадцатеричной системы счисления. Не следует тревожиться, если не все записи в данном примере ясны для Вас. Пройдет немного времени, Вы закончите изучение материалов данной главы, и все рассмотренные примеры станут для Вас простыми и понятными.

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

3.2. Типы данных в Си

 Сделать закладку на этом месте книги

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

Спецификация типа Описание Размер, байт Допустимый диапазон чисел
char Однобайтовое целое со знаком 1 –128 ÷ +127
unsigned char Однобайтовое целое без знака или символ из набора символов системы ASCII 1 0 до 255
int Целое значение естественного размера (машинное слово) со знаком 2 –32768 ÷ +32767
short int Целое значение естественного размера (машинное слово) со знаком 2 –32768 ÷ +32767
unsigned int Целое значение естественного размера без знака 2 от 0 до 65535
long int Целое значение двойного естественного размера (два машинных слова) со знаком 4 –2147483648 ÷ +2147483647
float Число в формате с плавающей запятой 4 ±1,176E–38 ÷ ±3,40E+38
double Не рекомендуется для использования 8 ±1,7E–308 ÷ ±1,7E+308 

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


Область памяти, отводимая для хранения объекта типа char, всегда составляет один байт. Размер области памяти, отводимой для хранения объектов int и long, определяется типом используемого компилятора. Как правило, int — машинное слово длиною в 16 бит, long двойное машинное слово, т.е. 32 бита. Формат и размер области памяти объектов float и double также зависит от типа используемого компилятора. В данном случае приведены значения для компилятора Си из среды разработки ICC12.

Служебные слово unsigned (без знака) используется вместе с целочисленными типами. Указание служебного слова unsigned перед спецификацией типа целочисленного значения определяет использование его старшего разряда. Для целых чисел со знаком старший разряд используется для хранения знака, что приводит к сужению диапазона модуля допустимых значений. В целых числах без знака старший разряд используется как дополнительный разряд числа, следовательно, диапазон допустимых значений расширяется. По умолчанию, т.е. без указания служебного слова unsigned, переменные типа char, int и long всегда считаются знаковыми. Числа в формате с плавающей запятой типов float и double также всегда знаковые.

В сочетании со спецификацией типа int возможно применение служебного слова short (короткий). Служебное слово short используется для сужения типа int до «короткого» целого. Применение служебного слова short имеет смысл, когда длина машинного слова микроконтроллера составляет четыре и более байтов. В этом случае спецификация типа short int соответствует целому числу, разрядностью в половину машинного слова. В случаях, когда машинное слово составляет два байта, спецификации типов int и short int совпадают (например, в 16-ти разрядном микроконтроллере HCS12). В некоторых компиляторах языка Си разрешается опускать слово int в спецификации типа short int и использовать одно слово short.

Слово long, обозначающее целое число, соответствующее двойному машинному слову,


убрать рекламу






является таким же служебным словом как unsigned и применяется перед спецификацией типа int для его расширения до «длинного» целого (до двойного машинного слова). Однако в языке Си разрешается опускать слово int в спецификации типа long int и использовать одно слово long.

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

• Array — массив, набор элементов одного типа;

• Pointer — указатель, переменная, которая содержит адрес переменной определенного типа;

• Structure — структура, набор элементов различного типа;

• Union — объединение, одна область памяти для двух различных типов данных;

• Function — функция, являясь сама определенным типом данных, может генерировать типы данных и возвращать типы данных.

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

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

<спецификация типа> <идентификатор>

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

<способ доступа/класс хранения> <спецификация типа> <идентификатор>

При объявлении массива может быть задано число элементов и их значения:

char a[10]

int m[] = {5,10,4000,34}

Первое поле, <способ доступа/класс хранения>, используется для задания типа памяти, куда должна быть помещена переменная. Второе поле, спецификация типа, содержит определение типа из табл. 3.1. Третье поле, идентификатор, содержит в себе придуманное программистом имя переменной. Четвертое поле, в котором проставлено численное значение или строка символов для массива, необязательное. Оно необходимо, если программист в строке объявления переменной желает также задать ее начальное значение, т.е. инициализировать переменную. Ниже приведен пример определения двухбайтовой переменной с именем «change» в целочисленном формате со знаком (тип int в соответствии с табл. 3.1):

int change;

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

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

auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int, long, register, return, short, signed, sizeof, struct, switch, typedef, union, unsigned, void, volatile, while

Шесть слов из приведенного списка используются в Си для определения класса хранения переменной:

extern, auto, static, register, const, volatile

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

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

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

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

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

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

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

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

const int change = 23

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

3.3. Операторы языка Си

 Сделать закладку на этом месте книги

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

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

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

Приоритет в выражениях Имя оператора Символ для обозначения
Общие
1 Скобки (), {}
1 Разделители -> , .
11 Условие ?:
12 Присваивание =, +=, *= и т.д.
Арифметические
3 Умножение *
3 Деление /
3 Получение целочисленного остатка от деления %
4 Сложение +
4 Вычитание -
Логические
6 Меньше <
6 Меньше или равно <=
6 Больше >
6 Больше или равно >=
7 Равно ==
7 Не равно !=
9 Логическое И &&
10 Логическое ИЛИ ||
Битовые манипуляции
5 Сдвиг влево <<
5 Сдвиг вправо >>
8 Поразрядное И &
8 Поразрядное исключающее ИЛИ ^
8 Поразрядное ИЛИ |
Унарные
2 Инверсия !
2 Взятие обратного кода числа ~
2 Инкремент ++
2 Декремент --
2 Минус -
2 Привести к типу (type)
2 Указатель *
2 Взять адрес &
2 Определить размер sizeof

Табл. 3.2. Операторы языка Си


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

2 * 23 + 15

Оператор умножения имеет приоритет над оператором сложения, поэтому результат вычисления выражения будет равен 61. Какие изменения мы должны внести в выражение, если хотим сначала сложить 23 и 15, и лишь затем умножить сумму на 2? Для изменения порядка действий над операндами мы воспользуемся круглыми скобками:

2 * (23 + 15)

И результат вычислений станет равным 76.

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

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

Sum = 2 + 3;

Для вычисления значения переменной sum сначала реализуется оператор сложения «+», а затем оператор присваивания «=». В колонке 1 табл. 3.2 отражено, что оператор сложения имеет приоритет над оператором присваивания. При этом необходимо, чтобы переменная sum ранее была определена как int. Что произойдет в случае, если переменная sum ранее была объявлена как переменная другого типа, например float? После сложения результат будет преобразован к тому формату представления числа, который был объявлен при определении переменной sum.

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

num1 = 2;

num2 = 3;

sum = num1 + num2;

Подразумевается, что все упомянутые переменные num1, num2 и sum ранее были определены.

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

number = number + 1;

number++;

++number;

Аналогично, три следующих записи реализуют операцию декремента, т.е. уменьшения на единицу переменной number.

number = number - 1;

number--;

--number;

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

Операторы логической группы. Операторы этой группы используются для определения условий, по которым реализуется ветвление алгоритма. Операторы логической группы возвращают в виде результата 1, если результат операции «правда», и 0, если результат операции «ложь». Допустим, мы хотим сравнить текущее значение некоторой переменной с пороговым значением 82. Для этого могут быть использованы операторы больше «>», меньше «<», больше или равно «>=», меньше или равно «<=», не равно «!=» или равно «==». Рассмотрим следующую запись на Си:

value = temperature > 82;

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

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

number = 24;

new_number_one = number << 1;

new_number_two = number >> 1;

Допустим, что три используемые в примере переменные определены как int. В первой строке переменной number присваивается значение 24 в десятичной системе счисления. Это же значение в двоичной системе счисления будет равно 00000000 00011000. Результатом действия оператора «<<» будет сдвиг влево на один разряд значения переменной number, т.е. 00000000 00110000 или 48 в десятичной системе счисления. Это значение и будем присвоено переменной new_number_one. В третьей строке оператор «>>» реализует сдвиг вправо числа number. Получится новое двоичное число 00000000 00001100 или 12 в десятичной системе счисления. В результате, значение переменной new_number_one будет равно удвоенному значению переменной number, в то время как переменная new_number_two будет равна поделенному на 2 значению number. С использованием рассматриваемых операторов мы можем также выполнить сдвиг на несколько разрядов, тогда результат операции будет эквивалентен умножению или делению на 2n. Например, если n = 3, то после выполнения следующих трех операторов:

number = 24;

new_number_one = number << 3;

new_number_two = number >> 3;

значение переменной new_number_one будет равно 192 (двоичный код 00000000 11000000), а значение переменной new_number_two — 3 (двоичный код 00000000 00000011).

Рассмотрим два других логических оператора: поразрядное логическое И и поразрядное логическое ИЛИ.

Символ Операция Пример
& Логическое И *(0x0023) & 0x57
| Логическое ИЛИ *(0x0000) | 0x35

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

Результат операции логического И над двумя двоичными числами 01011100 и 11000111 будет равен :

  01011100

& 11000111

----------

  01000100

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

  01011100

| 11000111

----------

  11011111

В каких задачах управления используются эти логические операторы? В прикладных программах (т.е. программах управления) часто приходится изменять сигналы на отдельных линиях портов ввода/вывода. Регистры данных портов расположены по строго определенным в техническом описании физическим адресам. Так для того, чтобы сконфигурировать все линии порта PORT A на ввод, необходимо в регистр направления передачи порта DDRA (физический адрес 0x0002) записать все нули. Это может быть выполнено под управлением следующей строки:

*(unsigned char volatile*)(0х0002) = 0х00;

Если порт Port A настроен на вывод, то установить линию PTA7 в единицу без изменения состояния остальных линий порта можно посредством следующей записи:

PORTA |= 0х80; //установить PTA7

Выше использована сокращенная форма записи выражения:

PORTA = PORTA | 0х80; //установить PTA7

Выражение возвращает результат операции поразрядного логического ИЛИ числа 0x80 (10000000 в двоичной системе счисления) и содержимого порта PortA. После операции старший бит Port A будет установлен в 1, остальные биты останутся без изменения.

Аналогично, старший бит порта Port A может быть установлен в 0 (сброшен) посредством записи выражения:

PORTA &= ~0х80; //сбросить бит PTA7

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

PORTA = PORTA & 0х7F; //сбросить бит PTA7

Для установки в 0 старшего разряда порта Port A содержимое порта побитно логически умножается на константу 0x7F (01111111 в двоичном коде). В результате старший бит становится равным 0, а остальные биты остаются без изменения. Запись ~0х80 в первом выражении предписывает перед выполнением операции логического И взять инверсию константы 0x80 (10000000), которая будет равна 0x7F (01111111). Вторая запись более понятна на начальном этапе программирования на Си, в то время как первая запись позволяет использовать одну и ту же константу в выражениях по установки и сбросу бита, что в практическом программировании удобно.

Операцию поразрядного логического И также следует использовать, если необходимо проверить, установлены или сброшены биты порта с определенными номерами. Например, приведенный ниже фрагмент программы производит чтение регистра данных порта Port A, логически умножает его содержимое на константу 0x81 и сравнивает полученный результат с нулем. Если условие равенства нулю выполняется, то это означает, что биты 7 и 0 порта Port A одновременно равны нулю, и следует выполнить действия, которые описаны операторами в фигурных скобках. Если хотя бы один бит PTA7 или PTA0 не равен нулю, то условие ((PORTA & 0х81) == 0) не выполняется, и операторы в фигурных скобках будут пропущены при исполнении.

if ((PORTA & 0x81) == 0) {

 :

}

В качестве примера использования оператора ИСКЛЮЧАЮЩЕГО ИЛИ приведем выражение для инвертирования значения бита 7 порта Port A:

PORTA ~= 0х80; //инвертировать бит PTA7

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

int num, address, new_num;

Также предположим, что переменная num расположена в памяти по адресу 0x2000. Запишем следующее выражение:

address = &num;

Результатом исполнения выражения будет присвоение переменной address значения адреса переменной num, т.е. новое значение переменной address будет равно 0x2000.

Запишем новое выражение:

new_num = *address;

Результатом выполнения этого выражения будет присвоение переменной new_num значения, которое содержится в ячейке памяти, адрес которой равен текущему значению переменной address. Поскольку содержимое address равно 0x2000, т.е. адресу переменной num, то рассматриваемое выражение в нашем случае эквивалентно выражению:

new_num = num;

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

int *address

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

Обсудим действие следующего выражения:

address = (int *) 0x1000;

Это выражение назначает ячейку памяти с адресом 0x1000 как указатель с именем address. Для того, чтобы извлечь содержимое ячеек памяти следует поместить оператор * перед именем address.

3.4. Функции

 Сделать закладку на этом месте книги

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

3.4.1. Что такое функция?

 Сделать закладку на этом месте книги

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

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

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

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

3.4.2. Основная программа

 Сделать закладку на этом месте книги

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


убрать рекламу






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

1  void main(void)

2  {

3   function_one();

4   function_two();

5   function_three();

6   :

7   :

8   :

9   function_n();

10 }

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

3.4.3. Прототипы функций

 Сделать закладку на этом месте книги

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

тип возвращаемой переменной имя функции

 (<тип переменной1> <имя переменной1>,

 <тип переменной2> <имя переменной2>,

 :

 <тип переменной> <имя переменнойN>);

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

Пример 1: int compute(int, int);

Пример 2: float change(char name, float number, int a);

Пример 3: double find(unsigned int, float, double);

В примере 1 функция compute использует два аргумента. Аргументы функции — это те переменные, которые необходимы для ее корректного исполнения. Спецификация типа аргументов функции приведена в круглых скобках. В данном случае указано, что функция compute будет использовать два целочисленных аргумента, т.е. при вызове функции ей должны быть указаны для целочисленных значения. Результатом действия функции compute будет вычисление значения некоторой переменной. Спецификация типа возвращаемой переменной приведена перед именем функции. В данном случае это тоже целочисленный 16 разрядный формат.

В примере 2 записан прототип функции change. Эта функция предполагает наличие трех аргументов: однобайтового целочисленного name, числа с именем number в формате с плавающей запятой и двухбайтового целого числа с именем a. Функция change должна возвратить значение переменной в формате с плавающей запятой. В примере 3 объявляется функция find с тремя аргументами, для которых указан тип данных, но не указаны имена.

При знакомстве с программами на Си Вы можете встретить прототип функции, в котором на первом месте указано слово extern:

extern not_here(int a, int b, int c)

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

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

compute(23, 12);

change('b', 7.825, 2);

find(25, 5.1524, 23.54721);

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

3.4.4. Описание функций

 Сделать закладку на этом месте книги

Каждая объявленная в начале некоторого программного модуля функция должна быть определена в этом модуле или в тексте программы другого модуля, который в процессе генерации исполняемого кода программы будет присоединен к текущему модулю. Функция может быть также определена в подключаемом файле стандартной библиотеки. Текст определения функции может быть записан в любом месте программного модуля, однако принято определения всех используемых функций располагать сразу за текстом основной программы main.c. Например, предположим, что объявленная в предыдущем параграфе функция compute вычисляет модуль вектора двух ортогональных составляющих a и b и возвращает его в переменной с именем result. Прототип функции:

int compute(int a, int b);

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

/*Функция compute: вычисляет модуль вектора по двум его ортогональным */

/*составляющим                                                        */

1 int compute(int a, int b)

2 {

3  int sum, result;

4  sum = a*a + b*b;

5  result=(int) (sqrt(sum));

6  return(result);

7 }

В приведенном примере строка 1 открывает определение функции, информируя компилятор о том, что имя функции compute, она использует для своей работы две целочисленных переменных и возвращает одну целочисленную переменную. Фигурная скобка в строке 2 открывает область операторов определяемой функции. В строке 3 объявляются локальные переменные, т.е. те переменные, которые используются только внутри функции. Это переменные sum и result. Операторы, расположенные в строках 4 и 5 выполняют заявленные в описании функции вычисления. Причем в строке 5 используется функция извлечения квадратного корня sqrt, которая определена в библиотеке математических вычислений. При компиляции эта библиотека должна быть обязательно присоединена к файлу с рассматриваемой функцией посредством специальных директив компилятора, которые мы рассмотрим в следующем параграфе. В строке 5 следует обратить внимание на оператор (int) перед вызовом функции извлечения квадратного корня. Этот оператор осуществляет преобразование типа данных к заявленному в прототипе функции compute целочисленному формату int, поскольку функция извлечения квадратного корня возвращает данные в другом формате. В строке 6 применен оператор возврата return, которые позволяет использовать значение переменной result другими операторами основной программы. Фигурная скобка в строке 7 завершает определение функции. Любые операторы, записанные после скобки, уже не будут ассоциироваться с функцией compute.

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

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

 Сделать закладку на этом месте книги

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

magnitude = compute(12, 24)

В этом примере мы предполагаем, что переменная magnitude ранее была объявлена как целочисленная. После того, как функция была вызвана и выполнена, переменной magnitude будет присвоено значение 26. Истинный результат вычисления равен 26,832816. Именно это значение будет вычислено функцией извлечения квадратного корня sqrt. Однако перед присвоением переменной result этого значения производится смена формата представления данных, и дробная часть результата отбрасывается.

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

3.5. Файлы заголовков

 Сделать закладку на этом месте книги

В этом параграфе мы расширим наши знания о технике программирования на Си посредством знакомства с заголовочными файлами (header file). Заголовочный файл — это внешний файл, помещаемый в начало программы с помощью директивы #include, обычно содержащий определения типов и переменных, используемых в программе. Язык Си предоставляет программисту некоторый набор стандартных функций, определения которых находятся в нескольких заголовочных файлах. Например, в созданной нами функции compute мы использовали функцию извлечения квадратного корня sqrt, которая определена в файле математических функций math.h.

Выражения языка С для включения файлов заголовков в модуль разрабатываемой программы обычно располагаются в начале программы. Заголовочные файлы содержат определения переменных, макросы, объявления функций, позволяя программисту возможность вызывать эти функции, использовать переменные и макросы без дополнительного определения их в тексте создаваемой программы. В процессе компиляции значения постоянных переменных замещают их символьные значения, упомянутые в основной программе. Далее в примерах программ мы будем использовать заголовочный файл stdio.h, в котором определены функции библиотеки стандартного ввода/вывода. Эти функции позволяют отобразить результаты преобразования данных в МК на экране дисплея. А также передать в МК код нажатой клавиши на клавиатуре. Поставляемые фирмами производителями программного обеспечения компиляторы уже содержат библиотеки и соответствующие им заголовочные файлы. Например, нами будет использована библиотека математических функций, и соответствующий ей файл math.h. Во многих случаях у пользователя возникает необходимость создания своего собственного заголовочного файла, в котором будут содержаться определения констант. Для того чтобы включить файл заголовка в разрабатываемый программный модуль, следует воспользоваться директивой #include. Приведем три примера:

#include <stdio>

#include <math.h>

#include "myheader.h"

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

3.6. Директивы компилятора

 Сделать закладку на этом месте книги

Директивы компилятора — это инструкции для программы компилятора, которые указывают ему каким образом следует обрабатывать исходный текст программы. Достаточно часто эти инструкции называют директивами препроцессора компилятора, акцентируя внимание пользователей на том, что эти директивы выполняют обработку исходного текста программы перед тем, как компилятор начнет генерацию ассемблерного текста программы. Известно 11 директив компилятора Си: #if, #ifdef, #ifndef, #else, #elif, #include, #define, #undef, #line, #error, #pragma. Из приведенного списка понятно, что директивы отмечаются символом # в первом знаке имени. Далее мы рассмотрим наиболее часто используемые директивы.

3.6.1. Директивы условной компиляции

 Сделать закладку на этом месте книги

Директивы #if, #ifdef, #ifndef, #else, #elif и #endif относятся к группе директив условной компиляции. Эти директивы используются для того, чтобы обозначенный фрагмент исходного текста программы можно было бы включать или не включать в компилируемый код в зависимости от выполнения некоторого наперед заданного условия. Такое действие может быть полезным, например, в процессе отладки программы. Тогда в отладочной версии программы промежуточные результаты вычислений будут выводиться на экран дисплея, в рабочей версии эти действия выполняться не будут.

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

1   #include <stdio.h>

2   #define DEBUG 1

3   void main(void)

4.  {

     :

     :

m   #if DEBUG

m+l  printf{"The program reached this point in the program\n"};

m+2 #endif

     :

     :

n   }

Для этого в строке 2 мы присвоили переменной DEBUG значение 1, используя директиву препроцессора #define. Эту директиву мы обсудим несколько позже, а пока констатируем, что единичное значение переменной DEBUG соответствует условию «истина» в строке m с директорией #if. Поэтому вызов функции prinf, записанный в строке m+1, будет включен в компилируемый текст программы. При ее исполнении мы увидим строку «The program reached this point in the program» на экране монитора. Обратите внимание, что точка с запятой в конце строки с директивой не ставится.

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

1  #define М68НС11 0

2  #define М68НС12 1

3  #define М8051 2

4  #define Processor 1

5  void main(void)

6  {

7  #if Processor == М68НС11

8   Instruction(s) А

9  #elif processor == М68НС12

10  Instruction(s) В

11 #elif processor == М8051

12  Instruction(s) С

13 #else

14  Instruction(s) D

15 #endif

16 }

В этом примере исходный текст программы написан таким образом, что он может быть компилирован для исполнения различными микроконтроллерами: Motorola HC11, Motorola HC12 и Intel 8051. Директивы #if, #elif и #else позволяют для данного сеанса компиляции выбрать конкретный тип МК. Для этого в строках 1…3 программы каждому символьному имени МК присвоено определенное численное значение. Далее в зависимости от выбранного типа МК переменной Processor присваивается желаемое значение. В примере мы собираемся компилировать программу для МК HC12, поэтому присвоили переменной Processor значение 1. В строке 7 компилятор проверяет истинность выражения, записанного в качестве условия директивы #if. Это условие не выполняется, поскольку Processor = 1 ≠ М68НС11 = 0. Поэтому группа инструкций Instruction(s) A не будет включена в программу. Далее в строке 9 компилятор обнаружит выполнение условия директивы #elif, и выражения Instruction(s) B будут присутствовать в конечном варианте программы. Условие строки 11 не выполняется, и группа инструкций Instruction(s) C в исполняемом коде программы присутствовать не будет. Если ни одно из условий для директив #elif не выполнено, то выражения, следующие за директивой #else, будут включены в программу автоматически.

Воспользуемся приведенной конструкцией условной компиляции. Допустим, мы предполагаем исполнение некоторого программного кода как на МК семейства Motorola HC11, так и на МК семейства Motorola 68HC12. Эти МК имеют различные карты памяти, и, соответственно, их порты ввода/вывода расположены по различным адресам. Для возможной адаптации текста программы к одному из типов МК воспользуемся директивами условной компиляции:

1 #if (Processor == 68НС11)

2 #define PORTA *(unsigned char volatile *) (0х1000)

3 #elsif (processor == 68НС12)

4 #define PORTA *(unsigned char volatile *) (0х0000)

5 #endif

В строках 1 и 3 располагаются директивы, которые проверяют условия компиляции. Значение переменной Processor должно быть определено выше по тексту программы директивой #define, или в подключаемом заголовочном файле. Строки 2 и 4 содержат директивы определения адреса для порта PORTA для двух различных типов МК. Директива #endif в строке 5 отмечает окончание фрагмента текста, который подлежит условной компиляции.

Директивы #ifdef и #ifndef используются для организации процесса компиляции при условии, что некоторая переменная с указанным именем была определена (#ifdef) или не определена (#ifndef) в тексте программы. Например:

1 #ifdef OUTPUT

2  Instruction(s) А

3 #else

4  Instruction(s) B

5 #endif

Если переменная с именем OUTPUT была определена в тексте программы до строки 1 с директивой #ifdef, то группа инструкций Instruction(s) А будет включена исполняемый код программы. В противном случае в конечный вариант программы будет включена группа инструкций Instruction(s) B.

Другой пример:

1 #ifndef OUTPUT

2  Instruction(s) А

3 #else

4  Instruction(s) B

5 #endif

Если переменная с именем OUTPUT не была определена в тексте программы до строки 1 с директивой #ifndef, то в конечный вариант программы будет включена группа инструкций Instruction(s) А. Если же эта переменная была определена ранее, то исполняемый код программы будет включена группа инструкций Instruction(s) B.

Директива #define используется в двух случаях. Во первых, она позволяет задать численные значения для символьных констант. Например, константе с именем HIGH необходимо присвоить значение 98:

#define HIGH 98

После записи этого выражения, если в тексте программы будет использовано имя HIGH, то при компиляции оно будет заменяться числом 98. Это удобно, поскольку в тексте программы имя HIGH может быть упомянуто сколь угодно большое число раз. Но для изменения его численного значения понадобится внести изменения только в одну строку с директивой #define.

Во вторых, директива #define используется для определения макросов. Макрос — это набор выражений языка Си, которому поставлено в соответствие определенное имя. При записи этого имени в программе, компилятор произведет замену этого имени обозначенным набором выражений. Например, Вам необходимо разрешить прерывания в МК. Для этого в МК 68HC12 используется команда ассемблера CLI. Для ее записи в тексте программы на Си определяют макрос:

#define CLI() asm("cli\n"); //разрешить маскируемые прерывания

Далее в программе используют только имя макроса:

CLI();

Кроме директивы определения символа или макроса #define, существует директива обратного действия #undef. Приведем пример ее использования:

#define VALUE 10

int number[VALUE];

#undef VALUE

В этом примере мы сначала назначили переменной VALUE значение 10. Далее в строке 2 мы воспользовались этим значением, чтобы определить массив целых чисел из 10 элементов. Далее переменная VALUE нам не нужна. И мы отменили ее определение директивой #undef.

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

#include <stdio.h>

Символы <> указывают на определенное место расположение файла stdio.h в папках директории компилятора.

Назначение директивы #error — упрощение процесса отладки разрабатываемой программы. Вы можете записать следующее выражение:

#error Programm made a logic error

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

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

Функции директивы #pragma определяются конкретным типом используемого компилятора. Для компилятора ICC12 эта директива определения сегментов данных и программы в исходном тексте программы на Си, для объявления подпрограмм прерывания, а также для присвоения желаемых значений ячейкам памяти с фиксированными адресами. Последнее позволяет инициализировать таблицу векторов прерываний в микроконтроллерах. Приведенный ниже пример демонстрирует использование директивы #pragma для объявления подпрограммы с именем TOISR в качестве подпрограммы прерывания:

#pragma interrupt_handler TOISR()

void TOISR(void);

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

Директива #pragma также используется для задания начального адреса расположения в памяти сегментов программного кода или кодов данных. Запишем вектор прерывания для подпрограммы TOISR в таблицу векторов прерывания МК. Мы знаем, что в соответствие с картой памяти МК, вектор прерывания по переполнению таймера должен располагаться по адресу 0x0B1E. Следующая запись помещает адрес начала подпрограммы TOISR в две ячейки памяти, начиная с адреса 0x0B1E:

#pragma abs_adress:0xB1E

void (*Timer_Overflow_interrupt_vector[])() = {TOISR};

#pragma end _abs_adress

Более подробно оформление подпрограмм прерывания мы обсудим в главе 4.

3.7. Конструкции программирования

 Сделать закладку на этом месте книги

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

3.8. Операторы для организации программных циклов

 Сделать закладку на этом месте книги

В языке Си существует несколько операторов, которые позволяют реализовать циклические вычисления (итерации). В этом параграфе мы рассмотрим программные конструкции циклов с операторами for, while, do while.

3.8.1. Оператор FOR

 Сделать закладку на этом месте книги

Оператор for предназначен для реализации циклов со счетчиком. В операторе for могут автоматически реализоваться сразу три операции: инициализация счётчика цикла, проверка его значения и модификация. Синтаксис оператора for:

for (<выражение1>; <выражение2>; <выражение3>)

 <операторы тела цикла>

Рассмотрим типичный пример реализации цикла с оператором for:

1 for(i = 0; i < 10; i = i++)

2 {

3  inst 1;

4  inst 2;

5  :

6  :

7  inst n;

8 }

В строке 1 записывается сам оператор for, за которым обязательно следуют три выражения, заключенные в круглые скобки. Выражение 1 вычисляется один и только один раз перед проверкой условия цикла. В нашем примере выражение 1 присваивает начальное значение переменной i. Выражения два и три могут иметь произвольный характер, но обычно их используют для проверки и модификации условия продолжения цикла. Выражение 2 задаёт условие продолжения цикла. Если его значение отлично от нуля (истина), будут выполнены операторы 3…7, составляющие тело цикла. После этого вычисляется выражение 3, указанное в скобках первой строки. В нашем примере выражение i = i++ = i + 1 осуществляет увеличение на 1 внутреннего счетчика циклов оператора for. Поэтому операторы тела цикла 3…7 будут выполняться 10 раз при значениях переменной цикла i от 0 до 9. В конце первого цикла значение i будет равно 1, в конце второго — i=2, и т.д. В конце десятого цикла переменная i примет значение 10. Далее начнется исполнение 11-ого цикла оператора for, но, проанализировав условие выражения 2 оператора for, программа выйдет из цикла, не исполняя операторов тела цикла.

Достаточно часто переменная счетчика циклов оператора for используется также в теле цикла этого оператора. Например, следующий программный фрагмент вычисляет таблицу соответствия значений температуры, записанных по шкале Цельсия и по шкале Фаренгейта, и последовательно выводит эти значения на экран монитора. Диапазон исходных значений температуры составляет от –10°C до +40°C.

1 for(k = –10; k <= 40; k++)

2 {

   //преобразовать значения температуры, измеренные по шкале Цельсия

   // к численному значению по шкале Фаренгейта

3  Temperature = k*9/5+32;

4  printf("Current temperature is \%f\n", Temperature);

5 }

Как видите, значение


убрать рекламу






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

3.8.2. Оператор WHILE

 Сделать закладку на этом месте книги

Второй способ организации циклов использует оператор while. Применение оператора while иллюстрирует следующий программный фрагмент:

1 k = -10;

2 while(k < 40)

3 {

4  Temperature = k*9/5+32;

5  k++;

6  printf("Current temperature is \%f\n", Temperature);

7 }

В отличие от оператора for, переменная k, используемая в качестве счетчика циклов, должна быть инициализирована перед оператором while, например, в строке 1. Обратите внимание, что в строке 2 в скобках оператора while записано всего лишь одно выражение, которое называется условием цикла. Выполнение оператора while начинается с вычисления этого выражения. Если значение выражения отлично от нуля («истина»), то выполняются операторы 4…6 тела цикла. После выполнения операторов тела цикла снова вычисляется выражение условия и процесс повторяется. Таким образом, выполнение тела цикла происходит пока значение выражения условия цикла отлично от нуля («истина»).

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

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

1 while (1)

2 {

3  Instructions //выполнение блока операторов

4 }

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

3.8.3. Оператор DO-WHILE

 Сделать закладку на этом месте книги

Третий способ организации циклов в Си использует оператор do-while. Синтаксис оператора do-while:

do {

 <операторы тела цикла>

} while (выражение 1);

Пример записи вычисления таблицы соответствия температур с использованием оператора do while приведен ниже:

1 k = -10;

2 do

3 {

4  Temperature = k*9/5+32;

5  k++;

6  printf("Current temperature is \%f\n", Temperature);

7 }

8 while (k < 40)

Оператор do продолжает циклическое исполнение операторов тела цикла 4…6 до тех пор, пока значение выражения 1 не станет равным нулю («ложным»). Оператор do while похож на оператор while, но условие цикла в нём вычисляется и проверяется после очередного исполнения операторов тела цикла. Таким образом, операторы тела цикла выполняются, по крайней мере, один раз, даже если условие цикла заведомо ложно.

3.9. Операторы принятия решения

 Сделать закладку на этом месте книги

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

3.9.1. Оператор IF

 Сделать закладку на этом месте книги

Оператор if — это оператор выбора. Синтаксис оператора if:

if (<выражение>) {

 <оператор 1>

} else {

 <оператор 2>

}

Работа оператора if заключается в следующем. Сначала вычисляется заключенное в скобки выражение. Если его значение оказалось отличным от нуля («истина»), то выполняется оператор 1. Если используется служебное слово else и значение выражения равно нулю («ложь»), то выполняется оператор 2, указанный после else. Если значение выражения равно нулю («ложь»), а служебное слово else не указано, управление передаётся следующему за if оператору программы.

1 if (input == 0x00)

2 {

3  output = 0x0F;

4 }

5 …………………

В этом примере переменная input проверяется на равенство 0. Если текущее значение этой переменной действительно равно 0, то выполняется оператор, записанный в строке 3. Служебное слово else в данном примере отсутствует, поэтому, если текущее значение переменной input не равно 0, то программа осуществляет переход к строке 5. В качестве первого и второго операторов в условном операторе if можно применять блоки операторов. Приведенный выше пример может быть записан в сокращенной форме, без выделения фигурными скобками блока операторов условно выполняемых операторов:

1 if (input == 0x00)

2  output = 0x0F;

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

1 if (1)

2  output = 0x0F;

Понятно, что действие output = 0x0F будет выполняться всегда, что иногда полезно на этапе отладки программы.

3.9.2. Оператор IF-ELSE

 Сделать закладку на этом месте книги

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

1 if (input > 78) // если температура по шкале Фаренгейта

                  //больше 78

2  air_condision = on; // то включить кондиционер

3 else

4  air_condision = off; //иначе выключить кондиционер

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

1 if (input <= 78) //если температура меньше или равна 78

2  air_condision = off; //то выключить кондиционер

3 else

4  air_condision = on; //иначе включить кондиционер

3.9.3. Оператор IF-ELSE IF-ELSE

 Сделать закладку на этом месте книги

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

1 if (input > 78)

2  air_condision = on; //включить кондиционер, если жарко

3 else

4  if (input > 58)

5   fan = on; //включить вентилятор,если душно, но

              //не жарко

6  else

7   heater = on; //включить обогреватель, если прохладно

8 …………

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

Те же управляющие действия могут быть записаны с применением другой конструкции операторов if-else:

1 if (input > 78)

2  air_condision = on; //включить кондиционер, если жарко

3 if (input > 58)

5  fan = on; //включить вентилятор,если душно и жарко

6 else

7  heater = on; //включить обогреватель, если прохладно

Отличие этого варианта программы от предыдущего состоит в том, что оба оператора if–else стали независимыми друг от друга. А в предыдущем примере второй оператор if– else был вложен в первый. Это конструктивное изменение программы внесло коррективы в реализуемый ею алгоритм управления. Так в первом варианте при значении переменной input=80 выражение первого оператора if окажется истинным и будет включен кондиционер. И далее управление будет передано строке 8, т.е. вторая конструкция if будет пропущена из рассмотрения. Во втором случае при том же значении переменной input=80 после проверки первого условия будет также включен кондиционер, но затем управление будет передано второму оператору if. Поскольку второе условие также выполняется, то вентилятор будет также включен.

Еще один вариант реализации того же задачи:

1 if (input > 78)

2  air_condision = on; //включить кондиционер, если жарко

3 if ((input > 58) && (input < 79))

5  fan = on; //включить вентилятор,если душно, но не жарко

6 if (input < 59)

7  heater = on; //включить обогреватель, если прохладно

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

1 if (condition 1)

2  (instruction set 1);

3 if (condition 2)

5  (instruction set 2);

6 if (condition 3)

7  (instruction set 3);

Если число различных значений переменной условия condition превышает 4 или 5, то для выполнения подобной задачи следует использовать оператор switch.

3.9.4. Оператор SWITCH

 Сделать закладку на этом месте книги

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

1  switch(<выражение>)

2  {

3  case <константное_выражение_1>:

4   <оператор_1>;

5   break;

6  case <константное_выражение_2>:

7   <оператор_2>;

8   break;

9   :

10  :

11 case <константное_выражение_n>:

12  <оператор_n>;

13  break;

14 default :

15  <оператор_n+1>;

16 }

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

Приведем пример использования конструкции с оператором switch:

1  switch (a) {

2  case 1:

3   printf("Correct value%d was chosen\n", a);

4   break;

5  case 2:

6   printf("Close but try again\n");

7   break;

8  case 3:

9   printf("Value %d is two away from the answer\n", a);

10  break;

11 default:

12  printf("Your chosen value is way off\n");

13 }

В примере текущее значение переменной a сравнивается со значениями 1, 2 и 3. Желаемое сообщение о правильном выборе появится на экране монитора в том случае, если переменная равна 1. Если же переменная равна 2 или 3, то будут выведены соответствующие сообщения об ошибках. Если ни одно из трех возможных значений не выбрано, то отобразится сообщение, записанное в строке 12. Обратите внимание, в примере мы не должны записывать слово break в строке 13, т.к. после выполнения оператора строки 12 программа автоматически продолжит исполнение следующих за конструкцией switch операторов.

А как будет вести себя программа, если мы пропустим слово break где то в середине конструкции switch, например, в строке 4? После отображения сообщения строки 3 программа перейдет к исполнению следующих операторов, пока не встретит следующее слово break или не дойдет до конца конструкции switch. В нашем случае программа отобразит сообщение строки 6, а затем предаст управление строке 13. Зная подобную особенность оператора switch, Вы можете пропустить несколько break в своей программе.

3.10. Массивы

 Сделать закладку на этом месте книги

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

int list[10];

Данное определение зарезервирует в памяти МК 20 однобайтовых ячеек памяти. В выражениях программы доступ к каждому элементу массива возможен с использованием индекса. Индекс в Си автоматически отсчитывается с 0. Поэтому в нашем примере индекс может принимать значения от 0 до 9 включительно. Как и любая другая переменная, массив может быть объявлен с одновременной инициализацией его значений. Для этого в правой части операции присваивания «=» в фигурных скобках, через запятую перечисляются значения всех элементов массива:

int list[10] = {1,2,3,4,5,6,7,8,9,10};

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

int list[] = {1,2,3,4,5,6,7,8,9,10}; // Размер массива будет равен

 //числу проинициализированных переменных т.е. 10

Также можно инициализировать произвольное число первых элементов массива с указанным размером:

int list[10]= {1,2,3,4,5,}; // Инициализация первых пяти элементов

 //массива, состоящего из 10 элементов

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

char message[6]= "Smile";

char message[]= "Smile";

Первый элемент массива message[0] содержит код символа «S», последний элемент message[5] — код конца строки 0x00.

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

int matrix[2],[3];

По аналогии с одномерными массивами, для многомерных массивов возможна инициализация в процессе его определения:

int matrix[2],[3]= {1,2,3}{4,5,6};

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

m[0][0] m[0][1] m[0][2] m[1][0] m[1][1] m[1][2]

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

m = matrix[1][2]

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

for (i=0, i<100, i++) odd[i] = odd[i] + 1;

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

3.11. Указатели

 Сделать закладку на этом месте книги

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

Для определения переменной указателя используется оператор *:

int *ptr

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

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

1 void main(void)

2 {

3  char *ptr;

4  static char message[] = "What a wonderful day!";

5  ptr = message;

6  printf("%s\n", ptr);

7 }

В этом примере переменная ptr была определена как указатель для однобайтовой переменной типа char. Поэтому переменная ptr должна содержать 16 разрядный адрес однобайтовой переменной. В строке 4 примера был определен и инициализирован массив однобайтовых переменных message. Этот массив содержит 22 элемента: 21 символ в кодах ASCII и один байт признака конца строки. Выражение в строке 5 имеет своей целью запись в переменную ptr начального адреса массива message, т.е. адреса символа «W». Выражение, записанное в строке 6, должно начать вывод на экран монитора символа, на который указывает содержимое переменной указателя ptr. В строке 5 данного примера может быть записано другое, более понятное выражение:

ptr = &message[0];

В этом выражении символ «&» выполняет операцию взятия адреса первого элемента массива message. И именно эта функция была реализована нами в строке 5 исходного примера.

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

void main(void) {

 static char message[] = "What a wonderful day!";

 int i;

 for (i=0; i<21; i++) putchar(message[i]);

}

Обратите внимание, что в данном примере внутренняя переменная цикла i принимает значения от 0 до 20 включительно, выводя при этом на экран 21 символ. Приведенный способ реализации задачи вывода на экран строки символов обладает одним существенным недостатком. При смене числа символов в записи, выводимой на экран, придется написать новый фрагмент кода. Указанный недостаток исправлен в следующем программном фрагменте:

void main(void) {

 char *ptr;

 static char message[] = "What a wonderful day!";

 ptr = message;

 while(*ptr != '\0') {

  putchar(*ptr);

  ptr++;

 }

}

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

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

#define PORTA *(volatile unsigned char *) 0x1000

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

DDRA = 0x00; //инициализировать порт PORTA на ввод

new_value = PORTA; //читать содержимое регистра данных PORTA в

                   //переменную new_value

3.12. Структуры

 Сделать закладку на этом месте книги

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

Структура — это объект, состоящий из данных различных типов. При использовании структур следует различать объявление (или описание) структуры, как нового типа данных, например тип данных «структура x», от фактического определения некоторой переменной с типом данных «структура x». Пример объявления структуры типа car:

struct car {

 int doors;

 char color[10];

 char *maker;

 int num_cyl;

 int year;

}

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

Анализируя приведенную запись, отметим, что имя car — это имя нового типа данных. Не следует путать его с именем переменных типа car, которые далее будут определены в программе:

struct car your_car;

struct car my_car;

struct car his_car;

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

Каждый элемент структуры имеет свое собственное имя: doors, color, maker и т.д. Допускается обращение к каждому элементу структуры с использованием его имени:

your_car.doors = 4;

Если переменная типа структура передается в качестве параметра в какую либо функцию, то следует помнить, что передаются не сами элементы структуры, а лишь указатель на первый элемент названной структуры. Поэтому при обращении внутри функции к отдельным элементам структуры следует вместо оператора «.» использовать оператор «–>». Например, в программе определяется функция assign_doornumber, которая присваивает численное значение первому элементу структуры типа car:

void assign_doornumber(struct car *some_car);

:

:

;

assign_doornumber(&your_car)<


убрать рекламу






/code>

:

:

void assign_doornumber(struct car *some_car) {

 some_car–>doors = 4;

 return 0;

}

А сейчас мы обсудим, как создать массив структур. Допустим, что мы уже определили структуру circuit_board как новый тип данных:

struct circuit_board {

 int transistor;

 int bus;

 int serial_port;

 int parallel_port;

}

Создадим теперь массив new_board с пятью элементами, каждый из которых является структурой типа circuit_board:

struct circuit_board new_board[5];

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

new_board[2].transistor = 100;

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

3.13. Процесс программирования и отладки микропроцессорной системы

 Сделать закладку на этом месте книги

В данном разделе мы обсудим технологию создания и отладки прикладной программы в микроконтроллерных системах. Сначала рассмотрим процесс создания исходного текста управляющей программы и его превращение в файл исполняемого кода (ехеcutable file).

3.13.1. Технология создания программного кода

 Сделать закладку на этом месте книги

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

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

Напомнив Вам основные моменты структурного подхода к процессу написания исходного кода и его отладке, рассмотрим процесс превращения файла исходного кода на Си в файл исполняемого кода для определенного типа микроконтроллера. Мы рассмотрим эту технологию с использованием интегрированной среды разработки ICC12 версии 6.12B от компании ImageCraft. Если Вы используете программную среду разработки от другого производителя, то этот материал не будет для Вас бесполезным, поскольку принципы преобразования кодов в процессе создания исполняемого модуля прикладной программы одинаковы для всех аналогичных программных продуктов.



Рис. 3.1. Интерфейс пользователя интегрированной среды разработки ICC12


На рис. 3.1 представлен интерфейс пользователя (картинка на экране монитора), возникающая при запуске среды ICC12. Большое пустое окно в центре экрана предназначено для ввода и редактирования исходного текста программы на Си. Окно меньшего размера в правой части экрана — окно менеджера проектов. Оно предназначено для отображения списка всех используемых в текущем проекте файлов. Окно состояния в нижней части экрана предназначено для отображения текущей информации о режимах работы и состоянии обрабатываемых в среде файлов. В этом окне будут выводиться сообщения об ошибках, возникающих при работе программ компилятора, Ассемблера, линковщика и загрузчика/программатора в процессе обработки файлов текущего проекта. Теоретически, для ввода и редактирования файлов исходного текста программ могут быть использованы любые текстовые редакторы, однако программные продукты класса «интегрированная среда разработки» обязательно содержат собственный редактор текста, которым и следует воспользоваться. Пакет ICC12, как и любая другая интегрированная среда разработки, предоставляет программисту удобный интерфейс пользователя для работы с встроенными в среду программами компилятора, Ассемблера, линковщика, загрузчика и программатора. Каждая из программ может быть запущена на исполнение, как из контекстного меню, так и с помощью кнопок на панели управления. На рис. 3.2 показан интерфейс пользователя среды ICC12 с текстом программы в окне редактирования и сообщениями о результатах ее компиляции в окне состояния.



Рис. 3.2. Интерфейс пользователя интегрированной среды разработки ICC12

В окне редактирования загружен файл исходного текста программы на Си. 

В окне состояния сообщение об успешной компиляции этого файла.


После того, как исходный текст программы написан и находится в окне редактирования, файл программы должен быть обработан препроцессором компилятора Си. Препроцессор – это часть программы компилятора, которая анализирует выражения в исходном тексте, которые начинаются с символа «#». Вспомните, с этого символа начинаются директивы подключения заголовочных файлов, директивы условной компиляции и директивы для объявления подпрограмм прерывания. Если препроцессор не зафиксировал синтаксических ошибок, то вступает в работу синтаксический анализатор и генератор ассемблерного текста компилятора Си. В результате, после обработки компилятором исходного текста программы на Си, будет получен текст исходной программы на языке Ассемблера для данного типа МК. В нашем случае это МК семейства 68HC12. Сгенерированный компилятором текст будет содержать как мнемоники команд ассемблера МК данного семейства, так и псевдокоманды и директивы для программы Ассемблер в составе пакета ICC12. Смысловые названия и шаблоны имен входных и выходных файлов компилятора Си для среды ICC12 приведены на рис. 3.3. Программы компиляторов, которые способны генерировать инструкции языка ассемблера для процессорного ядра, отличающегося (т.е. программно несовместимо) от ядра, на котором программа компилятора исполняется, называют кросс-компилятора ми. Так в нашем случае программа кросс-компилятора, исполняемая на персональном компьютере, генерирует ассемблерный текст для МК 68HC12.



Рис. 3.3. Последовательность работы программ в процессе генерации файла исполняемого кода прикладной программы


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

Полученный после обработки программой компилятора файл прикладной программы далее обрабатывается программой Ассемблер. Эта программа преобразует файл программы в файл объектного кода с расширением «o» (см. рис. 3.3).

В соответствие с методом системного проектирования, разрабатываемая прикладная программа должна состоять из нескольких файлов, каждый из которых содержит отдельный модуль программы. Часть этих модулей может быть разработана и отлажена в составе другого проекта, и поэтому не требует повторной компиляции. В этом случае для создания конечного варианта разрабатываемой программы необходимо объединить в один файл ранее полученные объектные файлы модулей и вновь разработанные, прошедшие обработку компилятором и Ассемблером файлы. Для объединения нескольких объектных модулей в один файл исполняемого кода используется программа линковщика. Линковщик генерирует три типа файлов с расширениями «s19», «map» и «lst». Файл карты памяти «xxx.map» содержит в себе информацию о расположении кодов прикладной программы в адресном пространстве МК. Файл листинга «xxx.lst» отражает процесс перевода мнемоник команд ассемблера в машинные коды. Файл в формате «s19» именуют файлом исполняемого кода или загрузочным модулем, поскольку именно этот файл заносится в постоянную память МК и исполняется им в процессе управления проектируемым устройством. Таким образом, в результате работы специальных программ в составе пакета интегрированной среды разработки, один или несколько файлов на Си были обработаны программами компилятора, Ассемблера и линковщика с целью получения одного исполняемого на выбранном типе МК файла машинных кодов прикладной программы.

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

Программа менеджера проектов считается основной в составе IDE, поскольку она управляет доступом пользователя и взаимодействием с обрабатываемыми файлами всех остальных программ пакета интегрированной среды разработки и отладки программного обеспечения (ПО) микропроцессорных систем. Кроме используемого в книге пакета ICC12, для создания прикладного ПО микроконтроллеров семейства 68HC12 могут также использоваться другие аналогичные пакеты, например CodeWarrior компании Metrowerks.

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



Рис. 3.4. Форматы представления прикладной программы на разных этапах создания файла исполняемого кода

3.13.2. Режим отладки BDM

 Сделать закладку на этом месте книги

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

В МК семейства 68HC12 реализован иной, более совершенный режим отладки BDM (Background Debug Mode), что в переводе означает «фоновый режим отладки». Этот режим позволяет выполнить основные процедуры отладки — просмотр и модификацию содержимого регистров и ячеек памяти без останова выполнения прикладной программы.

В процессе отладки МК обменивается данными с персональным компьютером, используя последовательный интерфейс с оригинальным протоколом. Для подключения микроконтроллера, который установлен на плате проектируемого устройства, к персональному компьютеру разработан унифицированный интерфейс, который носит название «BDM порт» (рис. 3.5). Стандартизация линий связи и типа разъема интерфейса отладки BDM позволяет разрабатывать универсальные программные пакеты и аппаратные средства отладки так, что любая аппаратная платформа на основе МК семейства 68HC12, в том числе и плата собственной разработки, способна работать под управлением любой интегрированной среды разработки для 68HC12/HCS12.



Рис. 3.5. Цоколевка разъема BDM порта


Используя порт BDM, встроенный в МК блок отладки принимает от персонального компьютера команды отладки и возвращает в персональный компьютер запрашиваемые данные. Часть команд отладки может выполняться только аппаратными средствами блока BDM, без остановки выполнения прикладной программы. При этом используются «холостые» машинные циклы внутренних магистралей, когда исполняемая прикладная программа не производит обращения к памяти. Если такие «холостые» циклы не возникают в течение 128 машинных циклов, то блок BDM захватывает последующие циклы для выполнения поступившей команды отладки. При этом выполнение прикладной программы слегка притормаживается. Обсуждаемые так называемые аппаратные команды отладки могут поступать в блок BDM от персонального компьютера не чаще, чем 1 раз в 150 машинных циклов. Перечень аппаратных команд отладки представлен в табл. 3.3. В табл. 3.4. дано описание этих команд.

№ команды Имя команды Код операции Данные
1 BACKGROUND 90 – (нет)
2 READ_BD_BYTE E4 16 бит адреса, 16 бит данных (вывод)
3 STATUS E4 FF01, 00000000 (вывод)
4     FF01, 10000000 (вывод)
5     FF01, 110000000 (вывод)
6 READ_BD_WORD EC 16 бит адреса, 16 бит данных (вывод)
7 READ_BYTE E0 16 бит адреса, 16 бит данных (вывод)
8 READ_WORD E8 16 бит адреса, 16 бит данных (вывод)
9 WRITE_BD_BYTE C4 16 бит адреса, 16 бит данных (ввод)
10 ENABLE_FIRMWARE C4 FF01, 1xxxxxxx (ввод)
11 WRITE_BD_ WORD CC 16 бит адреса, 16 бит данных (ввод)
12 WRITE_BYTE C0 16 бит адреса, 16 бит данных (ввод)
13 WRITE_ WORD C8 16 бит адреса, 16 бит данных (ввод)

Табл. 3.3. Команды отладки, исполняемые аппаратными средствами модуля отладки BDM


№ команды по табл.3.3 Описание команды
1 Ввод в режим отладки с использованием монитора BDM
2 Чтение байта из области памяти блока BDM. Адрес указан в команде. Если адрес четный, то искомый байт содержится в старшем байте возвращаемого 16-ти разрядного слова. Если адрес нечетный, то искомый байт в младшем байте 16-разрядного слова.
3 Частный случай команды READ_BD_BYTE. Производится чтение регистра состояния модуля BDM. Считанный код 00000000 означает, что МК не может быть переведен в режим отладки и работает только под управлением прикладной программы.
4 Частный случай команды READ_BD_BYTE. Производится чтение регистра состояния модуля BDM. Считанный код 10000000 означает, что режим отладки разрешен и МК может быть переведен в режим отладки инструкцией BACKGROUND из табл. 3.3.
5 Частный случай команды READ_BD_BYTE. Производится чтение регистра состояния модуля BDM. Считанный код 11000000 означает, что МК находится в режиме отладки.
6 Чтение 16 разрядного слова из области памяти блока BDM по указанному в команде адресу. Адрес должен быть четным и указывать на старший байт возвращаемого из МК слова.
7 Чтение байта из области памяти МК. Адрес указан в команде. Если адрес четный, то искомый байт содержится в старшем байте возвращаемого 16-тиразрядного слова. Если адрес нечетный, то искомый байт в младшем байте 16 разрядного слова.
8 Чтение слова из области памяти МК по указанному в команде адресу. Адрес должен быть четным и указывать на старший байт возвращаемого из МК слова.
9 Запись байта в область памяти блока BDM. Если в команде указан четный адрес, то байт для записи содержится в старшем байте передаваемого 16-тиразрядного слова. Если адрес нечетный, то байт для записи — в младшем байте 16 разрядного слова.
10 Частный случай команды WRITE_BD_BYTE. Производится запись в регистр состояния STATUS модуля BDM. Передаваемый в регистр состояния код 1xxxxxxx разрешает работу программно аппаратных средств модуля отладки BDM. Для перевода МК в режим отладки необходимо далее подать команду BACKGROUND из табл. 3.3.
11 Запись слова в область памяти блока BDM по указанному в команде адресу. Адрес должен быть четным и указывать на старший байт передаваемого в память BDM слова.
12 Запись байта в область памяти МК. Если в команде указан четный адрес, то байт для записи содержится в старшем байте передаваемого 16-ти разрядного слова. Если адрес нечетный, то байт для записи — в младшем байте 16-разрядного слова.
13 Запись слова в область памяти МК по указанному в команде адресу. Адрес должен быть четным и указывать на старший байт передаваемого в память МК слова.

Табл. 3.4. Описание аппаратных команд модуля отладки BDM


Другая часть команд отладки исполняется под управлением программы монитора отладки, которая хранится в ПЗУ модуля BDM. Это ПЗУ располагается в общем адресном пространстве МК по адресам 0xFF00…0xFFFF. Память блока BDM доступна только в режиме отладки. В рабочем режиме ячейки памяти с этими адресами используются для других целей, в частности для размещения векторов прерываний. Перечень команд, исполняемых монитором отладки, представлен в табл. 3.5.

Имя команды Код операции Данные Описание
GO 08 Исполнять прикладную программу
10 ТRAСЕ1 Выполнить одну команду прикладной программы и вернуться в монитор отладки
18 TAGGO Разрешить режим отладки и вернуться к исполнению прикладной программы
WRITE_NEXT 42 16 бит данных (ввод) X=X+2. Записать следующее слово по 0,X
WRITE_PC 43 16 бит данных (ввод) Записать данные в счетчик команд
WRITE_D 44 16 бит данных (ввод) Записать данные в аккумулятор D
WRITE_X 45 16 бит данных (ввод) Записать данные в регистр X
WRITE_Y 46 16 бит данных (ввод) Записать данные в регистр Y
WRITE_SP 47 16 бит данных (ввод) Записать данные в указатель стека
READ_NEXT 62 16 бит данных (вывод) X=X+2. Читать следующее слово по 0,X
READ_PC 63 16 бит данных (вывод) Читать счетчик команд
READ_D 64 16 бит данных (вывод) Читать аккумулятор D
READ_X 65 16 бит данных (вывод) Читать регистр X
READ_Y 66 16 бит данных (вывод) Читать регистр Y
READ_SP 67 16 бит данных (вывод) Читать указатель стека 

Табл. 3.5. Команды отладки, исполняемые монитором BDM


Для того, чтобы использование команд монитора отладки стало возможным, необходимо сначала установить бит ENBDM в регистре состояния STATUS (0xFF01), а затем выполнить команду BACKGROUND. Формат регистра состояния STATUS представлен на рис. 3.6.



Рис. 3.6. Формат регистра состояния модуля отладки ВDМ


Запись бита разрешения работы монитора отладки ENBDM осуществляется командой ENABLE_FIRMWARE из перечня аппаратных команд BDM (табл. 3.3). Отметим, что если МК 68HC12B32 сконфигурирован для работы в однокристальном режиме, то во время сброса бит ENBDM устанавливается в 1. Аппаратная команда отладки BACKGROUND также передается из персонального компьютера. Эта команда переводит МК в режим работы под управлением монитора отладки, когда центральный процессор на время прекращает выполнение основной программы и реализует команды монитора отладки. Для выполнения команд монитора отладки модуль BDM анализирует состояние внутренних магистралей МК. Если команда монитора требует для реализации только один машинный цикл, то работа прикладной программы не нарушается. Если же монитору необходимо несколько циклов, то работа процессора приостанавливается до завершения выполнения отладочной команды.

В области памяти модуля BDM расположены пять служебных регистров (табл. 3.6). Регистр INSTRUCTION хранит переданный из персонального компьютера код исполняемой команды отладки.

Адрес Имя регистра
0xFF00 INSTRUCTION — регистр кода выполняемой команды BDM
0xFF01 STATUS — регистр состояния блока BDM
0xFF02–0xFF03 SHIFTER — данные, передаваемые блоком BDM
0xFF04–0x
убрать рекламу






FF05
ADDRESS — адрес регистра или ячейки памяти BDM
0xFF06 CCRSAV — содержимое регистра признаков CCR

Табл. 3.6. Регистры модуля отладки BDM


Регистр состояния STATUS (рис. 3.6) отражает текущий режим работы модуля BDM. Бит ENBDM установлен, если работа программы монитора отладки разрешена, т.е. могут реализовываться не только аппаратные, но и программно исполняемые команды отладки. Установленный в 1 бит BDMACT показывает, что МК прекратил выполнение прикладной программы и ожидает поступления команды отладки. Бит ENTAG отражает перевод МК в специальный режим тегирования команд. Этот режим устанавливается после исполнения команды TAGGO монитора отладки (табл. 3.5). Бит SDV является служебным битом монитора отладки, он отражает наличие данных в регистре SHIFTER блока BDM. И, наконец, бит TRACE — это признак работы МК в режиме трассировки, который назначается после исполнения инструкции TRACE1 из списка табл. 3.5.

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

Регистр ADDRESS хранит принятый в команде отладки адрес регистра или ячейки памяти. В регистре CCRSAV сохраняется состояние регистра признаков CCR центрального процессора во время исполнения команд монитора отладки.

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

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

3.13.3. Аппаратные и программные средства отладчика P&E от компании PEMICRO

 Сделать закладку на этом месте книги

В данном параграфе представлены краткие сведения об аппаратных и программных средствах отладки для МК семейства 68HC12, которые используют порт модуля BDM для связи с микроконтроллером. Мы остановимся на описании возможных режимов отладки с использованием пакета внутрисхемного отладчика ICD12Z в составе интегрированной среды разработки WinIDE Pemicro HC12. Отладчики от других производителей работают схожим образом. Используя набок предоставляемых команд отладки, пользователь может обнаружить и зафиксировать ошибки в исполнении программы. Набор команд отладки приведен в табл. 3.7 и 3.8.

Имя команды Описание
А или АСС Установить значение аккумулятора А
B Установить значение аккумулятора В
BR Установить контрольную точку
CCR Установить значение регистра признаков
CLEARSYMBOL Очистить массив символов
CODE Показать дизассемблированный код в окне отладчика «Code window»
DASM Дизассемблировать инструкцию
DUMP Отобразить память в окне журнала отладки «Status window»
EXIT Выйти в DOS
G или GO Запустить программу на исполнение
GONEXT Выполнить, начиная с текущего состояния счетчика PC до начала следующего оператора 
GOTILROM Выполнить, начиная с текущего состояния счетчика PC до достижения указанного адреса в ПЗУ
HELP Показать справочную информацию
IX Установить значение индексного регистра X
LF или LOGFILE Открыть или закрыть файл журнала отладки
LOADALL Выполнить команды загрузки LOAD и LOADМAP
LOADV Выполнить команды загрузки LOAD и побайтового сравнения VERIFY
MACRO Выполнить файл макрокоманд
MACROSTART Начать запись файла макрокоманд
MD или MDx Отобразить содержимое ячеек памяти в окне «Memory window»
N Установить/сбросить бит знака N в регистре признаков CCR
REG Отобразить регистры центрального процессора в окне журнала отладки «Status window»
RTVAR Отобразить заданный адрес и содержимое ячейки с этим адресом в окне переменных «Variable window»
S Установить/сбросить бит S в регистре признаков CCR
SERIAL Установить параметры обмена для последовательного порта
SERIALON Открыть окно интерфейса связи с отладочной платформой
SS Выполнить один оператор программы на языке исходного текста
STEP or ST or Т Выполнить один оператор (команда пошаговой отладки)
STEPTIL Выполнять команду пошаговой отладки, начиная с текущего состояния счетчика PC до заданного адреса
Т [n] Выполнить заданное число n команд пошаговой отладки
ТRAСЕ Запустить программу на исполнение и включить режим трассировки
V Установить/сбросить бит переполнения V в регистре признаков CCR
VERIFY Сравнить содержимое памяти программ МК с кодами файла в формате S19
WHEREIS Отобразить код названного символа
Z Установить/сбросить бит нулевого результата Z в регистре признаков CCR

Табл.3.7. Команды интерфейса пользователя отладчика P&E


Имя команды Описание
ASM [add] Записать в память по заданному адресу код введенной команды
BELL Подать звуковой сигнал
BF Заполнить блок памяти константой
С Установить/сбросить бит нулевого переполнения C в регистре признаков CCR
CLEARMAP Очистить файл карты памяти
COLORS Изменение цветовой гаммы интерфейса пользователя
D Установить значение аккумулятора D
DUMP_TRACE Вывести содержимое памяти трассировки в окно «Debug window»
EVAL Вычислить выражение
FILL Заполнить блок памяти константой (аналог BF)
GOUNTIL Выполнить программу до указанного адреса
H Установить/сбросить бит дополнительного переноса H в регистре признаков CCR
I Установить/сбросить бит глобальной маски прерывания I в регистре признаков CCR
IY Установить значение индексного регистра Y
LOAD Загрузить файл в формате S19
LOADMAP Загрузить файл символьных имен *.map
LOAD_BIN Загрузить файл исполняемого кода с указанного в команде адреса
LPT1, LPT2, LPT3 Выбрать параллельный порт для обмена
МACROEND Остановить запись файла макрокоманд
МACS Вывести перечень макрокоманд
мм or МЕМ Изменить содержимое ячеек памяти
NOBR Сбросить все контрольные точки
QUIT Выход из программы
REM Добавить комментарии к файлу макрокоманд
RESET Имитировать сброс микроконтроллера
RUN Начать исполнение программы
SCRIPT Выполнить файл макрокоманд
SERIALOFF Закрыть окно интерфейса связи с отладочной платформой
SHOWTRACE Показать результаты трассировки
SOURCEPATH Указать имя и путь к файлу
STATUS Отобразить регистры центрального процессора в окне журнала отладки «Status window»
STEPFOR Выполнить по шагам до контрольной точки
SYMBOL Добавить символ в текущий список символьных имен
TIME Показать время исполнения программы
UPLOAD_SREC Обновить содержимое ячеек памяти на экране отладчика
VAR Показать значение переменной или ячейки памяти в окне переменных «Variable window»
VERSION Показать версию программного обеспечения
X Установить/сбросить бит X в регистре признаков CCR

Табл.3.8. Команды интерфейса пользователя отладчика P&E


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



Рис. 3.7. Система отладки на основе интерфейса BDM и платы микроконтроллером 68HC12B32




Рис. 3.8. Интерфейс пользователя отладчика P&E ICD12Z компании PEMICRO


Вы можете также организовать процесс отладки, используя другие аппаратные средства, например две платы MC68HC912B32EVB. На рис. 3.9. показана инсталляция аппаратных средств для этого случая. Одна из отладочных плат используется в качестве отладочного интерфейса BDM между персональным компьютером и платой, которая подлежит отладке. К плате MC68HC912B32EVB прилагается программное обеспечение — Motorola D-Bug12 монитор, который и будет использован для управления процессом отладки. Для того, чтобы воспользоваться таким режимом работы платы MC68HC912B32EVB, следует установить переключатели W3 и W4 платы в состояние 0 и 1 соответственно. Далее подсоединить кабель BDM от платы интерфейса к оставшейся плате MC68HC912B32EVB. Эта вторая плата будет платой целевой системы. Подключите источник питания к целевой системе. При этом плата интерфейса отладки будет питаться от этого же источника, используя BDM кабель. Теперь Вы можете использовать команды монитора отладки Motorola D-Bug12 для управления исполнением испытуемой прикладной программой.



Рис. 3.9. Система отладки на основе двух отладочных плат с микроконтроллером 68HC12B32

3.13.4. Эмуляторы

 Сделать закладку на этом месте книги

Другой способ отладки прикладной программы — использование программного пакета класса эмулятор, который изображает ход исполнения прикладной программы и при этом генерирует все аппаратные сигналы, которые были бы на выходе реального МК. Такие эмуляторы выпускают компании Noral и Hitex.

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

3.13.5. Логические анализаторы

 Сделать закладку на этом месте книги

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



Рис. 3.10. Логический анализатор фирмы Agilent Technologies


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

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

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

 Сделать закладку на этом месте книги

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

В представленном примере прикладная программа управляет светодиодами, подключенными к выходам порта PORTA микроконтроллера 68HC12B32. Периодически, по первому сигналу переполнения таймера светодиоды зажигаются, а последующему сигналу переполнения таймера эти светодиоды гасятся. Аппаратные средства, используемые для отладки этой задачи, представлены на рис. 3.11.



Рис. 3.11. Схема подключения светодиодов к микроконтроллеру 68HC912B32


/************************************************************/

/* Название: Sample.c                                       */

/* Описание: Эта программа производит включение             */

/* и выключение светодиодов с интервалом                    */

/* времени 1 с. Используется МК 68НС12ВЗ2                   */

/* Файл заголовка header содержит адреса всех               */

/* портов и регистров специальных функций                   */

/* Контроллер должен быть сконфигурирован                   */

/* для работы в однокристальном режиме                      */

/* Дата создания: May 15, 2004                              */

/* Авторы: Daniel Pack and Steve Barrett                    */

/************************************************************/

1 #include <68НС12ВЗ2.h>

2 /*****************************************************/

3 void TOIISR(void);

4 /*****************************************************/

5 #pragma interrupt_handler TOIISR() /* Объявление подпрограммы

6  прерывания по переполнению таймера*/

7 #pragma abs_address:0x0B1E /*задать адрес подпрограммы прерывания ISR */

8 void (* Timer_Overflow_interrupt_vector[])()={TOIISR}

9 #pragma end_abs_address

10 unsigned char second = 0x00;

11 void main (void)

12 {

13  TSCR=0x80; /*включить таймер*/

14  TMSK2=0x80; /*разрешить прерывания по таймеру*/

15  TFLG2=0x80; /*очистить флаг TOIF*/

16  DDRA=0xFF; /* настроить порт Port A на вывод*/

17  CLI(); /*разрешить прерывания*/

19  EXIT()

20 }

21

22 void TOIISR(void) /*подпрограмма прерывания*/

23 {

24  TFLG2=0x80; /*очистить флаг TOIF*/

25  second += 1; /*увеличить на 1 программный счетчик с именем second*/

26  if (second == 122)

27  {

28   PORTA = !PORTA; /*инвертировать порт PORT A*/

29   second = 0x00; /*обнулить программный счетчик*/

30  }

31 }

Обратите внимание! Каждая программа должна обязательно иметь заголовок, в котором прописаны: название программы, краткое описание реализуемого алгоритма, авторы и дата создания программы. Файл заголовка 68HC12B32.h содержит определения регистров специальных функций МК B32 и макроопределения для препроцессора компилятора. Номера строк в приведенном тексте программы при вводе исходного текста в редакторе интегрированной среды ICC12 не должны присутствовать. Это наше дополнение для удобства восприятия материала.

Разберем назначение отдельных элементов программы. В первой строке записана директива препроцессора компилятора #include, которая предписывает присоединить к программе заголовочный файл с именем 68НС12ВЗ2.h. Содержимое этого файла мы рассмотрим ниже. Строка 3 содержит объявление функции TOIISR как подпрограммы прерывания по переполнению таймера. Строки с пятой по девятую содержат директивы, которые назначают ячейку памяти с адресом 0x0B1E для размещения в ней адреса начала подпрограммы прерывания TOIISR. В строке 10 осуществляется определение и инициализация глобальной переменной с именем second, которая будет использоваться в качестве программного счетчика. Строки с одиннадцатой по двадцатую содержат текст основной программы, в которой происходит инициализация подсистемы таймера. Таймер запускается на счет, разрешаются прерывания по его переполнению. Обратите внимание, в строке 17 вызывается макрос разрешения прерывания, который был определен в заголовочном файле. Строка 18 содержит конструкцию бесконечного цикла, который обеспечивает выполнение пустых команд микроконтроллером, пока не поступит запрос на прерывание от таймера. В строке 19 записан макрос программного прерывания EXIT(), который также определен в заголовочной файле. В строке 22 начинается подпрограмма прерывания по таймеру. В ней сбрасывается флаг переполнения таймера (строка 24), а затем инкрементируется программный счетчик second (строка 25). Заметим, что период счета 16 разрядного счетчика таймера микроконтроллера 68HC12 при частоте шины 8 МГц составляет 8,19 мс. Поэтому для отсчета 1 с требуется 122 периода переполнения этого таймера. В строке 26 записана конструкция условия if. Выражения строк 28 и 29 будут исполняться, только если счетчик second достиг значения 122. Тогда код на линиях PORTA будет инвертирован, а содержимое программного счетчика обнулено.

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

1 #define _IO_BASE 0

2 #define _P(off) *(unsigned char volatile*) (_IO_BASE + off)

3 #define TSCR _Р(0х86)

4 #define TMSK2 _Р(0х8D)

5 #define TFLG2 _P(0x8F)

6 #define DDRA _Р(0х02)

7 #define PORTA _Р(0х00)

8 #define CLI() asm("cli\n")

9 #define EXIT() asm("swi\n")

Две первые строки приведенного фрагмента заголовочного файла используются для определения макроса _P с аргументом off. Обратите внимание на символ указателя в макросе. Все следующие выражения в строках с 3 по 7 определяют численные значения для символьных обозначений регистров специальных функций МК. Эти численные значения — адреса регистров в соответствии с картой памяти МК. Любое упоминание имен регистров в тексте программы связано с выполнением операций чтения или записи в эти регистры по их физическим адресам. Этим объясняется необходимость применения указателя в определении макроса _P(off). Две последние строки 8 и 9 являются примерами определения макросов.

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

1   .module interrupt.c

2   .area memory(abs)

3   .org 0xb1e

4  _Timer_Overflow_interrupt_vector::

5   .word _TOIISR

6   .area data

7  _second::

8   .blkb 1

9   .area idata

10 .byte 0

11 .area data

12  .area text _main::

14 ; void TOIISR(void);

15 ; #pragma interrupt_handler TOIISR() ;

16 ; #pragma abs_address:0x0B1E

17 ; void (*Timer_Overflow_interrupt_vector[]) ()={TOIISR};

18 ; #pragma end_abs_address ;

19 ; unsigned char second=0x00;

20 ;

21 ;void main(void)

22 ;{

23 ; TSCR=0x80;

24  ldab #128

25  stab 0х86

26 ; ТМSК2=0х80;

27  ldab #128

28  stab 0x8d

29 ; TFLG2=0x80;

30  ldab #128

31  stab 0x8f

32 ; DDRA=0xFF;

33  ldab #255

34  stab 0х2

35 ; CLI();

36  сli

37 L3: L4:

38  bra L3

39 X0:

40 ; while(1) {};

41 ; EXIT();

42  swi

43 ; }L2

44 .dbline 0

45 ; func end

46  rts

47 _TOIISR: :

48  void TOIISR(void)

49 ; {

50 ; TFLG2=0x80;

51  ldab #128

52  stab 0x8f

53 ; second + = 1;

54  ldab _second

55  clra

56  addd #1

57  stab _second

58 ; if(second = = 122)

59  ldab _second

60  cmpb #122

61  bne L7

62 ; {

63 ; PORTA = ~ PORTA;

64 ; vol

65  ldab 0

66  clra

67  coma

68  comb

69  stab 0

70 ; second = 0x00;

71  clr _second

72 ; }

73 L7:

убрать рекламу






e>

74 ; }

75 L6:

76 .dbline 0

77 ; func end

78  rti

Итак, мы видим текст после обработки кросс-компилятором, который содержит инструкции команд на языке ассемблера микроконтроллера 68HC12 и директивы языка Ассемблер в составе интегрированной среды разработки ICC12. Директивы программы Ассемблер — это специальные команды, которые осуществляют управления процессом генерации кодов команд для МК при обработке приведенного выше текста программой Ассемблер. В среде ICC12 директивы выделяются точкой перед их именем. Например: .area data или .byte 0. Разберем текст представленного файла.

В строке 1 записана директива Ассемблера, определяющая название программы. Директивы .area и .org генерируются при обработке строки 7 исходной программы на Си: #pragma abs_address:0x0B1E. Они устанавливают адрес ячейки памяти для записи адреса начала подпрограммы прерывания по переполнению таймера. Это адрес принято называть вектором прерывания. Для микроконтроллеров семейства 68HC12 ячейки памяти для хранения вектора прерывания от каждого источника запросов определены техническим описанием. В частности для МК модели 68HC12B32 в ячейке памяти с адресом 0x0B1E хранится вектор прерывания по переполнению таймера. Компилятор среды ICC12 добавляет символ подчеркивания перед именами идентификаторов исходного кода на Си (это имена переменных и функций). Это можно наблюдать в строках 4, 7 и 47. Два двоеточия после имени переменной отражают тот факт, что эти переменные доступны из всех программ, т.е. из текущей функции и из всех внешних функций. Директива .word в строке 5 производит запись адреса начала подпрограммы прерывания с именем TOIISR в ячейку памяти разрядностью в 2 байта. Директивы в строках с 7 по 11 выделяют память для хранения переменной second и инициализируют ее нулевым значением.

Начиная с линии 12 можно видеть сгенерированные кросс компилятором команды ассемблера микроконтроллера 68HC12, соответствующие основной программе. Заметьте, что все записи исходного текста на Си из основной программы перенесены в текст ассемблерной программы (строки с 13 по 23), но перед ними установлен символ «точка с запятой». Это означает, что эти записи переведены в статус комментария, что удобно при чтении программы. Аббревиатуры команд ассемблера начинаются со строки 24. Причем в строке 23 написана инструкция Си, которая присваивает регистру управления таймером TSCR значение 0x80. Ниже в строках 24 и 25 записаны две команды ассемблера, которые реализуют данное действие. Причем, кросс-компилятор уже использовал заголовочный файл для определения абсолютного адреса регистра управления TSCR как 0x86. Строки с 26 по 36 завершают процесс инициализации микроконтроллера, но уже на языке ассемблерных команд. В строках 37…40 записаны команды бесконечного цикла. Строки с 41 по 46 завершают ассемблерный текст основной программы. Обратите внимание, макросы CLI() и EXIT() генерируют ассемблерные команды cli и swi соответственно. Основная программа оформлена в виде подпрограммы и завершается командой возврата из подпрограммы rts. В строке 47 начинается программа прерывания по переполнению таймера. Анализируя ее текст, можно проследить соответствие команд ассемблера каждому оператору исходного текста на Си. Подпрограмма прерывания завершается командой rti в строке 78.

Следующий шаг в процессе генерации исполняемого машинного кода — это генерация объектного кода (файл interrupt.o) из рассмотренного ассемблерного исходного кода. После обработки программой Ассемблер среды ICC12 рассмотренного текста будет получен следующий объектный код:

H4 areas 4 global symbols

M interrupt.c

А text size 3D flags 0

S _main Def0000

S _TOIISR Def001A

А memory size В20 flags С

S _Timer_Overflow_interrupt_vector Def0B1E

А data size 1 flags 0

S _second Def0000

А idata size 1 flags 0

T 0В 1Е 00 1А

R 00 00 00 01 00 02 00 00

T 00 00 00

R 00 00 00 03

T 00 00 С6 80 7В 00 86 С6 80 7В 00 80 С6 80 7В

R 00 00 00 00

T 00 00 00 8F С6 FF 7В 00 02 10 EF 20 FE 3F 30 С6

R 00 00 00 00

T 00 1В 80 7В 00 8F F6 00 00 87 С3 00 01 7В 00 00

R 00 00 00 00 00 07 00 02 00 0E 00 02

T 00 29 F6 00 00 C1 7А 26 ОС F6 00 00 87 41 51 7B

R 00 00 00 00 00 03 00 02

Т 00 37 00 00 79 00 00 0B

R 00 00 00 00 00 05 00 02

Заметим, что в верхней половине представленного объектного кода, содержатся директивы для программы линковщика, а в нижней половине читатель может увидеть шестнадцатеричные коды инструкций ассемблера МК семейства 68HC12.

На заключительной стадии представленный выше объектный код обрабатывается программой линковщика. В результате формируются три файла: interrupt.lst, interrupt.map и interrupt.s19.

Файл листинга программы interrupt.lst представляет собой текстовый файл, который содержит команды ассемблера, машинные коды этих команд и абсолютные адреса в памяти микроконтроллера, в которых эти коды располагаются. Сгенерированный линковщиком файл листинга представлен ниже:

            .module interrupt.c

            .area memory(abs)

            .org 0хb1е

0B1Е _      _Timer_Overflow_interrupt_vector: :

0B1Е 8044   .word _TOIISR

            .area data

0800        _second::

0800        .blkb 1

            .area idata

--- 0000 00 .byte 0

            .area data

            .area text

802А _main: :

;#include <383HC12-ver1.h>

;void TOIISR(void) ;

;#pragma interrupt_handler TOIISR()

;

;#pragma abs_address:0x0B1E

;void(*Timer_Overflow_interrupt_vector[]) ()={TOIISR};

;#pragma end_abs_address

;

;unsigned char second=0x00;

;

;void main(void)

;{

;TSCR=0x80;

802А C680   ldab #128

802С 7В0086 stab 0х86

;TMSK2=0x80;

802F C680   ldab #128

8031 7B008D stab 0x8d

;TFLG2=0x80;

8034 C680   ldab #128

8036 7B008F stab 0x8f

;DDRA=0xFF;

8039 C6FF   ldab #255

803В 7В0002 stab 0x2

;CLI();

803Е 10EF   cli

8040        L3:

8040        L4:

8040 20FE bra L3

8042        X0:

;while (1) {};

;EXIT();

8042 3F     swi

; }

8043        L2:

8043        .dbline 0; func end

8043 3D     rts

8044        _TOIISR: :

;

; void TOIISR(void) {

;TFLG2=0x80;

8044 C680    ldab #128

8046 7B008F  stab 0x8f

;second += 1;

8049 f60800  ldab _second

804C 87      clra

804D C30001  addd #1

8050 7B0800  stab _second

;if(second == 122)

8053 F60800  ldab _second

8056 C17A    cmрb #122

8058 260C    bnе L7

;{

;PORTA = ~PORTA;

; vol

805A F60000  ldab 0

805D 87      clra

805E 41      comа

805F 51      comb

8060 7B0000  stab 0

;second = 0x00;

8063 790800  clr _second

;}

8066         L7:

;}

8066         L6:

8066         .dbline 0; func end

8066 0B      rti

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

Area

(Attributes) Addr Size Decimal Bytes

------------ ---- ---- ------- --------

text 8000    006В = 107. bytes (rel,con)

 Addr Global Symbol

 ---- --------------

 8000 __start

 8028 _exit

 802А _main

 8044 _TOIISR

 8067 __HC12Setup

 806B __text_end

Area

(Attributes) Addr Size Decimal Bytes

------------ ---- ---- ------- -----

idata 806B   0001 = 1. bytes (rel,con)

 Addr Global Symbol

 ---- --------------

 806B __idata_start

 806C __idata_end

Area

(Attributes) Addr Size Decimal Bytes

------------ ---- ---- ------- -----

data 0800 0001 = 1. bytes (rel,con)

 Addr Global Symbol

 ---- --------------

 0800 _second

 0800 __data_start

 0801 __data_end

Area

(Attributes) Addr Size Decimal Bytes

------------ ---- ---- ------- -----

memory 0000  0B20 = 2848. bytes (abs,ovr)

 Addr Global Symbol

 ---- --------------

 0B1E  _Timer_Overflow_interrupt_vector

Files Linked [ module(s)]

C:\icc\lib\crt12.o [crt12.s] interrupt.o [ interrup ]

<library> [psetup.c]

User Global Definitions

init_sp = 0хс00

User Bаsе Address Definitions

text = 0х8000 data =0х8000

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

S10E8000CF0C0016806787CE08018EAD

S110800B080127056A000820F6CE806BCD21

S111801808008E806C2706180A307020F516BA

S1078026802A20FE8A

S1050B1E80440D

S104806B0010

S110802AC6807B0086C6807B008DC6807BEF

S1118037008FC6FF7B000210EF20FE3F3DC607

S1118045807B008FF6080087C300017B0800D3

S1118053F60800C17A260CF600008741517B26

S109806100007908000B89

S10780677900163D45

S90380007C

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

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

3.15. Заключение по главе 3

 Сделать закладку на этом месте книги

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

Мы также рассмотрели процесс преобразования исходного текста программы на Си в файл исполняемых кодов для МК выбранного типа. Мы показали Вам примеры всех промежуточных генерируемых файлов по ходу этого процесса. Мы также кратко остановились на аппаратных особенностях МК семейства 68HC12/HCS12 для целей отладки, рассмотрели возможности использования аппаратных и программных средств платы MC68HC912B32EVB для тестирования и отладки примеров следующих глав данной книги.

3.16. Что еще почитать?

 Сделать закладку на этом месте книги

1. Kernighan, В. W., and D. М. Ritchie. The С Programming Language, 2nd ed. Upper Saddle River, NJ: Prentice Наll, 1988.

2. Schildt, Н. С: The Complete Reference. Osborne McGraw Нill.

3. Harbison, Samuel Р. III, and Guy Steele Jr. С А Reference Manual, 5th ed. Upper Saddle River, NJ: Prentice Наll, 2002.

4. ImageCraft С Compiler and Development Environment for Motorola HC12, ImageCraft Creations Inc., Раlo Alto, СА, 2002.

3.17. Вопросы и задания

 Сделать закладку на этом месте книги

Основные

1. Каково назначение символа «;» в программах на Си?

2. Сколько байт отводится для хранения переменной в формате integer?

3. Какое количество байт отводится для хранения переменной указателя?

4. В какой области памяти МК семейства 68HC12 размещаются переменные со статическим классом хранения?

5. Расскажите о двух назначениях символа * в программах на Си.

6. Опишите процесс преобразования файла с исходным текстом программы на Си в файл исполняемых кодов программы.


Более сложные

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

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

3. В тексте программы на Си присутствует запись:

static int array[10];

Поясните, какие действия компилятора или управляющей программы соотносятся с этим выражением?

4. Поясните назначение макроопределения. Приведите примеры макроопределений в программах на Си.

5. В чем отличие макроопределения от функции?


Исследовательские

1. Напишите программу на Си, которая переключает состояние светодиодов из выключенного во включенное и наоборот каждые 5 с. Функциональная схема подключения светодиодов (в составе семисегментного индикатора) к МК семейства 68HC12 приведена на рис. 3.12.



Рис. 3.12. Схема подключения семисегментного индикатора к микроконтроллеру 68HC912B32


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

3. Напишите программу для отображения на семимегментном индикаторе последовательности цифр от 0 до 9. Каждая цифра должна светиться 100 мс. Функциональная схема подключения семисегментного индикатора к МК семейства 68HC12 приведена на рис. 3.12. Семисегментный индикатор выполнен по схеме с общим катодом. Схема соединения светодиодов внутри корпуса индикатора и обозначения сегментов индикатора представлены на рис. 3.13. Аноды диодов подключаются к выходам логических буферных элементов (интегральная схема 74ALS244) через резисторы, которые служат ограничителями тока каждого сегмента (светодиода) индикатора. Входы интегральной схемы 74ALS244 подключены к выходам порта МК. Для формирования на индикаторе образов цифр и букв необходимо вывести под управлением программы на выводы порта МК кодовые комбинации, которые перечислены в табл. 3.9.

Цифра шестнадцатеричной системы счисления Кодовая комбинация Цифра шестнадцатеричной системы счисления Кодовая комбинация
0 0x3F 1 0x06
2 0x5B 3 0x4F
4 0x66 5 0x6D
6 0x7D 7 0x07
8 0x7F 9 0x6F
A 0x77 B 0x7F
C 0x39 D 0x3F
E 0x79 F 0x71

Табл. 3.9.  Кодовые комбинации для высвечивания цифр шестнадцатеричной системы счисления



Рис. 3.13. Семисегментный индикатор с общим катодом


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

Глава 4

МИКРОКОНТРОЛЛЕРЫ 68HC12 И HCS12: АРХИТЕКТУРА И ПРОГРАММИРОВАНИЕ

 Сделать закладку на этом месте книги

ПОСЛЕ ИЗУЧЕНИЯ ГЛАВЫ ВЫ СМОЖЕТЕ:

• Описать структуру и определить основные отличительные особенности МК семейства 68НС12;

• Описать различные режимы работы МК 68HC12;

• Описать, какие действия выполняются над аппаратными средствами МК в состоянии сброса;

• Объяснить необходимость подсистемы прерывания в составе МК;

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

• Описать работу модуля тактирования в составе МК 68HC12;

• Описать структуру и режимы работы модуля таймера TIM, счетчика внешних событий и модуля меток реального времени, привести примеры программирования всех перечисленных подсистем реального времени;

• Разъяснить термины, которые используются при описании обмена данными в последовательном коде;

• Описать структуру аппаратных средств и привести примеры программирования контроллера асинхронного последовательного обмена SCI в составе МК 68HC12;

• Составить программу для обмена в последовательном коде c заданными параметрами для модуля SCI;

• Описать структуру аппаратных средств и привести примеры программирования контроллера синхронного последовательного обмена SPI в составе МК 68HC12;

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

• Грамотно рассчитать параметры процесса аналого цифрового преобразования для сигнала с заданной частотой и формой;

• Описать модуль аналого цифрового преобразователя ATD в составе МК 68HC12;

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

• Подробно описать усовершенствования модуля АЦП в составе МК HCS12 по сравнению с модулем ATD в составе 68HC12;

• Составить программу и использовать модуль широтно-импульсного модулятора PWM в составе МК 68HC12B32 для управления электрическими двигателями.

Знакомясь с оглавлением, Вы должны были заметить, что эта глава — самая длинная в книге. В ней мы с достаточной степенью подробности изучим структуру и режимы работы всех подсистем микроконтроллеров семейства 68HC12 и HCS12. Для определенности рассмотрение будем вести на примере двух моделей МК: MC68HC912B32 и MC9S12DP256. Далее с целью удобства восприятия будем называть эти модели просто B32 и DP256. Периферийные модули в составе МК 68HC12 и HCS12 очень похожи друг на друга. Поэтому мы сначала будем рассматривать модули МК 68HC12, а затем остановимся на отличиях конкретного модуля в составе семейства HCS12 от его прототипа в составе 68HC12. Изучению каждого периферийного модуля будет предшествовать краткая теоретическая справка, затем будут рассмотрены структура аппаратных средств и регистры специальных функций модуля. В завершение для каждого модуля приведены несколько примеров его программного обслуживания.

Очень важно, чтобы Вы достаточно глубоко поняли особенности подсистем в составе МК 68HC12 перед тем, как перейти к примерам практической реализации достаточно сложных систем на основе этих МК. Если Вы уже знакомы с МК семейства 68HC12, то у Вас возникнет желание пропустить главу 4. Однако мы советуем Вам все же ознакомиться с примерами программ управления из этой главы, поскольку последние используются в приложениях главы 7. Заметим также, что примеры этой главы могут использоваться Вами для получения навыков отладки программного обеспечения с использованием платы отладки M68EVB912B32 или каких либо других отладочных средств.

4.1. Аппаратные средства микроконтроллеров семейства 68HC12

 Сделать закладку на этом месте книги

На рис. 4.1. представлена структура микроконтроллера MC68HC912B32 или в сокращенном виде B32. Мы уже использовали этот рисунок в гл. 1, однако обратились к нему снова, для более подробного рассмотрения технических характеристик МК B32.



Рис. 4.1. Структура микроконтроллера MC68HC912B32


Все МК семейства 68HC12 обладают 16-разрядным процессорным ядром. Семейство объединяет ряд моделей, в том числе ранее упомянутый МК 68HC812A4 (A4) и рассматриваемый в данной главе МК 68HC912B32 (B32). Отдельные модели в составе семейства различаются набором периферийных модулей, которые подключаются к внутренней межмодульной магистрали. Основные отличия между отдельными представителями семейства состоят в типе и объеме размещенной на кристалле резидентной памяти, количестве параллельных портов и контроллеров последовательных интерфейсов. В настоящей главе будет подробно рассмотрен МК модели 68HC912B32, который был выбран по причине наличия в нем всех типовых периферийных модулей. Подробное изучение предложенного МК позволит читателю с минимальными затратами адаптироваться к проектированию приложений на основе других моделей семейства 68HC12 и HCS12.

МК 68HC912B32 характеризуются следующими отличительными особенностями:

• Низкое энергопотребление. Микроконтроллеры семейства 68HC12 производятся на основе CMOS технологии (CMOS — Complementary Metal oxide semiconductor). Эта технология позволяет создать транзисторные структуры с относительно низкими потерями энергии при работе в ключевых режимах. Поэтому МК семейства 68HC12 характеризуются малым потреблением энергии, что позволяет рекомендовать их для использования в изделиях с автономным питанием (от аккумуляторов или батареек). Однако не следует забывать, что потребляемая энергия для полупроводниковых CMOS структур прямо пропорциональна частоте переключения. Поэтому для достижения оптимальных энергетических характеристик следует выбирать частоту тактирования центрального процессора микроконтроллеров 68HC12 минимально возможной для конкретного применения. Микроконтроллеры 68HC12 имеют специальные режимы пониженного энергопотребления, которые также позволяют оптимизировать энергетические характеристики проектируемого изделия.

• Высокопроизводительное 16 разрядное процессорное ядро. Центральный процессор семейства 68HC12 выполняет действия над 16-разрядными операндами, поэтому время выполнения алгоритмов над переменными, разрядность которых превышает байт, существенно сокращается по сравнению с 8 разрядными МК. Максимальная частота тактирования процессорного ядра fBUS для микроконтроллеров семейства 68HC12 составляет 8 МГц. Однако частота внешнего генератора или кварцевого резонатора должна составлять 16 МГц, поскольку внутренние цепи микроконтроллера делят эту частоту на два для получения fBUS .

• Резидентное ОЗУ объемом 1024 байта (1Кб). Встроенное в кристалл микроконтроллера ОЗУ используется для хранения промежуточных результатов вычислений. Число ячеек, равное 1К, достаточно для большинства прогнозируемых для семейства 68HC12 применений.

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

• Резидентная память программ типа Flash объемом 32 Кб. Этот тип памяти предназначен для хранения прикладной программы, которая функционально завершена, прошла отладку и тестирование на реальном объекте. Объем памяти программ МК B32 составляет 32 Кб, что позволяет разместить в ней достаточно большие программы. В процессе работы над примерами из нашей книги Вы почувствуете, какой алгоритм может быть реализован программным кодом объемом 32 Кб. Использование Flash памяти в качестве памяти программ позволяет реализовать технологию программирования в системе ISP (In System Programming). Эта технология обеспечивает выполнение операций стирания и записи новых кодов в резидентное ПЗУ программ микроконтроллера без демонтажа МК с платы конечного изделия. Учитывая, что наиболее надежным способом монтажа МК на плату встраиваемой системы в настоящее время является пайка, читатель должен оценить, сколь полезна технология ISP. Если Вы собрались использовать технологию ISP на плате отладки MC68HC912B32EVB, то следует помнить, что программа монитора отладки D-Bug12, которая в том числе необходима для реализации этой технологии, располагается в области Flash памяти. Поскольку любой операции записи во Flash ПЗУ предшествует операция стирания Flash памяти, необходимо соблюдать осторожность, чтобы не стереть коды монитора отладки. Необходимые для этого сведения Вы найдете в разделе 7.8.

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


убрать рекламу






уса МК при сохранении функций этих выводов является мультиплексирование линий магистралей адреса и данных для сопряжения МК с внешней памятью. При мультиплексировании одни и те же выводы МК на протяжении одного временного интервала используются для передачи информации об адресе внешней ячейки памяти, а в течение другого временного интервала — для обмена данными с этой ячейкой. В микроконтроллере B32 функции мультиплексированных во времени магистралей адрес/данные выполняют линии портов Port A и Port B (рис. 4.1).

• Многофункциональный таймер. Подсистема реального времени МК семейства 68HC12 включает несколько модулей, но основным является таймер с 16-разрядным счетчиком временной базы, программируемым делителем частоты тактирования и 8 каналами входного захвата IC (Input Capture) или выходного сравнения OC (Output Compare). Эти каналы могут быть сконфигурированы произвольно: любое число каналов из 8 настраивается на реализацию функции входного захвата IC, оставшиеся каналы — на функцию выходного сравнения OC. При этом возможны конфигурации, когда все каналы находятся в режиме IC или в режиме OC. Такая организация модуля таймера позволяет производить точные измерения временных характеристик входных сигналов МК, и генерировать многоканальные импульсные последовательности на его выходах.

• Независимый 16 разрядный счетчик внешних событий. Этот модуль также принадлежит к подсистеме реального времени. Он предназначен для подсчета так называемых внешних событий, каждое из которых представляется импульсом на одном из входов МК. Например, в главе 7 мы будем рассматривать пример системы управления скоростью вращения электрического двигателя. Этот двигатель оснащен оптическим датчиком скорости, который генерирует 60 импульсов на один оборот двигателя. С помощью счетчика внешних событий эти импульсы могут быть подсчитаны на определенном временном интервале, после чего МК рассчитает число оборотов двигателя в мин.

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

• Модули контроллеров последовательных интерфейсов SPI (Serial Peripheral Interface) и SCI (Serial Communication Interface). Микроконтроллеры семейства 68HC12 обладают достаточно мощными аппаратными средствами для обмена с другими устройствами в последовательном коде. Модуль контроллера SPI реализует обмен в синхронном режиме, в то время как модуль SCI предназначен для асинхронного последовательного обмена. Синхронный режим обмена в стандарте SPI характеризуется более высокими скоростями обмена по сравнению с стандартным асинхронным протоколом. Однако расстояние между взаимодействующими устройствами ограничено 20…30 см. Интерфейс в стандарте SPI часто используется для подключения к МК дополнительных интерфейсных компонентов, установленных на плате с МК. Например, МК семейства 68HC12 не имеют в своем составе цифро аналоговых преобразователей (ЦАП). Поэтому система с МК может быть дополнена внешней ИС ЦАП, подключенной к микроконтроллеру с использованием встроенного модуля контроллера SPI. Интерфейс асинхронного обмена SCI часто используется для обмена данными между двумя и более контроллерами, т.к на его основе созданы интерфейсы, сигналы которых могут передаваться на значительные расстояния.

• Модуль аналого-цифрового преобразователя ATD (Analog To Digital conversion system). Большинство сигналов в системах, которыми управляют микроконтроллеры, имеют аналоговую природу. Например, температура и давление воздуха окружающей среды изменяются плавно, а не скачкообразно. Для работы с аналоговыми сигналами в микропроцессорной системе, эти сигналы должны быть предварительно преобразованы в цифровую форму. В русскоязычной литературе говорят, что эти сигналы должны быть оцифрованы. Для этой цели в составе МК B32 имеется модуль аналого-цифрового преобразователя. Модуль имеет 8 входов для одновременного подключения восьми измеряемых аналоговых сигналов. Однако оцифровка этих сигналов будет производиться последовательно. Измеряемые аналоговые сигналы будут подключаться ко входу одного аналого цифрового преобразователя (АЦП) посредством встроенного в модуль ATD мультиплексора. Оцифрованный сигнал представляется в 8-и или 10-разрядном прямом коде без знака. Два дополнительных бита кода представления результата позволяют увеличить чувствительность АЦП с 19.53 до 4.88 мВ.

• Модуль сторожевого таймера COP (Computer Operating Properly). Встраиваемая микропроцессорная система должна обладать высокой надежностью. Одним из путей повышения этой надежности является свойство самовосстановления системы при возникающих некатострофических отказах. Такими отказами являются нарушения исполнения прикладной программы, вызванные помехами, и не сопровождаемые отказом аппаратных средств МК. Для восстановления правильного хода исполнения прикладной программы используется механизм сторожевого таймера. Если программа исполняется без нарушений, то сторожевой таймер регулярно обнуляется (сбрасывается) под управлением этой программы. Если же ход исполнения программы нарушен, то своевременный сброс может не произойти, и сторожевой таймер переполнится. Переполнение вызовет состояние внутреннего сброса МК, в результате исполнение прикладной программы будет начато заново, т.е. правильный ход исполнения программы будет восстановлен. В главе 5 мы обсудим возможные источники помех и шумов, которые могут вызвать сбой в исполнении программы. В главе 6 поговорим о дополнительных программных мерах, которые следует предпринять для предупреждения подобных отказов.

• Модуль широтно-импульсного модулятора PWM (Pulse Width Modulation). Широтно-импульсная модуляция (ШИМ) — один из способов формирования импульсного сигнала с регулируемыми временными характеристиками. Способ широтно-импульсной модуляции часто используется для регулирования скорости вращения двигателей постоянного тока, а также для управления электрическими двигателями других типов. Для генерации ШИМ-сигнала в МК B32 могут быть использованы аппаратные средства модуля многофункционального таймера TIM. Однако МК B32 оснащен специальным модулем ШИМ. Этот модуль позволяет генерировать четыре независимых импульсных последовательности с 8 разрядным разрешением для задания коэффициента заполнения, или две импульсные последовательности с 16-разрядным заданием коэффициента заполнения. Допускается комбинация этих режимов. Например, ШИМ сигнал используется для управления двигателем рулевого управления в игрушечных радиоуправляемых машинках. Для того, чтобы машинка повернула направо или налево, она должна получить импульсный сигнал, у которого частота следования импульсов постоянная, а длительность импульсов изменяется, как показано на рис. 4.2. Отношение длительности импульса к длительности периода сигнала называется коэффициентом заполнения. Машинка повернет налево, если коэффициент заполнения менее 50% , или направо, если коэффициент заполнения превышает 50%. Модуль PWM микроконтроллера B32 позволяет организовать импульсную последовательность с требуемыми значениями периода следования и коэффициента заполнения при использовании минимального числа команд прикладной программы.



а) Временные диаграммы ШИМ-сигналов с различными коэффициентами заполнения



б) Регулировочная характеристика

Рис. 4.2. Широтно-импульсная модуляция


• Модуль контроллера последовательного обмена BDLC (Byte Data Link Communication) поддерживает коммуникационный протокол SAE J1850, который является действующим стандартом бортовой информационной сети в автомобилях североамериканского производства.

• Модуль контроллера CAN интерфейса msCAN12 (Motorola Scalable Controller Area Network) содержит в себе набор аппаратных средств для поддержки коммуникационного протокола промышленных сетей в стандарте CAN 2.0 A/B. Этого модуля нет в составе МК модели B32, однако он присутствует во многих других моделях семейства HC12 и HCS12. Пример работы с этим модулем приведен в главе 9.

Для более полного восприятия структуры МК B32 мы дополним приведенные технические характеристики небольшим примером применения.

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



Рис. 4.3. Система управления электрическим двигателем на основе МК 68HC12


Вопрос: какие подсистемы МК семейства 68HC12 используются для реализации рассмотренной системы регулирования скорости вращения двигателя?

Ответ:

• Параллельный порт задействован для ввода сигналов с клавиатуры.

• Модуль ШИМ используется для генерации широтно-модулированного сигнала управления силовым ключом IRF530. Этот ключ коммутирует силовое напряжение к обмотке двигателя. Если в примере использовать МК семейства 68HC12, который не имеет в своем составе модуля ШИМ, например A4, то этот же сигнал может быть сгенерирован одним из каналов многофункционального таймера в режиме выходного сравнения OC.

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

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

• Параллельный порт и несколько дополнительных линий другого порта используются для вывода информации на ЖК индикатор.

4.2. Аппаратные средства МК семейства HCS12

 Сделать закладку на этом месте книги

Новое семейство МК HCS12 унаследовало архитектуру процессорного ядра и большинства периферийных модулей от своего предшественника, семейства 68HC12. Каковы основные отличия МК нового семейства HCS12 от изученных представителей 68HC12?

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

• Повышенна производительность процессорного ядра. Частота тактирования центрального процессора и межмодульных магистралей МК семейства HCS12 составляет 25 МГц против 8 МГц у HC12;

• Увеличен объем резидентной памяти. Объем встроенного в МК семейства HCS12 ОЗУ достигает 12 Кб, объем Flash ПЗУ — 512 Кб. Кроме того, в составе большинства моделей МК имеется значительная область EEPROM (до 4 Кб) для хранения перепрограммируемых констант пользователя;

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

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

• Память трех типов: FLASH память программ, энергонезависимая память EEPROM для хранения изменяемых констант пользователя и статическое ОЗУ для размещения промежуточных переменных прикладной программы управления;

• Многофункциональный 16-разрядный таймер с 8 каналами IC/OC;

• Многоканальный аналого-цифровой преобразователь;

• Контроллеры последовательного обмена нескольких стандартов;

• Модуль ШИМ общего назначения, ряд моделей оснащен специализированным модулем ШИМ для управления автономными вентильными преобразователями.

Структурная схема одного из представителей семейства HCS12 — микроконтроллера MC9S12DP256B представлена на рис. 4.4. Обратите внимание, что большая часть модулей этого МК уже рассматривалась Вами в составе МК MC68HC912B32 (рис. 4.1). Однако на кристалле MC9S12DP256B размещены уже два 8-канальных АЦП, добавлены 5 модулей контроллеров CAN и новый модуль PPAGE для аппаратной поддержки режима страничной адресации внешней памяти. Также претерпел изменения модуль таймера ECT, который стал именоваться «усовершенствованным таймером с функцией фиксации» (Enhanced Capture Timer).



Рис. 4.4. Структура микроконтроллера MC9S12DP256B


Мы надеемся, что читатель получил общее представление о МК семейства 68HC12/HCS12, и следует перейти к подробному изучению их технических особенностей. Далее на протяжении этой главы мы рассмотрим аппаратную реализацию и регистровые модели отдельных модулей в составе МК семейства 68HC12/HCS12. Также будут рассмотрены примеры программного обслуживания каждого модуля. В последующих главах мы объединим полученные навыки программирования периферии МК при создании микропроцессорных устройств различного назначения.

4.3. Режимы работы МК семейства 68HC12/HCS12

 Сделать закладку на этом месте книги

Микроконтроллеры семейства 68HC12/HCS12 функционируют в одном из восьми режимов, которые делят на две группы: рабочие режимы и специальные режимы. Рабочие режимы позволяют создать различную аппаратную реализацию встраиваемого контроллера, в то время как специальные режимы работы предназначены для проведения тестовых испытаний и диагностики МК в процессе производства. Поэтому инженерам по применению микроконтроллеров важно изучить лишь группу рабочих режимов.

BKGD MODB MODA Режим работы PORTA PORTB
000 Специальный однокристальный PORTA PORTB
001 Специальный расширенный с 8-разрядной внешней шиной ADDR [15...8]  DATA [7...0] ADDR [7...0]
010 Специальный периферийный ADDR, DATA ADDR, DATA
011 Специальный расширенный с 16-разрядной внешней шиной ADDR, DATA ADDR, DATA
100 Нормальный однокристальный PORTA PORTB
101 Нормальный расширенный с 8 разрядной внешней шиной ADDR [15...8] DATA [7...0] ADDR [7...0]
110 Резервный (периферийный)
111 Нормальный расширенный с 16 разрядной внешней шиной ADDR, DATA ADDR, DATA 

Рис. 4.5. Режимы работы микроконтроллеров семейства 68HC12


Каждый режим из группы рабочих задает собственное распределение адресного пространства МК и конфигурацию магистралей для подключения внешней памяти. Режим работы МК назначается посредством комбинации логических сигналов на входах BKGD, MODB, MODA микроконтроллера в состоянии начального запуска МК. Состояние начального запуска именуют также состоянием сброса (Reset). Сразу после выхода из состояния сброса МК запоминает кодовую комбинацию на перечисленных входах и переходит в соответствующий режим работы. Полный перечень режимов работы МК 68HC12/HCS12 представлен на рис. 4.5. Там же указаны альтернативные функции линий портов PORT A и PORT B, которые они приобретают в каждом из режимов работы.

4.3.1. Рабочие режимы

 Сделать закладку на этом месте книги

В большинстве проектируемых устройств Вы будете использовать МК 68HC12/HCS12 в одном из трех рабочих режимов:

• Однокристальном или автономном режиме;

• Расширенном режиме с 16-разрядной внешней шиной;

• Расширенном режиме с 8-разрядной внешней шиной.

Расширенные режимы работы предоставляют возможность подключения к МК внешней памяти и внешних периферийных ИС с использованием параллельных магистралей адреса и данных. Сигналы магистралей формируются на линиях портов PORTA и PORTB, поэтому использование соответствующих выводов МК в качестве линий ввода/вывода общего назначения в расширенных режимах работы становится невозможным.

Краткое описание рабочих режимов:

• Однокристальный режим работы (BKGD: 1, MODB: 0, MODA: 0) обеспечивает функционирование МК с использованием только внутренней памяти. Поэтому коды прикладной программы управления и ее переменные должны размещаться только во внутреннем ПЗУ и ОЗУ МК. Порты PORTA и PORTB используются в качестве обычных двунаправленных портов ввода/вывода. Подключение внешних периферийных ИС должно производиться с использованием последовательных интерфейсов или с программной поддержкой временной диаграммы обмена на линиях портов ввода/вывода.

• Расширенный режим с 16 разрядной системной шиной (BKGD: 1, MODB: 1, MODA: 1) обеспечивает функционирование МК с использованием как внутренней, так и внешней памяти. Для подключения внешней памяти предназначена 16-разрядная мультиплексированная магистраль адрес/данные ADDR15–0/DATA15–0. При этом старший байт мультиплексированной во времени магистрали ADDR15–8/DATA15–8 формируется на линиях PORTA, младший байт ADDR7–0/DATA7–0 — на линиях PORTB.

• Расширенный режим с 8 разрядной системной шиной (BKGD: 1, MODB: 0, MODA: 1) также реализует работу МК с использованием внутренней и внешней памяти. Но для подключения внешней памяти предназначены 16-разрядная магистраль адреса ADDR15–0 и 8-разрядная магистраль данных DATA7–0. Старший байт магистрали адреса ADDR15–8 выводится на PORTA, младший байт ADDR7–0 — на PORTB. Двунаправленная 8-разрядная магистраль данных DATA7–0 использует линии порта PORTA в мультиплексированном со старшими разрядами магистрали адреса режиме. В обоих расширенных режимах некоторые линии порта PORTE используются для передачи сигналов управления обменом по шине.

4.3.2. Режимы работы отладочной платы M68EVB912B32

 Сделать закладку на этом месте книги

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

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

• Режим EVB. В этом режиме реализуется работа под управлением резидентного монитора отладки D-Bug12. Аппаратные средства отладочной платы выполнены таким образом, что сразу после включения запустится программа, которая размещается во Flash ПЗУ МК. В заводском исполнении в эту область памяти помещается программа монитора отладки D-Bug12. Если же пользователь вместо программы монитора записал коды программы пользователя, то начнет исполняться последняя. Однако чтобы не потерять коды программы монитора, неопытному пользователю не следует перепрограммировать область Flash ПЗУ. Записанный в памяти МК монитор отладки D-Bug12 содержит в себе простую, но полнофункциональную среду отладки, которая позволяет загрузить в память МК небольшие программы и протестировать их работоспособность.

• Режим JUMP EE. В этом режиме исполняется программа, загруженная с адреса $D000 в область памяти EEPROM. Поскольку область памяти EEPROM ограничена 768 байтами, то исполняемый в реальном времени фрагмент программы должен быть очень коротким. Такой режим пригоден для лабораторных испытаний функционирования в реальном времени отдельных фрагментов разрабатываемой прикладной программы.

• Режим POD. В этом режиме аппаратные средства отладочной платы M68912B32EVB используются в качестве интерфейса между последовательным портом персонального компьютера и отладочным портом модуля отладки BDM другого микроконтроллера, установленного на другой отладочной плате (можно использовать вторую плату M68912B32EVB, как показано в гл.3), или на плате собственной разработки. При этом этот другой МК будет находиться в режиме внутрисхемной отладки под управлением встроенного в МК модуля BDM. В этом внутрисхемной отладки возможно реализовать все этапы отладки, начиная с записи программы во Flash память МК (программирование) и заканчивая испытаниями прикладной программы в реальном времени на объекте управления. Для взаимодействия с отлаживаемым МК следует использовать один из пакетов программного обеспечения, рассмотренных в гл. 3.

• Режим BOOTLOAD. Этот режим предназначен для занесения программы во Flash или EEPROM память микроконтроллера MC68HC912B32, установленного на отладочной плате.

4.4. Назначение выводов МК

 Сделать закладку на этом месте книги

Так же, как и любая другая современная ИС, один и тот же микроконтроллер семейства 68HC12/HCS12 может быть доступен в нескольких типах корпусов. Мы рассмотрим МК MC68HC912B32 в 80 и выводном корпусе типа QFP (Quart Flat Pack). Назначение выводов корпуса приведено на рис. 4.6. При инсталляции МК в конкретное устройство и при проектировании аппаратных средств, все множество выводов МК может быть разделено на три группы:



Рис. 4.6. Цоколевка корпуса микроконтроллера MC68HC912B32


• Выводы для подключения напряжения питания и опорного напряжения модуля АЦП. Имена выводов этой группы начинаются с буквы V. Например: VDD, VSS и т.д.

• Выводы портов ввода/вывода. Имена выводов этой группы начинаются с буквы P. Например: PA0, PB5 и т.д. Следующие за буквой P символы обозначают имя и номер линии порта: PORTA, линия 0 и PORTB, линия 5.

• Дополнительные выводы. Эти выводы используются для подключения дополнительных логических и нелогических сигналов, которые обеспечивают функционирование аппаратных средств микроконтроллера. Например, выводы XTAL и EXTAL используются для активизации системы тактирования МК.

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

4.5. Регистры специальных функций МК

 Сделать закладку на этом месте книги

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



Рис. 4.7. «Пульт» управления МК семейства HC12


Блок регистров специальных функций микроконтроллера по реализуемым функциям очень похож на пульт управления. Каждый регистр осуществляет управление или отображает состояние того периферийного модуля МК, к которому он отнесен в техническом описании. Часть битов регистров специальных функций может быть сопоставлена с переключателями: установка бита в 1 разрешает реализацию какой либо функции периферийного модуля, сброс в 0 — прекращает исполнение этой функции. Другая часть битов регистров аналогична индикаторам состояния: установка 1 свидетельствует о завершении выполнения назначенной функции, пребывание в 0 свидетельствует о том, что процесс еще не завершился.

Регистры специальных функций МК семейства 68HC12/HCS12 объединены в блок, который размещается в адресном пространстве памяти МК. Доступ к каждому из 512 регистров блока осуществляется теми же командами центрального процессора, что и к ячейкам памяти. Никакого различия с точки зрения программного обслуживания между регистрами специальных функций и ячейками ОЗУ не существует. Исключение составляют лишь регистры конфигурации и другие, так называемые защищенные регистры, состояние которых невозможно изменить в произвольный момент исполнения прикладной программы.

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

Каждый регистр специальных функций имеет свой собственный адрес в карте памяти МК. При программировании на ассемблере изменение значений регистров специальных функций и считывание их состояния может быть произведено командами загрузки и пересылки данных, такими как LDAA, STAA, MOV, а также командами битовых операций BSET, BCLR. Для того чтобы избавить программиста от запоминания физических адресов регистров специальных функций, следует использовать псевдокоманду операции присваивания EQU языка Ассемблер. Эта псевдокоманда


убрать рекламу






назначит символьному имени регистра, которое одинаково для всех моделей МК семейства 68HC12/HCS12, абсолютный адрес. И при записи исходного текста программы можно будет использовать только символьные имена регистров специальных функций. Использование символьных имен также полезно при переносе прикладной программы с одной модели МК на другую. В этом случае следует заменить только абсолютные адреса в псевдокомандах, в то время, как исходный текст программы останется неизменным.

При написании программы на Си с последующим использованием пакета ICC12 компании ImageCraft (см. гл. 3) для этих же целей следует использовать оператор присваивания «=». При программировании на Си установление соответствия между символьными именами регистров специальных функций и их абсолютными адресами в памяти МК наиболее часто производится с использованием директивы препроцессора #define. Для того чтобы освободить программиста от непроизводительного труда, каждая интегрированная среда разработки ПО для МК снабжена файлами заголовков (header file), которые содержат в себе полный набор директив #define для всех регистров специальных функций конкретной модели микроконтроллера. Этот файл включается в исходный текст прикладной программы директивой «include». После этого программист может обращаться к любому регистру специальных функций МК, называя символьное имя регистра. Более того, некоторые заголовочные файлы содержат определения для наиболее часто употребимых битов в составе регистров специальных функций МК, что позволяет устанавливать и сбрасывать эти биты в ходе программы, также используя их символьные имена. Применяя заголовочные файлы при программировании, необходимо помнить, что используемое в тексте программы символьное имя какого либо регистра должно в точности совпадать с именем, назначенным для него в заголовочном файле. Однако последнее не всегда совпадает с именем, приведенном в техническом описании МК.

Рассмотрим пример записи в заголовочном файле:

#define ATDCTL2 *(unsigned char volatile *) (IO_BASE + 0x62)

Разберем, что означает эта запись. Как было отмечено в гл. 3, директива #define используется препроцессором компилятора языка Си для присвоения численных значений символьным константам программы, или, как в нашем случае, определения абсолютного адреса для ячейки памяти или регистра с названным именем. После записи приведенной выше строки препроцессор будет заменять имя ATDCTL2 на указанное в директиве абсолютное значение.

Каково это значение? Оно определено в круглых скобках как сумма символьной константы IO_BASE и шестнадцатеричного числа 0x62. Константа IO_BASE — это начальный адрес блока регистров специальных функций в выбранной модели МК. Для МК B32 начальный адрес блока регистров равен 0x0000. Тогда адрес регистра ATDCTL2 будет равен 0x0062. Использованная форма записи адреса (IO_BASE + 0x62) не случайна, поскольку аппаратные средства 68HC12 позволяют программно изменять начальный адрес блока регистров (см. 4.5.1), сохраняя при этом порядок расположения регистров в памяти.

Каково назначение остальных символов рассматриваемой записи? Переменной ATDCTL2 назначается формат представления данных unsigned char, т.е 8-разрядный без знака. Определение volatile, которое следует за объявление формата, информирует компилятор о том, что изменение значения переменной ATDCTL2 может происходить не только в результате действия программы, но и на аппаратном уровне. Когда переменная сопровождается определением volatile, компилятор не использует по отношению к ней оптимизацию. Знак * после определения volatile указывает на то, что в следующих скобках заключено значение адреса переменной, а не значение этой переменной.

Пример.

Регистр ATDCTL2, расположенный в памяти МК по адресу 0x0062, управляет работой модуля аналого-цифрового преобразователя ATD. Бит 7 этого регистра разрешает (1) или запрещает (0) работу модуля. Этот бит, обозначенный в техническом описании как ATPU (ATD Powerup Bit), устанавливается в 0 в состоянии сброса МК. Для включения модуля ATD в работу необходимо программно установить этот бит в 1. На языке Ассемблера это действие может быть произведено следующим фрагментом программы:

;

;MAIN PROGRAMM

;

ATDCTL2 EQU  $0062    ;определить адрес регистра в МК

ATD_INI EQU  $80      ;определить значение слова

                      ;инициализации для включения АЦП

        LDAA #ATD_INI ;загрузить слово инициализации в ACC

        STAA ATDCTL2  ;записать значение инициализации в

                      ;регистр управления АЦП

                      ;

Первые две строки программы содержат директивы присвоения EQU языка Ассемблер, которые информируют программу о том, что вместо имени ATDCTL2 в кодах программы следует использовать значение $0062, а вместо ATD_INI — $80 или 10000000 в двоичном коде. Команда LDAA использует непосредственную адресацию, в результате ее выполнения число $80 загрузится в аккумулятор ACC. Команда STAA с прямой адресацией пересылает содержимое ACC в ячейку с адресом ATDCTL2. В результате, код в регистре управления ATDCTL2 будет равен 10000000, т.е. установленный в 1 бит 7 вызовет включение модуля АЦП. На языке Си аналогичное действие выполняет следующий программный фрагмент:

/*--------------------------*/

/*MAIN PROGRAMM             */

/*--------------------------*/

#include <912b32.h>


void main(void) {

 unsigned char ATD_INI = 0x80;

 ATDCTL2 = ATD_INI;

}

/*---------------------------*/

Как видите, Вам не пришлось указывать в программе физический адрес регистра ATDCTL2, т.к. он уже определен в заголовочном файле 912b32.h.

4.5.1. Виртуальный адрес блока регистров

 Сделать закладку на этом месте книги

Все регистры специальных функций МК семейства 68HC12/HCS12 объединены в блок, который занимает 512 ячеек памяти в адресном пространстве МК. Регистры располагаются в памяти, начиная с некоторого начального адреса, который принято в программном коде обозначать как IO_BASE. Адреса регистров следуют последовательно друг за другом, поэтому адрес каждого регистра можно представить, как (IO_BASE + код смещения). Численное значение кода смещения каждого регистра определено в карте памяти конкретной модели МК в составе семейства 68HC12/HCS12 и может быть получено из технического описания этого МК. Так в примере предыдущего параграфа код смещения регистра ATDCTL2 в составе МК B32 был равен $0062.

После выхода МК из состояния сброса блок регистров специальных функций располагается в адресном пространстве МК, начиная с адреса IO_BASE = $0000. Такое расположение блока наиболее часто сохраняется при использовании МК семейства 68HC12/HCS12 в однокристальном режиме работы, поскольку для обращения к регистрам могут быть использованы команды с прямой адресацией, которые имеют двухбайтовый формат и экономно расходуют память программ МК. Однако аппаратные средства МК семейства 68HC12/HCS12 позволяют переопределить значение базового адреса блока регистров IO_BASE = $0000 на любое другое кратное 2 Кб в пределах адресного пространства в 64Кб. Для этого достаточно записать соответствующее значение в один из регистров специальных функций МК с именем INITRG. После изменения базового адреса блок регистров будет «располагаться» в первых 512 ячейках выбранной области памяти объемом 2 Кб. Причем порядок расположения регистров, а значит и значения кодов смещения, в пределах этой области памяти останутся неизменными. Так если блок регистров назначен в область памяти с базовым адресом $1000, то регистр ATDCTL2 будет иметь новый виртуальный (т.е. кажущийся) адрес, равный $1000 + $0062. Заметим, что при использовании виртуальной адресации регистров программисту придется только переопределить базовый адрес IO_BASE, в то время как указанные в заголовочном файле коды смещения останутся прежними.

Зачем нужна система виртуальной адресации? Дело в том, что при работе МК в одном из расширенных режимов расположение блока регистров с адреса $0000 может вызвать неудобства при проектировании схемы подключения внешней памяти. А изменение базового адреса значительно упростит эту схемотехнику.

4.6. Порты ввода/вывода

 Сделать закладку на этом месте книги

Все МК семейства 68HC12 имеют некоторое количество линий ввода/вывода данных. Линии объединены в 8 разрядные параллельные порты данных: Port A, Port B, Port E, PORT AD и т.д.

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

Часть линий ввода/вывода имеют так называемую альтернативную функцию, т.е. обеспечивают связь встроенных периферийных модулей МК с «внешним миром». Так линии порта PORT AD используются для подключения к встроенному АЦП измеряемых напряжений, линии порта PORT S служат входами и выходами контроллеров последовательного обмена. Если соответствующий периферийный модуль МК не используется, то его выводы можно задействовать как обычные линии ввода/вывода.

Если линии порта двунаправленные, то для его обслуживания такого порта предусмотрены два типа регистров:

PORTx — регистр данных порта x, где x — имя порта ввода/вывода;

DDRx — регистр направления передачи порта x.

Например, порт PORT A обслуживается регистрами PORTA и DDRA, а порт PORT B — регистрами PORTB и DDRB.

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

Ниже приведен фрагмент текста программы, которая конфигурирует PORT T для вывода данных, а затем записывает в порт число $62. Для того, чтобы все линии порта PORT T стали линиями вывода, необходимо записать в регистр направления передачи DDRT код $FF.

/*----------------------------------------------*/

/* МAIN PROGRAМ:                                */

/*                                              */

/*подключаемые файлы*/

#include <912b32.h>


void main{void) {

 unsigned char DDRT_INI = 0xFF;

 DDRT = DDRT_INI; //установить порт PORT T на вывод

 PORTT = 0x62;

}

/*                                              */

4.6.1. Спецификация портов ввода/вывода

 Сделать закладку на этом месте книги

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

• PORT A. В однокристальном режиме работы — 8-разрядный порт ввода/вывода общего назначения. Направление передачи каждой линии порта определяется соответствующим битом регистра DDRA. В расширенном режиме работы на линиях порта формируются сигналы старшего байта мультиплексированной магистрали адрес/данные ADDR15–8/DATA15–8. В расширенном режиме с 8 разрядной шиной линии порта представляют собой мультиплексированную магистраль ADDR15–8/DATA7–0.

• PORT B. В однокристальном режиме работы — 8-разрядный порт ввода/вывода общего назначения. Направление передачи каждой линии порта определяется соответствующим битом регистра DDRB. В расширенном режиме работы на линиях порта формируются сигналы младшего байта мультиплексированной магистрали адрес/данные ADDR7–0/DATA7–0. В расширенном режиме с 8-разрядной шиной линии порта представляют собой немультиплексированную магистраль ADDR7-0.



• PORT AD. Однонаправленный 8-разрядный порт ввода. Все линии имеют альтернативную функцию. Если работа модуля аналого-цифрового преобразователя ATD разрешена, то линии порта используются для подключения измеряемых аналоговых сигналов.

• PORT T. Двунаправленный 8-разрядный порт ввода/вывода общего назначения. Направление передачи каждой линии порта определяется соответствующим битом регистра DDRT. Альтернативная функция линий порта PORT T — обслуживание модуля таймера. Если работа таймера разрешена, то линии используются в качестве входов входного захвата IC или выходов выходного сравнения OC.

• PORT S. Двунаправленный 8-разрядный порт ввода/вывода общего назначения. Направление передачи каждой линии порта определяется соответствующим битом регистра DDRS. Альтернативная функция линий порта PORT S — обслуживание модулей последовательного обмена SCI и SPI.

• PORT P. Двунаправленный 8-разрядный порт ввода/вывода общего назначения. Направление передачи каждой линии порта определяется соответствующим битом регистра DDRP. Четыре линии порта PORT P могут использоваться в качестве выходов модуля генератора ШИМ-сигнала (модуль PWM), если работа последнего программно разрешена.

• PORT DLC. Двунаправленный 8-разрядный порт ввода/вывода общего назначения. Направление передачи каждой линии порта определяется соответствующим битом регистра DDRDLC. Альтернативная функция двух линий порта PORT DLC — обслуживание модуля последовательного обмена в стандарте BDLC.


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

В МК семейства 68HC12/HCS12 каждый двунаправленный порт ввода/вывода общего назначения обслуживается двумя регистрами специальных функций. Это регистр данных порта и регистр направления передачи DDRx (вместо буквы «x» следует подставить буквенное обозначение порта). Если линии порта общего назначения настроены на ввод, то операция чтения регистра данных возвращает состояние выводов корпуса МК, с которыми связан порт. Если порт настроен на вывод, то операция записи в регистр данных устанавливает на выводах корпуса МК, связанных с портом, соответствующие логические уровни. Регистр DDRx определяет направления передачи каждой линии порта независимо от других линий этого же порта. Если какой либо бит регистра DDRx равен 0, то соответствующая линия настраивается на ввод, если 1 — то на вывод. Возможны решения, при которых часть линий одного и того же порта настроена на ввод, а часть на вывод. Например, при значении DDRx=10110010 линии D6, D3, D2 и D0 развернуты на ввод, а линии D7, D5, D4 и D1 — на вывод. В состоянии сброса МК все биты регистров направления передачи DDRx сбрасываются, поэтому сразу после включения питания все линии портов МК сконфигурированы как входы с высоким входным сопротивлением.

Часть портов ввода/вывода обслуживается дополнительными регистрами управления:

• PUCR (Pull Up Control Register) — регистр разрешения схемотехники подтягивающих резисторов. Формат регистра представлен на рис. 4.8. Если соответствующие биты регистра установлены, то в портах PORT A, PORT B и Port E при конфигурировании какой либо линии порта на ввод автоматически подключается встроенный подтягивающий к напряжению питания резистор. Если же эта линия настраивается на вывод, то встроенный резистор автоматически отключается. В расширенных режимах работы МК, когда названные порты используются для формирования сигналов внешних магистралей адреса, данных и управления, встроенные резисторы также автоматически отключаются.



Рис. 4.8. Формат регистров PUCR, RDRIV, PEAR


• RDRIV (Reduced DRIVe Register) — регистр выбора режима работы выходных каскадов с пониженными выходными токами. Формат регистра также представлен на рис. 4.8. Как следует из рис. 4.8, в МК B32 этот режим также доступен только для портов PORT A, PORT B и PORT E. В МК иных моделей этой функцией могут обладать также и другие порты. Если функция для порта разрешена установкой разряда RDPx в 1, то при конфигурировании какой либо линии порта на вывод ее выходной ток снижается с 0,6 мА до 0,3 мА.

• PEAR (Port E Assignment Register) — регистр выбора назначения линий порта Port E. Отдельные биты этого регистра (рис. 4.8) позволяют назначить линии альтернативную функцию или функцию линии ввода/вывода общего назначения.


Вопросы для самопроверки

1. Сколько портов ввода/вывода в МК B32?

Ответ: МК B32 имеет в своем составе восемь 8 разрядных портов (A, B, E, AD, T, S, P, DLC).

2. Какие альтернативные функции реализуют порты AD, T, S, P, DLC?

Ответ: Линии порта AD служат аналоговыми входами встроенного АЦП, порт T используется модулей таймера, на выходах порта P формируются ШИМ сигналы, порт S обслуживает контроллера последовательного ввода/вывода SCI и SPI.

3. Каково назначение регистра направления передачи порта?

Ответ: Каждый разряд этого порта определяет направление передачи соответствующей линии порта.

4. В какое состояние устанавливается регистр направления передачи во время сброса МК?

Ответ: Сбрасывается, т.е. устанавливается в 0. При этом все линии портов конфигурируются на ввод.


Пример применения

В этом примере мы подключили в порту PORTA группу зеленых и красных светодиодов. Схема подключения показана на рис. 4.9. Мы обсудим эту схему подробно в гл.5. А сейчас лишь договоримся, что если на линии порта установлена 1, то будет гореть зеленый светодиод, если логический 0 — то красный светодиод. А если линия порта переведена в состояние ввода, т.е. она представляется для цепи светодиодов нагрузкой с высоким входным сопротивлением, то оба светодиода окажутся погашенными. На рис. 4.10 приведена блок-схема алгоритма программы, которая зажигает на 30 мс зеленым цветом светодиоды с четными номерами и одновременно красным цветом светодиоды с нечетными номерами. Следующие 30 мс светодиоды «меняются цветами», далее этот процесс продолжается до бесконечности. Ниже приведен текст программы на языке Си, который реализует этот алгоритм.



Рис. 4.9. Схема отображения состояния порта PORTA


Схема содержит 8 идентичных светодиодных индикаторов для логических выходов с тремя состояниями. Индикатор каждого разряда состоит из двух светодиодов: зеленого и красного. Если на выходе порта PORTA[i] логическая 1,то светится зеленый светодиод, если логический 0 — то красный. Если линия порта PORTA[i] настроена на ввод, то ни один из светодиодов этого разряда порта не светится.



Рис. 4.10. Блок схема алгоритма управления светодиодами


/*----------------------------------------------------------------------*/

/* МAIN PROGRAМ: Эта программа зажигает на выходах порта PORTA          */

/* 30 мс зеленым цветом горят светодиоды на выходах порта с четными     */

/* номерами, красным цветом –светодиоды на выходах порта с нечетными    */

/* номерами. Следующие 30 мс на месте зеленых горят красные, и наоборот */

/*----------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>


/*используемые функции*/

void delay_100us(void);

void delay_30ms(void);


void main{void) {

 DDRA = 0xFF; //установить порт PORTA на вывод

 while(1) {

  PORTA = 0x55;

  delay_30ms();

  PORTA = 0xAA;

  delay_30ms();

 }

}


/*-----------------------------------------------------------------------*/

/* Функция delay_30ms формирует задержку в 30 мс, частота тактирования   */

/* межмодульных магистралей МК составляет 8 МГц                          */

/*-----------------------------------------------------------------------*/

void delay_30ms(void) {

 int i;

 for (i=0; i<=299; i++) delay_100us();

}


/*-----------------------------------------------------------------------*/

/* Функция delay_100us формирует задержку в 100 мкс, частота тактирования*/

/* межмодульных магистралей МК составляет 8 МГц                          */

/*-----------------------------------------------------------------------*/

void delay_100us(void) {

 int j;

 for (j=0; j<50; j++) {

  asm("nop\n");

 }

}

/*-----------------------------------------------------------------------*/

Обратите внимание, что функция задержки на 30 мс использует вложенную функцию задержки на 100 мкс. В приведенном тексте программы для формирования задержки на 100 мкс используются 50 циклов повторения операторов функции delay_100us. Выбор числа повторений производился из предположения, что данная программа будет исполняться микроконтроллером, частота внутренней шины которого составляет 8 МГц. По результатам рассмотрения файла в формате *.lst было установлено, что команды ассемблера, соответствующие одному повторению цикла функции delay_100us , реализуются за 16 машинных циклов. При частоте шины в 8 МГц для формирования временного интервала в 100 мкс потребуется 800 машинных циклов. Поэтому число повторений цикла функции delay_100us должно составлять 800/16 = 50. Если бы эта программа исполнялась бы микроконтроллером DP256, частота внутренней шины которого составляет 25 МГц, то число циклов функции delay_100us должно было бы быть увеличено до 156.

4.7. Подсистема памяти МК B32

 Сделать закладку на этом месте книги

Подсистема памяти МК семейства 68HC12/HCS12 включает четыре различных модуля памяти: энергонезависимая Flash-память программ, энергонезависимая EEPROM память данных, статическое ОЗУ и блок регистров специальных функций для управления режимами работы периферийных модулей. Расположение различных модулей памяти в адресном пространстве МК принято отражать на так называемой карте памяти. Карта памяти МК B32 представлена на рис. 4.11. Указанные на ней адреса будут действительны при выходе МК из состояния сброса. В ходе исполнения прикладной программы адресное пространство для каждого модуля памяти может быть изменено (см. 4.5.1.). Тогда для обращения к ячейкам памяти будут использоваться не указанные на рис. 4.11 физические адреса, а измененные виртуальные адреса.



Рис. 4.11. Карта памяти МК B32 в составе отладочной платы MC68HC912B32EVB


Микроконтроллер B32 предназначен для использования преимущественно в однокристальном режиме работы. Он содержит в себе 32Кб ПЗУ программ, 768 байт памяти типа EEPROM, 1Кб статического ОЗУ и 512 регистров управления.

Строго говоря, аббревиатура EEPROM (Electrically Erasable Programmable ROM) обозначает энергонезависимую память с электрическим программированием и электрическим стиранием. Поэтому и резидентная память программ, выполненная на основе технологии FLASH, и энергонезависимая память данных должны быть характеризованы как EEPROM. Однако энергонезависимая память программ и энергонезависимая память данных отличаются по своим свойствам не только на уровне технологии изготовления, но и на уровне разработчика встраиваемых систем. Память типа Flash допускает выполнение операции стирания только над некоторым множеством ячеек, что неудобно при необходимости замены только одного байта информации. Энергонезависимая память данных позволяет стереть и потом запрограммировать один байт информации. Однако ячейки памяти с подобным свойством занимают значительную площадь полупроводникового кристалла МК, поэтому на их основе не может быть выполнена память программ большого объема. Во избежание путаницы у российских разработчиков принято использовать аббревиатуру EEPROM только для памяти с побайтным стиранием и побайтным программированием. А память со стиранием блоками обозначают как Flash, хотя и эта память по своим свойствам относится к EEPROM.

Используя МК от Freescale Semiconductor, в частности семейство 68HC12/HCS12 следует знать, что гарантированное число циклов стирания/программирования для МК HCS12 составляет 10000, а для МК 68HC12 — всего 100. Именно поэтому во многих отладочных средствах на основе МК 68HC12 рекомендуется промежуточные версии программы записывать и исполнять из ОЗУ. Поскольку резидентное ОЗУ у микроконтроллеров обладает недостаточным объемом для размещения программы, то многие отладочные платформы используют расширенный режим работы МК с подключением внешнего ОЗУ. В МК семейства HCS12 для целей отладки обычно используется внутреннее Flash ПЗУ программ, т.к. 10000 циклов перезаписи обычно достаточно для внесения всех исправлений в процессе отладки.


Пример применения

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

4.7.1. Карта памяти МК B32

 Сделать закладку на этом месте книги

Карта памяти МК определяет, по каким адресам в конкретной модели МК расположены блоки памяти. Процессорное ядро HC12 позволяет линейно адресовать 64К слов памяти. Поскольку МК 68HC12 используют однобайтовые ячейки памяти, то получается, что при линейной адресации в МК семейства 68HC12 адресуют 64 Кб памяти. Определение «линейная адресация» означает, что в любой момент времени без применения дополнительных команд МК может обратиться к ячейке памяти с любым адресом из диапазона $0000…$FFFF.

Карта памяти МК B32 приведена на рис. 4.11. Резидентная память (т.е. память, расположенная на кристалле МК) включает четыре блока памяти: 512 байт регистров специальных функций для управления периферийными модулями, 1 Кб оперативного запоминающего устройства для хранения промежуточных результатов вычислений, 768 байт энергонезависимой памяти типа EEPROM с побайтным стиранием и побайтным программирования для хранения уставок программы пользователя, 32 Кб энергонезависимой Flash памяти для размещения прикладной программы пользователя. На рис. 4.11 карта памяти учитывает особенности размещения резидентной программы отладки D-Bug12 при работе МК в составе платы отладки MC68HC912B32EVB:

• $8000…$F600 — код программы отладчика D-Bug12;

• $F680…$F6BF — область пользователя;

• $F6C0…$F6FF — область D-Bug12;

• $F700…$F77F — код запуска D-Bug12;

• $F780…$F7FF — таблица векторов для режима отладки;

• $F800…$FBFF — зарезервированная разработчиком область;

• $FC00…$FFBF — код программы загрузчика в EEPROM;

• $FFC0…$FFFF — вектора сброса и прерывания.

Из представленного распределения адресного пространства МК в составе платы отладки видно, что код программы отладчика занимает практически всю область Flash ПЗУ, которая в реальных проектах предназначается для прикладной программы управления. А где же предполагается размещать отлаживаемую программу? Ответ на этот вопрос Вы найдете в параграфе 4.3.1.

4.7.2. Изменение адресов в карте памяти МК

 Сделать закладку на этом месте книги

Внимательно проана


убрать рекламу






лизировав распределение адресного пространства в карте памяти МК, можно заметить, что часть доступного адресного пространства не используется резидентной памятью микроконтроллера. Так в МК B32 (рис. 4.11) в диапазоне адресов $01FF…$0800, $0BFF…$0D00 и $0FFF…$8000 память отсутствует. Именно это незанятое адресное пространство может быть использовано для подключения внешней памяти в расширенных режимах работы МК. В процессе подключения внешней памяти может оказаться, что отдельные блоки внутренней памяти МК желательно «переместить» в пределах адресного пространства МК. Тогда схемотехника подключения внешней памяти упростится. Для назначения новых, виртуальных адресов блоков резидентной памяти МК предназначены три регистра специальных функций:

• INITRG — регистр базового адреса блока регистров специальных функций;

• INITRM — регистр базового адреса блока ОЗУ;

• INITEE — регистр базового адреса блока EEPROM.

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

4.8. Подсистема памяти МК DP256

 Сделать закладку на этом месте книги

Карта памяти для МК DP256 приведена на рис. 4.12. Расположение различных модулей памяти в адресном пространстве МК чрезвычайно похоже на рассмотренный ранее МК B32. Основное отличие подсистемы памяти DP256 от B32 — это наличие системы страничной адресации, которая позволяет обращаться к более чем 64 Кб памяти с использованием 16 разрядной магистрали адреса. Объем резидентной памяти МК DP256 составляет 256 Кб. Модули резидентного ОЗУ, EEPROM и регистры специальных функций доступны, как и ранее, с использованием обычной адресации в пределах 64 Кб (см. рис. 4.12). Основная часть ПЗУ программ разделена на страницы по 16 Кб, причем каждая из страниц может отображаться на одном и том же адресном пространстве $8000–$BFFF. Выбор конкретной страницы осуществляется занесением под управлением программы ее кода в специальный регистр. Поэтому частое переключение между страницами программной памяти замедляет исполнение программы.



Рис. 4.12. Карта памяти МК семейства HCS12 DP256



Вопросы для самопроверки

1. Каков объем Flash памяти программ МК B32?

Ответ: 32 Кб.

2. Как занести программу пользователя во Flash-память МК B32, установленного на отладочной плате M68EVB912B32?

Ответ: Для этого может быть использована программа загрузчика, которая поместит программу пользователя в область EEPROM, начиная с адреса $D000, или в область Flash ПЗУ начиная с адреса $8000. Однако в последнем случае программа монитора отладки D-Bug12 будет потеряна.

3. Сколько раз можно перепрограммировать резидентное Flash ПЗУ программ МК?

Ответ: 100 раз в МК семейства 68HC12 и 10000 раз в МК семейства HCS12.

4. Сколько раз можно перезаписать данные в энергонезависимой памяти данных типа EEPROM?

Ответ: гарантированное число циклов стирания/программирования резидентной энергонезависимой памяти данных равно 10000. На практике это число значительно больше.

4.9. Состояния сброса и прерывания МК

 Сделать закладку на этом месте книги

В процессе исполнения прикладной программы МК реализует монотонную многократно повторяющуюся последовательность действий:

• Выборку кода команды из памяти программ в регистр команды центрального процессора;

• Дешифрацию кода команды;

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

• Исполнение команды;

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

Если исполняется линейная последовательность команд, то содержимое счетчика PC центрального процессора постоянно увеличивается на 1, обеспечивая выборку из памяти следующих команд прикладной программы. Линейная последовательность исполняемых команд может быть изменена под управлением самой программы, например инструкциями «jmp» или «branch». При этом в счетчик команд под управлением программы будет записано новое число, и начнется исполнение следующего линейного фрагмента программы из другого сегмента памяти программ. Несмотря на явные различия механизмов формирования следующего за исполнением текущей операции значения счетчика команд PC, в обоих рассмотренных случаях это следующее значение PC определяется ходом вычислительного процесса и предсказывается программистом в ходе написания прикладной программы.

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

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

4.9.1. Реакция МК на внешние события

 Сделать закладку на этом месте книги

Рассматривая далее технические особенности подсистемы прерывания МК семейства 68HC12/HCS12, мы должны обсудить общие для всех микропроцессорных систем алгоритмы обработки прерываний:

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

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

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

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

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

Отметив эти общие свойства подсистемы прерывания, обратимся к более подробному рассмотрению последней в МК семейства 68HC12/HCS12.

4.10. Состояния сброса и прерывания в МК 68HC12

 Сделать закладку на этом месте книги

МК семейства 68HC12/HCS12 обладают мощной системой обработки исключений. По способу реакции микроконтроллера на возмущающие события исключения делятся на прерывание и на сброс. В русскоязычной литературе используют следующие словосочетания с терминами «прерывание» и «сброс» (прим. переводчика):

• МК реализует прерывание или МК находится в состоянии прерывания;

• МК находится в состоянии сброса или в состоянии начального запуска.

Прерывания в свою очередь делятся на маскируемые и немаскируемые. Полный список источников исключений в МК семейства 68HC12/HCS12 с указанием способа обработки исключения по каждому источнику события приведен на рис. 4.13. В следующих параграфах мы обсудим особенности работы внутренних ресурсов МК в процессе обработки каждого упомянутого на рис. 4.13 исключения.



Рис. 4.13. Классификация исключений 68HC12

4.10.1. Состояние сброса МК

 Сделать закладку на этом месте книги

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

Различают четыре источника событий, которые переводят МК в состояние сброса:

• Внешний сброс (External reset). Все МК семейства 68HC12/HCS12 имеют специальный вывод корпуса RESET для подачи сигнала внешнего сброса. Активный уровень сигнала – логический 0. Пока на входе RESET удерживается низкий уровень сигнала, МК будет находиться в состоянии сброса. После перевода линии RESET в состояние логической 1 МК перейдет в активный режим работы по истечении задержки, которая составляет 4096 периодов системной магистрали МК.

• Внутренний сброс по нарастанию напряжения питания (Power on reset — POR). Нарастание напряжения на входе VDD микроконтроллера вызывает состояние сброса. Таким образом реализуется начальный запуск МК с однозначно определенной аппаратной конфигурацией и с известным начальным адресом запускаемой на исполнение программы.

• Внутренний сброс по сторожевому таймеру (Computer Operating Properly reset — COP). Логика работы сторожевого таймера позволяет микроконтроллеру выявлять перемежающиеся ошибки в исполнении прикладной программы, которые могут возникнуть в результате электромагнитных помех или при колебаниях напряжения питания микропроцессорной системы. В процессе отладки работа сторожевого таймера запрещена. Работа модуля сторожевого таймера разрешается в конечном варианте прикладной программы, который используется при работе МК в системе. Сторожевой таймер — это счетчик, коэффициент счета которого настраивается пользователем при инициализации системы. Счетчик начинает счет внутренних тактовых импульсов в момент начала исполнения программы. Если счетчик переполнится, то МК перейдет в состояние сброса. Правильно исполняемая прикладная программа, в которой очередность исполнения операторов совпадает с предусмотренной программистом очередностью, должна постоянно сбрасывать сторожевой таймер. Тогда внутреннего сброса от него случаться не будет. Для сброса сторожевого таймера в МК семейства 68HC12/HCS12 необходимо в регистр COPRST записать сначала код $55, а затем код $AA. При создании конечного кода прикладной программы разработчик должен разместить операции записи приведенной последовательности кодов так, чтобы исполнение программы по любому возможному пути обеспечивало бы выполнение команд сброса через меньшие интервалы времени, чем период переполнения сторожевого таймера.

• Внутренний сброс по отклонению частоты тактовых импульсов МК (Clock Monitor reset). МК переводится в состояние сброса, когда модуль встроенного генератора тактирования обнаруживает выход частоты тактирования за заданные пределы или просто останов системы тактирования. После перехода в состояние сброса в счетчик команд центрального процессора автоматически загружается так называемый вектор сброса. Вектор сброса — это адрес ячейки памяти, в которой расположен первый оператор исполняемой программы. После загрузки начального адреса программа запускается на исполнение. Два источника сброса: сторожевой таймер и монитор частоты тактирования — обладают собственными векторами сброса (см. рис. 4.17).



Период переполнения сторожевого таймера

CR[2:0] Делитель Период переполнения сторожевого таймера
4 МГц 8 МГц
000 Не используется нет нет
001 213 2,048 мс 1,024 мс
010 215 8,192 мс 4,096 мс
011 217 32,768 мс 16,384 мс
100 219 131,072 мс 65,536 мс
101 221 524,288 мс 262,144 мс
110 222 1,048 с 524,288 с
111 223 2,097 с 1,048576 с

Рис. 4.14. Формат регистров COPCTL, COPRST



Регистры сторожевого таймера и монитора тактирования

Два регистра специальных функций используются МК семейства 68HC12/HCS12 для управления генерацией сигналов сброса от сторожевого таймера и монитора тактирования:

• COPCTL — регистр управления сторожевого таймера.

• COPRST — регистр сброса сторожевого таймера.

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

Назначение битов регистра COPCTL:

• CME — разрешает (CME=1) или запрещает (CME=0) работу монитора тактирования.

• FCME — разрешает работу монитора тактирования (FCME=1) независимо от значения бита CME.

• FCM — установка под управлением программы этого бита в 1 генерирует внутренний сброс по монитору тактирования.

• FCOP — установка под управлением программы этого бита в 1 генерирует внутренний сброс по переполнению сторожевого таймера.

• DISR — запрещает (при DISR=1) или запрещает (при DISR=0) перезапуск МК по установленным битам FCM и FCOP.

• CR2…CR0 задают коэффициент счета сторожевого таймера. Численные значения периода переполнения сторожевого таймера для некоторых частот системной шины МК приведены на рис. 4.14.

Регистр COPRST предназначен для сброса сторожевого таймера. В этот регистр под управлением программы должна быть записана последовательность кодов: сначала $55, затем $AA. И сторожевой таймер будет сброшен.

4.10.2. Прерывания

 Сделать закладку на этом месте книги

Мы рассмотрели один из способов реализации исключений в микроконтроллерах — это сброс МК. Другой способ принудительного изменения содержимого программного счетчика центрального процессора — это прерывания, которые в МК семейства 68HC12/HCS12 делятся на маскируемые и немаскируемые.

Программно логическая модель центрального процессора содержит регистр признаков CCR, формат которого представлен на рис. 4.15. Особенностью всех семейств МК от компании Freescale Semiconductor является наличие в регистре признаков не только флагов результатов операции, но и дополнительных битов управления подсистемой прерывания. В составе регистра признаков МК 68HC12/HCS12 — два таких бита. Бит I — глобальная маска прерываний — используется для управления маскируемыми прерываниями. Бит X — бит запрета немаскируемых прерываний — управляет немаскируемыми прерываниями. Оба этих бита устанавливаются в 1 в состоянии сброса МК. Обратите внимание, в МК 68HC12/HCS12 установка битов I и X запрещает соответствующие прерывания.



Рис. 4.15. Формат регистра состояния CCR



Немаскируемые прерывания

В соответствие со своим названием немаскируемые прерывания не могут быть отключены пользователем. Однако в предыдущем абзаце было упомянуто, что установка бита X в 1 запрещает немаскируемые прерывания. Значение бита X действительно равно 1 в состоянии сброса МК. Однако далее он может быть установлен в 0 под управлением программы инициализации, разрешая тем самым немаскируемые прерывания. Далее этот бит не может быть изменен под управлением программы, и в этом его отличие от бита глобальной маски прерываний I.

Три типа немаскируемых прерываний реализуются в МК 68HC12/HCS12:



• Прерывание по несуществующему коду команды. Каждая инструкция языка ассемблер МК имеет собственный код. В МК 68HC12/HCS12 коды операций могут быть однобайтовыми и двухбайтовыми. Но не все теоретически возможные коды использованы для кодирования реальных команд процессорного ядра CPU12. Если на этапе выборки кода команды из памяти произошло считывание несуществующего кода команды, то генерируется запрос на немаскируемое прерывание.

• Программное прерывание — инструкция SWI. Система команд МК 68HC12/HCS12 имеет инструкцию программного прерывания, которая позволяет перейти к исполнению подпрограммы прерывания из прикладной программы.


Маскируемые прерывания




Рис. 4.16. Внешняя цепь для подключения сигналов нескольких внешних запросов на прерывание


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

• Прерывание по событию канала захвата/сравнения (IC/OC) таймера. Восемь одинаковых блоков в составе модуля таймера, которые именуют «каналами», предназначены для контроля за уровнем сигнала на входе канала или для изменения в строго определенный момент времени логического уровня на выходе канала. Заданное программистом изменение входного или выходного сигнала канала рассматривается как событие, которое генерирует запрос на прерывание. Например, если канал настроен на слежение за перепадом входного сигнала из 1 в 0, то когда такое изменение произойдет, будет выставлен запрос на прерывание.

• Прерывание по переполнению таймера. Основным блоком модуля таймера является 16 разрядный счетчик временной базы. Этот счетчик невозможно остановить. Также невозможно изменить его коэффициент счета, который составляет 216 = 65536. Поэтому регулярно счетчик временной базы изменяет свой код с $FFFF на $0000. Такое изменение кода называют переполнением счетчика. В момент переполнения по желанию программиста может генерироваться запрос на прерывание, в то время как счетчик продолжает считать дальше. Такие прерывания особенно удобны при необходимости измерения очень больших временных интервалов. Для этого в микроконтроллере производят подсчет, сколько переполнений счетчика произошло за этот временной интервал, и, зная период счета счетчика, определяют длительность исследуемого временного интервала.

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

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

• Прерывание от модулей контроллеров последовательного ввода/вывода SCI и SPI. Каждый модуль последовательного ввода/вывода формирует целую группу запросов на прерывание: при завершении передачи слова, при приеме слова, при обнаружении различного рода нарушений в протоколе передачи информации.

• Прерывание от модуля АЦП. Модуль аналого-цифрового преобразователя формирует запрос на прерывание, когда процесс оцифровки очередного сигнала завершен, и двоичный код сигнала может быть считан в память МК.

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


Вопросы для самопроверки

1. Каковы различия между прерыванием и сбросом? 

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

2. Каково различие между маскируемыми и немаскируемыми прерываниями?

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









4.10.3. Вектора исключений

 Сделать закладку на этом месте книги

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

В МК семейства 68HC12/HCS12 начальные адреса подпрограмм прерывания и начального запуска располагаются в специальной области памяти, которая называется таблицей векторов прерывания. Таблица векторов прерывания размещается в последних 128 ячейках резидентной линейно адресуемой Flash памяти программ. Это означает, что независимо от того, каким реальным объемом резидентного ПЗУ обладает конкретная модель МК, имеет или не имеет этот МК страничную адресацию памяти программ, таблица векторов прерывания будет помещена в адресном пространстве $FF80…$FFFF. Причем, не все 128 ячеек памяти могут быть заняты векторами исключений. Объем таблицы векторов определяется числом источников прерываний и сброса в конкретной модели МК.

Адреса вектора Источник исключения Глобальная маска в регистре CCR Биты разрешения прерывания в регистрах специальных функций Значение регистра HPRIO для установления наивысшего уровня приоритета
Регистр Бит
$FFFE, $FFFF Внешний сброс нет нет нет
$FFFC, $FFFD Сброс от системы тактирования нет COPCTL CME, FCME
$FFFA, $FFFB COP нет нет COP rate selected
убрать рекламу






valign="top">$FFF8, $FFF9
Сброс по несуществующему коду команды нет нет нет
$FFF6, $FFF7 Программное прерывание SWI нет нет нет
$FFF4, $FFF5 Внешнее прерывание XIRQ X нет нет
$FFF2, $FFF3 Внешнее прерывание IRQ I INTCR IRQEN $F2
$FFF0, $FFF1 Метки реального времени RTI I RTICTL RTIE $F0
$FFEE, $FFEF Канал 0 таймера I TMSK1 C0I $EE
$FFEC, $FFED Канал 1 таймера I TMSK1  C1I $EC
$FFEA, $FFEB Канал 2 таймера I TMSK1 C2I $EA
$FFE8, $FFE9 Канал 3 таймера I TMSK1 C3I $E8
$FFE6, $FFE7 Канал 4 таймера I TMSK1 C4I $E6
$FFE4, $FFE5 Канал 5 таймера I TMSK1 C5I $E4
$FFE2, $FFE3 Канал 6 таймера I TMSK1 C6I $E2
$FFE0, $FFE1 Канал 7 таймера I TMSK1 C7I $E0
$FFDE, $FFDF Переполнение счетчика таймера I TMSK1 TOI $DE
$FFDC, $FFDD Переполнение счетчика внешних событий I PACTL PAOVI $DC
$FFDA, $FFDB Событие на входе счетчика внешних событий I PACTL PAI $DA
$FFD8, $FFD9 Контроллер SPI I SP0CR1 SPIE $D8
$FFD6, $FFD7 Контроллер SCI I SP0CR2 TIE, TCIE, RIE, ILIE $D6
$FFD4, $FFD5 зарезервирован I $D4
$FFD2, $FFD3 Модуль ATD I ATDCTL2 ASCIE $D2
$FFD0, $FFD1 Модуль BDLC I BCR1 IE $D0
$FF80, $FFC1 зарезервирован I $80–$C0
$FFC2, $FFC9 зарезервирован I $C2–$C8
$FFCA, $FFCB Переполнение счетчика внешних событий B I PBCTL PBOVI $CA
$FFCC, $FFCD Переполнение счетчика I MCCTL MCZI $CC
$FFCE, $FFCF зарезервирован I $CE

Рис. 4.17. Таблица векторов сброса и прерывания для МК MC68HC912B32






Рис. 4.18. Формат регистра INTCR


Внимательный читатель должен был заметить, что адреса ячеек памяти, в которых располагаются вектора исключений, находятся в защищенной области памяти. Эту область памяти невозможно стереть и затем занести в нее новые вектора. Для того чтобы программист в процессе отладки все-таки имел возможность использования подсистемы прерывания с произвольными векторами входа в подпрограммы, в отладочном режиме работы МК семейства 68HC12/HCS12 используют дополнительную таблицу векторов, которая располагается в незащищенной области памяти. Соответствие адресов таблиц векторов прерывания в отладочном и пользовательском режиме работы приведено на рис. 4.19. На рис. 4.19 представлены альтернативные адреса размещения векторов прерываний для МК MC68HC912B32. В других моделях МК альтернативная таблица может располагаться в области ОЗУ, поскольку она предназначена только для целей отладки.

Адреса вектора Источник исключения Адрес передачи управления
$FFC0–$FFCF зарезервирован $F7C0–$F7CF
$FFD0 Модуль BDLC $F7D0
$FFD2 Модуль ATD $F7D2
$FFD4 зарезервирован $F7D4
$FFD6 Контроллер SCI $F7D6
$FFD8 Контроллер SPI $F7D8
$FFDA Событие на входе счетчика внешних событий $F7DA
$FFDC Переполнение счетчика внешних событий $F7DC
$FFDE Переполнение счетчика таймера $F7DE
$FFE0 Канал 7 таймера $F7E0
$FFE2 Канал 6 таймера $F7E2
$FFE4 Канал 5 таймера $F7E4
$FFE6 Канал 4 таймера $F7E6
$FFE8 Канал 3 таймера $F7E8
$FFEA Канал 2 таймера $F7EA
$FFEC Канал 1 таймера $F7EC
$FFEE Канал 0 таймера $F7EE
$FFF0 Метки реального времени RTI $F7F0
$FFF2 Внешнее прерывание IRQ $F7F2
$FFF4 Внешнее прерывание XIRQ $F7F4
$FFF6 Программное прерывание SWI $F7F6
$FFF8 Сброс по несуществующему коду команды $F7F8
$FFFA COP $F7FA
$FFFC Сброс от системы тактирования $F7FC
$FFFE Внешний сброс $F7FE  

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

4.10.4. Система приоритетов для исключений

 Сделать закладку на этом месте книги

Среди представленного множества событий, которые могут вызвать исключения, ряд событий обладают большей значимостью для системы, чем другие. В микропроцессорной технике значимость события характеризуют термином «приоритет». События большей значимости обладают более высоким приоритетом. Рассматривая множество исключений для 68HC12/HCS12, можно отметить, что все немаскируемые источники исключений по умолчанию наделены более высоким приоритетом, нежели маскируемые. Поэтому, если в один и тот же момент времени поступят два запроса, то первым будет обслужен немаскируемый запрос, который обладает более высоким приоритетом. Затем будет выполнена подпрограмма обслуживания запроса с низшим приоритетом, в нашем случае этот запрос маскируемый.

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



2. Сброс по монитору системы тактирования;

3. Сброс по переполнению сторожевого таймера COP;

4. Программное прерывание SWI;



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


Вопросы для самопроверки

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

Ответ: Код $D2 следует записать в регистр уровня приоритета HPRIO.

2. Приведите запись выражения на Си, которое реализует действие вопроса 1.

Ответ: HPRIO = 0xD2

3. Как изменятся приоритеты немаскируемых и маскируемых исключений после изменения приоритета прерывания от модуля АЦП в результате действий вопроса 1 или 2?

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





4.10.5. Регистры подсистемы прерывания

 Сделать закладку на этом месте книги

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



• HPRIO — регистр уровня приоритета.





Рис. 4.20. Формат регистра HPRIO




4.11. Процесс перехода к подпрограмме прерывания

 Сделать закладку на этом месте книги

На рис. 4.12 показана последовательность действий МК семейства 68HC12/HCS12 по обработке запроса на прерывание, начиная с момента поступления запроса и заканчивая возвратом из подпрограммы прерывания к продолжению исполнения основной программы. При изучении механизма перехода к подпрограмме прерывания и возврата из нее Вам следует обратить внимание на то, какие действия совершаются аппаратными средствами МК, т.е. автоматически, а какие требуют программной поддержки, т.е. должны сопровождаться написанием специального программного кода.

Первый шаг при разработке прикладной программы, которая будет содержать подпрограммы прерывания, — создание в памяти таблицы векторов прерываний. Для этого в ячейки памяти с указанными в техническом описании МК адресами должны быть помещены адреса начала соответствующих подпрограмм прерывания. При написании исходного текста программы начальные адреса подпрограмм прерывания могут быть указаны в абсолютных значениях, т.е. в численном виде. Однако это неудобно при отладке программы, когда в результате исправления ошибок эти адреса будут изменяться. Поэтому более грамотно указывать в таблице векторов прерывания символьные имена подпрограмм прерывания. При программировании на ассемблере для этой цели обычно используется псевдокоманда Ассемблера «DW».

Второй шаг при разработке программы с прерываниями — инициализация начального значения указателя стека SP. Область стека используется микроконтроллером для хранения значений регистров центрального процессора во время исполнения подпрограммы прерывания. В МК семейства 68HC12/HCS12 при пересылке данных в память указатель стека сначала уменьшается на единицу, и только затем содержимое какого либо регистра загружается в память по новому адресу из SP. Поэтому начальное значение указателя стека должно быть равно увеличенному на единицу адресу последней ячейки в области стека. При программировании на Си программист обязан указать диапазон адресов области стека в опциях конфигурирования компилятора. Старший адрес этого диапазона будет загружен в указатель стека при исполнении файла Start.с.

Третий шаг — разрешить прерывания по выбранным источникам запросов. Это действие выполняется в два этапа. Сначала следует установить биты разрешения прерывания от каждого выбранного источника в соответствующем регистре специальных функций. Например, для прерывания от АЦП, должен быть установлен бит IRQEN в регистре INTCR. На втором этапе необходимо сбросить глобальную маску прерывания I в регистре признаков CCR. При программировании на ассемблере следует использовать команду «CLI».

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



Рис. 4.21. Последовательность действий МК при обслуживании запроса на прерывание


Наиболее вероятно, что запрос поступит в момент, когда центральный процессор уже начал, но еще не завершил исполнение очередной команды. В большинстве случаев исполнение текущей команды будет завершено, в счетчике PC будет сформирован адрес следующей команды основной программы, и только затем МК начнет процедуру перехода к подпрограмме прерывания. В отличие о других, МК семейства 68HC12/HCS12 обладают рядом специфических команд, время исполнения которых значительно превышает время исполнения традиционных команд ассемблера. К таким командам относятся инструкции нечеткой логики REV, REVW, WAV, которые могут потребовать для своего выполнения несколько сот циклов центрального процессора. Поэтому, при возникновении запроса, исполнение этих команд будет прервано с сохранением промежуточных результатов. Завершение исполнения инструкции произойдет после выполнения подпрограммы прерывания. Центральный процессор МК семейства 68HC12/HCS12 оснащен двухступенчатым конвейером команд. Это означает, что во время исполнения текущей команды регистры конвейера команд хранят выбранные из памяти коды двух следующих команд. Когда запрос на прерывание поступает, нормальный порядок исполнения команд фоновой программы нарушается. Поэтому хранящиеся в конвейере команд коды становятся бесполезными, и конвейер автоматически очищается. После этого в счетчике команд автоматически восстанавливается адрес первой не исполненной команды фоновой программы, к которой МК должен будет вернуться после прерывания. Далее содержимое программного счетчика PC и других регистров центрального процессора сохраняется в стеке. Последовательность загрузки в стек следующая (рис. 4.22): старший байт счетчика команд PCH, младший байт счетчика команд PCL, старший YH и младший YL байты индексного регистра Y, старший XH и младший XL байты индексного регистра X, аккумулятор B, аккумулятор A, регистр признаков CCR. Важно, что это сохранение выполняется микроконтроллером автоматически, никаких команд в подпрограмме прерывания для этого не требуется.

Адрес ячейки памяти Содержимое ячейки стека
Указатель стека – 2 Старший байт адреса возврата; младший байт адреса возврата
Указатель стека – 4 Старший байт регистра Y; младший байт регистра Y
Указатель стека – 6 Старший байт регистра X; младший байт регистра X
Указатель стека – 8 Аккумулятор B; Аккумулятор A
Указатель стека – 9 Регистр состояния CCR 

Рис. 4.22. Последовательность загрузки регистров центрального процессора в стек




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

По завершении исполнения подпрограммы прерывания, МК восстанавливает регистры центрального процессора из стека, включая программный счетчик PC, сбрасывает биты масок I и X в регистре CCR. Таким образом, в МК восстанавливается состояние центрального процессора, которое было до исполнения подпрограммы прерывания. И процесс выполнения фоновой программы возобновляется. В исходном тексте подпрограммы прерывания для ее корректного завершения записывается команда возврата из прерывания RTI. Именно эта команда реализует действия по восстановлению регистров из стека и сбросу масок прерывания. Обратите внимание, в начале подпрограммы прерывания для выгрузки регистров в стек и установки масок I и X не требуется команд. А для выполнения обратных действий программист должен воспользоваться командой RTI. При написании программы на Си подпрограмма прерывания оформляется как функция. При этом если объявлено, что функция является подпрограммой прерывания, то команда ассемблера RTI подставляется в исходный текст автоматически. Мы рассмотрим процесс составления исходного текста программы с прерываниями на Си в следующем параграфе.


Вопросы для самопроверки

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

• Инициализация таблицы векторов прерываний (программист);

• Инициализация указателя стека (программист);

• Разрешение прерываний в системе (программист);

• Завершение выполнения текущей команды (МК);

• Обнуление регистров конвейера команд (МК);

• Вычисление адреса возврата в основную программу (МК);

• Запоминание состояния регистров в стеке (МК);

• Установка в 1 бита I (МК);

• Загрузка из памяти вектора прерывания с максимальным приоритетом (МК);

• Передача управления подпрограмме прерывания (МК);

• Сброс сигнала запроса обслуживаемого прерывания (программист или МК, в зависимости от источника прерывания);

• Восстановление регистров центрального процессора из стека (программист командой RTI);

• Сброс маски I (МК);

• Возврат к исполнению основной программы (МК).

2. Каким образом МК семейства 68HC12/HCS12 определяет приоритет обслуживаемого запроса на прерывание?

Ответ: Последовательность расположения источников запросов в таблице векторов прерывания определяет их приоритет.

3. Часто в основной программе, которая содержит подпрограммы прерывания, одной из первых команд является команда SEI. Объясните почему?

Ответ: Простановка команды запрета маскируемых прерываний SEI в начале программы — своеобразный «хороший тон» при программировании. Эта команда запрещает прерывания во время инициализации периферии МК, т.е. когда МК находится в процессе создания своей внутренней структуры для решения конкретной задачи. Когда инициализация будет завершена, программист разрешит прерывания командой CLI.

4. Зачем МК семейства 68HC12/HCS12 очищает конвейер команд при прерываниях?

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

4.12. Оформление подпрограммы прерывания на Си

 Сделать закладку на этом месте книги

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

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

1. При написании программы обработки прерывания на Си, имя подпрограммы обработки прерывания должно быть объявлено с использованием специальной директивы препроцессора. В компиляторе ImageCraft ICC12 для этой цели следует использовать директиву #pragma:

#pragma interrupt_handler <name>

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

2. Далее по тексту подпрограмма прерывания оформляется как обычная функция. Компилятор в процессе перевода исходного текста этой функции на Си в инструкции ассемблера автоматически подставит в конце подпрограммы команду возврата из прерывания RTI, потому что эта функция была объявлена подпрограммой прерывания (директива #pragma на этапе 1).

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


убрать рекламу






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

4. Подсистема прерывания будет функционировать корректно, если для нее сформирована таблица векторов прерывания. Мы уже обсуждали, что таблица векторов прерывания в МК B32 находится в области Flash-памяти, которая защищена от перезаписи информации. Для того, чтобы пользователь имел возможность записать собственную таблицу векторов сброса и прерывания, в эту нестираемую область памяти записаны фиксированные вектора, которые передают управление по известным адресам в области перезаписываемой EEPROM памяти (см. рис. 4.19). По этим адресам программист должен вписать команду безусловного перехода JMP с адресом соответствующей подпрограммы обработки прерывания.

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

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

#define CLI() asm("cli\n"); //разрешить маскируемые прерывания

#define SEI() asm("sei\n"); //запретить маскируемые прерывания

Далее по тексту программы, если необходимо разрешить прерывания, то следует ввести CLI().

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


//объявление функции в модуле

void toggle_isr(void);


//директива #pragma для указания, что функция является подпрограммой

//обслуживания прерывания

#pragma interrupt_handler toggle_isr


//инициализация соответствующего вектора в таблице векторов прерываний

#pragma abs_address: 0xF7EA


//В32 RAМ based vector address

void (*Timer_Channel_2_interrupt_vector[])()={toggle_isr};

#pragma end_abs_address

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

 Сделать закладку на этом месте книги

Микроконтроллеры семейства 68HC12/HCS12 имеют в своем составе модуль генератора CGM (Clock Generation Module), который генерирует импульсные последовательности для тактирования центрального процессора, межмодульных магистралей, периферийных модулей в составе МК, а также внешние периферийные интегральные схемы. Структурная схема модуля CGM представлена на рис. 4.23.



Рис. 4.23. Структура модуля тактирования CGM


Микроконтроллеры семейства 68HC12/HCS12 используют три внутренних сигнала тактирования: TCLK, ECLK и PCLK. Эти сигналы образуются путем деления эталонной импульсной последовательности внутреннего генератора с внешним кварцевым резонатором. Сигнал TCLK предназначен для тактирования центрального процессора, импульсные последовательности ECLK и PCLK используются для тактирования межмодульных магистралей и различных периферийных модулей (рис. 4.23). Модуль тактирования CGM микроконтроллера B32 оснащен также дополнительным делителем, который позволяет существенно снизить частоту одной из импульсных последовательностей тактирования. Низкая частота тактирования таймерных модулей в некоторых применениях позволяет значительно упростить управляющую программу.

4.13.1.Система тактирования отладочной платы MC68HC912B32EVB

 Сделать закладку на этом месте книги

Микроконтроллер в составе платы отладки MC68HC912B32EVB тактируется от внешнего кварцевого резонатора с частотой 16 МГц. В модуле генератора CGM эта частота делится на 2, образуя импульсную последовательность для тактирования центрального процессора и межмодульных магистралей микроконтроллера с частотой 8 МГц. Эта же импульсная последовательность используется для тактирования всех периферийных модулей микроконтроллера: таймера, контроллеров последовательного обмена, АЦП. Многие периферийные модули обладают собственным делителем частоты. Этот делитель позволяет создать собственную внутреннюю частоту тактирования модуля, которая может не коррелироваться с частотами других модулей. Это удобно при проектировании.

Кварцевый резонатор может быть отключен от входа МК посредством переключателей на плате MC68HC912B32EVB. Вместо кварцевого резонатора для тактирования МК может быть использован внешний генератор или керамический резонатор. Последний обладает меньшей, чем кварцевый резонатор, стабильностью частоты, однако он является более дешевым компонентом. Мы не будем вносить каких-либо изменений в схемотехнику платы MC68HC912B32EVB. Поэтому далее на протяжении всей книги частота внутренней шины и центрального процессора МК будет составлять 8 МГц. Частота внутренней шины МК может быть понижена дополнительным делителем модуля CGM (рис. 4.23). Его коэффициент деления назначается под управлением программы и может составлять 1, 2, 4, …, 128. Для выбора желаемого коэффициента деления необходимо записать соответствующий таблице рис. 4.24 код в разряды SLDV2…SLDV0 регистра управления дополнительным делителем SLOW. Формат этого регистра приведен на рис. 4.24.



Выбор пониженной частоты межмодульных магистралей МК

SLDV[2:0] Коэффициент деления 2х При частоте внешнего кварцевого резонатора
16 МГц 8 МГц 4 МГц
000 1 8 МГц 4 МГц 2 МГц
001 2 4 МГц 2 МГц 1 МГц
010 4 2 МГц 1 МГц 500 кГц
011 8 1 МГц 500 кГц 250 кГц
100 16 500 кГц 250 кГц 125 кГц
101 32 250 кГц 125 кГц 62,5 кГц
110 64 125 кГц 62,5 кГц 31,2 кГц
111 128 62,5 кГц 31,2 кГц 15,6 кГц

Рис. 4.24. Формат регистра SLOW


Вы можете заинтересоваться, а зачем понижать частоту тактирования МК? Ведь тогда снизится его вычислительная производительность. Дело в том, что энергия потребления МК пропорциональна частоте его тактирования. Поэтому для достаточно медленных приложений, которые не требуют большой вычислительной производительности, частоту тактирования можно снизить ради экономии энергопотребления устройства управления. Понижение частоты тактирования возможно также для формирования таймерами необходимых временных интервалов. Например, если снизить частоту тактирования до 62,5 КГц (SLDV2…SLDV0 = 111), то период переполнения счетчика временной базы будет составлять около 1 с.

4.14. Подсистема реального времени — модуль таймера

 Сделать закладку на этом месте книги

Подсистема реального времени МК семейства 68HC12/HCS12 включает основной таймерный модуль, который имеет две модификации — TIM и ECT, и отдельный таймер меток реального времени.

Структура модуля таймера TIM (Timer Interface Module) ориентирована на реализацию трех основных функций:

• Входного захвата (IC — Input Capture). Функция входного захвата позволяет производить измерения временных параметров сразу нескольких импульсных сигналов на входах МК. Подсистема входного захвата может быть настроена на измерение длительности единичного или нулевого состояния на входе порта (рис. 4.25, а), а также периода, коэффициента заполнения или частоты периодического импульсного сигнала (рис. 4.25, б).



(а)



(б)

Рис. 4.25. Временные характеристики ШИМ сигнала


• Выходного сравнения (OC — Output Compare). Функция выходного сравнения позволяет МК генерировать на нескольких выходах импульсные последовательности с заданными временными характеристиками, такими, как период и коэффициент заполнения для повторяющихся сигналов, длительность единичного или нулевого состояния для неповторяющихся сигналов.

• Счетчика внешних событий (PA — Pulse Accumulator). Основная функция этого счетчика — подсчет импульсов (внешних событий) на одном из входов МК. Он также может быть использован для измерения временных параметров внешнего импульсного сигнала большой длительности.

Для реализации функций входного захвата/выходного сравнения (IC/OC) модуль таймера TIM использует восемь идентичных аппаратных блоков, которые принято называть каналами. Каждый из каналов посредством программных установок настраивается на реализацию режима входного захвата или выходного сравнения независимо от режима работы других каналов модуля таймера. Каждый из каналов использует общий счетчик временной базы для фиксации моментов наступления событий. Параллельная работа всех восьми каналов с одним счетчиком временной базы не вносит погрешностей в формируемые или измеряемые временные интервалы, поскольку фиксация этих интервалов реализуется на аппаратном уровне с последующим программным обслуживанием каналов по прерываниям. Каждый канал связан с одной из линий порта PORT Т. Счетчик событий PA в составе модуля TIM также связан с линией 7 порта PORT T. Поэтому линии 0…6 порта PORT T в подсистеме таймера могут использоваться или как входы IC, или как выходы OC, в то время как линия 7 порта PORT T кроме этих двух функций IC/OC может также использоваться как вход тактовых импульсов для счетчика внешних событий.

4.14.1. Структура модуля таймера

 Сделать закладку на этом месте книги

Структурная схема модуля таймера представлена на рис. 4.26. При ее первичном рассмотрении она кажется запутанной и сложной. Для облегчения понимания мы выделим в составе таймера три блока: блок счетчика временной базы (1), восемь каналов с функциями IC/OC (2), блок счетчика внешних событий (3). Далее мы рассмотрим каждый из этих блоков отдельно, и для каждого из них приведем более понятные структурные схемы.



Рис. 4.26. Структура модуля таймера

4.14.2. Счетчик временной базы

 Сделать закладку на этом месте книги

Основным блоком модуля таймера TIM является 16 разрядный счетчик временной базы TCNT, структурная схема которого представлена на рис. 4.27. Текущий код счетчика используется всеми каналами захвата/сравнения в качестве отсчета момента реального времени. Именно поэтому этот счетчик и называют счетчиком временной базы. Этот счетчик также называют свободно считающим счетчиком. Определение «свободно считающий» отражает следующую особенность работы счетчика. Если работа модуля таймера разрешена, то счетчик временной базы производит непрерывный счет, начиная с минимального кода $0000 до максимального кода $FFFF. При поступлении следующего тактового импульса код счетчика изменяется с $FFFF на $0000. Далее счет продолжается в порядке нарастания кода. Невозможно остановить счетчик под управлением программы, так же как и изменить коэффициент счета счетчика, равный 216. Текущее состояние счетчика отображается в двух 8-разрядных регистрах: TCNTH — старший байт счетчика, TCNTL — младший байт счетчика. В карте памяти МК эти регистры располагаются по следующим адресам: $0084 — TCNTH, $0085 — TCNTL. Вместе оба этих регистра составляют 16-разрядный регистр текущего состояния счетчика временной базы TCNT. Имя TCNT обычно объявляется в заголовочном файле.



Рис. 4.27. Структура и регистры управления счетчика временной базы модуля таймера



Особенности счетчика временной базы

Счетчик временной базы тактируется импульсной последовательностью с выхода мультиплексора MUX. Ко входам мультиплексора подключены четыре источника тактирования: основная импульсная последовательность с выхода делителя частоты и дополнительные сигналы PACLK, PACLK/256, PACLK/65536. На вход программируемого делителя частоты подключен сигнал PCLK с выхода подсистемы тактирования. Частота следования импульсов на линии PCLK равна частоте тактирования межмодульных магистралей МК. Коэффициент деления программируемого делителя частоты определяется разрядами PR2…PR0 регистра масок таймера 2 (TMSK2). Формат регистра TMSK2 приведен на рис. 4.27. Таблица соответствия численного значения коэффициента деления двоичной комбинации разрядов PR2…PR0 представлена на рис. 4.28.

PR[2:1:0] Коэффициент деления
000 1
001 2
010 4
011 8
100 16
101 32
110 зарезервирован
111 зарезервирован 

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


Величина коэффициента деления определяет длительность периода переполнения счетчика временной базы. Поскольку разрядность счетчика равна 16, то коэффициент счета этого двоичного счетчика равен 216 или 65356. Минимальный период переполнения счетчика составляет 8169 мс (216 импульсов × 1/8 МГц), поскольку максимальная частота импульсной последовательности PCLK, равная частоте тактирования межмодульных магистралей, составляет 8 МГц. Однако при задании максимального коэффициента деления, равного 32 (см. таблицу рис. 4.28), период переполнения счетчика составит уже 262424 мс (216 импульсов × 32/8 МГц).

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

Однако уменьшение частоты импульсной последовательности PCLK связано со снижением производительности процессорного ядра. Поэтому для счетчика временной базы предусмотрены три альтернативных источника тактирования PACLK, PACLK/256, PACLK/65536. Выбор одного из четырех источников тактирования осуществляется двухразрядным кодом CLK1:CLK0 в регистре управления счетчиком внешних событий PACL. Формат регистра PACL представлен на рис. 4.27.


Флаг переполнения счетчика

Если длительность измеряемых или формируемых микроконтроллером временных интервалов превышает период переполнения счетчика временной базы, то возникает необходимость в подсчете числа периодов переполнения этого счетчика. При достижении максимального кода $FFFF счетчик не останавливается, он продолжает считать дальше. Поэтому при поступлении следующего тактового импульса в счетчике установится код $0000. Такое изменение кода называется событием переполнения счетчика и фиксируется установкой бита TOF в регистре управления счетчиком TFLG2 (рис. 4.27). Триггер TOF называют триггером переполнения счетчика. Этот триггер может быть считан под управлением программы, или, если прерывания по событию переполнения счетчика разрешены, то установленный в 1 триггер TOF генерирует запрос на прерывание. Прерывание по переполнению счетчика временной базы имеет свой собственный вектор и собственный бит разрешения прерывания TOI в регистре TMSK2 (рис. 4.27).

Если код счетчика временной базы изменился с $FFFF на $0000, то триггер TOF устанавливается в 1. При использовании этого флага для вызова прерываний следует позаботиться о том, чтобы флаг был сброшен под управлением подпрограммы прерывания до наступления следующего переполнения таймера. Для сброса (установки в 0) флага TOF следует записать 1 в бит 7 регистра TMSK2, т.е. выполнить любую команду установки в 1 этого флага. Вышесказанное не ошибка! Большинство флагов регистров специальных функций МК семейства 68HC12/HCS12, генерирующих разнообразные запросы на прерывание, сбрасываются в 0 посредством записи 1 в находящийся в состоянии 1 бит флага. Мы обсудим ниже варианты программного кода, которые могут быть использованы для сброса различных флагов, в том числе и флага переполнения счетчика временной базы.

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


Определение длительности временных интервалов

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

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

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



а) Вариант 1: Код Stop > Код Start, переполнений счетчика временной базы за время измерения не было



б) Вариант 2: Код Start > Код Stop, за время измерения было одно переполнение счетчика временной базы



в) Вариант 3: Код Stop > Код Start, за время измерения было N переполнений счетчика временной базы



г) Вариант 4: Код Start > Код Stop, за время измерения было N переполнений счетчика временной базы



д) Вариант 5: Код Start = Код Stop, за время измерения было N переполнений счетчика временной базы

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


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

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

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

Рассмотрим более подробно вычисление реальной длительности измеряемого сигнала по второму способу. На рис. 4.29 показаны пять возможных ситуаций, в которых подсистемой входного захвата зафиксированы совершенно одинаковые коды начала и конца измеряемого временного интервала. В первом случае (рис. 4.29,а) код Stop превышает код Start, и переполнений счетчика временной базы не было. Тогда очевидно, что измеряемая длительность временного интервала TIME = Stop – Start. Во втором случае (рис. 4.29,б) код Stop меньше, чем код Start, и между изменениями сигнала было всего одно переполнение счетчика временной базы:

TIME  = (216 – Start ) + Stop  = 216 + (Stop  – Start )

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

TIME  = 216 × n  + (Stop  – Start ),

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

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

tIZM  = TIME  × (TCNTclock ),

где  TCNTclock  — период частоты тактирования счетчика временной базы.


Сброс счетчика временной базы

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

• Установить в 1 бит разрешения сброса счетчика TCRE (бит 3) в регистре управления TMSK2;

• Установить в $0000 регистр данных канала 7 модуля таймера. Комбинация этих двух состояний будет удерживать счетчик временной базы в нулевом состоянии.


Вопросы для самопроверки

1. Какова частота тактирования МК на отладочной плате MC68HC912B32EVB?

Ответ: Микроконтроллер B32, установленный на плате MC68HC912B32EVB тактируется от кварцевого резонатора с частотой 16 МГц. Эта частота делится внутренними средствами МК на 2, поэтому частота межмодульных магистралей составляет 8 МГц.

2. С какой целью Вам может понадобиться тактировать МК на с иной, отличной от  fBUS  = 8 МГц частотой?

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

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

Ответ: $EC20 – $0105 = $EB1B = 60187 тактов счетчика

4. Если в предыдущем примере частота на входе программируемого делителя составляет 2 МГц, и биты PR2…PR0 регистра TMSK2 установлены в 000, то каков интервал времени между событиями в мс?

Ответ: Интервал составляет: 60187 1/(2МГц) = 30093,5 мс.

5. Повторите расчет предыдущего вопроса, но при измененных значениях битов PR2…PR0 = 100.

Ответ: В предыдущем случае коэффициент деления программируемого делителя был равен 1. При указанных в данном примере значениях битов PR2…PR0 коэффициент деления составляет 16. Следовательно, интервал времени между событиями составит 30093,5 мс × 16 = 481496 мс.

6. Назовите три основных режима работы модуля таймера TIM?

Ответ: режим входного захвата IC, режим выходного сравнения OC и режим счетчика внешних событий PA.

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

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

8. Почему разработчик должен быть крайне осторожен при обнулении счетчика временной базы таймера?

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

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

 Сделать закладку на этом месте книги<hr><center><a target=_blank href=/premium>убрать рекламу</a><br /><br />
<!-- Yandex.RTB R-A-27845-20 -->
<div id="yandex_rtb_R-A-27845-20"></div>
<script type="text/javascript">
    (function(w, d, n, s, t) {
        w[n] = w[n] || [];
        w[n].push(function() {
            Ya.Context.AdvManager.render({
                blockId: "R-A-27845-20",
                renderTo: "yandex_rtb_R-A-27845-20",
                async: true
            });
        });
        t = d.getElementsByTagName("script")[0];
        s = d.createElement("script");
        s.type = "text/javascript";
        s.src = "//an.yandex.ru/system/context.js";
        s.async = true;
        t.parentNode.insertBefore(s, t);
    })(this, this.document, "yandexContextAsyncCallbacks");
</script></center><hr> <br /><br />
<center>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- read header -->
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-3560913519783077"
     data-ad-slot="8845389543"
     data-ad-format="auto"
     data-full-width-responsive="true"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
</center><br /><br />

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


Регистр управления модулем таймера

Регистр управления модулем таймера TSCR (Timer System Control Register) располагается в памяти МК по адресу $0086. Формат регистра представлен на рис. 4.30. Старший бит регистра TEN разрешает (при TEN=1) или запрещает (при TEN=0) функционирование модуля таймера. Этот бит используется разработчиками для включения или отключения модуля таймера в процессе работы устройства. Отключение модуля полезно с точки зрения снижения потребления энергии, если функции таймера не используются в алгоритме управления. Обратите внимание, что после сброса МК модуль таймера выключен, т.к. бит TEN автоматически устанавливается в 0 в состоянии сброса МК.



Рис. 4.30. Формат регистра TCSR


Бит TFFCA управляет механизмом сброса флагов событий модуля таймера. К этим флагам относятся флаг переполнения таймера TOF, флаги событий в каналах захвата/сравнения IC/OC и флаг переполнения счетчика внешних событий. Если бит TFFCA установлен в 0, то для сброса перечисленных флагов следует использовать обычную процедуру, когда в бит установленного флага под управлением программы записывается 1 (см. раздел 4.14.2, флаг переполнения счетчика). Попытка записи 0 в бит установленного флага оставит флаг без изменения. Если бит TFFCA установлен в 1, то вводится в действие дополнительный механизм сброса рассматриваемых флагов событий:

• Флаг переполнения счетчика временной базы TOF в регистре TFLG2 будет сброшен автоматически при выполнении операции чтения регистра текущего кода счетчика TCNT;

• Флаг события канала захвата/сравнения CnF (n — номер канала) в регистре TFLG1 будет сброшен автоматически при выполнении операции чтения или записи в регистр данных этого канала;

• Флаги PAONF и PAIF счетчика внешних событий в регистре PAFLG будут сброшены автоматически при чтении или записи в регистр PACNT.

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

/*-----------------------------------------------------------------*/

/* MAIN PROGRAMM                                                   */

/*-----------------------------------------------------------------*/

#include <912b32.h>


void main(void) {

 unsigned char TSCR_MASK = 0x80; /*разрешение работы модуля таймера*/

 TSCR = TSCR_MASK;

}

/*------------------------------------------------------------------*/


Регистр счетчика временной базы

Если работа модуля таймера разрешена, то счетчик временной базы изменяет свое состояние в порядке естественного счета. Число разрядов счетчика временной базы равно 16, поэтому коэффициент счета счетчика составляет 216. Изменение коэффициента счета не предусмотрено. Счетчик временной базы не возможно остановить, однако его состояние в любой момент времени может быть считано под управлением программы из регистра текущего состояния TCNT (Timer CouNTer register). Регистр TCNT — 16 разрядный, в памяти МК он занимает две ячейки. По адресу $0084 располагается старший байт регистра TCNTH, по адресу $0085 — младший байт регистра TCNTL. Формат регистра представлен на рис. 4.31.



Рис. 4.31. Формат регистра TCNT


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

/*-------------------------------------------------*/

/* MAIN PROGRAMM                                   */

/*-------------------------------------------------*/

#include<912b32.h>


void main(void) {

 unsigned int start_time; /*время начала процесса*/

 unsigned int stop_time; /*время окончания процесса*/

 start_time=TCNT;

 stop_time=TCNT;

}

/*-------------------------------------------------*/


Регистр масок таймера 2

Регистр масок таймера TMSK2 (Timer MaSK register 2) располагается в памяти МК по адресу $008D. Формат регистра представлен на рис. 4.32. В данном параграфе мы рассмотрим лишь некоторые биты этого регистра. Бит TCRE разрешает сброс счетчика временной базы таймера (см. раздел 4.14.2, сброс счетчика временной базы). Биты PR2:PR1:PR0 устанавливают коэффициент деления программируемого делителя на входе счетчика временной базы в соответствие с табл. рис. 4.28. Обратите внимание, что минимальный коэффициент деления равен 1, т.е. максимальная частота тактирования счетчика равна fBUS . Максимальный коэффициент деления составляет 32. Биты PUPT и TDRB предназначены для управления схемотехникой входных и выходных буферов линий порта PORT T.



Рис. 4.32. Формат регистра TMSK2

4.14.4. Каналы захвата/сравнения

 Сделать закладку на этом месте книги

Модуль таймера TIM содержит в себе восемь идентичных блоков захвата/сравнения, которые в микропроцессорной технике принято именовать каналами захвата/сравнения. Структурная схема аппаратных средств одного канала захвата/сравнения в составе модуля таймера МК семейства 68HC12/HCS12 представлена на рис. 4.33.



Рис. 4.33. Структура одного канала сравнения/захвата таймера и регистр выбора режима работы каналов TIOS


Каждый из восьми каналов захвата/сравнения подключен к выводу IOSn, где n — номер канала, n = 0, 1, 2…7. Если канал с номером n конфигурирован как канал захвата, то вывод IOSn автоматически подключается к одноименной линии PTn порта T. Работа в качестве входов подсистемы входного захвата или выходов подсистемы выходного сравнения является альтернативной функцией порта T. Регистр данных порта T расположен по адресу $00AE.

Реализуемая каналом n модуля таймера функция (входной захват или выходное сравнение) определяется битом IOCn регистра TIOC. Регистр расположен по адресу $0080, формат регистра представлен на рис. 4.33. Если бит IOCn установлен в 1, то канал n работает в режиме выходного сравнения. Если же бит IOCn равен 0, то канал n работает в режиме входного захвата.

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


Режим входного захвата

Структура аппаратных средств подсистемы входного захвата IC, которая образуется в результате конфигурирования универсального канала модуля таймера на режим захвата, представлена на рис. 4.34. Подсистема входного захвата запоминает код счетчика временной базы в момент изменения логического сигнала на входе IOSn (n — номер канала). Изменение логического сигнала распознается детектором события, который может быть программно настроен на один из четырех режимов работы:

• Распознавание изменения сигнала с 0 на 1 — положительный фронт;

• Распознавание изменения сигнала с 1 на 0 — отрицательный фронт;

• Распознавание любого изменения уровня сигнала;

• Соответствующий вывод МК не подключен к каналу входного захвата и является выводом порта T.



Рис. 4.34. Структура одного канала таймера в режиме входного захвата и регистры управления каналом TCTL3 и TCTL4


Если детектор определил заданное изменение входного сигнала, то говорят, что наступило событие входного захвата. В момент наступления события код счетчика временной базы запоминается в регистре защелке, одновременно устанавливается триггер события канал CnF (рис. 4.34). Триггер может быть считан программно, или генерируется запрос на прерывание, если прерывания от канала n модуля таймера разрешены.

Для настройки детектора события каждого канала на один из трех перечисленных режимов используются биты EDGnB:EDGnA в регистрах TCTL3 ($008A) и TCTL4 ($008B). Формат этих регистров представлен на рис. 4.34. Таблица рис. 4.35 устанавливает соответствие между режимом работы детектора события и кодом инициализации в разрядах EDGnB:EDGnA.

EDGnB: EDGnA Режим детектора событий
00 Входной захват не реализуется
01 Мониторинг нарастающего фронта
10 Мониторинг спадающего фронта
11 Мониторинг изменения уровня 

Рис. 4.35. Выбор режима работы детектора события


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

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

1. Текущее состояние 16-разрядного счетчика временной базы запоминается в регистре-защелке канала и сразу копируется в 16-разрядный регистр данных канала TCn (n — номер канала). Поскольку данные в регистре TCn не изменяются, то они могут быть считаны побайтно (TCnH — старший байт регистра данных канала, TCnL — младший байт регистра данных), или в двухбайтовом формате. При программировании на Си рекомендуется использовать двухбайтовый формат, используя для этого переменную в формате unsigned integer.

2. Устанавливается флаг события канала CnF. Этот флаг «сообщает» основной программе о том, что событие произошло, и регистр данных канала TCn должен быть считан программой.

3. Если прерывания по флагу события CnF разрешены (бит CnI установлен), то генерируется запрос на прерывание.

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

1. Управляющая программа устанавливает режим работы детектора событий канала 2. Должен быть выбран режим мониторинга нарастающего фронта входного сигнала. Для этого следует установить биты EDG2B:EDG2A в регистрах TCTL3:TCTL4 в состояние 01.

2. Управляющая программа контролирует состояние триггера события C2F.

3. Если триггер C2F установился в 1, то контролируемый сигнал на линии PT2 изменился с 0 на 1. В момент изменения код счетчика временной базы был автоматически переписан в регистр защелку канала 2. Теперь этот код доступен для чтения из регистра данных TC2.

4. Управляющая программа обнаруживает, что триггер C2F установился. Тогда программа считывает двухбайтовый код из регистра данных канала TC2 и записывает его в двухбайтовую беззнаковую переменную rising_edge.

5. Управляющая программа сбрасывает триггер события C2F посредством записи в бит C2F единицы.

6. Управляющая программа изменяет режим работы детектора событий канала 2. Должен быть выбран режим мониторинга отрицательного фронта входного сигнала. Для этого следует установить биты EDG2B:EDG2A в регистрах TCTL3:TCTL4 в состояние 10.

7. Управляющая программа контролирует состояние триггера события C2F.

8. Если триггер C2F установился в 1, то сигнал на линии PT2 изменился с 1 на 0. В момент изменения код счетчика временной базы был опять автоматически переписан в регистр защелку канала 2.

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

10. Управляющая программа сбрасывает триггер события C2F посредством записи в бит C2F единицы.

11. Управляющая программа вычисляет число периодов частоты тактирования счетчика временной базы между положительным и отрицательным фронтами исследуемого сигнала: TIME = falling_edge – rising_edge. Это число и есть искомая длительность импульса положительной полярности сигнала на входе PT2, выраженная числом периодов частоты тактирования счетчика временной базы.

12. При необходимости длительность импульса может быть представлена в общепринятых единицах измерения времени. Для этого управляющая программа должна выполнить операцию умножения числа TIME на длительность единицы измерения времени таймера, т.е. на длительность периода частоты тактирования счетчика временной базы: tIZM = TIME×1/fBASE.

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


Вопросы для самопроверки

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

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

2. Какие изменения необходимо внести для измерения периода повторяемости импульсного сигнала на входе PT2?

Ответ: Рассматриваем изменения исходной последовательности действий, которая приведена в предыдущем параграфе. Пункт 6 последовательности необходимо исключить. Тогда триггер события C2F будет в обоих случаях устанавливаться по положительному фронту исследуемого сигнала. Следовательно, в п.п. 11 и 12 будет вычисляться интервал времени между соседними положительным фронтами сигнала, т.е. период повторяемости этого сигнала.

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

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


Режим выходного сравнения

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



Рис. 4.36. Структура одного канала таймера в режиме выходного сравнения и регистры управления каналом TCTL1 и TCTL2


Цифровой компаратор подсистемы выходного сравнения непрерывно сравнивает код счетчика временной базы с 16 разрядным кодом в регистре данных канала TCn (n — номер канала). Момент равенства кодов в микропроцессорной технике называют событием выходного сравнения. Если цифровой компаратор определил равенство кодов, то аппаратные средства канала выходного сравнения автоматически совершают следующие действия:

1. Устанавливается флаг события канала CnF. Обратите внимание, события входного захвата и выходного сравнения отмечаются одним и тем же флагом. Это флаг события канала CnF. Смысловое значение флага (IC или OC) определяется ранее выбранным в процессе инициализации режимом работы канала. Флаг CnF «сообщает» основной программе о том, что событие выходного сравнения произошло, и в регистр данных канала TCn следует записать новое значение кода для сравнения.

2. Если прерывания по флагу события CnF разрешены (бит CnI установлен), то генерируется запрос на прерывание.

3. Формирователь уровня генерирует на выводе канала IOSn предварительно заданный логический уровень. Формирователь уровня в процессе инициализации может быть программно настроен на один из четырех режимов работы:

• Установка вывода в 1;

• Установка вывода в 0;

• Инвертирование уровня сигнала на выводе;

• Соответствующий вывод МК не подключен к каналу выходного сравнения и является выводом порта T.

OMn: OLn Режим формирователя уровня
00 Выход формирователя не соединен с выводом IOSn
01 Инвертирует сигнал на выходе
10 Устанавливает выход в 0
11 Устанавливает выход в 1

Рис. 4.37. Выбор режима работы формирователя уровня


Для настройки формирователя уровня каждого канала на один из трех перечисленных режимов работы используются биты OMn:OLn в регистрах TCTL1 ($0088) и TCTL2 ($0089). Формат этих регистров представлен на рис. 4.36. Таблица рис. 4.37 устанавливает соответствие между режимом работы формирователя уровня и кодом инициализации в разрядах OMn:OLn.

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

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

2. Управляющая программа устанавливает выход используемого канала в 0.

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

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

5. Управляющая программа задает режим работы формирователя уровня канала. Целесообразно выбрать режим установки выхода в 1, для чего необходимо записать в разряды OMn:OLn регистров TCTL1: TCTL2 комбинацию 11 (см. рис. 4.37).

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


Канал 7 в режиме выходного сравнения

До настоящего параграфа мы рассматривали все восемь каналов модуля таймера TIM, как полностью идентичные. Однако на самом деле полностью идентичными, работающими или в режиме входного захвата или в режиме выходного сравнения, являются лишь каналы 0…6. Канал 7 в режиме выходного сравнения обладает дополнительными возможностями. При этом рассмотренные режимы захвата/сравнения, совпадающие с режимами каналов 0…6, при соответствующей инициализации им полностью поддерживаются.

Если канал 7 находится в режиме выходного сравнения и его дополнительная функция разрешена, то в момент события в канале 7 устанавливается в назначенное состояние не только выход канала 7, но и любая комбинация выходов каналов 0…6. При этом выбранные для принудительной установки каналы также должны работать в режиме выходного сравнения. Два регистра специальных функций OC7M и OC7D используются для управления режимом принудительной установки по событию в канале 7. Каждый из битов регистра OC7M разрешает (при OC7Mn = 1) режим принудительной установки для одноименного (с номером n) канала. Соответствующий бит в регистре OC7D задает значение, которое должно быть установлено на выходе канала в момент принудительной установки. Например, если в регистре OC7M записан двоичный код 10110001, а в регистре OC7D – 01010101, то с каналом 7 в режиме принудительной установки будут связаны каналы 0, 4, 5. Тогда в момент события выходного сравнения на выходе канала 0 установится 1, на выходе канала 4 установится также 1, на выходе канала 5 установится 0 и на выходе канала 7 — тоже 0. На остальные каналы событие выходного сравнения в канале 7 влияния не окажет.

Свойство принудительной установки позволяет два раза за период работы счетчика временной базы изменять состояние на выходах каналов 0…6. Один раз по собственному событию выходного сравнения канала, второй раз — по событию в канале 7.


Регистры для управления каналами захвата/сравнения

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


Регистр режимов каналов захвата/сравнения

Регистр режимов каналов захвата/сравнения TIOS (Timer Input capture/Output compare Register) располагается в памяти МК по адресу $0080. Формат регистра представлен на рис. 4.38. Каждый из битов регистра IOSn определяет режим работы канала с номером n. Если бит установлен в 1, то канал работает в режиме выходного сравнения. Если бит равен 0, то канал настроен на режим входного захвата.



Рис. 4.38. Формат дополнительных регистров управления таймером: TIOS, CFORC, OC7M, OC7D



Регистр принудительного события выходного сравнения

Регистр принудительного события выходного сравнения CFORC (Timer Compare Force Register) располагается в памяти МК по адресу $0081. Формат регистра представлен на рис. 4.38. Установка бита FOCn в 1 немедленно вызывает событие выходного сравнения в канале с номером n, независимо от текущего состояния счетчика временной базы и регистра данных канала. Функция принудительной установки очень удобна для задания начального уровня выхода канала выходного сравнения.


Регистр разрешения работы под управлением канала 7

Регистр разрешения работы под управлением канала 7 OC7M (Timer Output Compare 7 Mask Register) располагается в памяти МК по адресу $0082. Формат регистра представлен на рис. 4.38. Каждый из битов регистра OC7M разрешает (при OC7Mn = 1) режим принудительной установки для одноименного (с номером n) канала по событию в канале выходного сравнения 7. Если бит OC7Mn = 0, то канал с номером n работает в автономном режиме.


Регистр установки данных под управлением канала 7

Регистр установки данных под управлением канала 7 OC7D (Timer Output Compare 7 Data Register) располагается в памяти МК по адресу $0083. Формат регистра представлен на рис. 4.38. Каждый из битов регистра OC7Dn задает значение, которое должно быть установлено на выходе канала с номером n в момент в момент события выходного сравнения в канале 7. При этом необходимо предварительно разрешить работу желаемых каналов под управлением канала 7 установкой соответствующих битов в регистре OC7M.


Регистры управления таймером 1 и 2

Регистры управления таймером TCTL1 и TCTL2 (Timer Control Register) располагаются в памяти МК по адресам $0088 и $0089. Форматы регистров приведены на рис. 4.39. Каждому каналу таймера поставлены в соответствие два бита OMn:OLn регистров TCTL1 и TCTL2. Биты OMn:OLn определяют один из четырех режимов работы формирователя уровня канала, если этот канал работает в режиме выходного сравнения. Комбинации кодов для битов OMn:OLn приведены на рис. 4.37.



Рис. 4.39. Формат основных регистров управления таймером:TCTL1, TCTL2, TCTL3, TCTL4


Регистры управления таймером 3 и 4

Регистры управления таймером TCTL3 и TCTL4 (Timer Control Register) располагаются в памяти МК по адресам $008A и $008B. Форматы регистров приведены на рис. 4.39. Каждому каналу таймера поставлены в соответствие два бита EDGnB:EDGnA регистров TCTL3 и TCTL4. Биты EDGnB:EDGnA определяют один из четырех режимов работы детектора события канала, если этот канал работает в режиме входного захвата. Комбинации кодов для битов EDGnB:EDGnA приведены на рис. 4.35.


Регистр масок таймера 1

Регистр масок таймера TMSK1 (Timer Mask Register 1) располагается в памяти МК по адресу $008C. Формат регистра приведен на рис. 4.40. Каждый бит этого регистра CnI разрешает или запрещает прерывания по событию в одноименном (с номером n) канале таймера. Если бит CnI равен 1, то прерывания разрешены. При CnI = 0 прерывания по событию в канале запрещены.



Рис. 4.40. Формат регистров масок таймера:TMSK1, TMSK2



Регистр масок таймера 2

Регистр масок таймера TMSK2 (Timer Mask Register 2) располагается в памяти МК по адресу $008D. Формат регистра приведен на рис. 4.40. Бит TOI разрешает прерывания по флагу переполнения счетчика временной базы TOF. Бит TCRE разрешает сброс счетчика временной базы (см. раздел 4.14.2, сброс счетчика временной базы). Биты PR2:PR1:PR0 устанавливают коэффициент деления программируемого делителя на входе счетчика временной базы в соответствие с табл. рис. 4.28.


Регистр флагов таймера 1

Регистр флагов таймера TFLG1 (Timer Flag Register 1) располагается в памяти МК по адресу $008E. Формат регистра представлен на рис. 4.41. Каждому каналу таймера поставлен в соответствие флаг события CnF. Флаг CnF устанавливается в 1 автоматически, если в канале произошло событие входного захвата или выходного сравнения, в зависимости от текущего режима работы канала. Установленный би


убрать рекламу






т события CnF вызовет прерывание, если в регистре TMSK1 установлен одноименный бит разрешения прерывания. Флаг события CnF должен быть сброшен под управлением программы, для чего в бит CnF должна быть записана 1. Существует альтернативный способ для сброса флагов события CnF. Если бит TFFCA в регистре TSCR установлен, то чтение или запись в регистр данных канала автоматически сбрасывает бит события этого канала.



Рис. 4.41. Формат регистров флагов таймера:TFLG1, TFLG2



Регистр флагов таймера 2

Регистр флагов таймера TFLG2 (Timer Flag Register 2) располагается в памяти МК по адресу $008F. Формат регистра представлен на рис. 4.41. В регистре присутствует всего один флаг — флаг переполнения счетчика временной базы TOF. Этот флаг сбрасывается посредством записи 1 в уже установленный бит TOF.


Регистры данных каналов захвата/сравнения

Регистры данных каналов захвата/сравнения TCn — 16 разрядные. В памяти каждый регистр представлен двумя 8 разрядными регистрами: TCnH — старший байт регистра данных канала с номером n, TCnL — младший байт регистра данных канала с номером n. Если канал настроен на режим входного захвата, то в регистре данных TCn содержится код счетчика временной базы в момент последнего события входного захвата. Если же канал настроен на режим выходного сравнения, то в регистр данных TCn под управлением программы записывается код момента сравнения. Формат и адреса расположения в памяти восьми регистров данных каналов TC0…TC7 приведены на рис. 4.42.

Регистр данных канала 0: TC0H:TC0L Адрес: $0090–0091
Регистр данных канала 1: TC1H:TC1L Адрес: $0092–0093
Регистр данных канала 2: TC2H:TC2L Адрес: $0094–0095
Регистр данных канала 3: TC3H:TC3L Адрес: $0096–0097
Регистр данных канала 4: TC4H:TC4L Адрес: $0098–0099
Регистр данных канала 5: TC5H:TC5L Адрес: $009A–009B
Регистр данных канала 6: TC6H:TC6L Адрес: $009C–009D
Регистр данных канала 7: TC7H:TC7L Адрес: $009E–009FФормат регистров данных таймера:TCnH, TCnL


Рис. 4.42. 



Вопросы для самопроверки

1. Опишите два возможных способа для сброса флага события в регистре TFLG1.

Ответ: По первому способу биты флагов событий в каналах захвата/сравнения CnF в регистре TFLG1 сбрасываются посредством записи 1 в тот разряд регистра TFLG1В, который подлежит сбросу. Попытка записи 0 в разряд, который установлен в 1, не даст желаемого результата. п.1. По второму способу чтение или запись в регистр данных канала автоматически сбрасывает бит события этого канала, если в регистре TSCR установлен бит TFFCA.

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

Ответ: $AA.

3. Какой код и в какие разряды регистра TCTL1 должен быть записан, чтобы настроить формирователь уровня канала 7 в режим установки 1?

Ответ: Код 11 в разряды OM7:OL7.

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

Ответ: Код 11 в разряды EDG1B:EDG1A.


Примеры работы с таймером

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


Измерение частоты и периода логического сигнала

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

• Бит разрешения работы модуля таймера TEN (регистр управления модулем таймера TSCR);

• Бит разрешения прерывания по переполнению счетчика временной базы TOI и биты выбора коэффициента деления программируемого делителя частоты на входе счетчика временной базы PR2:PR1:PR0 (регистр масок таймера TMSK2);

• Бит выбора режима работы канала IOSn (регистр режимов каналов захвата/сравнения TIOS). Если бит IOSn установлен в 1, то канал работает в режиме выходного сравнения. Если бит IOSn равен 0, то канал настроен на режим входного захвата;

• Биты выбора режима работы детектора события канала входного захвата EDGnB:EDGnA (регистры управления таймером TCTL3 и TCTL4);

• Бит события в канале CnF (регистр флагов таймера TFLG1);

• Бит разрешения прерывания по событию в канале CnI (регистр масок таймера TMSK1);

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

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

1. Разрешить работу модуля таймера;

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

3. Установить один из каналов в режим входного захвата по нарастающему фронту импульса;

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

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

6. Взять разность полученных кодов, которая будет равна периоду исследуемого сигнала. Воспользовавшись операцией деления, вычислить частоту исследуемого сигнала. На рис. 4.43 приведена блок схема рассмотренного алгоритма. Ниже приведен программный фрагмент (timer1.c), который реализует этот алгоритм. В программе применен метод программного опроса триггера события входного захвата C2F. Когда программа «обнаруживает» установленный в 1 триггер события первый раз, она копирует регистр данных канала в переменную rising_1, сбрасывает триггер и ожидает следующей установки триггера события. Когда триггер события установится второй раз, программа копирует регистр данных канала в переменную rising_2. Разность двух зафиксированных в регистре данных канала входного захвата значений позволит вычислить период, а затем и частоту исследуемого импульсного сигнала.



Рис. 4.43. Блок схема алгоритма измерения периода и частоты исследуемого сигнала


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

• Основная программа «main» содержит вызовы трех функций, каждая из которых выполняет отдельную смысловую задачу;

• Имена функций и переменных выбраны в соответствии с их смысловым назначением;

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

/*-------------------------------------------------------------------*/

/* filename: timer1.c                                                */

/* МAIN PROGRAМ: Эта программа измеряет период и частоту импульсного */

/* сигнала. Сигнал подключается на вход 2 подсистемы таймера (IC2).  */

/*-------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>

#include <stdio.h>

#include <math.h>


/*используемые функции*/

void timer_init(void);

void measure_wave(void);

void period_freq(void);


/*глобальные переменные*/

unsigned long int rising_1;

unsigned long int rising_2;


void main(void) {

 timer_init(); /*инициализация таймера*/

 measure_wave(); /*определение времени двух фронтов сигнала*/

 period_freq(); /*вычисление периода и частоты*/

}


/*----------------------------------------------------------------------*/

/* Функция timer_init производит инициализацию модуля таймера           */

/* Канал 2 таймера настраивается на режим входного захвата по переднему */

/* фронту сигнала                                                       */

/* Частота тактирования счетчика временной базы устанавливается 2 МГц.  */

/*----------------------------------------------------------------------*/

void timer_init(void) {

 TMSK1 = 0x00; /*запретить прерывания от каналов таймера*/

 TMSK2 = 0x02; /*назначить коэффициент деления 4*/

 TIOS = 0х00; /*установить канал 2 в режим входного захвата*/

 TSCR = 0х80; /*разрешить работу таймера*/

 TCTL4 = 0х10; /*назначить режим детектора событий по*/

               /*положительному фронту*/

 TFLG1 = 0xFF; /*очистить флаги событий*/

}


/*-------------------------------------------------------------------*/

/* Функция measure_wave запоминает два последовательных момента      */

/* нарастающего фронта исследуемого сигнала. Значения запоминаются с */

/* использованием глобальных переменных                              */

/*-------------------------------------------------------------------*/

void measure_wave(void) {

 while((TFLG1 & 0х04) == 0) {

  /*ожидать нарастающего фронта*/

  ;

 }

 rising_1 = TCNT; /*запомнить код счетчика временной базы*/

                  /*в переменной rising_1*/

 TFLG1 = 0х04; /*сброс триггера события канала 2*/

 while((TFLG1 & 0х04) == 0) {

  /*ожидать нарастающего фронта*/

  ;

 }

 rising_2 = TCNT; /*запомнить код счетчика временной базы*/

                  /*в переменной rising_2*/

 TFLG1 = 0х04; /*сброс триггера события канала 2*/

}


/*------------------------------------------------------------------------*/

/* Функция period_freq вычисляет период и частоту исследуемого импульсного*/

/* сигнала и отображает полученные значения на экране                     */

/*------------------------------------------------------------------------*/

void period_freq(void) {

 unsigned long int new_rising;

 unsigned long int new_falling;

 float frequency;

 float period;

 unsigned int int_period;

 unsigned int int_freq, freq_tenths;

 if(rising_2 < rising_1) /*вычисление периода*/

 {

  new_rising = rising_2 + 0xFFFF;

  period = ((float)new_rising (float)rising_l)*0.0000005;

 } else {

  period = ((float)rising_2 (float)rising_l)*0.0000005;

 }

 frequency = 1.0/period; /*вычисление частоты*/

 int_freq = (int)(frequency/l000.0);

 freq_tenths = (int)((frequency –(float) int_freq*1000)/100.0);

 /*вывод результатов*/

 printf("Frequency = %d.%d kHz \n\n" int_freq, freq_tenths);

 int_period = (int) (1000000*period);

 printf("Period = %d μs\n\n", int_period);

 printf{"Period = %f ms\n\n", (period*1000))};

}

/*------------------------------------------------------------------------*/

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

Period   = 216×n  + (rising_2  – rising_1 )

Рассматриваемая программа имеет также ограничение по измерению сигналов с достаточно высокой частотой. Как узнать максимальную частоту, которая может быть измерена? Для этого следует вспомнить, что в нашем учебном примере частота внутренней шины МК составляет 8 МГц. Вы должны просмотреть ассемблерный код функции измерения частоты measure_wave и определить, сколько машинных тактов необходимо для распознавания установленного в 1 флага события и считывания кода первого события из регистра данных канала. Именно этот интервал является минимальным периодом сигнала, который может быть измерен.


Генерация импульсной последовательности

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

• Бит разрешения работы модуля таймера TEN (регистр управления модулем таймера TSCR);

• Бит разрешения прерывания по переполнению счетчика временной базы TOI и биты выбора коэффициента деления программируемого делителя частоты на входе счетчика временной базы PR2:PR1:PR0 (регистр масок таймера TMSK2);

• Бит выбора режима работы канала IOSn (регистр режимов каналов захвата/сравнения TIOS). Если бит IOSn установлен в 1, то канал работает в режиме выходного сравнения. Если бит IOSn равен 0, то канал настроен на режим входного захвата;

• Биты выбора режима работы формирователя уровня канала выходного сравнения OMn:OLn (регистры управления таймером TCTL1 и TCTL2);

• Бит события в канала CnF (регистр флагов таймера TFLG1);

• Бит разрешения прерывания по событию в канале выходного сравнения CnI (регистр масок таймера TMSK1);

• Регистр данных канала TCn, код которого автоматически сравнивается с кодом счетчика временной базы. Момент равенства кодов и является событием выходного сравнения.

В нашем примере мы будем формировать импульсную последовательность, параметры которой определяются числом и годом рождения разработчика. Допустим, Вы родились 19 мая 1977 года. Тогда частота генерируемого сигнала будет равна 519 Гц, коэффициент заполнения будет равен 77%. Для задания численных констант, определяющих частоту и коэффициент заполнения генерируемого импульсного сигнала, проведем следующие несложные расчеты:

1. Назначим в качестве источника тактирования для счетчика временной базы программируемый делитель, на вход которого подается fBUS =8 МГц;

2. Установим коэффициент деления программируемого делителя частоты на входе счетчика временной базы, равный 4. Тогда частота тактирования счетчика будет равна 2 МГц, что соответствует разрешающей способности счетчика 0,5 мкс. Выбранная таким образом разрешающая способность должна быть достаточна для формирования периода следования и длительности импульса;

3. По условию задачи частота формируемого сигнала составляет 519 Гц, что соответствует периоду следования Т = 1/519 = 0.0019268 с;

4. Вычислим длительность высокого и низкого уровня сигнала на интервале периода. По условию задачи коэффициент заполнения равен 77%. Длительность искомых временных интервалов составляет:

Длительность_1 = 0.77*(0.0019268) = 0.001484 с

Длительность_0 = 0.23*(0.0019268) = 0.0004432 с

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

Код_1 = 0.001484 с/0.5 мкс = 2968 тактов

Код_0 = 0.0004432 с /0.5 мкс = 886 тактов

На рис. 4.44 приведена упрощенная блок схема алгоритма генерации импульсной последовательности. Ниже представлен исходный текст программы на Си (timer2.c), в котором используется метод программного опроса триггера события в канале выходного сравнения.



Рис. 4.44. Блок схема алгоритма генерации импульсной последовательности с заданными временными параметрами


/*------------------------------------------------------------------------*/

/* filename: timer2.c                                                     */

/* МAIN PROGRAМ: Эта программа генерирует импульсную последовательность   */

/* с частотой 519 Гц и коэффициентом заполнения 77%. Сигнал формируется на*/

/* выходе 2 подсистемы таймера (IC2)                                      */

/*------------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>


/*используемые функции*/

void timer_init(void);

void half_cycle(unsigned int time);


void main(void) {

 unsigned int high_time = 2968; /*число тактов высокого уровня*/

 unsigned int low_time = 886; /*число тактов низкого уровня*/

 timer_init();

 half_cycle(low_time); /*генерация низкого уровня*/

 while(1) {

  half_cycle(high_time); /*генерация высокого уровня*/

  half_cycle(low_time); /*генерация низкого уровня*/

 }

}


/*--------------------------------------------------------------------*/

/* Функция timer_init производит инициализацию модуля таймера.        */

/* Канал 2 таймера настраивается на режим выходного сравнения.        */

/* Частота тактирования счетчика временной базы устанавливается 2 МГц.*/

/*--------------------------------------------------------------------*/

void timer_init(void) {

 TMSK1 = 0x00; /*запретить прерывания от каналов таймера*/

 TMSK2 = 0x02; /*назначить коэффициент деления 4*/

 TIOS = 0х04; /*установить канал 2 в режим выходного сравнения*/

 TSCR = 0х80; /*разрешить работу таймера*/

 TCTL2 = 0х10; /*назначить режим формирователя уровня */

               /*"инвертирование"*/

 TFLG1 = 0x04; /*очистить флаг события канала 2*/

 TC2 = TCNT; /*записать в регистр данных канала 2 текущее*/

             /*состояние счетчика временной базы*/

}


/*------------------------------------------------------------------------*/

/* Функция half_cycle генерирует временной интервал заданной длительности */

/* Число тактов для отсчета должно быть определено вне функции            */

/*------------------------------------------------------------------------*/

void half_cycle(unsigned int time) {

 ТС2 += time; /*задать код сравнения в регистр данных канала*/

 while ((TFLG1 & 0x04) == 0) /*ожидать события выходного сравнения*/

 {

  ;

 }

 TFLG1 = 0x04; /*очистить флаг события канала 2*/

}

/*------------------------------------------------------------------------*/

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


Генерация импульсной последовательности с использованием прерывания

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

• Бит разрешения работы модуля таймера TEN (регистр управления модулем таймера TSCR);

• Бит разрешения прерывания по переполнению счетчика временной базы TOI и биты выбора коэффициента деления программируемого делителя частоты на входе счетчика временной базы PR2:PR1:PR0 (регистр масок таймера TMSK2);

• Бит выбора режима работы канала IOSn (регистр режимов каналов захвата/сравнения TIOS). Если бит IOSn установлен в 1, то канал работает в режиме выходного сравнения;

• Биты выбора режима работы формирователя уровня канала выходного сравнения OMn:OLn (регистры управления таймером TCTL1 и TCTL2);

• Бит события в канала CnF (регистр флагов таймера TFLG1);

• Бит разрешения прерывания по событию в канале выходного сравнения CnI (регистр масок таймера TMSK1);

• Регистр данных канала TCn, код которого автоматически сравнивается с кодом счетчика временной базы. Момент равенства кодов и является событием выходного сравнения.

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

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

#define CLI() asm("cli\n"); //разрешить маскируемые прерывания

#define SEI() asm("sei\n"); //запретить маскируемые прерывания

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

/*----------------------------------------------------------------------*/

/* filename: timer3.c                                                   */

/* МAIN PROGRAМ: Эта программа генерирует импульсную последовательность */

/* в форме меандра с использованием таймера и подсистемы прерывания     */

/* Сигнал формируется на выходе 2 таймера (IC2)                         */

/*----------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>


/*используемые функции*/

void initialize(void); /*функция инициализации*/

void toggle_isr(void); /*подпрограмма прерывания toggle_isr*/


//объявление функции обслуживания прерывания

#pragma interrupt_handler toggle_isr

//инициализация вектора прерывания

#pragma abs_address: 0xF7EA

void (*Timer_Channel_2_interrupt_vector[]) () = {toggle_isr};

#pragma end_abs address


/*глобальные переменные*/

int с;


void main(void) {

 с = 100;

 initialize(); /*инициализация подсистемы таймера*/

 TMSK1 = 0х04; /*разрешение прерывания по событию в канале 2*/

 TFLG1 = 0xFF; /*сброс всех флагов событий от каналов*/

 CLI(); /*разрешить прерывания*/

 while(1) {

  /*ожидание прерывания*/

  ;

 }

}


/*-------------------------------------------------------------*/

/* Функция initialize задает начальные установки модуля таймера*/

/*-------------------------------------------------------------*/

void initialize(void) {

 TMSK2 = 0x02; /*назначить коэффициент деления 4*/

 TIOS = 0х04; /*установить канал 2 в режим выходного сравнения*/

 TSCR = 0х80; /*разрешить работу таймера*/

 TCTL2 = 0х10; /*назначить режим формирователя уровня */

               /*инвертирование*/

}


/*----------------------------------------------*/

/* Функция toggle_isr – подпрограмма прерывания */

/*----------------------------------------------*/

void toggle_isr(void) {

 TFLG1 = 0xFF;

 /*сброс всех флагов событий от каналов*/

 ТС2 = TC2 + c;

 /*задать код сравнения в регистр данных канала*/

 c = c + 100;

 /*вычислить новое значение c*/

}

/*-----------------------------------------------*/

Проанализируйте функцию toggle_isr. Генерацию какого импульсного сигнала она обеспечивает?


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

/*------------------------------------------------------------------------*/

/*filename: timer4.c                                                      */

/*МAIN PROGRAМ: Эта программа генерирует две импульсных последовательности*/

/* с использованием таймера и двух каналов подсистемы прерывания          */

/* Сигналы формируются на выходах 2 и 3 таймера.                          */

/*------------------------------------------------------------------------*/


/*подключаемые файлы*/

#include <912b32.h>


/*используемые функции*/

void initialize(void); /*функция инициализации*/

void toggle1_isr(void); /*подпрограмма прерывания toggle1


убрать рекламу






_isr*/

void toggle2_isr(void); /*подпрограмма прерывания toggle2_isr*/


//объявление функции обслуживания прерывания

#pragma interrupt_handler toggle1_isr

#pragma interrupt_handler toggle2_isr

//инициализация векторов прерывания

#pragma abs_address: 0xF7E8

void (*Timer_Channel_3_interrupt_vector[]) () = {toggle2_isr};

void (*Timer_Channel_2_interrupt_vector[]) () = {toggle1_isr};

#pragma end_abs address


void main(void) {

 initialize(); /*инициализация подсистемы таймера*/

 TMSK1 = 0х0C; /*разрешение прерывания по событию в каналах 2 и 3*/

 TFLG1 = 0xFF; /*сброс всех флагов событий от каналов*/

 CLI(); /*разрешить прерывания*/

 while(l) {

  /*ожидание прерывания*/

 ;

 }

}


/*-------------------------------------------------------------*/

/* Функция initialize задает начальные установки модуля таймера*/

/*-------------------------------------------------------------*/

void initialize(void) {

 TMSK2 = 0x02; /*назначить коэффициент деления 4*/

 TIOS = 0х0C; /*установить каналы 2 и 3 в режим выходного*/

              /*сравнения*/

 TSCR = 0х80; /*разрешить работу таймера*/

 TCTL2 = 0х50; /*назначить режим формирователя уровня */

               /*инвертирование для обоих каналов*/

}


/*------------------------------------------------------------------*/

/* Функция toggle1_isr подпрограмма прерывания по событию в канале 2*/

/*------------------------------------------------------------------*/

void toggle1_isr(void) {

 TFLG1 = 0x04; /*сброс флага события канала 2*/

 ТС2 += 9091; /*задать код сравнения в регистр данных канала*/

}

/*------------------------------------------------------------------*/


/*-------------------------------------------------------------------*/

/* Функция toggle2_isr подпрограмма прерывания по событию в канале 3 */

/*-------------------------------------------------------------------*/

void toggle2_isr(void) {

 TFLG1 = 0x08; /*сброс флага события канала 3*/

 ТС2 += 4854; /*задать код сравнения в регистр данных канала*/

}

/*-------------------------------------------------------------------*/

Проанализируйте функции toggle1_isr и toggle2_isr. Генерацию каких импульсных последовательностей они обеспечивают?

4.14.5. Счетчик событий

 Сделать закладку на этом месте книги

Счетчик событий или аккумулятор импульсов (Pulse Accumulator) — это подсистема модуля таймера, которая разработана специально для подсчета импульсов. Основной элемент счетчика событий — 16 разрядный счетчик, который может работать в двух режимах:

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

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


Режимы работы счетчика

Структурная схема подсистемы счетчика событий представлена на рис. 4.45. Изучив ее, вы увидите, что счетчик событий в качестве входа PAI, на который должны поступать внешние импульсы, использует линию PT7 порта PORT T. Таким образом, обслуживание подсистемы счетчика событий альтернативная функция линии 7 порта PORT T. Однако линия PT7 обладает еще одной альтернативной функцией. Она используется как вход или как выход канала 7 подсистемы захвата/сравнения модуля таймера. Какие программные установки в регистрах управления таймера необходимо выполнить, чтобы конфигурировать линию PT7 как вход PAI счетчика событий?

• Сбросить бит IOS7 в регистре TIOS ($0080), тогда в канале 7 будет запрещен режим выходного сравнения;

• Сбросить биты OM7:OL7 регистра TCNTL1($0088),тогда линия PT7 окажется отсоединенной от аппаратных средств канала 7;

• Сбросить бит OC7M7 в регистре OC7M ($0082).



Рис. 4.45. Структура и регистры управления счетчика вешних событий


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

Если подсистема находится в режиме счетчика внешних событий, бит PEDGE определяет: по какому фронту сигнала, нарастающему (при PEDGE = 1) или спадающему (при PEDGE = 0) будет переключаться счетчик. Если детектор фиксирует на входе PAI заданное битом PEDGE изменение входного сигнала, то устанавливается флаг события PAIF.

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

Если работы подсистемы счетчика событий разрешена, то 16 разрядный счетчик начинает считать с нулевого значения. Текущий код счетчика может быть считан из 16-разрядного регистра текущего состояния счетчика PACNT, который в памяти размещается в двух ячейках памяти: PACNTH — старший байт счетчика событий, PACNTL — младший байт счетчика событий (рис. 4.45). Каждое переполнение 16-разрядного счетчика событий фиксируется установкой триггера переполнения PAOVF. Этот триггер сбрасывается посредством записи в установленный разряд PAOVF единичного значения.

Оба рассмотренных флага: флаг переполнения счетчика PAOVF и флаг события на входе счетчика PAIF, — способны генерировать запросы прерывания. Прерывания от указанных флагов разрешаются битами PAOVI и PAI соответственно. Биты PAOVI и PAI располагаются в регистре флагов счетчика событий PAFLG (рис. 4.45).


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

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


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

Регистр управления счетчиком событий PACTL (Pulse Accumulator Control Register) располагается в памяти МК по адресу $00A0. Формат регистра представлен на рис. 4.45. Регистр PACTL используется для задания режима работы счетчика событий, для назначения режима работы его детектора событий, для разрешения прерываний от подсистемы счетчика событий, а также для выбора источника тактирования счетчика временной базы модуля таймера.

Бит PTAE разрешает работу подсистемы счетчика событий. При PTAE = 1 работа подсистемы разрешена, при PTAE = 0 подсистема счетчика находится в неактивном состоянии. Бит PAMOD служит для выбора режима работы. При PAMOD = 0 подсистема работает в режиме счетчика внешних событий, при PAMOD = 1 для подсистемы назначается режим стробируемого таймера.

Бит PEDGE управляет режимом работы детектора событий подсистемы счетчика. Если счетчик работает в режиме счетчика внешних событий (PAMOD = 0), то при PEDGE = 1 детектор события настраивается на распознавание положительного фронта сигнала, при PEDGE = 0 — отрицательного фронта. При работе в режиме стробируемого таймера (PAMOD = 1) бит PEDGE определяет вид сигнала, разрешающего переключение счетчика таймера. Если PEDGE = 1, то счет разрешается при подаче 1 на вход PAI, при этом флаг PAI устанавливается по отрицательному фронту входного сигнала. Если же PEDGE = 0, то счет разрешается при подаче 0 на вход PAI, при этом флаг PAI устанавливается по положительному фронту входного сигнала.

Биты CLK1:CLK0 назначают источник тактирования для счетчика временной базы модуля таймера (см. рис. 4.27).

Биты PAOVI и PAI (не путать с одноименным входом) разрешают прерывания по событию переполнения счетчика (флаг PAOVF) и по событию на входе PAI (флаг PAIF), тип которого определяется режимом работы и значением бита PEDGE.


Регистр флагов счетчика событий

Регистр флагов счетчика событий PAFLG (Pulse Accumulator Flag Register) располагается в памяти МК по адресу $00A1 и содержит всего два значимых бита (рис. 4.45). Флаг переполнения счетчика устанавливается, когда 16-разрядный счетчик подсистемы изменяет свое значение с $FFFF на $0000. Флаг события подсистемы PAIF устанавливается в 1 при каждом перепаде потенциала на входе PAI, который указан битом PEDGE и режимом работы счетчика. Оба этих бита сбрасываются посредством записи в установленный бит 1.


Регистр текущего состояния счетчика событий

Регистр счетчика PACNT (Pulse Accumulator Counter Register) содержит текущий код 16-разрядного счетчика подсистемы. Поэтому он располагается в двух ячейках памяти: старший байт PACNTH — по адресу $00A2, младший байт PACNTL — по адресу $00A3. Поскольку изменение кода счетчика может произойти в произвольный момент времени, рекомендуется производить его чтение в двухбайтовом формата с использованием типа LDD или LDX/LDY.


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

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

• Линейные датчики, напряжение на выходе которых пропорционально напряженности магнитного поля, в которое помещен датчик;

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

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

В нашем примере мы поместим магнит на спицу вращающегося колеса. Однополярный датчик Холла установим на вилке колеса, выход датчика соединим со входом (PT7) счетчика внешних событий МК семейства 68HC12 (рис. 4.46). Тогда на выходе датчика будет генерироваться один импульс при каждом полном обороте колеса. Если мы подсчитаем число импульсов с выхода датчика на известном временном интервале, мы сможем определить скорость движения и расстояние, которое было преодолено за время измерения.



Рис. 4.46. Колесо велосипеда с датчиком Холла


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

• В первую очередь определите связь между одним оборотом колеса и пройденной дистанцией пути. Предположите, что диаметр колеса равен 66,04 см (26 дюймов).

• Произведите инициализацию подсистемы счетчика внешних событий:

 a. Подсистема счетчика событий использует вход PT7 для подключения внешнего импульсного сигнала. Для конфигурирования линии PT7 на ввод установите бит 7 регистра TIOS в 0, также в 0 должны быть установлены биты 6 и 7 регистра PCTL1.

 b. Запрограммируйте на выбранный режим регистр управления счетчиком событий PACTL. Определите необходимое состояние каждого бита самостоятельно.

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

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

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

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

/*------------------------------------------------------------------------------*/

/* Функция initialize_PA задает начальные установки подсистемы счетчика событий */

/*------------------------------------------------------------------------------*/

void initialize_PA(void) {

 TIOS = 0x00; /*конфигурировать вход PT7 для работы */

 TCTL1 = 0х00; /*в качестве источника сигналов для счетчика*/

 OC7M = 0x00 /*внешних событий – 3 команды*/

 TSCR = 0х80; /*разрешить работу всего модуля таймера*/

 PACTL = 0х70; /*разрешить работу в режиме счетчика внешних*/

               /*событий по положительному фронту сигнала*/

}

/*-------------------------------------------------------------------------------*/

4.15. Модуль меток реального времени

 Сделать закладку на этом месте книги

Многие применения требуют организации выполнения одного и того же фрагмента программы через равные интервалы времени. Для удобства разработчиков МК семейства 68HC12/HCS12 оснащены специальным модулем меток реального времени RTI (Real Time Interrupt), который генерирует равноотстоящие во времени запросы на прерывание (рис. 4.47). Тогда фрагмент программы, которые должен исполняться через равные интервалы времени, может быть оформлен как подпрограмма прерывания по запросу RTI. И желаемый алгоритм функционирования устройства будет реализован.



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


Модуль меток реального времени RTI использует два регистра специальных функций: регистр управления RTICTL (Real Time Interrupt Control Register) и регистр флагов RTIFLG (Real Time Interrupt Flag Register).

Бит RTIE в регистре управления RTICTL (рис. 4.47) разрешает работу подсистемы меток реального времени. При RTIE = 1 подсистема находится в активном состоянии, при RTIE = 0 работа системы запрещена. Биты RTR2:RTR1:RTR0 определяют период следования меток реального времени. Таблица рис. 4.47 устанавливает соответствие между кодовой комбинацией битов RTR2:RTR1:RTR0 и временным интервалом между двумя соседними метками модуля RTI. Последний именуют периодом RTI.

Выбор периода генерации меток реального времени

RTR[2:0] Коэффициент деления 2х При частоте внутренней системной шины
4 МГц 8 МГц
000 зарезервирован нет нет
001 13 2,048 мс 1,024 мс
010 14 4,096 мс 2,048 мс
011 15 8,192 мс 4,096 мс
100 16 16,384 мс 8,192 мс
101 17 32,768 мс 16,384 мс
110 18 65,536 мс 32,768 мс
111 19 131,072 мс 65,536 мс

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




Рис. 4.48. Блок-схема алгоритма часов реального времени


Регистр флагов RTIFLG (рис. 4.47) содержит всего один флаг RTIF. Этот флаг устанавливается, когда модуль закончил отсчет очередного периода RTI.

Счетчик подсистемы меток реального времени тактируется импульсной последовательностью с частотой fBUS . В модуле меток реального времени эта частота делится. Коэффициент деления, устанавливаемый разрядами RTR2:RTR1:RTR0, можно выбрать по таблице рис. 4.47. Проанализировав данные таблицы, можно установить, что для МК с частотой внутренней шины 8 МГц максимальный период меток реального времени составляет примерно 65 мс.


Пример использования модуля меток реального времени

Ниже приведен исходный текст программы realtime.c для реализации часов реального времени на основе отсчетов модуля RTI с интервалами 8,196 мс. В подпрограмме прерывания программный счетчик накапливает 122 отсчета RTI (рис.4.48), которые составляют временной интервал длительностью 1 с. По прошествии каждой секунды инкрементируется программный счетчик sec_ctr, по прошествии каждой минуты — счетчик mins_ctr и т.д. вплоть до счетчика дней.

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

/*-----------------------------------------------------------------------*/

/* filename: realtime.c                                                  */

/* МAIN PROGRAМ: Эта программа генерирует две импульсных                 */

/* последовательности с использованием таймера и двух каналов подсистемы */

/* прерывания.Сигналы формируются на выходах 2 и 3 таймера.              */

/*-----------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>


/*используемые функции*/

void RTI_isr{void); /*подпрограмма прерывания по RTI*/


/* interrupt pragma */

#pragma interrupt_handler RTI_isr

/*инициализация таблицы векторов прерывания*/

#pragma abs_address: 0xF7F0

void (*RTI_interrupt_vector[]) ()={RTI_isr};

#pragma end_abs_address


/*глобальные переменные*/

unsigned int ms_ctr, sec_ctr, mins_ctr, hrs_ctr, days_ctr;


void main{void) {

 ms_ctr = 0; /*инициализация переменных*/

 sec_ctr = 0;

 mins_ctr = 0;

 hrs_ctr = 0;

 days_ctr = 0;

 RTICTL = 0х84; /*разрешить прерывания от модуля RTI, выбрать*/

 CLI();         /*период RTI 8,196 мс*/

 while(1) /*ожидать прерывание*/

 {

  ;

 }

}


/*---------------------------------------------------------*/

/* Функция RTI_isr подпрограмма прерывания каждые 8,196 мс */

/*---------------------------------------------------------*/

void RTI_isr(void) {

 RTIFLG = 0х80; /*сброс флага события RTI*/

 ms_ctr = ms_ctr+1; /*обновить счетчик миллисекунд*/

 if (ms_ctr == 122) /*обновить счетчик секунд*/

 {

  ms_ctr = 0;

  sec_ctr = sec_ctr + 1;

 }

 if (sec_ctr == 60) /*обновить счетчик минут*/

 {

  sec_ctr = 0;

  mins_ctr = mins_ctr + 1;

 }

 if (mins_ctr == 60) /*обновить счетчик часов*/

 {

  mins_ctr = 0;

  hrs_ctr = hrs_ctr + 1;

 }

 if (hrs_ctr == 24) /*обновить счетчик дней*/

 {

  hrs_ctr = 0;

  days_ctr = days_ctr + 1;

 }

}

/*---------------------------------------------------------*/

4.16. Модуль таймера ECT в составе МК МC68HC12BE32 и HCS12

 Сделать закладку на этом месте книги

Все микроконтроллеры семейства HCS12 и всего одна модель MC68HC12BE32 семейства 68HC12 оснащены более совершенным модулем таймера ECT (Enhanced Capture Timer). Модуль таймера EST унаследовал основные технические решения от своего предшественника — модуля таймера TIM. Поэтому, так же как в модуле TIM, основу таймера EST составляют 16-разрядный счетчик временной базы и восемь универсальных каналов захвата/сравнения.

Однако в модуле EST четыре канала из восьми в режиме входного захвата обладают дополнительным регистром. Такое решение позволяет в режиме входного захвата зафиксировать два момента изменения сигнала на входе канала прежде, чем будет установлен триггер события в канале CnF. Рассматриваемые каналы называют буферированными, они могут работать как в режиме временного хранения, так и в режиме очереди. Четыре оставшихся канала называют небуферированными. Правила функционирования этих каналов в режиме входного захвата полностью соответствуют аналогичным для модуля TIM. Полный набор функций каналов захвата/сравнения модуля таймера EST приведен на рис. 4.49.



Рис. 4.49. Усовершенствованный модуль таймера ECT


Второе отличие модуля EST от модуля TIM состоит в том, что модуль EST имеет в своем составе четыре 8-разрядных счетчика события (PACN3…PACN0). Эти счетчики могут быть объединены парами для получения двух 16-разрядных счетчиков событий: (PACN3:PACN2) и (PACN1:PACN0).

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

4.16.1. Небуферированные каналы входного захвата

 Сделать закладку на этом месте книги

Алгоритм функционирования небуферированных каналов входного захвата полностью аналогичен функционированию в аналогичном режиме каналов модуля TIM. Однако небуферированные каналы модуля EST снабжены дополнительной функцией управления режимом. Регистр управления порядком перезаписи ICOVW (Input Control Overwrite Register) содержит восемь битов NOVWn (рис. 4.49). Если бит NOVWn установлен в 1, то регистр данных небуферированного канала с номером n не может быть перезаписан под действием аппаратных средств, пока этот регистр не будет считан программой. Если бит NOVWn = 0, то функция блокировки записи для небуферированного канала снимается.

4.16.2. Буферированные каналы входного захвата

 Сделать закладку на этом месте книги

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

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

Буферированные каналы входного захвата могут работать или в режиме временного хранения, или в режиме очереди. Режим работы назначается битом LATQ в регистре управления режимом входного захвата ICSYS. Если бит LATQ установлен в 1, то буферированные каналы работают в режиме временного хранения. Если же бит LATQ = 0, то для буферированных каналов назначается режим очереди.

В режиме временного хранения (LATQ = 1) текущий код счетчика временной базы запоминается в первом регистре данных при изменении входного сигнала, на которое настроен детектор события. Далее этот код автоматически переписывается во второй регистр данных при наступлении одного из трех событий:

• Код 16-разрядного вычитающего счетчика MCCNT достиг $0000;

• В счетчик MCCNT под управлением программы вписан код $0000;

• Бит ICLAT в регистре управления вычитающим счетчиком MCCTL (рис. 4.50) программно установлен в 1.



Рис. 4.50. Аппаратные средства буферированного канала входного захвата — режим временного хранения


В режиме временного хранения биты управления NOVWn действуют также, как и небуферированных каналах (см. 14.6.1)

В режиме очереди (LATQ = 0) и при NOVWn = 0 событие входного захвата вызывает автоматическую перезапись содержимого первого регистра данных канала во второй регистр данных, а в первый регистр данных загружается текущий код счетчика временной базы (рис. 4.51). Если буферированный канал работает в режиме очереди и бит NOVWn = 1, то и первый и второй регистры данных не запоминают момента наступления события, если они не очищены, т.е. не были считаны программой до наступления события.



Рис. 4.51. Аппаратные средства буферированного канала входного захвата — режим очереди

4.16.3. Особенности счетчиков событий

 Сделать закладку на этом месте книги

Модуль таймера EST оснащен четырьмя 8-разрядными счетчиками событий (рис. 4.52). Счетчики событий могут быть объединены попарно, тогда они образуют два 16-разрядных счетчика события. Так же, как и каналы захвата, счетчики событий могут работать или в режиме временного хранения, или в режиме очереди (рис. 4.52).



Рис. 4.52. Аппаратные средства счетчика внешних событий в составе таймера ECT

4.16.4. Регистры управления модуля EST

 Сделать закладку на этом месте книги

На рис. 4.53 приведен формат регистров модуля таймера EST, которые отсутствуют в рассмотренном ранее модуле TIM. Адреса регистров указаны как для МК BE32 семейства 68HC12, так и для микроконтроллеров семейства HCS12. Приведенные адреса можно рассматривать как абсолютный адрес, если в проекте используется настоящий физический адрес начала блока регистров $0000. Если же блок регистров перемещен в другое, виртуальное адресное пространство, то указанные адреса следует рассматривать как смещение адреса регистра относительно адреса начала регистрового блока.



Рис. 4.53. Формат регистров модуля ECT



Регистр управления порядком перезаписи

Регистр управления


убрать рекламу






порядком перезаписи ICOVW (Input Control Overwrite Register) располагается в памяти МК по адресу $00AA/$002A. Формат регистра представлен на рис. 4.53. Регистр содержит восемь битов NOVWn (n — номер канала). Если бит NOVWn = 0, то первый и второй регистры данных канала входного захвата с номером n могут быть автоматически перезаписаны при наступлении очередного события входного захвата. Если же бит NOVWn = 1, то регистры данных канала не могут быть перезаписаны, если они предварительно не были очищены, т.е. считаны под управлением программы.


Регистр управления режимом входного захвата

Регистр управления режимом входного захвата ICSYS (Input Control System Control Register) содержит бит разрешения буферированного режима в каналах BUFEN и бит выбора режима работы буферированных каналов LATQ (временного хранения или очереди). Если бит BUFEN установлен, то работа второго регистра данных и буферного регистра счетчика событий буферированных каналов модуля таймера разрешена. Если бит LATQ равен 1, то буферированные каналы входного захвата работают в режиме временного хранения, при LATQ = 0 эти каналы работают в режиме очереди.


Регистр управления счетчиком задержки

Регистр управления счетчиком задержки DLYCT (Delay Counter Control Register) разрешает вставку регулируемого временного интервала между моментом распознавания детектором события изменения входного сигнала и интерпретацией этого изменения как события входного захвата со всеми последующими действиями аппаратных средств канала таймера. Событие входного захвата будет распознано, если логический уровень сигнала по истечении временной задержки будет противоположен уровню сигнала перед запуском счетчика задержки. Такое решение позволяет повысить устойчивость входов к шумам на фронтах переключения. Длительность задержки определяется битами DLY1:DLY0. При DLY1:DLY0 = 00 задержка не вставляется. При DLY1:DLY0 = 01 задержка равна 256 периодам сигнала P clock системы тактирования, при DLY1:DLY0 = 10 задержка составляет 512 периодов, при DLY1:DLY0 = 11 — 1024 периода того же сигнала.


Регистр управления 16-разрядным вычитающим счетчиком

Регистр управления вычитающим счетчиком MCCTL (Modulus Down-Counter Control Register) предназначен для задания режима работы 16-разрядным вычитающим счетчиком с изменяемым коэффициентом счета. Если бит MODMC установлен в 0, то счетчик уменьшает код, начиная с предварительно записанного значения до 0, затем останавливается. Если бит MODMC равен 1, счетчик считает непрерывно. При достижении кода $0000, он автоматически перезагружается кодом, записанным в регистр коэффициента счета MCCNT.


Регистр коэффициента счета вычитающего счетчика

Регистр коэффициента счета вычитающего счетчика MCCNT (Modulus Down-Counter Register) содержит изменяемый программно коэффициент счета 16-разрядного вычитающего счетчика.


Регистр флагов вычитающего счетчика

Регистр флагов вычитающего счетчика MCFLG (Modulus Down-Counter Flag Register) содержит флаг обнуления счетчика MCZF. Этот флаг устанавливается в 1, когда код счетчика становится равным $0000. Флаг MCZF сбрасывается посредством записи в его разряд 1.

4.17. Обмен информацией в последовательном коде: многофункциональный последовательный интерфейс 

 Сделать закладку на этом месте книги

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

В МК семейства 68HC12/HCS12 обмен в последовательном коде обеспечивает модуль многофункционального последовательного интерфейса (MSI — Multiple Serial Interface). Этот модуль содержит в себе две независимых подсистемы последовательного обмена: контроллер асинхронного обмена SCI (Serial Communication Interface) и контроллер синхронного обмена SPI (Serial Peripheral Interface). Каждый из контроллеров обслуживают линии порта S, для которых эта функция является альтернативной.



Рис. 4.54. Два наиболее распространенных типа последовательных интерфейсов


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

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



Рис. 4.55. Сопряжение МК с ЦАП по параллельному и последовательному интерфейсу


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

Теоретически скорость обмена в синхронном режиме значительно превышает скорость обмена в асинхронном режиме.

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

Интерфейсы последовательного обмена используют различные способы синхронизации обмена. Формат кадра асинхронного обмена представлен на рис. 4.56. В асинхронном режиме с использованием интерфейса SCI данные передаются байтами в стандартном американском коде ASCII (American Standard Code for Information Interchange). Кроме восьми битов данных кадр обмена содержит также стартовый и стоповый биты, отмечающие начало и конец кадра, и необязательный бит паритета. Стартовый и стоповый биты участвуют в процессе синхронизации между передатчиком и приемником, бит паритета (если он присутствует в кадре) используется для контроля на стороне приемника за наличием ошибок в принятом байте данных.



Рис. 4.56. Форма кадра асинхронного обмена


Контроллер интерфейса SCI в составе МК 68HC12 обслуживают две линии ввода/вывода: TxD — выход передатчика контроллера SCI, RxD — вход приемника контроллера SCI. При использовании асинхронного интерфейса SCI взаимодействующие устройства перед сеансом обмена должны обязательно «договориться» о скорости передачи данных. Если передатчик находится в неактивном состоянии (Idle), то на его выходе устанавливается сигнал высокого логического уровня (рис. 4.56). В это время приемник аналогичного контроллера SCI на другом конце линии постоянно сканирует уровень сигнала на входе RxD. Если приемник обнаруживает, что сигнал на линии изменил состояние с 1 на 0, то он производит несколько контрольных выборок сигнала, чтобы убедиться в наличии на линии низкого логического уровня. Если низкий уровень присутствует на линии в течение времени, равного интервалу передачи одного бита для установленной скорости обмена, то приемник распознает такое состояние как старт-бит (рис. 4.56) и начинает прием последующих бит данных. В процессе приема аппаратные средства приемника формируют метки времени, которые должны соответствовать середине интервала присутствия на линии каждого бита. По каждой метке производятся три выборки уровня сигнала на линии. По результатам выборки методом мажоритарной логики определяется значение очередного принятого бита информации. Если все три значения равны, то прием бита полностью успешный. Если значения разные, то аппаратные средства приемника устанавливают бит звона на линии, который затем может быть использован программистом при оценке надежности приема. После приема восьми (при использовании бита паритета девяти) бит данных приемник контролирует наличие на линии логической 1. Это стоп-бит, который завершает прием одного кадра. Если аппаратные средства приемника не обнаружили на линии стоп-бита, будет установлен бит ошибки формата кадра. Тогда весь кадр должен быть воспринят программой как ошибочный.

В синхронных последовательных интерфейсах передача по линии каждого бита сопровождается сигналом подтверждения по другой вспомогательной линии. Эту линию в интерфейсе SPI обозначают как SCK (Shift Clock). Такой способ передачи данных позволяет достичь очень высоких скоростей обмена. Именно он и используется в контроллерах SPI в составе МК 68HC12.

4.17.1. Термины последовательного обмена

 Сделать закладку на этом месте книги

На рис. 4.57 представлена обобщенная временная диаграмма обмена в последовательном коде. Эта диаграмма позволит нам познакомиться с терминами, которые принято использовать при описании последовательного обмена.



Рис. 4.57. Временные диаграммы синхронного последовательного обмена


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

Скорость обмена (bit rate): Число бит, которые передаются по линии в одну секунду (бит/с). Скорость обмена в бит/с равна частоте сигнала синхронизации в Гц.

Скорость обмена (baud rate): Число бит, которые передаются по линии в одну секунду, выраженная в бодах. 1 бод = 1 бит/с.

Время передачи одного бита (bit time): Определяет временной интервал, в течение которого по линии передается один бит информации. Вычисляется как 1/(скорость обмена).

Кодирование информации для передачи одного бита (line code): Способ представления одного бита информации при передаче линиям связи.

Микроконтроллеры 68HC12 используют NRZ-кодирование (NonReturn to Zero — код с невозвращением к нулю). Этот способ кодирования предполагает, что при передаче единицы на линию выставляется высокий логический уровень, при передаче 0 — низкий логический уровень.



Рис. 4.58. Временные диаграммы передачи данных в коде с невозвращением к нулю


Стандартный американский код ASCII (American Standard Code for Information Interchange): Принятый всеми производителями вычислительной техники способ кодирования букв и цифр, а также знаков пунктуации. Каждый из перечисленных символов представляется одним байтом. При кодировании букв латинского алфавита используются только 7 младших битов, старший бит байта остается нулевым. В этот бит может быть помещен бит паритета. Таблица кодов представления символов латинского алфавита приведена на рис. 4.59.

  Старший полубайт
$0_ $1_ $2_ $3_ $4_ $5_ $6_ $7_
Младший полубайт $_0 NUL DLE SP 0 @ P ` p
$_1 SON DC1 ! 1 A Q a q
$_2 STX DC2 2 B R b r
$_3 ETX DC3 # 3 C S c s
$_4 EOT DC4 $ 4 D T d t
$_5 ENQ NAK % 5 E U e u
$_6 ACK SYN & 6 F V f v
$_7 BEL ETB ' 7 G W g w
$_8 BS CAN ( 8 H X h x
$_9 HT EM ) 9 I Y i y
$_A LF SUB * : J Z j z
$_B VT ESC + ; K [ k {
$_C FF FS , < L \ l |
$_D CR GS - = M ] m }
$_E SO RS . > N ^ n ~
$_F SI US / ? O _ o DEL

Рис. 4.59. Коды символов в ASCII


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

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

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

Дуплексный обмен: При дуплексном режиме обмена в каждый момент времени осуществляет двунаправленная передача информации между двумя устройствами.


Вопросы для самопроверки

1. Приведите коды ASCII для выражения «B32-VB». Для ответа воспользуйтесь таблицей рис. 4.59.

Ответ: $42 $33 $32 $2D $45 $56 $42

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

Ответ: $42 $33 $B2 $2D $C5 $56 $42

3. В приведенной кодовой строке использован нечетный паритет. Бит паритета находится в разряде D7 кода. Какое слово зашифровано в строке $C1, $F7, $E5, $73, $EF, $6D, $E5, $A1?

Ответ: Awesome!

4. Сравните SCI и SPI интерфейсы.

Ответ: Интерфейсы SCI и SPI — это интерфейсы для последовательной передачи данных. Интерфейс SCI использует асинхронный способ передачи данных, при котором дополнительный сигнал синхронизации не используется. Вместо него применяются специальные биты синхронизации (старт- и стоп-бит). Напротив, интерфейс SPI использует дополнительную линию синхронизации.

4.18. Контроллер асинхронного обмена SCI

 Сделать закладку на этом месте книги

Различные модели МК семейства 68HC12 и HCS12 могут интегрировать на кристалле сразу несколько интерфейсов для последовательного асинхронного обмена. Однако увеличение портов асинхронного обмена не сопровождается изменением аппаратных средств контроллера SCI. На кристалле МК просто размещают несколько полностью идентичных одноканальных контроллеров SCI, различая их порядковыми номерами: SCI0, SCI1 и т.д.

Основные технические характеристики контроллера асинхронного обмена (модуля SCI) в составе МК семейства 68HC12:

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

• Использует NRZ-кодирование, при котором для передачи единицы на линию выставляется высокий логический уровень, для передачи 0 — низкий логический уровень.

• Реализует широкий диапазон скоростей приема и передачи данных. Для задания скорости используются два регистра скорости обмена SCxBDH и SCxBDL (x — номер контроллера SCI в составе МК).

• Обеспечивает два стандартных кадра обмена в асинхронном режиме: 10-битовый (8 бит данных) и 11-битовый (9 бит данных) формат. Выбор формата кадра обмена определяет бит M в регистре управления.

• Обладает независимыми аппаратными средствами приемника (Transmitter) и передатчика (Receiver). Каждое из устройств имеет собственный бит разрешения работы: TE и RE соответственно.

• Приемник модуля SCI имеет специальный режим ожидания, который позволяет организовать локальную сеть в мультипроцессорных системах. В таких системах на основе асинхронного интерфейса одно устройство является ведущим, а все остальные — ведомыми. В каждый момент времени может происходить обмен между ведущим и одним из ведомых. Остальные ведомые при этом не должны воспринимать сигналы на общей линии связи. Это достигается путем перевода приемника контроллера SCI в состояние ожидания «Sleep Mode». Перевод приемника в это состояние осуществляется установкой бита RWU в регистре управления. Выход из состояния ожидания может происходить по двум сценариям. По первому сценарию аппаратные средства приемника должны распознать отсутствие обмена на линии связи (состояние Idle). Это состояние характеризуется наличием высокого логического уровня на линии в течение 10 или 11 интервалов передачи бита при назначенной скорости обмена. Если приемник обнаружил состояние Idle на линии, то это означает, что сеанс обмена с другим ведомым в сети окончен, ведущий может начать новый сеанс, поэтому ведомый должен стать активным, чтобы не пропустить обращение ведущего к нему. По второму сценарию ведущий посылает первый кадр обмена со специальным маркером, который информирует приемник о том, что в кадре указан адрес устройства, с которым ведущий будет производить сеанс связи. Аппаратные средства приемника реагируют на этот маркер в режиме ожидания, и при его поступлении переходят в активный режим работы. Бит WAKE в регистре управления модулем определяет выбор сценария для перевода приемника в активный режим работы.

• Аппаратные средства контроллера устанавливают четыре флага, которые могут генерировать запросы на прерывание от контроллера SCI.

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

 2. TC — бит завершения передачи данных. Устанавливается, если данные для передачи в сдвиговом и буферном регистре данных передатчика отсутствуют. Бит TC информирует МК об отсутствии процесса передачи данных в текущий момент времени. В это время на линии TxD установлен высокий логический уровень сигнала (состояние IDLE).

 3. RDRF — бит завершения приема байта данных. Устанавливается в момент, когда принятые по линии RxD данные автоматически переписываются в буферный регистр данных приемника.

 4. IDLE — бит неактивного состояния линии связи. Устанавливается в 1, если на линии RxD диагностируются 10 или 11 (в зависимости от формата кадра) последовательных единиц.

• Аппаратные средства приемника диагностируют три типа ошибок:

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

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

 3. Нарушение логики паритета кадра. Диагностируется, если функция паритета при обмене разрешена, и в принятом кадре значение бита паритета не удовлетворяет принятой логике формирования паритета: при назначенном нечетном паритете число единиц в слове четное, и наоборот. При обнаружении этого типа ошибки в регистре состояния устанавливается бит PF.

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


Вопросы для самопроверки

1. Каково назначение бита паритета?

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

2. По какому правилу определяется значения бита паритета? Поясните разницу между четным и нечетным паритетом.

Ответ: Существенной разницы нет. Правило формирования бита паритета:

 • В передаваемом слове данных подсчитывается число единиц;

 • Если это число четное (при четном паритете) или нечетное (при нечетном паритете), то бит паритета устанавливается равным 0;

 • Наоборот, если число нечетное (при четном паритете) или четное (при нечетном паритете), то бит паритета устанавливается равным 1.

4.18.1. Передатчик контроллера SCI

 Сделать закладку на этом месте книги

Функциональная схема передатчика в составе контроллера SCI представлена на рис. 4.60. Основным ее элементом является 11-разрядный сдвиговый регистр. Ранее, рассматривая временные диаграммы обмена, Вы могли заметить, что код символа ASCII содержит всего 7 бит. Зачем тогда передатчик использует 11-разрядный регистр? Дело в том, что в разряды этого регистра аппаратными средствами вписывается стартовый и стоповый биты. Кроме того, предусмотрена возможность обмена и 8-разрядными словами данных. В этом случае бит паритета уже невозможно будет поместить на место разряда D7, и для него предусмотрели разряд D8 сдвигового регистра. Аппаратные средства передатчика предусматривают возможность формирования как 10-разрядного кадра обмена (8 бит данных, старт и стоп-биты), так и 11-разрядного (9 бит данных, старт и стоп-биты). Выбор формата кадра обмена определяет бит M в регистре управления.



Рис. 4.60.

убрать рекламу






b>Аппаратные средства блока передатчика в составе контроллера асинхронного обмена


Аппаратные средства передатчика модуля SCI в составе МК 68HC12 предусматривают возможность автоматического (без специальных команд программы) формирования бита паритета по содержимому передаваемого слова данных.

Блок управления формирует все необходимые сигналы для корректной работы аппаратных средств передатчика. Работа передатчика разрешается независимо от состояния приемника в составе этого же контроллера SCI. Если бит TE в регистре управления установлен, то работа передатчика активизируется, и соответствующий вывод порта PORT S конфигурируется как выход TxD. Блок управления также генерирует все запросы на прерывания, связанные с работой передатчика.

Скорость передачи данных определяется программируемым делителем, на вход которого поступает импульсная последовательность P_CLOCK системы тактирования МК. Коэффициент деления назначается битами SBR12…SBR0 регистра скорости обмена.

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

4.18.2. Приемник контроллера SCI

 Сделать закладку на этом месте книги

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



Рис. 4.61. Аппаратные средства блока приемника в составе контроллера асинхронного обмена


Работа приемника разрешается установкой бита PE в регистре управления. Если приемник активирован, то соответствующая линия порта PORT S конфигурируется как вход RxD. Блок мажоритарной логики обрабатывает входной сигнал и формирует очередной младший бит сдвигового регистра приемника. В процессе приема каждый поступающий бит опрашивается три раза. Если все три выборки совпали (три 1 или три 0), то соответствующее значение передается в сдвиговый регистр. При несовпадении (два бита равны 1, третий — 0, или наоборот) значение бита формируется по логике «два из трех». Но одновременно устанавливается бит наличия шума на линии NF.

По завершении приема всех 10 или 11 бит кадра приемник автоматически переписывает принятую информацию в регистр данных контроллера SCI и устанавливает в 1 флаг RDRF, который информирует МК о необходимости считывания принятого байта в память МК.

4.18.3. Регистры контроллера SCI

 Сделать закладку на этом месте книги

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

• Регистры скорости обмена;

• Регистры управления;

• Регистры состояния;

• Регистры данных.

Далее мы рассмотрим формат и назначение битов каждого регистра модуля SCI.


Регистры скорости обмена SCxBDH и SCxBDL

Два 8-разрядных регистра SCxBDH и SCxBDL предназначены для управления скоростью обмена по последовательному интерфейсу SCI. Для назначения желаемой скорости используются разряды SBR12…SBR0 этих двух регистров (рис. 4.63). Число, которое следует записать в эти разряды может быть определено с использованием таблицы рис. 4.62 или рассчитано по формуле:

SBR = PCLOCK/(16×BAUD_RATE),

где SBR — десятичный эквивалент двоичного кода, который должен быть записан в разряды SBR12…SBR0 регистров SCxBDH и SCxBDL, PCLOCK — частота импульсной последовательности PCLK в Герцах, BAUD_RATE — частота обмена в бодах.

Желаемая скорость обмена (бод) Значение коэффициента при частоте внутренней системной шины
4 МГц 8 МГц
110 2273 4545
300 833 1667
600 417 833
1200 208 417
2400 104 208
4800 52 104
9600 26 52
14400 17 35
19200 13 26
38400 13

Рис. 4.62. Выбор коэффициента деления модуля SCI




Рис. 4.63. Формат регистра скорости обмена SCxBDH/SCxBDL



Пример

Необходимо настроить первый контроллер асинхронного обмена (SCI0) на скорость 9600 бод. Если частота импульсной последовательности PCLK равна 8 МГц, то коэффициент деления, который должен быть записан в регистры SC0BDH и SC0BDL, равен:

SBR0 = 8000000/(16×9600) = 52 = $34

Следующий программный фрагмент реализует инициализацию скорости обмена:

/*----------------------*/

/* filename: ini_SCI0.c */

/*----------------------*/

#include <912b32.h>


void main(void) {

 SC0BDH = 0х00;

 SC0BDL = 0х34;

}

/*----------------------*/


Регистры управления SCxCR1 и SCxCR2


Рис. 4.64. Формат регистра управления SCxCR1


Формат первого регистра управления контроллера SCI представлен на рис. 4.64. Биты этого регистра имеет следующее назначение:

LOOPS:

Бит разрешения «замкнутого» режима работы контроллера SCI. Установка в 1 бита LOOPS вызывает перекоммутацию входа приемника линии RxD, который внутренними средствами отсоединяется от вывода RxD и подсоединяется к выходу передатчика. В этом режиме возможен контроль передаваемой информации. Также режим может быть использован для тестирования работы программного обеспечения без использования устройства управления верхнего уровня. Для реализации «замкнутого» режима должна быть разрешена работа как передатчика, так и приемника.

1 — «замкнутый» режим работы разрешен;

0 — «замкнутый» режим работы запрещен.

WOMS:

Бит выбора режима открытого коллектора. Этот бит определяет состояние выходных буферов линий TxD и RxD.

1 — буферы переведены в режим открытого коллекторного выхода;

0 — буферы работают в режиме обычного двухстабильного логического выхода (TxD) и входа (RxD).

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

RSRC:

Бит выбора внутренней схемотехники в «замкнутом» режиме работы. Если бит LOOPS = 1 и бит RSRC = 1 то вход приемника коммутируется непосредственно к выводу TxD микроконтроллера. При RSRC = 0 вход приемника подсоединяется к выходу передатчика внутри МК.

M:

Бит выбора формата кадра асинхронного обмена.

1 — 11-битовый формат кадра: 1 стартовый бит, 9 бит слова данных, 1 стоповый бит;

0 — 10-битовый формат кадра: 1 стартовый бит, 8 бит слова данных, 1 стоповый бит.

WAKE:

Бит выбора способа выхода приемника из неактивного состояния:

1 — установка маркера адреса (бит D7 при M=0 или бит D8 при M=1) ) переводит приемник в активный режим работы;

0 — состояние IDLE на линии переводит приемник в активное состояние.

После сброса МК бит устанавливается в 0.

ILT:

Бит выбора режима распознавания неактивного состояния линии RxD. Этот бит определяет момент начала отсчета для определения неактивного состояния линии RxD:

1 — отсчет начинается после идентификации стоп-бита;

0 — отсчет начинается после идентификации старт-бита.

После сброса МК бит устанавливается в 0.

PE:

Бит разрешения работы логики паритета.

1 — формирование бита паритета передатчиком и его анализ приемником реализуются;

0 — функция паритета отключена.

PT:

Бит выбора четного или нечетного паритета (Parity Bit)

1 — бит паритета формируется из условия нечетного числа 1 в слове;

0 — бит паритета формируется из условия четного числа 1 в слове.



Рис. 4.65. Формат регистра управления SCxCR2


Формат второго регистра управления контроллера SCI приведен на рис. 4.65. Четыре старших бита этого регистра (TIE, TCIE, RIE, ILIE) разрешают генерацию запросов на прерывания по разным событиям контроллера SCI. Назначение отдельных битов регистра SCxCR2 следующее:

TIE:

Бит разрешения прерывания от передатчика контроллера SCI. Этот бит разрешает генерацию запроса на прерывание при установке в 1 флага готовности буфера данных передатчика к приему от программы нового байта (бит TDRE).

1 — прерывания от передатчика по флагу SCDE разрешены;

0 — прерывания от передатчика по флагу SCDE запрещены.

TCIE:

Бит разрешения прерывания от передатчика контроллера SCI. Этот бит разрешает генерацию запроса на прерывание при установке в 1 флага завершения работы передатчика TC.

1 — прерывания от передатчика по флагу TC разрешены;

0 — прерывания от передатчика по флагу TC запрещены.

RIE:

Бит разрешения прерывания от приемника контроллера SCI. Этот бит разрешает генерацию запроса на прерывание при установке в 1 флага завершения приема очередного байта RDRF.

1 — прерывания от приемника по флагу SCRF разрешены;

0 — прерывания от приемника по флагу SCRF запрещены.

ILIE:

Бит разрешения прерывания от приемника по флагу IDLE. Этот бит разрешает генерацию запроса на прерывание при установке в 1 флага неактивного состояния линии RxD.

1 — прерывания при установленном флаге IDLE разрешены;

0 — прерывания по флагу IDLE запрещены.

TE:

Бит разрешения работы передатчика контроллера SCI. Если бит TE будет сброшен в процессе передачи, то передача текущего байта будет завершена.

1 — передача разрешена;

0 — передача запрещена.

RE:

Бит разрешения работы приемника контроллера SCI.

1 — прием разрешен;

0 — прием запрещен.

RWU:

Бит управления режимом ожидания приемника контроллера SCI. Установка бита RWU под управлением программы в 1 переводит приемник контроллера SCI в режим ожидания. Пока приемник находится в этом режиме, ни один из флагов, которые связаны с работой приемника (RDRF, IDLE, OR, NF, FE, PE), не может быть установлен. Однако те флаги, которые уже были установлены к моменту перевода приемника в режим ожидания, не сбрасываются в момент записи 1 в бит RWU. Способ перевода приемника в активный режим работы определяет бит WAKE в регистре SCxCR1.

SBK:

Бит управления сообщением «конец сеанса обмена». Если бит SBK установить под управлением программы в 1, то передатчик контроллера SCI генерирует в линию TxD последовательность из 10 (бит M=0) или 11 (бит M=1) нулевых битов и одного единичного бита.


Регистры состояния SCxSR1 и SCxSR2


Рис. 4.66. Формат регистра состояния SCxSR1


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

TDRE:

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

TC:

Бит завершения передачи данных. Устанавливается, если данные для передачи в сдвиговом и буферном регистре данных передатчика отсутствуют, а также, если не реализуется режим передачи сообщения «конец сеанса обмена». Бит TC информирует МК об отсутствии процесса передачи данных в текущий момент времени. В это время на линии TxD установлен высокий логический уровень сигнала (состояние IDLE). Бит TC вызывает генерацию запроса на прерывание, если бит TCIE в регистре SCxCR2 установлен.

RDRF:

Бит завершения приема байта данных. Устанавливается в момент, когда принятые по линии RxD данные автоматически переписываются в буферный регистр данных приемника. Бит RDRF вызывает генерацию запроса на прерывание, если бит RIE в регистре SCxCR2 установлен.

IDLE:

Бит неактивного состояния линии RxD. Устанавливается в 1, если на линии RxD диагностируются 10 или 11 (в зависимости от формата кадра) последовательных единиц. Бит IDLE вызывает генерацию запроса на прерывание, если бит ILIE в регистре SCxCR2 установлен.

OR:

Бит ошибки приема. Устанавливается при попытке записи аппаратными средствами приемника очередного принятого байта из сдвигового регистра в буферный регистр данных в то время, как предыдущие данные из буферного регистра еще не считаны (бит RDRF установлен).

NF:

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

FE:

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

PF:

Бит нарушения паритета кадра. Устанавливается, если функция паритета при обмене разрешена, и в принятом кадре значение бита паритета не удовлетворяет принятой логике формирования паритета: при назначенном нечетном паритете число единиц в слове четное, и наоборот.

Формат второго регистра состояния контроллера SCI представлен на рис. 4.67. Регистр SCxSR2 содержит всего один бит RAF. Этот бит автоматически устанавливается в 1 в то время, когда в сдвиговом регистре приемника продолжается формирование очередного принимаемого байта данных.



Рис. 4.67. Формат регистра состояния SCxSR2



Регистры данных SCxDRH и SCxDRL

Формат двух 8-разрядных регистров данных контроллера SCI представлен на рис. 4.68. Регистр SCxDRL используется, если контроллер SCI настроен на обмен данными в 8-разрядном формате (10-битовый формат кадра). Тогда по адресу регистра SCxDRL записываются данные для передачи, и из этого же регистра считываются принятые данные. Если контроллер SCI настроен на обмен данными в 9-разрядном формате (11-битовый формат кадра), то старший бит для передачи записывается под управлением программы в разряд T8 регистра SCxDRH, а при приеме из разряда R8 считывается старший 9-ый бит принятого слова. Младшие восемь разрядов при передаче и при приеме, как и в случае 8-разрядного слова данных, находятся в регистре SCxDRL.



Рис. 4.68. Формат регистра данных SCxDRH/SCxDRL



Вопросы для самопроверки

1. Каково различие между битами TDRE и RDRF?

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

2. Каково назначение флага PF? Почему он чрезвычайно важен при обмене информацией в последовательном коде?

Ответ: Флаг нарушения паритета кадра PF устанавливается, когда произошла ошибка в приеме одного или нескольких бит одного кадра. Прикладная программа контролирует бит PF, как индикатор неверного приема, и должна повторить обмен.

3. Опишите события, которые могут генерировать прерывания от модуля SCI.

Ответ: Четыре источника прерываний ассоциируются с модулем SCI:

 • Прерывание по флагу TDRE, когда регистр данных приемника пуст. Это прерывание разрешается битом TIE в регистре управления SCxCR2;

 • Прерывание по флагу TC, когда передача слова закончена. Это прерывание разрешается битом TCIE в регистре управления SCxCR2;

 • Прерывание по флагу RDRF, когда прием очередного слова завершен. Это прерывание разрешается битом RIE в регистре управления SCxCR2;

 •  Прерывание по флагу IDLE, когда приемник находится в неактивном состоянии. Это прерывание разрешается битом ILIE в регистре управления SCxCR2.

4.18.4. Алгоритмы программного обслуживания контроллера SCI

 Сделать закладку на этом месте книги

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

• Инициализацию приемника и передатчика контроллера;

• Управление процессом передачи информации;

• Управление процессом приема информации.

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



Рис. 4.69. Блок-схемы алгоритмов программного обслуживания контроллера асинхронного обмена SCI


Инициализация контроллера SCI. Инициализацию контроллера SCI рекомендуется проводить в следующем порядке:

 •  Установить скорость обмена;

 • Выбрать формат кадра обмена: 8 или 9 бит данных;

 • Назначить параметры приема и передачи в регистрах управления SCxCR1 и SCxCR2;

 • Очистить флаг TDRE. Для этого сначала считать регистр состояния SCxSR1, а затем выполнить операцию записи в регистр данных SCxRD.

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

Управление процессом передачи информации. Для того чтобы передать один байт информации с использованием передатчика контроллера SCI, следует сначала проверить состояние флага TDRE. Если этот флаг установлен в 1, то регистр данных передатчика пуст, и в него может быть записан новый байт для передачи. Далее данные загружаются в один регистр данных SCxDRL, если обмен происходит в 8-разрядном формате, или в два регистра данных SCxDRH:SCxDRL, если обмен производится в 9-разрядном формате. Коды из регистра данных загружаются в сдвиговый регистр передатчика автоматически, после чего начинается собственно процесс передачи. О завершении передачи информирует бит TC, который установится в 1, когда все разряды регистра сдвига будут последовательно выданы на выход TxD. Флаги TDRE и TC могут генерировать запросы на прерывания, если соответствующие биты разрешения прерывания установлены.

Управление процессом приема информации. При приеме информации с использованием приемника контроллера SCI, следует постоянно контролировать состояние флага RDRF. Этот флаг устанавливается в 1, когда прием очередного байта закончен, и принятые данные доступны в регистре данных приемника. Бит может генерировать запрос на прерывание, при условии, что эти прерывания разрешены. Обнаружив в процессе мониторинга флага RDRF или прервавшись по его запросу, МК должен считать данные из регистров SCxDRH:SCxDRL.

4.18.5. Пример программирования контроллера SCI

 Сделать закладку на этом месте книги

Приведенный ниже программный фрагмент SCI.c иллюстрирует технику программного обслуживания асинхронного последовательного интерфейса МК семейства 68HC12.

Отладочная плата MC68HC912B32EVB предоставляет возможность использования только одного контроллера SCI с номером 0. Поэтому в именах регистров специальных функций символ «x» будет заменен нами на символ «0».

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

• SC0BDH:SC0BDL — регистры скорости обмена контроллера SCI. Записанное в него двоичное число определяет скорость передачи данных и скорость приема данных, которые для одного контроллера в соответствии с его принципом действия могут быть только равными;

• SC0CR1 — первый регистр управления контроллера SCI. Используется для выбора формата 8-ми или 9-ти разрядного представления слова в кадре обмена данными (бит M), для выбора режима работы с паритетом или без него (бит PE), для назначения четной или нечетной логики формирования паритета (бит PT);

• SC0CR2 — второй регистр управления контроллера SCI. Его биты разрешают работу передатчика (бит TE) и приемника (бит RE);

• SC0DRL — регистр данных контроллера SPI, младший байт. Используется для обмена данными в последовательном коде в 8-разрядном формате;

• SC0SR1 — первый регистр состояния контроллера SCI. Этот регистр содержит флаг готовности буфера передатчика к приему новых данных TDRE и флаг завершения приема очередного слова в буфер приемника RDRF.

В нашем примере задействован только передатчик контроллера SCI. Он будет непрерывно посылать по линии последовательной связи TxD (вывод PORTS0) код символа «S». Прерывания от контролера SCI в данном примере не используются.

Контроль за состоянием флага TDRE ведется методом полинга.

/*-------------------------------------------------------------------*/

/* filename: SCI.c                                                   */

/* МAIN PROGRAМ: Эта программа реализует непрерывную посылку кода    */

/* символа "S"с скоростью 9600 бод в 8-разрядном формате (кадр 10 бит)*/

/* с битом паритета                                                  */

/*-------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>


/*используемые функции*/

void sci_init(void);

void sci_trans(void);


void main(void) {

 sci_init(); /*инициализация модуля SCI*/

 while(1) {

  sci_trans(); /*передавать данные непрерывно*/

 }

}


/*-------------------------------------------------------*/

/* Функция sci_init производит инициализацию модуля SCI. */

/*-------------------------------------------------------*/

void sci_init(void) {

 unsigned char clear;

 SC0BDL = 0x34; /*установить скорость 9600 бод*/

 SC0BDH = 0x00;

 SC0CR1 = 0х04; /*10-разрядный формат кадра 8 бит данных, с*/

                /*контролем паритета, логика паритета нечетная */

 clear = SC0SR1; /*операция для сброса флага TDRE*/

                 /*флаг сбрасывается в два действия*/

                 /*сначала читать регистр SC0SR1*/

                 /*затем записать в регистр SC0DRL*/

}


/*-------------------------------------------------------------------*/

/* Функция sci_trans осуществляет непрерывную пересылку одного байта */

/*-------------------------------------------------------------------*/

void sci_trans(void) {

 SC0CR2 = 0x08; /*разрешить работу передатчика*/

 SC0DRL = 's'; /*загрузить в буфер передатчика код символа "S"*/

 while (SC0SR1 != 0x80) /*ожидать установления бита TDRE)

 {

  ;

 }

}

/*-------------------------------------------------------------------*/

Если соединить два микропроцессорных контроллера по последовательному интерфейсу так, что выход TxD первого МК будет соединен со входом RxD второго МК и наоборот, то можно будет организовать двусторонний обмен информацией.

Именно эту задачу Вам предстоит решить в домашнем задании №11, полный текст которого Вы найдете в конце главы.

4.19. Синхронный последовательный интерфейс SPI

 Сделать закладку на этом месте книги

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

4.19.1 Концепция интерфейса SPIФункциональная схема обмена между двумя контроллерами SPI

 Сделать закладку на этом месте книги


Рис. 4.70.


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

• Master Mode — режим ведущего. Устройство, работающее в режиме ведущего, начинает сеанс обмена, генерирует передаваемые данные в ведомое устройство и формирует сигналы синхронизации, сопровождающие эти данные.

• Slave Mode— режим ведомого. Устройство, работающее в режиме ведомого, получает сигналы синхронизации от ведущего. В момент поступления импульса синхронизации ведомое устройство запоминает очередной бит 8-разрядного слова, переданный ведущим по одной линии данных, и выставляет на другую линию данных очередной бит другого 8-разрядного слова, передаваемого от ведомого к ведущему.

MOSI (Master Output Slave Input) — линия передачи данных от ведущего  к ведомому.

• MISO (M


убрать рекламу






aster Input Slave Output) 
— линия передачи данных от ведомого к ведущему.

• SCK (Serial Shift Clock) — линия сигнала синхронизации данных. По этой линии ведущее устройство «сообщает» ведомому о начале сеанса обмена с ним.

4.19.2. Алгоритмы работы контроллера SPI

 Сделать закладку на этом месте книги

В данном разделе мы рассмотрим организацию обмена данными с использованием аппаратных средств контроллера SPI в составе МК 68HC12. Мы также кратко остановимся на регистрах управления контроллера SPI. Более подробно эти регистры будут рассмотрены в следующем параграфе.

На рис. 4.71 представлена функциональная схема контроллера SPI. Остановимся сначала на системе синхронизации, которая располагается в левом верхнем углу рисунка. Модуль SPI использует в качестве источника тактирования импульсную последовательность PCLOCK, частота которой равна частоте ECLOCK (т.е. частоте системной шины МК). Частота PCLOCK делится делителем с программируемым коэффициентом. На выходе делителя формируется сигнал, частота которого определяет скорость обмена данными по SPI, если контроллер работает в ведущем режиме. Коэффициент деления назначается битами SPR2…SPR0 регистра скорости передачи SP0BR.



Рис. 4.71. Аппаратные средства контроллера синхронного обмена SPI




Если два устройства связаны по SPI, то 8-разрядный регистр данных ведущего устройства и 8-разрядный регистр данных ведомого устройства образуют вместе 16-разрядный кольцевой сдвиговый регистр (рис. 4.70). В процессе передачи код 16-разрядного регистра сдвигается под действием импульсов синхронизации SCK. В ответ на каждый импульс SCK один двоичный разряд выдвигается из регистра данных ведущего на линию MOSI и запоминается в первом слева разряде регистра ведомого (см. рис. 4.70). В то же время крайний правый бит регистра данных ведомого выдвигается на линию MISO и запоминается в регистре ведущего. В результате, по прошествии восьми импульсов синхронизации SCK код 8-разрядного регистра данных ведущего переместится в регистр данных ведомого, а 8-разрядный код ведомого — в регистр данных ведущего. Таким образом, в процессе обмена ведущее и ведомое устройства поменяются содержимым их регистров данных.

Для того, чтобы начать обмен данными по SPI, необходимо выполнить некоторую последовательность действий по инициализации контроллера SPI. Во-первых, порт S должен быть конфигурирован соответствующим образом с использованием регистра направления передачи порта DDRS. Далее следует установить коэффициент деления частоты PCLOCK. Возможные значения коэффициента деления: 2, 4, 8, 16, 32, 64, 128 и 256. Желаемый коэффициент деления устанавливается разрядами SPR2…SPR0 регистра скорости передачи SP0BR. Для сигнала синхронизации SCK следует определить не только частоту, но и форму сигнала. По форме сигнала различают четыре типа сигналов синхронизации SCK, которые отличаются полярностью и сдвигом фазы по отношению к сигналам на линиях MOSI и MISO. Выбор формы сигнала SCK определяется комбинацией битов CPOL:CPHA в регистре управления SP0CR1.



После того, как все биты регистров управления SP0CR1 и SP0CR2 установлены в соответствии с выбранным режимом работы, следует разрешить работу контроллера SPI. Для этого предназначен бит SPE регистра SP0CR1. Разрешение работы ведущего контроллера SPI должно быть выполнено ранее ведомого.



Аппаратные средства контроллера SPI могут генерировать запросы на прерывание. Два источника запросов располагаются в регистре состояния SP0SR. Первый источник — триггер завершения обмена SPIF, второй источник — флаг нарушения режима MODF.

Оба прерывания разрешаются установкой в 1 бита SPIE в регистре управления SP0CR1.


Вопросы для самопроверки

1. Каковы различия между двумя режимами работы контроллера SPI: режимом ведущего и режимом ведомого?

Ответ: Контроллер SPI, работающий в режиме ведущего, начинает обмен и генерирует импульсы синхронизации SCK для обмена. Таким образом, ведущий контроллер управляет обменом. Ведомый контроллер SPI ожидает сигналов от ведущего, и под их управлением запоминает информацию с линии MOSI, а также генерирует информацию на линию MISO. Завершается обмен под управлением ведущего.

2. Каково назначение сигнала SCK?

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

4.19.3. Регистры контроллера SPI

 Сделать закладку на этом месте книги

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

• Регистр скорости обмена;

• Регистры управления;

• Регистр состояния;

• Регистр данных.

Далее мы рассмотрим формат и назначение битов каждого регистра модуля SPI.


Регистр скорости обмена SPxBR

Регистр скорости обмена SPxBR позволяет выбрать частоту следования импульсов синхронизации SCK, а, следовательно, и скорость обмена по синхронному последовательному интерфейсу. Формат регистра SPxBR представлен на рис. 4.72. Три бита этого регистра SPR2…SPR0 определяют коэффициент деления импульсной последовательности ECLOCK, из которой образуется сигна