![]() |
![]() |
![]() |
![]() |
Общие сведения
Энкодер - это устройство, которое позволяет определять направление и скорость вращения. В нашем случае энкодер прикреплён к валу и помещён в корпус, похожий на потенциометр, но есть различия: в отличии от типичного потенциометра энкодер можно вращать бесконечно и у экнодера нет определённого значения, то есть в момент включения микроконтроллер не может знать был ли энкодер повёрнут до включения.
Энкодеры бывают разные: оптические, механические, магнитные - мы рассмотрим применение механического энкодера.
Для этого урока нам понадобится:
Для работы данных примеров в Pi Pico необходимо загрузить прошивку MicroPython и установить Thonny IDE, о том как это сделать можно прочитать в этой статье https://lesson.iarduino.ru/page/pi-pico-python-ide
Подключение
Подключим Trema-модуль Зуммер согласно таблице
| Вывод модуля | Вывод Pi Pico |
|---|---|
| Vcc | 3V3(OUT) |
| GND | GND |
| S | GP15 |
Подключим Trema-модуль Энкодер согласно таблице
| Вывод модуля | Вывод Pi Pico |
|---|---|
| Vcc | 3V3(OUT) |
| GND | GND |
| A | GP3 |
| B | GP2 |
| K | GP7 |

О том, что такое прерывание
Конечно, неплохо постоянно опрашивать состояние кнопки в цикле и надеяться, что микроконтроллер прочтёт его в нужное время. Но что если пока кнопка была нажата пока микроконтроллер был занят чем-то другим? Вот тут на помощь и приходят так называемые "Прерывания" или Interrupt Request (IRQ) или запрос на прерывание.
Уже из названия понятно, что что-то прерывается, и это что-то - основной код программы. Если назначить на какой-либо вывод Pi Pico прерывание, то при изменении состояния этого вывода (например нажатие кнопки) будет выполнен специальный код. Конечно, внутри прерывания не стоит громоздить целую новую программу - это может привести к нестабильной работе, но вот изменить какую-либо переменную или сделать быстрое вычисление - это как раз самое то.
На каждый вывод Pi Pico можно назначить прерывание со своей функцией. Прерывания могут срабатывать при изменении состояния вывода с логической единицы на логический ноль (IRQ_FALLING), или наоборот, с логического нуля на логическую единицу (IRQ_RISING).
Для начала введём в оболочку следующие строки:
Подключим библиотеки
>>> from machine import Pin >>> from time import sleep_ms as delay
Создадим объект вывода
>>> A = Pin("GP3")
Зададим прерывание на выводе
>>> A.irq(trigger=Pin.IRQ_RISING, handler=lambda Pin: print("don't thouch me!"))
trigger- здесь задаётся при каком событии будет происходить прерывание (IRQ_RISING, IRQ_FALLING)handler- это функция, которая будет вызвана при возникновении прерывания. В данном случае мы передали безымянную лямбда-функцию, но здесь может быть и любая другая функция, определённая в программе.
Теперь, если покрутить энкодер, в оболочку будет выводиться
сообщение! При этом микроконтроллер будет отвечать на ваши команды,
если, предположим, далее ввести print("Hello"), то он с
радостью выполнит эту функцию.
>>> print("hello")
hello
>>> don't thouch me!
don't thouch me!
don't thouch me!
don't thouch me!
Крутим энкодер в разные стороны
В данном примере в оболочку выводится переменная-счётчик при повороте вала энкодера в разные стороны
# Подключаем Выводы
from machine import Pin
# Подключаем функцию сна в миллисекундах и называем её
from time import sleep_ms as delay
# Создаём объекты выводов энкодера
A = Pin("GP3", Pin.IN)
B = Pin("GP2", Pin.IN)
K = Pin("GP7", Pin.IN)
# создаём переменные-счётчики
last_counter = 0
counter = 0
# Функция-обработчик для прерывания вывода A энкодера
def callbackA(Pin):
global counter
if not Pin.value():
counter += 1
# Функция-обработчик для прерывания вывода B энкодера
def callbackB(Pin):
global counter
if not Pin.value():
counter -= 1
# Функция-обработчик для прерывания вывода K энкодера
# Для просторы просто выводит сообщение в оболочку,
# но сообщения в прерываниях лучше не выводить, потому
# как многие микроконтроллеры могут использовать прерывания в функции `print`
def callbackK(Pin):
print("button pressed!")
# Назначаем прерывания на выводы
A.irq(trigger=Pin.IRQ_FALLING, handler=callbackA)
B.irq(trigger=Pin.IRQ_FALLING, handler=callbackB)
K.irq(trigger=Pin.IRQ_FALLING, handler=callbackK)
# Бесконечный цикл
while True:
# Если изменился счётчик - выводим его в оболочку
if last_counter != counter:
last_counter = counter
print(counter)
delay(20)
Проект Музыкальная шкатулка
Это классический пример музыкальной шкатулки - мы крутим рычаг (в данном случае энкодер), шкатулка (в данном случае зуммер) играет мелодию. Не крутим рычаг - мелодия не играет.
from machine import Pin, PWM
from time import sleep_ms as delay
# Массив кортежей с нотами,
# где первое значение - частота ноты в герцах,
# второе - длительность в миллисекундах
notes = [
(440, 200),
(523, 200),
(440, 200),
(523, 400),
(659, 200),
(659, 400),
(587, 600),
(494, 200),
(494, 400),
(494, 400),
(523, 200),
(587, 600),
]
# Создаём объект вывода А энкодера
A = Pin("GP3", Pin.IN)
# Создаём объект зуммера
zum = PWM(Pin("GP15"))
# Устанавливаем широту ШИМ
zum.duty_u16(32000)
# Функция проигрывания ноты
def playNote(note):
zum.freq(note[0])
delay(note[1])
zum.deinit()
delay(100)
# Проигрываем первую ноту, для сигнализации готовности к работе
playNote(notes[0])
# создаём переменные-счётчики
last_counter = 0
counter = 0
note_index = 0
# Функция-обработчик для прерывания вывода A энкодера
def callbackA(Pin):
global counter
if not Pin.value():
counter += 1
# Назначаем прерывания на вывод А
A.irq(trigger=Pin.IRQ_FALLING, handler=callbackA)
# Бесконечный цикл
while True:
# Если изменился счётчик
if last_counter != counter:
last_counter = counter
# Проигрываем текущую ноту по индексу
playNote(notes[note_index%len(notes)])
# Приращиваем индекс
note_index += 1
delay(20)





Обсуждение