-
Notifications
You must be signed in to change notification settings - Fork 41
/
lcd.c
485 lines (438 loc) · 13.9 KB
/
lcd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
/*
* -----------------------------------------------------------------------------
* ----- LCD.C -----
* ----- EASYPAY -----
* -----------------------------------------------------------------------------
*
* File Description:
* This is a library of functions for interfacing the PIC18F67K22 with a 20x4
* LCD (ST7066U driver) in its 8-bit databus mode
*
* Table of Contents:
* (private)
* GenSpecChars - load special characters into LCD's CGRAM
*
* (public)
* LcdCommand - write a command byte to the LCD.
* LcdWrite - write a data byte to the LCD.
* LcdWaitBF - wait for LCD BF (Busy Flag) to be clear
* LcdInit - initialize the LCD
* LcdClear - clear the LCD and home the cursor
* LcdWriteStr - write a string of chars to the LCD
* LcdWriteInt - write an integer to the LCD
* LcdWriteHex - write a hex byte to the LCD
* LcdWriteFill - write strings to fill all rows of display
* LcdCursor - move the cursor to a specified location on the LCD
*
* Assumptions:
* Hardware Hookup defined in include file.
*
* Compiler:
* HI-TECH C Compiler for PIC18 MCUs (http://www.htsoft.com/)
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
* Apr. 21, 2013 Nnoduka Eruchalu Added LcdWriteFill
* May 02, 2013 Nnoduka Eruchalu Added LcdWriteHex
* May 15, 2013 Nnoduka Eruchalu LcdWriteInt argument changed:
* unsigned int32_t -> uint32_t
*/
#include <htc.h>
#include <stdio.h>
#include "lcd.h"
/* tables local to this file
---------------------------- */
/*
* NairaTable
* Description: This is the table containing the bit patten for the rows (group
* of bits representing pixels) in the CGRAM that will be used in
* generating the image of the Naira Symbol (=N=).
* This table MUST be exactly LCD_CHAR_HEIGHT rows long.
*
* Revision History:
* Apr. 20, 2013 Nnoduka Eruchalu Initial Revision
*/
static char NairaTable[LCD_CHAR_HEIGHT] = {
0b00010001, /* row 0 */
0b00010001, /* row 1 */
0b00011111, /* row 2 */
0b00010101, /* row 3 */
0b00011111, /* row 4 */
0b00010001, /* row 5 */
0b00010001, /* row 6 */
0b00000000 /* row 7 */
};
/* functions local to this file
------------------------------- */
static void GenSpecChars(void);
/*
* LcdCommand
* Description: This procedure simply writes a command byte to the LCD.
* It does not return until the LCD's busy flag is cleared.
*
* Argument: c: command byte
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Send the byte, then wait for the BF to be cleared.
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdCommand(unsigned char c)
{
LCD_DATA_LAT = c; /* put data on output port */
CLEAR_RS(); /* RS = 0: Command */
CLEAR_RW(); /* R/W = 0: Write */
LCD_STROBE();
LcdWaitBF(); /* dont exit until the LCD is no longer busy */
}
/*
* LcdWrite
* Description: This procedure simply writes a data byte to the LCD.
* It does not return until the LCD's busy flag is cleared.
*
* Argument: c: data byte
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Send the byte, then wait for the BF to be cleared.
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdWrite(unsigned char c)
{
LCD_DATA_LAT = c; /* put data on output port */
SET_RS(); /* RS = 1: Data */
CLEAR_RW(); /* R/W = 0: Write */
LCD_STROBE();
LcdWaitBF(); /* dont exit until the LCD is no longer busy */
}
/*
* LcdWaitBF
* Description: This procedure simply loops until the LCD is not busy.
* This clears the RS bit.
*
* Argument: None
* Return: None
*
* Input: LCD's Busy Flag
* Output: None
*
* Operation: Keep on looping and reading the LCD busy flag. Exit when it
* indicates the LCD is not busy.
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdWaitBF(void)
{
unsigned char busy, status=0x00;
LCD_DATA_TRIS = 0xFF; /* when reading a port change it to an input */
CLEAR_RS(); /* prepare to read BF and Address Counter */
SET_RW(); /* and put the LCD in read mode */
do {
SET_E(); /* during reads the E has to be active */
__delay_us(0.5); /* wait tPW for data to become available */
status = LCD_DATA_PORT; /* read in value on data lines */
busy = status & 0x80; /* busy flag is highest status bit */
__delay_us(0.5);
CLEAR_E(); /* pull E low for at least tC-tPW */
__delay_us(1);
} while(busy);
/* put the LCD in write mode */
CLEAR_RW(); /* in write mode when R/W\ is cleared */
LCD_DATA_TRIS = 0x00; /* and the I/O pins are set as outputs */
}
/*
* LcdInit
* Description: This initializes the LCD. This must be called before the LCD can
* be used.
* Thus this function has to be called before calling any other
* LCD-interface functions.
* The LCD is set to the following specifications:
* 8-bit mode, 4-line display, 5x8 font
* cursor INCs, display doesn't shift
* cursor visible, cursor blinking
*
* Argument: None
* Return: None
*
* Input: None
* Output: LCD
*
* Operation:
* Really just follows standard initialization sequence. See sketch below
*
* POWER ON
* |
* | Wait time >40ms
* \|/
* FUNCTION SET (RS = 0, RW=0, DB = 0b0011NFXX) [BF cannot be checked b4 this]
* |
* | Wait time >37us
* \|/
* FUNCTION SET (RS = 0, RW=0, DB = 0b0011NFXX) [BF cannot be checked b4 this]
* |
* | Wait time >37us
* \|/
* DISPLAY ON/OFF control (RS = 0, RW=0, DB = 0b00001DCB)
* |
* | Wait time >37us
* \|/
* DISPLAY Clear (RS=0, RW=0, DB=0b00000001)
* |
* | Wait time >1.52ms
* \|/
* Entry Mode Set (RS=0, RW=0, DB=0b0000001{I/D}S)
* |
* | Wait time >37us
* \|/
* Initialization End
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdInit(void)
{
LCD_DATA_TRIS = 0x00; /* setup LCD IO ports as outputs */
LCD_E_TRIS = 0;
LCD_RW_TRIS = 0;
LCD_RS_TRIS = 0;
LCD_DATA_LAT = 0; /* clear IO lines*/
CLEAR_RS(); CLEAR_RW(); CLEAR_E();
__delay_ms(40);
LCD_DATA_LAT = LCD_FUNC_SET; /* FUNCTION SET, done manually to prevent a */
LCD_STROBE(); /* BF check before next command */
__delay_us(40);
LcdCommand(LCD_FUNC_SET); /* FUNCTION SET, again done manually */
LCD_STROBE();
__delay_us(40);
LcdCommand(LCD_ON); /* DISPLAY ON/OFF control: Turn display on */
__delay_us(40);
LcdCommand(LCD_CLEAR); /* DISPLAY Clear */
__delay_ms(2);
LcdCommand(LCD_ENTRY_MD); /* ENTRY mode set */
GenSpecChars(); /* Now create some special characters */
}
/*
* LcdClear
* Description: This function clears the LCD and return the cursor to the
* starting position
* This function doesnt return until the LCD's BF is cleared.
*
* Arguments: None
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Write the clear command to the instruction register of the LCD.
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdClear(void)
{
LcdCommand(0x01);
}
/*
* LcdWriteStr
* Description: This function writes a string of characters to the LCD
* This function doesnt return until the LCD's BF is cleared.
*
* Arguments: str: string to write to LCD
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Choose the data register of the LCD then write each char of the
* string to the LCD.
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdWriteStr(const char *str)
{
while (*str != '\0') {
LcdWrite(*str++);
}
}
/*
* LcdWriteInt
* Description: This function writes an integer to the lcd
* This function doesnt return until the LCD's BF is cleared.
*
* Arguments: num: integer to write.
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Convert the integer to a string then write it to the LCD.
*
* Issues: Buffer Overflow/Truncation Issues
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdWriteInt(uint32_t num)
{
char buffer[LCD_WIDTH]; /* buffer to hold int string */
size_t i;
sprintf(buffer, "%lu", num);
for(i=0; ((buffer[i]!='\0') && (i<LCD_WIDTH)); i++) {
LcdWrite(buffer[i]);
}
}
/*
* LcdWriteHex
* Description: This function writes a hex byte to the LCD.
* This function doesnt return until the LCD's BF is cleared.
*
* Arguments: num = hex number in range [0, 255]
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Extract high nibble then extract low nibble.
* For each nibble:
* if it is in range [0,9] print it as an ASCII numeric,
* '0' + nibble
* if it is in range [10,15] print it as an ASCII alpha,
* nibble - 10 + 'A'
*
* Limitations: hex input must 1 byte long so in range [0, 255]
*
* Revision History:
* May 02, 2012 Nnoduka Eruchalu Initial Revision
*/
void LcdWriteHex(unsigned int8_t num)
{
char nibble;
/* extract high nibble and write out numeric or alpha */
nibble = (num & 0xF0) >> 4;
if (nibble < 10) LcdWrite('0'+nibble);
else LcdWrite(nibble-10+'A');
/* extract low nibble and write out numeric or alpha */
nibble = (num & 0x0F);
if (nibble < 10) LcdWrite('0'+nibble);
else LcdWrite(nibble-10+'A');
}
/*
* LcdWriteFill
* Description: This function writes strings to all rows of display.
*
* Arguments: displaytable - a table of strings (one string per row).
* each string is of length (LCD_WIDTH+1). The +1 accounts for
* each string's NULL-terminator.
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Clear LCD. Return Cursor Home. Write strings in table, one row
* at a time.
*
* Revision History:
* Apr. 21, 2013 Nnoduka Eruchalu Initial Revision
* May 14, 2013 Nnoduka Eruchalu Setting cursor per row
*/
void LcdWriteFill(const char (*displaytable)[LCD_WIDTH+1]) {
size_t i; /* row counter */
LcdCommand(LCD_CLEAR); /* clear LCD */
LcdCommand(LCD_RET_HOME); /* return cursor home */
for (i=0; i<LCD_HEIGHT; i++) { /* write strings in table, */
LcdCursor(i,0); /* one row at a time */
LcdWriteStr(displaytable[i]);
}
}
/* LcdCursor
* Description: This function moves the cursor to a specific position
* Below is a DDRAM address map by Row:
* Row 1: 0x00 --> 0x13
* Row 2: 0x40 --> 0x53
* Row 3: 0x14 --> 0x27
* Row 4: 0x54 --> 0x67
*
* Arguments: row: 0-indexed row number
* col: 0-indexed column number
* Return: None
*
* Input: None
* Output: LCD
*
* Operation: Choose the base register of the LCD then update the cursor
* location
*
* Error Checking: If row >= LCD_HEIGHT or col >= LCD_WIDTH, it is reset to 0.
*
* Revision History:
* Dec. 16, 2012 Nnoduka Eruchalu Initial Revision
* Apr. 20, 2013 Nnoduka Eruchalu Updated to actually compute loc
* from row and col arguments.
*/
void LcdCursor(uint8_t row, uint8_t col)
{
uint8_t loc;
if (row >LCD_HEIGHT) row = 0; /* error checking of indices */
if (col >= LCD_WIDTH) col = 0;
switch(row) { /* get LCD's relative DDRAM location */
case 0:
loc = 0x00;
break;
case 1:
loc = 0x40;
break;
case 2:
loc = 0x14;
break;
case 3:
loc = 0x54;
break;
default:
break;
}
loc += col; /* offset relative DDRAM location by column */
LcdCommand(DDRAM_BASE+loc); /* have to write to absolute DDRAM location */
}
/* GenSpecChars
* Description: This procedure loads the CGRAM with custom characters.
* This procedure should be called after initializing the LCD.
*
* Arguments: None
* Return: None
*
* Input: None
* Output: LCD CGRAM
*
* Operation: For each custom character, call this ShapeX, the procedure sets
* the CGRAM address to point to the corresponding base address
* as defined in lcd.h.
* Then use the values in ShapeXTable to write the pixel data.
* After generating all the custom characters of interest, the
* procedure returns the Cursor to a DDRAM location.
*
* Error Checking: None
*
* Revision History:
* Apr. 20, 2013 Nnoduka Eruchalu Initial Revision
*/
static void GenSpecChars(void)
{
size_t i; /* looping index */
/* Generate Naira Character */
LcdCommand(NAIRA_BASE); /* point to Naira Char's CGRAM address */
for(i=0; i < LCD_CHAR_HEIGHT; i++) { /* Loop through and write the bits in */
LcdWrite(NairaTable[i]); /* the pixel rows */
}
/* Done generating special Characters */
LcdCommand(DDRAM_BASE); /* return the Cursor to a DDRAM loc */
}