Skip to content

Commit db08789

Browse files
committed
User provided i2cport
added user provided i2c port. changed int to uint8_t provided example program for custom i2c port
1 parent 1be19f2 commit db08789

File tree

3 files changed

+433
-0
lines changed

3 files changed

+433
-0
lines changed

LiquidCrystal_PCF8574.cpp

+288
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
/// \file LiquidCrystal_PCF8574.cpp
2+
/// \brief LiquidCrystal library with PCF8574 I2C adapter.
3+
///
4+
/// \author Matthias Hertel, http://www.mathertel.de
5+
/// \copyright Copyright (c) 2019 by Matthias Hertel.
6+
///
7+
/// ChangeLog see: LiquidCrystal_PCF8574.h
8+
9+
#include "LiquidCrystal_PCF8574.h"
10+
11+
/// Definitions on how the PCF8574 is connected to the LCD
12+
13+
/// These are Bit-Masks for the special signals and background light
14+
#define PCF_RS 0x01
15+
#define PCF_RW 0x02
16+
#define PCF_EN 0x04
17+
#define PCF_BACKLIGHT 0x08
18+
// the 0xF0 bits are used for 4-bit data to the display.
19+
20+
// a nibble is a half Byte
21+
22+
LiquidCrystal_PCF8574::LiquidCrystal_PCF8574(uint8_t i2cAddr)
23+
{
24+
_i2cAddr = i2cAddr;
25+
_backlight = 0;
26+
27+
_entrymode = 0x02; // like Initializing by Internal Reset Circuit
28+
_displaycontrol = 0x04;
29+
} // LiquidCrystal_PCF8574
30+
31+
void LiquidCrystal_PCF8574::begin(uint8_t cols, uint8_t lines, TwoWire &wirePort)
32+
{
33+
_i2cPort = &wirePort; //Grab which port the user wants us to use
34+
35+
_cols = ((cols>80)?(80):(cols));
36+
_lines = ((lines>4)?(4):(lines));
37+
38+
uint8_t functionFlags = 0;
39+
40+
_row_offsets[0] = 0x00;
41+
_row_offsets[1] = 0x40;
42+
_row_offsets[2] = 0x00 + cols;
43+
_row_offsets[3] = 0x40 + cols;
44+
45+
if (lines > 1) {
46+
functionFlags |= 0x08;
47+
}
48+
49+
// initializing the display
50+
_i2cPort->begin();
51+
52+
_write2Wire(0x00, LOW, false);
53+
delayMicroseconds(50000);
54+
55+
// after reset the mode is this
56+
_displaycontrol = 0x04;
57+
_entrymode = 0x02;
58+
59+
// sequence to reset. see "Initializing by Instruction" in datatsheet
60+
_sendNibble(0x03);
61+
delayMicroseconds(4500);
62+
_sendNibble(0x03);
63+
delayMicroseconds(200);
64+
_sendNibble(0x03);
65+
delayMicroseconds(200);
66+
_sendNibble(0x02); // finally, set to 4-bit interface
67+
68+
// Instruction: Function set = 0x20
69+
_send(0x20 | functionFlags);
70+
71+
display();
72+
clear();
73+
leftToRight();
74+
} // begin()
75+
76+
77+
void LiquidCrystal_PCF8574::clear()
78+
{
79+
// Instruction: Clear display = 0x01
80+
_send(0x01);
81+
delayMicroseconds(1600); // this command takes 1.5ms!
82+
} // clear()
83+
84+
85+
void LiquidCrystal_PCF8574::init()
86+
{
87+
clear();
88+
} // init()
89+
90+
91+
void LiquidCrystal_PCF8574::home()
92+
{
93+
// Instruction: Return home = 0x02
94+
_send(0x02);
95+
delayMicroseconds(1600); // this command takes 1.5ms!
96+
} // home()
97+
98+
99+
/// Set the cursor to a new position.
100+
void LiquidCrystal_PCF8574::setCursor(uint8_t col, uint8_t row)
101+
{
102+
// check boundaries
103+
if ((col >= 0) && (col < _cols) && (row >= 0) && (row < _lines)) {
104+
// Instruction: Set DDRAM address = 0x80
105+
_send(0x80 | (_row_offsets[row] + col));
106+
}
107+
} // setCursor()
108+
109+
110+
// Turn the display on/off (quickly)
111+
void LiquidCrystal_PCF8574::noDisplay()
112+
{
113+
// Instruction: Display on/off control = 0x08
114+
_displaycontrol &= ~0x04; // display
115+
_send(0x08 | _displaycontrol);
116+
} // noDisplay()
117+
118+
119+
void LiquidCrystal_PCF8574::display()
120+
{
121+
// Instruction: Display on/off control = 0x08
122+
_displaycontrol |= 0x04; // display
123+
_send(0x08 | _displaycontrol);
124+
} // display()
125+
126+
127+
// Turns the underline cursor on/off
128+
void LiquidCrystal_PCF8574::cursor()
129+
{
130+
// Instruction: Display on/off control = 0x08
131+
_displaycontrol |= 0x02; // cursor
132+
_send(0x08 | _displaycontrol);
133+
} // cursor()
134+
135+
136+
void LiquidCrystal_PCF8574::noCursor()
137+
{
138+
// Instruction: Display on/off control = 0x08
139+
_displaycontrol &= ~0x02; // cursor
140+
_send(0x08 | _displaycontrol);
141+
} // noCursor()
142+
143+
144+
// Turn on and off the blinking cursor
145+
void LiquidCrystal_PCF8574::blink()
146+
{
147+
// Instruction: Display on/off control = 0x08
148+
_displaycontrol |= 0x01; // blink
149+
_send(0x08 | _displaycontrol);
150+
} // blink()
151+
152+
153+
void LiquidCrystal_PCF8574::noBlink()
154+
{
155+
// Instruction: Display on/off control = 0x08
156+
_displaycontrol &= ~0x01; // blink
157+
_send(0x08 | _displaycontrol);
158+
} // noBlink()
159+
160+
161+
// These commands scroll the display without changing the RAM
162+
void LiquidCrystal_PCF8574::scrollDisplayLeft(void)
163+
{
164+
// Instruction: Cursor or display shift = 0x10
165+
// shift: 0x08, left: 0x00
166+
_send(0x10 | 0x08 | 0x00);
167+
} // scrollDisplayLeft()
168+
169+
170+
void LiquidCrystal_PCF8574::scrollDisplayRight(void)
171+
{
172+
// Instruction: Cursor or display shift = 0x10
173+
// shift: 0x08, right: 0x04
174+
_send(0x10 | 0x08 | 0x04);
175+
} // scrollDisplayRight()
176+
177+
178+
// == controlling the entrymode
179+
180+
// This is for text that flows Left to Right
181+
void LiquidCrystal_PCF8574::leftToRight(void)
182+
{
183+
// Instruction: Entry mode set, set increment/decrement =0x02
184+
_entrymode |= 0x02;
185+
_send(0x04 | _entrymode);
186+
} // leftToRight()
187+
188+
189+
// This is for text that flows Right to Left
190+
void LiquidCrystal_PCF8574::rightToLeft(void)
191+
{
192+
// Instruction: Entry mode set, clear increment/decrement =0x02
193+
_entrymode &= ~0x02;
194+
_send(0x04 | _entrymode);
195+
} // rightToLeft()
196+
197+
198+
// This will 'right justify' text from the cursor
199+
void LiquidCrystal_PCF8574::autoscroll(void)
200+
{
201+
// Instruction: Entry mode set, set shift S=0x01
202+
_entrymode |= 0x01;
203+
_send(0x04 | _entrymode);
204+
} // autoscroll()
205+
206+
207+
// This will 'left justify' text from the cursor
208+
void LiquidCrystal_PCF8574::noAutoscroll(void)
209+
{
210+
// Instruction: Entry mode set, clear shift S=0x01
211+
_entrymode &= ~0x01;
212+
_send(0x04 | _entrymode);
213+
} // noAutoscroll()
214+
215+
216+
/// Setting the brightness of the background display light.
217+
/// The backlight can be switched on and off.
218+
/// The current brightness is stored in the private _backlight variable to have it available for further data transfers.
219+
void LiquidCrystal_PCF8574::setBacklight(uint8_t brightness)
220+
{
221+
_backlight = brightness;
222+
// send no data but set the background-pin right;
223+
_write2Wire(0x00, true, false);
224+
} // setBacklight()
225+
226+
227+
// Allows us to fill the first 8 CGRAM locations
228+
// with custom characters
229+
void LiquidCrystal_PCF8574::createChar(uint8_t location, byte charmap[])
230+
{
231+
location &= 0x7; // we only have 8 locations 0-7
232+
// Set CGRAM address
233+
_send(0x40 | (location << 3));
234+
for (int i = 0; i < 8; i++) {
235+
write(charmap[i]);
236+
}
237+
} // createChar()
238+
239+
240+
/* The write function is needed for derivation from the Print class. */
241+
inline size_t LiquidCrystal_PCF8574::write(uint8_t ch)
242+
{
243+
_send(ch, true);
244+
return 1; // assume sucess
245+
} // write()
246+
247+
248+
// write either command or data
249+
void LiquidCrystal_PCF8574::_send(uint8_t value, bool isData)
250+
{
251+
// write high 4 bits
252+
_sendNibble((value >> 4 & 0x0F), isData);
253+
// write low 4 bits
254+
_sendNibble((value & 0x0F), isData);
255+
} // _send()
256+
257+
258+
// write a nibble / halfByte with handshake
259+
void LiquidCrystal_PCF8574::_sendNibble(uint8_t halfByte, bool isData)
260+
{
261+
_write2Wire(halfByte, isData, true);
262+
delayMicroseconds(1); // enable pulse must be >450ns
263+
_write2Wire(halfByte, isData, false);
264+
delayMicroseconds(37); // commands need > 37us to settle
265+
} // _sendNibble
266+
267+
268+
// 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(uint8_t halfByte, bool isData, bool enable)
272+
{
273+
// map the given values to the hardware of the I2C schema
274+
uint8_t i2cData = halfByte << 4;
275+
if (isData)
276+
i2cData |= PCF_RS;
277+
// PCF_RW is never used.
278+
if (enable)
279+
i2cData |= PCF_EN;
280+
if (_backlight > 0)
281+
i2cData |= PCF_BACKLIGHT;
282+
283+
_i2cPort->beginTransmission(_i2cAddr);
284+
_i2cPort->write(i2cData);
285+
_i2cPort->endTransmission();
286+
} // write2Wire
287+
288+
// The End.

