On an ESP32 I have 6 push buttons connected to digital inputs that need to be checked every 10 milliseconds.
For each one I keep a history of the last 3 values and only register a button press or release if there are 3 consecutive 0 or 1 values over that 30 millisecond period. This debounces and rejects accidental brief presses.
Is it considered OK to run this type of scanning process in its own RTOS task, or would it be better to use a timer interrupt to give consistent 10 millisecond sample intervals?
Curious: In this scenario which seems like what tasks are for, what makes the scan happen (the task run) at 100 Hz your preferred rate of looking at the buttons?
FreeRtos has a software timer built in that you can use.
They are very simple to use also. When the timer times out it can run your function.
See FreeRtos_Real_Time_Kernal.pdf from the FreeRTOS site. It is a downloadable pdf that
describes with examples how to use FreeRTOS. Chapter 5 describes how to use the timer
with examples.
This task is triggered by freeRTOS to run after a time out,
void fmqttWatchDog( void * paramater )
{
int UpdateImeTrigger = 86400; //seconds in a day
int UpdateTimeInterval = 85000; // get another reading when = UpdateTimeTrigger
int maxNonMQTTresponse = 12;
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 5000; //delay for mS
for (;;)
{
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
xSemaphoreTake( sema_mqttOK, portMAX_DELAY ); // update mqttOK
mqttOK++;
xSemaphoreGive( sema_mqttOK );
if ( mqttOK >= maxNonMQTTresponse )
{
ESP.restart();
}
UpdateTimeInterval++; // trigger new time get
if ( UpdateTimeInterval >= UpdateImeTrigger )
{
TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
UpdateTimeInterval = 0;
}
}
vTaskDelete( NULL );
} //void fmqttWatchDog( void * paramater )
@LarryD does that do what @mikb55 wants ? If the switch does not bounce then there will only be a single state change no matter how long you hold down the key hence the counter will not increment
Let’s say when the counter reaches 3 you service the switch change.
The 1st 10ms timeout, when there is a change in switch state, the counter will be incremented (1) (the lastSwitchState is not updated yet).
The 2nd 10ms timeout, if the switch is still in that state, the counter is again incremented (2) (the lastSwitchState is not updated yet).
The 3rd 10ms timeout, if the switch is still in that state, the counter is again incremented (3).
When the counter is 3, the lastSwitchState is updated, then counter is reset to 0, we then check to see if the switch was closed or opened etc.
If during the 2nd 10ms interval a bounce on the switch is back to where things are considered steady state, the counter is reset to 0 and the change in the switch is rejected.
I was under the impression that this is a cooperative timer, and therefore the running of a particular scheduled function will be delayed if another scheduled function is still running.
This was what I was trying to explain, things have been slowed down to show things in the serial monitor but you should get the idea.
//********************************************^************************************************
// FileName.ino
// LarryD
//
// Version YY/MM/DD Comments
// ======= ======== ========================================================
// 1.00 YY/MM/DD Running code
//
//
//
//********************************************^************************************************
#define LEDon HIGH
#define LEDoff LOW
#define ENABLED true
#define DISABLED false
#define PUSHED LOW
#define RELEASED HIGH
//********************************************^************************************************
const byte startSwitch = 2;
const byte testLED = 12;
const byte heartbeatLED = 13;
const byte triggerAt = 10;
byte switch2Counter = 0;
byte lastStartSwitch = RELEASED;
//Timing stuff
unsigned long heartbeatMillis;
unsigned long switchMillis;
const unsigned long heartBeatInterval = 500ul; //1/2 second
const unsigned long sampleInterval = 100ul; //100 milliseconds
// s e t u p ( )
//********************************************^************************************************
//
void setup()
{
Serial.begin(115200);
pinMode(testLED , OUTPUT);
pinMode(heartbeatLED , OUTPUT);
pinMode(startSwitch , INPUT_PULLUP);
} //END of setup()
// l o o p ( )
//********************************************^************************************************
//
void loop()
{
//*********************************
//is it time to toggle the heartbeatLED ?
if (millis() - heartbeatMillis >= heartBeatInterval)
{
//restart this TIMER
heartbeatMillis = millis();
//toggle the heartbeatLED
digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
}
//*********************************
//is it time to check the switches ?
if (millis() - switchMillis >= sampleInterval)
{
//restart this TIMER
switchMillis = millis();
checkSwitches();
}
//*********************************
//other non blocking code
//*********************************
} //END of loop()
// c h e c k S w i t c h e s ( )
//********************************************^************************************************
//
void checkSwitches()
{
byte currentState;
//********************************* s t a r t S w i t c h
currentState = digitalRead(startSwitch);
//has this switch changed state ?
if (lastStartSwitch != currentState)
{
switch2Counter++;
Serial.println(switch2Counter);
//have we had 10 consecutive reads at this state ?
if (switch2Counter >= triggerAt)
{
//we have had a valid change, reset for the next one
switch2Counter = 0;
//update to the new switch state
lastStartSwitch = currentState;
//******************
//has the switch been pushed ?
if (currentState == PUSHED)
{
//toggle testLED
digitalWrite(testLED, !digitalRead(testLED));
}
//******************
//switch must have been released
else
{
//do somthing
}
}
} //END of if (lastStartSwitch != currentState)
else
{
//there was no valid chnge in state
switch2Counter = 0;
}
//*********************************
//future switches go here
//*********************************
} //END of checkSwitches()
//********************************************^************************************************
// E N D o f s k e t c h c o d e
//********************************************^************************************************
I don't know what else you have going on in your application. Just giving you some options, bro.
From what I read in the kernel documentation, the timer task priority can be set in the FreeRTOSConfig.h file. I don't know how the espressif deals with timer task priority though as they have modified vanilla FreeRTOS.
I don't use RTOS but my fast debounce works like yours, it looks for a stable pin after a first change detect. My way looks at an 8 read history over 4ms where you look at 3 reads over 10ms each.
I keep pin reads in the bits of a pinStateHistory byte, the pin read twice per ms for a 3500 us stable period debounce. I read every ms, 7 ms stable.
Each read, 1st the history bits are shifted left 1, same as a x 2. Bit 7 is lost, bit 0 = 0.
And the the read us added and that's it except for timing the reads. Bit 10 of millis() toggles twice a ms, I read on that change. My timer is the millis clock.