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

📄 hwgyjnkg.asm

📁 红外感应节能开关
💻 ASM
📖 第 1 页 / 共 4 页
字号:
		sbic	PINB,fRelaySense		;If relay sense signal is seen high, while
		rjmp	MfgTestX				; relay is off, declare error type 3
		ldi		temp2,8					;Otherwise, prepare to switch relay ON/OFF 4 times
MfgTest7:
		in		temp0,PORTB				;Flip state of relay
		ldi		temp1,1<<fRelayOn
		eor		temp0,temp1
		out		PORTB,temp0
		ldi		temp0,60				;Then wait 1 second = 60 line cycles
MfgTest8:
		wdr
		rcall	LineSyncSleep
		dec		temp0
		brne	MfgTest8
		dec		temp2
		brne	MfgTest7
;
; All tests passed - record valid status for next power-up
;
		inc		mode
		ldi		eepAdrs,eeValid		;Record valid state for next power-up
		ldi		temp0,EE_VALID
		rcall	WriteEEPROM
;
; Tests completed - display result as flash pattern until next power-down
;
MfgTestX:
		rcall	SetFlashPattern		;Establish pattern to display
MfgTestX1:
		wdr
		rcall	UpdateFlashPattern	;Display next bit of pattern
		rcall	Delay16Cycles		;Then pause for approximately 0.27S
		rjmp	MfgTestX1

Delay16Cycles:
		ldi	temp0,HIGH(41667)		;Then pause for the equivalent of
		ldi	temp1,LOW (41667)		;16 line cycles
Delay16C1:
		subi	temp1,LOW (1)
		sbci	temp0,HIGH(1)
		brne	Delay16C1
		ret

;----- Main Background Loop --------------------;
;
; The main processing in the WN-100 is performed by this loop, which executes
; once every AC line cycle.
;
MainLoop:
		rcall	LineSyncSleep			;Find next positive line half-cycle
;
; Here at beginning of a positive half-cycle of the AC waveform.
; First, determine if the relay is to be switched ON or OFF, as we wish to time
; the operational delay from this point...
;
		sbrc	status,fStaSwitchLoad	;If switch pending,
		rcall	DelayAndSwitch			;go implement it
;
; Next, determine status of front-panel button and program mode switch (plus CdS
; light sensor, if present).
;
		cpse	button,zero				;If button is not held down,
		clr		holdCounter				;reinitialize time held down
		ldi		temp0,ADMUX_LIGHT
		out		ADMUX,temp0
		rcall	SampleADC				;Start ADC, returning when sample complete
		in		temp0,ADCH
		ldi		temp1,ADC_BUTTON_MAX	;Set maximum threshold for button pressed
		cp		temp1,temp0				;Set C if button not pressed
		rol		button					;Insert new sample into button history
		sbrs	button,0				;If the button was pressed in this cycle,
		rjmp	UserInt2				;no other information can be extracted now
;
; Here if button is not pressed during this line cycle, in which case we can determine
; the state of the Program mode switch.
;
		sbrs	status,fStaProgram		;Interpret Program Mode switch status
		rjmp	UserInt1				;Jump if not presently in Program Mode
		cpi		temp0,ADC_PGOFF_MAX+1	;Else check for exit from Program Mode
		brsh	UserInt2				;If SH, still in Program Mode
		cbr		status,(1<<fStaProgram)	;Else cancel program mode operation
		ldi		temp0,TM_CANCEL_TIMEOUT	;and initiate Test Mode, setting it to
		mov		testModeTimer,temp0		;cancel in five minutes
		rcall	UpdateNightLight		;And set nightlight based upon present state
		ldi		eepAdrs,eeMode			;And record the new mode in the nonvolatile
		mov		temp0,mode				;memory for use at next power-up
		rcall	WriteEEPROM
		rjmp	UserInt5

UserInt1:
		cpi		temp0,ADC_PGOFF_MAX+1	;If not presently in Program Mode, check
		brlo	UserInt5				;for flip of mode switch
		sbr		status,(1<<fStaProgram)	;Else flag as now in Program Mode
		rjmp	UserInt3				;and initialize flash pattern

UserInt2:
		sbrs	status,fStaProgram		;If not in Program mode,
		rjmp	UserInt5				;simply go update timers
		rcall	CheckButton				;While in Program mode, if button is pressed,
		brne	UserInt4				;move to the next available mode
		inc		mode					;wrapping back to Mode 1 after maximum is
		ldi		temp0,MAX_MODE+1		;reached
		cp		mode,temp0
		brlo	UserInt3
		clr		mode
UserInt3:
		rcall	SetFlashPattern			;Update flash pattern on mode changes
UserInt4:
		ldi		temp0,0x0F				;While in Program mode, update flash pattern
		and		temp0,lineCycles		;once every 16 line cycles (= 0.27S)
		brne	UserInt5
		rcall	UpdateFlashPattern		;Drive Nightlight and rotate pattern
