;********************************************************************** ; Valgusfoori programm ; autor: Teemo Berkis ; 22.08.2016 ; ver 1.6 ; põhimõte: Üks korda vajutus lülitab järgmise tule põlema, pikem vajutus lülitab välja. ; -brown out reseti tunnetus, tühja aku jaoks. ; -kollane põlema alguses ;********************************************************************** list p=16F1824 radix dec include "p16f1824.inc" errorlevel -302 ; Dont complain about BANK 1 Registers during assembly ;========================================================================== ; ; Configuration Bits ; ;========================================================================== ;Internal osc. __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_NSLEEP & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF ;************************** Resources utilisation********************* ; Timer0 - delay timer for button press detection and debounce ; Timer1 - seconds timer ; Timer2 - time base for PWM module. ;************************* Register Definition ********************* MAINVAR UDATA_SHR flags res 1 ;some flags redpwm res 1 yelpwm res 1 grnpwm res 1 potearv res 1 delaycounter res 1 ;used in colors seconds counting mainstate res 1 ;main state machine buttonstate res 1 ;used in button press detection TEMP UDATA timertemp1 res 1 ;used in 1s tick counting. temp1 res 1 ;used in delay temp2 res 1 ;used in delay temp3 res 1 ;used in delay tempb res 1 ;used in button detection btemp2 res 1 ;**************************Flags definition********************** #define time1s flags,0 ;************************* Pins Definition ********************* POTOUT EQU RC0 ;potentiometer supply output FEEDBACK EQU RC1 ;current sence feedback RED EQU RC2 ;RED light drive YEL EQU RC3 ;Orange led drive GRN EQU RC4 ;Green led drive PWMOUT EQU RA1 ;step up driving BUTTON EQU RA2 ;button input POTIN EQU RA4 ;potentiometer voltage input pin ;************************* Constants Definition ********************* shortpush_max EQU .25 ;short push maximum duraton*20 =[ms], longer than this is long push double_push_max EQU .25 ;max wait between pulses [ms]/20 ,if longer than this pushes count as separate single pulses. debounce_delay EQU .20 ;debounce delay[ms], time to wait for button to stabilize before reading again. ;****************************************************************** ;Beginning of program ;****************************************************************** RESET_VECT CODE 0x0000 PAGESEL START GOTO START ;---------------------------------------------------------------------- ; INTERRUPT SERVICE ROUTINE ;---------------------------------------------------------------------- ISR CODE 0x0004 return ;*********************************************************************** ; ; MAIN PROGRAM ; ;*********************************************************************** PGM CODE START banksel OSCCON movlw b'01111011' movwf OSCCON ;configure oscillator to internal 16MHz, without PLL for faster startup from sleep nop nop ;----------init PORTA------------------------------- banksel PORTA clrf PORTA ;init portB banksel LATA clrf LATA ;init port data latch banksel ANSELA clrf ANSELA ;all digital I/O banksel TRISA clrf TRISA ;all outputs bsf TRISA,BUTTON ;button to input bsf TRISA,POTIN ;potentiometer to input bsf TRISA,RA5 ;RA5 to input ;----------init PORTC------------------------------- banksel PORTC clrf PORTC ;init portB banksel LATC clrf LATC ;init port data latch banksel ANSELC clrf ANSELC ;all digital I/O banksel TRISC clrf TRISC ;all outputs bsf TRISC,FEEDBACK ;feedback to input banksel ANSELA bsf ANSELA,FEEDBACK ;feedback analog input ;-----------init PWM--------------------------------- call initPWM ;-----------init timer1------------------------------ banksel T1CON movlw b'00000101' ;4MHz clock ->0,25us clock period ->16,384ms full (16bit) timer overflow movwf T1CON call timer1sReset ;-----------init button------------------------------ banksel btemp2 clrf btemp2 banksel buttonstate clrf buttonstate ;-----------init variables--------------------------- clrf flags clrf potearv clrf delaycounter movlw .6 movwf mainstate ;start with yellow clrf buttonstate ;----------test for low power(BOR reset)------------ banksel PCON btfss PCON,NOT_BOR call Brownout nop banksel PCON bsf PCON,NOT_BOR ;---------------------------------------------------- bra main ;goto main loop ;-----------Brown out subroutine----------------------------- ;---------only when battery empty--------------------------- Brownout call _250mS banksel TRISA bsf TRISA,PWMOUT call _250mS call _250mS banksel TRISA bcf TRISA,PWMOUT call _250mS banksel TRISA bsf TRISA,PWMOUT call _250mS call _250mS banksel TRISA bcf TRISA,PWMOUT ;-----------init PWM subroutine------------------------------ initPWM banksel TRISA bsf TRISA,PWMOUT ;disable output during setup banksel PR2 ;timer2 period register, sets the frequency movlw 0x7F movwf PR2 BANKSEL CCP1CON MOVLW b'00001100' ;00xxxxxx' -single output ;xxxx1100' -pwm mode MOVWF CCP1CON BANKSEL CCPR1L MOVLW .75 ;89 TÄHENDAB DUTY CYCLE 70% MOVWF CCPR1L BANKSEL CCPTMRS0 MOVLW b'00000000' ;PWM based on timer2 MOVWF CCPTMRS0 BANKSEL PIR1 BCF PIR1,TMR2IF BANKSEL T2CON CLRF T2CON ;set prescaler to 1 BSF T2CON,TMR2ON ;start timer2 BANKSEL PIR1 BTFSS PIR1,TMR2IF ;wait for the timer2 to overflow BRA $-1 banksel LATC bsf LATC,YEL ;activate yellow leds banksel TRISA bcf TRISA,PWMOUT ;enable output return ;------------------------------------------------------- ;------------------------MAIN program loop***************** main call timer1s ;1s tick generator call getADC ;measure potentiometer call button1 ;button press detection movf mainstate,w brw ;state goto loadred ;0 goto redled ;1 goto loadredyellow ;2 goto red_and_yellow ;3 goto loadgreen ;4 goto green ;5 goto loadyellow ;6 goto yellow ;7 clrf mainstate ;back to the roots. clrf mainstate nop nop bra main ;*********************************************************** getADC ;-----------------ADC -------------------------- btfss time1s ;check for time tick, do ADC only once in a second return ;out banksel ANSELA bsf ANSELA,POTIN ;potentiometer analog input BANKSEL ADCON1 ; MOVLW B'00100000' ;Left justify, Fosc/32 clock ;'xxxxxx11' ;internal voltage reference MOVWF ADCON1 ; BANKSEL ADCON0 MOVLW b'00001101' ;Select channel AN0 MOVWF ADCON0 ;Turn ADC On BANKSEL LATC BSF LATC,POTOUT ;power to the pot call rtrn2 call rtrn2 call rtrn2 call rtrn2 BANKSEL ADCON0 bsf ADCON0,ADGO ;start conversion BTFSC ADCON0,ADGO ;Is conversion done? BRA $-1 ;No, test again banksel ADRESH movf ADRESH,w movwf potearv BANKSEL ADCON0 clrf ADCON0 ;ADC off banksel ANSELA bsf ANSELA,POTIN ;potentiometer in back to digi input BANKSEL LATC BCF LATC,POTOUT ;power down the pot lsrf potearv,f ;divide potearv lsrf potearv,f lsrf potearv,f return timer1s ;-----------------TIMER 1s -------------------------- ;using timer1 ;no delays in code ;sets time1s flag for a tick ; BCF time1s ;never let it go twice in a row. banksel PIR1 btfss PIR1,TMR1IF ;Test for timer1 overflow return bcf PIR1,TMR1IF banksel timertemp1 decfsz timertemp1,f return BSF time1s movlw .61 ;61x16,384ms=1s banksel timertemp1 movwf timertemp1 return timer1sReset banksel T1CON bcf T1CON,TMR1ON banksel TMR1L clrf TMR1L clrf TMR1H banksel T1CON bsf T1CON,TMR1ON movlw .61 ;61x16,384ms=1s banksel timertemp1 movwf timertemp1 RETURN ;---------main sub programs that return to the beginning of the program (with goto) loadred call timer1sReset movfw potearv addlw .4 ;red time movwf delaycounter ;if 0 then load values incf mainstate,f goto main redled banksel LATC bsf LATC,RED ;activate red bcf LATC,YEL ;deactivate yellow bcf LATC,GRN ;deactivate green btfss time1s ;check for time tick goto main ;out banksel delaycounter decfsz delaycounter,f goto main ;out banksel mainstate incf mainstate,f goto main ;out loadredyellow BANKSEL CCPR1L MOVLW .100 ;89 TÄHENDAB DUTY CYCLE 70% MOVWF CCPR1L call timer1sReset lsrf potearv,w ;divide potearv lsrf WREG lsrf WREG addlw .2 ;red+yellow time movwf delaycounter ;load values incf mainstate,f goto main red_and_yellow banksel LATC bsf LATC,RED ;activate red bsf LATC,YEL ;acticate yellow bcf LATC,GRN ;deactivate green btfss time1s ;check for time tick goto main ;out banksel delaycounter decfsz delaycounter,f goto main ;out banksel mainstate incf mainstate,f goto main ;out loadgreen BANKSEL CCPR1L MOVLW .75 ;89 TÄHENDAB DUTY CYCLE 70% MOVWF CCPR1L call timer1sReset movfw potearv addlw .3 ;green time movwf delaycounter ;load values incf mainstate,f goto main green banksel LATC bsf LATC,GRN ;activate green bcf LATC,RED ;deactivate bcf LATC,YEL btfss time1s ;check for time tick goto main ;out banksel delaycounter decfsz delaycounter,f goto main ;out banksel mainstate incf mainstate,f goto main ;out loadyellow call timer1sReset lsrf potearv,w ;divide potearv lsrf WREG,w lsrf WREG,w addlw .3 ;yellow time movwf delaycounter ;load values incf mainstate,f goto main yellow banksel LATC bsf LATC,YEL ;activate bcf LATC,RED ;deactivate bcf LATC,GRN btfss time1s ;check for time tick goto main ;out banksel delaycounter decfsz delaycounter,f goto main ;out banksel mainstate incf mainstate,f ; goto main ;out ;------------------------------button press detection-------------------- ; With state machine algorithm (see documentation) ; no delays in code, no interrupts, uses timer0 polling ; Uses variables: ; buttonstate, btemp2 ; Usage: call button1 ;-------------- button1 banksel buttonstate movf buttonstate,w brw bra bstate0 bra bstate1 bra bstate2 bra bstate3 bra bstate4 bra bstate5 bra bstate6 bra bstate7 bra bstate8 bra bstate9 bra bstate10 bra bstate11 bra bstate12 clrf buttonstate nop return bstate0 incf buttonstate,f return bstate1;----------------------Check for button pressed----- banksel PORTA btfsc PORTA,BUTTON ;check for button press return banksel buttonstate incf buttonstate,f ;-----------------------------push arrived------------------- banksel mainstate incf mainstate,f ;any push do this ;-------------------------------------------------- call set10msTimer ;set up timer0 banksel btemp2 clrf btemp2 ;clear debounce counter return bstate2;-------------------------debounce button------- btfss INTCON,TMR0IF ;timer ready? return call set10msTimer ;yes then go again banksel btemp2 incf btemp2,f movf btemp2,w xorlw .2 ;this many times 2x10ms=20ms btfss STATUS,Z ;compare btemp to x. Kui võrdne siis 0. return ;wait more banksel buttonstate incf buttonstate,f banksel btemp2 clrf btemp2 ;clear temp counter bsf INTCON,TMR0IF ;force end timer return bstate3;-------------------------wait for button release(with timer)------- banksel PORTA btfss PORTA,BUTTON ;if button released go to double push detection bra bstate3timer;no release incf buttonstate,f ;to double push detection call set10msTimer ;reset timer banksel btemp2 clrf btemp2 ;clear temp counter return bstate3timer btfss INTCON,TMR0IF ;timer ready? return ;not yet call set10msTimer ;yes then go again incf btemp2,f movf btemp2,w xorlw .50 ;this many times 50x10ms=500ms btfss STATUS,Z ;compare btemp to x. Kui võrdne siis 0. return banksel btemp2 clrf btemp2 ;clear temp counter bra bstate7 ;long push detected bstate4;--Double push detection, debounce button release btfss INTCON,TMR0IF ;timer ready? return call set10msTimer ;yes then go again banksel btemp2 incf btemp2,f movf btemp2,w xorlw .2 ;this many times 2x10ms=20ms btfss STATUS,Z ;compare btemp to x. Kui võrdne siis 0. return ;no, wait more banksel buttonstate ;yes incf buttonstate,f banksel btemp2 clrf btemp2 ;clear temp counter return bstate5;--double push detection, check for button press. (Wait 500ms for button press) banksel PORTA btfss PORTA,BUTTON ;if button pressed confirm double push bra bstate8 ;to double push confirm btfss INTCON,TMR0IF ;timer ready? return ;no call set10msTimer ;yes then go again banksel btemp2 incf btemp2,f movf btemp2,w xorlw .50 ;50*10ms=500ms btfss STATUS,Z ;compare btemp to 50. Kui võrdne siis 0. return ;wait more clrf btemp2 ;clear temp banksel buttonstate movlw .6 ;timer runout, no second push, confirm short push movwf buttonstate return bstate6;--Short push detected, confirmed ;here things to do for short push call set10msTimer banksel btemp2 clrf btemp2 banksel buttonstate movlw .9 movwf buttonstate return bstate7;--Long push detected, confirmed ;here things to do for the long push ;turn off pwm banksel TRISA bcf TRISA,PWMOUT banksel CCP1CON clrf CCP1CON ;PWM OFF banksel TRISA bsf TRISA,PWMOUT banksel LATA bcf LATA,PWMOUT ;turn off lights banksel LATC bcf LATC,RED bcf LATC,YEL bcf LATC,GRN banksel ANSELA bcf ANSELA,POTIN ;potentiometer dig input BANKSEL LATC BCF LATC,POTOUT ;power down the pot ;Wait for the button release before sleep banksel PORTA btfss PORTA,BUTTON ;if button pressed confirm double push bra $-.1 call delay1ms call delay1ms call delay1ms call delay1ms ;sleep banksel OPTION_REG bcf OPTION_REG,INTEDG BCF INTCON,INTF bsf INTCON,INTE SLEEP nop bcf INTCON,INTE ;turn on PWM call initPWM banksel ANSELA bsf ANSELA,POTIN ;potentiometer analog input BANKSEL LATC BSF LATC,POTOUT ;power up the pot ;----------------------------------- call set10msTimer banksel btemp2 clrf btemp2 banksel buttonstate movlw .9 movwf buttonstate return bstate8;--Double push detected, confirmed ;here things to do for the long push incf mainstate,f ;----------------------------------- call set10msTimer banksel btemp2 clrf btemp2 banksel buttonstate movlw .9 movwf buttonstate return bstate9;--delay 20ms,debounce btfss INTCON,TMR0IF ;timer ready? return call set10msTimer ;yes then go again banksel btemp2 incf btemp2,f movf btemp2,w xorlw .2 ;this many times btfss STATUS,Z ;compare btemp to x. Kui võrdne siis 0. return ;wait more banksel buttonstate incf buttonstate,f return bstate10;--wait for button release banksel PORTA btfss PORTA,BUTTON ;if button released return banksel buttonstate ;yes incf buttonstate,f call set10msTimer banksel btemp2 clrf btemp2 return bstate11;--delay 20 ms, debounce btfss INTCON,TMR0IF ;timer ready? return call set10msTimer ;yes then go again banksel btemp2 incf btemp2,f movf btemp2,w xorlw .2 ;this many times btfss STATUS,Z ;compare btemp to x. Kui võrdne siis 0. return ;wait more banksel buttonstate incf buttonstate,f return bstate12;--back to be ready banksel buttonstate clrf buttonstate return set10msTimer ;sub program for button press banksel OPTION_REG movlw b'11010111' ;timer0 setup ;'xx0xxxxx' ;instruction clock ;'xxxx0xxx' ;prescaler assigned ;'xxxxx111' ;prescaler 1:256 movwf OPTION_REG banksel TMR0 movlw .156 ;value to timer0 comf WREG,W ;flip bits to upcounting timer movwf TMR0 bcf INTCON,TMR0IF ;clear timer0 overflow flag return ;**************************************************************** ;* Delays * ;**************************************************************** delay1ms ;1ms delay(16Mhz clock) debuggeris testitud ;mitte täitsa täpne banksel temp2 movlw .250 movwf temp2 D1 call rtrn2 call rtrn nop decfsz temp2,f goto D1 return _250mS ;250mS second delay, 16MHz kellale, umbes täpne banksel temp3 movlw .0 movwf temp3 movlw .156 movwf temp2 D11 call rtrn2 call rtrn2 call rtrn goto $+1 decfsz temp3,f goto D11 decfsz temp2,f goto D11 return rtrn ;1 microsecond delay return rtrn2 ;2 microsecond delay goto $+1 goto $+1 return END