Saturday, January 17, 2015

Seven segment displays on an Arduino

Adafruit sells a four digit, seven segment LED display. Unlike many of their products, they don't give a lot of help in hooking it up. They suggest that you should connect it with the transistors or a shift register on the common cathodes to sink enough current. I think this is probably unnecessary. If you connect the anodes through 1k resistors you get pretty good brightness. The current per segment should be something like 5V minus 0.6V for the diode (it may be more than this - 0.6V is for silicon and they are probably GaAsP), so this gives a current of 4.4mA per segment, or 35mA if you have all the segments on, provided you only drive one digit at a time. The Arduino should be able to handle this OK. At least mine didn't blow up when I set it up like this.

There's a couple of difficulties in getting it connected, and so I'll go through what I did in case it is helpful to anyone else. I don't think this kind of display is very well suited to using on an Arduino, at least if it is connected directly. You need to use 12 or 13 I/O lines for it, and the code has to continually refresh the display so it can't do much else. You can reduce the number of lines by using a shift register or and I/O extender, though the refresh problem remains. The description that follows shows how direct interfacing can be done if you really want to try it.

The datasheet that Adafruit links to is a bit misleading. It makes it look as if the display has twelve pins, 1-6 on the lower edge and 12-7 on the top one. In fact it has 14 pins, 1-7 on the lower edge and 14-8 on the upper one, reading from left to right if you are looking down on the display. The model I got had part number KW4-56NCLB-P, so you have to use the second of the two diagrams on the datasheet for the pins. It's a common cathode version, meaning the pointy end of the LEDs which the current comes out of are joined together. There cathode for each digit are connected together, as are the ones for the colon separator in the middle of the display. Typically, you would use it by setting one of the common cathodes to low (0V) to select that digit, with all the others high. Then you would set the pins for the segments you want to turn on to high while keeping the others low. For example, to display a 1 on the leftmost digit, pin 14 would be low and pins 11, 7, 10 and 6 high for the digit, and pins 9 and 4 would be high, with 13, 2, 1, 12, 3, 5, and 8 high for the segments.

This example may make the second difficulty apparent: the ordering of the pins is not at all logical: the segments don't come out in a nice order such as pins 1-8, they are in the order I just mentioned 13,2, 1, 12 etc. I assume this makes manufacturing easier by avoiding crossing tracks within the package. When you are using a breadboard, a trick that can help with this is to take jumper wires from the pins to another area of the breadboard, where you can put them into a more logical order. I've done this with ICs that have a weird pin ordering as well. There are eight LEDs per digit (seven segments plus a decimal point), it makes sense to bring them out with four in each block.

The breadboard that I have is a fairly common one in which there are two block of contacts, with 5 in each column.  The columns are labelled 1 through 64. I placed the display so that pins 1 and 14 were on column 50. I'll call the blocks of the breadboard A and B, with the top of the display (pins 8-14) going into A. The table for the wiring them goes like this:
Pin on the display Function of the pin Column on the breadboard Connect a jumper to...
1 Segment E 50B 41B
2 Segment D 51B 38A
3 Decimal point 52B 38B
4 Segment C 53B 39A
5 Segment G 54B 39B
6 Digit 4 55B 23B


9 Segment B 55A 40A
10 Digit 3 54A 23A
11 Digit 2 53A 24A
12 Segment F 52A 40B
13 Segment A 51A 41A
14 Digit 1 50A 25A

I didn't connect pins 7 and 8, which are for the colon. Now we have the four digit cathodes on 25A, 24A, 23A and 22A, segments A to D on 41A, 40A, 39A and 38A, and segments E to G and the decimal point on 41B, 40B, 39B and 38B. This is a much more logical ordering and it helps to stop your brain from hurting.

As I said before, each anode (segment) will have a 1k resistor on it. We need this to limit the current through the segment. Some people suggest putting the resistors on the digit cathodes, as then you only need four of them, or five if you use the colon. However, if you do it this way, the brightness will vary according to what the display is showing, as with more segments on there will be more current through the resistor and hence a larger voltage drop across it. So now you can connect up 8 1k resistors, keeping the nice ordering of the segments we achieved earlier. The resistors can span across some of the jumper wires to keep things tidy. Here's the table for the resistors:
Segment 10k resistor from... to...
Segment A 41A 37A
Segment B 40A 36A
Segment C 39A 35A
Segment D 38A 34A
Segment E 41B 37B
Segment F 40B 36B
Segment G 39B 35B
Decimal point 38B 34B

Now all that remains is to connect it up to the Arduino. I connected digits 1-4 (25A-22A on the breadboard) to I/O pins 2-5, and segments A-G plus the decimal point (37A-34A and 37B-34B) to pins 6-12. It looks like this:

The connections to the Arduino are very tidy with all the mess in the jumpers on the breadboard.

There is a code snippet here. It picks a random number from 0 to 9999 and displays it. To do the display, there is a function called displayNumber, which selects each digit in turn by setting the right one of pins 2-5 to LOW, sets up the segments that are on by setting some of pins 6-12 to HIGH and delays briefly to reduce flickering. To keep the display refreshed, this all has to be done in a loop.

On my display, there was one dead segment (the D segment of the first digit), but otherwise this works quite nicely.

No comments: