STM32 и ввод аналоговых сигналов: АЦП/ADC

В микроконтроллерах STM32 есть мощный модуль АЦП, который имеет действительно хорошие характеристики и интересные особенности:

  • 18 каналов ввода (16 внешних и 2 внутренних)
  • разрешение 12 бит
  • всевозможные режимы преобразования:
    1. однократное
    2. непрерывное
    3. по триггеру
    4. по таймеру
  • удобное выравнивание битов результата
  • конечно же, генерирование всевозможных прерываний и сигналов для DMA
  • скорость оцифровки — до 0.9 MSPS с программируемым временем захвата и преобразования
  • автокалибровка
  • режим сканирования входов по списку
  • аналоговый вотчдог

Необходимость в этом модуле возникает часто: просто потому, что природа вокруг нас не дискретна, а непрерывна, и всевозможные датчики обычно выдают именно аналоговый сигнал. Особенно это касается звука, но точно так же можно сделать и, к примеру, осциллограф: популярный китайский USB-осциллограф DSO Nano сделан именно на STM32F103.

Внутреннее строение

adc

Измерение и опорные напряжения

Принцип оцифровки очень прост: входное напряжение сравнивается с опорными напряжениями V_REF- и V_REF+:

  • V_REF- нужно подключить к земле
  • V_REF+ по желанию: либо к питанию процессора (оно плавающее и шумное, поэтому этот вариант годится только для неточных измерений), либо к внешнему источнику опорного напряжения (ИОН)

Впрочем, есть возможность программно настроить эти ноги на прямое соединение с землёй и питанием.

Входное напряжение V_In будет измерено относительно V_REF- и V_REF+, и результат преобразования сложен в выходной регистр в такой пропорции:

Напряжение Результат
V_Ref-
V_In V_In / (V_Ref+ — V_Ref-) * 4096
V_Ref+ 4096

К примеру, 1.2 В при питании АЦП от 3.3 В преобразуются в 1490.

Регистры АЦП в STM32

SR — регистр статуса

0 бит: флаг AWD (Analog WatchDog). Входной сигнал пересёк значения регистров LTR или HTR.

1 бит: флаг EOC (End Of Conversion). После окончания преобразования переключается в 1. Сбрасывается вручную или при чтении регистра DR.

4 бит: флаг STRT (Start). Сигнализирует о начале преобразования.

CR1 — первый регистр настроек

0..4 биты: значение AWDCH (Analog WatchDog Channel). Задаёт номер канала для слежения вотчдогом.

5 бит: EOCIE (End Of Conversion Interrupt Enable). Включает прерывание по окончанию преобразования.

6 бит: AWDIE (Analog WatchDog Interrupt Enable). Включает прерывание по срабатыванию аналогового вотчдога.

7 бит: JEOCIE.

8 бит: SCAN. Включает режим сканирования каналов по списку в регистрах SQR1, SQR2, SQR3.

9 бит: AWDSGL (Analog WatchDog Single). Задаёт тип срабатывания вотчдога в режиме SCAN: на один канал (1) или на все (0).

10 бит: JAUTO.

11 бит: DISCEN (Discontinious mode Enabled). Включает «рваный» режим работы — АЦП включается по внешнему триггеру.

12 бит: JDISCEN.

13..15 биты: DISCNUM (Discontinious mode Number of channels). Количество каналов для преобразования в «рваном» режиме.

16..19 биты: DUALMOD (Dual Mode selection). Задаёт режим совместной работы двух АЦП.

22 бит: JAWDEN.

23 бит: AWDEN (Analog WatchDog Enabled). Включает аналоговый вотчдог.

CR2 — второй регистр настроек

0 бит: ADON (Analog/Digital converter On/off). Включает АЦП.

1 бит: CONT (Continious coversion). Включает режим однократного (0) или зацикленных измерений (1).

2 бит: CAL (Calibration). Установка в 1 включает калибровку; после окончания калибровки сбрасывается в 0. Сначала нужно сбросить регистры.

3 бит: RSTCAL (Reset Calibration). Сброс регистров калибровки, точно так же устанавливаем в 1 и ждём сброса.

8 бит: DMA. Включает DMA.

11 бит: ALIGN. Выравнивает данные по правому (0) или левому (1) краю регистра.

12..14 бит: JEXTSEL.

15 бит: JEXTTRIG.

17..19 бит: EXTSEL (External event Select). Назначает номер события для запуска (TIM1 CC1, TIM1 CC2, TIM1 CC3, TIM1 CC4, TIM3 TRGO, TIM4 CC4, EXTI_11, SWSTART).

20 бит: EXTTRIG (External Trigger). Включает запуск преобразования по внешнему триггеру.

21 бит: JSWSTART.

22 бит: SWSTART (Start conversion). Запускает преобразование. После окончания сбрасывается.

23 бит: TSVREFE (Temp sensor and V_REF Enabled). Включает температурный сенсор и внутренний ИОН.

DR — регистр результата измерения

SMPR1, SMPR2 — время преобразования

Регистр настройки времени преобразования для каждого канала.

HTR и LTR — пределы вотчдога

Верхний и нижний пределы для аналогового вотчдога, аналогичны регистру DR.

SQR1, SQR2, SQR3 — список каналов для сканирования

Режим SCAN (бит SCAN в регистре CR1)

Практика: включаем АЦП

Самый простой случай использования АЦП: без прерываний, без всяких сложных режимов — просто берём и измеряем в цикле.

Инициализация

  1. Включаем тактирование модуля АЦП
  2. Настраиваем параметры модуля
  3. Включаем модуль АЦП
  4. Настраиваем вход (номер канала АЦП)
  5. Проводим калибровку

Я исхожу из того, что ножки кристалла не настроены, то есть находятся в дефолтном состоянии «аналоговый вход». Именно этот режим нам и нужен.

Только некоторые ноги STM32 могут работать в качестве входа АЦП, они обозначены символом ANx (x = 0..15, эта цифра — номер канала). Это удобно прикидывать в программе STM32Cube.

void adc_init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

// настройки ADC
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // режим работы - одиночный, независимый
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // не сканировать каналы, просто измерить один канал
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // однократное измерение
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // без внешнего триггера
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //выравнивание битов результат - прижать вправо
ADC_InitStructure.ADC_NbrOfChannel = 1; //количество каналов - одна штука
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);

// настройка канала
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_55Cycles5);

// калибровка АЦП
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
}

После выполнения этой функции АЦП1 настроен, откалиброван и готов к измерениям на восьмом канале.

Измерение

Измерение производится просто:

  1. Запускаем преобразование
  2. Ожидаем окончания оцифровки (проверяем флаг EOC = End Of Conversion)
  3. Читаем результат из регистра DR
uint16_t get_adc_value()
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}

Самое простое использование этих функций:

void main()
{
adc_init();
uint16_t value = 0;
while(1)
value = get_adc_value();
}

Можно просто запустить программу, остановить её брейкпойнтом и прочитать в отладчике измеренное значение.

Ссылка на основную публикацию