#include "lcd.h" #include /* The following 2 functions are not called directly but via the macro's _lcd_delay_us_small or _lcd_delay_us which calculate the parameter t using the delay in us and the microcontroller clock frequence F_CPU in Hz. _lcd_delay_us_small can be used for us <=47 (for worst case F_CPU == 16000000) _lcd_delay_us can be used for us <=16128 (for worst case F_CPU == 16000000) These functions and macro's are written by Jesse. */ /* One byte delay loop, one loop costs 3 cycles. */ void _lcd_delay_8(uint8_t t) { asm volatile ("\n" "L_dl0%=: subi %0,1" "\n\t" " brcc L_dl0%=" "\n\t" :: "r" (t)); } /* Two byte delay loop, one loop costs 4 cycles. */ void _lcd_delay_16(uint16_t t) { asm volatile ("\n" "L_dl1%=: subi %A0,1" "\n\t" " sbci %B0,0" "\n\t" " brcc L_dl1%=" "\n\t" :: "r" (t)); } // LCD is connected on PORTA in 4bit mode // Databus is connected to high nibble // PA4 == DB4 // PA5 == DB5 // PA6 == DB6 // PA7 == DB7 // Controlbus is connected to low nibble // configuration can be changed by the following defines // PA0 is Not Connected and is NOT AFFECTED by this LCD software #define _LCD_E PA1 #define _LCD_RW PA2 #define _LCD_RS PA3 uint8_t lcd_read_command(void) { uint8_t command; DDRA |= 1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS; // control bus output DDRA &= ~0xF0; // databus input PORTA |= 1<<_LCD_RW | 0xF0; // R/!W= 1 (Read) and Pullup inputs PORTA &= ~(1<<_LCD_RS); // RS=0 _lcd_delay_us_small(2); PORTA |= 1<<_LCD_E; // E=1 _lcd_delay_us_small(1); command = PINA & 0xF0; // read high nibble PORTA &= ~(1<<_LCD_E); // E=0 _lcd_delay_us_small(2); PORTA |= 1<<_LCD_E; // E=1 _lcd_delay_us_small(1); command |= PINA >> 4; // read low nibble PORTA &= ~(1<<_LCD_E); // E=0 return command; } uint8_t lcd_read_data(void) { uint8_t data; DDRA |= 1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS; DDRA &= ~0xF0; PORTA |= 1<<_LCD_RW | 1<<_LCD_RS | 0xF0; // R/!W= 1 (Read) RS=1 and Pullup inputs _lcd_delay_us_small(2); PORTA |= 1<<_LCD_E; _lcd_delay_us_small(1); data = PINA & 0xF0; PORTA &= ~(1<<_LCD_E); _lcd_delay_us_small(2); PORTA |= 1<<_LCD_E; _lcd_delay_us_small(1); data |= PINA>>4; PORTA &= ~(1<<_LCD_E); return data; } static void wait(void) { while (lcd_read_command() & 0x80); } static void pos_pulse_E(void) { _lcd_delay_us_small(2); PORTA |= 1<<_LCD_E; // E=1 _lcd_delay_us_small(1); PORTA &= ~(1<<_LCD_E); // E=0 } void lcd_write_command(uint8_t command) { wait(); DDRA |= 1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0; // controlbus and databus output PORTA &= ~(1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0); PORTA |= command & 0xF0; // all control signals low RS=0 R/!W=0 pos_pulse_E();// write high nibble PORTA &= ~(1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0); PORTA |= command << 4; // all control signals low RS=0 R/!W=0 pos_pulse_E();// write low nibble } void lcd_write_data(uint8_t data) { wait(); DDRA |= 1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0; PORTA &= ~(1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0); PORTA |= (data & 0xF0) | 1<<_LCD_RS; // RS=1 other control signals 0 R/!W=0 pos_pulse_E(); PORTA &= ~(1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0); PORTA |= (data << 4) | 1<<_LCD_RS; pos_pulse_E(); } void lcd_init(void) { DDRA |= 1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0; _lcd_delay_us(15000); PORTA &= ~(1<<_LCD_E | 1<<_LCD_RW | 1<<_LCD_RS | 0xF0); PORTA |= 0x30; // all control signals low RS=0 R/!W=0 pos_pulse_E(); _lcd_delay_us(4100); pos_pulse_E(); _lcd_delay_us(100); pos_pulse_E(); _lcd_delay_us(100); PORTA &= ~0x10; pos_pulse_E(); _lcd_delay_us(100); lcd_write_command(0x28); lcd_write_command(0x06); lcd_cls(); lcd_cursor(true, true); } void lcd_cls(void) { lcd_write_command(0x01); } void lcd_home(void) { lcd_write_command(0x02); } void lcd_cursor(bool cursorOn, bool cursorBlinks) { lcd_write_command(0x0C + (cursorOn ? 0x02 : 0) + (cursorBlinks ? 0x01 : 0)); } void lcd_goto(uint8_t row, uint8_t column) { if (row < 2 && column < 16) { lcd_write_command(0x80 + row * 0x40 + column); } } uint8_t lcd_get_row(void) { wait(); return lcd_read_command() & 1<<6 ? 1 : 0; } uint8_t lcd_get_column(void) { wait(); return lcd_read_command() & 0x3f; } void lcd_putc(char data) { lcd_write_data(data); } void lcd_puts(char *s) { while (*s) { lcd_putc(*s++); } } void lcd_puts_P(const char* PROGMEM s) { char c; while ((c = pgm_read_byte(s++))) lcd_putc(c); }