/*
 * Teplica001.asm
 *
 *  Created: 11.03.2020 13:34:48
 *   Author: Иванов И.Г.
 *	3 крана
 *
 *
 *
 */ 


  .include "m328pdef.inc"
  #define F_CPU 16000000

.equ fck	=	16000000		;частота в герцах внутренний осц с устан сдив8
.equ BAUD	=	9600			;скорость
.equ UBRR_value	=	(fck/(BAUD*16))-1	;значение для регистра
.equ OneSec  = fck/256		    ;счетчик 1 секунда предделитель 256	

; микросхема часов DS1302  // 2(PD2)-CLK // 3(PD3)-DAT // 4(PD4)-RST(CE)
.equ PinCLK = PIND2				;2	
.equ PinDAT = PIND3				;3
.equ PinRST = PIND4				;4

; выбор шагового мотора для работы с кранами // 5(PD5)-1 мотор // 6(PD6)-2 мотор // 7(PD7)-3 мотор
.equ Mtr01EN = PIND5			;5	
.equ Mtr02EN = PIND6			;6
.equ Mtr03EN = PIND7			;7

; датчики состояния кранов
.equ Tap01_On = PINB0			;8	
.equ Tap01_Off = PINB1			;9	
.equ Tap02_On = PINB2			;10	
.equ Tap02_Off = PINB3			;11	
.equ Tap03_On = PINB4			;12	
.equ Tap03_Off = PINB5			;13	

.equ Tap03_OffDW = PINC4			;A4   вместо неисправной 13

; выводы обмоток шаговых двигателей
.equ MtrAmns = PINC0			;A0	
.equ MtrApls = PINC1			;A1	
.equ MtrBmns = PINC2			;A2	
.equ MtrBpls = PINC3			;A3	

;флаги в байте флагов FlagByte
.equ SwGoGo = 0					;0			флаг начатия полива
.equ Mtr01_On_Off = 1			;1			полив по крану 1
.equ Mtr02_On_Off = 2			;2			полив по крану 2
.equ Mtr03_On_Off = 3			;3			полив по крану 3


.DSEG				//0x0100
ArdDTime:			.BYTE 6			;время дата на устройстве ssmmhhDDMMYY
FlagByte:			.BYTE 1			;см выше
SwWrkTime:			.BYTE 2			;время полива в секундах 

MaskDoW:			.BYTE 1			;маска дней недели
WaterOn:			.BYTE 2			;время открытия mmhh
WaterOFF:			.BYTE 2			;время закрытия mmhh
WaterPer:			.BYTE 2			;время открытия одного крана
FazaAct:			.BYTE 1			;фаза двигателя (на все одна)

;портовые переменные
LnRxD:				.BYTE 1			;количество байт на прием
CntrRxD:			.BYTE 1			;счетчик приемника
BufRxD:				.BYTE 16		;буфер приемника
TmNxBt:				.BYTE 1			;таймер ожидания следующего байта

lnTxD:				.BYTE 1			;количество передаваемых байт
CntrTxD:			.BYTE 1			;счетчик передатчика
BufTxD:				.BYTE 16		;буфер передатчика


.eseg				//0x0000 EEPROM

EMaskDoW:			.BYTE 1			;маска дней недели
EWaterOn:			.BYTE 2			;время открытия mmhh во флеш
EWaterOFF:			.BYTE 2			;время закрытия mmhh во флеш
EWaterPer:			.BYTE 2			;время открытия одного крана




.cseg				//0x0000 Programm

Label_01:           jmp Label_03	; Reset
					jmp Label_02	; External Interrupt Request 0
                    jmp Label_02	; External Interrupt Request 1
                    jmp Label_02	; Pin Change Interrupt Request 0
                    jmp Label_02	; Pin Change Interrupt Request 0
                    jmp Label_02	; Pin Change Interrupt Request 1
                    jmp Label_02	; Watchdog Time-out Interrupt
                    jmp Label_02	; Timer/Counter2 Compare Match A
                    jmp Label_02	; Timer/Counter2 Compare Match B
                    jmp Label_02	; Timer/Counter2 Overflow
                    jmp Label_02	; Timer/Counter1 Capture Event
                    jmp Int_T1MA_01	; Timer/Counter1 Compare Match A			// обработчик прерывания 1 СЕКУНДА
                    jmp Int_T1MB_01	; Timer/Counter1 Compare Match B			
                    jmp Label_02	; Timer/Counter1 Overflow
                    jmp Label_02	; TimerCounter0 Compare Match A
                    jmp Label_02	; TimerCounter0 Compare Match B
                    jmp Label_02	; Timer/Couner0 Overflow
                    jmp Label_02  	; SPI Serial Transfer Complete
                    jmp Int_Recv_01	; USART Rx Complete							// принят байт
                    jmp Label_02	; USART, Data Register Empty
                    jmp Label_02	; USART Tx Complete
                    jmp Label_02	; ADC Conversion Complete
                    jmp Label_02	; EEPROM Ready
                    jmp Label_02	; Analog Comparator
                    jmp Label_02	; Two-wire Serial Interface
                    jmp Label_02	; Store Program Memory Read
                    
Label_02:			reti
					cli
					jmp Label_01

					 ;поле констант

					 ;длина принимаемой команды в зависимости от параметра с учетом двух байт CRC
LnRxCMD:			.db		0x04		;1 - команда запроса времени даты
					.db		0x0A		;2 - команда записи времени даты
					.db		0x04		;1 - команда запроса времени
					.db		0x04		;1 - команда запроса времени
					
					
					 ;таблица значений ацп для термопары с 10 до 70 град с шагом 1 град
