analogRead в вольты: переводим код АЦП 0-1023 в напряжение
analogRead возвращает не вольты, а безразмерный код: целое от 0 до 1023, и новичок, который ожидает увидеть «2,5», честно получает «512». АЦП на Uno — 10-битный, то есть 1024 ступени шкалы, и каждая ступень при опорном напряжении 5 В стоит около 4,9 мВ. Весь перевод — одна строка арифметики, но вокруг этой строки хватает подводных камней: деление на 1023 против 1024, целочисленный ноль вместо дроби, входы, которые врут без подключения.
В симуляторе формула проверяется без железа: вытащите из палитры «Макетка» потенциометр или фоторезистор, подвигайте ползунок — значение течёт в analogRead, а скетч печатает вольты. Ниже — арифметика перевода, скетч с прогоном, делитель для напряжений выше 5 В и граница: analogReference рантайм браузера не исполняет.
Почему 0-1023 и сколько это в вольтах
АЦП ATmega328P — последовательного приближения, разрядность 10 бит: 2 в десятой степени = 1024 кода, от 0 до 1023. Опорное напряжение по умолчанию — питание платы, 5 В: код 0 — это 0 В, код 1023 — почти полные 5. Один шаг шкалы — 5 В на 1023, около 4,9 мВ. Отсюда и формула: U = код × 5,0 / 1023,0. Педантично ступень равна Vref/1024, а деление на 1023 — это конвенция Arduino, зато она даёт ровно 5,00 В на верхнем коде; разница на пределе шкалы — пол милливольта, меньше шума.
- Входов на Uno — шесть: A0-A5, это пины 14-19; на Nano то же, у Mega — шестнадцать.
- Одно измерение занимает около 100 мкс — максимальная частота опроса порядка 10 кГц на Uno.
- Опорное DEFAULT = 5 В (питание), INTERNAL = 1,1 В на ATmega328P — для мелких сигналов и токового шунта.
- Сопротивление источника сигнала больше 10 кОм заваливает показания: входу нужен ток на конденсатор выборки.
- Плавающий вход без датчика читает наводки — от 0 до 1023 в такт рукам и проводам.
Скетч: вольты в мониторе порта
void setup() { Serial.begin(9600);} void loop() { int raw = analogRead(A0); // код 0-1023 float u = raw * 5.0 / 1023.0; // вольты при опорном 5 В Serial.print("raw="); Serial.print(raw); Serial.print(" u="); Serial.print(u, 2); // два знака после точки Serial.println(" V"); delay(500);}Прогон в симуляторе: ползунок потенциометра из палитры «Макетка» на середине — raw=512, u=2.50 V; в крайних положениях 0.00 и 5.00. Арифметика живёт целиком в рантайме, включая печать дробного числа с двумя знаками. Честная граница: analogReference браузер не исполняет — константа INTERNAL даёт ошибку «Неизвестное имя», опорное в симе всегда 5 В. На живой плате INTERNAL переключает шкалу на 1,1 В, и та же формула пересчитывается с новым опорным. Ещё две грабли формулы: напишите 5 вместо 5.0 — целочисленное деление превратит любые показания в ноль, а сырой float без округления выедет в Serial хвостом из шести знаков.
Код → вольты: шпаргалка
| Код analogRead | Вольты | Где это на ручке потенциометра |
|---|---|---|
| 0 | 0,00 В | крайний против часовой |
| 256 | 1,25 В | четверть хода |
| 512 | 2,50 В | центр (заводской, не калиброванный) |
| 768 | 3,75 В | три четверти хода |
| 1023 | 5,00 В | крайний по часовой |
Напряжения выше 5 В: делитель на двух резисторах
Больше 5 В на аналоговый вход подавать нельзя — вверх шкалы у вас опорное, и лишнее напряжение идёт мимо таблицы токов. Выше измеряют делителем: два резистора, выход между ними. Vout = Vin × R2 / (R1 + R2); для автомобильных 12 В берут R1 = 10 кОм сверху и R2 = 7,5 кОм снизу — 12 В превращаются в 5,14 В, а формула в скетче умножает обратно на коэффициент 2,34. Ток через делитель — меньше миллиампера, для батареи наблюдения это копейки. Что делитель не спасает: от сети 220 В без гальванической развязки не измеряют ничего, это работа мультиметра и трансформатора тока, а не пина A0. Проверка фактического напряжения до входа Arduino — мультиметром, а не доверие к маркировке.
Шум: почему числа прыгают
Живой вход — не осциллограф, и его честные ±1-2 единицы дрожи растут от трёх причин: длинный провод-антенна, соседняя ШИМ-нагрузка по земле и высокоомный источник. Лечение по порядку: подтянуть вход к земле резистором 10-100 кОм (или конденсатором 100 нФ параллельно входу), усреднить десять замеров в скетче — шум падает примерно втрое, и развести землю датчика от силовой. Отдельный случай — висящий в воздухе вход: он ловит руку на расстоянии в полметра, и это не брак, а физика. Именно поэтому randomSeed(analogRead(A0)) — легальное применение плавающего входа, а для измерений — брак. Откуда берутся наводки и как их ловить — разбор в уроке про наводки и шум.