; Пример «Управление индикатором от ЭКР2102»
;
; Частота задающего генератора 1,2 МГц
; подключение файла описания ввода-вывода микросхемы ATtiny13
.include "tn13def.inc"
; начало программы

	.def	temp = r16
	.def	temp1 = r17
	.def	temp2 = r18
	.def	count = r19
	.def	count1 = r11		; счетчик прерываний Т0
	.def	out_dat = r20		; данные на индик. 1 байт
	.def	crc = r21
	.def	outByte = r22
	.def	bit = r23			; Счетчик битов	
	.def	DelayReg = r24
	.def	DelayReg1 = r25
	.def	in_dat = r26
	.def	const = r4
	.def	tmp_lo = r6
	.def	tmp_hi = r7
	.def	hi_0 = r8			; "00" ст. разряд темп. равен "0"
	.def	md_0 = r9			; "ff" ср. разряд не нуль
	.def	min = r10			; "ff" минус, "00" плюс
	


	.equ	BIT1wire=pb4
	.equ	DDR1wire=ddrb
	.equ	PIN1wire=pinb
	.equ	ind_d = pb3			; Выход данных
	.equ	ind_c = pb0			; Выход синхронизации
	.equ	ind_w1 = pb1		; Выход выбор 1 м/сх
	.equ	ind_w2 = pb2		; Выход выбор 2 м/сх
	.equ	time = 25			; счетчик переполнений (74=1010 миллисек)

;--------------------------------------------------------------------------

.org	0
   	rjmp	RESET				; Reset Handler
	rjmp	EXT_INT0			; IRQ0 Handler
	rjmp	PC_INT0				; PCINT0 Handler
	rjmp	TIM0_OVF			; Timer0 Overflow Handler
	rjmp	EE_RDY				; EEPROM Ready Handler
	rjmp	ANA_COMP			; Analog Comparator Handler
	rjmp	TIM0_COMPA			; Timer0 CompareA Handler
	rjmp	TIM0_COMPB			; Timer0 CompareB Handler
	rjmp	WATCHDOG			; Watchdog Interrupt Handler
	rjmp	ADC_Conv			; ADC Conversion Handler


;.org	0x40

reset:

	ldi		temp, low(RAMEND)
	out		spl, temp
	ldi		temp, (1<<acd)		; выкл. компаратор
	out		acsr, temp
	cli							; Disable interrupts
	ser		temp 
	out		tifr0, temp			; на всякий случай сбрасываем флаги
	ldi		temp, 1<<BIT1wire
	com		temp
	out 	DDRB, temp			; все на вывод, кроме BIT1wire
	ldi		temp2, 1<<ind_c
	out		portb, temp2		; нули на выход, кроме  clk
	ldi		yh, 0
	sei							; Enable interrupts
	rcall	tim_init			; Настройка таймера
	ldi		temp, 3				; Начальная заержка 150 миллисек
	mov		count1, temp
	rcall	ind_reset			; инициализ. индикатор
	rcall	Init1wire

iii3:
	tst		count1
	brne	iii3
	ldi		temp, time
	mov		count1, temp			; заряжаем счетчик 
									; прерываний таймера t0	

iii4:
; Работа:
	rcall	Init1wire
	ldi		outByte, 0xcc		; Skip Rom
	rcall	rw_byte
	ldi		outByte, 0x44		; Convert T
	rcall	rw_byte
; задержка 1,3 сек
iii5:
	tst		count1
	brne	iii5

	rcall	Init1wire
	ldi		outByte, 0xcc		; Skip Rom
	rcall	rw_byte
	ldi		outByte, 0xbe		; Read Scratchpad
	clr		crc
	rcall	rw_byte

	rcall	rd_byte				; T LSB
	mov		r6, outByte 
	rcall	do_crc				; вычисляем crc

	rcall	rd_byte				; T MSB
	mov		r7, outByte 
	rcall	do_crc				; вычисляем crc
	ldi		temp2, 7
