树莓派PWM风扇控制

927次阅读
5条评论

首先声明:极客物联吧帖子也是本人发布,非搬运。

马上夏天了,很多小伙伴的树莓派肯定也是热的不行了吧?我的也是,这代虽然说性能是增强了不少,但是发热也随之增大了不少。原来我是直接贴了几个散热片了事,正常使用情况下,冬天温度也才40-50度左右。最近想搞搞人脸识别,又入手了一个树莓派,也顺便买了一个散热小风扇,但是这个风扇是没有PWM调速的。本着生命不息,折腾不止的心态,既然本身不带,树莓派有这么好的条件,GPIO完全是可以用上的。

其实是以前就折腾过,不过再次翻出来来而已,顺便整理一下代码和文章。

某宝上面有这么一个小玩意儿,可以方便的用来控制风扇。嫌贵或者挡住了也可以自己用NPN三极管做一个,风扇+极直接接在5v上,-极接在三极管集电极C。三极管发射极E接0V,基极B接GPIO3。

树莓派PWM风扇控制

这玩意用到了GPIO3,wiringpi编码为8。

树莓派PWM风扇控制
PI GPIO

然后就是为风扇控制编写代码了,以下代码用C语言编写,直接拿来主义就是了。原理也很简单,就是获取CPU温度,然后判断CPU处于哪个阶段,再设置对应的PWM脉冲宽度即可。

/*
 *
 * main.c
 *
 * Created on: 2017年7月24日
 *
 * 说明:程序使用的是wiringPi。PWM接口为8
 *
 * Author: afirefish
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <wiringPi.h>
#include <softPwm.h>
#define _FANPIN 8
#define MAX_SIZE 32
#define TEMP_PATH "/sys/class/thermal/thermal_zone0/temp"

int initWiringPi();
float getCpuTemp();
void dieError( char *errors );

int main( void ) {
	/* 初始化 */
	if ( initWiringPi() < 0 ) {
		return(-1);
	}
	printf( "[ OK ]Start [quarkbook.com] fan controler.\n" );
	/* 启动时防止风扇卡死,全功率运行1s */
	softPwmWrite( _FANPIN, 99 );
	delay( 1000 );
	while ( 1 ) {
		/* 获取CPU温度 浮点数据 */
		float temp = getCpuTemp();
		printf( "CPU tempreture is %0.2f\n", temp );
		/* 如果小于0,说明获取失败,设置50%电压 */
		if ( temp < 0 ) {
			softPwmWrite( _FANPIN, 50 );
		} else if ( temp < 30 ) {
			softPwmWrite( _FANPIN, 0 );
		} else if ( temp > 30 && temp < 40 ) {
			softPwmWrite( _FANPIN, 30 );
		} else if ( temp > 40 && temp < 50 ) {
			softPwmWrite( _FANPIN, 40 );
		} else if ( temp > 50 && temp < 60 ) {
			softPwmWrite( _FANPIN, 50 );
		} else {
			softPwmWrite( _FANPIN, 80 );
		}
		delay( 1000 );
	}
	return(0);
}

/*
 *
 * 初始化wiringPi
 *
 */
int initWiringPi() {
	if ( wiringPiSetup() != 0 ) {
		dieError( "WiringPi setup failed!" );
		return(-1);
	}
	if ( softPwmCreate( _FANPIN, 0, 100 ) != 0 ) {
		dieError( "GPIO soft pwm setup failed!" );
		return(-2);
	}
	return(0);
}

/*
 *
 * 获取树莓派CPU温度
 *
 */
float getCpuTemp() {
	int fd;
	float temp = 0;
	char buf[MAX_SIZE];
	/* 打开/sys/class/thermal/thermal_zone0/temp */
	fd = open( TEMP_PATH, O_RDONLY );
	if ( fd < 0 ) {
		dieError( "Failed to open thermal_zone0/temp" );
		return(-1);
	}
	/* 读取内容 */
	if ( read( fd, buf, MAX_SIZE ) < 0 ) {
		fclose(fd);
		dieError( "Failed to read temp\n" );
		return(-1);
	}
	fclose(fd);
	/* 转换为浮点数打印 */
	temp = atoi( buf ) / 1000.0;
	return(temp);
}

/*
 *
 * 输出错误信息
 *
 */
void dieError( char *errors ) {
	if ( strlen( errors ) <= 0 ) {
		return;
	} else {
		printf( "[ FAILED ]%s\n", errors );
	}
}

很简单的C语言代码。创建一个.c的文件,然后将上述代码粘贴到创建的文件中。

nano fan_controler.c

然后编译。

sudo gcc fan_controler.c -o fan_controler -lwiringPi

因为用到了wiringPi,所以需要引用wiringPi。如果没有任何错误提示,即表示编译成功。先来测试一下,运行编译好的代码:

sudo ./fan_controler

可以看到控制台已经输出温度了,如果接线正确,风扇转速应该也随之降低了。

树莓派PWM风扇控制

然后就来配置后台运行和开机启动,我们将刚刚编译好的代码作为服务运行。

sudo cp fan_controler /usr/bin/
sudo nano /etc/systemd/system/fan-control.service  #编写服务

将下面的代码粘贴到fan-control.service中:

[Unit]
Description=Fan Controller

[Service]
WorkingDirectory=/usr/bin/
ExecStart=/usr/bin/fan_controler
Restart=always
SyslogIdentifier=Fan Controller
User=root

[Install]
WantedBy=multi-user.target

启动服务。

sudo systemctl start fan-control.service  #启动

查看服务的运行状态

sudo systemctl status fan-control.service  #状态

显示Active即表示服务已经正常启动了。然后设置服务开启自动启动。

sudo systemctl enable fan-control.service  #设置开机启动

到此,PWM小风扇就打造完成了,是不是so easy啦~

附录:

1、服务管理命令

sudo systemctl stop fan-control.service  #停止
sudo systemctl disable fan-control.service  #关闭开机启动

afirefish
版权声明:本站原创文章,由afirefish2021-02-26发表,共计2923字。
转载提示:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(5条评论)
载入中...
qcgzxw 评论达人 LV.1
2021-03-19 23:40:21 回复

sudo下执行 无法控制小风扇
普通用户却可以 这是可能是什么原因 :redface:

qcgzxw 评论达人 LV.1
2021-03-19 23:48:41 回复

闹了半天找到问题了 原来是gpio版本问题
pi@raspberrypi:~/Desktop $ gpio readall
Oops – unable to determine board type… model: 17
pi@raspberrypi:~/Desktop $ gpio -v
gpio version: 2.50

gpio默认最新版本为2.50
我的设备是Raspberry Pi 4B 会报错“Oops – unable to determine board type… model: 17”
解决方法:手动更新到gpio最新版2.52即可
https://project-downloads.drogon.net/wiringpi-latest.deb

    管理员 博主
    2021-03-22 14:46:18 回复

    @qcgzxw 这个倒没有注意,好想我的树莓派上面没有遇到这个问题。或者也可以通过apt dist-upgrade解决?

qcgzxw 评论达人 LV.1
2021-03-21 22:59:40 回复

function getCpuTemp()
函数结束之前使用close关闭 文件流
不关闭的话长时间运行可能会有问题

    管理员 博主
    2021-03-22 14:38:58 回复

    @qcgzxw 感谢指出问题,已经修改。