Statistics
| Branch: | Revision:

ddr4s / fw / wiringPi / devLib / lcd.c @ 32:cadb9025f1e0

History | View | Annotate | Download (11.3 KB)

1
/*
2
 * lcd.c:
3
 *        Text-based LCD driver.
4
 *        This is designed to drive the parallel interface LCD drivers
5
 *        based in the Hitachi HD44780U controller and compatables.
6
 *
7
 * Copyright (c) 2012 Gordon Henderson.
8
 ***********************************************************************
9
 * This file is part of wiringPi:
10
 *        https://projects.drogon.net/raspberry-pi/wiringpi/
11
 *
12
 *    wiringPi is free software: you can redistribute it and/or modify
13
 *    it under the terms of the GNU Lesser General Public License as published by
14
 *    the Free Software Foundation, either version 3 of the License, or
15
 *    (at your option) any later version.
16
 *
17
 *    wiringPi is distributed in the hope that it will be useful,
18
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 *    GNU Lesser General Public License for more details.
21
 *
22
 *    You should have received a copy of the GNU Lesser General Public License
23
 *    along with wiringPi.  If not, see <http://www.gnu.org/licenses/>.
24
 ***********************************************************************
25
 */
26

    
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <stdarg.h>
30

    
31
#include <wiringPi.h>
32

    
33
#include "lcd.h"
34

    
35
#ifndef        TRUE
36
#  define        TRUE        (1==1)
37
#  define        FALSE        (1==2)
38
#endif
39

    
40
// HD44780U Commands
41

    
42
#define        LCD_CLEAR        0x01
43
#define        LCD_HOME        0x02
44
#define        LCD_ENTRY        0x04
45
#define        LCD_CTRL        0x08
46
#define        LCD_CDSHIFT        0x10
47
#define        LCD_FUNC        0x20
48
#define        LCD_CGRAM        0x40
49
#define        LCD_DGRAM        0x80
50

    
51
// Bits in the entry register
52

    
53
#define        LCD_ENTRY_SH                0x01
54
#define        LCD_ENTRY_ID                0x02
55

    
56
// Bits in the control register
57

    
58
#define        LCD_BLINK_CTRL                0x01
59
#define        LCD_CURSOR_CTRL                0x02
60
#define        LCD_DISPLAY_CTRL        0x04
61

    
62
// Bits in the function register
63

    
64
#define        LCD_FUNC_F        0x04
65
#define        LCD_FUNC_N        0x08
66
#define        LCD_FUNC_DL        0x10
67

    
68
#define        LCD_CDSHIFT_RL        0x04
69

    
70
struct lcdDataStruct
71
{
72
  int bits, rows, cols ;
73
  int rsPin, strbPin ;
74
  int dataPins [8] ;
75
  int cx, cy ;
76
} ;
77

    
78
struct lcdDataStruct *lcds [MAX_LCDS] ;
79

    
80
static int lcdControl ;
81

    
82
// Row offsets
83

    
84
static const int rowOff [4] = { 0x00, 0x40, 0x14, 0x54 } ;
85

    
86

    
87
/*
88
 * strobe:
89
 *        Toggle the strobe (Really the "E") pin to the device.
90
 *        According to the docs, data is latched on the falling edge.
91
 *********************************************************************************
92
 */
93

    
94
static void strobe (const struct lcdDataStruct *lcd)
95
{
96

    
97
// Note timing changes for new version of delayMicroseconds ()
98

    
99
  digitalWrite (lcd->strbPin, 1) ; delayMicroseconds (50) ;
100
  digitalWrite (lcd->strbPin, 0) ; delayMicroseconds (50) ;
101
}
102

    
103

    
104
/*
105
 * sentDataCmd:
106
 *        Send an data or command byte to the display.
107
 *********************************************************************************
108
 */
