Seven segment display explained
In this article I intend to explain the functionality and usage of the seven segment display, probably you have seen many projects with these type of displays, however the price drop of LCD’s tend to overtake the market, there are a still few applications for which these devices are more suited. For large numeric displays, like clock’s, railway station displays, low-cost measuring devices or very stressing environments the led based displays are better, and cheaper. The most simple led display available is the seven segment display, it consists of 7 led stripes arranged forming the number 8, because of its simple construction it is very robust and can function in very low or high temperatures, can withstand vibrations, mechanical shocks without problems, for what the LCD would fail to work or even get permanently damaged.
If we look at one digit we can see 10pins each segment and the small dot are LED’s, each of them has one terminal connected to a common pin, from this comes the name common anode or common cathode, and the other terminal is connected to a standalone pin, since the common pin is doubled, we have the 10 pins for each digit.
Lets take as example the common anode type, to light the segments we need to connect the positive supply rail to the common pin, and pull to ground the segments, each segment depending on its size can handle a few miliamps, after all we are talking about LED’s not bulbs. That’s fine if you need just one number to display, but how can these digits be connected to form a multi-digit display? The first approach is to connect each segment to a micro-controller pin, this way for each digit you need 8 pins and isn’t elegant at all.
The other solution is to connect each corresponding segment from the digits to a common bus, and power the digits one at a time, thus multiplexing the data.
This multiplexing probably sounds more complicated than it really is, look at the next picture:
Since the digits share the same data bus, each digit will have the same number displayed, like the wheel on the picture, to change the number the “data guy” rotates the wheel. So how can we display 1234 you might ask, well wee need another guy, the selector, which will leave only one digit to be seen, all the others are shut off, by synchronizing the “data guy” and the “selector guy ” so they operate at the same time, when the wheel is at the 1111 position, the selector opens the first window, when at 2222 it opens the second and so on. By changing the data and selecting the digits at many times per second the human eye will see a steady image with 1234, the display refresh rate should be above 50 times in 1 second, otherwise the image may flicker.
In the schematic the “selector guy” is implemented by the PNP(BC327) transistors and the “data guy” is the data bus (PORTB0..7). For the practical demonstration I used my own avr development board with ATmega88, four HD1131R type seven segment digits which I rescued from an old TV a few years ago, the connections are made on a prototyping pcb with scrap wires. The data port is PORTB, for selection the PD4..PD7 pins where used.
Like I mentioned earlier we need a periodic data update with digit selection to have a steady image, and since the entire display refresh should be above 50Hz and we have four digits we need to change the digits at frequencies greater than 200Hz. Since the amount of time which one digit is turned on is 1/digit count, as the display has more digits the light intensity gets weaker, in our case the HD1131R has 1.6V voltage drop, by powering from 5V and trough 330Ohm results 10mA trough each segment, but since we have 4 digits the average current received by each segment is 10/4=2.5mA, this will result in a very fade light. For the demo application I used 220Ohm values, with the on board 100Ohm resistors the average current is 2.5mA/segment, although I could have used only the on board resistors, thus having 8.5mA average current, but the peak would be 35mA, and the micro-controller can handle at maximum 25mA/pin, off course the pin won’t get blowed right away from 35-50mA, but you should be careful when designing similar circuits.
That’s enough about the hardware, let’s see the software, for the periodic refresh I used a timer interrupt with 244Hz, resulting in 61Hz refresh rate, in Europe we have 50Hz AC power, so that’s fine, but in the case of 60Hz AC power the refresh rate should be at 70Hz to avoid the stroboscopic effect.
For the display data I used 4 byte buffer from which the interrupt reads and sends to PORTB, the buffer index can be used also for digit selection(see void DisplayData(uint8_t* Display) ).
Because of the seven segment data format by directly writing 5 to PORTB, won’t result in displaying 5, so the numeric data must be converted first, because there isn’t any easy algorithm to mathematically make this conversion, we must use another method, for a one digit display you could make if-else or switch statements, but with 2 digits you already need 100 lines of code, for 3 digits 1000 lines and so on. A very handy solution is a look-up table:
const uint8_t DigitCharTable[] = { DigImage0, DigImage1, DigImage2, DigImage3, DigImage4,\
DigImage5, DigImage6, DigImage7, DigImage8, DigImage9, };
By indexing the table with the numeric value 0-9 we get the needed data format, example PORTB = DigitCharTable[5]; results in displaying 5;
The void NumToDispValue(int16_t Number, uint8_t* DataBuffer) function uses this method to convert 16bit signed value into display compatible string.
After the conversion made, the actual display buffer needs to be updated with the new value, here is a tricky part, by converting 1234 into display compatible data we will have [DigImage1, DigImage2, DigImage3, DigImage4], by having DigImage1 at the first position and my display has D4,D3,D2,D1 physical configuration the data displayed will look like this: 4321, it gets reversed. This can be overcome by reversing the selection lines PD4..PD7, or by copying the reversed string into the display buffer(see void StrUpdateDisplay(uint8_t* DisplayBuffer, uint8_t* UpdateData, uint8_t InvDir) ).
After the conversion, the result is a string(not ascii!), so the string manipulation techniques can be easily used, the dot can be added to any digit, simply by setting the 7-th bit in that byte(see macro WITHPOINT(a) in SSDisplay.h ). There is also possible to display a limited amount of characters like E,F,c,C.., (see SSDisplay.h) it won’t be pretty but it’s readable.
Last but not least, since the refresh is done in interrupt, the display buffer update operation should be made atomic, in other words first disable the refresh interrupt, and then update the buffer, otherwise the image will flicker, and don’t forget to re-enable the interrupt after!
If you use only the refresh interrupt, than it’s easier to just disable all interrupts globally, although if you have other interrupt sources too, then disable only the refresh interrupt, this way you won’t hold back the other incoming events.
For data source I used the ADC to measure the potentiometer output, you can also tweak the macro’s used to handle the ADC, the dot in the 2th digit is activated if the ADC value is above 512.
The demo project was made using avr-gcc and avrstudio, some variable type notations may differ from the ANSI C standard since I use the avr-gcc typedefs, the entire project among with schematics, pdf’s is available for download.
In the next article I will explain the usage of the matrix keyboard.
Seven segment display explained: [download]






