-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFastDigitalPin.h
135 lines (110 loc) · 3.93 KB
/
FastDigitalPin.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
* FastDigitalPin Library for Arduino
*
* Fast but still easy-to-use methods
* for pin access using the names you know.
*
* Pin names are looked up once at initialization,
* afterwards direct port manipulation is used.
*
* License: BSD 3-Clause
*
* Nick Schwarzenberg,
* 11/2015-04/2021, v0.1.1
*/
// use names of Arduino environment
#include <Arduino.h>
// prevent redefinitions
#ifndef FastDigitalPin_class
#define FastDigitalPin_class
class FastDigitalPin
{
private:
// PORTx or PINx register
volatile unsigned char *portRegister;
// mask of the pin's bit in the register
unsigned char bitMask;
public:
// parameter-less constructor (allows to call setup() later)
// (initializes pointer and bitmask to valid but useless values)
FastDigitalPin()
{
// set register pointer to an arbitrary but valid register
// (PINB names an 8-bit input register for ATmega128/328, ATmega32u4 and ATmega2560)
this->portRegister = &PORTB;
// set bitmask to all zeroes (to prevent write() from changing anything)
this->bitMask = 0b00000000;
}
// constructor with instant setup (recommended)
FastDigitalPin( unsigned char pinNumber, unsigned char pinMode )
{
// call setup immediately
this->setup( pinNumber, pinMode );
};
// set up pin by its number and mode
bool setup( unsigned char pinNumber, unsigned char pinMode )
{
// map pin number to port register block
unsigned char portBlock = digitalPinToPort( pinNumber );
// abort if port is invalid
if ( portBlock == NOT_A_PIN ) { return false; }
// get direction register (to define input/output)
volatile unsigned char *directionRegister = portModeRegister( portBlock );
// get input and output registers
volatile unsigned char *inputRegister = portInputRegister( portBlock );
volatile unsigned char *outputRegister = portOutputRegister( portBlock );
// get the pin's bitmask for the port registers
this->bitMask = digitalPinToBitMask( pinNumber );
// treat as output?
if ( pinMode == OUTPUT )
{
// set up pin as output (by adding the pin's bit)
*directionRegister |= bitMask;
// keep pointer to output register
this->portRegister = outputRegister;
}
else
{
// set up pin as input (by clearing the pin's bit)
*directionRegister &= ~bitMask;
// enable pull-up?
if ( pinMode == INPUT_PULLUP )
{
// set bit in output register to high
*outputRegister |= bitMask;
}
else
{
// set bit in output register to low
*outputRegister &= ~bitMask;
}
// keep pointer to input register
this->portRegister = inputRegister;
}
// done, pin has been successfully mapped and set up
return true;
}
// read the pin's bit from register
inline bool read()
{
// read port register and mask the wanted bit
return ( *this->portRegister & this->bitMask );
}
// write the pin's bit in register
inline void write( bool logicValue )
{
// set output to high?
if ( logicValue )
{
// add bit to register value
*this->portRegister |= this->bitMask;
}
else
{
// clear bit in register value
*this->portRegister &= ~this->bitMask;
}
}
};
// see ifndef above
#endif