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)
78 digitalWrite (lcd->strbPin, 1) ; delayMicroseconds (1) ;
79 digitalWrite (lcd->strbPin, 0) ; delayMicroseconds (50) ;
85 * Send an data or command byte to the display.
86 *********************************************************************************
89 static void sendDataCmd (struct lcdDataStruct *lcd, uint8_t data)
95 d4 = (data >> 4) & 0x0F;
96 for (i = 0 ; i < 4 ; ++i)
98 digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
104 for (i = 0 ; i < 4 ; ++i)
106 digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
112 for (i = 0 ; i < 8 ; ++i)
114 digitalWrite (lcd->dataPins [i], (data & 1)) ;
124 * Send a command byte to the display
125 *********************************************************************************
128 static void putCommand (struct lcdDataStruct *lcd, uint8_t command)
130 digitalWrite (lcd->rsPin, 0) ;
131 sendDataCmd (lcd, command) ;
134 static void put4Command (struct lcdDataStruct *lcd, uint8_t command)
138 digitalWrite (lcd->rsPin, 0) ;
140 for (i = 0 ; i < 4 ; ++i)
142 digitalWrite (lcd->dataPins [i], (command & 1)) ;
150 *********************************************************************************
151 * User Code below here
152 *********************************************************************************
157 * Home the cursor or clear the screen.
158 *********************************************************************************
161 void lcdHome (int fd)
163 struct lcdDataStruct *lcd = lcds [fd] ;
164 putCommand (lcd, LCD_HOME) ;
167 void lcdClear (int fd)
169 struct lcdDataStruct *lcd = lcds [fd] ;
170 putCommand (lcd, LCD_CLEAR) ;
176 * Update the position of the cursor on the display
177 *********************************************************************************
181 void lcdPosition (int fd, int x, int y)
183 static uint8_t rowOff [4] = { 0x00, 0x40, 0x14, 0x54 } ;
184 struct lcdDataStruct *lcd = lcds [fd] ;
186 putCommand (lcd, x + (LCD_DGRAM | rowOff [y])) ;
192 * Send a data byte to be displayed on the display
193 *********************************************************************************
196 void lcdPutchar (int fd, uint8_t data)
198 struct lcdDataStruct *lcd = lcds [fd] ;
200 digitalWrite (lcd->rsPin, 1) ;
201 sendDataCmd (lcd, data) ;
207 * Send a string to be displayed on the display
208 *********************************************************************************
211 void lcdPuts (int fd, char *string)
214 lcdPutchar (fd, *string++) ;
220 * Printf to an LCD display
221 *********************************************************************************
224 void lcdPrintf (int fd, char *message, ...)
229 va_start (argp, message) ;
230 vsnprintf (buffer, 1023, message, argp) ;
233 lcdPuts (fd, buffer) ;
239 * Take a lot of parameters and initialise the LCD, and return a handle to
240 * that LCD, or -1 if any error.
241 *********************************************************************************
244 int lcdInit (int rows, int cols, int bits, int rs, int strb,
245 int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
247 static int initialised = 0 ;
252 struct lcdDataStruct *lcd ;
254 if (initialised == 0)
257 for (i = 0 ; i < MAX_LCDS ; ++i)
261 // Simple sanity checks
263 if (! ((bits == 4) || (bits == 8)))
266 if ((rows < 0) || (rows > 20))
269 if ((cols < 0) || (cols > 20))
274 for (i = 0 ; i < MAX_LCDS ; ++i)
276 if (lcds [i] == NULL)
286 lcd = malloc (sizeof (struct lcdDataStruct)) ;
291 lcd->strbPin = strb ;
292 lcd->bits = 8 ; // For now - we'll set it properly later.
296 lcd->dataPins [0] = d0 ;
297 lcd->dataPins [1] = d1 ;
298 lcd->dataPins [2] = d2 ;
299 lcd->dataPins [3] = d3 ;
300 lcd->dataPins [4] = d4 ;
301 lcd->dataPins [5] = d5 ;
302 lcd->dataPins [6] = d6 ;
303 lcd->dataPins [7] = d7 ;
307 digitalWrite (lcd->rsPin, 0) ; pinMode (lcd->rsPin, OUTPUT) ;
308 digitalWrite (lcd->strbPin, 0) ; pinMode (lcd->strbPin, OUTPUT) ;
310 for (i = 0 ; i < bits ; ++i)
312 digitalWrite (lcd->dataPins [i], 0) ;
313 pinMode (lcd->dataPins [i], OUTPUT) ;
319 // OK. This is a PIG and it's not at all obvious from the documentation I had,
320 // so I guess some others have worked through either with better documentation
321 // or more trial and error... Anyway here goes:
323 // It seems that the controller needs to see the FUNC command at least 3 times
324 // consecutively - in 8-bit mode. If you're only using 8-bit mode, then it appears
325 // that you can get away with one func-set, however I'd not rely on it...
327 // So to set 4-bit mode, you need to send the commands one nibble at a time,
328 // the same three times, but send the command to set it into 8-bit mode those
329 // three times, then send a final 4th command to set it into 4-bit mode, and only
330 // then can you flip the switch for the rest of the library to work in 4-bit
331 // mode which sends the commands as 2 x 4-bit values.
335 func = LCD_FUNC | LCD_FUNC_DL ; // Set 8-bit mode 3 times
336 put4Command (lcd, func >> 4) ; delay (35) ;
337 put4Command (lcd, func >> 4) ; delay (35) ;
338 put4Command (lcd, func >> 4) ; delay (35) ;
339 func = LCD_FUNC ; // 4th set: 4-bit mode
340 put4Command (lcd, func >> 4) ; delay (35) ;
345 func = LCD_FUNC | LCD_FUNC_DL ;
346 putCommand (lcd, func ) ; delay (35) ;
347 putCommand (lcd, func ) ; delay (35) ;
348 putCommand (lcd, func ) ; delay (35) ;
354 putCommand (lcd, func) ; delay (35) ;
357 // Rest of the initialisation sequence
359 putCommand (lcd, LCD_ON_OFF | LCD_ON_OFF_D) ; delay (2) ;
360 putCommand (lcd, LCD_ENTRY | LCD_ENTRY_ID) ; delay (2) ;
361 putCommand (lcd, LCD_CDSHIFT | LCD_CDSHIFT_RL) ; delay (2) ;
362 putCommand (lcd, LCD_CLEAR) ; delay (5) ;