1

I want to synchronize a timer interrupt from a button is pressed. I want to read a button state 3 seconds later from the first pulse moment (to identify long pressed button, 3 seconds for this example). I'm trying to do with this code:

#include <TimerOne.h>
#define pinButton 3
#define POWER_ON_TIME 3 //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;

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(); 

}

This way I can start the timer interrupt when the button is pressed, but the problem is the time is not the time from the function is attached but from the beginning. Any advice to change this?

6
  • 1
    The function button_act() is missing from the posted code. Please add it. One problem is probably that you need to add L at the end of a big integer number. Otherwise the compiler will by default treat it as integer (which cannot hold the value 1 million). But also: I don't understand the logic of your program. In pressed_check() you don't check the button but only set myTime_pressed, which is only ever printed but not used in any way. In loop() you attach and detach the timer interrupt on button press and release, which doesn't really make sense to me.
    – chrisl
    Feb 15, 2022 at 10:49
  • 2
    And why do you want to use an extra hardware timer to record the press duration? I don't see a reason why millis() and micros() wouldn't be enough for this. No need to go through the hassle of using a hardware timer.
    – chrisl
    Feb 15, 2022 at 10:50
  • Hi @chrisl . I cut the code, sorry. Now all is ok. I have two interrupts: one external, connected to the button, the other by timer. On this code I'm testing the micros() capture with timer interruption and I wanted to see the results. I thought micros() could capture the time from attachInterrupt action, not from the Arduino start.
    – Juanma
    Feb 15, 2022 at 11:05
  • 2
    micros() gives you the microseconds from the startup. When you need a time difference you need to capture the start and end value and then take the difference. Though I still don't see why you would need a hardware Timer for distinguishing short and long button presses.
    – chrisl
    Feb 15, 2022 at 11:12
  • 1
    Why are you using interrupts at all? Look at the State Change Detection example in the IDE (File->examples->02.digital->State Change Detection) to learn how to detect when the button gets pressed or released and then record the time of that event. After the current time - event time is greater than 3 seconds, read your button again. Or, make your life easier and use the Bounce2.h library. It has a Button class that will track the duration the button has been in any state. Feb 21, 2022 at 17:22

1 Answer 1

4

Don't know if I understand what you want to do. IMHO TimerOne is a good library for repetitive tasks, not for one shot events.

You should use Timer1.stop and Timer1.resume() to start the 3 seconds count whenever you press the button. But TimerOne has a known issue: when you use restart or start the ISR is fired immediatly

Here is my version of your code. It waits for button press and then starts timer. After 3 seconds pressed_check is fired and the longPressDetected flas is set. I hope I have correctly interpreted your question

#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();
}
2
  • Thank you so much! This is the answer for my question! I tried with restart and start but it didn't work like I wanted. Thank you so much!
    – Juanma
    Feb 16, 2022 at 9:45
  • @Juanma you're welcome, my pleasure.
    – Marco Cogo
    Feb 16, 2022 at 13:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.