/*
 * HD44780.asm
 *
 *  Created: 17.03.2013 9:07:14
 *   Author: sad
 */ 
  
 .def	temp=r16    ; директива .def назначает регистру r16 имя temp
 .def	temp1=r17
 .def	temp2=r18
 .def	temp3=r19
 .def	temp4=r20
 .def	temp5=r21
 .def	temp6=r22
 .def	temp7=r23
 .def	temp8=r24
 .def	Tx_b=r25
 
.equ	t1 = 180
.equ	t2 = 50
.equ	t3 = 250

.equ	E = 0		; нулевой вывод порта А
.equ	RS = 1		; 
.equ	DB7 = 7		; вывод порта В, подключенный к DB7 индикатора
.equ	DB6 = 6
.equ	DB5 = 5
.equ	DB4 = 4

.dseg
.org	0x60
flags:	.byte 1
Adress:	.byte 1	; LSB
Adress1:	.byte 1	; MSB
BCD_DT:	.byte 1		; Дес. тысяч
BCD_T:	.byte 1		; тысячи
BCD_S:	.byte 1		; Сотни 
BCD_D:	.byte 1		; десятки
BCD_E:	.byte 1		; единицы
Temps:	.byte 8		; Переменная для хранения регистров
Tim:	.byte 1		; при преобразованиях


;====================================================
; Начало программы
.cseg            ; директива .cseg определяет начало сегмента, где будет расположен
                    ; основной код программы. В AVR Studio 5 это директива не
                    ; обязательна
.org 0            ; начало первой строки программы
 rjmp Start       ; относительный переход к метке Start (в PIC соответствует 
                   ; команде goto)
rjmp INT_0
rjmp INT_1
rjmp Timer1_capt1
rjmp Timer1_comp1
rjmp Timer1_OVF1
rjmp Timer0_OVF0
rjmp UART_RX
rjmp UART_UDRE
rjmp UART_TX
rjmp ANA_COMP

;Start: ;сброс по питанию
INT_0:
INT_1:
Timer1_capt1:
;Timer1_comp1: ;счетчик
Timer1_OVF1:
Timer0_OVF0:
UART_UDRE:
UART_TX:
UART_RX:
ANA_COMP:
reti
; ====================================================
Start:

;PortX содержит информацию, предназначенную для вывода.
;PinX содержит вводимую информацию
;DDRX содержит информацию о том, какой канал настроен на ввод, какой - на вывод.

;То есть, DDRX определяет, грубо говоря, какая ножка микросхемы будет подключена к PinX, какая - к PortX:

;0 - ввод
;1 - вывод

ldi		temp,RamEnd
out		SPL,temp ; инициализация стека

ser temp; устанавливает все биты регистра temp  в 1
out DDRB,temp; переводит все биты на вывод
out DDRD,temp; порта B  и D на вывод
clr temp; обнуляет регистр temp (устанавливает все биты регистра temp в 0)
out PortB,temp; отключает подтягивающие резисторы 
out PortD,temp; портов B и D 
clr	temp
sts	flags,temp

ldi temp,0b01000000
out Timsk,temp ;разрешить прерывание компаратора
			;   101
ldi temp,0b00000100
out Tccr1b,temp ;тактовый сигнал /64

ldi temp,0xF4
out Ocr1ah,temp
ldi temp,0x24
out Ocr1al,temp ;запись числа сравнения 62500 (0.4сек. при 10мгц)

sei ; разрешение глобальных прерываний

	clr	temp
	sts	Adress1,temp
;******** ИНИЦИАЛИЗАЦИЯ ЖКИ ****************************
; Индикатор применим нерусифицированный, типа LM016
; 4 bits interfase
;******** Пауза более 30 мс + FUNCTION SET************

; Function set
	rcall	delay3		; >30 ms
	ldi		Tx_b,0b00110000 ;
	rcall	in_port
	cbi		Portb,RS		; instruction
	rcall	zapis		;(1)
	
	rcall	zapis		;(2)
	
	rcall	zapis		;(3)
		
	ldi		Tx_b,0b00100000	
	rcall	in_port
	rcall	zapis
	
; Function set
	ldi		Tx_b,0b00101000	
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   
; Display clear
	ldi		Tx_b,0b00001101
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   
	ldi		Tx_b,0b00000001	
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	rcall	delay2

	ldi		Tx_b,0b00000110	
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   
; Инициализация дисплея закончена
; Вывод информации находящейся в адресах
; 0x20 - 0xFF


	ldi		temp,0x20
	sts		Adress,temp		; Начальный адрес DDRAM
_one_:

clr	temp
sts	flags,temp
	
;Set_DDRAM_ADDRESS

	rcall	BIN_BCD

	cbi		Portb,RS
	ldi		Tx_b,131             ; db7=1, address=03h
    rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   
