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 * Send any arbitary command to the display
180 *********************************************************************************
183 void lcdSendCommand (int fd, uint8_t command)
185 struct lcdDataStruct *lcd = lcds [fd] ;
186 putCommand (lcd, command) ;
191 * Update the position of the cursor on the display
192 *********************************************************************************
196 void lcdPosition (int fd, int x, int y)
198 static uint8_t rowOff [4] = { 0x00, 0x40, 0x14, 0x54 } ;
199 struct lcdDataStruct *lcd = lcds [fd] ;
201 putCommand (lcd, x + (LCD_DGRAM | rowOff [y])) ;
207 * Send a data byte to be displayed on the display
208 *********************************************************************************
211 void lcdPutchar (int fd, uint8_t data)
213 struct lcdDataStruct *lcd = lcds [fd] ;
215 digitalWrite (lcd->rsPin, 1) ;
216 sendDataCmd (lcd, data) ;
222 * Send a string to be displayed on the display
223 *********************************************************************************
226 void lcdPuts (int fd, char *string)
229 lcdPutchar (fd, *string++) ;
235 * Printf to an LCD display
236 *********************************************************************************
239 void lcdPrintf (int fd, char *message, ...)
244 va_start (argp, message) ;
245 vsnprintf (buffer, 1023, message, argp) ;
248 lcdPuts (fd, buffer) ;
254 * Take a lot of parameters and initialise the LCD, and return a handle to
255 * that LCD, or -1 if any error.
256 *********************************************************************************
259 int lcdInit (int rows, int cols, int bits, int rs, int strb,
260 int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
262 static int initialised = 0 ;
267 struct lcdDataStruct *lcd ;
269 if (initialised == 0)
272 for (i = 0 ; i < MAX_LCDS ; ++i)
276 // Simple sanity checks
278 if (! ((bits == 4) || (bits == 8)))
281 if ((rows < 0) || (rows > 20))
284 if ((cols < 0) || (cols > 20))
289 for (i = 0 ; i < MAX_LCDS ; ++i)
291 if (lcds [i] == NULL)
301 lcd = malloc (sizeof (struct lcdDataStruct)) ;
306 lcd->strbPin = strb ;
307 lcd->bits = 8 ; // For now - we'll set it properly later.
311 lcd->dataPins [0] = d0 ;
312 lcd->dataPins [1] = d1 ;
313 lcd->dataPins [2] = d2 ;
314 lcd->dataPins [3] = d3 ;
315 lcd->dataPins [4] = d4 ;
316 lcd->dataPins [5] = d5 ;
317 lcd->dataPins [6] = d6 ;
318 lcd->dataPins [7] = d7 ;
322 digitalWrite (lcd->rsPin, 0) ; pinMode (lcd->rsPin, OUTPUT) ;
323 digitalWrite (lcd->strbPin, 0) ; pinMode (lcd->strbPin, OUTPUT) ;
325 for (i = 0 ; i < bits ; ++i)
327 digitalWrite (lcd->dataPins [i], 0) ;
328 pinMode (lcd->dataPins [i], OUTPUT) ;
334 // OK. This is a PIG and it's not at all obvious from the documentation I had,
335 // so I guess some others have worked through either with better documentation
336 // or more trial and error... Anyway here goes:
338 // It seems that the controller needs to see the FUNC command at least 3 times
339 // consecutively - in 8-bit mode. If you're only using 8-bit mode, then it appears
340 // that you can get away with one func-set, however I'd not rely on it...
342 // So to set 4-bit mode, you need to send the commands one nibble at a time,
343 // the same three times, but send the command to set it into 8-bit mode those
344 // three times, then send a final 4th command to set it into 4-bit mode, and only
345 // then can you flip the switch for the rest of the library to work in 4-bit
346 // mode which sends the commands as 2 x 4-bit values.
350 func = LCD_FUNC | LCD_FUNC_DL ; // Set 8-bit mode 3 times
351 put4Command (lcd, func >> 4) ; delay (35) ;
352 put4Command (lcd, func >> 4) ; delay (35) ;
353 put4Command (lcd, func >> 4) ; delay (35) ;
354 func = LCD_FUNC ; // 4th set: 4-bit mode
355 put4Command (lcd, func >> 4) ; delay (35) ;
360 func = LCD_FUNC | LCD_FUNC_DL ;
361 putCommand (lcd, func ) ; delay (35) ;
362 putCommand (lcd, func ) ; delay (35) ;
363 putCommand (lcd, func ) ; delay (35) ;
369 putCommand (lcd, func) ; delay (35) ;
372 // Rest of the initialisation sequence
374 putCommand (lcd, LCD_ON_OFF | LCD_ON_OFF_D) ; delay (2) ;
375 putCommand (lcd, LCD_ENTRY | LCD_ENTRY_ID) ; delay (2) ;
376 putCommand (lcd, LCD_CDSHIFT | LCD_CDSHIFT_RL) ; delay (2) ;
377 putCommand (lcd, LCD_CLEAR) ; delay (5) ;