Адвент-календарь Let it Glow, день #7: Время скользить!

Адвент-календарь Let it Glow, день 7 — время скользить!

Сегодня день #7 адвент-календаря Let it Glow!

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

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

Давайте сразу «скользнём» в работу…

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

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

  • 1x слайдер-потенциометр 45 мм

  • 1x колпачок для слайдера-потенциометра

  • 3x провода-перемычки «папа-папа»

Содержимое коробки адвент-календаря Let it Glow, день 7

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

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

Сначала поговорим о потенциометрах и аналоговых сигналах…

Что такое потенциометр?

Потенциометр — это переменный резистор.

В нашем календаре уже был обычный резистор для светодиода из коробки #2, но тот резистор имел фиксированное значение, обеспечивая определённое сопротивление. Потенциометр — это резистор, значение которого можно изменять (в нашем случае — перемещая ползунок вверх и вниз).

Слайдер-потенциометр в вашей коробке имеет номинал 10K, то есть его можно настроить в диапазоне от 0 Ом до 10 000 Ом (сопротивление измеряется в омах).

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

Что такое аналоговый сигнал?

До сих пор мы работали с цифровыми сигналами при помощи кнопок и светодиодов нашего календаря. Цифровые сигналы — это строго 1 или 0, HIGH или LOW, ВКЛ или ВЫКЛ. Одно или другое, и ничего между ними.

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

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

Наш слайдер-потенциометр может передавать эти аналоговые сигналы (в виде напряжения) на Raspberry Pi Pico, обеспечивая плавный ввод с широким диапазоном значений для использования в коде.

Сборка схемы

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

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

Оставьте RGB-светодиоды на месте, так как мы будем использовать их позже.

Ваша отправная точка должна выглядеть примерно так:

Отправная точка для дня 7 — оба светодиода на макетной плате

Установка слайдера

Эти слайдеры слишком длинные, чтобы поместиться в одну макетную плату, — именно поэтому мы просили вас соединить две макетные платы в день #1!

Нужно вставить ножки так, чтобы они охватывали обе макетные платы. Рекомендуем расположить ножки так же, как показано ниже: две ножки сзади и одна ножка спереди.

На этом же этапе нужно надеть маленький колпачок/ручку на слайдер, если он ещё не надет:

Слайдер на макетной плате, день 7

Подключение ножек слайдера

Для этой части вам понадобятся всего три провода-перемычки:

  • Подключите нижнюю одиночную ножку к выводу земли (GND) — мы используем физический вывод 28

  • Теперь подключите верхнюю левую ножку слайдера к выводу 3.3V — это физический вывод 36

  • Наконец, подключите верхнюю правую ножку слайдера к GPIO28 (физический вывод 34) — это специальный вывод АЦП (поясним через мгновение)

Ваша макетная плата должна выглядеть примерно так:

Полная схема дня 7

Задание 1: Показываем слайдер!

Начнём с простой программы, которая выводит аналоговые значения.

Мы используем именно GPIO28, так как это один из АЦП-выводов Pico. Но что такое АЦП?

Выводы АЦП

Если снова посмотреть на карту выводов Pico, можно увидеть три тёмно-зелёных вывода АЦП справа — GPIO26, 27 и 28 (физические выводы 31, 32 и 34).

АЦП — это аналого-цифровой преобразователь (Analogue to Digital Converter). Выводы АЦП на нашем Pico обладают особой способностью преобразовывать аналоговый входной сигнал в цифровую форму, которую мы можем использовать. Для задействования этой функции нужно импортировать ADC в коде.

Примечание

Вы также заметите выводы ADC_VREF и AGND, но мы не будем разбирать их в этом календаре, так как они не нужны для наших примеров — не хотим усложнять, пока мы ещё учимся.

Код

Приведённый ниже код импортирует ADC и настраивает GPIO28 как вывод АЦП, затем запускает цикл while, который каждые 0,3 секунды выводит значение потенциометра.

Часть read_u16 делает это, преобразуя переменное напряжение, подаваемое на вывод от потенциометра, в диапазон используемых выходных значений от 0 до 65535.

(Для тех, кто хочет разобраться технически: выводы АЦП Pico 12-битные, однако MicroPython масштабирует это до 16-битного диапазона, то есть 0–65535).

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

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

# Настройка слайдера на выводе АЦП 28
potentiometer = ADC(Pin(28))

while True: # Цикл навсегда

    print(potentiometer.read_u16()) # Считываем значение потенциометра

    time.sleep(0.3) # Короткая пауза до следующего считывания

Задание 2: Смена цвета слайдером

Наш слайдер-потенциометр даёт значение в широком диапазоне в зависимости от положения, поэтому давайте используем это для управления с помощью операторов if/elif. На этот раз с условиями, которые проверяют, больше, меньше или в диапазоне заданного значения, чтобы управлять цветом светодиода в зависимости от показания!

