Arduino прерывания по кнопке. Прерывания по кнопке на Arduino: аппаратные прерывания и программные решения

Как настроить и использовать прерывания по кнопке на 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 const int buttonPin = 4; volatile bool buttonPressed = false; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT_PULLUP); attachPCINT(digitalPinToPCINT(buttonPin), buttonISR, FALLING); } void loop() { if (buttonPressed) { Serial.println(«Кнопка нажата!»); buttonPressed = false; } } void buttonISR() { buttonPressed = true; } «`

Основные отличия от аппаратного прерывания:

  • Используется библиотека 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 const int buttonPin = 2; volatile bool buttonState = HIGH; volatile bool lastButtonState = HIGH; volatile unsigned long lastDebounceTime = 0; const unsigned long debounceDelay = 50; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(buttonPin), buttonISR, CHANGE); Timer1.initialize(1000); // проверка каждую миллисекунду Timer1.attachInterrupt(checkButtonState); } void loop() { // Основной код программы } void buttonISR() { lastDebounceTime = micros(); } void checkButtonState() { if ((micros() — lastDebounceTime) >
debounceDelay) { bool reading = digitalRead(buttonPin); if (reading != lastButtonState) { lastButtonState = reading; if (reading == LOW) { Serial.println(«Кнопка нажата!»); } } } } «`

В этом примере:


  • Прерывание срабатывает при любом изменении состояния кнопки
  • В прерывании только обновляется время последнего изменения
  • Таймер периодически проверяет, прошло ли достаточно времени с последнего изменения
  • Если время прошло, проверяется реальное состояние кнопки

Особенности работы с прерываниями

