Skip to content

Commit 11971eb

Browse files
committed
Allow arbitrary pin assignments
Add new constructors and class variables to allow changing the pin layout.
1 parent a024179 commit 11971eb

File tree

3 files changed

+80
-42
lines changed

3 files changed

+80
-42
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
A library for driving LiquidCrystal displays (LCD) by using the I2C bus and an PCF8574 I2C adapter.
44

5-
There are modules that can be soldered or stacked to the display that offers a I2C interface for communication instead of the 8+ digital lines that are used to send data to the display.
5+
There are modules that can be soldered or stacked to the display that offers an I2C interface for communication instead of the 8+ digital lines that are used to send data to the display.
66

7-
Most of these modules used the internal wiring that is supported by this library. If you use a module with a different wiring you can adjust this in the code (see comments).
7+
Most of these modules use the wiring that is supported by this library's default configuration. If you use a module with a different wiring, you can use one of the class constructors which allow you to specify the pin assignments.
88

99
See the web site for more details and pictures: <https://www.mathertel.de/Arduino/LiquidCrystal_PCF8574.aspx>
1010

src/LiquidCrystal_PCF8574.cpp

+55-31
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,50 @@
1010

1111
#include <Wire.h>
1212

13-
/// Definitions on how the PCF8574 is connected to the LCD
13+
LiquidCrystal_PCF8574::LiquidCrystal_PCF8574(uint8_t i2cAddr)
14+
{
15+
// default pin assignment
16+
init(i2cAddr, 0, 1, 2, 4, 5, 6, 7, 3);
17+
} // LiquidCrystal_PCF8574
1418

15-
/// These are Bit-Masks for the special signals and background light
16-
#define PCF_RS 0x01
17-
#define PCF_RW 0x02
18-
#define PCF_EN 0x04
19-
#define PCF_BACKLIGHT 0x08
20-
// the 0xF0 bits are used for 4-bit data to the display.
19+
// constructors, which allows to redefine bit assignments in case your adapter is wired differently
20+
LiquidCrystal_PCF8574::LiquidCrystal_PCF8574(uint8_t i2cAddr, uint8_t rs, uint8_t enable,
21+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight)
22+
{
23+
init(i2cAddr, rs, 255, enable, d4, d5, d6, d7, backlight);
24+
} // LiquidCrystal_PCF8574
2125

22-
// a nibble is a half Byte
26+
LiquidCrystal_PCF8574::LiquidCrystal_PCF8574(uint8_t i2cAddr, uint8_t rs, uint8_t rw, uint8_t enable,
27+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight)
28+
{
29+
init(i2cAddr, rs, rw, enable, d4, d5, d6, d7, backlight);
30+
} // LiquidCrystal_PCF8574
2331

24-
LiquidCrystal_PCF8574::LiquidCrystal_PCF8574(int i2cAddr)
32+
void LiquidCrystal_PCF8574::init(uint8_t i2cAddr, uint8_t rs, uint8_t rw, uint8_t enable,
33+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight)
2534
{
2635
_i2cAddr = i2cAddr;
2736
_backlight = 0;
2837

2938
_entrymode = 0x02; // like Initializing by Internal Reset Circuit
3039
_displaycontrol = 0x04;
31-
} // LiquidCrystal_PCF8574
40+
41+
_rs_mask = 0x01 << rs;
42+
if (rw != 255)
43+
_rw_mask = 0x01 << rw;
44+
else
45+
_rw_mask = 0;
46+
_enable_mask = 0x01 << enable;
47+
_data_mask[0] = 0x01 << d4;
48+
_data_mask[1] = 0x01 << d5;
49+
_data_mask[2] = 0x01 << d6;
50+
_data_mask[3] = 0x01 << d7;
51+
52+
if (backlight != 255)
53+
_backlight_mask = 0x01 << backlight;
54+
else
55+
_backlight_mask = 0;
56+
} // init()
3257

3358

3459
void LiquidCrystal_PCF8574::begin(int cols, int lines)
@@ -56,7 +81,7 @@ void LiquidCrystal_PCF8574::begin(int cols, int lines)
5681
_displaycontrol = 0x04;
5782
_entrymode = 0x02;
5883

59-
// sequence to reset. see "Initializing by Instruction" in datatsheet
84+
// sequence to reset. see "Initializing by Instruction" in datasheet
6085
_sendNibble(0x03);
6186
delayMicroseconds(4500);
6287
_sendNibble(0x03);
@@ -82,12 +107,6 @@ void LiquidCrystal_PCF8574::clear()
82107
} // clear()
83108

84109

