Arduino Seven-Segment Display Multiplexing: State Machine Implementation

Multiplexed Seven-Segment LED Display for Arduino Nano

Multiplexed Seven-Segment LED Display for Arduino Nano

Before continuing to the software implementation of the 7-segment display multiplexing, check out the multiplexed display hardware here and the programming model of  state machine class in a cooperative multitasking system here in case you’ve missed the basic.  To implement the cooperative state machine model, first we need to select a proper run interval.  A 5 milliseconds run interval is sufficient to give a simple switching delay between one digit to the next digit of the displays without adding a “wait state” in the machine. It means that all 3 digits will be periodically updated every 15 milliseconds or equivalent to about 66 frames per second for smooth appearance, so there should be no perceptible flickering effect at this high frame rate. Here is the snippet code:

class statemachine
{
  protected:
    virtual void run(){};
    unsigned long runInterval;
    unsigned long lastRun;
    int state;
    
  public:
    statemachine(unsigned long run_interval) //the  constructor
    {
        runInterval = run_interval;
        lastRun = millis();
        state = 0;
    }
    void execute() //the periodically called cooperative function
    {
    	unsigned long currentMillis = millis();
    	if((currentMillis - lastRun) < runInterval)
    		return;
    	lastRun = currentMillis;
    	run(); //the protected function that should be implemented by the 
    }
    virtual void setup(){}
};

#define digit0Pin 11
#define digit1Pin 12
#define digit2Pin 13
const byte segmentPin[]= {4,5,6,7,8,9,10};
const byte segmentPattern[10][7]={{ 1,1,1,1,1,1,0 },  // = 0
                                 { 0,1,1,0,0,0,0 },  // = 1
                                 { 1,1,0,1,1,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,1,0,1,1 }   // = 9
                                };
class displaymux:public statemachine
{    
  protected:
    enum states{digit0,digit1,digit2};
    byte val; //the value of a single digit
    byte remainder;
    void writeSegments()
    {
      for(int i=0;i<7;i++)
      {
        digitalWrite(segmentPin[i],segmentPattern[val][i]);
      }
    }
    void run()
    {
        switch(state)
        {
          case digit2:
          { 
            val = value/100;
            remainder = value%100;
            digitalWrite(digit0Pin,1); //deactivate previous segment
            writeSegments();
            digitalWrite(digit2Pin,0);
            digitalWrite(digit1Pin,1);
            state = digit1;
            break;
          }
          case digit1:
          {
            val = remainder/10;
            remainder = remainder%10;
            digitalWrite(digit2Pin,1); //deactivate previous segment
            writeSegments();
            digitalWrite(digit1Pin,0);
            digitalWrite(digit0Pin,1);
            state = digit0;
            break;
          }  
          case digit0:
          {
            val = remainder;
            digitalWrite(digit1Pin,1); //deactivate previous segment
            writeSegments();
            digitalWrite(digit2Pin,1);
            digitalWrite(digit0Pin,0);
            state = digit2;
            break;
          }        
        }
    }
  public:
    displaymux():statemachine(5){} //set the run interval in the constructor
    int value; //provide a public variable for external machine interface
    void setup()
    {
      state = digit2;
      pinMode(digit0Pin,OUTPUT);
      pinMode(digit1Pin,OUTPUT);
      pinMode(digit2Pin,OUTPUT);
      for(int i=0;i<7;i++)
      {
         pinMode(segmentPin[i],OUTPUT); 
      }
    }
};
displaymux DisplayMux;

void setup()
{
  DisplayMux.setup();
}

void loop()
{
  DisplayMux.execute();
}

//end of code

To test the code, now a state machine of a simple counter is added. The counter will be initialized with zero value, then will be incremented every 0.1 seconds (100 milliseconds). The counter rolls back to zero after it reach 999. Here is the testing code:

class statemachine
{
  protected:
    virtual void run(){};
    unsigned long runInterval;
    unsigned long lastRun;
    int state;
    
  public:
    statemachine(unsigned long run_interval) //the  constructor
    {
        runInterval = run_interval;
        lastRun = millis();
        state = 0;
    }
    void execute() //the periodically called cooperative function
    {
    	unsigned long currentMillis = millis();
    	if((currentMillis - lastRun) < runInterval)
    		return;
    	lastRun = currentMillis;
    	run(); //the protected function that should be implemented by the 
    }
    virtual void setup(){}
};

#define digit0Pin 11
#define digit1Pin 12
#define digit2Pin 13
const byte segmentPin[]= {4,5,6,7,8,9,10};
const byte segmentPattern[10][7]={{ 1,1,1,1,1,1,0 },  // = 0
                                 { 0,1,1,0,0,0,0 },  // = 1
                                 { 1,1,0,1,1,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,1,0,1,1 }   // = 9
                                };
class displaymux:public statemachine
{    
  protected:
    enum states{digit0,digit1,digit2};
    byte val; //the value of a single digit
    byte remainder;
    void writeSegments()
    {
      for(int i=0;i<7;i++)
      {
        digitalWrite(segmentPin[i],segmentPattern[val][i]);
      }
    }
    void run()
    {
        switch(state)
        {
          case digit2:
          { 
            val = value/100;
            remainder = value%100;
            digitalWrite(digit0Pin,1); //deactivate previous segment
            writeSegments();
            digitalWrite(digit2Pin,0);
            digitalWrite(digit1Pin,1);
            state = digit1;
            break;
          }
          case digit1:
          {
            val = remainder/10;
            remainder = remainder%10;
            digitalWrite(digit2Pin,1); //deactivate previous segment
            writeSegments();
            digitalWrite(digit1Pin,0);
            digitalWrite(digit0Pin,1);
            state = digit0;
            break;
          }  
          case digit0:
          {
            val = remainder;
            digitalWrite(digit1Pin,1); //deactivate previous segment
            writeSegments();
            digitalWrite(digit2Pin,1);
            digitalWrite(digit0Pin,0);
            state = digit2;
            break;
          }        
        }
    }
  public:
    displaymux():statemachine(5){} //set the run interval in the constructor
    int value; //provide a public variable for external machine interface
    void setup()
    {
      state = digit2;
      pinMode(digit0Pin,OUTPUT);
      pinMode(digit1Pin,OUTPUT);
      pinMode(digit2Pin,OUTPUT);
      for(int i=0;i<7;i++)
      {
         pinMode(segmentPin[i],OUTPUT); 
      }
    }
};
displaymux DisplayMux;

class counter:public statemachine
{
  protected:
    enum states{theOnlyOne};
    int count;
    void run()
    {
        switch(state)
        {
          case theOnlyOne:
          {
             count++;
             if(count>999) 
               count=0;
             DisplayMux.value = count;
             break;
          }
        }
    }
    
  public:
    counter():statemachine(100){} //set the run interval in the constructor
    void setup()
    {
      state = theOnlyOne;
      count = 0;
    }
};
counter Counter;

void setup()
{
  DisplayMux.setup();
  Counter.setup();
}
void loop()
{
  DisplayMux.execute();
  Counter.execute();
}

//end of code

The the running program can be seen on the following Youtube’s video:

Back to the main topic:

Digital Soldering Station: An Integrated Hardware and Software Designing Case Study

 

Leave a comment

Your email address will not be published.

*



five + = 7