lcd.c


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