Это старая версия документа!
В предыдущих уроках, мы писали достаточно простые программы. Их простота заключалась в линейности логики алгоритма. В главном цикле проверялось состояние кнопки и сразу же изменялось состояние светодиода. Задержка, если необходимо, вносилась с помощью функции time.sleep(). Этот пример отлично работает, с небольшими схемами и примитивной логикой. Но если хочется чего-то большего, то старыми средствами уже не обойтись и от использования time.sleep() придется отказаться.
Ранее, чтобы проверить состояние вывода микроконтроллера мы использовали команду вроде value_a = encA.value()
. Чтобы узнать изменилось ли состояние по сравнению с предыдущей проверкой мы хранили ее результат в переменной и сравнивали. А если нам нужно отслеживать короткие изменения состояния пинов, то проверять их состояние нужно как можно чаще. Все это заставляет микроконтроллер тратить процессорное время на простую работу с сигналом.
Оказывается есть отличное решение этой проблемы. Микроконтроллер умеет аппаратно отслеживать изменения состояния выводов. Пока процессор занят чем-то по-настоящему важным за состоянием пинов слежит специальная электронная схема. Как только изменение происходит, схема сигнализирует об этом процессору, который прерывает исполнение основной программы для того, чтобы обработать это прерывание — исполнить небольшой код, реагирующий на событие.
Прерывание — это сигнал (событие), который заставляет контроллер прекратить выполнение текущей задачи и приступить к исполнению другой, имеющей более высокий приоритет. После выполнения высокоприоритетной задачи, контроллер возвращается к той, которой был занят до прерывания.
Представь, что что ты — это микрокоонтроллер и ты очень занят важным делом — читаешь эту статью. Но внезапно начинает звонить твой телефон. Ты откладываешь статью и занимаешься обработкой этого прерывания — отвечаешь на звонок и ведешь беседу. Как только беседа завершена, ты возвращаешься к чтению статьи с того места, где прервался. Примерно так устроена обработка прерываний в микроконтроллере.
Попробуем применить прерывания для работы с энкодером. Нам потребуется сделать две вещи — настроить прерывание и написать функцию- обработчик прерывания.
Оставим схему прошлого эксперимента без изменений. Всё новое будет заключаться в программе.
Рисунок 1. Электрическая принципиальная схема эксперимента
from machine import I2C, Pin from esp8266_i2c_lcd import I2cLcd _init() DEFAULT_I2C_ADDR = 0x3F encA = Pin(13, Pin.IN) encB = Pin(12, Pin.IN) count = 0 def print_lcd(data): lcd.clear() lcd.putstr(str(data)) def callback(p): global count global encB global encA print('start') value_a = encA.value() value_b = encB.value() if (value_a and value_b) or (not value_a and not value_b): print('+') count += 1 print_lcd(count) elif (not value_a and value_b) or (value_a and not value_b): print('-') count -= 1 print_lcd(count) print('stop') i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16) lcd.backlight_on() encA.irq(trigger=Pin.IRQ_FALLING, handler=callback) while True: pass
Сначала настраиваем прерывание:
encA.irq(trigger=Pin.IRQ_FALLING, handler=callback)
Мы настроили, что при возникновении события изменения сигнала на выводе encA с высокого на низкий (Pin.IRQ_FALLING
) будет вызываться обработчик прерывания — функция callback
.
Какие могут быть события:
События можно комбинировать, например если нужна реакция и на событие Pin.IRQ_FALLING
и Pin.IRQ_RISING
, то можно записать так: trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING)
.