База знаний · Язык скетчей

pinMode, digitalWrite, analogRead: команды ввода-вывода

Пять команд, которыми плата говорит с миром: три режима вывода, десять бит АЦП, ШИМ вместо напряжения и ловушка map().

Пять команд — это весь разговор платы с внешним миром. Всё остальное, от датчика температуры до Wi-Fi, библиотеки строят поверх них. Стоит разобраться, что каждая делает на самом деле, и половина загадочных поломок объясняется сама.

КомандаЧто делаетГде применяется
pinMode(вывод, режим)Назначает выводу роль: выход, вход или вход с подтяжкойОдин раз в setup() — до всего остального
digitalWrite(вывод, HIGH/LOW)Подаёт на вывод 5 В или 0 ВСветодиод, реле, транзистор, сигнал другой плате
digitalRead(вывод)Возвращает HIGH или LOW — что сейчас на выводеКнопка, концевик, датчик с цифровым выходом
analogRead(A0…A5)Число 0…1023 — насколько напряжение близко к опорномуПотенциометр, фоторезистор, датчик с аналоговым выходом
analogWrite(вывод, 0…255)Включает ШИМ: быстрое мигание с заданной долей включённого времениЯркость светодиода, скорость мотора

pinMode: три режима одного вывода

pinMode не «настраивает программу» — он щёлкает настоящими ключами внутри микросхемы. Вывод устроен так: к нему ведут два ключа (один к питанию, другой к земле) и отдельный резистор подтяжки. Режим решает, что из этого включено.

pinMode(8, INPUT_PULLUP)5 ВGNDключ к 5 Включ к земле20…50 кОмвывод 8Внутри включается резистор 20…50 кОм между выводом и 5 В.Пока никто не трогает — читается HIGH. Замкнули на землю — LOW.
pinMode не «настраивает программу» — он щёлкает настоящими ключами внутри микросхемы. Отсюда и правило: вход без подтяжки читать нельзя, у него просто нет определённого напряжения.

Самое частое недоразумение новичка — режим INPUT. Кажется, что «просто вход» и есть нормальное состояние, но такой вывод ни к чему не подключён. Напряжения на нём нет вовсе, и digitalRead возвращает то, что нанесло наводками: от соседнего провода, от руки, от сети 50 Гц. Показания скачут, и это не поломка платы.

Почему именно скачут, а не читаются нулём. Вход в этом состоянии — это сопротивление порядка сотни мегаом, то есть заряду просто некуда стечь. А граница между нулём и единицей — не точка: при питании 5 В всё, что между 1,5 и 3,0 вольта, лист данных считает неопределённым.

Одно исключение всё же есть — вывод 13 на Nano, Pro Mini и старых платах: там встроенный светодиод с резистором припаян прямо к выводу и тянет его вниз, так что читается почти всегда LOW. На Uno этого эффекта нет: светодиод развязан буфером на операционном усилителе, и вывод 13 ведёт себя как любой другой.

INPUT_PULLUP включает внутри резистор между выводом и питанием. В листе данных ATmega328/P он назван RPU, и его номинал — от 20 до 50 кОм: разброс большой, потому что это не отдельная деталь, а сопротивление открытого транзистора. Для кнопки этого достаточно с запасом.

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

const int PIN = 8;  // к этому выводу НАРОЧНО ничего не подключено

void setup() {
  Serial.begin(9600);
}

void loop() {
  // Читаем один и тот же вывод дважды: сначала обычным входом,
  // потом с включённой внутренней подтяжкой.
  pinMode(PIN, INPUT);
  delay(5);
  int floating = digitalRead(PIN);

  pinMode(PIN, INPUT_PULLUP);
  delay(5);
  int pulled = digitalRead(PIN);

  Serial.print("Без подтяжки: ");
  Serial.print(floating);
  Serial.print("   С подтяжкой: ");
  Serial.println(pulled);

  delay(500);
}

В мониторе порта левое число прыгает между нулём и единицей, правое — всегда единица. Отсюда и способ подключать кнопку двумя проводами: одна нога к выводу, вторая к земле, никаких резисторов снаружи. Логика при этом переворачивается — нажатая кнопка читается как LOW:

const int BUTTON = 2;

