About Me

My photo
They never fall who never climb.

022 SEVEN-SEGMENT LED DISPLAY - SINGLE DIGIT


022 SEVEN-SEGMENT LED DISPLAY - SINGLE DIGIT

April 1, 2011    (See also Companion Blog )
[Go BACK to Table of Contents] [ Next Experiment ] [ Last Experiment ]

Goal:
To operate a seven-segment LED lamp from the Arduino without resorted to a factory-made IC (integrated circuit) chip. This involves plenty of theory, which I will supply here.


The seven-segment LED lamps were common in the 1970s and used in early calculators and watches. They are very power-hungry and used a lot of batteries, but they could be read in a dark room. They have largely been superseded by LCD which conserve power, but are hard to read except in ideal conditions.

The arrangement of the LEDs in seven segments is the most basic needed to display digits 0 through 9, but by mixing case and capital letters, they will display hex digits. I don’t bother with hex. I feel that using an IC chip is taking shortcuts, akin to cheating, since doing so does not contribute to the basic understanding that I am after.

After constructing a 3x3 LED dot matrix from scratch (see Experiment 018), the seven-segment lamp seemed straightforward enough to eliminate the IC and try to operate the device with commands from the Arduino.

Here is the planning diagram I drew while figuring out the pins. Just remember, as long as you create a match between the lamp pins and the Arduino pins, the rest is easy. I did not test the decimal point, I used the Arduino pins 3 through 9, avoiding any pins known to have weird operating characteristics (like pins 1, 2, and 13).


To keep better organized, I named the pins after the segments they represent on the lamp and “drew” the numbers in the same way they are normally written. For instance, most people begin writing the number 6 with a downstroke. Examine the code, you’ll get it.

If not, here is the diagram. I’m finding the automated “Fritzing” software isn’t the best for anything but the easiest circuits. The LED diode power comes from the 5V Arduino pins, although this is only possible for circuits with low power requirements.



Theory:
According to the packaging, the pins on the seven-segment LED lamp will accept up to 20 milliamps. Therefore, a 470Ω resistor should allow safe operation. The trick must be to match the Arduino pins up to the lamp pins in the correct configuration.

The lamp is a “common cathode” which Experiment 018 taught us was needed for efficient operation. It also tips us off that groups of these seven segment LED lamps must require multiplexing, as the number of input pins on the device exceeds the number of output pins normally available. The Arduino has 14 output pins, not all of them useable for every purpose.

Next, the code should be no more complicated than turning the correct pins “HIGH”, allowing current to flow and lighting the diodes in exactly the same fashion as a dot matrix display. That means flashing them on an off so fast that they are perceived as being on as a unit.

The common ground means I only have to operate the positive leads, which means only seven Arduino pins. I can do that. If all goes correctly, this may be a simpler version of what I’ve already done with my 3x3 (Experiment 018). I’m not using any transistors in the circuit as I have resistors that can regulate the voltage to the lamp diodes. The labor involved is easy to underestimate, these matrix designs take time.

Practice:
Success, with reservations. The first thing to be aware of is that the components used are rarely compatible. The lamp is a fourteen pin arrangement with only ten of the pins present. I used eight of them, seven for the segments and one ground for the common cathode. I ignored the pin labeled RHDP since it was not explained. (Later, I call it the Right Hand Decimal Point, but that’s a guess)

The next layer of incompatibility is the pins are numbered counter-clockwise, while the diode segments are the opposite, labeled a through g. Even then, the pin pattern is not in alphabetical order. I won’t describe this detail, I’ll let you encounter the problem on your own.

The key was always keeping organized enough and lining up the wiring steps so that each layer was compatible. Shown here is the finished product displaying the number 3. Almost any interruption caused me to have to go back and redo the previous step. The green jumpers on the left is the leads to the resistors, which straddle the board gap near the bottom (hard to see) which are in turn connected by red jumpers to the Arduino pins.

Initially, I had only five of the correct 470Ω resistors, so I was restricted to five segment numbers of which I chose 1, 3, and 7. I wanted to make these numbers flash, since we learned that “turning the light off” is equally important in a display. I also used a loop to call the subroutines to eliminate the need for repetitious code in the main loop. If this is not easy to visualize, don’t take it to heart for I am an old programming hand.

Later, when I purchased more resistors, I expanded the code to include all nine digits. To keep the code manageable, I used a main loop to call the matching subroutines. This means I could keep the subroutines in logical ascending order and do the “spelling” by arranging the calls to the subroutines. This code arrangement is more efficient in the long run, so examine it closely if the logic is not clear.

One surprise is that I required two delay commands. I wanted each digit to flash three times, then the next digit, and so on. Thus, I programmed a delay between the flashes but not between the change of digit. Again, to conserve code, I put the delays where they actually occurred rather my usual “least code” method. One is in the display loop, the other in each subroutine call.

The first results were perplexing until I realized my wiring was better on the Arduino end than the component end. This is where I found the lamp pins are not alphabetical. But within minutes, the numbers were flashing away in the correct pattern.

