分享几种管理C程序中标志位的方法

发布时间:2023-02-02  

嵌入式开发中,难免会涉及到非常多的标志位处理,特别是玩单片机、裸机开发的朋友,比如跟一些模块配合联调会遇到各种信号是否到位、成功等等状态,而这些信号大多都是bool类型,1个bit即可进行标识。


当然,如果仅仅是几个标志,直接拿个uint8_t的整形来进行标识也不会影响什么,但如果特别多的话似乎就比较废RAM了。然而,为了更好的管理这些标志位等,有个如下几种方式供大家更好的管理这些标志位 :


1


位域直接标识


采用位域是管理这些标志位比较直接且方便的方式,代码如下所示:


 1typedef union _tag_SystemFlag

 2{

 3    uint16_t all;

 4    struct 

 5    {

 6        uint16_t Run         :1;

 7        uint16_t Alarm       :1;

 8        uint16_t Online      :1;

 9        uint16_t TimerOver   :1;

10        uint16_t Reserver    :12;

11    }bit;

12

13} uSystemFlag;

14

15uSystemFlag  unSystemFlag;

16

17int main(int argc, char *argv[]) {

18

19    unSystemFlag.all = 0x00; //系统标志清除

20

21    unSystemFlag.bit.Run       = 1; //置位

22    unSystemFlag.bit.Alarm     = 1;

23    unSystemFlag.bit.Online    = 1;

24    unSystemFlag.bit.TimerOver = 1;

25

26    unSystemFlag.bit.Run       = 0; //清零

27    unSystemFlag.bit.Alarm     = 0;

28    unSystemFlag.bit.Online    = 0;

29    unSystemFlag.bit.TimerOver = 0;

30

31    return 0;

32}

这些标志位的操作无非就是置位、清零,以及读取三种方式。


但如代码中这样的操作方式在语句或语义表达上还是不够直观。


我经常谈到,代码可以不写注释,不过你的每个变量、函数名称等需要足够的直观,所以很多朋友习惯把这些标志封装起来。


2


枚举+移位


为了更好的表达一般会对标志位进行进一步的封装,如下代码所示:


 1typedef enum _tag_Flag {

 2cEmRun = 0,

 3cEmAlarm,

 4cEmOnline,

 5cEmTimerOver

 6}emSystemFlag;

 7

 8uint16_t SystemFlag ;

 9//置位

10void SetFlag(emSystemFlag flag)

11{

12    SystemFlag |=  ((uint16_t)0x01) << flag;

13}

14//清除

15void ClrFlag(emSystemFlag flag)

16{

17    SystemFlag &=  ~(((uint16_t)0x01) << flag);

18}

19//获得状态

20uint8_t  GetFlag(emSystemFlag flag)

21{

22    return (((SystemFlag & (((uint16_t)0x01) << flag)) != 0)? true:false);  

23}

24

25int main(int argc, char *argv[]) {

26

27    SetFlag(cEmAlarm);

28

29    if(GetFlag(cEmAlarm) == true)

30    {

31        printf("ClrFlagrn");

32        ClrFlag(cEmAlarm);

33    }

34    else

35    {

36        printf("SetFlagrn");

37        SetFlag(cEmAlarm);

38    }

39    return 0;

40}

当然,封装成函数是相对比较耗时的,不过代码也会更加的易懂,如果确实容忍不了函数封装带来的时间消耗,把函数修改为宏代码片段或者内敛函数(前提是编译器支持)也是可行的。


3


宏列表


或许这里才是本文的重中之重~


以前跟大家介绍过,用宏自动化的生成各种代码片段,以使得代码更加的紧凑。当然可读性会相对降低一点,但对于重复性代码就不需要太多考虑了。


 1#include

 2#include

 3

 4typedef unsigned char uint8_t;

 5typedef unsigned int uint16_t;

 6typedef signed char int8_t;

 7typedef int  int16_t;

 8

 9#define true  1

10#define false 0

11

12

13//宏列表

14#define TAG_LIST(tag)

15tag(Run)

16tag(Alarm)

17tag(Online)

18tag(TimerOver)

19

20

21//枚举处理

22#define DEFINE_TAG(_tag) _tag,

