Как настроить и использовать прерывания по кнопке на Arduino. Какие существуют виды прерываний. Как реализовать аппаратные и программные прерывания. Как избежать дребезга контактов.
Что такое прерывания и зачем они нужны
Прерывания — это механизм, позволяющий микроконтроллеру мгновенно реагировать на внешние события, не тратя ресурсы на постоянный опрос состояния входов. При возникновении прерывания основная программа приостанавливается, и управление передается специальной функции-обработчику.
Основные преимущества использования прерываний:
- Мгновенная реакция на событие без задержек
- Экономия ресурсов процессора
- Упрощение кода основной программы
- Возможность обработки асинхронных событий
Прерывания особенно полезны для обработки нажатий кнопок, энкодеров и других пользовательских интерфейсов. Они позволяют создавать более отзывчивые устройства.
Виды прерываний на Arduino
На платформе Arduino существует два основных типа прерываний:

1. Аппаратные прерывания
Аппаратные прерывания обрабатываются на уровне микроконтроллера. Они имеют наивысший приоритет и минимальную задержку срабатывания. Основные особенности:
- Поддерживаются только на определенных пинах
- Могут срабатывать по фронту или уровню сигнала
- Имеют фиксированные номера векторов прерываний
2. Программные прерывания
Программные прерывания реализуются на уровне Arduino API. Их преимущества:
- Работают на любом цифровом пине
- Позволяют использовать больше прерываний
- Проще настраиваются
Однако программные прерывания имеют большую задержку срабатывания по сравнению с аппаратными.
Настройка аппаратного прерывания по кнопке
Рассмотрим пример настройки аппаратного прерывания для обработки нажатия кнопки:
«`cpp const int buttonPin = 2; volatile bool buttonPressed = false; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(buttonPin), buttonISR, FALLING); } void loop() { if (buttonPressed) { Serial.println(«Кнопка нажата!»); buttonPressed = false; } } void buttonISR() { buttonPressed = true; } «` В этом примере:
- Кнопка подключена к пину 2 (поддерживает прерывания)
- Используется внутренняя подтяжка INPUT_PULLUP
- Прерывание настроено на срабатывание по спадающему фронту (FALLING)
- В обработчике прерывания (ISR) устанавливается флаг buttonPressed
- Основной цикл проверяет флаг и выводит сообщение при нажатии
Реализация программного прерывания
Программное прерывание можно реализовать с помощью библиотеки PinChangeInterrupt. Пример кода:
«`cpp #include- Используется библиотека PinChangeInterrupt
- Прерывание можно назначить на любой цифровой пин
- Вместо attachInterrupt используется attachPCINT
Устранение дребезга контактов
При использовании прерываний важно учитывать эффект дребезга контактов кнопки. Без устранения дребезга одно нажатие может вызвать множественные срабатывания прерывания.

Существует несколько способов устранения дребезга:
1. Программная задержка
Самый простой способ — добавить задержку в обработчик прерывания:
«`cpp volatile unsigned long lastInterruptTime = 0; const unsigned long debounceDelay = 200; void buttonISR() { unsigned long interruptTime = millis(); if (interruptTime — lastInterruptTime > debounceDelay) { buttonPressed = true; lastInterruptTime = interruptTime; } } «`2. Использование таймера
Более эффективный способ — использовать таймер для проверки состояния кнопки через некоторое время после первого срабатывания:
«`cpp #includeВ этом примере:

- Прерывание срабатывает при любом изменении состояния кнопки
- В прерывании только обновляется время последнего изменения
- Таймер периодически проверяет, прошло ли достаточно времени с последнего изменения
- Если время прошло, проверяется реальное состояние кнопки
Особенности работы с прерываниями
При использовании прерываний следует учитывать некоторые важные моменты:
- Функция-обработчик прерывания должна быть максимально короткой
- В обработчике нельзя использовать функции, работающие с прерываниями (например, delay())
- Переменные, используемые в прерывании и основном коде, должны быть объявлены как volatile
- Нужно правильно выбирать режим срабатывания (RISING, FALLING, CHANGE)
- При использовании аппаратных прерываний учитывайте их ограниченное количество
Заключение
Прерывания по кнопке — мощный инструмент для создания отзывчивых устройств на базе Arduino. Правильное использование аппаратных или программных прерываний, а также корректная обработка дребезга контактов позволяют существенно улучшить пользовательский опыт взаимодействия с вашими проектами.

Экспериментируйте с различными подходами и выбирайте оптимальный метод для вашей конкретной задачи. Помните о важности тестирования вашего кода в реальных условиях для обеспечения надежной работы устройства.
Урок 5. Управление двигателем постоянного тока ESP32 и MicroPython.
Приветствую вас на очередном уроке по программированию ESP32 на MicroPython
А начнём разбираться с данным примером с изменения примера из прошлого урока, где мы включали и выключали светодиод при нажатии на кнопку.
Для начала давайте немного уменьшим код, а именно избавимся от постоянного написания «machine» в коде.
Для этого поменяем код подключения модуля с
import machine
на
from machine import Pin
То есть получим функцию Pin из модуля machine. И сейчас в коде будет достаточно написать «Pin» вместо «machine.Pin».
Для использования внешнего прерывания в MycroPython используется следующая функция.
button.irq(trigger=Pin.IRQ_FALLING, handler=my_button)
button.irq(trigger=Pin.IRQ_FALLING, handler=my_button) – настраивает обработчик прерываний, который будет вызван при появлении сигнала запуска. Если контакт работает в режиме Pin.IN, то источником сигнала запуска будет служить внешнее значение контакта. Если контакт работает в режиме Pin.OUT, то источником сигнала запуска будет служить выходной буфер контакта. Но если контакт будет работать в режиме Pin.OPEN_DRAIN, то источником сигнала запуска будет служить выходной буфер (для «0») и внешнее значение контакта (для «1»).
trigger – определяет условие, при котором должно срабатывать прерывание:
- Pin.IRQ_FALLING – прерывание на заднем фронте.
- Pin.IRQ_RISING – прерывание на переднем фронте.
handler – функция, которую необходимо вызвать при возникновении прерывания, в моём случае это функция my_button. Функция handler должна принимать лишь один аргумент, которым должен быть экземпляр класса Pin.
В качестве примера напишем код включения встроенного светодиода при нажатии на кнопку «boot» по аналогии с примером из прошлого урока, но уже с использованием прерывания.
При вызове функции my_button меняем логическое стояние контакта, к которому подключен светодиод. Тем самым включаем и выключаем его.
При нажатии на кнопку, в консоли видим информацию о номере пина, к которому подключена кнопка.
Если поменять trigger=Pin.IRQ_RISING и проверить, то увидим, что информация появляется, когда мы отпускам кнопку. Вот в чём различие данных условий срабатывания прерывания.
Также можно использовать данные условия одновременно.
trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING
Тем самым при нажатии кнопки светодиод будет включаться, а при отпускании выключаться. Принцип работы аналогичен примеру из прошлого урока, но уже с помощью прерывания.
Управление двигателем постоянного тока с помощью ESP32 и MycroPython.
Давайте применим на практике полученные значения. Для этого
Схема подключения ESP32, драйвера L298n и двигателя постоянного тока.