Меньше, больше или между?

В нашем примере ниже мы проверяем, меньше ли аналоговое значение 20000, находится ли оно между 20000 и 40000 или больше 40000:

  • Чтобы оператор if искал значение «меньше или равно», используем оператор <=, вот так: if reading <= 20000

  • Чтобы оператор if искал значение «между» двумя числами, используем немного менее очевидную комбинацию двух операторов <, вот так: if 20000 < reading < 40000

  • Чтобы оператор if искал значение «больше или равно», используем оператор >=, вот так: if reading >= 40000

Внутри каждого оператора if находится тот же код, который мы использовали вчера для управления RGB-светодиодом, с переменными цвета красный/оранжевый/зелёный (немного как светофор!)

Код

Скопируйте приведённый ниже код в Thonny и попробуйте запустить, а затем почему бы не добавить больше операторов elif, разбив диапазон ещё сильнее, чтобы добавить больше цветов из вчерашнего занятия?

# Импорты
import time
from machine import Pin, ADC
from neopixel import NeoPixel

# Настройка слайдера на выводе АЦП 28
potentiometer = ADC(Pin(28))

# Определяем номер вывода светодиода (2) и количество светодиодов (1)
GRBled = NeoPixel(Pin(2), 1)

# Определяем несколько базовых переменных цвета GRB
red = 0,255,0
amber = 255,175,150
green = 255,0,0

# Создаём переменную для считывания
reading = 0

while True:

    reading = potentiometer.read_u16() # Считываем значение потенциометра и записываем в переменную 'reading'

    print(reading) # Выводим значение

    time.sleep(0.1) # Короткая пауза

    if reading <= 20000: # Если значение меньше или равно 20000

        GRBled.fill((red))
        GRBled.write()

    elif 20000 < reading < 40000: # Если значение между 20000 и 40000

        GRBled.fill((amber))
        GRBled.write()

    elif reading >= 40000: # Если значение больше или равно 40000

        GRBled.fill((green))
        GRBled.write()

Небольшое задание!

Приведённый выше код зажигает только один светодиод. Ваша задача — зажечь оба светодиода вместо одного. Не забудьте:

  • Дать светодиодам разные имена и правильные номера выводов

  • Добавить код там, где нужно, для включения второго светодиода

  • Использовать разные имена светодиодов в коде!

Задание 3: Плавное изменение яркости слайдером

Теперь используем аналоговое значение для управления значением GRB (от 0 до 255, если помните) нашего светодиода, позволяя плавно менять яркость с помощью слайдера!

Вместо операторов if, проверяющих диапазон значений, мы будем напрямую подставлять число в код нашего GRB-светодиода. Однако здесь нужно произвести вычисления, так как аналоговый диапазон — от 0 до 65535, а значение GRB составляет всего от 0 до 255.

Для этого нам нужно будет преобразовать показание и использовать функцию round. Держитесь крепче — пришло время математики!

Преобразование диапазонов чисел

Вот как мы будем преобразовывать диапазоны. Можете проследить с калькулятором, чтобы убедиться самостоятельно:

  • Нужно взять диапазон значений GRB (255) и разделить его на диапазон аналогового считывания (65535)

  • Это даёт нам 0.0038910505836576

  • При каждом считывании аналогового значения нам нужно умножить его на это число

  • Допустим, аналоговое значение равно 40249 — это будет 40249 x 0.0038910505836576 = 156.6108949416347

  • В коде для GRB не нужны десятичные дроби (числа с плавающей точкой) вроде той длинной выше, поэтому нам нужно округлить это число — для этого используем функцию round

  • Функция round смотрит на наше число (156**.6**108949416347) и приводит его к ближайшему целому числу, то есть округляет вверх до 157

  • Теперь наш код может автоматически преобразовывать любое показание слайдера в полезное значение для нашего RGB-светодиода.

Возможно, вам стоит перечитать это несколько раз, чтобы всё встало на место!

Код

Несколько дополнительных замечаний о приведённом ниже примере кода:

  • Мы создаём две переменные — одну для аналогового значения (analoguereading) и другую для преобразованного значения RGB (rgbvalue). Это позволяет нам выводить исходные значения рядом с преобразованным значением RGB, чтобы видеть, что происходит.

  • Вы заметите, что мы выводим текст вместе с переменной. Это достигается путём ввода текстовой строки в кавычках, затем запятой, затем имени переменной. Например: print(«мой текст здесь», имяпеременной)

    • Мы также используем несколько дополнительных пробелов для выравнивания чисел в окне оболочки при выводе, например: «RGB: «

  • Преобразование числа и округление выполняются в одной строке кода: rgbvalue = round(reading * (255 / 65535))

  • Мы могли бы сократить код, считывая аналоговое значение в той же строке, но и без этого достаточно сложно! Например: rgbvalue = round((potentiometer.read_u16()) * (255 / 65535))

