lcd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  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. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <stdarg.h>
  29. #include <wiringPi.h>
  30. #include "lcd.h"
  31. #ifndef TRUE
  32. # define TRUE (1==1)
  33. # define FALSE (1==2)
  34. #endif
  35. // HD44780U Commands
  36. #define LCD_CLEAR 0x01
  37. #define LCD_HOME 0x02
  38. #define LCD_ENTRY 0x04
  39. #define LCD_CTRL 0x08
  40. #define LCD_CDSHIFT 0x10
  41. #define LCD_FUNC 0x20
  42. #define LCD_CGRAM 0x40
  43. #define LCD_DGRAM 0x80
  44. // Bits in the entry register
  45. #define LCD_ENTRY_SH 0x01
  46. #define LCD_ENTRY_ID 0x02
  47. // Bits in the control register
  48. #define LCD_BLINK_CTRL 0x01
  49. #define LCD_CURSOR_CTRL 0x02
  50. #define LCD_DISPLAY_CTRL 0x04
  51. // Bits in the function register
  52. #define LCD_FUNC_F 0x04
  53. #define LCD_FUNC_N 0x08
  54. #define LCD_FUNC_DL 0x10
  55. #define LCD_CDSHIFT_RL 0x04
  56. struct lcdDataStruct
  57. {
  58. int bits, rows, cols ;
  59. int rsPin, strbPin ;
  60. int dataPins [8] ;
  61. int cx, cy ;
  62. } ;
  63. struct lcdDataStruct *lcds [MAX_LCDS] ;
  64. static int lcdControl ;
  65. // Row offsets
  66. static const int rowOff [4] = { 0x00, 0x40, 0x14, 0x54 } ;
  67. /*
  68. * strobe:
  69. * Toggle the strobe (Really the "E") pin to the device.
  70. * According to the docs, data is latched on the falling edge.
  71. *********************************************************************************
  72. */
  73. static void strobe (const struct lcdDataStruct *lcd)
  74. {
  75. // Note timing changes for new version of delayMicroseconds ()
  76. digitalWrite (lcd->strbPin, 1) ; delayMicroseconds (50) ;
  77. digitalWrite (lcd->strbPin, 0) ; delayMicroseconds (50) ;
  78. }
  79. /*
  80. * sentDataCmd:
  81. * Send an data or command byte to the display.
  82. *********************************************************************************
  83. */
  84. static void sendDataCmd (const struct lcdDataStruct *lcd, unsigned char data)
  85. {
  86. register unsigned char myData = data ;
  87. unsigned char i, d4 ;
  88. if (lcd->bits == 4)
  89. {
  90. d4 = (myData >> 4) & 0x0F;
  91. for (i = 0 ; i < 4 ; ++i)
  92. {
  93. digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
  94. d4 >>= 1 ;
  95. }
  96. strobe (lcd) ;
  97. d4 = myData & 0x0F ;
  98. for (i = 0 ; i < 4 ; ++i)
  99. {
  100. digitalWrite (lcd->dataPins [i], (d4 & 1)) ;
  101. d4 >>= 1 ;
  102. }
  103. }
  104. else
  105. {
  106. for (i = 0 ; i < 8 ; ++i)
  107. {
  108. digitalWrite (lcd->dataPins [i], (myData & 1)) ;
  109. myData >>= 1 ;
  110. }
  111. }
  112. strobe (lcd) ;
  113. }
  114. /*
  115. * putCommand:
  116. * Send a command byte to the display
  117. *********************************************************************************
  118. */
  119. static void putCommand (const struct lcdDataStruct *lcd, unsigned char command)
  120. {
  121. digitalWrite (lcd->rsPin, 0) ;
  122. sendDataCmd (lcd, command) ;
  123. delay (2) ;
  124. }
  125. static void put4Command (const struct lcdDataStruct *lcd, unsigned char command)
  126. {
  127. register unsigned char myCommand = command ;
  128. register unsigned char i ;
  129. digitalWrite (lcd->rsPin, 0) ;
  130. for (i = 0 ; i < 4 ; ++i)
  131. {
  132. digitalWrite (lcd->dataPins [i], (myCommand & 1)) ;
  133. myCommand >>= 1 ;
  134. }
  135. strobe (lcd) ;
  136. }
  137. /*
  138. *********************************************************************************
  139. * User Callable code below here
  140. *********************************************************************************
  141. */
  142. /*
  143. * lcdHome: lcdClear:
  144. * Home the cursor or clear the screen.
  145. *********************************************************************************
  146. */
  147. void lcdHome (const int fd)
  148. {
  149. struct lcdDataStruct *lcd = lcds [fd] ;
  150. putCommand (lcd, LCD_HOME) ;
  151. lcd->cx = lcd->cy = 0 ;
  152. delay (5) ;
  153. }
  154. void lcdClear (const int fd)
  155. {
  156. struct lcdDataStruct *lcd = lcds [fd] ;
  157. putCommand (lcd, LCD_CLEAR) ;
  158. putCommand (lcd, LCD_HOME) ;
  159. lcd->cx = lcd->cy = 0 ;
  160. delay (5) ;
  161. }
  162. /*
  163. * lcdDisplay: lcdCursor: lcdCursorBlink:
  164. * Turn the display, cursor, cursor blinking on/off
  165. *********************************************************************************
  166. */
  167. void lcdDisplay (const int fd, int state)
  168. {
  169. struct lcdDataStruct *lcd = lcds [fd] ;
  170. if (state)
  171. lcdControl |= LCD_DISPLAY_CTRL ;
  172. else
  173. lcdControl &= ~LCD_DISPLAY_CTRL ;
  174. putCommand (lcd, LCD_CTRL | lcdControl) ;
  175. }
  176. void lcdCursor (const int fd, int state)
  177. {
  178. struct lcdDataStruct *lcd = lcds [fd] ;
  179. if (state)
  180. lcdControl |= LCD_CURSOR_CTRL ;
  181. else
  182. lcdControl &= ~LCD_CURSOR_CTRL ;
  183. putCommand (lcd, LCD_CTRL | lcdControl) ;
  184. }
  185. void lcdCursorBlink (const int fd, int state)
  186. {
  187. struct lcdDataStruct *lcd = lcds [fd] ;
  188. if (state)
  189. lcdControl |= LCD_BLINK_CTRL ;
  190. else
  191. lcdControl &= ~LCD_BLINK_CTRL ;
  192. putCommand (lcd, LCD_CTRL | lcdControl) ;
  193. }
  194. /*
  195. * lcdSendCommand:
  196. * Send any arbitary command to the display
  197. *********************************************************************************
  198. */
  199. void lcdSendCommand (const int fd, unsigned char command)
  200. {
  201. struct lcdDataStruct *lcd = lcds [fd] ;
  202. putCommand (lcd, command) ;
  203. }
  204. /*
  205. * lcdPosition:
  206. * Update the position of the cursor on the display.
  207. * Ignore invalid locations.
  208. *********************************************************************************
  209. */
  210. void lcdPosition (const int fd, int x, int y)
  211. {
  212. struct lcdDataStruct *lcd = lcds [fd] ;
  213. if ((x > lcd->cols) || (x < 0))
  214. return ;
  215. if ((y > lcd->rows) || (y < 0))
  216. return ;
  217. putCommand (lcd, x + (LCD_DGRAM | rowOff [y])) ;
  218. lcd->cx = x ;
  219. lcd->cy = y ;
  220. }
  221. /*
  222. * lcdCharDef:
  223. * Defines a new character in the CGRAM
  224. *********************************************************************************
  225. */
  226. void lcdCharDef (const int fd, int index, unsigned char data [8])
  227. {
  228. struct lcdDataStruct *lcd = lcds [fd] ;
  229. int i ;
  230. putCommand (lcd, LCD_CGRAM | ((index & 7) << 3)) ;
  231. digitalWrite (lcd->rsPin, 1) ;
  232. for (i = 0 ; i < 8 ; ++i)
  233. sendDataCmd (lcd, data [i]) ;
  234. }
  235. /*
  236. * lcdPutchar:
  237. * Send a data byte to be displayed on the display. We implement a very
  238. * simple terminal here - with line wrapping, but no scrolling. Yet.
  239. *********************************************************************************
  240. */
  241. void lcdPutchar (const int fd, unsigned char data)
  242. {
  243. struct lcdDataStruct *lcd = lcds [fd] ;
  244. digitalWrite (lcd->rsPin, 1) ;
  245. sendDataCmd (lcd, data) ;
  246. if (++lcd->cx == lcd->cols)
  247. {
  248. lcd->cx = 0 ;
  249. if (++lcd->cy == lcd->rows)
  250. lcd->cy = 0 ;
  251. putCommand (lcd, lcd->cx + (LCD_DGRAM | rowOff [lcd->cy])) ;
  252. }
  253. }
  254. /*
  255. * lcdPuts:
  256. * Send a string to be displayed on the display
  257. *********************************************************************************
  258. */
  259. void lcdPuts (const int fd, const char *string)
  260. {
  261. while (*string)
  262. lcdPutchar (fd, *string++) ;
  263. }
  264. /*
  265. * lcdPrintf:
  266. * Printf to an LCD display
  267. *********************************************************************************
  268. */
  269. void lcdPrintf (const int fd, const char *message, ...)
  270. {
  271. va_list argp ;
  272. char buffer [1024] ;
  273. va_start (argp, message) ;
  274. vsnprintf (buffer, 1023, message, argp) ;
  275. va_end (argp) ;
  276. lcdPuts (fd, buffer) ;
  277. }
  278. /*
  279. * lcdInit:
  280. * Take a lot of parameters and initialise the LCD, and return a handle to
  281. * that LCD, or -1 if any error.
  282. *********************************************************************************
  283. */
  284. int lcdInit (const int rows, const int cols, const int bits,
  285. const int rs, const int strb,
  286. const int d0, const int d1, const int d2, const int d3, const int d4,
  287. const int d5, const int d6, const int d7)
  288. {
  289. static int initialised = 0 ;
  290. unsigned char func ;
  291. int i ;
  292. int lcdFd = -1 ;
  293. struct lcdDataStruct *lcd ;
  294. if (initialised == 0)
  295. {
  296. initialised = 1 ;
  297. for (i = 0 ; i < MAX_LCDS ; ++i)
  298. lcds [i] = NULL ;
  299. }
  300. // Simple sanity checks
  301. if (! ((bits == 4) || (bits == 8)))
  302. return -1 ;
  303. if ((rows < 0) || (rows > 20))
  304. return -1 ;
  305. if ((cols < 0) || (cols > 20))
  306. return -1 ;
  307. // Create a new LCD:
  308. for (i = 0 ; i < MAX_LCDS ; ++i)
  309. {
  310. if (lcds [i] == NULL)
  311. {
  312. lcdFd = i ;
  313. break ;
  314. }
  315. }
  316. if (lcdFd == -1)
  317. return -1 ;
  318. lcd = (struct lcdDataStruct *)malloc (sizeof (struct lcdDataStruct)) ;
  319. if (lcd == NULL)
  320. return -1 ;
  321. lcd->rsPin = rs ;
  322. lcd->strbPin = strb ;
  323. lcd->bits = 8 ; // For now - we'll set it properly later.
  324. lcd->rows = rows ;
  325. lcd->cols = cols ;
  326. lcd->cx = 0 ;
  327. lcd->cy = 0 ;
  328. lcd->dataPins [0] = d0 ;
  329. lcd->dataPins [1] = d1 ;
  330. lcd->dataPins [2] = d2 ;
  331. lcd->dataPins [3] = d3 ;
  332. lcd->dataPins [4] = d4 ;
  333. lcd->dataPins [5] = d5 ;
  334. lcd->dataPins [6] = d6 ;
  335. lcd->dataPins [7] = d7 ;
  336. lcds [lcdFd] = lcd ;
  337. digitalWrite (lcd->rsPin, 0) ; pinMode (lcd->rsPin, OUTPUT) ;
  338. digitalWrite (lcd->strbPin, 0) ; pinMode (lcd->strbPin, OUTPUT) ;
  339. for (i = 0 ; i < bits ; ++i)
  340. {
  341. digitalWrite (lcd->dataPins [i], 0) ;
  342. pinMode (lcd->dataPins [i], OUTPUT) ;
  343. }
  344. delay (35) ; // mS
  345. // 4-bit mode?
  346. // OK. This is a PIG and it's not at all obvious from the documentation I had,
  347. // so I guess some others have worked through either with better documentation
  348. // or more trial and error... Anyway here goes:
  349. //
  350. // It seems that the controller needs to see the FUNC command at least 3 times
  351. // consecutively - in 8-bit mode. If you're only using 8-bit mode, then it appears
  352. // that you can get away with one func-set, however I'd not rely on it...
  353. //
  354. // So to set 4-bit mode, you need to send the commands one nibble at a time,
  355. // the same three times, but send the command to set it into 8-bit mode those
  356. // three times, then send a final 4th command to set it into 4-bit mode, and only
  357. // then can you flip the switch for the rest of the library to work in 4-bit
  358. // mode which sends the commands as 2 x 4-bit values.
  359. if (bits == 4)
  360. {
  361. func = LCD_FUNC | LCD_FUNC_DL ; // Set 8-bit mode 3 times
  362. put4Command (lcd, func >> 4) ; delay (35) ;
  363. put4Command (lcd, func >> 4) ; delay (35) ;
  364. put4Command (lcd, func >> 4) ; delay (35) ;
  365. func = LCD_FUNC ; // 4th set: 4-bit mode
  366. put4Command (lcd, func >> 4) ; delay (35) ;
  367. lcd->bits = 4 ;
  368. }
  369. else
  370. {
  371. func = LCD_FUNC | LCD_FUNC_DL ;
  372. putCommand (lcd, func ) ; delay (35) ;
  373. putCommand (lcd, func ) ; delay (35) ;
  374. putCommand (lcd, func ) ; delay (35) ;
  375. }
  376. if (lcd->rows > 1)
  377. {
  378. func |= LCD_FUNC_N ;
  379. putCommand (lcd, func) ; delay (35) ;
  380. }
  381. // Rest of the initialisation sequence
  382. lcdDisplay (lcdFd, TRUE) ;
  383. lcdCursor (lcdFd, FALSE) ;
  384. lcdCursorBlink (lcdFd, FALSE) ;
  385. lcdClear (lcdFd) ;
  386. putCommand (lcd, LCD_ENTRY | LCD_ENTRY_ID) ;
  387. putCommand (lcd, LCD_CDSHIFT | LCD_CDSHIFT_RL) ;
  388. return lcdFd ;
  389. }