从事MTK功能机平台开发多年,习惯用StartTimer接口,void StartTimer(U16 timerid, U32 delay, FuncPtr funcPtr)
1.痛苦篇
刚开始在STM32上用timer很不习惯,见过别人写的一些代码,用一个定时的判断,至少需要定义三个全局变量,一个用作timer的计数,另一个用作开始计数的flag,还一个用作计时达到处理事件的flag,把TIM14定义1ms的定时器,在回调写入
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ if (htim->Instance == TIM14) { if(flag_delay_1s) index_ms++; if(index_ms>1000) { index_ms=0; flag_event = 1; } } } void main() { if() //达到某个事件,开始定时 { flag_delay_1s = 1; //设置定时启动的标志 } if(flag_event) //定时结束处理 { //do something flag_event = 0; flag_delay_1s = 0; } }
为了用一个定时的功能,要写这一堆代码,而且代码不能复用,真是不胜其烦。
2.解决篇
业务上有一堆定时的需求,代码不能复用的问题必须要解决,因此思考了很久,对mtk的StartTimer接口用法也做了对比,结合STM32上事件都在main中处理的方式,采用的方案是
1)定义1个1ms的定时器,用一个全局变量一直在累加,达到上限置0再累加
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43u32 get_tim3_int_num(void) { return tim3_arr_num; } void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 //定时器TIM1初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = (psc-1); //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //重复计数关闭 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE ); //使能指定的TIM1中断,允许更新中断 TIM_Cmd(TIM3, ENABLE); //使能TIMx //中断优先级NVIC设置 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM1中断 NVIC_InitStructure.NVIC_IRQChannelPriority = 3; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 } void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { if(tim3_arr_num==0xffffffff) { tim3_arr_num = 0; } tim3_arr_num++; TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx更新中断标志 } }
2)定义开始计时,时间达到,清除定时,判断定时是否在运行四个接口
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34void clear_timer(timer_struct* p_timer) { memset(p_timer, 0, sizeof(timer_struct)); } void begin_timer(timer_struct* p_timer,u32 timeout) { if(0==p_timer->flag) { p_timer->begin_int = get_tim3_int_num(); p_timer->flag = 1; p_timer->timeout = timeout; } } BOOL IsTImerExist(timer_struct* p_timer) { if(p_timer->flag) return TRUE; else return FALSE; } BOOL checkTimerOut(timer_struct* p_timer) { if(p_timer->flag) { u32 act_val; u32 int_val = get_tim3_int_num(); // 1ms act_val = int_val >= p_timer->begin_int?(int_val-p_timer->begin_int):(0xffffffff-p_timer->begin_int+int_val); if(act_val >= p_timer->timeout-1) return TRUE; } return FALSE; }
3)业务上先定义归属该事件的变量,然后调用接口
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24typedef struct{ u8 flag; u32 begin_int; u32 timeout; }timer_struct; timer_struct demo_timer; void main() { if()//达到某个条件要采用定时器 { if(!demo_timer.flag) { begin_timer(&demo_timer,1000); //开始计时1S定时器 } } if(demo_timer.flag && checkTimerOut(&demo_timer)) //定时器在运行且达到时间 { //do something clear_timer(&demo_timer); } }
4)需要用多少定时器,都可直接调用接口就可以了。这个对于时间精度要求不高的,非常方便。
感谢您的关注,专注STM32 + MC20/EC20/M5311的开发(Q190109829)
最后
以上就是傲娇胡萝卜最近收集整理的关于关于stm32 timer用法,用过mtk StartTimer接口的必看的全部内容,更多相关关于stm32内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复