Измерение тока STM32 АЦП HAL (шунт, дифференциальный усилитель)
Принцип работы (измерения)
Последовательно с нагрузкой включаем сопротивление малой величины.
Таким образом протекающий ток через Rload и Rsense будет одинаковый (здесь 690 мА), при этом зная сопротивление резистора-шунта Rsense = 0.1 Ом и измерив напряжение на нем (Usense = 0.069 В) можно легко вычислить протекающий через цепь ток:
I = Usense/Rshunt = 0.069/0.1 = 0.69 А = 690 мА
А теперь испытания на макетной плате, лампа накала в качестве нагрузки Rload (ИСКРА 13,5 В), низкоомный резистор Rsense 3.3 Ом 10 Вт.
Берем вольтметр и измеряем напряжение на резисторе.
Итак, падение на нем Usense = 0.2757 В. Вычисляем ток
I = Usense/Rshunt = 0.2757/3.3 = 0.08354 А = 83.54 мА
Учитывая неточность резистора, всё отлично, почти такой же, как показывает мультиметр ( ламповый блок питания показывает неправильно!).
Выбор шунта
- малое сопротивление (чтобы уменьшить потери и вносимое влияние)
- высокая точность сопротивления
- малый ТКС (чтобы сопротивление мало изменялось при изменении температуры)
Схема
Понятно, что при маленьком значении сопротивления Rsense будет падать и маленькое напряжение, а нам его еще и измерять, причем мы хотим получить диапазон от нуля то VCC (в данном случае от 0 В до 3.3 В), чтобы использовать все 12 разрядов внутреннего АЦП STM32.
В общем надо усилить сигнал в N раз. Применяем схему дифференциального (разностного, вычитающего) усилителя на операционном усилителе (питание однополярное).
Таким образом нам удастся усилить маленькое напряжение на Rsense, а напряжение на выходе будет определятся соотношениями сопротивления резисторов, при R1 = R3, R2 = R4:
U1 - напряжение на инвертирующем входе;
U1 - напряжение на неинвертирующем входе;
R2=R4 - сопротивление резистора;
R1=R3 - сопротивление резистора;
Выбор операционного усилителя
Нам нужен ОУ с низким напряжением питания (т.к. он будет жить вместе с МК на стабилизаторе 3.3 В), маленьким входным напряжением смещения (input offset voltage) и маленьким (как можно ближе к нулю) выходным напряжением низкого уровня.
LMV321
Смотрим на эту гадость, ну такое.
Проверим в бою. На входе Usense = 100 мВ (падение на шунте):
При R1 = R3 = 1 кОм, R2 = R4 = 10 кОм, допуск резисторов 1% (также отобрал вручную самые точные), таким образом на выходе должно быть Usense*10 = 100 мВ*10 = 1000 мВ = 1 В (выражение выше):
Хорошо, усиление в 10 раз сработало отлично!
Помня про высокое значение выходного напряжения низкого уровня замыкаем шунт (на входе ноль), а на выходе:
Ой, нифига себе, примерно 80 мВ (собственно как и написано в документации). Нам такого не нужно, ведь тогда не удастся измерять малые токи.
Но, выходное напряжение высокого уровня действительно почти равно питающему, то есть чуть ниже 3.3В и по сути будет отличаться на 100 мВ максимум.
LM358
Сравнивая с предыдущим у этого выходное напряжение низкого уровня будет около 5 мВ, вот это уже неплохо.
После замены ОУ на макетке измеряем напряжение на выходе при нуле на входах.
Неплохо, даже ниже обычного, то что нужно!
А теперь проверим выходное напряжение высокого уровня (питание 3.3 В):
И еще раз, но при питании 5 В:
Вот это печально. Выход ниже на более чем вольт по сравнению с напряжением питания, то есть использовать этот ОУ в схемах с низким
Uпит не советую, ведь тогда будут полезными (использоваться) не 12 разрядов АЦП, а в данном случае всего чуть более 7-бит! (исп. от 30.10.2021)
MCP6002
Приобрел ОУ MCP6002 в SOIC-8 от Micropchip.
Здесь выходное напряжение (Voltage Swing) мин 25 мВ, на деле оказалось около 7 мВ, вот эта микросхема и будет использована!
Не забудь добавить фильтр!
Настоятельно советую отфильтровать измеряемый сигнал перед подачей на АЦП простейший фильтр нижних частот (ФНЧ) в виде последовательно соединённых резистора и конденсатора ( как работает можно глянуть здесь). Также дополнительно советую использовать программный цифровой фильтр среднего скользящего.
Для использований общего назначения обычно ставят:
R = 10 - 100 Ом
C = 100 нФ - 1000 нФ
Сборка схемы на макетной плате
Создание проекта в STM32CubeIDE
Новый проект: New -> STM32 Project
Выбор МК: STM32F103C8T6
Имя проекта: Project Name: Current-Measeument-Shunt
Настройки тактирования по умолчанию (ничего не изменено):
Отладчик: SYS -> Debug: Serial Wire
Включение АЦП, Канал 0. Запуск от тригера Таймера 3:
ADC_Regular_ConversionMode: External Trigger Conversion Source
Во вкладке настройки ПДП (DMA):
Add: ADC1
Mode: Circular
Ну и
Таймер 3:
TIM3 -> Internal Clock
Prescaler: 800-1
Counter Period: 1000-1
Trigger Event Selection: Update Event
Ну и хватит!
Программирование
Массив из одного элемента для сырого значения с АЦП и вещественная переменная для напряжения, а также вспомогательная переменная:
/* USER CODE BEGIN PV */
/* adc variables */
uint16_t ADC_Raw[1];
float Current;
uint8_t sch_adc = 0;
/* USER CODE END PV */
Запуск АЦП с ПДП, ну и потом таймер, который будет производить запуск 10 раз/с:
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Raw, 1);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
В функции обратного вызова переменная устанавливается равной 255, то есть положительное значение:
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
sch_adc = 255;
}
/* USER CODE END 4 */
В главном цикле проверяется переменная sch_adc, если положительная, то рассчитывается значение тока (здесь в мА):
/* USER CODE BEGIN WHILE */
while (1)
{
if(sch_adc){
Current = ((ADC_Raw[0]/4095.0f))*100;
/* Nullify */
sch_adc = 0;
}
/* USER CODE END WHILE */
Испытание (отладка)
При отсутствии тока на выходе ненулевое значение. Его можно обнулять каждый раз при включении (учитывая что вначале нагрузка не должна быть подключена) или записать значение и потом вычитать из измеренного:
Точность неплохая и может быть лучше, потому что напряжение питание чуть ниже 3.3В и шунт-резистор использован неточный.
Особенности разводки платы
На рисунке ниже видно, что входы дифференциального усилителя хитро подключаются непосредственно к Rsense, ведь нам не нужны еще и падения на дорожках и соединениях.
Таким образом дорожки, идущие на вход по красоте ведем из середин, устраняя влияние сопротивлений дополнительных участков меди снимая падение именно с резистора-шунта.
Также здесь стоит обратить внимание на фильтрующий конденсатор 100 нФ, он подключен наиболее близко к ножкам GND-VCC и питание подведено сначала к нему.
Измерения без использования ОУ
В некоторых случаях для измерения малых токов, когда напряжение источника изменяется в широких пределах (и высокое падение на шунте не важно) можно оставить тупо резистор и измерять напряжение непосредственно на нем.
Примером может служить мой
тестер проверяльщик светодиодов, здесь нужно было измерять ток (0-100) мА, сначала хотел ставить шунт+ОУ, но из-за ограниченного напряжения питания и ненулевого выхода при нулевом токе схема была оптимизирована и упрощена вместе с решением проблемы измерения малых токов.
Готовые токоизмерительные усилители
Конечно существуют усилители с уже встроенными резисторами R1-R4, причем они имеет почти одинаковые параметры. К тому же мы экономим место на плате. Коэффициент усиления как-правило 20, 30, 50, но есть и такие, где он настраивается.
Самым подходящим я считаю решение INA180 от TI единственный недостаток - это низкая распространенность, ну и цена будет чутка выше.
Купить на Aliexpress
?️ ОУ MCP6002 DIP-8 10pcs (2.00?): https://ali.ski/AFO9Qp
Супер статья. Как раз собираюсь делать что-то подобное. Есть один вопрос: если неправильно подключить измерительные щупы от АЦП контроллера (перепутать "+" и "-"), он выйдет из строя? Направление течения тока ведь будет противоположное. Может, надо ставить защитный диод? Но на нем будет падение напряжения? Может есть еще варианты? Заранее спасибо за ответ!
Не должно выйти, там внутри есть защитные диоды.
Поставьте ОУ как дифференциальный усилитель.
А от высокого напряжения вполне можно убить канал.
У меня получилось напряжением где-то 5В-8В сжечь один из каналов АЦП
А вам лучше делать измерения тока в двух направлениях. То есть средней точкой будет 1.65В, при одной полярности напряжение будет 1.65В-3.3В, а при обратной 0В-1.65В. Такое легко сделать с помощью микросхемки INAxxx.
А почему ты для этих целей взял именно MCP6002, а не MCP6022?
Из rail-to-rail был именно этот доступнее для меня.
На практике практичнее использовать готовые токовые шунты INAxxx, скоро небольшой очерк по ним выйдет
О, это было бы очень круто! А то думаю заказывать с али, не знаю пока что. Пока сделал на доступных мне LM358 измерение тока. Но не нравится что с 0.06В ноль показывает. Как я понял это как раз связано с rail-to-rail характеристикой.
Опубликовал
Это норма, попробуйте делать измерения со средней точкой.
@Выход ниже на более чем вольт по сравнению с напряжением питанием, то есть использовать этот ОУ в схемах с низким Uпит не советую, ведь тогда будут полезными (использоваться) не 12 разрядов АЦП, а в данном случае всего чуть более 7-бит!@
это не совсем верно ..
просто вместо диапазона кодов 3-4095 от 0.003 до 3.3
будет доступно например 3-2854 от 0.003 до 2.3 вольт
… потеря до 40 % динамического диапазона но это ж не 7 бит.
Здравствуйте. Мне статья во многом помогла разобраться но у меня не работали преобразования большее 1 цикла. Пока я не установил настройки вот так:
DMA continuous Requests Enable
Долго ломал голову почему у меня не работало. Повторяю проект на STM32F411CEU6 или же в простонароде black pill.
У меня тоже есть такая платка:
https://cxemka.com/43-plata-razrabotchika-minif4-n...
B это действительно так, для f4xx отличаются настройки несколько, проверил у себя в другом проекте:
Не сочтите за нахальство — можно получить принципиальную схему, разобраться с
макеткой не смог.
спасибо
Как-то так там было