Измерение тока в одном/двух направлениях с помощью токового сенсора INA181

Вступление
В очерке про измерение постоянного тока было рассмотрено использование ОУ в качестве усилителя разности (дифференциального) напряжения на сопротивлении-шунте, что требовало прибор с выходными напряжениями близкими к нулю и питанию, а также точные резисторы для задания коэффициента усиления.
Всё это занимает много места на плате и времени разработки и для большинства применений (измерения тока) будет достаточно и лучше использовать одну маленькую микросхемку – токовый датчик (сенсор).
Новый датчик
Одноканальный датчик INA180/INA181 (а есть и многоканальные) представляет собой усилитель в корпусе SOT-23-6, где множитель (КУ) уже точно задан с помощью внутренних резисторов.

Коэффициент усиления (GAIN) может быть разным, у меня это 50 раз:
Назначение выводов
Если измерение тока производится только в одном направлении, то вывод REF нужно подключить в GND. Напряжение питание микросхемы 2.7V-5.5V.
Купить на Aliexpress
?️ INA180 (от 0.4?): https://ali.ski/ZxvXJ
?️ INA219 I²C (от 2.4?): https://ali.ski/rH9I3
?️ STM32F401 Module (3.50?): https://ali.ski/T9_RBe
?️ STM32F401 Black Pill USB C (3.88?): https://ali.ski/wvygW
?️ STM32F401 DevBoard Type-C (3.46?): https://ali.ski/SvrJ8d
Подключение
Пример для измерения тока в положительном полюсе (токосъемный резистор SHUNT подключен к плюсу, таким образом нагрузка заземлена):
Макетная плата для первые испытания

Сопротивление шунта
Шунт использован на с сопротивлением 2 Ом, поэтому измерять будем маленькие токи, а учитывая что усиление моей микры INA181A2 равно 50 (GAIN (Vout/Vin)), то при питании от 3.3В наибольший возможный для измерения ток:
Imax = UVS/(Rsh*GAIN) = 3.3/(2*50) = 0.033 A = 33 mA
Усиление напряжения на шунте в 50 раз
Слева видим падение на резисторе Ush = 31.3 mV. Учитывая, что моя МС усиливает в 50 раз, имеем:
Uout = Ush*GAIN = 31.350 = 1565 mV = 1.56 V

Расчет протекающего тока
Учитывая, что сопротивление резистора на котором измеряется падение напряжения
Rsh = 2 Ом, выходное напряжение с микросхемы Uout = 1.56В (измеряется микроконтроллером) и усиление GAIN = 50 можем легко рассчитать ток (что и нужно было
):
I = Ush/Rsh = (Uout/50)/Rsh = 0.0156 A = 15.6 mA
Выходное напряжение при почти нулевом входном
При почти нулевом входном сигнале в схеме для измерения тока в положительном полюсе и питании от 16В на выходе имеем 9.2 мВ.

Учитывая, что приложенное напряжение 16В измеренное значение почти идеально совпало с предоставленной информацией на графике в документации:
Чтобы получить как можно меньшее значение на на выходе нужно использовать схему для измерения в отрицательном полюсе.
Наибольшее выходное напряжение при UVS=3.3V
Почти соответствует напряжению питания.
Настройка АЦП в STM32CubeIDE
Плата, которая здесь применяется известная уже всем, это новая черная пилюля с STM32F401CC:

Она является сейчас наиболее доступной на ранке и при этом имеет отличную цену и современные компоненты вместе с разъемом USB Type-C.

Новый проект, выбор МК и любое название, включить отладчик:

Выбрать внешний резонатор и частоту 84 МГц:

Врубаем используемый АЦП и переходим на вкладку ПДП и делаем настройку на циклический режим (Circular):

А в настройках включаем режим постоянных преобразований и разрешаем постоянные запросы ПДП. Время преобразования ставим наибольшее:

Готово! Переходим к коду

Создадим глобальный массив из одного элемента:
/* USER CODE BEGIN PV */
uint16_t AdcRaw[1];
/* USER CODE END PV */
Перед главным циклом запускаем АЦП и ПДП, складываем данные в нулевой элемент массива AdcRaw, количество каналов 1 (также на некоторых МК перед запуском нужно выполнить калибровку фцнкцией HAL_ADC_Calib...):
/* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)AdcRaw, 1);
/* USER CODE END 2 */
Важно! Если у вас еще где-нибудь использован прямой доступ к памяти и установлено маленькой время преобразования (в настройках АЦП), то это может сломать остальные задачи.
На этом этапе можно проверить, что АЦП успешно работает, зайдя в режим отладки ( Debug -> Run) и добавив AdcRaw[0] в окно Live Expressions (поиск Ctrl + 3):

