1// ---------------------------------------------------------------------------
2// Created by Francisco Malpartida on 20/08/11.
3// Copyright 2011 - Under creative commons license 3.0:
4// Attribution-ShareAlike CC BY-SA
5//
6// This software is furnished "as is", without technical support, and with no
7// warranty, express or implied, as to its usefulness for any purpose.
8//
9// Thread Safe: No
10// Extendable: Yes
11//
12// @file LiquidCrystal_I2C.c
13// This file implements a basic liquid crystal library that comes as standard
14// in the Arduino SDK but using an I2C IO extension board.
15//
16// @brief
17// This is a basic implementation of the LiquidCrystal library of the
18// Arduino SDK. The original library has been reworked in such a way that
19// this class implements the all methods to command an LCD based
20// on the Hitachi HD44780 and compatible chipsets using I2C extension
21// backpacks such as the I2CLCDextraIO with the PCF8574* I2C IO Expander ASIC.
22//
23// The functionality provided by this class and its base class is identical
24// to the original functionality of the Arduino LiquidCrystal library.
25//
26//
27//
28// @author F. Malpartida - fmalpartida@gmail.com
29// ---------------------------------------------------------------------------
30#if (ARDUINO < 100)
31#include <WProgram.h>
32#else
33#include <Arduino.h>
34#endif
35#include <inttypes.h>
36#include "Visuino_I2CIO.h"
37#include "Visuino_LiquidCrystal_I2C.h"
38
39// CONSTANT definitions
40// ---------------------------------------------------------------------------
41
42// flags for backlight control
43/*!
44 @defined
45 @abstract LCD_NOBACKLIGHT
46 @discussion NO BACKLIGHT MASK
47 */
48#define LCD_NOBACKLIGHT 0x00
49
50/*!
51 @defined
52 @abstract LCD_BACKLIGHT
53 @discussion BACKLIGHT MASK used when backlight is on
54 */
55#define LCD_BACKLIGHT 0xFF
56
57
58// Default library configuration parameters used by class constructor with
59// only the I2C address field.
60// ---------------------------------------------------------------------------
61/*!
62 @defined
63 @abstract Enable bit of the LCD
64 @discussion Defines the IO of the expander connected to the LCD Enable
65 */
66#define EN 6 // Enable bit
67
68/*!
69 @defined
70 @abstract Read/Write bit of the LCD
71 @discussion Defines the IO of the expander connected to the LCD Rw pin
72 */
73#define RW 5 // Read/Write bit
74
75/*!
76 @defined
77 @abstract Register bit of the LCD
78 @discussion Defines the IO of the expander connected to the LCD Register select pin
79 */
80#define RS 4 // Register select bit
81
82/*!
83 @defined
84 @abstract LCD dataline allocation this library only supports 4 bit LCD control
85 mode.
86 @discussion D4, D5, D6, D7 LCD data lines pin mapping of the extender module
87 */
88#define D4 0
89#define D5 1
90#define D6 2
91#define D7 3
92
93
94// CONSTRUCTORS
95// ---------------------------------------------------------------------------
96LiquidCrystal_I2C::LiquidCrystal_I2C( uint8_t lcd_Addr )
97{
98 config(lcd_Addr, EN, RW, RS, D4, D5, D6, D7);
99}
100
101
102LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t backlighPin,
103 t_backlighPol pol = POSITIVE)
104{
105 config(lcd_Addr, EN, RW, RS, D4, D5, D6, D7);
106 setBacklightPin(backlighPin, pol);
107}
108
109LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
110 uint8_t Rs)
111{
112 config(lcd_Addr, En, Rw, Rs, D4, D5, D6, D7);
113}
114
115LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
116 uint8_t Rs, uint8_t backlighPin,
117 t_backlighPol pol = POSITIVE)
118{
119 config(lcd_Addr, En, Rw, Rs, D4, D5, D6, D7);
120 setBacklightPin(backlighPin, pol);
121}
122
123LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
124 uint8_t Rs, uint8_t d4, uint8_t d5,
125 uint8_t d6, uint8_t d7 )
126{
127 config(lcd_Addr, En, Rw, Rs, d4, d5, d6, d7);
128}
129
130LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
131 uint8_t Rs, uint8_t d4, uint8_t d5,
132 uint8_t d6, uint8_t d7, uint8_t backlighPin,
133 t_backlighPol pol = POSITIVE )
134{
135 config(lcd_Addr, En, Rw, Rs, d4, d5, d6, d7);
136 setBacklightPin(backlighPin, pol);
137}
138
139// PUBLIC METHODS
140// ---------------------------------------------------------------------------
141
142//
143// begin
144void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize)
145{
146
147 init(); // Initialise the I2C expander interface
148 LCD::begin ( cols, lines, dotsize );
149}
150
151
152// User commands - users can expand this section
153//----------------------------------------------------------------------------
154// Turn the (optional) backlight off/on
155
156//
157// setBacklightPin
158void LiquidCrystal_I2C::setBacklightPin ( uint8_t value, t_backlighPol pol = POSITIVE )
159{
160 _backlightPinMask = ( 1 << value );
161 _polarity = pol;
162 setBacklight(BACKLIGHT_OFF);
163}
164
165//
166// setBacklight
167void LiquidCrystal_I2C::setBacklight( uint8_t value )
168{
169 // Check if backlight is available
170 // ----------------------------------------------------
171 if ( _backlightPinMask != 0x0 )
172 {
173 // Check for polarity to configure mask accordingly
174 // ----------------------------------------------------------
175 if (((_polarity == POSITIVE) && (value > 0)) ||
176 ((_polarity == NEGATIVE ) && ( value == 0 )))
177 {
178 _backlightStsMask = _backlightPinMask & LCD_BACKLIGHT;
179 }
180 else
181 {
182 _backlightStsMask = _backlightPinMask & LCD_NOBACKLIGHT;
183 }
184 _i2cio.write( _backlightStsMask );
185 }
186}
187
188
189// PRIVATE METHODS
190// ---------------------------------------------------------------------------
191
192//
193// init
194int LiquidCrystal_I2C::init()
195{
196 int status = 0;
197
198 // initialize the backpack IO expander
199 // and display functions.
200 // ------------------------------------------------------------------------
201 if ( _i2cio.begin ( _Addr ) == 1 )
202 {
203 _i2cio.portMode ( OUTPUT ); // Set the entire IO extender to OUTPUT
204 _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
205 status = 1;
206 _i2cio.write(0); // Set the entire port to LOW
207 }
208 return ( status );
209}
210
211//
212// config
213void LiquidCrystal_I2C::config (uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs,
214 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 )
215{
216 _Addr = lcd_Addr;
217
218 _backlightPinMask = 0;
219 _backlightStsMask = LCD_NOBACKLIGHT;
220 _polarity = POSITIVE;
221
222 _En = ( 1 << En );
223 _Rw = ( 1 << Rw );
224 _Rs = ( 1 << Rs );
225
226 // Initialise pin mapping
227 _data_pins[0] = ( 1 << d4 );
228 _data_pins[1] = ( 1 << d5 );
229 _data_pins[2] = ( 1 << d6 );
230 _data_pins[3] = ( 1 << d7 );
231}
232
233
234
235// low level data pushing commands
236//----------------------------------------------------------------------------
237
238//
239// send - write either command or data
240void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode)
241{
242 // No need to use the delay routines since the time taken to write takes
243 // longer that what is needed both for toggling and enable pin an to execute
244 // the command.
245
246 if ( mode == FOUR_BITS )
247 {
248 write4bits( (value & 0x0F), COMMAND );
249 }
250 else
251 {
252 write4bits( (value >> 4), mode );
253 write4bits( (value & 0x0F), mode);
254 }
255}
256
257//
258// write4bits
259void LiquidCrystal_I2C::write4bits ( uint8_t value, uint8_t mode )
260{
261 uint8_t pinMapValue = 0;
262
263 // Map the value to LCD pin mapping
264 // --------------------------------
265 for ( uint8_t i = 0; i < 4; i++ )
266 {
267 if ( ( value & 0x1 ) == 1 )
268 {
269 pinMapValue |= _data_pins[i];
270 }
271 value = ( value >> 1 );
272 }
273
274 // Is it a command or data
275 // -----------------------
276 if ( mode == DATA )
277 {
278 mode = _Rs;
279 }
280
281 pinMapValue |= mode | _backlightStsMask;
282 pulseEnable ( pinMapValue );
283}
284
285//
286// pulseEnable
287void LiquidCrystal_I2C::pulseEnable (uint8_t data)
288{
289 _i2cio.write (data | _En); // En HIGH
290 _i2cio.write (data & ~_En); // En LOW
291}