Here’s an easy to overlook detail. In the code, I specifically turned all the desired segments on, and then off. It turns out I could probably have added a transistor switch to the circuit and opened the ground lead to accomplish the same thing. I did not test that option. But my thinking was that if I did it that way and the ground was reconnected, it would display the last digit, whereas mine method would display a blank and leave the ground alone. I can think of advantages to both.

One item not tested were the decimal points. That’s plural, as two of the points are included on the lamp, to the left and right of the display diodes. As pointed out in my blog, the LED display is slanted to the right as in italics. The purpose of this is because it makes the digits more easily readable.

Conclusion:
These LED lamps must have been a quantum leap for electronics in the 1970s. Although no longer made, I suspect they still exist in the millions as I picked mine up for $2.00 at the Shack. They are available in more segments, up to 14 to display the entire alphanumeric range. They cannot be beat of high visibility, but they eat batteries. Make sure you have a power supply if you leave the experiment running.

I was fortunate to discover several nice built-in features of the lamp, including a predictable default behavior. Still, I included hard code to dictate every operation, both on and off modes, to be on the safe side. The C language always makes this far more difficult than need be, and I was held up for twenty minutes by a missing semi-colon.

At this time, I cannot even fathom the code needed to operate two lamps to display digits up to 99. This experiment was almost trivial, in that most of the challenge was keeping the pins matched, and hint, do that in advance or your code will get pretty complicated in a hurry if you do not. Note the package instructions give no hint as to how to cascade or “daisychain” more than one of the LED lamps.

Also noted was that the LED lamp fits across a standard breadboard gap, which means two lamps cannot be placed side by side for display. I do not know how to get around this yet. I have seen diagrams purporting to do this, but the diagrams must be wrong.

Here is the code.

/**************************************************************************/
/* This is an LED dot matrix experiment
 * It matches Experiment 022 in the Minutes
 * This experiment is to light the Arabic digits 0-9
 * on a seven-segment LED lamp without using an integrated
 * circuit.
 * Today is April 18, 2011
 */
 
////////////////////////////////////////////////////////////////////////////
//Begin Initialization & Variables
int SegmentA = 9; //Assign pins to the corresponding LED Segments
int SegmentB = 8; //There are 7 segments, called A thru G
int SegmentC = 7; //on the LED design.
int SegmentD = 6; //
int SegmentE = 5; //
int SegmentF = 4; //
int SegmentG = 3; //
int vDelay = 500; //To adjust the ON/OFF intervals
int vFlashCounter = 1; //Number of flashes during each call.
//End Initialization & Variables
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Begin Main Program
////////////////////////////////////////////////////////////////////////////
void setup()
{
  pinMode(SegmentA, OUTPUT); //all pins used in this sketch are outputs
  pinMode(SegmentB, OUTPUT); //do not neglect these commands, as all pins on
  pinMode(SegmentC, OUTPUT); //on the Arduino default to INPUTs
  pinMode(SegmentD, OUTPUT);
  pinMode(SegmentE, OUTPUT);
  pinMode(SegmentF, OUTPUT);
  pinMode(SegmentG, OUTPUT);
}
//-----------------------------------------------------------------------
void loop()
//This loop calls the subroutines repeatedly to keep the LEDS lit.
//Make sure you follow this logic completely before continuing.
//Do you understand why two delays are necessary?  One in the mail loop
//and another in the subroutines.
{  //Begin loop
//-----------------------------------------------------------------------
     for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralZERO();   //calls the segments that displays "0"
    delay(vDelay);
  }   
//----------------------------------------------------------------------- 
     for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralNINE();   //calls the segments that displays "9"
    delay(vDelay);
  }   
//-----------------------------------------------------------------------
     for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralEIGHT();   //calls the segments that displays "8"
    delay(vDelay);
  }   
//-----------------------------------------------------------------------
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralSEVEN();   //calls the segments that displays "7"
    delay(vDelay);
  }
//-----------------------------------------------------------------------
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralSIX();     //calls the segments that displays "6"
    delay(vDelay);
  }
//-----------------------------------------------------------------------
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralFIVE();    //calls the segments that displays "5"
    delay(vDelay);
  }
//-----------------------------------------------------------------------
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralFOUR();    //calls the segments that displays "4"
    delay(vDelay);
  }
//-----------------------------------------------------------------------
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralTHREE();   //calls the segments that displays "3"
    delay(vDelay);
  }   
//----------------------------------------------------------------------- 
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralTWO();     //calls the segments that displays "2"
    delay(vDelay);
  }   
//-----------------------------------------------------------------------
    for (int i = 0; i < vFlashCounter; i = i + 1)
  {
    subNumeralONE();     //calls the segments that displays "1"
    delay(vDelay);
  }
