;attiny2313+ds18b20+радиомодуль rf02
;передает измеренную температуру широковещательным собщением
;затактирован от внутреннего генератора с частотой 1 МГц
;фьюзы: BODLEVEL=101, CKDIV=0, CKSEL=0100 SUT=01

;перед каждым программированием нового устройства установить новый IDNEW!!!
.include "tn2313def.inc"

.def	ChkSum = r22
.equ	PORT_SEL	= PORTB
.equ	PIN_SEL		= PINB
.equ	DDR_SEL		= DDRB

.equ	PORT_SDI	= PORTB
.equ	PIN_SDI		= PINB
.equ	DDR_SDI		= DDRB

.equ	PORT_SCK	= PORTB
.equ	PIN_SCK		= PINB
.equ	DDR_SCK		= DDRB

.equ	PORT_SDO	= PORTB
.equ	PIN_SDO		= PINB
.equ	DDR_SDO		= DDRB

.equ	PORT_DATA	= PORTD
.equ	PIN_DATA	= PIND
.equ	DDR_DATA	= DDRD

.equ	portDS1820 	= portD
.equ	DDRDS1820 	= DDRD
.equ	pinDS1820 	= pinD
.equ	DS1820		= 0


.equ	RFXX_SCK	= 7
.equ	RFXX_SDO	= 6
.equ	RFXX_SDI	= 5
.equ	RFXX_SEL	= 4
.equ	RFXX_DATA	= 5	;portD


.DSEG
TempAct:		.db	0,0,0
ID_DS:			.db	0,0,0,0,0,0,0,0
Scratchpad:		.db	0,0,0,0,0,0,0,0,0
CRC:			.db	0
RfBuffer:		.db	0,0,0,0,0,0,0,0,0,0


.CSEG
rjmp	Start
.org	$12	;прерывание сторожевого таймера
rjmp	TIMER1_COMPA
.org	$15	;15h байт - векторы прерываний
IDNEW:		.db 02,00,00,01
Start:
;---------сконфигурируем порты ввода/вывода и стэк--------
	cli
	ldi	r16,low(RAMEND)
	out	SPL,r16
	sei

	ldi	r16,$ff		
	out	DDRB,r16
	out	DDRD,r16	

	ldi	r16,$0
	out	portD,r16
	out	portB,r16
;------установка начальных значений------------------------
	ldi	r16,$0
	sts	TempAct,r16
	ldi	r16,$0
	sts	TempAct+1,r16
;----------инициализация периферии-------------------------
	rcall	IniWDT
	rcall	SleepingMode
	rcall	IniDS1820
	ldi		r16,$6
	rcall	WAIT_100ms
	rcall	IniOfRf02
	ldi		r16,5
	rcall	WAIT_100us
s0:
	;переведём передатчик rf02 в спящий режим
	ldi		r19,$0
	ldi		r20,$c4
	rcall	RFXX_WRT_CMD	;
	
	;включим спящий режим МК
	in 		r16,MCUCR
	sbr		r16,(1<<SE)
	out		MCUCR,r16
	;перейти в спящий режим
	sleep
	nop
	rjmp	s0
;-------------------------------------------------------------------
;--------------------инициализация сторожевого таймера--------------
IniWDT:
	cli
	wdr
	in	r16,WDTCSR
	ori	r16,(1<<WDCE|1<<WDE)
	out	WDTCSR,r16
	ldi	r16,(0<<WDE|1<<WDIE|1<<WDCE|1<<WDP3|1<<WDP0)
	out	WDTCSR,r16
	sei
	ret
;-------------------------------------------------------------------
;----------------------прерывание таймера---------------------------
TIMER1_COMPA:
	;отключим спящий режим rf02
	ldi		r19,$0
	ldi		r20,$cc
	rcall	RFXX_WRT_CMD	;Status register read

	;отключим спящий режим
	in 		r16,MCUCR
	cbr		r16,(1<<SE)
	out		MCUCR,r16
	;получим температуру
	rcall	GetTempDS
	ldi		r30,low(IDNEW*2)
	ldi		r31,high(IDNEW*2)
	ldi		r16,$81
	sts		RfBuffer,r16
	lpm		r16,Z+
	sts		RfBuffer+1,r16
	lpm		r16,Z+
	sts		RfBuffer+2,r16
	lpm		r16,Z+
	sts		RfBuffer+3,r16
	lpm		r16,Z+
	sts		RfBuffer+4,r16
	ldi		r16,$8
	sts		RfBuffer+5,r16

	lds		r16,TempAct
	sts		RfBuffer+6,r16
	lds		r16,TempAct+1
	sts		RfBuffer+7,r16
	ldi		r16,$8
	rcall	Rf02_Transmitting
	;моргнём контактом
	ldi		r16,(1<<1)
	in		r17,portD
	eor		r17,r16
	out		portD,r17
	reti
