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

最新更新时间:2023-02-02来源: zhihu关键字:标志位  位域 手机看文章 扫描二维码
随时随地手机看文章

在嵌入式开发中,难免会涉及到非常多的标志位处理,特别是玩单片机、裸机开发的朋友,比如跟一些模块配合联调会遇到各种信号是否到位、成功等等状态,而这些信号大多都是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宏中添加一个标识符,即可生成一系列相关的操作函数等。


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


关键字:标志位  位域 编辑:什么鱼 引用地址:分享几种管理C程序中标志位的方法

上一篇:动图演示UART、SPI、 I2C等串行通信的底层原理
下一篇:电流检测电路

推荐阅读

分享几种管理C程序标志的方法
在嵌入式开发中,难免会涉及到非常多的标志位处理,特别是玩单片机、裸机开发的朋友,比如跟一些模块配合联调会遇到各种信号是否到位、成功等等状态,而这些信号大多都是bool类型,1个bit即可进行标识。当然,如果仅仅是几个标志,直接拿个uint8_t的整形来进行标识也不会影响什么,但如果特别多的话似乎就比较废RAM了。然而,为了更好的管理这些标志位等,有个如下几种方式供大家更好的管理这些标志位 :1位域直接标识采用位域是管理这些标志位比较直接且方便的方式,代码如下所示:1typedef union _tag_SystemFlag2{3 uint16_t all;4 struct5 {6 uint16_t Run :1;7
发表于 2023-02-02
汇编语言 标志
加法和进位标志位两个无符号整数相加时,进位标志位是目的操作数最高有效位进位的副本。如果和数超过了目的操作数的存储大小,就可以认为CF=1。mov al, 0FFHadd al , 1 ; AL = 00 , CF = 1在上面的加法运算中,AL最高有效位的进位复制到进位标志位。如果AX的值为00FFH,则对其进位加1操作后,和数不会超过16位,那么进位标志位清0.mov ax, 00FFHadd ax, 1 ; AX = 0100H, CF = 0但是,如果AX的值为FFFFH,则对其进行加1操作后,AX的高位就会产生进位mov ax, 0FFFFHadd ax, 1 ; AX = 0000,
发表于 2022-10-19
汇编语言 <font color='red'>标志</font><font color='red'>位</font>
B001-Atmega16-的汇编实现
-------------------------------------------------------------------------------------------------------------------------------------开发环境:AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86芯片型号:ATmega16芯片主频:8MHz--------------------------------------------------------------------------------------------
发表于 2022-01-12
stm32专题十六:IIC(二)stm32 IIC通讯过程 标志
1 IIC进入主模式的步骤:在主模式时,I 2 C接口启动数据传输并产生时钟信号。串行数据传输总是以起始条件开始并以停止条件结束。当通过START位在总线上产生了起始条件,设备就进入了主模式。以下是主模式所要求的操作顺序:● 在I2C_CR2寄存器中设定该模块的输入时钟以产生正确的时序● 配置时钟控制寄存器● 配置上升时间寄存器● 编程I2C_CR1寄存器启动外设● 置I2C_CR1寄存器中的START位为1,产生起始条件2 作为主机发送器时的传送时序图主发送器发送流程及事件说明如下:(1) 控制产生起始信号(S),当发生起始信号后,它产生事件“EV5”,并会对 SR1 寄存器的“SB”位置 1,表示起始信号已经发送;EV5事件:(
发表于 2021-10-22
stm32专题十六:IIC(二)stm32 IIC通讯过程 <font color='red'>标志</font><font color='red'>位</font>
STM32 与联合体结合优化操作
1、位域详细介绍参考文章:位域位域可以实现在信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。2、联合体在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作
发表于 2021-02-07
IAR环境定义变量标志 STM8 MSP430通用
首先建立一个公共点H文件,加入通用代码如下typedef union{ struct { unsigned char b0:1; unsigned char b1:1; unsigned char b2:1; unsigned char b3:1; unsigned char b4:1; unsigned char b5:1; unsigned char b6:1; unsigned char b7:1; } bits;} UINT8_VAL;通用定义联合体写好以后,要定义一个只占用个Byte的标志位的话,只要定义一下uchar型字节,然后引用它的其中某一位就可以了。比如在C文件
发表于 2020-09-18
小广播
设计资源 培训 开发板 精华推荐

何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2023 EEWORLD.com.cn, Inc. All rights reserved