Быстрый и точный 4-разрядный ампервольтметр на STM8S103F3, INA226 и 74HC595
Надоели мне медленные и не точные китайские ампервольтметры и захотелось сделать для себя ампервольтметр без этих недостатков. И цвета индикатора поменять — белый на напряжение и красный на ток. А корпус можно оставить – он вполне удобный.
Вместо операционников для измерения тока и напряжения, имеющих малую точность, проще взять на Алике плату с INA226 за доллар и подключить её к простенькому контроллеру STM8S103F3 / STM8S003F3 за треть доллара.
Т.к. для управления двумя четырёхразрядными индикаторами нужно 8 выходов на сегменты и 8 на разряды индикаторов, плюс не менее двух выходов на подключение INA226. А у STM8S103F3 всего 16 информационных выходов. Поэтому нужно добавлять в схему сдвиговый регистр 74НС595, чтобы, используя три выхода STM8S103F3, можно было перебирать 8 знаков на индикаторах и 8 выходов подключить к сегментам LED.
Для создания своего ампервольтметра можно или делать свою плату, к которой добавлять плату INA226 или переделать китайский четырёхразрядный ампервольтметр с добавлением INA226 (его схему я ниже привёл).
Если использовать для переделки готовый китайский четырёхразрядный ампервольтметр, то в нём часто стоит аналог STM8S103F3, который не отмаркирован вообще. По факту это часто Nuvoton 76E003. Он почти совпадает по распиновке с STM8S103F3 и его можно заменить на STM8S103F3 с минимальными переделками. Но тогда индикаторы останутся оригинальных цветов. А я хотел белый и красный.
Предел измерения напряжения для INA226 составляет 36 вольт. Если хотим питать наш прибор от напряжения до 35 В, то нужно выбрать соответствующий стабилизатор. Я использовал MST5333 с допустимым входным напряжением до 35 вольт и током стабилизации до 200 мА. Желательно на вход питания также добавить диод для защиты от переполюсовки при подключении питания.
Чаще всего китайцы ставят на INA226 шунт на 0,1 Ом, что обеспечивает измерение тока всего до 0,8 А. Для увеличения диапазона измерения тока до 13 ампер, добавил к шунту два резистора по 0,01 Ом, включенных параллельно. Должно было получиться меньше 5 мОм. По факту получилось 5,41 мОм. Измерял сопротивление шунта по падению на нём напряжения при пропускании через шунт тока в 1 ампер.
Для правильной работы INA226, ей нужно при запуске программы загружать данные в два регистра. Один – регистр конфигурации (по его настройке есть детальное описание в документации на INA226). Другой регистр – калибровочный.
В коде программы есть закомментированные строки с несколькими вариантами значений для регистров с пояснениями к ним. Эти строки можно раскомментировать, если они Вам больше подходят (и не забыть тогда закомментировать первоначальные варианты).
Для регистра конфигурации я выбрал значение 0x45FF, которое включает режим постоянного измерения тока и напряжения с временем преобразования 8,24 миллисекунды и 16-ю повторам измерений с усреднением. При этом скорость обновления данных на индикаторе (оценивал чисто визуально) около 5 раз в секунду.
Если нужно ещё быстрее, то можно взять значение для регистра конфигурации 0x45B7. Время преобразования будет 4,156 миллисекунды. Еще быстрее – 2,116 миллисекунды, если взять значение 0x456F для регистра конфигурации.
Второй регистр – калибровочный. В него записывается рассчитанное значение калибровки для получения правильного значения тока в зависимости от выбранного шунта. Рассчитать придётся самостоятельно под конкретное значение сопротивления шунта.
Рассчитать можно как описано ниже или можно почитать документацию и разобраться самому:
1. Выбираем значение Current_LSB. Сначала получаем его минимальное значение по формуле Current_LSB = Макс_Ток / 32768. Где Макс_Ток берём таким, чтобы при его прохождении через выбранный шунт, падение напряжения на шунте не превышало 81,92 мВ (это предельное значение для INA226). Например, для шунта 0,005 Ом Макс_Ток = 0,08192 В / 0,005 Ом = 16,384 А. Для такого тока Current_LSB = 16,384 А / 32768 = 0,0005 А.
При таком значении Current_LSB в скетче нужно умножить значение из регистра тока на коэффициент К = Current_LSB / 0,001. Тогда К = 0,0005 / 0,001 = 0,5. Можно взять больший Current_LSB = 0,001 А. Тогда коэффициент К = 1 и ничего в скетче пересчитывать не нужно. В регистре тока будет сразу правильное значение тока в миллиамперах. Я взял Current_LSB = 0,0005 и К = 0,5. При этом, точность измерения будет чуть выше (погрешность менее 0, 0005 А). В общем, каждый решает сам – как кому нравится.
Такие же Current_LSB = 0,001 и коэффициент К = 1 можно брать и для шунтов от 0,02 до 0,003 Ом.
Для шунта сопротивлением выше 0,02 Ом можно взять Current_LSB = 0,0001 и использовать коэффициент 0,1.
2. На основе выбранного Current_LSB и фактического значения сопротивления шунта, рассчитаем значение регистра калибровки (CAL).
CAL = 0,00512 / (Current_LSB * Rшунта).
В моём случае CAL = 0,00512 / (0,0005 * 0,00541) = 1892,791128. Округляем до целой части (CAL = 1893). И переводим в шестнадцатеричное значение 0x765. Вот это значение 0x765 я и пишу в калибровочный регистр.
Теперь мы готовы к получению данных о токе и напряжении от INA226. Для получения значения тока, нужно считанное из регистра тока (04h) значение умножить на наш коэффициент К. Это и будет измеренный INA226 ток в миллиамперах. У меня было умножение на 0,5. Если коэффициент у Вас был 1, то ничего умножать не нужно.
Значение напряжения из регистра напряжения (02h) записано в битах, каждый из которых равен 0,8 В. Для получения величины напряжения в милливольтах, нужно считанное из регистра значение умножить на 1,25.
Поскольку напряжение в милливольтах мы меряем до 36 вольт (ХХХХХ вольт), а ток в миллиамперах до 16384 мВ (ХХХХХ мА), то получаем пять знаков в величине напряжения и тока. А индикатор у нас четырёхразрядный. Поэтому в зависимости от того, есть ли у нас не нулевое значение в старшем разряде, мы выводим на индикатор либо ХХ, ХХ либо Х, ХХХ. Соответственно теряем единицы милливольт при напряжениях выше 9,999 В и единицы миллиампер при токах выше 9,999 А. Это вынужденная мера из-за ограничения разрядности индикатора.
Кто хочет получать пятизначные значения, то может доработать схему и код для вывода пяти знаков на индикаторы. У контроллера остались незадействованными ещё три выхода. Этого вполне хватит для работы ещё с двумя разрядами индикатора даже без второго сдвигового регистра. Правда корпус тогда нужен другой для ампервольтметра.
Для программатора на плате пять ножек контроллера выведены на разъём:
— Vdd – питание +3,3 В
— GND
— RST
— SWIM
— TX – на случай, если нужно будет при отладке выводить на терминал какие-то данные
В коде уже есть строки для вывода на терминал данных из регистров INA226. Их нужно рас комментировать, если вы собираетесь мониторить состояние регистров INA226.
Скетч загружался из Arduino IDE версии 1.8.19 через китайский ST-Link V2.
Для работы с STM8S103F3 нужно добавить соответствующие платы в менеджер плат. Для этого сначала нужно, чтобы в настройках в разделе «Дополнительные ссылки для менеджера плат» была добавлена ссылка для STM8 href=«https://github.com/tenbaht/sduino/raw/master/package_sduino_stm8_index.json

