# PIC based MCU coding to make a speedometer

#### sidd342

Joined Oct 9, 2023
26
I am trying to make a speedometer cum odometer. I'm using a PIC based MCU. The speed I'm getting is as an analog input. (at 0V, I get 0 Km/hr and at 25V, I get 25Km/hr). I can easily measure the speed using the ADC conversion. The issue I'm facing is how do I measure the distance here. Does anyone have any ideas for the same?

One thing I can think of is having a delay of 100ms in the code and multiplying the instantaneous speed by 100mS. Since all other function execution should take a maximum of 1-5mS (including ADC conversion and sending bits to LCD displays etc), I can neglect that time and consider the distance here. But this method is not very exact. Does anyone have a better solution?

PFA the basic code
currentSpeedVoltage = (currentSpeedVoltage * 0.001220703125); //(0.001220703125 = 5/4096) (12 bit resolution for ADC)
currentSpeed = (currentSpeedVoltage*25)/18; // assumed here that at 18 Volts, we show the speed as 25 Km/hr.
distance += (currentSpeedx100x5*(pow(10,-5))/18)/1000;

#### BobTPH

Joined Jun 5, 2013
8,665
You are trying to get the distance travelled based on a varying speed input.

That would be called numerical integration. The distance travelled is the integral of the speed over time. There are full books about methods of numeric integration, but you probably don’t need that level of accuracy.

The simplest way to integrate is called the “rectangle rule”. You take a measurement if speed at a regular interval, say the 100 msec you mentioned. Then you assume the speed was constant across that interval, so the distance moved is the speed x the interval.

If you express the speed in m / sec then, for a 100 msec interval is the speed times 0.1. Just add all of these uo to get the running total of the distance moved.

Far better than the rectangle rule is the trapezoid rule. Here, we take the same measurements, but we use the speed at both ends of the interval. The speed is now the interval x the average of the two speeds. This is the simplest method typically used in the real world.

The names rectangle and trapezoid come from the shape of the area you are calculating on a graph.

Last edited:

#### MrChips

Joined Oct 2, 2009
30,494
As a rule, I never do floating point arithmetic on microcontrollers.
Why?

1) FP takes a lot of memory space.
2) FP takes a lot of CPU cycles to compute.
3) I can replace all FP calculations with integer arithmetic.

To solve your problem I would,

1) Use the ADC reading and convert to speed using simple integer (or fixed point) arithmetic.
2) Integrate the ADC reading at fixed intervals and convert to distance. I don't need to know the time interval.

#### MrChips

Joined Oct 2, 2009
30,494
Actually this is based on using a hall sensor to calculate the number of rotations of the wheel whereas I'm getting the speed as a DC voltage.
Ah! Well that makes life even simpler. Just count the pulses from the hall sensor.

#### sidd342

Joined Oct 9, 2023
26
You are trying to get the distance travelled based on a varying speed input.

That would be called numerical integration. The distance travelled is the integral of the speed over time. There are full books about methods of numeric integration, but you probably don’t need that level of accuracy.

The simplest way to integrate is called the “rectangle rule”. You take a measurement if speed at a regular interval, say the 100 msec you mentioned. Then you assume the speed was constant across that interval, so the distance moved is the speed x the interval.

If you express the speed in m / sec then, for a 100 msec interval is the speed times 0.1. Just add all of these uo to get the running total of the distance moved.

Far better than the rectangle rule is the trapezoid rule. Here, we take the same measurements, but we use the speed at both ends of the interval. The speed is now the interval x the average of the two speeds. This is the simplest method typically used in the real world.

The names rectangle and trapezoid come from the shape of the area you are calculating on a graph.

Thank you so much for such a clear response. I however have a couple questions in terms of the code required.
I'm making a speedometer for an EV that shows various other things including indicators, headlights etc.
All these would also require some time in processing. Would you recommend that I have a separate clock to set in a delay for a fixed time interval (like 100ms) and ignore the time taken for other ADC conversions and the time in sending the signals to the LED driver etc.?

Thanks again

#### sidd342

Joined Oct 9, 2023
26
As a rule, I never do floating point arithmetic on microcontrollers.
Why?

1) FP takes a lot of memory space.
2) FP takes a lot of CPU cycles to compute.
3) I can replace all FP calculations with integer arithmetic.

To solve your problem I would,

1) Use the ADC reading and convert to speed using simple integer (or fixed point) arithmetic.
2) Integrate the ADC reading at fixed intervals and convert to distance. I don't need to know the time interval.
Could you please give me an idea on how to avoid the floating point calculation in this case? And/or how to integrate to convert to distance?

Thanks again

#### sidd342

Joined Oct 9, 2023
26
Ah! Well that makes life even simpler. Just count the pulses from the hall sensor.
Actually I'm not using any hall sensor. I'm just getting a speed and DC voltage mapping that I Use to find speed and furthermore get distance

#### nsaspook

Joined Aug 27, 2009
12,805
Could you please give me an idea on how to avoid the floating point calculation in this case? And/or how to integrate to convert to distance?

Thanks again
At this point, if you have adequate controller resources of code space and speed don't worry about using FP. Get the code working correctly first and optimize later. Premature optimization is the root of all programming evil.
At this point, your time (developing the correct set of equations) is more valuable than CPU time.

