⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hwgyjnkg.asm

📁 红外感应节能开关
💻 ASM
📖 第 1 页 / 共 4 页
字号:
; ManualOff State
; ---------------
; This is the initial state of the device, and the state entered whenever the 
; load is explicitly switched off with a button press. It can also be entered from
; the AutoOff state in models that disable auto-on operation after a fixed vacancy time.
;
ManualOff:
		rcall	CheckButton			;Check for a button press
		brne	ModeDone			;If none, no action
GoLoadOn:
		rcall	ResetTimeouts
		sbr		status,(1<<fStaSwitchLoad)  ;Else turn on load
		ldi		temp0,ST_LOAD_ON			;And change to LoadOn state
		rjmp	NewState					;Return to the main loop
;
; LoadOn State
; ------------
; This is the only state in which the load is energized. It can be entered
; by a button press (from any other state), or due to occupancy and/or light
; level conditions.
;
LoadOn:	rcall	CheckButton					; Pressing button requests
		brne	LoadOn1						; turn-off of load,
		sbr		status,(1<<fStaSwitchLoad)  ; and return to ManualOff state
		rjmp	GoManualOff

LoadOn1:rcall	CheckOccupancy				; If area is now vacant,
		brne	ModeDone					; then the load should be turned off
		sbr		status,(1<<fStaSwitchLoad)	; and we move to AutoOff state
		rjmp	GoAutoOff
;
; AutoOff State
; -------------
; This state is entered from LoadOn or OnIfDark on the condition of an occupancy
; timeout. If a re-occupancy event occurs, OnIfDark will be entered. If, however,
; no such event occurs before the maximum vacancy period, "AutoOn" mode is cancelled
; by transitioning to the ManualOff state.
;
AutoOff:rcall	CheckButton		;Pressing the button is only
		breq	GoLoadOn		; meaningful here if the occupancy sensor
								; has failed; we implement this to allow
								; the user a way to turn on the load again

		rcall	CheckOccupancy		;If the area becomes occupied,
		breq	AutoOff1			; we go to OnIfDark to see if light level
		ldi		temp0,ST_ON_IF_DARK	; permits the lights to turn on
		rjmp	NewState			; automatically

AutoOff1:
		sbrs	mode,2				;If in Mode 5,
		cpse	testModeTimer,zero	; or if in Test Mode,
		rjmp	ModeDone			; stay in Auto Off
		cpi		vacantTimer,TM_AUTO	;Else remain in Auto Off only until 
		brlo	ModeDone			; area has been vacant long enough
GoManualOff:
		ldi		temp0,ST_MANUAL_OFF	; by defining VAC_CANCEL as $FFFF.		
		rjmp	NewState			;Return to the main loop
;
; OnIfDark State
; --------------
; This state is entered if the load was off, and the area transitioned from vacant
; to occupied. The load will be energized (and the LoadOn state entered) if the light
; level is low enough, or if the light level sensor is turned off. Otherwise, the
; unit will wait here until the light level drops, or until the area again becomes
; vacant, in which case the AutoOff state will again be entered.
;
OnIfDark:	rcall	CheckButton		;If the button is pressed, the user
			breq	OnIfDark1		; wants to override the light sensor,
									; so go turn on load
;
; If and when light-level sensing is added to the WN-100, code should be inserted here
; to branch to OnIfDark2 if the light level is too high.
;
OnIfDark1:	rjmp	GoLoadOn			; turn load on now
OnIfDark2:	rcall	CheckOccupancy		;Else, if the area becomes vacant
			brne	ModeDone			; again, we want to return to the
GoAutoOff:	ldi		temp0,ST_AUTO_OFF	; AutoOff state to await motion.
NewState:	cbr		status,ST_MASK		;Switch to desired new operating
			or		status,temp0		; state, and
			rjmp	ModeDone			;Return to the main loop

;----- S U B R O U T I N E S -------------------;
;      ---------------------
;
; The following routines are called from the above mainline code. Note that,
; due to the very limited internal stack of the ATtiny15 (only 3 levels!!),
; one must be careful to not insert too many call/return levels or unintended 
; operation will result.
;

; CheckButton
;
; Checks the debounced button status; if the button was just pressed,
; it returns the "EQ" condition (SREG Z set), else it returns "NE".
; If the button is seen as pressed, the occupancy timeout is reset, so
; that the unit will operate properly (and timeout!) even if the PIR sensor
; has not yet warmed up, or is in fact non-functional.
;
; Destroys:	temp0
;
CheckButton:
		mov		temp0,button			;Copy the button history
		andi	temp0,DEBOUNCE_MASK		; and mask off only the last few samples
		cpi		temp0,DEBOUNCE_RELEASE	;Check for button just released
		brne	CheckButton1			;If button released, area is occupied
		cpi		holdCounter,HOLD_CYC	;Also ignore if the button was held down
		brlo	ResetTimeouts			; too long, to avoid switching in mode change
