14. pwm(脉宽调制)

本章讲解Linux pwm相关应用层程序控制。

本章的示例代码目录为:base_linux/pwm

14.1. 脉宽调制

14.1.1. 什么是PWM

PWM(Pulse Width Modulation)简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术, 广泛应用在测量、通信、工控等方面。

14.1.2. PWM的频率

是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位Hz。

14.1.3. PWM的周期

计算公式为:T=1/f,其中T是周期,f是频率。

如果频率为50Hz ,也就是说一个周期是20ms,那么一秒钟就有 50次PWM周期。

14.1.4. 占空比

是一个脉冲周期内,高电平的时间与整个周期时间的比例,取值范围为0-100%

一个周期的长度,如下图所示

未找到图片

其中,周期是一个脉冲信号的时间,1s内的周期T次数等于频率f,脉宽时间是指高电平时间。

上图中,脉宽时间占总周期时间的比例,就是占空比。

例如,假设周期的时间为10ms,脉宽时间为8ms,那么占空比是8/10= 80%,这就是占空比为80%的脉冲信号。

PWM就是脉冲宽度调制,通过调节占空比就可以调节脉冲宽度。

14.1.5. PWM原理

假设高电平为5V、低电平则为0V,那么要输出不同的模拟电压就要用到PWM。

通过改变IO口输出的方波的占空比,从而获得使用数字信号模拟成的模拟电压信号。

电压是以一种脉冲序列被加到模拟负载上去的,接通时是高电平1,断开时是低电平0。

接通时直流供电输出,断开时直流供电断开。通过对接通和断开时间的控制,理论上来讲,可以输出任意不大于最大电压值5V的模拟电压。

比方说,占空比为50%那就是高电平时间一半,低电平时间一半。在一定的频率下,就可以得到模拟的2.5V输出电压。那么75%的占空比,得到的电压就是3.75V,如下图所示。

未找到图片

14.2. pwm引脚

LubanCat-H618系列板卡上集成了一个具有pwm功能的GPIO,该PWM引脚与板载的FAN接口共用。下图为鲁班猫A1的PWM引脚。

未找到图片

由于LubanCat-H618系列板卡的PWM控制器可能会不一样,具体引脚可以查看 — LubanCat-H618系列-26pin引脚对照图

14.2.1. 使能PWM接口功能

PWM接口在默认情况是关闭状态的,需要使能才能使用, 下面的使能操作以 PWM1 为例

14.2.1.1. 方法一

可以通过打开 /boot/uEnv.txt 查看是否启用了pwm相关设备设备树插件。

编辑文件,选择需要开启的pwm设备树插件,粘贴到 overlays= 后面,多个设备树插件开启,设备树插件之间要用空格隔开,如下图:

未找到图片

然后重启激活设备

注解

如果是通过直接拔插电源的方式重启,会有可能出现文件没能做出修改 (原因:文件未能及时从内存同步到存储设备中,解决方法,在终端上输入 “sync” 同步修改之后再拔插电源重启)

14.3. PWM控制方式(shell终端)

下面操作以pwm1为例

注意

在操作前必须先打开设备树插件,重启使能pwm1引脚

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#将pwm1导出到用户空间
echo 1 > /sys/class/pwm/pwmchip0/export

#设置pwm周期 单位为ns
echo 1000000 > /sys/class/pwm/pwmchip0/pwm1/period

#设置PWM周期中“ON”的时间,单位为ns,即占空比=duty_cycle/period=50%。
echo 500000 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle

#设置pwm极性,正常normal,反相inversed
echo "normal" > /sys/class/pwm/pwmchip0/pwm1/polarity

#使能pwm
echo 1 > /sys/class/pwm/pwmchip0/pwm1/enable

#取消将pwm1导出到用户空间
echo 1 > /sys/class/pwm/pwmchip0/unexport

提示

当设置period与duty_cycle值的时候需要注意在任何的情况下都得保证:0 ≤ duty_cycle ≤ period。

