Arduino Helpers master
Utility library for Arduino
RegisterEncoders.hpp
Go to the documentation of this file.
1#pragma once
2
5
7#include <AH/STL/limits>
8#include <AH/STL/type_traits>
9
11
14constexpr static int8_t RegisterEncodersLUT[16] = {
15 0, // 0 0 0 0
16 +1, // 0 0 0 1
17 -1, // 0 0 1 0
18 +2, // 0 0 1 1
19 -1, // 0 1 0 0
20 0, // 0 1 0 1
21 -2, // 0 1 1 0
22 +1, // 0 1 1 1
23 +1, // 1 0 0 0
24 -2, // 1 0 0 1
25 0, // 1 0 1 0
26 -1, // 1 0 1 1
27 +2, // 1 1 0 0
28 -1, // 1 1 0 1
29 +1, // 1 1 1 0
30 0, // 1 1 1 1
31};
32
50template <class RegisterType, uint8_t NumEnc,
51 class EncoderPositionType = int32_t, bool InterruptSafe = false>
53 private:
54 static_assert(std::is_unsigned<RegisterType>::value,
55 "RegisterType should be an unsigned integer type");
56
58 typename std::conditional<InterruptSafe, volatile EncoderPositionType,
59 EncoderPositionType>::type;
60
62 typename std::conditional<InterruptSafe, volatile RegisterType,
63 RegisterType>::type;
64
67
68 public:
70 void reset() {
71 positions = {{}};
73 }
74
76 void reset(RegisterType resetstate) {
77 positions = {{}};
78 state = resetstate;
79 }
80
96 bool update(RegisterType newstate) {
97 RegisterType oldstate = state;
98
99 // If the state didn't change, do nothing
100 if (newstate == oldstate)
101 return false;
102
103 // Save the new state
104 state = newstate;
105
106 // For each encoder, compare the new state of its two pins
107 // to the old state. Combine the four states into a 4-bit
108 // number and use a lookup table to determine the delta between
109 // the two encoder positions.
110 for (uint8_t i = 0; i < NumEnc; ++i) {
111 // Top two bits are new pin states
112 uint8_t change = static_cast<uint8_t>(newstate) & 0b11;
113 change <<= 2;
114 // Bottom two bits are old pin states
115 change |= static_cast<uint8_t>(oldstate) & 0b11;
116 auto delta =
117 static_cast<EncoderPositionType>(RegisterEncodersLUT[change]);
118 if (delta != 0) // small speedup on AVR
119 positions[i] += delta;
120 oldstate >>= 2;
121 newstate >>= 2;
122 }
123 return true;
124 }
125
136 EncoderPositionType read(uint8_t idx) const {
137 if (InterruptSafe) {
138 noInterrupts();
139 EncoderPositionType ret = positions[idx];
140 interrupts();
141 return ret;
142 } else {
143 return positions[idx];
144 }
145 }
146
157 EncoderPositionType readAndReset(uint8_t idx) {
158 if (InterruptSafe) {
159 noInterrupts();
160 EncoderPositionType ret = positions[idx];
161 positions[idx] = 0;
162 interrupts();
163 return ret;
164 } else {
165 EncoderPositionType ret = positions[idx];
166 positions[idx] = 0;
167 return ret;
168 }
169 }
170
181 void write(uint8_t idx, EncoderPositionType pos) {
182 if (InterruptSafe) {
183 noInterrupts();
184 positions[idx] = pos;
185 interrupts();
186 } else {
187 positions[idx] = pos;
188 }
189 }
190
195 class Encoder {
196 private:
197 friend class RegisterEncoders;
198
201
203
204 public:
207 EncoderPositionType read() const {
208 if (InterruptSafe) {
209 noInterrupts();
210 EncoderPositionType ret = *position;
211 interrupts();
212 return ret;
213 } else {
214 return *position;
215 }
216 }
217
220 EncoderPositionType readAndReset() {
221 if (InterruptSafe) {
222 noInterrupts();
223 EncoderPositionType ret = *position;
224 *position = 0;
225 interrupts();
226 return ret;
227 } else {
228 EncoderPositionType ret = *position;
229 *position = 0;
230 return ret;
231 }
232 }
233
236 void write(EncoderPositionType pos) {
237 if (InterruptSafe) {
238 noInterrupts();
239 *position = pos;
240 interrupts();
241 } else {
242 *position = pos;
243 }
244 }
245
246#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
247 // begin_if_possible doesn't work on GCC 4.x and earlier, so provide a
248 // dummy begin method instead.
249 void begin() {}
250#endif
251 };
252
259 Encoder operator[](uint8_t index) {
260 if (index >= NumEnc)
261 index = NumEnc - 1;
262 return &positions[index];
263 }
264};
265
#define END_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
static constexpr int8_t RegisterEncodersLUT[16]
Lookup table that maps rotary encoder (2-bit gray code) state changes to position deltas.
Proxy to access a single encoder of the encoders managed by RegisterEncoders.
EncoderPositionStorageType * position
A pointer to the position value inside of the RegisterEncoders class.
void write(EncoderPositionType pos)
Set the position of the encoder.
EncoderPositionType read() const
Read the position of the encoder.
EncoderPositionType readAndReset()
Read the position of the encoder and reset it to zero.
Encoder(EncoderPositionStorageType *position)
Class for keeping track of the position of multiple rotary encoders.
Encoder operator[](uint8_t index)
Get a proxy to one of the encoders managed by this object.
StateStorageType state
typename std::conditional< InterruptSafe, volatile EncoderPositionType, EncoderPositionType >::type EncoderPositionStorageType
typename std::conditional< InterruptSafe, volatile RegisterType, RegisterType >::type StateStorageType
void reset(RegisterType resetstate)
Reset the positions to zero and the state to the given value.
EncoderPositionType read(uint8_t idx) const
Read the position of the given encoder.
Array< EncoderPositionStorageType, NumEnc > positions
bool update(RegisterType newstate)
Update the encoder positions based on the new state.
EncoderPositionType readAndReset(uint8_t idx)
Read the position of the given encoder and reset it to zero.
void reset()
Reset the positions to zero and the state to 0xFF...FF.
void write(uint8_t idx, EncoderPositionType pos)
Set the position of the given encoder.
constexpr auto max(const T &a, const U &b) -> decltype(a< b ? b :a)
Return the larger of two numbers/objects.
Definition: MinMaxFix.hpp:19