Интервальный таймер на Arduino: Сомнения по поводу библиотеки TimerOne

Я хочу синхронизировать прерывание таймера с нажатием кнопки. Я хочу прочитать состояние кнопки через 3 секунды с момента первого импульса (чтобы идентифицировать долго нажатую кнопку, 3 секунды для этого примера). Я пытаюсь сделать это с помощью этого кода:

#include <TimerOne.h>
#define pinButton 3
#define POWER_ON_TIME 3 //Длительное нажатие в секундах

volatile unsigned long pressed_Time = 0;
volatile unsigned long myTime_button = 0;
volatile unsigned long myTimeOn_button = 0;
volatile unsigned long myTime_pressed = 0;

unsigned long holdTime = 0;
bool button_state = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(pinButton, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  
  Timer1.initialize();
  Timer1.attachInterrupt(pressed_check);
  attachInterrupt(digitalPinToInterrupt(pinButton), button_act, CHANGE);
  Serial.begin(9600); 
}

void loop() {
  
  Serial.println("myTime_pressed");  
  Serial.println(myTime_pressed);
  
  if (!digitalRead(pinButton)){Timer1.attachInterrupt(pressed_check,POWER_ON_TIME*1000000 );}
    else {Timer1.detachInterrupt();}
   

}
  
void button_act(){
  if (!digitalRead(pinButton)){myTime_button = micros(); //Flanco de bajada
  } 
  else{myTimeOn_button = micros(); } //Flanco de subida
}

void pressed_check(){
  myTime_pressed = micros(); 

}

Таким образом, я могу запустить прерывание таймера при нажатии кнопки, но проблема в том, что время-это не время с момента подключения функции, а с самого начала. Есть ли какие-нибудь советы, чтобы изменить это?

, 👍1

Обсуждение

Функция button_act() отсутствует в опубликованном коде. Пожалуйста, добавьте его. Одна из проблем, вероятно, заключается в том, что вам нужно добавить " L " в конце большого целого числа. В противном случае компилятор по умолчанию будет рассматривать его как целое число (которое не может содержать значение 1 миллион). Но еще: я не понимаю логики вашей программы. В pressed_check() вы не проверяете кнопку, а только устанавливаете myTime_pressed, который только когда-либо печатается, но никак не используется. В loop() вы прикрепляете и отсоединяете прерывание таймера при нажатии и отпускании кнопки, что на самом деле не имеет смысла для меня., @chrisl

И почему вы хотите использовать дополнительный аппаратный таймер для записи продолжительности нажатия? Я не вижу причины, по которой millis() и micros() было бы недостаточно для этого. Нет необходимости проходить через хлопоты с использованием аппаратного таймера., @chrisl

Привет @chrisl . Извините, я перерезал код. Теперь все в порядке. У меня есть два прерывания: одно внешнее, подключенное к кнопке, другое по таймеру. В этом коде я тестирую захват micros() с прерыванием таймера, и я хотел увидеть результаты. Я думал, что micros() может захватить время от attachInterrupt action, а не от запуска Arduino., @Juanma

"micros ()" дает вам микросекунды с момента запуска. Когда вам нужна разница во времени, вам нужно зафиксировать начальное и конечное значения, а затем взять разницу. Хотя я до сих пор не понимаю, зачем вам нужен аппаратный таймер для различения коротких и длинных нажатий кнопок., @chrisl

Я сейчас я сейчас, возможно, что проще сделать это без таймеров, но теперь я хочу знать, почему прикрепленная функция таймера выполняется на интервале времени с самого начала, а не с определенного события., @Juanma

Почему вы вообще используете прерывания? Посмотрите на пример обнаружения изменения состояния в IDE (File->examples->02.digital->State Change Detection), чтобы узнать, как определить, когда кнопка нажата или отпущена, а затем записать время этого события. После того, как текущее время события времени превысит 3 секунды, прочитайте вашу кнопку еще раз. Или сделайте свою жизнь проще и используйте библиотеку Bounce2.h. У него есть класс Button, который будет отслеживать продолжительность пребывания кнопки в любом состоянии., @Arjun Suhass


1 ответ


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

4

Не знаю, понимаю ли я, что ты хочешь сделать. ИМХО TimerOne-хорошая библиотека для повторяющихся задач, а не для событий с одним выстрелом.

Вы должны использовать Timer1.stop и Timer1.resume (), чтобы начать отсчет 3 секунд при каждом нажатии кнопки. Но у TimerOne есть известная проблема: когда вы используете restart или start, ISR запускается немедленно

Вот моя версия вашего кода. Он ждет нажатия кнопки, а затем запускает таймер. Через 3 секунды срабатывает pressed_check и устанавливается longPressDetected flas. Надеюсь, я правильно истолковал ваш вопрос

#include <TimerOne.h>
#define pinButton 3
#define POWER_ON_TIME 3UL //Long press in seconds

volatile unsigned long pressed_Time = 0;
volatile unsigned long myTime_button = 0;
volatile unsigned long myTimeOn_button = 0;
volatile unsigned long myTime_pressed = 0;

volatile bool firstISR_Call = true;
volatile bool longPressDetected = false;

unsigned long holdTime = 0;
bool button_state = false;

void setup() {
    // put your setup code here, to run once:
    pinMode(pinButton, INPUT_PULLUP);
    pinMode(LED_BUILTIN, OUTPUT);

    Timer1.initialize();
    // Create an ISR that is called every POWER_ON_TIME seconds
    Timer1.attachInterrupt(pressed_check, POWER_ON_TIME * 1000000UL);
    // Stop Timer1 now
    Timer1.stop();  
    
    //Timer1.attachInterrupt(pressed_check);

    attachInterrupt(digitalPinToInterrupt(pinButton), button_act, CHANGE);
    Serial.begin(9600);
}

void loop() {
    if (longPressDetected) {
        longPressDetected = false;
        Serial.println("Long press detected");
    }
    delay(100);
}

void button_act() {
    if (!digitalRead(pinButton)) {
        myTime_button = micros(); //Flanco de bajada
        firstISR_Call = true;       // Set to true toprevent "phantom" interrupt
        longPressDetected = false;  // Clear long press detection flag
        Timer1.restart();           // Restart timer from 0 - ISSUE: this fires immediatly an interrupt
                                    // causing a so called "phantom" interrupt
    }
    else { 
      myTimeOn_button = micros() - myTime_button; 
      Timer1.stop();
    } //Flanco de subida
}

void pressed_check() {
    // Detect "phantom" interrupt
    if (firstISR_Call) {
        firstISR_Call = false;
        return;
    }
    longPressDetected = true;
    myTime_pressed = micros() - myTime_button;
    Timer1.stop();
}
,

Большое вам спасибо! Это ответ на мой вопрос! Я попробовал перезапустить и запустить, но это сработало не так, как я хотел. Большое вам спасибо!, @Juanma

@Juanma не за что, моя радость., @Marco Cogo