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