树莓派几种不同的PWM及其应用

树莓派上PWM其实应用的不多,很多例子都是简单地用代码控制小灯地闪亮黯淡过程,这在我之前刚接触硬件时充满懵懂的脑子面前显得十分新奇,后来慢慢懂了PWM,很多时候用在步进马达上,后来,慢慢过了半年后,我才发现一个问题,当树莓派有发热现象,传统地调用树莓派PWM功能时,步进马达总是怪怪的,转的不是很规律,有点性能跟不上的感觉。深入进去,发现PWM有多东西,这次就趁机总结一下,方便以后使用。

1. 树莓派上PWM的分类

1.1 Fully hardware PWM (全硬件PWM)

这种类型的PWM由树莓派的PWM外设产生。脉冲的时序由PWM外设控制。它是最准确的,而且可以说是最灵活的。
它可以在GPIO 12/13/18/19上生成。但是,只有两个通道,因此一次只能生成两个不同的PWM流。GPIO 12/18在一个通道上,GPIO 13/19在另一个通道上。
适用于无抖动的伺服,无干扰的LED亮度控制,电机速度控制。

1.2 DMA timed PWM (DMA定时PWM)

这种类型的PWM由树莓派的DMA外设产生。
脉冲的时序由DMA控制。它的定时精度不如完全硬件的PWM精确,但比软件定时的PWM精确得多。取决于实现方式,它不如完全硬件的PWM灵活,例如,频率的数量要受限制得多,开和关之间的步数要受限制得多。
此类PWM可以在扩展头上的任何GPIO上生成。所有GPIO可能具有不同的设置。
适用于无抖动的伺服,无干扰的LED亮度控制,电机速度控制。

1.3 Software Timed PWM (软件定时PWM)

这种类型的PWM由软件生成。
脉冲的时序由(Linux)调度程序控制。与完全硬件PWM或DMA定时PWM相比,它的定时精度明显降低。它比DMA定时PWM灵活得多,并且与完全硬件PWM一样灵活,例如,频率数量是无限的,开和关之间的步数是无限的。
此类PWM可以在扩展头上的任何GPIO上生成。所有GPIO可能具有不同的设置。时序精度将根据用于PWM的GPIO数量而变化。
不太适合伺服器,可以控制LED的亮度,但会出现毛刺,适合于电机速度控制。

脉冲稳定性当然是:全硬件PWM >> DMA定时PWM >> 软件定时PWM

2. 树莓派上PWM的实现方式

2.1 传统的实现方式

手动sleep来实现pwm功能,步进马达连接与传统实现可以看这里

1
2
3
4
5
6
7
8
9
10
while True:
print ("Move Backward")
for i in range (5*200):
GPIO.output(LinearActuatorDir, 0)
GPIO.output(LinearActuatorStepPin, 1)
time.sleep(LowSpeed)
GPIO.output(LinearActuatorStepPin, 0)
time.sleep(LowSpeed)
print ("Moving")
...

2.2 神级武器gpiozero

这里我们可以用gpiozero中的PWMOutputDevice类

1
2
# 初始化完即运行,initial_value为占空比,frequency为频率
p = PWMOutputDevice(pin, *, active_high=True, initial_value=0, frequency=100, pin_factory=None)

注意,这里有一个点,pin_factory=None一般情况下默认使用的是RPi.GPIO,而RPi.GPIO默认的PWM是Software Timed PWM,所以可能稳定性不太好,所以我们可以使用factory = PiGPIOFactory(host='127.0.0.1')PiGPIO支持DMA timed PWM,这个比较好

2.3 庞大的pigpio (不推荐新手)

piggio python库中的set_PWM_dutycycle函数和hardware_PWM函数分别对应DMA,以及Fully hardware,这里不做过多阐述,自己也不是很懂 =。= ,有点尴尬,感觉相对于gpiozero稍微有点麻烦,可以看两者区别pigpio文档