UserInt5:
;
; Update other software timers, once every 256 line cycles
;
UpdateTimers:
		cpse	lineCycles,zero			;Only process once every 256 line cycles (= 4.27S)
		rjmp	UpdateTimers1
		cpse	testModeTimer,zero		;If test mode is active, count down its
		dec		testModeTimer			;timeout
		mov		temp0,nightLightDisableL;And, if nightlight function is disabled by user,
		or		temp0,nightLightDisableH;count down time until it can be reenabled
		breq	UpdateTimers1			;If EQ, nightlight not now disabled
		ldi		temp0,1					;Else decrement the timeout
		sub		nightLightDisableL,temp0
		sbc		nightLightDisableH,zero
UpdateTimers1:
;
; Check for user enable/disable of nightlight, which is signalled by pressing and holding the button.
;
		sbrc	status,fStaProgram		;If we are in Program mode, skip all other steps,
		rjmp	EndMainLoop				;and ignore PIR processing for now
		cpse	button,zero				;If the button is not held down,
		rjmp	CheckEnbDis4			;no work here
CheckEnbDis1:
		cpi		holdCounter,$FE			;When we reach the end of the 4.27S hold period,
		brne	CheckEnbDis3			;toggle the enable/disable state of the nightlight
		mov		temp0,nightLightDisableL
		or		temp0,nightLightDisableH
		brne	CheckEnbDis2
		ldi		temp0,LOW (NL_DISABLE)
		mov		nightLightDisableL,temp0
		ldi		temp0,HIGH(NL_DISABLE)
		mov		nightLightDisableH,temp0
		rjmp	CheckEnbDis3

CheckEnbDis2:
		clr		nightLightDisableH		;If nightlight was disabled, enable it now
		clr		nightLightDisableL
CheckEnbDis3:
		cpi		holdCounter,$FF			;Track button hold time, but do not allow to
		adc		holdCounter,zero		;exceed $FF
CheckEnbDis4:
		rcall	UpdateNightLight;In any case, ensure proper display of nightlight now
;
; Check for occupancy detection, and update occupancy and vacancy timers.
;
Sample:	mov		lastSample,newSample	;Preserve previous sample for detection
		clr		newSample				;Take four new occupancy samples
		clr		temp2					;and average them, to ensure that
		ldi		counter,4				;any transient noise effects are
		ldi		temp0,ADMUX_OCCUP		;minimized before later processing.
		out		ADMUX,temp0
Sample1:rcall	SampleADC				;Start new conversion
		in		temp1,ADCL				;Then fetch the data
		in		temp0,ADCH
		add		newSample,temp1
		adc		temp2,temp0
		dec		counter
		brne	Sample1
		andi	newSample,$F0			;Create single 8-bit average from
		or		newSample,temp2			;the sum of the four 10-bit samples
		swap	newSample
		cpi		newSample,MAX_PIR+1		;Limit range of PIR to be symmetric
		brlo	Sample2
		ldi		newSample,MAX_PIR
Sample2:
		subi	newSample,PIR_CENTER	;Get offset from centerline of PIR signal
		brcc	Sample3					;If new value was below centerline,
		neg		newSample				;take its absolute value

Sample3:
		subi	ignoreTimer,1			;Decrease cycles to ignore, but do
		adc		ignoreTimer,zero		;not allow to go negative
		brne	OccupDone				;Skip processing if ignoring transients
		cp		maxNoise,newSample		;Track peaks in PIR waveform,
		brsh	Sample4					;only when area is declared vacant,
		cpse	vacantTimer,zero		;to use as a measure of the IR noise
		mov		maxNoise,newSample		;for automatic sensitivity adjustment
Sample4:
		cpse	pulseTimer,zero			;Update time from initial exceeding
		inc		pulseTimer				;of threshold, in line cycles
		cpi		pulseTimer,MAX_WIDTH	;but do not allow to exceed two seconds
		brlo	Sample5					;because pulses must be closely spaced
		clr		pulseTimer				;to warrant a detection declaration
Sample5:
		cp		newSample,threshold		;If present sample exceeds the
		brlo	Sample7					;dynamically-adjusted sensitivity,
		cpi		pulseTimer,MIN_WIDTH	;and we have seen a previous pulse
		brlo	Sample6					;more than 0.5 seconds ago,
		cp		lastSample,threshold	;and the present pulse is at least
		brlo	NoOccupancy				;33mS wide, and
		sbrs	status,fStaFirstSeen	;the signal dropped below the threshold
		rjmp	NoOccupancy				;at least once since the first crossing,
		rcall	ResetTimeouts			;we declare the area occupied,
		rjmp	OccupDone				;going back to a full timeout

Sample6:
		tst		pulseTimer				;If above threshold, but not yet a
		brne	NoOccupancy				;valid occupancy event,
		cp		lastSample,threshold	;and this is a new low-to-high
		adc		pulseTimer,zero			;transition on the occupancy signal,
		rjmp	NoOccupancy				;start the pulse timer

