1
- /*
1
+ /* *
2
2
* Class: KY040
3
3
*
4
4
* Description:
8
8
* by ignoring invalid CLK/DT sequences
9
9
*
10
10
* License: 2-Clause BSD License
11
- * Copyright (c) 2023 codingABI
11
+ * Copyright (c) 2024 codingABI
12
12
* For details see: LICENSE.txt
13
13
*
14
14
* Valid clockwise sequence for CLK/DT: Low/High->Low/Low->High/Low->High/High
15
15
*
16
+ * @code
16
17
* 0 1 2 3
17
18
* --+ +---- High
18
19
* CLK | |
21
22
* ----+ +-- High
22
23
* DT | |
23
24
* +---+ Low
24
- *
25
+ * @endcode
25
26
*
26
27
* Valid counter-clockwise sequence for CLK/DT: High/Low->Low/Low->Low/High->High/High
27
28
*
29
+ * @code
28
30
* 0 1 2 3
29
31
* ----+ +--- High
30
32
* CLK | |
33
35
* --+ +----- High
34
36
* DT | |
35
37
* +---+ Low
36
- */
38
+ * @endcode
39
+ *
40
+ * Home: https://github.com/codingABI/KY040
41
+ *
42
+ * @author codingABI https://github.com/codingABI/
43
+ * @copyright 2-Clause BSD License
44
+ * @file KY040.h
45
+ * @version 1.0.1
46
+ */
37
47
#pragma once
38
48
49
+ /* * Library version */
39
50
#define KY040_VERSION " 1.0.1"
40
51
41
52
#include < arduino.h>
42
53
43
- // When using sleep modes wait X milliseconds for next sleep after a CLK/DT sequence start do prevent missing signals
54
+ /* * When using sleep modes wait X milliseconds for next sleep after a CLK/DT sequence start do prevent missing signals */
44
55
#define PREVENTSLEEPMS 150
45
56
// Pin idle state
46
57
#define INITSTEP 0b11
47
58
// Max steps for a signal sequence
48
59
#define MAXSEQUENCESTEPS 4
49
60
61
+ /* * Class for a KY-040 rotary encoder */
50
62
class KY040 {
51
63
public:
52
- enum directions { IDLE, ACTIVE, CLOCKWISE, COUNTERCLOCKWISE };
53
- KY040 (byte clk_pin, byte dt_pin) {
64
+ /* * Rotation states */
65
+ enum directions
66
+ {
67
+ IDLE, /* *< Rotary encoder is idle */
68
+ ACTIVE, /* *< Rotary encoder is rotating, but the CLK/DT sequence has not finished */
69
+ CLOCKWISE, /* *< CLK/DT sequence for one step clockwise rotation has finished */
70
+ COUNTERCLOCKWISE /* *< CLK/DT sequence for one step counter-clockwise rotation has finished */
71
+ };
72
+
73
+ /* *@brief
74
+ * Constructor of a the KY040 rotary encoder
75
+ *
76
+ * @param[in] clk_pin Digital input pin connected to CLK aka. A
77
+ * @param[in] dt_pin Digital input pin connected to DT aka. B
78
+ */
79
+ KY040 (byte clk_pin, byte dt_pin)
80
+ {
54
81
m_clk_pin = clk_pin; // aka. A
55
82
m_dt_pin = dt_pin; // aka. B
56
83
v_state = 255 ;
@@ -60,43 +87,20 @@ class KY040 {
60
87
v_direction = IDLE;
61
88
v_oldState = INITSTEP;
62
89
}
63
- // Get pin states for CLK and DT (Left bit is for CLK, right bit is for DT). Should be called from ISR, when needed
64
- byte getState () {
65
- return v_state;
66
- }
67
- // Set pin states for CLK and DT (Left bit is for CLK, right bit is for DT). Should be called from ISR, when needed
68
- void setState (byte state) {
69
- v_state = state;
70
- }
71
- // Returns true, if device was running long enough to get a full sequence (Do not use inside ISR)
72
- bool readyForSleep () {
73
- cli ();
74
- unsigned long lastStepMillis = v_lastSequenceStartMillis;
75
- sei ();
76
- return (millis ()-lastStepMillis > PREVENTSLEEPMS);
77
- }
78
- // Get and reset the last rotary rotation (Do not use inside ISR)
79
- byte getAndResetLastRotation () {
80
- cli ();
81
- byte result = v_lastResult;
82
- v_lastResult = IDLE;
83
- sei ();
84
- return result;
85
- }
86
- // Get pin state for CLK and DT and returns the current rotation state
87
- byte getRotation () {
88
- setState ((digitalRead (m_clk_pin)<<1 )+digitalRead (m_dt_pin));
89
- return checkRotation ();
90
- }
91
- /* Returns current rotation state:
92
- * - KY040::CLOCKWISE = CLK/DT Sequence for clockwise rotation has finished
93
- * - KY040::COUNTERCLOCKWISE = CLK/DT Sequence for counter-clockwise rotation has finished
94
- * - KY040::IDLE = Rotary encoder is not rotating
95
- * - KY040::ACTIVE = Rotary encoder is rotating, but the CLK/DT sequence has not finished
96
- * If you do not use interrupts, you have to start checkRotation() or a function using
97
- * checkRotation() very frequently in your loop to prevent missing signals
90
+
91
+ /* *@brief
92
+ * Returns current rotation state from stored pin state.
93
+ *
94
+ * If you do not use interrupts, you have to start setState() and checkRotation() or a function using
95
+ * these (for example getRotation()) very frequently in your loop to prevent missing signals
96
+ *
97
+ * @retval KY040::CLOCKWISE CLK/DT sequence for one step clockwise rotation has finished
98
+ * @retval KY040::COUNTERCLOCKWISE CLK/DT sequence for one step counter-clockwise rotation has finished
99
+ * @retval KY040::IDLE Rotary encoder is idle
100
+ * @retval KY040::ACTIVE Rotary encoder is rotating, but the CLK/DT sequence has not finished
98
101
*/
99
- byte checkRotation () {
102
+ byte checkRotation ()
103
+ {
100
104
byte result = IDLE;
101
105
102
106
if (v_state != v_oldState) { // State changed?
@@ -157,6 +161,74 @@ class KY040 {
157
161
}
158
162
return result;
159
163
}
164
+
165
+ /* *@brief
166
+ * Get and reset last finished rotation step (Do not use inside ISR)
167
+ *
168
+ * @retval KY040::CLOCKWISE CLK/DT sequence for one step clockwise rotation has finished
169
+ * @retval KY040::COUNTERCLOCKWISE CLK/DT sequence for one step counter-clockwise rotation has finished
170
+ * @retval KY040::IDLE Rotary encoder is idle
171
+ */
172
+ byte getAndResetLastRotation ()
173
+ {
174
+ cli ();
175
+ byte result = v_lastResult;
176
+ v_lastResult = IDLE;
177
+ sei ();
178
+ return result;
179
+ }
180
+
181
+ /* *@brief
182
+ * Read and stores current pin state for CLK and DT and returns the current rotation state.
183
+ *
184
+ * Reads pin state for CLK and DT with DigitalRead() and checks current rotation state by calling checkRotation()
185
+ *
186
+ * @retval KY040::CLOCKWISE CLK/DT sequence for one step clockwise rotation has finished
187
+ * @retval KY040::COUNTERCLOCKWISE CLK/DT sequence for one step counter-clockwise rotation has finished
188
+ * @retval KY040::IDLE Rotary encoder is idle
189
+ * @retval KY040::ACTIVE Rotary encoder is rotating, but the CLK/DT sequence has not finished
190
+ */
191
+ byte getRotation ()
192
+ {
193
+ setState ((digitalRead (m_clk_pin)<<1 )+digitalRead (m_dt_pin));
194
+ return checkRotation ();
195
+ }
196
+
197
+ /* *@brief
198
+ * Get stored pin states for CLK and DT (Left bit is for CLK, right bit is for DT). Should be called from ISR, when needed
199
+ *
200
+ * @returns Stored pin states for CLK and DT in two bits (Left bit is for CLK, right bit is for DT)
201
+ */
202
+ byte getState ()
203
+ {
204
+ return v_state;
205
+ }
206
+
207
+ /* *@brief
208
+ * Checks, if it save to go to sleep
209
+ *
210
+ * Returns true, if device was running long enough to get a full sequence (Do not use inside ISR)
211
+ *
212
+ * @retval true Yes, it is save to go to sleep
213
+ * @retval false No, it is not save and you could miss signals, if you go to sleep anyway
214
+ */
215
+ bool readyForSleep ()
216
+ {
217
+ cli ();
218
+ unsigned long lastStepMillis = v_lastSequenceStartMillis;
219
+ sei ();
220
+ return (millis ()-lastStepMillis > PREVENTSLEEPMS);
221
+ }
222
+
223
+ /* *@brief
224
+ * Stores pin states for CLK and DT (Left bit is for CLK, right bit is for DT). Should be called from ISR, when needed.
225
+ *
226
+ * @param[in] state Pin state for CLK and DT in two bits (Left bit is for CLK, right bit is for DT)
227
+ */
228
+ void setState (byte state)
229
+ {
230
+ v_state = state;
231
+ }
160
232
private:
161
233
byte m_clk_pin; // aka. A
162
234
byte m_dt_pin; // aka. B
0 commit comments