嵌入式开发技巧:舍弃标志位,用宏定义函数实现程序单次运行

一、介绍

在嵌入式开发过程中,我们经常会使用标志位实现部分代码的单次执行。如下:

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仍然能重置代码块,不影响使用。

相关推荐
('-')11 分钟前
《从根上理解MySQL是怎样运行的》第十章学习笔记
笔记·学习·mysql
hd51cc13 分钟前
MFC学习笔记 对话框
笔记·学习·mfc
卡提西亚21 分钟前
数据库笔记-4-SQL语言之DCL
数据库·笔记·sql
Radan小哥30 分钟前
Docker学习笔记—day0010
笔记·学习·docker
im_AMBER34 分钟前
Canvas架构手记 05 鼠标事件监听 | 原生事件封装 | ctx 结构化对象
前端·笔记·学习·架构
老神在在00139 分钟前
Mybatis01
后端·学习·spring·java-ee·mybatis
Y***89081 小时前
Neo4j图数据库学习(二)——SpringBoot整合Neo4j
数据库·学习·neo4j
理人综艺好会1 小时前
MySQL学习之go-mysql
学习·mysql·golang
想要成为计算机高手1 小时前
π*0.6: 从实践中学习 -- 2025.11.17 -- Physical Intelligence (π) -- 未开源
人工智能·学习·机器人·多模态·具身智能·vla
偶像你挑的噻1 小时前
15-Linux驱动开发-PWM子系统
linux·驱动开发·stm32·嵌入式硬件