109

    
110
static void sendDataCmd (const struct lcdDataStruct *lcd, unsigned char data)
111
{
112
  register unsigned char myData = data ;
113
  unsigned char          i, d4 ;
114

    
115
  if (lcd->bits == 4)
116
  {
117
    d4 = (myData >> 4) & 0x0F;
118
    for (i = 0 ; i < 4 ; ++i)
119
    {
120
      digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
121
      d4 >>= 1 ;
122
    }
123
    strobe (lcd) ;
124

    
125
    d4 = myData & 0x0F ;
126
    for (i = 0 ; i < 4 ; ++i)
127
    {
128
      digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
129
      d4 >>= 1 ;
130
    }
131
  }
132
  else
133
  {
134
    for (i = 0 ; i < 8 ; ++i)
135
    {
136
      digitalWrite (lcd->dataPins [i], (myData & 1)) ;
137
      myData >>= 1 ;
138
    }
139
  }
140
  strobe (lcd) ;
141
}
142

    
143

    
144
/*
145
 * putCommand:
146
 *        Send a command byte to the display
147
 *********************************************************************************
148
 */
149

    
150
static void putCommand (const struct lcdDataStruct *lcd, unsigned char command)
151
{
152
  digitalWrite (lcd->rsPin,   0) ;
153
  sendDataCmd  (lcd, command) ;
154
  delay (2) ;
155
}
156

    
157
static void put4Command (const struct lcdDataStruct *lcd, unsigned char command)
158
{
159
  register unsigned char myCommand = command ;
160
  register unsigned char i ;
161

    
162
  digitalWrite (lcd->rsPin,   0) ;
163

    
164
  for (i = 0 ; i < 4 ; ++i)
165
  {
166
    digitalWrite (lcd->dataPins [i], (myCommand & 1)) ;
167
    myCommand >>= 1 ;
168
  }
169
  strobe (lcd) ;
170
}
171

    
172

    
173
/*
174
 *********************************************************************************
175
 * User Callable code below here
176
 *********************************************************************************
177
 */
178

    
179
/*
180
 * lcdHome: lcdClear:
181
 *        Home the cursor or clear the screen.
182
 *********************************************************************************
183
 */
184

    
185
void lcdHome (const int fd)
186
{
187
  struct lcdDataStruct *lcd = lcds [fd] ;
188

    
189
  putCommand (lcd, LCD_HOME) ;
190
  lcd->cx = lcd->cy = 0 ;
191
  delay (5) ;
192
}
193

    
194
void lcdClear (const int fd)
195
{
196
  struct lcdDataStruct *lcd = lcds [fd] ;
197

    
198
  putCommand (lcd, LCD_CLEAR) ;
199
  putCommand (lcd, LCD_HOME) ;
200
  lcd->cx = lcd->cy = 0 ;
201
  delay (5) ;
202
}
203

    
204

    
205
/*
206
 * lcdDisplay: lcdCursor: lcdCursorBlink:
207
 *        Turn the display, cursor, cursor blinking on/off
208
 *********************************************************************************
209
 */
210

    
211
void lcdDisplay (const int fd, int state)
212
{
213
  struct lcdDataStruct *lcd = lcds [fd] ;
214

    
215
  if (state)
216
    lcdControl |=  LCD_DISPLAY_CTRL ;
217
  else
218
    lcdControl &= ~LCD_DISPLAY_CTRL ;
219

    
220
  putCommand (lcd, LCD_CTRL | lcdControl) ; 
221
}
222

    
223
void lcdCursor (const int fd, int state)
224
{
225
  struct lcdDataStruct *lcd = lcds [fd] ;
226

    
227
  if (state)
228
    lcdControl |=  LCD_CURSOR_CTRL ;
229
  else
230
    lcdControl &= ~LCD_CURSOR_CTRL ;
231

    
232
  putCommand (lcd, LCD_CTRL | lcdControl) ; 
233
}
234

    
235
void lcdCursorBlink (const int fd, int state)
236
{
237
  struct lcdDataStruct *lcd = lcds [fd] ;
238

    
239
  if (state)
240
    lcdControl |=  LCD_BLINK_CTRL ;
241
  else
242
    lcdControl &= ~LCD_BLINK_CTRL ;
243

    
244
  putCommand (lcd, LCD_CTRL | lcdControl) ; 
245
}
246

    
247

    
248
/*
249
 * lcdSendCommand:
250
 *        Send any arbitary command to the display
251
 *********************************************************************************
252
 */
253

    
254
void lcdSendCommand (const int fd, unsigned char command)
255
{
256
  struct lcdDataStruct *lcd = lcds [fd] ;
257
  putCommand (lcd, command) ;
258
}
259

    
260

    
261
/*
262
 * lcdPosition:
263
 *        Update the position of the cursor on the display.
264
 *        Ignore invalid locations.
265
 *********************************************************************************
266
 */