CheckButton1:	ret						;Return to caller with EQ/NE status

; ResetTimeouts
;
; Resets all appropriate timeout counters, based upon an occupancy event having
; occurred. Destroys eepAdrs, temp0.
;
ResetTimeouts:
		ldi		occupTimerL,LOW(TM_TIMEOUT)
		ldi		occupTimerH,HIGH(TM_TIMEOUT)
		cpse	testModeTimer,zero			;If in Test Mode,
		rjmp	ResetT1						; force short (15 second) timeout
		ldi		eepAdrs,eeTimeouts			; Construct appropriate address
		add		eepAdrs,mode				; from active operating mode
		adc		eepAdrs,mode
		rcall	ReadEEPROM
		mov		occupTimerL,temp0			;Update main occupancy timeout
		rcall	ReadEEPROM
		mov		occupTimerH,temp0
ResetT1:
		ldi		nightLightTimer,NL_TIMEOUT 	;And one for auto nightlight
		clr		vacantTimer					;Zero vacancy and guarantee Z bit
		ret									; in SREG set on return
		
; CheckOccupancy
;
; Checks for occupancy, based upon the occupancy timer being non-zero.
; Returns NE if the area is occupied, EQ if the area is vacant.
;
; Destroys:	temp0
;
CheckOccupancy:
		mov		temp0,occupTimerH	;Simply check for the timer
		or		temp0,occupTimerL	; being non-zero in either half
		ret							;Return to caller with EQ/NE status


; LineSyncSleep
;
; Synchronize with the AC line by finding the beginning of the
; next negative AC half-cycle. This routine, as presently implemented,
; does NOT use a low-power (SLEEP) mode, unlike the WR-100/MCX.
;
LineSyncSleep:	clr	temp1			; Clear history mask for the zero cross
LineSyncS1:
		lsl		temp1				; First, ensure that we are in the
		sbic	PINB,fZeroCross		; positive half-cycle, by demanding 8
		inc		temp1				; solid '1' samples.
		cpi		temp1,$FF
		brne	LineSyncS1
LineSyncS2:
		lsl		temp1				; Incorporate the new sample, which will
		sbic	PINB,fZeroCross		; be a '1' only if line is positive
		inc		temp1				; relative to neutral.
		cpi		temp1,$80			; Loop until positive is followed by
		brne	LineSyncS2			; seven negative samples
		inc		lineCycles
		ret

; DelayAndSwitch
;
; Called at the beginning of the negative half-cycle, to switch the relay from its
; present state to the opposite state, and to correct/adapt the timing as required.
;
DelayAndSwitch:
		cbr		status,1<<fStaSwitchLoad
		out		TCCR1,zero				; Ensure Timer1 is stopped
		mov		temp1,onDelay			; Assume we are closing the relay
		sbic	PORTB,fRelayOn			; or, if not correct, establish
		mov		temp1,offDelay			; delay for opening.
		out		TCNT1,zero				; Clear the timer,
		ldi		temp0,(1<<PSR1)			; and the prescaler as well
		out		SFIOR,temp0
		ldi		temp0,TCCR1_INIT		; Then start the timer
		out		TCCR1,temp0
DS1:	in		temp0,TCNT1				; Wait for turn on/off point,
		cpse	temp0,temp1				; which has a resolution of 80uS,
		rjmp	DS1						; so this loop approach is suitable
		sbis	PORTB,fRelayOn
		rjmp	DS6						; Jump if now turning on relay
		cbi		PORTB,fRelayOn			; Turn off relay
DS2:	sbis	PINB,fZeroCross			; Ensure that we are in positive half-cycle
		rjmp	DS2						; and wait if not
DS3:	sbic	PINB,fRelaySense		; Then wait for contacts to open
		rjmp	DS3						; or end of positive half-cycle
		in		temp1,TCNT1				; Get timing of event
		cpi		temp1,HALFCYC+6			; Ignore any false early indications,
		brlo	DS3						; caused by lower amplitude of sense signal
		ldi		temp0,100/3				; Delay 100uS to allow for slope differential 
DS4:	dec		temp0					; between the relay sense and zero cross signals;
		brne	DS4						; sense negates early, even if relay did not open.
		ldi		temp0,-BACKOFF			; Assume that opening occurred late
		sbis	PINB,fZeroCross			; If we are now in negative half-cycle,
		rjmp	DS5						; we are late - back up.
		ldi		temp0,FULLCYC			; Else move turn-off later to compensate
		sub		temp0,temp1
DS5:	add		offDelay,temp0			; Correct turn-off timing
		rjmp	DS9