Тогда в менеджере плат можно будет выбрать контроллер STM8S103F3.

При программировании STM8S103F3 у меня возникла неожиданная проблема. Скетч не захотел загружаться в контроллер. Выскакивала ошибка. Не знаю так ли у всех, но у меня все купленные контроллеры STM8S103F3 были заблокированы на чтение и запись и по этой причине не проходила заливка скетча из Arduino IDE.
Для решения проблемы нужно сначала снять защиту (прошивка в памяти контроллера конечно потеряется).
Как это сделать хорошо описано у пользователя CAMOKAT-BETEPAHA с drive2.ru в статье „Программирование микроконтроллеров: STM8 — как прошить?“. За что ему большое спасибо. Приведу здесь краткую выжимку оттуда.
Чтобы снять защиту можно использовать бесплатную программу ST Visual Programmer.
Её можно скачать с офсайта по ссылке https://www.st.com/en/development-tools/stvp-stm8.html или скачать по прямой ссылке https://umat.ru/files/en.stvp-stm8.zip (версия архива 42.0.0 конца 2018 года) и установить себе на компьютер.
При установке софта установится все необходимое, драйвера программатора и сама программа. Название приложения „ST Visual Programmer“ Запускаем его.
Сначала нужно настроить — в конфигурации ввести тип программатора, режим и название чипа.

После этого делаем следующее:
1. Подключаем через ST-Link V2 к компьютеру контроллер.
2. Запускаем программу ST Visual Programmer.
3. Переходим на вкладку „OPTION BYTE“(выделено синим).
4. Устанавливаем параметр защиты в положении OFF (выделено красным).
5. Нажимаем на выделенную зеленым кнопку чтобы записать данные.
После этого чип будет разблокирован и можно заливать прошивку из Arduino IDE.

Вообще для STM8S довольно мало нормальных библиотек под Arduino IDE. Первая попытка работы с INA226 через библиотеку Wire.h закончилась неудачей. В библиотеке нет функций, которые умеют писать по два байта в регистры INA226. Пришлось делать на основе функций из Wire.h свои и работать с INA через них.
Если у кого-то вместо индикаторов с общим анодом есть только индикаторы с общим катодом, то можно самостоятельно поправить скетч, чтобы регистр и контроллер давали обратные сигналы на индикатор для включения сегментов и разрядов.
Ниже для любителей поупражняться с кодом и схемами своими руками, приложены схема моего ампервольтметра и ссылка на файл в формате .spl7, а также код программы.
Схема моего ампервольтметра:

