Сегодня, в продолжение предыдущей статьи, мы реализуем еще один похожий проект. А именно решим задачу измерения напряжения аккумулятора, питающего всю схему, на микроконтроллере 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} - это напряжение, падающее непосредственно на самом преобразователе. Для нашей микросхемы:
То есть если на входе у нас достаточный уровень сигнала (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. АЦП будет постоянно опрашивать входные каналы, а результат будет сохраняться в буфер при помощи ДМА:
После всех настроек генерируем и открываем проект. Объявляем все, что нам понадобится:
/* 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.
Спасибо.
Спасибо! Полезная информация. Применил на практике))
Отлично =)
Через делитель постоянно течёт ток и сажает батарейку? в случае небольших емкостей может быть неприятностью
Да, все верно. Но величина незначительная - 35 мкА. Если требования очень жесткие, и даже такая утечка недопустима, то тогда ключ ставится - открывается во время замера, затем закрывается.
Допустим требования жесткие да. Была задача разработки ПДУ с ограниченным размером, предполагалось что зарядка раз в один-два месяца...
вы имеете ввиду допустим n-канальный полевой ключ для подключения R2 на землю? тогда при отключении ключа все напряжение батареи в 4.2 вольта пойдет на вход, судя по даташиту на f103 допустим входы АЦП не толерантны к 5В. Если только если p - канал перед R1, закрыться впринципе должен от 3.3в. Если не верно рассуждаю поправьте)
Все снова верно ) Если не толерантны, тогда такой вариант.
Спасибо , тоже думал об этом , только заместо биполяра тот же n канальный полевик тоже норм )
Можно, просто чаще всего полевик дороже выйдет )
Вопрос для повышения уровня образованности: А для чего конденсатор ?