2. Порты ввода/вывода 2.1. Описание работы с портами в dsPIC 2.2. Пример работы цифровых портов ввода/вывода (пример в PROTEUS)Все выводы микроконтроллера dsPIC (кроме выводов питания VDD, VSS, сброса MCLR и вывода тактирования OSC1/CLKIN) разделены между периферийными модулями и параллельными портами ввода-вывода {I/O}. Для того, чтобы один вывод мог одновременно использоваться несколькими модулями – предусмотрен мультиплексор. Мультиплексоры выбирают, кто подключён к выводу, или это периферия или это связанный порт входа выхода. Логика порта предотвращает образование, так называемой, петли. Т.е. когда выходы цифрового порта могут управлять входом периферийного модуля, с которой данный вход мультиплексирован. На рисунке 1 показано, каким образом разделены порты между цифровыми портами и периферией.Рисунок 1. Блок схема порта микроконтроллераКогда периферийный модуль включён и активно управляет связанным с ним выводом, то логика заблокирует работу цифрового порта. Состояние вывода входа/выхода{I/O} можно прочитать, но выходные драйверы отключат бит параллельного порта. Если периферия включена, но вывод активно не используется, то вывод может управляться цифровым портом. Для работы с портом предназначены три основных регистра:TRIS – регистр для выбора направления передачи. Если «0» то канал работает на выход, а если «1», то канал работает как вход. (Для запоминания можно считать так: «1» похожа на латинскую букву I, т.е. Input-вход, поэтому и настраивает порт как вход). Например запись TRISС=0b0000011110 говорит о том, что каналы RС9-RC5,RC0 работают как выход, а RC4-RC1 – как вход)PORT – регистр порта, вот именно с помощью этого регистра мы будем принимать данные или отправлять их. (Например запись value=PORTC, означает, что нужно данные присутствующие на выводах порта C, записать в переменную value, а запись PORTC=value означает что нужно на выводах порта C установить состояние, соответствующее переменной value). Для доступа к одному каналу в отдельности, например к третьему каналу порта C используют запись вида _RC3 (_RC3=0 сбрасываем третий бит регистра C). -Примечание: Обозначение отдельных выводов порта в компиляторе С30 и компиляторе HI-TECH отличается тем, что в С30 перед названием отдельного вывода нужно ставить знак подчёркивания. С моей точки зрения это более практично, так как сразу можно определить регистр это или бит. LAT – Защелка портов ввода/вывода. Главное назначение этого регистра отразим на примере. Предположим, мы используем полностью весь порт на выход. В регистр LAT заносим значение, которое хотим получить на выходе порта. Так как мы используем весь порт на выход, то содержимое регистра LAT полностью установится на выходе порта. Допустим, нам понадобится прочитать значение для АЦП, вывод которого совмещён с одним из выводов нашего цифрового порта. Для этого мы меняем назначение вывода, чтобы получить аналоговый сигнал. Получаем этот сигнал. И снова возвращаем работу порта в цифровой режим работы. Так как мы записали значение в регистр LAT, то оно на выходе цифрового порта восстановится. А если бы мы записывали значение в порт, используя регистр PORT, то старое бы значение на порту не установилось.Существует разные модификации dsPIC. Одним из различий является количество портов. Например в DSPIC33FJ32GP204 имеется 3 порта ввода вывода. В основном все порты идентичны и мы будем считать их функциональность одинаковой. Однако стоит обратить внимание, что некоторые порты не полные. Ведь микроконтроллер 16 разрядный и поэтому требует для каждого порта аж 16 выводов. В данном микроконтроллере только PORTB является полным, а остальные 2 порта урезанными. Причём в PORTA даже есть пропущенные выводы. Для других типов микроконтроллера могут быть реализовано больше портов и больше выводов (для большей информации смотреть даташит на нужный микроконтроллер)Примечание: напряжение на цифровом входе может быть от-0.3V до 5.6V.Вывод с открытым коллекторомКроме всего прочего, порт может настраиваться для работы, как обычный цифровой выход, так и выход с открытым коллектором. Этого можно достичь при помощи регистра управления открытым коллектором (Open-Drain Control) ODCx, связанным с каждым портом. Установка любого бита настраивает соответствующий вывод, чтобы работать в режиме выхода с открытым коллектором. Используя выход с отрытым коллектором, можно на цифровом выводе (только на цифровом) формировать напряжение больше чем напряжение питания (например, 5В), используя внешние подтягивающие резисторы. Примечание: работа с открытым коллектором не поддерживается на выводах, на которых мультиплексированы аналоговые функциональные возможности. С отрытым коллектором могут работать как цифровые порты, так и периферия.^ Настройка аналоговых портовДля управления выводами порта ADC используются регистры ADxPCFGH, ADxPCFGL и TRIS. Выводы порта, которые необходимы как аналоговые входы, должны иметь в соответствующих разрядах регистра TRIS установленные биты. Если TRIS бит сброшен (т.е. вывод настроен на выход), то преобразоваться будет напряжение логического уровня цифрового порта (т.е.VOH или VOL). Для того, чтобы вывод работал как аналоговый вход, необходимо сбросить соответствующий разряд в регистре ADxPCFGH или ADxPCFGL. ^ Внимание: После запуска микроконтроллера все выводы которые мультиплексированы с аналоговыми функциями ANx – устанавливается для работы в аналоговом режиме. И если нам необходимо, чтобы вход/вывод был именно цифровым, то за этим нужно следить. Для этого нужно при инициализации добавить, например, для микроконтроллера DSPIC33FJ32GP204 следующую команду: AD1PCFGL=0xffff; что означает, что все выводы, совмещённые с аналоговыми входами будут работать как цифровые входы выходы.Внимание: В устройствах с двумя ADC модулями, если связанный PCFG бит в любом регистре AD1PCFGH (L) и AD2PCFGH (L) сброшен, то линия работает как аналоговая. Для данного режима необходимо изучить даташит на конкретный тип dsPIC. Если выводы настроены как аналоговые входы, то при попытке прочитать регистр PORT в нём в данных битах будут логические нули. Выводы настроенные как цифровые входы не будут преобразовывать аналоговый уровень. Внимание: напряжение на аналоговом входе может находится в диапазоне от -0.3V до (VDD + 0.3 V). Т.е подавать 5В запрещено!Контроль изменения сигнала на выводах CN Функция контроля за изменением сигнала на выводах CN позволяет микроконтроллеру dsPIC33F сформировать прерывание, при изменении состояния на входе. Эта функция способна обнаружить изменение сигнала даже в режиме SLEEP, когда отключён генератор. В зависимости от исполнения микроконтроллера, есть до 24 внешних линий (CN0 - CN23), которые могут быть выбраны для формирования прерывания при изменении состояния на входе. Есть четыре регистра управления, связанные с модулем CN. Регистры CNEN1 и CNEN2 – разрешают прерывания CN. Разрешить прерывания можно для каждого CN порта отдельно устанавливая соответствующий бит CNxIE. К каждому входу CN можно программно подключить внутренний подтягивающий резистор. И уже не требуется использовать внешние резисторы (например при построении клавиатуры) на тех выводах портов, которые имеют в своём названии обозначение CN. Резисторы подключаются с помощью регистров CNPU1 и CNPU2. Если бит (CNxPUE) установлен, то к выводу CN подключается подтягивающий резистор. Для того, чтобы отдельно подтянуть какой-нибудь один вывод можно обращаться непосредственно к биту соответствующего регистра (Например, для микроконтроллера DSPIC33FJ32GP204 запись _CN4PUE=1 означает, что нужно включить подтягивающий резистор на выводе CN4 (RB0)Внимание: Если порт предполагается использовать как цифровой выход, то обязательно необходимо отключить подтягивающие резисторы на выводе CN.^ 2.2. Пример работы цифровых портов ввода/выводаТеперь рассмотрим пример программы для работы с портами. В данной главе будет описана работа только цифровых входов выходов. Работа с аналоговыми портами и использование функций выводов CN будет описана в последующих главах. Пока функциональность программы PROTEUS позволяет изучать архитектуру dsPIC, мы этим будем пользоваться. К сожалению, перечень микроконтроллеров данной архитектуры в PROTEUS очень маленький. Однако, учитывая, что у всех dsPIC ядро одинаковое, то мы можем обучаться на одном микроконтроллере, а в дальнейшем с лёгкостью перейти на другой контроллер данной архитектуры. Для примера мы поставим себе следующую задачу: Разработать программу для управления 8-ю светодиодами. Конечно, особого смысла в управлении светодиодами нет, но на их место можно поставить силовые ключи и управлять уже электромеханизмами. А это уже намного интереснее. Но для ознакомления с портами нам достаточно и светодиодов. Для задачи необходимо выполнить следующие условия: При нажатии на кнопку SB1 зажечь первую четвёрку светодиодов, а вторую погасить. При нажатии на кнопку SB2 зажечь вторую четвёрку светодиодов, а первую погасить. При нажатии на кнопку SB3 зажигать первую четвёрку, вторую гасить, через паузу погасить первую четвёрку, а вторую зажечь и так мерцать непрерывно, пока не будет нажата кнопка SB1 или SB2.Для начала разработаем схему. Она будет иметь приблизительно следующий вид (изображено в работе, после нажатия на кнопку SB2):Так как в цикле лекций это первая схема, то пару слов о ней. В PROTEUS для наших примеров мы будем использовать микроконтроллер DSPIC33FJ33GP204. Обязательно в его свойствах необходимо указать ссылку на hex файл программы управления. Установить требуемую частоту (например, 8MHz). На вывод MCLR мы подаём логическую единицу. Иначе микроконтроллер может не работать, т.е. будет считать, что его сбрасывают. Ну, в принципе, и всё что касается микроконтроллера. Остаётся только набросать нужные нам элементы, подключить их, и можно проверять работу программы. Переходим к управляющей программе#include "p33Fxxxx.h" // Устанавливаем биты настройки генератора (HS)_FOSCSEL(0x02); _FOSC(0xE2);//************* ОБЪЯВЛЕНИЯ ФУНКЦИЙ ********************************void init(void);//***************** Подпрограмма инициализации *********************void init(void) {_CN4PUE=1; // включаем подтягивающие резисторы туда,_CN1PUE=1; // куда подключены кнопки_CN22PUE=1;AD1PCFGL=0xffff; // аналоговые входы отключаем, а цифровые включаем //производим инициализацию порта ВPORTB=0; //сбрасываем регистр порта ВLATB=0; //сбрасываем защёлку порта ВTRISB=0b100010001; //устанавливаем выводы куда подключены кнопки, // как вход, остальные - выход// инициализации порта C.PORTC=0; LATC=0; TRISC=0; //устанавливаем все выводы как выходPORTC=0;} // end init//***************** ТОЧКА ВХОДА В ПРОГРАММУ ***********************void main(void){ char state; //объявляем переменную которая будет хранить текущий режим работыlong int i; // вводим переменную для создания мерцания // принимает значение от -2147483648 до 2147483647 init(); //вызываем подпрограмму инициализацииwhile(1) // запускаем бесконечный цикл. Необходимо,{ // чтобы больше не производить инициализациюif (!_RB0 && state!=1) //Если нажата кнопка SB1 и текущее состояние не равно 1, то{ PORTC=0x000F; // гасим первую четвёрку и зажигаем вторую четвёркуstate=1; // запоминаем текущее состояние программы} // if (!RB0&&state!=1)else if (!_RB4 && state!=2) //Если нажата кнопка SB2 и текущее состояние не равно 2, то{ PORTC=0x00F0; // гасим вторую четвёрку и зажигаем первуюstate=2; // запоминаем текущее состояние программы}//if (!RB4&&state!=2)else if (!_RB8 && state!=3) //Если нажата кнопка SB3 и текущее состояние не равно 3, тоstate=3; // запоминаем текущее состояние программы // реализуем мерцаниеif (state==3) //Если активен третий режим, то { if (i>0) // Если переменная i>0, тоPORTC=0x00F0; // гасим первую четвёрку и зажигаем вторуюelse // иначеPORTC=0x000F; // гасим вторую четвёрку и зажигаем первуюi+=20000; // увеличиваем число на 20000, чем меньше число, тем реже мерцание} //if (state==3)} // while(1)}Думаю данная тема не вызовет ни у кого затруднений.Мотькин Игорь Сергеевич, Республика Беларусь, г. Гомель, +375 (29) 736-67-41 motskin@tut.by