Counter and MPH on Garden Tractor - State Machine

I’m sure this will work. My Idea is that there are 2 buttons. Button1 controls if it displays a count or MPH. (I’ve included Debounce for the buttons - I hope)

Button 2 will reset the counter as needed.

The counter is for spacing on holes that will be drilled for planting trees in our orchard. (I spaced out the 1st 250 holes last fall with a tape and that sucked!)

The MPH is so I can replicate a given speed for spraying after getting the calibration done.

I’ve got the code started and it compiles. I need to solder it up and make a “wheel” to test it.

Disregard the print statement, they are still there from testing the sensor and make sure it was working.

I will be using a 7 digit display like this.

I’m attaching a flow chart - I think I’ll add a print timer yet - but this gives my feeble attempt.

Here’s the code at this point;

#define reading A0

// these constant won't change:
const int  buttonPin1 = 2;    // the pin that the pushbutton is attached to
const int  buttonPin2 = 3;    // the pin that the pushbutton is attached to
const int ledPin = 13;        // the pin that the LED is attached to
int buttonPushCounter = 0;    // start the couner = 0

// Variables will change:
//int ledState = HIGH;         // the current state of the output pin
int buttonState1 = HIGH; // the current reading from the input pin
int buttonState2 = HIGH; // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

//***************define global variables****************
float value = 0;
float rev = 0;
int count = 0;
int rpm = 0;
int oldtime = 0;
int time = 0;
int mph = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(reading, INPUT);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);

  Serial.begin(9600);  //set the baud rate of the serial monitor

}

void loop() {
  // put your main code here, to run repeatedly:
  value = analogRead(reading);  //take reading from sensor

  //********************Pushbutton Section**********************
  // read the pushbutton input pin:
  buttonState1 = digitalRead(buttonPin1);

  // compare the buttonState to its previous state
  if (buttonState1 != lastButtonState)
  {
    // if the state has changed, increment the counter
    if (buttonState1 == HIGH)
    {

    }
    lastButtonState = buttonState1;

    //**********************code for counter***********************
    if (lastButtonState = buttonState1)
    {
      if (value <= 4)
      {
        ++count;
      }
    }
    if (buttonState2 = HIGH)
    {
      count = 0;
    }
    //**********************code for MPH**********************************
    if (buttonState1 == LOW)
    {
      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

    }
    lastButtonState = buttonState1;

    // *********************Print stuff here************
    float raw_voltage = value * 0.00488; //convert analog value to voltage
    Serial.print(value);  //display analog value in serial monitor
    Serial.print("\t");
    Serial.print(raw_voltage);  //display value of voltage in serial monitor
    Serial.print("\t");
    Serial.println(count);
    delay(500);  //create a delay of 1s
  }
}

Thanks for taking a look and I’m looking forward to constructive criticism!!!

if (lastButtonState = buttonState1)

buggy buggy buggy. Go study the difference between = and ==. You have the same bug elsewhere as well.

Forgot to attach the flow chart!

I also notice that you aren't using pull-up resistors and you are expecting the buttons to read backwards (HIGH when pressed). So do you have external pull-down resistors? It is much easier to wire the button between the pin and ground and use the built-in pull-up resistors via pinMode(pin, INPUT_PULLUP) and then reverse the logic on your buttons so they are expected to read LOW when pressed like normal.

I knew better on the = vs ==. I think I caught them all

Yes I’m using pull ups on the circuit board. I works just flashing pin 13 with the led being off at startup.

#define reading A0

// these constant won't change:
const int  buttonPin1 = 2;    // the pin that the pushbutton is attached to
const int  buttonPin2 = 3;    // the pin that the pushbutton is attached to
const int ledPin = 13;        // the pin that the LED is attached to
int buttonPushCounter = 0;    // start the couner = 0

// Variables will change:
//int ledState = HIGH;         // the current state of the output pin
int buttonState1 = HIGH; // the current reading from the input pin
int buttonState2 = HIGH; // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

//***************define global variables****************
float value = 0;
float rev = 0;
int count = 0;
int rpm = 0;
int oldtime = 0;
int time = 0;
int mph = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(reading, INPUT);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);

  Serial.begin(9600);  //set the baud rate of the serial monitor

}

