Микроконтроллеры PIC. Архитектура и программирование. Часть 11. Обработка аналоговых сигналов в микроконтроллере PIC24F » Программирование устройств на PIC микроконтроллерах


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

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

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

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


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


Последние материалы
  • Тестовая плата для отладки программ на микроконтроллере PIC18F4550
  • Кнопка On/OFF на PIC12F629.
  • Часы с синхронизацией от китайского будильника
  • ШИМ регулятор на PIC16F628A.
  • Счетчики прямого и обратного счета на PIC16F628A.
  • Таймер отключения питания для мультиметра и не только.
  • Измеритель напряжения и тока
  • Маршрутный компьютер для электровелосипеда
  • Простой двухканальный термометр на PIC16F690 и датчиках DS18B20
  • Электронная "Незабудка" для забывчивых
  • Популярные материалы
    Случайная книга
    Программирование устройств на PIC микроконтроллерах » Справочник » Микроконтроллеры PIC. Архитектура и программирование. Часть 11. Обработка аналоговых сигналов в микроконтроллере PIC24F
    Микроконтроллеры PIC. Архитектура и программирование. Часть 11. Обработка аналоговых сигналов в микроконтроллере PIC24F
    Автор публикации: alex Просмотров: 16288 Добавлен: 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 обладают развитыми возможностями по обработке аналоговых сигналов. Помимо того, что к этим микроконтроллерам, как и к любым другим, можно подключать внешние микросхемы аналого-цифровых преобразователей (АЦП), они уже имеют в своем составе интегрированный модуль 16-канального 10-битного АЦП. Вначале рассмотрим возможности встроенного модуля АЦП. Его упрощенная блок-схема приведена на Рис. 11.1.

    Рис. 11.1. Модуль аналого-цифрового преобразователя

         Аналого-цифровой преобразователь микроконтроллера разработан на основе регистра последовательного приближения и позволяет обрабатывать аналоговые сигналы с 16 каналов (обозначаются как AN0…AN15) с использованием двух мультиплексоров MUXA и MUXB (см. Рис. 11.1). Результаты преобразований сохраняются в массиве 16-битных слов ADC1BUFx. Установка режимов работы и рабочих параметров преобразователя осуществляется с помощью регистров AD1CON1…AD1CON3, AD1CHS, AD1PCFG и AD1PCFG (мы обсудим их далее).
         Аналого-цифровой преобразователь микроконтроллеров PIC24F имеет следующие характеристики:
         • разрешающая способность — 10 бит;
         • способ преобразования — метод последовательного приближения (Successive Approximation Register, SAR);
         • частота преобразования — до 500 тыс. выборок/с;
         • количество входных аналоговых каналов — 16;
         • возможность подключения внешних источников опорного напряжения;
         • униполярный усилитель выборки/хранения входного сигнала;
         • возможность сканирования каналов в автоматическом режиме;
         • имеется буфер на 16 значений;
         • возможность выполнения операций в «спящем» режиме и режиме «холостого хода» микроконтроллера.
         Микроконтроллеры семейства PIC24F могут различаться количеством входных каналов, поэтому всегда следует знакомиться с документацией на конкретное устройство. Однако во всех моделях имеются два вывода для подключения опорного напряжения, VREF+ и VREF-, а сами варианты выбора источника опорного напряжения можно задавать программным способом. Входы аналоговых сигналов через два независимых мультиплексора (MUXA и MUXB) подключаются к усилителю выборки и хранения аналого-цифрового преобразователя.
         В преобразователе предусмотрен вариант автоматического сканирования нескольких каналов ввода. Кроме того, процессом преобразования можно управлять как на этапе выборки аналогового сигнала на входе АЦП, так и при выполнении собственно самого преобразования. В преобразователе предусмотрены режимы автовыборки и автопреобразования, что значительно упрощает управление преобразователем и избавляет разработчика от трудоемких расчетов временных характеристик преобразования.
         Модуль АЦП можно настроить так, чтобы после каждого полного цикла преобразования генерировалось прерывание, что можно использовать при построении систем реального времени. Данные преобразования сохраняются в виде 16-битных слов во внутреннем буфере.
         При написании этой главы я не ставил целью подробное описание всех режимов работы АЦП и использование всех возможностей преобразователя для обработки сигналов. Мы рассмотрим только важнейшие аспекты функционирования АЦП и проиллюстрируем их несложными практическими примерами, что даст возможность научиться быстро и на достаточно хорошем уровне разрабатывать системы обработки аналоговых данных. Освоив основы работы с АЦП микроконтроллеров семейства PIC24F, можно двигаться дальше и изучать обширную документацию, предоставляемую фирмой Microchip.
         Процесс преобразования аналогового сигнала в цифровой можно представить в виде последовательности двух фаз или этапов: этапа выборки и этапа собственно преобразования (Рис. 11.2).

    Рис. 11.2. Последовательность выполнения аналого-цифрового преобразования

         Преобразование аналогового сигнала в цифровой код начинается с момента подключения одного из входов АЦП к источнику сигнала (1). На программном уровне это подключение выполняется путем установки бита SAMP регистра управления AD1CON1. Устройство выборки-хранения представляет собой матрицу конденсаторов, которые заряжаются напряжением входного сигнала в течение определенного интервала времени (время выборки). Интервал выборки должен быть достаточно продолжительным, чтобы конденсаторы смогли зарядиться до напряжения, соответствующего входному сигналу. Интервал выборки задается программным способом в регистре управления AD1CON3.
         Вместе с тем, интервал выборки не должен быть слишком большим, поскольку общее время преобразования в этом случае будет увеличиваться. Кроме того, при большом времени выборки может происходить частичная утечка заряда на конденсаторах устройства выборки-хранения, что скажется на точности преобразования. Лучше всего при выборе интервала выборки руководствоваться рекомендациями производителя (это относится не только к данному конкретному случаю, но и к технике аналого-цифрового преобразования в целом).
         По завершении этапа выборки источник входного аналогового сигнала отключается от устройства выборки-хранения, и начинается процесс преобразования накопленного на матрице конденсаторов заряда в цифровой код (2). Для данного преобразователя предусмотрен целый ряд режимов, позволяющих управлять процессом преобразования вручную или автоматически. Управление этапом преобразования выполняется путем программирования отдельных битов регистра AD1CON1 (мы рассмотрим это при анализе примеров программного кода).
         На этапе преобразования каждый бит результата выдается по отдельному синхронизирующему импульсу. Для 10-битного преобразования требуется 10 импульсов синхронизации плюс два дополнительных импульса, т. е. всего 12 импульсов. Период этих импульсов (обозначается как TAD) выбирается программно путем установки соответствующих битов в регистре AD1CON3. По завершении преобразования 10-битный цифровой код результата помещается в один из 16-битных буферных регистров, которые доступны для чтения (3). Об окончании преобразования свидетельствует либо установленный бит DONE в регистре управления-состояния AD1CON1, либо установленный флаг прерывания АЦП.
         В следующем разделе мы ознакомимся с программной моделью аналого-цифрового преобразователя.

    11.1. Программная модель интегрированного АЦП

         Для программиста модуль аналого-цифрового преобразователя можно представить группой регистров, с помощью которых можно задавать как общие параметры преобразования (интервал выборки, частоту преобразования), так и режимы выполнения самого преобразования (возможность сканирования каналов входных сигналов, автоматического запуска преобразования и т. д.). Думаю, нет смысла подробно описывать абсолютно каждый бит регистров управления и состояния — это все имеется в документации на микроконтроллер.
         При первоначальном знакомстве с модулем АЦП достаточно понять смысл основных настраиваемых опций — остальные можно оставить по умолчанию.
         В подавляющем большинстве практических разработок аналого-цифровой преобразователь работает в одном из стандартных режимов, для программирования которого потребуется установка всего нескольких битов в регистрах управления АЦП. Тем не менее, нужно четко себе представлять схемотехнические принципы функционирования АЦП — это позволит создавать самые сложные системы сбора аналоговой информации.
         Аналого-цифровой преобразователь имеет 22 регистра, шесть из которых служат для управления АЦП и хранения информации о состоянии устройства.
    К управляющим регистрам относятся:
         • AD1CON1 — регистр управления 1 АЦП;
         • AD1CON2 — регистр управления 2 АЦП;
         • AD1CON3 — регистр управления 3 АЦП;
         • AD1CHS — регистр выбора входного канала;
         • AD1PCFG — регистр конфигурации входов АЦП;
         • AD1CSSL — регистр настройки сканирования входных каналов.
         Регистры AD1CON1…AD1CON3 управляют ходом выполнения преобразования АЦП. С их помощью устанавливается частота преобразования, выбирается конфигурация источников опорного напряжения, а также выполняется программное управление выборкой и преобразованием входного сигнала. Регистр AD1CHS позволяет выбрать входные каналы, которые будут подключены к устройству выборки-хранения сигнала преобразователя, а также мультиплексор для работы с входными сигналами. С помощью регистра AD1PCFG осуществляется настройка выводов микроконтроллера для работы в одном из режимов: либо как аналогового входа, либо как линии ввода/вывода цифровых сигналов. Наконец, регистр AD1CSSL позволяет выбрать каналы входных сигналов для режима сканирования.
         Модуль аналого-цифрового преобразователя включает блок из 16-и регистров ADC1BUF. Регистры именуются, начиная с ADC1BUF0 и заканчивая ADC1BUFF. Их содержимое доступно только для чтения.
         Перейдем к описанию регистров преобразователя и начнем с регистра управления AD1CON1 (Табл. 11.1).

    Таблица 11.1. Биты регистра управления и состояния AD1CON1
    Позиция бита Обозначение Описание
    15 ADON 1 – модуль АЦП включен
    0 – модуль АЦП отключен
    14 - Не задействован, читается как 0
    13 ADSIDL 1 – АЦП прекращает работу в режиме «холостого хода» микроконтроллера
    0 – АЦП продолжает работу в режиме «холостого хода»
    12 - Не задействован, читается как 0
    11 - Не задействован, читается как 0
    10 - Не задействован, читается как 0
    9-8 FORM1–FORM0 Формат выходных данных (обычно равен 00, что означает беззнаковое целое число)
    7-5 SSRC2–SSRC0 Метод инициализации преобразования:
    111 – процесс выборки контролируется внутренним счетчиком. По окончании выборки начинается преобразование(автопреобразование);
    110 – зарезервирован;
    10х – зарезервирован;
    100 – зарезервирован;
    011 – зарезервирован;
    010 – окончание выборки контролируется таймером 3.
    По окончании выборки немедленно начинается преобразование;
    001 – переход в активное состояние сигнала на выводе INT0 завершает преобразование, после чего немедленно начинается преобразование;
    000 – очистка бита SAMP приводит к завершению выборки и началу процесса преобразования
    4 - Не задействован, читается как 0
    3 - Не задействован, читается как 0
    2 ASAM 1 – процесс выборки начинается сразу после окончания предыдущего преобразования, при этом бит SAMP устанавливается автоматически
    0 – выборка сигнала начинается при установке бита SAMP
    1 SAMP Бит разрешения выборки:
    1 – устройство выборки хранения начинает выборку сигнала;
    0 – устройство выборки находится в режиме хранения сигнала.
    Если ASAM = 0, то запись 1 в этот бит инициирует начало выборки сигнала. Если SSRC2–SSRC0 = 000, то запись 0 в этот бит приводит к завершению выборки и началу преобразования
    0 DONE Бит состояния преобразования. Установка в 1 свидетельствует об окончании процесса преобразования, установка в 0 означает, что либо преобразование не выполнено по каким"то причинам, либо оно вообще не начиналось

    Таблица 11.2. Биты регистра управления и состояния AD1CON2
    Позиция бита Обозначение Описание
    15-13 VCFG2 – VCFG0 Эти биты определяют конфигурацию источника опорного напряжения для АЦП:
    000 – в качестве VR+ выбирается AVDD, а в качестве VR– – AVSS;
    001 – в качестве VR+ выбирается источник напряжения, подключенный к выводу VREF+, а VREF– подключается к AVSS;
    010 – в качестве VR+ выбирается AVDD, а VREF– подключается к AVSS;
    011 – в качестве VR+ выбирается источник напряжения, подключенный к выводу VREF+, а в качестве VREF– – AVSS;
    1xx – в качестве VR+ выбирается AVDD, а в качестве VR– – AVSS
    12 Зарезервирован, читается как 0
    11 Зарезервирован, читается как 0
    10 CSCNA Выбор режима сканирования для канала MUXA:
    1 – входы сканируются;
    0 – входы не сканируются
    9 Зарезервирован, читается как 0
    8 Зарезервирован, читается как 0
    7 BUFS Режим записи буфера данных:
    1 – АЦП сохраняет результат в ADC1BUF8–ADC1BUFF, а доступ к ADC1BUF0–ADC1BUF7 выполняется вручную;
    0 – АЦП сохраняет результат в ADC1BUF0–ADC1BUF7, а доступ к ADC1BUF8–ADC1BUFF выполняется вручную
    6 Зарезервирован, читается как 0
    5-2 SMPI3–SMPI0 Биты определяют, как часто должно инициироваться прерывание:
    1111 – после каждого 16"го преобразования;
    1110 – после каждого 15"го преобразования;
    . . .
    0001 – после каждого 2"го преобразования;
    0000 – после каждого преобразования
    1 BUFM Выбор режима работы буфера данных:
    1 – буфер конфигурируется как две отдельные группы буферов по 8 слов (ADC1BUF0–ADC1BUF7 и ADC1BUF8–ADC1BUFF);
    0 – буфер конфигурируется как непрерывный (ADC1BUF0–ADC1BUFF)
    0 ALTS Выбор альтернативного источника входного сигнала:
    1 – при первой выборке используется мультиплексор MUXA, затем выполняется переключение между MUXA и MUXB;
    0 – всегда используется MUXA

    Таблица 11.3. Биты регистра управления и состояния AD1CON3
    Позиция бита Обозначение Описание
    15 ADRC Этот бит определяет источник тактового сигнала преобразователя:
    0 – используется внутренний RC"генератор;
    1 – используется системная тактовая частота
    14-13   Зарезервирован, читается как 0
    12-8 SAMC4–SAMC0 Биты устанавливают интервал автовыборки входного сигнала:
    11111 – 31 TAD;
    . . . . . . . .
    00001 – 1 TAD;
    00000 – 0 TAD (не рекомендуется)
    7-0 ADCS7–ADCS0 Выбор тактовой частоты преобразования:
    11111111 – 128 TCY;
    11111110 – 127 TCY;
    . . . . . . . .
    00000001 – 1 TCY;
    00000000 – TCY/2

    Таблица 11.4. Биты регистра управления и состояния AD1CHS
    Позиция бита Обозначение Описание
    15 CH0NB Этот бит определяет источник отрицательного аналогового входного сигнала для мультиплексора MUXB:
    1 – в качестве входа используется AN1;
    0 – в качестве входа используется вывод VR–
    14-12   Зарезервирован, читается как 0
    11-8 SH0SB3–SH0SB0 Биты определяют источник положительного аналогового входного сигнала для мультиплексора MUXB:
    1111 – AN15;
    1110 – AN14;
    1101 – AN13;
    . . . .
    0001 – AN1;
    0000 – AN0;
    7 CH0NA Этот бит определяет источник отрицательного аналогового входного сигнала для мультиплексора MUXA:
    1 – в качестве входа используется AN1;
    0 – в качестве входа используется вывод VR–
    6-4   Зарезервированы, читаются как 0
    7-0 SH0SA3–SH0SA0 Биты определяют источник положительного аналогового входного сигнала для мультиплексора MUXA:
    1111 – AN15;
    1110 – AN14;
    1101 – AN13;
    . . . .
    0001 – AN1;
    0000 – AN0;

    Таблица 11.5. Биты регистра управления и состояния AD1PCFG
    Позиция бита Обозначение Описание
    15-0 PCFG15–PCFG0 Этот бит определяет режим работы порта ввода/вывода:
    1 – порт сконфигурирован для цифрового ввода/вывода;
    0 – порт сконфигурирован как аналоговый

    Таблица 11.6. Биты регистра управления и состояния AD1CSSL
    Позиция бита Обозначение Описание
    15-0 CSSL15–CSSL0 Биты определяют номера сканируемых каналов аналоговых входных сигналов для MUXA:
    1 – соответствующий канал ANxx сканируется;
    0 – соответствующий канал ANxx пропускается


    11.2. Практическое использование модуля АЦП

         Из описания общих принципов функционирования 10-битного аналого-цифрового преобразователя микроконтроллеров PIC24F может показаться, что программировать обработку данных таким модулем очень сложно. На самом деле это не так. При решении практических задач большинство настроек можно оставить такими, какими они задаются по умолчанию, и настроить только несколько ключевых характеристик преобразователя. Как это делается, мы рассмотрим на нескольких практических примерах.
         В первом примере микроконтроллер PIC24FJ128GA010 будет преобразовывать в цифровой код аналоговое напряжение, которое подается на вход AN7.
         Аналоговый сигнал будет преобразовываться каждый раз при переходе напряжения на входе прерывания INT3 из ВЫСОКОГО уровня в НИЗКИЙ. Цифровой код сигнала можно, например, обработать дальше и использовать для генерации сигналов управления или передать его через асинхронный последовательный порт другому устройству или компьютеру. Вот упрощенная схема нашего устройства (Рис. 11.3).

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

         Создадим в MPLAB IDE проект с помощью мастера проектов и добавим в него файл со следующим исходным текстом программы:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define Channel 7
    #define AINPUTS 0x0
    unsigned int bReq = 0;
    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       bReq = 1;
       _INT3IF = 0;
    }
    void initADC(int adcmask)
    {
       AD1PCFG = adcmask;
       AD1CON1 = 0;
       AD1CSSL = 0;
       AD1CON2 = 0;
       AD1CON3 = 0x1F02;
       AD1CON1bits.ADON = 1;
    }
    int readADC(int channel)
    {
       AD1CHS = channel;
       AD1CON1bits.SAMP = 1;
       T1CONbits.TON = 1;
       TMR1 = 0;
       while (TMR1 < 100);
       AD1CON1bits.SAMP = 0;
       while (!AD1CON1bits.DONE);
       return ADC1BUF0;
    }
    void main()
    {
       int a1;
       float res;
       TRISA = 0xff00;
       INTCON2bits.INT3EP = 1;
       _INT3IF = 0;
       _INT3IP = 4;
       _INT3IE = 1;
       initADC(AINPUTS);
       while (1)
       {
         if (bReq == 1)
         {
           a1 = readADC(Channel);
           res = 5.0 / 1024.0 * a1;
           bReq = 0;
         }
       }
    }

         Исходный текст программы с первого взгляда может показаться довольно сложным, но мы проанализируем его шаг за шагом, и вскоре смысл операторов станет понятен. Прежде всего, рассмотрим функции, относящиеся к работе аналого-цифрового преобразователя. Это initADC и readADC. В функции initADC выполняется установка основных параметров преобразования. В качестве входного параметра функции передается маска аналоговых входов adcmask. Оператор
    AD1PCFG = adcmask;

    устанавливает в регистре AD1PCFG конфигурацию выводов порта B микроконтроллера, которые используются в качестве аналоговых. В нашем примере все выводы порта являются аналоговыми, что указано в константе AINPUTS:
    #define AINPUTS 0x0

    Оператор
    AD1CON1 = 0;

    сбрасывает все биты регистра управления 1 АЦП в 0. Помимо всего прочего, такие установки означают, что процесс преобразования должен запускаться вручную. Поскольку наша программа не будет выполнять последовательное сканирование аналоговых каналов ввода, то все биты регистра AD1CSSL тоже сбрасываются в 0:
    AD1CSSL = 0;

    С помощью оператора
    AD1CON2 = 0;

    в качестве мультиплексора каналов АЦП выбирается MUXA, а в качестве опорных напряжений Vref+ и Vref– выбираются напряжения питания AVdd и земли AVss соответственно. Далее мы устанавливаем интервал преобразования (Tsamp) и период тактирования (Tad):
    AD1CON3 = 0x1F02;

         В данном случае, при тактовой частоте 8 МГц интервал преобразования выбирается равным 32*Tad, а период тактирования Tad равным 125 нс. Последний оператор разрешает работу модуля АЦП:
    AD1CON1bits.ADON = 1;

         Собственно преобразование выполняется функцией readADC. В качестве параметра функция принимает номер тестируемого канала, который для нашей программы равен 7 и задается константой Channel:
    #define Channel 7

    Оператор
    AD1CHS = channel;

    устанавливает в регистре AD1CHS номер тестируемого канала. После всех этих установок мы можем запустить процесс выборки входного сигнала, что выполняется путем установки бита SAMP:
    AD1CON1bits.SAMP = 1;

         Здесь есть очень важный момент. Поскольку преобразование аналогового сигнала контролируется вручную, то необходим определенный интервал времени для того, чтобы конденсатор устройства выборки/хранения АЦП мог полностью зарядиться. В этом случае заряд будет точно соответствовать входному напряжению, и результат преобразования будет достаточно точным. Для задания интервала времени выборки можно воспользоваться Таймером 1. Следующая группа операторов обеспечивает интервал выборки, равный 6.25 мкс (для данной тактовой частоты):

    T1CONbits.TON = 1;
    TMR1 = 0;
    while (TMR1 < 100);

    По прошествии этого интервала времени можно начать процесс преобразования, для чего следует сбросить бит SAMP:
    AD1CON1bits.SAMP = 0;

    Окончание процесса преобразования определяется по установке бита DONE регистра AD1CON:
    while (!AD1CON1bits.DONE);

         Полученный в результате преобразования 16-битный цифровой код помещается в регистр ADC1BUF0, который и возвращается вызывающей программе.
         Преобразование аналогового сигнала будет выполняться каждый раз при перепаде напряжения из ВЫСОКОГО уровня в НИЗКИЙ на входе прерывания INT3 микроконтроллера PIC24FJ128GA010, следовательно, в нашу программу мы должны включить код обработчика прерывания INT3. Алгоритм измерения довольно простой: каждый раз при возникновении прерывания функция-обработчик устанавливает переменную bReq, значение которой непрерывно проверяется в цикле while основной программы. При равенстве bReq единице выполняется преобразование, и результат запоминается в переменной res в виде числа с плавающей точкой. По окончании преобразования переменная bReq сбрасывается, и цикл продолжает выполнение до следующего прерывания.
    Обработчик прерывания INT3 предельно прост:

    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       bReq = 1;
       _INT3IF = 0;
    }

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

    TRISA = 0xff00;
    INTCON2bits.INT3EP = 1;
    _INT3IF = 0;
    _INT3IP = 4;
    _INT3IE = 1;

         Бит _INT3EP, установленный в 1, определяет генерацию внешнего прерывания по спаду сигнала на входе INT3. Следующие три оператора сбрасывают флаг прерывания, устанавливают уровень приоритета и разрешают прерывание.
         Результат преобразования записывается в целочисленную переменную a1, а окончательный результат вычисляется при помощи следующего оператора:
    res = 5.0 / 1024.0 * a1;

         Переменная res будет содержать вещественное число, которое и будет являться результатом преобразования. Здесь выражение 5.0/1024.0 определяет значение младшего значащего бита (LSB) для 10-битного преобразователя (1024 = 210).
         Если использовать прерывание АЦП, то результата преобразования можно не дожидаться, а продолжить выполнение программы. Модифицируем исходный текст основной программы из предыдущего примера таким образом, чтобы можно было работать с прерыванием АЦП. Вот исходный текст новой программы:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define Channel 7
    #define AINPUTS 0x0
    unsigned int bReq = 0;
    unsigned int bDone = 0;
    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       bReq = 1;
       _INT3IF = 0;
    }
    void __attribute__ ((interrupt)) _ADC1Interrupt(void)
    {
       bDone = 1;
       _AD1IF = 0;
    }
    void initADC(int adcmask)
    {
       AD1PCFG = adcmask;
       AD1CON1 = 0;
       AD1CSSL = 0;
       AD1CON2 = 0;
       AD1CON3 = 0x1F02;
       _AD1IF = 0;
       _AD1IP = 3;
       _AD1IE = 1;
       AD1CON1bits.ADON = 1;
    }
    void readADC(int channel)
    {
       AD1CHS = channel;
       AD1CON1bits.SAMP = 1;
       T1CONbits.TON = 1;
       TMR1 = 0;
       while (TMR1 < 100);
       AD1CON1bits.SAMP = 0;
    }
    void main()
    {
       int a1;
       float res;
       TRISA = 0x0;
       INTCON2bits.INT3EP = 1;
       _INT3IF = 0;
       _INT3IP = 4;
       _INT3IE = 1;
       initADC(AINPUTS);
       while (1)
       {
         if (bReq == 1)
         {
           bReq = 0;
           readADC(Channel);
         }
         if (bDone == 1)
         {
           bDone = 0;
           a1 = ADC1BUF0;
           res = 5.0 / 1024.0 * a1;
         }
       }
    }

         Мы добавили в программу переменную bDone, которая, будучи установленной в 1, указывает на окончание преобразования аналогового сигнала, что используется основной программой для обработки результата. Установка переменной выполняется в обработчике прерывания модуля АЦП, программный код которого показан далее:

    void __attribute__ ((interrupt)) _ADC1Interrupt(void)
    {
       bDone = 1;
       _AD1IF = 0;
    }
         Кроме установки переменной bDone, в обработчике также сбрасывается и флаг прерывания _AD1IF. Текст функции readADC упростился и теперь выглядит так:
    void readADC(int channel)
    {
       AD1CHS = channel;
       AD1CON1bits.SAMP = 1;
       T1CONbits.TON = 1;
       TMR1 = 0;
       while (TMR1 < 100);
       AD1CON1bits.SAMP = 0;
    }

         В этой функции последний оператор запускает процесс преобразования, а окончание преобразования фиксируется в обработчике _ADC1Interrupt. Что же касается изменений в исходном тексте функции initADC, то в нее дополнительно включены три оператора, инициализирующие прерывание АЦП.
         Изменения в основной программе читатели без труда смогут проанализировать самостоятельно.
         В микроконтроллерах PIC24F предусмотрен очень удобный вариант конфигурирования АЦП, позволяющий обойтись без ручного задания точных временных интервалов, как это мы делали, например, с помощью Таймера 1 в предыдущих двух примерах. Это позволяет в определенной степени автоматизировать процесс аналого-цифрового преобразования и облегчить задачу программисту.
         Для работы в таком режиме нужно установить биты SSRC2…SSRC0 регистра AD1CON1 в значение 0b111 (0xE). В этом случае временные параметры процесса выборки и преобразования будут определяться внутренним счетчиком, а процесс преобразования будет запускаться автоматически по окончании этапа выборки.
         Рассмотрим пример программы, в которой будем использовать такую конфигурацию модуля АЦП. В качестве исходного текста возьмем тот, который мы использовали в первом примере, и модифицируем его. Вот как выглядит текст модифицированной программы:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define Channel 7
    #define AINPUTS 0x0
    unsigned int bReq = 0;
    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       bReq = 1;
       _INT3IF = 0;
    }
    void initADC(int adcmask)
    {
       AD1PCFG = adcmask;
       AD1CON1 = 0x00E0;
       AD1CSSL = 0;
       AD1CON2 = 0;
       AD1CON3 = 0x1F02;
       AD1CON1bits.ADON = 1;
    }
    int readADC(int channel)
    {
       AD1CHS = channel;
       AD1CON1bits.SAMP = 1;
       while (!AD1CON1bits.DONE);
       return ADC1BUF0;
    }
    void main()
    {
       int a1;
       float res;
       TRISA = 0x0;
       INTCON2bits.INT3EP = 1;
       _INT3IF = 0;
       _INT3IP = 4;
       _INT3IE = 1;
       initADC(AINPUTS);
       while (1)
       {
         if (bReq == 1)
         {
           bReq = 0;
           a1 = readADC(Channel);
           res = 5.0 / 1024.0 * a1;
         }
       }
    }

         Изменения исходного текста программы касаются, в основном, двух функций — initADC и readADC. Оператор
    AD1CON1 = 0x00E0;

    в функции initADC устанавливает режим внутренней синхронизации процесса преобразования. По этой причине исходный текст функции readADC также значительно упрощается; фактически для запуска и выполнения полного цикла преобразования достаточно установить бит SAMP, а затем проверить соответствующие флаги (либо DONE, либо флаг прерывания _AD1IF).
         При разработке сложных измерительных систем возникает необходимость обработки нескольких аналоговых сигналов. Напомню, что для АЦП можно установить опцию сканирования, позволяющую обрабатывать каналы последовательно. В том случае, если нужно выборочно обработать несколько каналов аналоговых сигналов, это можно реализовать программно. На следующем примере мы посмотрим, как можно обработать три аналоговых сигнала с каналов 1, 2 и 5. Аппаратная часть проекта представлена на Рис. 11.4.

    Рис. 11.4. Аппаратная часть проекта обработки аналоговых сигналов 1-го, 2-го и 5-го каналов

         Для преобразования аналоговых сигналов выберем полуавтоматическое преобразование с использованием прерывания АЦП. Создадим с помощью мастера проектов среды MPLAB IDE шаблон проекта и включим в него файл со следующим исходным текстом:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define AINPUTS 0x0
    int channels[3] = {1, 2, 5};
    unsigned int bReq = 0;
    unsigned int bDone = 0;
    void __attribute__ ((interrupt)) _INT3Interrupt(void)
    {
       bReq = 1;
       _INT3IF = 0;
    }
    void __attribute__ ((interrupt)) _ADC1Interrupt(void)
    {
       bDone = 1;
       _AD1IF = 0;
    }
    void initADC( int adcmask)
    {
       AD1PCFG = adcmask;
       AD1CON1 = 0x00E0;
       AD1CSSL = 0;
       AD1CON2 = 0;
       AD1CON3 = 0x1F02;
       _AD1IF = 0;
       _AD1IP = 3;
       _AD1IE = 1;
       AD1CON1bits.ADON = 1;
    }
    void readADC(int channel)
    {
       AD1CHS = channel;
       AD1CON1bits.SAMP = 1;
    }
    void main()
    {
       int a1[3];
       float res[3];
       int i1;
       int *pADC = &ADC1BUF0;
       bDone = 0;
       TRISA = 0x0;
       INTCON2bits.INT3EP = 1;
       _INT3IF = 0;
       _INT3IP = 4;
       _INT3IE = 1;
       initADC(AINPUTS);
       while (1)
       {
         if (bReq == 1)
         {
           bReq = 0;
           for (i1 = 0; i1 < 3; i1++)
           {
             readADC(channels[i1]);
             while(bDone == 0);
             bDone = 0;
             a1[i1] = *pADC;
             res[i1] = 5.0 / 1024.0 * a1[i1];
           }
         }
       }
    }

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

    int a1[3];
    float res[3];

         В массиве a1 будут храниться двоичные коды результатов преобразования, а в массиве res — окончательные результаты в виде чисел с плавающей точкой.
         В указателе pADC будет храниться адрес внутреннего буфера АЦП, в котором сохраняются результаты преобразования. Этот адрес будет равен адресу первого элемента, т. е. адресу регистра ADC1BUF0. Поскольку в программе используется автоматическое преобразование, окончание которого фиксируется установкой флага прерывания _AD1IF, то исходный текст функции readADC существенно упрощается и выглядит так:

    void readADC(int channel)
    {
       AD1CHS = channel;
       AD1CON1bits.SAMP = 1;
    }

         В качестве параметра функции readADC будут передаваться номера выбранных каналов из массива channels. Смысл остальных переменных и операторов, думаю, понятен. Преобразование и запись результатов выполняются в цикле while(1) основной программы.
         Мы проанализировали только часть возможностей интегрированного 10-битного АЦП. В принципе, возможности модуля позволяют подобрать наилучшую конфигурацию для каждой конкретной системы. Чтобы АЦП обеспечивал высокую достоверность результатов, требуются и довольно серьезные расчеты схемотехнической части устройства. В наших демонстрационных примерах предполагалось, что интегрированный АЦП является идеальным, т. е. не вносит помех и искажений в обрабатываемый сигнал, источники аналоговых сигналов являются идеальными в плане подавления шумов, источник питания дает абсолютно точное напряжение +5 В на выходе, в схеме отсутствуют электромагнитные помехи и т. д. К сожалению, в реальных схемах далеко не все так гладко. Далее в этой главе мы еще вернемся к вопросам схемотехнической (аппаратной) реализации систем с использованием АЦП.
         Внутренний АЦП очень удобен и избавляет разработчика от многих проблем, связанных с настройками параметров преобразования и расчетом временных зависимостей, однако разрешения в 10 бит в ряде случаев может оказаться недостаточно. В этом случае можно воспользоваться внешним аналого-цифровым преобразователем. Пример применения такого внешнего 12-битного преобразователя мы рассмотрим в следующем разделе.

    11.3. Использование внешнего АЦП

         Подключение внешней микросхемы аналого-цифрового преобразователя к микроконтроллеру PIC24F — задача достаточно тривиальная. В нашем следующем проекте мы подключим к порту А аналого-цифровой преобразователь LTC1292 фирмы Linear Technology. Данный преобразователь выполняет передачу данных в микроконтроллер по протоколу SPI и подключается в соответствии со схемой, показанной на Рис. 11.5.
         Программную часть проекта разработаем по обычной схеме. Создадим в MPLAB IDE новый проект и добавим в него файл со следующим текстом:

    #include <p24fj128ga010.h>
    _CONFIG2(FCKSM_CSDCMD&OSCIOFNC_ON&POSCMOD_HS&FNOSC_PRI)
    #define DOUT PORTAbits.RA0
    #define CLK PORTAbits.RA1
    #define CS PORTAbits.RA2
    unsigned int getBinary(void)
    {
       int cnt;
       unsigned int dat = 0;
       CS = 1;
       CLK = 1;
       CS = 0;
       CLK = 0;
       for (cnt = 0; cnt < 13; cnt++)
       {
         CLK = 1;
         CLK = 0;
         dat |= DOUT;
         dat = dat << 1;
       }
       CS = 1;
       dat = dat >> 1;
       dat &= 0xfff;
       return dat;
    }
    void main()
    {
       unsigned int binData;
       float res;
       int temp;
       TRISA = 0x0f01;
       while (1)
       {
         if (_INT3IF == 1)
         {
         _INT3IF = 0;
         binData = getBinary();
         res = 5.0 / 4096.0 * binData;
         temp = res * 100 – 273.16;
         }
       }
    }

    Рис. 11.5. Интерфейс АЦП LTC1292 с микроконтроллером

         Проанализируем текст программы. Собственно преобразование выполняется функцией getBinary. Чтобы понять работу функции, нам следует обратиться к временной диаграмме работы микросхемы аналого-цифрового преобразователя LTC1292 (Рис. 11.6).

    Рис. 11.6. Временная диаграмма работы АЦП LTC1292

         Преобразование аналогового сигнала выполняется при НИЗКОМ уровне сигнала CS. После фазы выборки, которая завершается в момент второго спада на линии CLK, начинается фаза преобразования. Данные на линии Dout становятся действительными по спаду синхроимпульсов CLK, а по фронту CLK их можно считывать в микроконтроллер. По окончании преобразования следует установить сигнал CS в ВЫСОКИЙ уровень. Временная диаграмма одного преобразования формируется в функции getBinary.
         Эта временная диаграмма является типичной для большинства аналогоцифровых преобразователей последовательного приближения, поэтому, поняв принцип работы какого-либо одного устройства, можно успешно применять и другие микросхемы этого типа. Само преобразование запускается при перепаде сигнала на входе прерывания INT3 из НИЗКОГО уровня в ВЫСОКИЙ. В этой программе используется тот факт, что при возникновении запроса на прерывание флаг прерывания _INT3IF будет установлен в любом случае, независимо от того, разрешено конкретное прерывание или нет.
         Двоичный результат преобразования помещается в переменную binData, а окончательный результат в формате вещественного числа с плавающей точкой помещается в переменную res.
         На базе этого проекта можно реализовать несложный измеритель температуры, в котором используется прецизионный аналоговый датчик температуры LM335. Аппаратная часть проекта представлена на Рис. 11.7.
         В этой схеме используется прецизионный датчик температуры LM335, выходное напряжение которого пропорционально температуре измеряемого объекта или среды с коэффициентом пропорциональности 10 мВ/К°. Например, при температуре 0°С выходное напряжение датчика будет равно 2.73 В.
         Принципиальная схема, думаю, в объяснениях не нуждается. Что же касается программной части, то практически весь код позаимствован из предыдущей программы, поэтому я остановлюсь только на изменениях. Их два: в основную программу включена целочисленная переменная temp, в которой будет храниться значение температуры, а также добавлен оператор temp = res * 100 – 273.16;

    Рис. 11.7. Схема измерителя температуры

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

    Комментарии