20、STM32定时器PWM信号的生成与输入

STM32定时器PWM信号的生成与输入

1. STM32定时器概述

STM32F103系列有多种定时器可供使用,包括通用定时器TIM2、TIM3、TIM4、TIM5和高级定时器TIM1、TIM8。通用定时器功能丰富,通常能满足大多数需求,无需使用高级定时器。这些定时器有四个通道,可配置为GPIO输入或输出。

定时器 类型 通道1 通道2 通道3 通道4
TIM1 高级 PA12
PB13=CH1N
PA8
PB14=CH2N
PA9
PB15=CH3N
PA10
PB12=BKIN
TIM2 通用 PA0 PA1 PA2 PA3
TIM3 通用 PA6 PA7 PB0 PB1
TIM4 通用 PB6 PB7 PB8 PB9
TIM5 通用 PA3
TIM8 高级

2. 使用定时器2生成PWM信号

2.1 定时器2特性

通用定时器TIM2 - TIM5非常灵活,具有以下特性:
- 16位向上、向下、向上/向下自动重载计数器。
- 16位预分频器,可将计数器时钟频率除以1 - 65536。
- 预分频器可“动态”更改。
- 最多四个独立通道,可用于输入捕获、输出捕获、PWM生成(边沿和中心对齐模式)、单脉冲模式输出。
- 同步电路,可通过外部信号控制定时器,并与其他定时器互连。
- 可生成中断/DMA:计数器溢出/下溢更新、软件或触发计数器初始化、触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)、输入捕获、输出捕获。
- 触发输入。

2.2 软件配置

软件演示代码位于 ~/stm32f103c8t6/rtos/tim2_pwm 目录下,源代码在 main.c 文件中。以下是关键配置步骤:

2.2.1 PA1配置
0029:   rcc_periph_clock_enable(RCC_TIM2);
0030:   rcc_periph_clock_enable(RCC_AFIO);
0031:
0032:   // PA1 == TIM2.CH2
0033:   rcc_periph_clock_enable(RCC_GPIOA);
0034:   gpio_primary_remap(
0035:       AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF,  // Optional
0036:       AFIO_MAPR_TIM2_REMAP_NO_REMAP);     // default: TIM2.CH2=GPIOA1
0037:   gpio_set_mode(GPIOA,GPIO_MODE_OUTPUT_50_MHZ,   // High speed
0038:       GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,GPIO1);     // GPIOA1=TIM2.CH2
  • 第29行:使能定时器2的时钟。
  • 第30行:使能AFIO的时钟,需在第35行之前完成。
  • 第33行:使能GPIOA的时钟,供PA1使用。
  • 第34 - 36行:AFIO调用,使用默认映射,定时器2的通道2输出到PA1(默认情况下可省略)。
  • 第37 - 38行:使用ALTFN宏将GPIO引脚连接到定时器2的PA1。
2.2.2 定时器2初始化和模式设置
0042:   // TIM2:
0043:   timer_disable_counter(TIM2);
0044:   timer_reset(TIM2);
0045:
0046:   timer_set_mode(TIM2,
0047:       TIM_CR1_CKD_CK_INT,
0048:       TIM_CR1_CMS_EDGE,
0049:       TIM_CR1_DIR_UP);
  • 第43 - 44行:禁用计数器并重置定时器2。
  • 第46行:设置定时器2的操作模式:
  • TIM_CR1_CKD_CK_INT :配置定时器时钟(CLK_INT)频率与数字滤波器采样时钟之间的分频比,此处不使用数字滤波器,该宏将数字滤波器频率设置为等于时钟频率。
  • TIM_CR1_CMS_EDGE :指定使用边沿对齐模式。
  • TIM_CR1_DIR_UP :指定计数器向上计数。
2.2.3 定时器2剩余配置和启动
0026:   static const int ms[4] = { 500, 1200, 2500, 1200 };
0027:   int msx = 0;
...
0050:   timer_set_prescaler(TIM2,72);
0051:   // Only needed for advanced timers:
0052:   // timer_set_repetition_counter(TIM2,0);
0053:   timer_enable_preload(TIM2);
0054:   timer_continuous_mode(TIM2);
0055:   timer_set_period(TIM2,33333);
0056:
0057:   timer_disable_oc_output(TIM2,TIM_OC2);
0058:   timer_set_oc_mode(TIM2,TIM_OC2,TIM_OCM_PWM1);
0059:   timer_enable_oc_output(TIM2,TIM_OC2);
0060:
0061:   timer_set_oc_value(TIM2,TIM_OC2,ms[msx=0]);
0062:   timer_enable_counter(TIM2);
  • 第50行:通过设置预分频器来确定定时器频率。
  • 第52行:仅高级定时器需要,此处注释掉。
  • 第53行:启用预加载,表明TIM2_ARR寄存器被缓冲。
  • 第54行:配置定时器连续运行。
  • 第55行:设置定时器的最大计数值,确定其周期。
  • 第57 - 59行:将定时器2的通道OC2配置为PWM1模式。
  • 第61行:将输出比较寄存器设置为 ms[] 数组中的值,确定起始脉冲宽度。
  • 第62行:启动定时器。

