Issue with programming a 4 digit 8 segment display

Well, I don't really know if it's the right place for my topic, but I believe this is the most relevant one at least, so let's get to it.

What I'm trying to accomplish: I have a 4 digit 8 segment display, and I'd like to have it display the seconds elapsed, with showing the 1000th of seconds after a dot on the last 3 digits.

I got the said 4 digit 8 segment display in my Infiduino starter kit, I attached the data sheet, and a basic sketch of the circuit to this post. This is a common anode one.

The code I'm using was provided with the starter kit, it does what it should without problem, it displays the number 2014:

/*
  4 Digital 8-Segment LED Display
  Display four numbers on 4 Digital 8-Segment LED Display
  In this sketch, we use D2-D9 to control A/B/C/D/E/F/G/DP segment respectively. And use D10/D11/D12/D13 to control the anode of DIG1-DIG4 respectively.
*/
int DIG[4]={10,11,12,13};//The pins used to controll the anode of the 4 bit,DIG1-DIG4.
char Str[4] = {'2', '0', '1', '4'};//The number to be displayed.
byte Numcode[10]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};//the character code for number 1-9
void setup()
{
  int i=2;
  //Set D2-D13 as OUTPUT
  for(i=2;i<14;i++)
  {
   pinMode(i,OUTPUT);
   digitalWrite(i,HIGH);
  }
}
void loop()
{
 int i=0;
  int j;
  int k=0;
  int l=0;
  //Display DIG1-DIG4
   for(k=0;k<4;k++)
  { 
    digitalWrite(DIG[k],HIGH);//Set DIG[K] to be ON.
    i=Str[k]-48;//find out the number's position in the character code array.
    //display the number
      for(j=0;j<8;j++)
     {  
      if(Numcode[i]&1<<j)
      digitalWrite(9-j,LOW);
      else
      digitalWrite(9-j,HIGH);
      }
    delay(1);
    digitalWrite(DIG[k],LOW);
  }

}

I thought this sample code would be a good start to tinker around with to try and achieve my goal. I unfortunately don't fully understand the code, I'm quite new to Arduino, electronics and C in general, but how it works is the following I think:

Each digit has a pin, which has to be on HIGH, for us to be able to set the segments of the actual digit. It sets DIG1 to HIGH, then it uses the variable 'j' to go through the 8 segments (A,B,C,D,E,F,G and the dot, DP) somehow it determines using the 'Numcode' array that which segment should be on, and sets those to LOW, while the others to HIGH (since this is a common anode display) and when all the segments have been set, then sets DIG1 to LOW, and moves on to DIG2, repeat until all 4 digits have been set.

