Arduino Helpers master
Utility library for Arduino
MCP23017Encoders.hpp
Go to the documentation of this file.
1#pragma once
2
4
8
10
31template <class WireType, class EncoderPositionType = int32_t,
32 bool InterruptSafe = false>
34 private:
35 constexpr static uint8_t I2C_BASE_ADDRESS = 0x20;
36
37 WireType *wire;
38 uint8_t address;
40
43
45
46 protected:
48 template <size_t N>
49 void writeI2C(const uint8_t (&values)[N]) {
50 this->wire->beginTransmission(address);
51 this->wire->write(values, N);
52 this->wire->endTransmission();
53 }
54
63 template <class... Args>
64 void writeI2C(uint8_t addr, Args... values) {
65 const uint8_t v[] = {addr, static_cast<uint8_t>(values)...};
66 writeI2C(v);
67 }
68
70 uint16_t readGPIO() {
71 // No need to specify the register address, since this was done in the
72 // begin method, and the MCP23017 mode was set to Byte mode with
73 // IOCON.BANK = 0 (see §3.2.1 in the datasheet).
74 //
75 // TODO:
76 // For some reason, it sometimes seems to mess up though, and it'll read
77 // the wrong register, so we'll select the register again (for now).
78
79 writeI2C(0x12); // GPIOA
80
81 this->wire->requestFrom(address, size_t(2));
82 uint8_t a = this->wire->read();
83 uint16_t b = this->wire->read();
84 return a | (b << 8);
85 }
86
87 public:
106 MCP23017Encoders(WireType &wire, uint8_t addr_offset = 0,
108 : wire(&wire), address(I2C_BASE_ADDRESS | addr_offset),
110
125 void begin() {
126 // Set the IOCON register (configuration register)
127 writeI2C(0x0A, // IOCON register for BANK=0
128 0b01100100);
129 // │││││││└─ Unimplemented
130 // ││││││└── INTPOL = Active-low
131 // │││││└─── ODR = Open-drain output (overrides the INTPOL bit)
132 // ││││└──── HAEN = Disables the MCP23S17 address pins
133 // │││└───── DISSLW = Slew rate enabled
134 // ││└────── SEQOP = Sequential operation disabled, address pointer does not increment
135 // │└─────── MIRROR = The INT pins are internally connected
136 // └──────── BANK = The registers are in the same bank (addresses are sequential)
137
138 // Set all GPIO pins to input mode
139 writeI2C(0x00, // IODIRA
140 0xFF, // input mode for GPIO A
141 0xFF); // input mode for GPIO B
142
143 // Enable all pin change interrupts
144 writeI2C(0x04, // GPINTENA
145 0xFF, // interrupt enable for GPIO A
146 0xFF); // interrupt enable for GPIO B
147
148 // Enable all internal pullups
149 writeI2C(0x0C, // GPPUA
150 0xFF, // pullup enable for GPIO A
151 0xFF); // pullup enable for GPIO B
152
153 // Interrupts are configured in open-drain mode, so enable
154 // the internal pullup resistor on the Arduino pin that
155 // reads the interrupt pin.
156 if (interrupt_pin != NO_PIN)
158
159 // Set the address pointer to the GPIOA register.
160 // This means that subsequent reads will all toggle between the
161 // GPIOA and GPIOB register, so we can speedup reading the GPIO
162 // by not having to send an opcode/register address each time.
163 writeI2C(0x12); // GPIOA
164
167 }
168
179 void update() {
180 // Only update if a pin change interrupt happened
181 if (interrupt_pin != NO_PIN &&
183 return;
184 // Read both GPIO A and B
185 uint16_t newstate = readGPIO();
186 encs.update(newstate);
187 }
188
199 EncoderPositionType read(uint8_t idx) const { return encs.read(idx); }
200
211 EncoderPositionType readAndReset(uint8_t idx) {
212 return encs.readAndReset(idx);
213 }
214
225 void write(uint8_t idx, EncoderPositionType pos) { encs.write(idx, pos); }
226
232
240 MCP23017Encoder operator[](uint8_t index) { return encs[index]; }
241};
242
constexpr PinStatus_t HIGH
constexpr PinMode_t INPUT_PULLUP
constexpr pin_t NO_PIN
A special pin number that indicates an unused or invalid pin.
uint16_t pin_t
The type for Arduino pins (and ExtendedIOElement pins).
#define END_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
Class for reading 8 rotary encoders using a MCP23017 I²C port expander.
MCP23017Encoders(WireType &wire, uint8_t addr_offset=0, pin_t interrupt_pin=NO_PIN)
Constructor.
RegisterEncoderType encs
typename RegisterEncoderType::Encoder MCP23017Encoder
Proxy to access a single encoder of the 8 encoders managed by MCP23017Encoders.
EncoderPositionType read(uint8_t idx) const
Read the position of the given encoder.
uint16_t readGPIO()
Read the state of all GPIO pins.
static constexpr uint8_t I2C_BASE_ADDRESS
void begin()
Initialize the MCP23017.
MCP23017Encoder operator[](uint8_t index)
Get a proxy to one of the encoders managed by this MCP23017.
EncoderPositionType readAndReset(uint8_t idx)
Read the position of the given encoder and reset it to zero.
void update()
If the state of the MCP23017's GPIO changed, read the new state and update the encoder positions.
void writeI2C(uint8_t addr, Args... values)
Write any data to the MCP23017.
void write(uint8_t idx, EncoderPositionType pos)
Set the position of the given encoder.
void writeI2C(const uint8_t(&values)[N])
Write any data to the MCP23017.
Proxy to access a single encoder of the encoders managed by RegisterEncoders.
Class for keeping track of the position of multiple rotary encoders.
EncoderPositionType read(uint8_t idx) const
Read the position of the given encoder.
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.
void pinMode(pin_t pin, PinMode_t mode)
An ExtIO version of the Arduino function.
PinStatus_t digitalRead(pin_t pin)
An ExtIO version of the Arduino function.