tmprgrid:			 .dw      0x014A       ;   330		10
					 .dw      0x0156       ;   342
					 .dw      0x0162       ;   354
					 .dw      0x016E       ;   366
					 .dw      0x017A       ;   378
					 .dw      0x0186       ;   390
					 .dw      0x0192       ;   402
					 .dw      0x019E       ;   414
					 .dw      0x01AB       ;   427
					 .dw      0x01B7       ;   439
					 .dw      0x01C3       ;   451		20
					 .dw      0x01CF       ;   463		1
					 .dw      0x01DC       ;   476		2
					 .dw      0x01E8       ;   488		3
					 .dw      0x01F4       ;   500		4
					 .dw      0x0200       ;   512		25   10кОм
					 .dw      0x020C       ;   524
					 .dw      0x0218       ;   536
					 .dw      0x0224       ;   548
					 .dw      0x022F       ;   559
					 .dw      0x023B       ;   571		30
					 .dw      0x0246       ;   582
					 .dw      0x0252       ;   594
					 .dw      0x025D       ;   605
					 .dw      0x0268       ;   616
					 .dw      0x0272       ;   626
					 .dw      0x027D       ;   637
					 .dw      0x0287       ;   647
					 .dw      0x0292       ;   658
					 .dw      0x029C       ;   668
					 .dw      0x02A5       ;   677		40
					 .dw      0x02AF       ;   687
					 .dw      0x02B9       ;   697
					 .dw      0x02C2       ;   706
					 .dw      0x02CB       ;   715
					 .dw      0x02D4       ;   724
					 .dw      0x02DC       ;   732
					 .dw      0x02E5       ;   741
					 .dw      0x02ED       ;   749
					 .dw      0x02F5       ;   757
					 .dw      0x02FD       ;   765		50
					 .dw      0x0305       ;   773
					 .dw      0x030C       ;   780
					 .dw      0x0313       ;   787
					 .dw      0x031A       ;   794
					 .dw      0x0321       ;   801
					 .dw      0x0328       ;   808
					 .dw      0x032E       ;   814
					 .dw      0x0335       ;   821
					 .dw      0x033B       ;   827
					 .dw      0x0341       ;   833		60
					 .dw      0x0346       ;   838
					 .dw      0x034C       ;   844
					 .dw      0x0351       ;   849
					 .dw      0x0357       ;   855
					 .dw      0x035C       ;   860
					 .dw      0x0361       ;   865
					 .dw      0x0366       ;   870
					 .dw      0x036A       ;   874
					 .dw      0x036F       ;   879
tmprgridend:		 .dw      0x0373       ;   883		70



					 ;старт программы - инициализация
Label_03:           eor r1, r1			;r1 в ноль
					out SREG, r1		;в SREG ноль
					
					;------------------------------------------
					;время включения 
					ldi r16,15			;мин 
					sts WaterOn,r16 
					ldi r16,9			;час
					sts WaterOn+1,r16 
					;время отключения
					ldi r16,30			;мин 
					sts WaterOff,r16 
					ldi r16,11			;час
					sts WaterOff+1,r16 
					;маска дней недели
					ldi r16,0b00101100 
					sts MaskDoW,r16		;байт маски дней недели
					;время открытия одного крана в секундах
					ldi r16,low(15*60)			;мин 
					sts WaterPer,r16 
					ldi r16,high(15*60)			;час
					sts WaterPer+1,r16 
					
					
					
					;-------------------------------------------
					
					;--------------------------------------------------------------------------
					;системные настройки

					;определить стек
                    ldi r28,low(RAMEND) ;
                    ldi r29,high(RAMEND);конец рамы
                    out SPH, r29		; 
                    out SPL, r28		;загрузить стек 
					
					;настройка уарта
					ldi R16,high(UBRR_value)   ;устанавливаем скорость 9600 бод
	  				sts UBRR0H,R16
  					ldi R16,low(UBRR_value)   
					sts UBRR0L,R16
  					ldi R16,0b10011000  ;прерывание по приему, разрешен прием и передача, 8 бит
					sts UCSR0B,R16
					ldi R16, 0b10000110 ;работа с UCSR0C, асинхр, 8 бит, без контроля чет, 1 стоп
					sts UCSR0C,R16
					
					ldi R16, 0x00		
					sts CntrRxD,r16	;счетчик приемника в ноль	
					sts TmNxBt,r16		;таймер ожидания в 0
					ldi R16, 0x04		;4 байта на прием
					sts LnRxD,r16;
					
					
					;Т1 настроить на 1 секунду
					ldi r16, 0b00000000	;
					sts TCCR1A, r16		;норм раб, OC1A отключен, OC1B отключен, WGM11 0, WGM10 0
                    ldi r16, 0b00001100	;clk/256, WGM13 0, wgm12 1
					sts TCCR1B, r16		;предделитель 256 100,	Clear Timer On Compare (Сброс по совпадению) по А 0100
                    ldi r16, 0b00000000	;clk/256
					sts TCCR1C, r16		;предделитель
                    
					ldi r16, high(OneSec)	;
					sts OCR1AH, r16		;задать частоту 1гц
					ldi r16, low(OneSec)	;
					sts OCR1AL, r16		;задать частоту по А
					
					ldi r16,high(OneSec/250/2)		;
					sts OCR1BH, r16		;задать первый временной отступ по В половина 500гц
					ldi r16,low(OneSec/250/2)	;что бы каждое десятое не совпадало с прерыванием по секунде
					sts OCR1BL, r16		;задать прерывание по В

					ldi r16, 0x06		;
					sts TIMSK1, r16		;прерывание по совпадению А и В
					
					ldi r16, 0x00		;
					sts TIMSK2, r16		; нет прерываний по т2
					
					;-----------------------------------------------------------------
					;настройки по переферии
										
					;настройка порта D ножки 2,3,4 для чтения времени с DS1302
					in r16,DDRD
					sbr r16,(1<<PinCLK)|(1<<PinDAT)|(1<<PinRST) ;как выход
					out DDRD,r16 
					in r16,PIND	
					cbr r16,(1<<PinCLK)|(1<<PinDAT)|(1<<PinRST);снять выборку микросхемы СЕ=0, CLK вниз, DAT в ноль
					out PORTD,r16

					;обнулитьи флаги 
					ldi r16,00			; 
					sts FlagByte,r16	;байт программных флажков обнулить
					
					ldi r16,01			; 
					sts FazaAct,r16

					;зарядить счетчик открытия крана в секундах 
					lds r16,WaterPer 
					sts SwWrkTime,r16	;счетчик открытия крана в секундах мл.б.
					lds r16,WaterPer+1 
					sts SwWrkTime+1,r16 ;счетчик открытия крана в секундах ст.б.
					
					;снять выбор с моторов 
					in r16,DDRD
					sbr r16,(1<<Mtr01EN|1<<Mtr02EN|1<<Mtr03EN)  ;как выход
					out DDRD,r16 
					in r16,PIND
					cbr r16,(1<<Mtr01EN|1<<Mtr02EN|1<<Mtr03EN)	;в ноль
					out PORTD,r16
					
					; выводы обмоток шаговых двигателей занулить
					in r16,DDRC
					sbr r16,(1<<MtrAmns|1<<MtrApls|1<<MtrBmns|1<<MtrBpls)  ;как выход
					out DDRC,r16 
					in r16,PINC
					cbr r16,(1<<MtrAmns|1<<MtrApls|1<<MtrBmns|1<<MtrBpls)	;в ноль
					out PORTC,r16
					sei					;разрешить прерывание глобально

					; входы датчиков открытия закрытия как вход
					in r16,DDRB
					cbr r16,(1<<Tap01_On|1<<Tap01_Off|1<<Tap02_On|1<<Tap02_Off|1<<Tap03_On|1<<Tap03_Off)  ;как вход
					out DDRB,r16 
					in r16,PORTB
					cbr r16,(1<<Tap01_On|1<<Tap01_Off|1<<Tap02_On|1<<Tap02_Off|1<<Tap03_On|1<<Tap03_Off)  ;убрать подтягивающий резистор
					out PORTB,r16 
					
					;a4 вместо 13
					in r16,DDRC
					cbr r16,(1<<Tap03_OffDW)  ;как вход
					out DDRC,r16 
					in r16,PORTC
					cbr r16,(1<<Tap03_OffDW)  ;убрать подтягивающий резистор
					out PORTC,r16 
					
					;в режим ожидания
					ldi r16, 0x01
					out SMCR, r16		;режим ожидания Idle
