Мониторинг напряжения аккумулятора на микроконтроллере 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
1 Комментарий
старее
новее большинство голосов
Inline Feedbacks
View all comments
Павел
Павел
12 часов назад

Спасибо.

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

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Сентябрь 2020
Пн Вт Ср Чт Пт Сб Вс
 123456
78910111213
14151617181920
21222324252627
282930  

© 2013-2020 MicroTechnics.ru