void setup() {
  // INPUT_PULLUP включает внутренний резистор: кнопку можно подключить
  // просто между выводом и землёй, без лишних деталей.
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // С подтяжкой логика перевёрнута: нажата — LOW, отпущена — HIGH.
  bool pressed = (digitalRead(BUTTON) == LOW);

  digitalWrite(LED_BUILTIN, pressed ? HIGH : LOW);

  if (pressed) {
    Serial.println("Кнопка нажата");
    delay(200);  // простая защита от дребезга контактов
  }
}

Историческая деталь, которая иногда встречается в старом коде: digitalWrite(вывод, HIGH) на выводе в режиме INPUT тоже включает подтяжку. Так писали до 2012 года, пока не появился INPUT_PULLUP. Причина не в программе, а в железе: уровнем выхода и подтяжкой управляет один и тот же бит внутри чипа. Код рабочий, но читается плохо — команда «записать» на самом деле ничего не записывает.

Из этого же общего бита растёт неприятная ловушка. Вывод, который был INPUT_PULLUP, при переводе в OUTPUT сразу становится единицей: бит-то остался установленным. Если снаружи к этому выводу подключено что-то, тянущее линию к земле, получится короткое замыкание. Лечится одной строкой, но поставить её надо до смены режима: digitalWrite(вывод, LOW), пока вывод ещё вход, гасит подтяжку, и только потом идёт pinMode(вывод, OUTPUT). Наоборот делать нельзя — между двумя строками вывод успеет выдать единицу.

Сколько тока можно взять с вывода

Здесь путаются чаще всего, потому что в интернете гуляет одно число — 40 мА. Оно есть в листе данных, но это абсолютный максимум: значение, за которым производитель обещает необратимую порчу чипа. Рабочее — вдвое меньше.

Что ограниченоПределПояснение
Один вывод, предел, за которым чип портится40 мААбсолютный максимум из листа данных. Это не рабочее значение
Один вывод, на что рассчитаны характеристики20 мА при 5 ВУсловия испытаний. За ними напряжение на выводе уже не гарантируется
Группа выводов (на Uno это 5–13 вместе)100 мАГрупп три: 5–13, отдельно A0–A5, отдельно 0–4 со сбросом
Весь чип, через выводы питания и земли200 мАТоже абсолютный максимум: за ним чип портится, а не «просто не даёт»
Вывод 3,3 В на плате Uno50 мАЭто уже не вывод чипа, а отдельный источник на плате

Забавная деталь: официальная документация Arduino сама себе противоречит. Учебная страница про цифровые выводы до сих пор пишет 40 мА, а спецификация платы Uno R3 — 20 мА. Верить надо второй: 40 — это предел разрушения из листа данных микросхемы.

И ещё одно, о чём почти не говорят: «единица» на выводе — это не ровно 5 вольт. Лист данных гарантирует не меньше 4,2 В при токе 20 мА. Чем больше тока вы берёте, тем сильнее просаживается выходное напряжение — отсюда и тусклые светодиоды в цепочках, собранных без транзистора.

Практический вывод: обычный светодиод с резистором — это 10–15 мА, и таких можно повесить несколько. А вот мотор, реле, лента адресных светодиодов и даже мощный зуммер с вывода не питаются: им нужен отдельный источник, а вывод только управляет транзистором или готовым драйвером. Подробнее — в разборе питания Arduino.

digitalWrite медленнее, чем кажется

Выглядит команда как одно действие, но внутри ядро успевает многое: трижды заглянуть в таблицы соответствия «номер вывода — порт, бит, таймер», проверить, не занят ли вывод ШИМ, и на всякий случай выключить ШИМ, а потом на время записи запретить прерывания.

Мы измерили это, собрав два одинаковых скетча и разобрав готовую прошивку: функция digitalWrite занимает 144 байта и 66 команд процессора. Прямая запись в регистр порта — PORTB |= (1 << PB0) — превращается в одну команду. Вся прошивка при этом весит 734 байта против 450.

Для мигалки разница не важна: 66 команд на 16 мегагерцах — это считаные микросекунды. Она становится важной, когда вывод дёргают десятки тысяч раз в секунду: программная передача данных, генерация сигнала, опрос ленты светодиодов. Скетч ниже покажет разницу на вашей собственной плате. Он рассчитан на Uno, Nano и Pro Mini: только там вывод 8 — это тот самый нулевой бит порта B. На Mega выводы разложены иначе, и сравнение получится не про то:

