Показаны различия между двумя версиями страницы.
Предыдущая версия справа и слеваПредыдущая версияСледующая версия | Предыдущая версия | ||
products:laboratory_iot:exp35 [2020/05/22 11:33] – [Программный код эксперимента] labuser29 | products:laboratory_iot:exp35 [2024/11/16 11:25] (текущий) – [Программный код эксперимента] labuser30 | ||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ===== Эксперимент 35. Прерывания | + | ===== Эксперимент 35. Конечные автоматы ===== |
- | В предыдущих уроках, | + | Коне́чный автома́т — абстрактный автомат, число |
- | Их простота заключалась в линейности логики алгоритма. В главном цикле проверялось | + | |
- | состояние светодиода. Задержка, | + | |
- | с помощью | + | |
- | небольшими схемами и примитивной логикой. Но если хочется | + | |
- | чего-то большего, то старыми средствами уже не обойтись | + | |
- | использования time.sleep() придется отказаться. | + | |
- | Ранее, чтобы проверить состояние вывода микроконтроллера мы использовали команду вроде '' | + | {{ : |
- | ==== Прерывания ==== | + | Видно, что |
- | Оказывается есть отличное решение | + | |
- | //Прерывание// — это сигнал (событие), который заставляет контроллер прекратить выполнение текущей задачи и приступить к исполнению другой, имеющей более высокий приоритет. После выполнения высокоприоритетной задачи, | + | Конечные автоматы иногда |
+ | {{ :encoder.png?nolink |}} | ||
- | Представь, что | + | По графику |
- | ==== Эксперимент ==== | + | Зная это мы можем отфильтровывать ложные показания |
- | Попробуем применить прерывания для работы с энкодером. Нам потребуется сделать две вещи — настроить прерывание | + | |
==== Схема эксперимента ==== | ==== Схема эксперимента ==== | ||
- | Оставим схему прошлого эксперимента | ||
{{ : | {{ : | ||
// | // | ||
Строка 31: | Строка 23: | ||
==== Программный код эксперимента ==== | ==== Программный код эксперимента ==== | ||
- | <file python Exp35[enable_line_numbers=" | + | <file python Exp35.py[enable_line_numbers=" |
+ | from time import sleep_ms, ticks_ms | ||
from machine import I2C, Pin | from machine import I2C, Pin | ||
from esp8266_i2c_lcd import I2cLcd | from esp8266_i2c_lcd import I2cLcd | ||
_init() | _init() | ||
- | DEFAULT_I2C_ADDR = 0x3F | + | DEFAULT_I2C_ADDR = 0x3F # Или 0x27 в зависимости от модели микросхемы на плате |
encA = Pin(13, Pin.IN) | encA = Pin(13, Pin.IN) | ||
encB = Pin(12, Pin.IN) | encB = Pin(12, Pin.IN) | ||
+ | |||
+ | states = ( | ||
+ | (0,0), | ||
+ | (1,0), | ||
+ | (1,1), | ||
+ | (0,1) | ||
+ | ) | ||
+ | |||
+ | old_state = 0 | ||
count = 0 | count = 0 | ||
Строка 48: | Строка 50: | ||
lcd.putstr(str(data)) | lcd.putstr(str(data)) | ||
- | def callback(p): | ||
- | global count | ||
- | global encB | ||
- | global encA | ||
- | print(' | + | i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) |
- | + | lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, | |
+ | lcd.backlight_on() | ||
+ | |||
+ | |||
+ | while True: | ||
value_a = encA.value() | value_a = encA.value() | ||
value_b = encB.value() | value_b = encB.value() | ||
- | | + | |
- | print(' | + | |
- | count += 1 | + | if (state - old_state == 1) or (state == 0 and old_state == 3): |
+ | count += 1 | ||
+ | print(' | ||
print_lcd(count) | print_lcd(count) | ||
- | | + | old_state = state |
- | print(' | + | |
count -= 1 | count -= 1 | ||
+ | print(' | ||
print_lcd(count) | print_lcd(count) | ||
- | print(' | + | old_state = state |
+ | </ | ||
+ | Описываем возможные состояния конечного автомата: | ||
+ | <code python[enable_line_numbers=" | ||
+ | states = ( | ||
+ | (0,0), | ||
+ | (1,0), | ||
+ | (1,1), | ||
+ | (0,1) | ||
+ | ) | ||
+ | </ | ||
+ | Список из 4 элементов. В каждом элементе первая цифра это состояние сигнала A, вторая — сигнала B. | ||
+ | Номер состояния — это индекс элемента списка. Логика переключения состояний автомата простая — состояние может смениться только на соседнее: | ||
- | i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) | + | В переменной '' |
- | lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, | + | |
- | lcd.backlight_on() | + | |
- | encA.irq(trigger=Pin.IRQ_FALLING, | + | В основном цикле программы мы получаем данные о текущем состоянии линий А и B: |
+ | <code python[enable_line_numbers=" | ||
+ | value_a = encA.value() | ||
+ | value_b | ||
+ | </ | ||
+ | И определяем номер состояния конечного автомата, | ||
+ | <code python[enable_line_numbers=" | ||
+ | state = states.index((value_a, | ||
+ | </ | ||
- | while True: | + | Формируем список с состояниями А и B '' |
- | pass | + | с помощью оператора '' |
- | </ | + | |
+ | Теперь мы знаем индекс только что измеренного состояния линий. А индекс последнего состояния конечного автомата хранится в переменной '' | ||
- | Сначала настраиваем прерывание: | + | <code python[enable_line_numbers=" |
- | <code python[enable_line_numbers=" | + | if (state - old_state |
- | encA.irq(trigger=Pin.IRQ_FALLING, | + | |
</ | </ | ||
- | Мы настроили, | + | Если индекс нового состояния |
- | Какие могут | + | Аналогично для вращения в обратную |
- | * Pin.IRQ_FALLING | + | |
- | * Pin.IRQ_RISING | + | |
- | * Pin.IRQ_LOW_LEVEL наличие логического 0 | + | |
- | * Pin.IRQ_HIGH_LEVEL | + | |
- | События можно комбинировать, например если нужна реакция | + | Когда ты запустишь эту программу в конструкторе, то увидишь, что значение на дисплее всегда меняется сразу на 2 и в терминале появляется по два + или -. Дело в том, что |