;-------------------------------------------------------------------
;-----------------------инициализация спящего режима----------------
SleepingMode:
	;настройка спящего режима
	in 		r16,MCUCR
	cbr		r16,(1<<SM0|1<<SM1)
	sbr		r16,(1<<SM0|0<<SM1)		;power down
	out		MCUCR,r16
	ret

;-------------------------------------------------------------------
;----------------------инициализируем канал связи-------------------
IniOfRf02:
	sbi		PORT_SEL,RFXX_SEL
	sbi		PORT_SDI,RFXX_SDI
	sbi		PORT_SDO,RFXX_SDO
	cbi		PORT_SCK,RFXX_SCK
	sbi		DDR_SEL,RFXX_SEL
	sbi		DDR_SDI,RFXX_SDI
	cbi		DDR_SDO,RFXX_SDO
	sbi		DDR_SCK,RFXX_SCK
	sbi		PORT_DATA,RFXX_DATA
	sbi		DDR_DATA,RFXX_DATA
;
	ldi		r19,$0
	ldi		r20,$cc
	rcall	RFXX_WRT_CMD	;Status register read
	ldi		r19,$61
	ldi		r20,$8b
	rcall	RFXX_WRT_CMD	;band=433MHz, CLK = 2MHz, frequency deviation = 60kHz
	ldi		r19,$40
	ldi		r20,$a6
	rcall	RFXX_WRT_CMD	;f=434MHz
	ldi		r19,$40
	ldi		r20,$d0
	rcall	RFXX_WRT_CMD	;???RATE/2 - не нашёл в даташите
	ldi		r19,$23
	ldi		r20,$c8
	rcall	RFXX_WRT_CMD	;BR = 4789bps
	ldi		r19,$20
	ldi		r20,$c2
	rcall	RFXX_WRT_CMD	;enable TX bit sinchronization, no Low Battary Detector
	ldi		r19,$01
	ldi		r20,$c0
	rcall	RFXX_WRT_CMD	;disable CLK pin
	ret
;-------------------------------------------------------------------
;------------------передача данных через rf02-----------------------
Rf02_Transmitting:
	ldi		ChkSum,0
	ldi		r19,$39
	ldi		r20,$c0
	rcall	RFXX_WRT_CMD	;enable power amplifier, enable osc, enable synthesizer

	ldi		ChkSum,0
	ldi		r21,$aa
	rcall	RF02B_SEND

	ldi		r21,$aa
	rcall	RF02B_SEND
	ldi		r21,$aa
	rcall	RF02B_SEND
	ldi		r21,$2d
	rcall	RF02B_SEND
	ldi		r21,$d4
	rcall	RF02B_SEND

	mov		r21,r16
	rcall	RF02B_SEND

	ldi		r30,low(RfBuffer)
	ldi		r31,high(RfBuffer)
Trans1:
	ld		r21,Z+
	add		ChkSum,r21
	rcall	RF02B_SEND
	dec		r16
	brne	Trans1

	mov		r21,ChkSum
	rcall	RF02B_SEND
	ldi		r21,$aa
	rcall	RF02B_SEND

	ldi		r19,$01
	ldi		r20,$c0
	rcall	RFXX_WRT_CMD	;close ALL
	ret
;-------------------послать слово команды в rf02--------------------
RFXX_WRT_CMD:
	push	r16
	cbi		PORT_SCK,RFXX_SCK
	cbi		PORT_SEL,RFXX_SEL
	ldi		r16,16
R_W_C1:
	lsl		r17
	rol		r18
	sbic	PIN_SDO,RFXX_SDO
	ori		r17,1
	cbi		PORT_SCK,RFXX_SCK
	sbrc	r20,7
	sbi		PORT_SDI,RFXX_SDI
	sbrs	r20,7
	cbi		PORT_SDI,RFXX_SDI
	sbi		PORT_SCK,RFXX_SCK
	lsl		r19
	rol		r20
	dec		r16
	brne	R_W_C1
	cbi		PORT_SCK,RFXX_SCK
	sbi		PORT_SEL,RFXX_SEL
	pop		r16
	ret
