вторник, 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 следующее

  1. #include "msp430.h"
  2. #include "stdint.h"
  3. #include "adc.h"
  4.  
  5. void ADC_init_intref_repeating(uint16_t *buffer,uint16_t samples_cnt)
  6. // Эта функция инициализирует АЦП. Параметры --- адрес массива,
  7. // где будут храниться результаты преобразования и его длина
  8. {
  9. ADC10CTL0 &= ~ENC; // Остановим АЦП
  10. ADC10CTL0 = MSC + // Многократные выборки
  11. SREF_1 + // АЦП работает от внутреннего источник
  12. // образцового напряжения (ИОН)
  13. ADC10SHT_2 + // параметры быстродействия АЦП
  14. REF2_5V + // Напряжение ИОН VREF=2.5V
  15. REFON + // Включим ИОН
  16. ADC10ON; // Включим АЦП
  17. ADC10CTL1 = INCH_5 + // Выбираем 5-й канал - ножку P1.5
  18. SHS_0 +
  19. ADC10SSEL_0 + // Источник тактирования АЦП = SMCLK
  20. ADC10DIV_0 + // Без предделителя
  21. CONSEQ_2; // Переводим АЦП в многократный одноканальный режим
  22. ADC10AE0 = BIT5; // Переводим ножку P1.5 в режим аналогового входа
  23. ADC10DTC0 = ADC10CT; // Настройка DMA
  24. ADC10DTC1 = samples_cnt; // Длина массива
  25. while (ADC10CTL1&BUSY);
  26. ADC10SA = (int) buffer; // Стартовый адрес
  27. ADC10CTL0 |=ENC + ADC10SC; // Запускаем АЦП
  28. }
А это файл adc.h:
  1. #ifndef ADC_H
  2. #define ADC_H
  3.  
  4. #include "stdint.h"
  5.  
  6. void ADC_init_intref_repeating(uint16_t *adc,uint16_t samples_cnt);
  7.  
  8. #endif
Не забываем добавить эти файлы в Makefile, иначе ничего не скомпилируется.

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

  1. #define SAMPLES_CNT 16
  2.  
  3. uint16_t adc[SAMPLES_CNT];

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

  1.  
  2. ADC_init_intref_repeating(adc,SAMPLES_CNT);
  3.  

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

  1. void uart_rx_isr(unsigned char c)
  2. {
  3. uint16_t mV=0; // Volatge in mV
  4. uint32_t adc_avg=0; // ADC average
  5. int i=0;
  6.  
  7. switch (c) {
  8. case '1': P1OUT ^=LED_RED;
  9. uart_puts("Red led toggled\n");
  10. break;
  11. case '2': P1OUT ^= LED_GREEN;
  12. uart_puts("Green led toggled\n");
  13. break;
  14. case '3': adc_avg=0;
  15. for (i=0;i < SAMPLES_CNT;i++) { // Выполним усреднение
  16. adc_avg += adc[i]; // Просуммируем все элементы массива
  17. }
  18. adc_avg /= SAMPLES_CNT; // И разделим сумму
  19. // на количество элементов
  20. mV = (adc_avg*2500)/1024; // Рассчитаем напряжение
  21. printf("P1.5 pin voltage = %d mV\n",mV);
  22. // Печатаем напряжение в UART
  23. break;
  24. default: uart_putc(c);
  25. break;
  26. }
  27. }

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

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

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