Датчик касания — определение длительности нажатия/удержания и соответствующее изменение хода программы

Приведенный ниже код используется для управления реле с помощью Arduino. Нажатие на сенсорный датчик подключает и отключает реле.

Если пользователь нажимает/касается/удерживает палец на датчике касания дольше двух секунд, как мне настроить программу так, чтобы она выполняла что-то иное, кроме подключения или отключения реле?

#define TouchSensor 9 // Контакт для емкостного сенсорного датчика

int relay = 2; 

boolean currentState = LOW;
boolean lastState = LOW;
boolean RelayState = LOW;

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT);  
  pinMode(TouchSensor, INPUT);
}

void loop() {
  currentState = digitalRead(TouchSensor);
    if (currentState == HIGH && lastState == LOW){
    Serial.println("pressed");
    delay(1);

    if (RelayState == HIGH){
      digitalWrite(relay, LOW);
      RelayState = LOW;
    } else {
      digitalWrite(relay, HIGH);
      RelayState = HIGH;
    }
  }
  lastState = currentState;
}

, 👍1


3 ответа


Лучший ответ:

1

Вам необходимо определить, как долго датчик был нажат до момента отпускания. Когда он отпущен, вы можете предпринять соответствующие шаги. Если нажатие было короче, скажем, 1,5 с, вы можете переключить реле. В противном случае вы можете сделать что-то еще.

Есть много способов добиться этого. Вы можете запрограммировать это самостоятельно, используя функцию millis(). Вам придется установить временную метку, когда состояние датчика изменится на высокое, затем дождаться, пока оно станет низким, и вычесть временную метку из текущего значения millis(). Это даст вам длительность нажатия, которую вы можете использовать в соответствующем операторе if.

Или вы можете использовать библиотеку Debounce, которая немного упрощает задачу (не намного, но вам следует рассмотреть возможность устранения дребезга в зависимости от типа используемого вами датчика). Посмотрите на ответ VE7JRO на этот вопрос. Функция debouncer.update() проверяет, изменилось ли состояние кнопки. Если это так и значение было LOW (в вашем случае его нужно изменить на HIGH), устанавливается временная метка со значением millis(). Когда происходит обновление с LOW, вычисляется разница во времени между двумя событиями и выполняется соответствующее действие. Я добавлю код из ответа для справки здесь:

// Подключите один конец кнопочного переключателя NO к GND, а другой
// конец к выводу 4 Arduino.
// ПРИМЕЧАНИЕ: Если кнопка удерживается нажатой меньше времени, чем задержка устранения дребезга
// время, прошедшее время отобразит время задержки устранения дребезга.
#include <Debounce.h>
const byte SWITCH = 4;
unsigned long startTime = 0;
unsigned long endTime = 0;
unsigned long elapsedTime = 0;
const byte debounceDelayTime = 50;

Debounce debouncer = Debounce(debounceDelayTime, SWITCH);

void setup(){
  Serial.begin(9600);
  pinMode(SWITCH, INPUT_PULLUP);
}

void loop(){
  if(debouncer.update()){
    if(debouncer.read() == 0){
      startTime = millis();
      Serial.println("Button Pressed");
    }
    else if(debouncer.read() == 1){
      endTime = millis();
      Serial.println("Button Released");
      elapsedTime = endTime - startTime;
      Serial.print("Button Held Down For ");
      Serial.print(elapsedTime);
      Serial.println(" ms.");
    }
  }
}
,

1

Этот скетч использует таймер millis() для добавления концепции времени к устранению дребезга кнопки с помощью библиотеки Bounce2 (эта библиотека может быть включена в текущую версию Arduino IDE). Этот скетч не содержит никакого кода для включения и выключения реле.

// Подключите один конец кнопочного переключателя NO к GND
// а другой конец — к контакту 4 Arduino.
#include <Bounce2.h>

byte buttonState = 0;
byte lastButtonState = 0;
const byte buttonPin = 4;
const byte debouncerInterval = 50;         // Время в мс.
unsigned long buttonHeldThreshold = 2000;  // Время в мс.
unsigned long buttonPressTimeStamp;

Bounce debouncer = Bounce();

void setup(){
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  debouncer.attach(buttonPin);
  debouncer.interval(debouncerInterval);
}

