Counter and MPH on Garden Tractor - State Machine

Like this:

Question:
Does the input to A0 go between 5 volts and 0 volts only?

What is the minimum expected duration of the pulse on A0?

Larry,

I'm no expert on reading electrical diagrams like you have presented. I wired it up according to the sellers instructions. (All wiring descriptions are copied from sellers sites). They all seem to work with test code.

Do you have a voltmeter?

If so, measure the DC voltage on A0 with the LED light shining on the photo transistor.
Then measure the voltage on A0 when no light is on the transistor.

What are these two voltages?

Here's what I got from Terry. I not sure I have that hooked right but I get signal that's good enough to test. I'm getting a brick that I only have to deal with 3 wires no resistors.

http://www.yourduino.com/sunshop/index.php?l=product_detail&p=217

I do have a tester and The code I used to test it gave a raw voltage. I'll do both if you need them.

Will you be looking at a clean reflecting mirror?

Okay, I think I have one of those.

I will test it out after I BBQ some salmon.

For now, play with this:

#define PUSHED HIGH

//                          m a k e T i m e r
//**********************************************************************
struct makeTimer
{
  public:
    unsigned long StartTime;   //the time this Timer was (re)started
    unsigned long Interval;    //interval time we are looking for
    bool          Restart;     //do we restart Timer timing automatically. true = restart
    bool          EnableFlag;  //is "this Timer" enabled/allowed to be accessed, true = enabled

}; //END of structure


//***************************
makeTimer BlockingTMR =
{
  0, 500, true, true           //StartTime, Interval, Restart, EnableFlag
};
//***************************
makeTimer SwitchTMR =
{
  0, 50, true, true            //StartTime, Interval, Restart, EnableFlag
};
//***************************
makeTimer DisplayUpdateTMR =
{
  0, 1000, true, true          //StartTime, Interval, Restart, EnableFlag
};
//***************************


//**********************************************************************
unsigned long testMicros;
//Serial.println(micros() - testMicros);
//testMicros = micros();
//**********************************************************************

const byte SwitchPB  = 2;  //Pushing the switch puts a HIGH on the pin
byte lastSwitchPBstate;

const byte ResetPB   = 3;  //Pushing the switch puts a HIGH on the pin
byte lastResetPBstate;

const byte IR_Switch = A0; //    
byte lastIR_SwitchState;

unsigned int counter;      //maximum count is 65,535
float MPH;

byte displayMode;

const byte BlockingLED = 13;

//**********************************************************************


//                             s e t u p ( )
//======================================================================
void setup()
{
  Serial.begin(9600);

  pinMode(BlockingLED, OUTPUT);

  //initialize 'input' pins
  pinMode(SwitchPB, INPUT);
  lastSwitchPBstate = digitalRead(SwitchPB);

  pinMode(ResetPB, INPUT);
  lastResetPBstate = digitalRead(ResetPB);

} //END of:                    s e t u p ( )


//                              l o o p ( )
//======================================================================
void loop()
{
  //******************************************
  //Some code to check for blocking code, the Blocking LED should flash at a 1 Hertz rate.
  //Is it time to toggle the LED?
  if (CheckTimer(BlockingTMR))
  {
    //Toggle the Blocking LED
    digitalWrite(BlockingLED, !digitalRead(BlockingLED));
  }

  //******************************************
  //Is it time to check the switches?
  if (CheckTimer(SwitchTMR))
  {
    //it is now time to check the switches
    CheckSwitches();
  }

  //******************************************
  //Is it time to check the switches?
  if (CheckTimer(DisplayUpdateTMR))
  {
    //it is now time to check the switches
    DisplayUpdate();
  }


} //END of:                     l o o p ( )


//======================================================================
//                           F U N C T I O N S
//======================================================================


//                         C h e c k T i m e r ( )
//======================================================================
// Used when actions are needed 'after' a period of time.
boolean CheckTimer(makeTimer &TimerX)
{
  //StartTime  = the time TimerX was (re)started
  //Interval   = interval/delay we are looking for
  //Restart    = do we restart TimerX automatically
  //EnableFlag = is TimerX enabled/allowed to be accessed

  //Is TimerX enabled and has TimerX expired?
  if (TimerX.EnableFlag == true && millis() - TimerX.StartTime >= TimerX.Interval)
  {
    //Should we restart TimerX automatically?
    if (TimerX.Restart == true)
    {
      TimerX.StartTime = millis();           //get ready for the next iteration
      //or use
      //TimerX.StartTime += TimerX.Interval;
    }

    //This Timer did expired
    return true;
  }

  //This timer did not expire or it is disabled
  return false;

} //END of:                 C h e c k T i m e r ( )

