6.1.1. Ввод/вывод под управлением программы

(Руководство разработчика по микроконтроллерам семейства HCS08)

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

В этом режиме наиболее часто используются два регистра управления портами: регистр данных PTxD и регистр направления передачи PTxDD. Первый используется для записи/чтения данных порта, второй — для определения, какая линия будет работать на ввод, а какая — на вывод. Три остальных регистра — регистр входного сопротивления порта PTxPE, регистр контроля нарастания напряжения на выводах порта PTxSE и регистр нагрузочной способности выводов порта PTxDS — используются реже, в основном в подпрограмме начальной установки конфигурации, которую принято называть подпрограммой инициализации.

6.1.1.1. Режим вывода

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

PTADD=1;//PTA0настроенанавывод.Всеостальныелинии—наввод

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

  1. На вывод и оставлены неподключенными. Это основное решение, которое позволяет далее использовать эти линии.
  2. На ввод и подключены к напряжению VSS или VDD (предпочтительнее к VSS);
  3. На ввод, и программно активированы внутренние подтягивающие резисторы.

При использовании демонстрационной платы Spyder08 мы просто сконфигурируем все остальные линии на вывод. Для этого напишем:

PTADD=Ox1F;//ЛиниисPTA0поPTA4настроенынавывод,PTA6иPTA7в
//данноймоделиМКнесуществуют!

Также можно использовать символьное описание, приведенное в файле hcs08.h:

PTADD=BIT_4|BIT_3|BIT_2|BIT_1|BIT_0;

Если МК располагается в 8-выводном корпусе, то линии PTA6 и PTA7 для этого МК не существуют. Если МК располагаются в 8- и 16-выводных корпусах, то линия PTA4 выполняет альтернативную функцию BKGD (для связи с BDM), а линия PTA5 — функцию внешнего сброса Reset. Для остальных моделей МК, которые располагаются в корпусах с большим числом выводов, линия PTA4 может работать только на вывод (если не выполняет функцию BKGD), а линия PTA5 — только на ввод (если не выполняет функцию Reset).

Если линии порта сконфигурированы на вывод, то их состоянием можно управлять с помощью регистра данных порта PTxD (x — латинская буква, вместо которой может быть подставлена любая буква, так что образуется полное имя порта, например PTAD, PTBD).

Так, для включения светодиода LD1 на демонстрационной плате Spyder08, необходимо установить нулевой бит порта PTAD в 1. Это можно сделать, например, операцией маскирования с помощью логических выражений:

Бит:76543210
Маска:00000001
hex:01

PTAD=PTAD|0x01;//Установитьбит0портаPTAв1(установитьPTA0)

Или:

PTAD=PTAD|BIT_0;//Установитьбит0портаPTA(установитьPTA0)

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

PTAD|=BIT_0;//ВместоPTAD=PTAD|BIT_0

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

Бит:76543210
Состояние порта:00110000
Маска:00000001
Результат:00110001← Только бит 0 изменился!

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

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

PTAD_PTAD0=1;//УстановитьбитPTAD0

Для обнуления состояния бита следует использовать другую логическую операцию — операцию И:

PTAD=PTAD&0xFE;

Бит:76543210
Маска:11111110
hex:FE

Или:

PTAD=PTAD&~0x01;//Записьсиспользованиемтойжемаски,чтоидляустановки
//бита0
//Предварительномаскаинвертируется

Или:

PTAD=PTAD|~BIT_0;

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

Ниже показан результат выполнения данной операции. Предположим, что значение порта PTAD до операции было равно 0x0F, или 00001111 в двоичной системе счисления:

Бит:76543210
Состояние порта:00001111
Маска:11111110
Результат:00001110← Только бит 0 изменился!

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

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

PTAD_PTADO=0;//Сброситьбит0портаPTA

Еще один пример программы «мигающий светодиод» для демонстрационной платы Spyder08:

Пример 6.1. Мигающий светодиод

