快捷搜索:  as  xxx

stm32定时器中断与误区

STM32准时器知知趣称繁杂,这里枚举一些根基常识,在之后的文章我会写一下它的各类利用。

通用准时器是一个经由过程可编程预分频器驱动的16位自动装载计数器构成。它适用于多种场合,包括准时中断、丈量输入旌旗灯号的脉冲长度(输入捕获)或者孕育发生输出波形(输出对照和PWM)。每个准时器都是完全自力的,没有相互共享任何资本,它们可以一路同步操作。

STM32F103RC系列有4个通用准时器,2个高档准时器和两个基础准时器:

我们最常应用通用准时器,功能包括:

1、16位向上 、向下、向上/向下自动装载计数器(TIMx_CNT),例如向上是指:计数器从0计数到自动加载值(TIMx_ARR),然后从新从0开始计数并且孕育发生一个计数器溢出事故。

2、16 位可编程(可以实时改动)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的随意率性数值。

3、4 个自力通道(TIMx_CH1~4)。

4、支持多种中断,如溢出中断等。

这里我们讲述应用通用准时器中断实验:

一、准时器时钟选择

我们常应用内部时钟(CK_INT),经由过程设置设置设备摆设摆设TIMx_SMCR的SMS[2:0],设置设置设备摆设摆设为000。该时钟是ABP1时钟的的1倍(APB1不分频)或2倍(APB1分频)。

二、计数器模式

可选择向上 、向下或者向上/向下。

三、准韶光诡计略

溢出光阴 = ( 自动加载值(ARR)+ 1 )( 预分频系数(PSC)+ 1 ) / 准时器时钟(Tclk)

四、库函数设置设置设备摆设摆设

1、使能能准时器时钟。

2、初始化准时器,设置设置设备摆设摆设ARR,PSC(在stm32f10x_tim.c)

TIM_TimeBaseInit();

此中的布局体:typedef struct

{

uint16_t TIM_Prescaler; //设置分频系数

uint16_t TIM_CounterMode; //计数要领

uint16_t TIM_Period; //自动重装载值

uint16_t TIM_ClockDivision;

uint8_t TIM_RepetitionCounter;

} TIM_TimeBaseInitTypeDef;

3、开启准时器中断,设置设置设备摆设摆设中断优先级分组NVIC。

void TIM_ITConfig();

NVIC_Init();

4、 使能准时器。

TIM_Cmd();

5、编写中断办事函数。

TIMx_IRQHandler();

stm32准时器误区

在用到STM32准时器的更新中断时,发明有些情形下只要开启准时器就急速进入一次中断。准确说,只要使能更新中断容许位就急速相应一次更新中断【当然条件是相关NVIC也已经设置设置设备摆设摆设好】。换言之,只要使能了相关准时器更新中断,不管你准光阴隔多长以致不在乎你是否启动了相关准时器,它都邑急速进入一次准时器更新中断办事法度榜样。

以STM32F051芯片为例,做了几种不合顺序的组合测试。根据测试发明,切实着实有些环境下一运行TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); 【纵然能更新中断】就急速进入更新中断办事法度榜样。当然后面的中断都是正常的。

老实说,这个问题对照轻易漠视,有些环境下也无关紧要,但有些环境可能会给利用带来困扰。从ST MCU相关技巧手册彷佛并不能显着地找到关于这个问题的很相宜或者逻辑性很强的前因后果。

颠末验证测试,假如留意一下相关指令代码顺序是可以逃避这个问题的。

先做更新中断标志的清除操作,即清除TIMx-》SR寄存器里的UIF标志,然后做准时器更新中断的使能操作。至于开启相关准时器的指令摆放位置并不严格。下面是相关动作的操作顺序及结果,可以参考、验证之。这里共列举了6种写法,此中有3种情形是会急速进入中断的,别的3种不会。

TIM_ClearITPendingBit(TIM1, TIM_IT_Update); //清除更新中断哀求位

TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //使能准时器1更新中断

TIM_Cmd(TIM1, ENABLE); //启动准时器

(1)。。。。。。不会急速进入更新中断法度榜样。

TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清除更新中断哀求位

TIM_Cmd(TIM1, ENABLE);

TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);//使能准时器1更新中断

(2)。。。。。。不会急速进入更新中断法度榜样。

TIM_Cmd(TIM1, ENABLE);

TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清除更新中断哀求位

TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);//使能准时器1更新中断

(3)。。。。。。不会急速进入更新中断法度榜样。

TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清除更新中断哀求位

TIM_Cmd(TIM1, ENABLE);

(5)。。。。。。急速进入更新中断法度榜样。

(6)。。。。。。急速进入更新中断法度榜样。

顺便提下关于准时器里UG位和URS位的应用,分手在TIMx-》EGR和TIMx-》CR1寄存器里。对UG位置1可以孕育发生更新事故并对相关计数器和寄存看从新初始化,假如URS位为0的话,同时会孕育发生更新中断。假如不盼望对UG位置1的同时孕育发生更新中断,得置URS位为1,否则会急速进入更新中断。

别的

我们日常平凡应用准时器的时刻多半都是处于开启状态,日常平凡的准时中断书写款式一样平常是:

void TIM3_IRQHandler(void)

{

if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)

{

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

//要处置惩罚的事故内容。。。。

}

}

然则,项目的实验历程中,我应用的准时器处置惩罚事故轻细有点特殊,即,准时器不是不停处于开启状态, 而且关闭时刻也是在中断里关闭。大年夜概形式这样:

void TIM3_IRQHandler(void)

{

if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)

{

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

//要处置惩罚的事故内容。。。。

TIM_Cmd(TIM3, DISABLE); //掉能(函数外使能)

}

}

看似没错,而且也看似正常。然则,处置惩罚的事故内容呈现了很多未知差错(因为我的这个处置惩罚事故有很强的时序性,开始和停止都对照严格),无法正常履行。经由过程后来的调试中发明(把处置惩罚光阴改为点灯或者打印输出要领),发明是:TIM_Cmd(TIM3, DISABLE); 扰乱了时序关系。当掉能后,着实中断并没有真正掉能,还会再进入一次中断,是以事故又被履行了一次,对付时序对照严格的事故,就孕育发生了问题!

找到了缘故原由,是以,我预测虽然准时器掉能并且关闭了准时器,然则可能中断标志位并没真正清除,虽然中断开始已经清除过一次,但预计由于掉能使得标志位又被置位了,是以,我在掉能前面加了句清除中断更新标志位,如下:

void TIM3_IRQHandler(void)

{

if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)

{

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

//要处置惩罚的事故内容。。。。

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//再清除标志位

TIM_Cmd(TIM3, DISABLE); //掉能(函数外使能)

}

}

公然,法度榜样可以正常的时序运行。

对照纳闷关准时器前又得清下标志位,是以引起了另一个好奇心,是不是在其他地方关闭准时器(如主函数),也得这样做才可以。以是对这个好奇心进行了下测试。发明:假如把关闭准时器放到了主函数后,不用再清中断标志位。能正常把准时器关闭,并不会进入中断。

经由过程此次的问题,挥霍了很多光阴办理,不过也罗致到了点履历,但对付内在真正缘故原由:在中断里掉能和中断外掉能效果为什么不一样,暂时还没搞清楚。。。但这个可以作为今后的前车之鉴,以及大年夜家的前车之鉴,少走弯路。

您可能还会对下面的文章感兴趣: