Мониторинг напряжения аккумулятора на микроконтроллере STM32.

Приветствую всех на нашем сайте! Сегодня, в продолжение предыдущей статьи, мы реализуем еще один похожий проект. А именно решим задачу измерения напряжения аккумулятора, питающего всю схему, на микроконтроллере STM32.

И для начала рассмотрим типичную схему организации питания:

Схема питания микроконтроллера

Здесь напряжение с аккумулятора приходит на вход преобразователя, который обеспечивает на выходе 3.3 В для питания нашего микроконтроллера. С аккумулятора, если мы говорим о наиболее часто использующихся литий-полимерных (Li-Pol), будет приходить 2.8 – 3.7 В в зависимости от уровня заряда. Нижний порог будет зависеть от использующейся схемы защиты аккумулятора от глубокого разряда, обычно эта схема отключает батарею при напряжениях 2.8 – 3 В.

В целом, мы получаем следующее – нам необходимо обеспечить измерение напряжений от 2.8 до 3.7 В. Поскольку питание микроконтроллера – 3.3 В, то мы не можем подать на вход АЦП 3.7 В напрямую. Что же, используем простейший делитель:

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

Казалось бы, на этом и все, но нужно учесть еще один нюанс. При использовании самого обычного LDO-преобразователя (в данном случае MIC5504) на его выходе будет напряжение:

V_{OUT} = \begin{cases} 3.3 \medspace В &\text{если } V_{IN} \medspace – \medspace V_{DO} \geqslant 3.3 \medspace В \\ V_{IN} \medspace – \medspace V_{DO} &\text{если } V_{IN} \medspace – \medspace V_{DO} \lt 3.3 \medspace В \end{cases}

Здесь V_{DO} – это напряжение, падающее непосредственно на самом преобразователе. Для нашей микросхемы:

Dropout voltage.

То есть если на входе у нас достаточный уровень сигнала (V_{IN} \medspace – \medspace V_{DO} \geqslant 3.3 \medspace В), то микросхема обеспечит нам железные 3.3 В на выходе, что нас полностью устраивает.

Но по мере разряда аккумулятора напряжение будет естественным образом падать, что приведет к тому, что на выходе MIC5504 уже не будет этих 3.3 В. Уровень будет ниже. И это, как мы обсуждали в предыдущей статье, приведет к тому, что измеренное напряжение (после делителя) уже не будет верным.

Вот по этой причине нам и нужно предпринять дополнительные действия, чтобы обеспечить корректность измерений. А действия эти заключаются в том, что мы снова используем внутренний источник опорного напряжения STM32, который аппаратно заведен на 17-й канал ADC1!

Алгоритм действий будет таким:

  • Определяем реальный уровень напряжения питания микроконтроллера по формуле:
V_{пит} = \frac{4095}{{ADC}_{изм \medspace пит}} * 1.2 В
  • И, следующим шагом, зная точное значение V_{пит}, ничего нам не мешает рассчитать верное значение напряжения аккумулятора:
V_{акк} = 2 * \frac{{ADC}_{изм \medspace акк}}{4095} \medspace * \medspace V_{пит}

Здесь мы умножаем на 2 потому что на вход АЦП сигнал подается через делитель 1:2.

Итак, разобрали теорию и план действий, переходим к практической реализации! Подключим напряжение с делителя на 1-й канал ADC1 (PA1).

Переходим в STM32CubeMx и настраиваем нужные каналы ADC, а также активируем DMA. АЦП будет постоянно автоматически опрашивать входные каналы, а результат будет сохраняться в буфер при помощи ДМА:

STM32CubeMx ADC.
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;
float batteryVoltage = 0;
uint16_t adcData[2];

/* USER CODE END PV */

После инициализации всей периферии запускаем АЦП:

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcData, 2);

/* USER CODE END 2 */

После чего в цикле while(1) нам остается только производить расчеты:

/* Infinite loop *//* USER CODE BEGIN WHILE */
while (1)
{
	/* USER CODE END WHILE */

	/* USER CODE BEGIN 3 */
	mcuVoltage = ADC_MAX * ADC_REFERENCE_VOLTAGE / adcData[0];
	batteryVoltage = 2 * adcData[1] * mcuVoltage / ADC_MAX;
}
/* USER CODE END 3 */

Теперь в переменных mcuVoltage и batteryVoltage у нас будут соответственно значения напряжений питания и аккумулятора. Наша цель достигнута, и на этом на сегодня все, спасибо за внимание и до скорых встреч!

Ссылка на полный проект – MT_BatteryMeasurement.

Поделиться!

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

Спасибо.

Алексей
Алексей
5 дней назад

Спасибо! Полезная информация. Применил на практике))

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

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Ноябрь 2020
Пн Вт Ср Чт Пт Сб Вс
 1
2345678
9101112131415
16171819202122
23242526272829
30  

© 2013-2020 MicroTechnics.ru