Wednesday, February 06, 2013

PIC12F609 for That Fancy On/Off Switch

My previous post showed the hardware to light a string of white LEDs to be placed to illuminate a boy scout equipment trailer. The post previous to that went into some detail about the boost DC-DC SMPS that is the LED driver. This time I'm going to show what I came up to put inside that 8-pin chip labeled "PIC12F609"

I chose the PIC12F609 because I have some experience with Microchip products, it is a small 8-pin package, it can be obtained in an easily soldered through whole package, it is low power, it requires no external components, and it is cheap. There are other micro-controllers that meet these criteria; I chose this one. 

I haven't messed with any Microchip PICs for about five years and they have moved forward in that time. My good old PICKit1 is no longer supported by the current IDE, so I had to purchase a new programmer. I got a PICKit3. The IDE is now available for Mac and Linux in addition to Windows. Since I do most of my development work on a Linux workstation, I was very happy to see that. But I had enough trouble getting the installation to actually work, that I gave up and just used the MPLAB8 under Windows. Microchip provides reasonably good getting started information on their website. 

I am a hacker by nature. I approach problems by breaking them into smaller problems until I can solve them easily. Then I string the solutions together while testing at each step. This is reflected in my programs. Looking back over this program, I realize it probably should have been written interrupt driven. Interrupt at the timer crossings and button changes. But it works as written. 



;
; Trailer Boost 2
; Bruce McLaren
; nanoDragon LLC
; Bruce.McLaren@nanoDragon.com
; 16 Dec 12 - 19 Dec 12
;
;
; Hardware notes:
; PIC12F609 runnimg at 4MHz using internal oscillator
;
; GP0 : Output, LIGHT - A high turns the lights on
; GP4 : Output, SHUTDOWN - A high turns power off
; GP5 : Input, RELEASE - High when button released
; GP1 : Output, TICK - 200msec period TEST NOT USED IN APP
; GP2 : Output, SECOND - 2sec period TEST NOT USED IN APP
;

#include

__CONFIG _FOSC_INTOSCIO & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _IOSCFS_4MHZ & _BOR_OFF

errorlevel -302 ; suppress "not in bank0" warning

; Variables
CBLOCK 0x40 ; 64 bytes RAM in BANK0
TENTHS ; tenths of seconds counter
SECONDS ; seconds counter
MINUTES ; minutes counter
ENDC

ORG 0
nop ;
nop ;
nop ;
nop ;
nop ;

Initialization:
banksel GPIO ;
clrf GPIO ; clear outputs
banksel ANSEL ;
clrf ANSEL ; all digital I/O
movlw b'00100000' ;
movwf TRISIO ; GP5 is input
banksel T1CON ;
movlw b'00110000' ;
movwf T1CON ; /8, internal clock, disabled
banksel CMCON1 ;
bcf CMCON1, T1ACS ; FOSC/4
btfss GPIO, GP5 ; check RELEASE pin
goto $-1 ; wait for it to be 1


LightOn:
banksel TENTHS ;
movlw .9 ;
movwf TENTHS ; TENTHS = .9 (Counts Down)
movlw .59 ;
movwf SECONDS ; SECONDS = .59 (Counts Down)
movlw .29 ;
movwf MINUTES ; MINUTES = .29 (Counts Down)
movlw b'11001111' ; Seed Timer1 for FFFF - .12,500
movwf TMR1H ;
movlw b'00101100' ;
movwf TMR1L ;

LightAgain:
banksel PIR1 ;
bcf PIR1, TMR1IF ; Clear Timer1 overflow
bsf GPIO, GP0 ; set LIGHT
bsf T1CON, TMR1ON ; enable Timer 1
btfss PIR1, TMR1IF ;
goto $-1 ;
movlw b'11001111' ; Seed Timer1 immediately after
movwf TMR1H ; roll over, otherwise time
movlw b'00101100' ; delay depends on logic
movwf TMR1L ;
bcf PIR1, TMR1IF ; Clear Timer1 overflow
decfsz TENTHS, F ;
goto OnDecDoneTenths ; TENTHS is 0
decfsz SECONDS, F ;
goto OnDecDoneSecs ; SECONDS is 0
decfsz MINUTES, F ;
goto OnDecDone ;
goto Blink ; Time is up! Start blinking.
OnDecDoneTenths:
btfss TENTHS, 7 ; -1
goto OnDecDone ;
movlw b'00000100' ; bit 2
xorwf GPIO, F ; toggle SECOND
banksel TENTHS ;
movlw .9 ;
movwf TENTHS ; TENTHS = .9 (Counts Down)
OnDecDoneSecs:
btfss SECONDS, 7 ; -1
goto OnDecDone ;
banksel SECONDS ;
movlw .59 ;
movwf SECONDS ; SECONDS = .59 (Counts Down)
OnDecDone:
btfss GPIO, GP5 ; check RELEASE pin
goto WaitToBlink1 ; If RELEASE is 0, might Blink
movlw b'00000010' ; bit 1
xorwf GPIO, F ; toggle TICK1
goto LightAgain ; Do it again, light stays on.


