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.
7 * Copyright (c) 2012 Gordon Henderson.
8 ***********************************************************************
9 * This file is part of wiringPi:
10 * https://projects.drogon.net/raspberry-pi/wiringpi/
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.
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.
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 ***********************************************************************
42 #define LCD_CLEAR 0x01
44 #define LCD_ENTRY 0x04
46 #define LCD_CDSHIFT 0x10
48 #define LCD_CGRAM 0x40
49 #define LCD_DGRAM 0x80
51 // Bits in the entry register
53 #define LCD_ENTRY_SH 0x01
54 #define LCD_ENTRY_ID 0x02
56 // Bits in the control register
58 #define LCD_BLINK_CTRL 0x01
59 #define LCD_CURSOR_CTRL 0x02
60 #define LCD_DISPLAY_CTRL 0x04
62 // Bits in the function register
64 #define LCD_FUNC_F 0x04
65 #define LCD_FUNC_N 0x08
66 #define LCD_FUNC_DL 0x10
68 #define LCD_CDSHIFT_RL 0x04
72 int bits, rows, cols ;
78 struct lcdDataStruct *lcds [MAX_LCDS] ;
80 static int lcdControl ;
84 static const int rowOff [4] = { 0x00, 0x40, 0x14, 0x54 } ;
89 * Toggle the strobe (Really the "E") pin to the device.
90 * According to the docs, data is latched on the falling edge.
91 *********************************************************************************
94 static void strobe (const struct lcdDataStruct *lcd)
97 // Note timing changes for new version of delayMicroseconds ()
99 digitalWrite (lcd->strbPin, 1) ; delayMicroseconds (50) ;
100 digitalWrite (lcd->strbPin, 0) ; delayMicroseconds (50) ;
106 * Send an data or command byte to the display.
107 *********************************************************************************
110 static void sendDataCmd (const struct lcdDataStruct *lcd, unsigned char data)
112 register unsigned char myData = data ;
113 unsigned char i, d4 ;
117 d4 = (myData >> 4) & 0x0F;
118 for (i = 0 ; i < 4 ; ++i)
120 digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
126 for (i = 0 ; i < 4 ; ++i)
128 digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
134 for (i = 0 ; i < 8 ; ++i)
136 digitalWrite (lcd->dataPins [i], (myData & 1)) ;
146 * Send a command byte to the display
147 *********************************************************************************
150 static void putCommand (const struct lcdDataStruct *lcd, unsigned char command)
152 digitalWrite (lcd->rsPin, 0) ;
153 sendDataCmd (lcd, command) ;
157 static void put4Command (const struct lcdDataStruct *lcd, unsigned char command)
159 register unsigned char myCommand = command ;
160 register unsigned char i ;
162 digitalWrite (lcd->rsPin, 0) ;
164 for (i = 0 ; i < 4 ; ++i)
166 digitalWrite (lcd->dataPins [i], (myCommand & 1)) ;
174 *********************************************************************************
175 * User Callable code below here
176 *********************************************************************************
181 * Home the cursor or clear the screen.
182 *********************************************************************************
185 void lcdHome (const int fd)
187 struct lcdDataStruct *lcd = lcds [fd] ;
189 putCommand (lcd, LCD_HOME) ;
190 lcd->cx = lcd->cy = 0 ;
194 void lcdClear (const int fd)
196 struct lcdDataStruct *lcd = lcds [fd] ;
198 putCommand (lcd, LCD_CLEAR) ;
199 putCommand (lcd, LCD_HOME) ;
200 lcd->cx = lcd->cy = 0 ;
206 * lcdDisplay: lcdCursor: lcdCursorBlink:
207 * Turn the display, cursor, cursor blinking on/off
208 *********************************************************************************
211 void lcdDisplay (const int fd, int state)
213 struct lcdDataStruct *lcd = lcds [fd] ;
216 lcdControl |= LCD_DISPLAY_CTRL ;
218 lcdControl &= ~LCD_DISPLAY_CTRL ;
220 putCommand (lcd, LCD_CTRL | lcdControl) ;
223 void lcdCursor (const int fd, int state)
225 struct lcdDataStruct *lcd = lcds [fd] ;
228 lcdControl |= LCD_CURSOR_CTRL ;
230 lcdControl &= ~LCD_CURSOR_CTRL ;
232 putCommand (lcd, LCD_CTRL | lcdControl) ;
235 void lcdCursorBlink (const int fd, int state)
237 struct lcdDataStruct *lcd = lcds [fd] ;
240 lcdControl |= LCD_BLINK_CTRL ;
242 lcdControl &= ~LCD_BLINK_CTRL ;
244 putCommand (lcd, LCD_CTRL | lcdControl) ;
250 * Send any arbitary command to the display
251 *********************************************************************************
254 void lcdSendCommand (const int fd, unsigned char command)
256 struct lcdDataStruct *lcd = lcds [fd] ;
257 putCommand (lcd, command) ;
263 * Update the position of the cursor on the display.
264 * Ignore invalid locations.
265 *********************************************************************************
268 void lcdPosition (const int fd, int x, int y)
270 struct lcdDataStruct *lcd = lcds [fd] ;
272 if ((x > lcd->cols) || (x < 0))
274 if ((y > lcd->rows) || (y < 0))
277 putCommand (lcd, x + (LCD_DGRAM | rowOff [y])) ;
286 * Defines a new character in the CGRAM
287 *********************************************************************************
290 void lcdCharDef (const int fd, int index, unsigned char data [8])
292 struct lcdDataStruct *lcd = lcds [fd] ;
295 putCommand (lcd, LCD_CGRAM | ((index & 7) << 3)) ;
297 digitalWrite (lcd->rsPin, 1) ;
298 for (i = 0 ; i < 8 ; ++i)
299 sendDataCmd (lcd, data [i]) ;
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 *********************************************************************************
310 void lcdPutchar (const int fd, unsigned char data)
312 struct lcdDataStruct *lcd = lcds [fd] ;
314 digitalWrite (lcd->rsPin, 1) ;
315 sendDataCmd (lcd, data) ;
317 if (++lcd->cx == lcd->cols)
320 if (++lcd->cy == lcd->rows)
323 putCommand (lcd, lcd->cx + (LCD_DGRAM | rowOff [lcd->cy])) ;
330 * Send a string to be displayed on the display
331 *********************************************************************************
334 void lcdPuts (const int fd, const char *string)
337 lcdPutchar (fd, *string++) ;
343 * Printf to an LCD display
344 *********************************************************************************
347 void lcdPrintf (const int fd, const char *message, ...)
352 va_start (argp, message) ;
353 vsnprintf (buffer, 1023, message, argp) ;
356 lcdPuts (fd, buffer) ;
362 * Take a lot of parameters and initialise the LCD, and return a handle to
363 * that LCD, or -1 if any error.
364 *********************************************************************************
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)
372 static int initialised = 0 ;
377 struct lcdDataStruct *lcd ;
379 if (initialised == 0)
382 for (i = 0 ; i < MAX_LCDS ; ++i)
386 // Simple sanity checks
388 if (! ((bits == 4) || (bits == 8)))
391 if ((rows < 0) || (rows > 20))
394 if ((cols < 0) || (cols > 20))
399 for (i = 0 ; i < MAX_LCDS ; ++i)
401 if (lcds [i] == NULL)
411 lcd = (struct lcdDataStruct *)malloc (sizeof (struct lcdDataStruct)) ;
416 lcd->strbPin = strb ;
417 lcd->bits = 8 ; // For now - we'll set it properly later.
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 ;
434 digitalWrite (lcd->rsPin, 0) ; pinMode (lcd->rsPin, OUTPUT) ;
435 digitalWrite (lcd->strbPin, 0) ; pinMode (lcd->strbPin, OUTPUT) ;
437 for (i = 0 ; i < bits ; ++i)
439 digitalWrite (lcd->dataPins [i], 0) ;
440 pinMode (lcd->dataPins [i], OUTPUT) ;
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:
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...
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.
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) ;
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) ;
481 putCommand (lcd, func) ; delay (35) ;
484 // Rest of the initialisation sequence
486 lcdDisplay (lcdFd, TRUE) ;
487 lcdCursor (lcdFd, FALSE) ;
488 lcdCursorBlink (lcdFd, FALSE) ;
491 putCommand (lcd, LCD_ENTRY | LCD_ENTRY_ID) ;
492 putCommand (lcd, LCD_CDSHIFT | LCD_CDSHIFT_RL) ;