树莓派4B中降低软件PWM的CPU占用率方案咨询
问题描述
我在树莓派4B上使用C语言的pigpio库,在GPIO引脚5、6、19、26上生成4路8kHz的软件PWM信号,用于控制连接执行器的BTS7960 43A大功率电机驱动模块。目前已成功实现电机的可变占空比控制,但即使控制器无动作时CPU占用率仍高达107%。
软件启动时仅初始化gpioSetPWMfrequency和gpioSetPWMrange函数,在需要改变引脚占空比的循环中调用gpioPWM函数。根据pigpio文档,其采用DMA访问,现寻求降低CPU占用率的方法,以及更合适的替代库。
伪代码如下:
#include <pigpio.h> // 电机1引脚定义 static const int kiShieldFwdPWMIOPin = 5;//21; // 前进PWM引脚 static const int kiShieldBackPWMPin = 6;//22; // 后退PWM引脚 static const int kiShieldENIOPin = 13;//23; // 使能引脚 // 电机2引脚定义 static const int kiColumnFwdPWMIOPin = 19;//24; // 前进PWM引脚 static const int kiColumnBackPWMIOPin = 26;//25; // 后退PWM引脚 static const int kiColumnENIOPin = 12;//26; // 使能引脚 void setup(){ // 初始化PWM频率为8kHz gpioSetPWMfrequency(kiShieldFwdPWMIOPin,8000); gpioSetPWMfrequency(kiShieldBackPWMPin,8000); gpioSetPWMfrequency(kiColumnFwdPWMIOPin,8000); gpioSetPWMfrequency(kiColumnBackPWMIOPin,8000); // 设置PWM范围为0-100(对应占空比0%-100%) gpioSetPWMrange(kiShieldFwdPWMIOPin, 100); gpioSetPWMrange(kiShieldBackPWMPin, 100); gpioSetPWMrange(kiColumnFwdPWMIOPin, 100); gpioSetPWMrange(kiColumnBackPWMIOPin, 100); } void BerryController::move(STATE state, DIRECTION direction, const int &pwmValue){ switch (state) { case STATE::Shield: switch (direction) { case DIRECTION::Open: gpioPWM(kiShieldBackPWMPin,PI_LOW); gpioPWM(kiShieldFwdPWMIOPin,pwmValue); break; case DIRECTION::Close: gpioPWM(kiShieldBackPWMPin,pwmValue); gpioPWM(kiShieldFwdPWMIOPin,PI_LOW); break; case DIRECTION::Stop: gpioPWM(kiShieldFwdPWMIOPin,PI_LOW); gpioPWM(kiShieldBackPWMPin,PI_LOW); break; default: break; } break; case STATE::Column: switch (direction) { case DIRECTION::Open: gpioPWM(kiColumnBackPWMPin,PI_LOW); gpioPWM(kiColumnFwdPWMIOPin, pwmValue); break; case DIRECTION::Close: gpioPWM(kiColumnFwdPWMIOPin,PI_LOW); gpioPWM(kiColumnBackPWMPin, pwmValue); break; case DIRECTION::Stop: gpioPWM(kiColumnFwdPWMIOPin,PI_LOW); gpioPWM(kiColumnBackPWMPin,PI_LOW); break; default: break; } break; default: break; } }
当前CPU占用率为107%
解决方案
降低CPU占用率的方法
1. 切换到硬件PWM引脚
树莓派4B的硬件PWM由片上硬件生成,无需CPU持续干预,占用率极低。你当前使用的引脚中仅GPIO19是硬件PWM引脚,其余5、6、26均为软件模拟PWM。建议更换为以下硬件PWM引脚:
- GPIO12(PWM通道0)
- GPIO13(PWM通道1)
- GPIO18(PWM通道0)
- GPIO19(PWM通道1)
更换引脚后,pigpio会自动使用硬件PWM模式,CPU占用率会大幅下降。
2. 优化pigpio调用逻辑
- 避免重复调用
gpioPWM:如果循环中频繁调用gpioPWM(即使占空比未变化),会产生不必要的开销。可以为每个引脚维护一个当前占空比的缓存变量,仅当新值与缓存值不同时才调用gpioPWM。示例修改:
// 新增缓存变量 static int currentShieldFwdPWM = PI_LOW; static int currentShieldBackPWM = PI_LOW; static int currentColumnFwdPWM = PI_LOW; static int currentColumnBackPWM = PI_LOW; void BerryController::move(STATE state, DIRECTION direction, const int &pwmValue){ switch (state) { case STATE::Shield: switch (direction) { case DIRECTION::Open: if (currentShieldBackPWM != PI_LOW) { currentShieldBackPWM = PI_LOW; gpioPWM(kiShieldBackPWMPin, PI_LOW); } if (currentShieldFwdPWM != pwmValue) { currentShieldFwdPWM = pwmValue; gpioPWM(kiShieldFwdPWMIOPin, pwmValue); } break; // 其余case同理修改 } break; // 其余state同理修改 } }
- 使用pigpio守护进程模式:通过
pigpiod启动守护进程,程序通过socket与守护进程通信,而非直接操作硬件,能进一步降低CPU占用。编译时链接pigpio库改为链接pigpiod_if2库,调用相关接口。
3. 调整PWM参数
8kHz的频率对于软件PWM来说较高,若业务允许,可适当降低PWM频率(比如降至2kHz-5kHz),能减少软件模拟的CPU开销。
替代库推荐
1. bcm2835库
直接操作BCM2835芯片寄存器,底层高效,支持硬件PWM配置,几乎无CPU占用,适合对性能要求极高的场景。
2. libgpiod
Linux官方推荐的GPIO操作库,基于字符设备接口,支持硬件PWM,API规范且现代,适配最新树莓派系统。
3. wiringPi
虽然已停止维护,但对树莓派4B兼容性良好,硬件PWM调用简单,CPU占用低,适合快速开发。
内容的提问来源于stack exchange,提问作者BhavinT
相关产品推荐
相关产品推荐

