Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
pousseseringue-arduino
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
FabLAAS
PousseSeringue
pousseseringue-arduino
Commits
7d9662b4
Commit
7d9662b4
authored
1 year ago
by
David Gauchard
Browse files
Options
Downloads
Patches
Plain Diff
+debouncer.h
parent
d35df548
No related branches found
Branches containing commit
No related tags found
1 merge request
!19
+debouncer.h
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
Debouncer.h
+365
-0
365 additions, 0 deletions
Debouncer.h
with
365 additions
and
0 deletions
Debouncer.h
0 → 100644
+
365
−
0
View file @
7d9662b4
#pragma once
#include
<stdint.h>
#ifndef DEBOUNCER_DEFAULT_DEBOUNCE_PUSH_MS
#define DEBOUNCER_DEFAULT_DEBOUNCE_PUSH_MS 50 // debounce delay for push button
#endif
#ifndef DEBOUNCER_DEFAULT_DEBOUNCE_ROTARY_MS
#define DEBOUNCER_DEFAULT_DEBOUNCE_ROTARY_MS 1 // debounce delay for rotary button
#endif
#ifndef DEBOUNCER_DEFAULT_SHORT_MS
#define DEBOUNCER_DEFAULT_SHORT_MS 200 // max interval between multiple short clicks
#endif
#ifndef DEBOUNCER_DEFAULT_LONG_MS
#define DEBOUNCER_DEFAULT_LONG_MS 400 // min interval for long click
#endif
#if defined(ESP8266) && !DEBOUNCER_WITH_MILLIS
#pragma message "Debouncer: using esp_get_cycle_count"
#define DEBOUNCER_DEFAULT_CYCLE_FUNC esp_get_cycle_count
#define DEBOUNCER_DEFAULT_CYCLE_PER_MS (F_CPU / 1000)
#else
#if !defined(__AVR__)
#pragma message "Debouncer: using millis"
#endif
#define DEBOUNCER_DEFAULT_CYCLE_FUNC millis
#define DEBOUNCER_DEFAULT_CYCLE_PER_MS (1)
#endif
#if 0
#define DEBUGBUTTON(x...) do { Serial.print(cycle_f()); Serial.print(":"); x; } while (0)
#else
#define DEBUGBUTTON(x...) do { } while (0)
#endif
#ifndef IRAM_ATTR
#define IRAM_ATTR // nothing
#endif
///////////////////////////////////////////////////////////////
/*
ButtonFast::
!enable_multi && !enable_long:
short click: response on click
no long click
ButtonLong::
!enable_multi && enable_long:
short click: response on release + debounce time
long click: response on long click delay
Debouncer<long_cycle=0>::
enable_multi && !enable_long:
short clicks number: response on final release + debounce time
no long click
Debouncer<true,≠0>:: (default)
enable_multi && enable_long:
short clicks number: reponse on final release + debounce time
long click: response on long click delay
*/
#if __GNUC__ <= 7
#define __cycle_template_decl
#define __cycle_template_args
#define __cycle_template_impl
#define cycle_f DEBOUNCER_DEFAULT_CYCLE_FUNC
#define cyclePerMs DEBOUNCER_DEFAULT_CYCLE_PER_MS
#else
#define __cycle_template_decl \
auto cycle_f = DEBOUNCER_DEFAULT_CYCLE_FUNC, \
auto cyclePerMs = DEBOUNCER_DEFAULT_CYCLE_PER_MS, \
#define __cycle_template_impl \
auto cycle_f, \
auto cyclePerMs, \
#define __cycle_template_args \
cycle_f, \
cyclePerMs, \
#endif
template
<
const
bool
enable_multi
=
true
,
__cycle_template_decl
const
decltype
(
cycle_f
())
long_cycle
=
DEBOUNCER_DEFAULT_LONG_MS
*
cyclePerMs
,
/* 0 to disable long press */
const
decltype
(
cycle_f
())
debounce_cycle
=
DEBOUNCER_DEFAULT_DEBOUNCE_PUSH_MS
*
cyclePerMs
,
const
decltype
(
cycle_f
())
short_cycle
=
DEBOUNCER_DEFAULT_SHORT_MS
*
cyclePerMs
>
class
Debouncer
{
protected:
using
T
=
decltype
(
cycle_f
());
enum
state_e
{
off
,
on
,
on_long
,
on_debounce
,
off_debounce
,
};
state_e
state
;
uint_fast8_t
short_count
;
bool
long_state
;
T
state_cycle
;
public
:
Debouncer
()
:
state
(
off
),
short_count
(
0
),
long_state
(
false
),
state_cycle
(
0
)
{
DEBUGBUTTON
(
Serial
.
println
(
enable_multi
));
DEBUGBUTTON
(
Serial
.
println
(
long_cycle
));
DEBUGBUTTON
(
Serial
.
println
(
debounce_cycle
));
DEBUGBUTTON
(
Serial
.
println
(
short_cycle
));
}
// - must be called in the main loop or from interrupt
// - return true if a change has occured
bool
update
(
bool
pressed
);
// simulate a long press
void
simLongClick
()
{
long_state
=
true
;
}
// simulate n short presses
void
simShortClick
(
uint_fast8_t
n
)
{
short_count
+=
n
;
}
// returns long state, does not clear shorts
bool
longState
()
{
bool
state
=
long_state
;
long_state
=
false
;
return
state
;
}
// returns short count, does not clear long
uint_fast8_t
shortCount
()
{
auto
count
=
short_count
;
short_count
=
0
;
return
count
;
}
// returns long state and clears/ignore shorts
bool
longClick
()
{
return
longState
();
}
// returns short count and clears/ignore long
uint_fast8_t
shortClick
()
{
return
shortCount
();
}
bool
isOff
()
const
{
return
state
==
off
;
}
bool
isLong
()
{
long_state
=
false
;
return
state
==
on_long
;
}
};
///////////////////////////////////////////////////////////////
template
<
__cycle_template_decl
const
decltype
(
cycle_f
())
debounce_cycle
=
DEBOUNCER_DEFAULT_DEBOUNCE_PUSH_MS
*
cyclePerMs
,
const
decltype
(
cycle_f
())
short_cycle
=
DEBOUNCER_DEFAULT_SHORT_MS
*
cyclePerMs
>
class
ButtonFast
:
public
Debouncer
<
/*no multi*/
false
,
__cycle_template_args
/*no long*/
0
,
debounce_cycle
,
short_cycle
>
{
public:
// multiclick disabled, longclick disabled
ButtonFast
()
:
Debouncer
<
false
,
__cycle_template_args
0
,
debounce_cycle
,
short_cycle
>
()
{
}
bool
pressed
()
{
using
d
=
Debouncer
<
false
,
__cycle_template_args
0
,
debounce_cycle
,
short_cycle
>
;
return
d
::
state
==
d
::
on_debounce
||
d
::
state
==
d
::
on
;
}
bool
longState
()
=
delete
;
uint_fast8_t
shortCount
()
=
delete
;
bool
longClick
()
=
delete
;
uint_fast8_t
shortClick
()
=
delete
;
};
///////////////////////////////////////////////////////////////
template
<
__cycle_template_decl
const
decltype
(
cycle_f
())
long_cycle
=
DEBOUNCER_DEFAULT_LONG_MS
*
cyclePerMs
>
class
ButtonLong
:
public
Debouncer
<
/* no multi */
false
,
__cycle_template_args
long_cycle
>
{
public:
ButtonLong
()
:
Debouncer
<
false
,
__cycle_template_args
long_cycle
>
()
{
}
bool
pressed
()
{
return
Debouncer
<
false
,
__cycle_template_args
long_cycle
>::
isLong
();
}
bool
longState
()
=
delete
;
uint_fast8_t
shortCount
()
=
delete
;
bool
longClick
()
=
delete
;
uint_fast8_t
shortClick
()
=
delete
;
};
///////////////////////////////////////////////////////////////
template
<
__cycle_template_decl
const
decltype
(
cycle_f
())
debounce_cycle
=
DEBOUNCER_DEFAULT_DEBOUNCE_ROTARY_MS
*
cyclePerMs
>
class
Rotary
{
protected:
ButtonFast
<
__cycle_template_args
debounce_cycle
>
b1
,
b2
;
int_fast8_t
rot
;
public:
Rotary
()
:
b1
(),
b2
(),
rot
(
0
)
{
}
bool
update
(
bool
in1
,
bool
in2
);
// steady state with pullup: true, true
bool
right
()
{
bool
ret
;
if
((
ret
=
(
rot
>
0
)))
--
rot
;
return
ret
;
}
bool
left
()
{
bool
ret
;
if
((
ret
=
(
rot
<
0
)))
++
rot
;
return
ret
;
}
};
///////////////////////////////////////////////////////////////
template
<
const
bool
enable_multi
,
__cycle_template_impl
const
decltype
(
cycle_f
())
long_cycle
,
const
decltype
(
cycle_f
())
debounce_cycle
,
const
decltype
(
cycle_f
())
short_cycle
>
IRAM_ATTR
// can be called from ISR
bool
Debouncer
<
enable_multi
,
__cycle_template_args
long_cycle
,
debounce_cycle
,
short_cycle
>::
update
(
bool
pressed
)
{
// get current time
auto
cycle
=
cycle_f
();
switch
(
state
)
{
case
off
:
if
(
pressed
)
{
// button is off, and now pressed
DEBUGBUTTON
(
Serial
.
println
(
"off->on_debounce"
));
state_cycle
=
cycle
;
if
(
!
enable_multi
&&
/*long press disabled*/
(
long_cycle
==
0
))
{
bool
ret
=
state
!=
on_debounce
;
state
=
on_debounce
;
return
ret
;
// true on first change
}
state
=
on_debounce
;
}
break
;
// off, no change, return unreaded state
case
on_long
:
if
(
pressed
)
return
false
;
// no change
DEBUGBUTTON
(
Serial
.
println
(
"on_long->off_debounce"
));
state
=
off_debounce
;
state_cycle
=
cycle
;
return
!
enable_multi
;
case
on_debounce
:
if
((
cycle
-
state_cycle
)
<
debounce_cycle
)
{
// don't care before debounce delay
DEBUGBUTTON
(
Serial
.
println
(
"debounce-on"
));
return
false
;
}
DEBUGBUTTON
(
Serial
.
println
(
"on_debounce->on"
));
state
=
on
;
// fall through
case
on
:
if
(
/*long press enabled*/
(
long_cycle
>
0
)
&&
(
cycle
-
state_cycle
)
>
long_cycle
)
{
// long press in progress
DEBUGBUTTON
(
Serial
.
println
(
"on->on_long"
));
state
=
on_long
;
long_state
=
true
;
return
true
;
}
if
(
!
pressed
)
{
// off after debounce delay
DEBUGBUTTON
(
Serial
.
println
(
"on->off_debounce"
));
state
=
off_debounce
;
state_cycle
=
cycle
;
if
(
!
enable_multi
)
// single press is released
return
true
;
// it was a short click
short_count
++
;
return
!
enable_multi
&&
/*long press enabled*/
(
long_cycle
>
0
);
}
return
false
;
// no change
case
off_debounce
:
if
((
cycle
-
state_cycle
)
<
debounce_cycle
)
{
// don't care before debounce delay
DEBUGBUTTON
(
Serial
.
println
(
"debounce-off"
));
return
false
;
}
if
(
pressed
)
{
// multiclick in progress
DEBUGBUTTON
(
Serial
.
println
(
"off_debounce->on_debounce"
));
state
=
on_debounce
;
state_cycle
=
cycle
;
return
false
;
}
if
(
enable_multi
&&
(
cycle
-
state_cycle
)
<
short_cycle
)
{
// wait for multiclick
DEBUGBUTTON
(
Serial
.
println
(
"(multiclick?)"
));
return
false
;
}
// released for good
DEBUGBUTTON
(
Serial
.
println
(
"off_debounce->off"
));
state
=
off
;
break
;
}
return
short_count
||
long_state
;
}
///////////////////////////////////////////////////////////////
template
<
__cycle_template_impl
const
decltype
(
cycle_f
())
debounce_cycle
>
bool
Rotary
<
__cycle_template_args
debounce_cycle
>::
update
(
bool
pressed1
,
bool
pressed2
)
{
bool
b1u
=
b1
.
update
(
pressed1
);
bool
b2u
=
b2
.
update
(
pressed2
);
if
(
b1u
&&
b2
.
isOff
()
&&
b1
.
pressed
())
{
rot
++
;
return
true
;
}
if
(
b2u
&&
b1
.
isOff
()
&&
b2
.
pressed
())
{
rot
--
;
return
true
;
}
return
false
;
}
///////////////////////////////////////////////////////////////
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment