Displaying a Rasberry Pi's CPU Temperature with a 4 Digit 7 Segment Display
Image linked from: Adafruit product website |
The Rasberry Pi is a great, affordable platform for creating demonstrations for kids about various computing challenges. For example, the Tiny Titan project by the Department of Energy's Oak Ridge National Laboratory visually teaches how multicore computing works using 9 Rasberry Pis linked together. You can build your own Tiny Titan following Oak Ridge National Lab's instructions on GitHub. Now if only they would publish instructions on summoning the Demogorgon from the Upside Down alternate reality....
This temperature tutorial was inspired by the Tiny Titan project which include a demonstration showing how speeding up processors and increasing the processing load generates more heat (pdf - see page 25). The demonstration allows an interactive exploration of what mitigations can be done for cooling. However, simply showing kids textual screen output like:
pi@raspberrypi ~ $ vcgencmd measure_temp
temp=35.8'C
or
pi@raspberrypi ~ $ cat /sys/class/thermal/thermal_zone0/temp
35780
is kind of boring (and requires continually querying from the command-line), whereas hooking up an external display module that continuously updates itself allows for a more interactive and non-distracting presentation.
Unfortunately, most of the on-line tutorials for doing this were old with outdated packages and buggy code. So here's an updated procedure (based on Adafruit's legacy tutorials) for using the HT16K33 display.
Parts List:
- Raspberry Pi Model B+ 512MB RAM
- Adafruit 1.2" 4-Digit 7-Segment Display w/I2C Backpack - Red
- Premium Female/Female Jumper Wires - 40 x 6"
Helpful Additional Parts:
- HDMI Monitor
- HDMI Cable
- USB Keyboard
- Nine Inch Nails blasting in the background
Solder the HT16K33
Image linked from: Adafruit product website |
The 7 Segment display and it's HT16K33 controller will arrive as separate components. Prior to soldering the components together, ensure the display and controller are properly oriented. Lay the display so that its digits are visible on the top with the pins facing downward. Rotate the display so that the side colon ":" is to the left. Now lay the controller board with the chip on the bottom of the PCB. Rotate the controller so the "1.2" 7-segment LED HT16K33 Backpack" text is readable, right-side-up, on the bottom edge. With the components properly oriented, simply align the 8 pins on each side (16 total) of the display with the 8 holes (16 total) on the HT16K33 and push them together. Follow proper soldering technique and solder each pin to its corresponding location.
Finally, insert the 5 pin jumper to the HT16K33 controller's header slots. Again, follow proper soldering procedures and secure each pin to the controller's PCB.
Connect the HT16K33
Image linked from: RasberryPi.org documentation website |
Use five female-to-female jumper wires to connect the pins from the HT16K33 to the Rasberry Pi's General Purpose IO (GPIO) pins.
HT16K33 Pin | GPIO Pin |
---|---|
SCL | Pin 5 - GPIO |
SCA | Pin 3 - GPIO |
GND | Pin 6 - Ground |
+5V | Pin 4 - 5V |
V_10 | Pin 1 - 3.3V |
Configure the Rasberry Pi
As always when installing packages, make sure the apt repository is up to date:
sudo apt-get update
The inter-integrated circuit (I2C) library is necessary for interfacing with I2C devices. I2C is a serial protocol designed for allowing digital circuits to communicate with one another using only two wires. Install the necessary system libraries:
sudo apt-get install -y i2c-tools
From the python.org website: "Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together." Install the essential python development packages and serial bus libraries:
sudo apt-get install -y git build-essential python-dev python-smbus
Install the Adafruit LED Backpack code library which supports the 7 segment LED display and 8x8 matrix displays:
git clone https://github.com/adafruit/Adafruit_Python_LED_Backpack.git
cd Adafruit_Python_LED_Backpack
sudo python setup.py install
Finally, enable the I2C interface on the Rasberry Pi using the raspi-config
utility (run as sudo
of course).
- Select
Advanced Options
- Select
I2C
- Select
YES
to enable - Select
OK
to enable on boot - Select
Finished
and reboot the Rasberry Pi
After rebooting, confirm the I2C interface is functioning using the sudo i2cdetect -y 1
command. If everything is working, the Rasberry Pi will display a matrix of the GPIO pins and attempts to detect connected devices.
Program the Rasberry Pi
The following code is based on the example from Adafruit's Large Pi-based Thermometer and Clock. This version removes irrelevant code for handling the external DS1307 real-time clock and external DS18B20 digital temperature probe. This version also corrects a logic bug where temperatures between 100-109 degrees failed to display the "tens" digit. Create the following Python program file with your favorite editor:
import os
import time
from Adafruit_LED_Backpack import SevenSegment
import RPi.GPIO as io
import subprocess
io.setmode(io.BCM)
switch_pin = 18
io.setup(switch_pin, io.IN)
#Initialize the Display
segment = SevenSegment.SevenSegment(address=0x70)
segment.begin()
#Load the Raspberry's Modules for General Purpose IO
os.system('modprobe w1-gpio')
def read_temp_raw():
#Read the CPU temperature from the system
f = open('/sys/class/thermal/thermal_zone0/temp', 'r')
data = f.read()
f.close
#Strip the newline character and convert the string into an integer
temp = int(data.strip())
return temp
def read_temp():
temp = read_temp_raw()
#scale the system value into Celsius
temp_c = float(temp) 1000.0
#convert the system value into Fahrenheit
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f
def display_temp():
segment.set_colon(False)
#Comment the undesired temperature unit
temp = int(read_temp()[0]) #Celsius
temp = int(read_temp()[1]) #Fahrenheit
#Process the temperature into distinct digits
temp = abs(temp) #compensate for negative numbers
digit_1 = temp % 10 #calculate ones digit
temp = temp / 10
digit_2 = temp % 10 #calculate tens digit
temp = temp / 10
digit 3 = temp % 10 #calculate hundreds digit
#Turn off inactive segments (e.g. hundreds digit if temp is < 100, etc.)
if digit_3 == 0:
segment.set_digit_raw(0, 0)
if digit_3 == 0 and digit_2 == 0:
segment.set_digit_raw(1, 0)
#Activate ones digit
segment.set_digit(2, digit_1)
#Activate tens digit
if digit_3 == 0 and digit_2 > 0:
segment.set_digit(1, digit_2)
#Activate hundreds digit
if digit_3 > 0:
segment.set_digit(0, digit_3)
segment.set_digit(1, digit_2)
#Comment the undesired temperature unit
segment.set_digit_raw(3, 0x39) #Celsius
segment.set_digit_raw(3, 0x71) #Fahrenheit
while True:
segment.clear()
display_temp()
segment.write_display()
time.sleep(0.5)
Execute the Code
Before running the Python script, it's necessary to load the I2C kernel module. Without running this command, the script will throw an error "Error: Could not open file `/dev/i2c-1' or `/dev/i2c/1': No such file or directory
" about a missing device.
sudo modprobe i2c_dev
With the kernel module loaded, simply execute the Python script:
sudo python cputhermo.py
Now observe the CPU temperature update every half second (as per the time.sleep(0.5)
instruction. The demonstration's effect can now be shown with the Rasberry at its default clock speed, 700Mhz while idling and at full load. Subsequently, use the raspi-config
utility to overclock the Rasberry Pi up to "turbo" at 1Ghz and repeat the idle and full load experiments. Lastly, with the Rasberry Pi running hot, experiment with various cooling methodologies such as heat sinks, active fans, and even mineral oil submersion.