0

I am trying to program a basic counter using 7segment display and a button. What I am trying to achieve is the following:

  1. Display 0 at the beginning.
  2. When the button is pressed: Start Loop 0-9
  3. Display 0 when the button is pressed the second time.

So basically the button should function as ON/OFF switch for the looping numbers function.

So far I have managed to change the mode from displaying 0 to looping 0-9, but can't seem to get changing the mode back to displaying 0:

int buttonPin = 10; // Button connected to digital pin 10.
// variable for reading the pushbutton status
boolean buttonPressed = false;
int mode;

void setup() {
    // initialize the pushbutton pin as an input:
    pinMode(buttonPin, INPUT);

    pinMode(1, OUTPUT); 
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT); 
    pinMode(4, OUTPUT); 
    pinMode(5, OUTPUT); 
    pinMode(6, OUTPUT); 
    pinMode(7, OUTPUT); 
    pinMode(8, OUTPUT); 
    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(13, OUTPUT);
}

void displayZero() {
    //while (buttonState == true){
    // Displays 0.
    digitalWrite(11,1);
    //button();
    delay(1000);
    //}
}

void displayCounter() {
    // Displays 0.
    digitalWrite(4,1);
    digitalWrite(11,1);
    delay(1000);

    //Displays 1.
    digitalWrite(2,1);
    digitalWrite(3,1);
    digitalWrite(4,1);
    digitalWrite(8,1);
    delay(1000);

    //Displays 2.
    digitalWrite(2,0);
    digitalWrite(8,0);
    digitalWrite(6,0);
    digitalWrite(4,0);
    digitalWrite(9,1);
    digitalWrite(3,1);
    digitalWrite(11,0);
    delay(1000);

    //Displays 3.
    digitalWrite(4,1);
    digitalWrite(9,0);
    digitalWrite(11,0);
    delay(1000);

    //Displays 4.
    digitalWrite(2,1);
    digitalWrite(8,1);
    digitalWrite(3,0);
    delay(1000);

    //Displays 5.
    digitalWrite(6,1);
    digitalWrite(2,0);
    digitalWrite(8,0);
    digitalWrite(11,0);
    delay(1000);

    //Displays 6.
    digitalWrite(4,0);
    delay(1000);

    //Displays 7.
    digitalWrite(3,1);
    digitalWrite(4,1);
    digitalWrite(6,0);
    digitalWrite(8,1);
    digitalWrite(11,1);
    delay(1000);

    //Displays 8.
    digitalWrite(3,0);
    digitalWrite(4,0);
    digitalWrite(8,0);
    digitalWrite(11,0);
    delay(1000);

    //Displays 9.
    digitalWrite(4,1);
    //button();
    delay(1000);
}

void loop() {
    // Check button status.
    int buttonStatus = digitalRead(buttonPin);

    if (buttonStatus == HIGH)
    {
        // Checks if button is pressed and changes buttonPressed from false to true.
        buttonPressed = true;

        // While button is pressed.
        while(buttonPressed == true) {
            // Calls displayCounter method 10 times.
            for (int i=0; i<10; i++) {  
                displayCounter();
                delay(30);
                buttonPressed == false;
            }
        }
    }
    else if (buttonStatus == LOW) 
        displayZero();
}
  • You try to set pin 10 in INPUT then OUTPUT mode, hence it will not receive any input from your button. Also, based on your circuit, you may need to use INPUT_PULLUP instead of mere INPUT, otherwise you may have a dangling input signal. – jfpoilpret Oct 9 '16 at 20:45
3

In your loop() function, the statement buttonPressed == false; doesn't do anything; it is simply an expression that evaluates to 0 or false (because buttonPressed is equal to true). Your while() loop will never end which is why you can't stop the counter by pressing the button again.

You probably meant buttonPressed = false;, which is an assignment statement setting the value of buttonPressed. But doing that within the while loop makes the loop contents iterate once which it would do anyway, so there is no need for the surrounding while statement. The for() statement will still be executed once, without the while (the loop contents will be iterated 10 times in that one execution).

So you can reduce your loop() function to:

