延时函数(阻塞式,非阻塞式)

常规阻塞式延时:

void delay_1ms(uint32_t count)
{
    delay = count;
    delay--;    

    while(0U != delay){
    }
}

非常规阻塞式延时(可用于中断):

//处理延时在中断中卡死的情况
static u8 delaying_times = 0;//叠加执行延时的次数
static u16 delaying_finish = 0;//记录最多16个的递归溢出事件中,每一个是否都已经记数溢出
void delay_ms(u16 nms)
{
	u32 last_systick_val;
	if(delaying_times != 0)//如果主程序在跑delay函数的过程中,发生中断并在中断中又进入了delay函数
	{
		last_systick_val = SysTick->VAL;//将上次的计数器的值保存下来以便退出中断后回去时可以从该值继续递减
		//如果上次记数已经溢出,代表着上次的delay已经记数完成,将该次溢出事件记录下来,以便出了中断回到原delay函数时,可以直接跳出while
		//delaying_finish是16位的,最多可以记录16次溢出事件,即16层的递归
			if(SysTick->CTRL & (1 << 16))delaying_finish |= (1 << (delaying_times - 1));
	}
	delaying_times ++;
	SysTick->LOAD = (u32)fac_ms * nms;//自动重装载值
	SysTick->VAL = 0x00;//清除计时器的值
	SysTick->CTRL |= (1 << 0);//SysTick使能,使能后定时器开始倒数
	while(!(SysTick->CTRL & (1 << 16)))//判断是否减到0,减到0时CTRL的第16位会置1,读取后会自动置0
	{
		//如果在中断中计数器已经溢出,就退出while,并且对应中断位清零
		if(delaying_finish & (1 << (delaying_times- 1)))
		{
			delaying_finish &= ~(1 << (delaying_times- 1));
			break;
		}
	}
    delaying_times --;
	if(delaying_times == 0)
	{
		SysTick->CTRL &= ~(1 << 0);//关闭SysTick,关闭后记数器将不再倒数
		SysTick->VAL = 0x00;//清除计时器的值(执行关闭SysTick程序时,记数器又开始了新一轮的倒数,所以关闭后记数器的值不为0)
	}
	else
	{
		/* 读取CTRL寄存器的同时,CTRL的第16位会变为0,关闭SysTick后给VAL寄存器赋值再使能的原因
		 * 1.若未关闭SysTick,且先将CTRL的第16位清零后再给VAL寄存器赋值,则在赋值的过程中计数器可能会记数到0,从而导致CTRL的第16位又被置1
		 * 2.若未关闭SysTick,且先给VAL寄存器赋值后再将CTRL的第16位清零,则在清零的过程中计数器会继续递减并且可能在CTRL的第16位完成清零前就溢出
		 * 所以必须关闭SysTick,且赋值完需要再使能使得递归回原函数的while中计数器会继续递减
		 */
		SysTick->CTRL &= ~(1 << 0);//关闭SysTick,关闭后记数器将不再倒数
		SysTick->LOAD = last_systick_val;
		SysTick->VAL = 0x00;//清除计时器的值
		SysTick->CTRL |= (1 << 0);//SysTick使能,使能后定时器开始倒数
	}
}

为何用非阻塞式延时:

1.非阻塞式延时可以在等待的时间进行其他函数处理,可节省单片机效率

2.在中断中使用延时函数(如,按键的消抖),在中断中使用阻塞式延时,可能导致处理中断函数的时间大于中断处理时间,即要跳出中断时,还未处理完执行函数,会导致程序卡停在延时函数的计时处。故在中断函数中最好不要使用延时函数。

非阻塞式延时:

void SysTick_Handler(void)    //滴答定时器中断
{
	delay_decrement();
	time_ms ++;
	time_ms %=1000;
}



uint8_t Time_ms(uint8_t ms)
{
	uint8_t turn = 0;
	if(time_ms == ms)
	{
		time_ms = 0;
		turn = ms;
	}
	return turn;
}

//调用
void time_ues()
{
    if(Time_ms(1) == 1)        //delay_ms(1);
    {
        ;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值