Общие сведения
В этом уроке мы научимся обрабатывать состояния кнопки. Для показательности во втором и третьем примере будет использоваться светодиод, с которым мы работали в прошлом уроке.
Для этого урока нам понадобится:
Подключение
Подключим Trema-модуль Светодиод согласно таблице
Вывод модуля | Вывод Pi Pico |
---|---|
Vcc | 3V3(OUT) |
GND | GND |
S | GP15 |
Подключим Trema-модуль Кнопку согласно таблице
Вывод модуля | Вывод Pi Pico |
---|---|
Vcc | 3V3(OUT) |
GND | GND |
S | GP2 |
Выводим состояние кнопки в монитор последовательного порта
В следующем примере состояние кнопки считывается в цикле и выводится в монитор:
// определяем вывод к которому подключена кнопка #define BUT_PIN 2 // создаём переменную для хранения последнего состояния кнопки bool last_button = false; void setup() { // Инициируем последовательный порт Serial.begin(115200); // Устанавливаем работу вывода кнопки на вход pinMode(BUT_PIN, INPUT); } void loop() { // записываем текущее состояние кнопки bool button = digitalRead(BUT_PIN); // если текущее состояние кнопки не соответсвует предыдущему if (last_button != button) { // записываем новое состояние кнопки last_button = button; // если кнопка нажата, выводи информацию в последовательный порт if (button) { Serial.println("Кнопка нажата"); } } delay(100); }
Переключаем светодиод
В данном примере мы переключаем состояние светодиода при помощи кнопки. Это простое исполнение кнопки как переключателя.
Пример:
// определяем вывод к которому подключена кнопка #define BUT_PIN 2 // определяем вывод к которому подключён светодиод #define LED_PIN 15 // сосдаём переменные для хранения состояния кнопки и светодиода bool last_button = false; bool led_state = false; void setup() { // Инициируем последовательный порт Serial.begin(115200); // Устанавливаем работу вывода кнопки на вход pinMode(BUT_PIN, INPUT); // устанавливаем режим работы вывода светодиода pinMode(LED_PIN, OUTPUT); } void loop() { // записываем текущее состояние кнопки bool button = digitalRead(BUT_PIN); // если состояние изменилось if (last_button != button) { // записывем состояние в глобальную переменную last_button = button; // если состояени - кнопка отжата if (!button) { // переключаем состояние переменной светодиода led_state = !led_state; // устанавливаем уровень на выводе светодиода digitalWrite(LED_PIN, led_state); } } delay(100); }
Устранение дребезга
При нажатии или отпускании кнопка может поменять своё состояние
несколько раз в течении 50-100 миллисекунд (попробуйте убрать строчку
delay(100)
из предыдущего примера и посмотрите, что
произойдёт). Это называется дребезг кнопки (bounce).
Для устранение этого в предыдущем примере мы использовали функцию
sleep
. Теоретически эта функция отличается от типичного для
ардуино delay
, так как она не блокирует другие задачи,
запущенные в операционной системе, если таковая имеется, но в контексте
данных уроков sleep
всё же блокирует текущий поток
выполнения. Поэтому рассмотрим неблокирующее устранение дребезга.
Алгоритм данного примера кажется сложным, но на самом деле он очень прост:
- проверяем состояние кнопки
- если состояние кнопки изменилось - записываем время изменения
- продолжаем выполнять программу дальше
- если подошёл интервал проверки DEBOUNCE_MS и состояние кнопки до сих
пор отличается от записанного ранее, значит состояние кнопки
действительно изменилось
- записываем новое состояние
- если подошёл интервал проверки DEBOUNCE_MS и состояние кнопки до сих
пор отличается от записанного ранее, значит состояние кнопки
действительно изменилось
// вывод к которому подключена кнопка #define BUT_PIN 2 // вывод к которому подключён светодиод #define LED_PIN 15 // интервал для устранения дребезга #define DEBOUNCE_MS 100 // интервал для вывода информации в последовательный порт #define PRINT_INTERVAL 2000 // переменные для хранения состояний кнопки bool button_state = false; bool last_state = false; // переменная для хранения состояние светодиода bool led_state = false; // переменные для хранения относительного времени событий unsigned long debounce_millis, print_millis; void setup() { // инициируем работу с последовательным портом Serial.begin(115200); // Устанавливаем работу вывода кнопки на вход pinMode(BUT_PIN, INPUT); // Устанавливаем работу вывода светодиода на выход pinMode(LED_PIN, OUTPUT); } void loop() { // записываем текущее состояние кнопки bool current_state = digitalRead(BUT_PIN); // если состояние изменилось, записываем время изменения if (current_state != last_state) { debounce_millis = millis(); } // если подошёл интервал устранения дребезга if (millis() - debounce_millis > DEBOUNCE_MS) { // если состояние кнопки не соответсвует записаному ранее if (current_state != button_state) { // записываем новое состояние button_state = current_state; // Если новое состояние - отжатая кнопка if (!button_state) { // Переключаем светодиод led_state = !led_state; digitalWrite(LED_PIN, led_state); } } } // Записиваем последнее состояние кнопки last_state = current_state; // Выводим текст через интервал if (millis() - print_millis > PRINT_INTERVAL) { print_millis = millis(); Serial.println("Выполняем что-то ещё, устранение дребезга кнопки не блокирует поток"); } }
Обсуждение