2.3 PWM循环

0064:   for (;;) {
0065:       vTaskDelay(1000);
0066:       gpio_toggle(GPIOC,GPIO13);
0067:       msx = (msx+1) % 4;
0068:       timer_set_oc_value(TIM2,TIM_OC2,ms[msx]);
0069:   }
  • 第65行:延迟约一秒。
  • 第66行:切换PC13 LED的GPIO状态。
  • 第67行:更新数组索引变量 msx
  • 第68行:使用新的索引值更改输出比较寄存器的值,从而改变脉冲宽度。

2.4 定时器预分频计算

输入到计数器的时钟为72 MHz,因为Blue Pill配置时,APB1预分频器通常设置为2,总线频率降至36 MHz,但对于定时器2 - 5,由于APB1预分频器不为1,定时器全局预分频器输入为APB1总线频率的2倍,即72 MHz。设置预分频器为72,定时器将以1 MHz的频率更新,每个计数为1微秒,方便以微秒为单位指定脉冲宽度。

2.5 30 Hz周期配置

若RC伺服器需要30 Hz的周期,可通过以下代码配置:

timer_set_prescaler(TIM2,33333);

若要将周期降低(频率提高)到50 Hz,只需将计算中的30替换为50。

2.6 伺服器连接

伺服器通常工作在约6伏电压,而STM32需要一个小驱动电路来实现电压转换。可使用CD4050、74HCT244或74HCT245等芯片来桥接电压差,同时要确保6伏系统接地与STM32接地连接,提供公共电压参考点。

2.7 运行演示

按以下步骤构建和烧录软件:

$ make clobber
$ make
$ make flash

确保连接正确并接通电源,伺服器应每秒切换一次位置。若伺服器的PWM要求不同,可能需要更改脉冲宽度表和周期设置。

2.8 PWM输出到PB3

若需要5伏PWM信号,可将定时器2的输出比较2重定向到PB3。源代码位于 stm32f103c8t6/rtos/tim2_pwm_pb3 目录下,主要更改如下:

// 原PA1配置
!     // PA1 == TIM2.CH2
!     rcc_periph_clock_enable(RCC_GPIOA);     // Need GPIOA clock
      gpio_primary_remap(
          AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF, // Optional
!         AFIO_MAPR_TIM2_REMAP_NO_REMAP);    // default: TIM2.CH2=GPIOA1
!     gpio_set_mode(GPIOA,GPIO_MODE_OUTPUT_50_MHZ, // High speed
!         GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,GPIO1);   // GPIOA1=TIM2.CH2
--- 29,41 ----
// 改为PB3配置
!     // PB3 == TIM2.CH2
!     rcc_periph_clock_enable(RCC_GPIOB);          // Need GPIOB clock
      gpio_primary_remap(
          AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF,       // Optional
!         AFIO_MAPR_TIM2_REMAP_PARTIAL_REMAP1);    // TIM2.CH2=PB3
!     gpio_set_mode(GPIOB,GPIO_MODE_OUTPUT_50_MHZ, // High speed
!         GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN,GPIO3);  // PB3=TIM2.CH2
  • 激活GPIOB代替GPIOA。
  • 使用 AFIO_MAPR_TIM2_REMAP_PARTIAL_REMAP1 将定时器2的输出比较2定向到PB3。
  • 将PB3配置为开漏输出,并添加2K - 10K欧姆的上拉电阻,可生成5伏输出信号。

2.9 更多PWM通道

每个定时器有四个通道,例如TIM8虽无GPIO连接,但可基于每个通道的输出比较寄存器生成多达四个不同的中断,中断程序可通过软件驱动GPIO输出,且精度无损失。

3. 使用定时器4测量PWM输入信号

3.1 伺服信号特点

伺服器的位置由脉冲宽度控制,而非占空比。伺服器的中间位置可能是一个1.5 ms宽的脉冲。

3.2 信号电压处理

演示程序使用定时器4,其通道2位于GPIO PB6,该引脚具有5伏耐压能力。大多数伺服信号电压在4.5 - 6伏之间,可在接收器和PB6之间使用2千欧电阻来安全限制电流。

3.3 演示项目配置

源代码位于 ~/stm32f103c8t6/rtos/tim4_pwm_in 目录下。

3.3.1 GPIO配置
0045:   // PB6 == TIM4.CH1
0046:   rcc_periph_clock_enable(RCC_GPIOB);  // Need GPIOB clock
0047:   gpio_set_mode(GPIOB,GPIO_MODE_INPUT, // Input
0048:       GPIO_CNF_INPUT_FLOAT,GPIO6);     // PB6=TIM4.CH1

第45 - 48行:启用GPIOB的时钟,并将PB6配置为输入。

3.3.2 定时器4配置
0050:   // TIM4:
0051:   timer_disable_counter(TIM4);
0052:   timer_reset(TIM4);
0053:   nvic_set_priority(NVIC_DMA1_CHANNEL3_IRQ,2);
0054:   nvic_enable_irq(NVIC_TIM4_IRQ);
0055:   timer_set_mode(TIM4,
0056:       TIM_CR1_CKD_CK_INT,
0057:       TIM_CR1_CMS_EDGE,
0058:       TIM_CR1_DIR_UP);
0059:   timer_set_prescaler(TIM4,72);
0060:   timer_ic_set_input(TIM4,TIM_IC1,TIM_IC_IN_TI1);
0061:   timer_ic_set_input(TIM4,TIM_IC2,TIM_IC_IN_TI1);
0062:   timer_ic_set_filter(TIM4,TIM_IC1,TIM_IC_CK_INT_N_2);
0063:   timer_ic_set_prescaler(TIM4,TIM_IC1,TIM_IC_PSC_OFF);
0064:   timer_slave_set_mode(TIM4,TIM_SMCR_SMS_RM);
0065:   timer_slave_set_trigger(TIM4,TIM_SMCR_TS_TI1FP1);
0066:   TIM_CCER(TIM4) &= ~(TIM_CCER_CC2P|TIM_CCER_CC2E
0067:       |TIM_CCER_CC1P|TIM_CCER_CC1E);
0068:   TIM_CCER(TIM4) |= TIM_CCER_CC2P|TIM_CCER_CC2E|TIM_CCER_CC1E;
0069:   timer_ic_enable(TIM4,TIM_IC1);
0070:   timer_ic_enable(TIM4,TIM_IC2);
0071:   timer_enable_irq(TIM4,TIM_DIER_CC1IE|TIM_DIER_CC2IE);
0072:   timer_enable_counter(TIM4);
  • 第51 - 52行:禁用计数器并重置定时器4。
  • 第53 - 54行:为定时器4中断做准备。
  • 第55行:设置定时器4的主要元素:
  • 定时器预分频器的输入为内部时钟。
  • 定时器内的事件为边沿驱动。
  • 计数器向上计数。
  • 第59行:设置定时器的预分频器为72,使每个时钟脉冲为1微秒。
  • 第60 - 61行:将定时器输入IC1和IC2都定向到定时器输入1(TI1),可通过单个GPIO(PB6)采样伺服信号,但使用两个不同处理的定时器输入。

通过以上步骤,我们可以使用STM32的定时器2生成PWM信号来控制伺服器,同时使用定时器4测量PWM输入信号,实现对伺服器的精确控制。

4. 定时器配置总结与对比

4.1 定时器类型与通道总结

定时器 类型 通道1 通道2 通道3 通道4
TIM1 高级 PA12
PB13=CH1N
PA8
PB14=CH2N
PA9
PB15=CH3N
PA10
PB12=BKIN
TIM2 通用 PA0 PA1 PA2 PA3
TIM3 通用 PA6 PA7 PB0 PB1
TIM4 通用 PB6 PB7 PB8 PB9
TIM5 通用 PA3
TIM8 高级

从这个表格可以看出,高级定时器TIM1和TIM8有其独特的功能和通道配置。TIM1有较为全面的I/O分配,包括反极性的GPIOs和特殊的“中断”输入BKIN;而TIM8虽然没有GPIO连接,但可以内部链接到其他定时器。通用定时器TIM2 - TIM4有完整的GPIO通道,TIM5只有通道4连接到PA3。

4.2 定时器2与定时器4配置对比

定时器2配置流程
graph LR
    A[使能定时器2时钟] --> B[使能AFIO时钟]
    B --> C[使能GPIOA时钟]
    C --> D[配置PA1为TIM2.CH2]
    D --> E[禁用并重置定时器2]
    E --> F[设置定时器2模式]
    F --> G[设置预分频器]
    G --> H[配置定时器其他选项]
    H --> I[配置OC2为PWM1模式]
    I --> J[设置输出比较寄存器值]
    J --> K[启动定时器2]
