Go Down

Topic: Preference-Based Button Programming Help (Read 92 times) previous topic - next topic

MrMagoo1234

May 24, 2020, 04:25 am Last Edit: May 24, 2020, 04:27 am by MrMagoo1234
I am trying to create a preference based voting box / system where the first button a voter presses selects that candidate as his first preference, the second button he presses is his second preference, and so on until he presses the last button (fourth in my case) which is his last preference.

What I do is that I assign a running total for each candidate. The first preference gets 3 points and the fourth preference gets 0 points. Whoever has the largest score at the end wins!

The problem is that if a user attempts to press the same button twice, it will add 3 points and then the second preference points (2 points), leading to a total of 5 points which is what I want to prevent.

How do I reject input from buttons that are pressed the second time and then after all buttons have been pressed, the process is reset but running total is kept so the next candidate can put their vote in?

Edit: I attempted to create the program using a long list of embedded IF statements, but the problem is that it takes the Arduino Uno too long to process the code and eventually causes to overheat the system as well. I need something that is more concise with shorter execution time.

aarg

...but the problem is that it takes the Arduino Uno too long to process the code and eventually causes to overheat the system as well.
You can just keep a bool value for each button, initialize to NOTPRESSED. Then if a button has been pressed, change the variable to PRESSED. You can be smart and use an enum for that, or you can simply use "true" and "false".

If your board is overheating, you have a hardware, not software problem.
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

finola_marsaili

I was thinking to use an array to keep the score for each button, initialised 0.

Have a counter for how many presses there have been. You only need to count 3 for 4 buttons I think, since once you pressed 3, the last (unpressed) button must be the 4th choice?

For each press, check if the array slot is 0 (aarg's idea of the boolean is really the same thing). If it's 0, stick the score associated with that press (3,2,1) into the button's array slot. If it's not 0, you did that one already, do nothing.

Then you have a handy array of scores say {1,0,3,2} to do with what you wish.







MrMagoo1234

Thank you so much! It really helped!  :)  :)  :)  :)

finola_marsaili

I'm interested to see your code, which may also help anyone else with a similar question in future.

I did it as a state machine, so there's a "voting" state which accepts button presses until each candidate's button has been pressed, then it goes to a "voted" state at which point you can then easily do what you like with the scores, and have a "restart" button if you want to go again with the scores reset.


MrMagoo1234

Here's my code, IDK why its not working!!!




int buttonState1 = 0;
int buttonState2 = 0;
int buttonState3 = 0;
int buttonState4 = 0;
int score1 = 0;
int score2 = 0;
int score3 = 0;
int score4 = 0;
int alreadyPressed [4];
int state = 3;
int x = 0;
void setup()
{
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(13, OUTPUT);
  Serial.begin(1200);
  alreadyPressed[0] = 0;
  alreadyPressed[1] = 0;
  alreadyPressed[2] = 0;
  alreadyPressed[3] = 0;
}