iii6:
	rcall	rd_byte	
	rcall	do_crc				; вычисляем crc
	dec		temp2
	brne	iii6

	tst		crc
	brne	err
	rcall	cel
	rcall	mem_ind
	ldi		yl, 0x60	
	rcall	ind_mem				; выводим память на индикатор
	ldi		temp, time
	mov		count1, temp		; заряжаем счетчик 
	rjmp	iii4

err:
; crc не равно 0
	ldi		yl, 0x68
	clr		temp
	st		y+, temp 
	ldi		temp, 0x1a
	st		y+, temp 
	ldi		temp, 0x0a
	st		y+, temp 
	ldi		temp, 0x1a
	st		y+, temp
	clr		temp
	st		y+, temp 
	ldi		temp, 0x9e
	st		y+, temp
	ldi		temp, 0x0a
	st		y+, temp
	st		y+, temp 
	ldi		yl, 0x68
	rcall	ind_mem				; выводим память на индикатор  
	ldi		temp, time
	mov		count1, temp		; заряжаем счетчик 
	rjmp	iii4


; Настройка таймера
tim_init:
	clr		temp
	out		tccr0a, temp					; Режим Normal
	out		tcnt0, temp						; Счетчик в "0"
	ldi		temp, (1<<cs02);  | (1<<cs02)
	out		tccr0b, temp					; /256 + start t0
	ldi		temp, (1<<toie0)
	out		timsk0, temp					; прерывание по Overflow
	ret



;Обработка прерываний

EXT_INT0:	; IRQ0 Handler
	reti

PC_INT0:		; PCINT0 Handler
	reti

TIM0_OVF:	; Timer0 Overflow Handler
	dec		count1
	reti

EE_RDY:		; EEPROM Ready Handler
	reti

ANA_COMP:	; Analog Comparator Handler
	reti

TIM0_COMPA:	; Timer0 CompareA Handler
	reti

TIM0_COMPB:	; Timer0 CompareB Handler
	reti

WATCHDOG:	; Watchdog Interrupt Handler
	reti

ADC_Conv:	; ADC Conversion Handler
	reti



; Процедуры для работы с индикатором

;*********подача строба************
clk:
	nop
	cbi		portb, ind_c
	nop
	nop
	sbi		portb,ind_c
	ret
;*******end подача строба***********


;*********cs1 в ноль************
cs1_0:
	sbi		portb, ind_w1
	ret
;******end cs1 в ноль***********


;*********cs2 в ноль************
cs2_0:
	sbi		portb, ind_w2
	ret
;******end cs2 в ноль***********


;*********cs1 и cs2 в единицу************
cs_1:
	cbi		portb, ind_w2
	cbi		portb, ind_w1
	ret
;******end cs1 и cs2 в единицу***********



;*********выдача байта данных************
data:
	ldi		temp, 8			; счетчик бит
data3:
	lsr		out_dat
	brcc	data1
	cbi		portb, ind_d
	rjmp	data2
data1:
	sbi		portb, ind_d
data2:
	rcall	clk
	dec		temp
	brne	data3
	ret
;*******end выдача байта данных***********
	

;*********начальная настройка индикатора************
ind_reset:
	rcall	cs1_0
	rcall	cs2_0
	clr		out_dat 
	ldi		temp1, 4			; счетчик байт
ind_reset1:
	rcall	data
	dec		temp1
	brne	ind_reset1
	ldi		out_dat, 0xe0
	rcall	data
	rcall	cs_1
	nop
	nop
	rcall	cs2_0
	clr		out_dat 
	ldi		temp1, 4			; счетчик байт
ind_reset2:
	rcall	data
	dec		temp1
	brne	ind_reset2
	ldi		out_dat, 0x10
	rcall	data
	rcall	cs_1
	ret
;*******end начальная настройка индикатора**********


;*********конвертация данных************
; вход in_dat, выход out_dat
conv:
	ldi		zh,high(tab1*2)
	ldi		zl,low(tab1*2)
	add		zl, in_dat
	brcc	conv1
	inc		zh
conv1:
	lpm
	mov		out_dat, r0
	ret