23enum Flag {

24None = 0,

25TAG_LIST(DEFINE_TAG)

26EmMAX

27};

28#undef DEFINE_TAG

29

30//位定义变量

31uint16_t SysFlag = 0x0000;

32

33

34//通用方法定义

35uint8_t GetFlags(uint16_t mask)

36{

37    return ((SysFlag & mask) != 0)? true:false;

38}

39

40void SetFlags(uint16_t mask)

41{

42     SysFlag |=  mask;

43}

44

45void ClrFlags(uint16_t mask)

46{

47     SysFlag &=  ~mask;

48}

49

50

51//自动生成三类函数定义

52#define FLAG_Operater(flag)

53uint8_t  get##flag()  {

54return GetFlags(1 << flag);

55}

56void set##flag() {

57SetFlags(1 << flag);

58}

59void clr##flag() {

60ClrFlags(1 << flag);

61}

62

63//反向函数关联

64TAG_LIST(FLAG_Operater)

65

66int main(int argc, char *argv[]) {

67

68    setRun();

69    setAlarm();

70

71    if(getAlarm() == true)

72    {

73        printf("set rn");

74    }

75    else

76    {

77        printf("clr rn");

78    }

79

80    return 0;

81}

如果以前有过类似代码处理的朋友,应该看这段代码还是比较轻松的吧,如果有点生疏,可以一层一层展开了解。


其主要的功能是,通过宏替换和代码拼接符号,自动的生成通用的代码片段。这样做的好处是,不再需要我们在代码中定义一大堆setflag、clrflag、getflag等函数。


通过上面的代码当我们向TAGLIST宏中添加一个标识符,即可生成一系列相关的操作函数等。


这样一方面可以及简化代码,同时也能避免一些人工编码带来的错误。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    万用表上的符号怎么看?万用表上的字母代表什么?;aca(交流电流) dca(直流电流) dcv是直流电压 acv是交流电压 上面的标志是测电路是否导通 hz是频率 插线com是公共端,另一......
    开车时,不小心碰到一个按钮,一开始他没发现有什么问题。但不久后,他注意到仪表盘上有一个像小指针一样的标识亮了。“我不知道那个标识代表什么,但为了安全起见,我还是选择了靠边停车。” 随后......
    功能在现在很多家用汽车中都有应用,主要采用毫米波雷达或者摄像头来检测安全风险。 V2I,这里的I就是 Infrastructure,是指车与道路基础设施的通信,比如说路上的信号灯,摄像头等检测设备,以及车道标志等交通标志......
    操控寄存器的顺序后写代码 使能GPIOB代码最直接,直接把相关寄存器的地址强制类型转换为指针变量再调用,后面赋的值要看相应寄存器的具体位代表什么涵义。 后面的代码则使用了宏定义,让最后的命名和手册相关,让人......
    FX3U系列PLC型号代表什么意思;我们必须先理解PLC铭牌上的型号代表什么意思,并了解其功能。选型时才能正确选择需要的PLC。其中FX1系列和FX2系列的PLC已经停产多年,因此......
    电磁阀上的字母ABRPS代表什么意思;电磁阀(Solenoid valve)是用电磁控制的工业设备,是用来控制流体的自动化基础元件,属于执行器,并不限于液压、气动。用在......
    的最低的责任之一是交叉检查ADAS组件,以确定它们是否可以按预期协同工作。 乔治梅森大学工程学教授Missy Cummings说:“我对此事和相关事件的担忧是,为什么没有对这条道路上的已知限速进行交叉检 查……”数字......
    单相电表实物彩图接线方法 8、铜线用线计算公式 9、指示灯颜色代表什么含义-黄绿红白蓝 10、费控......
    一图看懂什么是纳米制程; 来源:内容来自科技新报 ,谢谢。 常听到财经新闻在讨论台积电或三星的半导体技术正进展到几纳米,各位读者是否真的知道这代表什么意思呢?所谓......
    近施工路段时,在驾驶员视野前方15米处显示1.5米高的“在建”标志,还能提示限速。这是一项专门用于通过提高驾驶员在夜间的能见度来防止事故发生的技术。驾驶员可以很容易地识别出什么时候出现颠簸,以及进出高速公路的道路......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>