void loop() {
  // put your main code here, to run repeatedly:
  value = analogRead(reading);  //take reading from sensor

  //********************Pushbutton Section**********************
  // read the pushbutton input pin:
  buttonState1 = digitalRead(buttonPin1);

  // compare the buttonState to its previous state
  if (buttonState1 != lastButtonState)
  {
    // if the state has changed, increment the counter
    if (buttonState1 == HIGH)
    {

    }
    lastButtonState == buttonState1;

    //**********************code for counter***********************
    if (lastButtonState == buttonState1)
    {
      if (value <= 4)
      {
        ++count;
      }
    }
    if (buttonState2 == HIGH)
    {
      count = 0;
    }
    //**********************code for MPH**********************************
    if (buttonState1 == LOW)
    {
      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

    }
    lastButtonState == buttonState1;

    // *********************Print stuff here************
    float raw_voltage = value * 0.00488; //convert analog value to voltage
    Serial.print(value);  //display analog value in serial monitor
    Serial.print("\t");
    Serial.print(raw_voltage);  //display value of voltage in serial monitor
    Serial.print("\t");
    Serial.println(count);
    delay(500);  //create a delay of 1s
  }
}

lastButtonState == buttonState1;

delay(500); :o

It is time that you start using the appropriate sized ‘type’ when you define your variables. ;)

example:

int buttonState1 = HIGH; use byte buttonState1 = HIGH; int count = 0; use byte count = 0; int time = 0; use unsigned long time = 0; int rpm = 0; use unsigned int rpm = 0; etc.

You need two lastButtonState variables - sharing it between two buttons is going to be a headache.

Better names would be nice: Not buttonPin2 but ResetButtonPin.

It's been 2 weeks since my last post. From the voice of experience - don't get the flu they talk about on the news everyday!! It'll first make you wonder if you will die and the wish you could.

I've tried looking at this project the last couple days and nothing was making sense yet. Today it's coming back to me.

I may be foggy yet but I'm trying.

My debounce must not be working. I've it over and over again and can't find what's wrong. My sample code works fine.

First the sample code.

// this constant won't change:
const int  buttonPin1 = 2;    // the pin that the pushbutton is attached to
//const int  buttonPin2 = 3;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to
int buttonPushCounter = 0; //

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState1 = HIGH; // the current reading from the input pin
// int buttonState2 = HIGH; // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin1, INPUT);

  // initialize the button pin as a input:
//  pinMode(buttonPin2, INPUT);
  
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);

  // initialize serial communication:
  Serial.begin(9600);
}

void loop() {
  // read the pushbutton input pin:
  buttonState1 = digitalRead(buttonPin1);

  // compare the buttonState to its previous state
  if (buttonState1 != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState1 == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    //delay(50);----------------------------Taken care of with millis code
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState1;


  // turns on the LED every four button pushes by checking the modulo of the
  // button push counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (buttonPushCounter % 4 == 0) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

}

Here's the file I'm working on.

#define IR_switch  A0                //Pin the IR sensor is attached to

// these constant won't change:
const int  switch_button = 2;     // the pin that the pushbutton is attached to
const int  reset_button = 3;      // the pin that the pushbutton is attached to
const int ledPin = 13;            // the pin that the LED is attached to
int SwitchCounter = 0;            // start the couner = 0

// Variables will change:
//int ledState = HIGH;            // the current state of the output pin
byte buttonState1 = HIGH;         // the current IR_switch from the input pin
byte buttonState2 = HIGH;         // the current IR_switch from the input pin
byte lastButtonStateSwitch = LOW; // the previous IR_switch from the input pin
byte lastButtonStateReset = LOW;  // the previous IR_switch from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

//***************define global variables****************
float value = 0;
float rev = 0;
byte count = 0;
byte rpm = 0;
unsigned long oldtime = 0;
unsigned long time = 0;
unsigned int mph = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(IR_switch, INPUT);
  pinMode(switch_button, INPUT);
  pinMode(reset_button, INPUT);

  Serial.begin(9600);  //set the baud rate of the serial monitor

}