Label_End:          sleep
					jmp Label_End

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// обработчик подинтервала по В, 10гц   r24 используем только здесь
Int_T1MB_01:		push r2 
                    push r3 
                    push r18
					push r19
					push r24
					in r24, SREG
					sbr r24,(1<<SREG_I)		;разрешить прерывания при восстановлении SREG, RETI не обязательно
					push r24                ;сохранить SREG
					push r25
					
					;в r2r3 счетчик таймера Т1
					lds r2,TCNT1L
					lds r3,TCNT1H
					//прибавить количество импульстов в OneSec/10 10гц
					ldi r24,low(OneSec/250-1)
					add r2,r24 
                    ldi r25,high(OneSec/250-1)
					adc r3,r25 
					brcc Int_T1MB_07	;если нет выхода за FFFF переход
					// выход за пределы FFFF - прибавить разницу 10000h-OneSec
					ldi r24,low(0x10000-OneSec)
					add r2,r24 
                    ldi r25,high(0x10000-OneSec)
					adc r3,r25 
					jmp Int_T1MB_15
Int_T1MB_07:		// сравнить с границей одной секунды
					push r2
					push r3
					ldi r24,low(OneSec)
					sub r2,r24 
                    ldi r25,high(OneSec)
					sbc r3,r25
					brcc Int_T1MB_11	;если ушел за OneSec, переход
Int_T1MB_09:		pop r3				;восстановить из стека
					pop r2
					jmp Int_T1MB_15
Int_T1MB_11:		or r2,r3
					breq Int_T1MB_09	;восстановить если было равно
					pop r24				;освободить стек
					pop r24				;освободить стек
Int_T1MB_15:		// записать новой значение для сравнения
					sts OCR1BH, r3		;задать значение на совпадение B таймера T1
					sts OCR1BL, r2		;задать частоту 
					sei

					;смотрим состояния датчиков у датчиков 1 - нет магнита 0 - есть магнит
					lds r24,FlagByte	;флаги в r24
					
					;
					in r25,PINC
					bst r25,Tap03_OffDW
					;
					
					in r25,PINB			;датчики в r25
					
					;
					bld r25,Tap03_Off
					;

					in r18,PIND			;выборка моторов в r18 - что сохранить другие ножки
					cbr r18,(1<<Mtr01EN|1<<Mtr02EN|1<<Mtr03EN)	;снять выборку моторов, выберутся при проверке датчиков

					;проверить на закрытие кранов те которые должны быть закрыты
					clt						;T = 0
					sbrc r24,Mtr01_On_Off	;первый кран должен быть закрыт - перескочить проверить на закрытие
					jmp Int_T1MB_19			;дальше
					sbrs r25,Tap01_Off		;первый кран не закрыт - надо закрыть - перепрыг
					jmp Int_T1MB_19
					sbr r18,(1<<Mtr01EN)	;выборка первого мотора
					set						;T = 1
Int_T1MB_19:		sbrc r24,Mtr02_On_Off	;второй кран должен быть закрыт - перескочить проверить на закрытие
					jmp Int_T1MB_21			;дальше
					sbrs r25,Tap02_Off		;второй кран не закрыт - надо закрыть - перепрыг
					jmp Int_T1MB_21
					sbr r18,(1<<Mtr02EN)	;выборка второго мотора
					set						;T = 1
