Statistics
| Revision:

root / Ports / PortsLCD.cpp

History | View | Annotate | Download (10.2 KB)

1
//>>> The latest version of this code can be found at https://github.com/jcw/ !!
2
3
#include "PortsLCD.h"
4
#include <stdio.h>
5
#include <string.h>
6
#include <inttypes.h>
7
#include "WProgram.h"
8
9
void LiquidCrystalBase::begin(byte cols, byte lines, byte dotsize) {
10
  if (lines > 1) {
11
    _displayfunction |= LCD_2LINE;
12
  }
13
  _numlines = lines;
14
  _currline = 0;
15
16
  // for some 1 line displays you can select a 10 pixel high font
17
  if ((dotsize != 0) && (lines == 1)) {
18
    _displayfunction |= LCD_5x10DOTS;
19
  }
20
21
  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
22
  // according to datasheet, we need at least 40ms after power rises above 2.7V
23
  // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
24
  delayMicroseconds(50000); // can't use delay, may get called before main!
25
26
  // Now we pull both RS and R/W low to begin commands
27
  config();
28
  
29
  //put the LCD into 4 bit or 8 bit mode
30
  if (! (_displayfunction & LCD_8BITMODE)) {
31
    // this is according to the hitachi HD44780 datasheet
32
    // figure 24, pg 46
33
34
    // we start in 8bit mode, try to set 4 bit mode
35
    write4bits(0x03);
36
    delayMicroseconds(4500); // wait min 4.1ms
37
38
    // second try
39
    write4bits(0x03);
40
    delayMicroseconds(4500); // wait min 4.1ms
41
    
42
    // third go!
43
    write4bits(0x03); 
44
    delayMicroseconds(150);
45
46
    // finally, set to 8-bit interface
47
    write4bits(0x02); 
48
  } else {
49
    // this is according to the hitachi HD44780 datasheet
50
    // page 45 figure 23
51
52
    // Send function set command sequence
53
    command(LCD_FUNCTIONSET | _displayfunction);
54
    delayMicroseconds(4500);  // wait more than 4.1ms
55
56
    // second try
57
    command(LCD_FUNCTIONSET | _displayfunction);
58
    delayMicroseconds(150);
59
60
    // third go
61
    command(LCD_FUNCTIONSET | _displayfunction);
62
  }
63
64
  // finally, set # lines, font size, etc.
65
  command(LCD_FUNCTIONSET | _displayfunction);  
66
67
  // turn the display on with no cursor or blinking default
68
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;  
69
  display();
70
71
  // clear it off
72
  clear();
73
74
  // Initialize to default text direction (for romance languages)
75
  _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
76
  // set the entry mode
77
  command(LCD_ENTRYMODESET | _displaymode);
78
79
}
80
81
/********** high level commands, for the user! */
82
void LiquidCrystalBase::clear()
83
{
84
  command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
85
  delayMicroseconds(2000);  // this command takes a long time!
86
}
87
88
void LiquidCrystalBase::home()
89
{
90
  command(LCD_RETURNHOME);  // set cursor position to zero
91
  delayMicroseconds(2000);  // this command takes a long time!
92
}
93
94
void LiquidCrystalBase::setCursor(byte col, byte row)
95
{
96
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
97
  if ( row > _numlines ) {
98
    row = _numlines-1;    // we count rows starting w/0
99
  }
100
  
101
  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
102
}
103
104
// Turn the display on/off (quickly)
105
void LiquidCrystalBase::noDisplay() {
106
  _displaycontrol &= ~LCD_DISPLAYON;
107
  command(LCD_DISPLAYCONTROL | _displaycontrol);
108
}
109
void LiquidCrystalBase::display() {
110
  _displaycontrol |= LCD_DISPLAYON;
111
  command(LCD_DISPLAYCONTROL | _displaycontrol);
112
}
113
114
// Turns the underline cursor on/off
115
void LiquidCrystalBase::noCursor() {
116
  _displaycontrol &= ~LCD_CURSORON;
117
  command(LCD_DISPLAYCONTROL | _displaycontrol);
118
}
119
void LiquidCrystalBase::cursor() {
120
  _displaycontrol |= LCD_CURSORON;
121
  command(LCD_DISPLAYCONTROL | _displaycontrol);
122
}
123
124
// Turn on and off the blinking cursor
125
void LiquidCrystalBase::noBlink() {
126
  _displaycontrol &= ~LCD_BLINKON;
127
  command(LCD_DISPLAYCONTROL | _displaycontrol);
128
}
129
void LiquidCrystalBase::blink() {
130
  _displaycontrol |= LCD_BLINKON;
131
  command(LCD_DISPLAYCONTROL | _displaycontrol);
132
}
133
134
// These commands scroll the display without changing the RAM
135
void LiquidCrystalBase::scrollDisplayLeft(void) {
136
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
137
}
138
void LiquidCrystalBase::scrollDisplayRight(void) {
139
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
140
}
141
142
// This is for text that flows Left to Right
143
void LiquidCrystalBase::leftToRight(void) {
144
  _displaymode |= LCD_ENTRYLEFT;
145
  command(LCD_ENTRYMODESET | _displaymode);
146
}
147
148
// This is for text that flows Right to Left
149
void LiquidCrystalBase::rightToLeft(void) {
150
  _displaymode &= ~LCD_ENTRYLEFT;
151
  command(LCD_ENTRYMODESET | _displaymode);
152
}
153
154
// This will 'right justify' text from the cursor
155
void LiquidCrystalBase::autoscroll(void) {
156
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
157
  command(LCD_ENTRYMODESET | _displaymode);
158
}
159
160
// This will 'left justify' text from the cursor
161
void LiquidCrystalBase::noAutoscroll(void) {
162
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
163
  command(LCD_ENTRYMODESET | _displaymode);
164
}
165
166
// Allows us to fill the first 8 CGRAM locations
167
// with custom characters
168
void LiquidCrystalBase::createChar(byte location, byte charmap[]) {
169
  location &= 0x7; // we only have 8 locations 0-7
170
  command(LCD_SETCGRAMADDR | (location << 3));
171
  for (int i=0; i<8; i++) {
172
    write(charmap[i]);
173
  }
174
}
175
176
/*********** mid level commands, for sending data/cmds */
177
178
inline void LiquidCrystalBase::command(byte value) {
179
  send(value, LOW);
180
}
181
182
inline void LiquidCrystalBase::write(byte value) {
183
  send(value, HIGH);
184
}
185
186
// When the display powers up, it is configured as follows:
187
//
188
// 1. Display clear
189
// 2. Function set: 
190
//    DL = 1; 8-bit interface data 
191
//    N = 0; 1-line display 
192
//    F = 0; 5x8 dot character font 
193
// 3. Display on/off control: 
194
//    D = 0; Display off 
195
//    C = 0; Cursor off 
196
//    B = 0; Blinking off 
197
// 4. Entry mode set: 
198
//    I/D = 1; Increment by 1 
199
//    S = 0; No shift 
200
//
201
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
202
// can't assume that its in that state when a sketch starts (and the
203
// LiquidCrystal constructor is called).
204
205
LiquidCrystal::LiquidCrystal(byte rs, byte rw, byte enable,
206
             byte d0, byte d1, byte d2, byte d3, byte d4, byte d5, byte d6, byte d7)
