Seven Seg
Seven Seg
Sigvald Marholm
08.06.2015
1
Disclaimer
I do not take any responsibility for the usage of my code (or additional material
such as this document). Although I've tested most of it, some parts may not
be working, and some information herein may not be correct. Updates and
backward/-forward compatibility are not guaranteed (but it may still happen).
Use it at your own risk. I do provide it free of charge for non-commercial
purposes.
Further on, I discovered after I started developing this library that there
already was a similar library at the Arduino playground called SevSeg v.2.0. I
decided to proceed, however, since that didn't quite have the exibility I wanted.
Nevertheless, SevSeg was rst.
2
1 Introduction
SevenSeg is a exible library for Arduino for outputting information to 7-
segment displays. The main focus is to be a library which gets you started
quickly while being exible and cover most needs. That is, the most common
7-segment displays should be easily connected to an Arduino and information of
various kinds should be easily output to it. This library is intended for beginners
as well as more sophisticated users who just want something up and running.
It is not intended to be an extremely lightweight library. Key functionality
includes:
Text strings
Leading zero suppression (e.g. 123 is displayed as 123 rather than 0123
when using 4 digits)
No shadow artifact
Future releases may happen, so feel free to contact me with suggested im-
provements and corrections ([email protected]). In future releases,
functionality and beauty of the code
1 will likely be prioritized above for in-
stance backward compatibility.
1 Today, parts of the code are clean an beautiful, while other parts are not. In the end I
just had to nish up the project before getting tired of it. I hope to provide a cleaner code in
future versions.
3
A
F B
E C
D DP
A B C D E F G
2 Getting Started
Let's start with a quick example to get most users up and running. We will
assume a 4-digit 7-segment common anode display. The segments in each digit
are labelled A to G in the standard way as depicted in Fig. 1. Some displays
also have an 8th segment for the decimal point (DP). This example assumes a
display without that segment (see Sec. 3.3 for how to use SevenSeg with decimal
points).
The schematics for a 4-digit common anode display is depicted in Fig. 2.
Each segment houses a LED light. All anodes (positive terminal) on a digit are
tied together into one pin which is hereinafter referred to as a digit pin (dig 1
to dig 4 on the schematic). The cathodes (negative terminals) of segments A to
G are tied together across the digits, and their pins are hereinafter referred to
as segment pins A to G.
For a common cathode display, it's the other way around: the cathodes
are the digit pins, being connected together within each digit (hence the name
common cathode) while the anodes act as segment pins and are connected
across the digits. Fig. 3 shows a 4-digit common cathode display.
Nevertheless, the digit pins should be connected directly to available output
pins on the Arduino, while the segment pins should be connected to Arduino
output pins through appropriately dimensioned resistors (see Fig. 10). Make
sure the resistors are dimensioned such that neither the display nor the Arduino
is damaged. For dimensioning of resistors, see App. A.
Finally, an example code for making this work is shown below:
4
A B C D E F G
2 Sorry about that. It's global in order to allow an arbitrary number of digits while pre-
venting dynamic memory allocation.
5
3 Hardware Setup
This section contain information about how to congure the SevenSeg-library
to the hardware. These member-functions are typically called in setup(){...}
except for the declaration of the SevenSeg-object which can be put in global scope
to make it accessible in loop(){..}.
void setCommonCathode();
Congures whether the segment and digit pins should be active high
or low. As an example, a common cathode display has segment pins
that are active high, since the LEDs light up for high segment pins.
The digit pins, however, are active low, since only digits with a low
digit pin are on. Hence, calling setCommonCathode(); is equivalent to
setActivePinState(HIGH,LOW);.
calling
The setActivePinState()-function, however, allows for a wider range
of circuit topologies. Take for instance that you want to run more
6
A B C D E F G
current through the digit pins of a common cathode display than al-
lowed per Arduino I/O pin. A classic solution in this case would be to
add NPN-transistors at the digit pins as shown in Fig. 4. This, how-
ever, inverts the digit pins. For this topology, call setActivePinState
(HIGH,HIGH);.
Additional segment pin for colon. Two separate LEDs are used for the up-
per and lower dot in the colon (UC and LC) as shown in Fig. 5. They
share an additional segment pin (labelled colon) for turning on/o colon.
They share digit pins with other digits. On some variants only one LED
(UC) is present (at least apparently). This is indicated by the dashed line.
These kind of displays are congured by setColonPin().
Additional digit pin for colon and apostrophe. On these kind of displays
a separate digit pin symb is used for symbols: apostrophe (AP) and
colon (UC and LC if split in two). The symbols share segment pins with
the usual segments A-G. See Fig. 6. These displays are congured by
setSymbPins().
7
dig 1 dig 2 dig 3 dig 4
UC LC
A B C D E F G Colon
Figure 5: A 4-digit common anode display with a separate segment pin for colon
AP UC LC
A B C D E F G
Figure 6: A 4-digit common anode display with a separate symbol digit pin for
colon and apostrophe
8
3.5 Example: 4-digit Display with Symbols
Finally, a more complex example. How to setup a 4-digit common cathode
display with decimal points, one unterminated LED for apostrophe, and one
unterminated LED for colon.
First, the cathodes of the apostrophe LED and the colon LED are tied
together and connected to Arduino I/O pin 1. This is the symbol pin. The
anode of the apostrophe LED is tied together with segment pin A and connected
to Arduino I/O pin 11 through a resistor. The anode of the colon LED is tied
together with segment pin B and connected to the Arduino I/O pin 7 through a
resistor. The other segment pins C-G are connected (through resistors) to I/O
pins 3, 5, 6, 10 and 2, respectively. The DP segment pin is connected to pin 4.
At last, the digit pins 1 to 4 (leftmost to rightmost) are connected to pins 12,
9, 8 and 13, respectively. Then, the code to initialize it would be:
9
5
6 const int numOfDigits1 = 4;
7 const int numOfDigits2 = 2;
8 int digitPins1 [ numOfDigits1 ]={9 ,8 ,7 , A4 };
9 int digitPins2 [ numOfDigits2 ]={6 ,5};
10
11 void setup () {
12
13 disp1 . setDigitPins ( numOfDigits1 , digitPins1 );
14 disp1 . setDigitDelay (1667) ;
15
16 disp2 . setDigitPins ( numOfDigits2 , digitPins2 );
17 disp2 . setDigitDelay (1667) ;
18
19 }
20
21 void loop () {
22
23 disp1 . write (1234) ;
24 disp1 . clearDisp () ;
25
26 disp2 . write (56) ;
27 disp2 . clearDisp () ;
28
29 }
Moreover, since the two objects are unaware of each other both running in
loop(){...}, the refresh rate will not be 100 Hz which is default. The function
setRefreshRate() also do not work. When multiplexing several displays the time
to spend (in microseconds) on each digit must be manually calculated and spec-
ied using setDigitDelay(). For this example the time is calculated as follows
(assuming a refresh rate of f = 100 Hz which is usually a good number):
1 1
Tdigit = = 1667 s (1)
nf 6 100 Hz
Unfortunately, it is not possible for several displays to share segment pins
while using interrupt timers.
10
Writes the number num on the display. See Sec. 2 for an example.
Supports signed integers. If the numbers are out of range they
are trimmed to the largest positive or negative number the display
can show. I.e. write(1234) will output 1234 on a 4-digit display but
99 on a 2-digit display. write(-50) will print -9 on a 2-digit display
and -50 on displays with at least three digits.
Similar to write(long num) except that this one writes a xed point
decimal. The integer point tells how many digit should be treated as
decimals. Example: write(1234,2) outputs 12.34. As for the above
function num will be trimmed if outside the range of what the display
can handle.
Same as above but uses the String object rather than null-terminated
string.
11
Same as above but automatically uses colon if it exists, decimal point
if not or simply nothing if the display has neither colon nor decimal
points. See Sec. 3 for conguration of decimal points and colons.
This writes the time in the format mm:ss, mm.ss or mmss depending
on whether c is ':', '.' or '_'. The minutes are derived from the sec-
onds. Example: writeClock(72,':') outputs 01:12 since 72 seconds
is 1 minute and 12 seconds.
Activates the digit given by digit (and deactivates the others). I.e.
changeDigit(1) makes the leftmost digit the active one. Each time
changeDigit() is called all the segments are cleared. Hence, the fol-
lowing (erroneous) code will leave digit 2 empty:
1 changeDigit (2) ;
2 writeDigit (4) ;
3 delay (5) ;
The reason for this behaviour is to prevent shadows . The purpose
4
of the delay is to leave the segment on for some milliseconds before
changing digit again. Immediately changing digits will make the
digits be on for only a brief moment (as long as it takes to process
the code) before the changeDigit() clears the digit again resulting in
a very dim light.
12
void writeDigit(int digit);
Writes the number digit to the active digit. See changeDigit() for an
example of how to use it.
Outputs the character digit to the active digit. The following ex-
ample outputs the string -3F:
1 changeDigit (1) ;
2 writeDigit ( '- ');
3 delay (5) ;
4 changeDigit (2) ;
5 writeDigit ( '3 ');
6 delay (5) ;
7 changeDigit (3) ;
8 writeDigit ( 'F ');
9 delay (5) ;
Valid characters are a-z, A-Z, 0-9, minus (-), space ( ), and degree ( ).
Small and capital letters are displayed equally. The degree-symbol
should probably be written as an escaped character, i.e writeDigit('
\370').
void setDP();
1 changeDigit (2) ;
2 writeDigi (3) ;
3 setDP () ;
4 delay (5) ;
void clearDP();
void setColon();
Turns on the colon segment(s). See Sec. 3.4 for how colons are
implemented in hardware. If colon utilizes an additional segment
pin, this function behaves similar to setDP() in that it is cleared on
each changeDigit(). If a separate digit pin for symbols is used instead,
setColon() means that colon segment should be automatically turned
on each time the symbol pin is activated using changeDigit('s'). To
clear it, you must call clearColon().
void clearColon();
13
void setApos();
void clearApos();
4.3 Multiplexing
The high-level printing functions (c.f. Sec. 4.1) automatically parses and mul-
tiplexes
5 the data to be displayed. The functions in this subsection allows the
user to tweak parameters of the multiplexing.
void setRefreshRate(int freq);
Sets the refresh rate used for the display for high-level printing func-
tions. I.e. setRefreshRate(150) means that the whole display (all
digits) updates 150 times each second.
If you have n digits and a refresh rate of f (in Hz) the display
will spend Tdigit = 1/(nf ) seconds per digit6 . The limit for when
ickering becomes visible lies at under 50 Hz
7 (or perhaps somewhat
higher if the display is vibrating or moving with respect to the ob-
server). The SevenSeg-library has a default refresh rate of 100 Hz
to ensure smooth operation by default.
Rather than setting the refresh rate you can also set the quantity
Tdigit to delay (in microseconds) directly. See setRefresRate().
5 Multiplexing is the process of showing one digit at a brief time before showing the next
digit and so on. Doing this repetitively and at a suciently fast refresh rate makes it appear
as if all digits light up at the same time.
6 If you have for instance a 4-digit display with a separate symbol digit for apostrophe and
colon then n also includes the symbol pin; n = 5. See Sec. 3.4.
7 That's why old CRT TVs has a refresh rate of 50Hz (in Europe at least).
8 Technically, it might be more correct to say that dc/n is the duty cycle rather than dc,
since that's the percentage of the time each digit is on. I.e. if you set dc = 100% and have
n=4 digits then, technically, each digit is on only 25% of the time, not 100%. Nevertheless, I
nd the denition used herein more convenient, since its easier and maps directly to brightness
without depending on the number of digits.
14
4.4 Using Interrupt Timers
Running the printing functions in an endless loop to perform multiplexing is
not always an ideal way to do things. Outputting information to a 7-segment
display is not a computationally intensive task, but due to the delay used for
multiplexing, the microcontroller just sits there and waits for most of the time.
Sure, you can insert commands taking little time in a loop together with the
printing functions, but if they are slightly time-consuming, the display will halt
or icker. For this purpose it is possible to use SevenSegalong with interrupt
timers. Then, you can do whatever you want inside loop(){...}, and simply
run a high-level printing function only when you want to change what's on the
display. The microcontroller will automatically be interrupted just briey to
update the display as needed. You can still change the refresh rate and the
duty cycle like normal, the SevenSeg-library will take care of conguring the
timers for you.
Let's begin with an example of how to get started with timers:
15
timer 0. Hence in order for delay() to work, you can not use timer 0 for SevenSeg
(or other purposes).
void setTimer(int timerID);
Tells the library that timer number timerID is to be used for mul-
tiplexing. timerID can be '0', '1' or '2'. Timers 3, 4 and 5 are not
supported yet.
void clearTimer();
Clears the timer settings from the SevenSeg-object such that the ob-
ject can again multiplex in the default way.
void interruptAction();
void startTimer();
Version History
v1.0 (12.07.2013) Initial version
v1.1 (02.06.2015)
write(double,int) implemented.
v1.2 (08.06.2015) Bug x: Error in leading zero suppression. Numbers '0.02'
would show as ' . 2' (and similar).
16
V cc
IF n
VF
Figure 7: Forward biased diode with current limiting resistor. The order of the
diode and the resistor is insignicant.
A Current Calculations
A.1 Basic LED Current Calculation
Consider rst a simple forward biased
9 Light Emitting Diode (LED) as shown in
Fig. 7. LEDs are current controlled devices, and the easiest way to control the
current through an LED is by limiting it with a resistor. The way to dimension
the resistor is to rst choose the forward current IF through the LED, then,
determine the voltage drop VF over the LED, and nally you compute the
resistance R of the resistor.
As an example, we'll assume the diode 17-21USRC from Everlight. Some
selections from the datasheet are included in Fig. 8 and Fig. 9. We see that
the diode has a maximum forward current of 25mA, but according to the curve
of luminous intensity IV versus forward current, the diode should still light up
relatively well at smaller currents (for more about luminous intensity, see Avago
Application Brief D-004). Besides, we should have some margin to account for
component tolerances and round-o errors in selection of components. For now
we'll just choose the forward current somewhere in the mid-range: IF = 10 mA.
Next, the IF vs. VF curve shows that the voltage will be approx. VF = 1.8V .
If Vcc is the output of an Arduino then Vcc = 5V (when the output is high) and
the voltage across the resistor is
The current through the resistor must be IF and using Ohm's law the resistance
must be
VR 3.2 V
R= = = 320 330 (E12) (3)
IF 10 mA
The resistance was approximated to 330 since not all values of resistors are
commonly available. 330 is a standard value in the E12-series of resistors.
9 Forward biased simply means that plus is connected to the diodes anode and minus/-
ground to its cathode such that the current ows in the forward direction. Diodes prevent
currents from owing in the reverse direction. For 7-segment displays this is utilized for
multiplexing by letting only one digit be forward biased at a time.
17
Figure 8: Absolute maximum characteristics for Everlight 17-21USRC. Note
that they may deviate from these values at temperatures other than T =
25 deg C .
18
Figure 9: IV vs. IF (left) and IF vs. VF (right) for Everlight 17-21USRC. Notice
how the dashed line is for higher currents than maximum DC-rated IF . This
region can only be utilized if multiplexing suciently fast.
This increased resistance will make the forward current slightly smaller, but
visually not notably dierent.
Sometimes datasheet lack information. A typical dirty way to do it is to
simply assume IF to 5 or 10 mA and VF = 2V , but you should make sure you're
not overriding the absolute maximum characteristics which always should be in
the datasheet.
where dc is the duty cycle as dened for the function setDutyCycle(). If setDutyCycle
() is not used dc = 1 (= 100%). Hence to have the same average current in the
case of multiplexing a seven-segment display as for a constantly forward biased
LED like above you should dimension R like before but for n times higher IF .
Even though the average forward current is equal, it may be that the luminous
intensity is not, due to what is called the relative eciency of the LED (Avago
Application Brief D-004 is highly recommended for more information about this
topic). However, it usually is not that big an error to say that the peak current
IF through an LED should be n times higher that it would've been for a single
non-multiplexed LED since our eyes are not sensitive to an error of a couple of
tens of percent. When choosing IF , however, you should make sure the following
criteria are met such that nothing is damaged:
19
1. IF should not override the maximum value in the datasheet, typically
20-30 mA.
2. The maximum reverse voltage VR for the segment LEDs should be higher
than Arduinos I/O pin voltage Vcc = 5V since multiplexing 7-segment
displays imply reverse biasing some segments LEDs.
3. The current IF will ow through the segment pins. Hence IF should be
lower than the maximum current handled by the Arduino I/O pin, which
is 40 mA. You should probably stay well below this due to tolerances, etc.,
say, not more than 20-30 mA.
4. 7IF will ow through the digit pin while displaying the number '8'. Hence
7IF should also be lower than what can handled by the Arduino IF pin;
40 mA or preferrably not more than 20-30 mA. Note that some displays
have more than 7 segments per digit, i.e. if there is a decimal point (see
Fig. 10) or colon (see Fig. 5). In that case, you need to multiply IF by 8
or whatever number of segments are present per digit.
As a design procedure, you could start by assuming that you want Iavg =
3 mA of average current through each segment and calculate the resistors ac-
cordingly. You make sure all the above criteria are met, and test it (without
using setDutyCycle()). From there on, experiment with dierent values of re-
sistors until you are satised. If you want to utilize the adjustable brightness
feature this will now be the maximum brightness. This is it! If you have troubles
overriding the above listed criteria, go on reading the next two subsections.
20
dig 1 dig 2
A B C D E F G DP
Figure 10: A 2-digit common anode digit with resistors (and a decimal point)
21