//                       C h e c k S w i t c h e s ( )
//======================================================================
void CheckSwitches()
{
  byte switchPosition;

  //******************************************
  //check if SwitchPB has changed state
  switchPosition = digitalRead(SwitchPB);

  if (switchPosition != lastSwitchPBstate)
  {
    //update to the new switch state
    lastSwitchPBstate = switchPosition;

    //This switch position has changed, let's do some stuff

    //Switch went from HIGH to LOW condition
    if (switchPosition == PUSHED)
    {
      displayMode++;
      displayMode = displayMode % 2;
    }

    //Switch went from LOW to HIGH condition
    else
    {
    }

  } //END of:    SwitchPB code

  //******************************************
  //check if ResetPB has changed state
  switchPosition = digitalRead(ResetPB);

  if (switchPosition != lastResetPBstate)
  {
    //update to the new switch state
    lastResetPBstate = switchPosition;

    //This switch position has changed, let's do some stuff

    //Switch went from HIGH to LOW condition
    if (switchPosition == PUSHED)
    {
      counter = 0;
    }

    //Switch went from LOW to HIGH condition
    else
    {
    }

  } //END of:    ResetPB code


  //******************************************
  //check if IR_Switch has changed state
  switchPosition = digitalRead(IR_Switch);

  if (switchPosition != lastIR_SwitchState)
  {
    //update to the new switch state
    lastIR_SwitchState = switchPosition;

    //This switch position has changed, let's do some stuff

    //Switch went from HIGH to LOW condition
    if (switchPosition == PUSHED)
    {
      counter++;
    }

    //Switch went from LOW to HIGH condition
    else
    {
    }

  } //END of:    IR_Switch code

  //******************************************


} //END of:               C h e c k S w i t c h e s ( )


//                        D i s p l a y U p d a t e ( )
//======================================================================
void DisplayUpdate()
{
  switch (displayMode)
  {
    case 0:
      Serial.print("Counter = ");
      Serial.println(counter);

      break;

    case 1:
      Serial.print("MPH = ");
      Serial.println(MPH);
      break;


    default:
      Serial.println("ERROR");
      break;
  }

} //END of              D i s p l a y U p d a t e ( )



//======================================================================
//                             END OF CODE
//======================================================================

Okay I am feed up. :art:

This is a simple ON/OFF sensor, you could feed it into a digital input.

No reflection = 0.1 volts
Full reflection = 5 volts

I used a 100 ohm resistor in series with the IR LED and got about 1 inch of effective distance.

What algorithm will you use to calculate MPH?

BTW
I use this photo transistor a lot.
3DU5C
https://www.ebay.ca/itm/332031591970

here then mph calcs

time = millis() - oldtime;              //finds the time
          rpm = (rev / time) * 60000;             //calculates rpm
          mph = (((15.5 * 3.142) * rpm) / 63360); //1st# is wheel diameter in inches

Here's the sensor

http://www.yourduino.com/sunshop/index.php?l=product_detail&p=217

I'm sure I don't have it wired right. I'm 2 v open and 0v closed. That's why I'm going to get a brick.

http://www.yourduino.com/sunshop/index.php?l=product_detail&p=436

Highly suggest you look at 'Hall Effect Sensors'.
These are resistant to dirt/dust and ambient light does not get into the equation.

See

Looked at all the vids - It appears that the magnet needs to be pretty close!!!

Also looked closer at my IR sensor and it is made to go low, so I think it is wired right.

RayJorgensen:
Looked at all the vids - It appears that the magnet needs to be pretty close!!!

Would depend on the strength of the magnet.

Your IR sensor has a range of only 1 inch.

You might what to design a mechanical linkage from your wheel to a cleaner environment where the sensor is installed.

A range of 1/2 inch would be fine. Dirt etc, might be an issue. I look more at the hall.

I had a few mins to look at the code you sent. Toggle and reset work as I wanted. I'm not seeing where the IR sensor is being read. I'm I missing it? If not let me try placing that in the right spot.