Ссылка на файл .spl7 — https://www.dropbox.com/scl/fi/xmykxzvx7vzi3kzpawt60/STM8S103F3-03.spl7?rlkey=ifyjj9or16zrhyl1gh8qa2tpb&dl=0
Ампервольтметр собирался в качестве эксперимента, на скорую руку, без изготовления платы — на мекетке + плата переходник для контроллера + впаянная в макетку плата INA226. Выглядит конечно не сильно презентабельно, но, главное, что быстро собирается и всё работает. ))
При проверке работы прибора и сравнении его показаний с четырёхразрядным вольтметром и пятиразрядным амперметром блока питания KORAD U203, расхождение не превысило единички в младшем разряде и по току и по напряжению. Учитывая, что INA226 по напряжению даёт достаточно точные показания, то появился повод даже похвалить изготовителей KORAD U203 за хорошую точность приборов.
Ну а это фото результата.




Приборчик планируется к установке в мой лабораторный блок питания. Поэтому претензий у владельца блока к непрезентабельному виду получившегося приборчика не возникает. ))
Ну вот на этом, пожалуй, и всё.
Удачи всем, кто решит попробовать свои силы в создании приборчиков более вменяемых версии, чем продают китайцы на Алике!
P.S.
Пока делал этот ампервольтметр, появилась ещё пара идей на эту же тему. Тем более, что осталось ещё несколько не использованных контроллеров. Думаю, скоро будет продолжение. ))
Вместо операционников для измерения тока и напряжения, имеющих малую точность, проще взять на Алике плату с INA226 за доллар и подключить её к простенькому контроллеру STM8S103F3 / STM8S003F3 за треть доллара.
Т.к. для управления двумя четырёхразрядными индикаторами нужно 8 выходов на сегменты и 8 на разряды индикаторов, плюс не менее двух выходов на подключение INA226. А у STM8S103F3 всего 16 информационных выходов. Поэтому нужно добавлять в схему сдвиговый регистр 74НС595, чтобы, используя три выхода STM8S103F3, можно было перебирать 8 знаков на индикаторах и 8 выходов подключить к сегментам LED.
Для создания своего ампервольтметра можно или делать свою плату, к которой добавлять плату INA226 или переделать китайский четырёхразрядный ампервольтметр с добавлением INA226 (его схему я ниже привёл).
Если использовать для переделки готовый китайский четырёхразрядный ампервольтметр, то в нём часто стоит аналог STM8S103F3, который не отмаркирован вообще. По факту это часто Nuvoton 76E003. Он почти совпадает по распиновке с STM8S103F3 и его можно заменить на STM8S103F3 с минимальными переделками. Но тогда индикаторы останутся оригинальных цветов. А я хотел белый и красный.
Предел измерения напряжения для INA226 составляет 36 вольт. Если хотим питать наш прибор от напряжения до 35 В, то нужно выбрать соответствующий стабилизатор. Я использовал MST5333 с допустимым входным напряжением до 35 вольт и током стабилизации до 200 мА. Желательно на вход питания также добавить диод для защиты от переполюсовки при подключении питания.
Чаще всего китайцы ставят на INA226 шунт на 0,1 Ом, что обеспечивает измерение тока всего до 0,8 А. Для увеличения диапазона измерения тока до 13 ампер, добавил к шунту два резистора по 0,01 Ом, включенных параллельно. Должно было получиться меньше 5 мОм. По факту получилось 5,41 мОм. Измерял сопротивление шунта по падению на нём напряжения при пропускании через шунт тока в 1 ампер.
Для правильной работы INA226, ей нужно при запуске программы загружать данные в два регистра. Один – регистр конфигурации (по его настройке есть детальное описание в документации на INA226). Другой регистр – калибровочный.
В коде программы есть закомментированные строки с несколькими вариантами значений для регистров с пояснениями к ним. Эти строки можно раскомментировать, если они Вам больше подходят (и не забыть тогда закомментировать первоначальные варианты).
Для регистра конфигурации я выбрал значение 0x45FF, которое включает режим постоянного измерения тока и напряжения с временем преобразования 8,24 миллисекунды и 16-ю повторам измерений с усреднением. При этом скорость обновления данных на индикаторе (оценивал чисто визуально) около 5 раз в секунду.
Если нужно ещё быстрее, то можно взять значение для регистра конфигурации 0x45B7. Время преобразования будет 4,156 миллисекунды. Еще быстрее – 2,116 миллисекунды, если взять значение 0x456F для регистра конфигурации.
Второй регистр – калибровочный. В него записывается рассчитанное значение калибровки для получения правильного значения тока в зависимости от выбранного шунта. Рассчитать придётся самостоятельно под конкретное значение сопротивления шунта.
Рассчитать можно как описано ниже или можно почитать документацию и разобраться самому:
1. Выбираем значение Current_LSB. Сначала получаем его минимальное значение по формуле Current_LSB = Макс_Ток / 32768. Где Макс_Ток берём таким, чтобы при его прохождении через выбранный шунт, падение напряжения на шунте не превышало 81,92 мВ (это предельное значение для INA226). Например, для шунта 0,005 Ом Макс_Ток = 0,08192 В / 0,005 Ом = 16,384 А. Для такого тока Current_LSB = 16,384 А / 32768 = 0,0005 А.
При таком значении Current_LSB в скетче нужно умножить значение из регистра тока на коэффициент К = Current_LSB / 0,001. Тогда К = 0,0005 / 0,001 = 0,5. Можно взять больший Current_LSB = 0,001 А. Тогда коэффициент К = 1 и ничего в скетче пересчитывать не нужно. В регистре тока будет сразу правильное значение тока в миллиамперах. Я взял Current_LSB = 0,0005 и К = 0,5. При этом, точность измерения будет чуть выше (погрешность менее 0, 0005 А). В общем, каждый решает сам – как кому нравится.
Такие же Current_LSB = 0,001 и коэффициент К = 1 можно брать и для шунтов от 0,02 до 0,003 Ом.
Для шунта сопротивлением выше 0,02 Ом можно взять Current_LSB = 0,0001 и использовать коэффициент 0,1.
2. На основе выбранного Current_LSB и фактического значения сопротивления шунта, рассчитаем значение регистра калибровки (CAL).
CAL = 0,00512 / (Current_LSB * Rшунта).
В моём случае CAL = 0,00512 / (0,0005 * 0,00541) = 1892,791128. Округляем до целой части (CAL = 1893). И переводим в шестнадцатеричное значение 0x765. Вот это значение 0x765 я и пишу в калибровочный регистр.
Теперь мы готовы к получению данных о токе и напряжении от INA226. Для получения значения тока, нужно считанное из регистра тока (04h) значение умножить на наш коэффициент К. Это и будет измеренный INA226 ток в миллиамперах. У меня было умножение на 0,5. Если коэффициент у Вас был 1, то ничего умножать не нужно.
Значение напряжения из регистра напряжения (02h) записано в битах, каждый из которых равен 0,8 В. Для получения величины напряжения в милливольтах, нужно считанное из регистра значение умножить на 1,25.
Поскольку напряжение в милливольтах мы меряем до 36 вольт (ХХХХХ вольт), а ток в миллиамперах до 16384 мВ (ХХХХХ мА), то получаем пять знаков в величине напряжения и тока. А индикатор у нас четырёхразрядный. Поэтому в зависимости от того, есть ли у нас не нулевое значение в старшем разряде, мы выводим на индикатор либо ХХ, ХХ либо Х, ХХХ. Соответственно теряем единицы милливольт при напряжениях выше 9,999 В и единицы миллиампер при токах выше 9,999 А. Это вынужденная мера из-за ограничения разрядности индикатора.
Кто хочет получать пятизначные значения, то может доработать схему и код для вывода пяти знаков на индикаторы. У контроллера остались незадействованными ещё три выхода. Этого вполне хватит для работы ещё с двумя разрядами индикатора даже без второго сдвигового регистра. Правда корпус тогда нужен другой для ампервольтметра.
Для программатора на плате пять ножек контроллера выведены на разъём:
— Vdd – питание +3,3 В
— GND
— RST
— SWIM
— TX – на случай, если нужно будет при отладке выводить на терминал какие-то данные
В коде уже есть строки для вывода на терминал данных из регистров INA226. Их нужно рас комментировать, если вы собираетесь мониторить состояние регистров INA226.
Скетч загружался из Arduino IDE версии 1.8.19 через китайский ST-Link V2.
Для работы с STM8S103F3 нужно добавить соответствующие платы в менеджер плат. Для этого сначала нужно, чтобы в настройках в разделе «Дополнительные ссылки для менеджера плат» была добавлена ссылка для STM8 href=«https://github.com/tenbaht/sduino/raw/master/package_sduino_stm8_index.json

