A countdown counter with the MAX7221 and a seven-segment display
3, 2, 1 … Go!
Build a countdown counter with a Raspberry Pi and some electronics, and you can count down the time to any event.
Days until Christmas, time until retirement: We count the days to many events in life. A countdown counter can help make the time to wait fly by and increase anticipation. In this article, I show you how to use the Raspberry Pi as a control unit to build a chic countdown counter based on an LED segment display.
To ensure that the countdown can be seen from a distance easily, a large seven-segment Kingbright SC08-11SRWA [1] display (20.32mm/0.8 inch high) is used to display the remaining days to an event. The LEDs use a common cathode, which makes the display compatible with a MAX7221 display driver.
The combination of parts used here requires the use of a soldering iron. Completely assembled modules that match the capabilities of the MAX7221 are available, but they have considerably smaller displays of (typically) eight digits. Four digits should be enough for a day countdown (i.e., 9,999 days or more than 27 years). If you really want to count down for a longer period of time, simply add an additional segment to the setup.
MAX7221 Display Driver
In the MAX7221 display driver, an external resistor controls the current for the LEDs. I'll shoot for 33kohm, which results in a current of just under 20mA for one segment of the display. Otherwise, the MAX7221 does not require external wiring. Internally, the display stores the information to be displayed in 8x8-bit RAM.
Table 1 is an overview of the MAX7221 registers and their functions; a data sheet [2] provides further information. The MAX7221 is addressed through the SPI interface. Many microcontrollers are suitable for this purpose – I concentrate on the Raspberry Pi.
Table 1
MAX7221: Register Assignment
Register | Function | Description |
---|---|---|
0x00 |
No-op |
Functionless. In the case of several SPI blocks on one bus, it is used to address only one block. All others receive a no-op. |
0x01 |
Digit0 |
Digit 0 of the display. |
0x02 |
Digit1 |
Digit 1 of the display. |
0x03 |
Digit2 |
Digit 2 of the display. |
0x04 |
Digit3 |
Digit 3 of the display. |
0x05 |
Digit4 |
Digit 4 of the display. |
0x06 |
Digit5 |
Digit 5 of the display. |
0x07 |
Digit6 |
Digit 6 of the display. |
0x08 |
Digit7 |
Digit 7 of the display. |
0x09 |
Decode mode |
Each bit corresponds to one digit of the display (bit 0 = digit 0, etc.). If it is set, the digit works as a segment display; the lower 4 bits of the digit registers are then interpreted as a BCD number. If it is deleted, each segment of the digit can be controlled as a single LED. |
0x0A |
Intensity |
The lower 4 bits of the register control the brightness of the LEDs. |
0x0B |
Scan limit |
The lower 3 bits of the register control which digits of the display are used (0x00 = only digit 0; 0x01 = digits 0 and 1; etc.). |
0x0C |
Shutdown |
Bit 0 = 1: Normal mode, all displays and functions active. Bit 0 = 0: Shutdown mode, all displays off, no response to commands. |
0x0F |
Display test |
Lights all LEDs. |
Circuit Diagram
In the countdown counter circuit diagram (Figure 1), the MAX7221 is the central component. Connected to the four seven-segment displays, it only requires one external component: resistor R1. The complete circuit operates at 3.3V, which is supplied by a type LD1117v33 voltage regulator by STMicroelectronics (input voltage range = 4.3-15V).
The setup is thus quite independent of the voltage source (e.g., a USB power supply, car battery, etc.). Two capacitors buffer fluctuations in the input voltage and counteract the oscillation of the voltage regulator. A header plug joins the connectors of the SPI interface to the Raspberry Pi. Figure 2 shows the complete setup; all components are listed in Table 2.
Table 2
Components
No. | Name | Source | Price/Unit (EUR) |
---|---|---|---|
4 |
SC08-11SRWA 7-segment display |
reichelt.de |
1.15 |
1 |
MAX7221CNG 8-digit LED display driver |
reichelt.de |
5.99 |
1 |
PCB prototype 8x12 |
aliexpress.com |
~1 |
Various small parts |
Craft kit |
2 |
|
Total cost ~EUR20 |
Program
The experimental setup is based on a Raspberry Pi 1 with a current Raspbian image, but the steps described here also work with any other Raspberry Pi model.
First, activate the SPI interface with raspi-config
in 5 Interfacing Options | P4 SPI. After the next reboot, the /dev/spidev0.0
Raspberry Pi device directory contains the SPI device, which can be used as a character-oriented device under Unix.
Listing 1 shows the counter.c
example program, which loads all the libraries used and defines the necessary variables. The write_register()
function (lines 14-17) encapsulates the write()
C function and arranges the parameters accordingly. The main()
function (line 19 to end of code) establishes the connection to the SPI device and sets the speed of the SPI interface. It then initializes the MAX7221 to use digits 0 to 3 in decoder mode and sets the brightness to the maximum.
Listing 1
counter.c
01 #include <fcntl.h> 02 #include <sys/ioctl.h> 03 #include <linux/spi/spidev.h> 04 #include <inttypes.h> 05 #include <stdio.h> 06 #include <time.h> 07 08 static const char *device = "/dev/spidev0.0"; 09 static uint32_t speed = 500000; 10 int handle, diff; 11 time_t ts_now, ts_target; 12 struct tm target; 13 14 void write_register(int handle, uint8_t regi, uint8_t value) { 15 uint8_t tx[] = { regi, value }; 16 write(handle,tx,2); 17 } 18 19 int main() { 20 if ((handle = open(device, O_RDWR)) < 0) { 21 perror("SPI Device Error"); 22 return 1; 23 } 24 if (ioctl(handle, SPI_IOC_RD_MAX_SPEED_HZ, &speed)<0) { 25 perror("SPI Speed Error"); 26 return 1; 27 } 28 // MAX7221-Setup 29 write_register(handle,0x0C,0x01); 30 write_register(handle,0x09,0xFF); 31 write_register(handle,0x0F,0x00); 32 write_register(handle,0x0B,0x03); 33 write_register(handle,0x0A,0x0F); 34 ts_now = time(NULL); 35 target.tm_mday=1; 36 target.tm_mon=4; // Month 1 (Jan = 0) 37 target.tm_year=119; // Year - 1900 38 target.tm_sec=59; 39 target.tm_min=59; 40 target.tm_hour=23; 41 ts_target=mktime(&target); 42 diff=(ts_target-ts_now)/(60*60*24); 43 write_register(handle,0x04,(diff%10000)/1000); 44 write_register(handle,0x03,(diff%1000)/100); 45 write_register(handle,0x02,(diff%100)/10); 46 write_register(handle,0x01,(diff%10)); 47 }
The target
date structure (line 12) generates the timestamp of the target date. This structure has some peculiar characteristics that can cause a great deal of trouble: Days count from 1 and months from 0, and 1900 must be deducted from the year. The values for time of day can be written one to one into the structure.
The remaining lines of the program calculate the difference between the current and target dates and write it to the corresponding memory locations of the MAX7221. By transferring the start of the program to a cronjob (see the "Cron" box), you can start the program once a day, calculate the current display value, and transfer it to the display driver. Save the program and compile it with gcc
(GNU C compiler):
$ gcc counter.c -o counter $ ./counter
The last line runs the program.
Cron
The Unix cron service allows commands and scripts to be executed automatically at certain times. The crontab
command-line tool is used for configuration. Use crontab -l
to see the current settings for the logged in user. The -e
switch puts Crontab in edit mode. An entry contains, separated by white space, the specifications for minute, hour, day of the month, month, and weekday, as well as the command to be executed at the specified time.
The first five parameters control execution time. Numbers stand for times or dates and an asterisk for any given minute, hour, or day. If necessary, you can also use a backslash to define multiple values (e.g., */2
for every second minute). As far as timing is concerned, it is important to ensure that one call can be processed before the next initiates; otherwise, the system will become overloaded over time.
The following are some typical cron examples:
* * * * * /home/user/script # every minute 0 */2 * * * /home/user/script # at the start of every other hour 0 0 * * * /home/user/script # every day at midnight 30 18 * * * /home/user/script # every day at 6:30pm * * 1 * * /home/user/script # every minute on the first day of the month
Further detailed information can be found on the cron man page. Useful pages on the web, such as at Corntab [3], can help you to compose cron lines. You need to make sure that cron executes scripts with the rights of its own user account but does not use environment variables. To do this, specify all paths in full and do not use aliases.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.