我有下面的结构
typedef struct fpButtons {
/** BYTE 0 **/
uint8_t button_1:1;
uint8_t button_2:1;
uint8_t button_3:1;
uint8_t button_4:1;
uint8_t button_5:1;
uint8_t button_6:1;
uint8_t button_7:1;
uint8_t button_8:1;
/** And BYTE 2 which I didn't paste to save SO's space lol **/
// button_9:1 to button_16:1
} FP_BUTTONS;
这个函数给出一个无符号整数,其位应构建上面的结构
void FP_UpdateData(FP_BUTTONS *data, uint8_t b1, uint8_t b2)
{
data->button_1 = (b1 & ( 1 << 1 )) >> 1;
data->button_2 = (b1 & ( 1 << 2 )) >> 2;
data->button_3 = (b1 & ( 1 << 3 )) >> 3;
data->button_4 = (b1 & ( 1 << 4 )) >> 4;
data->button_5 = (b1 & ( 1 << 5 )) >> 5;
data->button_6 = (b1 & ( 1 << 6 )) >> 6;
data->button_7 = (b1 & ( 1 << 7 )) >> 7;
data->button_8 = (b1 & ( 1 << 8 )) >> 8;
//Do the same thing for button 9 to 16
}
现在存储后,我必须将其发送到其他地方:
void APP_Send(){
uint8_t packet[2];
packet[0] = *((uint8_t*) &FP_BUTTONS_Data);
packet[1] = *(((uint8_t*) &FP_BUTTONS_Data)+1);
//Send stuff away.....
}
尽管付出了很多努力,但上述代码似乎都不起作用。我在嵌入式处理器上这样做,它很难调试。我想知道一些C-Guru家伙是否可以告诉我这些代码有什么问题?
答案 0 :(得分:4)
比特是0索引的,但是您对转换进行了编码,就好像比特是1索引的一样。您必须使用0
到7
进行uint8_t
的转换。
此外,可以删除右移。
试试这个:
void FP_UpdateData(FP_BUTTONS *data, uint8_t b1, uint8_t b2)
{
data->button_1 = (b1 & ( 1 << 0 )) != 0;
data->button_2 = (b1 & ( 1 << 1 )) != 0;
data->button_3 = (b1 & ( 1 << 2 )) != 0;
data->button_4 = (b1 & ( 1 << 3 )) != 0;
data->button_5 = (b1 & ( 1 << 4 )) != 0;
data->button_6 = (b1 & ( 1 << 5 )) != 0;
data->button_7 = (b1 & ( 1 << 6 )) != 0;
data->button_8 = (b1 & ( 1 << 7 )) != 0;
//Do the same thing for button 9 to 16
}
void APP_Send()
{
uint8_t packet[2];
uint8_t *data = (uint8_t*) &FP_BUTTONS_Data;
packet[0] = data[0];
packet[1] = data[1];
//Send stuff away.....
}
话虽如此,如果你将结构数据包装在union
中,那么所有这些手动移动都是不必要的:
typedef struct fpButtons {
/** BYTE 0 **/
union {
struct {
uint8_t button_1:1;
uint8_t button_2:1;
uint8_t button_3:1;
uint8_t button_4:1;
uint8_t button_5:1;
uint8_t button_6:1;
uint8_t button_7:1;
uint8_t button_8:1;
};
uint8_t rawbuttons_1;
};
/** BYTE 1 **/
union {
struct {
uint8_t button_9:1;
uint8_t button_10:1;
uint8_t button_11:1;
uint8_t button_12:1;
uint8_t button_13:1;
uint8_t button_14:1;
uint8_t button_15:1;
uint8_t button_16:1;
};
uint8_t rawbuttons_2;
};
} FP_BUTTONS;
void FP_UpdateData(FP_BUTTONS *data, uint8_t b1, uint8_t b2)
{
data->rawbuttons_1 = b1;
data->rawbuttons_2 = b2;
}
void APP_Send()
{
uint8_t packet[2];
packet[0] = FP_BUTTONS_Data.rawbuttons_1;
packet[1] = FP_BUTTONS_Data.rawbuttons_2;
//Send stuff away.....
}
答案 1 :(得分:2)
如果您实际上将两个八位字节保存到自定义位打包结构中,只是将这两个八位字节拉回来将它们发送到其他位置,您可以考虑更改方法。
假设您的所有位字段都是1位宽(如示例中所示),您可以使用位移来访问值(编译器将为您执行此操作),例如:
/* Button shift values */
typedef enum
{
BUTTON_1 = 0,
BUTTON_2 = 1,
...
BUTTON_16 = 15,
} button_t;
void FP_UpdateData(uint16_t *buttons, uint8_t b1, uint8_t b2)
{
/* You could also just return the value rather than passing a pointer
* around like this. Even better, skip this function call and do the
* math. */
*buttons = (uint16_t)b1;
*buttons |= (uint16_t)(b2 << 8);
}
bool get_button_state(uint16_t *buttons, button_t button)
{
return *buttons & (1 << button);
}
void APP_Send()
{
uint8_t packet[2];
packet[0] = (uint8_t)(buttons & 0xff);
packet[1] = (uint8_t)((buttons >> 8) & 0xff);
}
如果您正在使用GCC,则可以执行以下操作来制作打包结构:
typedef struct __atrribute__((packed)) {
/** BYTE 0 **/
unsigned button_1:1;
unsigned button_2:1;
unsigned button_3:1;
unsigned button_4:1;
unsigned button_5:1;
unsigned button_6:1;
unsigned button_7:1;
/** And BYTE 2 which I didn't paste to save SO's space lol **/
// button_9:1 to button_16:1
} FP_BUTTONS;
答案 2 :(得分:2)
代码有一些缺陷:
void
)。(b1 & ( 1 << 1 )) >> 1
将计算为int
。对于签名类型,右移是实现定义的。虽然它可能有效,但肯定不是&#34;防御性编程&#34;; - )因此,在嵌入式系统上,通常只使用uint8_t
作为位图并避免使用位域结构。这是因为不能保证它们与外围寄存器的布局匹配,例如移动等等非常烦人,可能会很好地破坏你的时序(例如中断处理程序)。
此外,使用掩码可以很容易地同时操作多个位。
enum {
BIT0 = (1U<<0),
BIT1 = (1U<<1),
...
};
uint8_t buttons;
... in a function:
buttons |= BIT1 | BIT2; // set the corresponding bits
buttons &= ~(BIT5 | BIT7); // clear those bits
if ( buttons & BIT4 )
...
GPIOB->OUTR = BIT4 | BIT6; // set the output bits on STM32F port B
这是如何在嵌入式编程中实现的。请注意,STM32F具有16位GPIO端口,而不是8位。
哦,并获得一个0/1值的位:
int single_bit = !!(buttons & BIT3)
这将使用第一个否定创建一个布尔结果,标准为0或1。第二个否定将再次成为积极的逻辑。然而,这很少使用,上面if ...
中的那个是足够的时间。
然而,一个好的编译器(作为gcc)应该在Cortex-M上很好地优化它。
后者可以简单地分配给每个位字段。如果您很幸运,编译器会知道该模式并创建一个简单的赋值(或者至少只是一个带有两条指令的位域传输)。