?? hwgyjnkg.asm
字號(hào):
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)
;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -