Here an example how to use a MCP23S17 to read out encoders with the EncoderTool (working example here: https://github.com/luni64/EncoderToo...lexed_MCP23S17). If you want to use any kind of multiplexer all you need to do is to subclass the EncPlex base class and call its update(A,B) function whenever you have got new A/B values for one of the encoders. In this example the updates happen in a tick() function which you need to call as often as possible (loop() or better yield() is a good place to do so)
file: EncPlex23S17.h
Code:
#pragma once
#include "Adafruit_MCP23X17.h" // //https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library, a bit slow, I'd look for a faster one
#include "EncoderTool.h"
namespace EncoderTool
{
class EncPlex23S17 : public EncPlexBase // The base class will take care of the bookkeeping and decoding
{
public:
inline EncPlex23S17(unsigned EncoderCount);
inline void begin(CountMode mode);
inline void tick(); // call as often as possible
protected:
Adafruit_MCP23X17 mcp21S17;
bool isSetup = false;
};
//================================================================================
// INLINE IMPLEMENTATION
EncPlex23S17::EncPlex23S17(unsigned encoderCount) // nothing to do but telling the base class the number of encoders it shall generate
: EncPlexBase(encoderCount)
{}
void EncPlex23S17::begin(CountMode mode = CountMode::quarter)
{
EncPlexBase::begin(mode); // setup the base class
mcp21S17.begin_SPI(10); // setup the Adafruit MCP21S17 interface: SPI, CS on pin 10
for (unsigned i = 0; i < encoderCount; i++) // configure all needed pins as input. We start with A_0/B_0 up to the required number of pin pairs
{
mcp21S17.pinMode(i, INPUT_PULLUP);
mcp21S17.pinMode(i + 8, INPUT_PULLUP);
}
isSetup = true;
}
void EncPlex23S17::tick() // call this as often as possible
{
if (isSetup) // tick might be called from a timer or yield before begin was called -> Prevent accessing the muliplexer before it is setup
{
uint16_t data = mcp21S17.readGPIOAB(); // read the data from the 23S17 multiplexer
for (unsigned i = 0; i < encoderCount; i++) // for all configured encoders
{ // extract the A/B
unsigned A = (data & 1 << i) != 0; //
unsigned B = (data & 1 << (i + 8)) != 0; //
int delta = encoders[i].update(A, B); // the base class will take care of the decoding
if (delta != 0 && callback != nullptr) callback(i, encoders[i].getValue(), delta); // if something changed, invoke the callback
}
}
}
} // namespace EncoderTool
And here how to use it. The example uses a callback to print changes of the encoder. You can also directly access the encoders using the [] operator of the EncPlex23S17 class. E.g. encoders[3].getValue() would return the current value of the encoder attached to A_3 B_3 inputs of the 23S17 (See here https://github.com/luni64/EncoderToo...lexed-encoders for more information on using mulitplexed encoders)
Code:
/************************************************************
*
* Use a MCP23S17 multiplexer to read out up to 8 attached encoders
* The A/B pins of the encoders go to the A/B inputs of the MCP
*
************************************************************/
#include "EncPlex23S17.h"
#include "EncoderTool.h"
using namespace EncoderTool;
EncPlex23S17 encoder(8); // use all 8 (A/B) inputs of the 23S17 to connect encoders
// this will be called whenever one of the connected encoders changes
void onChange(byte ch, int value, int delta)
{
Serial.printf("Encoder #: %d, value: %3d, delta: %2d\n", ch, value, delta);
}
void setup()
{
digitalWriteFast(LED_BUILTIN, OUTPUT);
encoder.begin();
encoder.attachCallback(onChange); // attach a common callback for all encoders
}
void loop()
{
encoder.tick();
}
To extend the code to more than one 23S17 you'd simply extend the tick function to loop over the used chips. The example uses the Adafruit_MCP23X17 library to read out the multiplexer. Looks like this library is a bit slow (takes ~30µs to read out the 16 pins). If you want to read out 150+ encoders with this chip, using a faster library might be a good idea.
I used this breakout:
https://www.amazon.de/-/en/MCP23017-...ps%2C71&sr=8-1
Hope that helps...