Измерение напряжения питания микроконтроллера 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
17 комментариев
старее
новее большинство голосов
Inline Feedbacks
View all comments
Алексей
Алексей
7 месяцев назад

Спасибо!

К....
К....
6 дней назад

Не могу понять где указывается что в adcData нужно положить именно значение с Vrefint Chanel. И как быть если например, я хочу считывать значение с IN1 и Vrefint Chanel?

К....
К....
Reply to  Aveal
6 дней назад

Спасибо! 🙂

К....
К....
4 дней назад

Будет ли статья на тему фильтрации сигнала перед АЦП? Только не голая теория, которой и так полно. А именно реализация, подбор компонентов фильтра, подключение, сравнение сигнала с фильтром и без. Думаю многим было бы интересно.

К....
К....
Reply to  Aveal
4 дней назад

Да. Хотя бы, что бы иметь представление как построить простейший ФНЧ перед входом АЦП. На одной софтовой фильтрации далеко не уедешь. Бегущее среднее, среднее арифметическое, скользящее среднее не дают желаемого результата)

К....
К....
Reply to  Aveal
4 дней назад

Значит я определённо что то делаю не так) Пытаюсь подружить STM32F103 с датчиком тока ACS758-100B. Датчик тока запитан от источника опорного напряжения REF198(4.096 Вольта). REF198 запитан от отладочной платы с контроллером. “Минус” соответственно общий. При отсутствии тока на датчике, он должен выдавать половину своего напряжения питания. Т.е. 2.048 В. Мультиметр показывает стабильные 2.047 В. Но на АЦП STM32F103 показания прыгают. Что при пересчёте в напряжение приводит к скачкам в районе десятков мВольт. А учитывая что у датчика 20мВна ампер, это очень много. Как я понимаю, мультиметр показывает максимально близкое к расчётному напряжение благодаря хорошему фильтру на входе своего АЦП и грамотной программной обработке.

К....
К....
Reply to  Aveal
4 дней назад

Это был последний способ програмной фильтрации, после которого я понял что нужен аппаратный фильтр) Значение напряжения на входе АЦП прыгают от 2.04 до 2.09.

К....
К....
Reply to  К....
4 дней назад

Подключил осциллограф и призадумался… Пульсации на выходе источника опорного напряжения +-0.4 В. Соответственно и на выходе датчика та же картина. Напряжение 3.3 В и 5 В на отладочной плате идеальные, по сравнению с ИОНом…

К....
К....
Reply to  Aveal
14 часов назад

Взял другой ИОН. Значение АЦП перестало скакать. Только начал думать о том как дальше работать с полученными данными… Как датчик тока отказал. Или датчик такой же как ИОН бракованный, или коротнул его выход на минус. Жду новый датчик)

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

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Март 2021
Пн Вт Ср Чт Пт Сб Вс
1234567
891011121314
15161718192021
22232425262728
293031  

© 2013-2020 MicroTechnics.ru