подпрограммы работы с ЖКИ 2*16  HD44780
написаны для 8-ми битной шины под 4 перевести думаю труда не составит
Проц Atmega64 такт. 8 МГц
Порт А- шина данных
Порт D- RS,E

.def t0          =r16          
.def lcd         =r17
.def cont        =r18
.def cpd         =r19

.equ RS          =PD6
.equ E           =PD7


.org OVF2addr  ;пропишем вектор по переполнению таймера в начале программы
rjmp tm2_per


;******** Подпрограмма инициализации портов **********

port_init:
      
      ldi t0,0b11111111
      out ddra,t0
      
      ldi t0,0b11000000
      out ddrd,t0
ret

;******** Подпрограмма инициализации ЖКИ **********
;Стандартные настройки для ЖКИ - две строки по 16 символов
;курсор отключен,знак 5*7.
lcd_init:
 
      ldi lcd,0b00111000
      rcall lcd_com
      rcall del
      
      ldi lcd,0b00001100
      rcall lcd_com
      rcall del
      
      ldi lcd,0b00111000
      rcall lcd_com
      rcall del

      ldi lcd,0b00000001
      rcall lcd_com
      rcall delay

ret

;******** Подпрограмма вывода команд в ЖКИ ********

lcd_com:

      push t0
      mov t0,lcd
 
      cbi portd,RS
      sbi portd,E
      out porta,t0
      cbi portd,E
 
      pop t0            

ret

;******** Подпрограмма вывода данных в ЖКИ ********

lcd_dat:

      push t0
      mov t0,lcd
 
      sbi portd,RS
      sbi portd,E
      out porta,t0
      cbi portd,E
 
      pop t0

ret

;******** Курсор ЖКИ вправо на Х позиций ********
;значение на сколько нужно сдвинуть записывается в регистр cpd перед вызовом подпрограммы

tem_right:
      
shift: 
      
      ldi lcd,0b00010100
      rcall lcd_com
      rcall del
      dec cpd
      brne shift

ret

;******** Курсор ЖКИ влево на Х позиций ********

tem_left:
      
shift_1: 
      
      ldi lcd,0b00010000
      rcall lcd_com
      rcall del
      dec cpd
      brne shift_1

ret

;Пример: Перевод курсора на вторую строку после вывода 16 символов

;     ldi cpd,24
;     rcall tem_right
;     rcall delay


;******** Курсор ЖКИ влево на одну позицию ********
lcd_left:
      
      ldi lcd,0b00010000
      rcall lcd_com
      rcall del
ret

;******** Курсор ЖКИ вправо на одну позицию *******
lcd_right:

      ldi lcd,0b00010100
      rcall lcd_com
      rcall del
ret

;******** Очистка ЖКИ ********
lcd_clear:
      
      ldi lcd,0b00000001
      rcall lcd_com
      rcall delay

ret

;******* Задержки для ЖКИ *******

;******** Настройка таймера2 на 40мкс **********

timer2_4_0:
      
	  ldi t0,0xd9
      out TCNT2,t0
      
	  ldi t0,(0b010<<CS20)
      out TCCR2,t0 
      
	  ldi t0,(1<<TOIE2)
      out TIMSK,t0

ret

;******** Настройка таймера2 на 1,5мс **********

timer2_1_5:
      
	  ldi t0,0x68
      out TCNT2,t0
      
	  ldi t0,(0b011<<CS20)
      out TCCR2,t0
      
	  ldi t0,(1<<TOIE2)
      out TIMSK,t0

ret

;Собственно это и есть задержки. Ждем прерывание по переполнению таймера 
;в регистр cont записываем 0b00000001. в подпрограмме wait проверяем наличие 1 в 
;нулевом разряде, если есть значит задержка прошла-выходим.

tm2_per:

      ldi cont,0b00000001
reti

del:
 
      rcall timer2_4_0
      rcall wait

ret

delay:

      rcall timer2_1_5
      rcall wait

ret

wait:
n:
      sbrs cont,0
      rjmp n
      clr cont

ret
