Help needed with some sort of counter

Below a piece of code.

What I am doing is connecting 3 buttons on 1 analog pin while reading the incoming values on A0. This value determines what button has been pushed.

The problem is that I need to count how many times that button has been pushed but with this code it keeps counting as long as but button has been pushed.

How can I tackle this? By creating some sort of "changestatus" code?

Please some advise.

void loop()
{
Serial.print("Knop 1: ");
Serial.println(button1Value);   
Serial.print("Knop 2: ");
Serial.println(button2Value);   
Serial.print("Knop 3: ");
Serial.println(button3Value);   
 

  buttonValue = analogRead(A0);  //Read in the button value
  if (buttonValue>=925 && buttonValue<=935){  // Set button 1 Value
    //button1Value = 1;
    digitalWrite(ledPin, HIGH);
      if (button1Value>=0 && button1Value<=4){
        button1Value=button1Value+1;
        }
        else button1Value=0;
      }

You need to have a small state machine and ensure you count when the buttons are GOING down, not when they ARE down

How can I do that? When I connect the button directly to a pin it maybe easier but I am running out of pins. That why I use this way.

You need to detect when the value read enters the range being tested rather than when it is in the range being tested.

The StateChangeDetection example in the IDE shows how to do this with digital inputs. It should not be difficult to adapt it for use with analogue inputs.

Ok, I will read into it. If I have a new code I will report back :wink:

I used a tuto from site and changed the conditions to my setup.

However it keeps counting while i hold the button. What am I missing?

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 10;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the pushbutton input pin:
  buttonState = analogRead(A0);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState>=925 && buttonState<=935) {
      // 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);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  // 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);
  }

}

I added this bit of code and it works. When I set the value to HIGH manually it does work. Why not within a range of analog input?

Can somebody explain this to me?

 // read the pushbutton input pin:
  buttonValue = analogRead(A0);
  if (buttonValue>=925 && buttonValue<=935){
    buttonState = HIGH;
    //Serial.println(buttonValue);
  }
else buttonState = LOW;

What am I missing?

The digital version of the program relies on the fact that the state of the input can only be HIGH or LOW and it detects when the value has changed since the last time that it was read and tests what it is now

However, using an analogue input there are no HIGH/LOW values to test so you must do something else. Maybe something like this (untested)

static boolean buttonIsPressed = false;
int buttonValue = analogRead(A0);
if (buttonValue >= 925 && buttonValue <= 935)
  {
    buttonIsPressed = true;
  }
else
  {
    buttonIsPressed = false;
  }

Now you have variable that will tell you whether the button is pressed or not that you can use to determine whether it became pressed since the last time you looked

That is quite like I did. Except I did not use a boolean. Maybe I should.

Either way will work.

Thanks, it works like a charm. Up to the next challenge, scrolling through menupages with these buttons. :slight_smile:

I think I have worked it out and will open a topic tomorrow with code for more advice.

As a matter of interest, how have you implemented it for multiple buttons ?
Not by simply repeating the code 3 times, I hope ?

I dont have the code at hand right now but the range check I have to do 3 times, in 1 IF statement.

I also need to track the state and counter of all 3 so at this point it is setup fairly simple. Maybe I could put the buttons in an array and do it with 1 check.

Do you know if I can put those ranges in variables? ;

RangeButton1 = 995 - 1005;

if (buttonValue = RangeButton1)
Button1State=HIGH;

Something like that, can that be done?

For responsetimes purposes (RC CAR) I dont want to use While, For and delay. Or at least as little as possible.

The buttons are meant for navigation in a menu displayed on a LCD or Oled screen. I have 12 pages to navigate to. These pages are indexed in a 4x4 matrix array. So when it is 0 (through switch case) I get main menu etc etc. With the first two buttons I fill the query to get menu[1][2].

All this is to program the arduino that sits in a fully waterproof enclosure in the RC car. I can turn data logging on or of, GPS on or of, max brake power.

And also read max speed, session duration, acceleration time, max RPM etc.

