[STM32F1]STM32F103滴答定时器定时不准?)

文章讲述了在使用STM32F103ZET6开发板时遇到的系统定时器不准的问题,原因是选择了错误的时钟源。作者指出系统定时器的时钟源应通过SysTick_CLKSourceConfig函数配置,并提到了配置时钟源为HCLK或HCLK_Div8的影响。此外,还讨论了滴答定时器中断配置,包括中断优先级和计数值的影响,以及在不同配置下计数行为的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 前几天调了1块F103ZET6的开发板,用了个系统定时器,感觉不准,最终找到原因是因为选错了时钟源。
今天来分享一下也算是给大家以后出现问题做个参考吧。
    说到时钟源,得说到STM32系统时钟的初始化。
   

24784631ef81c09c1b.png (44.07 KB )

下载附件

2022-9-12 17:12 上传



     前面就不说了,直接从复位中断说起。 复位所有的中断之后,导入Main函数
然后,进入SystemInit函数,进行时钟配置。在SystemInit函数中有一个  SetSysClock()函数

配置系统时钟为72M,这是在外部晶振为8M的情况下。
配置完系统时钟之后,然后运行Main函数,这就是STM32程序的启动过程。

系统定时器是是Core_cm3和Core_cm4内核均存在的定时器
F103c8t6,共有7个定时器,一个高级定时器TIM1,3个通用定时器TIm2、TIM3和TIM4、1个系统定

时器和2个看门狗定时器(独立的和窗口型)。
系统定时器(滴答定时器)是一个24位自减型计数器,也就是说他的最大计数次数为
111111111111111111111111,换算成十六进制为0XFFFFFF,十进制为16777215。
系统定时器的时钟来源可以通过 SysTick_CLKSourceConfig()来选择。

如果选择 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK)则为0,选择内部时钟72M。

若选择SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8),则系统时钟72M的8分频,

网上很多说把SysTick_CLKSource_HCLK_Div8叫做外部分始时钟,不知道是啥原因?

系统定时器时钟频率为9M
1 = 外部时钟源(STCLK) (AHB总线时钟的1/8(HCLK/8)
0 = 内核时钟(FCLK) (AHB总线时钟的频率(HCLK))

也就是这里我用错了时钟源导致系统定时器不准!!

这是原因1,还有一个原因在下面解释。
要是用滴答定时器中断,要配置滴答定时器的中断优先级,否则为默认的最低优先级。
滴答定时器发生中断后,不需要人为去清除中断标志位和重新加载预装值,系统会自动清除和装载,比较简单


 

滴答定时器配置



我们采用系统时钟的八分频,也就是系统时钟为9M,每秒钟计数为9M
设置计数值为9M,也就是说1秒钟进一次系统定时器中断函数,用变量i自加来表示。

但是这样的配置我们发现i的自加并没有按照1s加一次的理论进行,而且加的很快。
但后来把计数值放在系统分频的前面,也就是如下图所示,计数正常。


这个原因没找到,但是结果正确,哪位大佬帮忙解释一下,代码已上传。

还有个提示,就是用了滴答定时器做定时器中断之后,就不要再用于延时函数了
否则就冲突程序跑飞了,比如这样

还需要知道一点的是:

时钟配置为72MHz,第一行代码已经选择为滴答定时器系统时钟的8分频,也就是滴答定时器时钟为9MHz,

下面的“fac_us”需要得到的是时钟周期,即1us(1个fac_us)需要9个时钟周期,1个fac_ms需要9000个时钟周期。

以上就是对系统定时器计数不准的解释。
---------------------
作者:woai32lala
链接:https://bbs.21ic.com/icview-3252426-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

### STM32F103 Tick Timer 中断服务函数中判断中断产生的方法 在 STM32F103滴答定时器(SysTick 或其他通用定时器)中断服务函数中,可以通过检查特定寄存器的状态来确认是否发生了中断。以下是具体实现方式: #### 使用 SysTick 定时器的情况 对于 SysTick 定时器,其本身并不具备状态标志位供程序查询,因此无法像外部中断那样显式地检测中断是否发生。然而,当进入 `SysTick_Handler` 函数时,默认情况下已经触发了 SysTick 中断[^4]。 如果需要进一步验证当前确实是由于 SysTick 计数溢出而引发的中断,则可以在每次进入中断前设置一个全局变量作为标记,并在退出中断时清除该标记。例如: ```c volatile uint8_t systick_flag = 0; void SysTick_Handler(void) { systick_flag = 1; // 设置标志表示已进入中断 } ``` 随后可在主循环或其他地方读取此标志以决定下一步操作逻辑。 #### 对于通用定时器 TIMx 的情况 如果是基于通用定时器(如 TIM2 至 TIM5),则可以利用相应的 SR 寄存器中的更新事件标志 UEV 来判定是否有新的周期结束所引起的中断到来。下面是一个典型的例子展示如何完成这一过程[^1]: 假设我们正在处理 TIM2 更新中断: ```c #include "stm32f1xx.h" // 假设定义了一个回调函数指针数组存储各个定时器对应的处理函数 _TIMER_ISR g_TimerIsrFuncs; void TIM2_IRQHandler(void){ if(__HAL_TIM_GET_FLAG(&htim2,TIM_IT_UPDATE)!=RESET && __HAL_TIM_GET_IT_SOURCE(&htim2,TIM_IT_UPDATE)!=RESET ){ HAL_TIM_IRQHandler(&htim2); if(g_TimerIsrFuncs.T1_Handle != NULL){ g_TimerIsrFuncs.T1_Handle(); // 调用注册好的用户自定义处理函数 } __HAL_TIM_CLEAR_IT(&htim2,TIM_IT_UPDATE); // 清除中断标志位以防重复调用 } } ``` 这里需要注意两点: 1. 需要先通过宏 `__HAL_TIM_GET_FLAG()` 和 `__HAL_TIM_GET_IT_SOURCE()` 双重校验确保确实是因为指定类型的中断源才执行后续动作; 2. 执行完毕后记得清空中断标志以免造成死循环或者不必要的多次触发[^2]. 综上所述,无论是采用 SysTick 还是常规的 TIMx 定时器,在编写其中断服务例程的时候都需要遵循类似的思路去捕捉并响应实际发生的硬件事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值