; Пример «Управление индикатором от ЭКР2102»
;
; Частота задающего генератора 1,2 МГц
; светодиод подключен к выводу PB4 и через резистор - на питание.
; подключение файла описания ввода-вывода микросхемы ATtiny13
.include "tn13def.inc"
; начало программы

	.def	temp = r16
	.def	temp1 = r17
	.def	temp2 = r18
	.def	count = r19
	.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


	.equ	BIT1wire=pb4
	.equ	DDR1wire=ddrb
	.equ	PIN1wire=pinb
;	.equ	led = pb4			; led
	.equ	ind_d = pb3			; Выход данных
	.equ	ind_c = pb0			; Выход синхронизации
	.equ	ind_w1 = pb1		; Выход выбор 1 м/сх
	.equ	ind_w2 = pb2		; Выход выбор 2 м/сх
	.equ	time = 37			; счетчик переполнений (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:

; первая операция - инициализация стека
; если этого не сделать, то вызов подпрограммы или прерывания
; не вернет управление обратно
; указатель на конец стека устанавливается на последний
; адрес внутреннего ОЗУ - RAMEND.

	ldi		temp, low(RAMEND)
	out		spl, temp
	ldi		temp, (1<<acd)		; выкл. компаратор
	out		acsr, temp
	cli							; Disable interrupts
	ser		temp 
	out		tifr0, temp			; на всякий случай сбрасываем флаги
								; прерываний T0
	
; для того, чтобы управлять светодиодами, подключенными к выводу PB4,
; необходимо объявить этот вывод выходным.
; для этого нужно записать "1" в соответствующие биты
; регистра DDRB (DataDiRection)
	ldi		temp, 1<<BIT1wire
	com		temp
	out 	DDRB, temp			; все на вывод, кроме BIT1wire
;	cbi		temp2, BIT1wire
	ldi		temp2, 1<<ind_c
	out		portb, temp2		; нули на выход, кроме  clk
;	ldi		temp, 1<<upr
;	out		portb, temp			; резистор подтяжки на вход upr 
	nop

; Информация для вывода на индикатор в памяти 0x60-0x67

;	ldi		temp, 5
	ldi		yh, 0
	ldi		yl, 0x60
;	st		x, temp
;	cbi		portb, 0

	rcall	mem_write			; загрузка памяти 0x60-0x67 
								; (служебная прог.)




;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

;	ldi		r25, 25
;	rjmp	TmpLoop				; работаем с температурой
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!





;	sei							; Enable interrupts
	rcall	tim_init			; Настройка таймера
	ldi		count, time	



PROBA:
	ldi		temp, 0x6c
	mov		r6, temp
	rcall	drob
	nop
	

; работаем с индикатором
	
			

	rcall	ind_reset			; инициализ. индикатор
povtor:
	rcall	mem_ind				; выводим память на индикатор
	rjmp	povtor


	clr		r21
iii5:
	ldi		temp2, 2			; счетчик повторов
ind_w5:
; пишем в младшие
	rcall	cs1_0
	ldi		temp1, 4			; счетчик байт
	

ind_w3:
	rcall	conv
	mov		out_dat, r22	
	rcall	data
	inc		r21
	andi	r21, 0x0f
	dec		temp1
	brne	ind_w3
;	ldi		out_dat, 0x60
;	rcall	data
	rcall	cs_1

;iii3:
;	tst		count
;	brne	iii3
;	ldi		count, time	
	nop
	nop
	

; пишем в старшие
	rcall	cs2_0
	ldi		temp1, 3;4			; счетчик байт
ind_w4:
	rcall	conv
	mov		out_dat, r22	
	rcall	data
	inc		r21
	andi	r21, 0x0f
	dec		temp1
	brne	ind_w4
;	ldi		out_dat, 0x10
;	rcall	data
	rcall	cs_1

iii3:
	tst		count
	brne	iii3
	ldi		count, time	

;	dec		temp2
;	brne	ind_w5

;iii4:
;	tst		count
;	brne	iii4
;	ldi		count, time	
	rjmp	iii5

	





ind:
	rjmp	ind

	sei							; Enable interrupts

; проба для EEPROMa
	ldi		temp, 0xff
	out		eear, temp
	out		eedr, temp



; end проба для EEPROMa

	rcall	tim_init			; Настройка таймера
			
; основной цикл программы
	ldi		count, time			; заряжаем счетчик прерываний таймера t0	
	
loop:
	rjmp	loop				; бесконечный цикл


	ldi temp,(1<<4) ; светится один светодиод
	out PORTB,temp
	rcall delay ; задержка
	ldi temp,(0<<4) ; светится второй светодиод
	out PORTB,temp
	rcall delay ; задержка
	rjmp loop ; повторение цикла
; процедура задержки
; примерно полсекунды при частоте 7,37 МГц
; три пустых вложенных цикла соответственно
delay:
	ldi temp,30 ; 30
delay1:
	ldi temp1,20 ; 200
delay2:
	ldi temp2,200 ; и еще 200 итераций
delay3:
	dec temp2
	brne delay3
	dec temp1
	brne delay2
	dec temp
	brne delay1
	ret ; возврат в главную программу

; Настройка таймера
tim_init:
	clr		temp
	out		tccr0a, temp					; Режим Normal
;	clr		temp
	out		tcnt0, temp						; Счетчик в "0"
;	ser		temp
;	sbi		tccr0b, cs02		
;	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		count
;	brne	tim_end				; перейти, если не 0
;	sbic	portb, led			; пропустить, если бит 0
;	rjmp	tim_end1
;	sbi		portb, led
	
;tim_end:
	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:
;	push	r21
	ldi		zh,high(tab1*2)
	ldi		zl,low(tab1*2)
	add		zl, in_dat
;	sec
;	clr		r21
	brcc	conv1
	inc		zh
conv1:
	lpm
	mov		out_dat, r0
;	pop		r21
	ret
;*******end конвертация данных***********



;******* УТИЛИТЫ ТЕРМОМЕТРА **************************







TmpLoop:

	ldi		outByte, 0x2
	ldi		temp, 0
	mov		crc, temp
	rcall	do_crc
	ldi		outByte, 0x1c
	rcall	do_crc
	ldi		outByte, 0xb8
	rcall	do_crc
	ldi		outByte, 0x01
	rcall	do_crc
	ldi		outByte, 0
	rcall	do_crc
	ldi		outByte, 0
	rcall	do_crc
	ldi		outByte, 0
	rcall	do_crc
	ldi		outByte, 0xa2
	rcall	do_crc
		

	rjmp	PC
	
		
	rcall	Init1wire
	ldi		outByte, 0xcc			; Skip Rom
	rcall	rw_byte
	ldi		outByte, 0x44		; Convert T
	rcall	rw_byte
		rcall	RD1wire
;		sbrc	inByte, 0
		  rjmp	TmpLoop
		

		rcall	Init1wire
		ldi	outByte, 0xB2		; Read registr
		rcall	rw_byte
		ldi	outByte, 0x62		; Temperature register adr
		rcall	rw_byte
		rcall	Init1wire
		rcall	RD1wire
; iByte - температура...
		rjmp	PC



; ****************************************************************************
uSDelay4:	rcall	usDelay2
uSDelay2:	rcall	usDelay
uSDelay:	; Подпрограмма паузы
uSDelay_l1:
		dec		DelayReg
		brne	uSDelay_l1
		mov		DelayReg, DelayReg1		
		ret


; ****************************************************************************
RD1wire:	; Попрограмма приёма байта по 1-wire интерфейса
		; Принятый байт возвращается в регистре inByte

		ldi	bit,8
RD1_l1:		cli			    ; Запрещаем обработку прерываний

		sbi	DDR1wire, BIT1wire  ; Импульс запроса передачи бита >1 мкс
		rcall	RD1_dummy	    ; (при частоте 7.3728 -> 1.22 мкс)
		cbi	DDR1wire, BIT1wire

		ldi	DelayReg, (86+2)/3	    ; (7.3728 * 14) - 6 - 11
		rcall	usDelay
		clc			    ; Проверка линии после 14 мкс после импульса запроса
		sbic    PIN1wire, BIT1wire
		  sec
		sei			    ; Разрешение прерываний
;		ror	inByte

		ldi	DelayReg, 404/3	   ; (7.3728 * 70) - 6 - 106 
		rcall	usDelay		    ;	Через 70 мкс от импульса запроса бита
					    ; ожидает появления "1"  на линии в течении 50 мкс
		ldi	DelayReg, 368/5	    ; (7.3728 * 50)
RD1_l2:		sbic    PIN1wire, BIT1wire
		  rjmp	RD1_l3
		dec     DelayReg
		brne	RD1_l2
;;;;;;		ldi	DelayReg, 1	    ; Если в течении 50 мкс на линии "0", то похоже она замкнута на землю
;;;;;;		sts	fTIMEOUT, DelayReg  ; Устанавливаем флажок тайаута

RD1_l3:		dec	bit
		brne	RD1_l1
RD1_dummy:	ret


; ****************************************************************************
rw_byte:	; Попрограмма передачи-приема байта по 1-wire интерфейса
			; Передаёт байт из регистра outByte, принимаем туда-же

	ldi		bit,8
WR1_l1:	
	cli			   				; Запрещаем обработку прерываний

	sbi		DDR1wire, BIT1wire	; Переводим линию в "0" в течении минимум 1 мкс
	;rcall	RD1_dummy	   		; (при частоте 7.3728 -> 1.35 мкс)
	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
	nop
;	in		temp, pinb
	sbic    pin1wire, BIT1wire
	sbr		outByte, 0x80
	
                                            
	ldi		DelayReg, 24		; Выдерживаем интервал Tslot=67 мкс
	rcall	usDelay
	
	cbi		DDR1wire, BIT1wire
	sei							   ; Разрешение прерываний
	dec		bit
	brne	WR1_l1
	ret

; ****************************************************************************
Init1wire:	; Попрограмма инициализации устройств расположеных на шине 1-wire
	sbi		DDR1wire, BIT1wire  ; Переводим линию в "0"
	ldi		DelayReg, 55	    ; Ждём >480 мкс (575 мкс)
	mov		DelayReg1, DelayReg	; буферим	
	rcall	usDelay4
;rcall	usDelay
	cbi		DDR1wire, BIT1wire  ; Переводим линию в "1"
	rcall	usDelay4	   		 ; Ждём >480 мкс (575 мкс)
;	rcall	usDelay
	ret




;-----------------------------------------------------------------------------
; Процедура обновления crc. байт в outByte.
do_crc1:
		push	outByte				;сохраняем outByte
		push	temp				;сохраняем temp
		push	outByte				;сохраняем байт

		ldi		temp, 0x18			
		mov		const, temp			;заряжаем константу
		ldi		temp, 8				;set shift = 8 bits 
crc_loop:   
		eor		outByte, crc		;считаем crc
		ror		outByte				;сдвиг вправо через перенос
		brcc	zero				;переход, если с = 0
		eor		crc, const			;обновляем crc с константой
zero:
		ror		crc					;снова двигаем crc
		pop		outByte				;восстанавливаем данные
		lsr		outByte				;свиг вправо
		push	outByte				;сохраняем данные
		dec		temp
		brne	crc_loop			;повторяем для следующего бита
		pop		outByte				;очищаем стек
		pop		temp				;восстанавливаем temp
		pop		outByte				;восстанавливаем outByte
		ret
;-----------------------------------------------------------------------------


; ****************************************************************************
do_crc:						; Программы обновления CRC8 

	push	outByte	
	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
	pop		outByte	
	ret

;------------------------------------------------
; загрузка памяти 0x60-0x67 (служебная прог.)		
mem_write:
	push	yl
	ldi		temp, 1
	ldi		temp1, 6
mem_wr1:
	st		y+, temp
	inc		temp
	dec		temp1
	brne	mem_wr1
	ldi		temp, 0xc6
	st		y+, temp
	ldi		temp, 0x9c
	st		y+, temp
	pop		yl
	ret	

;------------------------------------------------
; вывод на индикатор содержимого памяти 0x60-0x67 
mem_ind:
	push	yl
; пишем в младшие
	ldi		temp1, 4
	rcall	cs1_0
mem_ind1:
	ld		in_dat, y+
	rcall	conv
	rcall	data
	dec		temp1
	brne	mem_ind1
	ldi		out_dat, 0x60
	rcall	data
	rcall	cs_1
; пишем в старшие
	rcall	cs2_0
	ld		in_dat, y+
	rcall	conv
	sbr		out_dat, 1			; добавляем запятую		
	rcall	data
	ld		in_dat, y+
	rcall	conv
	rcall	data
	ldi		temp1, 2			; счетчик байт
mem_ind3:
	ld		in_dat, y+
	mov		out_dat, in_dat
	rcall	data
	dec		temp1
	brne	mem_ind3
	ldi		out_dat, 0x10
	rcall	data
	rcall	cs_1
	pop		yl
	ret	
;-----------------------------------------------

;-----------------------------------------------
; обработка дробной части температуры, надо умножить на 10 и 
; поделить на 16
; вход r6, выход 0x65, используется temp2
drob:
	mov		temp1, r6
; выделяем дробную часть
	andi	temp1, 0x0f
	mov		temp2, temp1
; умножаем на 10 по ф-ле: (temp1*8)+temp1+temp1
	lsl		temp1				; x2
	lsl		temp1				; x4
	lsl		temp1				; x8
	add		temp1, temp2
	add		temp1, temp2
; делим на 16
	swap	temp1
	andi	temp1, 0x0f
; выводим в память
	ldi		zh,0
	ldi		zl,0x65
	st		z, temp1 
	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
