Измерение напряжения питания микроконтроллера STM32.

При работе с микроконтроллером порой возникает ситуация, когда необходимо измерить напряжение питания. Например, это может понадобиться при анализе процессов заряда и разряда аккумулятора, который питает всю схему. Либо если мы хотим скорректировать наши измерения АЦП, то тут не обойтись без знания точного значения питающего напряжения.

И, казалось бы, что может быть проще – берем один канал АЦП и спокойно замеряем. Но нельзя упускать из виду один ключевой момент. И заключается он в том, что в качестве опорного используется чаще всего именно напряжение питания. Конечно, можно использовать выводы V_{REF+} и V_{REF-} для того, чтобы подавать опорное напряжение на микроконтроллер отдельно. Но эти выводы есть далеко не у всех контроллеров, тем более если говорить о экземплярах в корпусах с небольшим количеством выводов.

А к чему это все приведет при измерении напряжения питания? А к тому, что на выходе АЦП мы всегда будем иметь одно и то же значение, равное 0xFFF (максимальное значение для 12-ти битного аналого-цифрового преобразователя), поскольку сигнал на входе АЦП будет равен опорному напряжению.

К счастью, эта ситуация далеко не безвыходная!

В микроконтроллерах от ST есть свой собственный внутренний источник опорного напряжения. Его величина составляет примерно 1.2 В. К примеру, для микроконтроллера STM32F103C8T6:

Измерение напряжения питания.

Кроме того, для некоторых контроллеров это значения измерено на заводе и сохранено в специальный регистр, из которого его можно прочитать. Возьмем, к примеру, STM32F030x4/x6/x8/xC. Для них это калибровочное значение находится в регистре VREFINT_CAL:

Калибровочное значение VREFINT в STM32.

Аналогично, для STM32F303:

Регистр VREFINT_CAL.

Наш же сегодняшний герой – STM32F103C8, как и, в целом, контроллеры семейства STM32F10x, этих данных не хранит. Поэтому мы будем использовать стандартное значение, указанное в даташите и равное 1.2 В. Также и контроллеры STM32F4x этой опции не имеют, в отличие от F0 и F3. В общем, при использовании конкретного микроконтроллера информацию об этом регистре можно найти в документации. Только не в reference manual на семейство, а именно в даташите на выбранный контроллер.

Итак, с этим все понятно. Давайте разберемся, как нам поможет это внутреннее напряжение в решении нашей задачи. Идея заключается в следующем…

Напряжение V_{REFINT} с этого источника опорного напряжения заведено аппаратно на один из каналов АЦП, а именно на 17-й канал ADC1. То есть мы можем в любой момент его измерить. И по полученному значению определить, чему равно в данным момент напряжение питания. Зависимость будет выглядеть следующим образом:

V_{пит} = \frac{4095}{{ADC}_{изм}} * 1.2 В

Здесь 4095 – это максимальное значение АЦП. Эта формула вытекает из пропорции:

\begin{matrix} 1.2 В & \implies & {ADC}_{изм} \\ V_{пит} & \implies & 4095 \end{matrix}

Конечно же, нельзя обойтись без реального практического примера, чем и займемся 🙂 Будем опрашивать этот канал АЦП (ADC1_IN17) и анализировать измеренное значение. Для этого включаем модуль ADC1 и нужный нам канал:

Настройка канала АЦП в STM32CubeMx.

Кроме того, сделаем этот процесс максимально автономным. И тут, естественно, нам поможет DMA, настраиваем АЦП и ДМА на постоянный опрос:

Постоянные непрерывные преобразования АЦП.
Настройка DMA в STM32CubeMx.

В программе нам нужно будет один раз запустить измерение и в дальнейшем DMA автоматически будет обновлять значение в переменной без участия процессора.

Генерируем проект и переходим к редактированию кода. Первым делом, добавим пару переменных и дефайнов:

/* USER CODE BEGIN PD */
#define ADC_REFERENCE_VOLTAGE                                           1.2
#define ADC_MAX                                                         0xFFF

/* USER CODE END PD */

/* USER CODE BEGIN PV */
float mcuVoltage = 0;
uint16_t adcData = 0;

/* USER CODE END PV */

В adcData будем сохранять результат аналого-цифрового преобразования, а в переменной mcuVoltage уже значение напряжения питания в Вольтах. Запускаем АЦП, добавив вызов функции калибровки:

/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adcData, 1);

/* USER CODE END 2 */

А в main() в цикле while(1) рассчитываем требуемое значение:

mcuVoltage = ADC_MAX * ADC_REFERENCE_VOLTAGE / adcData;

Вот и все! Запускаем отладчик и проверяем полученное значение:

Точное значение напряжения питания.

Все соответствует действительности!

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

Полный проект – MT_SupplyVoltageMeasurement.

Поделиться!

Подписаться
Уведомление о
guest
2 Комментарий
старее
новее большинство голосов
Inline Feedbacks
View all comments
Алексей
Алексей
19 часов назад

Спасибо!

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Август 2020
Пн Вт Ср Чт Пт Сб Вс
 12
3456789
10111213141516
17181920212223
24252627282930
31  

© 2013-2020 MicroTechnics.ru