Electrical – Detecting Switch input in ARM 7 and multiplexing two seven segment displays

7segmentdisplayarmarm7microcontrollerswitches

I am trying to multiplex two seven segment displays, once a switch input is detected.

  1. If a switch is pressed then the seven segment displays should show 1
  2. If pressed again, 2, then 3 and so on.

My problem arises when I reach number 9 since the next switch input will show 10. 1 on the first SSD and 0 on the second SSD. Below is a snippet of my code with regards to how I am detecting inputs from 1 – 9.

   int k = 0;
   unsigned int SW1;

   PINSEL0 = 0;                             //Set P0.0 - P0.15 as GPIOS
   PINSEL1 = 0;                             //Set P0.16 - P0.31 as GPIOS
   IO0DIR  = 0xFFFFF9FF;                //Setting  P0.9 as input for SW1     

    while (1)
   {

    SW1 = IO0PIN & 0x00000200; //switch connected on P0.9
    if ( SW1 != 0x00000200 )  //when pressed        
      {
        k++;                
        IO0SET = T1;
        IO0SET = T2;

        if (k == 1){
        IO0SET = T1;               //switching on left seven segment display
        IO0CLR = T2;               //clearing the right seven segment display 
        IO0CLR = a;
        IO0SET = b;
        IO0SET = c;
        IO0CLR = d;             
        IO0CLR = g;                //displaying number 1
        IO0CLR = e;
        IO0CLR = f;
        small_delay();
        }       
       }

I am following the same structure for the 10th switch press:

        else if (k == 10){ 
        IO0CLR = 0x000000FF;        //turn off all the segments as well as both common anodes. Then your outputs will be ready for the new segment patterns to be set up.
        IO0SET = T2;                //switching on first display                            
        IO0SET = b;                     
        IO0SET = c;                 //displaying number 1         
        small_delay();              //calling short delay           
        IO0CLR = 0x000001FF;        

        IO0SET = a;
        IO0SET = b;
        IO0SET = c;             
        IO0SET = d;                 //displaying number 0
        IO0SET = e;
        IO0SET = f;
        IO0SET = T1;    
        small_delay();
        IO0CLR = 0x000000FF;}

The problem with the second code I provide is that the seven segment display only displays 10 once. That is, first 1 is shown on the left display and then 0 on the second display as required, however this is performed only once and does not go on until the next switch input is detected.

One solution this problem which I have come up with is that I included a while statement after the if else such that:

    else if (k == 10){
        while (k == 10) {   //rest of code

This actually does what I want it to do, and keeps multiplexing both seven segments, showing number 10, however the problem in this case is that it does not step out of the while loop to accommodate for the next switch input.

How can I multiplex both displays until the next switch input is detected? Any ideas/suggestions would be greatly appreciated.

Best Answer

Two options:

The correct way to do this would be that your counting code just counts, it doesn't set the display it sets a variable. You then have code running on a timer interrupt that reads the count variable and displays the number. If the number is over 9 then this timer can switch between digits as needed.

The second way is to only set one digit each time through your loop

int digitToDisplay = 0; // track which digit we need to display next
while (true) {          // loop forever 
  if (buttonPress())      // count button presses
    count++;

  // no need to do this every time, could be only when count changes but I'm being lazy
  int topDigit = count / 10;       // split value into separate digits.
  int bottomDigit = count % 10;      

  setDisplayOff();                // avoid glitches by turning all LED pins off

  displaySelect(digitToDisplay);  // select the display digit to drive
  if (digitToDisplay == 0)         
    setDisplay(bottomDigit);      // set the pins to display a number
  else
    setDisplay(topDigit);

  if (++digitToDisplay == 2)      // next time we display the other digit
    digitToDisplay = 0;
}

I've assumed a few functions, bool buttonPress(void) which returns tru if the button has been pressed, void setDisplay(int value) which sets the correct IO pins active to display the given value from 0 to 9 and void setDisplayOff(void) which turns off all the leds.
By setting the IO lines in a separate function you keep the big messy switch command (or if...else if...else if...) away from your core logic, this makes the logic a lot easier to follow since it now all fits on the screen at the same time.

Update -
Just in case your dislike of functions and switch commands is due to a lack of familiarity with using them here are the function definitions. These either need to go before main() or you need to declare them in advance and then put the code after main(). I also moved the display select into a function so that all of the IO is out of the main code.
You'd need to fill in the remaining values of the switch but it should be fairly obvious how.

void setDisplay(int value) {
  IO0CLR = 0x000000FF; // all pins low (probably redundant but best to be safe.)
  switch (value) {
    default:
        // outside the allowed range. Ignore it. (or display an E I suppose)
      break;
    case 0:
      IO0SET = a;
      IO0SET = b;
      IO0SET = c;             
      IO0SET = d; 
      IO0SET = e;
      IO0SET = f;
      break;
    case 1:
      IO0SET = b;                     
      IO0SET = c;
      break;
    case 2:
      IO0SET = a;
      IO0SET = b;
      IO0SET = d; 
      IO0SET = e;
      IO0SET = g;
      break;
    }
}

void displaySelect(int digitToDisplay) {
  if (digitToDisplay == 0) { // right hand digit
    IO0CLR = T1;  // always clear first.
    IO0SET = T2;           
  } else {
    IO0CLR = T2;  // always clear first.
    IO0SET = T1;           
  }
}


void setDisplayOff(void) {
  IO0CLR = 0x000000FF;
}


// detect button press with basic de-bouncing
// button must have been down exactly 5 calls to this function to return true.

int buttonPress(void) {
  static int downCount= 0; // static = value isn't lost between calls.
  //switch connected on P0.9
  int currentButton = ((IO0PIN & 0x00000200) == 0x00000200); 

  if (currentButton) { // button is down
    if (downCount == 5) { // button has been down for 5 counts
        downCount++;      // increase the count so we don't trigger next time
        return 1;
    } else {              // some count other than 5
      if (downCount < 5)  // increase if it's less than 5
         downCount++;
    }
  } else  // button is up
    downCount=0; 

  return 0;
}