PWM学习PWM+SG90
一、硬件上介绍
1、鲁班猫4 pwm引脚介绍
LubanCat板卡上集成了四个具有pwm功能的GPIO,其他有些io也能复用为pwm。
| LubanCat-4-V1系列 | pwm14 | pwm15 | pwm10 | pwm11 |
|---|

2、SG90舵机介绍

2、SG90电机简介
SG90舵机接受固定周期、可变脉宽的PWM信号:
-
工作电压: 5V(扩展板提供)
-
固定周期 :始终 20ms (50Hz)
-
可变部分 :高电平持续时间 (0.5ms - 2.5ms)
-
线性关系:高电平时间 ∝ 舵机角度
| 角度 | 脉冲宽度 | 占空比 | 说明 |
|---|---|---|---|
| 0° | 500μs | 2.5% | 最小位置 |
| 45° | 1000μs | 5.0% | 四分之一 |
| 90° | 1500μs | 7.5% | 中心位置 |
| 135° | 2000μs | 10.0% | 四分之三 |
| 180° | 2500μs | 12.5% | 最大位置 |
黄、红、棕三根线分别对应:PWM信号线、5V电源线、GND线
二、PWM功能简单测试--shell控制SG90
1、硬件连接
- SG90舵机红线(VCC) → 扩展板5V(通常是黄色端子)
- SG90舵机棕线(GND) → 扩展板GND(黑色端子)
- SG90舵机橙线(信号) → 扩展板舵机接口信号线(如PWM11 -> pin35)

2、启用PWM通道
使能前,检查PWM设备:
undefined
ls /sys/class/pwm
cat /sys/kernel/debug/pwm

从下往上,依次对应着:
- 风扇 pwm0 -> pwmchip0
- 背光0 pwm0 -> pwmchip1
- 背光1 pwm0 -> pwmchip2
通过修改 /boot/uEnv/board.txt 使能PWM10、11,修改后reboot:
shell
vim /boot/uEnv/uEnv.txt


3、使用shell测试可用性
shell
echo 0 > /sys/class/pwm/pwmchip4/unexport 2>/dev/null # 清理可能存在的旧通道
echo 0 > /sys/class/pwm/pwmchip4/export # 导出PWM通道0
echo 20000000 > /sys/class/pwm/pwmchip4/pwm0/period # 设置20ms周期(50Hz)
echo 1 > /sys/class/pwm/pwmchip4/pwm0/enable # 启用PWM输出
echo 500000 > /sys/class/pwm/pwmchip4/pwm0/duty_cycle # 设置0度位置(0.5ms)
echo 1500000 > /sys/class/pwm/pwmchip4/pwm0/duty_cycle # 设置90度位置(1.5ms)
echo 2500000 > /sys/class/pwm/pwmchip4/pwm0/duty_cycle # 设置180度位置(2.5ms)
echo 1500000 > /sys/class/pwm/pwmchip4/pwm0/duty_cycle # 回到90度位置
整个流程是这样的:
shell
硬件初始化流程:
清理 → 激活 → 配置 → 启用 → 控制
↓ ↓ ↓ ↓ ↓
unexport → export → period → enable → duty_cycle
此时,可以看到舵机旋转相应的角度
echo 0 > /sys/class/pwm/pwmchip4/export命令的作用
shell
# 执行前
/sys/class/pwm/pwmchip4/
├── npwm # 只读,显示可用通道数
├── export # 只写,用于创建通道
└── unexport # 只写,用于删除通道
# 执行后
/sys/class/pwm/pwmchip4/
├── npwm
├── export
├── unexport
└── pwm0/ # 新创建的目录
├── period # 周期设置文件
├── duty_cycle # 占空比设置文件
├── enable # 使能控制文件
└── polarity # 极性设置文件(如果支持)
三、Linux驱动方式
6. PWM子系统 --- [野火\]嵌入式Linux驱动开发实战指南------基于LubanCat-RK系列板卡 文档](https://doc.embedfire.com/linux/rk356x/driver/zh/latest/linux_driver/subsystem_pwm.html)
首先看一下刚刚放开的设备树

shell
root@lubancat:/boot# find / -name rk3588-lubancat-pwm11-ir-m3-overlay.dtbo
/boot/dtb/overlay/rk3588-lubancat-pwm11-ir-m3-overlay.dtbo
转化为dts进行查看:
shell
root@lubancat:/boot/dtb/overlay# dtc -I dtb -O dts /boot/dtb/overlay/rk3588-lubancat-pwm11-ir-m3-overlay.dtbo -o /tmp/pwm11_ir_m3.dts
root@lubancat:/boot/dtb/overlay# cat /tmp/pwm11_ir_m3.dts
/dts-v1/;
/ {
fragment@0 {
target = <0xffffffff>;
__overlay__ {
status = "okay";
pinctrl-names = "active";
pinctrl-0 = <0xffffffff>;
};
};
__fixups__ {
pwm11 = "/fragment@0:target:0";
pwm11m3_pins = "/fragment@0/__overlay__:pinctrl-0:0";
};
};
解读这段设备树的意思:
shell
原始DTS(开发时) → 编译为DTBO → 内核加载时
target = <&pwm11> target = <0xffffffff> target = <&pwm11>
__fixups__记录 根据__fixups__重定位
pwm11 = "/fragment@0:target:0"
- 意思:将
fragment@0的target属性替换为&pwm11 - 运行时效果:
target = <&pwm11>
pwm11m3_pins = "/fragment@0/__overlay__:pinctrl-0:0"
- 意思:将
fragment@0/__overlay__的pinctrl-0属性替换为&pwm11m3_pins - 运行时效果:
pinctrl-0 = <&pwm11m3_pins>
因此,该DTBO实际加载后,系统看到的是:
shell
// 内核实际处理的配置:
&pwm11 { // 目标节点:pwm11控制器
status = "okay"; // 启用这个设备
pinctrl-names = "active"; // 引脚状态名
pinctrl-0 = <&pwm11m3_pins>; // 使用pwm11在复用模式3的引脚配置
};