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