Subversion Repositories HomeAutomation

Rev

Rev 675 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

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