;-----------------послать байт данных через 434МГц-------------------
RF02B_SEND:
	push	r16
	ldi		r16,8
SEND1:
	sbic	PIN_SDO,RFXX_SDO
	rjmp	SEND1
SEND2:
	sbis	PIN_SDO,RFXX_SDO
	rjmp	SEND2

	sbrc	r21,7
	rjmp	SEND3
	cbi		PORT_DATA,RFXX_DATA
	rjmp	SEND4
SEND3:
	sbi		PORT_DATA,RFXX_DATA
SEND4:
	lsl		r21
	dec		r16
	brne	SEND1
	pop		r16
	ret
;-------------------------------------------------------------------
;-----------------считать температуру с датчика---------------------
GetTempDS:
	rcall	ResetDS1820
	cpi		r16,$0
	breq	DS1820connect
	rcall	Error_
	ret
DS1820connect:
;считываю температуру
	rcall	ResetDS1820
	ldi		r17,$55			;команда MATCH ROM
	rcall	WriteDS
	rcall	WriteID_DS
	ldi		r17,$be			;команда Read Scratchpad
	rcall	WriteDS
	
	ldi		r16,9
	ldi		r30,low(Scratchpad)
	ldi 	r31,high(Scratchpad)
T_CA1:
	rcall	ReadDS
	st		Z+,r17
	dec		r16
	brne	T_CA1
;проверить CRC
	ldi		r30,low(Scratchpad)
	ldi 	r31,high(Scratchpad)
	ldi		r17,$8
	ldi		r16,0
	sts		CRC,r16
T_CA2:
	ld		r16,Z+
	rcall	CRC_
	dec		r17
	brne	T_CA2

	ld		r16,Z
	lds		r17,CRC
	cp		r16,r17
	brne	T_CA3
;запустить новое преобразование
	rcall	ResetDS1820
	ldi		r17,$55			;команда MATCH ROM
	rcall	WriteDS
	rcall	WriteID_DS
	ldi		r17,$44			;команда Convert T
	rcall	WriteDS
	sbi		portD,0			;оставить pinD0 в еденичном состоянии, чтобы датчик не думал что это reset



	lds		r16,Scratchpad
	lds		r17,Scratchpad+1
	lsl		r16
	rol		r17
	lsl		r16
	rol		r17
	lsl		r16
	rol		r17
	lsl		r16
	rol		r17
	sts		TempAct,r17
	swap	r16
	sts		TempAct+1,r16
	ldi		r16,0		;флаг что программа прошла без ошибок
	ret
T_CA3:
	ldi		r16,3
	rcall	Error_
	ret
;-------------------------------------------------------------------
;-----вычислить CRC контрольную сумму байт данных - в r16-----------
CRC_:
	push	r17
	push	r20
	push	r16
	lds		r20,CRC
	ldi		r17,$8
CRC_LOOP:
	eor		r16,r20
	sbrc	r16,0
	rjmp	CRC_1
	lsr		r20
	rjmp	CRC_2
CRC_1:
	ldi		r16,$19
	eor		r20,r16
	lsr		r20
	ori		r20,$80
CRC_2:
	pop		r16
	lsr		r16
	push	r16
	dec		r17
	brne	CRC_LOOP
	sts		CRC,r20
	pop		r16
	pop		r20
	pop		r17
	ret

;-------------------------------------------------------------------
;---------------вывести ID датчика на 1-wire------------------------		
WriteID_DS:
	ldi		r30,low(ID_DS)
	ldi 	r31,high(ID_DS)
	ldi		r17,0
	ldi		r16,8
WRID2:
	ld		r17,Z+
	rcall	WriteDS
	dec		r16
	brne	WRID2
	ret

;-------------------------------------------------------------------
;-----------------считать ID датчика на 1-wire----------------------		
ReadID_DS:
	ldi		r30,low(ID_DS)
	ldi 	r31,high(ID_DS)
	ldi		r16,8
RID2:
	rcall	ReadDS
	st		Z+,r17
	dec		r16
	brne	RID2
	ret