LiquidCrystal_PCF8574.h

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/// \file LiquidCrystal_PCF8574.h
2+
/// \brief LiquidCrystal library with PCF8574 I2C adapter.
3+
///
4+
/// \author Matthias Hertel, http://www.mathertel.de
5+
///
6+
/// \copyright Copyright (c) 2019 by Matthias Hertel.\n
7+
///
8+
/// The library work is licensed under a BSD style license.\n
9+
/// See http://www.mathertel.de/License.aspx
10+
///
11+
/// \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.
14+
/// The API if common to many LCD libraries and documented in https://www.arduino.cc/en/Reference/LiquidCrystal.
15+
/// and partially functions from https://playground.arduino.cc/Code/LCDAPI/.
16+
17+
///
18+
/// ChangeLog:
19+
/// --------
20+
/// * 19.10.2013 created.
21+
/// * 05.06.2019 rewrite from scratch.
22+
/// * 16.12.2020 modified to provide user's chosen I2C hardware, changed int to unint8_t
23+
24+
#ifndef LiquidCrystal_PCF8574_h
25+
#define LiquidCrystal_PCF8574_h
26+
27+
#include "Arduino.h"
28+
#include <Wire.h>
29+
30+
#include "Print.h"
31+
#include <stddef.h>
32+
#include <stdint.h>
33+
34+
35+
class LiquidCrystal_PCF8574 : public Print
36+
{
37+
public:
38+
LiquidCrystal_PCF8574(uint8_t i2cAddr);
39+
// note:
40+
// There is no sda and scl parameter for i2c in any api.
41+
// The Wire library has standard settings that can be overwritten by using Wire.begin(sda, scl) before calling LiquidCrystal_PCF8574::begin();
42+
// When using multiple I2C ports one can use
43+
// LiquidCrystal_PCF8574 lcd(0x27);
44+
// TwoWire Wire_1 = TwoWire();
45+
// Wire_1.begin(sdaPin, sclPin);
46+
// Wire_1.setClock(100000); // standard 100kHz speed
47+
// Wire_1.setClockStretchLimit(200000); // 200ms, for slow devices
48+
// lcd.begin(clos, rows, Wire_1);
49+
50+
// Funtions from reference:
51+
void begin(uint8_t cols, uint8_t rows, TwoWire &wirePort = Wire);
52+
53+
void init();
54+
55+
void home();
56+
void setCursor(uint8_t col, uint8_t row);
57+
void cursor();
58+
void noCursor();
59+
void blink();
60+
void noBlink();
61+
void display();
62+
void noDisplay();
63+
void scrollDisplayLeft();
64+
void scrollDisplayRight();
65+
void autoscroll();
66+
void noAutoscroll();
67+
void leftToRight();
68+
void rightToLeft();
69+
void createChar(uint8_t, byte[]);
70+
71+
// plus functions from LCDAPI:
72+
void clear(); // same as init()
73+
void setBacklight(uint8_t brightness);
74+
75+
// support of Print class
76+
virtual size_t write(uint8_t ch);
77+
using Print::write;
78+
79+
private:
80+
TwoWire * _i2cPort; //The generic connection to user's chosen I2C hardware
81+
// instance variables
82+
uint8_t _i2cAddr;
83+
uint8_t _backlight; ///< the backlight intensity
84+
uint8_t _cols; ///< number of cols of the display
85+
uint8_t _lines; ///< number of lines of the display
86+
uint8_t _entrymode; ///<flags from entrymode
87+
uint8_t _displaycontrol; ///<flags from displaycontrol
88+
uint8_t _row_offsets[4];
89+
90+
// low level functions
91+
void _send(uint8_t value, bool isData = false);
92+
void _sendNibble(uint8_t halfByte, bool isData = false);
93+
void _write2Wire(uint8_t halfByte, bool isData, bool enable);
94+
};
95+
96+
#endif

0 commit comments

Comments
 (0)