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
-
Thousands of Linux Servers Infected with Stealth Malware Since 2021
Perfctl is capable of remaining undetected, which makes it dangerous and hard to mitigate.
-
Halcyon Creates Anti-Ransomware Protection for Linux
As more Linux systems are targeted by ransomware, Halcyon is stepping up its protection.
-
Valve and Arch Linux Announce Collaboration
Valve and Arch have come together for two projects that will have a serious impact on the Linux distribution.
-
Hacker Successfully Runs Linux on a CPU from the Early ‘70s
From the office of "Look what I can do," Dmitry Grinberg was able to get Linux running on a processor that was created in 1971.
-
OSI and LPI Form Strategic Alliance
With a goal of strengthening Linux and open source communities, this new alliance aims to nurture the growth of more highly skilled professionals.
-
Fedora 41 Beta Available with Some Interesting Additions
If you're a Fedora fan, you'll be excited to hear the beta version of the latest release is now available for testing and includes plenty of updates.
-
AlmaLinux Unveils New Hardware Certification Process
The AlmaLinux Hardware Certification Program run by the Certification Special Interest Group (SIG) aims to ensure seamless compatibility between AlmaLinux and a wide range of hardware configurations.
-
Wind River Introduces eLxr Pro Linux Solution
eLxr Pro offers an end-to-end Linux solution backed by expert commercial support.
-
Juno Tab 3 Launches with Ubuntu 24.04
Anyone looking for a full-blown Linux tablet need look no further. Juno has released the Tab 3.
-
New KDE Slimbook Plasma Available for Preorder
Powered by an AMD Ryzen CPU, the latest KDE Slimbook laptop is powerful enough for local AI tasks.