Top.Mail.Ru

Измерение напряжения питания микроконтроллера 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

27 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Алексей
Алексей
4 лет назад

Спасибо!

К....
К....
3 лет назад

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

К....
К....
Ответ на комментарий  Aveal
3 лет назад

Спасибо! 🙂

К....
К....
3 лет назад

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

К....
К....
Ответ на комментарий  Aveal
3 лет назад

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

К....
К....
Ответ на комментарий  Aveal
3 лет назад

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

К....
К....
Ответ на комментарий  Aveal
3 лет назад

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

К....
К....
Ответ на комментарий  К....
3 лет назад

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

К....
К....
Ответ на комментарий  Aveal
3 лет назад

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

Валерий
Валерий
8 дней назад

То есть так как значение adcData в Вашей формуле в знаменателе то чем больше считанное с канала значение adcData тем меньше будет значение mcuVoltage? А если повесить вход на землю, что покажет Ваша программа?

Валерий
Валерий
Ответ на комментарий  Aveal
8 дней назад

Спасибо за ответ! По невнимательности увидел только, что на картинке где выбираются каналы в CubeMX стоят галки напротив IN1 и Vrefint, а далее HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adcData, 1); вроде как передается один канал, подумал на IN1. К сожалению " Полный проект -  MT_SupplyVoltageMeasurement ." у меня не распаковывается.

bezymyannyj
Макс
Макс
3 дней назад

вот в этом месте мк зависает наглухо у меня...

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adcData, 1);
Макс
Макс
Ответ на комментарий  Aveal
2 дней назад

Пробую, пока не получается. Попробовал скачать ваш проект, указал папку для открытия, попробовал построить - почему-то куб в вашем проекте не видит взаимосвязи файлов, те, например, не видит заголовочные файлы, так и пишет - "не вижу main.h". У меня 15й, при открытии что-то спросил про совместимость версий, я нажал "Migrate". Без использования dma как-то заработало

Макс
Макс
Ответ на комментарий  Aveal
21 часов назад

вроде cube, там ещё файл конфигурационный открылся, я даже проверил галочки, как в статье выше) Попробую пересобрать

27
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x