14.4. cpu风扇案例(shell脚本)

下面操作以pwm1为例,案例内容为根据CPU温度调节风扇转速。

代码位置
1
base_linux/pwm/cpu_pwm.sh

代码较长复制粘贴容易乱序,可以下载我们提供的源码 cpu_pwm.sh

base_linux/pwm/cpu_pwm.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/bash

tempstart=55  # 风扇启动的温度阈值,单位为摄氏度
period=1000000 #PWM周期
cpu_temp1=65 #节点1
cpu_temp1_pwm=50 #节点1占空比,%
cpu_temp2=75 #节点2
cpu_temp2_pwm=80  #节点2占空比,%
cpu_temp3=85 #节点3
cpu_temp3_pwm=100 #节点3占空比,%

#将pwm1导出到用户空间
echo 1 > /sys/class/pwm/pwmchip0/export
#设置pwm周期
sudo echo $period > /sys/class/pwm/pwmchip0/pwm1/period
#设置PWM周期中“ON”的初始时间
echo 0 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
#设置pwm极性
echo "normal" > /sys/class/pwm/pwmchip0/pwm1/polarity
#使能pwm
echo 1 > /sys/class/pwm/pwmchip0/pwm1/enable

while true; do
   temp=$(cat /sys/class/thermal/thermal_zone0/temp)
   temp=$((temp/1000))  # 将温度转换为摄氏度
   
   if ((temp > tempstart)); then
      echo 1 > /sys/class/pwm/pwmchip0/pwm1/enable
      if ((temp < cpu_temp1)); then
         cpu_pwm1=$(( cpu_temp1_pwm*(temp-tempstart)/(cpu_temp1-tempstart)*period/100 ))
         echo $cpu_pwm1 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
         # echo "CPU Temp: ${temp}℃ CPU PWM1: ${cpu_pwm1}"
      elif ((temp > cpu_temp1))&&((temp < cpu_temp2)); then
         cpu_pwm2=$(( ( (cpu_temp2_pwm-cpu_temp1_pwm)*(temp-cpu_temp1)/(cpu_temp2-cpu_temp1)+cpu_temp1_pwm)*period/100 ))
         echo $cpu_pwm2 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
         # echo "CPU Temp: ${temp}℃ CPU PWM2: ${cpu_pwm2}"
      elif ((temp > cpu_temp2))&&((temp < cpu_temp3)); then
         cpu_pwm3=$(( ( (cpu_temp3_pwm-cpu_temp2_pwm)*(temp-cpu_temp2)/(cpu_temp3-cpu_temp2)+cpu_temp2_pwm)*period/100 ))
         echo $cpu_pwm3 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
         # echo "CPU Temp: ${temp}℃ CPU PWM3: ${cpu_pwm3}"
      elif ((temp > cpu_temp3)); then
         cpu_pwm_end=$(( cpu_temp3_pwm*period/100 ))
         echo $cpu_pwm_end > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
         # echo "CPU Temp: ${temp}℃ CPU PWM_END: ${cpu_pwm_end}"
      fi

   else
      echo 0 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
      echo 0 > /sys/class/pwm/pwmchip0/pwm1/enable
      # echo "CPU Temp: ${temp}℃ CPU风扇关闭"
   fi

   sleep 30
done

为了更直观低展示CPU风扇控制效果,可以取消掉32、36、40、44行的注释,并将53行的sleep时间修改为3。

注意

实际使用时,为了减少CPU资源占用,sleep时间可以设置成30秒。

修改完成后,运行以下命令进行测试。

1
2
3
4
5
6
#移除之前导出的pwm1
echo 1 > /sys/class/pwm/pwmchip0/unexport
#赋予可执行权限
chmod +x cpu_pwm.sh
#运行
./cpu_pwm.sh

以下为CPU压测,且未安装CPU主动散热的运行结果:

未找到图片

14.5. 参考声明

本篇文章参考 《PWM原理及其应用》