#### BobTPH

Joined Jun 5, 2013
8,665
Would you recommend that I have a separate clock to set in a delay for a fixed time interval (like 100ms) and ignore the time taken for other ADC conversions and the time in sending the signals to the LED driver etc.?
It is imperative that the interval is known accurately. The easiest way to do that is to make each interval identical. You should use a timer interrupt to trigger the readings. I think this can even be done automatically by the PIC ADC, depending on which PIC you are using.

#### sidd342

Joined Oct 9, 2023
26
It is imperative that the interval is known accurately. The easiest way to do that is to make each interval identical. You should use a timer interrupt to trigger the readings. I think this can even be done automatically by the PIC ADC, depending on which PIC you are using.
I can calculate the time it takes for the ADC conversion but the issue becomes when there are other operation (including some if else analysis and sending all the bits to the led drivers) which also takes time.
Is it possible to calculate that within the code?

#### Ian0

Joined Aug 7, 2020
9,504
As a rule, I never do floating point arithmetic on microcontrollers.
Why?

1) FP takes a lot of memory space.
2) FP takes a lot of CPU cycles to compute.
3) I can replace all FP calculations with integer arithmetic.

To solve your problem I would,

1) Use the ADC reading and convert to speed using simple integer (or fixed point) arithmetic.
2) Integrate the ADC reading at fixed intervals and convert to distance. I don't need to know the time interval.
I find that with a 32-bit processor and appropriate scaling, integers can be used for everything.

#### MrChips

Joined Oct 2, 2009
30,494
I find that with a 32-bit processor and appropriate scaling, integers can be used for everything.
I wrote routines to calculate dewpoint temperature from temperature and relative humidity measurements all in integer arithmetic on 8-bit MCUs, not exactly an easy thing to do.

#### BobTPH

Joined Jun 5, 2013
8,665
I can calculate the time it takes for the ADC conversion but the issue becomes when there are other operation (including some if else analysis and sending all the bits to the led drivers) which also takes time.
Is it possible to calculate that within the code?
You are not understanding me. You need to have a constant interval. That is what timers and interrupts are for.

You set up a timer to interrupt every 100 msec. Then, in the interrupt handler, you start the ADC. You set the ADC to interrupt when it is done.

Then, in the interrupt handler for the ADC interrupt you fetch the result and add to an accumulator for the distance.

What goes on in the background and the time it takes to do the sample or calculation are not relevant at all. The samples will be precisely at the same interval as long as no higher priority interrupt disturbs them.

If you intend to do real-time programming, you need to understand interrupts and timers, they are the bread and butter of real-time.

#### nsaspook

Joined Aug 27, 2009
12,805
I find that with a 32-bit processor and appropriate scaling, integers can be used for everything.
it depends on the hardware
With 32-bit controller (the PIC32MK has double precision FP/DSP hardware) FP hardware, single/double precision FP is faster than integers in C.

#### BobTPH

Joined Jun 5, 2013
8,665
Why are we arguing over what type of arithmetic is used when the TS still has no idea how the calculation is done, or even how to sample at a fixed interval?

#### nsaspook

Joined Aug 27, 2009
12,805
Why are we arguing over what type of arithmetic is used when the TS still has no idea how the calculation is done, or even how to sample at a fixed interval?
I'm not arguing as I agree with you. Use what's easiest to understand the creation of the calculation as a first step. Implementation optimization details are for later.

#### Ian0

Joined Aug 7, 2020
9,504
Depending on your processor, you can probably set it to trigger the A/D every time the timer times out; and then interrupt when the A/D has finished.
Then all the interrupt routine has to do is read the A/D and add it to the accumulator variable that is the distance.

If you want to use the trapezium rule then add the latest reading to the previous and divide by two. Then add that to the accumulator.

However if you sum that over the whole time period the two answers are the same except for the first and last A/D reads.

#### BobTPH

Joined Jun 5, 2013
8,665
Depending on your processor, you can probably set it to trigger the A/D every time the timer times out; and then interrupt when the A/D has finished.
Then all the interrupt routine has to do is read the A/D and add it to the accumulator variable that is the distance.
Just as I have been saying in my last two posts.
If you want to use the trapezium rule then add the latest reading to the previous and divide by two. Then add that to the accumulator.

However if you sum that over the whole time period the two answers are the same except for the first and last A/D reads.
Correct, I realized that as I was posting, but didn’t want to add more confusion.

#### sidd342

Joined Oct 9, 2023
26
You are not understanding me. You need to have a constant interval. That is what timers and interrupts are for.

You set up a timer to interrupt every 100 msec. Then, in the interrupt handler, you start the ADC. You set the ADC to interrupt when it is done.

Then, in the interrupt handler for the ADC interrupt you fetch the result and add to an accumulator for the distance.

What goes on in the background and the time it takes to do the sample or calculation are not relevant at all. The samples will be precisely at the same interval as long as no higher priority interrupt disturbs them.

If you intend to do real-time programming, you need to understand interrupts and timers, they are the bread and butter of real-time.
Ohh understood. I was thinking along a wrong tangent but yes I can have a fixed delay, and set up an interrupt and whenever there is an interrupt, I can begin the ADC conversion and use the Trapezoid Rule.

Thanks again