PDA

View Full Version : High Resolution Timer & Speed Calculator



WOZZY-2010
- 7th February 2010, 06:36
This PBP project is a high precision timer and Speed Calculator.
Its designed to be used with a 2 sensor optical gate, though it can accurately measure the time of any single pulse.

It is mostly an experiment to carry as much precision as possible.
But also a useful gadget in it's own right.
It uses Darrel' Taylor's Instant Interrupts and N-Bit Math (64-Bits) throughout.

The core program is based on an implementation of CCP1, TIMER-1 Interrupts that was originally developed by Bruce from Rentron.
http://www.picbasic.co.uk/forum/showpost.php?p=23401&postcount=3

Here is the Start of the 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


to be concluded in next post due to length limitations.

The timer has a 200 nS resolution and can go for 99Minutes: 99.9999999Seconds.

Here is the Schematic of the setup
http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3972&stc=1&d=1265519692
The Full Resolution PDF file is here:
http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3971&stc=1&d=1265519692

Here is an photo of the actual Circuit:
http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3973&stc=1&d=1265519978

This timer was developed to use an input pulse from the 2-Beam Pulse Generator Circuit which I presented here:http://www.picbasic.co.uk/forum/showthread.php?t=12614

While this code looks like an abomination, it's actually pretty cool that all the math is done with 64 bit precision.

I'm pretty new at all this, so I'd really like to hear your comments or criticism.

This is a work in progress. I have several features I'm still planning to include.

I'll follow up with a post with some comments and limitations.

Many thanks to Darrel, Bruce and Alexander for their excellent Code examples.

WOZZY-2010
- 7th February 2010, 06:38
Here is the rest of the Code:



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

It wouldn't all fit in a single post

--Bob

WOZZY-2010
- 7th February 2010, 07:09
Features:
1) MAXIMUM TIME: 99 MIN, 99.9999999 SEC ...Really just a display limitation
2) MINIMUM TIME: 0.0000522 SEC also a display limit at 9999.999998 MPH
3) Time Resolution: 200 nS = 0.0000002 SEC
4) Input single PULSE to Pin RC2
5) Displays Measurement and resets awaiting next pulse.
6) Data is sent out to 57600 N-8-1 Serial terminal on Pin RC6
7) Status LED shows when pulse is being timed.

Comments:
This was an experiment in precision of the code.
No oscillator is really this accurate.
Probably pretty close for relative measurements.
But Not for absolute measurements

Currently the speed is based on fixed distance of the optical sensors.
they are fixed and hard coded at 6.000 inches.
The circuit I use to derive the pulse is here:
http://www.picbasic.co.uk/forum/showthread.php?t=12614

Future Plans:
1) Add additional speed units (M/S, KMH)
2) Add user menu to set gate distance and displayed units
3) Add an oscillator correction factor after comparing it to bench-top timer.
4) Write settings to Onboard EEPROM
5) Try a 40 MHz crystal oscillator or other High accuracy clock
6) Build a thermal oven for crystal oscillator ...

Enjoy,
--Bob

WOZZY-2010
- 7th February 2010, 15:36
Please note that there are three include files in the above code which are required for it to operate.

N-BIT_Math.pbp
At its core is the Multibyte Arithmetic Assembly Library that was written by Alexander Avtanski.
The Assembly Library was wrapped for PBP by Darrel Taylor [Version:1.3 Beta (JAN 07,2010)]
This library is used to assemble the 64-Bit high precision math,
You can find reference to it in this PB Forum Thread:
http://www.picbasic.co.uk/forum/showthread.php?t=12433

DT_INTS-18.bas & ReEnterPBP-18.bas
DT_INTS-18.bas is Darrel Taylor's Base Interrupt System for PIC18F [Version:3.3 (MAR 24, 2008)]
ReEnterPBP-18.bas is Darrel Taylor's PBP interrupts for PIC18F [Version:1.4 (MAR 24, 2008)]
Both can be referenced at this PB Forum Thread:
http://www.picbasic.co.uk/forum/showthread.php?t=3251
Or directly from Darrel Taylor's web page here:
http://darreltaylor.com/DT_INTS-18/home.html
Please note that there are different versions for (PIC12F, 14F, & 16F) and for PIC18F.

--Bob

aratti
- 7th February 2010, 17:45
WOZZY-2010, interesting project and well documented. Thank you for sharing it.

Al.