![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
filjoa
Joined: 04 May 2008 Posts: 260
|
speed calculator |
Posted: Wed Sep 02, 2009 6:17 am |
|
|
Hi
I try make an speed metter for my bike but for front gear where we put feets... for that I think put two sensors like that:
I start my program with interrupts, but I don't know how I can calculate the speed, because I don't have time for apply V=D/T...
Quote: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,BROWNOUT,STVREN
#use delay(clock=20000000)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#int_rb
void int_rb_isr(void)
{
int8 temp1,temp2;
temp1 = input(PIN_B1);
temp2 = input(PIN_B2);
}
//======================
void main()
{
clear_interrupt(INT_RB);
enable_interrupts(GLOBAL);
while(1)
{
// diameter = 200mm
}
}
|
some one can help me?
kind regards |
|
![](templates/subSilver/images/spacer.gif) |
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Wed Sep 02, 2009 8:20 am |
|
|
You have a 20MHz clock!
Program a timer to interrupt at a regular interval and increment a counter. When your sensors interrupt, read the counter, then reset the counter.
To detect when the bike has stopped, your counter increment code will need to test when the count gets too big (it hasn't been reset by the sensor code).
You will need to do the maths to convert timer ticks and wheel circumferences into speeds. _________________ Andrew |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed Sep 02, 2009 10:13 am |
|
|
As a further comment, if you are measuring on the 'front gear where we put feets' (pedals?), this will not directly correspond to 'speed', unless you know the gear ratio selected. Unless this is a single speed bike, things are going to get complex.
The measurement of pedal rotation, is normally called 'cadence' on a bicycle. For a cadence of 100, depending on the selected gear, I could be going anywhere from 6mph, to 33mph....
So, unless you want to measure 'cadence' (a useful measurement for training etc.), or this is a single speed bike, 'think again', and switch to the normal method, of timing the wheel revolutions...
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
filjoa
Joined: 04 May 2008 Posts: 260
|
|
Posted: Wed Sep 02, 2009 5:34 pm |
|
|
hi
Thanks for your comments.
Idea is meter speed of front gear, not the bike speed.
How I can have time in seconds of the interruptions?
Is possible to write a little example?
kind regards |
|
![](templates/subSilver/images/spacer.gif) |
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Wed Sep 02, 2009 11:21 pm |
|
|
Your example code gave your clock speed as 20MHz. That's your "Fosc" or oscillator frequency. Next, look at your micro data sheet. You'll see that it supports several timers.
I'll pick Timer 0, but look at all of them. It has both an external input, and an internal input. The internal input is marked "Fosc/4". That means the clock will be ticking at 20MHz/4 = 5MHz. You'll also see it has an optional "programmable prescalar". That can divide the clock by up to 256. See the data sheet for the exact values.
The result is that you can configure Timer 0 to tick anywhere from 5MHz down to 19.53125kHz.
The next thing is the timer interrupt. This occurs when the timer overflows (exceeds its maximum) and rolls over to zero. If Timer 0 is in 8-bit mode, the interrupt occurs when it rolls over from 255 to 0. If Timer 0 is in 16-bit mode, it's when it rolls over from 65535 to 0. That means interrupts can be from 5Mhz /1 (no prescale) / 256 (8-bit rollover) = 19.53125kHz down to 5Mhz /256 (maximum prescale) /65536 (16-bit rollover) = 0.298Hz (1 interrupt every ~3.355seconds).
It should now be obvious that if you can select an oscillator with a power-of-2 based frequency, eg 16.384MHz, the maths becomes a lot easier!
You should also take a close look at Timer 2. It's only an 8-bit timer and has fewer prescale options, but it has a comparator - you can set the exact Timer 2 value where the interrupt will occur. eg. 5MHz prescaled by 16 is 312500Hz. Set the comparator to 3125 and you'll have an interrupt every 0.01sec (or 0.1sec if the value is 31250). _________________ Andrew |
|
![](templates/subSilver/images/spacer.gif) |
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Thu Sep 03, 2009 2:53 am |
|
|
Sorry, I must be really tired. Timer 2 is 8-bit, so there's no way to set the comparator higher than 255.
Hmmm. Maybe a 16MHz crystal, a Timer 2 prescale of 16 and a comparator value of 250 to get a 1ms interrupt? Or a 3.2768MHz crystal, a Timer 0 prescale of 32 in 8-bit mode will overflow (and interrupt) in 0.01sec.
There's lots of options, but I think you'll need to change crystals. _________________ Andrew |
|
![](templates/subSilver/images/spacer.gif) |
filjoa
Joined: 04 May 2008 Posts: 260
|
|
Posted: Thu Sep 03, 2009 4:03 am |
|
|
Hi
thanks for this great explanation...
I'll change crystal to 16Mhz and use timer2 but I never use them and I'm very young on interrupts...
in my program code after I change clock to 16Mhz timer2 configuration is setup_timer_2(T2_DIV_BY_16,250,1); correct?
but after I add this on my code I need put an counter, where? in function in_rb_isr?
I don't understand how with interruption I get correct time...
because I see interruption like that:
program stay on infinite cycle "while(1)" but when have an signal an one interrupt ports it go to interruption function make some think... and after that return to infinite cycle...
on there where it count impulses of sensors? and where I go see timer between sensors?
kind regards |
|
![](templates/subSilver/images/spacer.gif) |
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Thu Sep 03, 2009 4:23 am |
|
|
Your setup_timer_2 code looks good.
Your Timer 2 interrupt handler will increment a counter. Your Port B interrupt will save the counter and clear it. Each should probably save values and set flags for your main loop to handle. Your main loop can then do the calculation to turn counts into speed, etc. _________________ Andrew |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Thu Sep 03, 2009 4:45 am |
|
|
OK.
So you are actually trying to measure cadence.
Now, provided you are doing this for your own use, and don't mind the effort involved, great. However you should be aware, that cadence meters, are _cheap_. You can source basic bicycle computers, with this function, for under $20, including the sensors. Even cheaper, you can get a standard bicycle speedometer, for about $10, attach the magnet to the pedals, instead of the wheel, use a second magnet as well, and adjust it's calibration constants to read directly the cadence figure. If you do a Google search for "make a cadence meter for your bike for $12", you will find an article about this.
So assuming you still want to go ahead.
Lets put some 'numbers' into this. The maximum cadence you are likely to encounter, will be something like 160/min (useable, will be slightly lower). With two sensors, there will be a _minimum_ of about 60/(160*2) seconds between the pulses. 0.1875 seconds. You wll need to be able to handle right 'down' to the pedal stopping, so your interval goes from this value upwards. Now, lets assume you want a resolution of 0.1 revs/minute the time for a cadence of 169.9 goes up to 0.18761726. The change, is 0.11726mSec. So the 'resolution' of the count, needs to be 1/8528 second or better. The finer you make the resolution here, the quicker the maths will hit limits.
According to the original post, your chip is running at 20MHz. Timer0, then offers 8, or 16bit resolution, operating off 5MHz, down to 19531.25Hz, with the available rates in powers of 2 between these values. If one went for 78125Hz, the timer would overflow in just under a second, which perhaps represents a reasonable 'timeout', allowing a '0' display, if no rotation is seen in this interval.
So, program timer0, to use the /64 divisor, and 16bit mode.
Then wait for the first sensor to trigger (say sensor 1). When it does, reset the timer0 count, and the RTCC interrupt.
Then sit is a loop checking sensor2, and the RTCC interrupt flag.
If sensor2 triggers, read the timer value. Then the rotational rate, is 1000000/(count*768). If you use int32 maths, and instead generate:
10000000/(count*768), you get the rotational rate _times ten_, so effectively the rate in 1/10th RPM steps. Use say "%5.1w" for the output, and this will display nicely in 1/10th RPM steps.
Now, if the RTCC interrupt goes 'true, without seeing the second edge,simply display '0'.
Now loop back and wait for sensor1.
In 'time' terms, the display wll update every second sensor pulse, or at 0.83 seconds, if no second pulse is seen. The maths will take about 250uSec. If it takes too long, and you miss the sensor edge, it'll simple measure the next pair of pulses. Doesn't matter at all....
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
filjoa
Joined: 04 May 2008 Posts: 260
|
|
Posted: Thu Sep 03, 2009 6:44 am |
|
|
hi
Is very dificult for my first program with interrupts... I'll start for put impulse of imans to RS232 make a litle program in VB, and after make all with pic.
so.. some like that work? or I need put printf on cycle while?
Code: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,BROWNOUT,STVREN
#use delay(clock=20000000)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#int_rb
void int_rb_isr(void)
{
int8 temp1,temp2;
temp1 = input(PIN_B1);
temp2 = input(PIN_B2);
if (temp1==1) printf("S1\n");
if (temp2==1) printf("S2\n");
}
//======================
void main()
{
clear_interrupt(INT_RB);
enable_interrupts(GLOBAL);
while(1)
{
}
}
|
Other question... I like have more 6 buttons type SW but this PIC only have 3 interruption pins, is possible make some virtual interrupts?
kind regards |
|
![](templates/subSilver/images/spacer.gif) |
filjoa
Joined: 04 May 2008 Posts: 260
|
|
Posted: Thu Sep 03, 2009 2:09 pm |
|
|
Hi
what you think for I have many buttons used an logic port conect on INT port and when have an interruption, program read state of all buttons and sensors?
some like this:
at the end I put all on string and send to PC.
Quote: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,BROWNOUT,STVREN
#use delay(clock=20000000)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#int_rb
void int_rb_isr(void)
{
int8 speed1,speed2,btn1,btn2,btn3,btn4,btn5,btn6,btn7;
if ((PIN_B7)==1) speed1=1; else speed1=0;
if ((PIN_B6)==1) speed2=1; else speed2=0;
if ((PIN_B5)==1) btn1=1; else btn1=0;
if ((PIN_B4)==1) btn2=1; else btn2=0;
if ((PIN_B3)==1) btn3=1; else btn3=0;
if ((PIN_C5)==1) btn4=1; else btn4=0;
if ((PIN_C4)==1) btn5=1; else btn5=0;
if ((PIN_C3)==1) btn6=1; else btn6=0;
if ((PIN_C2)==1) btn7=1; else btn7=0;
printf(RESULT);
}
//======================
void main()
{
clear_interrupt(INT_RB);
enable_interrupts(GLOBAL);
while(1)
{
}
}
|
stay correct this code? or it don't work fine? I don't understand where I need put instrutions of interrupts...
some one can tell me?
kind regards |
|
![](templates/subSilver/images/spacer.gif) |
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Thu Sep 03, 2009 9:52 pm |
|
|
First, your pin reading code is all wrong. It should be more like: Code: | btn7 = input(PIN_C2); |
Second, I think you could just read the push buttons in your main loop and save the interrupts for the pedal sensors (BTW, why do you have two, wouldn't one be enough?) In any case, you have external interrupts for both sensors.
Third, the RB interrupt will only occur when B7-B4 change. No other pin changes will trigger the interrupt. That's another reason to not use the interrupt to read your button inputs.
Fourth, doing a printf in an interrupt is a very bad idea. The printf will wait until all the data has been sent. Set a flag in the interrupt handler and do the printf in your main loop. _________________ Andrew |
|
![](templates/subSilver/images/spacer.gif) |
bkamen
Joined: 07 Jan 2004 Posts: 1611 Location: Central Illinois, USA
|
|
Posted: Thu Sep 03, 2009 11:00 pm |
|
|
andrewg wrote: | Maybe a 16MHz crystal, a Timer 2 prescale of 16 and a comparator value of 250 to get a 1ms interrupt? Or a 3.2768MHz crystal, a Timer 0 prescale of 32 in 8-bit mode will overflow (and interrupt) in 0.01sec.
There's lots of options, but I think you'll need to change crystals. |
16.384MHz is a nice number to use that divides down into seconds nicely and commonly available.
8.192MHz would work too...
Cheers,
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|