//ДемонстрационнаяплатаSpyder08,мигающийсветодиод
#include/*Файл,позволяющийвключитьпрерывания*/
#include"derivative.h"/*Файлсобъявлениямирегистровпериферии*/
#include"hcs08.h"//Этонашфайлсобъявлениями!
voidmain(void)
{
unsignedinttemp;
SOPT1=bBKGDPE;/*ИнициализациярегистраSOPT1,разрешениелинииBKGDдля
отладки*/
PTADD=BIT_4|BIT_3|BIT_2|BIT_1|BIT_0;
//Настройкалинийс0-йпо4-юнавывод
while(1)
{
PTAD|=BIT_0;//Светодиодвключить
for(temp=10000;temp;temp--);//Программнаязадержка
PTAD&=~BIT_0;//Светодиодвыключить
for(temp=10000;temp;temp--);//Программнаязадержка
}
}

Для изменения состояний портов С и Е в МК серии QE можно использовать регистры SET/RESET/TOGGLE. Однако надо иметь в виду, что для изменения состояния только одной линии порта использование этих регистров не эффективно, поскольку регистры данных порта PTxD находятся на странице прямого доступа памяти, и изменение их состояния производится с помощью команд битового процессора BSET и BCLR.

Тем не менее, для изменения состояния сразу нескольких линий портов предпочтительнее использовать регистры SET/RESET/TOGGLE.

Предположим, что нам необходимо установить состояние линий PTC7 и PTC0 в 1. Используя стандартный способ изменения данных, мы бы написали:

PTCD|=0x81;//Установитьбит7ибит0портаPTC
//(остальныелиниинеизменять)

При использовании специальных обозначений из файла hcs08.h:

PTCD|=BIT_7|BIT_0;//Установитьбит7ибит0портаPTC
//(остальныелиниинеизменять)

Для МК серии QE та же операция может быть выполнена с помощью регистра PTCSET:

PTCSET=BIT_7|BIT_0;//Установитьбит7ибит0портаPTC
//(остальныелиниинеизменять)

Хотя приведенные записи программного кода очень похожи, следует понимать, что в первом случае будет выполнена последовательность команд ассемблера, реализующая сначала чтение регистра данных порта в аккумулятор, затем побитовое логическое ИЛИ с маской, затем запись нового значения в регистр PTCD. Вторая запись будет преобразована в иную последовательность команд ассемблера, и установка соответствующих битов будет выполнена на аппаратном уровне, Все операции с использованием регистров типа SET, CLEAR и TOGGLE выполняются аппаратными средствами, логические операции программа не выполняет!

Рассмотрим еще один похожий пример, но с использованием регистра типа TOGGLE. Для изменения состояния линии на противоположное принято использовать операцию побитового Исключающего ИЛИ. В следующем примере показано, как инвертировать состояние линий PTC0 и PTC7. Обратите внимание, что мы используем ту же маску, что и в операции логического ИЛИ:

PTCD=PTCD^0x81;//Установитьбиты0и7портаPTC,
//состояниявсехостальныхбитовнеизменяются

После компиляции этой строки генерируется следующий ассемблерный код:

LDAPTCD/*ЗагрузитьсодержимоепортаPTCDваккумуляторА
(3периодаBUSCLK)*/
EOR#0x81/*Установитьзначение7-гои0-гобитоваккумулятораА
(2периодаBUSCLK)*/
STAPTCD/*ЗаписатьсодержимоеаккумулятораАнапортPTCD
(3периодаBUSCLK)*/

Это стандартная операция чтения/модификации/записи: сначала данные записываются в аккумулятор АСС, затем изменяются, а результат записывается в регистр-источник. Общее время выполнения операции составляет 8 периодов частоты BUSCLK или 400нс при частоте 20МГц. Если использовать регистр TOGGLE, та же операция будет выполняться следующей образом:

PTCTOG=0x81;

Cгенерированный код ассемблера в данном случае:

LDA#0x81//ЗагрузитьваккумулятораАмаскуоперации(2периодаBUSCLK)
STAPTCTOG//ЗаписатьаккумуляторАврегистрPTCTOG(4периодаBUSCLK)

Видно, что время выполнения операции уменьшилось с 8 тактов до 6 и стало равным 300нс при частоте шины 20МГц. Регистр PTCTOG находится в странице памяти прямого доступа, чтобы время обращения к нему было минимальным.

