Основы · 9 мин чтения

Блок «если» в блочном коде: кнопка и светодиод на Arduino с if/else

Блок «если» в блочном коде на примере кнопки и светодиода на Arduino: чтение пинов, if/else, =, ≠, <, >, вложенные условия, вкл/выкл одной кнопкой, антидребезг и ночник на LDR.

Блок «если» в блочном коде позволяет программе выбрать один из двух путей в зависимости от ответа на вопрос: «Кнопка нажата? Если да, включи светодиод; если нет, выключи». В C++ для Arduino эта конструкция называется if/else, а блок «если … то … иначе» в BlueGrays — её точное соответствие. В этой статье на проекте кнопка и светодиод на Arduino ты узнаешь, как настроить пин на вход и прочитать его, а затем разберёшь блок «если», операторы сравнения, вложенные условия и объединение двух условий через «и» — блок за блоком и строка за строкой.

Эта статья — 3-я часть серии От блоков к коду. В предыдущей части мы написали первую программу и помигали светодиодом с помощью блоков, а в следующей разберём циклы и переменные.

До сих пор наши программы всегда делали одно и то же: светодиод загорался, ждал, гас и снова ждал. Внешний мир их совсем не интересовал. Когда появляются условия, плата начинает принимать решения, глядя на кнопку, датчик освещённости или измеренное расстояние, и именно здесь начинается самое интересное в программировании роботов. Все примеры здесь взяты из бесплатных блочных проектов, поэтому их блоки и код можно открыть на странице «Блочный код» или в приложении и следить за статьёй параллельно.

Вход и выход: в какую сторону работает пин?

Цифровые пины Arduino выполняют одну из двух задач. Пин, настроенный как выход, выдаёт 5 V (HIGH) или 0 V (LOW); так управляют светодиодом, зуммером или реле. Пин, настроенный как вход, ничего не выдаёт и только «слушает» напряжение на себе: на Arduino Uno всё, что выше примерно 3 V, читается как HIGH, а всё, что ниже 1,5 V, — как LOW. В блоках этот выбор делается в разделе настройки: блок «настроить пин 13 как INPUT» в C++ становится pinMode(13, INPUT);, а «настроить пин 7 как OUTPUT» — pinMode(7, OUTPUT);. Чтобы прочитать пин, используется блок «прочитать пин 13». Он выглядит не так, как остальные: это не команда, которую ставят в стопку, а скруглённый блок значения, который вставляется в гнездо внутри другого блока. Его соответствие в C++ — digitalRead(13), и эта функция возвращает HIGH или LOW. Поскольку на Arduino HIGH равно 1, а LOW равно 0, результат можно сохранить в переменную, как число. Короче говоря, блоки команд что-то делают, блоки значений дают результат, а гнездо условия блока «если» можно заполнить только таким результатом.

БлокСоответствие в C++Что делает
настроить пин 13 как INPUTpinMode(13, INPUT);Переводит пин в режим прослушивания (один раз, в настройке)
настроить пин 7 как OUTPUTpinMode(7, OUTPUT);Позволяет пину выдавать напряжение
прочитать пин 13digitalRead(13)Возвращает HIGH (1) или LOW (0)
записать HIGH в пин 7digitalWrite(7, HIGH);Подаёт на пин 5 V, светодиод загорается
аналоговое чтение A0analogRead(A0)Возвращает число от 0 до 1023
если … то … иначеif (…) { … } else { … }Выполняет один из двух путей в зависимости от условия

Подключение: кнопка на пине 13, светодиод на пине 7, стягивающий резистор обязателен

В проекте «Управление светодиодом кнопкой (Push)» кнопка подключена к D13, а светодиод — к D7. Одна ножка кнопки идёт на 5V, другая — на D13, а между D13 и GND стоит стягивающий резистор (pull-down) на 10 kΩ. Когда кнопка отпущена, резистор притягивает пин к GND, и пин читается как LOW. Когда кнопку нажимают, 5V попадает прямо на пин, и он читается как HIGH. Поскольку сопротивление резистора большое, пока кнопка нажата, от 5V к GND течёт всего около половины миллиампера. Длинная ножка светодиода подключается к D7 через резистор 220 Ω, а короткая — к GND.