;-------------------------------------------------------------------
;---------Резет + проверка наличия отклика от датчика---------------
ResetDS1820:
	sbi		DDRDS1820,DS1820		;portD0 -  выход
	cbi		portDS1820,DS1820
	ldi		r16,$5
	rcall	WAIT_100us	;пауза примерно 500мкс
	sbi		portDS1820,DS1820		;portD0 -  вход подтянутый к 1
	nop
	cbi		DDRDS1820,DS1820		;portD0 -  вход
	ldi		r16,$1		
	rcall	WAIT_100us	;пауза примерно 100мкс
	ldi		r16,1		;флаг ошибки
	sbic	pinDS1820,DS1820
	ret
	ldi		r16,$4
	rcall	WAIT_100us	;пауза примерно 400мкс
	ldi		r16,0		;флаг что программа прошла без ошибок
	ret
;-------------------------------------------------------------------
;----------------Считать байт с 1-wire------------------------------
ReadDS:
	ldi		r17,0
	push	r16
	ldi		r16,8
RDS1:
	push	r16
	sbi		DDRDS1820,DS1820		;portD0 -  выход
	sbi		portDS1820,DS1820		;portD0=1
	nop					;пауза	>1мкс
	cbi		portDS1820,DS1820		;portD0=0
	nop
	sbi		portDS1820,DS1820		;portD0 -  вход подтянутый к 1
	cbi		DDRD,0		;portD0 -  вход
	ldi		r16,1
	rcall	WAIT_15us	;пауза 60мкс<pause<120
	sbic	pinDS1820,DS1820
	ori		r17,1
	ror		r17
	ldi		r16,2
	rcall	WAIT_15us	;пауза 60мкс<pause<120
	pop		r16
	dec		r16
	brne	RDS1
	ror		r17
	pop		r16
	ret

;-------------------------------------------------------------------
;--------------Записать байт на 1-wire------------------------------
WriteDS:
	push	r16
	ldi		r16,8
WDS1:
	push	r16
	sbi		DDRDS1820,DS1820	;portD0 -  выход
	sbi		portDS1820,DS1820		;portD0=1
	nop					;пауза	>1мкс
	cbi		portDS1820,DS1820		;portD0=0
	nop					;пауза	>1мкс
	sbrc	r17,0
	sbi		portDS1820,DS1820		;portD0=1
	ldi		r16,1
	ldi		r16,3
	rcall	WAIT_15us	;пауза 60мкс<pause<120
	lsr		r17
	pop		r16
	dec		r16
	brne	WDS1
	pop		r16
	ret

;-------------------------------------------------------------------
;-----------------инициализация термодатчика------------------------
IniDS1820:
	rcall	ResetDS1820
	cpi		r16,$0
	breq	IniDS1	;если датчик присутствует --> перейти
	rcall	Error_	;если датчик не ответил вывести ошибку номер r16
	ret

IniDS1:
	ldi		r17,$33			;команда READ ROM
	rcall	WriteDS
	rcall	ReadID_DS
;проверить CRC
	ldi		r30,low(ID_DS)
	ldi 	r31,high(ID_DS)
	ldi		r17,$7
	ldi		r16,0
	sts		CRC,r16
IniDS2:
	ld		r16,Z+
	rcall	CRC_
	dec		r17
	brne	IniDS2
	ld		r16,Z
	lds		r17,CRC
	cp		r16,r17
	brne	IniDS3
	ret
IniDS3:
	ldi		r16,2
	rcall	Error_
	
	ret
;-------------------------------------------------------------------
;-------------------пауза 100 мкс-----------------------------------
WAIT_100us:
	push	r16
	ldi		r16,$1f
W100_1:
	dec		r16
	brne	W100_1
	pop		r16
	dec		r16
	brne	WAIT_100us
	ret

;-------------------------------------------------------------------
;------------------пауза 15 мкс-------------------------------------
WAIT_15us:
	push	r16
	ldi		r16,1
W15_1:
	dec		r16
	brne	W15_1
	pop		r16
	dec		r16
	brne	WAIT_15us
	ret

;-------------------------------------------------------------------
;-------------------пауза 100 мс------------------------------------
WAIT_100ms:
	push	r16
	ldi		r16,$64
W100m_1:
;1000u
	push	r16
	ldi		r16,$f9
W100m_2:
	nop
	dec		r16
	brne	W100m_2
	pop		r16
;-----
	dec		r16
	brne	W100m_1
	pop		r16
	dec		r16
	brne	WAIT_100ms
	ret

;-------------------------------------------------------------------

;-------------------------------------------------------------------
Error_:
	ret
.EXIT