const int PIN = 8;  // это ножка PB0 — нулевой бит порта B

void setup() {
  Serial.begin(9600);
  pinMode(PIN, OUTPUT);
}

void loop() {
  // Замер 1: тысяча переключений обычной командой.
  unsigned long start = micros();
  for (int i = 0; i < 1000; i++) {
    digitalWrite(PIN, HIGH);
    digitalWrite(PIN, LOW);
  }
  unsigned long slow = micros() - start;

  // Замер 2: то же самое прямой записью в регистр порта.
  // Годится для Uno, Nano и Pro Mini: там вывод 8 — это как раз PB0.
  start = micros();
  for (int i = 0; i < 1000; i++) {
    PORTB |= (1 << PB0);
    PORTB &= ~(1 << PB0);
  }
  unsigned long fast = micros() - start;

  Serial.print("digitalWrite: ");
  Serial.print(slow);
  Serial.print(" мкс   напрямую: ");
  Serial.print(fast);
  Serial.println(" мкс");

  delay(2000);
}

Вывод простой: начинать надо с digitalWrite. Она понятная, переносится между платами, сама гасит ШИМ и не даст промахнуться мимо вывода. Прямая запись — приём для того редкого случая, когда упёрлись в скорость и точно знаете, какой бит какого порта дёргаете.

Кстати, про запрет прерываний внутри digitalWrite часто думают наоборот. Он нужен не для защиты вашего кода, а потому что ядро читает-меняет-записывает регистр через указатель, и эту тройку прерывание разорвать может. Одиночная команда sbi, в которую превращается прямая установка бита, неделима сама по себе и ни в какой защите не нуждается.

Побочный эффект, о котором стоит знать заранее: digitalRead тоже выключает ШИМ. Прочитали вывод 9 после analogWrite(9, 128) — яркость погасла. А вот pinMode ШИМ не трогает, хотя интуиция подсказывает обратное. Обе строчки видны в исходнике ядра.

analogRead: десять бит и сто микросекунд

analogRead не измеряет вольты. Он сравнивает напряжение на входе с опорным (на Uno это питание, 5 В) и возвращает, какая это доля, числом от 0 до 1023. Уровней 1024, поэтому одна ступенька — 4,883 мВ, а вольты считают так: значение умножить на 5 и разделить на 1024. В примерах Arduino часто делят на 1023 — разница меньше одной ступеньки, но в листе данных формула именно с 1024.

void setup() {
  Serial.begin(9600);
}

void loop() {
  int raw = analogRead(A0);  // 0…1023 — что «видит» плата

  // map() переводит один диапазон в другой: удобнее думать в процентах.
  int percent = map(raw, 0, 1023, 0, 100);

  Serial.print("Сырое значение: ");
  Serial.print(raw);
  Serial.print("  Это ");
  Serial.print(percent);
  Serial.println("%");

  delay(300);
}

Замер не мгновенный. Преобразование занимает 13 тактов самого АЦП, а ядро специально замедляет АЦП в 128 раз — до 125 кГц, потому что точность гарантируется только в диапазоне 50–200 кГц. Это записано прямо в исходнике ядра. Итого около 104 микросекунд на одно измерение: примерно девять тысяч замеров в секунду, и то если больше ничего не делать. Самое первое измерение после включения АЦП идёт дольше — 25 тактов вместо 13.

Ещё одна тонкость из листа данных: АЦП рассчитан на источники с сопротивлением примерно до 10 кОм — с такими о времени выборки можно вообще не думать. Внутри АЦП есть конденсатор, который надо успеть зарядить; если сигнал приходит через резистор в сотню килоом, зарядиться тот не успевает, и показания уползают в сторону предыдущего замера. Отсюда народный приём «читать датчик дважды и брать второе значение» — он лечит следствие, а не причину.

И про Nano отдельно: выводы A6 и A7 у него подключены только к АЦП. Они не умеют быть цифровыми, digitalRead и pinMode для них не работают, а подтяжки у них нет вовсе.

analogWrite — это не напряжение

Название сбивает с толку дважды. Во-первых, никакого аналогового напряжения плата не выдаёт: analogWrite включает ШИМ — вывод продолжает переключаться между нулём и пятью вольтами, меняется только доля времени, когда он наверху. Во-вторых, к аналоговым выводам A0–A5 и к analogRead эта команда отношения не имеет вовсе — так и написано в официальной справке.