void loop()
{
 
  buttonState1 = digitalRead(2);
  buttonState2 = digitalRead(3);
  buttonState3 = digitalRead(4);
  buttonState4 = digitalRead(5);
 
 
 if (buttonState1 == HIGH && alreadyPressed
  • != 1 && alreadyPressed [1] != 1 && alreadyPressed[2] != 1 && alreadyPressed[3] != 1) {

      
      score1 = score1 + state;
      state = state - 1;
      alreadyPressed
  • = 1;

        x = x + 1;
        digitalWrite(13, HIGH);
        delay(1000);
      digitalWrite(13, LOW);
 
  }
 
  if (buttonState2 == HIGH && alreadyPressed
  • != 2 && alreadyPressed [1] != 2 && alreadyPressed[2] != 2 && alreadyPressed[3] != 2) {


      score2 = score2 + state;
      state = state - 1;
      alreadyPressed
  • = 2;

      x = x +1;
      Serial.println('Two works!');
      digitalWrite(13, HIGH);
        delay(1000);
      digitalWrite(13, LOW);
  }
 
  if (buttonState3 == HIGH && alreadyPressed
  • != 3 && alreadyPressed [1] != 3 && alreadyPressed[2] != 3 && alreadyPressed[3] != 3) {


      score3 = score3 + state;
      state = state - 1;
      alreadyPressed
  • = 3;

      x = x +1;
      Serial.println('Three works!');
  }
 
 
  if (buttonState4 == HIGH && alreadyPressed
  • != 4 && alreadyPressed [1] != 4 && alreadyPressed[2] != 4 && alreadyPressed[3] != 4) {


      score4 = score4 + state;
      state = state - 1;
      alreadyPressed
  • = 4;

      x = x +1;
      Serial.println('Four works!');
  }
 
  if ( alreadyPressed > 0 ) {
   
   x = 0;
   alreadyPressed[0] = 0;
   alreadyPressed[1] = 0;
   alreadyPressed[2] = 0;
   alreadyPressed[3] = 0;
   state = 3;
   Serial.print('Thank you for voting!');
     
   
  }
 
 
 
 
 // To test if Btn is working
 /*if (buttonState1 == HIGH) {
   
    digitalWrite(13, HIGH);
  } else {
   
    digitalWrite(13, LOW);
  } */
 
 
  delay(10);
}

Robin2

Here's my code, IDK why its not working!!!
To make it easy for people to help you please modify your post and use the code button </>


Code: [Select]
so your code
looks like this
and is easy to copy to a text editor. See How to use the Forum

It will also get rid of the funny symbols.


Separately, if the order in which buttons are pressed is important you need some means to identify when one group of entries is complete so that the next button press can be considered the first of a new group. You can't rely on users ALWAYS doing things correctly for example someone might stop after 3 presses or accidentally make 5 presses.

If you are creating a voting machine for several candidates you should also have an extra button for "none of the above"  :)

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

finola_marsaili

Here's how I did it. It may give you some ideas. There's a state st_voting during which button presses are accepted. The pressed button puts its score into an array in the right slot. Once 4 buttons are pressed (I decided to force the user to explicitly press the 4th button. Scores start as 99 for not pressed, the get a 3,2,1 or 0 in sequence) it goes to state st_voted where you do whatever it is that needs to be done with the results. In that state, it accepts a 5th button to restart, when it sets the scores back to 99 and starts over with no buttons pressed.

The builtin led blinks without delay to prove nothing's blocking.

Here's some output:

Code: [Select]

It's time to vote! Press the buttons....
 
You voted for candidate 2, Score: 3
You voted for candidate 1, Score: 2
   BZZZZZT! You already voted for candidate 2
You voted for candidate 0, Score: 1
   BZZZZZT! You already voted for candidate 1
You voted for candidate 3, Score: 0
You have voted for all 4 candidates. Their scores are 1230
Press the restart button to vote again...
It's time to vote! Press the buttons....



Code: [Select]

// https://forum.arduino.cc/index.php?topic=686090
// 24 may 2020
// voting system
// built-in led blinks with no delay() to prove no blocking
// candidtaes' scores start at 99, you have to explicitly vote for the last candidate
//    scores are in an array 3,2,1,0 so it's easy to change those to say 5,4,2,1 or whatever
// a led comes on for each voted-for candidate
// when all candidates have a vote, you can press restart, and reset to 99

//states
enum {st_voting, st_voted} votingState = st_voting;

// the buttons
struct buttons
{
  byte pin;
  bool state;
  bool prevState;
  byte led;
  byte score;
};
const byte buttonPins[] = {2, 3, 4, 5};
const byte numberOfButtons = sizeof(buttonPins) / sizeof(buttonPins[0]);
buttons mybuttons[numberOfButtons];
const byte leds[] = {8, 9, 10, 11};

byte numberOfVotesCast = 0;
const byte scores[] = {3, 2, 1, 0};

