STM32单片机关于如何非阻塞的实现长时间延时的一些思考

因为我是新手,今天写STM32单片机主逻辑的时候我遇到了一个问题:在while (1)死循环中要实现功能就是播放完一首音乐后延时1s时间然后再播放另外一首音乐,在延时1s过程中我的呼吸灯能够正常呼吸,不存在明显阻塞?

方法1:

while (1)
{
    for (int i = 0; i<3; i++)
    {
        delay_ms(1000);                        /*delay_ms()函数是内部调用systick相关寄存器实现的*/
    }

    current_state = STATE_IDLE;    /*要做的工作*/

    led_breath();
}

这种写法存在明显卡顿,因为在delay_ms()中是使用阻塞查询方式实现延时的。

我思考,人眼感觉卡顿是因为单次延时的时间太长了,我的做法是单次延时10ms,用一个变量记录死循环循环次数,然后我在主循环中去判断当这个变量达到100次的时候,我再作其他事情。

改进1:

u32 time_count = 0;   /*定义临时变量记录循环次数*/

while (1)
{
    delay_ms(10);
    time_count++;      /*寄存循环次数*/
    if (time_count >= 100)  //100*10ms = 2s

    {

        time_count = 0;
        current_state = STATE_IDLE;    /*要做的工作*/
    }
    led_breath();                        /*呼吸灯处理*/
}

我这种写法就更加优秀了:利用了“标志变量+死循环+条件判断”的方式,大部分情况led_breath()都会得到运行。

但是,改进1还是有一个缺陷就是delay_ms(10),还是会发生阻塞,我就想有没有非阻塞的方法呢?我第一时间想到的是利用一个定时器TIM2中断的方式实现,定义一个全局变量tim2_isr_count,使其在中断服务函数中不断+1,这样这个数值就代表了流过的时间(1ms为单位)。我再定义一个函数:tim2_delay_nms()实现短时间延时。

void tim2_delay_ms(u32 count)
{
	u32 start_count = tim2_isr_count; // 记录当前中断计数值
	while ((tim2_isr_count - start_count) < count)
	{
		// 等待tim2_isr_count增加到目标值
	}
}

但是,发现上述函数中还是存在一个while的查询阻塞代码段。如果参数count的值太大也会阻塞。那我该怎么办呢?后来我一个同事提醒我了说“你可以考虑继续进一步采用改进1的办法,也就是采用标志变量+条件判断+大循环的方式”,于是就有了一下代码:

static u32 time_count = 0;
static u32 tim2_count = 0; 	/**多次循环需要保持不变所以使用静态局部变量 */
static u32 code_excuted = 0; 	/**多次循环需要保持不变,只有延时时间到了才会写0 */

while (1)
{
	/**使用定时器2中断方式 */
	if (code_excuted == false) 					/**第一次才会更新tim2_count的值 */
	{
		tim2_count = tim2_isr_count;
		code_excuted = true;
	}
	
	if (tim2_isr_count - tim2_count >= 10)      /**10次循环满足了10ms达到了 */
	{
		code_excuted = false;       			/**下次需要更新tim2_count */
		time_count++;
		if (time_count >= 300)  //300*10ms = 3s
		{
			time_count = 0;
			current_state = STATE_IDLE;
		}
	}
	led_breath();
}

我想这种方法的有点就是尽可能少的减少了延时函数的阻塞,led_breath()函数不断得到循环运行。但是我也考虑到这样写有几个弊端:1、就是静态局部变量变得越来越多;而就是很难封装成一个可可执行函数(可能也可以实现,明天试一下哈)。

最后,第一次写博客,希望对大家有所帮助,若大家有更好的办法可以在评论中说明一下(本人暂时不考虑移植RTOS的方法实现,还是希望在轮询+中断的架构方法实现)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值