Int_T1MB_21:		sbrc r24,Mtr03_On_Off	;третий кран должен быть закрыт - перескочить - проверить на закрытие
					jmp Int_T1MB_23			;дальше
					sbrs r25,Tap03_Off		;третий кран не закрыт - надо закрыть - перепрыг
					jmp Int_T1MB_23
					sbr r18,(1<<Mtr03EN)	;выборка третьего мотора
					set						;T = 1
Int_T1MB_23:		brtc Int_T1MB_27		;если Т=0 не нужно ничего закрывать, дальше проверка на открытие
					;поменять шаг в обратную сторону
					lds r24,FazaAct
					dec r24
					brne Int_T1MB_25
					ldi r24,8
Int_T1MB_25:		sts FazaAct,r24
					out PORTD,r18			;установить выборку моторов
					jmp Int_T1MB_47

Int_T1MB_27:		;проверить на открытие кранов те которые должны быть открыты
					;Т и так в 0
					sbrs r24,Mtr01_On_Off	;первый кран должен быть открыт - перескочить проверить на открытие
					jmp Int_T1MB_29			;дальше
					sbrs r25,Tap01_On		;первый кран не открыт - надо открыть - перепрыг
					jmp Int_T1MB_29
					sbr r18,(1<<Mtr01EN)	;выборка первого мотора
					set						;T = 1
Int_T1MB_29:		sbrs r24,Mtr02_On_Off	;второй кран должен быть открыт - перескочить проверить на открытие
					jmp Int_T1MB_31			;дальше
					sbrs r25,Tap02_On		;второй кран не открыт - надо открыть - перепрыг
					jmp Int_T1MB_31
					sbr r18,(1<<Mtr02EN)	;выборка первого мотора
					set						;T = 1
Int_T1MB_31:		sbrs r24,Mtr03_On_Off	;третий кран должен быть открыт - перескочить - проверить на открытие
					jmp Int_T1MB_33			;дальше
					sbrs r25,Tap03_On		;третий кран не открыт - надо открыть - перепрыг
					jmp Int_T1MB_33
					sbr r18,(1<<Mtr03EN)	;выборка первого мотора
					set						;T = 1
Int_T1MB_33:		out PORTD,r18			;установить выборку моторов
					brts Int_T1MB_35		;если Т=1 идем открывать
					jmp Int_T1MB_79			;ничего не делаем
Int_T1MB_35:		;поменять шаг в сторону открывания
					lds r24,FazaAct
					inc r24					;след шаг
					cpi r24,9
					brne Int_T1MB_37
					ldi r24,1
Int_T1MB_37:		sts FazaAct,r24
					
Int_T1MB_47:	    ;крутим 
					lds r24,FazaAct
					cpi r24,1
					brne Int_T1MB_49
					;1->
					in r24,PINC	
					sbr r24,(1<<MtrAmns)	;1 1
					cbr r24,(1<<MtrApls)	;2 0
					cbr r24,(1<<MtrBmns)	;3 0
					cbr r24,(1<<MtrBpls)	;4 0
					out PORTC,r24
					jmp Int_T1MB_79

Int_T1MB_49:		cpi r24,2
					brne Int_T1MB_51
					;2->
					in r24,PINC	
					sbr r24,(1<<MtrAmns)	;1 1
					cbr r24,(1<<MtrApls)	;2 0
					sbr r24,(1<<MtrBmns)	;3 1
					cbr r24,(1<<MtrBpls)	;4 0
					out PORTC,r24
					jmp Int_T1MB_79

Int_T1MB_51:		cpi r24,3
					brne Int_T1MB_53
					;3->
					in r24,PINC	
					cbr r24,(1<<MtrAmns)	;1 0
					cbr r24,(1<<MtrApls)	;2 0
					sbr r24,(1<<MtrBmns)	;3 1
					cbr r24,(1<<MtrBpls)	;4 0
					out PORTC,r24
					jmp Int_T1MB_79
Int_T1MB_53:		cpi r24,4
					brne Int_T1MB_55
					;4->
					in r24,PINC	
					cbr r24,(1<<MtrAmns)	;1 0
					sbr r24,(1<<MtrApls)	;2 1
					sbr r24,(1<<MtrBmns)	;3 1
					cbr r24,(1<<MtrBpls)	;4 0
					out PORTC,r24
					jmp Int_T1MB_79
Int_T1MB_55:		cpi r24,5
					brne Int_T1MB_57
					;5->
					in r24,PINC	
					cbr r24,(1<<MtrAmns)	;1 0
					sbr r24,(1<<MtrApls)	;2 1
					cbr r24,(1<<MtrBmns)	;3 0
					cbr r24,(1<<MtrBpls)	;4 0
					out PORTC,r24
					jmp Int_T1MB_79
Int_T1MB_57:		cpi r24,6
					brne Int_T1MB_59
					;6->
					in r24,PINC	
					cbr r24,(1<<MtrAmns)	;1 0
					sbr r24,(1<<MtrApls)	;2 1
					cbr r24,(1<<MtrBmns)	;3 0
					sbr r24,(1<<MtrBpls)	;4 1
					out PORTC,r24
					jmp Int_T1MB_79
Int_T1MB_59:		cpi r24,7
					brne Int_T1MB_61
					;7->
					in r24,PINC	
					cbr r24,(1<<MtrAmns)	;1 0
					cbr r24,(1<<MtrApls)	;2 0
					cbr r24,(1<<MtrBmns)	;3 0
					sbr r24,(1<<MtrBpls)	;4 1
					out PORTC,r24
					jmp Int_T1MB_79
Int_T1MB_61:		cpi r24,8
					brne Int_T1MB_63
					;8->
					in r24,PINC	
					sbr r24,(1<<MtrAmns)	;1 1
					cbr r24,(1<<MtrApls)	;2 0
					cbr r24,(1<<MtrBmns)	;3 0
					sbr r24,(1<<MtrBpls)	;4 1
					out PORTC,r24
					jmp Int_T1MB_79
Int_T1MB_63:		

