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 ***********************************************************************
37 #define LCD_CLEAR 0x01
39 #define LCD_ENTRY 0x04
40 #define LCD_ON_OFF 0x08
41 #define LCD_CDSHIFT 0x10
43 #define LCD_CGRAM 0x40
44 #define LCD_DGRAM 0x80
46 #define LCD_ENTRY_SH 0x01
47 #define LCD_ENTRY_ID 0x02
49 #define LCD_ON_OFF_B 0x01
50 #define LCD_ON_OFF_C 0x02
51 #define LCD_ON_OFF_D 0x04
53 #define LCD_FUNC_F 0x04
54 #define LCD_FUNC_N 0x08
55 #define LCD_FUNC_DL 0x10
57 #define LCD_CDSHIFT_RL 0x04
61 uint8_t bits, rows, cols ;
62 uint8_t rsPin, strbPin ;
63 uint8_t dataPins [8] ;
66 struct lcdDataStruct *lcds [MAX_LCDS] ;
71 * Toggle the strobe (Really the "E") pin to the device.
72 * According to the docs, data is latched on the falling edge.
73 *********************************************************************************
76 static void strobe (struct lcdDataStruct *lcd)
79 // Note timing changes for new version of delayMicroseconds ()
81 digitalWrite (lcd->strbPin, 1) ; delayMicroseconds (50) ;
82 digitalWrite (lcd->strbPin, 0) ; delayMicroseconds (50) ;
88 * Send an data or command byte to the display.
89 *********************************************************************************
92 static void sendDataCmd (struct lcdDataStruct *lcd, uint8_t data)
98 d4 = (data >> 4) & 0x0F;
99 for (i = 0 ; i < 4 ; ++i)
101 digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
107 for (i = 0 ; i < 4 ; ++i)
109 digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
115 for (i = 0 ; i < 8 ; ++i)
117 digitalWrite (lcd->dataPins [i], (data & 1)) ;
127 * Send a command byte to the display
128 *********************************************************************************
131 static void putCommand (struct lcdDataStruct *lcd, uint8_t command)
133 digitalWrite (lcd->rsPin, 0) ;
134 sendDataCmd (lcd, command) ;
137 static void put4Command (struct lcdDataStruct *lcd, uint8_t command)
141 digitalWrite (lcd->rsPin, 0) ;
143 for (i = 0 ; i < 4 ; ++i)
145 digitalWrite (lcd->dataPins [i], (command & 1)) ;
153 *********************************************************************************
154 * User Code below here
155 *********************************************************************************
160 * Home the cursor or clear the screen.
161 *********************************************************************************
164 void lcdHome (int fd)
166 struct lcdDataStruct *lcd = lcds [fd] ;
167 putCommand (lcd, LCD_HOME) ;
170 void lcdClear (int fd)
172 struct lcdDataStruct *lcd = lcds [fd] ;
173 putCommand (lcd, LCD_CLEAR) ;
179 * Update the position of the cursor on the display
180 *********************************************************************************
184 void lcdPosition (int fd, int x, int y)
186 static uint8_t rowOff [4] = { 0x00, 0x40, 0x14, 0x54 } ;
187 struct lcdDataStruct *lcd = lcds [fd] ;
189 putCommand (lcd, x + (LCD_DGRAM | rowOff [y])) ;
195 * Send a data byte to be displayed on the display
196 *********************************************************************************
199 void lcdPutchar (int fd, uint8_t data)
201 struct lcdDataStruct *lcd = lcds [fd] ;
203 digitalWrite (lcd->rsPin, 1) ;
204 sendDataCmd (lcd, data) ;
210 * Send a string to be displayed on the display
211 *********************************************************************************
214 void lcdPuts (int fd, char *string)
217 lcdPutchar (fd, *string++) ;
223 * Printf to an LCD display
224 *********************************************************************************
227 void lcdPrintf (int fd, char *message, ...)
232 va_start (argp, message) ;
233 vsnprintf (buffer, 1023, message, argp) ;
236 lcdPuts (fd, buffer) ;
242 * Take a lot of parameters and initialise the LCD, and return a handle to
243 * that LCD, or -1 if any error.
244 *********************************************************************************
247 int lcdInit (int rows, int cols, int bits, int rs, int strb,
248 int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
250 static int initialised = 0 ;
255 struct lcdDataStruct *lcd ;
257 if (initialised == 0)
260 for (i = 0 ; i < MAX_LCDS ; ++i)
264 // Simple sanity checks
266 if (! ((bits == 4) || (bits == 8)))
269 if ((rows < 0) || (rows > 20))
272 if ((cols < 0) || (cols > 20))
277 for (i = 0 ; i < MAX_LCDS ; ++i)
279 if (lcds [i] == NULL)
289 lcd = malloc (sizeof (struct lcdDataStruct)) ;
294 lcd->strbPin = strb ;
295 lcd->bits = 8 ; // For now - we'll set it properly later.
299 lcd->dataPins [0] = d0 ;
300 lcd->dataPins [1] = d1 ;
301 lcd->dataPins [2] = d2 ;
302 lcd->dataPins [3] = d3 ;
303 lcd->dataPins [4] = d4 ;
304 lcd->dataPins [5] = d5 ;
305 lcd->dataPins [6] = d6 ;
306 lcd->dataPins [7] = d7 ;
310 digitalWrite (lcd->rsPin, 0) ; pinMode (lcd->rsPin, OUTPUT) ;
311 digitalWrite (lcd->strbPin, 0) ; pinMode (lcd->strbPin, OUTPUT) ;
313 for (i = 0 ; i < bits ; ++i)
315 digitalWrite (lcd->dataPins [i], 0) ;
316 pinMode (lcd->dataPins [i], OUTPUT) ;
322 // OK. This is a PIG and it's not at all obvious from the documentation I had,
323 // so I guess some others have worked through either with better documentation
324 // or more trial and error... Anyway here goes:
326 // It seems that the controller needs to see the FUNC command at least 3 times
327 // consecutively - in 8-bit mode. If you're only using 8-bit mode, then it appears
328 // that you can get away with one func-set, however I'd not rely on it...
330 // So to set 4-bit mode, you need to send the commands one nibble at a time,
331 // the same three times, but send the command to set it into 8-bit mode those
332 // three times, then send a final 4th command to set it into 4-bit mode, and only
333 // then can you flip the switch for the rest of the library to work in 4-bit
334 // mode which sends the commands as 2 x 4-bit values.
338 func = LCD_FUNC | LCD_FUNC_DL ; // Set 8-bit mode 3 times
339 put4Command (lcd, func >> 4) ; delay (35) ;
340 put4Command (lcd, func >> 4) ; delay (35) ;
341 put4Command (lcd, func >> 4) ; delay (35) ;
342 func = LCD_FUNC ; // 4th set: 4-bit mode
343 put4Command (lcd, func >> 4) ; delay (35) ;
348 func = LCD_FUNC | LCD_FUNC_DL ;
349 putCommand (lcd, func ) ; delay (35) ;
350 putCommand (lcd, func ) ; delay (35) ;
351 putCommand (lcd, func ) ; delay (35) ;
357 putCommand (lcd, func) ; delay (35) ;
360 // Rest of the initialisation sequence
362 putCommand (lcd, LCD_ON_OFF | LCD_ON_OFF_D) ; delay (2) ;
363 putCommand (lcd, LCD_ENTRY | LCD_ENTRY_ID) ; delay (2) ;
364 putCommand (lcd, LCD_CDSHIFT | LCD_CDSHIFT_RL) ; delay (2) ;
365 putCommand (lcd, LCD_CLEAR) ; delay (5) ;