ДетальКуда подключаетсяПин Arduino Uno
Кнопка, ножка 1Напрямую5V
Кнопка, ножка 2 (по диагонали)НапрямуюD13
Резистор 10 kΩ (pull-down)Между D13 и GNDD13 – GND
Длинная ножка светодиода (анод)Через резистор 220 ΩD7
Короткая ножка светодиода (катод)НапрямуюGND
Если пропустить стягивающий резистор, при отпущенной кнопке D13 ни к чему не подключается; это называется «висящий» вход (floating). Пин ловит электрические помехи, digitalRead() возвращает случайные HIGH и LOW, и светодиод мерцает, хотя ты ничего не трогаешь, а то и загорается, когда рядом оказывается рука. У кнопок с четырьмя ножками две ножки с одной стороны уже соединены внутри, поэтому используй ножки по диагонали. Подробнее — в статьях Как подключить кнопку к Arduino и подтягивающие и стягивающие резисторы (pull-up и pull-down).

Блок «если» и if/else: светодиод горит, пока нажата кнопка

Блочная версия проекта состоит из двух разделов. В разделе «настройка (один раз)» пин 13 настраивается как INPUT, а пин 7 — как OUTPUT. В разделе «повторять всегда» стоит один большой блок: если … то … иначе. В его шестиугольном гнезде условия находится сравнение «прочитать пин 13 = HIGH». Если условие истинно, выполняется блок «записать HIGH в пин 7» в ветке «то»; если ложно — блок «записать LOW в пин 7» в ветке «иначе».

Блок «если» в блочном коде: блоки проекта «Управление светодиодом кнопкой (Push)»
Пин 13 — вход (INPUT), пин 7 — выход (OUTPUT); если пин 13 читается как HIGH, светодиод загорается, иначе гаснет.
C++ (Arduino IDE)
1void setup() {
2  pinMode(13, INPUT);    // Buton girişi (harici pull-down) / Button input (external pull-down)
3  pinMode(7, OUTPUT);    // LED çıkışı / LED output
4}
5
6void loop() {
7  if (digitalRead(13) == HIGH) {   // Buton basılı mı? / Is the button pressed?
8    digitalWrite(7, HIGH);         // Basılı: LED yanar / Pressed: LED on
9  } else {
10    digitalWrite(7, LOW);          // Bırakıldı: LED söner / Released: LED off
11  }
12}
13

Поставь код рядом с блоками, и соответствие становится очевидным. Слово if соответствует «если», условие digitalRead(13) == HIGH в скобках — гнезду условия, первая пара фигурных скобок — ветке «то», а else со своими скобками — ветке «иначе». Каждый блок, который ставится в ветку, становится строкой внутри соответствующих скобок в коде. Поскольку loop() выполняется десятки тысяч раз в секунду, плата читает кнопку снова и снова; как только ты убираешь палец, на следующем проходе условие становится ложным, и светодиод гаснет. Поэтому проект и называется «Push»: светодиод горит, только пока ты держишь кнопку. Ветка «иначе» не обязательна: блок «если» только с веткой «то» превращается в if без else. Но если убрать здесь ветку «иначе», то светодиод, загоревшись один раз, больше никогда не погаснет, потому что не останется строки, которая его выключает. Продумывать обе ветки для каждого условия — хорошая привычка.

Блоки сравнения: =, ≠, < и >

Знак в блокеC++ЗначениеПример из проектов
===равноdigitalRead(13) == HIGH (светодиод с кнопкой, Push)
≠!=не равноbutton != lastButton (вкл/выкл светодиода кнопкой)
<<меньшеvalue < 50 (ночник на LDR)
>>большеdistance > minDistance (расстояние с HC-SR04)
Знак «=» в блоке сравнения в C++ записывается как ==. Одиночный знак равенства в C++ — это не сравнение, а присваивание. Если написать if (button = 1), компилятор не остановит: переменной button присваивается 1, результат не равен нулю, поэтому условие истинно на каждом проходе, и светодиод горит независимо от кнопки. В блоках такую ошибку допустить невозможно, потому что присваивание («установить … в …») и сравнение — это разные блоки. А вот при переходе к коду это самая частая ошибка из всех.

