Code:
'******************************************************************
'*********************[ High-Resolution Timer ]********************
'******************************************************************
'** Author : Robert Wozniak, Robert.Wozniak -at- gmail.com **
'** Notice : This code may be freely used and distributed **
'** for use in non-commercial applications **
'** Version : 6.10 : Feb 06, 2010 **
'** Date : JAN 14, 2010 **
'******************************************************************
'** Versions: **
'** 6.0 : All 64 bit MATH, 99 min limit **
'** 5.0 : Working Timer and Speed Calculator with 64 bit math **
'******************************************************************
'** Hardware Tested: PIC18F4680 @20MHz **
'** 4x16 Parallel LCD Module **
'** PBP 2.60 / MPLAB IDE 8.40.000 **
'** Compiled with: [-n -ampasmwin] Build Options **
'** 32 BIT LONG SIGNED INTEGER **
'** **
'** Thanks to Darrel & Bruce at MEL PB Forums for Code examples **
'** Alexander for N-Bit Math...Excellent ASM code **
'******************************************************************
'** MAX OVRFLO=457763, COUNTS=44041 for 99min:59.9999998sec **
'** MIN OVRFLO=0, COUNTS=261 for 9999.999MPH **
'******************************************************************
PRECISION CON 8 SYSTEM ; Set 8 bytes = 64-bit Precision for N-Bit_Math.pbp
INCLUDE "N-BIT_Math.pbp" ; Include Alexander Avtanski's Multibyte Arithmetic
; Assembly Library Wrapped for PBP by Darrel Taylor [Version:1.3 Beta (JAN 07,2010)]
; Version:1.3 Beta (1/7/2010)
INCLUDE "DT_INTS-18.bas" ; Include Darrel Taylor's Base Interrupt System for PIC18F [Version:3.3 (MAR 24, 2008)]
INCLUDE "ReEnterPBP-18.bas" ; Include Darrel Taylor's PBP interrupts for PIC18F [Version:1.4 (MAR 24, 2008)]
DEFINE OSC 20
DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 57600 ' 38400 BAUD N-8-1, PORT C6
DEFINE DEBUG_MODE 1 ' 1 = inverted, 0 = true
DEFINE LCD_DREG PORTA ' Set LCD Data port
DEFINE LCD_DBIT 0 ' Set starting Data bit (0 or 4) if 4-bit bus
DEFINE LCD_RSREG PORTA ' Set LCD Register Select port
DEFINE LCD_RSBIT 4 ' Set LCD Register Select bit
DEFINE LCD_EREG PORTB ' Set LCD Enable port
DEFINE LCD_EBIT 3 ' Set LCD Enable bit
DEFINE LCD_BITS 4 ' Set LCD bus size (4 or 8 bits)
DEFINE LCD_LINES 4 ' Set number of lines on LCD
DEFINE LCD_COMMANDUS 2000 ' Set command delay time in us (2000)
DEFINE LCD_DATAUS 50 ' Set data delay time in us (50)
TRISA=%00000000 ' SET to Output
TRISC.2=1 ' SET to Input
ADCON0=%11000000
ADCON1=%00000111
T1CON.7=1 ' Set Timer1 to 16 bit mode
LED VAR PORTD.1 ' Alias PORTD.0 to LED
I VAR BYTE
J VAR BYTE
OVRFLO VAR LONG ' Timer1 Overflow total
COUNTS VAR WORD ' Timer1 Counts after falling edge capture
PRESET VAR BYTE
OVFLS32 VAR LONG
COUNTS32 VAR LONG
TSEC32 VAR LONG
OVFLS64 VAR BYTE[PRECISION]
OVFLS64M VAR BYTE[PRECISION]
COUNTS64 VAR BYTE[PRECISION]
TSEC64 VAR BYTE[PRECISION]
BITS16 VAR LONG
BITS1664 VAR BYTE[PRECISION]
TMIN64 VAR BYTE[PRECISION]
TSECINT64 VAR BYTE[PRECISION]
TSECDEC64 VAR BYTE[PRECISION]
CONVSEC VAR LONG
CONVSEC64 VAR BYTE[PRECISION]
AA32 VAR LONG
AA64 VAR BYTE[PRECISION]
BB32 VAR LONG
BB64 VAR BYTE[PRECISION]
CC32 VAR LONG
CC64 VAR BYTE[PRECISION]
TMIN VAR LONG
TSEC VAR LONG
TSECINT VAR LONG
TSECDEC VAR LONG
DISTINCH VAR LONG
DISTFT VAR LONG
DISTFT64 VAR BYTE[PRECISION]
DISTFT64M VAR BYTE[PRECISION]
FPS32 VAR LONG
FPS64 VAR BYTE[PRECISION]
FPSINT VAR LONG
FPSINT64 VAR BYTE[PRECISION]
FPSDEC VAR LONG
FPSDEC64 VAR BYTE[PRECISION]
MPH64 VAR BYTE[PRECISION]
MPHINT64 VAR BYTE[PRECISION]
MPHDEC64 VAR BYTE[PRECISION]
MPH32 VAR LONG
MPHINT VAR LONG
MPHDEC VAR LONG
' ****** Setup Variables with Initial Parameters and 64-BIT Constants
I = 0
J = 1
PRESET = 3 ' ********** PER OVERFLOW LOOP TICS CORRECTION **********
BITS16 = 65536 * 2 ' ********** COUNTS MAX * 200 NS PER TIC**********
@ MOVE?LP _BITS16, _BITS1664
DISTINCH = 6000 ' ********** 6.000 inches (MAX = 65.535 in) **********
DISTFT = ((DISTINCH*10000)/12)
@ MOVE?LP _DISTFT, _DISTFT64 ' ********** CONVERT TO FEET **********
AA32 = 1000000 ' ********** BUMP UP RESOLUTION
@ MOVE?LP _AA32, _AA64
@ MATH_MUL _DISTFT64, _AA64, _DISTFT64M ' ********** BUMP UP DISTANCE DIGITS
CONVSEC = 600000000
@ MOVE?LP _CONVSEC, _CONVSEC64 ' ********** BUMP UP TIME DIGITS
Pause 500
LCDOUT $FE,1
LCDOUT $FE,$80,"HIGH-RESOLUTION "
LCDOUT $FE,$C0," TIMER "
LCDOUT $FE,$90," Version 6.10 "
LCDOUT $FE,$D0," Robert Wozniak "
DEBUG 10,13,10,13,10,13
DEBUG "HIGH-RESOLUTION ",10,13
DEBUG " TIMER ",10,13
DEBUG " Version 6.10 ",10,13
DEBUG " Robert Wozniak ",10,13,10,13,10,13
For I = 1 to 5
HIGH LED ' Turn ON LED connected to PORTD.1
Pause 50
LOW LED
PAUSE 50 ' Turn OFF LED connected to PORTD.1
NEXT I
I = 0
;----[High Priority Interrupts (DT_INTS_18)]----------------------------------------
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler CCP1_INT, _Capture, PBP, yes
INT_Handler TMR1_INT, _Timer1, PBP, yes
endm
INT_CREATE ; Creates the High Priority interrupt processor
ENDASM
CCP1CON = %00000101 ' Capture mode, capture on rising edge
T1CON = 0 ' TMR1 prescale=1, clock=Fosc/4, TMR1=off (200nS per count @20MHz)
@ INT_ENABLE CCP1_INT ; enable Capture interrupts
Main:
IF T1CON.0 <> 0 And I = 0 THEN
LCDOUT $FE,1
LCDOUT $FE,$C0," MEASURING"
I = 1
GOTO LCDEND
ENDIF
IF T1CON.0 <> 0 THEN LCDEND
IF T1CON.0 = 0 AND J = 0 THEN
'********** CONVERT COUNTS, OVERFLOWS to SECONDS **********
@ MOVE?LP _OVRFLO, _OVFLS64
@ MATH_MUL _OVFLS64, _BITS1664, _OVFLS64M
COUNTS32 = (COUNTS-10)*2 ' 10 TICS START CORRECTION, 200 nS PER COUNT
@ MOVE?LP _COUNTS32, _COUNTS64
@ MATH_ADD _OVFLS64M, _COUNTS64, _TSEC64
' ********** CONVERT SECONDS TO MINUTES **********
@ MATH_DIV _TSEC64, _CONVSEC64, _TMIN64
@ MOVE?PL _TMIN64, _TMIN
' ********** GET INTEGER SECONDS **********
CC32 = 10000000
@ MOVE?LP _CC32, _CC64
@ MATH_MUL _TMIN64, _CONVSEC64, _AA64
@ MATH_SUB _TSEC64, _AA64, _BB64
@ MATH_DIV _BB64, _CC64, _TSECINT64
@ MOVE?PL _TSECINT64, _TSECINT
' ********** GET DECIMAL SECONDS **********
@ MATH_MUL _TSECINT64, _CC64, _AA64
@ MATH_SUB _BB64, _AA64, _TSECDEC64
@ MOVE?PL _TSECDEC64, _TSECDEC
' ********** CALCULATE SPEED (FPS) **********
@ MATH_DIV _DISTFT64M, _TSEC64, _FPS64
' ********** GET INTEGER FPS **********
CC32 = 1000000
@ MOVE?LP _CC32, _CC64
@ MATH_DIV _FPS64, _CC64, _FPSINT64
@ MOVE?PL _FPSINT64, _FPSINT
' ********** GET DECIMAL FPS **********
@ MATH_MUL _FPSINT64, _CC64, _BB64
@ MATH_SUB _FPS64, _BB64, _FPSDEC64
@ MOVE?PL _FPSDEC64, _FPSDEC
' ********** CONVERT FPS to MPH **********
AA32 = 15
@ MOVE?LP _AA32, _AA64
BB32 = 22
@ MOVE?LP _BB32, _BB64
@ MATH_MUL _AA64, _FPS64, _CC64
@ MATH_DIV _CC64, _BB64, _MPH64
' ********** GET INTEGER MPH **********
AA32 = 1000000
@ MOVE?LP _AA32, _AA64
@ MATH_DIV _MPH64, _AA64, _MPHINT64
@ MOVE?PL _MPHINT64, _MPHINT
' ********** GET DECIMAL MPH **********
@ MATH_MUL _MPHINT64, _AA64, _BB64
@ MATH_SUB _MPH64, _BB64, _MPHDEC64
@ MOVE?PL _MPHDEC64, _MPHDEC
' ********** DISPLAY RESULTS **********
LCDOUT $FE,1
LCDOUT $FE,$80," ",DEC2 TMIN,":",DEC2 TSECINT,".",DEC7 TSECDEC
LCDOUT $FE,$90, DEC4 FPSINT,".",DEC6 FPSDEC," FPS"
LCDOUT $FE,$D0, DEC4 MPHINT,".",DEC6 MPHDEC," MPH"
DEBUG "OVRFLO: ",DEC10 OVRFLO,13,10
DEBUG "COUNTS: ",DEC10 COUNTS,13,10,13,10
DEBUG "TIME: ",DEC2 TMIN,":", DEC2 TSECINT,".",DEC7 TSECDEC,13,10
DEBUG "SPEED: ",DEC4 FPSINT,".",DEC6 FPSDEC," FPS",13,10
DEBUG "SPEED: ",DEC4 MPHINT,".",DEC6 MPHDEC," MPH",13,10,13,10
J = 1
ENDIF
GOTO LCDEND
LCDEND:
PAUSE 25
@ INT_ENABLE CCP1_INT ; Start new capture
GOTO Main
'---[CCP1 - interrupt handler]------------------------------------------
Capture:
IF CCP1CON = %00000101 THEN ' If rising edge capture then
HIGH LED ' Turn on LED to Indicate Measuring
TMR1L = PRESET ' Clear Timer1 counts with Preset (High)
TMR1H = 0 ' Clear Timer1 counts (LOW)
T1CON.0 = 1 ' Turn Timer1 on at rising edge capture
OVRFLO = 0 ' Zero Over flow counts
COUNTS = 0 ' Zero remainder
CCP1CON = %00000100 ' Switch to falling edge capture
PIR1.0 = 0 ' Clear Timer1 overflow flag before enable
I = 0 : J = 0
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts
GOTO OVER_CCP ' Done, exit
ENDIF
IF CCP1CON = %00000100 THEN ' If falling edge capture then
T1CON.0 = 0 ' Stop Timer1
CCP1CON = %00000101 ' Switch back to rising edge capture
@ INT_DISABLE TMR1_INT ; Disable Timer 1 Interrupts
@ INT_DISABLE CCP1_INT ; Disable CCP1 Interrupts
COUNTS.LowByte = TMR1L ' Get remaining Timer1 counts on falling edge (Low Byte)
COUNTS.HighByte = TMR1H ' Get remaining Timer1 counts on falling edge (High Byte)
LOW LED ' Turn off LED
ENDIF
OVER_CCP:
@ INT_RETURN
'---[TMR1 - interrupt handler]---------------------------------------------
Timer1:
OVRFLO = OVRFLO + 1
@ INT_RETURN
END
Bookmarks