Int_T1MB_79:		;освободить стек
					pop r25
					pop r24
					out SREG,r24
					pop r24
					pop r19
					pop r18
					pop r3
					pop r2
					ret


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//! обработчик прерывания 1 СЕКУНДА
Int_T1MA_01:		push r0 
                    push r16
					in r16, SREG
					sbr r16,(1<<SREG_I)		;разрешить прерывания при восстановлении SREG, RETI не обязательно
					push r16
					push r17
					push r26				;X
                    push r27				;
					push r30				;Z
                    push r31				;
					sei						;разрешить прерывания глобально
					
					;порт - контроль таймера
					lds r16,TmNxBt			;таймер ожидания 
					tst	r16
					breq Int_T1MA_03		;если таймер не заряжен ничего не делать
					dec r16
					sts TmNxBt,r16			;таймер ожидания уменьшить
					brne Int_T1MA_03		;если не ноль ждем дальше
					sts  CntrRxD,r16		;счетчик приемника в ноль	
					ldi  R16, 0x04			
					sts  LnRxD,r16;			;4 байта на прием по умолчанию
Int_T1MA_03:
					;прочитать время дату с DS1302   // 4(PD4)-CLK // 5(PD5)-DAT // 6(PD6)-RST(CE)
					call DtTmRead_01
					
Int_T1MA_19:		;проверяем день недели соответствует маске или нет
					call GetDoW_01			;посмотреть день недели текущего дня в r16 1..7
					lds r17,MaskDoW			;считать маску дней недели
Int_T1MA_21:		bst r17,0				;в T нулевой бит
					lsr r17					;сдвиг	
					dec r16					
					brne Int_T1MA_21		;не дошли до дня недели	
					brts Int_T1MA_23		;день полива, перейти
					jmp Int_T1MA_45		    ;Т=0 в этот день недели не нужно ничего делать
Int_T1MA_23:		;проверка времени на включение/отключение полива
					ldi r26,low(ArdDTime+1) ;
                    ldi r27,high(ArdDTime+1);адрес минуты
					ld r16,X+
					call DecToHex			;перевести из десятичного представления в шестнадцатиричный 
					mov r0,r16				;в r0 минуты
					ld r16,X
					call DecToHex			;перевести из десятичного представления в шестнадцатиричный 
					mov r1,r16				;в r1 часы
					;проверить: текущее время меньше времени закрытия?
					ldi r30,low(WaterOff) ;
                    ldi r31,high(WaterOff);загрузить в Z адрес времени отключения
					ld r16,Z+				;минута отключения
					ld r17,Z				;час отключения
					cp r0,r16
					cpc r1,r17				;сравнить время
					brcs Int_T1MA_25		;текущее время не достигло времени отключения
					;текущее время больше времени отключения - закончить полив
					lds r16,FlagByte
					sbrs r16,SwGoGo		    ;если флаг установлен - перешагунть и снять флаг выполнения полива
					jmp Int_T1MA_45			;не установлен - на выход
					cbr r16,(1<<SwGoGo|1<<Mtr01_On_Off|1<<Mtr02_On_Off|1<<Mtr03_On_Off)	;снять флаги полива и открытия кранов	
					sts FlagByte,r16		;сохранить состояния флажков
					lds r16,WaterPer		;зарядить счетчик открытия крана на будущее
					sts SwWrkTime,r16		;счетчик открытия крана в секундах мл.б.
					lds r16,WaterPer+1 
					sts SwWrkTime+1,r16		;счетчик открытия крана в секундах ст.б.
					jmp Int_T1MA_45
Int_T1MA_25:		;проверть: текущее время больше времени открытия?
					ldi r30,low(WaterOn) 	;
                    ldi r31,high(WaterOn)	;загрузить в Z время включения
					ld r16,Z+				;минута включения
					ld r17,Z				;час включения
					cp r0,r16
					cpc r1,r17				;сравнить время
					brcs Int_T1MA_45		;текущее время не достигло времени включения - на выход
					;текущее время в зоне полива
					lds r16,FlagByte
					sbrc r16,SwGoGo		    ;если флаг не установлен - перешагунть
					jmp Int_T1MA_27			;установлен - анализ
					;начать полив 
					sbr r16,(1<<SwGoGo|1<<Mtr01_On_Off)	;установить флаги полива и первого крана	
					cbr r16,(1<<Mtr02_On_Off|1<<Mtr03_On_Off)	;снять флаги открытия второго и третьего кранов	
					sts FlagByte,r16
					jmp Int_T1MA_45
Int_T1MA_27:		;полив уже идет
					lds r26,SwWrkTime
					lds r27,SwWrkTime+1
					sbiw r27:r26, 0x01 
					sts SwWrkTime,r26
					sts SwWrkTime+1,r27
					brne Int_T1MA_45
					;время открытия крана закончилось поменять кран
					lds r16,FlagByte
					lds r17,FlagByte
					;из 1 в 2
					bst r17,Mtr01_On_Off	;T <- Mtr01_On_Off из r17
					bld r16,Mtr02_On_Off	;Mtr02_On_Off <- T в r16
					;из 2 в 3
					bst r17,Mtr02_On_Off	;T <- Mtr02_On_Off из r17
					bld r16,Mtr03_On_Off	;Mtr03_On_Off <- T в r16
					;из 3 в 1
					bst r17,Mtr03_On_Off	;T <- Mtr03_On_Off из r17
					bld r16,Mtr01_On_Off	;Mtr01_On_Off <- T в r16
					sts FlagByte,r16		;сохранить состояния флажков
					
					lds r16,WaterPer		;зарядить счетчик открытия крана на будущее
					sts SwWrkTime,r16		;счетчик открытия крана в секундах мл.б.
					lds r16,WaterPer+1 
					sts SwWrkTime+1,r16		;счетчик открытия крана в секундах ст.б.

