关于利用结构体和联合体数据收发的两种方法
关于最近接手的小项目,有了一些经验,所以进行一下记录。
文章目录
- 关于利用结构体和联合体数据收发的两种方法
- 前言
- 一、联合体法
- 二、结构体法
- 小tips
前言
在我们利用自己的板子进行数据的收发通信时,会遇到发来的数据不是我想要的数据或者我发出的数据和对方接收到的数据不是一个。这是因为在数据转移的过程中出现了对齐不正确或者大小端的纰漏,在这里我介绍自己项目开发中常用的两种方法。此处的通讯线路为CAN总线进行介绍。
一、联合体法
当我们进行CAN总线通讯时,收发的字节数为8个字节以内,而我们收发的过程中,这些字节数据是以数组的形式uint8_t arr[ ]进行保存的。这就帮助我们可以顺利的将数据进行打包和存储。接收CAN消息,利用固件库的CAN结构体可以将8字节数据引用出来。接下来介绍联合体获取数据和发送数据的方法。
typedef union
{
uint32_t u32_data[2];
uint16_t u16_data[4];
uint8_t u8_data[8];
}c_wttk;
c_wttk function;
如上为我们所定义的联合体类型和联合体变量。当我们从CAN中获取到8字节数组数据即
typedef struct {
uint32_t rx_sfid;
uint32_t rx_efid;
uint8_t rx_ff;
uint8_t rx_ft;
uint8_t rx_dlen;
uint8_t rx_data[8];
uint8_t rx_fi;
} can_receive_message_struct;
can_receive_message_struct pframe;
中的 uint8_t rx_data[8]; 我们将这些数据赋值给以上的联合体数据,举个例子即:
memcpy(&function.u8_data,pframe.rx_data,sizeof(u8_data));
我们就把数据转移到我们所需要的联合体中了,根据我以前博文中利用的联合体使用方法就可以将数据进行不同位数转换的发送了。
二、结构体法
首先向大家介绍一下结构体的按字节对齐的两种方法:
第一种方法:
#pragma pack(1) //按照1字节方式对齐
“结构体类型”
#pragma pack() //对齐结束
两个预编译指令之间的结构体内的内容都会非常紧密的按单个字节对齐,不会留出多余的空隙。
第二种方法:
利用预编译指令__attribute__((packed))
比如:
typedef struct
{
uint8_t selfcheck_status : 2;
uint8_t selfcheck_reserved : 6;
uint8_t alm_empty : 1;
uint8_t alm_block : 1;
uint8_t alm_reserved : 6;
uint8_t signal_source : 2;
uint8_t signal_reserved : 6;
uint16_t baud_rate;
uint8_t reserved1;
uint8_t enable_empty : 1;
uint8_t enable_block : 1;
uint8_t enable_reserved : 6;
uint8_t heartbeat;
}__attribute__((__packed__)) status_msg_t;
第二种方法的好处就是,可以进行单个结构体的按字节对齐结构体,不用多次强调第一种方法的预编译指令。
同样地,可以进行数值的转移:
status_msg_t status;
can_receive_message_struct pframe;
memcpy(&status, pframe.rx_data, sizeof(status_msg_t ));
通过以上方法,就可以将发来的数据进行了保存。
同样的发送,也是先将数据放到联合体中,按位进行存放,即uint8_t中数值实际上只占1位的数据存到结构体按位1位的元素内容中。把所有数据都填充到结构体中后,通过memcpy拷贝到发送数据结构体的数组中,进行CAN的发送:
(此处使用我自己的代码进行回忆)
memcpy(frame.u8Data,&Spreader_status_tx.valve_ctrl,sizeof(valve_ctrl_def));
memcpy(&spreader_valve_can_frame, &frame, sizeof(can_basic_frame_t));
小tips
一、联合体的赋值可以直接 ‘=’,比如:
Spreader_status_rx.plate_report = plate_report_t;
联合体的取地址必须加&符号,比如:&plate_report_t;
二、数组的赋值,不能直接‘=’赋值,它需要用函数strcpy()或者memcpy()来进行所有数组元素的数值转移。但是数组的取地址直接使用数组首地址直接进行取地址即可,即:pRxCan->u8Data。即数组名pRxCan->u8Data就是首地址。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)