; Вывод символа 
	
	sbi		Portb,RS			; RS=1
	lds		Tx_b,BCD_DT        ; Значение десятков тысяч
	rcall	in_port
	rcall   zapis
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	
	lds		Tx_b,BCD_T        ; Значение тысяч
	rcall	in_port
	rcall   zapis
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   

	lds		Tx_b,BCD_S        ; Значение сотен
	rcall	in_port
	rcall   zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   

	lds		Tx_b,BCD_D        ; Значение десятков
	rcall	in_port
	rcall   zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   

	lds		Tx_b,BCD_E        ; Значение единиц
	rcall	in_port
	rcall   zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   

	ldi		Tx_b,0x1f	      ; пробел
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   

	lds		Tx_b,Adress
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   
; Выведем в порт слово

	cbi		Portb,RS
	ldi		Tx_b,171             ; db7=1, address=43h
    rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	sbi		Portb,RS

	ldi		Tx_b,'S'	      ; С
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	
	ldi		Tx_b,'i'	      ; и
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	
	ldi		Tx_b,'m'	      ; м
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	
	ldi		Tx_b,'b'	      ; в
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	
	ldi		Tx_b,'o'	      ; о
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	
	ldi		Tx_b,'l'	      ; л
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	in_port
	rcall	zapis
	   
	   		
; Для того, чтобы успеть записать значение с 
; экрана дисплея выполним задержку в виде выс
; тавленного в прерывании флага
	lds		temp,BCD_E
	cbi		Portd,2
	sbrc	temp,0
	sbi		Portd,2

	cbi		Portd,3
	sbrc	temp,1
	sbi		Portd,3

	cbi		Portd,4
	sbrc	temp,2
	sbi		Portd,4

	cbi		Portd,5
	sbrc	temp,3
	sbi		Portd,5



s8:
	lds		temp,flags
	tst		temp
	breq	s8
	clr		temp
	sts		flags,temp

	; Выполним проверку работы подавая питание на светодиод
	SBIC	Portd,1
	rjmp	out_3
	sbi		Portd,1
	rjmp	out_4
out_3:
	cbi		Portd,1
out_4:



; Clear display
	cbi		Portb,RS
	ldi		Tx_b,0b00000001
	rcall	in_port
	rcall	zapis
	   
	swap	Tx_b
	rcall	zapis
	rcall	delay2
	sbi		Portb,RS

	lds		Tx_b,Adress
	inc		Tx_b
	sts		Adress,Tx_b
	
	tst		Tx_b
	brne	s9
	ldi		Tx_b,0x20
	sts		Adress,Tx_b
s9:
	rjmp	_one_
	
	
; Процедура стробирования
zapis:     
	sbi		Portb,E		; E=1 - запись
	ldi		temp,5	; 1 мкс - пауза для записи
s3:
	nop
	nop
	dec		temp
	tst		temp
	brne	s3
	cbi		Portb,E		; 1 мкс - пауза для записи
	rcall	delay1
	ret

; Пауза >100 uS
delay1:
	ldi	temp,t1
s4:
	nop
	nop
	nop
	dec	temp 
	tst	temp
	brne	s4
	ret

; Процедура Паузы 2 (>4.1 мс) 
delay2:
	ldi	temp,t2
	ldi	temp1,0xff
	clr	temp2
s1:
	nop
	nop
	nop
	add	temp2,temp1
	tst	temp2
	brne s1
	dec	temp
	tst	temp
	brne	s1
	nop
	ret
;******** Процедура Паузы 3 (30 мс) ********************************************************************
delay3:
	ldi	temp,t3
	ldi	temp1,0xff
	clr	temp2
s2:
	nop
	nop
	nop
	nop
	add	temp2,temp1
	tst	temp2
	brne s2
	nop
	nop
	nop
	nop
	dec	temp
	tst	temp
	brne	s2
	ret

;******** Процедура записи байта сообщения в защелки портов
in_port:
	cbi		Portb,DB7	; Очистим вывод, подключенный к DB7
	sbrc	Tx_b,7		; Если бит 7 нулевой
	sbi		Portb,DB7	; пропустим эту команд
;------------------------------------
	cbi		Portb,DB6	; Очистим вывод, подключенный к DB6
	sbrc	Tx_b,6		; Если бит 6 нулевой
	sbi		Portb,DB6	; пропустим эту команду         
;------------------------------------
	cbi		Portb,DB5	; Очистим вывод, подключенный к DB5
	sbrc	Tx_b,5		; Если бит 5 нулевой
	sbi		Portb,DB5	; пропустим эту команду               
;------------------------------------
	cbi		Portb,DB4	; Очистим вывод, подключенный к DB4
	sbrc	Tx_b,4		; Если бит 4 нулевой
	sbi		Portb,DB4	; пропустим эту команду                    
;------------------------------------
	ret

