What would be the best method to capture the RPM for example. intially i wanted to use the Timer function. I read a post by kent_twt4 that said the Timer function can be as must as 20% out? ideally i would like it to be as accurate as possible?
Would it be possible to count instructions in the loop and deduce the time delay from that?
Also i have been reading about the timer function in the GCbasic help file and im unsure about a couple of things?
- what are the prescalers for? (if you could give me an example that would be great)
- what is the purpose of these 2 lines of code in the given example , see bottom of post
Hello... i think you should look for information about the timers and how they work. Have a look to datasheets and microchip webpages.
There are several timers available, depending on the pic you are using...
You can use some timers as counter, this way you dont need the polling routine... just attach the signal to the required pin and timer count will increase every rising or falling edge.
You can use another timer as "base time".
But you need to know how timers work and what are the registers involved ( tmr0,tmr1h,tmr1l.....) and how to use prescaler and postscaler.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've done something similar recently...a digital tach in fact.
To my way of thinking a timer is just a counter. If the frequency is fixed, the count indicates time elapsed.
The inverse is perfect for rpm. Define a time and the counts indicates frequency. Just format the signal for 0-5 volts, and input it to a timer pin. Ask the timer to start, then enter a wait command for the period you want to count for. turn the counter off and read the value like this (example for timer 0):
countvariable = TMR0
This will load the contents of the counter into countvariable.
As far as scaling goes, my chip will count up to 255 max on timer 0 (8 bit), and up to 65k+ on timer 1 (16 bit). Therfore I picked a resonable maximum rpm and equated the sampling time to that max rpm.
For example, timer 0 and 10krpm max for a v8, with 1 spark every two rpm (HEI gm distributor tach output) will yeild a frequency of 10k/60(min to sec)*4(8cylinders, 4 transitions per revolution) = 666hz. If you sample for 1/3 of a second that yeilds 222 counts. This is pretty good for the top end, but what is the resolution like? 1 count yeilds 45 rpm resoution...not bad.
I've found this technique to be very good. Also, throw some digital filtering in there to get rid of some of the variance. Ad 5 counts together and divide by 5. Have it rolling so that it continues to update each .33 seconds.
The prescalars are for faster signals. If you have a 100khz signal you will need to divide the frequency down...this is what the prescalars do. If you look at the basic setup, timer 2 can have a prescalar of 1:1...I suggest you use this. If your frequency is faster then you can use the 16 bit as well for better resolution.
EPwrite is eprom write if I'm not mistaken, no need to use this. TMR1h is the high 8 bits of timer1's count, TMR1l is the low 8 bits. If you use timer 1, then you have to deal with both if you go over 255 counts.
If you use word variables pay particular attention to the online help notes in defining them. I didn't, and couldn't figure out why my words acted like bytes....ha ha they end up being bytes if not defined properly.
Chay
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There is one other technique for RPM...it is to deterine the interval between positive transitions of the signal. This would be a much faster way to do it, because you have 4 (V8) samples per rev. I haven't thought too much about it 'cause my brain is too slow to process much more than .1s anyway!
But, if it's for an automated system (Fuel map, for example) it would be way faster and therefore better.
Chay
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Do a Cntl A/Cntl C and paste it into a text file so it's readable.
I don't know if it works, but I'll test it one day soon. It should be a way beter way to go.
;This is a new stab at an old problem.
; Try to get a good rpm read on the boat.
;The technique will be to try to use the time between pulses to determine the rpm. This shoud yeild more
;stable and way faster results
#chip 16f74, 20; chip is obvious, 20 is 20mhz crystal oscillator
#include <lowlevel\pwm.h> ; Required for pwm operation
#include <lowlevel\timer.h> ;required for timer/counter operation
Dim Count as word ; Storage for the timer period
Dim Math as worD ; Storage for math operations
dIM maTH2 AS WORD ; Storage for math operations (mORE STUFF)
#byte Success ;true if timer has done it's job
#byte PWMCOUNT ; Store the duty cycle for the pwm output
dir porta.1 in ;Setup this pin as an input. This will recieve the tach signal
dir portc.1 out ; Setup the output pwm pins, physical pin 16, pwm output 2
dir portc.2 out ; Setup the other pwm for checking duty cycle on, physical pin 17, pwm out1
dir porta.0 out ; setup this pin as an output. It is a test pin to see if chip is running
InitTimer1 (OSC, PS1_1/4) ; Bring timer 1 online, use internal oscillator
; With a 20 MHZ oscillator, and a minimum rpm of 500, the prescalar has to
; be pretty big to slow things down enough to get it into a word size
;variable.
;How this works is, the instruction cycle takes 4 clock cycles, which at 20
;mhz = 200ns. The slowest rpm I want to display is 500rpm. So, with 4 sparks
;per rev (V8,HEI) this yeilds 33.3 hz, or 30ms between pulses
;If this takes all 65536 counts in the 16 bit register then each count has to
;take at least 457ns. So, set the prescalar to 1:4 (800ns) and 500 rpm yeilds
;37500 counts, 1000rpm = 18750, etc. So the formula will be:
;rpm = 18750000/counts = rpm. Wow. But, in real life, this will be output by
;the pwm. I will pick a range of 500-6000 rpm, where 6000 = 5 volts output (256)
;so, 500 = 21.3 (Out of 255) output to the pwm.So, if we divide the counts by 100, and
;use the output to the pwm, the formula looks like this:
;7987/(timer counts/100)=pwm counts
;Simple eh?
ClearTimer (1) ; Set value to 0, it's ready to go
STARTMAIN:
Sub GETTIME ;Get the first timing interval, results will be contained in TMR1H, and TMR1L
COUNT = TMR1H ;pULL THE VALUE OF TMR1H INTO COUNT
ROTATE COUNT LEFT SIMPLE ; Shift the data in count to the left 1 place (towards the msb)
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ; This moves the lower bytw of data into the high byte's position
ROTATE COUNT LEFT SIMPLE ; This is required for a 16 bit number to be made up from
ROTATE COUNT LEFT SIMPLE ; two 8 bit numbers
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ; It is now shifted 8 places, with the low places being made 0's
count = count + tmr1l ; Add in the low byte of data and the counts are complete
count = count/100 ; Reduce count as per above
math = 7987/count ; Math now contains the pwm output duty cycle
cOUNT5 = COUNT4
COUNT4 = COUNT3
COUNT3 = COUNT2
COUNT2 = COUNT1
COUNT1 = MATH ;rolling values for average
MATH2 = COUNT1
MATH2 = MATH2 + COUNT2
MATH2 = MATH2 + COUNT3
MATH2 = MATH2 + COUNT4
MATH2 = MATH2 + COUNT5
MATH2 = MATH2/5
PWMCOUNT = math2 ; dIGITALLY aVERAGED READING
pwmon; turn on the pwm function (not capture or compare)
hpwm 1,10,PWMCOUNT ; set pwm 1 to 10khz
hpwm 2,10,PWMCOUNT ; set pwm 2 to 10khz
GOTO STARTMAIN
SUB GETTIME: ;
Success = 0 ; Set the 'done' latch to 0 to initialize
WaitHigh: ; Label to return to if signal is not high
If porta.1 = on then ; The signal is true
StartTimer (1) ; Start the timer counting
Stillon:
If porta.1 = off then ; The signal has gone false, wait for it to go true again
If porta.1 = on then ; The signal has gone true again, stop the timer
StopTimer(1) ; Stop the timer
success = 1 ; Timing complete
goto done
end if
endif
goto Stillon ;Signal is still true, wait for it to be false
end if
Done:
If success = 0 then goto WaitHigh ; Timer is not done
end sub
pwm1 = count ;Set up pwm's to varry output
pwm2 = count
pwmon; turn on the pwm function (not capture or compare)
hpwm 1,10,PWM1 ; set pwm 1 to 10khz
hpwm 2,10,PWM2 ; set pwm 2 to 10khz
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
What would be the best method to capture the RPM for example. intially i wanted to use the Timer function. I read a post by kent_twt4 that said the Timer function can be as must as 20% out? ideally i would like it to be as accurate as possible?
Would it be possible to count instructions in the loop and deduce the time delay from that?
Also i have been reading about the timer function in the GCbasic help file and im unsure about a couple of things?
- what are the prescalers for? (if you could give me an example that would be great)
- what is the purpose of these 2 lines of code in the given example , see bottom of post
EPWrite(DataCount, TMR1H)
EPWrite(DataCount + 1, TMR1L)
specifically TMR1H & TMR1L bit ?
Thanks in advance
Dan
Taken from Help file:
'This example will measure that time that a switch stays on for
#chip 16F819, 20
#define Switch PORTA.0
dir Switch In
DataCount = 0
InitTimer Osc, PS1_1/8
Start:
ClearTimer 1
Wait until Switch On
StartTimer 1
Wait until Switch Off
StopTimer 1
EPWrite(DataCount, TMR1H)
EPWrite(DataCount + 1, TMR1L)
Goto Start
Hello... i think you should look for information about the timers and how they work. Have a look to datasheets and microchip webpages.
There are several timers available, depending on the pic you are using...
You can use some timers as counter, this way you dont need the polling routine... just attach the signal to the required pin and timer count will increase every rising or falling edge.
You can use another timer as "base time".
But you need to know how timers work and what are the registers involved ( tmr0,tmr1h,tmr1l.....) and how to use prescaler and postscaler.
rpm - you could use the optical sensor in a ball mouse??
I've done something similar recently...a digital tach in fact.
To my way of thinking a timer is just a counter. If the frequency is fixed, the count indicates time elapsed.
The inverse is perfect for rpm. Define a time and the counts indicates frequency. Just format the signal for 0-5 volts, and input it to a timer pin. Ask the timer to start, then enter a wait command for the period you want to count for. turn the counter off and read the value like this (example for timer 0):
countvariable = TMR0
This will load the contents of the counter into countvariable.
As far as scaling goes, my chip will count up to 255 max on timer 0 (8 bit), and up to 65k+ on timer 1 (16 bit). Therfore I picked a resonable maximum rpm and equated the sampling time to that max rpm.
For example, timer 0 and 10krpm max for a v8, with 1 spark every two rpm (HEI gm distributor tach output) will yeild a frequency of 10k/60(min to sec)*4(8cylinders, 4 transitions per revolution) = 666hz. If you sample for 1/3 of a second that yeilds 222 counts. This is pretty good for the top end, but what is the resolution like? 1 count yeilds 45 rpm resoution...not bad.
I've found this technique to be very good. Also, throw some digital filtering in there to get rid of some of the variance. Ad 5 counts together and divide by 5. Have it rolling so that it continues to update each .33 seconds.
The prescalars are for faster signals. If you have a 100khz signal you will need to divide the frequency down...this is what the prescalars do. If you look at the basic setup, timer 2 can have a prescalar of 1:1...I suggest you use this. If your frequency is faster then you can use the 16 bit as well for better resolution.
EPwrite is eprom write if I'm not mistaken, no need to use this. TMR1h is the high 8 bits of timer1's count, TMR1l is the low 8 bits. If you use timer 1, then you have to deal with both if you go over 255 counts.
If you use word variables pay particular attention to the online help notes in defining them. I didn't, and couldn't figure out why my words acted like bytes....ha ha they end up being bytes if not defined properly.
Chay
thanks very much i will have a play and see how i get on.
Dan
There is one other technique for RPM...it is to deterine the interval between positive transitions of the signal. This would be a much faster way to do it, because you have 4 (V8) samples per rev. I haven't thought too much about it 'cause my brain is too slow to process much more than .1s anyway!
But, if it's for an automated system (Fuel map, for example) it would be way faster and therefore better.
Chay
I wrote this in my spare time :).
Do a Cntl A/Cntl C and paste it into a text file so it's readable.
I don't know if it works, but I'll test it one day soon. It should be a way beter way to go.
;This is a new stab at an old problem.
; Try to get a good rpm read on the boat.
;The technique will be to try to use the time between pulses to determine the rpm. This shoud yeild more
;stable and way faster results
#chip 16f74, 20; chip is obvious, 20 is 20mhz crystal oscillator
#include <lowlevel\pwm.h> ; Required for pwm operation
#include <lowlevel\timer.h> ;required for timer/counter operation
Dim Count as word ; Storage for the timer period
Dim Math as worD ; Storage for math operations
dIM maTH2 AS WORD ; Storage for math operations (mORE STUFF)
#byte Success ;true if timer has done it's job
#byte PWMCOUNT ; Store the duty cycle for the pwm output
#byte count1 ;
#byte count2 ;
#byte count3 ;
#byte count4 ;
#byte count5 ;
dir porta.1 in ;Setup this pin as an input. This will recieve the tach signal
dir portc.1 out ; Setup the output pwm pins, physical pin 16, pwm output 2
dir portc.2 out ; Setup the other pwm for checking duty cycle on, physical pin 17, pwm out1
dir porta.0 out ; setup this pin as an output. It is a test pin to see if chip is running
porta.0 = on ; Turn pin on as a check point
pwm1 = 0 ;Initalize to 0 output
pwm2 = 0 ;
COUNT1 = 0
COUNT2 = 0
COUNT3 = 0
COUNT4 = 0
COUNT5 = 0 ;iNITIALIZE TO 0
InitTimer1 (OSC, PS1_1/4) ; Bring timer 1 online, use internal oscillator
; With a 20 MHZ oscillator, and a minimum rpm of 500, the prescalar has to
; be pretty big to slow things down enough to get it into a word size
;variable.
;How this works is, the instruction cycle takes 4 clock cycles, which at 20
;mhz = 200ns. The slowest rpm I want to display is 500rpm. So, with 4 sparks
;per rev (V8,HEI) this yeilds 33.3 hz, or 30ms between pulses
;If this takes all 65536 counts in the 16 bit register then each count has to
;take at least 457ns. So, set the prescalar to 1:4 (800ns) and 500 rpm yeilds
;37500 counts, 1000rpm = 18750, etc. So the formula will be:
;rpm = 18750000/counts = rpm. Wow. But, in real life, this will be output by
;the pwm. I will pick a range of 500-6000 rpm, where 6000 = 5 volts output (256)
;so, 500 = 21.3 (Out of 255) output to the pwm.So, if we divide the counts by 100, and
;use the output to the pwm, the formula looks like this:
;7987/(timer counts/100)=pwm counts
;Simple eh?
ClearTimer (1) ; Set value to 0, it's ready to go
STARTMAIN:
Sub GETTIME ;Get the first timing interval, results will be contained in TMR1H, and TMR1L
COUNT = TMR1H ;pULL THE VALUE OF TMR1H INTO COUNT
ROTATE COUNT LEFT SIMPLE ; Shift the data in count to the left 1 place (towards the msb)
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ; This moves the lower bytw of data into the high byte's position
ROTATE COUNT LEFT SIMPLE ; This is required for a 16 bit number to be made up from
ROTATE COUNT LEFT SIMPLE ; two 8 bit numbers
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ;
ROTATE COUNT LEFT SIMPLE ; It is now shifted 8 places, with the low places being made 0's
count = count + tmr1l ; Add in the low byte of data and the counts are complete
count = count/100 ; Reduce count as per above
math = 7987/count ; Math now contains the pwm output duty cycle
cOUNT5 = COUNT4
COUNT4 = COUNT3
COUNT3 = COUNT2
COUNT2 = COUNT1
COUNT1 = MATH ;rolling values for average
MATH2 = COUNT1
MATH2 = MATH2 + COUNT2
MATH2 = MATH2 + COUNT3
MATH2 = MATH2 + COUNT4
MATH2 = MATH2 + COUNT5
MATH2 = MATH2/5
PWMCOUNT = math2 ; dIGITALLY aVERAGED READING
pwmon; turn on the pwm function (not capture or compare)
hpwm 1,10,PWMCOUNT ; set pwm 1 to 10khz
hpwm 2,10,PWMCOUNT ; set pwm 2 to 10khz
GOTO STARTMAIN
SUB GETTIME: ;
Success = 0 ; Set the 'done' latch to 0 to initialize
WaitHigh: ; Label to return to if signal is not high
If porta.1 = on then ; The signal is true
StartTimer (1) ; Start the timer counting
Stillon:
If porta.1 = off then ; The signal has gone false, wait for it to go true again
If porta.1 = on then ; The signal has gone true again, stop the timer
StopTimer(1) ; Stop the timer
success = 1 ; Timing complete
goto done
end if
endif
goto Stillon ;Signal is still true, wait for it to be false
end if
Done:
If success = 0 then goto WaitHigh ; Timer is not done
end sub
pwm1 = count ;Set up pwm's to varry output
pwm2 = count
pwmon; turn on the pwm function (not capture or compare)
hpwm 1,10,PWM1 ; set pwm 1 to 10khz
hpwm 2,10,PWM2 ; set pwm 2 to 10khz