; ; ; Code for the 12F675 PIC based LMA and glitch detector. ; SCCS: @(#) lma.asm 1.4@(#) processor 12F675 radix dec errorlevel -302 ; ; This module is configurable for a number of different combinations of ; facilities. ; ; It is *your* responsibility to ensure that the configuration parameters set ; in the code below match your components and features required. ; ; The options are: ; ; LMA power up beep ; Set POWERUPBEEP to 0 to disable the initial power up beep ; Set POWERUPBEEP to 1 for an initial beep to indicate power on ; ; LMA turn on point in terms of runtime: ; Set LMARUNTIME to 0 for no automatic runtime based turnon ; Set LMARUNTIME to ?? for automatic LMA after ?? minutes ; ; LMA turn on when loss of signal occurs: ; Set LMAONLOS to 0 for no LMA on loss of signal ; Set LMAONLOS to 1 for LMA turn on when signal is lost ; ; LMA turn on under servo pulse command turn on point, or configurable turn on: ; Set LMAONCMD to 0 for no command turn on ; Set LMAONCMD to 1 for programable command on facility ; Set LMAONCMD to ???? to turn on LMA when received pulse is ; greater than ????us (ie. ?.???msec) ; Set LMAONCMD to -???? to turn the on the LMA when received pulse ; is less than ????us. ; ; Glitch detection system: ; Set GLITCH_COUNT to 0 to disable the glitch counter output, note that ; this doesn't actually stop the glitches being counted - you just ; can't get them out... ; Set GLITCH_COUNT to 1 to enable the counter, with output via beeper, ; this also enables servo pulse monitoring for glitches ; ; Lost Model Alert siren/buzzer type: ; Set LMAFREQUENCY to 1 to drive siren with inbuilt driver, this ; option is for DC sirens ; Set LMAFREQUENCY to ???? to drive siren with given frequency, ; This option is for AC piezo transducers. ; eg. 4500 means 4.5kHz. ; ; LMA alarm sequence parameters. The LMA alarm sequence consists of a number ; of very short beeps followed by a pause. This sequence is repeated until ; the LMA condition is over. NOTE: The maximum LMAALARMREPEAT is 60 seconds. ; Set LMAALARMCOUNT to the number of beeps that are required. ; Set LMAALARMREPEAT to the number of seconds that the alarm cycle ; should repeat in. ; ; Low voltage detection point ; Set LOWVOLTS to 0 if no low volateg detection is required. ; Set LOWVOLTS to the value in mV that is required as the low ; voltage detecion point. For example, to detect low voltage ; at 4.2V set LOWVOLTS to 4200. ; Note: The value of LOWVOLTSREF must be set to the reference ; voltage supplied by the zenner diode D1. The 3V3 (1N746A) ; shown in the circuit diagrams is recommended. ; ; Low voltage alarm sequence parameters. The low volts sequence consists of a ; number of very short beeps followed by a pause. This sequence is repeated until ; the condition is over. NOTE: The maximum LOVALARMREPEAT is 60 seconds. ; Set LOVALARMCOUNT to the number of beeps that are required. ; Set LOVALARMREPEAT to the number of seconds that the alarm cycle ; should repeat in. ; ---- Please read detailed description above ---- ; ---- For the full description of these settings ---- POWERUPBEEP equ 1 ; 0 or 1 LMARUNTIME equ 0 ; time in minutes that the LMA should turn on LMAONLOS equ 1 ; turn on LMA on loss of receiver signal LMAONCMD equ 1 ; 0,1 or turn on at < usec GLITCH_COUNT equ 1 ; 0 or 1 LMAFREQUENCY equ 4500 ; 1 or frequency in Hz LMAALARMCOUNT equ 2 ; number of beeps in alarm sequence LMAALARMREPEAT equ 30 ; Repeat time in seconds (max. 60) LOWVOLTS equ 4200 ; 0 or low voltage point in mV LOWVOLTREF equ 3300 ; Reference voltage in mV (correct for 3V3 Zener) LOVALARMCOUNT equ 1 ; number of beeps in low volts sequence LOVALARMREPEAT equ 5 ; Repeat time in seconds (max. 60) ; ; Assumes: ; Bandgap as calibrated at factory ; CPD disabled ; CP disabled ; BODEN enabled ; MCLR disabled ; PWRTE enabled ; WDT (Watchdog) enabled ; OSC internal RC (no clockout) ; ; The basic circuit for the LMA is as follows: ; ; ; power ----------------------- ; | | ; ----------------- ; | + (1) (8) - | ; | PIC12F675 | ; | | ; rx | (3) GP4 |-<- ; >--XXXX-------| GP1 (6) | | (active low rx pulse) ; 4k7 | (5) GP2 |->- ; | | ; | | ; | (2) GP5 | ----------> Buzzer On (active high) ;Switch >----| GP3 (4) | ; | (7) GP0 | ----------> Buzzer On (active high) ; ----------------- ; ; ; See the full circuit diagram for further details. ; ; Features of this software are as follows: ; ; Watchdog timer ensure the software is running, this is used to ensure ; that the software always gets back to the main sensing code. If ; it doesn't the chip is reset. ; ; Timer 0 is used to measure the time for both the LMA alert and elapsed time. ; ; This timer runs at 1Mhz with a 1:2 prescaler. ; ; Timer 1 is used to measure the input pulse width. Pulse width should be ; 1.5msec nominal at central position +/- 0.5msec depending on the ; control direction. ; ; At 4Mhz clock timer 1 will run at 0.001msec count rate. This gives ; count values for 1.5msec that are well within 16-bit resolution. ; ; ; The LMA command on point can either be auto calibrating, or operate a a ; fixed point. ; ; For piezo elements that do not have a built in siren we need ; to be able to generate frequencies between 800Hz and 5000Hz. ; At 800Hz we need one output change every 625us, at 5000Hz ; we need an output change every 100us. ; ; For normal on/off control of a piezo element with built in siren ; there is no timing control. ; ; LMA constants, this depends on the type of piezo ; siren we have if LMAFREQUENCY <= 1 lmaTrte equ 2000 ; 2000 interrupts per second lmaTcnt equ 256 - ((1000000+lmaTrte/2) / lmaTrte - 11 + 1)/2 else if LMAFREQUENCY < 1000 ; Determine parameters for < 1kHz using 8us per timer clock lmaTrte equ LMAFREQUENCY*2 lmaTcnt equ 256 - ((1000000+lmaTrte/2) / lmaTrte - 11 + 4)/8 else ; Determine parameters for >= 2kHz using 2us per timer clock lmaTrte equ LMAFREQUENCY*2 lmaTcnt equ 256 - ((1000000+lmaTrte/2) / lmaTrte - 11 + 1)/2 endif endif ; The timing rate (per second) lmaIrte equ 4 ; Now calculate the 'unit' time constant in terms of the interrupt rate ; The LMA beeper software measures the length of sounds and silence in ; multiples of this basic unit time. lmaIcnt equ ((lmaTrte + lmaIrte/2)/lmaIrte)+1 ; Unit noise time is 1/4 sec #include __CONFIG(_BODEN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_ON & _INTRC_OSC_NOCLKOUT) ; Main parameters autopulse equ 5 ; Required number 'same value' to program autofuzz equ 3 ; +/- autofuzz is the same value framems equ 25 ; glitch if no signal in 25ms commandcnt equ 10 ; 10 consecutine command pulse to turn LMA on losglitch equ 4 ; LOS if 4 consequtive frames with no signal lmadisable equ 10 ; 10 consecutive good pulses turns LMA off lowvavgln2 equ 3 ; ln2(number of low volts avg) ; GPIO register bits and other constants comparitorinuse = 0 switchinuse = 0 atodinuse = 0 if (LMAONLOS != 0) || (LMAONCMD != 0) || (GLITCH_COUNT == 1) comparitorinuse = 1 inrxraw equ 1 ; Active high receiver input outrxinv equ 2 ; Active low receiver output (--> inrxbit) inrxbit equ 4 ; Active low rx input always on GP4 endif if (LMAONCMD == 1) || (GLITCH_COUNT == 1) switchinuse = 1 switch equ 3 ; Command switch on GP3 endif if LOWVOLTS > 0 atodinuse = 1 if comparitorinuse voltsense equ 0 else voltsense equ 1 endif endif piezoA equ 5 ; Piezo drive controlled by GP5 if atodinuse && comparitorinuse piezoB equ piezoA ; Only one piezo drive is used else piezoB equ 0 ; Piezo drive is also on GP0 endif ; EEPROM Data offsets eep_thresL equ 0 eep_thresH equ 1 eep_thresCHK equ 2 eep_thresGTLT equ 3 GT_flag equ 055h ; data values stored for GTLT indicator LT_flag equ 0AAh ; RAM Definitions cblock 20h w_save ; Int save: !! Both banks used !! sts_save ; lmastatus ; Various status bits lovstatus ; Low voltage status lmaglitch ; Count of the number of glitches lmaONio ; I/O bits to turn on during interrupts lmacmdcnt ; Count down for command mode lmathresL ; LMA command threshold lmathresH frmtL ; Frame rate timer frmtH lmatL ; 16-bit timer containing time delay lmatH lmatival ; Interval counter lmaoffcnt ; Counts left to turn LMA off runtL ; 32-bit timer containing runtime delay runt2 runt3 runtH beep10s ; 10 factor for beeps beep1s ; 1 factor for beeps beeptmp lowvoltavg:1< threshold ; The various Low voltage status lov_islow equ 0 ; Low voltage has been detected ; Also the R/C frame counter. Note we round the counter up to the count above ; because we want a minimum of framems. The '+ 1' is to compensate for the fact ; that the interrupt precision means that there may be no time until the first ; interrupt and thus the first count could occur in zero time. frmIcnt equ ((lmaTrte * framems) + 999) / 1000 + 1 ; ; Reset vector org 0000h goto start ; ; Interupt vector ; ; The LMA interrupt routine, note that when LMAFREQUENCY == 1 the lmaONio is ; always copied to the output port. In other situations there is a flip-flop ; to toggle the output on and off. Note this code does not ensure absolute symetry ; out the output waveform. One or two clock cycle asymetry is not important here. org 0004h ; Save the state (see page 64 of PIC12F675 data) movwf w_save ; Save W register swapf STATUS,W ; Save status (don't touch flags) banksel sts_save ; Back to bank 0 movwf sts_save ; Clear the timer interrupt, and reload counter movlw lmaTcnt movwf TMR0 bcf INTCON, T0IF ; Now perform the processing of the interrupt if LMAFREQUENCY > 1 btfsc lmastatus,lma_pzisOFF goto lma_turnON ; We are currently in phaseA (on), so produce phaseB (off) bsf lmastatus,lma_pzisOFF clrf GPIO goto srvtmr lma_turnON ; We are currently in phaseB bcf lmastatus,lma_pzisOFF endif ; drive the output in the 'ON' phase movfw lmaONio movwf GPIO srvtmr ; Decrement the timers decfsz lmatL,F ; beeper timer goto srvtmr1 decf lmatH,F srvtmr1 decfsz frmtL,F ; frame monitor timer goto srvtmr2 decf frmtH,F srvtmr2 if (LMARUNTIME > 0) || (atodinuse && !comparitorinuse) movlw 1 subwf runtL,F ; Runtime based LMA trigger btfsc STATUS,C ; 32-bit decrement, a 32-bit increment goto exitint ; from a -ve value would be more efficient subwf runt2,F btfsc STATUS,C goto exitint subwf runt3,F btfsc STATUS,C goto exitint subwf runtH,F endif ; All done, restore status exitint swapf sts_save,w movwf STATUS swapf w_save,f swapf w_save,w retfie ; Record the information we need, we want this to appear in ic_prog on an ; 8 word boundary so that it is clearly visible ; The source version information, and the circuit type while ($ & 7) != 0 dt " " endw dt "lma.asm" ; Source information while ($ & 7) != 0 dt " " endw dt "V1.4" ; Source information while ($ & 7) != 0 dt " " endw if !comparitorinuse ; Circuit type information dt "LMAA" if atodinuse dt "+V" endif else if !atodinuse dt "LMAB" else dt "LMAC" endif endif while ($ & 7) != 0 dt " " endw ; Record the software configuration so we can look at it later if LMARUNTIME > 0 dt "T", LMARUNTIME endif if LMAONLOS > 0 dt "L" endif if LMAONCMD == 1 dt "C" endif if LMAONCMD < 0 || LMAONCMD > 1 dt "c", LMAONCMD/100 endif if GLITCH_COUNT > 0 dt "G" endif if LOWVOLTS > 0 dt "V", LOWVOLTS/100 endif while ($ & 7) != 0 dt " " endw ; -------------------------- Main LMA code ---------------------- ; ; Chip reset, or similar, operation. start ; Calibrate the internal oscilator banksel OSCCAL call 3FFh movwf OSCCAL banksel GPIO ; Default to output driven low when enabled clrf GPIO ; Configure the weak pullups, and analog input bits, and the comparator that ; is used as an inverter, so that the control signal can control TMR1 if comparitorinuse banksel VRCON movlw 10101000b movwf VRCON ; Select a 1/3 supply rail reference point banksel CMCON movlw 00000011b ; Comparitor with internal reference movwf CMCON endif banksel ANSEL movlw 00110000b if comparitorinuse iorlw 1< 1 && LMAFREQUENCY < 1000 movlw 00000010b ; Enable pullups, timer0 clk/4 with 1:8 prescale else movlw 00000000b ; Enable pullups, timer0 clk/4 with 1:2 prescale endif movwf OPTION_REG movlw ~(1< 0 clrf runtL ; Protect against interrupt decrement movlw low ((LMARUNTIME*60*lmaTrte) >> 24) movwf runtH movlw low ((LMARUNTIME*60*lmaTrte) >> 16) movwf runt3 movlw low ((LMARUNTIME*60*lmaTrte) >> 8) movwf runt2 movlw low (LMARUNTIME*60*lmaTrte) movwf runtL endif if LMAONCMD == 1 ; Read the EEPROM data for the command threshold and direction bcf lmastatus, lma_thresgt banksel EEADR movlw eep_thresGTLT movwf EEADR bsf EECON1,RD movfw EEDATA banksel lmastatus xorlw LT_flag btfsc STATUS,Z goto read_gtlt xorlw LT_flag ^ GT_flag btfss STATUS,Z goto eepfail bsf lmastatus, lma_thresgt read_gtlt banksel EEADR movlw eep_thresL movwf EEADR bsf EECON1,RD movfw EEDATA banksel lmathresL movwf lmathresL banksel EEADR movlw eep_thresH movwf EEADR bsf EECON1,RD movfw EEDATA banksel lmathresH movwf lmathresH banksel EEADR movlw eep_thresCHK movwf EEADR bsf EECON1,RD movfw EEDATA banksel lmathresL xorwf lmathresL,W xorwf lmathresH,W btfsc STATUS,Z goto poweron ; Failed to recover EEPROM eepfail movlw 2 call lma_sound movlw 2 call lma_silent movlw 6 call lma_sound movlw 6 call lma_silent goto eepfail endif if LMAONCMD > 1 ; Use a constant threshold point, turn on is > LMAONCMD movlw low LMAONCMD movwf lmathresL movlw high LMAONCMD movwf lmathresH bsf lmastatus,lma_thresgt endif if LMAONCMD < -1 ; Use a constant threshold point, turn on is < LMAONCMD movlw low -LMAONCMD movwf lmathresL movlw high -LMAONCMD movwf lmathresH bcf lmastatus,lma_thresgt endif poweron ; Wait until we see a number of good receiver pulses, this ; gives everything time to power up if comparitorinuse repower movlw autopulse movwf beep10s powerlp call getrxapulse ; See what we have movfw lmastatus andlw (1< 99 is too big... btfss STATUS,C goto beeptoobig ; How many 10's clrf beep10s movfw lmaglitch count10s addlw -10 btfss STATUS,C goto got10s incf beep10s,F goto count10s got10s ; The rest are ones addlw 10 movwf beep1s movfw beep10s btfsc STATUS,Z goto no10s call beepdigit movlw 6 call lma_silent no10s movfw beep1s call beepdigit movlw 2 call lma_silent goto lmaoff beepdigit movwf beeptmp iorlw 0 ; check for zero btfsc STATUS,Z goto beepzero beepdlp movlw 2 call lma_sound decfsz beeptmp,F goto beepdlp1 return beepdlp1 movlw 2 call lma_silent goto beepdlp beepzero movlw 6 goto lma_sound beeptoobig movlw 6 call lma_sound movlw 2 call lma_silent movlw 6 call lma_sound movlw 2 call lma_silent goto lmaoff endif mainlowv ; Check for the low voltage condition if LOWVOLTS > 0 btfsc lovstatus,lov_islow goto lovon endif mainrx ; Check for the expiry of runtime if LMARUNTIME > 0 btfsc runtH,7 goto lmaon endif ; Then have a look at the the rx input if comparitorinuse call getrxpulse ; See what we have else clrwdt if atodinuse call lovreader endif endif btfsc lmastatus, lma_rxLMAon goto lmaon if LMAONLOS btfss lmastatus, lma_rxLOS endif goto mainlp ; Enter LMA mode and sound the alarm... lmaon bsf lmastatus, lma_alarmon bsf lmastatus, lma_soundok ; Set the exit counter movlw lmadisable movwf lmaoffcnt ; reset the arm counter ; Go through the process of sounding the alarm ; then pausing, then sound the alarm etc. ; Although this loop appears to only check once every loop it ; actually exits immediately the LMA event is over. The reason ; being that the subroutines return immediately once the LMA event is over ; and hence the SOS stuff completes immediately and the check for end of LMA ; performs the exit operation. ; This saves a lot of repetative test for exit code. lmaloop btfss lmastatus, lma_alarmon goto lmaoff ; LMA event is over movlw LMAALARMCOUNT ; Sound a number of beeps movwf beeptmp lmanoise movlw 1 call lma_sound movlw 1 call lma_silent decfsz beeptmp,F goto lmanoise movlw LMAALARMREPEAT*lmaIrte - 2*LMAALARMCOUNT ; And silence call lma_silent goto lmaloop if LOWVOLTS > 0 ; Enter LOV mode and sound the alarm... lovon bsf lmastatus, lma_soundok ; Go through the process of sounding the low volts alarm ; then pausing, then sound the alarm etc. lovloop btfss lovstatus, lov_islow goto lovoff ; LOV event is over movlw LOVALARMCOUNT ; Sound a number of beeps movwf beeptmp lovnoise movlw 1 call lma_sound movlw 1 call lma_silent decfsz beeptmp,F goto lovnoise movlw LOVALARMREPEAT*lmaIrte - 2*LOVALARMCOUNT ; And silence call lma_silent goto lovloop endif ; Sound the LMA signal, and pause, while monitoring for the end of LMA lma_silent movwf lmatival clrf lmaONio ; disable piezo drive goto lma_ilp ; assumes piezo is already off lma_sound movwf lmatival ; remember how many timer loops we are doing movlw (1 << piezoA) | (1 << piezoB) movwf lmaONio ; enable the piezo drives lma_ilp clrf lmatL ; zap low counter to stop interrupt touching H movlw high lmaIcnt ; Initialise our special interval timer... movwf lmatH movlw low lmaIcnt movwf lmatL lma_lp btfss lmastatus,lma_soundok return ; LMA sounds are over, just stop call lmarxpulse btfss lmatH,7 ; check for time up goto lma_lp decfsz lmatival,F ; Another one 'unit' of time has gone past goto lma_ilp return ; Check for valid receiver pulse and monitor the LMA status. This routine ; ignores the LMA status update if the LMA is not active lmarxpulse if comparitorinuse call getrxpulse else clrwdt if atodinuse call lovreader endif endif btfss lmastatus, lma_alarmon ; give up if the LMA is off return if LMARUNTIME > 0 btfsc runtH,7 ; Stay on forever based on runtime return endif if LMAONLOS btfsc lmastatus, lma_rxLOS goto lmastay ; no signal, stay in LMA endif btfsc lmastatus, lma_rxLMAon goto lmastay ; LMA mode still requested decf lmaoffcnt,F btfss STATUS,Z return bcf lmastatus,lma_alarmon ; LMA mode should exit bcf lmastatus,lma_soundok ; turn off noises now return lmastay movlw lmadisable movwf lmaoffcnt ; reset the arm counter return if LMAONCMD == 1 ; wait for the switch to go on wait_switch btfss GPIO,switch return call getrxapulse goto wait_switch ; Wait for the switch to go off wait_noswitch btfsc GPIO,switch ; Switch still down? return call getrxapulse goto wait_noswitch ; Process receiver pulses until we see a 'stable' value for the required ; configuration procedure. ; This main complete due to loss of signal in which case lma_rxLOS ; will be set. ; ; Local data storage for stable pulse detection cblock stablecnt ; How many times we have seen this reading stablel ; Value we keep on seeing stableh tmpl ; temporary storage tmph endc getstablepulse call getrxpulse btfsc lmastatus, lma_rxLOS return ; Bail out on LOS ; See if this can be made stable movlw autopulse movwf stablecnt movfw TMR1L movwf stablel movfw TMR1H movwf stableh ; Lets have a look... stable_lp call getrxpulse btfsc lmastatus, lma_rxLOS return ; Bail out on LOS movfw stablel addlw -autofuzz movwf tmpl movfw stableh btfss STATUS,C addlw -1 movwf tmph ; tmp:16 is the minimum stable value movfw tmpl subwf TMR1L,W movwf tmpl movfw tmph btfss STATUS,C addlw 1 subwf TMR1H,W movwf tmph btfss STATUS,Z goto getstablepulse ; Too far from the last pulse... movlw 2*autofuzz+1 subwf tmpl,W btfsc STATUS,C goto getstablepulse ; Too big a difference decfsz stablecnt,f goto stable_lp ; Wait for enough that are the same return endif if comparitorinuse ; ; This subrouting returns when a valid RX pulse is seen. ; The return value is in the TMR1 registers.... ; Note caller must check the status prior to proceeding, valid signal ; may have stopped. ; Return value is between 0300h (0.768msec) and 09ffh (2.559msec) and ; represents a 'valid' sort of pulse. ; ; Local data cblock loscnt ; LOS counter endc getrxpulse ; Arm the LOS information bcf lmastatus, lma_rxLOS movlw losglitch movwf loscnt pulselp call getrxapulse ; Increment the glitch counter if we had one btfss lmastatus, lma_rxglitch goto pulsenog incf lmaglitch,F btfsc STATUS,Z decf lmaglitch,F ; Stick at 0xFF, don't wrap to 0 pulsenog btfss lmastatus, lma_rxtimeout goto checkpulse ; No timeout, so OK decfsz loscnt,F goto pulselp ; Keep looking ; We have had LOS bsf lmastatus, lma_rxLOS return checkpulse if (LMAONCMD != 0) movfw lmathresL subwf TMR1L,W movfw lmathresH btfss STATUS,C addlw 1 subwf TMR1H,W btfsc lmastatus,lma_thresgt goto pulsegt ; the LT check and GT check btfss STATUS,C goto turncmdon goto turncmdoff pulsegt btfsc STATUS,C goto turncmdon goto turncmdoff ; command is off turncmdoff movlw commandcnt movwf lmacmdcnt bcf lmastatus, lma_rxLMAon return turncmdon btfsc lmastatus, lma_rxLMAon return decfsz lmacmdcnt,F return bsf lmastatus, lma_rxLMAon endif return getrxapulse ; Arm the glitch information bcf lmastatus, lma_rxglitch bcf lmastatus, lma_rxtimeout clrf frmtL ; protect us from interrupts movlw high frmIcnt movwf frmtH movlw low frmIcnt movwf frmtL apulselp ; Rearm the R/C pulse counter clrf TMR1L ; start at 0 clrf TMR1H ; Enable Timer 1 for pulse width counting movlw 01000001b ; Enable movwf T1CON ; While there is nothing to do just stay here and check for LOS .... whileoff call checktime btfsc lmastatus,lma_rxtimeout return movfw TMR1L iorwf TMR1H,W ; Anything on the counter? btfsc STATUS,Z goto whileoff ; Trigger voltage conversion if required if atodinuse movlw 00000011b | (voltsense << 2) movwf ADCON0 ; Commence operation of the A/D endif ; Now wait for the pulse to end whileon call checktime btfsc lmastatus,lma_rxtimeout return movlw 9 ; If counter >= 2.303 msec signal pulse is faulty subwf TMR1H,W btfsc STATUS,C goto toolong btfss GPIO,inrxbit goto whileon ; Stop timer so we can convert things clrf T1CON ; If we are checking low voltage then sample the A/D if atodinuse btfsc ADCON0,1 goto itislowv ; No A/D completion, funny assume low volts ; Perform averaging if required, else just get the AD value if lowvavgln2 > 0 call checklowv else movfw ADRESH endif ; Now consider the voltage... sublw (LOWVOLTREF * 255 + LOWVOLTS/2) / LOWVOLTS btfss STATUS,C goto itislowv ; Low voltage... bcf lovstatus, lov_islow goto nolowv itislowv bsf lovstatus, lov_islow nolowv endif ; Now the pulse has ended and we are ready to consider the outcome of this... ; First drop pulses that are too small to be valid, these must be an error... movlw 3 subwf TMR1H,W btfss STATUS,C goto hadglitch ; < 0.768msec return ; A pulse > 2.560msec is present, wait for it to end and ignore it toolong call checktime btfsc lmastatus,lma_rxtimeout return btfss GPIO,inrxbit goto toolong hadglitch bsf lmastatus, lma_rxglitch goto apulselp ; Watch for timeout, this routine is called about once every 12 cycles, ; and checks the frame counter timeout decremented in the ISR. ; The watchdog is cleared so that if the PIC doesn't get back to ; processing the next receiver pulse in 18msec the chip resets... ; checktime clrwdt ; track software is working... btfss frmtH,7 return itislos bsf lmastatus,lma_rxglitch ; Flag a glitch bsf lmastatus,lma_rxtimeout return endif ; If the comparitor is not in use then we are not processing ; receiver pulses, in which case we need to sample the A/D ; to determine the supply voltage every 20ms or so if atodinuse && !comparitorinuse lovreader movfw runtL btfss STATUS,Z return movlw 00000011b | (voltsense << 2) movwf ADCON0 ; Commence operation of the A/D mainlov1 btfsc ADCON0,1 goto mainlov1 ; No A/D completion, keep checking ; Perform averaging if required, else just get the AD value if lowvavgln2 > 0 call checklowv else movfw ADRESH endif ; Now consider the voltage... sublw (LOWVOLTREF * 255 + LOWVOLTS/2) / LOWVOLTS btfss STATUS,C goto itislowv ; Low voltage... bcf lovstatus, lov_islow return itislowv bsf lovstatus, lov_islow return endif ; ; If low voltage averaging is active then compute and return the average if atodinuse && lowvavgln2 > 0 cblock lvt_l ; Low Voltage Total LSB lvt_h ; Low Voltage Total MSB endc checklowv ; Shift down the averaging registers i = (1<= 1 movfw lowvoltavg+i-1 movwf lowvoltavg+i i -= 1 endw ; Grab the current A/D value and put it the the most recent slot movfw ADRESH movwf lowvoltavg ; Add up all the values to form a total movwf lvt_l clrf lvt_h i = 1 while i < (1<