OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 19688|回复: 13

[F4开发板通用] STM32的定时器中断,只要开启,会立即进入中断的解决办法(适合STM32全系列)

[复制链接]

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165352
金钱
165352
注册时间
2010-12-1
在线时间
2108 小时
发表于 2017-3-22 11:53:46 | 显示全部楼层 |阅读模式
有细心的客户发现,我们的STM32定时器中断实验,只要开启定时器中断,就会立即进入一次定时器中断服务程序,此后便正常了。
这个初次初始化,按理说,不应该这么快进入中断的(定时时间还未到),但是配置什么的,都是正常,可STM32就不按规则来,只要你开启,立即进入中断。
以我们探索者STM32F407开发板的定时器中断实验(实验8)为例,我们直接仿真例程,可以发现,只要执行完TIM3_Int_Init函数最后一行代码,便立即跳转到
TIM3_IRQHandler中断服务函数,点亮了LED1。如下图所示:
23.png
进入中断服务函数后,点亮LED1,所以大家可以看到,每次按复位,都是先亮LED1,然后再亮LED0的。
按设计来说,LED1应该在程序启动500ms以后,才开始亮的,而LED0则是初始化完成,就点亮闪烁。
所以和设计不符。

解决办法,其实很简单,在此贴:http://www.openedv.com/thread-68826-1-1.html ,1楼就给出了解决办法。
我们只需要在MY_NVIC_Init这行代码之前,添加2行代码,就可以了,修改后代码如下:
[mw_shl_code=c,true]//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为42M
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
        RCC->APB1ENR|=1<<1;        //TIM3时钟使能   
        TIM3->ARR=arr;          //设定计数器自动重装值
        TIM3->PSC=psc;          //预分频器          
        TIM3->DIER|=1<<0;   //允许更新中断          
        TIM3->CR1|=0x01;    //使能定时器3
       
        TIM3->EGR|=1<<0;        //产生更新事件
        TIM3->SR=0;                        //清所有标志
       
          MY_NVIC_Init(1,3,TIM3_IRQn,2);        //抢占1,子优先级3,组2                                                                  
}[/mw_shl_code]

实际上就是在设置定时器中断优先级之前,人为的产生一次更新事件,并对产生的标记进行清零。
这样,就解决了STM32定时器启动后立即进入中断的bug。

最后,感谢xkwy提供的解决思路,并附上修改后的测试代码(基于探索者F407开发板,不会立即进入定时器中断)。
实验8 定时器中断实验(修改后,不立即中断).rar (127.53 KB, 下载次数: 941)
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

11

主题

28

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
455
金钱
455
注册时间
2016-1-19
在线时间
114 小时
发表于 2017-4-20 14:05:12 | 显示全部楼层
回复 支持 反对

使用道具 举报

11

主题

28

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
455
金钱
455
注册时间
2016-1-19
在线时间
114 小时
发表于 2017-4-20 15:18:24 | 显示全部楼层

可以了,标志位写错了,__HAL_TIM_CLEAR_FLAG(&TIM3_Handler,TIM_IT_UPDATE);
回复 支持 反对

使用道具 举报

1

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2017-7-29
在线时间
18 小时
发表于 2017-8-1 19:55:19 | 显示全部楼层
mark!!
回复 支持 反对

使用道具 举报

17

主题

84

帖子

0

精华

初级会员

Rank: 2

积分
108
金钱
108
注册时间
2015-11-30
在线时间
22 小时
发表于 2017-10-18 14:11:36 | 显示全部楼层
我实验了一下,这样子确实好像解决了定时器启动后立即进入中断的bug,可是真正上还是进了中断,只是标SR的更新中断的标志位被清零,导致第一中断不会执行任何有效的函数,最后看起来的结果好像是定时器没有进中断。还有原子哥,这个问题的原因是什么呢?本着一个学习的心问一问、、、、、、、
回复 支持 反对

使用道具 举报

17

主题

84

帖子

0

精华

初级会员

Rank: 2

积分
108
金钱
108
注册时间
2015-11-30
在线时间
22 小时
发表于 2017-10-18 14:13:56 | 显示全部楼层
对了 还有    寄存器版本存在这个问题,不知道库函数存在这个问题吗?我个人觉得应该有,要不利用库函数就可以解决这个问题了、、、、、!
回复 支持 反对

使用道具 举报

27

主题

118

帖子

0

精华

高级会员

Rank: 4

积分
845
金钱
845
注册时间
2015-12-8
在线时间
175 小时
发表于 2018-3-22 19:36:49 | 显示全部楼层
MARK一下
回复 支持 反对

使用道具 举报

29

主题

338

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1181
金钱
1181
注册时间
2018-4-13
在线时间
170 小时
发表于 2018-10-22 19:20:33 | 显示全部楼层
感谢分享!
回复 支持 反对

使用道具 举报

3

主题

15

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2018-11-23
在线时间
9 小时
发表于 2019-2-13 11:06:14 | 显示全部楼层
原子哥,最近我也遇到类似的问题。我是用 F103CBT6 的 TIM4 的通道3作为输入捕获通道,可一旦开启定时器,SR寄存器中的UIF、CC1IF、CC2IF、CC3IF、CC4IF位就立即置1,就算调用TIM_ClearITPendingBit、TIM_ClearFlag函数也清不了。网上的“通过将清标志位放在开启中断之前”的方法不奏效,按照您的帖子中的方法依然不行。
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2019-6-11
在线时间
17 小时
发表于 2019-10-22 12:52:12 | 显示全部楼层
经调试,确实是初始化定时器后,TIMx_SR寄存器的UIF位会置位,若是马上开启更新中断,则立即进入中断服务函数。
主要的原因是,库函数内部出发了一次软件更新时间,目的是将TIM外设的部分预装载寄存器更新到期影子寄存器。代码如下:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx));
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));

  tmpcr1 = TIMx->CR1;  

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5))
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
  }

  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
  }

  TIMx->CR1 = tmpcr1;

  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;

  /* Set the Prescaler value */
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
   
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler and the Repetition counter
     values immediately */
  TIMx->EGR = TIM_PSCReloadMode_Immediate;    //就是此条语句导致的  
}
解决办法:在调用TIM_TimeBaseInit()函数后,调用TIM_ClearFlag()或TIM_ClearITPendingBit()函数清除更新标志即可
回复 支持 反对

使用道具 举报

7

主题

20

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2019-7-19
在线时间
24 小时
发表于 2019-12-30 11:28:38 | 显示全部楼层
我在库函数中添加这两行没用啊,是什么问题
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2018-12-29
在线时间
19 小时
发表于 2020-3-24 10:01:04 | 显示全部楼层
解决了吗
回复 支持 反对

使用道具 举报

5

主题

129

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
432
金钱
432
注册时间
2020-5-8
在线时间
66 小时
发表于 2020-10-9 18:36:48 | 显示全部楼层
优秀啊老哥
回复 支持 反对

使用道具 举报

4

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2019-5-25
在线时间
45 小时
发表于 2022-4-4 11:57:19 | 显示全部楼层
zzqssq 发表于 2019-2-13 11:06
原子哥,最近我也遇到类似的问题。我是用 F103CBT6 的 TIM4 的通道3作为输入捕获通道,可一旦开启定时器,S ...

我也遇到,SR变成0x1F,debug的时候也无法清除,但是中断还是可以正常进的,请最后解决方法吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 22:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表