267

    
268
void lcdPosition (const int fd, int x, int y)
269
{
270
  struct lcdDataStruct *lcd = lcds [fd] ;
271

    
272
  if ((x > lcd->cols) || (x < 0))
273
    return ;
274
  if ((y > lcd->rows) || (y < 0))
275
    return ;
276

    
277
  putCommand (lcd, x + (LCD_DGRAM | rowOff [y])) ;
278

    
279
  lcd->cx = x ;
280
  lcd->cy = y ;
281
}
282

    
283

    
284
/*
285
 * lcdCharDef:
286
 *        Defines a new character in the CGRAM
287
 *********************************************************************************
288
 */
289

    
290
void lcdCharDef (const int fd, int index, unsigned char data [8])
291
{
292
  struct lcdDataStruct *lcd = lcds [fd] ;
293
  int i ;
294

    
295
  putCommand (lcd, LCD_CGRAM | ((index & 7) << 3)) ;
296

    
297
  digitalWrite (lcd->rsPin, 1) ;
298
  for (i = 0 ; i < 8 ; ++i)
299
    sendDataCmd (lcd, data [i]) ;
300
}
301

    
302

    
303
/*
304
 * lcdPutchar:
305
 *        Send a data byte to be displayed on the display. We implement a very
306
 *        simple terminal here - with line wrapping, but no scrolling. Yet.
307
 *********************************************************************************
308
 */
309

    
310
void lcdPutchar (const int fd, unsigned char data)
311
{
312
  struct lcdDataStruct *lcd = lcds [fd] ;
313

    
314
  digitalWrite (lcd->rsPin, 1) ;
315
  sendDataCmd  (lcd, data) ;
316

    
317
  if (++lcd->cx == lcd->cols)
318
  {
319
    lcd->cx = 0 ;
320
    if (++lcd->cy == lcd->rows)
321
      lcd->cy = 0 ;
322
    
323
    putCommand (lcd, lcd->cx + (LCD_DGRAM | rowOff [lcd->cy])) ;
324
  }
325
}
326

    
327

    
328
/*
329
 * lcdPuts:
330
 *        Send a string to be displayed on the display
331
 *********************************************************************************
332
 */
333

    
334
void lcdPuts (const int fd, const char *string)
335
{
336
  while (*string)
337
    lcdPutchar (fd, *string++) ;
338
}
339

    
340

    
341
/*
342
 * lcdPrintf:
343
 *        Printf to an LCD display
344
 *********************************************************************************
345
 */
346

    
347
void lcdPrintf (const int fd, const char *message, ...)
348
{
349
  va_list argp ;
350
  char buffer [1024] ;
351

    
352
  va_start (argp, message) ;
353
    vsnprintf (buffer, 1023, message, argp) ;
354
  va_end (argp) ;
355

    
356
  lcdPuts (fd, buffer) ;
357
}
358

    
359

    
360
/*
361
 * lcdInit:
362
 *        Take a lot of parameters and initialise the LCD, and return a handle to
363
 *        that LCD, or -1 if any error.
364
 *********************************************************************************
365
 */
366

    
367
int lcdInit (const int rows, const int cols, const int bits,
368
        const int rs, const int strb,
369
        const int d0, const int d1, const int d2, const int d3, const int d4,
370
        const int d5, const int d6, const int d7)