При использовании прерываний следует учитывать некоторые важные моменты:

  • Функция-обработчик прерывания должна быть максимально короткой
  • В обработчике нельзя использовать функции, работающие с прерываниями (например, 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 и двигатель. Я буду использовать мотор редуктор от машинки, которую собирал и программировал на 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» в коде.py1 Kb 245Скачать
Пример 2. Прерывания на микроконтроллере ESP32 с помощью языка MycroPython. py1 Kb 250Скачать
Пример 3. Управление двигателем постоянного тока с помощью ESP32 и MycroPython.py1 Kb 261Скачать

Ардуино. Описание GPIO.



Левая сторона. Сверху вниз.

вывода
Наименование
вывода
GPIOInputOutputI/OADCTOUCHШИМ
PWM
DAC  Описание
             
23V3          Питание: +3,3В
3EN          Сброс
4SENSOR VP36OK  ADC0 +   input only
5SENSOR VP39OK  ADC3 +   input only
6IO3434OK  ADC6 +   input only
7IO3535OK  ADC7 +   input only
8IO3232OKOK ADC4TOUCH9+    
9IO3333OKOK ADC5TOUCH8+    
10IO2525OKOK ADC18 +DAC_1   
11IO2626OKOK ADC19 +DAC_2   
12IO2727OKOK ADC17TOUCH7+    
13IO1414OKOK ADC16TOUCH6+ HSPICLKHS2 CLKoutputs PWM signal at boot
14IO1212OKOK ADC15TOUCH5+ HSPICHS DATA2boot fail if pulled high
1GND           
16IO1313OKOK ADC14TOUCh5+ HSPIDHS DATA3 
17SD29xx   +   connected to the integrated SPI flash
18SD310xx   +   connected to the integrated SPI flash
 GND           
 +5V          Питание: +5В
             
Правая сторона. Сверху вниз.

вывода
Наименование
вывода
GPIOInputOutputI/OADCTOUCHШИМ
PWM
DAC  Описание
             
 GND           
37IO2323OKOK   + VSIPIDHS1 STROBE 
36 SCLIO2222OKOK   + VSPIWP  
35 TXD0 1     +   debug output at boot
34 RXD0 3OK    +   HIGH at boot
33 SDAIO2121OKOK   + VSIHD  
 GND           
31IO1919OKOK   + VSPIQ  
30IO1818OKOK   + VSPICLKHS1-DATA7 
29IO055OKOK   + VSPICSOHS1-DATA6outputs PWM signal at boot
28IO1717OKOK   +  HS1-DATA5 
27IO1616OKOK   +  HS1-DATA4 
26IO44OKOK ADC10TOUCH0+ HSPIHDHS1-DATA1 
25IO00   ADC11TOUCh2+    
24IO22OKOK ADC12TOUCh3+ HSPIWPHS2-DATA0connected to on-board LED
23IO1515OKOK ADC13TOUCh4+ HSPICSOHS2-CMD 
22SD18xx   + SPIDHS1-DATA1connected to the integrated SPI flash
21SD07xx   + SPIQHS1-DATA0connected to the integrated SPI flash
20CLK6xx   + SPICLKHS1-CLKconnected to the integrated SPI flash
             
  0pulled upOK       outputs PWM signal at boot
  11xx       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 по умолчанию:

SPIMOSIMISOCLKCS
VSPIGPIO 23GPIO 19GPIO 18GPIO 5
HSPIGPIO 13GPIO 12GPIO 14GPIO 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. Разработано с использованием Fritzing

Raspberry Pi Pico имеет 26 легкодоступных GPIO на своей коммутационной плате. Вы можете использовать любой из этих контактов GPIO для подключения кнопок. Вот схема контактов Raspberry Pi Pico W для справки. Распиновка

Raspberry Pi Pico W. Источник: Datasheet

Мы напишем скрипт, чтобы определить, является ли кнопка ВЫСОКОЙ или НИЗКОЙ. Пико может подтянуть контакт к положительному напряжению с помощью внутреннего резистора. Зачем нужен подтягивающий резистор? Потому что без настроенного подтягивания контакт будет давать шумный ввод, поскольку он будет в плавающем состоянии.

Подключите Pico к компьютеру и загрузите следующий скрипт:

 

с PIN-кода импорта машины счетчик=0 вывод = вывод (5, вывод.IN, вывод.PULL_UP) пока верно: если pin.value()==0: print("Кнопка нажата") счетчик+=1 print("Count={}".format(counter))

Язык кода: Python (python)

Сохраните файл на Raspberry Pi Pico с расширением «.py». После нажатия кнопки вы должны увидеть вывод, как показано ниже:

В качестве альтернативы, если вы хотите обнаружить нажатие кнопки, когда кнопка находится в ВЫСОКОМ положении, а не в НИЗКОМ, используйте PULL_DOWN вместо PULL_UP и измените свой код, как показано ниже:

 

из пина импорта машины счетчик=0 контакт = контакт (5, контакт. IN, контакт.PULL_DOWN) пока верно: если pin.value() равно 1: счетчик+=1 print("Кнопка нажата") print("Count={}".format(counter))

Язык кода: Python (python)

Объяснение кода :

  • Мы импортируем класс Pin из модуля машины , который необходим для взаимодействия с контактами GPIO. Затем мы создаем переменную с именем counter для подсчета количества нажатий переключателя.
 

от штифта импорта машины counter=0

Язык кода: JavaScript (javascript)
  • Создается объект с именем pin , который принимает 3 аргумента. Мы обозначаем GPIO 5 как вход с включенным PULL_UP.
 

pin = Pin(5, Pin. IN, Pin.PULL_UP)

Язык кода: Python (python)
  • Внутри цикла while мы видим, равно ли pin.value() 0, что означает, что контакт подключен к земле (т. е. кнопка нажата). Если обнаружено нажатие кнопки, мы увеличиваем переменную счетчика и печатаем значение счетчика.
 

, если pin.value() равно 1: счетчик+=1 print("Кнопка нажата") печать("Счетчик={}".формат(счетчик))

Язык кода: Python (python)

Устранение дребезга пина с помощью MicroPython в Raspberry Pi Pico

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

Чтобы реализовать устранение дребезга, нам нужно изменить наш скрипт, чтобы нажатия кнопок обнаруживались с небольшой задержкой между ними. Для этого мы будем использовать модуль time в MicroPython. Он содержит функцию time.ticks_ms() , которая описывается как «возвращает увеличивающийся счетчик миллисекунд с произвольной контрольной точкой, которая возвращается после некоторого значения». Таким образом, функция возвращает случайное значение времени (в миллисекундах), которое увеличивается до определенного значения, и мы можем использовать его для измерения временного интервала между двумя событиями.

Загрузите этот модифицированный скрипт и сохраните файл на Raspberry Pi Pico с расширением имени файла «. py»:

 

из 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))