WaitToBlink1: ; debounce button
banksel TMR0 ;
btfss PIR1, TMR1IF ;
goto $-1 ;
btfss GPIO, GP5 ; Check RELEASE pin
goto WaitToBlink2 ; If RELEASE is still 0, head to Blink
movlw b'00000010' ; bit 1
xorwf GPIO, F ; Toggle TICK1
; decrement the counters here for more accuracy
bcf PIR1, TMR1IF ; Clear Timer1 overflow
movlw b'11001111' ; Seed Timer1 for FFFF - .12,500
movwf TMR1H ;
movlw b'00101100' ;
movwf TMR1L ;
goto LightAgain ; Just a glitch, stay lit


WaitToBlink2: ; wait for button release
banksel T1CON
bcf T1CON, TMR1ON ; disable Timer 1
btfsc GPIO, GP5 ; Check RELEASE pin
goto Blink ; Button Released, go Blink
goto WaitToBlink2 ; Button still held, check again


Blink:
movlw .9 ;
movwf TENTHS ; TENTHS = .9 (Counts Down)
movlw .33 ;
movwf SECONDS ; SECONDS = .33 (Counts Down)
movlw .0 ;
movwf MINUTES ; MINUTES = .00 (Counts Down)
BlinkAgain:
movlw b'11001111' ; Seed Timer1 for FFFF - .12,500
movwf TMR1H ;
movlw b'00101100' ;
movwf TMR1L ;
bcf PIR1, TMR1IF ; Clear Timer1 overflow
bsf T1CON, TMR1ON ; enable Timer 1
btfss PIR1, TMR1IF ;
goto $-1 ;

decfsz TENTHS, F ;
goto BlinkDecDoneTenths ; TENTHS is 0
decfsz SECONDS, F ;
goto BlinkDecDone ;
goto ShutDown ; SECONDS is 0
BlinkDecDoneTenths:
btfss TENTHS, 7 ; -1
goto BlinkDecDone ;
movlw b'00000100' ; bit 2
xorwf GPIO, F ; toggle SECOND
banksel TENTHS ;
movlw .9 ;
movwf TENTHS ; TENTHS = .9 (Counts Down)

movlw b'00000111'
andwf SECONDS, W
btfsc STATUS, Z
goto BlinkLight ; not divisible by 8, Light
bsf GPIO, GP0 ; divisble by 8, go DARK
goto BlinkDecDone
BlinkLight:
bcf GPIO, GP0 ; Light

BlinkDecDone:
btfss GPIO, GP5 ; check RELEASE pin
goto WaitToRemain1 ; If RELEASE is 0, might Remain lit
movlw b'00000010' ; bit 1
xorwf GPIO, F ; toggle TICK1
goto BlinkAgain


WaitToRemain1:
banksel TMR0 ;
btfss PIR1, TMR1IF ;
goto $-1 ;
btfss GPIO, GP5 ; Check RELEASE pin
goto WaitToRemain2 ; If RELEASE is still 0, head to LightOn
movlw b'00000010' ; bit 1
xorwf GPIO, F ; Toggle TICK1
bcf PIR1, TMR1IF ; Clear Timer1 overflow
goto BlinkAgain ; Just a glitch, keep blinking


WaitToRemain2: ; wait for button release
banksel T1CON
bcf T1CON, TMR1ON ; disable Timer 1
btfss GPIO, GP5 ; Check RELEASE pin
goto WaitToRemain2 ; Button still held, check again
goto LightOn ; Button Released, return to Light


ShutDown:
banksel T1CON
bcf T1CON, TMR1ON ; disable Timer 1
bcf GPIO, GP0 ; not LIGHT
bsf GPIO, GP4 ; SHUTDOWN
goto $ ; wait for power to die

end
;


One of the YouTube channels I subscribe to is EEVblog. I find it entertaining as well as informative. OK, the guy whines a bit, but I like his approach. One of the episodes was his replacement for a toggle switch. He was meeting different requirements then I am, but I found the solution cool.

I seem to be able to keep up a one post per month schedule. In spite of contract work coming (and going), I can always put enough minutes together in any given month get one of these little guys written. So I'll stick with that schedule. 

Next month will be the physical parts of the Trailer LED project: PC board, case, and putting it in the trailer. At long last the culmination of these efforts. 

Until next month, good luck on your own projects!

Bruce McLaren