День #3: Невероятные входные сигналы!

День #3 адвент-календаря Let it Glow — Невероятные входные сигналы

Это день #3 адвент-календаря Let it Glow!

Вчера мы познакомились с созданием схем с выходными сигналами (outputs), используя наш светодиод, и научились работать с ними в коде. Сегодня мы рассмотрим входные сигналы (inputs) и то, как они могут управлять нашим кодом и заставлять его делать разные вещи.

Лучший способ познакомиться с входными сигналами — использовать кнопку, а в этом году в наборе есть две крупные цветные кнопки, которые просты в использовании и добавляют изюминку нашей макетной плате! Использование кнопок вместе со светодиодами и другими мигающими элементами — отличный способ создать весёлый интерактивный проект!

Мы научим кнопку управлять нашим светодиодом через код, так что мы уже начинаем заставлять компоненты работать вместе… и с каждым днём будет только интереснее!

Начнём!

Содержимое коробки #3

В этой коробке вы найдёте:

  • 1 зелёную квадратную тактильную кнопку 12 мм

  • 1 красную квадратную тактильную кнопку 12 мм

  • 5 соединительных проводов «папа-папа»

Содержимое коробки #3

Сегодняшние задания

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

Мы познакомимся с новыми навыками и функциями, которые пригодятся нам по мере прохождения календаря.

Те из вас, кто прошёл наш календарь «12 дней Кодмаса» в прошлом году, уже знакомы с кнопками — это самый популярный способ отправки входных сигналов микроконтроллеру. Именно поэтому в этом году мы включили кнопки другого яркого стиля, но поскольку основы уже освоены, сходство между двумя календарями на этом практически заканчивается!

Как работает кнопка?

Мы все знаем, что такое кнопка — большинство из нас пользуется ими каждый день. Тем не менее некоторые могут задаться вопросом: что заставляет их работать и что происходит под этим ярким колпачком?

Кнопки просто дают нам удобный способ замкнуть или разомкнуть цепь. Это то же самое, что подключить или отключить провод — просто в удобном для нас формате!

Разница с микроконтроллерами состоит в том, что цепь можно использовать для отправки сигнала (входного сигнала) каждый раз, когда кнопка нажата, что затем говорит нашему коду что-то сделать. Когда мы нажимаем кнопку в схеме, которую сейчас будем собирать, электрический сигнал (3,3 В) может продолжить свой путь до нашего вывода GPIO, который способен обнаружить это и заставить код среагировать соответствующим образом.

Сборка схемы

Как всегда, перед работой со схемой убедитесь, что Pico отключён от USB-кабеля.

Подготовка макетной платы

Светодиод из вчерашней коробки должен остаться на месте. Если нет — вернитесь к дню #2 и снова соберите ту схему.

Установка кнопок

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

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

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

Кнопки установлены на макетную плату

Теперь нужно подключить кнопки к выводам GPIO нашего Pico.

Сначала создадим шину питания 3,3 В с помощью одной из красных дорожек, к которой затем сможем подключаться. На Pico есть только один вывод 3,3 В, поэтому это позволит нам создать несколько соединений с ним.

Подключите соединительный провод от вывода 3V3 OUT (физический вывод 36), затем вставьте другой конец в верхнюю красную шину. Теперь, когда вся шина подключена к выводу 3,3 В, можно подключить обе кнопки к ней. Подключите верхнюю левую ножку каждой кнопки к этой шине с помощью отдельного провода для каждой:

Подключение шины питания 3,3 В и кнопок

Наконец, нужно соединить другую сторону наших кнопок с выводами GPIO.

Подключите нижнюю правую ножку левой кнопки к GPIO3 (физический вывод 5), а нижнюю правую ножку правой кнопки к GPIO2 (физический вывод 4):

Полная схема — день #3

Несколько советов

  • Если соединительные провода с трудом входят, немного покрутите их. Иногда они цепляются, и небольшое вращение помогает.

  • После запуска кода, если окажется, что кнопка постоянно определяется как нажатая, скорее всего, провод подключён не к той ножке, что создаёт постоянное соединение.

  • Если кнопка не держится и постоянно выскакивает, попробуйте переместить провод в другое отверстие той же дорожки или вставить кнопку в другое место на макетной плате.

Кнопки готовы — приступим к коду!

Задание 1: Базовое использование кнопки

Сначала рассмотрим основы работы с кнопками в MicroPython/на Pico, затем перейдём к чуть более сложным проектам.

Мы снова воспользуемся тем, что использовали вчера, — главным образом циклами while. Циклы часто используются для кнопок и входных сигналов, поскольку с их помощью можно непрерывно проверять состояние входного сигнала, чтобы узнать, изменилось ли оно.

Внутри цикла while мы используем кое-что новое — оператор if — чтобы определить, что происходит при нажатии кнопки.

Операторы if

Если вы раньше пользовались Microsoft Excel или похожим программным обеспечением, то уже догадались, что делают операторы if.

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

Отступ здесь важен — блок цикла while имеет отступ, но поскольку цикл while содержит оператор if, мы делаем отступ ещё раз для блока оператора if. Посмотрите на пример ниже, чтобы увидеть это в действии.

