; ; SpookyBulb.asm (c) 2008, Mats Engstrom ; ; See http://www.instructables.com/id/EUKXDOPFC2BTV59/ for more information ; ; This software is licenced as: ; Attribution Non-commercial Share Alike (by-nc-sa) ; ; This license lets others remix, tweak, and build upon your work non-commercially, ; as long as they credit you and license their new creations under the identical terms. ; Others can download and redistribute your work just like the by-nc-nd license, but ; they can also translate, make remixes, and produce new stories based on your work. ; All new work based on yours will carry the same license, so any derivatives will ; also be non-commercial in nature. ; ; ; ; This project was inspired by the project at: http://imakeprojects.com/Projects/glow-crystal/ ; ; ; 12F675 ; +--()--+ ; VCC | 1 8| GND ; GP5/T1CKI/OSC1/CLKIN| 2 7| GP0/AN0/CIN+/ICSPDAT ; GP4/AN3/-T1G/OSC2/CLKOUT| 3 6| GP1/AN1/CIN-/VREF/ICSPCLK ; GP3/-MCLR/VPP | 4 5| GP2/AN2/T0CKI/INT/COUT ; +------+ ; ; GP0 - UV Led #1 ; GP1 - UV Led #2 ; GP2 - Red Led ; GP3 - n/c ; GP4 - n/c ; GP5 - n/c ; ; LIST P=12F675, R=DEC INCLUDE ERRORLEVEL -302 ; No bank warning messages please ; ; ==== CONFIGURATION WORD ==== ; ; No Data protect, No code protect, Brown-out reset enabled ; No MCLR pin, Power-up Timer enabled, Watchdog Timer disabled ; Oscillator is INTOSC with no CLKOUT ; __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF ; ; ==== VARIABLES ==== ; cblock 0x20 status_tmp ; Holds the STATUS register during ISR w_tmp ; Holds the W register during ISR pwmtick ; Tick used to compare with led* pwm values flags ; See Constatnts for definition of the flags ledUv1 ; Pwm value for the first UV led ledUv2 ; Pwm value for the second UV led ledRed ; Pwm value for the red led rnd ; Random number generator timetick1 ; Backwards counting timer, approx 15 mS / step timetick2 ; Backwards counting timer, approx 15 mS / step speed1 ; Speed for UV1 speed2 ; Speed for UV2 target1 ; Target value for UV1 target2 ; Target value for UV2 endc ; ; ==== CONSTANTS ==== ; ticked equ 0 ; Set each time a ; ==== CODE ==== ORG 0000h ; Power-on Reset vector goto Reset ORG 0004h ; Interrupt vector goto Interrupt Reset: bsf STATUS, RP0 ; Bank 1 call 0x3ff ; Get the cal value movwf OSCCAL ; Calibrate oscillator clrf ANSEL ; Digital I/O movlw B'00000000' ; Timer0 prescaler 1:2 movwf OPTION_REG movlw B'10100000' ; Enable interrups in T0IE movwf INTCON movlw B'00111000' ; Set GP0,1,2 = OUTPUT movwf TRISIO ; and GP3,4,5 = INPUT bcf STATUS, RP0 ; Bank 0 movlw 0x07 ; Set GP to digital IO movwf CMCON movlw B'00000111' ; Turn off all leds movwf GPIO ; Init GPIO clrf ledUv1 ; Start with all leds off clrf ledUv2 clrf ledRed movlw 2000/15 ; Delay for 2 seconds a startup movwf timetick1 tstf timetick1 bnz $-2 movlw 0xFF ; Red on for 0.1 seconds movwf ledRed movlw 100/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0x00 ; Red off for 0.5 seconds movwf ledRed movlw 500/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0xFF ; Red on for 0.1 seconds movwf ledRed movlw 100/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0x00 ; Red off for 0.5 seconds movwf ledRed movlw 500/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 300/15 ; Fade up red for 0.3 seconds movwf timetick1 f0 movlw 4 ; steprate btfss flags, ticked goto ff0 addwf ledRed,F bcf flags, ticked ff0 tstf timetick1 bnz f0 movlw 0x00 ; Red off for 0.5 seconds movwf ledRed movlw 500/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 100/15 ; Fade up red for 1 seconds movwf timetick1 f1 movlw 1 ; steprate btfss flags, ticked goto ff1 addwf ledRed,F bcf flags, ticked ff1 tstf timetick1 bnz f1 movlw 0x10 ; Faint Green on for 0.1 seconds movwf ledUv1 movlw 100/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0x00 ; Faint Green Off movwf ledUv1 movlw 0x00 ; Red off for 0.3 seconds movwf ledRed movlw 300/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 500/15 ; Fade up red for 0.5 seconds movwf timetick1 f2 movlw 1 ; steprate btfss flags, ticked goto ff2 addwf ledRed,F bcf flags, ticked ff2 tstf timetick1 bnz f2 movlw 0x05 ; Faint Green on for 0.1 seconds movwf ledUv1 movlw 100/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0xFF ; Green on for 0.1 seconds movwf ledUv1 movlw 100/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0x00 ; Red off movwf ledRed movlw 0x05 ; Faint Green on for 0.1 seconds movwf ledUv1 movlw 100/15 movwf timetick1 tstf timetick1 bnz $-2 movlw 0x00 ; Fade up UV1 for 2 seconds movwf ledUv1 movlw 2000/15 movwf timetick1 f3 movlw 1 ; steprate btfss flags, ticked goto ff3 addwf ledUv1,F bcf flags, ticked ff3 tstf timetick1 bnz f3 call ReadEEValue ; Initialize the random seed movwf rnd ; with data from the EEPROM incf rnd,W call WriteEEValue ; Write back a new seed to the EEPROM call GetRandomUV1 ; Initialize values & rates call GetRandomUV2 ; with random values movlw 1 movwf timetick1 movwf timetick2 Loop: ; The rest of the time will ; be spent here flickering the ; UV leds HandleUV1 tstf timetick1 ; If not tick timeout then bnz huv1c ; goto next led movf speed1,W ; Reset the tick time movwf timetick1 movf ledUv1,W ; Test if current value is at target subwf target1,W bnz huv1a call GetRandomUV1 ; yes, get new random values goto huv1c huv1a movf ledUv1,W ; Test for going up or down subwf target1,W skpnc goto huv1b decf ledUv1,F ; decrease the light level goto huv1c huv1b incf ledUv1,F ; increase the light level huv1c HandleUV2 tstf timetick2 ; If not tick timeout then bnz huv2c ; goto next led movf speed2,W ; Reset the tick time movwf timetick2 movf ledUv2,W ; Test if current value is at target subwf target2,W bnz huv2a call GetRandomUV2 ; yes, get new random values goto huv2c huv2a movf ledUv2,W ; Test for goinng up or down subwf target2,W skpnc goto huv2b decf ledUv2,F ; decrease the light level goto huv2c huv2b incf ledUv2,F ; increase the light level huv2c decf timetick1,F ; OOOPS! I forgot these here decf timetick2,F ; while stepping the code in the ; debugger. Since the ranges of rates ; now are tuned with these two lines ; I can't remove them because that would ; require a re-tune and that can't be done ; since the microcontroller now is embedded in ; hotglue. So they have to stay here in the ; production code. Normaly these variables ; are decremented by the ISR. goto Loop ; Go back and contuinue the everlasting ; incrementing and decrementing of the ; light levels.... ; ; ==== THE INTERRUPT SERVICE ROUTINE ==== ; ; The ISR are handling the PWM-ing of the three ; ports connected to the LEDs. ; Interrupt: movwf w_tmp ; Save STATUS & W swapf STATUS,W bcf STATUS,RP0 movwf status_tmp movlw 0xE8 ; Reset timer to a high value to get a fast timeout movwf TMR0 bcf INTCON,T0IF ; Clear Timer0 interrupt flag incfsz pwmtick,F ; Increment the pwm counter value goto NoTimeTick decf timetick1,F ; Decrement the time counter 1 if pwm have wrapped decf timetick2,F ; Decrement the time counter 2 if pwm have wrapped bsf flags, ticked ; Set flag to show a tick has occurred NoTimeTick: movf ledUv1,W ; Turn off the UV1-led if the pwm value has reached subwf pwmtick,W ; the UV1-led value btfss STATUS,C goto Uv1Off bsf GPIO,0 goto Uv1Done Uv1Off: bcf GPIO,0 Uv1Done: movf ledUv2,W ; Turn off the UV2-led if the pwm value has reached subwf pwmtick,W ; the UV2-led value btfss STATUS,C goto Uv2Off bsf GPIO,1 goto Uv2Done Uv2Off: bcf GPIO,1 Uv2Done: movf ledRed,W ; Turn off the Red-led if the pwm value has reached subwf pwmtick,W ; the Red-led value btfss STATUS,C goto RedOff bsf GPIO,2 goto RedDone RedOff: bcf GPIO,2 RedDone: swapf status_tmp,W ; Restore W & STATUS and return to main movwf STATUS swapf w_tmp,F swapf w_tmp,W retfie ; ; ==== GET THE VALUE STORED IN EEPROM CELL 0 ==== ; ReadEEValue bsf STATUS,RP0 ;Bank 1 clrf EEADR ;Set EEPROM address 0 bsf EECON1,RD ;EE Read movf EEDATA,W ;Move data to W bcf STATUS,RP0 ;Bank 0 return ; ; ==== WRITE A NEW VALUE TO EEPROM CELL 0 ==== ; WriteEEValue bsf STATUS,RP0 ;Bank 1 movwf EEDATA ;Save W into EEDATA clrf EEADR ;Set EEPROM address 0 bsf EECON1,WREN ;Enable write bcf INTCON,GIE ;Disable INTs movlw 0x55 ;Unlock write movwf EECON2 ; movlw 0xAA ; movwf EECON2 ; bsf EECON1,WR ;Start the write bsf INTCON,GIE ;Enable INTS bcf STATUS,RP0 ;Bank 0 return ; ; ==== GENERATE A PSEUDO RANDOM NUMBER ==== ; Random: ; Generate a random number clrc ; and return it in W rlf rnd, 1 swapf rnd, 0 andlw 0xE0 rrf rnd, 1 addwf rnd, 0 addwf rnd, 0 addwf rnd, 0 sublw 0x35 movwf rnd return ; ; ==== GET RANDOM VALUES FOR THE UV1 LED ==== ; GetRandomUV1: call Random ; Get a new target light level value movwf target1 call Random ; Get a new (adjusted) speed movwf speed1 movlw 0x80 andwf speed1,F movlw 0x30 addwf speed1,F return ; ; ==== GET RANDOM VALUES FOR THE UV2 LED ==== ; GetRandomUV2: call Random ; Get a new target light level value movwf target2 call Random ; Get a new (adjusted) speed movwf speed2 movlw 0x80 andwf speed2,F movlw 0x30 addwf speed2,F return END