//the pulse led
int pulseLedInterval = 500;
unsigned long previousMillisPulse;
bool pulseState = false;

const byte restartButton = 7;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println("** voting system **");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);

  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  Serial.println(" ");
  Serial.print("Initialising "); Serial.print(numberOfButtons); Serial.println(" pins");
  for (int i = 0; i < numberOfButtons; i++)
  {
    mybuttons[i].pin = buttonPins[i];
    pinMode(mybuttons[i].pin, INPUT_PULLUP);
    mybuttons[i].state = digitalRead(mybuttons[i].pin);
    mybuttons[i].prevState = mybuttons[i].state;
    mybuttons[i].led = leds[i];
    pinMode(mybuttons[i].led, OUTPUT);
    mybuttons[i].score = 99; //shows not voted for
    Serial.print("Candidate: "); Serial.print(i);
    Serial.print(", Button: "); Serial.print(mybuttons[i].pin);
    //Serial.print(", State: "); Serial.print(mybuttons[i].state);
    //Serial.print(", Prev state: "); Serial.print(mybuttons[i].prevState);
    Serial.print(", Led: "); Serial.print(mybuttons[i].led);
    Serial.print(", Score: "); Serial.println(mybuttons[i].score);

  }

  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pulseState);
  Serial.println(" ");

  pinMode(restartButton, INPUT_PULLUP);

  Serial.println("setup() done");
  Serial.println("It's time to vote! Press the buttons....");
  Serial.println(" ");
}

void loop()
{
  manageVoting();
  doPulse();
} //loop

void manageVoting()
{
  switch (votingState) //st_voting, st_voted
  {
    case st_voting:
      checkForButtonPress();
      
      if (numberOfVotesCast == numberOfButtons)
      {
        votingState = st_voted;
        Serial.print("You have voted for all ");
        Serial.print(numberOfButtons);
        Serial.print(" candidates. Their scores are ");
        for (int i = 0; i < numberOfButtons; i++)
        {
          Serial.print(mybuttons[i].score);
        }
        Serial.println("");
        Serial.println("Press the restart button to vote again...");
      }

      break;

    case st_voted:
      if (!digitalRead(restartButton))
      {
        for (int i = 0; i < numberOfButtons; i++)
        {
          mybuttons[i].score = 99;
          digitalWrite(mybuttons[i].led, LOW);
        }
        Serial.println("It's time to vote! Press the buttons....");
        votingState = st_voting;
        numberOfVotesCast = 0;
      }
      break;
  }//switch
}//manageVoting