Вкл/выкл одной кнопкой: вложенные «если» и переменная состояния

В проекте Push светодиод горит, только пока ты держишь кнопку. Если нужно поведение настоящего выключателя света («одно нажатие — включить, ещё одно — выключить»), программа должна помнить две вещи: горит ли светодиод прямо сейчас и что показала кнопка на предыдущем проходе. Проект «Переключение светодиода кнопкой (вкл/выкл)» объявляет для этого две целочисленные переменные в разделе «глобальные переменные (в начале)»: ledState (0 = выключен, 1 = включён) и lastButton (предыдущее показание). Схема та же, что и раньше: кнопка на D13 с внешним стягивающим резистором, светодиод на D7.

Блоки проекта «Переключение светодиода кнопкой (вкл/выкл)»: вложенный блок «если», сравнение ≠ и блок «не»
Внешний блок «если» ловит изменение состояния кнопки, внутренний проверяет, что это нажатие; «не ledState» переворачивает состояние светодиода.
C++ (Arduino IDE)
1int ledState = 0;     // LED durumu: 0 = sönük, 1 = yanık / LED state: 0 = off, 1 = on
2int lastButton = 0;   // Butonun önceki okuması / Previous button reading
3
4void setup() {
5  pinMode(13, INPUT);   // Buton girişi (harici pull-down) / Button input (external pull-down)
6  pinMode(7, OUTPUT);   // LED çıkışı / LED output
7}
8
9void loop() {
10  int button = digitalRead(13);   // Butonu oku / Read the button
11  if (button != lastButton) {     // Buton durumu değişti / Button state changed
12    if (button == 1) {            // Yalnız basış anında (LOW -> HIGH) / Only at the press (LOW -> HIGH)
13      ledState = !ledState;       // Durumu ters çevir / Flip the state
14      digitalWrite(7, ledState);
15    }
16    delay(50);                    // Sıçramayı atlamak için kısa bekleme / Short wait to skip the bounce
17    lastButton = button;          // Bu okumayı sakla / Store this reading
18  }
19}
20
БлокСтрока C++Задача
объявить целое (int) ledState = 0int ledState = 0;Хранит состояние светодиода
объявить целое (int) lastButton = 0int lastButton = 0;Хранит предыдущее показание кнопки
установить button в прочитать пин 13int button = digitalRead(13);Читает текущее состояние кнопки
если button ≠ lastButtonif (button != lastButton) {Заходит внутрь, если состояние кнопки изменилось
если button = 1if (button == 1) {Заходит внутрь, если изменение — это нажатие (с 0 на 1)
установить ledState в не ledStateledState = !ledState;Превращает 0 в 1, а 1 в 0
записать ledState в пин 7digitalWrite(7, ledState);Переводит светодиод в новое состояние
ждать 50 мсdelay(50);Пропускает дребезг контактов
установить lastButton в buttonlastButton = button;Сохраняет это показание для следующего прохода

Сердце программы — пара вложенных блоков «если». Внешнее условие button ≠ lastButton истинно только на том проходе, где состояние кнопки меняется; за тысячи проходов, пока ты держишь кнопку или вообще её не трогаешь, ничего не происходит. Изменение бывает двух видов: нажатие (с 0 на 1) или отпускание (с 1 на 0). Внутреннее условие button = 1 выбирает только нажатие. Так светодиод меняет состояние один раз за нажатие и совсем не меняет его при отпускании. В коде вложенные if выглядят как скобки внутри скобок. В блоках внутренний блок «если» стоит в ветке «то» внешнего, поэтому с первого взгляда видно, какая строка от какого условия зависит.

Блок не ledState в C++ записывается как !ledState. Восклицательный знак даёт логическую противоположность: противоположность 0 — это 1, а противоположность любого ненулевого числа — 0. Присваивание ledState его же противоположности переключает состояние при каждом нажатии. Следующий блок, «записать ledState в пин 7», — это строка digitalWrite(7, ledState); поскольку HIGH равно 1, а LOW равно 0, значение переменной можно записать прямо в пин. Наконец, lastButton получает показание этого прохода, чтобы сравнение на следующем проходе было верным. Если забыть это присваивание, lastButton так и останется 0; пока ты держишь кнопку, внешнее условие истинно на каждом проходе, и светодиод быстро мигает.

Блок ждать 50 мс — не украшение, а простой способ антидребезга (debounce). Металлические контакты кнопки при замыкании несколько миллисекунд то размыкаются, то замыкаются; плата читает так быстро, что может принять одно нажатие за несколько, и светодиод в итоге случайно остаётся включённым или выключенным. Пауза 50 мс после изменения даёт дребезгу время затихнуть. Пока delay() ждёт, плата ничем другим заниматься не может; об отсчёте времени без остановки программы читай в статье millis() и delay().

Аналоговое условие: ночник на LDR

Условия бывают не только про HIGH и LOW. В проекте «Ночник на LDR» блок «установить value в аналоговое чтение A0» превращает напряжение на A0, куда подключён фоторезистор (LDR), в число от 0 до 1023; в C++ это строка value = analogRead(A0);. Затем блок «если» проверяет value < 50. Если значение меньше 50, считается, что темно, и светодиод на D13 загорается; иначе он гаснет. Структура та же, что у проекта Push; отличается только сравнение в гнезде условия.

Блоки проекта «Ночник на LDR»: аналоговое чтение A0 и условие value < 50
Аналоговое чтение даёт число от 0 до 1023; если value меньше 50, светодиод загорается, иначе гаснет.
C++ (Arduino IDE)
1int value;   // Işık okuması (0-1023) / Light reading (0-1023)
2
3void setup() {
4  pinMode(13, OUTPUT);   // LED çıkışı / LED output
5}
6
7void loop() {
8  value = analogRead(A0);   // Işık seviyesini oku / Read the light level
9
10  // Eşik 50: altı karanlık sayılır, hassasiyeti bu sayıyla ayarla
11  // Threshold 50: anything below counts as dark. Tune the sensitivity with this number
12  if (value < 50) {
13    digitalWrite(13, HIGH);   // Karanlık: LED yanar / Dark: LED on
14  } else {
15    digitalWrite(13, LOW);    // Aydınlık: LED söner / Bright: LED off
16  }
17}
18

В зависимости от твоего фоторезистора и резистора в схеме порог 50 может оказаться для твоей комнаты слишком низким или слишком высоким. Чтобы найти подходящее число, сначала с помощью проекта «Измерение освещённости с LDR» посмотри в мониторе порта значения на свету и в темноте, а потом поставь порог между ними. Если значение колеблется прямо около порога, светодиод может мерцать; изящное решение — два отдельных порога для включения и выключения. Как работает фоторезистор, рассказано в статье Фоторезистор (LDR).

Объединяем условия: блок «и» и &&

Иногда одного условия мало. В проекте «Измерение расстояния с HC-SR04 (монитор порта)» измеренное расстояние выводится в монитор порта, только если оно от 3 см до 100 см. В блоках два сравнения соединяются рядом блоком и: «distance > minDistance и distance < maxDistance». В C++ эта строка становится if (distance > minDistance && distance < maxDistance). Оператор && делает результат истинным, только если истинны обе стороны; если ложна хотя бы одна, условие ложно. Так бессмысленные значения за пределами диапазона датчика никогда не попадают на экран. «Или» в C++ записывается как ||, и тогда достаточно одного истинного условия. Таблицы истинности AND (И), OR (ИЛИ) и NOT (НЕ) можно попробовать в утилите логических элементов.

Те же условия на ESP32: встроенная подтяжка и инверсная логика

Проект «Управление светодиодом кнопкой на ESP32 (Push)» использует тот же блок «если» на ESP32, но с двумя отличиями. Светодиод на GPIO 5, кнопка на GPIO 4, а для пина кнопки в блоке режима пина выбран вход с подтяжкой (INPUT_PULLUP). В C++ это pinMode(BUTTON_PIN, INPUT_PULLUP);: резистор внутри чипа подтягивает пин к HIGH, поэтому внешний резистор не нужен. На этот раз кнопка подключается к GND, так что при нажатии пин читается как LOW, и условие становится «прочитать пин BUTTON_PIN = LOW». Проект «Управление светодиодом кнопкой на ESP32 (Toggle)» делает вкл/выкл не через паузу 50 мс, а через блок прошедшего времени «миллисекунд с запуска», то есть millis(), и снова объединяет два условия блоком «и». Пины ESP32 работают от 3,3 V; не подключай кнопку к 5 V.

Частые ошибки и как их исправить

ОшибкаПризнакРешение
Нет стягивающего резистораСветодиод мерцает без причины и загорается, когда рядом рукаПоставь 10 kΩ между D13 и GND или используй INPUT_PULLUP и инвертируй логику
Одиночный знак равенства в условии: if (button = 1)Светодиод горит всегда и не реагирует на кнопкуДля сравнения используй ==
Точка с запятой в конце строки ifКод в фигурных скобках выполняется на каждом проходе независимо от условияУдали ; после if (…)
Используются ножки кнопки с одной стороныПин всегда читается как HIGH или всегда как LOWИспользуй ножки по диагонали
В переключателе не обновляется lastButton или нет паузыСветодиод мигает, пока кнопка нажата, или остаётся в случайном состоянииДобавь lastButton = button и паузу 50 мс
HIGH при INPUT_PULLUP принимается за нажатиеСветодиод работает наоборот и загорается при отпусканииСо встроенной подтяжкой LOW означает «нажата»
Порог LDR не подходит для комнатыСветодиод никогда не загорается или горит всегдаПосмотри значение в мониторе порта и выбери новый порог

Блоки и код рядом в приложении

Все проекты из этой статьи входят в число бесплатных блочных проектов в приложении BlueGrays. Включи переключатель Показать блоками в разделе кода проекта, и вместо кода появится та же программа в виде блоков; нажми на изображение, чтобы открыть его на весь экран. Вкладка Разбор блоков проводит по программе шаг за шагом: на каждом шаге видны только блоки этого шага и то, что они делают, так что вложенные блоки «если» можно разобрать по одному. Примеры if/else и digitalRead в Справочнике по коду тоже показаны блоками. Блоки не загружаются в плату напрямую, и пока нельзя собрать собственную программу, расставляя блоки; ты всегда копируешь настоящий код проекта на C++ в Arduino IDE и загружаешь его оттуда. Если хочется повторить изученное, раздел Вопросы дня каждый день даёт 5 вопросов уровней от A1 до C2.

Теперь, когда условия тебе знакомы, следующий шаг — повторения и счётчики: в части циклы и переменные ты увидишь, как «повторять всегда» связано с loop(), а блок «считать» — с циклом for. А пока в приложении BlueGrays можно посмотреть схему подключения и код проектов со светодиодом на кнопке, ночником на LDR и кнопкой на ESP32, переключиться на блочный вид через Показать блоками и на пошаговое объяснение через Разбор блоков.

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

Что делает блок «если» в блочном коде?

Блок «если» позволяет программе принять решение: если условие истинно, выполняются блоки в ветке «то», если ложно — в ветке «иначе». В проектах на Arduino его обычно используют, чтобы проверить, нажата ли кнопка или перешло ли значение датчика через порог. Его соответствие в C++ — конструкция if/else.

Чем if отличается от else в Arduino?

if выполняет код в своих фигурных скобках, когда условие в круглых скобках истинно. else — необязательная часть, в ней находится код, который выполняется только тогда, когда условие ложно. Без else при ложном условии ничего не происходит, и программа переходит к следующей строке.

Чем = отличается от == в Arduino?

Одиночный знак равенства (=) присваивает переменной значение, а двойной (==) сравнивает два значения. Запись if (x = 1) присваивает x значение 1 и делает условие всегда истинным; правильно — if (x == 1). В блоках знак «=» в блоке сравнения переводится в коде в ==.

Почему светодиод на Arduino загорается без нажатия кнопки?

Скорее всего, пин кнопки «висит в воздухе», то есть нет стягивающего или подтягивающего резистора. Тогда пин читает окружающие помехи и случайно показывает HIGH или LOW. Поставь резистор 10 kΩ между пином и GND или используй pinMode(pin, INPUT_PULLUP) и подключи кнопку к GND.

Как включать и выключать светодиод одной кнопкой на Arduino?

Храни состояние светодиода в одной переменной (ledState), а предыдущее показание кнопки — в другой (lastButton). Когда состояние кнопки меняется и новое состояние — «нажата», переключи состояние через ledState = !ledState и запиши его в светодиод через digitalWrite. Добавь короткую паузу, например 50 мс, чтобы пропустить дребезг контактов; именно так работает проект «Переключение светодиода кнопкой (вкл/выкл)».

Можно ли загрузить блоки BlueGrays в Arduino?

Нет, блоки не загружаются в плату напрямую. Они один к одному совпадают с настоящим кодом проекта и нужны, чтобы понять программу. В плату ты всегда загружаешь код проекта на C++, предварительно скопировав его в Arduino IDE.

Все проекты
Управление светодиодом кнопкой (удержание)
#9Новичок

Управление светодиодом кнопкой (удержание)

Как дверной звонок: свет горит, пока ты нажимаешь, и гаснет, когда отпускаешь. Arduino всё время слушает кнопку; пока она нажата, светодиод горит, а как только ты убираешь палец, он гаснет. Эта просте

4.8(113)
229
Включение и выключение светодиода кнопкой (вкл/выкл)
#10Новичок

Включение и выключение светодиода кнопкой (вкл/выкл)

Нажми кнопку один раз — свет загорится, нажми ещё раз — погаснет, совсем как выключатель в твоей комнате. Arduino замечает каждое нажатие и переводит светодиод в противоположное состояние, выжидая кор

4.8(100)
167
Ночник на LDR
#12Новичок

Ночник на LDR

Маленький ночник, который сам включается, когда темнеет, и гаснет, когда наступает утро. Датчик освещённости измеряет, насколько светло в комнате, и Arduino включает светодиод, когда достаточно темно,

4.8(102)
205
Измерение расстояния HC-SR04 (вывод в порт)
#27Новичок

Измерение расстояния HC-SR04 (вывод в порт)

Датчик HC-SR04 работает совсем как летучая мышь, которая находит дорогу в темноте: он посылает звук, которого ты не слышишь, слушает эхо и измеряет, насколько далеко предмет перед ним. Arduino каждые

4.6(46)
71
Управление светодиодом кнопкой на ESP32 (удержание)
#104Новичок

Управление светодиодом кнопкой на ESP32 (удержание)

Светодиод горит, когда кнопка нажата, и гаснет, когда её отпускают. Показывает, как используются цифровой входной пин ESP32 и встроенный подтягивающий резистор. Режим INPUT_PULLUP избавляет от внешнего резистора.

4.6(36)
55
Управление светодиодом кнопкой на ESP32 (переключение)
#105Новичок

Управление светодиодом кнопкой на ESP32 (переключение)

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

4.6(39)
57
Измерение освещённости с LDR
#11Новичок

Измерение освещённости с LDR

Хочешь увидеть яркость своей комнаты в виде числа? LDR — маленькая деталь, реагирующая на свет, — измеряет освещённость вокруг, а Arduino каждые полсекунды выводит значение на экран компьютера. Закрой

4.6(81)
139
Мигающий светодиод
#1Новичок

Мигающий светодиод

Самое первое «привет» в электронике: включение и выключение одного светодиода. Arduino включает и выключает светодиод через короткие промежутки, поэтому свет быстро мигает. Ты самым простым способом в

4.6(188)
1127