定时器4配置流程
graph LR
    A[使能定时器4时钟] --> B[使能GPIOB时钟]
    B --> C[配置PB6为输入]
    C --> D[禁用并重置定时器4]
    D --> E[准备定时器4中断]
    E --> F[设置定时器4模式]
    F --> G[设置预分频器]
    G --> H[配置定时器输入IC1和IC2]
    H --> I[配置其他定时器选项]
    I --> J[启用定时器输入和中断]
    J --> K[启动定时器4]

从这两个流程图可以看出,定时器2主要用于生成PWM信号,重点在于配置输出通道和设置脉冲宽度;而定时器4主要用于测量PWM输入信号,重点在于配置输入通道和处理中断。

4.3 不同定时器的应用场景

  • 高级定时器(TIM1、TIM8) :适用于需要复杂功能和更多I/O配置的场景,如电机控制、工业自动化等。
  • 通用定时器(TIM2 - TIM5) :可满足大多数常见的PWM信号生成和测量需求,如控制伺服器、LED调光等。

5. 常见问题与解决方案

5.1 定时器频率计算问题

在计算定时器频率时,由于存在多个预分频器,容易产生混淆。例如,APB1总线频率和定时器全局预分频器的关系需要特别注意。当APB1预分频器不为1时,定时器全局预分频器输入为APB1总线频率的2倍。

解决方案:仔细阅读数据手册,明确各个预分频器的作用和设置。在代码中设置预分频器时,要根据实际的总线频率和需求进行计算。

5.2 伺服器连接问题

伺服器通常工作在约6伏电压,而STM32工作在较低电压,需要一个驱动电路来桥接电压差。如果连接不当,可能会导致伺服器无法正常工作。

解决方案:使用合适的芯片(如CD4050、74HCT244或74HCT245)来实现电压转换,并确保6伏系统接地与STM32接地连接,提供公共电压参考点。

5.3 PWM信号输出问题

如果PWM信号输出不符合预期,可能是定时器配置错误或代码逻辑问题。

解决方案:检查定时器的配置代码,确保预分频器、周期、脉冲宽度等设置正确。可以使用示波器观察PWM信号的波形,进行调试。

6. 总结与展望

6.1 总结

通过以上内容,我们详细介绍了如何使用STM32的定时器2生成PWM信号来控制伺服器,以及如何使用定时器4测量PWM输入信号。我们了解了定时器的类型、通道配置、软件配置步骤、频率计算方法、伺服器连接方式等重要知识。同时,我们还对定时器配置进行了总结和对比,分析了不同定时器的应用场景,并提出了常见问题的解决方案。

6.2 展望

随着技术的不断发展,STM32的应用场景将越来越广泛。未来,我们可以进一步探索如何利用多个定时器同时工作,实现更复杂的控制任务。例如,同时使用多个定时器生成不同频率和脉冲宽度的PWM信号,控制多个伺服器协同工作。此外,还可以结合其他外设(如传感器、通信模块等),实现更智能的控制系统。

总之,掌握STM32定时器的使用方法,对于实现各种嵌入式系统的控制和测量任务具有重要意义。希望本文能为读者提供有价值的参考,帮助大家更好地应用STM32进行开发。

【事件触发一致性】研究多智能体网络如何通过分布式事件驱动控制实现有限时间内的共识(Matlab代码实现)内容概要:本文围绕多智能体网络中的事件触发一致性问题,研究如何通过分布式事件驱动控制实现有限时间内的共识,并提供了相应的Matlab代码实现方案。文中探讨了事件触发机制在降低通信负担、提升系统效率方面的优势,重点分析了多智能体系统在有限时间收敛的一致性控制策略,涉及系统模型构建、触发条件设计、稳定性收敛性分析等核心技术环节。此外,文档还展示了该技术在航空航天、电力系统、机器人协同、无人机编队等多个前沿领域的潜在应用,体现了其跨学科的研究价值和工程实用性。; 适合人群:具备一定控制理论基础和Matlab编程能力的研究生、科研人员及从事自动化、智能系统、多智能体协同控制等相关领域的工程技术人员。; 使用场景及目标:①用于理解和实现多智能体系统在有限时间内达成一致的分布式控制方法;②为事件触发控制、分布式优化、协同控制等课题提供算法设计仿真验证的技术参考;③支撑科研项目开发、学术论文复现及工程原型系统搭建; 阅读建议:建议结合文中提供的Matlab代码进行实践操作,重点关注事件触发条件的设计逻辑系统收敛性证明之间的关系,同时可延伸至其他应用场景进行二次开发性能优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值