Skip to content

Commit 47c73a4

Browse files
authored
Merge pull request #24 from markisch:feature-pin-assignment
Allow arbitrary pin assignments
2 parents 0ea7dfb + 11971eb commit 47c73a4

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
@@ -256,12 +275,12 @@ void LiquidCrystal_PCF8574::createChar_P(uint8_t location, const byte *charmap)
256275
inline size_t LiquidCrystal_PCF8574::write(uint8_t ch)
257276
{
258277
_send(ch, true);
259-
return 1; // assume sucess
278+
return 1; // assume success
260279
} // write()
261280

262281

263282
// write either command or data
264-
void LiquidCrystal_PCF8574::_send(int value, bool isData)
283+
void LiquidCrystal_PCF8574::_send(uint8_t value, bool isData)
265284
{
266285
// write high 4 bits
267286
_sendNibble((value >> 4 & 0x0F), isData);
@@ -273,30 +292,35 @@ void LiquidCrystal_PCF8574::_send(int value, bool isData)
273292
// write a nibble / halfByte with handshake
274293
void LiquidCrystal_PCF8574::_sendNibble(int halfByte, bool isData)
275294
{
276-
_write2Wire(halfByte, isData, true);
295+
// map the data to the given pin connections
296+
uint8_t data = 0;
297+
298+
// allow for arbitrary pin configuration
299+
if (halfByte & 0x01) data |= _data_mask[0];
300+
if (halfByte & 0x02) data |= _data_mask[1];
301+
if (halfByte & 0x04) data |= _data_mask[2];
302+
if (halfByte & 0x08) data |= _data_mask[3];
303+
304+
_write2Wire(data, isData, true);
277305
delayMicroseconds(1); // enable pulse must be >450ns
278-
_write2Wire(halfByte, isData, false);
306+
_write2Wire(data, isData, false);
279307
delayMicroseconds(37); // commands need > 37us to settle
280308
} // _sendNibble
281309

282310

283311
// private function to change the PCF8674 pins to the given value
284-
// Note:
285-
// you may change this function what the display is attached to the PCF8574 in a different wiring.
286-
void LiquidCrystal_PCF8574::_write2Wire(int halfByte, bool isData, bool enable)
312+
void LiquidCrystal_PCF8574::_write2Wire(uint8_t data, bool isData, bool enable)
287313
{
288-
// map the given values to the hardware of the I2C schema
289-
int i2cData = halfByte << 4;
290314
if (isData)
291-
i2cData |= PCF_RS;
292-
// PCF_RW is never used.
315+
data |= _rs_mask;
316+
// _rw_mask is not used here.
293317
if (enable)
294-
i2cData |= PCF_EN;
318+
data |= _enable_mask;
295319
if (_backlight > 0)
296-
i2cData |= PCF_BACKLIGHT;
320+
data |= _backlight_mask;
297321

298322
Wire.beginTransmission(_i2cAddr);
299-
Wire.write(i2cData);
323+
Wire.write(data);
300324
Wire.endTransmission();
301325
} // write2Wire
302326

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();
@@ -66,13 +70,12 @@ class LiquidCrystal_PCF8574 : public Print
6670
#endif
6771

6872
// plus functions from LCDAPI:
69-
void clear(); // same as init()
73+
void clear();
7074
void setBacklight(int brightness);
7175
inline void command(uint8_t value) { _send(value); }
7276

7377
// support of Print class
7478
virtual size_t write(uint8_t ch);
75-
using Print::write;
7679

7780
private:
7881
// instance variables
@@ -84,10 +87,21 @@ class LiquidCrystal_PCF8574 : public Print
8487
int _displaycontrol; ///<flags from displaycontrol
8588
int _row_offsets[4];
8689

90+
// variables describing how the PCF8574 is connected to the LCD
91+
uint8_t _rs_mask;
92+
uint8_t _rw_mask;
93+
uint8_t _enable_mask;
94+
uint8_t _backlight_mask;
95+
// these are used for 4-bit data to the display.
96+
uint8_t _data_mask[4];
97+
8798
// low level functions
88-
void _send(int value, bool isData = false);
99+
void _send(uint8_t value, bool isData = false);
89100
void _sendNibble(int halfByte, bool isData = false);
90-
void _write2Wire(int halfByte, bool isData, bool enable);
101+
void _write2Wire(uint8_t data, bool isData, bool enable);
102+
103+
void init(uint8_t i2cAddr, uint8_t rs, uint8_t rw, uint8_t enable,
104+
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlight=255);
91105
};
92106

93107
#endif

0 commit comments

Comments
 (0)