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 12000000UL // we use 8 MHz but we set it to 12 to increase delay and
18 // make it work better with slow LCDs
19 #include <util/delay.h>
24 /* compatibilty macros for old style */
26 #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
30 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
38 #define lcd_e_high() sbi(LCD_E_PORT, LCD_E_PIN)
39 #define lcd_e_low() cbi(LCD_E_PORT, LCD_E_PIN)
41 #define lcd_cmd_mode() cbi(LCD_RS_PORT, LCD_RS_PIN) /* RS=0 command mode */
42 #define lcd_data_mode() sbi(LCD_RS_PORT, LCD_RS_PIN) /* RS=1 data mode */
43 #define lcd_data_port_out() { /* defines all data pins as output */ \
44 sbi(LCD_DATA_DDR_D7,LCD_DATA_PIN_D7);\
45 sbi(LCD_DATA_DDR_D6,LCD_DATA_PIN_D6);\
46 sbi(LCD_DATA_DDR_D5,LCD_DATA_PIN_D5);\
47 sbi(LCD_DATA_DDR_D4,LCD_DATA_PIN_D4);\
51 #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
53 #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
57 ** function prototypes
59 static void lcd_e_toggle(void);
60 static void lcd_out_high(uint8_t d);
61 static void lcd_out_low(uint8_t d);
67 void lcd_delay_ms(uint8_t ms)
68 // delay for a minimum of <ms>
76 static void lcd_out_low(uint8_t d)
77 { /* output low nibble */
78 if (d&0x08) sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
79 else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
80 if (d&0x04) sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
81 else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
82 if (d&0x02) sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
83 else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
84 if (d&0x01) sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
85 else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
87 static void lcd_out_high(uint8_t d)
88 { /* output high nibble */
89 if (d&0x80) sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
90 else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
91 if (d&0x40) sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
92 else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
93 if (d&0x20) sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
94 else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
95 if (d&0x10) sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
96 else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
99 static void lcd_e_toggle(void)
100 /* toggle Enable Pin */
109 static void lcd_write(uint8_t data, uint8_t rs)
111 // configure data pins as output, already done at init
112 //lcd_data_port_out();
115 /* output high nibble first */
121 lcd_data_mode(); /* RS=1: write data */
123 lcd_cmd_mode(); /* RS=0: write instruction */
126 /* output low nibble */
131 lcd_data_mode(); /* RS=1: write data */
133 lcd_cmd_mode(); /* RS=0: write instruction */
139 static unsigned char lcd_waitcmd(unsigned char cmdwait)
140 /* this function used to loop while lcd is busy and read address i
141 * counter however for this we need the RW line. This function
142 * has been changed to just delay a bit. In that case the LCD
143 * is only slightly slower but we do not need the RW pin. */
146 /* the display needs much longer to process a command */
158 void lcd_command(uint8_t cmd)
159 /* send commando <cmd> to LCD */
167 void lcd_gotoxy(uint8_t x, uint8_t y)
168 /* goto position (x,y) */
171 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
175 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
177 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
181 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
183 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
185 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
189 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
191 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
193 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
195 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x);
202 void lcd_putc(char c)
203 /* print character at current cursor position */
206 lcd_write((unsigned char)c, 1);
211 void lcd_puts(const char *s)
212 /* print string on lcd */
222 void lcd_puts_p(const char *progmem_s ) // note this is how you would declare a variable: const char str_pstr[] PROGMEM = "FLASH STRING";
223 /* print string from program memory on lcd */
227 while ((c = pgm_read_byte(progmem_s++))) {
235 lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
236 lcd_command(LCD_DISP_OFF); /* display off */
237 lcd_clrscr(); /* display clear */
238 lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
239 lcd_command(LCD_DISP_ON); /* display/on no cursor */
244 /* initialize display and select type of cursor */
245 /* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */
247 /*------ Initialize lcd to 4 bit i/o mode -------*/
249 lcd_data_port_out(); /* all data port bits as output */
250 sbi(LCD_RS_DDR, LCD_RS_PIN); /* RS pin as output */
251 sbi(LCD_E_DDR, LCD_E_PIN); /* E pin as output */
254 lcd_delay_ms(12); /* wait 12ms or more after power-on */
256 /* initial write to lcd is 8bit */
257 lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
259 lcd_delay_ms(2); /* delay, busy flag can't be checked here */
261 lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
263 lcd_delay_ms(2); /* delay, busy flag can't be checked here */
265 lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
267 lcd_delay_ms(2); /* delay, busy flag can't be checked here */
269 lcd_out_high(LCD_FUNCTION_4BIT_1LINE); /* set IO mode to 4bit */
272 /* from now the lcd only accepts 4 bit I/O, we can use lcd_command() */