-
Notifications
You must be signed in to change notification settings - Fork 0
/
pushbutton.c
145 lines (131 loc) · 4.54 KB
/
pushbutton.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* pushbutton.c
*
* Debounce pushbuttons.
*
* Created: 07/09/2020
* Author : Richard Tomlinson G4TGJ
*/
#include "config.h"
#include "pushbutton.h"
#include "millis.h"
// Debounce a pushbutton
void debouncePushbutton( bool bDown, bool *pbShortPress, bool *pbLongPress, uint16_t debounceTime, uint16_t longPressTime, struct sDebounceState *pDebounceState)
{
// Get the time now
uint32_t currentTime = millis();
// Dummy in case the long press pointer is null
bool bLongPress;
// If the long press pointer is null then just use a dummy
if( pbLongPress == 0 )
{
pbLongPress = &bLongPress;
}
// Nothing pressed yet
*pbShortPress = false;
*pbLongPress = false;
// Debounce the pushbutton with a state machine
switch( pDebounceState->state )
{
// Currently idle i.e. nothing pressed
case PUSHBUTTON_IDLE:
// If the pushbutton is pressed then debounce it
if( bDown )
{
// Start the debounce timer
pDebounceState->debounceTimer = currentTime + debounceTime;
pDebounceState->state = PUSHBUTTON_DOWN;
}
break;
// The pushbutton is down but not yet debounced
case PUSHBUTTON_DOWN:
// If the pushbutton is released then back to idle
// to start debounce timer again
if( !bDown )
{
pDebounceState->state = PUSHBUTTON_IDLE;
}
// If pushbutton down long enough then it can be
// considered pressed.
// Have to see how long it is pressed for
else if( currentTime > pDebounceState->debounceTimer )
{
// Start the long press time if appropriate
if( longPressTime > 0 )
{
// Start the long press timer
pDebounceState->longPressTimer = currentTime + longPressTime;
}
else
{
// Can consider button pressed
*pbShortPress = true;
}
pDebounceState->state = PUSHBUTTON_PRESSED;
}
break;
// The pushbutton has been down long enough to have
// been debounced
case PUSHBUTTON_PRESSED:
// Switch is no longer pressed so need to start
// the debounce process
if( !bDown )
{
// Start the debounce timer
pDebounceState->debounceTimer = currentTime + debounceTime;
// Also restart the long press timer to
// prevent a spurious result
pDebounceState->longPressTimer = currentTime + longPressTime;
pDebounceState->state = PUSHBUTTON_RELEASED;
}
// Are we interested in long presses?
else if( longPressTime > 0 )
{
// The pushbutton has been down long enough that it is
// a long press
if( currentTime > pDebounceState->longPressTimer )
{
*pbLongPress = true;
pDebounceState->state = PUSHBUTTON_LONG_PRESS;
}
}
else
{
// Switch is still down
*pbShortPress = true;
}
break;
// The pushbutton was down but has now been released
case PUSHBUTTON_RELEASED:
// If the pushbutton is down again then keep
// debouncing
if( bDown )
{
pDebounceState->state = PUSHBUTTON_PRESSED;
}
// The pushbutton has been up long enough so it is
// a short press and we are idle again
else if( currentTime > pDebounceState->debounceTimer )
{
// If the long press time is zero we will will have already
// reported the button when it was pressed
if( longPressTime > 0 )
{
*pbShortPress = true;
}
pDebounceState->state = PUSHBUTTON_IDLE;
}
break;
// The pushbutton has been pressed a long time so just waiting
// for it to be released.
case PUSHBUTTON_LONG_PRESS:
if( !bDown )
{
pDebounceState->state = PUSHBUTTON_IDLE;
}
break;
default:
// Should never get here
break;
}
}