关于stm32 timer用法,用过mtk StartTimer接口的必看

从事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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的抉择

每周至少一篇,感谢!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值