Int_T1MA_45:		;закончить прерывание
					pop r31
					pop r30
					pop r27
					pop r26
					pop r17
					pop r16
					out SREG,r16
					pop r16
					pop r0
					ret

					

					
;прочитать время дату с DS1302   // 4(PD4)-CLK // 5(PD5)-DAT // 6(PD6)-RST(CE)
DtTmRead_01:		ldi r26,low(ArdDTime) 	;буфер времени в X
                    ldi r27,high(ArdDTime)	;
					;читать секунду
					ldi r16,0x81			;читать секунду		
					call DTOnBtRead_01
					st X+,r16
					;читать минуту
					ldi r16,0x83			;читать 
					call DTOnBtRead_01
					st X+,r16
					;читать час
					ldi r16,0x85			;читать 
					call DTOnBtRead_01
					st X+,r16
					;читать день
					ldi r16,0x87			;читать 
					call DTOnBtRead_01
					st X+,r16
					;читать месяц
					ldi r16,0x89			;читать 
					call DTOnBtRead_01
					st X+,r16
					;читать год
					ldi r16,0x8D			;читать 
					call DTOnBtRead_01
					st X+,r16
					
					ret


;получить один байт
DTOnBtRead_01:		cli
					;in r30,DDRD
					;sbr r30,(1<<PinCLK)|(1<<PinDAT)|(1<<PinRST) ;как выход
					;out DDRD,r30 
					
					in r30,PIND	
					sbr r30,(1<<PinRST)		;выбрать микросхему СЕ=1
					cbr r30,(1<<PinCLK)		;CLK вниз
					out PORTD,r30
					;выдать команду
					ldi r17,0x08			;счетчик 8 бит
DTOnBtRead_02:		cbr r30,(1<<PinDAT)|(1<<PinCLK)	;сначала записать 0
					sbrc r16,0				;если мл.бит 0 пропуск, оставить 0
					sbr r30,(1<<PinDAT)		;записать 1 если мл.бит 1
					out PORTD,r30			;дернуть ножку DAT и одновременно CLK вниз
					sbr r30,(1<<PinCLK)		;записать 1 mode=0 
					out PORTD,r30			;дернуть ножку CLK вверх
					nop
					nop
					lsr r16					;двинуть в право
					dec r17
					brne DTOnBtRead_02
					;получить байт
					in r31,DDRD
					cbr r31,(1<<PinDAT)		;DAT как вход
					out DDRD,r31 
					ldi r17,0x08			;счетчик 8 бит
DTOnBtRead_03:		cbr r30,(1<<PinCLK)		;записать 0 mode=1
					out PORTD,r30			;дернуть ножку CLK вниз
					nop
					nop
					nop
					in r31,PIND				;прочитать в r31 на всякий не в r30
					cbr r16,(1<<7)			;ст.бит в 0
					sbrc r31,PinDAT				;если бит PinDAT 0 оставить 0
					sbr r16,(1<<7)			;ст.бит в 1
					dec r17
					breq DTOnBtRead_04
					sbr r30,(1<<PinCLK)		;записать 1 mode=1
					out PORTD,r30			;дернуть ножку CLK вверх
					lsr r16					;двинуть в право
					jmp DTOnBtRead_03
DTOnBtRead_04:		
					cbr r30,(1<<PinRST)|(1<<PinDAT)		;снять выборку микросхемы СЕ=0, DAT вниз для красоты
					out PORTD,r30
					in r31,DDRD
					sbr r31,(1<<PinDAT)		;DAT как выход
					out DDRD,r31 
					sei
					ret



//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// протокол: первый байт D1h
//			 второй байт параметр: 01h - запрос времени


//! обработчик прерывания прием байта
Int_Recv_01:		push r0					;r0
                    push r16				;r16
					in r16, SREG
					sbr r16,(1<<SREG_I)		;разрешить прерывания при восстановлении SREG, RETI не обязательно
					push r16				;sreg
					push r17				;r17
					push r18				;r18
					push r19				;r19
					push r26				;X
                    push r27				;
					push r30				;Z
                    push r31				;
					
					;прочитать байт
					lds r0,UDR0				;прочитать байт
					sei
					
					lds r16,CntrRxD
					cpi r16,0x00			;первый байт
					brne Int_Recv_05		;не первый байт
					;первый байт - "01"
					mov r16,r0
					cpi r16,0xD1			;первый байт "D1"
					brne Int_Recv_55		;не первый байт - выход
Int_Recv_03:		;запись байта и увеличение счетчика байт
					
					
					
					ldi R16, 0x02			;
					sts TmNxBt,r16			;таймер ожидания в 2
					lds r16,CntrRxD
					ldi r30,low(BufRxD) 	;
                    ldi r31,high(BufRxD)	;загрузить в Z адрес начала буфера
					add r30,r16
					brcc Int_Recv_04
					inc r31
Int_Recv_04:		st Z,r0					;записать байт в буфер
					inc r16					
					sts CntrRxD,r16			;сохранить счетчик принятых байт 
					;проверить не последний ли байт
					lds  r30,LnRxD
					cp r16,r30
					brcs Int_Recv_55		;не последний ждать следующий байт
					;записан последний байт команды - проверить контрольную сумму
					ldi r30,low(BufRxD) 	;
                    ldi r31,high(BufRxD)	;загрузить в Z адрес начала буфера
					call CRCBUF_00
					breq Int_Recv_21		;CRC совпадает, команда принята
					jmp Int_Recv_07			;CRC совпадает не совпадает сброс
					;
Int_Recv_05:		cpi r16,0x01			;второй
					brne Int_Recv_03		;не второй байт записать и увеличить счетчик
					;второй байт - параметр
					tst r0					;проверка на ноль
					brne Int_Recv_09		;параметр не нулевой
