Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Speedometer - questions

Status
Not open for further replies.

Airmaster86

New Member
Hi,

Ive recently started with PIC microcontrollers, and now Im building/programming a digital speedometer using the PIC16F84A. Im new to the whole thing programming pics, so I got some questions. :)

I use C to program PICs as im familiar with C++.

I want to count the time for one revolution of the wheel then calculate the speed. As I want the PIC to jump directly to the "timing-function" when the signal goes high (from the wheel-sensor), I thought that I could use the Interrupt pin on the PIC. When the signal goes high again (one revolution later..) it will stop counting. The problem is that I do not know how to solve this, and if there is functions for rising edge and interrupts.

If there is someone that would like to help me I would be very happy and thankful. :)

Thanks,
Anders

Sweden
 
You can turn a high going signal into a low going signal with an inverter. Echoing Nigel's usual comment, "don't use the 16F84, use the 16F628A"

When using interrupts make sure that you can clear the interrupt condition when you are done with the interrupt service routine. If you don't or can't do this then when you execute the RETFIE instruction you will go right back to your interrupt routine.

A method that should work for you is to bring your signal to the CLOCK input of a D-Flip-Flop (74HCT74 for example). Connect the D input to logic high. Take the Q-bar output to the interrupt input of the PIC. Take a port line from the PIC and run it to the Asyncronous Clear Input of the Flip-Flop, and remember to tie the PRESET Input High.

So the logic is:
Rising Edge on Clock Input sets Q = 1, and Q* = 0
PIC Sees interrupt line go low and vectors to location 4
Interrupt service clears the Flip-Flop by taking the port pin low then high
which forces Q = 0 and Q* = 1, removing the interrupt condition until the next rising edge of the Clock Input.
 
Maybe I don't understand the problem - using the Int pin (RB0), you can select rising or falling edge interrupts (yes, even on the 84...). On each interrupt, read the timer value, save it for calculating the rotational frequency and then reset the timer. discard the first timer reading since it's wrong. I would do the actual rpm calculations in the main loop of your code. To do really slow RPMs, you will have to take the timer overflow (er, underflow) interrupt and keep track of total time.
 
Thanks for the replies,

This is how i want it to work,

**broken link removed**

Count the time between the pulses in a while-loop. It starts when the pulse goes high, and stops one revolution later when the pulse goes high again. Then the value from the while-loop is calculated to get the speed. Next rising edge (one revolution later) it starts counting again and so on. Every second revolution it gets a new the time...

The problem is that i do not really know how to write interrupts as i havent got any example code to look at. :)

Maybe its sufficient to only have a reading from a input pin and wait for a rising edge?

To start timing:

main()

if (rising edge)
{
go to timerfunction
}

and to stop timing:

timerfunction()

while(time < condition)
{

if (rising edge)
{
break the while loop
}
time++
}

I may be totally wrong, any other ideas?

Thanks,
Anders.
 
Thanks, I will try the D-flipflop. Got the speedo to work okay, but there is some small problems that the flipflop will solve.

I wonder about trimming the speedo (change the delay in the timing-whileloop), is there any neat idea you guys have?

Thanks
 
I'm not into PIC's, but there shouldn't be a timing while loop. This should all be able to be done with just a timer and an interrupt service routine.

Can't you make an ISR that interrupts on high edge? Just check the timer value and whether it's overflowed. Reset the timer and let it go on it's way. Calculate your current speed from the previously read timer value.
 
Airmaster86 and all

The only purpose of the D-FF is to guard against the pulse lasting longer than the interrupt service routine. There was no timing information on the diagram so it is hard to imply a time scale.

Writing an interrupt service routine is trivial. At location 4 put a "goto" to the service routine. Check the appropriate timer flag. If it is set, perform the service, if it's clear check any other enabled sources. Remember to exit from the interrupt service routine with a RETFIE instruction. Try it in the MPLAB simulator -- it's free.
 
I don't see why a ff is needed at all. the INT interrupt triggers on an edge. my previous post will work and is incredibly simple. also, if you keep track of timer roll overs (via timer interrupt), you can measure effectively unlimited time periods.

programmed loop timing can work but you have to recalculate every thing if you change the loop code.
 
If the interrupt triggers on an edge, and the edge is clean and doesn't bounce then all is well. I thought the INT* was level triggered, my mistake.
 
level triggered ints are VeryBadThing (tm). The old intel 8259 interrupt controller had them and I spent many many hours trying to make level triggered interrupts work properly. what a mess. typical problem occured when the pulse was shorter than a <I forget> length. the controller *knew* an interrupt had occured but it couldn't determine the actual source so it selected the lowest priority int. Of course then the device that actually had interrupted was hung. bah, wattamess. Of course, I couldn't get the designers to change it - who cares what a software guy thinks???

