C語言Bit定義注意點:
首先看一個C位域使用的官方例子(摘自MC9S12XS128.h):
/*** ATD0CTL23 - ATD 0 Control Register 23; 0x000002C2 ***/ typedef union { word Word; /* Overlapped registers: */ struct { /*** ATD0CTL2 - ATD 0 Control Register 2; 0x000002C2 ***/ union { byte Byte; struct { byte ACMPIE :1; /* ATD Compare Interrupt Enable */ byte ASCIE :1; /* ATD Sequence Complete Interrupt Enable */ byte ETRIGE :1; /* External Trigger Mode enable */ byte ETRIGP :1; /* External Trigger Polarity */ byte ETRIGLE :1; /* External Trigger Level/Edge control */ byte ICLKSTP :1; /* Internal Clock in Stop Mode Bit */ byte AFFC :1; /* ATD Fast Conversion Complete Flag Clear */ byte :1; } Bits; } ATD0CTL2STR; #define ATD0CTL2 _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Byte #define ATD0CTL2_ACMPIE _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.ACMPIE #define ATD0CTL2_ASCIE _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.ASCIE #define ATD0CTL2_ETRIGE _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.ETRIGE #define ATD0CTL2_ETRIGP _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.ETRIGP #define ATD0CTL2_ETRIGLE _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.ETRIGLE #define ATD0CTL2_ICLKSTP _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.ICLKSTP #define ATD0CTL2_AFFC _ATD0CTL23.Overlap_STR.ATD0CTL2STR.Bits.AFFC #define ATD0CTL2_ACMPIE_MASK 1U #define ATD0CTL2_ASCIE_MASK 2U #define ATD0CTL2_ETRIGE_MASK 4U #define ATD0CTL2_ETRIGP_MASK 8U #define ATD0CTL2_ETRIGLE_MASK 16U #define ATD0CTL2_ICLKSTP_MASK 32U #define ATD0CTL2_AFFC_MASK 64U /*** ATD0CTL3 - ATD 0 Control Register 3; 0x000002C3 ***/ union { byte Byte; struct { byte FRZ0 :1; /* Background Debug Freeze Enable Bit 0 */ byte FRZ1 :1; /* Background Debug Freeze Enable Bit 1 */ byte FIFO :1; /* Result Register FIFO Mode */ byte S1C :1; /* Conversion Sequence Length 1 */ byte S2C :1; /* Conversion Sequence Length 2 */ byte S4C :1; /* Conversion Sequence Length 4 */ byte S8C :1; /* Conversion Sequence Length 8 */ byte DJM :1; /* Result Register Data Justification */ } Bits; struct { byte grpFRZ :2; byte :1; byte :1; byte :1; byte :1; byte :1; byte :1; } MergedBits; } ATD0CTL3STR; #define ATD0CTL3 _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Byte #define ATD0CTL3_FRZ0 _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.FRZ0 #define ATD0CTL3_FRZ1 _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.FRZ1 #define ATD0CTL3_FIFO _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.FIFO #define ATD0CTL3_S1C _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.S1C #define ATD0CTL3_S2C _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.S2C #define ATD0CTL3_S4C _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.S4C #define ATD0CTL3_S8C _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.S8C #define ATD0CTL3_DJM _ATD0CTL23.Overlap_STR.ATD0CTL3STR.Bits.DJM #define ATD0CTL3_FRZ _ATD0CTL23.Overlap_STR.ATD0CTL3STR.MergedBits.grpFRZ #define ATD0CTL3_FRZ0_MASK 1U #define ATD0CTL3_FRZ1_MASK 2U #define ATD0CTL3_FIFO_MASK 4U #define ATD0CTL3_S1C_MASK 8U #define ATD0CTL3_S2C_MASK 16U #define ATD0CTL3_S4C_MASK 32U #define ATD0CTL3_S8C_MASK 64U #define ATD0CTL3_DJM_MASK 128U #define ATD0CTL3_FRZ_MASK 3U #define ATD0CTL3_FRZ_BITNUM 0U } Overlap_STR;
struct { word FRZ0 :1; /* Background Debug Freeze Enable Bit 0 */ word FRZ1 :1; /* Background Debug Freeze Enable Bit 1 */ word FIFO :1; /* Result Register FIFO Mode */ word S1C :1; /* Conversion Sequence Length 1 */ word S2C :1; /* Conversion Sequence Length 2 */ word S4C :1; /* Conversion Sequence Length 4 */ word S8C :1; /* Conversion Sequence Length 8 */ word DJM :1; /* Result Register Data Justification */ word ACMPIE :1; /* ATD Compare Interrupt Enable */ word ASCIE :1; /* ATD Sequence Complete Interrupt Enable */ word ETRIGE :1; /* External Trigger Mode enable */ word ETRIGP :1; /* External Trigger Polarity */ word ETRIGLE :1; /* External Trigger Level/Edge control */ word ICLKSTP :1; /* Internal Clock in Stop Mode Bit */ word AFFC :1; /* ATD Fast Conversion Complete Flag Clear */ word :1; } Bits; struct { word grpFRZ :2; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; word :1; } MergedBits; } ATD0CTL23STR; extern volatile ATD0CTL23STR _ATD0CTL23 @(REG_BASE + 0x000002C2UL); #define ATD0CTL23 _ATD0CTL23.Word #define ATD0CTL23_FRZ0 _ATD0CTL23.Bits.FRZ0 #define ATD0CTL23_FRZ1 _ATD0CTL23.Bits.FRZ1 #define ATD0CTL23_FIFO _ATD0CTL23.Bits.FIFO #define ATD0CTL23_S1C _ATD0CTL23.Bits.S1C #define ATD0CTL23_S2C _ATD0CTL23.Bits.S2C #define ATD0CTL23_S4C _ATD0CTL23.Bits.S4C #define ATD0CTL23_S8C _ATD0CTL23.Bits.S8C #define ATD0CTL23_DJM _ATD0CTL23.Bits.DJM #define ATD0CTL23_ACMPIE _ATD0CTL23.Bits.ACMPIE #define ATD0CTL23_ASCIE _ATD0CTL23.Bits.ASCIE #define ATD0CTL23_ETRIGE _ATD0CTL23.Bits.ETRIGE #define ATD0CTL23_ETRIGP _ATD0CTL23.Bits.ETRIGP #define ATD0CTL23_ETRIGLE _ATD0CTL23.Bits.ETRIGLE #define ATD0CTL23_ICLKSTP _ATD0CTL23.Bits.ICLKSTP #define ATD0CTL23_AFFC _ATD0CTL23.Bits.AFFC #define ATD0CTL23_FRZ _ATD0CTL23.MergedBits.grpFRZ
#define ATD0CTL23_FRZ0_MASK 1U #define ATD0CTL23_FRZ1_MASK 2U #define ATD0CTL23_FIFO_MASK 4U #define ATD0CTL23_S1C_MASK 8U #define ATD0CTL23_S2C_MASK 16U #define ATD0CTL23_S4C_MASK 32U #define ATD0CTL23_S8C_MASK 64U #define ATD0CTL23_DJM_MASK 128U #define ATD0CTL23_ACMPIE_MASK 256U #define ATD0CTL23_ASCIE_MASK 512U #define ATD0CTL23_ETRIGE_MASK 1024U #define ATD0CTL23_ETRIGP_MASK 2048U #define ATD0CTL23_ETRIGLE_MASK 4096U #define ATD0CTL23_ICLKSTP_MASK 8192U #define ATD0CTL23_AFFC_MASK 16384U #define ATD0CTL23_FRZ_MASK 3U #define ATD0CTL23_FRZ_BITNUM 0U
1、位域的分配
位域定義時的位地址分配並不是我們想象的那樣依次按從上而下,從低位到高位的順序排列起來的。他在分配時根據當前占用的位域和下一個位域能否合並為一個字節,來
判斷是否將當前位域獨立為一個字節,如果不注意這一點,很有可能位域分配時會存在只有幾個位就占用了一個字節的情況。比如:
struct{ union{ struct{ unsigned char bit0:4; unsigned char bit1:1; unsigned char bit2:3; unsigned char bit4:4; unsinged char bit5:6; unsigned char bit6:6; }bitdata; unsigned char data[3]; }example_unn; }example_stt;
本來我們以為:4+1+3+4+6+6=24個bit占3個字節;
而實際上位域並沒有我們想象的那麼靈活:
struct{ union{ struct{ //byte1: 4+1+3=8(正好8位) unsigned char bit0:4; unsigned char bit1:1; unsigned char bit2:3; //byte2:因為4+6>8,bit4所以單獨占一個字節 unsigned char bit4:4; //byte3:同上bit5單獨占一個一節(6+6>8) unsinged char bit5:6; //byte4:最後bit6再單獨占一個字節 unsigned char bit6:6; }bitdata; unsigned char data[4];//所以一共占用了4個字節 }example_unn; }example_stt;
C語言位域定義並不是太好用,當我們根據實際使用情況需要將內存那麼分配時,位域將會失去他的便捷性,如上我們無法將bit4和bit5的低4位合並起來訪問,實際操作
我們還是要自己移位賦值,所以在制定協議時最好不要做跨字節的連續位定義。
2、位定位定義中的無名位域
無名位域可以用來填充使用,但無法訪問。
對於1中的情況,我們可以加入無名位域使其看起來更直觀的表示其位域地址分配的情況:
struct{ union{ struct{ //byte1: 4+1+3=8(正好8位) unsigned char bit0:4; unsigned char bit1:1; unsigned char bit2:3; //byte2:因為4+6>8,bit4所以單獨占一個字節 unsigned char bit4:4; unsigned char :4;//無名位域,占位用,這樣你一下就可以看出,bit4單獨占一個字節! //byte3:同上bit5單獨占一個一節(6+6>8) unsigned char bit5:6; unsigned char :2; //byte4:最後bit6再單獨占一個字節 unsigned char bit6:6; unsigned char :2; }bitdata; unsigned char data[4];//所以一共占用了4個字節 }example_unn; }example_stt;
還有一種特殊情況 unsigned char