C 将两个未签名字符强制合并
在我的微控制器中,我从UART接收两个C 将两个未签名字符强制合并,c,struct,bit-manipulation,bitwise-operators,unions,C,Struct,Bit Manipulation,Bitwise Operators,Unions,在我的微控制器中,我从UART接收两个uint8\t。我需要对它进行解析,以便以后可以轻松地引用它的内容。传入的数据如下所示: 10 | 9 8 | 7 6 | 5 4 | 3 2 1 0 TRETRY | DEAD_TMIE | OCP_MODE | OCP_DEG | VDS_LVL DRV_OverCurrentProtection ocp;
uint8\t
。我需要对它进行解析,以便以后可以轻松地引用它的内容。传入的数据如下所示:
10 | 9 8 | 7 6 | 5 4 | 3 2 1 0
TRETRY | DEAD_TMIE | OCP_MODE | OCP_DEG | VDS_LVL
DRV_OverCurrentProtection ocp;
ocp.data = buff[0] << 8 | buff[1];
由于我是一个笨蛋,无法工作,我尝试了工会的把戏……但它并没有像预期的那样工作。这是我的工会:
typedef union {
struct {
uint8_t dont_care :5; //b15-b11 these bits should be discarded
uint8_t retry_time :1; //b10
uint8_t dead_time :2; //b9-b8
uint8_t ocp_mode :2; //b7-b6
uint8_t degl_time :2; //b5-b4
uint8_t vds_lvl :4; //b3-b0
} bits;
uint16_t data;
uint8_t bytes[2];
} DRV_OverCurrentProtection;
我收到的正是0000000 101011001
我试着这样填补工会的空缺:
10 | 9 8 | 7 6 | 5 4 | 3 2 1 0
TRETRY | DEAD_TMIE | OCP_MODE | OCP_DEG | VDS_LVL
DRV_OverCurrentProtection ocp;
ocp.data = buff[0] << 8 | buff[1];
我觉得没有希望了,我想对于工会,我什么都不去……你能告诉我我的代码和实现中出了什么问题吗?更好的是,做这样的事情最好的方法是什么?这对新手来说是一个很大的帮助。您的结构正在将位字段从低到高打包。只需颠倒顺序:
struct {
uint8_t vds_lvl :4; //b3-b0
uint8_t degl_time :2; //b5-b4
uint8_t ocp_mode :2; //b7-b6
uint8_t dead_time :2; //b9-b8
uint8_t retry_time :1; //b10
uint8_t dont_care :5; //b15-b11 these bits should be discarded
} bits;
这应该会产生您正在寻找的关联。听起来您正好接收到两个字节,所以您可以将它们复制到ocp.DATA。您希望8位的左移位为8位值带来什么?我会跳过“联合技巧”,只使用常规的旧位掩蔽和移位。位字段和联合的工作方式的定义允许编译器在实现上具有一定的灵活性,这可能与您的期望不符。可能重复的建议您收听@jdigital,除非这是一个爱好项目,不需要使用一个编译器的多个版本。了解位屏蔽是一件好事,因为它通常为位字段生成比编译器生成的代码更紧凑的代码。假设您想检查
degl_time
是否为3if((x_as_short&0x300)==0x300){…}
生成的代码比if(x_as_union.bits.degl_time==3)生成的代码要少,对于我检查过的所有编译器来说,这是相当多的。如果OP的目标就是让代码正常工作,那么这个答案就足够了。如果OP对不依赖于编译器特定行为的代码感兴趣,那么请参阅@jdigital Yes的答案,我同意这一点。这只是解释了OP所看到的行为,以及什么样的变化会使它在那个环境中工作。感谢这一点,现在解决了这个问题…但我真的需要学习如何使用掩蔽和stuff@DEKKER使用变换和遮罩是相当容易的。要提取字段,只需将包含的字右移,然后屏蔽适当数量的低阶位。要设置字段,首先清除字中的位,然后将值左移,并按位或将其放入字中。如果您需要更多详细信息,请告诉我。@TomKarzes谢谢……我不得不做另一个按位操作,但我也失败了……我在这里发布了一个问题,如果您能看一下,我会很高兴的