/* vim: set sw=8 ts=8 si : */ /**************************************************************************** Title : HD44780U LCD library Authors: Based on Volker Oth's lcd library (http://members.xoom.com/volkeroth) modified by Peter Fleury's (http://jump.to/fleury). Flexible pin configuration by Markus Ermert. Adapted for the linuxfocus LCD display by Guido Socher. Software: AVR-GCC with AVR-AS Target: any AVR device Copyright: GPL *****************************************************************************/ #include <io.h> #include <progmem.h> #include "avr-util.h" #include "lcd_hw.h" #include "lcd.h" /* ** constants/macros */ #define DDR(x) ((x)-1) /* address of data direction register of port x */ #define PIN(x) ((x)-2) /* address of input register of port x */ #if LCD_IO_MODE /* #define lcd_e_delay() delay_us(1) */ #define lcd_e_delay() asm volatile("rjmp _PC_+0") /* delay 500ns with 4Mhz */ #define lcd_e_high() sbi(LCD_E_PORT, LCD_E_PIN) #define lcd_e_low() cbi(LCD_E_PORT, LCD_E_PIN) #define lcd_e_toggle() toggle_e() #define lcd_cmd_mode() cbi(LCD_RS_PORT, LCD_RS_PIN) /* RS=0 command mode */ #define lcd_data_mode() sbi(LCD_RS_PORT, LCD_RS_PIN) /* RS=1 data mode */ #define lcd_wr_mode() cbi(LCD_RW_PORT, LCD_RW_PIN) /* RW=0 write mode */ #define lcd_rd_mode() sbi(LCD_RW_PORT, LCD_RW_PIN) /* RW=1 read mode */ #define lcd_data_port_in() { /* defines all data pins as input */ \ cbi(DDR(LCD_DATA_PORT_D7),LCD_DATA_PIN_D7);\ cbi(DDR(LCD_DATA_PORT_D6),LCD_DATA_PIN_D6);\ cbi(DDR(LCD_DATA_PORT_D5),LCD_DATA_PIN_D5);\ cbi(DDR(LCD_DATA_PORT_D4),LCD_DATA_PIN_D4);\ } #define lcd_data_port_out() { /* defines all data pins as output */ \ sbi(DDR(LCD_DATA_PORT_D7),LCD_DATA_PIN_D7);\ sbi(DDR(LCD_DATA_PORT_D6),LCD_DATA_PIN_D6);\ sbi(DDR(LCD_DATA_PORT_D5),LCD_DATA_PIN_D5);\ sbi(DDR(LCD_DATA_PORT_D4),LCD_DATA_PIN_D4);\ } #endif #if LCD_IO_MODE #if LCD_LINES==1 #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE #else #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES #endif #else #if LCD_LINES==1 #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE #else #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES #endif #endif /* ** function prototypes */ #if LCD_IO_MODE static void toggle_e(void); static void lcd_out_high(u08 d); static void lcd_out_low(u08 d); #endif /* ** local functions */ #if LCD_IO_MODE static void lcd_out_low(u08 d) { /* output low nibble */ if (d&0x08) sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7); else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7); if (d&0x04) sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6); else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6); if (d&0x02) sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5); else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5); if (d&0x01) sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4); else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4); } static void lcd_out_high(u08 d) { /* output high nibble */ if (d&0x80) sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7); else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7); if (d&0x40) sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6); else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6); if (d&0x20) sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5); else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5); if (d&0x10) sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4); else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4); } static void toggle_e(void) /* toggle Enable Pin */ { lcd_e_high(); lcd_e_delay(); lcd_e_low(); } #endif #if LCD_IO_MODE static void lcd_write(u08 data, u08 rs) { /* configure data pins as output */ lcd_data_port_out(); /* output high nibble first */ lcd_out_high(data); if (rs) lcd_data_mode(); /* RS=1: write data */ else lcd_cmd_mode(); /* RS=0: write instruction */ lcd_wr_mode(); /* RW=0 write mode */ lcd_e_toggle(); /* output low nibble */ lcd_out_low(data); if (rs) lcd_data_mode(); /* RS=1: write data */ else lcd_cmd_mode(); /* RS=0: write instruction */ lcd_wr_mode(); /* RW=0 write mode */ lcd_e_toggle(); /* all data pins high (inactive) */ lcd_data_port_in(); } #else /* Memory mapped mode */ #define lcd_write(d,rs) if (rs) *(volatile u08*)(LCD_IO_DATA) = d; else *(volatile u08*)(LCD_IO_FUNCTION) = d; /* rs==0 -> write instruction to LCD_IO_FUNCTION */ /* rs==1 -> write data to LCD_IO_DATA */ #endif #if LCD_IO_MODE static u08 lcd_read(u08 rs) { register u08 data; /* configure data pins as input */ lcd_data_port_in(); if (rs) lcd_data_mode(); /* RS=1: read data */ else lcd_cmd_mode(); /* RS=0: read busy flag */ lcd_rd_mode(); /* RW=1 read mode */ lcd_e_high(); lcd_e_delay(); /* read high nibble first */ data = bit_is_set(PIN(LCD_DATA_PORT_D7), LCD_DATA_PIN_D7) ? 0x80 : 0; data |= bit_is_set(PIN(LCD_DATA_PORT_D6), LCD_DATA_PIN_D6) ? 0x40 : 0; data |= bit_is_set(PIN(LCD_DATA_PORT_D5), LCD_DATA_PIN_D5) ? 0x20 : 0; data |= bit_is_set(PIN(LCD_DATA_PORT_D4), LCD_DATA_PIN_D4) ? 0x10 : 0; lcd_e_low(); lcd_e_delay(); /* Enable low */ lcd_e_high(); lcd_e_delay(); /* read low nibble */ data |= bit_is_set(PIN(LCD_DATA_PORT_D7), LCD_DATA_PIN_D7) ? 0x08 : 0; data |= bit_is_set(PIN(LCD_DATA_PORT_D6), LCD_DATA_PIN_D6) ? 0x04 : 0; data |= bit_is_set(PIN(LCD_DATA_PORT_D5), LCD_DATA_PIN_D5) ? 0x02 : 0; data |= bit_is_set(PIN(LCD_DATA_PORT_D4), LCD_DATA_PIN_D4) ? 0x01 : 0; lcd_e_low(); return (data); } #else #define lcd_read(rs) (rs) ? *(volatile u08*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile u08*)(LCD_IO_FUNCTION+LCD_IO_READ) /* rs==0 -> read instruction from LCD_IO_FUNCTION */ /* rs==1 -> read data from LCD_IO_DATA */ #endif static unsigned char lcd_waitbusy(void) /* loops while lcd is busy, reads address counter */ { register unsigned char c; while ((c = lcd_read(0)) & (1 << LCD_BUSY)) { } return (c); // return address counter=position } /* ** PUBLIC FUNCTIONS */ void lcd_command(u08 cmd) /* send commando <cmd> to LCD */ { lcd_waitbusy(); lcd_write(cmd, 0); } void lcd_gotoxy(u08 x, u08 y) /* goto position (x,y) */ { #if LCD_LINES==1 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); #endif #if LCD_LINES==2 if (y == 0) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); else lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); #endif #if LCD_LINES==3 if (y == 0) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); else if (y == 1) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); else if (y == 2) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x); #endif #if LCD_LINES==4 if (y == 0) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); else if (y == 1) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); else if (y == 2) lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x); else /* y==3 */ lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x); #endif } /* lcd_gotoxy */ void lcd_clrscr(void) /* clear lcd and set cursor to home position */ { lcd_command(1 << LCD_CLR); } void lcd_home(void) /* set cursor to home position */ { lcd_command(1 << LCD_HOME); } void lcd_putc(char c) /* print character at current cursor position */ { lcd_waitbusy(); // read busy-flag and address counter lcd_write((unsigned char)c, 1); } void rolltext_lcd_p(prog_char *text, int shiftlen){ unsigned char i; unsigned char j; unsigned char textlen=0; while (PRG_RDB(text+textlen)){ textlen++; } if (shiftlen <= ROLLLEN){ i=0; j=ROLLLEN-shiftlen + 1; while(i < j){ lcd_putc(' '); i++; } j=0; }else{ j=shiftlen-ROLLLEN; i=0; } if (j <= textlen) { while(i < ROLLLEN){ if (PRG_RDB(text+j)=='\0') break; lcd_putc(PRG_RDB(text+j)); j++; i++; } } } void lcd_puts(const char *s) /* print string on lcd */ { while (*s) { lcd_putc(*s); s++; } } void lcd_puts_p(const prog_char *progmem_s) /* print string from program memory on lcd */ { register char c; while ((c = PRG_RDB(progmem_s++))) { lcd_putc(c); } } void lcd_init(u08 dispAttr) /* initialize display and select type of cursor */ /* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */ { #if LCD_IO_MODE /*------ Initialize lcd to 4 bit i/o mode -------*/ lcd_data_port_out(); /* all data port bits as output */ sbi(DDR(LCD_RS_PORT), LCD_RS_PIN); /* RS pin as output */ sbi(DDR(LCD_RW_PORT), LCD_RW_PIN); /* RW pin as output */ sbi(DDR(LCD_E_PORT), LCD_E_PIN); /* E pin as output */ delay_us(16000); /* wait 16ms or more after power-on */ /* initial write to lcd is 8bit */ lcd_out_high(LCD_FUNCTION_8BIT_1LINE); lcd_e_toggle(); delay_us(4992); /* delay, busy flag can't be checked here */ lcd_out_high(LCD_FUNCTION_8BIT_1LINE); lcd_e_toggle(); delay_us(64); /* delay, busy flag can't be checked here */ lcd_out_high(LCD_FUNCTION_8BIT_1LINE); lcd_e_toggle(); delay_us(64); /* delay, busy flag can't be checked here */ lcd_out_high(LCD_FUNCTION_4BIT_1LINE); /* set IO mode to 4bit */ lcd_e_toggle(); /* from now the lcd only accepts 4 bit I/O, we can use lcd_command() */ #else /*----- Initialize lcd to 8 bit memory mapped mode ------*/ /* enable external SRAM (memory mapped lcd) and one wait state */ /* add -Wl,--defsym,__init_mcucr__=0xC0 to the link command */ /* or uncomment the next line: */ outp((1 << SRE) | (1 << SRW), MCUCR); /* reset lcd */ delay_us(16000); /* wait 16ms after power-on */ lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */ delay_us(4992); /* wait 5ms */ lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */ delay_us(64); /* wait 64us */ lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */ delay_us(64); /* wait 64us */ #endif lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */ lcd_command(LCD_DISP_OFF); /* display off */ lcd_clrscr(); /* display clear */ lcd_command(LCD_MODE_DEFAULT); /* set entry mode */ lcd_command(dispAttr); /* display/cursor control */ } /* lcd_init */
mirror server hosted at Truenetwork, Russian Federation.