; команды для работы с датчиком DS1820
.equ	CMD_SEARCH_ROM = 0xF0	; поиск адресов всех устройств по спецалгоритму
.equ	CMD_READ_ROM = 0x33	; считываение адреса единственного устройства
.equ	CMD_MATCH_ROM = 0x55	; активация конкретного устройства по его адресу
.equ	CMD_SKIP_ROM = 0xCC 	; обращение к единственному на шине устройству без указания его адреса
;.equ	CMD_ALARM_SEARCH = 0xEC	; поиск устройств, у которых сработал ALARM (алгоритм поиска как у CMD_SERCH_ROM)
.equ	CMD_CONVERT_T = 0x44	; старт преобразования температуры
.equ	CMD_W_SCRATCHPAD = 0x4E	; запись во внутренний буфер (регистры)
.equ	CMD_R_SCRATCHPAD = 0xBE	; чтение внутреннего буфера (регистров)
.equ	CMD_C_SCRATCHPAD = 0x48	; сохранение регистров в EEPROM 
;.equ	CMD_RECALL_EE = 0xB8	; заносит в буфер из EEPROM значение порога ALARM
;.equ	CMD_READ_POWER = 0xB4	; определение, есть ли в шине устройства с паразитным питанием

;используемые порты и регистры
;перед началом работы необходимо настроить выбранную линию порта 
;на работу в качестве входа без подтягивающего резистора, т. е. DDRx=0 PORTx=0
.equ	wireport = DDRB			; порт вывода 1-Wire
.equ	wirepin  = PinB;		; порт сигнальных линий 1-Wire
.equ	wirebit  = 2			; номер линии порта 1-Wire
.equ    wirePORTx = PORTB

.def	wiretemp = R25			; temp регистр для 1-Wire
.def 	wireres	 = R2			; регистр из числа r0...r15			

;сегмент данных
.dseg
	buffer_1w:	.byte	9		; 9 байт буфера приема				
	CRC:	        .byte	1		; расчитываемая контр.сумма
.cseg		
;сегмент кода

;+--------------------------------------------------+
;| Данная конфигурация для ATmega88PA, кварц 16 МГц |
;| Датчиков 2 штуки, PB2                            |
;| 244 байт ПЗУ, 10 байт ОЗУ                        |
;+--------------------------------------------------+

delay1us:							
; задержка повышенной точности в 1 микросекунду c учетом длительности RCALL и RET
; rcall (им вызываем эту задержку) дает 3 + 9 nop + 4 ret = 16
; 1 микросекунда при 16МГц не использует никаких регистров
	nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
       	ret			



delay10us:	
; задержка повышенной точности в 10 микросекунд, основана на delay1us
; rcall (им вызываем эту задержку) дает 3 + 11 команд вне цикла + (6*(16+3+2)+16+3+1)=146 дает сам цикл
; Итого 160 тактов = 10 микросекунд
	push	wiretemp	
	ldi	wiretemp, 7	
delay10us_loop:				
	rcall	delay1us	
	dec	wiretemp
        nop
        nop	
	brne	delay10us_loop	
	pop	wiretemp	
	nop
        nop			
	ret			

delayus:
; задержка в wiretemp десятков микросекунд, повышенной точности не требуется
; на входе - wiretemp, где записано число десятков секунд (wiretemp изменяется)
	dec	wiretemp
delayus_loop:
	rcall	delay10us
	dec	wiretemp
	brne	delayus_loop
	rcall	delay1us
	rcall	delay1us
ret	


;============================================================================================

Init_1W:

; выполняет сброс линии и выдает наличие сигнала присутствия PRESENCE от датчика
; при наличии сигнала присутствия взводим Z-флаг, иначе сбрасываем его


        cbi     wirePORTx, wirebit      ; PORTx=0	
	cbi	wireport, wirebit	 ; 0->DDR = Z-состояние
	sbis	wirepin, wirebit	; проверим наличие 1 в линии
	rjmp	presence_fault		; если нет - это ошибка
	sbi	wireport, wirebit		; иначе давим линию в 0
	ldi	wiretemp, 48			; задержка в 480 микросекунд
	rcall	delayus			
	cbi	wireport, wirebit		; отпускаем линию, 0->DDR = Z-состояние
	ldi	wiretemp, 6			; задержка в 60 микросекунд
	rcall	delayus			
	; начинаем ждать сигнал присутствия PRESENCE
        ; Датчик должен прижать линию к земле втечение 240 мкс
	ldi	wiretemp, 250			; ждем с запасом - 240 max
