PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lcd4bit.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 #include "pic24_all.h"
31 
32 
33 /** \file
34 Demonstrates a Character LCD using the industry
35 standard parallel interface in 4-bit mode.
36 Assumes a 5V LCD; digital-only IO pins are assumed
37 to be used for the four-bit data bus because they are
38 5V input tolerant.
39 
40 Tested with Optrex 24227 and
41 Optrex DMC-50448N-AAE-AD.
42 Should work with any LCD that uses the
43 Hitachi HD44780 LCD controller.
44 */
45 
46 #define RS_HIGH() _LATB9 = 1
47 #define RS_LOW() _LATB9 = 0
48 #define CONFIG_RS() CONFIG_RB9_AS_DIG_OUTPUT()
49 
50 #define RW_HIGH() _LATB13 = 1
51 #define RW_LOW() _LATB13 = 0
52 #define CONFIG_RW() CONFIG_RB13_AS_DIG_OUTPUT()
53 
54 #define E_HIGH() _LATB14 = 1
55 #define E_LOW() _LATB14 = 0
56 #define CONFIG_E() CONFIG_RB14_AS_DIG_OUTPUT()
57 
58 #define LCD4O _LATB5
59 #define LCD5O _LATB6
60 #define LCD6O _LATB7
61 #define LCD7O _LATB8
62 #define LCD7I _RB8
63 
64 #define CONFIG_LCD4_AS_INPUT() CONFIG_RB5_AS_DIG_INPUT()
65 #define CONFIG_LCD5_AS_INPUT() CONFIG_RB6_AS_DIG_INPUT()
66 #define CONFIG_LCD6_AS_INPUT() CONFIG_RB7_AS_DIG_INPUT()
67 #define CONFIG_LCD7_AS_INPUT() CONFIG_RB8_AS_DIG_INPUT()
68 
69 #define CONFIG_LCD4_AS_OUTPUT() CONFIG_RB5_AS_DIG_OUTPUT()
70 #define CONFIG_LCD5_AS_OUTPUT() CONFIG_RB6_AS_DIG_OUTPUT()
71 #define CONFIG_LCD6_AS_OUTPUT() CONFIG_RB7_AS_DIG_OUTPUT()
72 #define CONFIG_LCD7_AS_OUTPUT() CONFIG_RB8_AS_DIG_OUTPUT()
73 
74 #define GET_BUSY_FLAG() LCD7I
75 
76 /**
77  Functions above this line must be redefined for
78  your particular PICmicro-to-LCD interface
79 */
80 
81 //Configure 4-bit data bus for output
82 void configBusAsOutLCD(void) {
83  RW_LOW(); //RW=0 to stop LCD from driving pins
84  CONFIG_LCD4_AS_OUTPUT(); //D4
85  CONFIG_LCD5_AS_OUTPUT(); //D5
86  CONFIG_LCD6_AS_OUTPUT(); //D6
87  CONFIG_LCD7_AS_OUTPUT(); //D7
88 }
89 
90 //Configure 4-bit data bus for input
91 void configBusAsInLCD(void) {
92  CONFIG_LCD4_AS_INPUT(); //D4
93  CONFIG_LCD5_AS_INPUT(); //D5
94  CONFIG_LCD6_AS_INPUT(); //D6
95  CONFIG_LCD7_AS_INPUT(); //D7
96  RW_HIGH(); // R/W = 1, for read
97 }
98 
99 //Output lower 4-bits of u8_c to LCD data lines
100 void outputToBusLCD(uint8_t u8_c) {
101  LCD4O = u8_c & 0x01; //D4
102  LCD5O = (u8_c >> 1)& 0x01; //D5
103  LCD6O = (u8_c >> 2)& 0x01; //D6
104  LCD7O = (u8_c >> 3)& 0x01; //D7
105 }
106 
107 //Configure the control lines for the LCD
108 void configControlLCD(void) {
109  CONFIG_RS(); //RS
110  CONFIG_RW(); //RW
111  CONFIG_E(); //E
112  RW_LOW();
113  E_LOW();
114  RS_LOW();
115 }
116 
117 //Pulse the E clock, 1 us delay around edges for
118 //setup/hold times
119 void pulseE(void) {
120  DELAY_US(1);
121  E_HIGH();
122  DELAY_US(1);
123  E_LOW();
124  DELAY_US(1);
125 }
126 
127 /* Write a byte (u8_Cmd) to the LCD.
128 u8_DataFlag is '1' if data byte, '0' if command byte
129 u8_CheckBusy is '1' if must poll busy bit before write, else simply delay before write
130 u8_Send8Bits is '1' if must send all 8 bits, else send only upper 4-bits
131 */
132 void writeLCD(uint8_t u8_Cmd, uint8_t u8_DataFlag,
133  uint8_t u8_CheckBusy, uint8_t u8_Send8Bits) {
134 
135  uint8_t u8_BusyFlag;
136  uint8_t u8_wdtState;
137  if (u8_CheckBusy) {
138  RS_LOW(); //RS = 0 to check busy
139  // check busy
140  configBusAsInLCD(); //set data pins all inputs
141  u8_wdtState = _SWDTEN; //save WDT enable state
142  CLRWDT(); //clear the WDT timer
143  _SWDTEN = 1; //enable WDT to escape infinite wait
144  do {
145  E_HIGH();
146  DELAY_US(1); // read upper 4 bits
147  u8_BusyFlag = GET_BUSY_FLAG();
148  E_LOW();
149  DELAY_US(1);
150  pulseE(); //pulse again for lower 4-bits
151  } while (u8_BusyFlag);
152  _SWDTEN = u8_wdtState; //restore WDT enable state
153  } else {
154  DELAY_MS(10); // don't use busy, just delay
155  }
157  if (u8_DataFlag) RS_HIGH(); // RS=1, data byte
158  else RS_LOW(); // RS=0, command byte
159  outputToBusLCD(u8_Cmd >> 4); // send upper 4 bits
160  pulseE();
161  if (u8_Send8Bits) {
162  outputToBusLCD(u8_Cmd); // send lower 4 bits
163  pulseE();
164  }
165 }
166 
167 // Initialize the LCD, modify to suit your application and LCD
168 void initLCD() {
169  DELAY_MS(50); //wait for device to settle
170  writeLCD(0x20,0,0,0); // 4 bit interface
171  writeLCD(0x28,0,0,1); // 2 line display, 5x7 font
172  writeLCD(0x28,0,0,1); // repeat
173  writeLCD(0x06,0,0,1); // enable display
174  writeLCD(0x0C,0,0,1); // turn display on; cursor, blink is off
175  writeLCD(0x01,0,0,1); // clear display, move cursor to home
176  DELAY_MS(3);
177 }
178 
179 //Output a string to the LCD
180 void outStringLCD(char *psz_s) {
181  while (*psz_s) {
182  writeLCD(*psz_s, 1, 1,1);
183  psz_s++;
184  }
185 }
186 
187 
188 int main (void) {
189  configBasic(HELLO_MSG); // Set up heartbeat, UART, print hello message and diags
190 
191  configControlLCD(); //configure the LCD control lines
192  initLCD(); //initialize the LCD
193 
194  outStringLCD("******Hello, my name is Bob********");
195  writeLCD(0xC0,0,1,1); // cursor to 2nd line
196  outStringLCD("-----these lines are moving!-------");
197  while (1) {
198  writeLCD(0x18,0,1,1); // shift left
199  DELAY_MS(200);
200  doHeartbeat();
201  }
202 }