В коде определим контакты подключения кнопок. Чтобы не использовать подтягивающие резисторы, воспользуемся подтягивающими резисторами платы ESP32. Для этого инициализируем пины с использованием Pin.PULL_UP.
Инициализируем два пина для работы с драйверами.
Создадим две глобальные переменные:
- press — будет хранить флаг стояния кнопки.
- n_pin – номер контакта кнопки (pin).
Функция my_button будет поднимать флаг нажатия кнопки и сохранять в переменной n_pin номер пина нажатой кнопки. Для того чтобы получить номер пина в виде числа, нужно взять из строки символы после четвёртого и без последнего символа строки и преобразовать в целочисленное значение.
Создадим прерывание для каждой кнопки с вызовом функции my_button.
В бесконечном цикле будем выполнять следующие действия.
Сперва мы проверяем переменную press. Если кнопка была нажата, тогда выводим в монитор номер контакта нажатой кнопки и отпускаем флаг press.
Далее проверяем, какая кнопка была нажата. Если левая кнопка, то начинаем вращать двигатель вправо и выводим в монитор надпись о направлении вращения. Если сработала правая кнопка, то меняем направление вращения и выводим в монитор надпись «Влево».
В противном случае ничего не делаем.
Как видно из примера, при нажатии на кнопку в мониторе время от времени отображается несколько строчек с одним пином кнопки. Это связанно с дребезгом контактов. В данном проекте это никак не повлияет на работу, а в других проектах это может стать серьёзной проблемой. Поэтому в одном из следующих уроков разберём, как можно устранить дребезг кнопки.
В следующем уроке начнём изучать работу с ШИМ.
Понравился Урок 5. Управление двигателем постоянного тока ESP32 и MicroPython? Не забудь поделиться с друзьями в соц. сетях.
А также подписаться на наш канал на YouTube, вступить в группу Вконтакте, в группу на Facebook.
Спасибо за внимание!
Технологии начинаются с простого!
Фотографии к статье
Файлы для скачивания
Скачивая материал, я соглашаюсь с Правилами скачивания и использования материалов.
Пример 1. Избавимся от постоянного написания «machine» в коде.py | 1 Kb | 245 | Скачать | |
Пример 2. Прерывания на микроконтроллере ESP32 с помощью языка MycroPython.![]() | 1 Kb | 250 | Скачать | |
Пример 3. Управление двигателем постоянного тока с помощью ESP32 и MycroPython.py | 1 Kb | 261 | Скачать |
Ардуино. Описание GPIO.
Левая сторона. Сверху вниз. | ||||||||||||
№ вывода | Наименование вывода | GPIO | Input | Output | I/O | ADC | TOUCH | ШИМ PWM | DAC | Описание | ||
2 | 3V3 | Питание: +3,3В | ||||||||||
3 | EN | Сброс | ||||||||||
4 | SENSOR VP | 36 | OK | ADC0 | + | input only | ||||||
5 | SENSOR VP | 39 | OK | ADC3 | + | input only | ||||||
6 | IO34 | 34 | OK | ADC6 | + | input only | ||||||
7 | IO35 | 35 | OK | ADC7 | + | input only | ||||||
8 | IO32 | 32 | OK | OK | ADC4 | TOUCH9 | + | |||||
9 | IO33 | 33 | OK | OK | ADC5 | TOUCH8 | + | |||||
10 | IO25 | 25 | OK | OK | ADC18 | + | DAC_1 | |||||
11 | IO26 | 26 | OK | OK | ADC19 | + | DAC_2 | |||||
12 | IO27 | 27 | OK | OK | ADC17 | TOUCH7 | + | |||||
13 | IO14 | 14 | OK | OK | ADC16 | TOUCH6 | + | HSPICLK | HS2 CLK | outputs PWM signal at boot | ||
14 | IO12 | 12 | OK | OK | ADC15 | TOUCH5 | + | HSPIC | HS DATA2 | boot fail if pulled high | ||
1 | GND | |||||||||||
16 | IO13 | 13 | OK | OK | ADC14 | TOUCh5 | + | HSPID | HS DATA3 | |||
17 | SD2 | 9 | x | x | + | connected to the integrated SPI flash | ||||||
18 | SD3 | 10 | x | x | + | connected to the integrated SPI flash | ||||||
GND | ||||||||||||
+5V | Питание: +5В | |||||||||||
Правая сторона.![]() | ||||||||||||
№ вывода | Наименование вывода | GPIO | Input | Output | I/O | ADC | TOUCH | ШИМ PWM | DAC | Описание | ||
GND | ||||||||||||
37 | IO23 | 23 | OK | OK | + | VSIPID | HS1 STROBE | |||||
36 SCL | IO22 | 22 | OK | OK | + | VSPIWP | ||||||
35 TXD0 | 1 | + | debug output at boot | |||||||||
34 RXD0 | 3 | OK | + | HIGH at boot | ||||||||
33 SDA | IO21 | 21 | OK | OK | + | VSIHD | ||||||
GND | ||||||||||||
31 | IO19 | 19 | OK | OK | + | VSPIQ | ||||||
30 | IO18 | 18 | OK | OK | + | VSPICLK | HS1-DATA7 | |||||
29 | IO05 | 5 | OK | OK | + | VSPICSO | HS1-DATA6 | outputs PWM signal at boot | ||||
28 | IO17 | 17 | OK | OK | + | HS1-DATA5 | ||||||
27 | IO16 | 16 | OK | OK | + | HS1-DATA4 | ||||||
26 | IO4 | 4 | OK | OK | ADC10 | TOUCH0 | + | HSPIHD | HS1-DATA1 | |||
25 | IO0 | 0 | ADC11 | TOUCh2 | + | |||||||
24 | IO2 | 2 | OK | OK | ADC12 | TOUCh3 | + | HSPIWP | HS2-DATA0 | connected to on-board LED | ||
23 | IO15 | 15 | OK | OK | ADC13 | TOUCh4 | + | HSPICSO | HS2-CMD | |||
22 | SD1 | 8 | x | x | + | SPID | HS1-DATA1 | connected to the integrated SPI flash | ||||
21 | SD0 | 7 | x | x | + | SPIQ | HS1-DATA0 | connected to the integrated SPI flash | ||||
20 | CLK | 6 | x | x | + | SPICLK | HS1-CLK | connected to the integrated SPI flash | ||||
0 | pulled up | OK | outputs PWM signal at boot | |||||||||
11 | x | x | connected to the integrated SPI flash |
К периферийным устройствам ESP32 относятся:
- 18 Каналов аналого-цифрового преобразователя (АЦП )
- 3 Интерфейса SPI3
- Интерфейс UART2
- Интерфейс I2C16
- Выходные каналы ШИМ
- 2 Цифро-аналоговых преобразователя (ЦАП)
- 2 Интерфейса I2S10
- Емкостные считывающие GPIO
Функции АЦП (аналого-цифровой преобразователь) и ЦАП (цифро-аналоговый преобразователь) назначены строго определённым пинам. Тем не менее, вы сами решаете, какие контакты будут отведены под интерфейсы UART, I2C, SPI, PWM и т. д. — они определяются в коде прошивки. Это возможно благодаря функции мультиплексирования чипа ESP32.
Существуют пины, назначенные по умолчанию, как показано на следующем рисунке (это пример платы ESP32 DEVKIT V1 DOIT с 36 контактами — расположение контактов может меняться в зависимости от производителя). Вы можете их переопределять.
Кроме того, есть контакты с определенными функциями, которые делают их подходящими или не подходящими для конкретного проекта. В следующей таблице показано, какие выводы лучше всего использовать в качестве входов, выходов, а с какими следует соблюдать осторожность.
Контакты, с «ОК», подходят для использования. Пины без «ОК», подходят для использования, но вы должны обратить на них внимание, потому что они могут иметь неожиданное поведение, в основном при загрузке.
GPIO с 34 по 39 являются GPI — только входные. Эти контакты не имеют внутренних подтягивающих или понижающих резисторов. Они не могут быть использованы как выходы, поэтому используйте эти контакты только как входы:
- GPIO 34
- GPIO 35
- GPIO 36
- GPIO 39
От GPIO 6 до GPIO 11 представлены в некоторых платах ESP32. Однако эти пины подключены к встроенной флэш-памяти SPI на микросхеме ESP-WROOM-32 их рекомендуется использовать для других целей. Назначение этих пинов:
- GPIO 6 (SCK / CLK)
- GPIO 7 (SDO / SD0)
- GPIO 8 (SDI / SD1)
- GPIO 9 (SHD / SD2)
- GPIO 10 (SWP / SD3)
- GPIO 11 (CSC / CMD)
ESP32 имеет 10 внутренних емкостных сенсорных датчиков. Они могут отслеживать всё, что содержит электрический заряд, например, они могут обнаруживать изменения, возникающие при касании пальцами GPIO. Эти контакты могут быть легко встроены в датчики касания и заменять механические кнопки. Емкостные сенсорные контакты также могут быть использованы для пробуждения ESP32 от глубокого сна.
Внутренние сенсорные датчики подключены к этим GPIO:
- T0 (GPIO 4)
- T1 (GPIO 0)
- T2 (GPIO 2)
- T3 (GPIO 15)
- T4 (GPIO 13)
- T5 (GPIO 12)
- T6 (GPIO 14)
- T7 (GPIO 27)
- T8 (GPIO 33)
- T9 (GPIO 32)
ESP32 имеет входные каналы АЦП 18 x 12 бит. Это GPIO, которые можно использовать в качестве АЦП:
- ADC1_CH0 (GPIO 36)
- ADC1_Ch2 (GPIO 37)
- ADC1_Ch3 (GPIO 38)
- ADC1_Ch4 (GPIO 39)
- ADC1_Ch5 (GPIO 32)
- ADC1_CH5 (GPIO 33)
- ADC1_CH6 (GPIO 34)
- ADC1_CH7 (GPIO 35)
- ADC2_12 GPO (0)
- ADC2_Ch3 (GPIO 2)
- ADC2_Ch4 (GPIO 15)
- ADC2_Ch5 (GPIO 13)
- ADC2_CH5 (GPIO 12)
- ADC2_CH6 (GPIO 14)
- ADC2_CH7 (GPIO 27)
- ADC2_CH8 (GPIO 25)
- ADC2_CH9 (GPIO 26)
Примечание: контакты ADC2 нельзя использовать при использовании Wi-Fi. Поэтому, если вы используете Wi-Fi и у вас возникают проблемы с получением значения от GPIO ADC2, вы можете вместо этого рассмотреть возможность использования GPIO ADC1, что должно решить вашу проблему.
Входные каналы АЦП имеют разрешение 12 бит. Это означает, что вы можете получить аналоговые показания в диапазоне от 0 до 4095, в которых 0 соответствует 0 В, а 4095 — 3,3 В. У вас также есть возможность установить разрешение ваших каналов в коде, а также диапазон АЦП.
Выводы АЦП ESP32 работают не линейно. Об этом следует помнить при использовании выводов АЦП. Ниже представлен график получемых значений в зависимости от напряжения:
На ESP32 имеются два 8-битных канала ЦАП для преобразования цифровых сигналов в аналоговые выходные сигналы напряжения. Пины ЦАП:
- ЦАП1 (GPIO25)
- ЦАП2 (GPIO26)
На ESP32 есть поддержка RTC GPIO. GPIO, маршрутизируемые в подсистему с низким энергопотреблением RTC, можно использовать, когда ESP32 находится в состоянии глубокого сна. Эти RTC GPIO могут использоваться для выхода ESP32 из глубокого сна, когда работает сопроцессор Ultra Low Power (ULP). Следующие GPIO могут быть использованы в качестве внешнего источника пробуждения.
- RTC_GPIO0 (GPIO36)
- RTC_GPIO3 (GPIO39)
- RTC_GPIO4 (GPIO34)
- RTC_GPIO5 (GPIO35)
- RTC_GPIO6 (GPIO25)
- RTC_GPIO7 (GPIO26)
- RTC_GPIO8 (GPIO33)
- RTC_GPIO9 (GPIO32)
- RTC_GPIO10 (GPIO4)
- RTC_GPIO11 (GPIO0)
- RTC_GPIO12 (GPIO2)
- RTC_GPIO13 (GPIO15)
- RTC_GPIO14 ( GPIO13)
- RTC_GPIO15 (GPIO12)
- RTC_GPIO16 (GPIO14)
- RTC_GPIO17 (GPIO27)
ШИМ-контроллер ESP32 имеет 16 независимых каналов, которые можно настроить для генерации ШИМ-сигналов с различными свойствами. Все выводы, которые могут выступать в качестве выходов, могут использоваться в качестве выводов ШИМ (GPIO с 34 по 39 не могут генерировать ШИМ).
Чтобы установить сигнал ШИМ, вам необходимо определить эти параметры в коде:
- Частота сигнала;
- Рабочий цикл;
- ШИМ-канал;
- GPIO, на которых вы хотите вывести сигнал.
При использовании ESP32 с Arduino IDE следует использовать выводы ESP32 I2C по умолчанию (поддерживаются библиотекой Wire):
- GPIO 21 (SDA)
- GPIO 22 (SCL)
Пины для SPI по умолчанию:
SPI | MOSI | MISO | CLK | CS |
VSPI | GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 |
HSPI | GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
Все GPIO могут быть настроены для обработки прерываний.
Strapping pin — связывающий вывод, связывающий контакт (переопределяющий назначение других выводов при подаче на него сигнала)
- GPIO 0
- GPIO 2
- GPIO 4
- GPIO 5
- GPIO 12
- GPIO 15
Они используются для перевода ESP32 в режим загрузчика или в режим перепрошивки. На большинстве плат разработки со встроенным USB / Serial вам не нужно беспокоиться о состоянии этих контактов. Плата переводит контакты в правильное состояние для перепрошивки или режима загрузки.
Однако, если к этим контактам подключены периферийные устройства, у вас могут возникнуть проблемы при попытке загрузить новый код, перепрошить ESP32 или перезагрузить плату.
Некоторые GPIO изменяют свое состояние на Hight или выводят ШИМ-сигналы при загрузке или сбросе. Это означает, что если у вас есть выходы, подключенные к этим GPIO, вы можете получить неожиданные результаты при перезагрузке или загрузке ESP32.
- GPIO 1
- GPIO 3
- GPIO 5
- GPIO 6 — GPIO 11 (подключены к встроенной флэш-памяти SPI ESP32 — использовать не рекомендуется).
- GPIO 14
- GPIO 15
En (Enable) / RST (Reset) — Вы можете использовать этот контакт, подключенный к кнопке, например, для перезапуска ESP32.
Для автоматизации загрузки программы в модуль — поставить электролитический конденсатор 10мкФ между выводами EN и GND!!! Без конденсатора для загрузки необходимо наживать кнопку «boot/En/RST».
Также, не забудьте саединить вывод(ы) GND контроллера с шиной GND макетной платы!!! Это позволит сэкономить массу времени и нервов.
Абсолютный максимальный ток, потребляемый GPIO, составляет 40 мА.
ESP32 также имеет встроенный датчик Холла, который обнаруживает изменения в магнитном поле в его окружении.
Похожие запросы по теме:
Прерывания Raspberry Pi Pico и учебник по интерфейсу кнопок с использованием MicroPython.

