第30章 通用定时器-同步
第三十章 通用定时器-同步
1. 硬件设计
无需硬件设计
2. 软件设计
2.1 编程大纲
-
定时器参数宏定义
-
定时器GPIO初始化
-
定时器输出PWM及主从模式配置
2.2 代码分析
2.2.1 定时器相关参数宏定义
/* 主从定时器参数 */
#define TIM_MASTER TIM2 // 主定时器--TIM2
#define TIM_MASTER_CLK RCC_APB1Periph_TIM2
#define TIM_SLAVE1 TIM3 // 从定时器1--TIM3
#define TIM_SLAVE1_CLK RCC_APB1Periph_TIM3
#define TIM_SLAVE2 TIM4 // 从定时器2--TIM4
#define TIM_SLAVE2_CLK RCC_APB1Periph_TIM4
/* 主从定时器通道参数 */
#define TIM_MASTER_PIN GPIO_Pin_10 // TIM2-PB10
#define TIM_MASTER_PORT GPIOB
#define GTIM_MASTER_GPIO_CLK RCC_APB2Periph_GPIOB
/* 从定时器输出通道参数 */
#define TIM_SLAVE1_PIN GPIO_Pin_6 // TIM3-PC6
#define TIM_SLAVE1_PORT GPIOC
#define GTIM_SLAVE1_GPIO_CLK RCC_APB2Periph_GPIOC
#define TIM_SLAVE2_PIN GPIO_Pin_6 // TIM4-PB6
#define TIM_SLAVE2_PORT GPIOB
#define GTIM_SLAVE2_GPIO_CLK RCC_APB2Periph_GPIOB
2.2.2 定时器GPIO初始化
// 初始化GPIO,配置与定时器相关的引脚
static void TIM_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能与定时器相关的GPIO时钟
RCC_APB2PeriphClockCmd(GTIM_MASTER_GPIO_CLK | GTIM_SLAVE1_GPIO_CLK | GTIM_SLAVE2_GPIO_CLK, ENABLE);
// 使能AFIO时钟,用于处理引脚复用
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// 配置TIM2的引脚重映射,将TIM2_CH3映射到PB10引脚
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // 重映射TIM2引脚 TIM2_CH3 -> PB10
// 配置TIM3的引脚重映射,将TIM3_CH1映射到PC6引脚
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); // 重映射TIM3引脚 TIM3_CH1 -> PC6
// 配置从定时器1(TIM3)的GPIO引脚,PC6
GPIO_InitStructure.GPIO_Pin = TIM_SLAVE1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速度
GPIO_Init(TIM_SLAVE1_PORT, &GPIO_InitStructure); // 初始化TIM3_CH1(PC6)
// 配置从定时器2(TIM4)的GPIO引脚,PB6
GPIO_InitStructure.GPIO_Pin = TIM_SLAVE2_PIN;
GPIO_Init(TIM_SLAVE2_PORT, &GPIO_InitStructure); // 初始化TIM4_CH2(PB6)
// 配置主定时器(TIM2)的GPIO引脚,PB10
GPIO_InitStructure.GPIO_Pin = TIM_MASTER_PIN;
GPIO_Init(TIM_MASTER_PORT, &GPIO_InitStructure); // 初始化TIM2_CH3(PB10)
}
- 使能GPIO时钟:
RCC_APB2PeriphClockCmd
使能了与主定时器和从定时器相关的GPIO时钟,并使能了AFIO时钟。GPIO_PinRemapConfig
配置了定时器通道的引脚重映射,例如将TIM2_CH3
重映射到PB10
。
- 配置GPIO引脚:
- 使用
GPIO_InitTypeDef
结构体配置引脚。 GPIO_InitStructure.GPIO_Mode
设置为推挽复用输出 (GPIO_Mode_AF_PP
),以支持定时器的PWM输出。GPIO_InitStructure.GPIO_Speed
设置为 50MHz。
- 具体GPIO引脚配置:
- PC6: 配置为
TIM3_CH1
的推挽复用输出。 - PB6: 配置为
TIM4_CH1
的推挽复用输出。 - PB10: 配置为
TIM2_CH3
的推挽复用输出。
这里出现了一个新的库函数,我们需要分析一下:
GPIO_PinRemapConfig
是一个用于配置GPIO引脚重映射的库函数,通常用于定时器或其他外设的引脚重映射,以便将外设功能映射到不同的引脚上。它的主要功能是在微控制器中重新定义某些功能引脚的位置。
函数原型
void GPIO_PinRemapConfig(GPIO_TypeDef* GPIOx, FunctionalState NewState);
参数说明
GPIOx
: 需要重映射的GPIO配置。例如,GPIO_FullRemap_TIM2
代表定时器2的完全重映射。NewState
: 指定是否启用重映射。ENABLE
启用重映射,DISABLE
禁用重映射。
功能描述
- 重映射引脚: 该函数将定时器或其他外设的特定功能引脚映射到其他可用引脚上。例如,将
TIM2_CH3
的功能映射到PB10
。 - 灵活性: 提供了更大的灵活性以适应不同的硬件布局和需求。
使用场景
- 当你需要将外设的功能引脚分配到不同的物理引脚时,例如在开发过程中调整硬件布局或在应用程序中使用不同的引脚。
示例
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // 启用 TIM2 的完全重映射
2.2.3 TIM模式配置
// 初始化定时器的工作模式(主从定时器模式)
static void TIM_Mode_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能主定时器和从定时器的时钟
RCC_APB1PeriphClockCmd(TIM_MASTER_CLK | TIM_SLAVE1_CLK | TIM_SLAVE2_CLK, ENABLE);
// 配置主定时器时基参数
TIM_TimeBaseStructure.TIM_Period = 72; // 设置定时器的自动重载值(周期为72)
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不使用预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频系数为0
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数向上计数
TIM_TimeBaseInit(TIM_MASTER, &TIM_TimeBaseStructure); // 初始化主定时器
// 配置从定时器1时基参数(周期设置为4)
TIM_TimeBaseStructure.TIM_Period = 4; // 设置周期为4
TIM_TimeBaseInit(TIM_SLAVE1, &TIM_TimeBaseStructure); // 初始化从定时器1
// 配置从定时器2时基参数(周期设置为4)
TIM_TimeBaseStructure.TIM_Period = 4; // 设置周期为4
TIM_TimeBaseInit(TIM_SLAVE2, &TIM_TimeBaseStructure); // 初始化从定时器2
// 配置主定时器为PWM模式
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
TIM_OCInitStructure.TIM_Pulse = 5; // 设置PWM占空比为5
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高
TIM_OC3Init(TIM_MASTER, &TIM_OCInitStructure); // 配置主定时器的PWM输出通道3
// 配置主定时器为主从模式
TIM_SelectMasterSlaveMode(TIM_MASTER, TIM_MasterSlaveMode_Enable); // 使能主从模式
TIM_SelectInputTrigger(TIM_MASTER, TIM_TRGOSource_Update); // 设置输出触发源为更新事件
// 配置从定时器1为PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
TIM_OCInitStructure.TIM_Pulse = 4; // 设置PWM占空比为4
TIM_OC1Init(TIM_SLAVE1, &TIM_OCInitStructure); // 配置从定时器1的PWM输出通道1
// 配置从定时器1为主从模式
TIM_SelectMasterSlaveMode(TIM_SLAVE1, TIM_MasterSlaveMode_Enable);
// 配置从定时器1为门控同步模式
TIM_SelectSlaveMode(TIM_SLAVE1, TIM_SlaveMode_Gated); // 设置为门控同步模式
TIM_SelectInputTrigger(TIM_SLAVE1, TIM_TS_ITR1); // 设置触发源为主定时器的更新事件
// 配置从定时器2为门控同步模式
TIM_SelectSlaveMode(TIM_SLAVE2, TIM_SlaveMode_Gated); // 设置为门控同步模式
TIM_SelectInputTrigger(TIM_SLAVE2, TIM_TS_ITR2); // 设置触发源为另一个输入触发源
// 启动主定时器和从定时器
TIM_Cmd(TIM_MASTER, ENABLE); // 启动主定时器
TIM_Cmd(TIM_SLAVE1, ENABLE); // 启动从定时器1
TIM_Cmd(TIM_SLAVE2, ENABLE); // 启动从定时器2
}
2.2.4 主函数
#include "stm32f10x.h"
#include "general_tim.h"
int main(void)
{
TIMx_Init();
while(1)
{
}
}
3. 小结
其他步骤我们已经很熟悉了,下面重点来分析一下配置TIM模式:
3.1 启用定时器时钟
RCC_APB1PeriphClockCmd(GENERAL_TIM_MASTER_CLK | GENERAL_TIM_SLAVE1_CLK | GENERAL_TIM_SLAVE11_CLK, ENABLE);
这行代码启用了主定时器(GENERAL_TIM_MASTER
)和两个从定时器(GENERAL_TIM_SLAVE1
和 GENERAL_TIM_SLAVE11
)的时钟,使能它们的计数功能。
3.2 配置时基
TIM_TimeBaseStructure.TIM_Period = 72;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(GENERAL_TIM_MASTER, &TIM_TimeBaseStructure);
TIM_Period
:定时器计数周期。当计数器的值从0增加到此值时,会产生一个溢出事件。TIM_Prescaler
:预分频器的值。它控制定时器计数频率。此处设置为0,意味着时钟频率没有被分频。TIM_ClockDivision
:时钟分频系数。设置为0时,定时器时钟没有额外分频。TIM_CounterMode
:计数模式,这里设置为TIM_CounterMode_Up
,意味着计数器将从0向上计数。
3.3 配置 PWM 模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 36; // 占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(GENERAL_TIM_MASTER, &TIM_OCInitStructure);
TIM_OCMode
:输出比较模式,这里设置为TIM_OCMode_PWM1
,配置为PWM1模式。TIM_OutputState
:设置为TIM_OutputState_Enable
,启用输出。TIM_Pulse
:设置PWM信号的脉宽,决定占空比。脉宽为36。TIM_OCPolarity
:输出极性设置为高,即PWM信号的高电平在计数器计数期间持续时间。
3.4 配置从定时器
TIM_TimeBaseStructure.TIM_Period = 4;
TIM_TimeBaseInit(GENERAL_TIM_SLAVE1, &TIM_TimeBaseStructure);
TIM_TimeBaseInit(GENERAL_TIM_SLAVE11, &TIM_TimeBaseStructure);
为两个从定时器设置周期为4的计数器。
TIM_OCInitStructure.TIM_Pulse = 1; // 占空比
TIM_OC1Init(GENERAL_TIM_SLAVE1, &TIM_OCInitStructure);
TIM_OC1Init(GENERAL_TIM_SLAVE11, &TIM_OCInitStructure);
3.5 配置主从模式
使能主从模式
TIM_SelectMasterSlaveMode(GENERAL_TIM_MASTER, TIM_MasterSlaveMode_Enable);
启用主定时器的主从模式,这使得主定时器可以作为触发源来驱动从定时器。
选择输出触发源
TIM_SelectOutputTrigger(GENERAL_TIM_MASTER, TIM_TRGOSource_Update);
设置主定时器的触发源为更新事件(计数器溢出时),主定时器的更新事件将触发从定时器。
配置从定时器为从模式
TIM_SelectSlaveMode(GENERAL_TIM_SLAVE1, TIM_SlaveMode_Gated);
TIM_SelectInputTrigger(GENERAL_TIM_SLAVE1, TIM_TS_ITR1);
将GENERAL_TIM_SLAVE1
配置为“门控模式”(Gated Mode),这意味着从定时器的计数会被主定时器的触发事件控制。触发源设置为输入触发1(ITR1
),这是主定时器的触发信号。
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Gated);
TIM_SelectInputTrigger(GENERAL_TIM_SLAVE11, TIM_TS_ITR2);
同样地,将GENERAL_TIM_SLAVE11
配置为“门控模式”,并设置触发源为输入触发2(ITR2
),另一个主定时器的触发信号。
3.6 启用定时器
TIM_Cmd(GENERAL_TIM_SLAVE1, ENABLE);
TIM_Cmd(GENERAL_TIM_MASTER, ENABLE);
TIM_Cmd(GENERAL_TIM_SLAVE11, ENABLE);
最后,启用所有定时器,使它们开始计数和生成PWM信号。
2024.9.13 第一次修订,后期不再维护
2025.1.26 优化代码
本文作者:hazy1k
本文链接:https://www.cnblogs.com/hazy1k/p/18412294
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步