Int_Recv_07:		;ошибка приема
					lds r16,0x00			
					sts CntrRxD,r16			;обнулить счетчик принятых байт 
					sts TmNxBt,r16			;таймер ожидания в 0
					ldi R16, 0x04			;4 байта на прием
					sts LnRxD,r16;
					jmp Int_Recv_55
Int_Recv_09:		;по байту параметра определить длину принимаемой команды
					mov r16,r0
					cpi r16,0x05			;параметров <5 ()
					brcc Int_Recv_07		;если номер параметра уходит за пределы выход с обнулением счетчика
					dec r16					;-1
					lsl r16					;*2
					ldi r30,low(LnRxCMD*2) 	;
                    ldi r31,high(LnRxCMD*2)	;загрузить в Z адрес начала массива длины принимаемых команд
					add r30,r16
					brcc Int_Recv_11
					inc r31
Int_Recv_11:		lpm r16,Z				;прочитать длину команды согласно параметра
					sts LnRxD,r16			;записать длину принимаемой команды
					jmp Int_Recv_03			;записать принятый байт и увеличить счетчик	
Int_Recv_55:		;восстановить регистры и флаги
					pop r31
					pop r30
					pop r27
					pop r26
					pop r19
					pop r18
					pop r17
					pop r16
					out SREG,r16
					pop r16
					pop r0
					ret	

Int_Recv_21:		
					

					;команда принята - выдать ответ
					ldi r30,low(BufRxD+1) 	;
                    ldi r31,high(BufRxD+1)	;загрузить в Z адрес начала буфера
					ld r16,Z				;номер параметра
					cpi r16,0x01			;параметров <5
					brne Int_Recv_29		;не параметр = 1
					;параметр 1 - запрос времени
					ldi r17,0x01			;параметр чтения времени
Int_Recv_22:		ldi r16,0x06
					mov r0,r16				;счетчик 6 байт
					ldi r30,low(BufTxD) 	;
                    ldi r31,high(BufTxD)	;загрузить в Z адрес начала буфера
					ldi r16,0xC1
					st Z+,r16				;начальный байт 
					mov r16,r17
					st Z+,r16				;байт параметра
					ldi r26,low(ArdDTime) 	;
                    ldi r27,high(ArdDTime)	;дата время в X
					cli
Int_Recv_23:		ld r16,X+
					st Z+,r16				;байт параметра
					dec r0
					brne Int_Recv_23
					sei
					ldi r16,0x08			;количество байт без CRC
					;выдать ответ в порт
Int_Recv_24:		mov r0,r16				;счетчик 6 байт
					inc r0
					inc r0					;увеличить количество выдаваемых байт на 2 байта CRC
					ldi r30,low(BufTxD) 	;
                    ldi r31,high(BufTxD)	;загрузить в Z адрес начала буфера
					push r0
					call CRCBUF_00			;посчитать контрольную сумму			
					pop r0
					ldi r30,low(BufTxD) 	;
                    ldi r31,high(BufTxD)	;загрузить в Z адрес начала буфера
Int_Recv_25:		lds r16,UCSR0A
					sbrs  r16,UDRE0         ;ждем пока бит UDRE регистра UCSRA не будет пуст
					jmp  Int_Recv_25
					ld r16,Z+
					sts   UDR0,R16	
					dec r0
					brne Int_Recv_25
					jmp Int_Recv_07		;приготовится к следующему запросу

Int_Recv_29:		cpi r16,0x02			;параметров <5
					brne Int_Recv_39		;не параметр = 2
					;параметр 2 - запись времени и даты
					call DtTmWrite_01		;записать время дату в DS1302
					
					call DtTmRead_01		;считать время дату из DS1302
					ldi r17,0x02			;параметр чтения времени
					jmp Int_Recv_22		


Int_Recv_39:

					jmp Int_Recv_07		;ошибочный прием, приготовится к следующему запросу


;---proc подсчет контрольной суммы CRC: где Z(r31:r30) адрес буфера, R16 кол-во байт
					;исп. CRC - r19:r18, r0 - буфера для расчета 
CRCBUF_00:			ldi r19,0x00
					ldi r18,0x00			;инициализировать CRC
					mov r0,r18				;инициализировать буфер
CRCBUF_01:			push r16				;сохранить счетчик
					ld r0,Z+
					ldi r16,0x08			;счетчик бит зарядить 8
CRCBUF_03:			push r16				;счетчик бит в стек
					
					ldi r16,0x80			;для следующей операции
					lsl r0					;двинуть влево проверка старшего бита в С
					brcc CRCBUF_05			;если старший бит был 0 пропустить
					eor r19,r16
CRCBUF_05:			lsl r18
					rol r19
					brcc CRCBUF_07
					ldi r16,0x05			;для следующей операции
					eor r18,r16
					ldi r16,0x80			;для следующей операции
					eor r19,r16
CRCBUF_07:			pop r16
					dec r16
					brne CRCBUF_03
					pop r16
					dec r16
					brne CRCBUF_01
					st Z+,r19
					st Z+,r18
					or r18,r19
					ret
		
;записать время дату в DS1302   // 4(PD4)-CLK // 5(PD5)-DAT // 6(PD6)-RST(CE)
DtTmWrite_01:		
					;разрешить запись
					ldi r16,0x8E			;
					ldi r18,0x00			;байт на запись
					call DTOnBtWrite_01
					;записать заряд малым током
					ldi r16,0x90			;записать заряд малым током
					ldi r18,0xAB			;байт на запись
					call DTOnBtWrite_01
					
					ldi r26,low(BufRxD+2) 	;буфер времени в X
                    ldi r27,high(BufRxD+2)	;
					;записать секунду
					ldi r16,0x80			;
					ld r18,X+
					call DTOnBtWrite_01
					;записать минуту
					ldi r16,0x82			;
					ld r18,X+
					call DTOnBtWrite_01
					;записать час
					ldi r16,0x84			;
					ld r18,X+
					call DTOnBtWrite_01
					;записать день
					ldi r16,0x86			;
					ld r18,X+
					call DTOnBtWrite_01
					;записать месяц
					ldi r16,0x88			;
					ld r18,X+
					call DTOnBtWrite_01
					;записать год
					ldi r16,0x8C			;
					ld r18,X+
					call DTOnBtWrite_01
					
					ret


					;записать один байт
