Code:
+;********************************************************************* ; Function Description: ;********************************************************************* ;A simple Time Interval Counter with RS-232 output using a GPS 1PPS as ;the reference. By default the counter outputs a 10-digit BCD reading ;once per minute at 1.04ns per count resolution. Per count resolution ;equals (1 / XO speed) / samples per update period. Max specified TMR1 ;async clock speed is 16.7MHz so 16MHz XO is used, but XO's at other ;freqs are usable by adjusting the sample time for the resolution ;desired. Sample time is set using Simple Commands by entering @@Sxx ;where xx = HEX 00-FF (3C default=60 sec). Entering 00 takes 256 ;samples, 01-FF takes 1-255 samples per update. Entering @@P prints ;the current sample time in HEX to the serial port for verification. ;Time readings near zero or max count are not as linear as those at ;mid-scale. Adding an offset by inverting the DUT 1Hz to the TIC ;will improve operation where the inputs are closely aligned. ; ; +5v ; +5v + 1uf | ; |8 +5v GND ----| |---| ; ___|____ |1 |14 |2 | ; | | _|____|_ 1 _|______ 16 | ; | 16 MHZ |5 2| | ---| |---| ; | XO |-------| | + | | | + | ; | | | | --- | | --- ; |________| | | 1uf--- | | ---1uf ; | | | | 3| |15 | ; |4 | | ---| |---|--- GND ; GND | | 4| | + | ; | | ---| | --- ; +5v | 16F688 | + | | MAX232 | ---1uf _____ ; |___ | | --- | |6 | 7| | ; |16 |5 | | 1uf--- | |--- ---| | ; _|___|__ 3| | | 5| | | 8| | ; 14| | ---| | ---| | ---| | ;GPS 1PPS --------| | | | |5 12| |13 3| | ; |Phillips|15 | 11| |-----------| |----------|DB-9F| ; | HC4046 |-------| |6 11| |14 2| | ; 3 | | | |-----------| |----------| | ;DUT 1Hz --------| | |________| |________| 5| | ; |________| GND ----| | ; | |_____| ; |8 ; GND ; ; NOTE: Fairchild HC4046 won't work, use Phillips (best) or TI HC4046. ; ;********************************************************************* ; I/O Pin Assignments: ;********************************************************************* ; Register Bit Pin Function ; PORTA 0 13 N/U ; 1 12 N/U ; 2 11 Interrupt (Ph Det falling edge) ; 3 4 N/U ; 4 3 TMR1 Gate In (Ph Det hi = count) ; 5 2 TMR1 Clock In (16M XO) ; PORTC 0 10 N/U ; 1 9 N/U ; 2 8 N/U ; 3 7 N/U ; 4 6 USART Async TX Out ; 5 5 USART Async RX In ;********************************************************************* ; Serial Command Functions: ;********************************************************************* ; NOTE: Make sure that RTS is connected to CTS at the PIC serial port ; (DB-9 pin 7 tied to pin 8) and a standard serial cable (all pins ; connected) is used or commands may not function correctly. ; Command Function ; @@Sxx Set Averaging Time 00-FF per sample ; @@P Print Averaging Time once to serial TX ;********************************************************************* ; Change History: ;********************************************************************* ; 08/10/2006 Time Interval Counter with RS-232 Output (Rev 1.00) ;********************************************************************* ; Software Listing: ;********************************************************************* TITLE "Time Interval Counter with RS-232 Output - Richard H McCorkle, August 10, 2006" LIST n=58, p=PIC16F688 errorlevel 1 include P16F688.INC __CONFIG _INTOSCIO & _PWRTE_ON & _WDT_OFF & _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF ;********************************************************************* ; Define Storage Locations ;********************************************************************* CBLOCK 0x20 ;Bank 0 Registers - 96 max, 24 used W_TEMP ;temp storage for W on interrupt STAT_TEMP ;ditto for status reg TX_BUF ;the next char to be xmitted RX_BUF ;the last char received BD4,BD3,BD2,BD1,BD0 ;Keep in sequence BD4,BD3,BD2,BD1,BD0 Hac,Mac,Lac,Sac ;32 bit data for BCD convert bCnt,bTst ;Binary-to-BCD regs BytCt,Dadr ;serial data entry regs HofCtr,LofCtr ;overflow counters cHdr0 ;command header flags flg0 ;flag bit storage temp ;temporary storage TicCt ;Averaging time storage tick ;interrupt counter ENDC ;********************************************************************* ; Flag Bit Assignments: ;********************************************************************* #define t1e T1CON,TMR1ON ;Timer 1 Enable #define t1f PIR1,TMR1IF ;Timer 1 Overflow Flag #define Zflag STATUS,Z ;Zero Flag #define Cflag STATUS,C ;Carry Flag #define BrdyF flg0,0 ;Byte Ready Flag #define LoByt flg0,1 ;Low Byte Flag #define Nrdy flg0,2 ;Not Ready Flag ;********************************************************************* ; Command Header Flags: ;********************************************************************* #define Hdr0 cHdr0,0 ;Header 0 Flag (@ ) #define Hdr1 cHdr0,1 ;Header 1 Flag (@@ ) #define Hdr2 cHdr0,2 ;Header 2 Flag (Nrtn) ;********************************************************************* ; Initialization ;********************************************************************* ;Set interrupt vector and start of code org 0 ;initialize code goto start org 4 ;interrupt routine goto int_srv ;Initialize bank 0 ports and control registers start clrf PORTA ;clear port output latches clrf PORTC clrf INTCON ;disable all interrupts for now clrf T1CON ;Stop Timer1 movlw 0x07 ;set PORTA pins as digital (not comparator inputs) movwf CMCON0 bsf CMCON1,T1GSS ;set to use external gate on TMR1 ;Initialize bank 1 control regs bsf STATUS,RP0 ;select bank 1 movlw 0x71 ;select 8MHz internal clock for PIC movwf OSCCON ;(Using XO for PIC disables TMR1 ext clk!) ; movlw 0x00 ;put a cal value in OSCTUNE to ; movwf OSCTUNE ;calibrate oscillator if desired clrf OPTION_REG ;no TMR0, int on falling edge clrf ANSEL ;PORTA pins as digital movlw 0x3f ;set PORTA pins as inputs movwf TRISA movlw 0x3f ;set PORTC pins as inputs, 2 serial port pins movwf TRISC clrf PIE1 ;no int. on async xmt (tst TRMT instead) ;Back to bank 0 bcf STATUS,RP0 ;select bank 0 bsf TXSTA,TXEN ;enable USART xmt (async mode) bsf TXSTA,BRGH ;set USART hi speed mode movlw D'51' ;set async rate at 9600 baud (51. for 8 MHz int, BRGH=1) movwf SPBRG bsf RCSTA,CREN ;enable USART rcv (async mode) bsf RCSTA,SPEN ;enable serial port bsf INTCON,INTE ;enable interrupt on RA2 clrf PIR1 ;clear peripheral interrupt flags movlw 0xc6 ;set TMR1 as f_osc/1, async, inv gate, ext clk movwf T1CON clrf TMR1H ;clear the counter clrf TMR1L clrf flg0 ;clear all flags clrf cHdr0 ;clear cmd headers clrf HofCtr ;clear overflow counters clrf LofCtr movlw 0x3c ;initialize at 60 samples/update movwf TicCt movwf tick bsf t1e ;enable TMR1 bsf INTCON,GIE ;enable interrupts ;********************************************************************* ; Background Routine ;********************************************************************* ; Check for command and process, check for TMR1 overflow and ; increment the overflow counters as needed. Allows 4.1ms for ; command process with no adverse effect on the count. Bkgnd call Rx232 ;check for character received btfss BrdyF ;if no byte ready goto $ + 3 ;jump past process command bcf BrdyF ;clear byte ready flag call CmdProc ;Process command btfss t1f ;wait for TMR1 overflow goto Bkgnd bcf t1f ;clear TMR1 o/f flag incf LofCtr ;inc Low overflow counter btfsc Zflag ;carry? incf HofCtr ;inc Hi overflow counter goto Bkgnd ;loop ;********************************************************************* ; Interrupt Service Routine ;********************************************************************* ; Disable and read TMR1 counter to get phase data. Reset and enable ; immediately so TMR1 is free to count while BCD convert and print ; are executed to minimize deadband error at max counts. Read and ; reset overflow counters used to extend TMR1 to 32-bits. Data is ; placed in AC, converted to 10-digit BCD, and printed. Reload ; the loop counter and return from interrupt. int_srv movwf W_TEMP ;"push" instructions swapf STATUS,W ;swapf affects no status bits movwf STAT_TEMP ;save STATUS bcf INTCON,INTF ;clear interrupt decfsz tick ;Display @ Loop count goto pop ;otherwise just exit bcf t1e ;disable TMR1 before read movf TMR1H,W ;read TMR1 hi byte movwf Lac ;and store movf TMR1L,W ;read TMR1 lo byte movwf Sac ;and store clrf TMR1H ;clear TMR1 clrf TMR1L bsf t1e ;enable TMR1 to count while printing btfss t1f ;check for TMR1 overflow goto $ + 5 bcf t1f ;if set, clear TMR1 o/f flag incf LofCtr ;inc Low overflow counter btfsc Zflag ;carry? incf HofCtr ;inc Hi overflow counter movf LofCtr,W ;get Low overflow Counter movwf Mac ;store clrf LofCtr ;and clear movf HofCtr,W ;get Hi overflow Counter movwf Hac ;store clrf HofCtr ;and clear call prt32 ;convert and print as 10-digit BCD movf TicCt,W ;reload tick counter movwf tick pop swapf STAT_TEMP,W ;restore STATUS movwf STATUS swapf W_TEMP ;set status bits swapf W_TEMP,W ;restore W retfie ;return from interrupt ;********************************************************************* ; Subroutines ;********************************************************************* ; Print 10-digit BCD ASCII to TX DATA prt32 call BCD32 ;convert to BCD movf BD0,W ;send BD0 (10-digit BCD) call TXBD movf BD1,W ;send BD1 call TXBD movf BD2,W ;send BD2 call TXBD movf BD3,W ;send BD3 call TXBD movf BD4,W ;send BD4 call TXBD TxLfCr movlw "\r" ;send CR direct to Tx call Tx movlw "\n" ;send LF direct to Tx goto Tx ;Tx returns to caller ;********************************************************************* ; 32 bit binary to BCD conversion (adapted from AN544) ; Input in Hac, Mac, Lac, Sac and output in BD0, BD1, BD2, BD3, BD4 BCD32 bcf Cflag ;convert 32 bit data to 10-digit BCD movlw D'32' movwf bCnt ;set bCnt = 32 bits clrf BD0 clrf BD1 clrf BD2 clrf BD3 clrf BD4 RL32 rlf Sac ;rotate 1 bit rlf Lac rlf Mac rlf Hac rlf BD4 rlf BD3 rlf BD2 rlf BD1 rlf BD0 decfsz bCnt ;32 bits done? goto $ + 2 ;no, process more BCD return movlw BD4 ;load addr of BD4 as indir addr movwf FSR movlw 0x05 ;process 5 registers movwf temp Adj movf INDF,W ;get reg via indirect addr addlw 0x03 movwf bTst ;sum to bTst for test btfsc bTst,3 ;test if >0x07 movwf INDF ;yes - store sum movf INDF,W ;get original or sum addlw 0x30 ;test hi byte movwf bTst ;sum to bTst for test btfsc bTst,7 ;test result >0x70 movwf INDF ;save as BCD incf FSR ;next reg decfsz temp ;Done? goto Adj ;no, do next adj goto RL32 ;********************************************************************* ; Send ASCII to TX DATA TXBD movwf TX_BUF swapf TX_BUF ;hi nibble call TxChar swapf TX_BUF ;low nibble TxChar movf TX_BUF,W ;get the buffer andlw 0x0f ;mask high nibble addlw "0" ;make into ASCII Tx btfss TXSTA,TRMT ;test for Tx buffer empty goto $ - 1 ;wait till buffer empty movwf TXREG ;send it return ;********************************************************************* ; Simple Commands by Richard H McCorkle ;********************************************************************* ; Get data via USART rcv mode Rx232 btfss PIR1,RCIF ;have we received a char? return ;no - nothing to do movf RCSTA,W ;check for rcv status for error andlw 0x06 ;select only error bits btfss Zflag ;if any set, jump to goto RxErr ;error service routine movf RCREG,W ;get char from input buffer movwf RX_BUF ;store in RX_BUF bsf BrdyF ;set byte available flag return RxErr bcf RCSTA,CREN ;clear CREN to clear overrun error movf RCREG,W ;read RCREG to clear framing error bsf RCSTA,CREN ;set CREN to rcv bcf BrdyF ;clear byte ready flag clrf cHdr0 ;clear header flags return ;********************************************************************* ; Check command received via USART rcv mode CmdProc btfss Hdr2 ;header 2 flag set (Number Return)? goto H1 ;no, test for next header call GetByt ;get data bytes btfsc Nrdy ;check not ready return ;if set, get next data goto Chf ;clear header flags and exit H1 btfss Hdr1 ;header 1 flag set (@@ received)? goto H0 ;no, test for header start ; @@P Print Averaging Time to serial TX port movlw "P" ;is char a "P" ? movwf temp movf RX_BUF,W subwf temp,W btfss Zflag goto $ + 3 ;no, next header call prtS ;print Averaging Time goto Chf ;clear header flags and exit ; @@Sxx Set Averaging Time 00-FF per sample movlw "S" ;is char an "S" ? movwf temp movf RX_BUF,W subwf temp,W btfss Zflag goto Chf ;no valid @@ command, exit movlw TicCt ;move indirect address to W movwf Dadr ;store in Dadr movlw 0x01 ;get 1 register (2 bytes) movwf BytCt bsf Nrdy ;set not ready flag bsf Hdr2 ;set Header 2 flag return H0 movlw "@" ;is char a "@" ? movwf temp movf RX_BUF,W subwf temp,W btfsc Zflag goto $ + 4 btfsc Hdr0 ;If @ rcvd but second char not @ bcf Hdr0 ;clear header 0 flag and return ;exit btfsc Hdr0 ;was header 0 flag set? goto $ + 3 bsf Hdr0 ;no, set header 0 flag (@ rcvd) return ;exit bsf Hdr1 ;yes, set header 1 flag (@@ rcvd) return ;exit Chf clrf cHdr0 ;clear header flags return ;********************************************************************* ; Hex Convert - convert ASCII 0-9 or A-F to number 0-15 in W ; converts small a-f to caps by clearing 32 bit first ; so either caps or smalls for a-f work. HexC movf RX_BUF,W ;get the byte movwf temp btfss temp,6 ;number or char? goto $ + 4 bcf temp,5 ;clear 32 bit (convert small to caps) movlw D'7' ;subtract 55 to convert A-F to values 10-15 subwf temp movlw D'48' ;subtract 48 to value subwf temp movf temp,W andlw 0x0f ;discard high bits (if wrong char) return ;********************************************************************* ; Get Bytes - fetch number of registers in BytCt and store ; at address starting at Dadr, clear Nrdy when finished GetByt movf Dadr,W ;get storage address movwf FSR call HexC ;convert input to value btfsc LoByt ;if LoByte set, goto $ + 5 movwf INDF ;load in storage swapf INDF ;move to hi nibble bsf LoByt ;set low byte flag return addwf INDF ;add to value in storage bcf LoByt ;clear low byte flag decfsz BytCt ;got all the registers? goto $ + 3 bcf Nrdy ;clear not ready flag return incf FSR ;point to next data movf FSR,W movwf Dadr ;and store in Dadr return ;********************************************************************* ; Provides display of average time in Hex format used for data entry. prtS swapf TicCt,W ;print average time movwf TX_BUF call TxHex ;print hi nibble in hex movf TicCt,W movwf TX_BUF call TxHex ;print low nibble in hex goto TxLfCr ;TxLfCr returns to caller ;********************************************************************* ; Convert lo nibble in TX_BUF to HEX ASCII and send TxHex movf TX_BUF,W ;get transmit data andlw 0x0f ;mask hi bits sublw 0x09 ;9 - W if >9, Cflag = 0 movf TX_BUF,W ;get data andlw 0x0f ;mask hi bits btfss Cflag ;is input >9 addlw 0x07 ;if >9 add 7 for A-F addlw "0" goto Tx ;********************************************************************* de "TIC-232 Rev 1.00, Richard H McCorkle 2006" de " " END
file: /Techref/member/RHM-SSS-SC4/TIC232.htm, 19KB, , updated: 2006/8/11 11:55, local time: 2024/11/27 11:08,
owner: RHM-SSS-SC4,
3.14.132.43:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/member/RHM-SSS-SC4/TIC232.htm"> Simple Time Interval Counter with RS-232 Output – The Simple Time Interval Counter uses the 14-pin 16F688 PIC, a GPS receiver 1PPS as a reference, has variable averaging time set by serial port command, and provides a 10-digit BCD output to an RS-232 port. It is a low-cost four-IC solution for determining the time difference between a locally generated 1PPS and a GPS 1PPS and logging the difference to a computer for analysis. Demonstrates the addition of Simple Commands in page 0 memory to alter or print a single variable in a user program. <BR></A> |
Did you find what you needed? |