You are going to count the pulses from the IR sensor then display the running total.
You will use the same pluses to determine MPH and display it.

Try this:

#define PUSHED HIGH

//                          m a k e T i m e r
//**********************************************************************
struct makeTimer
{
  public:
    unsigned long StartTime;   //the time this Timer was (re)started
    unsigned long Interval;    //interval time we are looking for
    bool          Restart;     //do we restart Timer timing automatically. true = restart
    bool          EnableFlag;  //is "this Timer" enabled/allowed to be accessed, true = enabled

}; //END of structure


//***************************
makeTimer BlockingTMR =        //1/2 second
{
  0, 500, true, true          //StartTime, Interval, Restart, EnableFlag
};
//***************************
makeTimer SwitchTMR =          //10ms
{
  0, 10, true, true            //StartTime, Interval, Restart, EnableFlag
};
//***************************
makeTimer DisplayUpdateTMR =   //1 second
{
  0, 1 * 1000, true, true      //StartTime, Interval, Restart, EnableFlag
};
//***************************
makeTimer MPHtmr =             //10 seconds
{
  0, 10 * 1000, true, true     //StartTime, Interval, Restart, EnableFlag
};
//***************************


//**********************************************************************
unsigned long testMicros;
//Serial.println(micros() - testMicros);
//testMicros = micros();
//**********************************************************************

const byte BlockingLED = 13;

const byte SwitchPB  = 2;         //Pushing the switch puts a HIGH on the pin
byte lastSwitchPBstate;

const byte ResetPB   = 3;         //Pushing the switch puts a HIGH on the pin
byte lastResetPBstate;

const byte IR_Switch = A0;
byte lastIR_SwitchState;

unsigned int counter;             //maximum count is 65,535

float MPH;
const float WheelDiameter = 15.5; //inches

byte displayMode;
byte revCounter;                  //pulses in MPHtmr seconds (10 sec)

//**********************************************************************


//                             s e t u p ( )
//======================================================================
void setup()
{
  Serial.begin(9600);

  pinMode(BlockingLED, OUTPUT);

  //initialize 'input' pins
  pinMode(SwitchPB, INPUT);
  lastSwitchPBstate = digitalRead(SwitchPB);

  pinMode(ResetPB, INPUT);
  lastResetPBstate = digitalRead(ResetPB);

  pinMode(IR_Switch, INPUT);
  lastResetPBstate = digitalRead(IR_Switch);

} //END of:                    s e t u p ( )


//                              l o o p ( )
//======================================================================
void loop()
{
  //******************************************
  //Some code to check for blocking code, the Blocking LED should flash at a 1 Hertz rate.
  //Is it time to toggle the LED?
  if (CheckTimer(BlockingTMR))
  {
    //Toggle the Blocking LED
    digitalWrite(BlockingLED, !digitalRead(BlockingLED));
  }

  //******************************************
  //Is it time to check the switches?
  if (CheckTimer(SwitchTMR))
  {
    //it is now time to check the switches
    CheckSwitches();
  }

  //******************************************
  //Is it time to update the display?
  if (CheckTimer(DisplayUpdateTMR))
  {
    //it is now time to check the switches
    DisplayUpdate();
  }

  //******************************************
  //Is it time to calculate MPH?
  if (CheckTimer(MPHtmr))
  {
    MPHcalc();
  }


} //END of:                     l o o p ( )


//======================================================================
//                           F U N C T I O N S
//======================================================================


//                         C h e c k T i m e r ( )
//======================================================================
// Used when actions are needed 'after' a period of time.
boolean CheckTimer(makeTimer &TimerX)
{
  //StartTime  = the time TimerX was (re)started
  //Interval   = interval/delay we are looking for
  //Restart    = do we restart TimerX automatically
  //EnableFlag = is TimerX enabled/allowed to be accessed

  //Is TimerX enabled and has TimerX expired?
  if (TimerX.EnableFlag == true && millis() - TimerX.StartTime >= TimerX.Interval)
  {
    //Should we restart TimerX automatically?
    if (TimerX.Restart == true)
    {
      TimerX.StartTime = millis();           //get ready for the next iteration
      //or use
      //TimerX.StartTime += TimerX.Interval;
    }

    //This Timer did expired
    return true;
  }

  //This timer did not expire or it is disabled
  return false;

} //END of:                 C h e c k T i m e r ( )