Тогда в менеджере плат можно будет выбрать контроллер STM8S103F3.

При программировании STM8S103F3 у меня возникла неожиданная проблема. Скетч не захотел загружаться в контроллер. Выскакивала ошибка. Не знаю так ли у всех, но у меня все купленные контроллеры STM8S103F3 были заблокированы на чтение и запись и по этой причине не проходила заливка скетча из Arduino IDE.
Для решения проблемы нужно сначала снять защиту (прошивка в памяти контроллера конечно потеряется).
Как это сделать хорошо описано у пользователя CAMOKAT-BETEPAHA с drive2.ru в статье „Программирование микроконтроллеров: STM8 — как прошить?“. За что ему большое спасибо. Приведу здесь краткую выжимку оттуда.
Чтобы снять защиту можно использовать бесплатную программу ST Visual Programmer.
Её можно скачать с офсайта по ссылке https://www.st.com/en/development-tools/stvp-stm8.html или скачать по прямой ссылке https://umat.ru/files/en.stvp-stm8.zip (версия архива 42.0.0 конца 2018 года) и установить себе на компьютер.
При установке софта установится все необходимое, драйвера программатора и сама программа. Название приложения „ST Visual Programmer“ Запускаем его.
Сначала нужно настроить — в конфигурации ввести тип программатора, режим и название чипа.

После этого делаем следующее:
1. Подключаем через ST-Link V2 к компьютеру контроллер.
2. Запускаем программу ST Visual Programmer.
3. Переходим на вкладку „OPTION BYTE“(выделено синим).
4. Устанавливаем параметр защиты в положении OFF (выделено красным).
5. Нажимаем на выделенную зеленым кнопку чтобы записать данные.
После этого чип будет разблокирован и можно заливать прошивку из Arduino IDE.

