1 | /****************************************************************************
|
2 | Title : HD44780U LCD library
|
3 | Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
4 | File: $Id: lcd.c,v 1.14.2.1 2006/01/29 12:16:41 peter Exp $
|
5 | Software: AVR-GCC 3.3
|
6 | Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega
|
7 |
|
8 | DESCRIPTION
|
9 | Basic routines for interfacing a HD44780U-based text lcd display
|
10 |
|
11 | Originally based on Volker Oth's lcd library,
|
12 | changed lcd_init(), added additional constants for lcd_command(),
|
13 | added 4-bit I/O mode, improved and optimized code.
|
14 |
|
15 | Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in
|
16 | 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.
|
17 |
|
18 | Memory mapped mode compatible with Kanda STK200, but supports also
|
19 | generation of R/W signal through A8 address line.
|
20 |
|
21 | USAGE
|
22 | See the C include lcd.h file for a description of each function
|
23 |
|
24 | *****************************************************************************/
|
25 |
|
26 | #include <inttypes.h>
|
27 | #include <avr/io.h>
|
28 | #include <avr/pgmspace.h>
|
29 | #include "lcd.h"
|
30 |
|
31 |
|
32 |
|
33 | /*
|
34 | ** constants/macros
|
35 | */
|
36 | #define DDR(x) (*(&x - 1)) /* address of data direction register of port x */
|
37 | #if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
|
38 | /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */
|
39 | #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) )
|
40 | #else
|
41 | #define PIN(x) (*(&x - 2)) /* address of input register of port x */
|
42 | #endif
|
43 |
|
44 |
|
45 | #if LCD_IO_MODE
|
46 | #define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" );
|
47 | #define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN);
|
48 | #define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN);
|
49 | #define lcd_e_toggle() toggle_e()
|
50 | #define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN)
|
51 | #define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN)
|
52 | #define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN)
|
53 | #define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN)
|
54 | #endif
|
55 |
|
56 | #if LCD_IO_MODE
|
57 | #if LCD_LINES==1
|
58 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
|
59 | #else
|
60 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
|
61 | #endif
|
62 | #else
|
63 | #if LCD_LINES==1
|
64 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE
|
65 | #else
|
66 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES
|
67 | #endif
|
68 | #endif
|
69 |
|
70 | #if LCD_CONTROLLER_KS0073
|
71 | #if LCD_LINES==4
|
72 |
|
73 | #define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */
|
74 | #define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */
|
75 | #define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */
|
76 |
|
77 | #endif
|
78 | #endif
|
79 |
|
80 | /*
|
81 | ** function prototypes
|
82 | */
|
83 | #if LCD_IO_MODE
|
84 | static void toggle_e(void);
|
85 | #endif
|
86 |
|
87 | /*
|
88 | ** local functions
|
89 | */
|
90 |
|
91 |
|
92 |
|
93 | /*************************************************************************
|
94 | delay loop for small accurate delays: 16-bit counter, 4 cycles/loop
|
95 | *************************************************************************/
|
96 | static inline void _delayFourCycles(unsigned int __count)
|
97 | {
|
98 | if ( __count == 0 )
|
99 | __asm__ __volatile__( "rjmp 1f\n 1:" ); // 2 cycles
|
100 | else
|
101 | __asm__ __volatile__ (
|
102 | "1: sbiw %0,1" "\n\t"
|
103 | "brne 1b" // 4 cycles/loop
|
104 | : "=w" (__count)
|
105 | : "0" (__count)
|
106 | );
|
107 | }
|
108 |
|
109 |
|
110 | /*************************************************************************
|
111 | delay for a minimum of <us> microseconds
|
112 | the number of loops is calculated at compile-time from MCU clock frequency
|
113 | *************************************************************************/
|
114 | #define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 )
|
115 |
|
116 |
|
117 | #if LCD_IO_MODE
|
118 | /* toggle Enable Pin to initiate write */
|
119 | static void toggle_e(void)
|
120 | {
|
121 | lcd_e_high();
|
122 | lcd_e_delay();
|
123 | lcd_e_low();
|
124 | }
|
125 | #endif
|
126 |
|
127 |
|
128 | /*************************************************************************
|
129 | Low-level function to write byte to LCD controller
|
130 | Input: data byte to write to LCD
|
131 | rs 1: write data
|
132 | 0: write instruction
|
133 | Returns: none
|
134 | *************************************************************************/
|
135 | #if LCD_IO_MODE
|
136 | static void lcd_write(uint8_t data,uint8_t rs)
|
137 | {
|
138 | unsigned char dataBits ;
|
139 |
|
140 |
|
141 | if (rs) { /* write data (RS=1, RW=0) */
|
142 | lcd_rs_high();
|
143 | } else { /* write instruction (RS=0, RW=0) */
|
144 | lcd_rs_low();
|
145 | }
|
146 | lcd_rw_low();
|
147 |
|
148 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
149 | && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
|
150 | {
|
151 | /* configure data pins as output */
|
152 | DDR(LCD_DATA0_PORT) |= 0x0F;
|
153 |
|
154 | /* output high nibble first */
|
155 | dataBits = LCD_DATA0_PORT & 0xF0;
|
156 | LCD_DATA0_PORT = dataBits |((data>>4)&0x0F);
|
157 | lcd_e_toggle();
|
158 |
|
159 | /* output low nibble */
|
160 | LCD_DATA0_PORT = dataBits | (data&0x0F);
|
161 | lcd_e_toggle();
|
162 |
|
163 | /* all data pins high (inactive) */
|
164 | LCD_DATA0_PORT = dataBits | 0x0F;
|
165 | }
|
166 | else
|
167 | {
|
168 | /* configure data pins as output */
|
169 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
170 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
171 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
172 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
173 |
|
174 | /* output high nibble first */
|
175 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
176 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
177 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
178 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
179 | if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
180 | if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
181 | if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
182 | if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
183 | lcd_e_toggle();
|
184 |
|
185 | /* output low nibble */
|
186 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
187 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
188 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
189 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
190 | if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
191 | if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
192 | if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
193 | if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
194 | lcd_e_toggle();
|
195 |
|
196 | /* all data pins high (inactive) */
|
197 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
198 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
199 | LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
200 | LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
201 | }
|
202 | }
|
203 | #else
|
204 | #define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d;
|
205 | /* rs==0 -> write instruction to LCD_IO_FUNCTION */
|
206 | /* rs==1 -> write data to LCD_IO_DATA */
|
207 | #endif
|
208 |
|
209 |
|
210 | /*************************************************************************
|
211 | Low-level function to read byte from LCD controller
|
212 | Input: rs 1: read data
|
213 | 0: read busy flag / address counter
|
214 | Returns: byte read from LCD controller
|
215 | *************************************************************************/
|
216 | #if LCD_IO_MODE
|
217 | static uint8_t lcd_read(uint8_t rs)
|
218 | {
|
219 | uint8_t data;
|
220 |
|
221 |
|
222 | if (rs)
|
223 | lcd_rs_high(); /* RS=1: read data */
|
224 | else
|
225 | lcd_rs_low(); /* RS=0: read busy flag */
|
226 | lcd_rw_high(); /* RW=1 read mode */
|
227 |
|
228 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
229 | && ( LCD_DATA0_PIN == 0 )&& (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
|
230 | {
|
231 | DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */
|
232 |
|
233 | lcd_e_high();
|
234 | lcd_e_delay();
|
235 | data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */
|
236 | lcd_e_low();
|
237 |
|
238 | lcd_e_delay(); /* Enable 500ns low */
|
239 |
|
240 | lcd_e_high();
|
241 | lcd_e_delay();
|
242 | data |= PIN(LCD_DATA0_PORT)&0x0F; /* read low nibble */
|
243 | lcd_e_low();
|
244 | }
|
245 | else
|
246 | {
|
247 | /* configure data pins as input */
|
248 | DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);
|
249 | DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);
|
250 | DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);
|
251 | DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);
|
252 |
|
253 | /* read high nibble first */
|
254 | lcd_e_high();
|
255 | lcd_e_delay();
|
256 | data = 0;
|
257 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10;
|
258 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20;
|
259 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40;
|
260 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80;
|
261 | lcd_e_low();
|
262 |
|
263 | lcd_e_delay(); /* Enable 500ns low */
|
264 |
|
265 | /* read low nibble */
|
266 | lcd_e_high();
|
267 | lcd_e_delay();
|
268 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01;
|
269 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02;
|
270 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04;
|
271 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08;
|
272 | lcd_e_low();
|
273 | }
|
274 | return data;
|
275 | }
|
276 | #else
|
277 | #define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ)
|
278 | /* rs==0 -> read instruction from LCD_IO_FUNCTION */
|
279 | /* rs==1 -> read data from LCD_IO_DATA */
|
280 | #endif
|
281 |
|
282 |
|
283 | /*************************************************************************
|
284 | loops while lcd is busy, returns address counter
|
285 | *************************************************************************/
|
286 | static uint8_t lcd_waitbusy(void)
|
287 |
|
288 | {
|
289 | register uint8_t c;
|
290 |
|
291 | /* wait until busy flag is cleared */
|
292 | while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) {}
|
293 |
|
294 | /* the address counter is updated 4us after the busy flag is cleared */
|
295 | delay(2);
|
296 |
|
297 | /* now read the address counter */
|
298 | return (lcd_read(0)); // return address counter
|
299 |
|
300 | }/* lcd_waitbusy */
|
301 |
|
302 |
|
303 | /*************************************************************************
|
304 | Move cursor to the start of next line or to the first line if the cursor
|
305 | is already on the last line.
|
306 | *************************************************************************/
|
307 | static inline void lcd_newline(uint8_t pos)
|
308 | {
|
309 | register uint8_t addressCounter;
|
310 |
|
311 |
|
312 | #if LCD_LINES==1
|
313 | addressCounter = 0;
|
314 | #endif
|
315 | #if LCD_LINES==2
|
316 | if ( pos < (LCD_START_LINE2) )
|
317 | addressCounter = LCD_START_LINE2;
|
318 | else
|
319 | addressCounter = LCD_START_LINE1;
|
320 | #endif
|
321 | #if LCD_LINES==4
|
322 | #if KS0073_4LINES_MODE
|
323 | if ( pos < LCD_START_LINE2 )
|
324 | addressCounter = LCD_START_LINE2;
|
325 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) )
|
326 | addressCounter = LCD_START_LINE3;
|
327 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) )
|
328 | addressCounter = LCD_START_LINE4;
|
329 | else
|
330 | addressCounter = LCD_START_LINE1;
|
331 | #else
|
332 | if ( pos < LCD_START_LINE3 )
|
333 | addressCounter = LCD_START_LINE2;
|
334 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) )
|
335 | addressCounter = LCD_START_LINE3;
|
336 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) )
|
337 | addressCounter = LCD_START_LINE4;
|
338 | else
|
339 | addressCounter = LCD_START_LINE1;
|
340 | #endif
|
341 | #endif
|
342 | lcd_command((1<<LCD_DDRAM)+addressCounter);
|
343 |
|
344 | }/* lcd_newline */
|
345 |
|
346 |
|
347 | /*
|
348 | ** PUBLIC FUNCTIONS
|
349 | */
|
350 |
|
351 | /*************************************************************************
|
352 | Send LCD controller instruction command
|
353 | Input: instruction to send to LCD controller, see HD44780 data sheet
|
354 | Returns: none
|
355 | *************************************************************************/
|
356 | void lcd_command(uint8_t cmd)
|
357 | {
|
358 | lcd_waitbusy();
|
359 | lcd_write(cmd,0);
|
360 | }
|
361 |
|
362 |
|
363 | /*************************************************************************
|
364 | Send data byte to LCD controller
|
365 | Input: data to send to LCD controller, see HD44780 data sheet
|
366 | Returns: none
|
367 | *************************************************************************/
|
368 | void lcd_data(uint8_t data)
|
369 | {
|
370 | lcd_waitbusy();
|
371 | lcd_write(data,1);
|
372 | }
|
373 |
|
374 |
|
375 |
|
376 | /*************************************************************************
|
377 | Set cursor to specified position
|
378 | Input: x horizontal position (0: left most position)
|
379 | y vertical position (0: first line)
|
380 | Returns: none
|
381 | *************************************************************************/
|
382 | void lcd_gotoxy(uint8_t x, uint8_t y)
|
383 | {
|
384 | #if LCD_LINES==1
|
385 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
|
386 | #endif
|
387 | #if LCD_LINES==2
|
388 | if ( y==0 )
|
389 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
|
390 | else
|
391 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
|
392 | #endif
|
393 | #if LCD_LINES==4
|
394 | if ( y==0 )
|
395 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
|
396 | else if ( y==1)
|
397 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
|
398 | else if ( y==2)
|
399 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x);
|
400 | else /* y==3 */
|
401 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x);
|
402 | #endif
|
403 |
|
404 | }/* lcd_gotoxy */
|
405 |
|
406 |
|
407 | /*************************************************************************
|
408 | *************************************************************************/
|
409 | int lcd_getxy(void)
|
410 | {
|
411 | return lcd_waitbusy();
|
412 | }
|
413 |
|
414 |
|
415 | /*************************************************************************
|
416 | Clear display and set cursor to home position
|
417 | *************************************************************************/
|
418 | void lcd_clrscr(void)
|
419 | {
|
420 | lcd_command(1<<LCD_CLR);
|
421 | }
|
422 |
|
423 |
|
424 | /*************************************************************************
|
425 | Set cursor to home position
|
426 | *************************************************************************/
|
427 | void lcd_home(void)
|
428 | {
|
429 | lcd_command(1<<LCD_HOME);
|
430 | }
|
431 |
|
432 |
|
433 | /*************************************************************************
|
434 | Display character at current cursor position
|
435 | Input: character to be displayed
|
436 | Returns: none
|
437 | *************************************************************************/
|
438 | void lcd_putc(char c)
|
439 | {
|
440 | uint8_t pos;
|
441 |
|
442 |
|
443 | pos = lcd_waitbusy(); // read busy-flag and address counter
|
444 | if (c=='\n')
|
445 | {
|
446 | lcd_newline(pos);
|
447 | }
|
448 | else
|
449 | {
|
450 | #if LCD_WRAP_LINES==1
|
451 | #if LCD_LINES==1
|
452 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
|
453 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
|
454 | }
|
455 | #elif LCD_LINES==2
|
456 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
|
457 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);
|
458 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ){
|
459 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
|
460 | }
|
461 | #elif LCD_LINES==4
|
462 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
|
463 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);
|
464 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ) {
|
465 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE3,0);
|
466 | }else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH ) {
|
467 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE4,0);
|
468 | }else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH ) {
|
469 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
|
470 | }
|
471 | #endif
|
472 | lcd_waitbusy();
|
473 | #endif
|
474 | lcd_write(c, 1);
|
475 | }
|
476 |
|
477 | }/* lcd_putc */
|
478 |
|
479 |
|
480 | /*************************************************************************
|
481 | Display string without auto linefeed
|
482 | Input: string to be displayed
|
483 | Returns: none
|
484 | *************************************************************************/
|
485 | void lcd_puts(const char *s)
|
486 | /* print string on lcd (no auto linefeed) */
|
487 | {
|
488 | register char c;
|
489 |
|
490 | while ( (c = *s++) ) {
|
491 | lcd_putc(c);
|
492 | }
|
493 |
|
494 | }/* lcd_puts */
|
495 |
|
496 |
|
497 | /*************************************************************************
|
498 | Display string from program memory without auto linefeed
|
499 | Input: string from program memory be be displayed
|
500 | Returns: none
|
501 | *************************************************************************/
|
502 | void lcd_puts_p(const char *progmem_s)
|
503 | /* print string from program memory on lcd (no auto linefeed) */
|
504 | {
|
505 | register char c;
|
506 |
|
507 | while ( (c = pgm_read_byte(progmem_s++)) ) {
|
508 | lcd_putc(c);
|
509 | }
|
510 |
|
511 | }/* lcd_puts_p */
|
512 |
|
513 |
|
514 | /*************************************************************************
|
515 | Initialize display and select type of cursor
|
516 | Input: dispAttr LCD_DISP_OFF display off
|
517 | LCD_DISP_ON display on, cursor off
|
518 | LCD_DISP_ON_CURSOR display on, cursor on
|
519 | LCD_DISP_CURSOR_BLINK display on, cursor on flashing
|
520 | Returns: none
|
521 | *************************************************************************/
|
522 | void lcd_init(uint8_t dispAttr)
|
523 | {
|
524 | #if LCD_IO_MODE
|
525 | /*
|
526 | * Initialize LCD to 4 bit I/O mode
|
527 | */
|
528 |
|
529 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
530 | && ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT)
|
531 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)
|
532 | && (LCD_RS_PIN == 4 ) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6 ) )
|
533 | {
|
534 | /* configure all port bits as output (all LCD lines on same port) */
|
535 | DDR(LCD_DATA0_PORT) |= 0x7F;
|
536 | }
|
537 | else if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
538 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
|
539 | {
|
540 | /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */
|
541 | DDR(LCD_DATA0_PORT) |= 0x0F;
|
542 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
543 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
544 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
545 | }
|
546 | else
|
547 | {
|
548 | /* configure all port bits as output (LCD data and control lines on different ports */
|
549 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
550 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
551 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
552 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
553 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
554 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
555 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
556 | }
|
557 |
|
558 | delay(16000); /* wait 16ms or more after power-on */
|
559 | PORTD = PORTD | 0b00010000;
|
560 | /* initial write to lcd is 8bit */
|
561 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // _BV(LCD_FUNCTION)>>4;
|
562 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4;
|
563 | lcd_e_toggle();
|
564 | delay(4992); /* delay, busy flag can't be checked here */
|
565 | /* repeat last command */
|
566 | lcd_e_toggle();
|
567 | delay(64); /* delay, busy flag can't be checked here */
|
568 |
|
569 |
|
570 | /* repeat last command a third time */
|
571 | lcd_e_toggle();
|
572 | delay(64); /* delay, busy flag can't be checked here */
|
573 |
|
574 |
|
575 | /* now configure for 4bit mode */
|
576 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4
|
577 | lcd_e_toggle();
|
578 | delay(64); /* some displays need this additional delay */
|
579 |
|
580 |
|
581 | /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */
|
582 | #else
|
583 | /*
|
584 | * Initialize LCD to 8 bit memory mapped mode
|
585 | */
|
586 |
|
587 | /* enable external SRAM (memory mapped lcd) and one wait state */
|
588 | MCUCR = _BV(SRE) | _BV(SRW);
|
589 |
|
590 | /* reset LCD */
|
591 | delay(16000); /* wait 16ms after power-on */
|
592 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
593 | delay(4992); /* wait 5ms */
|
594 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
595 | delay(64); /* wait 64us */
|
596 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
597 | delay(64); /* wait 64us */
|
598 | #endif
|
599 |
|
600 | #if KS0073_4LINES_MODE
|
601 | /* Display with KS0073 controller requires special commands for enabling 4 line mode */
|
602 | lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);
|
603 | lcd_command(KS0073_4LINES_MODE);
|
604 | lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);
|
605 | #else
|
606 | lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
|
607 | #endif
|
608 | lcd_command(LCD_DISP_OFF); /* display off */
|
609 | lcd_clrscr(); /* display clear */
|
610 | lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
|
611 | lcd_command(dispAttr); /* display/cursor control */
|
612 |
|
613 | }/* lcd_init */
|