Go Down

Topic: Change functionality of mechanical switches (Read 994 times) previous topic - next topic


Jan 16, 2019, 12:09 am Last Edit: Jan 16, 2019, 12:44 am by darkenney
Thank you! Coincidentally, I had just come across blink without Delay() during the search for an approach. Implementing it here worked out well! I've been Delay() free now for over 75 minutes.

Also coincidentally, it's a critical precursor for what I need to do next on this project - which is create a speedometer from a reed switch input. (Those buttons increase and decrease the speed of a DC motor.)

The code for this is proving tougher. For a single revolution, the magnet takes a small amount of time to pass the reed sensor, so the input pin reads, not as a single LOW but, as a string of LOWs as it's going past. There's also the bounce of the reed switch adding some misleading HIGHS into those LOWs, and there's a lot of interference here - probably from the dc motor; so, there are more incorrect HIGHs and LOWs scattered throughout. Edge detection, filtering, I'm thinking that I still won't need interrupts since updating the mph display would be in the loop of pressing and holding the speed buttons. 

At the highest speed I need to measure with the reed switch (about 1,300 rpm equaling 12mph), a full revolution would take 45 milliseconds. (I wouldn't be able to get a Hall effect Sensor into the setup.) I found that without Serial.printing individual vales, the Arduino can repeat the loop checking the magnet state about 200,000 times a second. That would give me 900 inputs in the span of 45 milliseconds to analyze in order to determine speed. However, when I output through Serial.print for troubleshooting, it will output *significantly* less than that leaving me looking at a collection of HIGHs and LOWs that isn't definitive.

Since this next issue is no longer related to my mechanical switches, I'll start a new thread somewhere else in the forum.

Now, make that over 80 minutes Delay() free.


I think that you are supposed to keep everything in the project in 1 thread for the reason that members searching the forum for solutions find all the info in one place.

You're getting to where you are coding for events in time. It's GREAT that you can get multiple closed reads through the reed switch, your sensing is fast enough to be solid!

You don't want to go by the pin state but rather by changes in the pin state and this is where finite state machine style coding comes in as key #2 in real world automating. With a state machine you track and control the progress of your process through a variable and most often a switch-case statement that has all the steps your process needs with that state variable as the means to switch from one step to another (not confined to the next), do something until finished in one case then change the state to run a different case --- the description is general/non-specific because the technique is, it can stretch to do incredible things where you have state machines working inside of state machines to analyze text and other complex things.

Those Nick Gammon tutorial links in my sig space, the 2nd one has a very nice State Machine example that reads formatted serial input as user control info, check it out.

Watch events in time and control events over time.

1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.


I'm a bit stuck on the next level of my speedometer code. Any guidance would be much appreciated.

I've got a reed switch with magnet on a wheel. The goal is to Serial.print the speed in mph every .5 seconds to 1 decimal place. At the slowest speed of the wheel, I'll need about 8 seconds worth of input to resolve to .1 mph.   Make sense?

Right now I just have a single 8 second loop, followed by another, followed by another rather than -- I guess -- 16 of them going at once --

So two things with the code - 1) I don't have the data types correct so mph comes out as 0

11:15:24.106 -> number of revolutions in this 8 seconds is   20;   mph is    0
11:15:32.125 -> number of revolutions in this 8 seconds is   20;   mph is    0

2) An approach to get a most recent 8 second update every .5 second.

Again, this code is just the 8 second loop, but it seems to work except for the mph calculation. Just some direction would be helpful. Thank you!

Code: [Select]

const int reedPin = A2; //the analog inpout pin that will receive the data from the reed switch
const int interval = 8000; //the number of millis needed to see an edge (revolution) at slow speeds
const long multiplier = 0.069691051; //multiple the number of edges (revolutions) by this number to get mph
long mph =0.0; //final calc of mph is revoultions x multiplier
int firstInput = 1;  //variable to get a reading from the reed switch
int secondInput = 1; //varaible to get a second reading from the read switch
int edges = 0;  //variable that will count the number of edges in the 8 second timefrome
unsigned long startMillis = 0; //will hold the millis of the start of the 8 second interval
unsigned long currentMillis = 0; //will get updated with the current millis to check if we're still in the 8 seconds
 void setup() {
  pinMode(reedPin, INPUT_PULLUP);
  Serial.begin(9600); //troubleshooting has been challenging as output to screen slows down capture of inputs
  startMillis = millis(); //with such a long inteval want the first loop to be mostly valid

void loop(){
  currentMillis = millis(); //as we loop keep updating the currentMillis with the correct time

  if(currentMillis - startMillis <= interval) { //if we're still in the 8 second time frame...
    firstInput = analogRead(reedPin); //get a reading from the reed pin
    if(firstInput < 130){firstInput = 0;} //if it's low enough make it 0
    delay(4); //pause very briefly
    secondInput = analogRead(reedPin); //get a second reading from the reed pin
    if(secondInput < 130){secondInput = 0;} //if it's low enough make it 0
    if(firstInput !=0 && secondInput ==0){edges++;}//if the first input is not 0 and the second input is
                                          //we've scored ourselves and edge, which is the same as a revolution
    else {//we're no longer in the 8 second loop so print out and reset
          mph = edges * multiplier;
          Serial.print ("number of revolutions in this 8 seconds is   ");
          Serial.print (edges);
          Serial.print (";   mph is    ");
          Serial.println (mph);
          edges = 0; //reset edges
          startMillis = millis(); //restart the 8 second counter



Get more reads per revolution. Lots of ways to do that without multiplying magnets required, know what a gear tooth counter is?
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.


You take the wrong approach.

Don't time how many rotations you get in 8 seconds, instead time how long it takes for a single rotation. Or, when it rotates faster, how long for 2 or more rotations.

Secondly, don't get yourself stuck in a loop waiting for the next edge. Just check every time loop() runs; and update the speed every 500 ms to reflect the latest measurement.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.


Thanks. Yes, makes sense. I tried some versions of that but I couldn't get it right. I'll go back and have a look at that approach again. A revolution at the slowest speed takes about 6 seconds, and at the highest speed, it's 45 milliseconds.

For now, I made it its own function and call it at 1/2 second intervals when needed. It's nicely updating a 3 digit 7 segment display.

There's an odometer component so I also need to keep a count of total wheel revolutions. Thanks again.

Go Up