DTOnBtWrite_01:		cli
					nop
					nop
					in r30,PIND	
					sbr r30,(1<<PinRST)		;выбрать микросхему СЕ=1
					cbr r30,(1<<PinCLK)		;CLK вниз
					out PORTD,r30
					;выдать команду
					ldi r17,0x08			;счетчик 8 бит
DTOnBtWrite_02:		cbr r30,(1<<PinDAT)		;сначала записать 0
					sbrc r16,0				;если мл.бит 0 пропуск, оставить 0
					sbr r30,(1<<PinDAT)		;записать 1 если мл.бит 1
					out PORTD,r30			;дернуть ножку DAT и одновременно CLK вниз
					nop
					nop
					sbr r30,(1<<PinCLK)		;записать 1 mode=0 
					out PORTD,r30			;дернуть ножку CLK вверх
					nop
					nop
					cbr r30,(1<<PinCLK)		;CLK вниз
					out PORTD,r30
					nop
					nop
					lsr r16					;двинуть в право
					dec r17
					brne DTOnBtWrite_02
					;выдать записываемый байт
					ldi r17,0x08			;счетчик 8 бит
DTOnBtWrite_03:		cbr r30,(1<<PinDAT)		;сначала записать 0
					sbrc r18,0				;если мл.бит 0 пропуск, оставить 0
					sbr r30,(1<<PinDAT)		;записать 1 если мл.бит 1
					out PORTD,r30			;дернуть ножку DAT и одновременно CLK вниз
					nop
					nop
					sbr r30,(1<<PinCLK)		;записать 1 mode=0 
					out PORTD,r30			;дернуть ножку CLK вверх
					nop
					nop
					cbr r30,(1<<PinCLK)		;CLK вниз
					out PORTD,r30
					nop
					nop
					lsr r18					;двинуть в право
					dec r17
					brne DTOnBtWrite_03
					nop
					nop
					cbr r30,(1<<PinRST)|(1<<PinDAT)		;снять выборку микросхемы СЕ=0, DAT вниз для красоты
					out PORTD,r30
					sei
					ret

; GetDoW_01 определить день недели ArdDTime:			.BYTE 6			;время дата на устройстве ssmmhhDDMMYY
MnthDoW:			.db		0x00,0x03,0x03,0x06,0x01,0x04,0x06,0x02,0x05,0x00,0x03,0x03
					;	0x00		; январь  31 без отступа
					;	0x03 		; февраль 28 остаток 31/7 - 3
					;	0x03 		; март    31 остаток (31+28=59)/7 - 3
					;	0x06 		; апрель  30 остаток (59+31=90)/7 - 6
					;	0x01 		; май     31 остаток (90+30=120)/7 - 1
					;	0x04 		; июнь    30 остаток (120+31=151)/7 - 4
					;	0x06 		; июль    31 остаток (151+30=181)/7 - 6
					;	0x02 		; август  31 остаток (181+31=212)/7 - 2
					;	0x05 		; сентябрь 30 остаток (212+31=243)/7 - 5
					;	0x00 		; октябрь 31 остаток (243+30=273)/7 - 0
					;	0x03 		; ноябрь  30 остаток (273+31=304)/7 - 3
					;	0x03 		; декабрь 31 остаток (304+30=334)/7 - 5
					;первое число года по YY(с каждым годом +1)+1(потому что нулевой уже высокосный)+|YY/4|(по одному дню на высокосный)+6(начало столетия - суббота)
GetDoW_01:			ldi r18,0x07				;день недели начала столетия + 1
					ldi r26,low(ArdDTime+6) 	;
                    ldi r27,high(ArdDTime+6)	;адрес года +1 (потому что ld r16,-X сначала минусует потом читает)
					ld r16,-X					;год в десятичном формате
					call DecToHex				;перевести год из десятичного представления в шестнадцатиричный 
					add r18,r16					;YY+7
					lsr r16						;/2
					lsr r16						;/2
					add r18,r16					;+|YY/4| делить на 7 будем после прибавления по месяцу и дню
					;добавить отступ за месяц
					ld r16,-X					;месяц в десятичном формате
					call DecToHex				;перевести год из десятичного представления в шестнадцатиричный 
					ldi r30,low(MnthDoW*2) 		;
                    ldi r31,high(MnthDoW*2)		;загрузить в Z адрес MnthDoW масива месячных отступов
					dec r16						;отступ с нуля
					add r30,r16
					brcc GetDoW_03
					inc r31
GetDoW_03:		    lpm r16,Z					;взять отступ из массива
					add r18,r16					;прибавить отсуп по месяцу
					;добавить отступ по дням
					ld r16,-X					;день в десятичном формате
					call DecToHex				;перевести год из десятичного представления в шестнадцатиричный 
					dec r16
					add r16,r18					;прибавить отсуп по дню
					;разделить на 7, остаток будет днем недели
GetDoW_05:			cpi r16,8	
					brcs GetDoW_07				;если меньше 8 т.е. от 1 до 7 значит нашли день недели - выход
					subi r16,7					;минус 7
					jmp GetDoW_05
GetDoW_07:			ret		
					
					
DecToHex:  			push r0
					push r1
					push r17
					push r18
					mov r17,r16
					andi r17,0x0F				;выделить единицы
					andi r16,0xF0				;выделить десятки
					swap r16					;поменять ниблсы
					ldi r18,0x0A				
					mul r18,r16					;умножить десятки на 10
					mov r16,r0					;результат из r0
					add r16,r17					;добавить единицы
					pop r18
					pop r17
					pop r1
					pop r0
					ret