Sample7:
		cpse	pulseTimer,zero			;When signal falls below threshold,
		sbr		status,1<<fStaFirstSeen	;note that a first pulse has been seen
		cpi		pulseTimer,MIN_PULSE	;However, we must qualify the width and
		brsh	NoOccupancy				;ignore it if the pulse was less than
		clr		pulseTimer				;33 mS wide, by cancelling timer

NoOccupancy:
		tst		pulseTimer				;If pulse timer is cancelled, forget
		brne	NoOccupancy1			;any valid initial pulse that was
		cbr		status,1<<fStaFirstSeen	;seen earlier

NoOccupancy1:
		ldi		temp1,0x0F				;Only count down timeouts every 16 line cycles
		and		temp1,lineCycles		;or approximately 0.27S
		mov		temp0,occupTimerH		;If no detection this cycle, see if the
		or		temp0,occupTimerL		;area has already been declared vacant
		breq	NowVacant				;and if so, jump

		cpi		newSample,HOLD_THRESH	;If the area is still occupied, and the
		brlo	NoOccupancy2			;PIR signal is large, consider the area
		rcall	ResetTimeouts			;as continuing to show motion

NoOccupancy2:
		cpse	temp1,zero				;Only decrement timeouts every 16 cycles
		rjmp	OccupDone
		subi	occupTimerL,LOW(1)		;Else count down to vacancy
		sbci	occupTimerH,HIGH(1)
		cpse	nightLightTimer,zero	;And update special nightlight occupancy
		cpse	lineCycles,zero			;timeout as well, once every 256 line cycles
		rjmp	OccupDone
		dec		nightLightTimer
		rjmp	OccupDone

NowVacant:
		cpse	temp1,zero			;Only increment vacancy count every 16 cycles
		rjmp	OccupDone
		cpi		vacantTimer,0xFF	;Measure time since vacancy, but don't
		adc		vacantTimer,zero	;allow to exceed 255 (maximum)
OccupDone:
;
; Dispatch based upon present operating state to handle any changes.
;
ModeXX:	sbrc	status,fStaMode1	;Dispatch to one of four possible
		rjmp	Mode1X				;operating states, based upon the
Mode0X:	sbrs	status,fStaMode0	;two-bit mode field in the status
		rjmp	ManualOff			;register.
		rjmp	LoadOn

Mode1X:	sbrs	status,fStaMode0	;Note that all state processors will
		rjmp	AutoOff				;return to label "ModeDone" upon
		rjmp	OnIfDark			;completion of their processing

ModeDone:
;
; Every 256 line cycles (4.27 seconds), we adjust the occupancy sensor sensitivity
; based upon a weighted average of the last 65536 such periods (approx. 3.24 days).
;
AdjustSens:
		cpse	maxNoise,zero		;No processing if no noise collected,
		cpse	lineCycles,zero		;or if not at 4.27 second boundary
		rjmp	Adjust4

		sub		noiseL,noiseH		;Average new data point with the
		sbc		noiseM,zero			;the existing 24-bit value
		sbc		noiseH,zero
		add		noiseL,maxNoise
		adc		noiseM,zero
		adc		noiseH,zero

		clr		maxNoise			;Reset peak detector for next interval

		ldi		temp0,NOISE_OFFSET	;Use present average to create new
		add		temp0,noiseH		;threshold value for occupancy detect
		brvs	Adjust2				;If overflow, use minimum sensitivity
		cpi		temp0,MIN_THRESH	;Else compare against minimum valid
		brsh	Adjust1				;threshold (= maximum sensitivity)
		ldi		temp0,MIN_THRESH	;and limit if too low
		rjmp	Adjust3

Adjust1:
		cpi		temp0,MAX_THRESH+1	;Ensure threshold not too high
		brlo	Adjust3				;(sensitivity too low)
Adjust2:
		ldi		temp0,MAX_THRESH	;and limit if too high
Adjust3:
		mov		threshold,temp0		;Finally, update sensitivity to use now
Adjust4:
;
; Finally, update watchdog timer, indicating successful completion of the work for this
; line cycle. If we should experience a line dropout, or if the internal state of the
; microcontroller should be damaged by ESD or other sources, the watchdog will cause the
; unit to reset, returning to an OFF state.
;
EndMainLoop:
		wdr					;Reset the watchdog for another 0.75 second
		rjmp	MainLoop	;Loop, looking for new line cycle


;----- O P E R A T I N G   S T A T E S ---------;
;      -------------------------------
;
; The following routines process input conditions for each of the
; four possible states of the WCP device. The states are defined
; as follows in the "status" byte:
;
.equ	ST_MANUAL_OFF = (0<<fStaMode1)+(0<<fStaMode0)
.equ	ST_LOAD_ON	  = (0<<fStaMode1)+(1<<fStaMode0)
.equ	ST_AUTO_OFF   =	(1<<fStaMode1)+(0<<fStaMode0)
.equ	ST_ON_IF_DARK =	(1<<fStaMode1)+(1<<fStaMode0)
.equ	ST_MASK 	  =	(1<<fStaMode1)+(1<<fStaMode0)
;

⌨️ 快捷键说明

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