单片机定时,延时执行功能设计

        在原先一篇文章里面我有分享一种裸机时间片轮训的实现方式,现在在上面的基础上增加一个倒计时判定的功能。

        举个例子:现在有一个设定,在采集温度小于50度时,想实现先打开继电器1,30s后打开继电器2,当采集温度大于100度时,关闭这两个继电器,并且要求在接下来的5分钟内,禁止打开继电器(即使温度小于50度)。

       上面的逻辑很简单,实现的方式也很多,下面我记录分享一种最近接触到的。

       考虑不同时间计时的共同元素都有:计时是否开始,计时是否完成,计时多久。所以先定义一个基础的计时单元结构体定义在定时器头文件;

typedef struct{
	uint8_t  flg;//计时标志
	uint8_t  sta;//计时状态
	uint32_t cnt;//计数值
}Stc_Timer,*Pstc_Timer;//基本单元

        好的,到这里就算完成一半了,可以庆祝了。

        接下来我们就可以考虑怎么结合上面的共同元素去开始计时,以及如何计时了,以前提过计时原理基本都是利用单片机的定时器,那么可以设计一个开始计时的函数,在需要计时的时候调用一下,把上面的参数传入。告诉单片机定时器,这个东西我要倒计时,你自己去减,减好了和我说一下。

#define	START                  1
#define	NOT_START              0
#define	FINISH                 1
#define	NOT_FINISH             0
extern int16_t Start_Timer(Stc_Timer *ptm,u32 dly)
{
	if(ptm == NULL)
    {
        return -1;
    }
	ptm->sta = START;
	ptm->flg = NOT_FINISH;
	ptm->cnt = dly;
	return ERROR_OK;
}

       设计了开始计时,就要考虑如何去计时了,很简单,我定时的去判定有没有需要计时的,有我就按照上面要求的去不断地减设定的计数值。

Stc_Timer Relay_Timer[Relay_Num];//定义一个数据类型为计时单元的数组
//只要你想让某个流程开始计时,你就可以为其设定一个计时单元类型的变量

int16_t Relay_Timer_Count(void)
{
	for(u8 i = 0;i < Relay_Num;i++)//遍历数组里面所有成员
	{
		if(Relay_Timer[i].sta == START)//如果是计时状态
		{
			if(Relay_Timer[i].cnt <= 1)//判断计时数值是否减完
			{
				Relay_Timer[i].flg = FINISH;//计时完成
				Relay_Timer[i].sta = NOT_START;//不用计时
				Relay_Timer[i].cnt = INIT_TIME;//装载初始值100次
			}
			else//计时未完成就继续减
			{
				gen_timer[i].cnt--;
			}
		}
	} 
	return 0;
}

        上面的函数一定要定时的去执行,比如放在10ms执行一次的任务当中。10ms减一次。这样我填写计数值的时候,填写一个3000,就表示3000个10ms,也就是30s。

        如何计时设计完了,接下来就是考虑停止计时了,将计时单元恢复到不用计时的初始状态。有的可能会考虑到,它自己计时完毕已经恢复到初始状态了 ,没必要多此一举。

但用到if,就一定要考虑else的必要性!!!

        如果存在开始计时,那么一定存在计时未完成被中断的情况,假如继电器2坏掉,就没有必要计时了。

extern int16_t Stop_Timer(Stc_Timer *ptm)
{
	if(ptm == NULL)
    {
        return -1;
    }
	ptm->sta = NOT_START;//不开始计时
	ptm->flg = NOT_FINISH;//计时结束
	ptm->cnt = 0;
	return 0;
}

 

//伪代码
#define RELAY1_ON
#define RELAY2_ON
#define RELAY1_OFF
#define RELAY2_OFF

int Relay_Time_Task(void)
{
    if(RELAY1_ON == 1)
    {
        start_timer(&Relay_Timer[0],3000);
    }
    if(Relay_Timer.flg != FINISH)
    {
        return 0;
    }
    RELAY2_ON;
}

还有关闭5分钟禁止再次开启,也是同样的道理就不写了。

        编写一个关继电器的函数,把开启倒计时5分钟的函数也放一起,定义一个新的结构体变量。在开启继电器函数最开始就判定这个倒计时标志是否完成,未完成就直接return不继续往下执行。

        有大佬愿意指点,可以分享更好的办法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GQli2048

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值