When writing Arduino libraries that need quite a few IO pins, it can be difficult to decide if the library should use an IO expansion device such as the 8574 chip, or just use Arduino pins directly. This library is designed to easily solve both cases at once, for the vast majority of cases.
The ubiquitous LiquidCrystal library; which almost all Arduino developers will have come across at some point, has two versions LiquidCrystal and LiquidCrystalI2C. If a similar abstraction method had been used, there would be no need for two versions. I’m not saying anything bad about the library; more just pointing out an observation as I use it a lot.
This library abstracts away the access to read and write to pins, such that there is an implementation that works with Arduino pins direct and another that uses an 8574 IO expander. Other chips could easily be added in the future and I’d happily accept pull requests or patches!
When using Arduino pins mode, there is very little overhead, it just calls directly out to Arduino underlying functions.
However, for i2c you need to understand what the library is doing. As there is an overhead to sending things over the
wire, rather than sending each bit change one at a time, the library waits for a
runLoop() call, and then sends a
write command if needed followed by a read.
Although I’ve packaged this as a library, I assume that some people may want to copy the header and source into their own library directly, and that’s absolutely fine, but please do rename the classes in that case to avoid conflicts and consider an attribution to me. Many libraries could make use of this code, so I’ve put a very open and permissive license on it: Apache 2.0; which allows commercial use.
This library is hosted on our github account, it comes complete with a working example showing both modes of operation.
Git hub library page [https://github.com/davetcc/BasicIoAbstraction/].
To use the library, get the latest source as an zip and expand it into your Arduino libraries directory.
In all cases include the library
To create an instance for direct Arduino pins, simply:
BasicIoAbstraction* pins = ioUsingArduino();
To create an instance for an 8574 IO expander provide the i2c address and include the Wire library:
#include <Wire.h> BasicIoAbstraction* pins = ioFrom8754(0x20);
To configure input and output pins use the library instead of the usual pinMode call. Use standard Arduino constants for
pins->pinDirection(0, INPUT); pins->pinDirection(6, OUTPUT);
In the main loop read and write values using the library. For the Arduino version, the pin number is used, for i2c 8574 it is the bit 0-7 of the port.
uint8_t switchValue = pins->readValue(0); pins->writeValue(6, switchValue); // this is absolutely needed on the IO exapnder, it makes it send the i2c command pins->runLoop();
As the old saying goes, it’s better to work smarter than harder (although it’s often said at inappropriate times). Rather than polling for a switch transition, why not use the interrupt support available on the 8574 chip, and only read from it when needed.
If you are bit blasting at a very high frequency or using PWM, you’re better off using Arduino pins directly.
There are few main sources of overhead in this library. For most cases, these should not pose a problem:
As far as I can tell, it uses no RAM beyond the object creation, the virtual method table usage is all in flash memory, so that should not be a problem for most devices. If the library is constantly setting and testing bits thousands of times a second, then this library is probably not appropriate; but I’d argue that in that case neither is using an IO expander.