your bouncing point is well taken. that's why you shouldn't have switches run directly into interrupt pins. at least with out debouncing HW.
 
Last edited:
Funny, I knew a smart guy once upon a time, who had the very same attitude about edge triggered interrupts. He considered them as welcome as the plague. I think he was always worried about missing an interrupt. He felt that the idea of resetting the interrupt condition in the interrupt service routine was an extra measure of confidence. I have no religion on the subject of interrupts, I can make what ever I have work just fine.
 
Last edited:
Hi all,

To get a resonable resolution in higher velocities I got to recalculate everything and the and thats why i didnt have any timing information on the diagram.
To have the speedo showing speeds from 20 to 200 km/h, I need to increase the "time" by one every 0.1ms. Start to increase the "time" at 360 (200km/h) and go up to 3600 (20km/h). Total steps needed is 3240, in other words 0.324s. The duration of high time is hard to say, it depends on how fast the wheel is spinning, as i dont have the sensor yet i do not really know.

I have a hard time explaining in english, but I hope you understand how I mean. :)

If I use the interrupt routine - edgetriggered, start the timer when the a rising edge is detected. Stop when it detect next rising edge, get the timer value and do some calculations to get the speed? Do I got it right?

I must look into interrupts to understand how it works before i use it. :)

Thanks.
 
If I use the interrupt routine - edgetriggered, start the timer when the a rising edge is detected. Stop when it detect next rising edge, get the timer value and do some calculations to get the speed? Do I got it right?

basically, that is correct. I'd start the timer again on the second int after getting the timer value.

however, your timer is only 8 bit. I believe this what you were refering to with "resolution". You don't need to change timing (prescale, I think is what you meant). Simply keep track of how many times the timer overflows (counts down to 0). Timer overflow generates a timer interrupt and in the interrupt service routine (ISR) you increment a counter. This is the high byte of the time and when the second tach pulse interrupt happens, the timer holds the low byte.

so, in sorta-code:
Code:
tach_ISR:
    perLow = 255-timer0
    perHigh = timerHigh
    timerHigh = 0
    timer0 = 255
    return

timer_ISR:
    timerHigh = timerHigh + 1
    return

in your main line code (non-interrupt), you use perHigh : perLow as a 16 bit period and do your calculations from there. You will need to handle several issues: 1) where the timer roll over happens immediately after the tach interrupt but before the timer value is read and 2) knowing when it is ok to use perHigh : perLow (since the interrupt can happen any time). You should adjust the value that you set timer0 to so as to reflect the amount of time you waste in the tach_ISR before setting timer0.

Of course, if you used a PIC16F628A, you could just use the 16 bit timer...
 
Last edited:
Hi,

Ive changed my mind about using the 16F84A and I think I will try the 16F628A instead. If Im correct it is much easier to use it in this application. Im a beginner and because of all those projects and tutorials based on the 16F84 I automaticly chose to use it.

I will use the 16 bit timer and the only thing I need to do if a timer overflow occur is to put "000" on the display?

If anyone knows some good C code examples (that handles interrups and timer start-stop) on the net please let me know. =)

Thanks,
Anders
 
Geez. From someone that acutally programs pics and has done this project:

You don't need the FF. You also do not want to tie it to B0/B1 INT and try and use that isr. Thats a great one for buttons, there is a better option.

This is a project clearly for CCP (Capture Compare PWM). This is exactly what ccp was made for. Go look at the ECCP Tips and Tricks datasheet on microchips page, you'll see four 'measuring pulse width' examples. You could do this fast, reliable, and the only thought you'll have to put in is what to do when the pusle length is greter then your timer overflow. ie: When motion is coming to a stop.

I'm not sure if the pic you are planning to use has a CCP/ECCP module, but if it doesn't it would be a good idea to select a pic that does.

You'll also want to make sure that your signal is as clean as possible. When tying into hall sensors I usually use a resistor and a small cap.
 
Hi,

iso9001, 16F628A has CCP.

I found and altered some CCP-code and I got it to work, but im not sure if the result is what I expected...

I measure the time between the pulses.
But what values could I get from the interrupt?
Here is the code:

static void interrupt isr(void)
{

if ( CCP1IF )
{
time = (CCPR1L & 0x00ff);
CCP1IF = 0;
}

}

I mean the value "time". Its a 16bit timer, is it counting upwards or downwards(?) every 1us? Im using the internal osc on the pic...

Im confused, a little help from you guys would be great.

Thanks,
Anders
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top