The arduino (or atmega only) will only come out of the care if reaaally needed. All other parameters will be programmed with this display.

So, ambitious as it is, I first want it to work before I experiment with the code. Unless I run into some other issues and have time to spare.:slight_smile:

This is the code that I now use for testing. Because I can find tutorials for individual things, I cannot find it for smarter programming. So please, advise :slight_smile:

// this constant won't change:
const int ledPin = 10;       // the pin that the LED is attached to
const int valuePin = A0;       // the pin that the Buttons are attached to
// Variables will change:
int button1PushCounter = 0;    // counter for the number of button 1 presses
int button2PushCounter = 0;    // counter for the number of button 2 presses
int button3PushCounter = 0;    // counter for the number of button 3 presses
int button1State = 0;         // current state of button 1
int button2State = 0;         // current state of button 2
int button3State = 0;         // current state of button 3
int lastButton1State = 0;     // previous state of button 1
int lastButton2State = 0;     // previous state of button 2
int lastButton3State = 0;     // previous state of button 3
int buttonValue=0;            // Waarde op Pin A0
int maxButton1=5;             // Maximaal aantal pushes tot terug naar 0;
int maxButton2=4;             // Maximaal aantal pushes tot terug naar 0;
int maxButton3=4;             // Maximaal aantal pushes tot terug naar 0;
//String menu1 = "Voltage";
//String menu2 = "Temperatuur";
//String menu3 = "Remmen";
//String menu4 = "Prestaties";
//String menu5 = "Iets Anders";
char *myMenus[] = {"Hoofdmenu", "Temperatuur", "Voltage",
                     "Remmen", "Prestaties", "Iets Anders"
                    };


void setup() {
    // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the pushbutton :
  //Serial.println(buttonValue);
  buttonValue = analogRead(valuePin);

  //Set buttons High or Low
  if (buttonValue>=925 && buttonValue<=935){
    button1State = HIGH;
  }
  else button1State = LOW;

  if (buttonValue>=985 && buttonValue<=993){
    button2State = HIGH;
  }
  else button2State = LOW;
  
  if (buttonValue>=1015 && buttonValue<=1055){
    button3State = HIGH;
  }
  else button3State = LOW;
  
//************************ Button 1 **********************************
//Serial.print("number of button pushes: ");
//      Serial.println(buttonPushCounter);
  // compare the buttonState to its previous state
  if (button1State != lastButton1State) {
    // if the state has changed, increment the counter
    if (button1State == HIGH) {
      if (button1PushCounter>=0 && button1PushCounter<maxButton1){
         button1PushCounter++;
          //buttonValue = 0;
         }
         else button1PushCounter=0;
      
      // if the current state is HIGH then the button went from off to on:
      //button1PushCounter++;
      //Serial.println("on");
      switch (button1PushCounter) {
      case 1:{
        Serial.println (myMenus[button1PushCounter]);
         break;
      }
      case 2:{
        Serial.println (myMenus[button1PushCounter]);
         break;
      }
      case 3:{
        Serial.println (myMenus[button1PushCounter]);
         break;
      }
      case 4:{
        Serial.println (myMenus[button1PushCounter]);
         break;
      }
      case 5:{
        Serial.println (myMenus[button1PushCounter]);
         break;
      }
      case 0:{
        Serial.println("Hoofdmenu");
         break;
      }
      }
      //Serial.print("number of button 1 pushes: ");
      //Serial.println(button1PushCounter);
    } 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);
  }
  // save the current state as the last state, for next time through the loop
  lastButton1State = button1State;

//************************ Button 1 **********************************

//************************ Button 2 **********************************
//Serial.print("number of button pushes: ");
//      Serial.println(buttonPushCounter);
  // compare the buttonState to its previous state
  if (button2State != lastButton2State) {
    // if the state has changed, increment the counter
    if (button2State == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      button2PushCounter++;
      Serial.println("on");
      Serial.print("number of button 2 pushes: ");
      Serial.println(button2PushCounter);
      Serial.println(buttonValue);
    } 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);
  }
  // save the current state as the last state, for next time through the loop
  lastButton2State = button2State;

