;********************************************************************** ; flashlight.asm ; Software for LED flashlight ; used as a step up converter to drive 12 white LEDs out of a 4,5V battery pack ; -regulated current (ca. 20mA) ; -overvoltage protction (LEDs failure) ; -undervoltage protection (Battery low) ; ; Usage of Pins: ; GP5: - ; GP4: input for overvoltage protection ; GP3: - ; GP2: output to driver transistor ; GP1: input for current sensing ; GP0: - ; ; Assuming INTOSC f=4MHz ;------------------------------- ;Stephan Asmus, Germany ;(c) info@sasmus.de ; ;------------------------------- ; 16.11.2019 Starting ; 17.11.2019 1st version running ; ;********************************************************************** LIST P=PIC12F675 #include ; processor specific variable definitions errorlevel -302 ;No bank select warnings __CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _BOREN_ON & _CP_OFF & _CPD_OFF & 0x01ff ;added & 0x01ff because of error within MPLAB X IDE Toolchain. / inc file for 12f675 ;***** VARIABLE DEFINITIONS cblock 0x20 ;define a series of variables. W_TEMP ;context saving during interrupt STATUS_TEMP ;dto d1 ;Register to hold Delayloop d2 ;dto. d3 ;dto pulse_h ;current pulse length high endc ; ***********Constants definitions #define output GPIO,2 ;output to power stage transistor #define sense CMCON,6 ;current sensing result (1 if max current received) #define overvoltage GPIO,4 ;over voltage input ; ********************************************************************** ; ********************************************************************** ORG 0x000 ; processor reset vector goto init ; go to beginning of program ORG 0x004 ; interrupt vector location movwf W_TEMP swapf STATUS,w bcf STATUS,RP0 movwf STATUS_TEMP ;the only interrupt is GP change on GP4, so we came here if an overvoltage was identified (GP4=1) movf GPIO,w ;read GPIO to handle mismatch condition call handle_ov ;handle over-voltage condition bcf INTCON,GPIF ;clear interrupt flag swapf STATUS_TEMP,w movwf STATUS swapf W_TEMP,f swapf W_TEMP,w retfie ; ; ------------------------------------------------------------------------------ ; START OF CODE to initialize the processor (Variables, I/O ...) ; ------------------------------------------------------------------------------ init bcf STATUS,RP0 ; Select Bank 0 ;initialise variables & hardware clrf GPIO ; Init I/O-Port by clearing the outp. latches. movlw b'00010100' ;output inverted (since sense input is on VIN-) and internal vref w/o output movwf CMCON ; bsf STATUS, RP0 ;Switch to BANK 1 btfss PCON,1 ;if clear, a power-on Reset occurred goto init1 ;if power on reset, then no need to check brown out btfss PCON,0 ;check if Brown-out reset occurred call delay1s ;if brown out then delay for additional 1sec bsf PCON,0 ;set to 1 (no BOR) init1 bsf PCON,1 ;set power on reset indicator to 1 to identify brown out later movlw b'10100111' ;vref enabled, low range, vref=(7/24)*Vdd = 1,3125V at 4,5 V Vdd movwf VRCON movlw b'00000010' ;configure analog input (GP1/AN1 analog, others digital) clrf ANSEL ; movlw b'00010010' ;configure in/output (GP1, GP4: input. others output) movwf TRISIO ; movlw b'00000000' ;no weak pullup movwf WPU ; movlw b'10001000' ;No Pullups, internal clock for timer 0, prescaler to WDT movwf OPTION_REG ; movlw b'00010000' ;interrupt on change on GP4 movwf IOC ;calibrating the oscillator... call 3FFh ;Get the cal value movwf OSCCAL ;Calibrate it bcf STATUS, RP0 ;Back to BANK 0 clrf INTCON ;no interrupts, clear all flags bsf INTCON,GPIE ;enable GP interrupt on change bsf INTCON,GIE ;enable global interrupts ; init conditions movlw 0x01 movwf pulse_h ;Start with minimal pulse length clrf TMR0 ;clear timer 0 ; ****************************************************************************** ; MAIN, here we go... ; ****************************************************************************** startup bcf output ;output off mainloop ;now we have to set TMR0 to "255-pulse_h" movf pulse_h,w ;high phase sublw 0xff bcf INTCON,T0IF movwf TMR0 ;4 bsf output ;switch transistor on ;now during the on state we have time to do things that have to be done ... ;(overvoltage-protection moved to ISR) btfss sense ;add to pulse lenght if < max current, otherwise decrement it incf pulse_h,f btfsc sense decf pulse_h,f ;max loop = 60, max on: 90% =54. Because TMR0 is inhibited after a write for 2 cycles, we are reducing these values to 56 and 50 movf pulse_h,w xorlw d'51' ;check if pulse_h is > max (50) btfsc STATUS,Z decf pulse_h,f ;yes, than set back to 50 movf pulse_h,w btfsc STATUS,Z ;check if pulse_h is < min (1) bsf pulse_h,0 ;yes, than set to 1 sublw d'50' ;calculate duration of low phase (w still holds pulse_h) ;should be d56, 'cause outer loop holds some more instructions, we reduce the "off" loop with 6 to reduce the error sublw 0xff ;prepare next TRMR0-value... btfss INTCON,T0IF ;now wait until TMR0 overflow goto $-1 ;not relevant bcf INTCON,T0IF movwf TMR0 ;prepare delay loop für low phase bcf output ;begin low phase btfss INTCON,T0IF goto $-1 ;2 goto mainloop ;and start over ;2 ;low phase is longer than necessary: 8 Tosc handle_ov ;we went here if GP4 got high, which means, that the output-voltage exeeds the limits bcf output ;first: shut off power stage movlw 0x01 ;set pulse duration to min movwf pulse_h call delay1s ;and wait for a moment to cool things down.... btfsc overvoltage ;wait until no overvoltage detected goto $-1 return ;and try again ; ------------------------------------------------------------------------------ ; delay: several delay routines used in the program ; ------------------------------------------------------------------------------ delay1s ;999990 cycles movlw 0x07 movwf d1 movlw 0x2F movwf d2 movlw 0x03 movwf d3 delay1s_0 decfsz d1, f goto $+2 decfsz d2, f goto $+2 decfsz d3, f goto delay1s_0 ;6 cycles goto $+1 goto $+1 goto $+1 ;4 cycles (including call) return END ;'end of program''