Это руководство посвящено многоканальному режиму АЦП в микроконтроллере 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;
- }
- }
Исходники для этого примера можно забрать с Гитхаба .
Комментариев нет:
Отправить комментарий