STM32 定时器 PWM 实战:从呼吸灯到舵机控制

很多人刚玩 STM32,点灯用 GPIO_Toggle,调亮度就傻了------直接 IO 口只能给高低电平,要平滑的亮度、要控制舵机转到指定角度,靠的是 PWM(脉冲宽度调制)

这篇不讲那些绕来绕去的理论,直接把一个定时器通道配成 PWM 输出,先做个呼吸灯,再顺手把舵机也控了。## 一、定时器是怎么"变"出 PWM 的一句话:定时器在数数,数到某个值就把引脚拉高/拉低。STM32 的通用定时器(TIM2~TIM5 这类)里面有个计数器 CNT,每个时钟沿加 1,数到 ARR(自动重装载值) 就归零重新数。PWM 的关键在两个寄存器:- PSC(预分频) :把 TIM 的输入时钟分频,决定数数有多快。- ARR :一个周期的计数上限,决定 PWM 频率。- CCR(捕获比较值) :数数过程中,CNT < CCR 时输出高,CNT >= CCR 时输出低。CCR 越大,高电平占比越大,占空比越高。所以频率公式是:PWM频率 = TIM时钟 / ((PSC + 1) * (ARR + 1))占空比 = CCR / (ARR + 1)注意是 PSC+1ARR+1,这俩寄存器是从 0 开始算的,新手最常在这里算错一个 off-by-one。## 二、CubeMX 怎么配以 STM32F103(72MHz 系统时钟)为例,选一个定时器通道当 PWM:1. 左侧 Timers → 选 TIM3Clock SourceInternal Clock。2. 切到 PWM Generation CH1(通道1)。3. 下方参数: - Prescaler (PSC) = 72-1 → 分频后计数时钟 = 1MHz(72M/72)。 - Counter Period (ARR) = 1000-1 → 每 1000 个数一个周期,PWM 频率 = 1MHz/1000 = 1kHz 。 - Pulse (CCR) = 0,先给 0,后面代码里改。4. GPIO 里对应引脚会自动变成 TIM3_CH1 的复用功能,不用手动配。5. 生成代码。想控舵机的话,把 ARR 改成 20000-1、PSC 保持 72-1,这样频率就是 1MHz/20000 = 50Hz,刚好是舵机要的。## 三、最少的代码CubeMX 生成后,启动 PWM 只需要一行,再一行改占空比:c// 启动 TIM3 通道1 的 PWM 输出HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);// 改占空比:CCR 设成 500,就是 50% 占空比(ARR=1000 时)__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 500);就这么简单。__HAL_TIM_SET_COMPARE 是改 CCR 的宏,运行时随便改,占空比立刻变。## 四、呼吸灯1kHz 的频率肉眼看不出闪,改 CCR 就能改亮度。呼吸灯就是让 CCR 在 0~ARR 之间慢慢来回走:cint main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM3_Init(); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); int ccr = 0; int dir = 1; while (1) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, ccr); ccr += dir * 10; if (ccr >= 1000) { ccr = 1000; dir = -1; } if (ccr <= 0) { ccr = 0; dir = 1; } HAL_Delay(10); // 调这个延时改呼吸快慢 }}接在 TIM3_CH1 那个引脚上的 LED,就会慢慢亮慢慢暗。注意 LED 要串限流电阻,别直接怼 IO 口。## 五、顺手把舵机也控了舵机认的是 50Hz 信号 ,高电平宽度决定角度:0.5ms 对应 0°,1.5ms 对应 90°,2.5ms 对应 180°。前面把 ARR 配成 20000(PSC=71,计数时钟 1MHz),那 1ms = 1000 个计数。所以:- 0° → CCR = 500- 90° → CCR = 1500- 180° → CCR = 2500c// 转到 90 度(中点)__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1500);HAL_Delay(500); // 舵机转需要时间,别秒切实测里有个坑:很多舵机吃电流很猛 ,直接由开发板 3.3V 供电基本转不动或者抖。单独给舵机供 5V,信号线共地接到开发板就行。## 六、几个我翻过车的地方- 频率算错 :先想清楚你要多少 Hz,再反推 PSC 和 ARR。舵机必须 50Hz,电机调速一般几 kHz~几十 kHz。- ARR 太小分辨率低 :ARR=100 时,占空比只能以 1% 步进;想精细就调大 ARR、相应调 PSC 保频率不变。- 忘了 __HAL_TIM_SET_COMPARE 前要先 HAL_TIM_PWM_Start :不启动通道,改 CCR 没输出。- 舵机抖 :供电不足或信号受干扰,量一下 5V 电压,信号线尽量短。- 占空比超过 100% :CCR 别大于 ARR,否则输出常高,舵机直接到头。## 七、完整 main.c 骨架把上面拼起来,一个文件就能跑(CubeMX 已经生成 MX_TIM3_Init()htim3):cint main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM3_Init(); // 呼吸灯:ARR=1000, PSC=71, 1kHz // 舵机: 把 ARR 改成 20000 即可切到 50Hz HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); int ccr = 0, dir = 1; while (1) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, ccr); ccr += dir * 10; if (ccr >= 1000) { ccr = 1000; dir = -1; } if (ccr <= 0) { ccr = 0; dir = 1; } HAL_Delay(10); }}PWM 这东西上手比想象中简单,核心就一句话:PSC 定快慢、ARR 定周期、CCR 定占空比 。把这三个数玩明白,呼吸灯、舵机、电机调速都是同一套逻辑换组参数。---下篇可以写 ADC + DMA 采集模拟量,或者输入捕获测频率,想看哪个评论区告诉我。

相关推荐
世人万千丶8 小时前
鸿蒙日志体系高级应用:HiLog分级输出/隐私脱敏/远程日志采集/线上问题精准溯源方案
学习·harmonyos·鸿蒙
azwsm10 小时前
驱动第一阶段——启动流程
单片机·嵌入式硬件
ctlover11 小时前
Python学习第 5 日
学习
单片机杂货铺12 小时前
基于单片机的自动开窗器设计
stm32·嵌入式硬件·51单片机·硬件工程
六点_dn12 小时前
RabbitMQ学习笔记-部署和使用
笔记·学习·rabbitmq
天天爱吃肉821813 小时前
商用车多体动力学实战笔记|第6篇:动力传动系统(发动机、变速箱、分动器、TCS、LSD限滑差速)
大数据·人工智能·笔记·python·嵌入式硬件·汽车
别催小唐敲代码13 小时前
STM32 I2C协议详解:从原理到实战
stm32·网络协议·协议
lhbweilai14 小时前
STM32 I2C(hal库)
stm32·单片机·嵌入式硬件
MartinYeung514 小时前
[论文学习]OSReward:为跨平台计算机使用奖励模型建立标准化评估
人工智能·学习