/* * "THE BEER-WARE LICENSE" (Revision 42): * Martin Wenger and Stefan Rupp * wrote this file. As long as you retain this notice you can do whatever you want * with this stuff. If we meet some day, and you think this stuff is worth it, * you can buy me/us a beer in return. * (c) 2005-2010 Martin Wenger, Stefan Rupp * (c) 2014 Stefan Rupp */ #include #include #include #include // ==> _NOP() #include "timer.h" #include "lcd.h" #define LCD_DATA_PIN (PINA) #define LCD_DATA_PORT (PORTA) #define LCD_DATA_DIR (DDRA) #define LCD_DATA_MASK (0x0f) #if (F_CPU <= 4000000UL) #define WAIT_250_ns() _NOP() #elif (F_CPU <= 8000000UL) #define WAIT_250_ns() _NOP();_NOP() #elif (F_CPU <= 12000000UL) #define WAIT_250_ns() _NOP();_NOP();_NOP() #elif (F_CPU <= 16000000UL) #define WAIT_250_ns() _NOP();_NOP();_NOP();_NOP() #elif (F_CPU <= 20000000UL) #define WAIT_250_ns() _NOP();_NOP();_NOP();_NOP();_NOP() #else #include #define WAIT_250_ns() _delay_us(1) #endif #define LCD_DATA_MODE() (PORTA |= (1< t_enter + T_TIMEOUT) { return 0; } byte = lcd_read_byte(0); } while (byte & 0x80); return 1; } static inline void send_nibble(uint8_t nibble) { LCD_SET_WRITE(); LCD_DATA_PORT = (LCD_DATA_PORT & 0xf0) | (0x0f & nibble); LCD_SET_ENABLE(); WAIT_250_ns(); LCD_RESET_ENABLE(); } /** * Send one byte to the LCD * \param byte The byte to send to the LCD * \param RS specifies whether byte sent is data (RS==1) or command (RS==0) */ static inline int8_t lcd_send_byte(uint8_t byte, uint8_t RS) { if (lcd_wait_while_busy() ) { if (RS) LCD_DATA_MODE(); else LCD_CMD_MODE(); send_nibble(byte >> 4); _NOP(); send_nibble(0x0f & byte); return 1; } return 0; } int lcd_get(void) { if ( lcd_wait_while_busy() ) { return lcd_read_byte(1); } return -1; } int lcd_put(char c) { if (!lcd_initialized) { return 0; } return lcd_send_byte(c, 1); } void lcd_puts(char *s) { if (!lcd_initialized) { return; } while (*s) { //lcd_put(*s++); if (!lcd_send_byte(*s++, 1)) { return; } } return; } void lcd_cursor(uint8_t blink) { if (blink) { // enable display with cursor + blinking lcd_send_byte(0x0f, 0); } else { // enable display, no cursor, no blinking lcd_send_byte(0x0c, 0); return; } } void lcd_init(void) { /* Initialize both ATmega and Display * After return from this function, * display we be set to 4-bit data mode */ lcd_initialized = 0; // wait until LCD gets ready to accept instructions. timer_wait(50); // set CONTROL Pins as outputs: DDRA |= (0x70); LCD_CMD_MODE(); LCD_SET_WRITE(); // set LCD to 8-bit mode send_nibble(0x03); timer_wait(5); send_nibble(0x03); timer_wait(5); send_nibble(0x03); // LCD definitely is in 8-bit mode now // set module to 4-bit mode now // Remember! As we're in 8-bit mode now, // send_nibble is the right thing, not send_byte! timer_wait(5); send_nibble(0x02); timer_wait(5); // set to 5 x 8 dots per character, // 16 characters per line, 2 lines int success = lcd_send_byte(0x28, 0); if ( !success ) { return; } // enable display, no cursor, no blinking //lcd_send_byte(0x0c, 0); // enable display with cursor + blinking //lcd_send_byte(0x0f, 0); lcd_cursor(1); // Set display to // + Move cursor (and do not shift display) // + Move right lcd_send_byte(0x04, 0); // clear dislay lcd_clear(); lcd_initialized = 1; return; } void lcd_clear(void) { lcd_send_byte(0x01, 0); } void lcd_locate(uint8_t row, uint8_t col) { if (!lcd_initialized) { return; } if (row) col += 0x40; lcd_send_byte(0x80 + col, 0); }