正文
项目需求:
上篇Rd03d测试的文章中用到了struct+union解析串口发来的数据,把代码扣了下来在实际应用中,Rd03d发的数据格式是:帧头部(AA FF 03 00)+帧内数据(目标1信息(8个8位数据)+目标2信息(8个8位数据)+目标3信息(8个8位数据))+帧尾部(55 CC).我的目的是要把帧内数据的两个8位数据拼成一个十六位数据来得到Rd03d检测到的X(16位),Y(16位),Z(16位)坐标数据,有一个方法很简单就是你把读出来的两个8位数据转成16位然后高8位左移8位与低8位进行或逻辑运算就可以的到,但这种方法很笨,如果他发送100个8位数据过来你是不是要一个一个写!所以还有一种方法就是struct+union解析.
extern uint8_t Buffer[30];
//目标1的信息
int16_t Target1_XPos=0;
int16_t Target1_YPos=0;
int16_t Target1_Speed=0;
int16_t Target1_Rate=0;
//目标2的信息
int16_t Target2_XPos=0;
int16_t Target2_YPos=0;
int16_t Target2_Speed=0;
int16_t Target2_Rate=0;
//目标3的信息
int16_t Target3_XPos=0;
int16_t Target3_YPos=0;
int16_t Target3_Speed=0;
int16_t Target3_Rate=0;
#pragma pack (1)
typedef struct{
short x;
short y;
short v;
short d;
}PersonInfo;
typedef struct{
union{
unsigned char data[4];
unsigned int data4;
}head;
PersonInfo person[3];
// unsigned char tail[2];
} Info;
#pragma pack()
//将数组Buffer里的数据解析成十进制数据
void Translat_Rd05RegDate()
{
if(BuffFullFlag==1)
{
Info * pInfo = (Info*)Buffer;
Target1_XPos =pInfo->person[0].x;
Target1_YPos =pInfo->person[0].y;
Target1_Speed=pInfo->person[0].v;
Target1_Rate =pInfo->person[0].d;
Target2_XPos =pInfo->person[1].x;
Target2_YPos =pInfo->person[1].y;
Target2_Speed=pInfo->person[1].v;
Target2_Rate =pInfo->person[1].d;
Target3_XPos =pInfo->person[2].x;
Target3_YPos =pInfo->person[2].y;
Target3_Speed=pInfo->person[2].v;
Target3_Rate =pInfo->person[2].d;
}
}
void Show_Rd03d_Data()
{
Translat_Rd05RegDate();
if (BuffFullFlag == 1)//判断数组是否满了
{
Serial_Printf("***************Rd05 Data***************:\n");
Serial_Printf("Target1_XPos=%d\n",Target1_XPos);
Serial_Printf("Target1_YPos=%d\n",Target1_YPos);
Serial_Printf("Target1_Speed=%d\n",Target1_Speed);
Serial_Printf("Target1_Rate=%d\n",Target1_Rate);
Serial_Printf("Target2_XPos=%d\n",Target2_XPos);
Serial_Printf("Target2_YPos=%d\n",Target2_YPos);
Serial_Printf("Target2_Speed=%d\n",Target2_Speed);
Serial_Printf("Target2_Rate=%d\n",Target2_Rate);
Serial_Printf("Target3_XPos=%d\n",Target3_XPos);
Serial_Printf("Target3_YPos=%d\n",Target3_YPos);
Serial_Printf("Target3_Speed=%d\n",Target3_Speed);
Serial_Printf("Target3_Rate=%d\n",Target3_Rate);
Serial_Printf("**************Buffer Data*************:\n");
for(int i=0;i<30;i++)
{
Serial_Printf("Buffer[%d]=%x",i,Buffer[i]);
Serial_Printf("\n");
}
Serial_Printf("\n\n");
BuffFullFlag = 0;
}
}
怎么用 struct+union:
先把上面这个代码放一边,先来看怎么用通俗易懂的话讲清struct+union怎么用.
先来看一段代码
#include<stdio.h>
int xPos=0,yPos=0,zPos=0,kPos=0;
int head0,head1,tail0,tail1;
int dat;
#pragma pack (1)
typedef struct{
unsigned short x;
unsigned short y;
unsigned short z;
unsigned short k;
}Pos;
typedef struct{
union{
unsigned char dat[2];
short data4;
}head;
Pos DatInfo;
unsigned char tail[2];
}RxStr;
#pragma pack ()
unsigned char buffer[12]={0x88,0x88,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x99};
int main()
{
RxStr *pDat=(RxStr*)buffer;
dat=pDat->head.data4;
head0=pDat->head.dat[0];
head1=pDat->head.dat[1];
xPos=pDat->DatInfo.x;
yPos=pDat->DatInfo.y;
zPos=pDat->DatInfo.z;
kPos=pDat->DatInfo.k;
tail0=pDat->tail[0];
tail1=pDat->tail[1];
printf("data4=%x\n\n",dat);
printf("head0=%x\n",head0);
printf("head1=%x\n",head1);
printf("xPos=%x\n",xPos);
printf("yPos=%x\n",yPos);
printf("zPos=%x\n",zPos);
printf("kPos=%x\n",kPos);
printf("tail0=%x\n",tail0);
printf("tail1=%x\n",tail1);
}
运行结果
一步一步看
主函数
RxStr *pDat=(RxStr*)buffer;
将buffer数组强制转换成了结构体RxSrt型的指针,并创建一个RxStr型的指针pDat指向buffer.
此时结构体RxStr会一一被塞满buffer数组的数据,先接收到的塞在后面,后接收到的塞在前面.比如最开始,0x88,0x88分别塞到了union里的dat[0],dat[1]当中.紧接着0x11,0x22塞入unsigned short型的x中,0x33,0x44塞入unsigned short型的y中,0x55,0x66塞入unsigned short型的z中,0x77,0x88塞入unsigned short型的k中,然后0x99,0x99分别塞入tail[0]和tail[1]中.这样完成了接收到的数据一一塞入对应的变量中,有些变量是8位(unsigned char),有些变量是16位(short),我们要的是把两个8位放在一个16位的变量中解析数据,所以我们只取那个16位的变量.
遇到的隐式转换的问题:
有一个问题是问什么在Pos结构体中要用到unsigned short的类型而不直接用short类型?
这里就涉及到隐式类型转换
来看个例子
如果用short型的变量打印16进制有时候好像并没有打印出自己设想的值来,这是为什么
因为运算时计算机把short和char型的变量隐式转换了,把他转为int的变量进行运算.记住有符号时,如果他的补码最高位为1那转为int型运算时他就会把高位位补上1,反之则补上0如上图:
a的16进制是1000100010001000
b的16进制是0111011101110111
a的最高位是1所以隐式转换时他的高位都被补上了1,也就是ffff
b的最高位是0所以隐式转换时他的高位都被补上了0
如何解决隐式转换的问题:
无符号时不会补位,所以用无符号的short,如下图: