news 2026/5/15 17:01:11

STM32F103 TIM3四路PWM驱动舵机与LED调光实战:一份代码搞定两种应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103 TIM3四路PWM驱动舵机与LED调光实战:一份代码搞定两种应用

STM32F103 TIM3四路PWM驱动舵机与LED调光实战:一份代码搞定两种应用

在嵌入式开发中,PWM(脉冲宽度调制)技术是实现电机控制、LED调光等功能的基石。STM32F103系列微控制器内置的定时器模块,特别是TIM3定时器,提供了灵活的四通道PWM输出能力。本文将带你深入探索如何利用TIM3的四个通道同时实现舵机角度控制和LED呼吸灯效果,通过实战项目解决"学了PWM能干嘛"的困惑。

1. 项目概述与硬件准备

核心目标:使用TIM3的四个通道(CH1-CH4)同时驱动两个舵机和两个LED,其中两路PWM用于精确控制舵机角度,另外两路实现LED呼吸灯效果。这种组合在实际项目中非常常见,比如机器人关节控制配合状态指示灯,或是智能家居中的窗帘电机控制与环境灯光调节。

硬件需求清单:

  • STM32F103C8T6最小系统板(Blue Pill)
  • SG90舵机(2个)
  • LED(2个,建议不同颜色)
  • 220Ω电阻(2个,用于LED限流)
  • 面包板与杜邦线若干
  • USB转TTL串口模块(用于调试)

提示:SG90舵机的工作电压通常为4.8-6V,建议使用外部电源供电而非STM32的3.3V输出,以避免电流不足导致舵机抖动或STM32复位。

电路连接示意图:

TIM3_CH1(PC6) --> 舵机1信号线(黄色/白色) TIM3_CH2(PC7) --> 舵机2信号线 TIM3_CH3(PC8) --> LED1(串联220Ω电阻到GND) TIM3_CH4(PC9) --> LED2

2. PWM基础与TIM3配置原理

2.1 关键参数解析

PWM控制有三个核心参数需要理解:

  1. ARR(Auto-Reload Register):决定PWM波的周期

    • 计算公式:PWM周期 = (ARR + 1) × (PSC + 1) / TIMx时钟频率
    • 对于72MHz的STM32F103,若PSC=71,ARR=999,则周期为:(999+1)×(71+1)/72MHz = 1ms
  2. PSC(Prescaler):时钟预分频系数

    • 实际分频系数 = PSC + 1
    • 用于扩展ARR的有效范围,当需要极低频率时配合使用
  3. CCRx(Capture/Compare Register):决定占空比

    • 占空比 = CCRx / (ARR + 1)
    • 对于舵机控制,0.5ms-2.5ms的脉冲宽度对应0°-180°

2.2 舵机与LED的PWM需求差异

参数舵机控制要求LED调光要求
频率50Hz(周期20ms)100Hz-1kHz
占空比范围2.5%-12.5%0%-100%
分辨率需求中等(约180个步进)高(256级及以上)

TIM3配置策略:

  • 通道1&2:50Hz PWM用于舵机(ARR=19999, PSC=71)
  • 通道3&4:1kHz PWM用于LED(ARR=999, PSC=71)
  • 使用GPIO完全重映射(FullRemap)将TIM3通道输出到PC6-PC9

3. 代码实现与工程组织

3.1 硬件抽象层设计

采用模块化编程思想,将PWM相关功能封装为独立模块:

// pwm.h #ifndef __PWM_H #define __PWM_H #include "stm32f10x.h" void PWM_Servo_Init(uint16_t arr, uint16_t psc); void PWM_LED_Init(uint16_t arr, uint16_t psc); void Set_Servo_Angle(uint8_t ch, float angle); void Set_LED_Brightness(uint8_t ch, uint8_t brightness); #endif

3.2 TIM3多通道PWM初始化

关键点在于同一定时器不同通道可以独立设置占空比,但共享ARR和PSC值。因此需要折中处理:

// pwm.c void TIM3_PWM_Init(uint16_t arr, uint16_t psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 开启时钟和GPIO重映射 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); // 配置PC6-PC9为复用推挽输出 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); // 定时器基础配置 TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 通道1-4 PWM模式配置 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_OC3Init(TIM3, &TIM_OCInitStructure); TIM_OC4Init(TIM3, &TIM_OCInitStructure); // 启用预装载 TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); }

3.3 应用层接口实现

针对舵机和LED的不同需求封装易用接口:

