My project is on a PIC16F628 4MHz with a Hall sensor TLE4905 on Pin 6 ie RB0/INT.
I would like to measure the cycle time in microseconde for one cycle. As the engine does not give a very regular speed I would like to take an average on several revolutions.
I do not see how to do this with Great Cow Basic.
I would appreciate to get a coding sample or links on this matter.
Thanks a lot,
Jacques eMail: capaction at free.fr
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There are 2 ways I can see to go about this, unfortunately both will involve some slightly complex coding.
The first option is to use some inline assembly code to measure the time between pulses. You can mix assembly code and GCBASIC code in the same program, but the bit of code for measuring time would have to be written in assembly - a downside to using a high level language is that it's hard to get exact timing. The code would have to keep checking the bit to see if it has changed, incrementing a counter if it hasn't.
A better idea would be to use the Capture mode of the CCP module on the PIC. This would require moving the input to the CCP1 pin, which is on PORTB.3. Then, start timer 1 and set the CCP1CON register so that Capture mode is enabled. When something happens on CCP1, the current timer 1 value will be copied into the CCPR1H and CCPR1L registers, and the CCP interrupt will occur. Here is some sample code showing how to do this:
'Set up timer
InitTimer1 Osc, PS1_1/1
ClearTimer 1
StartTimer 1
'Set up CCP
On Interrupt CCP Call PulseReceived
CCP1CON = b'00000101'
Dim CapturedTime As Word Alias CCPR1H, CCPR1L
Then a bit further down in your code, after the main routine:
Sub PulseReceived
'Clear and restart time
ClearTimer 1
StartTimer 1
'Get time since last pulse
Dim TimeDifference As Word
TimeDifference = CapturedTime
'Now do whatever you need to do with the time
'On a 4 MHz chip, with a 1/1 prescaler, Timer 1 will increment every microsecond
'So the value in TimeDifference is the time in microseconds since anything happened
'
' ...
'
End Sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
let's do it in tricky and mathematic way... let's assmume that max 12 000 rpm. it is 200 revolutions per second. 200 Hz only. if you need to display data once per second, than it could be easy. just make timer routine who count pulses in one second and multiply by 60 and send to display. I recomend You to use different oscillator frequency. why? look on this greant tavle of common crystal oscillators frequenncies: http://en.wikipedia.org/wiki/Crystal_oscillator#Commonly_used_crystal_frequencies
now info from datasheet: oscilator frequency is dividet by 4 to get clock frequency. from clock frequency is updatind timer and this is step for cpu instructions. if you are using 4 mhz oscillator than you can get 1 million instructions per second (1 MIPS). also internal timer frequency is 1 MHz. now little tricky part: timer is 8 bit counter. divide 1 MHZ to 256 to get how often timer will be overloaded: 3906.25 timer verload per second. this is bad because have decimal part. if you will use 4,096 MHZ clock than you will get exactly 4000 timer owerflows per second. all data if you are not using prescaler. now! write interrupt subrutine when timer is overloaded.
some pseido code (geeks will write correct gcbasic code from this idea):
#chip 16F628, 4 MHZ 'actualy we have 4.096 MHZ
#config blablabla
#define portb.0 sensor
dim postscaler as word 'because we have 4000 per second
dim sensordata as word 'just in case because we have 200 pulses per socons on max and we don't want to woverload this variable
dim workdata as word 'should be same as sensordata
dim displaydata as word 'this is display buffer
on timer interrupt goto timeoverflow
on portb.o interrupt goto countsensor
setup:
postscaler=0
main:
if postscaler>4000 then
clear postscaler
call prepare data
call show data on display
end if
goto main
END PROGRAM
sub timer overflow
postscaler ++
end sub
sub countsensor
sensordata ++
end sub
sub prepare data
disable sensor interrupt
workdata=sensordata
sensordata=0
enable sensor interrupt
displaydata=workdata * 60
end sub
sub displaydata
send displaydata to LCD or whatever
end sub
this is my idea. this isnt the most precise algorythm, but any way. the error is following:
1 revolution per seond=60 rpm.
if you have 100 rps, tha it is 6000 rpm.
if you miss 1 rps tha you will get 99 rps=5940 rpm
this is algoryth error.
if you want tu apdate data 10 times per second you will get more error.
6000 rpm=10 revolutons per ten times second.
if you miss now one pulse tha you will get 9 revolutons per ten times second.
this is 5400 rpm. big difference if in true there 6000 rpm?
is this idea good for you?
another ide is to sount time betwenn two pulses.
if we assume 12000 rmp that is 200 pulses/second, 5 milisecons between two pulses.
clock owerload is 4000 times per secons, 4 khz, 200 microsecons per overload.
now start timer when get pulse.
on next pulse stop timer, calculate difference between two pulses and sotre somewhere.
etc.
i am thinking now on preido code for this...
will post later.
sorry for my mistakes in text. I am typing on my eeePC.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
it is enough to display data 3-4 times per second. error will be +/- 180 or 240 rpm. I don't have a car or understand lot of real engine rpm, but i think that this error is OK for engine. make your calculations for your real situation! Also high refresh rate isn't readable on LCDs.
Remember: interrupts must be as short as possible or you can miss pulses from sensor!
Anyway this is how i get 19200 bit/s bit banging rs232 using 16f84a with 19,66 mhz clock.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
My project is on a PIC16F628 4MHz with a Hall sensor TLE4905 on Pin 6 ie RB0/INT.
I would like to measure the cycle time in microseconde for one cycle. As the engine does not give a very regular speed I would like to take an average on several revolutions.
I do not see how to do this with Great Cow Basic.
I would appreciate to get a coding sample or links on this matter.
Thanks a lot,
Jacques eMail: capaction at free.fr
There are 2 ways I can see to go about this, unfortunately both will involve some slightly complex coding.
The first option is to use some inline assembly code to measure the time between pulses. You can mix assembly code and GCBASIC code in the same program, but the bit of code for measuring time would have to be written in assembly - a downside to using a high level language is that it's hard to get exact timing. The code would have to keep checking the bit to see if it has changed, incrementing a counter if it hasn't.
A better idea would be to use the Capture mode of the CCP module on the PIC. This would require moving the input to the CCP1 pin, which is on PORTB.3. Then, start timer 1 and set the CCP1CON register so that Capture mode is enabled. When something happens on CCP1, the current timer 1 value will be copied into the CCPR1H and CCPR1L registers, and the CCP interrupt will occur. Here is some sample code showing how to do this:
'Set up timer
InitTimer1 Osc, PS1_1/1
ClearTimer 1
StartTimer 1
'Set up CCP
On Interrupt CCP Call PulseReceived
CCP1CON = b'00000101'
Dim CapturedTime As Word Alias CCPR1H, CCPR1L
Then a bit further down in your code, after the main routine:
Sub PulseReceived
'Clear and restart time
ClearTimer 1
StartTimer 1
'Get time since last pulse
Dim TimeDifference As Word
TimeDifference = CapturedTime
'Now do whatever you need to do with the time
'On a 4 MHz chip, with a 1/1 prescaler, Timer 1 will increment every microsecond
'So the value in TimeDifference is the time in microseconds since anything happened
'
' ...
'
End Sub
let's do it in tricky and mathematic way... let's assmume that max 12 000 rpm. it is 200 revolutions per second. 200 Hz only. if you need to display data once per second, than it could be easy. just make timer routine who count pulses in one second and multiply by 60 and send to display. I recomend You to use different oscillator frequency. why? look on this greant tavle of common crystal oscillators frequenncies: http://en.wikipedia.org/wiki/Crystal_oscillator#Commonly_used_crystal_frequencies
now info from datasheet: oscilator frequency is dividet by 4 to get clock frequency. from clock frequency is updatind timer and this is step for cpu instructions. if you are using 4 mhz oscillator than you can get 1 million instructions per second (1 MIPS). also internal timer frequency is 1 MHz. now little tricky part: timer is 8 bit counter. divide 1 MHZ to 256 to get how often timer will be overloaded: 3906.25 timer verload per second. this is bad because have decimal part. if you will use 4,096 MHZ clock than you will get exactly 4000 timer owerflows per second. all data if you are not using prescaler. now! write interrupt subrutine when timer is overloaded.
some pseido code (geeks will write correct gcbasic code from this idea):
#chip 16F628, 4 MHZ 'actualy we have 4.096 MHZ
#config blablabla
#define portb.0 sensor
dim postscaler as word 'because we have 4000 per second
dim sensordata as word 'just in case because we have 200 pulses per socons on max and we don't want to woverload this variable
dim workdata as word 'should be same as sensordata
dim displaydata as word 'this is display buffer
on timer interrupt goto timeoverflow
on portb.o interrupt goto countsensor
setup:
postscaler=0
main:
if postscaler>4000 then
clear postscaler
call prepare data
call show data on display
end if
goto main
END PROGRAM
sub timer overflow
postscaler ++
end sub
sub countsensor
sensordata ++
end sub
sub prepare data
disable sensor interrupt
workdata=sensordata
sensordata=0
enable sensor interrupt
displaydata=workdata * 60
end sub
sub displaydata
send displaydata to LCD or whatever
end sub
this is my idea. this isnt the most precise algorythm, but any way. the error is following:
1 revolution per seond=60 rpm.
if you have 100 rps, tha it is 6000 rpm.
if you miss 1 rps tha you will get 99 rps=5940 rpm
this is algoryth error.
if you want tu apdate data 10 times per second you will get more error.
6000 rpm=10 revolutons per ten times second.
if you miss now one pulse tha you will get 9 revolutons per ten times second.
this is 5400 rpm. big difference if in true there 6000 rpm?
is this idea good for you?
another ide is to sount time betwenn two pulses.
if we assume 12000 rmp that is 200 pulses/second, 5 milisecons between two pulses.
clock owerload is 4000 times per secons, 4 khz, 200 microsecons per overload.
now start timer when get pulse.
on next pulse stop timer, calculate difference between two pulses and sotre somewhere.
etc.
i am thinking now on preido code for this...
will post later.
sorry for my mistakes in text. I am typing on my eeePC.
it is enough to display data 3-4 times per second. error will be +/- 180 or 240 rpm. I don't have a car or understand lot of real engine rpm, but i think that this error is OK for engine. make your calculations for your real situation! Also high refresh rate isn't readable on LCDs.
Remember: interrupts must be as short as possible or you can miss pulses from sensor!
Anyway this is how i get 19200 bit/s bit banging rs232 using 16f84a with 19,66 mhz clock.