Pin
is a class for pin manipulation: you can read, write, turnOn, turnOff, toggle and a lot more. Please, stop writing horrible code like digitalWrite(led, HIGH)
and start writing led.turnOn()
instead.
Pin
is actually an abstract class, so you won't use it directly, but through its specialized implementations:
- DigitalIn
- DigitalOut
- AnalogIn
- AnalogOut
Import the library
#import <eIO.h>
using namespace Eloquent::Pin;
If the namespace stuff is new to you, here I'll briefly say that it is used to avoid name collisions among different libraries. This seems to be an alien topic in the Arduino world and I can't really explain why.
99% of the libraries out there deal with this problem in one of two modes:
- ignoring it altogether, so you have an
MPU6050.h
library, which elects itself as the only one implementation possible to access the MPU6050 accelerometer in the world - prefixing each library file, so you get the
Adafruit_Si7021
class
With namespaces, it would become:
using namespace Adafruit;
Si7021 si;
How to use
First of all, all the 4 implementations accept a single constructor argument: the pin number.
DigitalOut led(BUILTIN_LED);
DigitalIn pushButton(10);
AnalogIn potentiometer(A0);
AnalogOut pwmLed(8);
Then it is good practice to init your pins in the setup.
void setup() {
led.begin();
pushButton.begin();
potentiometer.begin();
pwmLed.begin();
}
All the 4 classes let you ask for the pin current value via the value()
method:
void test() {
// DigitalIn returns the last read value, as 0/1
digitalIn.value();
// AnalogIn returns the last read value, in the range [0, 1024]
analogIn.value();
// DigitalOut returns the last written value, as 0/1
digitalOut.value();
// AnaloglOut returns the last written value, in the range [0, 255]
analogOut.value();
}
At this point each class will provide its specialized methods.
DigitalIn
void test() {
// configure pin as INPUT_PULLUP
pin.pullup();
// configure pin as Active Low
// that is, pin is ON when digitalRead() is LOW
pin.activeLow();
// read and update pin value
pin.read();
// test if pin is on (doesn't read the pin)
pin.isOn();
// test if pin is off (doesn't read the pin)
pin.isOff();
// test if pin value changed from last reading
pin.changed();
}
DigitalOut
void test() {
// set pin as Active Low
// that is, turnOn writes LOW
pin.activeLow();
// turn pin on
pin.turnOn();
// turn pin off
pin.turnOff();
// toggle
pin.toggle();
// blink N times at intervals of X milliseconds
pin.blink(N, X);
}
AnalogIn
void test() {
// read current pin value
pin.read();
// get pin previous value
pin.prev();
// get difference between current value and previous
pin.delta();
// get absolute value of delta()
pin.absDelta();
}
AnalogOut
void test() {
// write value X to pin
pin.write(X);
}
If you don't believe a whole class is worthwhile to work with pins, I'll show a few use cases to illustrate my point.
Use case #1: active low LED
The ESP8266 has a builtin LED you can control, but it is an active low one: it will turn on when you write LOW
. In this case, digitalWrite(BUILTIN_LED, LOW)
can be misleading regarding your actual intentions.
It doesn't look intuitive, it doesn't look eloquent! builtinLed.turnOn()
does, however. All you need to get it working correctly is calling builtinLed.activeLow()
once in your setup.
// BEFORE
void loop() {
// to turn the builtin LED on
digitalWrite(led, LOW);
}
// AFTER
DigitalOut buildtinLed;
void setup() {
builtinLed.activeLow();
}
void loop() {
// to turn the builtin LED on
builtinLed.turnOn();
}
Use case #2: toggle
If you need to toggle the current state of a digital output, you need an helper variable to keep track of the state and remember to always update that variable when you write to the output.
With a class, the state is tightly bound to the instance, so you have a single source of truth: turnOn()
, turnOff()
and toggle()
will take care of updating the inner state accordingly.
// BEFORE
#define LED 1
bool ledState = true;
loop() {
digitalWrite(LED, ledState);
ledState = !ledState
}
// AFTER
DigitalOut led(1);
void loop() {
led.toggle();
}
Use case #3: analog delta
What if you have an analog input and want to know if its valued changed by at least X from your latest reading? You would need an helper variable again.
Now imagine if you have 5 analog inputs you want to track: you'll end up with 10 variables and of course you have again to always keep both in sync.
AnalogIn
conveniently provides delta()
and absDelta()
methods that give you the change from the previous reading and will always be in sync. Awesome!
// BEFORE
#define INPUT1 A1
#define INPUT2 A2
uint16_t current1, prev1;
uint16_t current2, prev2;
void loop() {
prev1 = current1;
current1 = analogRead(INPUT1);
prev2 = current2;
current2 = analogRead(INPUT2);
if (abs(current1 - prev1) > THRESHOLD)
...
// AFTER
AnalogIn input1(A1), input2(A2);
void loop() {
input1.read();
input2.read();
if (input1.absDelta() > THRESHOLD)
...
}
Did you find this tutorial useful? Was is it easy to follow or did I miss something? Let me know in the comments so I can keep improving the blog.