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?
1 Answer 1
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();
}
-
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– Juanma2022年02月16日 09:45:51 +00:00Commented Feb 16, 2022 at 9:45
-
@Juanma you're welcome, my pleasure.Marco Cogo– Marco Cogo2022年02月16日 13:35:11 +00:00Commented Feb 16, 2022 at 13:35
Explore related questions
See similar questions with these tags.
button_act()
is missing from the posted code. Please add it. One problem is probably that you need to addL
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. Inpressed_check()
you don't check the button but only setmyTime_pressed
, which is only ever printed but not used in any way. Inloop()
you attach and detach the timer interrupt on button press and release, which doesn't really make sense to me.millis()
andmicros()
wouldn't be enough for this. No need to go through the hassle of using a hardware timer.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.