void checkForButtonPress()
{
  for (int i = 0; i < numberOfButtons; i++)
  {
    mybuttons[i].state = digitalRead(mybuttons[i].pin);
    // compare the buttonState to its previous state
    if (mybuttons[i].state != mybuttons[i].prevState) // means it changed... but which way?
    {
      if (mybuttons[i].state == LOW)  // changed to pressed
      {
        if (mybuttons[i].score == 99)
        {
          mybuttons[i].score = scores[numberOfVotesCast];
          digitalWrite(mybuttons[i].led, HIGH);
          Serial.print("You voted for candidate ");
          Serial.print(i);
          Serial.print(", Score: ");
          Serial.println(mybuttons[i].score);
          numberOfVotesCast++;
        }
        else
        {
          Serial.print("   BZZZZZT! You already voted for candidate ");
          Serial.println(i);

        }
      }

      // poor man's de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    mybuttons[i].prevState = mybuttons[i].state;
  }
} // checkForButtonPress()

void doPulse()
{
  if (millis() - previousMillisPulse >= (unsigned long) pulseLedInterval)
  {
    previousMillisPulse = millis();
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
  }
} //doPulse


MrMagoo1234

Finally got the code working, well basically. Thank you for all your guys' help (also added a reset button and used the Code tag as per your instructions Robin2. thx :) ) After this im gonna make it an RFID based voting system where it confirms that the user only votes once! Probably will ask for help again! Lmao 

Code: [Select]
int buttonState1 = 0;
int buttonState2 = 0;
int buttonState3 = 0;
int buttonState4 = 0;
int buttonState5 = 0;
int score1 = 0;
int score2 = 0;
int score3 = 0;
int score4 = 0;
int alreadyPressed [4];
int state = 3;
int x = 0;
void setup()
{
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  alreadyPressed[0] = 0;
  alreadyPressed[1] = 0;
  alreadyPressed[2] = 0;
  alreadyPressed[3] = 0;
}

void loop()
{
 
  buttonState1 = digitalRead(2);
  buttonState2 = digitalRead(3);
  buttonState3 = digitalRead(4);
  buttonState4 = digitalRead(5);
  buttonState5 = digitalRead(6);
 
 /*if (buttonState1 == HIGH && alreadyPressed [0] != 1 && alreadyPressed [1] != 1 && alreadyPressed[2] != 1 && alreadyPressed[3] != 1) {
   
      score1 = score1 + state;
      state = state - 1;
      alreadyPressed[x] = 1;
      x = x + 1;
      digitalWrite(13, HIGH);
      delay(1000);
      digitalWrite(13, LOW);
 
  } */
 
  if (buttonState1 == HIGH) {
    if (alreadyPressed[0] != 1) {
      if (alreadyPressed[1] != 1) {
        if (alreadyPressed [2] != 1) {
          if (alreadyPressed [3] != 1) {
            score1 = score1 + state;
      state = state - 1;
      alreadyPressed[x] = 1;
      x = x + 1;
    digitalWrite(13, HIGH);
      delay(1000);
      digitalWrite(13, LOW);
          }
        }
      }
    }
  }
 
  if (buttonState2 == HIGH) {
    if (alreadyPressed[0] != 2) {
      if (alreadyPressed[1] != 2) {
        if (alreadyPressed [2] != 2) {
          if (alreadyPressed [3] != 2) {
            score2 = score2 + state;
      state = state - 1;
      alreadyPressed[x] = 2;
      x = x + 1;
    digitalWrite(13, HIGH);
      delay(1000);
      digitalWrite(13, LOW);
          }
        }
      }
    }
  }
 
    if (buttonState3 == HIGH) {
    if (alreadyPressed[0] != 3) {
      if (alreadyPressed[1] != 3) {
        if (alreadyPressed [2] != 3) {
          if (alreadyPressed [3] != 3) {
            score3 = score3 + state;
      state = state - 1;
      alreadyPressed[x] = 3;
      x = x + 1;
    digitalWrite(13, HIGH);
      delay(1000);
      digitalWrite(13, LOW);
          }
        }
      }
    }
  }
 
    if (buttonState4 == HIGH) {
    if (alreadyPressed[0] != 4) {
      if (alreadyPressed[1] != 4) {
        if (alreadyPressed [2] != 4) {
          if (alreadyPressed [3] != 4) {
            score4 = score4 + state;
      state = state - 1;
      alreadyPressed[x] = 4;
      x = x + 1;
    digitalWrite(13, HIGH);
      delay(1000);
      digitalWrite(13, LOW);
          }
        }
      }
    }
  }
 
    if (buttonState5 == HIGH) {
    if (alreadyPressed[0]  > 0) {
      if (alreadyPressed[1] > 0) {
        if (alreadyPressed [2] > 0) {
          if (alreadyPressed [3] > 0) {
            x = 0;
            state = 3;
            alreadyPressed[0] = 0;
  alreadyPressed[1] = 0;
            alreadyPressed[2] = 0;
  alreadyPressed[3] = 0;
          }
        }
      }
    }
  }
 
   delay(10);
}

Robin2

Finally got the code working, well basically.
It would be a major PITA to extend your system to a larger number of candidates. Have you looked at how it is done in the code in Reply #7 ?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up