因为我是新手,今天写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的方法实现,还是希望在轮询+中断的架构方法实现)
1784

被折叠的 条评论
为什么被折叠?



