TIM通用定时器设置外部时钟源&输出比较功能
文章目录
1. TIM通用定时器
STM32微控制器中的通用定时器(General-Purpose Timers)是一组非常灵活且功能强大的外设,它们能够支持多种不同的应用需求,如精确的定时控制、脉宽调制(PWM)信号生成、脉冲宽度测量等。
1. 通用定时器的特点
- 通常基于一个16位的自动装载计数器(某些型号可能是32位)。
- 可以通过预分频器(Prescaler)进行计数频率的调整。
- 支持向上计数、向下计数、中央对齐模式等多种计数模式。
- 具有多个捕获/比较通道(通常4个或更多)。
- 支持输入捕获功能,可用于测量外部信号的周期或脉宽。
- 支持输出比较功能,可以生成PWM信号。
- 支持互补输出功能,可以生成互补的PWM信号。
- 支持中断和DMA请求。
2. STM32中的通用定时器
- 一般指TIM2、TIM3、TIM4和TIM5(具体型号可能会有所不同)。
- 这些定时器位于低速APB1总线上,这意味着它们的运行频率不会超过APB1的最大频率(通常是36MHz或更低)。
2. 使用步骤:
- 时钟配置:启用定时器的时钟。
- 初始化定时器:配置定时器的预分频器、自动装载值等参数。
- 配置捕获/比较通道:如果需要使用输入捕获或输出比较功能,则需要进一步配置这些通道。
- 使能定时器:启动定时器开始计数。
- 处理中断:如果使用中断,则需要配置中断服务程序来处理事件。
2.通用定时器选择外部时钟源
1. 配置流程
这段代码是在STM32微控制器上配置一个通用定时器(TIM2)并设置相应的GPIO引脚和中断。下面是对每一部分的详细解释:
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
这里首先启用了TIM2定时器的时钟和GPIOA的时钟。TIM2位于APB1总线上,而GPIOA位于APB2总线上。ENABLE
宏用于开启这些时钟。
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
这部分设置了GPIOA的第0号引脚(PA0)为上拉输入模式,并且设置了最大速度为50MHz。这通常是为了连接到外部设备或者用于某种输入信号的捕获。
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
这里配置了TIM2的外部触发输入(ETR)的时钟模式2。这里关闭了外部触发预分频器,设置了非反转极性,并且配置了触发滤波器的采样点数为16(0x0F + 1)。这个配置对于不使用外部触发的情况是默认的。
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
这部分配置了TIM2的基本计数特性:
TIM_CKD_DIV1
: 时钟分频设置为1,即计数器的时钟频率等于输入时钟频率。TIM_CounterMode_Up
: 计数模式设置为向上计数。TIM_Period = 10 - 1
: 自动装载寄存器的值设置为9,这意味着计数器从0开始计数,当计数值达到9时重置回0,完成一个周期。TIM_Prescaler = 1 - 1
: 预分频器设置为0,意味着没有额外的分频。TIM_RepetitionCounter = 0
: 没有重复计数。
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
这部分清除了TIM2的更新标志,并使能了更新中断。当计数器完成一个周期时,会设置更新标志并触发中断。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
配置嵌套向量中断控制器(NVIC)的优先级分组为2,这意味着主优先级有2位,子优先级也有2位,总共4个优先级级别。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
这部分配置了NVIC中断优先级,使能了TIM2的中断,并设置了它的抢占优先级为2,子优先级为1。
TIM_Cmd(TIM2, ENABLE);
最后,使能TIM2定时器。
当PA0引脚的电平发生变化时,自动重装载寄存器的值进行增加,当计数溢出时,进入中断。实现了外部时钟作为定时器时钟源的操作。
2. 完整代码
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
3. 自动重装载寄存器和预分频器
在STM32的定时器中,自动重装载寄存器(Auto-Reload Register)和预分频器(Prescaler)是非常重要的组成部分,它们共同决定了定时器的工作周期和频率。
1. 自动重装载寄存器 (Auto-Reload Register)
-
定义:
- 自动重装载寄存器(ARR,Auto-Reload Register)是定时器的一个重要寄存器,它存储了定时器向上计数或向下计数时的目标值。
- 当定时器的计数器CNT(Counter)的值达到ARR的值时,CNT会被重载为0(向上计数模式)或ARR的值减1(向下计数模式),然后触发更新事件(Update Event)。
-
作用:
- 决定了定时器的一个完整计数周期的长度。
- 通过设置ARR的值,可以调整定时器的周期时间,从而改变定时器的频率。
-
例子:
- 假设ARR被设置为9999,定时器的计数器从0开始向上计数,当计数器达到9999时,它会重新加载为0,此时触发更新事件。
2. 预分频器 (Prescaler)
-
定义:
- 预分频器(PSC,Prescaler)是用来减少定时器的输入时钟频率的。
- 它可以将定时器的输入时钟频率降低一个可编程的比例,使得定时器可以工作在一个较低的频率上。
-
作用:
- 调整定时器的频率,从而可以精确地设置定时器的周期时间。
- 减少定时器的功耗,因为较低的频率意味着较低的能量消耗。
-
例子:
- 如果系统的时钟频率为72MHz,而预分频器被设置为83,那么定时器的输入频率就会变为72MHz / (83 + 1),大约是867kHz。
通过上面的描述,我们就明白了,自动重装载寄存器的值决定了我们的计数个数,而预分频器的值决定了我们计每个数的频率。我们再来理解我们定时时间的配置,当预分频系数为7200时,72 / 7200 = 0.01MHZ ,则每增加一个数的时间为100us,故定时器的时间为 100us * 10000(ARR) = 1s.
3. 输出比较
在STM32微控制器中,通用定时器支持输出比较功能,该功能允许定时器通过其输出引脚生成特定类型的信号,最常见的是脉宽调制(PWM)信号。输出比较功能通过配置定时器的捕获/比较通道来实现。
1. 输出比较的基本原理
- 捕获/比较通道:每个通用定时器都有多个捕获/比较通道(通常为4个),这些通道可以被配置为输出比较模式。
- 输出比较模式:在输出比较模式下,定时器会在计数器CNT的值等于某个指定的捕获/比较寄存器(CCR)的值时改变对应的输出引脚的状态。
- 输出类型:输出可以配置为活跃高、活跃低、PWM模式等。
2. 输出比较的应用
- PWM信号生成:最常见的用途之一就是生成PWM信号,用于电机控制、LED亮度调节等。
- 事件计时:可以用来生成定时事件,比如定时中断。
- 模拟输出:可以用来生成模拟电压信号。
3. 配置输出比较的基本步骤
- 初始化定时器:配置定时器的基本属性,如预分频器、自动重装载值等。
- 配置捕获/比较通道:选择要使用的通道并配置其输出模式。
- 设置捕获/比较寄存器:设置CCR寄存器的值来确定输出信号的占空比。
- 使能输出:使能选定通道的输出。
4. 输出比较配置PWM
配置流程:
-
启用GPIO时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
这一行启用了GPIOB端口的时钟,因为电机控制相关的GPIO引脚位于GPIOB端口上。
-
配置GPIO引脚:
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = Motor_IA; GPIO_Init(Motor_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = Motor_IB; GPIO_Init(Motor_GPIO, &GPIO_InitStructure);
这里配置了两个GPIO引脚,
Motor_IA
和Motor_IB
。Motor_IA
被配置为普通的推挽输出模式 (GPIO_Mode_Out_PP
),而Motor_IB
被配置为复用推挽输出模式 (GPIO_Mode_AF_PP
),这意味着它将被用作定时器的输出引脚。即PWM输出引脚需要配置为复用推挽输出模式。 -
启用TIM4时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
这一行启用了TIM4定时器的时钟。
-
配置TIM4内部时钟:
TIM_InternalClockConfig(TIM4);
这一行配置TIM4使用内部时钟源。
-
配置TIM4基本定时器设置:
TIM_BaseInitStu.TIM_ClockDivision = TIM_CKD_DIV1; TIM_BaseInitStu.TIM_CounterMode = TIM_CounterMode_Up; TIM_BaseInitStu.TIM_Prescaler = 36 - 1; //预分频值 PSC TIM_BaseInitStu.TIM_Period = 100 - 1; //自动装载值 ARR TIM_BaseInitStu.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM4,&TIM_BaseInitStu);
这里设置了TIM4的基本定时器特性:
TIM_ClockDivision
: 设置时钟分割因子为1,即不分频。TIM_CounterMode
: 设置向上计数模式。TIM_Prescaler
: 设置预分频器值为35,意味着实际的预分频器值为36。TIM_Period
: 设置自动装载寄存器值为99,意味着每100个计数周期后会重新加载。TIM_RepetitionCounter
: 设置重复计数器为0,不使用重复计数功能。
-
配置TIM4输出比较通道:
TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = ENABLE; TIM_OCInitStructure.TIM_Pulse = 50; //CCR TIM_OC3Init(TIM4,&TIM_OCInitStructure);
这里配置了TIM4的输出比较通道3 (CH3),以生成PWM信号:
TIM_OCMode_PWM1
: 设置为PWM1模式,这意味着输出在计数器溢出后保持高电平,直到达到指定的脉冲宽度。TIM_OCPolarity_High
: 设置输出极性为高。TIM_OutputState
: 使能输出。TIM_Pulse
: 设置CCR3寄存器值为50,这意味着PWM信号的占空比为50%。
PWM频率:Freq = CK_PSC / (PSC + 1) / (ARR + 1) 72 / 36 / 100 = 0.02MHZ = 20 KHZ
PWM占空比:Duty = CCR / (ARR + 1) 50 / 100 = 50
PWM分辨率:Reso = 1 / (ARR + 1) 1%
-
使能TIM4:
TIM_Cmd(TIM4, ENABLE);
最后,使能TIM4定时器。
对于PWM的输出引脚,需要参考引脚定义图,TIM_OC3Init(TIM4,&TIM_OCInitStructure);
,这里的oc3
表示要使用的为定时器4的CH3通道。
完整代码:
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = Motor_IA;
GPIO_Init(Motor_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = Motor_IB;
GPIO_Init(Motor_GPIO, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_BaseInitStu;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_InternalClockConfig(TIM4);
TIM_BaseInitStu.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_BaseInitStu.TIM_CounterMode = TIM_CounterMode_Up;
TIM_BaseInitStu.TIM_Prescaler = 36 - 1; //预分频值 TIM_Period x TIM_Prescaler / 时钟频率
TIM_BaseInitStu.TIM_Period = 100 - 1; //自动装载值
TIM_BaseInitStu.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4,&TIM_BaseInitStu);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = ENABLE;
TIM_OCInitStructure.TIM_Pulse = 50;
TIM_OC3Init(TIM4,&TIM_OCInitStructure);
TIM_Cmd(TIM4, ENABLE);
}
另外需要在初始化后更改占空比需要调用PWM_SetCompare3(value);
。
value为CCR值。