6.1.1.2. Режим ввода

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

Если МК по напряжению питания принадлежит к группе VDD=3.0...5.0В, то логической 1 соответствует напряжение, превышающее 0.7×VDD, а логическому 0 — напряжение не свыше 0.35×VDD. Для МК с напряжением питания 1.8...3.3В логической 1 соответствует напряжение, превышающее 0.7×VDD, если напряжение питания VDD находится в диапазоне от 2.3 до 3.3В, и 0.85×VDD, если напряжение питания VDD составляет 1.8...2.3В. Напряжение логического 0 для этой группы МК не должно превышать 0.35×VDD, если VDD=2.3...3.3В, и 0.3×VDD, если VDD=1.8...2.3В.

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

pin_state=PTAD|0x04;

Или:

pin_state=PTAD|BIT_2;

Или:

pin_state=PTAD_PTAD2;

Типичная схема подключения переключателя или кнопки к порту МК показана на Рис.6.1,а. Пока ключ разомкнут, потенциал логической 1 обеспечивает резистор R1. Если ключ замкнут, то напряжение на выводе МК становится равным потенциалу общего вывода, что соответствует логическому 0 при чтении порта. Во время переключения ключа на линии будет генерироваться дребезг. Конденсатор C1 уменьшает шумы дребезга при переключении.

Внешний резистор R1 в МК HCS08 можно заменить внутренним подтягивающим резистором. Также можно применить программную защиту от дребезга, что позволяет не подключать внешний конденсатор C1. Схемное решение упрощается (Рис.6.1,б).

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

В соответствии с техническим описанием МК семейства HCS08 внутренние подтягивающие резисторы обладают сопротивлением от 17.5кОм до 52.5кОм!

Для подключения внутреннего подтягивающего резистора следует записать 1 в соответствующий бит регистра PTxPE. Например, для подключения подтягивающего резистора линии PTA2, необходимо записать:

PTAPE=0x04;//ПодключениеподтягивающегорезистораPTA2

Или:

PTAPE=BIT_2;

Применим полученные знания о линиях ввода/вывода, изменив программу мигающего диода. Превратим его в управляемый мигающий диод. На Рис.6.2 показана упрощенная схема подключения периферийных компонентов к МК, для которой справедлив программный код Примера 6.2.

Рис.6.2. Упрощенная схема для демонстрационной платы DEMO9S08QG8.

Пример 6.2. Управляемый мигающий светодиод для DEMO9S08QG8

//ДемонстрационнаяплатаDEMO9S08QG8,управляемыймигающийсветодиод
#include/*forEnableInterruptsmacro*/
#include"derivative.h"/*includeperipheraldeclarations*/
//ДвестрокивышегенерируютсясредойCodeWarriorавтоматически,перевод
//комментариевкнимсмотритевПримере6.1
#include"hcs08.h"//Этонашфайлсобъявлениями!
voidmain(void)
{
unsignedinttemp;
unsignedcharblinking=0;//Переменнаядляуправлениярежимомсветодиода
SOPT1=bBKGDPE;//НастройкарегистраSOPT1
PTADD=0;//НастройкавсехлинийпортаPTAнаввод
PTBDD=0xFE;//PTB0наввод,аостальныелиниипортаPTB—навывод
PTBD=0xC0;//Выключитьсветодиодыизаписатьнулевыезначенияна
//выводPTB
PTAPE=BIT_2;//ВключениеподтягивающегорезистораPTA2
while(1)
{
if(blinking)
{
PTBD_PTBD6=0;//Включитьсветодиод
for(temp=3000;temp;temp--);//Программнаязадержка
PTBD_PTBD6=1;//Выключитьсветодиод
for(temp=30000;temp;temp--);//Программнаязадержка
}
if(!PTAD_PTAD2)//ЕсликнопкаSWI1нажата,
{
//подождать,покаонабудетотключена
while(!PTAD_PTAD2)for(temp=100;temp;temp--);
blinking=!blinking;//Изменитьсостояниепеременнойрежимасветодиода
}
}
}

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

Электронные компоненты Freescale >>>
Подробнее о компании Freescale >>>