Показаны различия между двумя версиями страницы.
| Следующая версия | Предыдущая версия | ||
| products:laboratory_iot_c:exp36 [2024/11/17 13:20] – создано labuser30 | products:laboratory_iot_c:exp36 [2024/11/17 17:04] (текущий) – [Программный код эксперимента] labuser30 | ||
|---|---|---|---|
| Строка 4: | Строка 4: | ||
| Их простота заключалась в линейности логики алгоритма. В главном цикле проверялось состояние кнопки и сразу же изменялось | Их простота заключалась в линейности логики алгоритма. В главном цикле проверялось состояние кнопки и сразу же изменялось | ||
| состояние светодиода. Задержка, | состояние светодиода. Задержка, | ||
| - | с помощью функции | + | с помощью функции |
| небольшими схемами и примитивной логикой. Но если хочется | небольшими схемами и примитивной логикой. Но если хочется | ||
| чего-то большего, | чего-то большего, | ||
| - | использования | + | использования |
| - | Ранее, чтобы проверить состояние вывода микроконтроллера мы использовали команду вроде '' | + | Ранее, чтобы проверить состояние вывода микроконтроллера мы использовали команду вроде '' |
| ==== Прерывания ==== | ==== Прерывания ==== | ||
| Строка 19: | Строка 19: | ||
| ==== Эксперимент ==== | ==== Эксперимент ==== | ||
| - | Попробуем применить прерывания для работы с энкодером. Нам потребуется сделать две вещи — настроить прерывание и написать функцию- обработчик прерывания. | + | Попробуем применить прерывания для работы с энкодером. Нам потребуется сделать две вещи — настроить прерывание и написать функцию-обработчик прерывания. |
| ==== Схема эксперимента ==== | ==== Схема эксперимента ==== | ||
| Строка 31: | Строка 31: | ||
| ==== Программный код эксперимента ==== | ==== Программный код эксперимента ==== | ||
| - | < | + | < |
| - | from machine import I2C, Pin | + | #include < |
| - | from esp8266_i2c_lcd import I2cLcd | + | |
| - | import time | + | |
| - | _init() | + | |
| - | DEFAULT_I2C_ADDR | + | #define ENC_A 13 |
| + | #define ENC_B 12 | ||
| + | # | ||
| - | encA = Pin(13, Pin.IN) | + | LCDI2C_Generic lcd(DEFAULT_I2C_ADDR, 16, 2); |
| - | encB = Pin(12, Pin.IN) | + | |
| - | count = 0 | + | bool states[4][2] |
| + | {0,0}, | ||
| + | {1,0}, | ||
| + | {1,1}, | ||
| + | {0,1} | ||
| + | }; | ||
| - | states | + | volatile int count = 0; |
| - | (1,1), | + | volatile int state = 0; |
| - | (0,1), | + | volatile int state_old = 0; |
| - | (0,0), | + | |
| - | (1,0) | + | |
| - | ) | + | |
| - | old_state = 0 | + | void printLcd(int number) { |
| + | lcd.clear(); | ||
| + | lcd.print(number); | ||
| + | } | ||
| - | def print_lcd(data): | + | int index(bool a, bool b){ |
| - | | + | |
| - | | + | |
| + | return i; | ||
| + | } | ||
| + | } | ||
| + | return -1; | ||
| + | } | ||
| - | def callback(p): | + | void ICACHE_RAM_ATTR |
| - | | + | bool value_a = digitalRead(ENC_A); |
| - | | + | bool value_b = digitalRead(ENC_B); |
| - | global encA | + | |
| - | global states | + | |
| - | global old_state | + | |
| - | value_a | + | state = index(value_a, |
| - | | + | |
| - | current_state = states.index((value_a, value_b)) | + | if ((state - state_old |
| - | + | count++; | |
| - | if (current_state | + | if (not(count % 2)){ |
| - | count += 1 | + | |
| - | if not (count % 2): | + | |
| - | print('+'); | + | } |
| - | | + | |
| - | | + | } |
| - | | + | else if ((state |
| - | count -= 1 | + | count--; |
| - | if not (count % 2): | + | if (not(count % 2)){ |
| - | print('-'); | + | |
| - | | + | |
| - | | + | } |
| + | state_old | ||
| + | } | ||
| + | } | ||
| + | void setup() { | ||
| + | lcd.init(); | ||
| + | lcd.setBacklight(0); | ||
| + | pinMode(ENC_A, | ||
| + | pinMode(ENC_B, | ||
| - | i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) | + | attachInterrupt(digitalPinToInterrupt(ENC_A), callback, CHANGE); |
| - | lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, | + | |
| - | lcd.backlight_on() | + | } |
| - | + | ||
| - | encA.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=callback) | + | void loop() { |
| - | encB.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=callback) | + | } |
| - | + | ||
| - | + | ||
| - | while True: | + | |
| - | pass | + | |
| </ | </ | ||
| Сначала настраиваем прерывания: | Сначала настраиваем прерывания: | ||
| - | <code python[enable_line_numbers=" | + | <code python[enable_line_numbers=" |
| - | encA.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=callback) | + | |
| - | encB.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=callback) | + | |
| </ | </ | ||
| - | Мы настроили, | + | Мы настроили |
| Какие могут быть события: | Какие могут быть события: | ||
| - | * Pin.IRQ_FALLING | + | * FALLING |
| - | * Pin.IRQ_RISING | + | * RISING |
| - | * Pin.IRQ_LOW_LEVEL | + | * CHANGE любое изменение |
| - | * Pin.IRQ_HIGH_LEVEL | + | * LOW наличие логического 0 |
| + | * HIGH_LEVEL | ||
| - | События можно комбинировать. Например, если нужна реакция | + | Обратите внимание на новое |
| + | <code arduino[enable_line_numbers=" | ||
| + | volatile int count = 0; | ||
| + | volatile int state = 0; | ||
| + | volatile int state_old = 0; | ||
| + | </ | ||
| - | Рассмотрим функцию- обработчик прерывания: | + | Рассмотрим функцию-обработчик прерывания, она в свою очередь объявлена с атрибутом ICACHE_RAM_ATT. Причина аналогична указанной для переменных выше. |
| - | < | + | < |
| - | def callback(p): | + | void ICACHE_RAM_ATTR |
| - | | + | bool value_a = digitalRead(ENC_A); |
| - | | + | bool value_b = digitalRead(ENC_B); |
| - | global encA | + | |
| - | global states | + | |
| - | global old_state | + | |
| - | value_a | + | state = index(value_a, |
| - | | + | |
| - | current_state = states.index((value_a, value_b)) | + | if ((state - state_old |
| - | + | count++; | |
| - | if (current_state | + | if (not(count % 2)){ |
| - | count += 1 | + | |
| - | if not (count % 2): | + | |
| - | print('+'); | + | } |
| - | | + | |
| - | | + | } |
| - | | + | else if ((state |
| - | count -= 1 | + | count--; |
| - | if not (count % 2): | + | if (not(count % 2)){ |
| - | print('-'); | + | |
| - | | + | |
| - | | + | } |
| + | state_old | ||
| + | } | ||
| + | } | ||
| </ | </ | ||
| Она начинается с | Она начинается с | ||
| - | < | + | < |
| - | | + | bool value_a = digitalRead(ENC_A); |
| - | | + | bool value_b = digitalRead(ENC_B); |
| - | global encA | + | |
| - | global states | + | |
| - | global old_state | + | |
| </ | </ | ||
| - | Ключеваое слово '' | + | Здесь мы впервые объявляем переменные внутри функции. По умолчанию, |
| Потом, как и раньше, | Потом, как и раньше, | ||
| Строка 154: | Строка 164: | ||
| Как мы заметили ранее, при одном щелчке энкодера происходит смена двух состояний энкодера. Чтобы одному щелчку соответствовало изменение счетчика на 1, мы просто проверяем счетчик на четность. | Как мы заметили ранее, при одном щелчке энкодера происходит смена двух состояний энкодера. Чтобы одному щелчку соответствовало изменение счетчика на 1, мы просто проверяем счетчик на четность. | ||
| - | < | + | < |
| - | | + | if (not(count % 2)){ |
| - | print('+'); | + | |
| - | | + | |
| + | } | ||
| </ | </ | ||
| Строка 164: | Строка 175: | ||
| Теперь самое главное. Обратим внимание на основной цикл программы. Мы в нем ничего не делаем. Все действия, | Теперь самое главное. Обратим внимание на основной цикл программы. Мы в нем ничего не делаем. Все действия, | ||
| - | <WRAP center round important 60%> | + | <WRAP center round info 80%> |
| - | В этом эксперименте мы производили настройку аппаратных средств микроконтроллера, а именно настраивали прерывания. Как мы уже узнали, работа прерываний не зависит | + | [[https:// |
| + | |||
| + | [[https:// | ||
| </ | </ | ||
| + | |||
| + | |||