A library for controlling various peripherals with Arduino / ESP boards.
This library provides a collection of classes to interface with common hardware peripherals, making it easier to build interactive electronic projects.
The peripherals are created by a single factory class, PeripheralFactory, which handles all of the update logic and peripheral instance creation.
Output Devices:
- LEDs: A driver for simple LEDs, supporting blinking and simple on/off control.
- RGB LEDs (WS2812)
- LiquidCrystal over I2C
- Seven-Segment Displays wit the MAX7219 driver.
- Buzzer
- Motor controlled with H Bridge
- OLED Display
- 7 Segment / Bargraph controlled with 595 shift registers
Input Devices:
- Rotary Encoders
- Buttons
- Buttons with LED feedback
- RFID Reader
- Sliding potentiometers
Peripherals that will be added support:
This library is designed to be used with the PlatformIO ecosystem. This library depends on the following libraries (will be installed automatically):
- https://github.com/OSSLibraries/Arduino_MFRC522v2.git
- adafruit/Adafruit GFX Library @ ^1.11.9
- adafruit/Adafruit SSD1306 @ ^2.5.9
- adafruit/Adafruit NeoPixel
- https://github.com/LennartHennigs/ESPRotary
- https://github.com/LennartHennigs/Button2
- marcoschwartz/LiquidCrystal_I2C @ ^1.1.2
You can either clone this repository into your PlatformIO project's lib directory or add it as a dependency in your platformio.ini file.
#include <PeripheralFactory.h>The PeripheralFactory class is the main entry point for creating peripheral objects. It simplifies the process of initializing and using the various components.
The standard framework for using this library is as follows:
#include <Arduino.h>
#include <PeripheralFactory.h>
PeripheralFactory factory;
void setup() {
Serial.begin(115200);
factory.init(); //calls init() method for every periphery
}
void loop() {
factory.update(); //updates every periphery periodically (like a blinking LED), to avoid the usage of delay()
}#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET_PIN -1
#define I2C_ADDRESS 0x3C
OLEDDisplay* oled = factory.createOLED(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET_PIN);
oled->clear();
oled->setCursor(0, 0);
oled->setTextSize(1);
oled->setTextColor(SSD1306_WHITE);
oled->print(F("Hello World"));
oled->show();#define LED_PIN D7
LED* led = factory.createLed(D7);
led->on();
led->off();
led->startBlink(500); //blinking time in ms
led->stopBlink();
led->setBrightness(255);A button that reacts to presses, releases and toggles. It can show its state with its integrated LED. We can add UpdateFunctions to call certain functions,
without busy checking in the main loop.
Here is an example of two buttons, switiching a state of external LEDs, while one button maximum can be pressed at a time.
#include <Arduino.h>
#include "PeripheralFactory.h"
PeripheralFactory factory;
LEDButton* btnG = nullptr;
LEDButton* btnR = nullptr;
LED* led1 = nullptr;
LED* led2 = nullptr;
void RedOff() {
btnR->setToggleState(false); //togle the other button off
}
void GreenOff() {
btnG->setToggleState(false); //toggle the other button off
}
void UpdateLEDState() { //update the LEDs when a button has been toggled (no need to check in the loop)
led1->setState(btnR->getToggleState());
led2->setState(btnG->getToggleState());
}
void setup(){
btnR = factory.createLEDButton(5, 4);
btnG = factory.createLEDButton(7, 6);
led1 = factory.createLed(15);
led2 = factory.createLed(16);
if (btnR) {
btnR->setMode(LEDButtonMode::TOGGLE); //add a toggle mode, in which the button stays lit when pressed, can be set to TOGGLE, FOLLOW or MANUAL (default)
btnR->addUpdateFunction(GreenOff, UpdateFunction::TOGGLE); //a function that is called when a button is toggled, can be TOGGLE, PRESS or RELEASE
btnR->addUpdateFunction(UpdateLEDState, UpdateFunction::TOGGLE);
}
if (btnG) {
btnG->setMode(LEDButtonMode::TOGGLE);
btnG->addUpdateFunction(RedOff, UpdateFunction::TOGGLE);
btnG->addUpdateFunction(UpdateLEDState, UpdateFunction::TOGGLE);
}
factory.init();
}
void loop() {
factory.update();
}Seven-Segment Display Using the MAX7219 Driver - Deprecated due to used library support, please use the ShiftRegisterChain method instead.
#define MAX7219_DATA_PIN D1
#define MAX7219_CLK_PIN D2
#define MAX7219_CS_PIN D0
#define MAX7219_NUM_DEVICES 3
Segment* segment = factory.createSegment(MAX7219_DATA_PIN, MAX7219_CLK_PIN, MAX7219_CS_PIN, MAX7219_NUM_DEVICES);
segment->setBrightness(50);
segment->clearAll();
segment->setBrightness(int intensity);
segment->clearAll();
segment->setChar(int overallDigitIndex, char character, bool decimalPoint);
segment->printString(const char* text);
segment->printNumber(long number);
// Display an integer (0-9999) on a specific 4-digit logical display.
// logicalDisplayNum: 0 to (totalNumDevices * 2) - 1
// Each MAX7219 hosts two 4-digit logical displays.
segment->displayPower(int logicalDisplayNum, int value);
// Display a float on a specific 4-digit logical display.
// If value is 0.0 to 999.9, displays as XXX.X (e.g., "123.4", " 23.4", " 3.4").
// If value is 1000.0 to 9999.0, displays as an integer YYYY.
// Other values (negative, too large) will display "----".
segment->displayPower(int logicalDisplayNum, float value);#define RGBLED_PIN D7
RGBLED* rgb = factory.createRGBLED(RGBLED_PIN);
rgb->setColor(255, 0, 0);
rgb->setBrightness(50);
rgb->show();#define ENCODER_PIN_A D0
#define ENCODER_PIN_B D5
#define ENCODER_PIN_SW D7
Encoder* encoder = factory.createEncoder(ENCODER_PIN_A, ENCODER_PIN_B, ENCODER_PIN_SW, 0, 255, 1);
int16_t val = encoder->getValue();
encoder->setValue(int set_val);
//button press
if (encoder->isButtonPressed()) {
}#define MOTOR_A_IA_PIN D5;
#define MOTOR_A_IB_PIN D6;
Motor* motor = factory.createMotor(MOTOR_A_IA_PIN, MOTOR_A_IB_PIN);
motor->forward(int speed);
motor->backward(int speed);
motor->stop();The library also supports a ShiftRegisterDevice, which is a part of a ShiftRegisterChain. These devices function by leveraging the 74HC595 shift registers to control multiple outputs with fewer pins.
Every device connected to the chain can be controlled individually, the library handles the bit-communication and ordering.
Currently implemented devices are the 7-Segment DisplSay (common cathode) and a LED Bargraph (or a strip of LEDs). The wiring diagram of a single 7-Segment Display (common cathode, 4 digits) is as follows:
Where, the first register controls the individual segments of the display, and the second register selects which digit to turn on. To light up all segments of the, lets say second digit, we would need to send:
0b11111101 - select the second digit (common cathode, pulling the cathode pin low)
0b01111111 - turn all 7 segments, without the decimal point (pulling all segment pins high)This is being handled by the library on its own.
As there are four leftover bits in the digit selection, we can add another 4-digit display to the second register, and wire it in parallel with the first one. This could be done like this:
The digit selection bits are now shared, the first 4 bits select the first display, and the second 4 bits select the second display. The segments are still controlled by the first register (they are shared).
A bargraph is simpler, it just uses the registers to turn the LEDs individually on or off, the second lead is connected to the ground, which is shared. If the bargraph has more pins, we just add another register to the chain and connect the Q_H' of the first register to the SER pin of the second register.
A simple combination of a 7-Segment LED display and a LED Bargraph can be controlled in the following way:
#include <Arduino.h>
#include "PeripheralFactory.h"
#define LATCH_PIN D1
#define DATA_PIN D2
#define CLOCK_PIN D0
#define NUM_DIGITS 8
PeripheralFactory factory;
ShiftRegisterChain* shiftChain = factory.createShiftRegisterChain(LATCH_PIN, DATA_PIN, CLOCK_PIN);
//devices are added in the reverse order, due to the chaining of the shift registers (physically the LED display is first, then the bargraph)
//connect the Q_H' of the second shift register used for the LED display to the SER pin of the first shift register used for the bargraph
Bargraph* bargraph1 = factory.createBargraph(shiftChain, 10);
SegmentDisplay* display1 = factory.createSegmentDisplay(shiftChain, 8);
unsigned long lastUpdateTime = 0;
void setup() {
Serial.begin(115200);
factory.init();
}
void loop() {
factory.update();
if(millis() % 100 == 0) {
display1->displayNumber(millis());
}
if(millis() % 1000 == 0) {
static bool reversed = false;
bargraph1->setValue((millis() / 1000) % 11); // update bargraph based on millis (every of the 10 leds, 0-10 left by modulo)
//reverse the order after every 10 seconds
if ((millis() / 1000) % 11 == 0) {
reversed = !reversed;
bargraph1->setReversed(reversed);
Serial.println(reversed ? F("Bargraph reversed") : F("Bargraph normal"));
}
}
}Contributions are welcome! Please open an issue or submit a pull request if you have any improvements or bug fixes.
This project is licensed under the GPLv2 License - see the LICENSE file for details.