Это руководство посвящено многоканальному режиму АЦП в микроконтроллере MSP430G2553 на плате Launchpad. В предыдущей части был рассмотрен одноканальный режим АЦП с прямым доступом к памяти DMA. Точно так же можно использовать АЦП и во многоканальном режиме. АЦП будет автоматически пересылать результаты преобразования со всех каналов на заданный адрес в памяти. В этом процессе ядро микроконтроллера не задействовано и может заниматься другими делами (например расчётами). Операции с АЦП выполняются как бы в отдельном потоке. Таким образом реализуется примитивная аппаратная многозадачность. Как это сделать рассмотрено под катом.
Чтобы перевести АЦП в повторяющийся многоканальный режим нужно установить биты CONSEQ_3 регистра ADC10CTL1 и задать количество каналов установив биты INCH_xx. В остальном процедура настройки АЦП не отличается от многоканального режима.
Если например установить биты INCH_7, то АЦП будет работать в восьмиканальном режиме. Микроконтроллер будет сканировать входы АЦП последовательно от седьмого до нулевого и каждый раз помещать результат преобразования в регистр ADC10MEM. Модуль DMA будет пересылать каждый раз результат из этого регистра на пользовательский адрес в памяти.
Значения регистра счётчика пересылок ADC10DTC1 нужно установить равным
ADC10CTL1 = число_каналов * количество_выборок
Результаты АЦП можно складывать в двухмерный массив, который следует объявить так
uint16_t adc[Количество_выборок][Число_каналов];
Теперь рассмотрим пример. Переведём АЦП в восьмиканальный режим, сделаем усреднение по четырём выборкам и выведем результат по запросу с UART. Для этого сперва модифицируем функцию инициализации АЦП из файла adc.cследующим образом:
#include "msp430.h" #include "stdint.h" #include "adc.h" void ADC_init_intref_multichannel(uint16_t *buffer,uint16_t samples_cnt) // Init ADC single channel oneshot with internal reference 2.5V { ADC10CTL0 &= ~ENC; // Стоп АЦП ADC10CTL0 = MSC + // Разрешаем многократные выборки SREF_1 + // Внутренний ИОН ADC10SHT_2 + // Настраиваем скорость работы АЦП REF2_5V + // Напряжение ИОН VREF=2.5В REFON + // Включаем встроенный ИОН ADC10ON + // Включаем АЦП ADC10IE; // Разрешаем прерывание от АЦП ADC10CTL1 = INCH_7 + // Сканировать 8 каналов АЦП начиная с A7 до A0 SHS_0 + ADC10SSEL_0 + // Источник тактирования АЦП = SMCLK ADC10DIV_0 + // без предделителя CONSEQ_3; // Переводим АЦП во многоканльный режим ADC10AE0 = BIT4+BIT5+BIT7; // Подключаем ножки P1.4, P1.5, P1.7 // как аналоговый вход ADC10DTC0 = ADC10CT; // Разрешаем непрерывный перенос результатов ADC10DTC1 = samples_cnt; // Число пересылок //while (ADC10CTL1&BUSY); ADC10SA = (int) buffer; // Стартовый адрес, куда отсылать результат АЦП ADC10CTL0 |=ENC + ADC10SC; // Старт АЦП }
В файле объявляем двухмерный массив, где будут храниться результаты АЦП:
#define SAMPLES_CNT 4 // Делаем 4 последовательных выборки #define CHANNELS_CNT 8 // По 8 каналам uint16_t adc[SAMPLES_CNT][CHANNELS_CNT];
В этом массиве нумерация каналов идёт с конца. То есть элемент adc[0][0] будет соответствовать 0-й выборке с 7-го канала, adc[0][1] - 0-й выборке с 6-го канала и так до adc[3][7], который соответствует 3-й выборке с нулевого канала.
И модифицируем обработчик прерывания от UART:
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++) { // Вычисляем среднее напряжение // по 5-му каналу adc_avg += adc[i][((CHANNELS_CNT-1)-5)]; } adc_avg /= SAMPLES_CNT; mV = (adc_avg*2500)/1024; printf("P1.5 pin voltage = %d mV\n",mV); // Печатаем напряжение // на ножке P1.5 break; default: uart_putc(c); break; } }
Исходники для этого примера можно забрать с Гитхаба .
Комментариев нет:
Отправить комментарий