June 2nd, 2009 at 4:29 pm
I am about to work on a LM35 based thermometer, but with a 7 segment led for displaying temperature in Celsius (for portability), and I got very interested in your idea, because I thought it was really stupid to use one pin per led segment, and I didn’t want to increase entropy by adding a couple of 7447 7 segment led controller IC.
But what I got from your tutorial, the whole trick is changing each 7 segment led fast enough so we won’t notice that we are changing them one at a time, and multiplying 50Hz by the number of 7 segment leds we are using, so we’ll have a stable reading, i.e., without flickering. (please correct me if I am wrong).
The only thing I don’t get is what the transistor needed for? So I can increase the led brightness, because I’m flickering it too fast or using too much current for having so many leds on?
June 2nd, 2009 at 6:44 pm
I’m glad that you find the article useful.
The transistor used for selecting the digit must be able to carry the peak worst-case amount of current, you have 7 segments+ 1 dot by powering each led with the maximum average current, for example 20mA(for larger digits this gets more), the peak current/digit is (8*20mA)*DigitNumber, if you have a 4 digit display => 160mA*4 = 640mA. But be careful, the micro-controller output pin can handle only 25mA, and not more than 200mA overall current output/micro controller, if you want to have maximum brightness use npn(common anode display!) transistor array(ULN2003) or discrete npn transistors for driving the segments LOW.
Yeah, now I said it, I really got you in the mist, is that complicated in real life? If you want to engineer every little aspect than yes, if not just throw a 150-220Ohm resistor in series with the segment driving pin and you are ready to go, this will give an acceptable light intensity for a display made of maximum 8 small digits. This results in 200mA peak current for each digit => the selecting transistor could be BC327(0.8A), BC807(0.5A SMD!), 2N2907(0.6A) these are PNP transistors use them with common anode type display.
June 2nd, 2009 at 8:03 pm
Thanks, Laci!
My intention is to use only a double digit reading from the temperature (more than enough for a tropical country, so I won’t have to use negative numbers either). I’ll try it as soon as I get the transistor (lost the chance today, maybe in a couple of weeks) – or just prototype it without the thing.
Wish me luck
June 3rd, 2009 at 1:27 am
I once need 3 seven segment LEDs to count to 999 for a project. I created the wiring diagram which connected the LEDs to three decade counter chips. In my excitement I wired everything together using perf-board and wire-wrap upside down. That is to say I read the diagram rightside up but connected all the wires with the board upside down looking from the bottom. This created a perfect mirror image wiring of the chips and LEDs. When I applied the power it didn’t smoke but just turned on as if all was just fine. With one very scary issue…The LEDs displayed 666 all the time! Never counting up or down. I’m not kidding this really happen and can be reproduced simply by reproducing my mirror image wiring error. Once I noticed my issue I rewired the LEDs, decade counters, latches correctly and everything worked just fine. But WOW very spooky!
Todd Harrison
June 3rd, 2009 at 4:02 am
Ummm… how exactly are you arriving at your worst case current scenario? The transistors in question are only powering a single digit each, there is NO way they could have to supply power to ALL the digits (that would kinda defeat the purpose of multiplexing), which would be at maximum 8 leds. So the worst case current for a single transistor is 160mA regardless of number of digits.
June 3rd, 2009 at 9:46 am
@Nocturnal: The purpose of multiplexing is to reduce the pin count.
Let’s take as example the display presented in the article, 4 digits, each segment can support 20mA, for maximum light intensity we want to drive each segment with 20mA this gives 160mA/digit that’s about correct, but what happens when you drive each digit 1/4 of the time? Because of the multiplexing at any moment only 1 digit is powered, what would be the average current passing trough the segments? The worst-case scenario assumed is to drive each segment at its maximum power, in that case the permissible pulse handling capacity plot of the segments(see datasheet) has to be considered too.
June 4th, 2009 at 11:45 am
[...] counting up or down. The whole display is multiplexed, more information about that you can find here. There are five push buttons you can use to configure the [...]
August 23rd, 2009 at 1:20 pm
Great article, thanks a lot.
Just one error, the google bookmarking isn’t working, HTML encoding galore (URLs are composed with & instead of &)
August 23rd, 2009 at 1:23 pm
what URL’s are you referring to ?
August 23rd, 2009 at 2:05 pm
The Google button below this sentence “Do you like this article ? Bookmark it on:” does not work because the URL is html encoded : & are expanded to & amp ; so they don’t work anymore.
August 23rd, 2009 at 2:07 pm
It’s probably a WordPress config mistake or something minor, I had no will to pollute your excellent tutorials
August 23rd, 2009 at 8:24 pm
Yup, I know what you mean now. It’s an issue with the social plugin for wordpress, cause that’s behind the bookmarking buttons. I’ll have to wait for an update to fix it.
Until then you’ll have to copy and paste the URL
Thanks for letting me know.
August 26th, 2009 at 8:28 pm
Hi there, my name is walter and i’m working on a project that will measure the distance of an object up to 35 feet, and i was currently using a serial 7 segment display, but i would like to use 4 7 segments instad, i find it way cheaper than the serial 7 segment displays which run for about 30 – 60 dfollars, the language i’m using is Bascom 8051 but i’m having a little bit of trouble trying to multiplex the data into the segments, i was wondering if you could help me with this i understand exactly what i need to do the problem is that i don’t know how to do it and i’m not really familiar with C language, i understand that in order to display the digits i must do it one digit at a time but in a fast enough manner so that the eyes won’t see any flickering that’s where my problem is, i don’t know how to start, please help,
Thanks.
August 26th, 2009 at 10:22 pm
Yep, for 4 digits that is the cheapest solution, above 8 digits you should consider alpha numeric LCD’s 15-20$.
I strongly suggest that you use some timer interrupt for the multiplexing(like I did in the demo), you should try to port the C code to Basic, that would be the easiest way, since the code is really straight forward and commented.
June 2nd, 2010 at 1:32 pm
Thank u!..i was searching for this long time
April 27th, 2011 at 6:34 pm
hi and appreciate the information you have – I have surely picked up interesting things from your site. I nevertheless ran into a few on site issues using this website. I have been wondering whether your website hosting is fine? Not that I am filing a complaint, but poor loading times might very likely influence your position in the search engines and might harm your high-quality content on this site. Well I’m putting this Rss feed to my personal email and will look forward to much more of your fascinating content..
June 25th, 2011 at 5:13 am
Why would one segment of a 2 digit-7 segment display not function when both “a” should be on at the same time. It is digit 1 on the right of the two. I’ve tried 3 led displays. So it’s not the displays and I’ve checked all of my connections. The processor functions normally also. Just the one segment. Arrghh. Please, any help. Thx Mathew
June 25th, 2011 at 3:06 pm
Hi Mathew,
First try to display the 8 character, since that uses all of the segments, but my hint is that the problem comes from the multiplexing, the problematic digit stays on for a very short time, while the other stays on considerably more, off course could be some hardware issue too, like pcb/schematic error.
A good way to search for the root cause, override the multiplexing routine, just select the first digit and display some character(recompile the software, re-flash and test), do this for the second digit too, this will show you if you have some connection problem or software bug(my vote is on the multiplexing bug
)
May 31st, 2012 at 2:34 am
I found this video helpful: