树莓派是一个很经典的小主机,实际上现在这个博客现在也是跑在树莓派上的。而树莓派本身是一个被动散热的机器。虽然本身树莓派的CPU有温控限制,但是毕竟也是热得发飙。因此需要重新弄下树莓派的散热方案。
被动散热
网上其实很多被动散热的外壳,直接装上就可以的,有点就是几乎没有任何噪音,但是问题就是其实被动散热的效果特别不好,如果对静音有极致需求的话倒是可以考虑这个方案。
主动散热
主动散热的话效果肯定是最好的,但是会有以下几个问题:
- 由于树莓派的市售外壳一般是mini壳子。所以配备的都是3,4cm直径左右的风扇。这种风扇转速极快因此噪音也极高。日用非常难受。
- 风扇倒是可以PWM调速,但是这里有些技术门槛。
前提
对于树莓派4b的话,一般是使用gpio18来进行pwm调速,以下都是基于gpio18端口来,如果有不一样的可以改成自己要用的端口。
方案1: 基于/boot/config.txt 的
dtoverlay=gpio-fan,gpiopin=18,temp=55000
这个虽然说是gpio,并且调用了pwm模式,但本质上还是以全速运行的,只不过会根据temp设定的温度来定时调度。如上述模式就是55度来启动。
实际上这种模式在和一直运行没区别,只不过是会根据情况来启动,相对来说智能一些。哦还有一个好处这个是系统级的,不用再基于什么东西来后台启动。
方案2 基于python的方式
先上代码吧
#!/usr/bin/env python3
import pigpio
import time
import os
import sys
from datetime import datetime
## 不清楚什么问题,买的双滚珠风扇貌似不支持PWM调速,支持PWM的调度在非全速运行时会有风扇8KHZ的高频啸叫
# 配置参数
FAN_GPIO = 18 # 使用GPIO 18 (物理引脚12)
MIN_TEMP = 55.0 # 风扇开始工作的最低温度 (°C)
MAX_TEMP = 55.0 # 最高温度阈值 (°C)
PWM_MIN = 255 # 最低PWM占空比 (0-255)
PWM_MAX = 255 # 最高PWM占空比 (0-255)
# 自定义温度-风速曲线 (温度: 风速)
# 格式: [(温度, 风速), (温度, 风速), ...]
# 注意: 温度必须按升序排列
TEMP_CURVE = [
(MIN_TEMP, PWM_MIN), # 40°C -> 50%
# (50.0, 150), # 50°C -> 80%
# (55.0, 200), # 55°C -> 120%
#(60.0, 160), # 60°C -> 160%
#(65.0, 200), # 65°C -> 200%
(MAX_TEMP, PWM_MAX) # 80°C -> 255%
]
# 全局变量
pi = None
fan_pwm = None
last_temp = None
def get_cpu_temp():
"""获取CPU温度 (摄氏度)"""
try:
with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
temp = float(f.read()) / 1000.0
return round(temp, 1)
except Exception as e:
print(f"Error reading CPU temperature: {e}")
return 0.0
def get_fan_speed(temp):
"""根据温度获取风扇转速 (0-255)"""
# 1. 确保温度在有效范围内
if temp < MIN_TEMP:
return 0 # 温度太低,关闭风扇
# 2. 确保温度不超过最大阈值
if temp > MAX_TEMP:
return PWM_MAX
# 3. 在温度曲线上查找对应的转速
for i in range(len(TEMP_CURVE) - 1):
if TEMP_CURVE[i][0] <= temp < TEMP_CURVE[i+1][0]:
# 线性插值计算
t1, s1 = TEMP_CURVE[i]
t2, s2 = TEMP_CURVE[i+1]
speed = s1 + (s2 - s1) * (temp - t1) / (t2 - t1)
return int(max(PWM_MIN, min(PWM_MAX, speed)))
# 如果温度超过最后一个点
return PWM_MAX
def setup_fan():
"""初始化风扇控制"""
global pi
pi = pigpio.pi()
if not pi.connected:
print("Failed to connect to pigpiod daemon")
sys.exit(1)
# 设置PWM频率 (通常25kHz是风扇最佳频率)
pi.set_PWM_frequency(FAN_GPIO, 25000)
pi.set_PWM_range(FAN_GPIO, 255) # 设置PWM范围为0-255
# 初始关闭风扇
pi.set_PWM_dutycycle(FAN_GPIO, 0)
print(f"Fan initialized on GPIO {FAN_GPIO} (PWM frequency: 25kHz)")
def cleanup():
"""清理资源"""
if pi:
pi.set_PWM_dutycycle(FAN_GPIO, 0)
pi.stop()
print("Fan control stopped")
def main():
"""主控制循环"""
setup_fan()
try:
print("Starting fan speed control (press Ctrl+C to exit)")
print(f"Temperature curve: {TEMP_CURVE}")
while True:
# 获取CPU温度
temp = get_cpu_temp()
# 获取风扇转速
speed = get_fan_speed(temp)
current_hour = datetime.now().hour
if current_hour in (23,0,1,2,3,4,5,6,7,8):
#睡眠时间,不执行
speed=0
# 更新风扇转速
if speed != last_temp:
pi.set_PWM_dutycycle(FAN_GPIO, speed)
print(f"Temperature: {temp:.1f}°C | Fan speed: {speed}%")
# 等待一段时间 (5秒)
time.sleep(20)
except KeyboardInterrupt:
print("\nShutting down...")
finally:
cleanup()
if __name__ == "__main__":
main()
在这个代码执行前,应该要
sudo pigpiod
来启用pgpiod功能。
代码解析
其实上述代码在比较关键的地方都有解释,日常使用的话 可以在TEMP_CURVE中设定温度转速map。然后pwm转速的是以0-255来定义的,但是要注意的是,有些风扇在极低的PWM频率下是不可运行的,然后有些风扇是压根不能以PWM模式来执行的。比如我上次买的双滚珠风扇压根就不支持255。就相当于是一个更加智能化的模式1罢了。
总结
唉,怎么说呢。树莓派的散热确实是一个挺麻烦的事情,或者其本质就不是一个设计给长时间运行服务器的定位。这几天逛逛拓竹社区看看有没有什么好用的3D打印大机箱,然后上个8厘米低速扇好了。
另外要注意点的是,如果是用PWM风扇的,得好好注意下风扇你兼容性,我最近买的几个3cm的油封风扇在使用pwm模式下,如果不用最高速度,就一直会有8khz左右的高频啸叫,另外一个双滚珠的直接就不支持pwm模式,只能以255模式来跑。
最后
搞了一个摆烂的方法,直接放在nas之后吃硬盘风扇的尾气就算了。