371
{
372
  static int initialised = 0 ;
373

    
374
  unsigned char func ;
375
  int i ;
376
  int lcdFd = -1 ;
377
  struct lcdDataStruct *lcd ;
378

    
379
  if (initialised == 0)
380
  {
381
    initialised = 1 ;
382
    for (i = 0 ; i < MAX_LCDS ; ++i)
383
      lcds [i] = NULL ;
384
  }
385

    
386
// Simple sanity checks
387

    
388
  if (! ((bits == 4) || (bits == 8)))
389
    return -1 ;
390

    
391
  if ((rows < 0) || (rows > 20))
392
    return -1 ;
393

    
394
  if ((cols < 0) || (cols > 20))
395
    return -1 ;
396

    
397
// Create a new LCD:
398

    
399
  for (i = 0 ; i < MAX_LCDS ; ++i)
400
  {
401
    if (lcds [i] == NULL)
402
    {
403
      lcdFd = i ;
404
      break ;
405
    }
406
  }
407

    
408
  if (lcdFd == -1)
409
    return -1 ;
410

    
411
  lcd = (struct lcdDataStruct *)malloc (sizeof (struct lcdDataStruct)) ;
412
  if (lcd == NULL)
413
    return -1 ;
414

    
415
  lcd->rsPin   = rs ;
416
  lcd->strbPin = strb ;
417
  lcd->bits    = 8 ;                // For now - we'll set it properly later.
418
  lcd->rows    = rows ;
419
  lcd->cols    = cols ;
420
  lcd->cx      = 0 ;
421
  lcd->cy      = 0 ;
422

    
423
  lcd->dataPins [0] = d0 ;
424
  lcd->dataPins [1] = d1 ;
425
  lcd->dataPins [2] = d2 ;
426
  lcd->dataPins [3] = d3 ;
427
  lcd->dataPins [4] = d4 ;
428
  lcd->dataPins [5] = d5 ;
429
  lcd->dataPins [6] = d6 ;
430
  lcd->dataPins [7] = d7 ;
431

    
432
  lcds [lcdFd] = lcd ;
433

    
434
  digitalWrite (lcd->rsPin,   0) ; pinMode (lcd->rsPin,   OUTPUT) ;
435
  digitalWrite (lcd->strbPin, 0) ; pinMode (lcd->strbPin, OUTPUT) ;
436

    
437
  for (i = 0 ; i < bits ; ++i)
438
  {
439
    digitalWrite (lcd->dataPins [i], 0) ;
440
    pinMode      (lcd->dataPins [i], OUTPUT) ;
441
  }
442
  delay (35) ; // mS
443

    
444

    
445
// 4-bit mode?
446
//        OK. This is a PIG and it's not at all obvious from the documentation I had,
447
//        so I guess some others have worked through either with better documentation
448
//        or more trial and error... Anyway here goes:
449
//
450
//        It seems that the controller needs to see the FUNC command at least 3 times
451
//        consecutively - in 8-bit mode. If you're only using 8-bit mode, then it appears
452
//        that you can get away with one func-set, however I'd not rely on it...
453
//
454
//        So to set 4-bit mode, you need to send the commands one nibble at a time,
455
//        the same three times, but send the command to set it into 8-bit mode those
456
//        three times, then send a final 4th command to set it into 4-bit mode, and only
457
//        then can you flip the switch for the rest of the library to work in 4-bit
458
//        mode which sends the commands as 2 x 4-bit values.
459

    
460
  if (bits == 4)
461
  {
462
    func = LCD_FUNC | LCD_FUNC_DL ;                        // Set 8-bit mode 3 times
463
    put4Command (lcd, func >> 4) ; delay (35) ;
464
    put4Command (lcd, func >> 4) ; delay (35) ;
465
    put4Command (lcd, func >> 4) ; delay (35) ;
466
    func = LCD_FUNC ;                                        // 4th set: 4-bit mode
467
    put4Command (lcd, func >> 4) ; delay (35) ;
468
    lcd->bits = 4 ;
469
  }
470
  else
471
  {
472
    func = LCD_FUNC | LCD_FUNC_DL ;
473
    putCommand  (lcd, func     ) ; delay (35) ;
474
    putCommand  (lcd, func     ) ; delay (35) ;
475
    putCommand  (lcd, func     ) ; delay (35) ;
476
  }
477

    
478
  if (lcd->rows > 1)
479
  {
480
    func |= LCD_FUNC_N ;
481
    putCommand (lcd, func) ; delay (35) ;
482
  }
483

    
484
// Rest of the initialisation sequence
485

    
486
  lcdDisplay     (lcdFd, TRUE) ;
487
  lcdCursor      (lcdFd, FALSE) ;
488
  lcdCursorBlink (lcdFd, FALSE) ;
489
  lcdClear       (lcdFd) ;
490

    
491
  putCommand (lcd, LCD_ENTRY   | LCD_ENTRY_ID) ;
492
  putCommand (lcd, LCD_CDSHIFT | LCD_CDSHIFT_RL) ;
493

    
494
  return lcdFd ;
495
}