//************************ Button 2 **********************************

//************************ Button 3 **********************************
//Serial.print("number of button pushes: ");
//      Serial.println(buttonPushCounter);
  // compare the buttonState to its previous state
  if (button3State != lastButton3State) {
    // if the state has changed, increment the counter
    if (button3State == HIGH) {
      // if the current state is HIGH then the button went from off to on:

        if (button3PushCounter>=0 && button3PushCounter<maxButton3){
         button3PushCounter++;
          //buttonValue = 0;
         }
         else button3PushCounter=0;
      
      
      Serial.println("on");
      Serial.print("number of button 3 pushes: ");
      Serial.println(button3PushCounter);
      Serial.println(buttonValue);


      
    } 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);
  }
  // save the current state as the last state, for next time through the loop
  lastButton3State = button3State;

//************************ Button 3 **********************************
  


  // 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 (button1PushCounter % 4 == 0) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

}

I would put the values for each button in a struct and put the structs in an array

Something (untested) to get you started :

struct dataDefinition
{
  const byte pinNumber;
  const int lowerValue;
  const int upperValue;
  boolean previouslyPressed;
  byte count;
};

dataDefinition data[] =
{
  {A0, 500, 600, false, 0}, {A1, 600, 700, false, 0}, {A2, 700, 800, false, 0}
};

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  for (int inputNumber = 0; inputNumber < 3; inputNumber++)
  {
    boolean buttonIsPressed = false;
    int inputValue = analogRead(data[inputNumber].pinNumber);
    if (inputValue >= data[inputNumber].lowerValue && inputValue <= data[inputNumber].upperValue)
    {
      buttonIsPressed = true;
    }
    else
    {
      buttonIsPressed = false;
    }
    //code here to test whether the button has become pressed and to act on it if it has
    //do this by testing the previouslyPressed value against the current value
    //update the count if has become pressed
  }
}

You need to put in the correct pin numbers and lower/upper values and add code where indicated

Thanks but your code assumes that every button has its own pin. Mine (4pcs) are all connected to a0. The only way the code can see the difference in the buttons is the resistance and thus value on A0 that the button creates. Each button has its own resistor.

EDIT: I see what you did, sorry. But how fast is this FOR loop? I really want to avoid FOR and while as much as possible.

Throughout the sketch the arduino is receiving signals from my RC receiver and has to put that signal out again with the least of delay.

Probably the slowest part of the code is the analogRead(). If you are worried about that being in a for loop then don't use one, use the fact that loop() repeats and check for just one range of input values each time through loop() by incrementing an index variable.

I am working with your code now but it is not what I meant I think. You still read from 3 pins.

I have to read from 1 pin and with the value that is read, I need to determine what button it has been.

hmm, I like how you did the struct but how can I get it to work with values to button instead of button to value, if you now what I mean.

Edit: Where do you change the state of previously pressed? I cant find it in the code?

I apologise if my example code using an array of structs has confused things but you seem to have grasped the principle of such an array.

To use an array of structs with one pin the first thing to do us to change the data in the struct as the pin number is not needed. I will leave you to write the actual program but the principle will be as follows

start of loop()
  read the analogue pin
  for each level in the array check to see if the value read is in the target range
    if the value is in range of the current level of the array
      check whether the state has changed and the button is now pressed
        if the button has become pressed
          take whatever action is required such as moving a servo, changing the state of an LED etc
        end if
        save the current button state as the previous state
      end if
     end of for loop
end of loop()

If you don't want to use a for loop then use loop() to do the looping for you so that you can deal with the RC signals between checking for button presses

Where do you change the state of previously pressed? I cant find it in the code?

Well spotted, the code did not save the previous state

Thanks,

I will try and implement your tips. The only challenge I have is to map the analog input to a certain button. I will start out by testing one button and work my way further.

IF I can figure it out I will also have way to identify the throttle lever on my remote to be in Neutral, Forward, Brake or Reverse state.

Sounds handy,