analogWrite(9, 128)5 В0 Всреднее 2,51 ВНапряжение всё время либо 0, либо 5 вольт. Меняется только доля времени наверху.Светодиод и мотор усредняют это сами, а вольтметр и вход другой платы — нет.Вывод 9: 490 переключений в секунду. На выводах 5 и 6 — 977.
Крайние значения обрабатываются особо: analogWrite(пин, 0) и analogWrite(пин, 255) вызывают обычный digitalWrite и вообще выключают ШИМ. Это видно прямо в исходнике ядра.

Светодиод, мотор, нагреватель усредняют это сами: глаз не успевает за сотнями переключений в секунду, а мотор — за счёт инерции. А вот вход другой платы, аналоговая схема или ЦАП такое не примут: им нужен фильтр. Мультиметр покажет что-то среднее только потому, что усредняет он сам.

const int LED = 9;  // вывод с поддержкой ШИМ (значок ~ на плате)

void setup() {
  pinMode(LED, OUTPUT);
}

void loop() {
  // analogWrite умеет не только «включено/выключено», а 256 уровней яркости.
  for (int level = 0; level <= 255; level++) {
    analogWrite(LED, level);
    delay(5);
  }
  for (int level = 255; level >= 0; level--) {
    analogWrite(LED, level);
    delay(5);
  }
}

Выводов с ШИМ на Uno всего шесть, и на этом обычно заканчиваются попытки сделать цветную подсветку. Выход — адресные светодиоды: там один вывод управляет хоть сотней ламп, и у каждой свой цвет. Как это устроено, разобрано в статье «Адресные светодиоды WS2812B».

ШИМ умеют не все выводы, а частота у них разная — и это не мелочь, если вы фильтруете сигнал или управляете мотором. Частоты не взяты из воздуха: они вычисляются из настроек таймеров, которые ядро делает при старте.

Выводы UnoКто их качаетЧастотаКто ещё на них претендует
5 и 6таймер 0976,56 ГцОн же считает millis() и delay()
9 и 10таймер 1490,20 ГцЕго забирает библиотека Servo
3 и 11таймер 2490,20 ГцЕго забирает tone()

Откуда именно эти числа. Таймер 0 ядро настраивает в режим быстрого ШИМ с предделителем 64: 16 000 000 / (64 × 256) = 976,5625 Гц. Таймеры 1 и 2 работают в режиме с точной фазой, где полный цикл вдвое длиннее: 16 000 000 / (64 × 510) = 490,196 Гц. Обе строчки видны в файле ядра wiring.c.

Если вызвать analogWrite на выводе без ШИМ, ошибки не будет — и это главная ловушка. Ядро молча подставит digitalWrite: всё, что меньше 128, погасит вывод, всё, что от 128 и выше, включит его на полную. Плавной яркости не получится, а причину искать негде.

Два края обрабатываются особо. analogWrite(вывод, 0) и analogWrite(вывод, 255) вообще не включают ШИМ, а вызывают обычный digitalWrite. Полезное следствие: между 254 и 255 разница не «одна ступенька», а «ШИМ и постоянное питание». И ещё одна приятная мелочь — analogWrite сам делает pinMode(вывод, OUTPUT), так что отдельно объявлять вывод не обязательно.

Кто ещё претендует на таймеры

Таймеров всего три, а желающих больше. tone() берёт таймер 2 и на время звука ломает ШИМ на выводах 3 и 11. Библиотека Servo берёт таймер 1 — прощай ШИМ на 9 и 10. Таймер 0 трогать нельзя вовсе: на нём держатся millis() и delay().

const int LED = 11;     // ШИМ на этом выводе качает таймер 2
const int BUZZER = 8;

void setup() {
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
}

void loop() {
  analogWrite(LED, 128);
  Serial.println("Только свет: светодиод горит вполнакала");
  delay(2000);

  // tone() забирает себе таймер 2 — тот самый, что обслуживает выводы 3 и 11.
  tone(BUZZER, 440);
  Serial.println("Пошёл звук: яркость на выводе 11 сбилась");
  delay(2000);

  // После noTone яркость сама не вернётся — её нужно задать заново.
  noTone(BUZZER);
  analogWrite(LED, 128);
  Serial.println("Звук выключен, яркость задана заново");
  delay(2000);
}

