Микроконтроллеры PIC. Архитектура и программирование. Часть 9. Программирование интерфейса PMP » Программирование устройств на PIC микроконтроллерах


Логин:
Пароль:
О сайте:

Pic.Rkniga.ru - Сайт как для начинающих, так и для опытных радиолюбителей, разрабатывающих свои устройства на популярных PIC микроконтроллерах.
Здесь можно обмениваться сообщениями на форуме, а также добавлять на сайт статьи и схемы своих устройств.

Меню сайта
Главная Форум по PIC микроконтроллерам Форум Статьи по PIC микроконтроллерам Статьи Справочная информаци по PIC микроконтроллерам Справочник Литература по PIC микроконтроллерам Литература Схемотехника Схемотехника устройств на PIC микроконтроллерах Микроконтроллеры Программаторы Все по программированию PIC микроконтроллеров Программы, Софт Программы Ссылки
Опрос

На каком языке программирования вы пишите программы?


Ассемблер
Си
Бейсик
Паскаль
Другой


Последние материалы
  • Тестовая плата для отладки программ на микроконтроллере PIC18F4550
  • Кнопка On/OFF на PIC12F629.
  • Часы с синхронизацией от китайского будильника
  • ШИМ регулятор на PIC16F628A.
  • Счетчики прямого и обратного счета на PIC16F628A.
  • Таймер отключения питания для мультиметра и не только.
  • Измеритель напряжения и тока
  • Маршрутный компьютер для электровелосипеда
  • Простой двухканальный термометр на PIC16F690 и датчиках DS18B20
  • Электронная "Незабудка" для забывчивых
  • Популярные материалы
    Случайная книга
    Программирование устройств на PIC микроконтроллерах » Справочник » Микроконтроллеры PIC. Архитектура и программирование. Часть 9. Программирование интерфейса PMP
    Микроконтроллеры PIC. Архитектура и программирование. Часть 9. Программирование интерфейса PMP
    Автор публикации: alex Просмотров: 7459 Добавлен: 27-09-2012, 14:08 Комментарии: 0

    Содержание
    1. Обзор 16-битных PIC-микроконтроллеров
    2. Архитектура микроконтроллеров PIC24F
    3. Система команд и основы программирования микроконтроллеров PIC24F
       3.1 Программная модель микроконтроллеров PIC24F
       3.2 Режимы адресации и система команд
    4. Программирование портов ввода-вывода
       4.1 Аппаратно-программная архитектура портов ввода/вывода
       4.2 Программирование портов ввода/вывода
       4.3 Модуль регистрации событий
    5. Программирование прерываний
    6. Программирование таймеров
       6.1 Практическое использование 16-битных таймеров
       6.2 Работа таймеров в 32-битном режиме
    7. Интерфейс SPI микроконтроллеров PIC24F
       7.1 Аппаратно-программная реализация SPI в микроконтроллерах PIC24F
       7.2 Практическое программирование обмена данными по SPI
    8. Интерфейс I2C микроконтроллеров PIC24F
       8.1 Принципы функционирования интерфейса I2C
       8.2 Модуль интерфейса I2C микроконтроллеров PIC24F
       8.3 Практическое использование интерфейса I2C
    9.Программирование интерфейса PMP
       9.1 Режимы работы PMP
       9.2 Практические примеры программирования интерфейса PMP
    10. Последовательный интерфейс микроконтроллеров PIC24F
       10.1 Аппаратно$программная архитектура UART
       10.2 Практическое использование последовательного порта
    11. Обработка аналоговых сигналов в микроконтроллере PIC24F
       11.1 Программная модель интегрированного АЦП
       11.2 Практическое использование модуля АЦП
       11.3 Использование внешнего АЦП
    12. Генерация аналоговых и цифровых сигналов
       12.1 Модуль генерации цифровых сигналов
       12.2 Аналоговые компараторы в микроконтроллерах PIC24F

         В микроконтроллерах семейства PIC24F предусмотрен обмен данными с внешними устройствами по параллельному интерфейсу, называемому PMP (Parallel Master Interface). Этот интерфейс был специально разработан для взаимодействия с многочисленными периферийными устройствами, которые передают данные по параллельному интерфейсу (принтеры, сканеры, жидкокристаллические индикаторы, устройства памяти и др.).
         Модуль параллельного интерфейса PMP обладает следующими характеристиками:
    • обмен данными выполняется по 8-битной шине;
    • можно адресовать до 16 линий адреса;
    • можно использовать две линии выбора устройства;
    • можно использовать отдельные сигналы чтения/записи либо общий сигнал чтения/записи совместно с сигналом разрешения;
    • автоинкремент/автодекремент адреса;
    • мультиплексирование линий адреса/данных;
    • программирование задержки сигналов.
         В общем виде функциональную схему интерфейса PMP можно представить так, как показано на Рис. 9.1.
         Эта схема довольно наглядно демонстрирует возможности параллельного интерфейса PMP. Рассмотрим эти возможности более подробно. Начнем с режимов адресации. Адресацию внешних устройств можно осуществлять несколькими способами, в зависимости от конкретной реализации интерфейса. Если необходимо выполнять обмен данными с микросхемами памяти, то, как правило, нужно использовать отдельные линии адреса, данных и управления.
         Кроме линий адреса, в такой конфигурации могут быть задействованы и сигналы выбора устройства. Таким образом, адресация устройств может осуществляться либо с использованием только линий адреса, либо в комбинации с сигналами выбора устройства. Второй вариант часто применяется при ограниченных возможностях адресации, при этом линии сигналов выбора устройства используются как дополнительные адресные линии.
         Адресация устройств может осуществляться как с применением мультиплексирования, так и без него. Например, для передачи младших битов 16-битного адреса можно использовать линии данных PMD7…PMD0 (см. Рис. 9.1). При обмене данными с внешними устройствами во многих случаях можно обойтись и без использования линий адреса. Адресация устройств в этом случае может осуществляться с применением сигналов выбора микросхемы PMCS1 и PMCS2, что намного упрощает проектирование несложных систем.

    Рис. 9.1. Упрощенная функциональная схема интерфейса PMP

         Сигналы управления интерфейса PMP позволяют разрабатывать схемы управления практически для любых внешних устройств с параллельным интерфейсом. Для управления чтением/записью данных можно выбрать один из двух вариантов. В первом варианте для стробов чтения/записи можно использовать отдельные сигнальные линии – PMRD и PMWR соответственно. Такой вариант удобен для обмена данными с устройствами, имеющими отдельные линии чтения/записи.
         Второй вариант — использовать совмещенную линию чтения/записи и отдельную линию разрешения. В этом случае чтение данных может выполняться, например, при ВЫСОКОМ, а запись — при НИЗКОМ уровне сигнала на такой совмещенной линии. Соответственно, операции чтения/записи в этом случае будут осуществляться при появлении импульса на линии разрешения.
         Интерфейс PMP можно настроить для работы в одном из базовых режимов: в режиме «ведущего» или в режиме «ведомого». Фундаментальное отличие этих режимов состоит в следующем: в режиме «ведущего» микроконтроллер управляет сигналами интерфейса PMP, обеспечивая необходимую синхронизацию передачи и приема данных. При этом второе устройство работает в режиме «ведомого», обеспечивая прием и передачу данных по сигналам «ведущего».
         Устройство, выполняющее функцию «ведомого», не генерирует сигналы управления, хотя может выдавать на шину управления сигналы готовности, которые позволяют «ведущему» более эффективно выполнять функции управления.
         При обмене данными по интерфейсу PMP в любой момент времени только одно устройство может быть «ведущим», второе будет обязательно «ведомым».
         Часто применяются конфигурации, когда в процессе функционирования одно и то же устройство может становиться как «ведущим», так и «ведомым». Рассмотрим режимы работы параллельного интерфейса PMP и их настройки.

    9.1. Режимы работы PMP

         Параллельный интерфейс PMP настраивается и контролируется с помощью группы программно-доступных регистров (всего 8). Вот их назначение:
    • регистр PMCON используется для установки основных настроек интерфейса PMP;
    • регистр PMMODE используется для установок режимов работы интерфейса («ведущий», «ведомый»), а также для анализа состояния операций обмена данными (бит BUSY);
    • регистр PMADDR/PMDOUT1 выполняет, в зависимости от выбранного режима работы («ведущий»/«ведомый»), одну из двух функций. В режиме «ведущий» он работает как регистр адреса PMADDR, в который записывается адрес устройства, к которому происходит обращение. В режиме «ведомый» регистр работает как PDMOUT1 и содержит выходные данные;
    • регистр PMDOUT2 используется в режиме «ведомый» для хранения выходных данных;
    • регистр PMDIN1 используется в режимах «ведущий» и «ведомый» в качестве буфера входных данных. В режиме «ведомого» в регистре запоминаются данные, переданные «ведущим». В режиме «ведущего» регистр может хранить как входные, так и выходные данные;
    • регистр PMDIN2 используется точно так же, как и регистр PMDIN1, но работает только в режиме «ведомого» для хранения входных данных;
    • регистр PMAEN используется для управления выводами адреса и выбора устройства модуля PMP. Установка соответствующих битов подключает эти выводы к модулю PMP, а сброс битов разрешает их использование в составе портов ввода/вывода;
    • регистр PMSTAT хранит информацию о состоянии выполнения операции интерфейса, работающего в режиме «ведомого».
         Остановимся более подробно на двух основных режимах функционирования интерфейса: режиме «ведущего» и режиме «ведомого». Функционирование микроконтроллера в режиме «ведущего» схематически показано на Рис. 9.2.

    Рис. 9.2. Упрощенная схема взаимодействия «ведущего» и «ведомого»

         В режиме «ведущего» микроконтроллер формирует сигналы управления (PMCS2, PMRD или PMWR), устанавливая направление обмена, формат обмена (8 или 16 бит) и адрес «ведомого» устройства на шине адреса PMA.
         В конкретных вариантах использования интерфейса PMP комбинации сигналов могут варьироваться, например использоваться одна совмещенная линия чтения/записи вместо двух раздельных, применяться мультиплексирование линий адреса и данных и т.д.
         Для установки режима «ведущего» нужно выполнить как минимум два действия:
    • установить соответствующим образом биты 9:8 регистра режима PMMODE ( или );
    • разрешить функционирование интерфейса PMP, установив бит 15 (PMPEN) регистра управления PMCON.
         Остальные настройки интерфейса в этом режиме зависят от конкретной конфигурации: полярности активных уровней управляющих сигналов (ВЫСОКИЙ/НИЗКИЙ), мультиплексирования адресных линий и т. д. Рассмотрим, как выполняются операции записи и чтения байта «ведущим» устройством.
    Чтобы выполнить запись байта в параллельный порт PMP в режиме «ведущего», программа должна записать байт в регистр PMDIN1. Все дальнейшие операции модуль интерфейса выполнит автоматически в следующей последовательности:
         1. Модуль интерфейса PMP установит соответствующие значения на линиях адреса и линиях выбора устройства.
         2. Байт данных из регистра PMDIN1 будет выставлен на шину данных PMD7…PMD0.
         3. Сигнал стробирования PMWR устанавливается в активное состояние, стробируя запись байта. В этой фазе принимающее устройство («ведомый») может считать байт данных с линий PMD7…PMD0. Это удобно сделать по перепаду сигнала PMWR из активного состояния в неактивное, особенно если на входе данных «ведомого» установлены регистры-защелки.
    Чтение байта «ведущим» выполняется по схожей схеме, только направление передачи данных меняется на противоположное, а вместо сигнала PMWR используется PMRD. Для приема байта по интерфейсу PMP программа читает данные из регистра PMDIN1. В этом случае модуль интерфейса PMP автоматически выполнит такую последовательность операций:
         1. Модуль интерфейса PMP установит соответствующие значения на линиях адреса и линиях выбора устройства.
         2. Сигнал стробирования PMRD устанавливается в активное состояние, стробируя чтение байта с линий данных PMD7…PMD0 в регистр PMDIN1.
         Для синхронизации обмена данными между «ведущим» и «ведомым» можно проверять состояние бита BUSY (бит 15 регистра режима PMMODE), который доступен для чтения в режиме «ведущего». Для «ведомого» устройства признаком окончания цикла записи/чтения может служить бит 15 (IBF) или бит 7 (OBE) регистра состояния PMSTAT. Кроме того, можно проверить состояние флага прерывания, который устанавливается по завершении операции.
         Интерфейс PMP можно настроить и для работы в режиме «ведомого».
         Упрощенную схему взаимодействия двух микроконтроллеров, из которых один «ведущий», а другой «ведомый», можно представить схемой на Рис. 9.3.

    Рис. 9.3. Микроконтроллеры PIC24F в роли «ведущего» и «ведомого»

         В режиме «ведомого» управляющие сигналы (PMCSx, PMRD, PMWR) поступают от внешнего микроконтроллера. Кроме того, в режиме «ведомого» можно использовать только сигнал выбора устройства PMCS1.
         Для установки режима «ведомого» нужно выполнить как минимум два действия:
    • установить биты 9:8 регистра режима PMMODE в ;
    • разрешить функционирование интерфейса PMP, установив бит 15 (PMPEN) регистра управления PMCON.
         Как и в режиме «ведущего», полярности активных уровней управляющих сигналов (ВЫСОКИЙ/НИЗКИЙ), мультиплексирование адресных линий и другие настройки задаются соответствующим образом в регистрах PMCON и PMMODE.
         Для записи байта данных в «ведомое» устройство необходимо, чтобы сигнал выбора устройства PMCS1 и сигнал записи PMWR находились в активном состоянии. В этом случае данные, находящиеся на линиях PMD7…PMD0 «ведомого», будут сохранены в младших восьми битах регистра PMDIN1. Об успешном окончании операции записи могут свидетельствовать установленные биты PMPIF (флаг прерывания) и IBF.
         Для чтения байта данных из «ведомого» устройства необходимо, чтобы сигнал выбора устройства PMCS1 и сигнал чтения PMRD находились в активном состоянии. В этом случае младшие 8 бит регистра PMDOUT1 будут установлены на линиях PMD7…PMD0. Об успешном завершении чтения байта может свидетельствовать установленный флаг OBE регистра состояния PMSTAT.
         Далее мы рассмотрим несколько практических примеров программирования параллельного интерфейса в различных режимах работы.

    9.2. Практические примеры программирования интерфейса PMP

         В этом разделе мы рассмотрим некоторые примеры программирования обмена данными с использованием интерфейса PMP. Интерфейс можно настроить для работы в различных конфигурациях систем обмена данными. В последующих примерах мы рассмотрим некоторые из них.
         Первый проект, который мы разработаем, продемонстрирует работу интерфейса PMP микроконтроллера PIC24F в режиме «ведомого». В этом режиме сигналы синхронизации формируются другим внешним устройством. Наш пример является в достаточной степени искусственным, поскольку сигналы синхронизации будут генерироваться самим микроконтроллером на отдельных линиях цифровых портов ввода/вывода.
         В стандартном варианте модуль интерфейса конфигурируется как параллельный интерфейс обмена данными с соответствующими установками портов.
         При этом бит PMPEN регистра управления PMCON должен быть установлен в 1, а биты 9 и 8 регистра режима PMMODE должны быть сброшены. В этом режиме внешнее устройство, например микроконтроллер или микропроцессор, сможет выполнять асинхронную запись/чтение данных на шине PMD7:PMD0 с использованием сигналов синхронизации PMRD (чтение), PMWR (запись) и PMCSx (выбор устройства).
         Для демонстрации возможностей интерфейса PMP микроконтроллеров PIC24F разработаем несколько аппаратно-программных проектов. В первом проекте будет показан вывод строки данных с микроконтроллера PIC24FJ128GA010 через интерфейс PMP на жидкокристаллический дисплей (LCD). Схема аппаратной части проекта представлена на Рис. 9.4.
         По этой схеме линии данных микроконтроллера PMD0…PMD7 подсоединяются к соответствующим линиям дисплея. Управляющие сигналы на жидкокристаллический дисплей подаются с выводов RA1:RA0 порта А, а сигналы синхронизации интерфейса PMP — с выводов RB0:RB1 порта B микроконтроллера. В данной схеме данные «читаются» дисплеем, поэтому интерфейс PMP работает в режиме «ведомого» с чтением данных. Вывод RB0 управляет сигналом PMCS1, а вывод RB1 — сигналом PMRD. Тактовая частота микроконтроллера выбрана равной 8 МГц.
         Программная часть проекта разработана в среде MPLAB IDE и включает программу со следующим исходным текстом:

    Рис. 9.4. Аппаратная часть проекта

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define EN _RA1
    #define RS _RA0
    #define PMCS1 _RB0
    #define PMRD _RB1
    char status;
    void Delay(void)
    {
       _T1IF = 0x0;
       TMR1 = 0;
       PR1 = 0xffff;
       T1CON = 0x8000;
       while (_T1IF == 0);
       T1CON = 0x0;
    }
    void DataSet(char c1)
    {
       PMDOUT1 = c1;
       PMCS1 = 1;
       PMRD = 1;
       PMRD = 0;
       PMCS1 = 0;
    }
    void ClearLCD(void)
    {
       EN = 1;
       RS = 0;
       DataSet(0x1);
       EN = 0;
       Delay();
    }
    void InitLCD(void)
    {
       EN = 1;
       RS = 0;
       DataSet(0x38);
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DataSet(0x0E);
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DataSet(0x6);
       EN = 0;
       Delay();
    }
    void WriteLCD(char c1)
    {
       EN = 1;
       RS = 1;
       DataSet(c1);
       EN = 0;
       Delay();
    }
    void main()
    {
       char *str = "Test of PMP interfacing";
       TRISA = 0x0;
       AD1PCFG = 0xffff;
       TRISB = 0x0;
       PMCONbits.PMPEN = 0x1;
       PMMODE = 0x0;
       _PMPIF = 0;
       Delay();
       InitLCD();
       ClearLCD();
       while (*str != 0)
       {
         WriteLCD(*str++);
         while (_PMPIF == 0);
       }
       while (1);
    }

         Анализ программы начнем с констант и переменных, определенных в программе. Следующие директивы:

    #define EN _RA1
    #define RS _RA0

         обозначают, какие сигнальные линии жидкокристаллического дисплея каким портам присвоены. В данном случае линия разрешения работы EN будет управляться битом 1 порта А, а линия команд RS будет управляться битом 0 этого же порта. Замечу, что в данной схеме линия чтения/записи LCD (RW, см. Рис. 9.4) подключена к общему проводу, т. е. выполняются только команды записи в дисплей.
         Константы PMCS1 и PMRD обозначают выводы порта В, с которых сигналы управления подаются на управляющие входы PMCS1 и PMRD интерфейса PMP:

    #define PMCS1 _RB0
    #define PMRD _RB1

         Функция DataSet выполняет чтение байта с линий PMD7:PMD0 в соответствии с временной диаграммой, показанной на Рис. 9.5.

    Рис. 9.5. Временная диаграмма чтения данных с интерфейса PMP

    Легко проверить, что операторы
    PMDOUT1 = c1;
    PMCS1 = 1;
    PMRD = 1;
    PMRD = 0;
    PMCS1 = 0;

         этой функции в точности эмулируют временную диаграмму, показанную на этом рисунке. Биты данных на линиях PMD7:PMD0 определяются содержимым регистра PMDOUT1, в который они загружаются из переменной c1.
         Признаком успешного завершения операции является установка флага прерывания PMPIF по завершении операции чтения.
         Акцентирую внимание читателей на том, что данные читаются с линий PMD внешним устройством, в данном случае жидкокристаллическим дисплеем, при подаче внешних сигналов синхронизации PMCS1 и PMRD. В этом примере мы эмулируем эти сигналы самим микроконтроллером посредством соответствующих битов регистра PORTB. Обратите внимание на то, что сигнал чтения PMRD устанавливается в активное состояние с некоторой задержкой по отношению к сигналу выбора кристалла PMCS1 и становится неактивным перед снятием сигнала PMCS1. Сигнал записи PMWR на этой диаграмме во время цикла чтения должен находиться в неактивном состоянии (НИЗКИЙ уровень).
         Точно такая же временная диаграмма характерна и для записи данных по интерфейсу PMP, только в этом случае активным будет сигнал записи PMWR, а PMRD должен удерживаться в состоянии НИЗКОГО уровня.
         Кратко остановимся на функциях, выполняющих операции с жидкокристаллическим дисплеем. Функция ClearLCD выполняет очистку дисплея, InitLCD инициализирует устройство, а с помощью функции WriteLCD осуществляется вывод символа данных на жидкокристаллический дисплей. Я не буду подробно останавливаться на принципах программирования жидкокристаллических индикаторов, обширную информацию по этой теме можно обнаружить во многих Интернет-источниках. Замечу только, что при любых операциях с LCD всегда следует проверять бит состояния, который выставляется в разряде D7 индикатора.
         До тех пор пока он равен 1, никаких последующих операций с устройством выполнять нельзя. В нашем примере (как и во многих реальных устройствах) мы не проверяем бит D7, а формируем определенную задержку, достаточную для того, чтобы текущая операция завершилась. Эта задержка реализуется функцией Delay посредством 16-битного таймера Timer 1.
         Преимущество такого подхода заключается в следующем: если по какой-либо причине жидкокристаллический индикатор окажется неисправным, то бит D7 может никогда не установиться в 1, что приведет к «вечному» циклу и зависанию программы (если, конечно, не включен сторожевой таймер WDT, но в этом случае произойдет аварийный рестарт программы, что тоже плохо).
         В любом случае время задержки определяется параметрами конкретного LCD, поэтому всегда полезно предварительно изучить документацию на устройство.
    Операторы

    TRISA = 0x0;
    AD1PCFG = 0xffff;
    TRISB = 0x0;

         основной программы конфигурируют порты А и В как выходные. Поскольку порт В по умолчанию используется модулем АЦП, то эту функцию следует отключить, установив в 1 все биты регистра AD1PCFG.
         Для инициализации интерфейса PMP в режиме «ведомого» следует установить бит разрешения PMPEN в регистре PMCON и сбросить биты 9:8 регистра режима PMMODE. Если не требуется каких-либо специфичных настроек, можно просто сбросить все биты этого регистра. Эти действия выполняются с помощью следующих операторов:

    PMCONbits.PMPEN = 0x1;
    PMMODE = 0x0;

         О завершении операции чтения данных из микроконтроллера можно судить по установленному биту прерывания _PMPIF. В начале программы он сбрасывается оператором
    _PMPIF = 0;

         Чтение строки str для вывода на дисплей осуществляется в цикле while

    (*str != 0) основной программы:
    while (*str != 0)
    {
       WriteLCD(*str++);
       while (_PMPIF == 0);
    }

         Очередной символ читается из микроконтроллера и выводится на дисплей функцией WriteLCD, при этом выполняется автоинкремент указателя, который продвигается к следующему байту строки. Далее ожидается установка флага прерывания _PMPIF, после чего выполняется следующая итерация, и так до тех пор, пока не будет обнаружен нулевой символ.
         Следующий пример, который мы рассмотрим, демонстрирует работу микроконтроллера в режиме «ведущего» интерфейса PMP. Аппаратная часть проекта показана на Рис. 9.6.
         В этой схеме байт данных микроконтроллера PIC24FJ128GA010 через выводы интерфейса PMP PMD7:PMD0 выводится в регистр DD1 74HC373, к выходам которого подключены светодиоды. Микроконтроллер работает в режиме «ведущего», формируя все необходимые сигналы интерфейса. В данном случае выбрана такая конфигурация шины, при которой для синхронизации передачи данных используются сигналы PMCS2 (выбор кристалла 2) и PMWR (запись).

    Рис. 9.6. Аппаратная часть проекта

         Оба сигнала через схему совпадения на микросхеме DD2 стробируют запись данных на входных линиях D0:D7 регистра-защелки DD1.
         Программная часть проекта разработана в среде MPLAB IDE и включает в себя файл с исходным текстом, который представлен далее.

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    void main()
    {
       PMCON = 0x8392;
       PMMODE = 0x200;
       _PMPIF = 0;
       PMDIN1 = 0x5;
       while (1)
       {
       }
    }

         Программа очень проста и содержит небольшое количество операторов.
         Вывод байта (0x5) в параллельный интерфейс осуществляется путем записи его значения в регистр PMDIN1; далее модуль интерфейса PMP генерирует все необходимые для операции записи сигналы синхронизации. Для настройки интерфейса PMP в режиме «ведущего» программа должна установить соответствующие биты в регистре управления PMCON и в регистре режима PMMODE.
         Признаком окончания цикла записи данных является установка флага прерывания PMPIF. В этой программе мы не проверяем его состояние, но при выводе последовательности байтов во внешнее устройство следует всегда контролировать его значение.
         В следующем демонстрационном проекте мы прочитаем данные с внешнего устройства и выведем их на жидкокристаллический индикатор. Интерфейс PMP будет функционировать в режиме «ведущего». Аппаратная часть проекта показана на Рис. 9.7.
         Эта схема работает следующим образом: при нажатии кнопки вызывается прерывание INT3 микроконтроллера PIC24FJ128GA010, функция-обработчик которого считывает посредством линий PMD7:PMD0 интерфейса PMP байт данных со входов буферных микросхем DD1 и DD2. Затем этот байт в символьном виде выводится на жидкокристаллический индикатор. Линии данных D7:D0 индикатора подключены к порту А, а управляющие сигналы на LCD подаются с выводов 0 (линия E) и 2 (линия RS) порта В. Чтение данных с буферов DD1 и DD2 осуществляется с помощью сигналов PMCS2 и PMRD интерфейса PMP. Как и в предыдущих проектах, тактовая частота микроконтроллера равна 8 МГц.

    Рис. 9.7. Аппаратная часть проекта

    Исходный текст программы содержит следующие строки:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define INT3Tris TRISAbits.TRISA14
    #define EN _RB0
    #define RS _RB2
    #define DATA PORTA
    char c1;
    void Delay(void)
    {
       _T1IF = 0x0;
       TMR1 = 0;
       PR1 = 0xffff;
       T1CON = 0x8000;
       while (_T1IF == 0);
       T1CON = 0x0;
    }
    void ClearLCD(void)
    {
       EN = 1;
       RS = 0;
       DATA = 0x1;
       EN = 0;
       Delay();
    }
    void InitLCD(void)
    {
       EN = 1;
       RS = 0;
       DATA = 0x38;
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DATA = 0x0E;
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DATA = 0x6;
       EN = 0;
       Delay();
    }
    void WriteLCD(char c1)
    {
       EN = 1;
       RS = 1;
       DATA = c1;
       EN = 0;
       Delay();
    }
    void __attribute__((interrupt)) _INT3Interrupt(void)
    {
       _INT3IF = 0;
       InitLCD();
       ClearLCD();
       c1 = PMDIN1;
       while (_PMPIF == 0);
       WriteLCD(c1);
    }
    void main()
    {
       TRISA = 0x0;
       AD1PCFG = 0xffff;
       TRISB = 0x0;
       INT3Tris = 0x1;
       _INT3IF = 0;
       _INT3IE = 1;
       _PMPIF = 0;
       PMCON = 0x8350;
       PMMODE = 0x20F;
       InitLCD();
       ClearLCD();
       while (1)
       {
       }
    }

         Прежде всего, для функционирования интерфейса PMP в режиме «ведущего» нужно установить соответствующим образом биты регистра управления PMCON и регистра режима PMMODE. В режиме чтения формируется небольшая задержка (биты 0:3 регистра PMMODE).
         Для функционирования требуемых выводов портов A и B в качестве выходов должны быть сброшены соответствующие биты в регистрах TRIS. Для использования прерывания INT3 необходимо разрешить его с помощью операторов

    _INT3IF = 0;
    _INT3IE = 1;

         Собственно чтение байта данных с линий PMD7:PMD0 и вывод символьного представления на LCD выполняется в функции-обработчике прерывания _INT3Interrupt. Для выполнения цикла чтения с генерацией соответствующих сигналов шинного интерфейса необходимо прочитать регистр PMDIN1:
    c1 = PMDIN1;

         В результате байт данных сохраняется в переменной c1 и затем выводится на жидкокристаллический индикатор с помощью функции WriteLCD. Как обычно, функция-обработчик прерывания должна сбрасывать флаг прерывания. Для управления LCD и выводом на него данных программа использует функции InitLCD, ClearLCD и WriteLCD.
         Настройка интерфейса PMP в каждом конкретном случае зависит от внешнего устройства, с которым происходит обмен данными. Особенно это касается полярности активных уровней сигналов, которые используются для синхронизации обмена данными.
         До сих пор мы рассматривали проекты, в которых в качестве активного устройства выступала система с микроконтроллером, а устройство, в которое данные записывались или с которого читались, было реализовано в форме аппаратного модуля (регистр или буфер). В большинстве систем процесс обмена данными по параллельному интерфейсу осуществляется между двумя и более «интеллектуальными» устройствами, в качестве которых используются микроконтроллеры, микропроцессоры или цифровые процессоры сигналов.
         Следующие проекты, которые мы рассмотрим, демонстрируют подобное взаимодействие. Использование параллельного интерфейса PMP существенно упрощает разработку таких систем, поскольку разработчик не теряет времени на программирование отдельных сигналов шины.
         В первом проекте обмен данными будет осуществляться между микроконтроллерами PIC24FJ128GA010. Одно из устройств работает в режиме «ведущего» и считывает байты данных по интерфейсу PMP из другого, работающего в режиме «ведомого». Аппаратная часть проекта представлена на Рис. 9.8.

    Рис. 9.8. Аппаратная часть проекта

         «Ведущий» инициирует чтение байта с «ведомого» при возникновении прерывания INT3 (нажатие кнопки). Считанный байт данных в символьном виде выводится на жидкокристаллический индикатор. Линии данных PMD7:PMD0 и линии управляющих сигналов PMCS1 (выбор устройства) и PMRD (чтение) обоих микроконтроллеров соединены между собой.
         Программная часть проекта разработана в среде MPLAB IDE с помощью мастера проектов и включает две отдельные программы для «ведущего» и «ведомого» устройств. Исходный текст программы для «ведущего» имеет следующий вид:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define EN _RB0
    #define RS _RB2
    #define DATA PORTA
    char c1;
    int cnt = 0;
    void Delay(void)
    {
       _T1IF = 0x0;
       TMR1 = 0;
       PR1 = 0xffff;
       T1CON = 0x8000;
       while (_T1IF == 0);
       T1CON = 0x0;
    }
    void ClearLCD(void)
    {
       EN = 1;
       RS = 0;
       DATA = 0x1;
       EN = 0;
       Delay();
    }
    void InitLCD(void)
    {
       EN = 1;
       RS = 0;
       DATA = 0x38;
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DATA = 0x0E;
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DATA = 0x6;
       EN = 0;
       Delay();
    }
    void WriteLCD(char c1)
    {
       EN = 1;
       RS = 1;
       DATA = c1;
       EN = 0;
       Delay();
    }
    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       _INT3IF = 0;
       c1 = PMDIN1;
       while (_PMPIF == 0);
       if (cnt == 15)
       {
         InitLCD();
         ClearLCD();
         cnt = 0;
       }
       WriteLCD(c1);
       cnt++;
    }
    void main()
    {
       TRISA = 0x0;
       AD1PCFG = 0xffff;
       TRISB = 0x0;
       TRISAbits.TRISA14 = 0x1;
       _INT3IF = 0;
       _INT3IE = 1;
       _PMPIF = 0;
       PMCON = 0x8340;
       PMMODE = 0x20F;
       InitLCD();
       ClearLCD();
       while (1)
       {
       }
    }

         Для работы микроконтроллера в режиме «ведущего» и установки параметров управляющих сигналов прежде всего настраиваются требуемые биты регистра управления PMCON и регистра режима PMMODE. Это выполняется в основной программе операторами

    PMCON = 0x8340;
    PMMODE = 0x20F;

         Здесь биты 9:8 регистра PMMODE задают режим «ведущего», а младший байт определяет полярности сигналов управления PMCS1 и PMRD. Кроме того, в регистре режима устанавливается определенная задержка для четкой синхронизации чтения данных на шине (младший полубайт). Выводы портов А и В с помощью регистров TRIS настраиваются в соответствии с направлением сигналов на соответствующих линиях управления/данных жидкокристаллического индикатора и линии прерывания INT3.
         Чтение байта данных, полученного от «ведомого», осуществляется в функции-обработчике прерывания INT3, инициализация которого производится с помощью операторов

    _INT3IF = 0;
    _INT3IE = 1;

         Каждый следующий байт читается только в том случае, если принят предыдущий. С помощью счетчика cnt курсор дисплея возвращается в исходную позицию после вывода 15-го символа. Функции для работы с LCD мы уже рассматривали в предыдущих примерах, поэтому останавливаться подробно на них я не буду.
         «Ведомый» микроконтроллер использует те же линии данных и управления, что и «ведущий», но настраивается по-другому. Исходный текст программы для «ведомого» устройства показан далее.

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    void main()
    {
       char c1 = '0';
       _PMPIF = 0;
       PMCON = 0x8380;
       PMMODE = 0x0;
       while (1)
       {
         PMDOUT1 = c1;
         while (PMSTATbits.OBE != 1);
         c1 = c1 + 1;
       }
    }

         Программный код для «ведомого» микроконтроллера состоит всего из нескольких строк. Первым выводимым на шину символом будет 0, поэтому переменная c1 инициируется именно этим значением. При последовательном чтении данных двоичный код выводимого символа будет увеличиваться на 1.
         Регистр управления PMCON настраивается соответствующим образом с учетом полярности сигналов «ведущего». В регистре режима PMMODE биты 9:8 должны быть сброшены в 0 (режим «ведомого»).
         Собственно чтение байта с шины данных интерфейса PMP осуществляется в цикле while(1). Байт данных запоминается в регистре PMDOUT1:
    PMDOUT1 = c1;

         При запросе на чтение данных «ведущего» микроконтроллера байт данных из регистра PMDOUT1 выставляется на линии данных PMD7:PMD0, откуда он считывается «ведущим». Признаком окончания передачи байта данных «ведомым» является установленный бит OBE регистра состояния. При равенстве этого бита единице байт считается переданным. Проверка бита OBE выполняется оператором
    while (PMSTATbits.OBE != 1);

         По окончании передачи очередного байта значение переменной инкрементируется, и программа ожидает следующего запроса на чтение от «ведущего».
         Как видно из этого проекта, взаимодействие двух микроконтроллеров PIC24 при обмене данными осуществляется минимальным количеством команд, поскольку внутренние аппаратные средства обоих устройств полностью обеспечивают генерацию сигналов интерфейса.
         В том случае, если в качестве одного из устройств обмена данными («ведущего» или «ведомого») выступает система на базе микроконтроллера другого типа, то реализация такого интерфейса в каждом конкретном случае будет полностью зависеть от аппаратно-программной конфигурации используемого микроконтроллера или микропроцессора.
         Наш следующий проект демонстрирует, каким образом можно осуществить взаимодействие по параллельному интерфейсу PMP между микроконтроллерами различных типов. В этом проекте в качестве «ведущего» будет выступать микроконтроллер семейства PIC24F, а в качестве «ведомого» — микроконтроллер, совместимый с 8052. В данном случае термин «ведомый» весьма условный, поскольку микроконтроллер 8052 не привязан к настройкам интерфейса PMP, имеющегося в PIC24. Данные с микроконтроллера 8052 будут считываться в микроконтроллер PIC24. Аппаратная часть проекта показана на Рис. 9.9.

    Рис. 9.9. Аппаратная часть проекта

         Для читателей, не знакомых с архитектурой систем на базе 8052, поясню некоторые детали работы схемы. Думаю, трудностей здесь не возникнет, поскольку 8052 имеет простую аппаратно-программную архитектуру, которую несложно понять. Для передачи данных в микроконтроллере 8052 используется порт P1, линии 7:0 которого соединены с соответствующими линиями интерфейса PMD7:PMD0 микроконтроллера PIC24. Сигналы PMCS2 и PMRD через элемент «И» поступают на вход прерывания INT0 микроконтроллера 8052. Это прерывание вызывается спадающим фронтом сигнала на линии INT0. Получив сигнал прерывания, микроконтроллер 8052 передает управление функции-обработчику, которая выставляет на линии порта P1 байт данных. Этот байт считывается «ведущим» и отображается на жидкокристаллическом индикаторе.
         Программное обеспечение, как и в предыдущем проекте, включает отдельные программы для «ведущего» и «ведомого» устройств. Исходный текст программы «ведущего» микроконтроллера семейства PIC24F показан далее.

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define EN _RB0
    #define RS _RB2
    #define DATA PORTA
    char c1;
    void Delay(void)
    {
       _T1IF = 0x0;
       TMR1 = 0;
       PR1 = 0xffff;
       T1CON = 0x8000;
       while (_T1IF == 0);
       T1CON = 0x0;
    }
    void ClearLCD(void)
    {
       EN = 1;
       RS = 0;
       DATA = 0x1;
       EN = 0;
       Delay();
    }
    void InitLCD(void)
    {
       EN = 1;
       RS = 0;
       DATA = 0x38;
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DATA = 0x0E;
       EN = 0;
       Delay();
       EN = 1;
       RS = 0;
       DATA = 0x6;
       EN = 0;
       Delay();
    }
    void WriteLCD(char c1)
    {
       EN = 1;
       RS = 1;
       DATA = c1;
       EN = 0;
       Delay();
    }
    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       _INT3IF = 0;
       c1 = PMDIN1;
       while (_PMPIF == 0);
       WriteLCD(c1);
    }
    void main()
    {
       TRISA = 0x0;
       AD1PCFG = 0xffff;
       TRISB = 0x0;
       TRISAbits.TRISA14 = 0x1;
       _INT3IF = 0;
       _INT3IE = 1;
       _PMPIF = 0;
       PMCON = 0x8340;
       PMMODE = 0x20F;
       InitLCD();
       ClearLCD();
       while (1)
       {
       }
    }

         Этот исходный текст во многом напоминает текст программы «ведущего» из предыдущего примера, за исключением обработчика прерывания INT3, который немного модифицирован. Большинство операторов программы уже знакомы читателям, поэтому рассматривать их мы не будем.
         Исходный текст программы для микроконтроллера 8052, выполняющего передачу данных «ведущему» PIC24, написан на ассемблере и выглядит следующим образом:

    org 0h
    jmp start
    Int0_ISR:
    org 3h
    mov P1, A
    inc A
    reti
    start:
    mov A, #'1'
    mov P1, #0h
    setb IT0
    setb EA
    setb EX0
    jmp $
    end

         В основной программе (метка start) в регистр-аккумулятор A заносится числовое значение символа ‘1’, которое затем будет инкрементироваться каждый раз при передаче символа из функции-обработчика в интерфейс PMP.
         Порт P1 настраивается на вывод данных, для чего во все его биты записываются нули командой
    mov P1, #0h

         Далее настраивается аппаратное прерывание INT0:
    • устанавливается срабатывание по спадающему фронту на линии INT0 (команда setb IT0);
    • разрешаются все прерывания (команда setb EA);
    • разрешается прерывание по линии INT0 (команда setb EX0).
         Программа-обработчик прерывания INT0 располагается по фиксированному адресу 0x3 в сегменте программного кода и включает всего две команды.
    Команда
    mov P1, A
         выставляет данные из аккумулятора A на линии порта P1, а команда reti завершает обработчик. Как видно из этой программы, механизмом синхронизации для микроконтроллера 8052 в данном случае является вызов прерывания при активных сигналах PMCS2 и PMRD микроконтроллера PIC24.
         Параллельный интерфейс микроконтроллеров семейства PIC24F можно настроить и для работы в более сложных конфигурациях, где применяется адресация устройств по отдельным линиям. Такие варианты часто применяются при реализации интерфейсов с запоминающими устройствами и дисковыми накопителями. В любом случае наличие интерфейса PMP существенно упрощает проектирование сложных систем передачи данных с шинным интерфейсом. Для дополнительной информации по данной теме я рекомендую обратиться к фирменной документации Microchip.

    Комментарии