вторник, 5 августа 2014 г.

Дополнительные режимы работы АЦП в MSP430. Часть 1.

В этой части рассказывается о том как запустить АЦП на плате Launchpad и воспользоваться продвинутыми режимами работы АЦП: одноканальным многократным и многоканальным многократным и взаимодействием с контроллером прямого доступа в памяти --- DMA. Благодаря этим режимам АЦП можно автоматизировать процесс аналого-цифрового преобразования, в отличие от PIC и AVR где нужно каждый раз дёргать бит в управляющем регистре, потом ждать конца преобразования и извлекать результат. Достаточно настроить АЦП один раз и потом АЦП будет автоматически пересылать результаты на нужный адрес в памяти без вмешательства со стороны пользователя. Несмотря на то, что микроконтроллер MSP430G2553, который идёт в комплекте с платой Launchpad, относится к категории бюджетных, плата позволяет получать результаты недостижимые для МК семейств PIC и AVR. О подробностях см. под кат.

Пример работы с АЦП для платы Launchpad в однократном режиме можно найти тут . Здесь работа с АЦП почти ничем не отличается от PIC и AVR. Нужно сконфигурировать АЦП, подождать конца преобразования и забрать результат из регистра ADC10MEM. Мы же будем реализовывать автоматическую запись в циклическом режиме 16-ти выборок с пятого канала АЦП в массив. Как только мы доходи до конца массива, то переходим к записи в нулевой элемент. Потом мы будем брать значения с этого массива, делать усреднение и выдавать значение напряжения по запросу с UART. Будет использоваться модифицированный проект из предыдущего поста.

В микроконтроллере MSP430G2553 АЦП 10--разрядное. За него отвечает модуль ADC10. Работа с ADC10 отличается от работы с 12-разрядным АЦП в более продвинутых МК MSP430. Всего в MSP430 4 режима АЦП:

  1. Однократный одноканальный (CONSEQ 0)
  2. Повторяющийся одноканальный (CONSEQ 2)
  3. Однократный многоканальный (CONSEQ 1)
  4. Повторяющийся многоканальный (CONSEQ 3)

Для реализации нашей задачи нам нужен повторяющийся одноканальный режим. Чтобы перевести в него АЦП, нужно установить биты CONSEQ_2 в регистре ADC10CTL1. Ещё нужно установить бит MSC регистра ADC10CTL0, который разрешает многократные преобразования.

Модуль ADC10, в отличие от модуля ADC12. имеет встроенный контроллер прямого доступа к памяти (DMA). Он отвечает за пересылку результата преобразования из регистра ADC10MEM на нужный адрес в памяти. Контроллер DMA работает без участия человека. Достаточно проинициализировать его один раз. Работать с ним даже проще, чем с АЦП в однократном режиме. Нам понадобятся три регистра этого модуля:

  • ADC10DTC0. В нём нужно установить бит ADC10CT, который разрешает последовательные переносы.
  • ADC10SA (start address). Стартовый адрес, то есть адрес в памяти на который будет автоматически пересылаться содержимое регистра ADC10MEM после завершения преобразования. После каждого преобразования увеличивается на единицу, пока не дойдёт до значения ADC10DTC1. Потом снова сбрасывается к исходному значению. И так в цикле.
  • ADC10DTC1 (data transfer count) --- количество пересылок данных. Должен быть равен длине массива, где будут храниться результаты АЦП.

Теперь рассмотрим пример. В предыдущий проект нужно добавить два файла adc.c и adc.h, которые содержат функции инициализации работы с АЦП. Исходный код можно забрать здесь.

Содержимое файла adc.c следующее

#include "msp430.h"
#include "stdint.h"
#include "adc.h"

void ADC_init_intref_repeating(uint16_t *buffer,uint16_t samples_cnt) 
// Эта функция инициализирует АЦП. Параметры --- адрес массива,
// где будут храниться результаты преобразования и его длина
{
    ADC10CTL0 &= ~ENC; // Остановим АЦП
    ADC10CTL0 = MSC + // Многократные выборки
                SREF_1 +  // АЦП работает от внутреннего источник 
                          // образцового напряжения (ИОН)
                ADC10SHT_2 + // параметры быстродействия АЦП
  REF2_5V + // Напряжение ИОН VREF=2.5V
  REFON + // Включим ИОН
  ADC10ON; // Включим АЦП
    ADC10CTL1 = INCH_5 + // Выбираем 5-й канал - ножку P1.5
                SHS_0 +
  ADC10SSEL_0 + // Источник тактирования АЦП = SMCLK
  ADC10DIV_0 + // Без предделителя
  CONSEQ_2; // Переводим АЦП в многократный одноканальный режим
    ADC10AE0 = BIT5; // Переводим ножку P1.5 в режим аналогового входа
    ADC10DTC0 = ADC10CT; // Настройка DMA
    ADC10DTC1 = samples_cnt; // Длина массива
    while (ADC10CTL1&BUSY);
    ADC10SA = (int) buffer; // Стартовый адрес
    ADC10CTL0 |=ENC + ADC10SC; // Запускаем АЦП
}
А это файл adc.h:
#ifndef ADC_H
#define ADC_H

#include "stdint.h"

void ADC_init_intref_repeating(uint16_t *adc,uint16_t samples_cnt); 

#endif
Не забываем добавить эти файлы в Makefile, иначе ничего не скомпилируется.

Теперь модифицируем файл main.c. Сначала добавлям #incude "adc.h". Потом добавляем глобальный массив, в который будут складываться результаты преобразования и необходимые дефайны.

#define SAMPLES_CNT 16

uint16_t adc[SAMPLES_CNT];

Перед уходом в спящий режим инициализируем АЦП.


ADC_init_intref_repeating(adc,SAMPLES_CNT);

И модифицируем обработчик прерывания от UART, чтобы он при получении символа "3" выдавал по UART значение напряжения на ножке P1.5 в милливольтах.

void uart_rx_isr(unsigned char c) 
{
    uint16_t mV=0; // Volatge in mV
    uint32_t adc_avg=0; // ADC average
    int i=0;

    switch (c) {
    case '1': P1OUT ^=LED_RED;
              uart_puts("Red led toggled\n");
              break;
    case '2': P1OUT ^= LED_GREEN;
              uart_puts("Green led toggled\n");
              break;
    case '3': adc_avg=0;
              for (i=0;i < SAMPLES_CNT;i++) { // Выполним усреднение
                 adc_avg += adc[i]; // Просуммируем все элементы массива
              }
       adc_avg /= SAMPLES_CNT; // И разделим сумму 
                                      // на количество элементов
              mV = (adc_avg*2500)/1024; // Рассчитаем напряжение
              printf("P1.5 pin voltage = %d mV\n",mV); 
            // Печатаем напряжение в UART
       break;
    default:  uart_putc(c);
              break;
    }
}

Исходный код для всего можно забрать с Гитхаба здесь. В следующей части будет рассказано о многоканальном режиме АЦП.

Комментариев нет:

Отправить комментарий