PDA

View Full Version : calculate time between pulses



hell_pk
- 3rd October 2007, 04:20
Hi!
I want to know how to calculate exact time between two pulses.Input is a pulse train with variable frequency.just want to calculate time between rising or falling edge of one pulse and the second one then second one and third one continously.
thnx

BrianT
- 3rd October 2007, 04:43
If the pulse train is slow, an all-Basic approach could be something like

Loop:
Counter = 0
input sensepin
if sensepin = 0 then Loop
TimeHigh:
counter = counter + 1
pauseus 1000
if sensepin = 1 then TimeHigh
TimeLow:
counter = counter + 1
pauseus 1000
if sensepin = 0 then TimeLow
Done:
Serout Tx232, 2, ["Pulsewidth = ", #counter, ", mSecs"]
GOTO Loop

This will need tweaking (by reducing the pauseus period) to get the timing exact. An oscilloscope needed.

If your target pulse rate is too fast for the above you will need to setup Timer1 or Timer3 then invoke the CCP register which will give you the number of ticks of Timer1/3 between events on the defined CCPx pin. This will give you microsecond speeds and very high accuracy which can be defined by analysis rather than measurement in the Basic approach above.

HTH
Brian

hell_pk
- 3rd October 2007, 07:03
Ok here is a code for CCP but for some reason it is not working:
Define LCD_DREG PORTD ' Define LCD connections
Define LCD_DBIT 4
Define LCD_RSREG PORTD
Define LCD_RSBIT 2
Define LCD_EREG PORTD
Define LCD_EBIT 3



Lcdout $fe, $80, " Pulse Reader"

Pause 2000
Lcdout $fe, $1





Period var Word
Capture var PIR1.2
Overflow var PIR1.0 CCP1CON = %00000100
T1CON = %00000001
Loop:
While Capture = 0 : Wend

Period.lowbyte = CCPR1L Period.highbyte = CCPR1H
If Overflow = 0 Then Lcdout $fe, $80, "Input Period: " , #Period , "uS"
Endif
Capture = 0 ' Clear the capture flag
Rst:
While Capture = 0 : Wend
TMR1L = 0 TMR1H = 0
Capture = 0
Overflow = 0
Goto loop

J. Mark Wolf
- 3rd October 2007, 12:39
I've used the PULSEIN command as a tachometer for years.

One trick is to employ a flip-flop in the signal chain that acts as a frequency divider. This has the effect of generating a single high pulse between two succesive edges, allowing the PULSEIN command to work, without having to switch context to time the high portion of the period and then the low portion of the period.

Acetronics2
- 3rd October 2007, 14:15
Hi, Hell_pk

<< I want to know how to calculate exact time between two pulses. >>

The question 1 ) is : How exact must be your "exact time" ??? : +/- 1 ms ? +/- 1µS ... better accuracy ???

The Question 2) is : Which is the period ( approximate ... ) of your signal.

Could you also tell us what is your "signal" ???


Then we will be able to show you ideas ...

Alain

hell_pk
- 4th October 2007, 06:14
signal is ttl from spindle of an old CNC machine.i want to measure rpm.max rpm are 2400 so max frequency is 50 Hz.the code i wrote above is now working correctly to calculate period.now iwant to calculate rpm.
rmp=60/period
should do the trick i think
but how to perform this division?
accuracy is not a problem now.

Acetronics2
- 4th October 2007, 08:50
Hi,

You were near it in your question ...

rmp=60/period * 1 000 000

But ...

care to the units of "period" , and overflow issues ...

if you Xtal is 4 Mhz, then, period will be in µS ... the minimum "correct" display will be ~ 1100 rpm due to an overflow of your timer ... ( Period > 65535 ...)

Then, the simplest way is to use a prescaler value of 8 ( 137 rpm ) or, if possible, 16 ( 68 rpm minimum )

period will be in 8µS ( or 16 µS ) steps

so,your result will then be :

rpm = 60*1 000 000 /period*prescaler_value

due to PBP limitations you'll have to use the DIV32 "function"

So it will be Written :