;*******end конвертация данных***********



;******* УТИЛИТЫ ТЕРМОМЕТРА **************************

; ****************************************************************************
uSDelay4:	rcall	usDelay2
uSDelay2:	rcall	usDelay
uSDelay:						; Подпрограммы выдерживают паузу
uSDelay_l1:
		dec		DelayReg
		brne	uSDelay_l1
		mov		DelayReg, DelayReg1		
		ret




; ****************************************************************************
rd_byte:
	ser		outByte				; Попрограмма передачи-приема байта по 1-wire интерфейса
								; Передаёт байт из регистра outByte, принимаем туда-же
rw_byte:
	ldi		bit,8
rw_byte1:	
	sbi		DDR1wire, BIT1wire	; Переводим линию в "0" в течении минимум 6 мкс
	nop
	nop
	sbrc	outByte, 0
	cbi		DDR1wire, BIT1wire	; Если нужно выдать "1" переводим 
								; линию в "1" сразу же
	clc							; готовим 0 в outByte, 7
	ror		outByte
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	sbic    pin1wire, BIT1wire
	sbr		outByte, 0x80
	ldi		DelayReg, 20		; Выдерживаем интервал Tslot=67 мкс
	rcall	usDelay
	
	cbi		DDR1wire, BIT1wire
	dec		bit
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	brne	rw_byte1
	ret

; ****************************************************************************
Init1wire:	; Попрограмма инициализации устройств расположеных на шине 1-wire
	sbi		DDR1wire, BIT1wire  ; Переводим линию в "0"
	ldi		DelayReg, 55	    ; Ждём >480 мкс (575 мкс)
	mov		DelayReg1, DelayReg	; буферим	
	rcall	usDelay4
	cbi		DDR1wire, BIT1wire  ; Переводим линию в "1"
	rcall	usDelay4	   		 ; Ждём >480 мкс (575 мкс)
	ret




;-----------------------------------------------------------------------------


; ****************************************************************************
do_crc:						; Программа обновления CRC8 

	ldi		temp, 0x0C
	ldi		temp1, 8
CRC8_l2: 
	ror		outByte
	ror		CRC
	brcc	CRC8_l3
	subi	CRC, 0x80		; Инверсия старшего бита накопителя CRC8
CRC8_l3:
	brpl	CRC8_l4
	eor		CRC, temp

CRC8_l4:
	dec		temp1
	brne	CRC8_l2
	ret

;------------------------------------------------
; загрузка памяти 0x60-0x67 (служебная прог.)		
mem_write:
	push	yl
	clr		temp
	ldi		temp1, 6
mem_wr1:
	st		y+, temp
	dec		temp1
	brne	mem_wr1
	pop		yl
	ret	

;------------------------------------------------
; вывод на индикатор 8 байт памяти с адр. yl 
ind_mem:
; пишем в младшие
	rcall	cs1_0
	ldi		temp1, 4
ind_mem1:
	ld		in_dat, y+
	mov		out_dat, in_dat
	rcall	data
	dec		temp1
	brne	ind_mem1	
	ldi		out_dat, 0x60		; служебная посылка
	rcall	data
	rcall	cs_1
; пишем в старшие
	rcall	cs2_0
	ldi		temp1, 4
ind_mem2:
	ld		in_dat, y+
	mov		out_dat, in_dat
	rcall	data
	dec		temp1
	brne	ind_mem2	
	ldi		out_dat, 0x10		; служебная посылка
	rcall	data
	rcall	cs_1
	ret	
;-----------------------------------------------

;-----------------------------------------------
; обработка дробной части температуры, надо умножить на 10 и 
; поделить на 16
; вход r6, выход 0x65, используется temp1, temp2
drob:
	push	temp
; выделяем дробную часть
	andi	temp, 0x0f
	mov		temp2, temp
; умножаем на 10 по ф-ле: (temp*8)+temp+temp
	lsl		temp				; x2
	lsl		temp				; x4
	lsl		temp				; x8
	add		temp, temp2
	add		temp, temp2
