Управление ЖК-дисплеем HD44780 довольно простое. Он имеет параллельную шину на 8 пин и три управляющих линии.
Их можно посмотреть, например, в Вики, я бы рекомендовал посмотреть datasheet на HD44780U, там они очень подробно рассмотрены, даже с иллюстрациями. Еще полезная штука - онлайн эмулятор HD44780, в котором мышкой можно "подергать" пины и научиться подавать команды. Очень помогает разобраться, что к чему.
В Arduino есть дефолтовая библиотека LiquidCrystal, в которой, в конструкторе можно задать какими именно GPIO подключаться к дисплею. Однако, для 8-разрядного микроконтроллера предпочтительно использовать 4-битный режим работы дисплея, и подключать его к GPIO одного порта. Тогда писать в дисплей можно будет "пакетами" по 6 бит. В ATmega8/168/328 есть порт D первые два пина которого заняты UART'ом, остаются еще 6 - т.е. ровно столько, сколько нужно для дисплея. Т.о. подключение будет таким:
т.е.
RS <==> PD2 (он же pin2 Arduino); E <==> PD3 (он же pin3 Arduino); D4 <==> PD4 (он же pin4 Arduino); D5 <==> PD5 (он же pin5 Arduino); D6 <==> PD6 (он же pin6 Arduino); D7 <==> PD7 (он же pin7 Arduino); RW <==> GND;
Дело за малым. Текст программы:
/* for ATmega8/168/328 display HD44780 support site: http://countzero.weebly.com avr-gcc -mmcu=atmega8 -Wall -Os -o lcd.elf lcd.c avr-objcopy -O ihex lcd.elf lcd.hex*/ #define F_CPU 16000000UL #include <avr/io.h> #include <util/delay.h> #define LCD_RS 2 #define LCD_E 3 #define LCD_D4 4 #define LCD_D5 5 #define LCD_D6 6 #define LCD_D7 7 #define LCD_PORT DDRD #define LCD PORTD #define CMD 0 // command #define DTA 1 // data #define LCD_CLEAR 0x01 #define LCD_OFF 0x08 #define LCD_ON 0x0C #define LCD_RETURN 0x02 // for 4bit mode static int send_lcd(uint8_t value, uint8_t mode) { LCD&=0x03; // clear LCD|=(value&0xF0)|(mode<<LCD_RS)|(1<<LCD_E); LCD&=0x03; LCD|=(value<<4)|(mode<<LCD_RS)|(1<<LCD_E); LCD&=~(1<<LCD_E); _delay_ms(5); return 0; } static int print_lcd(char* str) { uint8_t i; i=0; while(str[i] !=0 && i<255) { send_lcd(str[i],DTA); i++; }; return i; }; static int init_lcd() { LCD_PORT=0xFC; // pin 2,3,4,5,6,7 in OUTPUT mode _delay_ms(50); // 4bit mode LCD&=0b11; // clear LCD |=(1<<LCD_D5)|(1<<LCD_E); LCD&=0b11; // clear LCD |=(1<<LCD_D5); _delay_ms(5); send_lcd(0x28,CMD); // mode: 4bit, 2 lines send_lcd(LCD_OFF,CMD); send_lcd(LCD_CLEAR,CMD); send_lcd(0x06,CMD); // seek mode: right send_lcd(LCD_ON,CMD); return 0; } int main(void) { init_lcd(); print_lcd("Hello"); send_lcd(0xC0,CMD); // position on second line print_lcd(" World!"); send_lcd(LCD_RETURN,CMD); for(;;){}; return 0; }
Программа только выводит "Hello World!" на дисплей и больше ничего не делает. Самое сложное в ней, это функция send_lcd которая посылает байт на контроллер дисплея в 4-битном режиме. В этом режиме посылаются сначала старшие четыре разряда, затем младшие. Т.к. нельзя трогать PD0/PD1 которые заняты под UART, приходится использовать битовые операции вместо присваивания. Обнуление в сочетании с логическим сложением аналогично присваиванию. Остальное, думаю, понятно. Итоговая прошивка для ATmega8 занимает около 330 байт.