//-----------------------------------------------------------------------
}  //End loop
//----------------------------------------------------------------------- 
//  SUBROUTINES
//-----------------------------------------------------------------------
void subNumeralZERO() //Displays segments representing number "0".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentC, HIGH); //
  digitalWrite(SegmentD, HIGH);
  digitalWrite(SegmentE, HIGH);
  digitalWrite(SegmentF, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentB, LOW); //
  digitalWrite(SegmentC, LOW); //
  digitalWrite(SegmentD, LOW);
  digitalWrite(SegmentE, LOW);
  digitalWrite(SegmentF, LOW);
}    //End subNumeralZERO
//-----------------------------------------------------------------------
void subNumeralONE() //Displays segments representing number "1".
{
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentC, HIGH); //
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentB, LOW);
  digitalWrite(SegmentC, LOW); // Turn segments off
}    //End subNumeralONE
//----------------------------------------------------------------------- 
void subNumeralTWO() //Displays segments representing number "2".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentG, HIGH); //
  digitalWrite(SegmentE, HIGH);
  digitalWrite(SegmentD, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentB, LOW); //
  digitalWrite(SegmentG, LOW); //
  digitalWrite(SegmentE, LOW);
  digitalWrite(SegmentD, LOW);
}    //End subNumeralTWO
//----------------------------------------------------------------------- 
void subNumeralTHREE() //Displays segments representing number "3".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentC, HIGH); //
  digitalWrite(SegmentD, HIGH);
  digitalWrite(SegmentG, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentB, LOW); //
  digitalWrite(SegmentC, LOW); //
  digitalWrite(SegmentD, LOW);
  digitalWrite(SegmentG, LOW);
}    //End subNumeralTHREE
//----------------------------------------------------------------------
void subNumeralFOUR() //Displays segments representing number "4".
{
  digitalWrite(SegmentF, HIGH);
  digitalWrite(SegmentG, HIGH); //
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentC, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentF, LOW);
  digitalWrite(SegmentG, LOW); //
  digitalWrite(SegmentB, LOW); //
  digitalWrite(SegmentC, LOW);
}    //End subNumeralFOUR
//-----------------------------------------------------------------------
void subNumeralFIVE() //Displays segments representing number "5".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentF, HIGH); //
  digitalWrite(SegmentG, HIGH); //
  digitalWrite(SegmentC, HIGH);
  digitalWrite(SegmentD, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentF, LOW); //
  digitalWrite(SegmentG, LOW); //
  digitalWrite(SegmentC, LOW);
  digitalWrite(SegmentD, LOW);
}    //End subNumeralFIVE
//-----------------------------------------------------------------------
void subNumeralSIX() //Displays segments representing number "6".
{
  digitalWrite(SegmentF, HIGH);
  digitalWrite(SegmentE, HIGH); //
  digitalWrite(SegmentD, HIGH); //
  digitalWrite(SegmentC, HIGH);
  digitalWrite(SegmentG, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentF, LOW);
  digitalWrite(SegmentE, LOW); //
  digitalWrite(SegmentD, LOW); //
  digitalWrite(SegmentC, LOW);
  digitalWrite(SegmentG, LOW);
}    //End subNumeralSIX
//-----------------------------------------------------------------------
void subNumeralSEVEN() //Displays segments representing number "7".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentC, HIGH); //
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentB, LOW); //
}    //End subNumeralSEVEN
//-----------------------------------------------------------------------
void subNumeralEIGHT() //Displays segments representing number "8".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentB, HIGH); //
  digitalWrite(SegmentC, HIGH); //
  digitalWrite(SegmentD, HIGH);
  digitalWrite(SegmentE, HIGH);
  digitalWrite(SegmentF, HIGH);
  digitalWrite(SegmentG, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentB, LOW); //
  digitalWrite(SegmentC, LOW); //
  digitalWrite(SegmentD, LOW);
  digitalWrite(SegmentE, LOW);
  digitalWrite(SegmentF, LOW);
  digitalWrite(SegmentG, LOW);
}    //End subNumeralEIGHT
//-----------------------------------------------------------------------
void subNumeralNINE() //Displays segments representing number "9".
{
  digitalWrite(SegmentA, HIGH);
  digitalWrite(SegmentF, HIGH); //
  digitalWrite(SegmentG, HIGH); //
  digitalWrite(SegmentB, HIGH);
  digitalWrite(SegmentC, HIGH);
  delay(vDelay); // Remain lit for one second
  digitalWrite(SegmentA, LOW);
  digitalWrite(SegmentF, LOW); //
  digitalWrite(SegmentB, LOW);
  digitalWrite(SegmentC, LOW);
}    //End subNumeralNINE
//-----------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////
// END MAIN PROGRAM
////////////////////////////////////////////////////////////////////////////
// Key entered by Anton da Bassguy 2011
// Test successfully April 19, 2011
// This code does not test the decimal points on the lamp
// This code intentionally avoids use of arrays (for understandablility)
////////////////////////////////////////////////////////////////////////////
/**************************************************************************/