I know it's not BASIC, but this little gadget comes in handy for folks that are just too lazy (like myself)
to turn on/off light switches all the time.
It's pretty simple stuff, and heavily commented, but if you have questions let me know.
Code:
;************************************************************************
;* Name : IR_SWITCH.asm *
;* Author : Bruce Reynolds *
;* Date : Feb 8th, 2006 *
;* Version : 1.0 *
;* Notes : PIC10F200 Automatic IR Appliance Switch *
;* Assembler : MPASMWIN v5.01 *
;* Operation : GP0 modulates an IR LED at 40kHz by generating 'Cycles' *
;* : number of 40kHz pulses. GP2 samples the IR detector output after *
;* : each carrier burst period. A logic 0 on the IR detector output *
;* : indicates a target is within range reflecting IR energy back onto *
;* : the IR detector. After 6 Hits in approximately 2 seconds GP1 will *
;* : turn on to drive a relay controlling 1 or more lights. *
;* : After OffTime number of samples with no Hits, approx 11 seconds, *
;* : the drive output on GP1 is turned back off. *
;* : As long as the target is within range the output will remain on. *
;* : When target leaves the area, after ~11 seconds, it turns back off *
;& : providing an auto light switch by sensing presence / no presence. *
;************************************************************************
title "Infrared automatic light switch"
processor 10F200
include <P10F200.inc>
__CONFIG _IntRC_OSC & _WDT_OFF & _CP_OFF & _MCLRE_OFF
#define IRLED GPIO,0 ; IR LED drive output pin
#define IRDET GPIO,2 ; IR detector input pin
#define LightOn bsf GPIO,1 ; turn drive output on
#define LightOff bcf GPIO,1 ; turn drive output off
; OffTime = 45 = approx 11 seconds. Adjust as required
#define OffTime D'45' ; delay before turn off of drive output
; MAX_HITS = 6 = approx 2 seconds before turn on if target present
#define MAX_HITS D'6' ; MAX object hits before drive output turns on
; setup RAM variable space
cblock 0x10 ; user RAM starts at 0x10 for 10F200/204
DelayTime:3 ; reserve 3 locations for delay counters
Cycles ; # of carrier cycles to generate IR signal
OffDelay ; time counter for output drive turn off delay
Hits ; holds recorded # of target Hits
endc
org 0x00
goto Init ; initialize I/O & peripherals
Main:
movlw D'50' ; generate 50 x 40kHz carrier cycles
movwf Cycles ; load carrier cycle count
call Pulse ; generate carrier burst
movlw D'1' ;
call Delay2 ; delay between carrier bursts/target checks
goto Main ; loop to Main
; infrared LED connection
; GPIO,0 ----\/\/\/\----|<|---- +5V DC
; 420 IR LED
Pulse ; send 'Cycles' number of 40kHz bursts
bcf IRLED ; 1uS turn on IR LED here
goto $+1 ; 2us
goto $+1 ; 2uS
goto $+1 ; 2us
goto $+1 ; 2uS
goto $+1 ; 2us
goto $+1 ; 2uS (13uS with IR LED on)
bsf IRLED ; 1uS turn off IR LED here
goto $+1 ; 2us
goto $+1 ; 2uS
goto $+1 ; 2us
goto $+1 ; 2us
decfsz Cycles,f ; 1uS decrement Cycles count, end pulse if Cycles = 0
goto Pulse ; 2uS/1uS (25uS total = 40kHz)
; goto Pulse above is 1uS once Cycles = 0, so it takes 8uS after the LED
; is off before we test the IR detector output. This is plenty fast since
; it takes a while for the detector output to settle after ending the IR
; carrier burst.
btfsc IRDET ; test detector output. If 0, target in range, CountHits
goto AlarmOff ; else jump to AlarmOff & count down turn-off period
CountHits
incf Hits,f ; target detected, increment Hits count
movlw MAX_HITS ; load MAX_HITS for comparison with current Hits count
subwf Hits,w ; if Hits = MAX_HITS then turn on drive output
skpnc ; if no carry, skip over LightOn, has not reached MAX_HITS
LightOn ; carry true, Hits = MAX_HITS, now turn on drive output
clrf OffDelay ; reset OffDelay period after all Hits
retlw 0 ; return to caller
AlarmOff
incf OffDelay,f ; increment time until turn off
movlw OffTime ; load OffTime for comparison with current OffDelay count
subwf OffDelay,w ; if OffDelay = OffTime, then turn drive output off
skpnc ; if no carry, skip over LightOff, has not reached OffTime
LightOff ; carry true, turn off output, OffTime period has expired
clrf Hits ; reset Hits count when no target is detected
retlw 0 ; return to caller
Delay ;
movlw D'2' ; 2 = a delay period of approximately 500mS
Delay2 ;
movwf delaytime ; pre-load W & enter at Delay2 for different delays
movlw D'232' ;
movwf delaytime+1 ;
movlw D'255' ;
movwf delaytime+2 ;
Dloop
clrwdt ; 1
decfsz delaytime+2,f ; 1
goto $-2 ; 2/1
decfsz delaytime+1,f ; 1
goto $-4 ; 2/1
decfsz delaytime,f ; 1
goto $-6 ; 2/1
retlw 0 ; 2
Init
movwf OSCCAL ; load factory osccal value at start-up
bcf OSCCAL,0 ; do NOT output osc/4 on GP2 (IR sensor input)
movlw b'00000001' ; IR LED on GP0 off on power-up
movwf GPIO ; load port latches
movlw b'00000100' ; GP2 = IR sensor input, rest outputs
tris GPIO ; set I/O directions
movlw b'11011000' ; wake-up on pin change disabled, weak pull-ups off
; Timer0 clock select on GP2 internal
option ; write to OPTION_REG
; clear all user RAM/variables on boot
movlw 0x10 ; initialize pointer
movwf FSR ; to RAM start
ClearNext
clrf INDF ; clear RAM location @ INDF
incf FSR,f ; increment pointer to next location
btfsc FSR,4 ; have we cleared location 0x10 yet..?
goto ClearNext ; nope, keep clearing
; yep, all done, continue
; approximately ~500mS power-up delay period for
; stabilization time
call Delay
goto Main
end
I recommend using a solid state relay for AC lights/appliances if you have one in your parts bin, but a
mechanical relay will work as well. You can find a few thousand relay drive circuits on any decent
search engine.
Bookmarks