Также можно притянуть вывод A0 (это если канал 0) к минусу и увидеть 0 или к плюсу для 4095 (АЦП 12-ти разрядный).
Для удобства делаю ряд определений:
/* ADC BEGIN */
#define ADCCORR 3U /* U - unsigned int (uint16_t) */
#define MULTIPLY 50.0f /* f - float */
#define ADCMAX 4095.0f
#define SHUNT 0.01f
#define ADCREF 3.3f
#define ADCMEAN 2048U
/* ADC END */
В функции обратного вызова по окончанию преобразования выставляю флаг:
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
AdcFlag = 255;
}
/* USER CODE END 4 */
В главном цикле проверяю флаг, если он положительный (было осуществлено преобразование), то выполняю расчеты и обнуляю флаг:
/* USER CODE BEGIN WHILE */
while (1)
{
if(AdcFlag)
{
AdcVol = (((float)(AdcRaw[0])/ADCMAX)*ADCREF);
AdcCur = AdcVol/(MULTIPLY*SHUNT);
/* Nullify */
AdcFlag = 0;
}
/* USER CODE END WHILE */
Теперь расчет нового значения будет производится только после выполненного преобразования.
Испытание
После добавления нужных глобальных переменных и запуска программы получаем результат:

Сравним с прецизионным измерительным прибором


Довольно неплохо. Показания прыгают вокруг того же значения, которое показывает мультиметр.
Измерение тока в отрицательном полюсе
Самым распространенным способом является включение использующегося для измерения тока сопротивления между минусом питания и нагрузкой.
Измерение тока в положительном полюсе
Собственно это та схема, которая и была мною использована.
Потом подключил другой шунт, чтобы измерять большие токи:

Схема для измерения тока в двух направлениях
Наличие входа для опорного напряжения ( Reference) дает возможность использовать микросхему для измерения тока в разных направления (bidirectional). То есть, если UVS = 3.3В, то на REF можно подать половину 1.65В, таким образом при протекании тока в одном направлении напряжение будет увеличиваться, а если, в обратном то уменьшаться (и это относительно средней точки).
По схеме выше видео, что кроме делителя советуют ставить неинвертирующий повторитель на ОУ, для проверки обойдусь без него. В схеме осциллографов HSxxx, кстати, для получения виртуальной земли использован стабилизатор AMS1117-1.2:
А в измерителе uCurrent (https://www.eevblog.com/projects/ucurrent/) сделано почти так же, как и у меня – виртуальная земля создается резистивным делителем напряжения с сопротивлениями по 100к и повторителем на ОУ LMV321 (доступный RAIL-TO-RAIL усилитель).
Итак, возвращаясь к макетной плате. Здесь делаю просто делитель на точных резисторах 1 кОм, учитывая что питание стабильно 3.3В (беру от МК) и подключаю его к выводу REF (номер 5), который раньше был подключен к минусу.

Теперь у нас есть виртуальная земля с потенциалом 1.65В:

И есть возможность измерять ток в обоих направлениях! Когда нагрузка не подключена оцифрованное значение равно почти точно половине от 4095 (12² - 1 = 4096 - 1).

Когда ток течет в одном направлении напряжение будет увеличиваться, а когда в обратном – уменьшаться.
AdcTemp = AdcRaw[0]; // defined previously
if(AdcTemp <= ADCMEAN)
{
AdcTemp = ADCMEAN - AdcTemp;
AdcDir = 255; /* Forward Current */
}else
{
AdcTemp = AdcTemp - ADCMEAN;
AdcDir = 0; /* Backward Current */
}
Пару строк в коде и мы можем правильно посчитать ток и указывать направление тока с присваивая значение другой переменной, а на экране (например) обычно отображается знак минус в случае обратного направления (как на мультиметре).

Получается, что используется только часть разрешения АЦП для каждого из диапазонов (положительного и отрицательного), если это не устраивает, то нужно дополнительно во время измерения изменять напряжение на REF: подавать минус в случае измерения в одном направлении и плюс (опорное) в случае обратного первому.
Дополнительная фильтрация
Не лишним будет ФНЧ в виде двух резисторов с конденсатором на входе.
В случае, если сильно быстро изменяющийся ток измерять не нужно, можно поставить резисторы RF по 10 Ом и конденсатор CF на 1000 нФ:
Если место на плате позволяет:

Особенности разводки платы
Нужно делать так, чтобы ток шел по широким дорожкам, а падение напряжение снималось непосредственно с шунта для минимизации влияния сопротивление дорожки.
Также конденсатор 100 нФ ставим в непосредственной близости к микросхеме, чтобы минимизировать индуктивность и сопротивление дорожек от него к выводам питания (VS и GND).
Пример разводки платы
Учитывая приведенные выше советы от TI разводку сделал следующим образом (это KiCAD, если чё):

А теперь на настоящей плате:

А показывается ток на экранчике во время...

Использование INA180/INA181 на плате
Никогда не знаешь может ли быть доступна эта микра (особенно сейчас), поэтому советую делать посадочное место под SOT-23-6 с добавлением резистора, которым можно замкнуть вывод REF на минус (если ток будет изморятся только в одном направлении).
Видос
Итого

Итог такой, что почти всегда лучше использовать готовую выверенную маленькую схему - специализированную микросхему, которая будет занимать маленькое количество места и значительно упростит создание устройства. Вот только доступность не всегда, особенно сейчас, не всегда присутствует