BIN_BCD:
			
	clr	temp3
	clr	temp4
	clr	temp5
	clr	temp6
	clr	temp7

	lds	temp1,Adress
	lds	temp2,Adress1

	ldi		temp,16	; Запись в регистр числа проходов преобразования, 
						; равного суммарному количеству битов многоразрядного 
						; регистра LSB/MSB (8*2=16).
 ;------------------------------------------------------------------------------- 
 ; Примечание: процесс преобразования заканчивается при уменьшении числа проходов 
 ; преобразования, которые заложены в регистр TEMP (.16), до нуля. 
 ;------------------------------------------------------------------------------- 
 ; Циклический сдвиг влево. 
 ;-------------------------------------------------------------------------------          
Loop16:   
	clc
						; Циклический сдвиг влево 2-байтного двоичного числа, 
	rol	temp1			; записанного в группе регистров LSB/MSB,
	rol	temp2			; на одну позицию через бит С
	
	rol	temp7			; Циклический сдвиг влево будущего ответа,
	rol	temp6			; начиная с младшего (половину байт)
	rol	temp5			; на одну позицию через бит С
	
	dec	temp			
	tst	temp
	brne	adjDEC		; Если результат не=0, то переход в ПП adjDEC 
						; Если  результат =0, то программа исполняется далее.
	 
 ;----------------------------------------------- 
 ; Поразрядное распределение содержимого регистров LED1...3 (обоих 
 ; полубайтов) по младшим полубайтам регистров LED1...5.
 ; Число представлено в виде |0 6|5 5|3 6| в регистрах
 ; temp5,6,7
 ;----------------------------------------------- 

	mov		temp3,temp5		; Запись младшего полубайта LED3 
	andi	temp3,0x0f	; маскируем старший полубайт

	mov		temp4,temp6
	swap	temp4
	andi	temp4,0x0f

	mov		temp5,temp6
	andi	temp5,0x0f	; сохраним сотни

	mov		temp6,temp7
	andi	temp6,0xf0
	swap	temp6		; запишем десятки

	andi	temp7,0x0f
 ;---------------------------------------------- 
 ; Конец распределения. В младших полубайтах регистров LED1...7 установлены 
 ; двоично-десятичные числа в порядке возрастания разрядности. Старшие полубайты = 0. 
 ;---------------------------------------------- 
 ; Прибавим к числам число 30h для получения кода ASCII
	ori		temp3,0x30
	ori		temp4,0x30
	ori		temp5,0x30
	ori		temp6,0x30
	ori		temp7,0x30
	sts		BCD_DT,temp3	; load number
	sts		BCD_T,temp4
	sts		BCD_S,temp5
	sts		BCD_D,temp6
	sts		BCD_E,temp7
	ret		          ; Переход по стеку в группу подпрограмм   
                     ; 8-разрядной динамической индикации.  
 ;---------------------------------------------- 
 ; Запись в регистр FSR адресов регистров LED1...3 для дальнейшей косвенной адресации 
 ; к ним в ПП adjBCD. 
 ; Переход к обработке следующего LED - после возврата по стеку.                       
 ;--------------------------------------------- 
 adjDEC:
	nop
	st		X,temp7		; значение temp7 загружено в r0
	rcall	adjBCD
	mov		temp7,r0
	st		X,temp6		; значение temp7 загружено в r0
	rcall	adjBCD
	mov		temp6,r0
	st		X,temp5		; значение temp7 загружено в r0
	rcall	adjBCD
	mov		temp5,r0
	rjmp	Loop16
 ;------------------------------------ 
 ; Основные операции преобразования двоичных чисел в двоично-десятичные: 
 ; операции сложения LED1...3 и констант 03h,30h с условиями по 3-му и 7-му битам. 
 ;------------------------------------ 
 adjBCD:
	ldi	temp4,0x03		; Сложить содержимое текущего LED1 (LED1...3) с числом 03h, 
	add	temp4,r0		; в регистр TEMP. 
	sbrc	temp4,3		; Анализ состояния 3-го бита регистра TEMP. 
	st	X,temp4			; Если бит № 3 =1, то содержимое регистра TEMP  

	ldi	temp4,0x30		; копируется в текущий LED. 
  	add	temp4,r0		; Если бит №3 =0, то содержимое текущего LED складывается 
	sbrc	temp4,7		; с константой 30h, с последующей записью результата операции,   
	st	X,temp4			; через регистр W, в регистр TEMP. 
						; Анализ состояния 7-го бита регистра TEMP. 
	; Если бит №7 =1, то содержимое регистра TEMP  
	; копируется в текущий LED. 
	; Если бит №7 =0, то регистр W очищается и происх
 	; возврат по стеку в ПП adjDEC. 
	ret

Timer1_comp1:

in	r30,SREG

ldi r31,0
out Tcnt1h,r31
out Tcnt1l,r31 ;обнуление счетчика

; Здесь выполняется подпрограмма прерывания по таймеру
	ldi	r31,1
	sts	flags,r31
	SBIC	Portd,0
	rjmp	out_1
	sbi		Portd,0
	rjmp	out_2
out_1:
	cbi		Portd,0
out_2:

OUT SREG,r30
reti

.EXIT
