首页 > 技术文章 > 树莓派风扇自动控制随想

weilinfox 2021-02-05 15:43 原文

2021-02-05

最近要把树莓派扔家里一直开着,我呢上学去。风扇一直开着又吃灰又吵闹,“那就让它自动控制吧”,我想着:“它已经是个成熟的派了”。可不嘛,3B都五岁了。

自动控制的电路嘛,这不是网上一搜一大把,比如下面这个。

网上的电路

看起来不错,我加了两个指示灯,在面包板上搭了一圈,好家伙,这风扇开启时候也不是全速运行,关闭的时候假死,负载一高电压不稳(电源适配器也有一份锅)就开始震动……摘掉两个led确定不是加灯导致的问题,啥玩意啊……

其锅还是在于风扇接在了三极管的发射级,导通时s8550并没有工作在饱和区,截止时也没有完全截止;但是如果把风扇接在集电极,3.3v的电平不足以让发射级截止(5v的风扇),风扇还是会一直转,控制了个寂寞。

似乎一个管子不够用了,毕竟gpio高电平时只有3.3v,基极3.3v发射级5v,怎么想也不会截止吧?于是首先做了一个两管的版本。转念一想,多一个管子虽然性能好了,总什么地方不带劲,我就想办法在基极上加点什么可以分压的东西。如果用电阻,电阻到底是线性的,而且手头没有特性图,没法计算,那就二极管呗,多串几个不就结了……最后突然想到,用发光二极管咋样,反正也要指示灯的,基极电流弄个20mA对s8550来说也不是个事,而且作为非线性器件,截止时候能比较可靠地截止。于是有了下面这个玩意:

我的电路

一用还真可,可以很好地开启和截止,开启时Vec只有0.2v,风扇分到了4.8v的电压,呼啦呼啦的,截止时led熄灭,非常好地截止了。但是不同的led特性相差很大,使用一般的工作电压1.7-2.5v电流20-30mA的led灯,改变R1的大小,总能找到一个合适的点。图上R1只有100欧的缘故是D1使用了一支奇怪的古老发光二极管,实际可以取更大的值,但是应该小于R2。led工作电压电流范围比较大,s8550也具有几十到几百的电流放大系数,成功率还是非常高的。

控制代码如下参考,我使用的是Arch Linux Arm,所以跑的是WiringX。下面的WiringPi示例,可能有错误。注意WiringX和WiringPi的引脚编码是一样的,运行时都需要sudo。

#!/usr/bin/python3
# wiringX 版本
from wiringX import gpio
import time

# raspberrypi3
# 如果是pi4 gpio.setup(gpio.RASPBERRYPI4)
gpio.setup(gpio.RASPBERRYPI3)

# GPIO.1 PIN12
# wiringX 编码同 wiringPi
FAN_GPIO = gpio.PIN1

# 设置 FAN_GPIO 为输出
gpio.pinMode(FAN_GPIO, gpio.PINMODE_OUTPUT)
# 这里初始化一下
gpio.digitalWrite(FAN_GPIO, gpio.LOW)

# 树莓派cpu温度
tempFile = '/sys/class/thermal/thermal_zone0/temp'

while True:
    with open(tempFile, 'r') as temp:
    	tempData = temp.read()
    	cpu_temp = int(tempData) / 1000
    print(cpu_temp)
    # 低电平启动
    if cpu_temp >= 55.0:
    	gpio.digitalWrite(FAN_GPIO, gpio.LOW)
    elif cpu_temp < 40.0:
    	gpio.digitalWrite(FAN_GPIO, gpio.HIGH)

    time.sleep(10)
#!/usr/bin/python3
# wiringPi 版本
import wiringpi
import time

# GPIO.1 PIN12
FAN_GPIO = 1
fan_status = 1
# wiringPi 编码
wiringpi.wiringPiSetup()

# 设置 FAN_GPIO 为输出
wiringpi.pinMode(FAN_GPIO, 1)
# 这里初始化一下
wiringpi.digitalWrite(FAN_GPIO ,0)

# 树莓派cpu温度
tempFile = '/sys/class/thermal/thermal_zone0/temp'

while True:
    with open(tempFile, 'r') as temp:
    	tempData = temp.read()
    	cpu_temp = int(tempData) / 1000
    print(cpu_temp)
    # 低电平启动
    if cpu_temp >= 55.0:
    	wiringpi.digitalWrite(FAN_GPIO ,0)
    elif cpu_temp < 40.0:
    	wiringpi.digitalWrite(FAN_GPIO ,1)

    time.sleep(10)

电路图使用KiCad套件绘制,随便画了画只做参考演示。

by SDUST weilinfox

推荐阅读