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:0 ,其中无名位域定义为0个位,就是说此处占一个字节位置。
参考文档:
1、C语言中结构体的位域(bit-fields )