85-
void LiquidCrystal_PCF8574::init()
86-
{
87-
clear();
88-
} // init()
89-
90-
91110
void LiquidCrystal_PCF8574::home()
92111
{
93112
// Instruction: Return home = 0x02
@@ -241,12 +260,12 @@ void LiquidCrystal_PCF8574::createChar(int location, byte charmap[])
241260
inline size_t LiquidCrystal_PCF8574::write(uint8_t ch)
242261
{
243262
_send(ch, true);
244-
return 1; // assume sucess
263+
return 1; // assume success
245264
} // write()
246265

247266

248267
// write either command or data
249-
void LiquidCrystal_PCF8574::_send(int value, bool isData)
268+
void LiquidCrystal_PCF8574::_send(uint8_t value, bool isData)
250269
{
251270
// write high 4 bits
252271
_sendNibble((value >> 4 & 0x0F), isData);
@@ -258,30 +277,35 @@ void LiquidCrystal_PCF8574::_send(int value, bool isData)
258277
// write a nibble / halfByte with handshake
259278
void LiquidCrystal_PCF8574::_sendNibble(int halfByte, bool isData)
260279
{
261-
_write2Wire(halfByte, isData, true);
280+
// map the data to the given pin connections
281+
uint8_t data = 0;
282+
283+
// allow for arbitrary pin configuration
284+
if (halfByte & 0x01) data |= _data_mask[0];
285+
if (halfByte & 0x02) data |= _data_mask[1];
286+
if (halfByte & 0x04) data |= _data_mask[2];
287+
if (halfByte & 0x08) data |= _data_mask[3];
288+
289+
_write2Wire(data, isData, true);
262290
delayMicroseconds(1); // enable pulse must be >450ns
263-
_write2Wire(halfByte, isData, false);
291+
_write2Wire(data, isData, false);
264292
delayMicroseconds(37); // commands need > 37us to settle
265293
} // _sendNibble
266294

267295

268296
// private function to change the PCF8674 pins to the given value
269-
// Note:
270-
// you may change this function what the display is attached to the PCF8574 in a different wiring.
271-
void LiquidCrystal_PCF8574::_write2Wire(int halfByte, bool isData, bool enable)
297+
void LiquidCrystal_PCF8574::_write2Wire(uint8_t data, bool isData, bool enable)
272298
{
273-
// map the given values to the hardware of the I2C schema
274-
int i2cData = halfByte << 4;
275299
if (isData)
276-
i2cData |= PCF_RS;
277-
// PCF_RW is never used.
300+
data |= _rs_mask;
301+
// _rw_mask is not used here.
278302
if (enable)
279-
i2cData |= PCF_EN;
303+
data |= _enable_mask;
280304
if (_backlight > 0)
281-
i2cData |= PCF_BACKLIGHT;
305+
data |= _backlight_mask;
282306

283307
Wire.beginTransmission(_i2cAddr);
284-
Wire.write(i2cData);
308+
Wire.write(data);
285309
Wire.endTransmission();
286310
} // write2Wire
287311

src/LiquidCrystal_PCF8574.h

+23-9
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
/// See http://www.mathertel.de/License.aspx
1010
///
1111
/// \details
12-
/// This library is can drive a Liquid Cristal display based on the Hitachi HD44780 chip that is connected through a PCF8574 I2C adapter.
13-
/// This is given by many (not all) LCD adapters. This library uses the original Wire library for communication.
12+
/// This library can drive a Liquid Cristal display based on the Hitachi HD44780 chip that is connected
13+
/// through a PCF8574 I2C adapter. It uses the original Wire library for communication.
1414
/// The API if common to many LCD libraries and documented in https://www.arduino.cc/en/Reference/LiquidCrystal.
1515
/// and partially functions from https://playground.arduino.cc/Code/LCDAPI/.
1616

@@ -32,17 +32,21 @@
3232
class LiquidCrystal_PCF8574 : public Print
3333
{
3434
public:
35-
LiquidCrystal_PCF8574(int i2cAddr);
35+
LiquidCrystal_PCF8574(uint8_t i2cAddr);
3636
// note:
3737
// There is no sda and scl parameter for i2c in any api.
3838
// The Wire library has standard settings that can be overwritten by using Wire.begin(int sda, int scl) before calling LiquidCrystal_PCF8574::begin();
3939

40+
// constructors, which allows to redefine bit assignments in case your adapter is wired differently
41+
LiquidCrystal_PCF8574(uint8_t i2cAddr, uint8_t rs, uint8_t enable,
42+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight=255);
43+
LiquidCrystal_PCF8574(uint8_t i2cAddr, uint8_t rs, uint8_t rw, uint8_t enable,
44+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight=255);
45+
4046
// Funtions from reference:
4147

4248
void begin(int cols, int rows);
4349

44-
void init();
45-
4650
void home();
4751
void setCursor(int col, int row);
4852
void cursor();
@@ -60,13 +64,12 @@ class LiquidCrystal_PCF8574 : public Print
6064
void createChar(int, byte[]);
6165

6266
// plus functions from LCDAPI:
63-
void clear(); // same as init()
67+
void clear();
6468
void setBacklight(int brightness);
6569
inline void command(uint8_t value) { _send(value); }
6670

6771
// support of Print class
6872
virtual size_t write(uint8_t ch);
69-
using Print::write;
7073

7174
private:
7275
// instance variables
@@ -78,10 +81,21 @@ class LiquidCrystal_PCF8574 : public Print
7881
int _displaycontrol; ///<flags from displaycontrol
7982
int _row_offsets[4];
8083

84+
// variables describing how the PCF8574 is connected to the LCD
85+
uint8_t _rs_mask;
86+
uint8_t _rw_mask;
87+
uint8_t _enable_mask;
88+
uint8_t _backlight_mask;
89+
// these are used for 4-bit data to the display.
90+
uint8_t _data_mask[4];
91+
8192
// low level functions
82-
void _send(int value, bool isData = false);
93+
void _send(uint8_t value, bool isData = false);
8394
void _sendNibble(int halfByte, bool isData = false);
84-
void _write2Wire(int halfByte, bool isData, bool enable);
95+
void _write2Wire(uint8_t data, bool isData, bool enable);
96+
97+
void init(uint8_t i2cAddr, uint8_t rs, uint8_t rw, uint8_t enable,
98+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight=255);
8599
};
86100

87101
#endif

0 commit comments

Comments
 (0)