Hello!
Recently I've been working on an Arduino Nano based speedometer for bicycles. it basically measures the rotations of a wheel (by using a Hall effect sensor which outputs LOW when a magnet is near) and converts it to speed. The speedometer, however, outputs a constant speed when the bicycle is not moving AKA no signal from the Hall effect sensor. there are no problems with the wiring or hardware, I've checked multiple times. The program uses an LCD to display the speed. I have figured out the constant speed that is output is somehow related to the integers wheelMagnets and the delay() in loop(). The speed decreases if wheelMagnets is increased and the same with the delay() in the loop(). Thank you for your time! P.S I am not quite good at programming and am of a young age yet.
Variables shared between interrupt and non-interrupt context should be qualified as "volatile".
I'm also inclined to say your interrupt service routines are doing too much work.
This line in your interrupt routine calculates a value then does nothing with it:
distance + wheelCirc/wheelMagnets;
Why are you calling your interrupt routines from within loop()? Those functions are for servicing interrupts, and will be executed when the interrupt occurs.
darth_chikoo:
Can you please explain and/or tell me the changes I should make?
Change all the variables that are used inside and outside of an ISR ( Interrupt Service Routine ) to the volatile type. That is put the word volatile in front of the variable deceleration. For example:-
float speed;
should be
volatile float speed;
That is just one example do that with all variables used inside AND outside an ISR
Also as the speedCalc and revCalc functions are called by interrupts they should NOT be called in the loop function.
While reading variables of more than one byte long outside an ISR then you need to :-
Disable the interrupts
Read or use the variable
Enable the interrupts.
Do you know that millis() will not advance while inside an ISR?
david_2018:
Why are you calling your interrupt routines from within loop()? Those functions are for servicing interrupts, and will be executed when the interrupt occurs.
I deleted those lines - and it did solve the problem and the meter now starts off at zero. However now the ISR is only triggered upon a LOW signal from the sensor and so the speed does not update if there is no signal. Therefore if I were to stop instantly, the speed would not be zero as it wouldn't update. Everything else seems fine and this is the only shortcoming it seems. Could you suggest a way around this? Perhaps a timeout that turns the values to zero?
That is silly and will cause the LCD to flicker. Remove the delay and the clear.
Only update the parts of the display that actually change. Do the fixed part of the display in the setup function.
Therefore if I were to stop instantly, the speed would not be zero as it wouldn't update.
So you have a volatile variable in the ISR to simply count when that function is entered.
Then you look at that variable in the loop function and if it is non zero you clear it and update the display.
If it is zero for the first time you make a note of the time from the millis() function and set a flag saying it was timing.
When the current millis() reaches some threshold, say a second, you then display the zero speed.
In normal operation the clearing of the count variable will also be accompanied by the clearing of the timing flag.
Looks like your learning a lot about the use of interrupts.
You might like to explore the PulseIn() function. This returns the duration the HE sensor is high (or low). That value can be directly converted to rpm. The code is trivial.