DS6:	sbi		PORTB,fRelayOn			; Turn on relay
		ldi		temp0,-BACKOFF			; Assume we are closing late
DS7:	in		temp1,TCNT1				; Wait for closure indication or end of
		cpi		temp1,FULLCYC-1			; positive half-cycle
		brsh	DS8						; If SH, late - back up
		sbis	PINB,fRelaySense		; Else continue waiting unless relay
		rjmp	DS7						; is seen to close early
		ldi		temp0,FULLCYC			; If closed early, compute change to 
		sub		temp0,temp1				; make to timing
DS8:	add		onDelay,temp0			; Adapt turn-on timing
DS9:	ret

; SetFlashPattern
;
; Establishes a new LED flash pattern in flashPatternH,L based upon the present value
; of the mode register. Used only in Program mode.
;
SetFlashPattern:
		ldi		eepAdrs,eeModePatterns	; and setup LED flash pattern to indicate
		add		eepAdrs,mode			; present mode number
		add		eepAdrs,mode
		rcall	ReadEEPROM
		mov		flashPatternL,temp0
		rcall	ReadEEPROM
		mov		flashPatternH,temp0
		ret

; UpdateFlashPattern
;
; Drive Nightlight from high-order bit of flashPatternH,L and rotate flash pattern one
; bit position to the left. Used by manfacturing test and installer program interface.
;
UpdateFlashPattern:
		cbi		PORTB,fNightLight	; First, update Nightlight based on present
		sbrc	flashPatternH,7		; high bit in pattern
		sbi		PORTB,fNightLight
		lsl		flashPatternL		; Then rotate 16-bit flash pattern to the left,
		rol		flashPatternH		; one bit position
		adc		flashPatternL,zero
		ret

; SampleADC
;
; Starts ADC conversion, and waits for it to complete.
;
SampleADC:	sbi		ADCSR,ADSC	;Start new conversion
SampleADC1:	sbic	ADCSR,ADSC	;Wait for conversion complete
			rjmp	SampleADC1
			ret					;Return with data in ADCH,L

; ReadEEPROM
;
; Reads the EEPROM byte addressed by eepAdrs, returning it in temp0;
; eepAdrs is updated to point to the next byte.
;
ReadEEPROM:
		sbic	EECR,EEWE		;Wait for any previous write to
		rjmp	ReadEEPROM		;complete before starting read
		out		EEAR,eepAdrs	;Establish address to read
		sbi		EECR,EERE		;And start the read operation
		in		temp0,EEDR		;Fetch result
		rjmp	WriteEEP1		;Return, incrementing address

; WriteEEPROM
;
; Writes the byte in temp0 to the EEPROM address given in eepAdrs;
; updates eepAdrs to point to the next byte.
;
WriteEEPROM:
		sbic	EECR,EEWE		;Wait for any previous write to
		rjmp	WriteEEPROM		;complete before starting next
		cli						;Then disable interrupts to
		out		EEAR,eepAdrs	;*** ensure that the master
		out		EEDR,temp0		;*** write enable and write
		sbi		EECR,EEMWE		;*** enable operations occur
		sbi		EECR,EEWE		;*** close enough together
		sei						;*** to trigger write.
WriteEEP1:
		inc		eepAdrs			;Update address for next write
		ret

; UpdateNightLight
;
; Sets Nightlight to appropriate state, in normal operating modes, based upon
; enable/disable status and nightlight timeout.
;
UpdateNightLight:
		mov		temp1,nightLightDisableL ;Set temp1 <> 0 if nightlight
		or		temp1,nightLightDisableH ; operation is presently disabled
		cpse	button,zero
		rjmp	UpdateNL1
		cpi		holdCounter,HOLD_CYC	; If front-panel button is held
		brlo	UpdateNL1				; down for at least a half-second,
		sbi		PORTB,fNightLight		; then display the enable/disable
		cpse	temp1,zero				; status in the nightlight itself
		cbi		PORTB,fNightLight
		rjmp	UpdateNL2

UpdateNL1:
		cbi		PORTB,fNightLight		; Under normal operations, the
		sbic	PORTB,fRelayOn			; the nightlight is off if the relay is on
		rjmp	UpdateNL2
		cpse	temp1,zero				; Otherwise, it is ON if not disabled,
		cpse	nightLightTimer,zero	; else ON only if motion was detected
		sbi		PORTB,fNightLight		; during last 90 seconds
UpdateNL2:	ret

; Table Data
;
; The factory oscillator calibration value is stored in the low-order byte of 
; the highest address location, i.e., LOW(@$1FF), or at byte address $3FE.
;
		.org	512-1
								;Oscillator calibration will be
FactoryOscCal:					; written into the last location

; E N D   O F   S O U R C E   F I L E
; -----------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -