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.cpp
13// This file implements a basic liquid crystal library that comes as standard
14// in the Arduino SDK.
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 the parallel port of
21// the LCD (4 bit and 8 bit).
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// @author F. Malpartida - fmalpartida@gmail.com
28// ---------------------------------------------------------------------------
29#include <stdio.h>
30#include <string.h>
31#include <inttypes.h>
32
33#if (ARDUINO < 100)
34#include <WProgram.h>
35#else
36#include <Arduino.h>
37#endif
38#include "Visuino_LiquidCrystal.h"
39
40// CONSTANT definitions
41// ---------------------------------------------------------------------------
42#define LCD_NOBACKLIGHT 0xFF
43
44// LCD driver configuration (4bit or 8bit driver control)
45#define LCD_4BIT 1
46#define LCD_8BIT 0
47
48// STATIC helper functions
49// ---------------------------------------------------------------------------
50
51
52// CONSTRUCTORS
53// ---------------------------------------------------------------------------
54
55LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
56 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
57 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
58{
59 init(LCD_8BIT, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
60}
61
62LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
63 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
64 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
65{
66 init(LCD_8BIT, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
67}
68
69LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
70 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
71{
72 init(LCD_4BIT, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
73}
74
75LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
76 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
77{
78 init(LCD_4BIT, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
79}
80
81// Contructors with backlight control
82LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
83 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
84 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
85 uint8_t backlightPin, t_backlighPol pol)
86{
87 init(LCD_8BIT, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
88 setBacklightPin ( backlightPin, pol );
89}
90
91LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
92 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
93 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
94 uint8_t backlightPin, t_backlighPol pol)
95{
96 init(LCD_8BIT, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
97 setBacklightPin ( backlightPin, pol );
98}
99
100LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
101 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
102 uint8_t backlightPin, t_backlighPol pol)
103{
104 init(LCD_4BIT, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
105 setBacklightPin ( backlightPin, pol );
106}
107
108LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
109 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
110 uint8_t backlightPin, t_backlighPol pol)
111{
112 init(LCD_4BIT, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
113 setBacklightPin ( backlightPin, pol );
114}
115
116// PUBLIC METHODS
117// ---------------------------------------------------------------------------
118
119/************ low level data pushing commands **********/
120//
121// send
122void LiquidCrystal::send(uint8_t value, uint8_t mode)
123{
124 // Only interested in COMMAND or DATA
125 digitalWrite( _rs_pin, ( mode == DATA ) );
126
127 // if there is a RW pin indicated, set it low to Write
128 // ---------------------------------------------------
129 if (_rw_pin != 255)
130 {
131 digitalWrite(_rw_pin, LOW);
132 }
133
134 if ( mode != FOUR_BITS )
135 {
136 if ( (_displayfunction & LCD_8BITMODE ) )
137 {
138 writeNbits(value, 8);
139 }
140 else
141 {
142 writeNbits ( value >> 4, 4 );
143 writeNbits ( value, 4 );
144 }
145 }
146 else
147 {
148 writeNbits ( value, 4 );
149 }
150 waitUsec ( EXEC_TIME ); // wait for the command to execute by the LCD
151}
152
153//
154// setBacklightPin
155void LiquidCrystal::setBacklightPin ( uint8_t pin, t_backlighPol pol )
156{
157 pinMode ( pin, OUTPUT ); // Difine the backlight pin as output
158 _backlightPin = pin;
159 _polarity = pol;
160 setBacklight(BACKLIGHT_OFF); // Set the backlight low by default
161}
162
163//
164// setBackligh
165void LiquidCrystal::setBacklight ( uint8_t value )
166{
167 // Check if there is a pin assigned to the backlight
168 // ---------------------------------------------------
169 if ( _backlightPin != LCD_NOBACKLIGHT )
170 {
171 // Check if the pin is associated to a timer, i.e. PWM
172 // ---------------------------------------------------
173 if(digitalPinToTimer(_backlightPin) != NOT_ON_TIMER)
174 {
175 // Check for control polarity inversion
176 // ---------------------------------------------------
177 if ( _polarity == POSITIVE )
178 {
179 analogWrite ( _backlightPin, value );
180 }
181 else
182 {
183 analogWrite ( _backlightPin, 255 - value );
184 }
185 }
186 // Not a PWM pin, set the backlight pin for POSI or NEG
187 // polarity
188 // --------------------------------------------------------
189 else if (((value > 0) && (_polarity == POSITIVE)) ||
190 ((value == 0) && (_polarity == NEGATIVE)))
191 {
192 digitalWrite( _backlightPin, HIGH);
193 }
194 else
195 {
196 digitalWrite( _backlightPin, LOW);
197 }
198 }
199}
200
201// PRIVATE METHODS
202// ---------------------------------------------------------------------------
203
204
205// init
206void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
207 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
208 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
209{
210 uint8_t i;
211
212 // Initialize the IO pins
213 // -----------------------
214
215 _rs_pin = rs;
216 _rw_pin = rw;
217 _enable_pin = enable;
218
219 _data_pins[0] = d0;
220 _data_pins[1] = d1;
221 _data_pins[2] = d2;
222 _data_pins[3] = d3;
223 _data_pins[4] = d4;
224 _data_pins[5] = d5;
225 _data_pins[6] = d6;
226 _data_pins[7] = d7;
227
228 // Initialize the IO port direction to OUTPUT
229 // ------------------------------------------
230
231 for ( i = 0; i < 4; i++ )
232 {
233 pinMode ( _data_pins[i], OUTPUT );
234 }
235
236 // Initialize the rest of the ports if it is an 8bit controlled LCD
237 // ----------------------------------------------------------------
238
239 if ( !fourbitmode )
240 {
241 for ( i = 4; i < 8; i++ )
242 {
243 pinMode ( _data_pins[i], OUTPUT );
244 }
245 }
246 pinMode(_rs_pin, OUTPUT);
247
248 // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
249 if (_rw_pin != 255)
250 {
251 pinMode(_rw_pin, OUTPUT);
252 }
253
254 pinMode(_enable_pin, OUTPUT);
255
256 // Initialise displaymode functions to defaults: LCD_1LINE and LCD_5x8DOTS
257 // -------------------------------------------------------------------------
258 if (fourbitmode)
259 _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
260 else
261 _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
262
263 // Now we pull both RS and R/W low to begin commands
264 digitalWrite(_rs_pin, LOW);
265 digitalWrite(_enable_pin, LOW);
266
267 if (_rw_pin != 255)
268 {
269 digitalWrite(_rw_pin, LOW);
270 }
271
272 // Initialise the backlight pin no nothing
273 _backlightPin = LCD_NOBACKLIGHT;
274 _polarity = POSITIVE;
275}
276
277//
278// pulseEnable
279void LiquidCrystal::pulseEnable(void)
280{
281 // There is no need for the delays, since the digitalWrite operation
282 // takes longer.
283 digitalWrite(_enable_pin, HIGH);
284 waitUsec(1); // enable pulse must be > 450ns
285 digitalWrite(_enable_pin, LOW);
286}
287
288//
289// write4bits
290void LiquidCrystal::writeNbits(uint8_t value, uint8_t numBits)
291{
292 for (uint8_t i = 0; i < numBits; i++)
293 {
294 digitalWrite(_data_pins[i], (value >> i) & 0x01);
295 }
296 pulseEnable();
297}
298
299