Обратите внимание на две вещи. Первая: зуммер в скетче висит на выводе 8, а ломается ШИМ на выводе 11 — таймер занимается целиком, независимо от того, где именно играет звук. Вторая: после noTone() яркость сама не возвращается, её нужно задать заново. Это не ошибка библиотеки — таймер просто отдали обратно в том состоянии, в котором забрали.

Про tone() полезно знать ещё две вещи. Одновременно на Uno может звучать только один тон: вызов на втором выводе не сработает, пока не сделан noTone(). И ниже 31 герца звук не получится — дальше не хватает делителей таймера.

Самый неприятный случай — когда в проекте есть и сервопривод, и звук. Тогда заняты таймеры 1 и 2, и под analogWrite остаются только выводы 5 и 6.

map(): две ловушки

map() переводит число из одного диапазона в другой, и это честно написано в справке. Не написано другое: считает он целыми числами и остаток отбрасывает, а результат не ограничивает.

void setup() {
  Serial.begin(9600);
}

void loop() {
  int raw = analogRead(A0);  // 0…1023

  // Ловушка первая: map() считает целыми числами и остаток отбрасывает.
  int percent = map(raw, 0, 1023, 0, 100);

  // Ловушка вторая: map() НЕ ограничивает результат. Стоит датчику выйти
  // за 200…800, и проценты уедут в минус или за сотню.
  int narrow = map(raw, 200, 800, 0, 100);
  int safe = constrain(narrow, 0, 100);

  Serial.print(raw);
  Serial.print(" -> ");
  Serial.print(percent);
  Serial.print("%   узкий диапазон: ");
  Serial.print(narrow);
  Serial.print("   после constrain: ");
  Serial.println(safe);

  delay(300);
}

Первое проявляется, когда диапазоны не делятся нацело: 1023 ступеньки, разложенные на 100 процентов, дают проценты, которые перескакивают. Второе куда опаснее. Если вы сузили диапазон под свой датчик — скажем, 200…800, — а датчик выдал 150, map() послушно вернёт отрицательное число. Дальше оно уедет в analogWrite, и яркость прыгнет вместо того чтобы погаснуть. Лечится обёрткой constrain.

На других платах не всё так же

Команды называются одинаково, но за ними разное железо. Самое коварное — LED_BUILTIN на ESP8266: там светодиод подключён наоборот, и digitalWrite(LED_BUILTIN, LOW) его зажигает.

ПлатаanalogReadanalogWriteLED_BUILTIN
Arduino Uno, Nano0…1023 (10 бит), шесть входов0…255, шесть выводов13
Arduino Mega 25600…1023 (10 бит), шестнадцать входов0…255, пятнадцать выводов (2–13 и 44–46)13
ESP8266 (NodeMCU, Wemos)0…1023, но вход один и всего до 3,2 В0…255 в ядрах 3.x, раньше было 0…10232, и горит он от LOW
ESP320…4095 (12 бит), шкала неровная0…255 в новых ядрах, раньше был ledcWriteчаще 2, зависит от платы

У ESP8266 аналоговый вход всего один, и сам чип принимает не больше одного вольта — на готовых платах вроде NodeMCU перед ним стоит делитель, поэтому подавать можно около 3,2 В. У ESP32 входов много, но шкала заметно неровная, а половина входов перестаёт работать при включённом Wi-Fi. Про это подробно — на странице ESP8266.

Частые ошибки

