TIM通用定时器设置外部时钟源&输出比较

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. 使用步骤:

  1. 时钟配置:启用定时器的时钟。
  2. 初始化定时器:配置定时器的预分频器、自动装载值等参数。
  3. 配置捕获/比较通道:如果需要使用输入捕获或输出比较功能,则需要进一步配置这些通道。
  4. 使能定时器:启动定时器开始计数。
  5. 处理中断:如果使用中断,则需要配置中断服务程序来处理事件。

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)

  1. 定义

    • 自动重装载寄存器(ARR,Auto-Reload Register)是定时器的一个重要寄存器,它存储了定时器向上计数或向下计数时的目标值。
    • 当定时器的计数器CNT(Counter)的值达到ARR的值时,CNT会被重载为0(向上计数模式)或ARR的值减1(向下计数模式),然后触发更新事件(Update Event)。
  2. 作用

    • 决定了定时器的一个完整计数周期的长度。
    • 通过设置ARR的值,可以调整定时器的周期时间,从而改变定时器的频率。
  3. 例子

    • 假设ARR被设置为9999,定时器的计数器从0开始向上计数,当计数器达到9999时,它会重新加载为0,此时触发更新事件。

2. 预分频器 (Prescaler)

  1. 定义

    • 预分频器(PSC,Prescaler)是用来减少定时器的输入时钟频率的。
    • 它可以将定时器的输入时钟频率降低一个可编程的比例,使得定时器可以工作在一个较低的频率上。
  2. 作用

    • 调整定时器的频率,从而可以精确地设置定时器的周期时间。
    • 减少定时器的功耗,因为较低的频率意味着较低的能量消耗。
  3. 例子

    • 如果系统的时钟频率为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. 配置输出比较的基本步骤

  1. 初始化定时器:配置定时器的基本属性,如预分频器、自动重装载值等。
  2. 配置捕获/比较通道:选择要使用的通道并配置其输出模式。
  3. 设置捕获/比较寄存器:设置CCR寄存器的值来确定输出信号的占空比。
  4. 使能输出:使能选定通道的输出。

4. 输出比较配置PWM

配置流程:

  1. 启用GPIO时钟:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    

    这一行启用了GPIOB端口的时钟,因为电机控制相关的GPIO引脚位于GPIOB端口上。

  2. 配置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_IAMotor_IBMotor_IA 被配置为普通的推挽输出模式 (GPIO_Mode_Out_PP),而 Motor_IB 被配置为复用推挽输出模式 (GPIO_Mode_AF_PP),这意味着它将被用作定时器的输出引脚。即PWM输出引脚需要配置为复用推挽输出模式。

  3. 启用TIM4时钟:

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    

    这一行启用了TIM4定时器的时钟。

  4. 配置TIM4内部时钟:

    TIM_InternalClockConfig(TIM4);
    

    这一行配置TIM4使用内部时钟源。

  5. 配置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,不使用重复计数功能。
  6. 配置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%

  7. 使能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值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingLod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值