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 I/O pins changed to be compatible with the LCD connections
41 on the Explorer-16 board,
42 also changed the initialization code in initLCD slightly.
43 */
44 
45 #define RS_HIGH() _LATB15 = 1
46 #define RS_LOW() _LATB15 = 0
47 #define CONFIG_RS() CONFIG_RB15_AS_DIG_OUTPUT()
48 
49 #define RW_HIGH() _LATD5 = 1
50 #define RW_LOW() _LATD5 = 0
51 #define CONFIG_RW() CONFIG_RD5_AS_DIG_OUTPUT()
52 
53 #define E_HIGH() _LATD4 = 1
54 #define E_LOW() _LATD4 = 0
55 #define CONFIG_E() CONFIG_RD4_AS_DIG_OUTPUT()
56 
57 #define LCD4O _LATE4
58 #define LCD5O _LATE5
59 #define LCD6O _LATE6
60 #define LCD7O _LATE7
61 #define LCD7I _RE7
62 
63 #define CONFIG_LCD4_AS_INPUT() CONFIG_RE4_AS_DIG_INPUT()
64 #define CONFIG_LCD5_AS_INPUT() CONFIG_RE5_AS_DIG_INPUT()
65 #define CONFIG_LCD6_AS_INPUT() CONFIG_RE6_AS_DIG_INPUT()
66 #define CONFIG_LCD7_AS_INPUT() CONFIG_RE7_AS_DIG_INPUT()
67 
68 #define CONFIG_LCD4_AS_OUTPUT() CONFIG_RE4_AS_DIG_OUTPUT()
69 #define CONFIG_LCD5_AS_OUTPUT() CONFIG_RE5_AS_DIG_OUTPUT()
70 #define CONFIG_LCD6_AS_OUTPUT() CONFIG_RE6_AS_DIG_OUTPUT()
71 #define CONFIG_LCD7_AS_OUTPUT() CONFIG_RE7_AS_DIG_OUTPUT()
72 
73 #define GET_BUSY_FLAG() LCD7I
74 
75 /**
76  Functions above this line must be redefined for
77  your particular PICmicro-to-LCD interface
78 */
79 
80 //Configure 4-bit data bus for output
81 void configBusAsOutLCD(void) {
82  RW_LOW(); //RW=0 to stop LCD from driving pins
83  CONFIG_LCD4_AS_OUTPUT(); //D4
84  CONFIG_LCD5_AS_OUTPUT(); //D5
85  CONFIG_LCD6_AS_OUTPUT(); //D6
86  CONFIG_LCD7_AS_OUTPUT(); //D7
87 }
88 
89 //Configure 4-bit data bus for input
90 void configBusAsInLCD(void) {
91  CONFIG_LCD4_AS_INPUT(); //D4
92  CONFIG_LCD5_AS_INPUT(); //D5
93  CONFIG_LCD6_AS_INPUT(); //D6
94  CONFIG_LCD7_AS_INPUT(); //D7
95  RW_HIGH(); // R/W = 1, for read
96 }
97 
98 //Output lower 4-bits of u8_c to LCD data lines
99 void outputToBusLCD(uint8_t u8_c) {
100  LCD4O = u8_c & 0x01; //D4
101  LCD5O = (u8_c >> 1)& 0x01; //D5
102  LCD6O = (u8_c >> 2)& 0x01; //D6
103  LCD7O = (u8_c >> 3)& 0x01; //D7
104 }
105 
106 //Configure the control lines for the LCD
107 void configControlLCD(void) {
108  CONFIG_RS(); //RS
109  CONFIG_RW(); //RW
110  CONFIG_E(); //E
111  RW_LOW();
112  E_LOW();
113  RS_LOW();
114 }
115 
116 //Pulse the E clock, 1 us delay around edges for
117 //setup/hold times
118 void pulseE(void) {
119  DELAY_US(1);
120  E_HIGH();
121  DELAY_US(1);
122  E_LOW();
123  DELAY_US(1);
124 }
125 
126 /* Write a byte (u8_Cmd) to the LCD.
127 u8_DataFlag is '1' if data byte, '0' if command byte
128 u8_CheckBusy is '1' if must poll busy bit before write, else simply delay before write
129 u8_Send8Bits is '1' if must send all 8 bits, else send only upper 4-bits
130 */
131 void writeLCD(uint8_t u8_Cmd, uint8_t u8_DataFlag,
132  uint8_t u8_CheckBusy, uint8_t u8_Send8Bits) {
133 
134  uint8_t u8_BusyFlag;
135  uint8_t u8_wdtState;
136  if (u8_CheckBusy) {
137  RS_LOW(); //RS = 0 to check busy
138  // check busy
139  configBusAsInLCD(); //set data pins all inputs
140  u8_wdtState = _SWDTEN; //save WDT enable state
141  CLRWDT(); //clear the WDT timer
142  _SWDTEN = 1; //enable WDT to escape infinite wait
143  do {
144  E_HIGH();
145  DELAY_US(1); // read upper 4 bits
146  u8_BusyFlag = GET_BUSY_FLAG();
147  E_LOW();
148  DELAY_US(1);
149  pulseE(); //pulse again for lower 4-bits
150  } while (u8_BusyFlag);
151  _SWDTEN = u8_wdtState; //restore WDT enable state
152  } else {
153  DELAY_MS(10); // don't use busy, just delay
154  }
156  if (u8_DataFlag) RS_HIGH(); // RS=1, data byte
157  else RS_LOW(); // RS=0, command byte
158  outputToBusLCD(u8_Cmd >> 4); // send upper 4 bits
159  pulseE();
160  if (u8_Send8Bits) {
161  outputToBusLCD(u8_Cmd); // send lower 4 bits
162  pulseE();
163  }
164 }
165 
166 // Initialize the LCD, modify to suit your application and LCD
167 void initLCD() {
168  DELAY_MS(50); //wait for device to settle
169  writeLCD(0x28,0,0,0); // 4 bit interface, 2 line display
170  writeLCD(0x28,0,1,1); // repeat
171  writeLCD(0x06,0,0,1); // enable display
172  writeLCD(0x0C,0,0,1); // turn display on; cursor, blink is off
173  writeLCD(0x01,0,0,1); // clear display, move cursor to home
174  DELAY_MS(3);
175 }
176 
177 //Output a string to the LCD
178 void outStringLCD(char *psz_s) {
179  while (*psz_s) {
180  writeLCD(*psz_s, 1, 1,1);
181  psz_s++;
182  }
183 }
184 
185 
186 int main (void) {
187  configBasic(HELLO_MSG); // Set up heartbeat, UART, print hello message and diags
188 
189  configControlLCD(); //configure the LCD control lines
190  initLCD(); //initialize the LCD
191 
192  outStringLCD("******Hello, my name is Bob********");
193  writeLCD(0xC0,0,1,1); // cursor to 2nd line
194  outStringLCD("-----these lines are moving!-------");
195  while (1) {
196  writeLCD(0x18,0,1,1); // shift left
197  DELAY_MS(200);
198  doHeartbeat();
199  }
200 }