一、项目介绍
树莓派想跑AI项目,很好奇满负载跑起来后,温度能飙到多少。于是就计划着用温度传感器、OLED屏幕制作一个能实时查看树莓派CPU温度和周边扇热器外温度显示的项目。借助此次参加FastBond第四季机会完成本项目,本项目创意方向为“感知”
二、硬件介绍
1、温度传感器:这里温度传感器我选用的是亚德诺半导体-Analog Devices出品的EVAL-ADT7420-PMD模块。使用的温度传感器芯片为ADT7420。ADT7420是一款±0.25°C精度的16位数字I²C温度传感器,内置带隙温度基准源、温度传感器和16位ADC,无需用户校准即可实现高精度温度测量。模块使用I2C接口。
2、OLED屏幕:手头有好几片0.69寸OLED屏幕,分辨率为96x16,主控为SSD1306。正好借此机会验证一下屏幕。

温度传感器使用排母与板子相连接。OLED屏幕自带升压,所以电路比较简单,参考着网上的电路,使用fpc座与屏幕连接。整个模块使用一个QWIIC(SH1.0,1mm间距,4P接口)接口与主控连接。


完成后的板子

焊接好板子后,将整个模块黏在树莓派的板子上。通过杜邦线与树莓派的引脚相连接。
模块引脚 | 树莓派引脚 |
3V3 | 1 |
GND | 6 |
SDA | 3 |
SCL | 5 |

三、系统实现

系统循环读取传感器温度,然后在OLED屏幕上显示。读取温度有两部分,一块是读取ADT7420的温度,这部分通过I2C总线读取。一块是读取树莓派CPU温度,这部分通过系统的文件系统读取。OLED显示是通过I2C总线控制,将屏幕划分为左右两个部分,左边显示ADT7420读取到的温度,右边显示CPU当前的温度,都保留一位小数,每秒刷新1次。

编程使用python编程,在树莓派下使用python编程还是很轻松的。
首先确保EVAL-ADT7420-PMD模块和OLED屏幕能被系统识别到(连个设备都是通过I2C总线接入系统):

使用smbus扩展包来读取EVAL-ADT7420-PMD模块,要预先安装smbus包(pip install smbus)。建立读写ADT7420的类库。
class ADT7420:
def __init__(self, bus_num=1, addr=ADT7420_ADDR):
self.bus = smbus2.SMBus(bus_num)
self.addr = addr
def begin(self):
"""初始化传感器,设置为16位模式"""
# 读取ID寄存器确认设备存在
try:
device_id = self.bus.read_byte_data(self.addr, ADT7420_REG_ID)
print(f"Device ID: 0x{device_id:02X} (ADT7420应为0xCB)")
except Exception as e:
print(f"无法读取设备ID: {e}")
return False
# 配置为16位模式 (0x80 = 16位温度转换模式)
# 配置寄存器位7: 0=13位模式(默认), 1=16位模式
self.bus.write_byte_data(self.addr, ADT7420_REG_CONFIG, 0x80)
# 验证配置
config = self.bus.read_byte_data(self.addr, ADT7420_REG_CONFIG)
print(f"Config register: 0x{config:02X}")
return True
def read_temperature(self):
"""
读取温度值
返回: 摄氏度(float), 失败返回None
"""
try:
# 读取2字节温度数据 (MSB先)
# 使用read_i2c_block_data更可靠
data = self.bus.read_i2c_block_data(self.addr, ADT7420_REG_TEMP_MSB, 2)
msb = data[0]
lsb = data[1]
# 合并为16位数据
raw_temp = (msb << 8) | lsb
# 判断正负 (位15是符号位)
if (raw_temp & 0x8000) == 0:
# 正温度
temperature = raw_temp / 128.0
else:
# 负温度,补码转换
temperature = (raw_temp - 65536) / 128.0
return temperature
except Exception as e:
print(f"读取温度失败: {e}")
return None
def close(self):
"""关闭I2C总线"""
self.bus.close()
CPU温度的读取直接访问对应的设备文件即可获取。
def read_cpu_temp():
"""读取CPU温度,返回摄氏度"""
try:
with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
temp_str = f.read().strip()
# 数值是毫摄氏度,除以1000
temp_c = int(temp_str) / 1000.0
return temp_c
except Exception as e:
print(f"读取失败: {e}")
return None
OLED屏幕使用LUMA开源工具来进行驱动。预先安装一下(pip install luma),字体就直接使用系统自带的字体。
# 初始化I2C1 (SDA=GPIO2, SCL=GPIO3)
serial = i2c(port=1, address=0x3C)
device = ssd1306(serial, width=96, height=16)
# 加载字体(小字体更适合96x16)
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 18)
except:
font = ImageFont.load_default()
最终循环绘制温度信息。
try:
while True:
temp = sensor.read_temperature()
cputemp=read_cpu_temp()
if temp is not None:
print(f"温度: {temp:.2f}°C ",f"CPU: {cputemp:.2f}°C ")
device.clear()
with canvas(device) as draw:
draw.text((0, 0), "{:.1f}".format(temp)+" | "+"{:.1f}".format(cputemp), fill="white", font=font)
else:
print("读取失败")
time.sleep(1) # 每秒读取一次
四、效果展示
系统启动后,登录树莓派5。启动温度监控进程。这里使用nohup方式,将进程转为精灵进程,这样退出终端后,进程依旧存在。
nohup python disptemp.py &

使用stress工具让CPU满负荷跑起来。可以看见CPU虽然温度起来了,但是风扇开始工作,板子周围的环境温度反倒下降了。

结束CPU满负荷运行,温度开始下降。

五、心得体会:
感谢得捷和硬禾科技共同举办的FastBond活动,看着手头攒的一些元器件能够转换成具体的项目,成就感满满!借助参加活动的机会,动手学习电子知识,还能结识很多老师!非常感谢!