В этой статье мы обсудим, как взаимодействовать с кнопками с Raspberry Pi Pico RP2040 и запускать прерывания. Мы можем подключить кнопку, используя либо Опрос , либо Прерывание . Здесь вы можете узнать разницу между двумя методами и какой из них использовать. Мы также узнаем об устранении дребезга кнопки, чтобы избежать нежелательных вводов. Код в этой статье написан на MicroPython. Это руководство работает для всех вариантов Raspberry Pi Pico, включая 9.0003 Малина Пи Пико W .
Кнопки действуют как устройства ввода для микроконтроллера, и мы можем считывать их состояние. Кнопка, подключенная к положительному напряжению питания микроконтроллера, будет считываться как логический высокий уровень (1), а кнопка, подключенная к земле, будет считываться как логический низкий уровень (0). Raspberry Pi Pico питается от микроконтроллера RP2040, который имеет 36 многофункциональных контактов ввода/вывода общего назначения (GPIO) . Все выводы GPIO Raspberry Pi Pico можно настроить как входные или выходные. Все контакты GPIO также могут быть настроены как внешние прерывания .
Содержание
Опрос и прерывание
Опрос и прерывания — это два метода, используемые для взаимодействия с внешними переключателями, такими как кнопки, клавиатуры, цифровая клавиатура и т. д. Опрос используется, когда приложение не чувствительно ко времени. Прерывания используются, когда устройству немедленно требуется внимание микроконтроллера.
Опрос | Прерывание |
Опрос — это когда ЦП последовательно выполняет код, чтобы проверить, не произошло ли какое-либо изменение состояния. | В случае прерываний устройство или регистр уведомляет ЦП о том, что требует немедленного вмешательства. |
CPU заботится об опросе.![]() | Обработчик прерываний обрабатывает прерывания. |
Опрос происходит через равные промежутки времени благодаря последовательному выполнению кода. | Прерывания могут произойти в любое время. |
Прерывания обрабатываются частями программного обеспечения, называемого подпрограммой обслуживания прерываний (ISR). Когда происходит прерывание, ЦП начинает выполнение кода в рамках этой процедуры. Когда задача в подпрограмме завершена, процессор продолжает выполнение кода с того места, где он был остановлен.
Диаграмма обработки прерыванийПредварительные условия для этого руководства
- Raspberry Pi Pico под управлением MicroPython.
- Кнопка (например, мгновенный тактильный переключатель).
- Соединительные провода и макетная плата.
Нам нужен Raspberry Pi Pico с загруженным файлом MicroPython UF2 . Если вы новичок, вы можете ознакомиться с нашим руководством — Учебное пособие по Raspberry Pi Pico для начинающих — Начало работы с MicroPython и Thonny, чтобы настроить и начать использовать Pico.
Кнопки чтения с использованием опроса в Raspberry Pi Pico (RP2040).
Давайте сначала рассмотрим метод опроса чтения кнопки. Подключите кнопку к вашему Pico, как показано на схеме ниже.
Подключение кнопки Raspberry Pi Pico. Разработано Fritzing. Разработано с использованием FritzingRaspberry Pi Pico имеет 26 легкодоступных GPIO на своей коммутационной плате. Вы можете использовать любой из этих контактов GPIO для подключения кнопок. Вот схема контактов Raspberry Pi Pico W для справки. Распиновка
Raspberry Pi Pico W. Источник: Datasheet Мы напишем скрипт, чтобы определить, является ли кнопка ВЫСОКОЙ или НИЗКОЙ. Пико может подтянуть контакт к положительному напряжению с помощью внутреннего резистора. Зачем нужен подтягивающий резистор? Потому что без настроенного подтягивания контакт будет давать шумный ввод, поскольку он будет в плавающем состоянии.
Подключите Pico к компьютеру и загрузите следующий скрипт:
Язык кода: Python (python)
с PIN-кода импорта машины счетчик=0 вывод = вывод (5, вывод.IN, вывод.PULL_UP) пока верно: если pin.value()==0: print("Кнопка нажата") счетчик+=1 print("Count={}".format(counter))
Сохраните файл на Raspberry Pi Pico с расширением «.py». После нажатия кнопки вы должны увидеть вывод, как показано ниже:
В качестве альтернативы, если вы хотите обнаружить нажатие кнопки, когда кнопка находится в ВЫСОКОМ положении, а не в НИЗКОМ, используйте PULL_DOWN вместо PULL_UP и измените свой код, как показано ниже:
Язык кода: Python (python)
из пина импорта машины счетчик=0 контакт = контакт (5, контакт.
IN, контакт.PULL_DOWN) пока верно: если pin.value() равно 1: счетчик+=1 print("Кнопка нажата") print("Count={}".format(counter))
Объяснение кода :
- Мы импортируем класс Pin из модуля машины , который необходим для взаимодействия с контактами GPIO. Затем мы создаем переменную с именем counter для подсчета количества нажатий переключателя.
Язык кода: JavaScript (javascript)
от штифта импорта машины counter=0
- Создается объект с именем pin , который принимает 3 аргумента. Мы обозначаем GPIO 5 как вход с включенным PULL_UP.
Язык кода: Python (python)
pin = Pin(5, Pin.
IN, Pin.PULL_UP)
- Внутри цикла while мы видим, равно ли pin.value() 0, что означает, что контакт подключен к земле (т. е. кнопка нажата). Если обнаружено нажатие кнопки, мы увеличиваем переменную счетчика и печатаем значение счетчика.
Язык кода: Python (python)
, если pin.value() равно 1: счетчик+=1 print("Кнопка нажата") печать("Счетчик={}".формат(счетчик))
Устранение дребезга пина с помощью MicroPython в Raspberry Pi Pico
Вы заметили какие-либо недостатки в скрипте, который мы написали выше? Одно нажатие кнопки увеличивает счетчик на несколько единиц. Это связано с характером механических контактов в кнопке и называется дребезгом. Устранение дребезга — это процесс устранения дребезга с помощью программного или аппаратного обеспечения. Например, комбинация резистор-конденсатор может использоваться для устранения дребезга переключателя. В случае программного обеспечения измеряется время, прошедшее между двумя последовательными нажатиями кнопки, и если в течение определенного интервала времени происходит несколько вводов, регистрируется только один ввод.
Чтобы реализовать устранение дребезга, нам нужно изменить наш скрипт, чтобы нажатия кнопок обнаруживались с небольшой задержкой между ними. Для этого мы будем использовать модуль time в MicroPython. Он содержит функцию time.ticks_ms() , которая описывается как «возвращает увеличивающийся счетчик миллисекунд с произвольной контрольной точкой, которая возвращается после некоторого значения». Таким образом, функция возвращает случайное значение времени (в миллисекундах), которое увеличивается до определенного значения, и мы можем использовать его для измерения временного интервала между двумя событиями.
Загрузите этот модифицированный скрипт и сохраните файл на Raspberry Pi Pico с расширением имени файла «. py»:
Язык кода: Python (python)
из PIN-кода импорта машины. время импорта счетчик=0 debounce_time = 0 вывод = вывод (5, вывод.IN, вывод.PULL_UP) пока верно: если ((pin.value() равно 0) и (time.ticks_ms()-debounce_time) > 300): счетчик+=1 debounce_time=time.ticks_ms() print("Кнопка нажата") print("Count={}".format(counter))
Мы импортируем модуль времени и создаем переменную с именем debounce_time . Затем мы проверяем, не превышает ли время, прошедшее с момента последнего нажатия кнопки, 300 миллисекунд , используя (time.ticks_ms()-debounce_time) > 300) . Если это условие выполняется, то мы увеличиваем счетчик нажатий кнопки и устанавливаем debounce_time на текущее значение, возвращаемое time. ticks_ms() . Это очень похоже на использование millis() 9Функция 0004 в Arduino.
Внешние прерывания в Raspberry Pi Pico (RP2040)
Все контакты GPIO в Raspberry Pi Pico поддерживают прерывания, которые можно разделить на три типа:
- Высокий уровень
- Низкий уровень : Прерывание происходит, когда на выводе низкий уровень или логический 0.
- Нарастающий фронт : Прерывание происходит, когда контакт переходит из НИЗКОГО в ВЫСОКОЕ состояние.
- Falling Edge : Прерывание происходит, когда контакт переходит из состояния HIGH в LOW.
Прерывания уровня в Pico не фиксируются, т.е. прерывание становится неактивным, как только GPIO меняет свое состояние с HIGH на LOW или наоборот.
Рекомендуемая статья: OLED-дисплей Raspberry Pi Pico SSD1306 Учебное пособие по взаимодействию с использованием MicroPython
Использование кнопок для запуска прерываний Raspberry Pi Pico Теперь попробуем выполнить интерфейс с помощью кнопки прерывания. В этом примере мы будем использовать спадающий фронт (или низкий фронт) напряжения на выводе для запуска прерывания. 9Соединения 0003 будут теми же , которые мы использовали в предыдущем примере для опроса входа кнопки, т.е. подключите кнопку между контактами GP5 и GND .
- В Thonny IDE создайте новый проект и загрузите следующий пример сценария прерывания на Pi Pico.
Язык кода: Python (python)
от штифта импорта машины прерывание_флаг = 0 контакт = контакт (5, контакт. ВХОД, контакт. PULL_UP) Обратный вызов защиты (пин): глобальный флаг_прерывания прерывание_флаг = 1 pin.irq(триггер=Pin.IRQ_FALLING, обработчик=обратный вызов) пока верно: если флаг_прерывания равен 1: print("Произошло прерывание") прерывание_флаг=0
- Нажмите значок Run или F5 , чтобы запустить скрипт.
- Сохраните сценарий в Pico под именем interrupt.py или под любым другим именем с расширением «.py».
При запуске сценария вы должны увидеть строку «Произошло прерывание», отображаемую в окне оболочки Thonny при нажатии кнопки.
Объяснение кода внешнего прерыванияСначала мы импортируем класс Pin и инициализируем глобальную переменную с именем interrupt_flag значением 0. Мы будем использовать эту переменную для отслеживания возникновения прерываний. Глобальные переменные в MicroPython доступны для всех функций. Затем мы создаем объект pin класса Pin . GPIO 5 настроен как вход с включенным PULL_UP .
Язык кода: Python (python)
от штифта импорта машины прерывание_флаг = 0 контакт = контакт (5, контакт.
IN, контакт. PULL_UP)
Далее мы определяем функцию с именем callback() для обработки прерываний. Код внутри этой функции не должен выполнять какую-либо сложную задачу, поскольку ему необходимо быстро передать использование ЦП основной программе. Мы устанавливаем переменную interrupt_flag как 1. Обратите внимание, что нам нужно использовать ключевое слово global , когда мы меняем глобальную переменную внутри функции.
Язык кода: Python (python)
ответ обратного вызова (пин-код): глобальный флаг_прерывания прерывание_флаг=1
Чтобы привязать прерывание к пину, мы используем функцию irq() . Эта функция принимает два аргумента:
триггер : триггер может быть следующих типов-
(1) Pin. IRQ_FALLING – прерывание по заднему фронту.
(2) Pin.IRQ_RISING – прерывание по переднему фронту.
(3) Pin.IRQ_LOW_LEVEL – прерывание по НИЗКОМУ уровню.
(4) Pin.IRQ_HIGH_LEVEL -
прерывание по ВЫСОКОМУ уровню.
(5) Pin.IRQ_FALLING | Pin.IRQ_RISING – прерывание как по переднему, так и по заднему фронту.
обработчик : обработчик определяет функцию, которая будет вызываться при возникновении прерывания.
Язык кода: Python (python)
pin.irq(триггер=Pin.IRQ_FALLING, обработчик=обратный вызов)
В цикле while мы постоянно проверяем значение переменной interrupt_flag . Если это значение определяется как «1», это означает, что произошло прерывание. Мы сбрасываем переменную в «0», чтобы переменная могла быть установлена снова при возникновении прерывания.
Вы могли заметить, что строка «Произошло прерывание» печатается в несколько строк при нажатии всего одной кнопки. Это похоже на случай с подпрыгиванием кнопок, который мы обсуждали ранее в этой статье. Эту задачу мы решим на следующем шаге.
Использование внешнего прерывания для переключения светодиода с помощью MicroPython
В следующем примере давайте попробуем переключить встроенный светодиод Raspberry Pi Pico и устранить дребезг кнопки внешнего прерывания. Код должен быть понятным, как будто мы уже обсуждали подобный код ранее в этой статье.
Язык кода: Python (python)
# Источник: Electrocredible.com, язык: MicroPython из импорта машины Pin время импорта прерывание_флаг = 0 debounce_time = 0 вывод = вывод (5, вывод.
IN, вывод.PULL_UP) светодиод = контакт («светодиод», контакт. ВЫХ.) количество = 0 Обратный вызов защиты (пин): глобальный interrupt_flag, debounce_time если (time.ticks_ms()-debounce_time) > 500: прерывание_флаг = 1 debounce_time=time.ticks_ms() pin.irq(триггер=Pin.IRQ_FALLING, обработчик=обратный вызов) пока верно: если флаг_прерывания равен 1: прерывание_флаг = 0 print("Обнаружено прерывание") led.toggle()
Теперь при нажатии кнопки встроенный светодиод должен переключаться между состояниями ON и OFF.
Опрос или прерывание? Какой из них я должен использовать?
При взаимодействии с внешними устройствами, чувствительными ко времени, следует использовать прерывания. Если ваша программа проста, вы можете использовать опрос кнопок интерфейса. Некоторые микроконтроллеры имеют несколько внешних выводов, совместимых с прерываниями. Если вам нужно взаимодействовать со многими кнопками, такими как клавиатура, вам иногда приходится выбирать опрос вместо использования прерываний. Использование прерывания всегда является наиболее эффективным способом.
Надеюсь, эта статья об использовании внешних прерываний в Raspberry Pi Pico оказалась для вас полезной. Пожалуйста, поделитесь своими мыслями в комментариях ниже. Спасибо за чтение.
Читайте также :
- Учебное пособие по встроенному датчику температуры Raspberry Pi Pico с использованием MicroPython.
- Руководство по ШИМ для Raspberry Pi Pico.
- Руководство по АЦП Raspberry Pi Pico с использованием MicroPython.
- I2C в Raspberry Pi Pico.
Arduino Workshop — Глава 5 — Прерывания
В этом разделе мы рассмотрим, как использовать прерывания. Возможно, вы слышали о них раньше, и это отличный способ повысить эффективность вашей программы при работе с аппаратными входами.
Во всех разделах, которые мы рассмотрели до сих пор, мы использовали кнопки и другие аппаратные устройства в качестве входных данных для управления изменениями в программе, такими как управление выходными данными, а в случае с кнопкой мы должны были сделать Убедитесь, что наша программа регулярно и с высокой частотой выполняет проверку состояния кнопки, чтобы мы не пропустили ее нажатие или отпускание. Этот метод известен как опрос, так как вы включаете постоянный опрос или проверку состояния кнопки. Это все хорошо для простых программ, в которых мало что еще происходит, однако, как только ваша программа начинает расти и становиться более сложной, опрос не работает, потому что у вас есть куча других вещей, происходящих одновременно. Это требует, чтобы ваш микроконтроллер останавливал все, что он делает, и часто проверял состояние кнопки, даже если большую часть времени она точно такая же, как и раньше, к счастью, есть гораздо более эффективный способ считывания состояния цифрового входа с помощью прерываний.
Возможно, вы слышали о прерываниях раньше и представляли их как пугающе сложную процедуру, но Arduino действительно хорошо справляется с тем, чтобы сделать их невероятно удобными для пользователя. Итак, что такое прерывание? Прерывание — это аппаратная часть микроконтроллера, которая способна самостоятельно отслеживать состояние входного вывода и может буквально прерывать микроконтроллер во всем, что он делает, чтобы сообщить ему, что есть готовый вектор прерывания, который определяет состояние вывода. изменился в этом случае, является ли он высоким или низким. Прелесть этого в том, что обо всех прерываниях заботятся аппаратные флаги и некоторые очень низкоуровневые инструкции микроконтроллера, что означает, что вы можете заниматься другими делами, не беспокоясь о постоянной проверке шага кнопки. Хороший способ думать о прерываниях — представить, что вы ожидаете письмо от почтальона, вы можете выходить и регулярно проверять почтовый ящик каждые две минуты или чаще, чтобы узнать, доставлено ли оно, что не позволит вам получить много. сделать в промежутке, или у вас может быть почтовый ящик, который издает громкий шум, когда письмо доставлено, чтобы вы могли забыть о нем, но получать уведомления сразу же, как только оно прибывает, оставляя вас свободными делать все, что вам нравится, до этого момента.
Как упоминалось ранее, существует три основных типа изменения прерываний: повышение и понижение. Когда вы сообщаете Arduino, что хотите, чтобы для вывода было разрешено соответствующее прерывание, вы сообщаете ему, при каких условиях вы хотите вызвать прерывание. На переднем фронте сигнал идет от низкого к высокому, на заднем фронте сигнал идет от высокого к низкому или либо нарастает, либо падает, что называется изменением. Когда это условие выполнено, ваш Arduino запустит определенную функцию, уникальную для этого прерывания. Эта функция известна как подпрограмма обслуживания прерывания или ISR, как мы будем называть ее. Ключом к прерываниям является то, что код, который он выполняет в вашем ISR, должен быть как можно короче, потому что, как только прерывание сработает, оно перейдет из того места, где ваш микроконтроллер был в вашей программе, и обслужит прерванное, завершите ISR до того, как это произойдет. может вернуться к тому месту, где он остановился, и это означает, что он не может делать ничего другого, пока работает ISR, поэтому, если вы используете ЖК-дисплей или подключаетесь к сети Wi-Fi или что-то, что требует жесткой синхронизации и интеграции, эти процессоры часто выходят из строя, потому что, хотя они могут казаться серьезными только в фоновом режиме, если ваш микроконтроллер заблокирован, выполняя ISR, он не может ничего делать.
Попытка запомнить все, что нужно для использования прерываний, может немного сбить с толку, поэтому вот список некоторых основных правил, которые можно и чего нельзя делать при использовании прерываний с Arduino.
Держите ISR или подпрограмму обслуживания прерывания, функцию или причину прерывания как можно короче. Обычно вы используете эти подпрограммы обслуживания прерывания только для установки флага или изменения состояния, а не для выполнения всего раздела кода. ISR не могут возвращать значения или принимать параметры задержки в функции «миллис», встроенной в Arduino, они не будут работать внутри ISR, потому что они основаны на функциях прерывания, и вы можете одновременно выполнять только одно прерывание. Задержанные микросекунды, которые являются подкатегорией функции задержки, за исключением того, что они сохраняют и измеряют в микросекундах, будут работать, потому что они не основаны на прерываниях. Любая переменная, которая изменяется внутри ISR, должна быть объявлена с модификатором volatile, и только определенные выводы имеют возможность прерывания. На Arduino Uno только цифровые контакты 2 и 3 имеют возможности прерывания, и имейте в виду, что не все микросхемы поддерживают все три типа прерываний на всех контактах. Некоторые контакты могут разрешать только прерывание изменения, которое может определить, растет или падает сигнал, но оно будет запущено на любом из них, и вам нужно будет запустить дополнительный код, чтобы определить состояние входа, чтобы определить, был ли он нарастающим или падающим. край.
Для других выводов будут доступны все три параметра, поэтому вы можете установить его для спадающего фронта, нарастающего фронта или смены штифта. Теперь, когда мы поговорили о том, что такое прерывания, давайте посмотрим, как их использовать. Итак, я взгляну на Arduino IDE. Итак, у меня есть базовая функция, и она невероятно похожа на более продвинутую концепцию, которую мы используем для операторов «если», где мы рассмотрели «устранение дребезга» кнопки и использование некоторой логики «F» и некоторых переменных. чтобы отслеживать состояние, используя «Debouncing», чтобы убедиться, что наши переключатели нажимаются четко, и операторы «if», чтобы определить, было ли оно задержано или отпущено. Итак, это почти то же самое, у нас есть светодиодные контакты, контакты кнопок и некоторые глобальные переменные, и единственное отличие здесь, которое вы заметите, это этот изменчивый флаг кнопки int. Теперь флаг кнопки мы собираемся использовать как двоичную переменную флага единицы или нуля, как и любую другую, за исключением того, что мы использовали модификатор volatile, который объявляет, что это целое число может быть изменено без ведома остальной части тела Arduino о его вводе. с точки зрения, весь микроконтроллер сосредоточен на выполнении своей процедуры обслуживания прерываний, и не все остальные эти функции вообще не работают, поэтому вам нужно объявить как volatile, чтобы убедиться, что Arduino знает, что эта переменная может измениться в любое время внутри процедуры обслуживания прерывания.
У нас есть наша переменная «Debounce», как обычно, объявляющая некоторые режимы выводов, и здесь мы видим, что мы инициализируем это прерывание для выводов. Итак, мы используем прикрепленные прерывания, затем внутри мы используем цифровой вывод для прерываний и в скобках вывод, который вы используете, чтобы мы могли изменить его с «2» на вывод кнопки, «2» облегчает запоминание, что мы повторное использование определенного вывода с возможностью прерывания. Затем «, и вам нужно объявить имя функции, которую вы хотите запустить, поэтому «ISR_button» — это общее практическое правило для объявления функций, которые вы запускаете как ISR. Итак, кнопка прерывания сервисной программы, а затем мы хотим, чтобы она запускалась при изменении, то есть при переходе от высокого к низкому сигналу или от низкого к высокому сигналу и наоборот. Таким образом, вам не всегда нужно использовать цифровой вывод для прерывания, внутри Arduino есть несколько различных форматов синтаксиса для этого, однако цифровой вывод для прерывания является самым безопасным, это во многом зависит от модели платы Arduino, которую вы используете. но, вообще говоря, если вы используете цифровой вывод для прерывания, а не только сам вывод, большинство плат будут работать без сучка и задоринки.
Теперь в этом пустом цикле у нас есть точно такой же набор инструкций, который мы использовали для стандартного устранения дребезга, так что мы не будем повторяться слишком долго. Единственная разница в том, что мы добавили дополнительное условие, чтобы определить, входит ли наша Arduino в эту функцию устранения дребезга дыр, как обычно, до того, как у нас было «((millis ()– LastPress) > debounceTime», если это верно, то мы собираемся запустите часть кода, которая гарантировала, что он будет запускаться только с определенной частотой, отфильтровывая этот шум. Теперь мы также добавляем дополнительное условие для пометки кнопки. Флаг кнопки должен быть истинным или одним, чтобы это работало вообще, и причина этого в том, что он собирается обойти все это, потому что оператор «если» не выполняется, и цикл будет повторяться, ничего не делая, и единственный способ, которым флаг кнопки может быть равен 1, это если « ISR_Button», запускается процедура обслуживания прерывания для вывода 2. В этом случае все, что она делает, это устанавливает флаг кнопки, и этот процесс изменения состояния такой переменной флага очень короток. Это действительно хороший пример того, как использовать подпрограммы обслуживания прерываний, мы могли бы поместить весь этот код в сервер прерываний. если бы мы хотели, и это прекрасно работало бы в этом примере, но если бы у нас было много других запущенных фоновых процессов, это показывало бы больше времени, а затем Arduino застрял в этой служебной процедуре, потому что, если бы он выполнялся только через инструкции в цикле void, особенно если вы используете целую кучу других библиотек, о которых мы говорили, особенно если вы знаете синхронизацию конкретного оборудования или служб, которые, безусловно, будут запускать цикл void, но время от времени он будет разветвляться на это еще одна скрытая процедура обслуживания прерываний, которая работает в фоновом режиме и переходит ко всем этим различным частям кода, которые вы на самом деле не понимаете, но если они внутри этого ISR, это невозможно.
Вот почему очень важно, чтобы он был действительно коротким, и тогда он может запускать эту функцию переключения только в том случае, если процедура обслуживания прерывания уже была запущена. Другими словами, если он обнаружил изменение с помощью нажатия или отпускания, и единственное, что мы добавили, это флаг кнопки, равный «0», другими словами, когда он выполняет функцию переключения, включая все устранение дребезга, нет независимо от того, было ли это нажатие или отпускание, для флага кнопки установлено значение «0», что означает, что этот раздел кода не будет выполняться до тех пор, пока процедура обслуживания прерывания не будет запущена снова для сброса этого флага.
Итак, давайте продолжим и загрузим его, убедитесь, что у него правильные настройки, нажмите «Загрузить», и он будет работать точно так же, как и наш предыдущий пример с переключателем, потому что он достигает той же цели, но делает это в гораздо большем объеме. эффективным способом, поэтому, когда мы нажимаем его, это хороший маленький тумблер. Я использую контакт 3 здесь, но вы также можете использовать контакт 13 или любой другой цифровой контакт для светодиода. Однако важно то, что если вы хотите использовать прерывание для контакта кнопки, это может быть только контакт 2 или 3, и вы можете узнать, какие контакты могут прерываться, просто погуглив доску и выполнив поиск «Пины прерывания Arduino Uno» или « Pins прерывания Teensy» или любую другую плату, которую вы используете, быстрый Google откроет лист данных или справочную страницу документации и сообщит вам, что это такое и какие контакты могут иметь дело с прерываниями изменения или они могут иметь дело со всеми тремя, поэтому прибытие , падение, состояние также меняется. Итак, немного об использовании прерываний, они невероятно мощные, вы можете делать с ними все что угодно. Вы можете подключить несколько выводов к одному и тому же ISR или можете использовать его по своему усмотрению, если вы следуете тем рекомендациям, которые мы изложили ранее для основных общих рекомендаций по использованию прерываний.