void loop(){

  if(debouncer.update()){

    if(debouncer.read() == 0){
      buttonState = 1;
      buttonPressTimeStamp = millis();
      Serial.println("Button Pressed");
    }
    else if(debouncer.read() == 1){
      buttonState = 0;
      Serial.println("Button Released");
    }
  }

  if(buttonState == 1){
    if(millis() - buttonPressTimeStamp >= buttonHeldThreshold){
      buttonState = 2;
      Serial.println("Button Held for 2+ seconds");
    }
  }

  // Выводить содержимое переменной buttonState только при его изменении.
  if(buttonState != lastButtonState){
    Serial.print("Button state = ");
    Serial.println(buttonState);
    Serial.println();
    lastButtonState = buttonState;
  }
}

Помните, что в этой библиотеке есть функции debouncer.rose() и debouncer.fell(), которые могут быть вам полезны. Всегда полезно посмотреть файлы *.h и *.cpp в устанавливаемых библиотеках. Может быть несколько функций, которые не показаны в примерах библиотеки. Иногда автор(ы) используют комментарии к коду в библиотеке, которые могут помочь вам устранить любые возникающие проблемы.

,

1

Для такого рода сценария «активация» кнопки никогда не происходит при ее нажатии. Да, при «нормальных» обстоятельствах вы нажимаете кнопку, цепь замыкается, и что-то происходит.

Однако, если вам нужно больше, чем просто эта простая операция, вы никогда ничего не делаете, просто нажав ее.

Например, если вы нажимаете на ссылку на веб-странице, при нажатии кнопки мыши ничего не происходит. Да, ссылка «выбрана», но это все. Ничего активного не происходит, пока вы не отпустите кнопку мыши. Именно действие «нажать-отпустить» представляет собой «щелчок» — и то только в том случае, если отпускание происходит в течение определенного времени после нажатия.

Это позволяет реализовать другие варианты, например, «нажать-перетащить-отпустить» для перетаскивания или «нажать-подождать-отпустить» для выбора без активации и т. д.

Итак, для вашего сценария у вас есть два желаемых варианта «запуска»:

  • пресс-релиз
  • нажмите и удерживайте

Если «выпуск» «пресс-релиза» происходит за более короткое время, чем время «удержания» «пресс-удержания», вы можете различать их.

Итак, ваша методология будет выглядеть примерно так:

  • Кнопка нажата — засекаем время
  • Либо:
    • Кнопка отпущена, и время истекло < 2 секунд, или
    • Прошедшее время >= 2 секунды

Как код, который может выглядеть примерно так:

static uint32_t ts = 0;
static uint8_t buttonState = HIGH;

uint8_t buttonValue = digitalRead(ButtonPin);

if (buttonValue != buttonState) { // Состояние изменилось.
    buttonState = buttonValue; // Запишите его
    if (buttonState == LOW) { // Кнопка была нажата
        ts = millis(); // Записываем время
    } else if (ts > 0) { // Отпущено - ts должно быть установлено нажатием
        if (millis() - ts < 2000) { // Прошло менее 2 секунд
            // Запустите процедуру «пресса»
            ts = 0; // Очищаем нашу временную метку.
        }
    }
} else if (ts > 0) { // Состояние не изменилось, но кнопка была нажата
    if (buttonState == LOW) { // Он удерживается. Не является строго необходимым, но не повредит
        if (millis() - ts >= 2000) { // прошло 2 секунды
            // Запустите процедуру «удержания»
            ts = 0; // Очищаем нашу временную метку.
        }
    }
}

Переменная отметки времени ts используется как для записи времени нажатия кнопки, так и в качестве флага, указывающего, что мы в данный момент находимся в «неактивированном» состоянии. То есть, для состояния «hold» для указания, нужно ли нам все еще запускать нашу «hold»-процедуру или нет. Без этой проверки после 2 секунд удержания кнопки «hold»-процедура будет продолжать выполняться снова и снова, пока кнопка не будет отпущена. Это похоже на реализацию «принудительного» отпускания кнопки после того, как она запустила «hold»-процедуру. После этого первого срабатывания «hold» нам больше не важно, что делается с кнопкой. Мы игнорируем все до следующего ее нажатия, когда мы снова устанавливаем ts.

,