There are some parts that I don't really understand in this code, and would really like to get guidance with:

  • The whole code which sets the digits has to be looped constantly. Otherwise it just lights up for a brief moment, then goes dark forever. I cannot really see based on this code, why is that?
  • What is in the Numcode array, and how does it help to determine which segments should be on for each number through 1-9?
  • i=Str[k]-48; The comment next to it says that it finds out the number's position in the character code array (which is 'Numcode' I think?). How does this do that exactly?
  • if(Numcode(i)&1<<j). This statement determines if a particular segment should be on or off. This one is the most "cryptic" to me, I looked up the logic operators in C, and still don't really understand what this one does. (I replaced the square brackets to round ones due to it parsing it as italic)
  • digitalWrite(9-j,... The "for" cycle this command is in implies that the order of the segments and the order the program goes through said segments are reversed if I'm correct. Why?

So I had these questions in mind, but I still tinkered around with the code, trying to get it to display the timer as I wanted. I put the whole code in the loop function into another function, then increasing the last member of the array, hoping that it'd display the two numbers after each other. This didn't really work, probably because the type of the 'Str' array is char. Then I tried manually re-declaring the array with the new number, but it didn't work either. Then I thought since it needs to be looped to display the numbers continuously, I tried various combination of "for" cycles, then re-declaring the array. For example looping the displaying function 10 times, re-declaring the "Str" array, then looping the display function another 10 times, no luck this time either.

I'm pretty much out of ideas, and would really like to get help with this (pretty much first) project of mine. If someone could give me a sketch which does the timer thing what I originally wanted that would be great, but I'd highly appreciate if someone could answer the questions I had, and maybe help with the code too. The Arduino is a great platform, and I'm just getting into it, and realizing the potential it has. I hope this forum can help me. :slight_smile:

Radioshack.com has some arduino projects available. Along with the how to's & CODE! They did the same thing, im pretty sure. Check out Radioshack, it's worth a shot.

OK It appears you are having some difficulty understanding how these displays work..

Every character of the display has 7 bars (in a figure of 8 configuration) Each of these bars is an LED. In order to produce a digit a combination of these bars need to be illuminated.

for instance in the digit "8" every one of them has to be illuminated. Whereas the digit "1" has just the right hand pair illuminated.. Besides these 7 bars there is also a decimal point. So that makes 8 LEDs that need to be either illuminated or extinguished, dependent on what we're trying to display. So that we know which bar we are talking about, these are usually given a single letter name, where "a" is the top bar and then working around the outside in a clockwise direction we have "b","c","d","e","f" , the bar in the middle is called "g" and finally there's the decimal point "dp"

To help work out which LEDS are needed for any given digit, we can represent each of those bars (and the decimal point) as a single binary bit. Putting these bits together we can then store the pattern of bits as a byte of data. If we assemble the bits in the order a,b,c,d,e,f,g,dp

The digit 0 would be "11111100" (where those last two zeros are the centre bar and Decimal point)
the digit 1 would be "01100000" (just light up the right hand two bars)
the digit 2 would be "11011010" (bottom right, top left and decimal point are off but all others on)
the digit 8 would be "11111110" (everything alight except the decimal point)

In the code you have shown, the whole set for the digits 0 to 9 are stored in an array called Numcode (in his remarks the author erroneously says 1-9 but it really IS 0-9)
So the first of these is0xfc (which is just hex talk for "binary 11111100")
the next is0x60 (which is hex for binary 01100000)

So now if we want to display the digit "0" (the first one of the array we can find the pattern we need by reading Numcode[0]
to display the digit "1" we'd read Numcode[1].
If we wanted to find the pattern for a digit held in a variable called littleI, we'd read the byte Numcode[littleI];

Once we've got the byte we need we then need to send it out through the output pins, one bit at a time. When we're looking at the first bit (the least significant) we want to ignore all the other bits in the byte. We do this by ANDING it with the number 1. ( hence the &1)
To find the next bit we want to and the byte with 2 (which is the number 1 shifted once to the left)
To find the 3rd bit we want to and the byte with 4 (which is the number 1 shifted twice to the left)

So to explain that cryptic line if(Numcode[littlei]&1<<j)

Littlei is the value of the digit we're trying to display.
So Numcode[littlei] is the pattern of bars we need to display
J is the exact bar we're considering on this itteration of the loop
so we want to AND the pattern with (1 shifted J times to the left)

BTW I'm not familiar with this particular display. I'm just going by the code that you have presented here.

Anyhow I've got to dash, will explain some of the other questions issues later if I get some time.

The whole code which sets the digits has to be looped constantly. Otherwise it just lights up for a brief moment, then goes dark forever. I cannot really see based on this code, why is that?

It looks like that display is a simple multiplexing system that lets you control one 8 segment display at a time. It has no latching or memory. In consequence, you can only light one digit at a time. It relies on persistence of vision effects to make you think that all four are on at the same time. Since in actual fact, only one is, you need to run in a loop so that each is lit in turn, quickly enough that you don't realize it.

What is in the Numcode array, and how does it help to determine which segments should be on for each number through 1-9?

It encodes the information telling you which segments to light for each number into a bit for each. Consider the second character in the array: 0x60. This shows you how to display a '1', which means that you have to light segments B and C. 0x60 is binary 00110000. Bits4 & 5 are set - the bit shifting and 9- magic below uses them to interpret which arduino pins correspond to the B & C inputs on the display AKA pins 7 and 4 on the diagram of your LCD.

Looks like KenF has covered most of this while I was typing.

While it's worthwhile gaining an understanding of the code you have, as you've observed, it isn't the clearest - bit shifting and clever tricks with 9-x don't make for readable code for beginners.

For the purposes of your project, you can ignore a lot of the detail until later - I'd be tempted to abstract all the contents of loop into it's own function and just call it from loop. Then, observing that whatever digits are stored in your Str variable get shown on the display, just work on getting the digits you need put in there. sprintf may be useful. Then add a little hack to get the decimal place working and you're done. In fact, setting the decimal point might be a worthwhile precursor exercise - it may help you to better understand what's going on in the rest of the code.

I've used this library with some success:

http://playground.arduino.cc/Main/LedControl

  • This is not a timer and this is almost similar to the 1 digit 8 segment project. This only shows the 2014 one by one but you cannot see the scrolling effect because the delay is set to only 1 millisecond. Try to change to delay(1000); to see the effect.

  • numcode[10] is an array from 0 to 9 but in hexadecimal format. Array 1 which is the same as numcode[1] is equal to 0xfc and in binary form is 1111 1100 or segment ABCD EFGdp. The 1's signifies the segments that should be turned ON but instead of having an output of HIGH it will output LOW because the common anode is already HIGH.

  • regarding i=Str[k]-48, I have no idea or basis how we arrive to -48

  • if(Numcode*&1<<j) is to verify which are 1's from the binary format of the hex*
    - digitalWrite(9-j,LOW); j signifies the segment from A to dp, so if j = 0 pin number 9 will go LOW and the segment connected to pin 9 will be litted until pin 2 has been reached.
    notes: 0x just as in 0xfc is an indication that it is in hex format what you need to convert to binary is fc only. You can use many resources available free applications to convert hex to bin. Don't change square brackets to open-close parenthesis or in any form as this will not work anymore.
    - cheers!

regarding i=Str[k]-48, I have no idea or basis how we arrive to -48

I know this is an old post but I wanted to highlight a point.

What (i=Str[k]-48) actually does is that it converts the ASCII character value to a decimal value.

ASCII characters are represented with 8 bits. the character "0" is represented in binary value (00110000) which equals 48 in decimal.
The value of i in the statement (i = Str[0], which makes i equals the first element in the array above. the first element in the array equals '2') is not 2, but equals 50. (if you google for ASCII character codes you will find that the character 2 has the decimal value of 50).
The array Str stores characters, not integers (note that numbers are stored between single-quotation marks).
ASCII 0 = decimal 48.
ASCII 1 = decimal 49.
ASCII 2 = decimal 50.
...etc.

To convert the character string value to a decimal value, the subtraction of 48 is needed.

I think another alternative is to store integers in the array in the first place rather than storing characters.

I hope this is useful.

andalus