void Set_Servo_Angle(uint8_t ch, float angle) { angle = angle > 180 ? 180 : (angle < 0 ? 0 : angle); uint16_t pulse = 500 + angle * 2000 / 180; // 0.5ms-2.5ms switch(ch) { case 1: TIM_SetCompare1(TIM3, pulse); break; case 2: TIM_SetCompare2(TIM3, pulse); break; default: break; } } void Set_LED_Brightness(uint8_t ch, uint8_t brightness) { uint16_t pulse = brightness * 10; // 映射到0-1000 switch(ch) { case 1: TIM_SetCompare3(TIM3, pulse); break; case 2: TIM_SetCompare4(TIM3, pulse); break; default: break; } }

4. 主程序逻辑与效果优化

4.1 呼吸灯效果实现

利用SysTick定时器实现平滑的亮度变化:

// main.c #include "stm32f10x.h" #include "pwm.h" #include "delay.h" void Breathing_LED(uint8_t ch, uint16_t period) { static uint16_t counter = 0; static int8_t dir = 1; counter += dir; if(counter >= 100) dir = -1; else if(counter <= 0) dir = 1; Set_LED_Brightness(ch, counter); Delay_ms(period / 200); } int main(void) { Delay_init(); TIM3_PWM_Init(19999, 71); // 50Hz PWM基础 // 独立设置LED通道频率(通过修改ARR实现) TIM3->ARR = 999; // 1kHz for LED TIM3->CCR3 = 0; TIM3->CCR4 = 0; Set_Servo_Angle(1, 90); // 初始位置 Set_Servo_Angle(2, 0); while(1) { Breathing_LED(1, 3000); // 3秒周期 Breathing_LED(2, 5000); // 5秒周期,不同速度 // 舵机扫描演示 for(uint8_t i = 0; i < 180; i++) { Set_Servo_Angle(2, i); Delay_ms(20); } } }

4.2 性能优化技巧

  1. 动态频率调整:通过实时修改ARR值实现不同通道不同频率

    void Set_PWM_Frequency(uint8_t ch, uint32_t freq) { uint32_t arr = (72000000 / 72) / freq - 1; // PSC固定为71 if(ch == 1 || ch == 2) TIM3->ARR = arr; }
  2. 硬件加速:使用DMA自动更新CCR值,实现复杂波形

    // 配置DMA从内存数组自动传输数据到TIM3->CCRx
  3. 中断同步:利用定时器更新中断协调多通道操作

    void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { // 同步处理代码 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); } }

5. 常见问题与调试技巧

5.1 典型问题排查表

现象可能原因解决方案
舵机无反应信号线接反检查接线(黄/白线为信号)
LED亮度不可调GPIO模式错误确保设置为AF_PP模式
舵机抖动电源供电不足使用外部5V电源
只有部分通道工作重映射配置不完整检查GPIO_FullRemap_TIM3
PWM频率不准时钟配置错误确认系统时钟为72MHz

5.2 示波器调试要点

  1. 测量点选择

    • 直接在舵机信号线测量
    • LED引脚前测量(避免电阻影响)
  2. 关键参数验证

    • 舵机通道:20ms周期,0.5-2.5ms脉宽
    • LED通道:1ms周期,脉宽变化平滑
  3. 异常波形分析

    • 波形毛刺:检查接地是否良好
    • 频率漂移:检查晶振稳定性
    • 占空比异常:确认CCR值设置正确

在完成基础功能后,可以进一步扩展为通过串口命令控制舵机角度和LED亮度,或者增加电位器实现模拟量输入控制。这个框架也可以轻松移植到其他STM32系列,只需根据具体型号调整时钟配置和引脚定义。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/13 11:54:14

终极中文汉化方案:PowerToys-CN让你的Windows效率工具真正说中文

终极中文汉化方案&#xff1a;PowerToys-CN让你的Windows效率工具真正说中文 【免费下载链接】PowerToys-CN PowerToys Simplified Chinese Translation 微软增强工具箱 自制汉化 项目地址: https://gitcode.com/gh_mirrors/po/PowerToys-CN 还在为PowerToys满屏的英文界…

作者头像 李华
网站建设 2026/5/13 11:52:13

ArcGIS Pro实战:用30米DEM数据快速搞定RUSLE模型中的LS因子计算

ArcGIS Pro实战&#xff1a;30米DEM数据高效计算RUSLE模型LS因子全流程解析 当我们需要评估土壤侵蚀风险时&#xff0c;RUSLE&#xff08;修正通用土壤流失方程&#xff09;模型中的LS因子&#xff08;坡长坡度因子&#xff09;计算是关键环节。传统ArcMap在处理大规模DEM数据时…

作者头像 李华
网站建设 2026/5/13 11:51:08

FABRK全栈框架:模块化架构与AI原生开发实践

1. 从生产级样板到全栈框架&#xff1a;FABRK 的诞生与设计哲学如果你和我一样&#xff0c;在过去几年里反复构建过多个 SaaS 应用&#xff0c;那你一定对那种“重复造轮子”的疲惫感深有体会。每次新项目启动&#xff0c;都要重新搭建一遍身份验证、支付集成、仪表盘布局、数据…

作者头像 李华
网站建设 2026/5/13 11:49:27

别再手动核对Excel了!用Windows自带工具+SVN实现版本差异自动对比

告别Excel版本混乱&#xff1a;用SVNWindows神器打造自动化差异对比工作流 每次团队协作修改Excel文件后&#xff0c;你是否也经历过这样的噩梦&#xff1f;明明知道文件被修改过&#xff0c;却要逐行逐列翻找差异&#xff1b;或是收到同事发来的新版报表&#xff0c;却说不清具…

作者头像 李华
网站建设 2026/5/15 16:57:47

3步搞定!DistroAV插件让OBS Studio实现专业级网络音视频传输

3步搞定&#xff01;DistroAV插件让OBS Studio实现专业级网络音视频传输 【免费下载链接】obs-ndi DistroAV (formerly OBS-NDI): NDI integration for OBS Studio 项目地址: https://gitcode.com/gh_mirrors/ob/obs-ndi 想要在多台电脑之间传输高质量音视频流&#xff…

作者头像 李华