207
{
208
  init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
209
}
210
211
LiquidCrystal::LiquidCrystal(byte rs, byte enable,
212
             byte d0, byte d1, byte d2, byte d3, byte d4, byte d5, byte d6, byte d7)
213
{
214
  init(0, rs, -1, enable, d0, d1, d2, d3, d4, d5, d6, d7);
215
}
216
217
LiquidCrystal::LiquidCrystal(byte rs, byte rw, byte enable,
218
             byte d0, byte d1, byte d2, byte d3)
219
{
220
  init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
221
}
222
223
LiquidCrystal::LiquidCrystal(byte rs,  byte enable,
224
             byte d0, byte d1, byte d2, byte d3)
225
{
226
  init(1, rs, -1, enable, d0, d1, d2, d3, 0, 0, 0, 0);
227
}
228
229
void LiquidCrystal::init(byte fourbitmode, byte rs, byte rw, byte enable,
230
                         byte d0, byte d1, byte d2, byte d3, byte d4, byte d5, byte d6, byte d7)
231
{
232
  _rs_pin = rs;
233
  _rw_pin = rw;
234
  _enable_pin = enable;
235
  
236
  _data_pins[0] = d0;
237
  _data_pins[1] = d1;
238
  _data_pins[2] = d2;
239
  _data_pins[3] = d3; 
240
  _data_pins[4] = d4;
241
  _data_pins[5] = d5;
242
  _data_pins[6] = d6;
243
  _data_pins[7] = d7; 
244
245
  pinMode(_rs_pin, OUTPUT);
246
  // we can save 1 pin by not using RW. Indicate by passing -1 instead of pin#
247
  if (_rw_pin != -1) { 
248
    pinMode(_rw_pin, OUTPUT);
249
  }
250
  pinMode(_enable_pin, OUTPUT);
251
  
252
  if (fourbitmode)
253
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
254
  else 
255
    _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
256
  
257
  begin(16, 1);  
258
}
259
260
/************ low level data pushing commands **********/
261
262
void LiquidCrystal::config() {
263
  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
264
  // according to datasheet, we need at least 40ms after power rises above 2.7V
265
  // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
266
  delayMicroseconds(50000); 
267
  // Now we pull both RS and R/W low to begin commands
268
  digitalWrite(_rs_pin, LOW);
269
  digitalWrite(_enable_pin, LOW);
270
  if (_rw_pin != -1) { 
271
    digitalWrite(_rw_pin, LOW);
272
  }
273
}
274
275
// write either command or data, with automatic 4/8-bit selection
276
void LiquidCrystal::send(byte value, byte mode) {
277
  digitalWrite(_rs_pin, mode);
278
279
  // if there is a RW pin indicated, set it low to Write
280
  if (_rw_pin != -1) { 
281
    digitalWrite(_rw_pin, LOW);
282
  }
283
  
284
  if (_displayfunction & LCD_8BITMODE) {
285
    write8bits(value); 
286
  } else {
287
    write4bits(value>>4);
288
    write4bits(value);
289
  }
290
}
291
292
void LiquidCrystal::pulseEnable(void) {
293
  digitalWrite(_enable_pin, LOW);
294
  delayMicroseconds(1);    
295
  digitalWrite(_enable_pin, HIGH);
296
  delayMicroseconds(1);    // enable pulse must be >450ns
297
  digitalWrite(_enable_pin, LOW);
298
  delayMicroseconds(100);   // commands need > 37us to settle
299
}
300
301
void LiquidCrystal::write4bits(byte value) {
302
  for (int i = 0; i < 4; i++) {
303
    pinMode(_data_pins[i], OUTPUT);
304
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
305
  }
306
307
  pulseEnable();
308
}
309
310
void LiquidCrystal::write8bits(byte value) {
311
  for (int i = 0; i < 8; i++) {
312
    pinMode(_data_pins[i], OUTPUT);
313
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
314
  }
315
  
316
  pulseEnable();
317
}
318
319
enum {
320
  MCP_IODIR, MCP_IPOL, MCP_GPINTEN, MCP_DEFVAL, MCP_INTCON, MCP_IOCON,
321
  MCP_GPPU, MCP_INTF, MCP_INTCAP, MCP_GPIO, MCP_OLAT
322
};
323
324
// bits 0..3 and D4..D7, the rest is connected as follows
325
#define MCP_BACKLIGHT   0x80
326
#define MCP_ENABLE      0x40
327
#define MCP_OTHER       0x20
328
#define MCP_REGSEL      0x10
329
330
LiquidCrystalI2C::LiquidCrystalI2C (const PortI2C& p, byte addr)
331
    : device (p, addr) {
332
  _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
333
  begin(16, 2);  
334
}
335
336
void LiquidCrystalI2C::backlight() {
337
    device.send();
338
    device.write(MCP_IODIR);
339
    device.write(0); // IODIR: all outputs
340
    device.stop();
341
}
342
343
void LiquidCrystalI2C::noBacklight() {
344
    device.send();
345
    device.write(MCP_IODIR);
346
    device.write(MCP_BACKLIGHT); // IODIR: all outputs, except backlight
347
    device.stop();
348
}
349
350
/************ low level data pushing commands **********/
351
352
void LiquidCrystalI2C::config() {
353
  // IOCON: SEQOP = 1, ODR = 1, rest zero
354
  device.send();
355
  device.write(MCP_IOCON);
356
  device.write(0x24);
357
  device.stop();
358
  backlight(); // start with backlight on
359
}
360
361
// write either command or data, with automatic 4/8-bit selection
362
void LiquidCrystalI2C::send(byte value, byte mode) {
363
  if (mode != 0)
364
    mode = MCP_REGSEL;
365
  write4bits((value >> 4) | mode);
366
  write4bits((value & 0x0F) | mode);
367
}
368
369
void LiquidCrystalI2C::write4bits(byte value) {
370
  value |= MCP_BACKLIGHT | MCP_ENABLE;
371
  device.send();
372
  device.write(MCP_GPIO);
373
  device.write(value);
374
  device.write(value ^ MCP_ENABLE);
375
  device.write(value);
376
  device.stop();
377
}