//                       C h e c k S w i t c h e s ( )
//======================================================================
void CheckSwitches()
{
  byte switchPosition;

  //******************************************
  //check if SwitchPB has changed state
  switchPosition = digitalRead(SwitchPB);

  if (switchPosition != lastSwitchPBstate)
  {
    //update to the new switch state
    lastSwitchPBstate = switchPosition;

    //This switch position has changed, let's do some stuff

    //Switch went from HIGH to LOW condition
    if (switchPosition == PUSHED)
    {
      displayMode++;
      displayMode = displayMode % 2;
    }

    //Switch went from LOW to HIGH condition
    else
    {
    }

  } //END of:    SwitchPB code

  //******************************************
  //check if ResetPB has changed state
  switchPosition = digitalRead(ResetPB);

  if (switchPosition != lastResetPBstate)
  {
    //update to the new switch state
    lastResetPBstate = switchPosition;

    //This switch position has changed, let's do some stuff

    //Switch went from HIGH to LOW condition
    if (switchPosition == PUSHED)
    {
      counter = 0;
    }

    //Switch went from LOW to HIGH condition
    else
    {
    }

  } //END of:    ResetPB code


  //******************************************
  //check if IR_Switch has changed state
  switchPosition = digitalRead(IR_Switch);

  if (switchPosition != lastIR_SwitchState)
  {
    //update to the new switch state
    lastIR_SwitchState = switchPosition;

    //This IR switch has changed, let's do some stuff

    //IR switch went from HIGH to LOW condition
    if (switchPosition == PUSHED)
    {
      counter++;
      revCounter++;
    }

    //IR switch went from LOW to HIGH condition
    else
    {
    }

  } //END of:    IR_Switch code

  //******************************************


} //END of:               C h e c k S w i t c h e s ( )


//                        D i s p l a y U p d a t e ( )
//======================================================================
void DisplayUpdate()
{
  switch (displayMode)
  {
    case 0:
      Serial.print("Counter = ");
      Serial.println(counter);

      break;

    case 1:
      Serial.print("MPH = ");
      Serial.println(MPH);
      break;


    default:
      Serial.println("ERROR");
      break;
  }

} //END of              D i s p l a y U p d a t e ( )


//                           M P H c a l c ( )
//======================================================================
void MPHcalc() //runs every MPHtmr seconds  (10 sec.)
{
  unsigned int rpm = (revCounter) * 6;   //revolutions per minute
  unsigned int rph = rpm * 60;           //revolutions per hour
  float inchesPH = ((WheelDiameter * 3.142) * rph); //inches per hour
  MPH = inchesPH / 63360;                           //convert to MPH

  revCounter = 0;                        //initialize the revoultions counter

} //END of                   M P H c a l c ( )




//======================================================================
//                             END OF CODE
//======================================================================

Just getting back to looking at this again.

Why do you have the (makeTimer MPHtmr = //10 seconds) set 10 seconds?

Shouldn't ( lastResetPBstate = digitalRead(IR_Switch):wink: be analogRead since it's hooked to pin A0?

I looked more at the hall switches and have some ordered. I agree they may be a better option due the the operating enviorment.

//***************************
makeTimer MPHtmr = //10 seconds
{
0, 10 * 1000, true, true //StartTime, Interval, Restart, EnableFlag
};

This creates a timer.
You need a unit of time to calculate MPH.

You could use one second, but for accuracy, you would then need to have more pulses per revolution coming from the wheel sensor.

A0 can be used for either analog or digital input.
Since the signal from the sensor is 0v or 5v, you treat it as a digital signal.

If you had an analog sensor that gave 0v thru 5v, you would use analogRead.

.

All makes sense. I'll wait a few days for the hall sensors. In the mean time I start on output to the 7 segment display.

Thanks

When you assemble the final setup, make sure the ‘Hall effect’ sensor gets close enough to the magnet.
i.e.
Let’s say the magnet and sensor starts detection at 1 & 1/2 inches.
It may be best to move the magnet to 3/4 inches from the sensor.

Some kind of debris guard (from stones, twigs etc.) for the sensor would be a good idea.

Note:
You can bias the sensor with a magnet and then detect ferrous objects.
You can monitor the wheel with a linkage mounted at an isolated clean location.

Note:
You can bias the sensor with a magnet and then detect ferrous objects.

I'm not getting what you saying here.

See time unit @ ~5:14