Операторы if могут быть очень мощными, и существует множество разных и продвинутых способов их использования. Вы будете использовать их много при создании собственных проектов. Начнём с простого примера, но сначала объясним ещё кое-что новое в нашем коде — подтяжку к земле (pull down).

Подтяжка к земле (Pull down)

В коде ниже также используется подтяжка к земле — вы можете увидеть её в конце каждой строки настройки кнопки в виде Pin.PULL_DOWN.

Зачем мы это добавляем? Когда мы используем кнопку, на вывод GPIO подаётся 3,3 В, чтобы перевести его в состояние HIGH, однако нужно убедиться, что вывод изначально находится в состоянии LOW, иначе наш код может не обнаружить изменение и/или срабатывать случайным образом.

Это происходит потому, что выводы GPIO без подтяжки к земле (или к питанию) могут «плавать» между 0 В и 3,3 В — «подтягивая» вывод к 0 В, мы гарантируем, что он всегда начинает в состоянии LOW.

Иногда это достигается с помощью физических резисторов в схеме, однако некоторые микроконтроллеры (например, наш Pico) имеют эту функцию встроенной, и мы можем просто включить её в коде. Удобно!

Код

Начнём с одной из наших кнопок — красной (правой).

Код включает стандартные импорты, а затем настраивает вывод кнопки. Он задаётся как вход (Pin.IN) с подтяжкой к земле (Pin.PULL_DOWN).

Затем код запускает цикл while True. Внутри цикла while находится оператор if, который ожидает сигнал HIGH (1) на GPIO 2.

Если кнопка нажата и сигнал отправлен на этот вывод, наш код выведет «Красная кнопка нажата».

В этот цикл включена короткая задержка, чтобы у вас был шанс отпустить кнопку и не дать коду срабатывать много раз от одного нажатия (это называется устранением дребезга). Обычно хорошо работают значения 0,1 или 0,2 секунды.

Скопируйте пример в Thonny и попробуйте:

# Импорты
from machine import Pin
import time

# Указываем имя кнопки и номер вывода GPIO
# Задаём вывод как вход и используем подтяжку к земле
redbutton = Pin(2, Pin.IN, Pin.PULL_DOWN)

while True: # Бесконечный цикл

    time.sleep(0.2) # Короткая задержка

    if redbutton.value() == 1: # Если красная кнопка нажата
        print("Red button pressed")

Легко, правда? Двигаемся дальше и добавляем вторую кнопку.

Задание 2: Несколько входных кнопок

Так же, как мы добавляли дополнительные светодиоды в код в вчерашней коробке, добавим вторую (зелёную) кнопку в скрипт и изменим код так, чтобы он делал разные вещи в зависимости от того, какая кнопка нажата.

Первый шаг — добавить строку настройки вывода. Просто продублируйте эту строку и дайте ей другое название; мы назвали её очевидным образом — «greenbutton». Измените и номер GPIO на 3, поскольку наша зелёная кнопка подключена к этому выводу.

Затем всё, что нужно сделать, — это добавить второй оператор if, чтобы сообщить программе, что делать при обнаружении другого входного сигнала: изменить кнопку, которую она ожидает, и выводимый текст.

Посмотрите на пример кода ниже и попробуйте сами:

# Импорты
from machine import Pin
import time

# Указываем имя кнопки и номер вывода GPIO
# Задаём вывод как вход и используем подтяжку к земле
redbutton = Pin(2, Pin.IN, Pin.PULL_DOWN)
greenbutton = Pin(3, Pin.IN, Pin.PULL_DOWN)

while True: # Бесконечный цикл

    time.sleep(0.2) # Короткая задержка

    if redbutton.value() == 1: # Если красная кнопка нажата
        print("Red button pressed")

    if greenbutton.value() == 1: # Если зелёная кнопка нажата
        print("Green button pressed")

Задание 3: Управление светодиодом с помощью кнопок

Прежде чем двигаться дальше с входными сигналами, вернём наш светодиод и будем управлять им с помощью входных сигналов. Зелёная кнопка будет включать светодиод, а красная — выключать.

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

Затем под каждым оператором if добавим код управления светодиодом после строки print. Внутри операторов if можно добавить сколько угодно кода, что делает их очень удобными, когда нужно, чтобы одно условие запускало целый ряд событий и устройств.

Скопируйте пример ниже в Thonny и попробуйте:

# Импорты
from machine import Pin
import time

# Настройка входных выводов
redbutton = Pin(2, Pin.IN, Pin.PULL_DOWN)
greenbutton = Pin(3, Pin.IN, Pin.PULL_DOWN)

# Настройка выходных выводов
redled = Pin(14, Pin.OUT)

while True:

    time.sleep(0.2)

    if redbutton.value() == 1:
        print("Light OFF")
        redled.value(0) # Вывод светодиода LOW

    if greenbutton.value() == 1:
        print("Light ON")
        redled.value(1) # Вывод светодиода HIGH

Задание 4: Переключение светодиода с помощью кнопок

