Arduino Uno R3: цифровые входы, аналоговое измерение и PWM без путаницы
Почему классическая Uno остаётся отдельной платформой, как читаются кнопки и датчики и чем широтно-импульсный выход отличается от настоящего аналогового напряжения.

Uno — семейство, R3 — конкретная плата
Название Uno сегодня объединяет существенно разные устройства. В официальном справочнике Arduino классическая R3 выделена сочетанием ATmega328P, знакомой геометрии разъёмов и программного ядра Arduino Uno из пакета Arduino AVR Boards. Совпадение расположения контактов с другой Uno не означает совпадения процессора, драйверов и поведения всех библиотек.
Uno R4 использует 32-битный Renesas RA4M1 и другой пакет плат. У Uno WiFi Rev2 — ATmega4809, а не ATmega328P. Поэтому пример, рассчитанный на низкоуровневые регистры старого AVR, нельзя считать универсальной программой для любого изделия с надписью Uno. В этой статье рассматривается именно R3: классическая восьмибитная платформа, а не обзор новинок всего семейства.
Есть различие и внутри R3. В обычной версии микроконтроллер установлен в панельке, в SMD-варианте припаян к плате. Сторонние совместимые изделия могут использовать другие USB-последовательные преобразователи и требовать собственных драйверов. Эти особенности относятся к конкретной реализации платы, а не меняют смысл цифрового входа или функцию analogRead. Модель в среде разработки выбирают по фактическому оборудованию, а не только по похожему цвету и форме.
Контроллер, память и разъёмы
Основной ATmega328P работает в Uno R3 с частотой 16 МГц. Для программы предусмотрено 32 КБ Flash, для оперативных данных — 2 КБ SRAM, для сохраняемых между выключениями значений — 1 КБ EEPROM. Это три разных ресурса: свободное место для скетча не заменяет оперативную память, которую занимают переменные и буферы во время выполнения.
В составе платы также есть ATmega16U2, обслуживающий USB-соединение, разъём USB-B, вход питания, кнопка Reset и ICSP. USB используется для подключения к компьютеру и может питать плату. При автономном питании роль USB-кабеля и внешнего источника нужно различать; электрические пределы задаются схемой конкретного входа, а не формой разъёма.
Распиновка показывает четырнадцать цифровых линий и шесть аналоговых входов. Некоторые контакты имеют альтернативные назначения: A4 и A5 используются для I2C, отдельные цифровые линии — для SPI. Поэтому число установленных на плату модулей расширения само по себе ещё не описывает их совместимость. Два устройства могут претендовать на одинаковую линию, а подключаемая плата — занимать вывод, уже задействованный скетчем. Схема соединений и назначение контактов остаются частью программы.

| Ресурс | Объём | Назначение |
|---|---|---|
| Flash | 32 КБ | Программа |
| SRAM | 2 КБ | Оперативные данные |
| EEPROM | 1 КБ | Сохраняемые значения |
Источник: Arduino Uno R3 User Manual: Memory
Почему кнопка без подтяжки даёт случайные значения
Режим pinMode определяет электрическое поведение цифрового контакта. В состоянии INPUT он имеет высокое входное сопротивление и считывает воздействие внешней цепи, а не формирует устойчивое напряжение самостоятельно. Если разомкнутая кнопка оставляет провод ни к чему не подключённым, возникает плавающий вход: программа может получать меняющиеся значения без реального нажатия.
Подтягивающий резистор задаёт известное состояние такой цепи. При pull-down ненажатая кнопка обычно соответствует LOW, а замыкание на питание — HIGH. При pull-up логика обратная: без нажатия вход удерживается в HIGH, при соединении с землёй становится LOW. Внутренняя подтяжка ATmega включается режимом INPUT_PULLUP, поэтому отдельный внешний резистор требуется не во всякой простейшей схеме.
Именно здесь часто расходятся электрическая схема и бытовое представление «единица означает нажато». Значение зависит от соединения кнопки, а не от её внешнего вида. В скетче условие нажатия должно соответствовать выбранной схеме. OUTPUT — третий режим: контакт уже управляет состоянием цепи, а не только наблюдает за ним. Перестановка этих режимов не является косметическим изменением кода.
Аналоговый вход измеряет напряжение, не название датчика
Официальный пример Analog Input использует потенциометр или фоторезисторную цепь. Для потенциометра крайние выводы соединяются с питанием и землёй, средний — с A0. При вращении движка меняется напряжение на среднем контакте. Именно его преобразует АЦП; команда не измеряет механический угол непосредственно и не узнаёт автоматически сопротивление подключённой детали.
В рассмотренном примере диапазон от нуля до пяти вольт представлен целыми значениями от 0 до 1023. Это десятибитное преобразование. Число 512 здесь означает положение примерно посередине шкалы данного измерения, но ещё не температуру, освещённость или универсальную физическую единицу. Связь с физической величиной определяется датчиком, схемой и обработкой показаний.
В учебном скетче результат управляет длительностью мигания встроенного светодиода. Получается последовательность: напряжение считывается, число сохраняется, затем используется как задержка. Положение ручки меняет продолжительность цикла, а не непосредственно яркость. Такой пример удобен именно тем, что отделяет аналоговое измерение от последующего действия программы: один и тот же входной отсчёт можно использовать в совершенно разных алгоритмах.

analogWrite и широтно-импульсный выход
На Uno R3 поддерживаемые PWM-контакты — 3, 5, 6, 9, 10 и 11. Для них analogWrite принимает значения от 0 до 255. Название функции может создавать впечатление, будто любой контакт выдаёт произвольное постоянное аналоговое напряжение. В действительности для классической Uno здесь используется широтно-импульсный сигнал, а не отдельный универсальный ЦАП на каждом выводе.
В справочнике Arduino пример связывает потенциометр с PWM: analogRead возвращает диапазон до 1023, затем значение делится на четыре для шкалы до 255. Это преобразование диапазона чисел, а не повышение точности измерения. Внешнее устройство воспринимает получающийся сигнал в соответствии со своей электрической схемой; функция не делает силовую нагрузку безопасной для прямого питания от контакта контроллера.
Документация перечисляет PWM-пины отдельно для разных плат и предупреждает о зависимости дополнительных возможностей от таймеров. У некоторых других Arduino действительно есть выходы DAC, но это не свойство Uno R3. Поэтому одинаковая строка analogWrite на разных архитектурах должна читаться вместе с описанием выбранного оборудования. Метка тильды возле контакта помогает найти штатные PWM-линии, не заменяя полную распиновку.
Ожидание времени без остановки всего скетча
Пример Blink Without Delay посвящён другому ограничению простых программ: задержка delay останавливает выполнение последовательного кода на заданное время. Если в этот момент нужно опросить кнопку, основной цикл не делает этого до завершения ожидания. Светодиод может мигать правильно, но короткое событие между двумя опросами останется незамеченным.
В неблокирующем варианте сохраняется время последнего переключения, а при каждом прохождении loop проверяется, прошёл ли нужный интервал. Источником времени служит millis, возвращающая число миллисекунд после начала работы текущего скетча. До наступления момента переключения программа может выполнять другие короткие действия и снова возвращаться к проверке.
Это не превращает восьмибитный контроллер в компьютер с несколькими независимыми потоками. Меняется организация последовательной работы: программа не тратит весь интервал на одну команду ожидания. Для простого индикатора достаточно встроенного светодиода; внешний вариант в учебной схеме подключается через ограничивающий резистор. Так две задачи — периодическое переключение и регулярный опрос входа — описываются отдельными состояниями одного цикла, без необходимости выдавать паузу за параллельное выполнение.


