Мерить ток зарядного устройства я начал лобово: шунт в разрыв, шунт — на A0 Uno, analogRead, пересчёт. Получил бред: показания плясали на треть шкалы, а при пуске мотора уходили в минус. Причины две, и обе про врождённую слепоту однополярного входа. Первая: A0 меряет напряжение против земли платы, а на земле моего макетного питания висело полвольта шума от мотора — и всё это влезало в замер. Вторая: 10 бит — это 1024 ступени на пять вольт, и мои сто милливольт с шунта размазались в двадцать ступеней. Мультиметр при этом показывал честные полтора ампера, так что ток был — слеп был именно вход.
Лечение — ADS1115 в дифференциальном режиме. В базовом уроке про внешний АЦП мы читали канал против земли; здесь шаг дальше: пара AIN0-AIN1 меряет разность между собой, минуя общую землю, усилитель GAIN_SIXTEEN растягивает ±0,256 В на все 16 бит, и ток через шунт 10 мОм считается одной формулой. Разберём расчёт, синфазные ограничения и честную цену шестнадцати бит.
AIN0 минус AIN1: пара вместо земли
Внутри ADS1115 один АЦП и мультиплексор MUX, который решает, что именно сравнивается. Код MUX=100 из базового урока сравнивал AIN0 с землёй чипа; код 000 подключает пару AIN0 против AIN1, и результат приходит знаковым: AIN0 выше — плюс, ниже — минус, весь диапазон от −32768 до 32767. Земля платы в измерении больше не участвует: если на обоих входах шумит одинаково, дифференциальная пара молча вычитает его. Карта регистров и двухходовка «записал номер — прочитал байты» не меняются: карта регистров ADS из базового урока работает слово в слово, поле MUX живёт в тех же битах 14-12 конфигурации, а собирать его масками учат битовые операции. Заметьте: мультиплексор один на весь чип, одновременного чтения обеих пар не бывает — но чип щёлкает каналами до 860 раз в секунду, и поочерёдный опрос двух шунтов выглядит как параллельный.
#include <Wire.h>#include <Adafruit_ADS1X15.h> Adafruit_ADS1115 ads; const float SHUNT_OM = 0.010; // шунт 10 мОм в минусовом проводе void setup() { Serial.begin(9600); ads.setGain(GAIN_SIXTEEN); // полный масштаб ±0,256 В if (!ads.begin()) { // ADDR на земле -> адрес 0x48 Serial.println("ADS1115 ne otvechaet"); while (true) {} }} void loop() { int16_t raw = ads.readADC_Differential_0_1(); // AIN0 минус AIN1 float mv = raw * 0.0078125; // 0,256 В на 32768 ступеней float amper = mv / 1000.0 / SHUNT_OM; // I = U/R Serial.print("raw="); Serial.print(raw); Serial.print(" mV="); Serial.print(mv, 3); Serial.print(" I="); Serial.print(amper, 3); Serial.println(" A"); delay(250);}Считаем от конца. Полный масштаб при GAIN_SIXTEEN — ±0,256 В, и на 32768 ступеней приходится по 7,8125 мкВ. Шунт 10 мОм переводит ток в напряжение по закону Ома: 10 А дают 100 мВ, 1 А — 10 мВ, а потолок шкалы упирается в 25,6 А. Обратная формула для скетча: ток в миллиамперах равен милливольтам, умноженным на сто, — деление на фиксированные 0,01 Ом превращается в умножение. Греться шунт будет по закону Джоуля-Ленца: при 10 А на нём рассеивается целый ватт, поэтому берите резистор на 3-5 Вт, а не сантиметровую соплю на 0,25 Вт. Отдельные миллиамперы на фоне шума вытягиваются усреднением — приёмы из урока про фильтры АЦП переносятся один в один. Полезна и обратная проверка: при выключенной нагрузке на паре должен лежать честный ноль — если нет, смещение живёт в проводах или в подогретом шунте, и его стоит вычесть программно.
Шестнадцать бит против десяти
Арифметика честная: 65536 ступеней против 1024 — в 64 раза больше, шаг 7,8125 мкВ против 4,88 мВ у Uno. Но ни один АЦП не добавляет точности сверх собственного шума: у ADS1115 последние два-три бита дрожат даже на стабильной батарейке, так что реально опираетесь на 13-14 бит. Это всё равно на порядок выше Uno, и разница видна не в пиковых значениях, а в мелочах: ток покоя зарядки, утечка в сотни микроампер, плавный разгон мотора — на Uno всё это сливается в ступени по пять милливольт. В динамике ток любопытнее всего смотреть графиком: Serial Plotter рисует пусковой выброс мотора, на котором понятно, зачем вообще нужен дифференциальный вход. И помните про насыщение: пусковой ток в десять номиналов честно уезжает за пределы масштаба, отсчёт упирается в −32768 или +32767 — это не поломка, а сигнал, что усилению тесно.
| Усиление | Полный масштаб | Ступень | Потолок тока через шунт 10 мОм |
|---|---|---|---|
| GAIN_ONE | ±4,096 В | 125 мкВ | 409 А — предел не для шунта, а для напряжения |
| GAIN_FOUR | ±1,024 В | 31,25 мкВ | 102 А — запас по масштабу, ступень крупная |
| GAIN_SIXTEEN | ±0,256 В | 7,8125 мкВ | 25,6 А — рабочая зона для шунта 10 мОм |
| АЦП Uno на A0 | 0-5 В | 4,88 мВ | 488 А формально — по факту 1024 ступени и шум земли |
Проверить связку на практике проще, чем кажется. Мультиметр в режиме амперметра ставьте в ту же цепь последовательно — и сравнивайте в трёх точках: покой, половина нагрузки и максимум. При одном ампере шунт 10 мОм даёт десять милливольт: на GAIN_SIXTEEN это почти 1280 ступеней, на Uno — всего две, и разница между схемами видна невооружённым глазом по дрожи последних цифр. Сходится в пределах пары процентов — собираете дальше; расходится на десятки процентов — ищите плохой контакт в разрыве или замеряющий ток вольтметр, а не амперметр.
- 1. Что меряет readADC_Differential_0_1()?
- 2. Какой полный масштаб даёт усиление GAIN_SIXTEEN?
- 3. Шунт 10 мОм, на дифференциальной паре 100 мВ. Какой ток течёт?
- 4. Почему шунт для такой схемы ставят в минусовую линию (low-side)?
- 5. Сколько ступеней у 16-битного ADS1115 против 1024 ступеней АЦП Uno?
- Дифференциальный вход меряет разность AIN0 минус AIN1 со знаком — земля платы в формуле не участвует.
- GAIN_SIXTEEN — это полный масштаб ±0,256 В и шаг 7,8125 мкВ на ступень.
- Ток через шунт 10 мОм: I = U/R; 100 мВ — это 10 А, миллиамперы равны милливольтам, умноженным на сто.
- Оба входа пары обязаны держаться в окне 0...VDD+0,3 В — поэтому шунт ставят в минусовую линию.
- 65536 ступеней против 1024 у Uno, но последние биты живут в шуме: реальный запас — 13-14 бит.
Частые вопросы по теме урока
- Что меряет readADC_Differential_0_1()?
- Дифференциальный режим подключает пару AIN0 против AIN1: результат знаковый, от −32768 до 32767, и земля платы в измерении не участвует. Ток вы считаете сами, деля напряжение на сопротивление шунта. Разность напряжений AIN0 минус AIN1, включая знак
- Какой полный масштаб даёт усиление GAIN_SIXTEEN?
- GAIN_SIXTEEN растягивает вход на ±0,256 В — по 7,8125 мкВ на ступень 16-битного счёта. Это максимальное усиление ADS1115, и именно оно нужно для милливольтовых сигналов с шунта. ±0,256 В
- Шунт 10 мОм, на дифференциальной паре 100 мВ. Какой ток течёт?
- Закон Ома: I = U/R = 0,1 В / 0,01 Ом = 10 А. Удобная перекрёстная проверка: при 10 мОм ток в амперах равен милливольтам, делённым на десять. 10 А
- Почему шунт для такой схемы ставят в минусовую линию (low-side)?
- Оба входа пары обязаны держаться от 0 до питания чипа плюс 0,3 В. Шунт в минусовом проводе прижимает их к земле; в плюсовой линии потребителя входы уезжают за питание, и чип показывает чушь при любом усилении. Чтобы оба входа ADS оставались в окне 0...VDD по синфазному напряжению
- Сколько ступеней у 16-битного ADS1115 против 1024 ступеней АЦП Uno?
- Два в шестнадцатой — это 65536 ступеней против 1024 у 10-битного Uno: разница в 64 раза. Реальный запас меньше — последние два-три бита живут в шуме, но и 13-14 бит против 10 на порядок больше. 65536 — в 64 раза