1 /* vim: set sw=8 ts=8 si et: */
2 /****************************************************************************
3 Title : HD44780 LCD library
5 Based on Volker Oth's lcd library (http://members.xoom.com/volkeroth)
6 modified by Peter Fleury's (http://jump.to/fleury). Flexible pin
7 configuration by Markus Ermert. Adapted for the tuxgraphics LCD display
11 Target: any AVR device
14 *****************************************************************************/
16 #include <avr/pgmspace.h>
17 #define F_CPU 8000000UL // 8 MHz
18 #include <util/delay.h>
23 /* compatibilty macros for old style */
25 #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
29 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
37 #define lcd_e_high() sbi(LCD_E_PORT, LCD_E_PIN)
38 #define lcd_e_low() cbi(LCD_E_PORT, LCD_E_PIN)
40 #define lcd_cmd_mode() cbi(LCD_RS_PORT, LCD_RS_PIN) /* RS=0 command mode */
41 #define lcd_data_mode() sbi(LCD_RS_PORT, LCD_RS_PIN) /* RS=1 data mode */
42 #define lcd_data_port_out() { /* defines all data pins as output */ \
43 sbi(LCD_DATA_DDR_D7,LCD_DATA_PIN_D7);\
44 sbi(LCD_DATA_DDR_D6,LCD_DATA_PIN_D6);\
45 sbi(LCD_DATA_DDR_D5,LCD_DATA_PIN_D5);\
46 sbi(LCD_DATA_DDR_D4,LCD_DATA_PIN_D4);\
50 #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
52 #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
56 ** function prototypes
58 static void lcd_e_toggle(void);
59 static void lcd_out_high(uint8_t d);
60 static void lcd_out_low(uint8_t d);
66 void lcd_delay_ms(uint8_t ms)
67 // delay for a minimum of <ms>
75 static void lcd_out_low(uint8_t d)
76 { /* output low nibble */
77 if (d&0x08) sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
78 else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
79 if (d&0x04) sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
80 else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
81 if (d&0x02) sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
82 else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
83 if (d&0x01) sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
84 else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
86 static void lcd_out_high(uint8_t d)
87 { /* output high nibble */
88 if (d&0x80) sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
89 else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
90 if (d&0x40) sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
91 else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
92 if (d&0x20) sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
93 else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
94 if (d&0x10) sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
95 else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
98 static void lcd_e_toggle(void)
99 /* toggle Enable Pin */
108 static void lcd_write(uint8_t data, uint8_t rs)
110 // configure data pins as output, already done at init
111 //lcd_data_port_out();
114 /* output high nibble first */
120 lcd_data_mode(); /* RS=1: write data */
122 lcd_cmd_mode(); /* RS=0: write instruction */
125 /* output low nibble */
130 lcd_data_mode(); /* RS=1: write data */
132 lcd_cmd_mode(); /* RS=0: write instruction */
138 static unsigned char lcd_waitcmd(unsigned char cmdwait)
139 /* this function used to loop while lcd is busy and read address i
140 * counter however for this we need the RW line. This function
141 * has been changed to just delay a bit. In that case the LCD
142 * is only slightly slower but we do not need the RW pin. */
145 /* the display needs much longer to process a command */
157 void lcd_command(uint8_t cmd)
158 /* send commando <cmd> to LCD */
166 void lcd_gotoxy(uint8_t x, uint8_t y)
167 /* goto position (x,y) */
170 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
174 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
176 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
180 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
182 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
184 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
188 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
190 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
192 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
194 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x);
201 void lcd_putc(char c)
202 /* print character at current cursor position */
205 lcd_write((unsigned char)c, 1);
210 void lcd_puts(const char *s)
211 /* print string on lcd */
221 void lcd_puts_p(const prog_char *progmem_s)
222 /* print string from program memory on lcd */
226 while ((c = pgm_read_byte(progmem_s++))) {
234 lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
235 lcd_command(LCD_DISP_OFF); /* display off */
236 lcd_clrscr(); /* display clear */
237 lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
238 lcd_command(LCD_DISP_ON); /* display/on no cursor */
243 /* initialize display and select type of cursor */
244 /* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */
246 /*------ Initialize lcd to 4 bit i/o mode -------*/
248 lcd_data_port_out(); /* all data port bits as output */
249 sbi(LCD_RS_DDR, LCD_RS_PIN); /* RS pin as output */
250 sbi(LCD_E_DDR, LCD_E_PIN); /* E pin as output */
253 lcd_delay_ms(12); /* wait 12ms or more after power-on */
255 /* initial write to lcd is 8bit */
256 lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
258 lcd_delay_ms(2); /* delay, busy flag can't be checked here */
260 lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
262 lcd_delay_ms(2); /* delay, busy flag can't be checked here */
264 lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
266 lcd_delay_ms(2); /* delay, busy flag can't be checked here */
268 lcd_out_high(LCD_FUNCTION_4BIT_1LINE); /* set IO mode to 4bit */
271 /* from now the lcd only accepts 4 bit I/O, we can use lcd_command() */