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进行开发。
超级会员免费看
605

被折叠的 条评论
为什么被折叠?