intermediate = 60 * 1000 / prescaler_value ' Compulsory !!!
' ( no "intermediate CON xxx" allowed )

' Disable interrupts ... if some used !!!

Dummyvar = 1000 * intermediate

rpm = DIV32 period

' re-enable interrupts allowed

Alain



Alain

GioppY
- 4th October 2007, 10:19
if your period counter has 1uS resolution

asm
move?cb 00h,r2 ; load dividend 60e6
move?cb 87h,r2+1
move?cb 93h,r0
move?cb 03h,r0+1
endasm
TmpW = div32 Period
lcdout dec Tmpw

N.B. div32 is limited to 31bit / 15bit unsigned integer
so Period must be < 32767

Regards
Gianni

Acetronics2
- 4th October 2007, 12:16
Hi,

Gioppy is bright right ...

so let's add :



IF period.7 then

Period = period/2
scale = 2

ELSE

scale = 1

ENDIF


intermediate = 60 * 1000 / prescaler_value ' Compulsory !!!
' ( no "intermediate CON xxx" allowed )

' Disable interrupts ... if some used !!!

Dummyvar = 1000 * intermediate

rpm = DIV32 period

rpm = rpm / scale

Alain

hell_pk
- 8th October 2007, 05:08
thanks for ur help.
I am also interested in what Mr. Wolf mentioned:using PULSEIN with flipflop.would u shed some light on it also.
thanks

J. Mark Wolf
- 8th October 2007, 13:18
In short, what the flip-flop does for you, when measuring frequency, such as in a tachometer application, is it negates the need to measure the duration of the high portion of the period, then switch context and measure the duration of the low portion of the period. The time it takes to switch contexts (jump to another section of code) will be lost, and your measurement will be innacurate.

The flip-flop makes one long pulse, spanning the entire period of the tach signal, so that a single PULSEIN command can accurately measure the duration of the period.

For an explanation of the flip-flop idea go to the following Parallax URL:

http://www.parallax.com/dl/appnt/stamps/bs1appnotes.pdf

Scroll down to the "Practical Pulse Measurements" section.

For the complete blow-by-blow as to how I implemented rotor tachometers on my helicopter go to the following URL:

http://www.basicmicro.com/downloads/docs/RRPM.pdf

Charles Linquis
- 8th October 2007, 15:52
I have a PIC reliably reading 10 fan tachometers while it is doing other things. Something to keep in mind is that if your input signal is at all noisy, a simple period measurement may not result in a stable reading, since noise can easily affect a single reading. It is best to take a an average over a period.

My method involves running a timer interrupt with a period shorter than the shortest expected "high" or "low" tachometer time. The interrupt service routine reads the port bits, and XORs them with the last reading of those bits. If the bit has changed, a counter is incremented. There is one counter for each fan to be monitored. The interrupt service routine keeps track of how many times it has run, so after a period of time (say a quarter or a half-second) it stores the individual counts. Simply multiplying the number of counts by a fixed value yields the RPM.

The ISR is written in assembly, but this approach has several advantages:

It doesn't require any external hardware
It averages the counts over a short period, so the readings are stable even in the presence of noise.
It works when the duty cycle is far from 50%.
It runs in the background, so you can process other tasks at the same time.

If you choose this approach, I can send you the code.

nomad
- 9th October 2007, 02:55
your saying it counts all 10 inputs while using just one timer? I'd like to see that code! sounds sweet.

Charles Linquis
- 9th October 2007, 04:33
OK, here you go.


The interrupt period is 500uSec.

All transitions in .5 seconds are added, since FanClock has a count value
of 1000. 500E-9 X 1000 = .5 seconds.






'------------------ Timer 0 interrupt handler-----------------------------------

Asm
ReadTachs

movlw 0xEC ; Reload TMR0
movwf TMR0H
movlw 0x7E
movwf TMR0L

bcf INTCON,2 ; Clear the TIMER0 interrupt flag

infsnz MasterClock
incf MasterClock + 1 ; 16 bit Master system clock

btfss TPE,0 ; Fan counter active gate
bra CheckFans
bra DoneForNow