void loop() {

// Check button status.
   int buttonStatus = digitalRead(buttonPin);


   if (buttonStatus == HIGH)
   {
      // Calls displayCounter method 10 times.
      for (int i=0; i<10; i++){  
         displayCounter();
         delay(30);
      }
   }
   else
      displayZero();
}

which will check the button state on each call to loop() and either run the counter or zero it, once, depending on the state.

You'll need another refinement, that of debouncing the button. Push buttons (and some other kinds of switches don't have a clean 0 -> 1 (or vice versa) transition but take some amount of time during which their state appears to bounce between 0 and 1 before finally settling to the new state. Read Nick Gammon's excellent article about contact bounce to see why and what to do about it.

1

Not sure but this should work

const int segment[7] = {2,3,4,5,6,7,8}; //pins for each segment

const int nums[10][7] = //declaring array
{
  {1,1,1,1,1,1,0}, //0
  {0,1,1,0,0,0,0}, //1
  {1,1,0,1,0,0,1}, //2
  {1,1,1,1,0,0,1}, //3
  {0,1,1,0,0,1,1}, //4
  {1,0,1,1,0,1,1}, //5
  {1,0,1,1,1,1,1}, //6
  {1,1,1,0,0,0,0}, //7
  {1,1,1,1,1,1,1}, //8
  {1,1,1,0,0,1,1}  //9
};

//=======================================================================

#define button 9 //defining button that is connected to pin 9

//=======================================================================

void setup() {
  for(int i=2; i<=8; i++) //shorcut for declaring a buch of pin modes
  {
    pinMode(i, OUTPUT);
  }

  pinMode(button, INPUT); //set button as an input
}

//=======================================================================

void loop() {
  while(digitalRead(button) == LOW) //wait until user click the button
  {
    number(0); //display 0 when waiting
  }

  bool state = false; // create a status varible

  for(int i=0; i<10 && state == false; i++) //run the numbers from 0-9
  {

    number(i); //display the number

    for(int j=0; j<100 && state == false; j++)
    {

      if(digitalRead(button) == HIGH) //if the button is clicked, then cancel the loop ans go back to displaying 0
      {
        state = true;
      }

      delay(10); //this delay while execute a 1000 times so there is actualy a 1sec delay

    }
  }
}

//=======================================================================

void number(int num) //num is the number to display
{
  for(int i=0; i<7; i++)
  {
    digitalWrite(segment[i], nums[num][i]);
  }
}
  • Good starting answer, however there are few problems - you are displaying the current number 1000 times. This is not needed and takes a lot of time too. The call to number(i) should be just before the 'j' loop. Also you don't need millisecond granularity so the 'j' loop could be 0 to 10 and the delay could be 100 ms (or slightly less to adjust for the execution time of the extra commands). The user will probably not notice the difference, but then the timing would be closer to 1 second. – rslite Oct 9 '16 at 18:41
  • done, still prefer to have the delay low for better input resolution. espacially if he clicks fast. 100 ms is a liitle too much. also tried to keep it simple and not use any ISRs – Dat Ha Oct 9 '16 at 18:44
  • Only one more thing - since you are iterating 100 times the digitalRead will be called 100 times - this will introduce extra delay so the numbers are going to be displayed more than one second. This could probably be adjusted in real life by timing and decreasing the loop maximum from 100, or decreasing the delay(10) accordingly. – rslite Oct 9 '16 at 19:11
  • Thanks for the answer, howeverm I didn't get it to work with my breadboard coupling. The way I have set my wires and display is, instead of turning the LEDs ON, it turns all the other LEDs OFF to display a certain number. – Daniel Oct 9 '16 at 19:13
  • Apart from apparent issues in the details, the approach of using a lookup table here is far more sound than what Daniel was trying to do. However, it looks like Daniel has a common anode display (drive segment low to illuminate), while this assumes common cathode (drive segment high). Therefore, Daniel either needs to swap the 1's and 0's in the table, or change the output line to use the opposite of the table contents, ie !nums[num][i] – Chris Stratton Oct 9 '16 at 19:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.