/* Drive an HD44780 LCD display in 4-bit mode. Adam Sampson */ #include #include #include #include "lcd.h" static const uint8_t lcd_mask = _BV(LCD_E) | _BV(LCD_RS) | (0xF << LCD_D4); // Busy-wait for at least the given number of ms. void lcd_delay(uint16_t ms) { while (--ms != 0) { uint16_t i = (F_CPU / 1000) / 4; __asm__ __volatile__ ( "1:\tsbiw %0,1\n" "\tbrne 1b\n" : "=w" (i) : "0" (i)); } } static void lcd_nibble(uint8_t nibble, bool is_cmd) { uint8_t v = nibble << LCD_D4; if (!is_cmd) v |= _BV(LCD_RS); LCD_PORT = (LCD_PORT & ~lcd_mask) | v | _BV(LCD_E); lcd_delay(1); LCD_PORT &= ~_BV(LCD_E); lcd_delay(2); } void lcd_word(uint8_t word, bool is_cmd) { lcd_nibble((word >> 4) & 0xF, is_cmd); lcd_nibble(word & 0xF, is_cmd); } void lcd_clear() { lcd_word(CMD_CLEAR, true); lcd_delay(4); } void lcd_move(uint8_t x, uint8_t y) { lcd_word(CMD_SETDD | (0x40 * y) | x, true); } void lcd_puts(const char *s) { while (*s != '\0') lcd_word(*s++, false); } void lcd_init() { // Set the LCD pins to be outputs. LCD_DDR |= lcd_mask; lcd_delay(20); for (int i = 0; i < 3; i++) { lcd_nibble((CMD_FUNCSET | FUNCSET_DL) >> 4, true); lcd_delay(5); } lcd_nibble(CMD_FUNCSET >> 4, true); lcd_word(CMD_FUNCSET | FUNCSET_N, true); lcd_word(CMD_DISPCTL | DISPCTL_D, true); lcd_word(CMD_ENTRYSET | ENTRYSET_ID, true); lcd_clear(); }