CheckFans
infsnz FanClock
incf FanClock + 1 ; 16 bit loop counter

movlw 0x03 - 1 ; 1000 = 0x3E8, but must have one less
cpfsgt FanClock + 1 ; to compare with greater than
bra FanRoutine
movlw 0xE8 - 1 ; Again, subtract one
cpfsgt FanClock
bra FanRoutine
bsf TPE,0 ; Set the bit if completed 1000 loops
clrf FanClock
clrf FanClock + 1
bra DoneForNow


FanRoutine

movf PORTB,0,0 ; Read the port bits all at once
movwf Temp,0 ; Copy port into temp register
xorwf OldPortB,0,0 ; XOR bits to see which ones have changed
movwf changedB,0 ; Bits of changed ports will be set to "1"
movff Temp,OldPortB ; Save the register for next pass

movf PORTC,0,0
movwf Temp,0
xorwf OldPortC,0,0
movwf changedC,0
movff Temp,OldPortC

movf PORTD,0,0
movwf Temp,0
xorwf OldPortD,0,0
movwf changedD,0
movff Temp,OldPortD


Fan1
btfss changedB,0
bra Fan2
infsnz Fan1Counter
incf Fan1Counter+1

Fan2
btfss changedB,1
bra Fan3
infsnz Fan2Counter
incf Fan2Counter+1

Fan3
btfss changedB,2
bra Fan4
infsnz Fan3Counter
incf Fan3Counter+1
Fan4
btfss changedB,3
bra Fan5
infsnz Fan4Counter
incf Fan4Counter+1

Fan5
btfss changedB,4
bra Fan6
infsnz Fan5Counter
incf Fan5Counter+1

Fan6
btfss changedB,5
bra Fan7
infsnz Fan6Counter
incf Fan6Counter+1

Fan7
btfss changedC,0
bra Fan8
infsnz Fan7Counter
incf Fan7Counter+1

Fan8
btfss changedC,1
bra Fan9
infsnz Fan8Counter
incf Fan8Counter+1

Fan9
btfss changedC,5
bra Fan10
infsnz Fan9Counter
incf Fan9Counter+1

Fan10
btfss changedC,4
bra DoneForNow
infsnz Fan10Counter
incf Fan10Counter+1

DoneForNow
INT_RETURN ; Return from the interrupt
ENDASM

;---------------------- End of Timer 0 Int handler -----------------------------

nomad
- 10th October 2007, 03:34
Thanks for posting that!

hell_pk
- 10th October 2007, 08:01
thanks!
can nay body covert this to pic basic pro.

nomad
- 20th October 2007, 03:37
as far as i can tell this 1. can read a max of 1khz 2. reads or counts for half a second. and 3. was going to have more inputs on port D?

Charles Linquis
- 20th October 2007, 03:57
Yes, you are correct in assuming this version reads a max of 1KHz - and that is if the input is a square wave, less if the duty cycle is not 50%.

I have used this routine successfully to read fan RPMs over 15,000.

To increase the maximum frequency you can count, you have to increase the interrupt rate. Right now, the period is 500uSec, but could be easily decreased to less than 100uSec by changing the TMR preload (use Mr. E's calculator). I chose to run my routine for 1000 counts ( .5 seconds) so that I could get acceptable resolution, but there is no "magic". You do have to run it for a defined amount of time to come up with the answer you need.

There is no limit to the number of pins you can read with this method. Theoretically, every pin on the pic could be an input.

nomad
- 20th October 2007, 07:04
Thanks again for posting that. i actually learned a bit from it, and have a use for it! I mentioned the portd for expansion as it was read and compared while there doesn't appear to be a fan assigned to it. this is finally starting to make sense.

Charles Linquis
- 20th October 2007, 16:49
You are right about reading PortD and not using the result. I use this routine across several products. Some use PortD input, some do not. Because I support so many products, I sometimes have trouble with "cross pollination". This is one of those cases. I'll comment the port read out and save a few processor cycles. I have plenty of speed, since I always use 18F8722's at 40MHz.