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 采集模拟量,或者输入捕获测频率,想看哪个评论区告诉我。

相关推荐
william_yangshun12 分钟前
【大模型部署实战】kimi-k3-in-c 中文版:用 176KB 纯 C99 引擎在 CPU 上跑 Kimi K3 上手指南
c语言·开发语言
深圳市宝华视联1 小时前
Python 读取 IP 视频流简单 Demo
python·嵌入式硬件·opencv·网络协议·tcp/ip·实时音视频·嵌入式实时数据库
慧福堂1 小时前
偏印详解:十神中的智慧与孤影,如何善用偏印成就人生
大数据·学习·学习方法·八字·风水
2601_949950631 小时前
成绩提升不靠盲目刷题:用练题簿找准真正的薄弱知识点
学习·小程序·刷题·小程序推荐
步十人1 小时前
DeepRead-项目介绍
学习
恒锐丰科技韩生1 小时前
RB6005A|晶准 单节锂电池内置 MOS 保护芯片 DFN2×3‑8
嵌入式硬件·硬件工程
YM52e2 小时前
鸿蒙 ArkTS 实战|网络常用漫剧主角名称分类表:26 位主角 8 大分类 + 搜索筛选
学习·华为·harmonyos
youshi66682 小时前
stm32-PWR、低功耗模式
stm32·单片机·嵌入式硬件
ACP广源盛139246256732 小时前
Qwen3.8‑2.4T 开源落地@ACP#国产 Serdes 长距离视频传输芯片 GSV5800 在私有化 AI 服务中的价值与应用场景
大数据·数据库·人工智能·嵌入式硬件·矩阵·开源·音视频
Funing72 小时前
STM32 电机动态 PI 控制:从编码器反馈、增量式 PI 到 Matlab 参数拟合与 PWM 输出
stm32·嵌入式硬件·matlab·pi控制算法