Время попробовать самостоятельно!

# Импорты
import time
from machine import Pin, ADC
from neopixel import NeoPixel

# Настройка слайдера на выводе АЦП 28
potentiometer = ADC(Pin(28))

# Определяем номер вывода светодиода (2) и количество светодиодов (1)
GRBled = NeoPixel(Pin(2), 1)

# Создаём переменную для аналогового считывания
analoguereading = 0

# Создаём переменную для преобразованного значения GRB
GRBvalue = 0

while True:

    # Считываем значение потенциометра
    analoguereading = potentiometer.read_u16()

    # Берём диапазон аналоговых значений (65535), умножаем считанное значение
    # на диапазон GRB (255), делённый на 65535
    # Округляем результат, так как в коде RGB не нужны числа с плавающей точкой
    GRBvalue = round(analoguereading * (255 / 65535))

    # Выводим значения с поясняющим текстом
    print("Analogue: ",analoguereading) # исходное аналоговое значение
    print("GRB:      ",GRBvalue) # преобразованное значение RGB

    # Зажигаем светодиод с преобразованным значением BRG
    GRBled.fill((0,0,GRBvalue))
    GRBled.write()

    time.sleep(0.1)

Задание 4: Управление скоростью мигания слайдером

Мигающий — значит мигает, поэтому давайте используем слайдер для изменения скорости мигания светодиода. Сделаем это, создав простую переменную и напрямую используя аналоговое значение для её обновления.

Также сделаем это немного интереснее, добавив случайную смену цвета при каждой вспышке — как же по-праздничному это выглядит!

Совет

Использование переменных для задержек по времени может быть полезным и другими способами. Если ваш код содержит много похожих задержек в разных местах, обновление одной переменной может сэкономить вам массу времени. Например, просто используйте time.sleep(myvariable) везде в коде, а затем просто обновите myvariable на нужное значение задержки — и оно изменится везде!

Код

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

Внутри нашего цикла while мы обновляем переменную „flash“, считывая аналоговое значение и деля его на 65535. Мы делаем это потому, что — и это очень удобно — аналоговый диапазон (0 — 65535), делённый на 65535, даёт нам очень удобные небольшие значения для диапазона задержки по времени. Наибольшее число составит 1 секунду (65535 / 65535), что является примерно максимально разумным значением для мигающего светодиода.

Также мы создаём три переменные — g, r и b — и используем random для генерации случайного числа для каждой в заданном диапазоне от 0 до 255. Затем при заполнении светодиода мы подставляем эти переменные как цвета GRB, используя GRBled.fill((g,r,b)).

Задержка по времени является последней частью нашего кода — используем значение flash с time.sleep(flash).

Попробуйте запустить код:

# Импорты
import time
from machine import Pin, ADC
from neopixel import NeoPixel
import random

# Настройка слайдера на выводе АЦП 28
potentiometer = ADC(Pin(28))

# Определяем номер вывода светодиода (2) и количество светодиодов (1)
GRBled = NeoPixel(Pin(2), 1)

# Создаём переменную скорости мигания
flash = 0

while True:

    # Считываем значение потенциометра
    flash = potentiometer.read_u16() / 65000

    # Генерируем случайные значения GRB
    g = random.randint(0,255)
    r = random.randint(0,255)
    b = random.randint(0,255)

    # Зажигаем светодиод со случайными значениями GRB
    GRBled.fill((g,r,b))
    GRBled.write()

    # Пауза в зависимости от положения слайдера
    time.sleep(flash)

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

Надеемся, вам понравились сегодняшние задания. Всё становится намного интереснее и мигающее, и впереди ещё больше всего!

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

Ваш растущий набор знаний MicroPython должен уже наводить вас на мысли о проектах, которые можно создать, например…

  • Можно ли использовать линейку с слайдером?

  • Можно ли менять цвет светодиода кнопкой, одновременно меняя скорость мигания слайдером?

  • Можно ли использовать слайдер для плавного перехода между двумя светодиодами?

  • И многое другое!

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

Подведём итоги — сегодня вы:

  • Узнали о потенциометрах

  • Узнали об аналоговых сигналах

  • Собрали схему со слайдером-потенциометром

  • Узнали о выводах АЦП Pico и о том, как их использовать в MicroPython

  • Использовали операторы «меньше чем / больше чем / равно» в условных выражениях

  • Преобразовывали числовые диапазоны с помощью математики в MicroPython

  • Смешивали текст с переменными в функциях print

  • Узнали о функции round

  • Использовали функцию random для генерации цветов

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

До встречи утром!


Для создания схем подключения использовался Fritzing.