Вообще для STM8S довольно мало нормальных библиотек под Arduino IDE. Первая попытка работы с INA226 через библиотеку Wire.h закончилась неудачей. В библиотеке нет функций, которые умеют писать по два байта в регистры INA226. Пришлось делать на основе функций из Wire.h свои и работать с INA через них.
Если у кого-то вместо индикаторов с общим анодом есть только индикаторы с общим катодом, то можно самостоятельно поправить скетч, чтобы регистр и контроллер давали обратные сигналы на индикатор для включения сегментов и разрядов.
Ниже для любителей поупражняться с кодом и схемами своими руками, приложены схема моего ампервольтметра и ссылка на файл в формате .spl7, а также код программы.
Схема моего ампервольтметра:

Ссылка на файл .spl7 — https://www.dropbox.com/scl/fi/xmykxzvx7vzi3kzpawt60/STM8S103F3-03.spl7?rlkey=ifyjj9or16zrhyl1gh8qa2tpb&dl=0
Код программы:
/************************************************************************
* Скетч для вольтметра на STM8S103F3 + INA226 + семисегментнтный LED на 4 разряда с ОА
*
* Через стандартную библиотеку I2C для STM8S103F3 обмен корректно с INA226 не проходит
* В библиотеке Wire.h для STM8S103F3 нет функции записи двух байт в выбранный регстр.
* Есть только для одного байта.
* Пришлось брать функцию из этой библиотеки и созда на её основе свои, которые могут писать и читать двухбайтовые регистры INA226
*
* Регистры INA226:
* 00h: Регистр конфигурации
* 01h: Регистр напряжения шунта
* 02h: Регистр напряжения шины (это откуда мы читае напряжение для вольтметра)
* 03h: Регистр мощности
* 04h: Регистр тока - содержит в битах значение напряжение на шунте, делённое на 2,5 мкВ
* 05h: Регистр калибровки
* Коэф. пересчёта напряжения по данным из регистра 1.25mV
* Коэф. пересчёта напряжения на шунте по данным из регистра 2.5μV
* Регистр тока хранит данные в милиамперах
* Коэф. пересчёта мощности по данным из регистра 25mW
* Шунт - 0,005 (два в параллель по 0,01)
* Максимальный ток - 16,384 А
* Current_LSB (Current Least Significant Bit)
* — это разрешающая способность датчика тока (например у INA226, INA219) в Амперах на бит.
* Определяется как значение равное или большее (для удобства расчётов в программе)
* значения максимального допустимого измеряемого тока, разделённое на 32768
* часто выбирается из вариантов (0,5 мА; 1мА; 0,1мА; ... )
*
* Формула пересчёта - коэффициент калибровки CAL = 0,00512 / (Current_LSB * Rшунта)
* Current_LSB = Максимальный_ожидаемый_ток / 32768
* Максимальный ожидаемый ток определяется как такой ток,
*при котором на выбранном шунте падение напрядения не превысит значения 0,08192 вольт (предельного для INA226)
*
* Значение регистра калибровки зависит только от сопротивления шунта и выбранного Current_LSB
* Current_LSB лучше выбирать в 1 мА для шунтов меньше 0,05 Ом - тогда в регистре тока будет уже готовое значение в миллиамперах для только
* Если Current_LSB выбрать 0,5 мА, то значение из регистра тока нужно делить на 2. Но точность измерения будет выше. Поглешность около 0,5 мА.
* Для шунтов от 0,05 Ома и больше, можно выбрать Current_LSB = 0,1 мА. Тогда значение из регистра тока нужно будет поделить на 10 для получения
* реального значения тока.
*
* Примеры значений данных для регистра калибровки при Current_LSB = 0,5 мА (CAL = 0,00512 / (Rш * Current_LSB)):
* - сопротивление шунта - 0,005 Ом - > CAL = 0x800 --> 0,00512 / (0,005 Ом * 0,0005 A) = 2048 --> 0x800
* - сопротивление шунта - 0,00544 Ом - > CAL = 0x75A --> 0,00512 / (0,00544 Ом * 0,0005 A) = 1882,35 --> 0x75A
* - сопротивление шунта - 0,0056 Ом - > CAL = 0x725 --> 0,00512 / (0,0056 Ом * 0,0005 A) = 1828,57 --> 0x725
* - сопротивление шунта - 0,00541 Ом - > CAL = 0x765 --> 0,00512 / (0,00541 Ом * 0,0005 A) = 1892,791 --> 0x765
* --- в моём случае полученное из регистра тока значение не забыть разделить на 2 (К = 0,001 / Current_LSB)
* для получение реального значения тока в миллиамперах.
*
* LED индикаторы с общим анодом
* - для включения на регистры подаём 1, на сегменты 0
* - токоограничивающие резисторы с контроллера на сегменты - по 150 Ом
* Максимальный ток контроллера - когда на индикаторе светятся все 7 сегментов + точка на одном разряде касного индикатора
* с током 9 мА на сегмент = 9 х 8 = 72 мА - вполне допустимый ток контроллера
*
* Константин Трыков 12.2025
* Версия 110163_02
************************************************************************/
#include <I2C.h>
#include <stdio.h>
#include <Wire.h>
// Задаём адрес доступа к INA226
#define INA226adress 0x40
//-------------------------------------------------------------------------------------------------------------
// Задать значение для регистров INA226 - раскомментировать только нужеую строку
//#define configData 0x4327 // Значение для регистра конфигурации
// Постоянный режим, время преобразования тока и напряжения - 1,1 мс,
// устедняемое число отсчётов - 4
//#define configData 0x456F // Значение для регистра конфигурации
// Постоянный режим, время преобразования тока и напряжения - 2,116 мс,
// устедняемое число отсчётов - 16
//#define configData 0x45B7 // Значение для регистра конфигурации
// Постоянный режим, время преобразования тока и напряжения - 4,156 мс,
// устедняемое число отсчётов - 16
#define configData 0x45FF // Значение для регистра конфигурации
// Постоянный режим, время преобразования тока и напряжения - 8,244 мс,
// устедняемое число отсчётов - 16
//--------------------------------- Настройка регистра калибровки - раскомментировать только нужеую строку ---------------
//#define calibrationData 0x800 // Значение для регистра калибровки при Rш = 5 милиом и Current_LSB = 0,5 мА
//#define calibrationData 0x6D3 // Значение для регистра калибровки при Rш = 5,86 милиом и Current_LSB = 0,5 мА
//#define calibrationData 0x6AB // Значение для регистра калибровки при Rш = 6 милkиом и Current_LSB = 0,5 мА
//#define calibrationData 0x725 // Значение для регистра калибровки при Rш = 5,6 милkиом и Current_LSB = 0,5 мА
//#define calibrationData 0x669 // Значение для регистра калибровки при Rш = 6,24 милkиом и Current_LSB = 0,5 мА
//#define calibrationData 0x75A // Значение для регистра калибровки при Rш = 5,44 милkиом и Current_LSB = 0,5 мА
#define calibrationData 0x765 // Значение для регистра калибровки при Rш = 5,41 милkиом и Current_LSB = 0,5 мА
//---------------------------------------------------------------------------------------------------------------
// Назначаем пины сегментам LED индикатора
#define SEG_A PA1
#define SEG_B PC4
#define SEG_C PC7
#define SEG_D PD2
#define SEG_E PD3
#define SEG_F PA2
#define SEG_G PC6
#define SEG_P PD1
// Назначаем пины ножкам регистра
#define ST_CP PC5 // PIN защёлки - ножка 12
#define SH_CP PD4 // PIN синхронизации - ножка 11
#define DS PC3 // PIN данных
// Установка значений переменных
uint16_t voltage_mV = 0; // Переменная для значения напряжения
uint16_t current_mA = 0; // Переменная для значения тока
uint8_t cyfra5 = 0; // Переменная для вывода цифры старшего 5-го разряда на индикатор
uint8_t cyfra4 = 0; // Переменная для вывода цифры 4-го разряда на индикатор
uint8_t cyfra3 = 0; // Переменная для вывода цифры 3-го разряда на индикатор
uint8_t cyfra2 = 0; // Переменная для вывода цифры 1-го разряда на индикатор
uint8_t cyfra1 = 0; // Переменная для вывода цифры младшего 1-го разряда на индикатор
// Переменные для считывания данных регистров INA226 - только для отладки
//uint16_t configDataDo = 0;
//uint16_t configDataPosle = 0;
//uint16_t calibrationDo = 0;
//uint16_t calibrationPosle = 0;
//----------------------------------------------------------------------------------------------------
// Массив байтов для отображения сегментов по полученной цифре для LED с ОА
uint8_t numberCode[] = // В этом массиве задаются цифры на семисегментном индикаторе
{ 0xC0, //0
0xF9, //1
0xA4, //2
0xB0, //3
0x99, //4
0x92, //5
0x82, //6
0xF8, //7
0x80, //8
0x90 //9
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// Функции //////////////////////////////////////////////////////////////////
// Вкючение сегментов в зависимости от полученного байта
void SendDig(uint8_t byteCode) // Запись сегментов в индикатор
{
digitalWrite(SEG_A, (byteCode & 0x01));
digitalWrite(SEG_B, ((byteCode & 0x02)>>1));
digitalWrite(SEG_C, ((byteCode & 0x04)>>2));
digitalWrite(SEG_D, ((byteCode & 0x08)>>3));
digitalWrite(SEG_E, ((byteCode & 0x10)>>4));
digitalWrite(SEG_F, ((byteCode & 0x20)>>5));
digitalWrite(SEG_G, ((byteCode & 0x40)>>6));
digitalWrite(SEG_P, HIGH); // Выключить точку
}
// Запись байта в регистр 74НС595
void cyfraOut(uint8_t x)
{
delay (1);
digitalWrite(ST_CP, LOW); // начинаем передачу данных
shiftOut(DS, SH_CP, LSBFIRST, x); // устанавливаем нужный байт
digitalWrite(ST_CP, HIGH); // прекращаем передачу данных
}
// Объявление функций записи и чтения INA225
uint16_t readRegisterTK(uint8_t, uint8_t);
void writeRegisterTK(uint8_t, uint8_t, uint16_t);
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////// Начальная установка //////////////////////////////////////////////////////////////////
void setup()
{
I2C_begin(); // Инициализируем шину I2C - в библиотеке I2C эта функция выглядит так:
// void I2C_begin()
// {
// bytesAvailable = 0;
// bufferIndex = 0;
// totalBytes = 0;
// timeOutDelay = 10; // set default time out
// I2C_setSpeed(0); // initialize for standard speed (100kHz)
// }
// Считываем данные из регистра конфигурации
// configDataDo = readRegisterTK (INA226adress,0x00); // Читаем 2 байта из регистра 0х00
// Считываем данные из регистра калибровки
// calibrationDo = readRegisterTK (INA226adress,0x05); // Читаем 2 байта из регистра 0х05
writeRegisterTK(INA226adress, 0x00, configData); // Инициализируем INA226 (17191 в десятичной или 0x4327 в шестнадцатиричной)
// Пишем в I2C устройство по адресу 0x40 в регистр 0x00 значение 0x4327
// Что означает:
// Режим работы - "continuous"
// Время выборки и для напряжения и для шунта - 1,1 мс
// Усредненее по 4 измерениям
// По умолчанию значение 0x4127 в шестнадцатиричной или 16679 в десятичной
writeRegisterTK(INA226adress, 0x05, calibrationData); // Инициализируем регистр калибровки INA226 под ток 16,384 А
// ... и сопротивление шунта 5 милиом (два по 0,005) - десятичное значение 2048 или 0x800 в шестнадцатиричной
// Считываем данные из регистра конфигурации
// configDataPosle = readRegisterTK (INA226adress,0x00); // Читаем 2 байта из регистра 0х00 - только для отладки
// Считываем данные из регистра калибровки
// calibrationPosle = readRegisterTK (INA226adress,0x05); // Читаем 2 байта из регистра 0х05 - только для отладки
// Задаём режимы пинов
pinMode(ST_CP, OUTPUT);
pinMode(SH_CP, OUTPUT);
pinMode(DS, OUTPUT);
pinMode(SEG_A, OUTPUT);
pinMode(SEG_B, OUTPUT);
pinMode(SEG_C, OUTPUT);
pinMode(SEG_D, OUTPUT);
pinMode(SEG_E, OUTPUT);
pinMode(SEG_F, OUTPUT);
pinMode(SEG_G, OUTPUT);
pinMode(SEG_P, OUTPUT);
//=========================================================================
//-------------- Только для отладки ----------------------
// Инициализация последовательного порта на скоости 9600 bps:
// Serial_begin(9600);
//-----------------------------------------------------------
//===========================================================================
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////// Начало основного цикла //////////////////////////////////////////////////////////////////
void loop()
{
// Считываем данные из регистра напряжения
voltage_mV = readRegisterTK (INA226adress,0x02); // Читаем 2 байта из регистра напяжения 0х02
voltage_mV = voltage_mV + (voltage_mV / 4); // Получаем данные в миливольтах - увеличиваем на четверть
// Считываем данные из регистра тока
current_mA = readRegisterTK (INA226adress,0x04); // Читаем 2 байта из регистра 0х04 - ток в милиамперах
current_mA = current_mA / 2; // Умножаем на 0,5 - коэффициент для тока = Current_LSB / 0,001
// Считываем данные из регистра конфигурации
// configDataPosle = readRegisterTK (INA226adress,0x00); // Читаем 2 байта из регистра 0х00 - только для отладки
// Считываем данные из регистра калибровки
// calibrationPosle = readRegisterTK (INA226adress,0x05);// Читаем 2 байта из регистра 0х05 - только для отладки
/*
//======================================================================================================
//-------------- Только для отладки - вывод на терминал -------------------------------------------
Serial_print_s("Напряжение - "); // Вывод текста без перевода строки
Serial_println_u(voltage_mV); // Вывод переменной напряжения с переводом строки
Serial_print_s("Ток - "); // Вывод текста с переводом строки
Serial_println_u(current_mA); // Вывод переменной с переводом строки
Serial_print_s("calibrationDo - ");
Serial_println_u(calibrationDo);
Serial_print_s("calibrationPosle - ");
Serial_println_u(calibrationPosle);
Serial_print_s("configDataDo - ");
Serial_println_u(configDataDo);
Serial_print_s("configDataPosle - ");
Serial_println_u(configDataPosle);
Serial_print_s("\n\r"); // Перевод строки
//-----------------------------------------------------------------------------------------------
//========================================================================================================
*/
// Если старший разряд не нулевой, то выводим старшие четыре разряда из пяти на индикатор напряжения
if (voltage_mV > 9999)
{
cyfraOut(0b10000000); // Выбрать разряд 4 вольтметра (1-й с конца - младший - крайний правый)
SendDig(numberCode[voltage_mV/10%10]); // Вывести 4-й из 5-и разряд напряжения
cyfraOut(0b01000000); // Выбрать разряд 3 вольтметра (второй справа)
SendDig(numberCode[voltage_mV/100%10]); // Вывести 3-й из 5-и разряд напряжения
cyfraOut(0b00100000); // Выбрать разряд 2 вольтметра (третий справа)
SendDig(numberCode[voltage_mV/1000%10]); // Вывести 2-й из 5-и разряд напряжения
digitalWrite(SEG_P, LOW); // Включить точку
cyfraOut(0b00010000); // Выбрать разряд 1 вольтметра (крайний левый)
SendDig(numberCode[voltage_mV/10000%10]); // Вывести 1-й из 5-и разряд напряжения
}
// Иначе выводим младщие четыре разряда из пяти на индикатор напряжения
else
{
cyfraOut(0b10000000); // Выбрать разряд 4 вольтметра (1-й с конца - младший - крайний правый)
SendDig(numberCode[voltage_mV%10]); // Вывести 5-й из 5-и разряд напряжения
cyfraOut(0b01000000); // Выбрать разряд 3 вольтметра (второй справа)
SendDig(numberCode[voltage_mV/10%10]); // Вывести 4-й из 5-и разряд напряжения
cyfraOut(0b00100000); // Выбрать разряд 2 вольтметра (третий справа)
SendDig(numberCode[voltage_mV/100%10]); // Вывести 3-й из 5-и разряд напряжения
cyfraOut(0b00010000); // Выбрать разряд 1 вольтметра (крайний левый)
SendDig(numberCode[voltage_mV/1000%10]); // Вывести 2-й из 5-и разряд напряжения
digitalWrite(SEG_P, LOW); // Включить точку
}
// Если старший разряд не нулевой, то выводим старшие четыре разряда на индикатор тока
if (current_mA > 9999)
{
cyfraOut(0b00000001); // Выбрать разряд 4 амперметра (1-й с конца - младший - крайний правый)
SendDig(numberCode[current_mA/10%10]); // Вывести 4-й из 5-и разряд тока
cyfraOut(0b00000010); // Выбрать разряд 3 амперметра (второй справа)
SendDig(numberCode[current_mA/100%10]); // Вывести 3-й из 5-и разряд тока
cyfraOut(0b00000100); // Выбрать разряд 2 амперметра (третий справа)
SendDig(numberCode[current_mA/1000%10]); // Вывести 2-й из 5-и разряд тока
digitalWrite(SEG_P, LOW); // Включить точку
cyfraOut(0b00001000); // Выбрать разряд 1 амперметра (крайний левый)
SendDig(numberCode[current_mA/10000%10]); // Вывести 1-й из 5-и разряд тока
}
// Иначе выводим младщие четыре разряда на индикатор тока
else
{
cyfraOut(0b00000001); // Выбрать разряд 4 амперметра (1-й с конца - младший - крайний правый)
SendDig(numberCode[current_mA%10]); // Вывести 5-й из 5-и разряд тока
cyfraOut(0b00000010); // Выбрать разряд 3 амперметра (второй справа)
SendDig(numberCode[current_mA/10%10]); // Вывести 4-й из 5-и разряд тока
cyfraOut(0b00000100); // Выбрать разряд 2 амперметра (третий справа)
SendDig(numberCode[current_mA/100%10]); // Вывести 3-й из 5-и разряд тока
cyfraOut(0b00001000); // Выбрать разряд 1 амперметра (крайний левый)
SendDig(numberCode[current_mA/1000%10]); // Вывести 2-й из 5-и разряд тока
digitalWrite(SEG_P, LOW); // Включить точку
}
}
/////////////// Конец основного цикла //////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Запись 16-ти битного регистра INA226
void writeRegisterTK(uint8_t i2cAdress, uint8_t address, uint16_t dataTK)
{
Wire_beginTransmission(i2cAdress); // Начинаем передачу
Wire_write(address); // Отправляем адрес
Wire_write(highByte(dataTK)); // Отправляем старший байт
Wire_write(lowByte(dataTK)); // Отправляем младший байт
Wire_endTransmission(); // Заканчиваем передачу
}
// Чтение 16-ти битного регистра INA226
uint16_t readRegisterTK(uint8_t i2cAdress, uint8_t address)
{
Wire_beginTransmission(i2cAdress); // Начинаем передачу
Wire_write(address); // Отправляем адрес
Wire_endTransmission(); // Заканчиваем передачу
Wire_requestFrom2(i2cAdress, (uint8_t)2); // Запрашиваем 2 байта
return Wire_read() << 8 | Wire_read(); // Клеим и возвращаем результат
}Ампервольтметр собирался в качестве эксперимента, на скорую руку, без изготовления платы — на мекетке + плата переходник для контроллера + впаянная в макетку плата INA226. Выглядит конечно не сильно презентабельно, но, главное, что быстро собирается и всё работает. ))
При проверке работы прибора и сравнении его показаний с четырёхразрядным вольтметром и пятиразрядным амперметром блока питания KORAD U203, расхождение не превысило единички в младшем разряде и по току и по напряжению. Учитывая, что INA226 по напряжению даёт достаточно точные показания, то появился повод даже похвалить изготовителей KORAD U203 за хорошую точность приборов.
Ну а это фото результата.




Приборчик планируется к установке в мой лабораторный блок питания. Поэтому претензий у владельца блока к непрезентабельному виду получившегося приборчика не возникает. ))
Ну вот на этом, пожалуй, и всё.
Удачи всем, кто решит попробовать свои силы в создании приборчиков более вменяемых версии, чем продают китайцы на Алике!
P.S.
Пока делал этот ампервольтметр, появилась ещё пара идей на эту же тему. Тем более, что осталось ещё несколько не использованных контроллеров. Думаю, скоро будет продолжение. ))
Самые обсуждаемые обзоры
| +68 |
2739
95
|
| +73 |
3363
36
|
резисторы под нагрузкой будут плавать, их точно не стоило паять бутербродом.
PDF
ну и кстати тут критична только термостабильность, номинал можно задать в прошивке любой.
(с шунтом 5 мОм)
у меня был один аномальный, но когда собрался проверить оказалось что он сдох.
Брал здесь — https://www.aliexpress.com/item/1005009774355109.html
За и идею и статью — однозначно плюс!