我正在尝试设计一个数据结构(我已经把它缩短了很多,以节省空间,但我认为你得到了这个想法)用于字节级通信:
/* PACKET.H */
#define CM_HEADER_SIZE 3
#define CM_DATA_SIZE 16
#define CM_FOOTER_SIZE 3
#define CM_PACKET_SIZE (CM_HEADER_SIZE + CM_DATA_SIZE + CM_FOOTER_SIZE)
// + some other definitions
typedef struct cm_header{
uint8_t PacketStart; //Start Indicator 0x5B [
uint8_t DeviceId; //ID Of the device which is sending
uint8_t PacketType;
} CM_Header;
typedef struct cm_footer {
uint16_t DataCrc; //CRC of the 'Data' part of CM_Packet
uint8_t PacketEnd; //should be 0X5D or ]
} CM_Footer;
//Here I am trying to conver a few u8[4] tp u32 (4*u32 = 16 byte, hence data size)
typedef struct cm_data {
union {
struct{
uint8_t Value_0_0:2;
uint8_t Value_0_1:2;
uint8_t Value_0_2:2;
uint8_t Value_0_3:2;
};
uint32_t Value_0;
};
//same thing for Value_1, 2 and 3
} CM_Data;
typedef struct cm_packet {
CM_Header Header;
CM_Data Data;
CM_Footer Footer;
} CM_Packet;
typedef struct cm_inittypedef{
uint8_t DeviceId;
CM_Packet Packet;
} CM_InitTypeDef;
typedef struct cm_appendresult{
uint8_t Result;
uint8_t Reason;
} CM_AppendResult;
extern CM_InitTypeDef cmHandler;
这里的目标是建立可靠的结构,通过USB接口传输数据。最后,CM_Packet
应转换为uint8_t
数组,并提供给mcu(stm32)的数据发送寄存器。
在main.c
文件中,我尝试初始化结构以及与此数据包相关的其他一些内容:
/* MAIN.C */
uint8_t packet[CM_PACKET_SIZE];
int main(void) {
//use the extern defined in packet.h to init the struct
cmHandler.DeviceId = 0x01; //assign device id
CM_Init(&cmHandler); //construct the handler
//rest of stuff
while(1) {
CM_GetPacket(&cmHandler, (uint8_t*)packet);
CDC_Transmit_FS(&packet, CM_PACKET_SIZE);
}
}
这里是packet.h
的实现,它搞砸了一切都很糟糕。我添加了packet[CM_PACKET_SIZE]
来观看,但它就像是随机生成的。有时通过纯粹的运气我可以在这个数组中看到一些我感兴趣的值!但它有点像1%的时间!
/* PACKET.C */
CM_InitTypeDef cmHandler;
void CM_Init(CM_InitTypeDef *cm_initer) {
cmHandler.DeviceId = cm_initer->DeviceId;
static CM_Packet cmPacket;
cmPacket.Header.DeviceId = cm_initer->DeviceId;
cmPacket.Header.PacketStart = CM_START;
cmPacket.Footer.PacketEnd = CM_END;
cm_initer->Packet = cmPacket;
}
CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier,
uint8_t *data){
CM_AppendResult result;
switch(identifier){
case CM_VALUE_0:
handler->Packet.Data.Value_0_0 = data[0];
handler->Packet.Data.Value_0_1 = data[1];
handler->Packet.Data.Value_0_2 = data[2];
handler->Packet.Data.Value_0_3 = data[3];
break;
//Also cases for CM_VALUE_0, 1 , 2
//to build up the CM_Data sturct of CM_Packet
default:
result.Result = CM_APPEND_FAILURE;
result.Reason = CM_APPEND_CASE_ERROR;
return result;
break;
}
result.Result = CM_APPEND_SUCCESS;
result.Reason = 0x00;
return result;
}
void CM_GetPacket(CM_InitTypeDef *handler, uint8_t *packet){
//copy the whole struct in the given buffer and later send it to USB host
memcpy(packet, &handler->Packet, sizeof(CM_PACKET_SIZE));
}
所以,问题是这段代码给了我99%的随机时间。它永远不会有CM_START
这是我想要的值的数据包的开始指示符。但大多数时候它正确地有CM_END
个字节!我真的很困惑,无法找出原因。正在开发一个难以调试的嵌入式平台,我在这里迷失了......
答案 0 :(得分:1)
如果您将数据传输到另一个(不同的)体系结构,请不要只将结构作为blob传递。这是地狱的方式:endianess,alignment,padding bytes等等都可能(并且可能会)造成麻烦。
更好地以一致的方式序列化结构,可能使用一些解释的控制流,因此您不必手动编写每个字段。 (但仍然使用标准函数来生成该流)。
某些潜在或可能出现问题的区域:
CM_Footer
:第二个字段可能很好地从32或64位边界开始,因此前面的字段将跟随填充。此外,该结构的结尾很可能在32位体系结构上至少填充1个字节,以便在数组中使用时允许正确对齐(如果您确实需要,编译器不关心您)。甚至可能是8字节对齐。CM_Header
:在这里你可能(不保证)得到一个带有4 * 2位的uint8_t,其顺序未标准化。字段后面跟着3个未使用的字节,这是uint32_t对union的解释所必需的。