Адвент-календарь Let it Glow, день #7: Время скользить!
Сегодня день #7 адвент-календаря Let it Glow!
Сегодня мы возвращаемся к компоненту управления — тому, с помощью которого можно физически управлять мигающими компонентами, а код будет выступать посредником между ними.
Слайдер-потенциометр из вашей коробки позволит нам плавно увеличивать и уменьшать показания, которые мы можем использовать для изменения скорости мигания, цветов и многого другого с помощью аналоговых сигналов — отличный компаньон для светодиодов и других мигающих компонентов!
Давайте сразу «скользнём» в работу…
Содержимое коробки #7
В этой коробке вы найдёте:
1x слайдер-потенциометр 45 мм
1x колпачок для слайдера-потенциометра
3x провода-перемычки «папа-папа»
Сегодняшние задания
Сегодня мы научимся использовать этот аналоговый слайдер-потенциометр: разберёмся, что такое потенциометр, как он работает, как Pico может считывать с него аналоговые показания и как использовать эти показания в коде вместе со светодиодами.
Сначала поговорим о потенциометрах и аналоговых сигналах…
Что такое потенциометр?
Потенциометр — это переменный резистор.
В нашем календаре уже был обычный резистор для светодиода из коробки #2, но тот резистор имел фиксированное значение, обеспечивая определённое сопротивление. Потенциометр — это резистор, значение которого можно изменять (в нашем случае — перемещая ползунок вверх и вниз).
Слайдер-потенциометр в вашей коробке имеет номинал 10K, то есть его можно настроить в диапазоне от 0 Ом до 10 000 Ом (сопротивление измеряется в омах).
Способ подключения слайдера-потенциометра позволяет использовать его для передачи переменного напряжения на Raspberry Pi Pico, которое специальные аналоговые выводы могут считывать, преобразовывать и предоставлять значение для использования в проектах.
Что такое аналоговый сигнал?
До сих пор мы работали с цифровыми сигналами при помощи кнопок и светодиодов нашего календаря. Цифровые сигналы — это строго 1 или 0, HIGH или LOW, ВКЛ или ВЫКЛ. Одно или другое, и ничего между ними.
Аналоговые сигналы, в отличие от цифровых, предлагают широкий диапазон чисел для представления значений, что гораздо больше подходит для датчиков, ручек, слайдеров и подобных компонентов.
Представьте цифровой сигнал как выключатель света — он либо включён, либо выключен. Представьте аналоговый сигнал как регулятор громкости на стереосистеме — вы можете поворачивать ручку, постепенно увеличивая или уменьшая громкость небольшими шагами.
Наш слайдер-потенциометр может передавать эти аналоговые сигналы (в виде напряжения) на Raspberry Pi Pico, обеспечивая плавный ввод с широким диапазоном значений для использования в коде.
Сборка схемы
Как всегда, убедитесь, что Pico отключён от USB-кабеля при работе со схемой.
Подготовка макетной платы
Оставьте RGB-светодиоды на месте, так как мы будем использовать их позже.
Ваша отправная точка должна выглядеть примерно так:
Установка слайдера
Эти слайдеры слишком длинные, чтобы поместиться в одну макетную плату, — именно поэтому мы просили вас соединить две макетные платы в день #1!
Нужно вставить ножки так, чтобы они охватывали обе макетные платы. Рекомендуем расположить ножки так же, как показано ниже: две ножки сзади и одна ножка спереди.
На этом же этапе нужно надеть маленький колпачок/ручку на слайдер, если он ещё не надет:
Подключение ножек слайдера
Для этой части вам понадобятся всего три провода-перемычки:
Подключите нижнюю одиночную ножку к выводу земли (GND) — мы используем физический вывод 28
Теперь подключите верхнюю левую ножку слайдера к выводу 3.3V — это физический вывод 36
Наконец, подключите верхнюю правую ножку слайдера к GPIO28 (физический вывод 34) — это специальный вывод АЦП (поясним через мгновение)
Ваша макетная плата должна выглядеть примерно так:
Задание 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.