Использование кнопок для включения и выключения светодиода удобно, но в реальности большинство устройств в наших домах используют одну кнопку для переключения состояния вкл./выкл.

Хотелось бы найти способ получше…

Функция toggle (переключение)

…и он есть! Функция toggle делает именно то, что от неё ожидается — переключает состояние вывода между HIGH и LOW, что позволяет использовать одну кнопку как выключатель света или что-то подобное.

Это также уменьшает количество кода, что всегда хорошо при работе с микроконтроллерами с ограниченным объёмом памяти.

Вместо обычной строки включения или выключения светодиода просто используем redled.toggle(). Легко! Попробуйте код ниже с красной (правой) кнопкой:

# Импорты
from machine import Pin
import time

# Настройка входных выводов
redbutton = Pin(2, Pin.IN, Pin.PULL_DOWN)

# Настройка выходных выводов
redled = Pin(14, Pin.OUT)

while True:

    time.sleep(0.2)

    if redbutton.value() == 1:
        redled.toggle()

Задание 5: Счёт с помощью кнопок

Мы можем заставить нашу программу считать и управлять числами, используя кнопки для увеличения или уменьшения хранимого значения. Это пригодится при создании небольших игр или настройке таких вещей, как громкость, яркость и другие параметры, имеющие диапазон значений.

Это хранимое значение называется переменной. Давайте кратко разберём переменные, прежде чем продолжать…

Переменные

Переменная — это просто место для хранения значения («контейнер»), которое мы также можем обновлять при необходимости. Когда нам нужно использовать переменную в строке кода, мы просто используем её имя.

В нашем примере ниже переменная называется count. Мы создаём её перед циклом while и задаём начальное значение 0.

В программировании переменная может быть целым числом («целое число», integer), числом с десятичной точкой («число с плавающей точкой», float) или словом/текстом («строка», string). Здесь мы будем использовать целое число.

Код

Код ниже сначала импортирует необходимое, настраивает номера выводов, затем создаёт переменную под названием «count», которую мы будем использовать для отслеживания нажатий кнопок в рамках цикла while.

Красная кнопка будет уменьшать счётчик на 1, а зелёная — увеличивать на 1 (можете поменять их местами, если хотите — у вас теперь есть все навыки для этого!).

# Импорты
from machine import Pin
import time

# Настройка входных выводов
redbutton = Pin(2, Pin.IN, Pin.PULL_DOWN)
greenbutton = Pin(3, Pin.IN, Pin.PULL_DOWN)

# Настройка переменной-счётчика
count = 0 # Начинаем с нуля

while True:

    time.sleep(0.2)

    if redbutton.value() == 1:
        count = count - 1 # Уменьшаем счётчик на 1
        print(count)      # Выводим обновлённый счётчик

    if greenbutton.value() == 1:
        count = count + 1 # Увеличиваем счётчик на 1
        print(count)      # Выводим обновлённый счётчик

Задание 6: Счёт с помощью кнопок (с миганием)

Заставим наш светодиод мигать при каждом нажатии кнопки — просто для визуальной обратной связи и как способ показать ещё один вариант использования светодиодов в проектах.

Код в основном тот же, просто с добавленными элементами управления светодиодом. Мы включаем светодиод внутри каждого оператора if (после нажатия кнопки), но он снова гасится, когда код возвращается в начало цикла — там мы выключаем его после короткой задержки в 0,2 секунды.

Это создаёт эффект вспышки при каждом нажатии кнопки. Попробуйте:

# Импорты
from machine import Pin
import time

# Настройка входных выводов
redbutton = Pin(2, Pin.IN, Pin.PULL_DOWN)
greenbutton = Pin(3, Pin.IN, Pin.PULL_DOWN)

# Настройка выходных выводов
redled = Pin(14, Pin.OUT)

# Настройка переменной-счётчика
count = 0

while True:

    time.sleep(0.2)

    redled.value(0) # Светодиод выключен до нажатия кнопки

    if redbutton.value() == 1:
        count = count - 1
        redled.value(1) # Светодиод включён
        print(count)

    if greenbutton.value() == 1:
        count = count + 1
        redled.value(1) # Светодиод включён
        print(count)

День #3 завершён!

Ещё один хороший день обучения! Мы хорошо разобрались с входными сигналами, циклами и операторами if, что очень пригодится нам в будущих интересных заданиях.

Сегодня мы рассмотрели самое базовое использование операторов if, однако вернёмся к ним, чтобы показать более продвинутые возможности.

Время повторить — что мы разобрали в сегодняшней коробке?

  • Сборка схемы с кнопкой

  • Использование входных сигналов с MicroPython

  • Базовое использование операторов if

  • Подтяжка к земле (pull down)

  • Управление выходным сигналом с помощью входного

  • Функция toggle

  • Переменные

  • Целые числа, числа с плавающей точкой и строки

  • Счёт с переменными

Храните макетные платы в безопасном месте и оставьте схему в собранном виде — часть из неё нам понадобится завтра. До встречи утром!

Схемы для макетных плат в этом руководстве созданы с помощью Fritzing.