presence_wait:
	sbis 	wirepin, wirebit    ; Проверка линии на 1, если появляется 0, то всё ОК
	rjmp	presence_ok         ; и переходим на presence_ok
	rcall	delay1us
	dec	wiretemp
	brne 	presence_wait
presence_fault:
	; PRESENCE не получен
	clz	                    ; сбрасываем Z-флаг 
	ret                         ; и выходим

presence_ok:
	; PRESENCE получен, задержка в 480 микросекунд
	sez							; взводим Z-флаг
	ldi	wiretemp, 48
	rcall	delayus

	ret
				
;============================================================================================

Resive_1W:

; выполняет прием байта из линии
; на входе ничего, на выходе R0 - принятый байт
	ser	wiretemp				; wiretemp <- 0xFF
	mov	r0, wiretemp
	

Send_1W:
; выполняет передачу байта в линию
; вход: R0 - выводимый байт
; выход: R0 - то, что удалось ВВЕСТИ из линии 
; портит: R0
; примечание: если делать ВЫВОД 0хFF, то на выходе будет ПРИНЯТЫЙ байт
	ldi	wiretemp, 8				; число битов в байте

sw1_next:
	push	Temp1
	in	Temp1, SREG
	push	Temp1				; сохраним флаги, т.к. будем запрещать прерывания
	
	cli							; запрещаем прерывания
	sbi	wireport, wirebit	; 1->DDR = 0 на выходе						; давим линию в 0
	rcall	delay1us			; 1 мкс задержки
	ror	r0						; выталкиваем выводимый бит
	brcc	s0					; если бит C = 0 - обход 
	cbi	wireport, wirebit	; 0->DDR = Z-состояние						; линию в 1
s0:
	push	wiretemp
	ldi	wiretemp, 9				; в некоторых случаях может потребоваться
								; увеличить это значение, но не более 13!
sw1_wait:
	rcall	delay1us
	dec	wiretemp
	brne	sw1_wait
	clc	
	sbic	wirepin, wirebit
	sec
	ror	wireres          ;Если линия была в нуле, то в бит 7 R2 запишется 0,
                                 ;а если линия была в единице, то в бит 7 R2 запишется 1
	ldi	wiretemp, 9
	rcall	delayus				; 90 микросекунд - длительность тайм-слота
	cbi	wireport, wirebit	; 0->DDR = Z-состояние
	pop	wiretemp
	
	pop	Temp1
	out	SREG, Temp1
	pop	Temp1

	dec	wiretemp
	brne 	sw1_next		
	mov	r0, wireres

	ret	
;============================================================================================

ReadBytes_1W:
; считывает 9 байтов в буфер, подсчитывает CRC
; изменяет R0 и SREG, регистры X и Z
           
	clr	wiretemp
	sts	CRC, wiretemp			; обнуляем CRC
	ldi	XL, low(Buffer_1w)
	ldi	XH, high(Buffer_1w)
	ldi	wiretemp, 9				; 9 байтов
r1w_next:
	push	wiretemp
	rcall	Resive_1w			; считываем 1 байт
	; R0=считанному байту, начинаем подсчет CRC
	st	X+, r0					; сохраняем принятый байт
	rcall	crc8				; считаем контрольную сумму
 	pop	wiretemp
	dec	wiretemp
	brne	r1w_next
	ret

	
CRC8:
; выполняет подсчет CRC по алгоритму 1-Wire
; на входе r0 - считанный байт
; на выходе CRC - содержит подсчитанную сумму
; портит регистр Z, R0 сохраняется
; примечание: перед первым вызовом CRC необходимо обнулить
	push	r0
	ldi	wiretemp, 8
	mov	wireres,wiretemp
CRC8_loop:
	lds	wiretemp, CRC
	eor	r0, wiretemp
	ror	r0
	mov	r0, wiretemp
	brcc 	zero
	ldi	wiretemp, 0x18
	eor	r0, wiretemp
zero:
	ror	r0
	sts	CRC, r0
	pop	r0
	; 4 следующие команды делают циклический сдвиг r0
	push	r0
	ror	r0
	pop	r0
	ror	r0
	; сдвиг закончен
	push	r0
	dec	wireres
	brne 	CRC8_loop
	pop	r0
	lds	r0, CRC
	ret