Язык кода: Python (python)

Мы импортируем модуль времени и создаем переменную с именем 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.
 

от штифта импорта машины прерывание_флаг = 0 контакт = контакт (5, контакт. ВХОД, контакт. PULL_UP) Обратный вызов защиты (пин): глобальный флаг_прерывания прерывание_флаг = 1 pin.irq(триггер=Pin.IRQ_FALLING, обработчик=обратный вызов) пока верно: если флаг_прерывания равен 1: print("Произошло прерывание") прерывание_флаг=0

Язык кода: Python (python)
  • Нажмите значок Run или F5 , чтобы запустить скрипт.
  • Сохраните сценарий в Pico под именем interrupt.py или под любым другим именем с расширением «.py».

При запуске сценария вы должны увидеть строку «Произошло прерывание», отображаемую в окне оболочки Thonny при нажатии кнопки.

Объяснение кода внешнего прерывания

Сначала мы импортируем класс Pin и инициализируем глобальную переменную с именем interrupt_flag значением 0. Мы будем использовать эту переменную для отслеживания возникновения прерываний. Глобальные переменные в MicroPython доступны для всех функций. Затем мы создаем объект pin класса Pin . GPIO 5 настроен как вход с включенным PULL_UP .

 

от штифта импорта машины прерывание_флаг = 0 контакт = контакт (5, контакт. IN, контакт. PULL_UP)

Язык кода: Python (python)

Далее мы определяем функцию с именем callback() для обработки прерываний. Код внутри этой функции не должен выполнять какую-либо сложную задачу, поскольку ему необходимо быстро передать использование ЦП основной программе. Мы устанавливаем переменную interrupt_flag как 1. Обратите внимание, что нам нужно использовать ключевое слово global , когда мы меняем глобальную переменную внутри функции.

 

ответ обратного вызова (пин-код): глобальный флаг_прерывания прерывание_флаг=1

Язык кода: Python (python)

Чтобы привязать прерывание к пину, мы используем функцию 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 – прерывание как по переднему, так и по заднему фронту.

обработчик : обработчик определяет функцию, которая будет вызываться при возникновении прерывания.

 

pin.irq(триггер=Pin.IRQ_FALLING, обработчик=обратный вызов)

Язык кода: Python (python)

В цикле while мы постоянно проверяем значение переменной interrupt_flag . Если это значение определяется как «1», это означает, что произошло прерывание. Мы сбрасываем переменную в «0», чтобы переменная могла быть установлена ​​снова при возникновении прерывания.

Вы могли заметить, что строка «Произошло прерывание» печатается в несколько строк при нажатии всего одной кнопки. Это похоже на случай с подпрыгиванием кнопок, который мы обсуждали ранее в этой статье. Эту задачу мы решим на следующем шаге.

Использование внешнего прерывания для переключения светодиода с помощью MicroPython

В следующем примере давайте попробуем переключить встроенный светодиод Raspberry Pi Pico и устранить дребезг кнопки внешнего прерывания. Код должен быть понятным, как будто мы уже обсуждали подобный код ранее в этой статье.

 

# Источник: 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()

Язык кода: Python (python)

Теперь при нажатии кнопки встроенный светодиод должен переключаться между состояниями 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 или можете использовать его по своему усмотрению, если вы следуете тем рекомендациям, которые мы изложили ранее для основных общих рекомендаций по использованию прерываний.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *