STM32单片机示例:多个定时器级联使用

目的

有些情况下会遇到单片机的定时器位数不够用,这时候可以使用低定时器级联的方式来处理,这里将对此做个示例说明。

基础说明

这里说的定时器级联是指一个定时器正常计数工作,然后在发生溢出时发送一个时钟信号,这个时钟信号作为另一个定时器的时钟源。这样相当前一个定时器可以表达低数据,后一个定时器可以表达高数据。

定时器之间级联是有一定限制的,不是随便哪个定时器之间都可以随便触发的。对于哪个TIM可以被哪个TIM触发,ITRx是多少可以参考芯片参考手册的 TIMx internal trigger connection (TIMx 内部触发连接) 表格:
在这里插入图片描述

在下面演示中将使用TIM2作为主定时器,使用TIM4作为从定时器。

关键配置与代码

在这里插入图片描述
在这里插入图片描述

除了配置生成的代码,需要手动添加的代码就几行(LL库):

int main(void)
{
  LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_SYSCFG);
  NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),15, 0));
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();

  LL_TIM_EnableCounter(TIM4); // 使能TIM4开始计数(高数据)
  LL_TIM_EnableCounter(TIM2); // 使能TIM2开始计数(低数据)
  // TIM2设置1us计数一次,TIM2计数溢出时TIM4计数一次

  uint64_t pred = 0;
  while (1)
  {
      uint64_t d; // 用于保存当前时间
      uint32_t du = LL_TIM_GetCounter(TIM4); // 读取时间高数据
      uint32_t dl = LL_TIM_GetCounter(TIM2); // 读取时间低数据

      if (du == LL_TIM_GetCounter(TIM4)) // 和前次读取高数据相同, 表明低数据并未发生溢出
      {
          d = ((uint64_t)du * 4096) + dl;
      }
      else // 和前次读取高数据不同, 表明低数据发生溢出
      {
          d = ((uint64_t)LL_TIM_GetCounter(TIM4) * 4096) + LL_TIM_GetCounter(TIM2);
      }

      // 每1000us翻转一次IO输出用作验证
      if ((d - pred) > 1000)
      {
          pred = d;                                // 保存当前时间
          LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_4); // 翻转IO口
      }
  }
}

示例链接

仓库地址: https://github.com/NaisuXu/STM32_MCU_Examples

本示例为仓库中 TIM_Concatenation_LL_H750

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32中,可以通过定时器级联的方式来扩展定时器的位数,从而增加定时器的计数范围。下面是一个简单的定时器级联示例,假设我们要将TIM2和TIM3级联,以扩展定时器的位数。 首先,需要配置TIM2和TIM3的基本参数,如计数模式、预分频值、自动重载值等。这里假设TIM2和TIM3都使用内部时钟源,计数模式为向上计数,预分频值为71(即72MHz的时钟频率下,计数器每增加1需要消耗1us的时间),自动重载值为999。 ```c TIM_HandleTypeDef htim2, htim3; void TIM2_Configuration(void) { TIM_ClockConfigTypeDef sClockSourceConfig; TIM_MasterConfigTypeDef sMasterConfig; htim2.Instance = TIM2; htim2.Init.Prescaler = 71; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 999; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim2); sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig); sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig); } void TIM3_Configuration(void) { TIM_ClockConfigTypeDef sClockSourceConfig; TIM_MasterConfigTypeDef sMasterConfig; htim3.Instance = TIM3; htim3.Init.Prescaler = 71; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 999; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim3); sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig); sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig); } ``` 注意,在配置TIM2和TIM3时,需要使用HAL_TIMEx_MasterConfigSynchronization函数将TIM2配置为主定时器(Master),将TIM3配置为从定时器(Slave)。 接下来,需要在代码中启动TIM2和TIM3,并设置TIM2的ARR寄存器为0xFFFF,以便在TIM2计数器溢出时触发TIM3的更新事件,从而完成定时器级联。 ```c void TIM2_TIM3_Cascade(void) { // Start TIM2 and TIM3 HAL_TIM_Base_Start(&htim2); HAL_TIM_Base_Start(&htim3); // Set TIM2 ARR register to 0xFFFF __HAL_TIM_SET_AUTORELOAD(&htim2, 0xFFFF); } ``` 这样,就完成了TIM2和TIM3的定时器级联。在使用过程中,可以像使用单个定时器一样使用TIM2和TIM3,同时可以利用级联的方式扩展计数范围。需要注意的是,在使用级联定时器时,需要先停止从定时器(Slave),再停止主定时器(Master),否则可能会出现计数不准确的情况。 ```c // Stop TIM3 and TIM2 HAL_TIM_Base_Stop(&htim3); HAL_TIM_Base_Stop(&htim2); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Naisu Xu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值