打印
[开发工具]

union的数据打包场景 :灵活转换数组和数据

[复制链接]
305|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
AC, ar, DA, TE, IO, ni

我们平时会遇到一些数字传感器,往往他转换完成后的数据需要2 个字节或者4 个字节来存储,比如陀螺仪的3 轴 加速度的三个寄存器都是16bit 的,但是我们通过IIC 或者SPI 读取的时候都是一个字节一个字节的读取的。这时候我们就可以使用联合体来进行数据的大包转换。
union
{
    unsigned char ary[6];
    struct
    {
        unsigned short X;
        unsigned short Y;
        unsigned short Z;
    }Data;
}acc_t;

// 在SPI读取函数中按单字节给数组赋值
acc_t.ary[0] = 0x21;
acc_t.ary[1] = 0x43;

我们在 SPI 的读取程序中给联合体的数组赋值后,可以直接使用 Data 来获取到 short 类型的传感器输出值。
printf("The X is:0x%x\n",acc_t.Data.X);


输出为:
The X is:0x4321


这说明联合不需要额外的赋值和强制类型转换,同一个数据可解释为两个不一样的东西。
在使用联合在打包数据的时候,必须要清楚当前处理器是大端对齐还是小端对齐。
大端对齐:数据的低位保存在内存的高地址中,数据的高位保存的内存的低地址中。
小端对齐:数据的低位保存在内存的低地址中,数据的高位保存在内存的高地址中。
下面用图的形式举一个例子分别在大端对齐和小端对齐中的存储形式。


有了大端对齐和小端对齐的认知下,我们来看 union 如何对数据进行打包,下面给出一段代码:
int main(void) {
    // 定义一个联合体
    union ByteSplit {
        unsigned int word;
        unsigned char byte[4];
    } data;

    // 给联合体的字节成员赋值
    data.byte[0] = 0x11;
    data.byte[1] = 0x22;
    data.byte[2] = 0x33;
    data.byte[3] = 0x44;

    // 输出整数和字节
    printf("整数值为:%u\n", data.word);

    return 0;
}

上述的运行结果会根据对齐方式的不一样而有所差别。如果是小端模式:
整数值为:0x44332211

如果是大端模式:
整数值为:0x11223344

TIP:当然,采用这种方式进行数据的打包存在一定弊端,因为处理器的对齐方式不同会产生不同的结果。因此,通常我们会采用数据移位的方式来实现:

char byte1 = 0x21;
char byte2 = 0x43;

short word;
word = (((short)byte2) << 8)|((short)byte1);

上述的写法便不会收到处理器对齐方式的影响,也具有更好地移植性。


使用特权

评论回复
沙发
jf101| | 2024-6-23 14:16 | 只看该作者
union的使用灵活转换数组和数据,提高数据转换

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

240

主题

1848

帖子

3

粉丝