Subversion Repositories HomeAutomation

Rev

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