树莓派在跑编译任务、当下载机或者做家庭服务器时,最让人头疼的问题之一就是过热降频。官方固件里写得很清楚:CPU温度达到85摄氏度时会强制降低主频,温度继续攀升还可能触发更严厉的保护机制。降频之后性能可能只剩原来的一半,编译一个大项目的时间直接翻倍。解决思路其实就两条:一是把热量尽快导走,也就是加强被动散热;二是让风扇在需要的时候才转,避免全天候嗡嗡响。下面结合实际动手经验,把散热片选型、电路接法和控制脚本一次讲清楚。

先弄清楚降频是怎么发生的
树莓派的温控逻辑由固件负责,用户态无法直接关闭。以BCM2711(4代SoC)为例,温度阈值大致是这样:60到70摄氏度之间开始限制最大频率的幅度,85摄氏时触发热节流,主频会被压到最低档位。想要知道自己的板子有没有正在降频,最直接的办法是查询throttled状态位。
vcgencmd get_throttled # 输出 0x0 表示一切正常 # 常见位含义: # 0x1 曾触发欠压 # 0x2 当前欠压 # 0x4 曾触发降频 # 0x8 当前正在降频
如果返回值包含0x8,说明此刻CPU正在被热节流,散热问题已经很严重了。平时监控温度可以写一个简单的循环脚本,用vcgencmd measure_temp每秒采样一次,观察高负载时的温度曲线,为后面调风扇阈值提供数据依据。
while true; do
temp=$(vcgencmd measure_temp | grep -o '[0-9.]*')
echo "$(date +%T) 温度: ${temp}°C 节流: $(vcgencmd get_throttled)"
sleep 1
done另外要注意供电的影响。throttled状态里的欠压位同样会导致降频,很多人以为是温度问题,换了三套散热片温度还是降不下来,最后发现是电源线太细压降过大。排查时先确认电源输出稳定(建议5V3A以上),再谈散热才有意义。
散热片选型与安装要点
树莓派4B和5的主板上需要重点照顾的芯片有三颗:SoC主芯片、内存芯片(如果是POP封装则和SoC叠在一起)、以及USB控制芯片。4代的USB控制器发热相当可观,只给主芯片贴散热片往往压不住温度。
材质方面,市面上主流有铝制、铜制和铜铝结合三种。纯铜导热系数约400 W/(m·K),是铝(约237)的近两倍,但铜的比热容大、重量也大,贴在小芯片上未必有优势。实际测试下来,同样体积的纯铜散热片和铝合金散热片,满载时温差通常在3到5摄氏度之间。如果机箱空间紧张,铜铝复合款是折中选择:铜底座快速吸热,铝鳍片负责散热,性价比不错。
安装时有两个细节容易被忽略。第一是导热介质,最推荐相变化导热片或者信越7921之类的硅脂,廉价硅胶垫导热系数只有零点几,效果很差。第二是鳍片方向,如果机箱内有风扇,尽量让气流方向顺着鳍片缝隙吹过,形成穿堂风,而不是垂直撞在鳍片顶端。散热片本身的安装不难,撕掉背胶对准芯片压实即可,注意不要让散热片挤压到旁边的电容,也不要盖住天线区域。
被动散热的上限也要认清。一套好的散热片加金属外壳,可以让4B在轻负载下保持在55摄氏度左右,但持续满载(比如长时间编译)很难稳在70摄氏度以下。想要满血性能,风扇仍然是绕不开的。
风扇PWM智能控制脚本
直接把风扇接在5V上全程全速运转是最省事的做法,但噪音大、灰尘积累快,夜深人静时尤其烦人。借助PWM调速,让风扇转速随温度变化,体验会好很多。
电路连接
推荐使用树莓派的硬件PWM引脚GPIO18(物理引脚12),配一颗NPN三极管(如S8050)或者一块MOS管模块来驱动风扇,因为GPIO引脚最大只能输出约16毫安,直驱小风扇有烧引脚的风险。风扇用5V供电,负极接到三极管集电极,发射极接地,GPIO通过1K电阻接到基极。别忘了在风扇两端并联一颗二极管(1N4148即可)防反峰,防止电机感性负载损坏三极管。
控制脚本
下面是完整的Python控制脚本,读取核心温度后按区间映射到占空比,并带滞后逻辑避免风扇在阈值附近频繁启停:
import subprocess
import time
try:
import RPi.GPIO as GPIO
except RuntimeError:
print("请以 sudo 权限运行脚本")
raise
FAN_PIN = 18
TEMP_LOW = 50 # 低于此温度风扇停转或最低速
TEMP_HIGH = 70 # 高于此温度风扇全速
HYST = 3 # 滞后区间,防止频繁切换
GPIO.setmode(GPIO.BCM)
GPIO.setup(FAN_PIN, GPIO.OUT, initial=False)
pwm = GPIO.PWM(FAN_PIN, 25000) # 25KHz超出人耳听觉范围,避免啸叫
pwm.start(0)
def read_temp():
out = subprocess.check_output(
["vcgencmd", "measure_temp"], text=True)
return float(out.split("=")[1].split("'")[0])
def duty_for(temp):
if temp <= TEMP_LOW:
return 0
if temp >= TEMP_HIGH:
return 100
# 线性映射 50~70 度到 20%~100% 占空比
ratio = (temp - TEMP_LOW) / (TEMP_HIGH - TEMP_LOW)
return int(20 + ratio * 80)
try:
while True:
t = read_temp()
d = duty_for(t)
pwm.ChangeDutyCycle(d)
print(f"温度 {t:.1f}°C, 占空比 {d}%")
time.sleep(3)
except KeyboardInterrupt:
pass
finally:
pwm.stop()
GPIO.cleanup()几个参数解释一下。PWM频率设为25KHz是有讲究的:低频PWM会让风扇发出明显的电磁噪音,把频率抬到人耳听不到的频段就安静了。占空比最低设为20%而不是0,是因为大部分小风扇低于额定电压的一定比例就转不动了,硬给低占空比只会让它卡住嗡嗡响。线性映射区间50到70度可以按自己设备的情况调整,建议先用前面提到的监控脚本跑一天温度日志再定。
想让脚本开机自启,可以写成systemd服务:
[Unit] Description=Fan PWM Controller After=multi-user.target [Service] ExecStart=/usr/bin/python3 /opt/fanctl/fan.py Restart=always [Install] WantedBy=multi-user.target
保存为/etc/systemd/system/fanctl.service后执行systemctl enable --now fanctl即可。
验证效果与进一步优化
方案装好后,用stress-ng --cpu 4 --timeout 600s压测十分钟,同时跑温度监控脚本对比前后数据。比较理想的結果是:满载温度稳定在65到70摄氏度之间,throttled状态始终保持0x0,风扇转速随负载平滑变化。
如果还想再压温度,可以考虑调整config.txt里的参数,比如为树莓派4B设置arm_freq=1600锁频、适当降低GPU显存分配(gpu_mem=16)减少视频核心发热。再进一步就是机箱风道设计,在外壳上开进出风口形成对流,比单纯堆散热片有效得多。对于树莓派5,官方主动散热器已经做得比较到位,预算允许的话直接上官方方案省心不少。
最后提醒一点:树莓派5的部分GPIO供电策略和4代不同,风扇电流较大时建议独立供电或使用官方风扇接口,避免从GPIO排针取电导致的不稳定。整体来说,几十块钱的散热片加一个PWM小风扇,配合上面的控制脚本,基本可以让树莓派长期满血运行,性价比远超各种花哨的成品散热套装。