Что видноПричинаЧто делать
Кнопка «нажимается» сама, показания скачутВход без подтяжкиpinMode(вывод, INPUT_PULLUP) и кнопку между выводом и землёй
Светодиод горит еле-еле, хотя резистор правильныйЗабыт pinMode(вывод, OUTPUT) — светодиод питается через подтяжкуЧерез подтяжку идут десятые доли миллиампера. Добавить pinMode в setup()
Плата греется или перезагружается под нагрузкойС вывода берут больше 20 мАМощную нагрузку — через транзистор или готовый драйвер
analogWrite не даёт яркость: свет либо погас, либо на полнуюВывод без значка ~ — ШИМ на нём нет, и ядро молча зовёт digitalWriteПеренести на 3, 5, 6, 9, 10 или 11
Вывод скакнул в HIGH и закоротил цепь при переводе в OUTPUTОн был INPUT_PULLUP — бит подтяжки остался и стал уровнем выходаСначала digitalWrite(вывод, LOW), и только потом pinMode(вывод, OUTPUT)
Проценты уходят в минус или за сотнюmap() не ограничивает результатОбернуть в constrain(значение, 0, 100)
Заиграл зуммер — сбилась яркость на выводе 3 или 11tone() забрал таймер 2Перенести светодиод на 5, 6, 9 или 10
digitalRead(A6) на Nano всегда возвращает одно и то жеA6 и A7 у Nano — только аналоговые входыВзять любой другой вывод или читать через analogRead

Все скетчи из этой статьи собраны компилятором и лежат в каталоге готового кода. Если команда подчёркивается в редакторе красным или сборка ругается на незнакомое слово — загляните в разбор ошибок компиляции.

Частые вопросы

Чем INPUT_PULLUP отличается от INPUT?

INPUT_PULLUP включает внутри микросхемы резистор между выводом и питанием. По листу данных ATmega328/P его номинал — от 20 до 50 кОм. Без подтяжки вход висит в воздухе и digitalRead возвращает случайные значения: наводок хватает, чтобы вывод «дребезжал» сам по себе. С подтяжкой логика переворачивается: отпущенная кнопка читается как HIGH, нажатая на землю — как LOW.

Сколько тока можно взять с вывода Arduino?

Лист данных ATmega328/P даёт 40 мА как абсолютный максимум одного вывода — это значение, за которым чип портится, а не рабочее. Рабочим считается ток условий испытаний: 20 мА при питании 5 В. Есть и второй предел: сумма токов группы выводов не должна превышать 100 мА, а через выводы питания и земли всего чипа — 200 мА. Мотор, реле и лента светодиодов питаются не от вывода, а от отдельного источника.

Почему analogWrite не даёт настоящее напряжение?

Потому что это не цифро-аналоговый преобразователь, а ШИМ: вывод очень быстро переключается между 0 и 5 вольтами, и меняется только доля времени наверху. Светодиод, мотор и нагреватель усредняют это сами, а вольтметр покажет что-то среднее лишь потому, что усредняет он. Питать от такого вывода вход другой платы или аналоговую схему нельзя — нужен фильтр или настоящий ЦАП.

Какие выводы Arduino Uno умеют ШИМ и с какой частотой?

Шесть: 3, 5, 6, 9, 10 и 11 — на плате они помечены значком ~. Частоты разные, и это видно прямо в исходнике ядра: выводы 5 и 6 качает таймер 0 в режиме быстрого ШИМ с предделителем 64, отсюда 16 000 000 / (64 × 256) = 976,56 Гц. Выводы 9, 10 и 3, 11 работают от таймеров 1 и 2 в режиме с точной фазой: 16 000 000 / (64 × 510) = 490,20 Гц.

Почему analogRead возвращает 0…1023?

У ATmega328/P десятибитный АЦП: он делит измеряемый диапазон на 1024 ступеньки, поэтому наибольшее число — 1023, а шаг при опоре 5 В равен примерно 4,9 мВ. Одно измерение занимает 13 тактов АЦП, а ядро ставит АЦП предделитель 128, то есть 125 кГц — около 104 микросекунд на замер. У ESP32 другой АЦП: 12 бит и диапазон 0…4095.

Почему map() возвращает не то, что ожидалось?

У map() две ловушки. Первая: он считает целыми числами и дробную часть отбрасывает, поэтому 1023 ступеньки, разложенные на 100 процентов, дают заметные скачки. Вторая: map() не ограничивает результат. Если вы сжали диапазон датчика, скажем, до 200…800, а датчик выдал 150, то на выходе получится отрицательное число. Лечится обёрткой constrain.

Почему после tone() сбилась яркость светодиода?

Потому что tone() на Uno забирает себе таймер 2 — тот самый, который делает ШИМ на выводах 3 и 11. Пока играет звук, analogWrite на этих двух выводах работать не будет, а после noTone() яркость нужно задать заново. Такая же история у библиотеки Servo: она занимает таймер 1 и ломает ШИМ на выводах 9 и 10.

Обновлено: 25 августа 2026