; делим на 16
	swap	temp
	andi	temp, 0x0f
; выводим в память
	ldi		zh,0
	ldi		zl,0x66
	st		-z, temp 
	pop		temp
	ret
;-----------------------------------------------
	
;***** Subroutine Register Variables

;	drem8u	= temp1		;остаток
;	dres8u	= temp		;результат
;	dd8u	= temp		;делимое
;	dv8u	= 0xa		;делитель
;	dcnt8u	= count		;счетчик

;***** Code

div_10:
	ldi		temp2, 0xa
	sub		temp1, temp1		;clear остаток и перенос
	ldi		count, 9			;заряжаем счетчик
d8u_1:
	rol		temp				;shift left dividend
	dec		count				;decrement counter
	brne	d8u_2				;if done
	ret							;return
d8u_2:
	rol		temp1				;shift dividend into remainder
	sub		temp1, temp2		;remainder = remainder - divisor
	brcc	d8u_3				;if result negative
	add		temp1, temp2		;restore remainder
	clc							;clear carry to be shifted into result
	rjmp	d8u_1				;else
d8u_3:
	sec							;set carry to be shifted into result
	rjmp	d8u_1	



;-----------------------------------------------
	
;-----------------------------------------------
; обработка целой части температуры	
; вход r7:r6, выход 0x65, используется temp, temp1, temp2

cel:	
; определяем +/-
	mov		temp, r6
	mov		temp1, r7
	clr		temp2
	tst		temp1
	mov		min, temp2
	brpl	cel_pl
; работаем с минусом
	com		temp
	com		temp1
	ldi		temp2, 1
	add		temp, temp2				; +1 к младшему
	clr		temp2
	add		temp1, temp2
	dec		min
cel_pl:
; работаем с дробной частью
	rcall	drob
; формируем байт целой части температуры
	swap	temp1
	andi	temp1, 0xf0
	swap	temp
	andi	temp, 0x0f
	add		temp, temp1				; поместили в temp
	rcall	div_10
	st		-z, temp1 
	rcall	div_10
	st		-z, temp1 
	st		-z, temp
	ret

;-----------------------------------------------




;------------------------------------------------
; Подготовка к выводу на индикатор содержимого памяти 0x60-0x67 
mem_ind:
	ldi		yl, 0x60
	clr		temp1
	st		y+, temp1
	st		y+, temp1
	tst		r10					; проверяем на "-"
	brpl	plus
; минус
	st		y+, temp1
	ld		in_dat, y

;проверяем 0x63
	tst		in_dat
	ldi		temp2, 2			; "-"		
	brne	min62
	st		y+, temp2
	rjmp	norma	
min62:
	dec		yl		
	st		y+, temp2
	rcall	conv
	st		y+, out_dat
	rjmp	norma
		
		
plus:
;проверяем 0x62
	ld		in_dat, y
	tst		in_dat
	brne	inf62
; гасим 0х62
	st		y+, in_dat			; 0х62 загасили
;проверяем 0x63
	ld		in_dat, y
	tst		in_dat
	brne	inf63
; гасим 0х63
	st		y+, in_dat			; 0х63 загасили
	rjmp	norma
	
	nop	


inf62:
	rcall	conv
	st		y+, out_dat			; 0x62
	ld		in_dat, y
inf63:
	rcall	conv
	st		y+, out_dat			; 0x63




norma:			
	ld		in_dat, y
	rcall	conv
	sbr		out_dat, 1			; добавляем запятую	
	st		y+, out_dat			; 0х64 записали
	ld		in_dat, y
	rcall	conv
	st		y+, out_dat			; 0х65 записали
	ldi		temp, 0xc6
	st		y+, temp			; градус записали
	ldi		temp, 0x9c
	st		y+, temp			; "C" записали
	ret	
;-----------------------------------------------








;.org	0x00fa

; таблица кодировки символов
tab1:
	.db 0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0  ; 0-7
	.db 0xfe, 0xf6, 0xee, 0x3e, 0x9c, 0x7a, 0x9e, 0x8e	; 8-f
