一、介绍
在嵌入式开发过程中,我们经常会使用标志位实现部分代码的单次执行。如下:
cpp
uint8_t Flag = 0;//标志位
while(1)
{
if(Flag == 0)
{
LED_ON();//LED点亮
Flag == 1;
}
}
这样,我们就实现了只运行一次LED_ON函数,也就是单次执行。
如果复杂一点的程序想实现单次执行,用标志位的话就会让程序就会变得非常不美观,可读性也变得更差了,非常的不优雅。
那如果我使用宏定义函数实现单次执行
cpp
while(1)
{
RunOnce(block1,//单次执行,只运行一次
{
LED_ON();
//可添加其他代码
});
}
又或者是printf实现单次执行
cpp
int main(void)
{
RunOnce(block1, {printf("代码块1执行了一次!\n");});// 首次执行代码块
RunOnce(block1, {printf("代码块1执行了一次!\n");});// 已执行过,不执行
ResetOnce(block1); // 重置block1的状态
RunOnce(block1, {printf("代码块1执行了一次!\n");}); // 重置后可再次执行
return 0;
}
怎么样,用了宏定义函数之后,实现程序的单次执行是不是变得更加的优雅了?
话不多说,直接看例程
二、例程
我OnceRun_Port.h这个头文件用来装宏定义函数。引用这个头文件之后,就可以直接使用,有非常强的复用性。
OnceRun_Port.h
cpp
#ifndef __OnceRun_Port_h_
#define __OnceRun_Port_h_
#include <stdio.h>
// 宏定义:为代码块生成单次执行功能,需指定唯一标识名name
// block为待执行的代码块(可包含多条语句,用{}括起)
#define RunOnce(name, block) do \
{ \
static int name##_executed = 0; \
if (!name##_executed) \
{ \
block; \
name##_executed = 1; \
} \
} while(0)
// 宏定义:重置指定标识名的代码块执行状态
#define ResetOnce(name) do \
{ \
static int name##_executed; \
name##_executed = 0; \
} while(0)
#endif
使用方法
cpp
int main(void)
{
// 测试代码块1:单次执行
printf("代码块1第1次:");
RunOnce(block1,
{
printf("代码块1执行了一次!\n");
// 可添加更多语句,例如:
// printf("代码块1的第二行语句\n");
}
); // 首次执行代码块
printf("代码块1第2次:");
RunOnce(block1,
{
printf("代码块1执行了一次!\n");
}
); // 已执行过,不执行
// 测试代码块2:独立于代码块1
printf("\n代码块2第1次:");
RunOnce(block2,
{ // 标识名block2,独立状态
printf("代码块2执行了一次!\n");
}
); // 首次执行
printf("代码块2第2次:");
RunOnce(block2,
{
printf("代码块2执行了一次!\n");
}
); // 已执行过,不执行
// 重置代码块1后再次执行
printf("\n重置代码块1后:");
ResetOnce(block1); // 重置block1的状态
RunOnce(block1,
{
printf("代码块1执行了一次!\n");
}
); // 重置后可再次执行
return 0;
}
三、注意事项

当你调用ResetOnce函数后,可能会出现警告,显示"block1_executed"从未使用过。这个警告可以无需理会,我调用之后ResetOnce仍然能重置代码块,不影响使用。