void loop() {
  // put your main code here, to run repeatedly:
  value = analogRead(IR_switch);  //take reading from IR_switch sensor


  //********************Pushbutton Section**********************
  // read the pushbutton input pin:
  buttonState1 = digitalRead(switch_button);

  // compare the buttonState to its previous state
  if (buttonState1 != lastButtonStateSwitch) {
    // if the state has changed, increment the counter
    if (buttonState1 == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      SwitchCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(SwitchCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    lastButtonStateSwitch == buttonState1;
    /*
        //**********************code for counter***********************
        if (SwitchCounter == 1) // How many times hs the button been pushed
        {
          if (value = 0) // value returned by IR sensor
          {
            ++count; //
          }
        }
        if (buttonState2 == HIGH)
        {
          count = 0;
        }
        //Serial.println(buttonState1);
        //**********************code for MPH**********************************
        if (SwitchCounter == 0) // How many times hs the button been pushed
        {
          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

        }
        lastButtonStateSwitch == buttonState1;
        //Serial.println(buttonState1);

        // *********************Print stuff here************
        // float raw_voltage = value * 0.00488; //convert analog value to voltage
        //Serial.print(value);  //display analog value in serial monitor
        //Serial.print("\t");
        //Serial.print(raw_voltage);  //display value of voltage in serial monitor
        //Serial.print("\t");
        //Serial.println(count);

      }
    */
  }
}

As I said - I may still be a bit foggy, but I can not see why the debounce isn't working.

Following...am "Arduinoing" in an orchard environment as well...see https://forum.arduino.cc/index.php?topic=524897.0

I'm trying to be helpful here so at the risk of being insulting (not my intention at all) If you are new to orchard/vineyard layout here is a thought....

When we plant trees and the GPS tractor is not available we revert back to low tech: a ±120' light cable ±1/16 to 1/8" dia. with a split shot fishing weight crimped at the correct tree spacing for the length of the cable and a loop or ring in the cable at each end...lay the cable out in the tree row, pull the ends tight and stake them through the loops so the cable won't move and then put a cocktail straw by each split shot weight to mark where to dig tree hole, pull up one stake move that end down the unmarked tree row until tight and repeat...High tech is fun but some times low tech works nearly as well...Here's good advice, don't try and pass this activity off as quality time "doing something together with your wife"...BTDT

Farmer1949,

No offense taken. I agree with you totally. I laid out the first 3 acres somewhat as you suggested. It took me 3 days. I’ve got a bad hip and that’s why I’m looking to tech. I can lay this out and bore the holes accuratley with a little tech and save my self a whole lot of hurt and time.

After this first 3 acres there are another 12 acres to come. If the tech works it’ll get used for another 2 - 4 years.

For debouncing switches read them every ~50ms. Something like this:

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

See this tutorial: https://forum.arduino.cc/index.php?topic=525240.0

Suggest you this this sequence:

if (buttonState1 != lastButtonStateSwitch) { lastButtonStateSwitch == buttonState1; . . .

Larry, I will try tomorrow, I know that tonight yet just won’t work.

Farmer1949,

I read the post you are following. I really want'd GPS on this project, but the cost is way to high.

Regular GPS will not get even close enough for what I want and to get the hardware for RTK is not going to work.

For the counter I am going to use a wheel of a known circumference. Either 2 or 4'. By counting the spokes, I should be able to get within a 1/2" or so. That doesn't give the straight line, but when I farmed I was able to get some pretty straight rows over a 1/2 mile. I'll find out if this works once it's used on the first 3 acres. (I have flags for every hole and I will have a camera mounted to help position over those flags)

Our cherry rows are 15 feet apart and for what row we are in location, speed and odometer of acreage covered the $15 gps works for our application.....Am working on how to reset the odometer function of the sketch by a button, rotary encoder or ? The resetting will aid in calibrating the sprayer as explained in the other thread...not there yet, currently working on a conditional statement so when the sprayer comes out of the trees the odometer stops accumulating feet/acres...then it starts accumulating ones back in the row...after that is solved we are on to the reset button challenge...."How hard could it be?"...which would be our family motto, if we had a family crest...lol

I think I have all the “parts” needed for the state machine and timers added. Could you check it over before I go on?

Thanks

ir_sensor.03.ino (9.23 KB)

You are defining functions 'within' the loop() function. You cannot do this!

The compiler would have told you this if you did a trial compile.

void loop() {
  // put your main code here, to run repeatedly:
  value = analogRead(IR_switch);  //take reading from IR_switch sensor

  //                         C h e c k T i m e r ( )
  //======================================================================
  // Used when actions are needed 'after' a period of time.
  boolean CheckTimer(makeTimer & TimerX)
  {
.
.
.

I did the verify - I knew it was wrong. I need another hint as to fix it!

Code in the loop() function must be between the first { and the last }

void loop() {

// loop code goes here

}

// other functions are placed after here, i.e. after the }

The more I tried to fix the code the worse it got, so I’m backing up. I’ve stripped the sample code of everything I don’t think I need and it complies.

I’ll have 2 buttons, so I figure I need 2 “states” and 2 “timers”. Right???

1 button depending on how many times it is pressed will drop into a different “If” statement that either counts revs or calculates MPH.

The other button will rest the counter when pushed.

Could you look this over and see if I still have stuff I don’t need or have I taken to much out?

Thanks

counter_mph.01.ino (8.47 KB)