从事MTK功能机平台开发多年,习惯用StartTimer接口,void StartTimer(U16 timerid, U32 delay, FuncPtr funcPtr)
1.痛苦篇
刚开始在STM32上用timer很不习惯,见过别人写的一些代码,用一个定时的判断,至少需要定义三个全局变量,一个用作timer的计数,另一个用作开始计数的flag,还一个用作计时达到处理事件的flag,把TIM14定义1ms的定时器,在回调写入
void 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再累加
u32 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)定义开始计时,时间达到,清除定时,判断定时是否在运行四个接口
void 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)业务上先定义归属该事件的变量,然后调用接口
typedef 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)