Advertisement
Guest User

lcd.c

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