在各类通信中,常使用memcpy将接收到的字节数组(如:unsigned char buffer[100]),直接复制到结构体当中,无须解码,直接使用结构体中的变量就完事了。
但,使用MDK5作为IDE, 对STM32芯片进行编程完成类似操作时,确并不如意。
相关代码如下:
// 如果有一些似曾相识的感觉,那应该是上一篇讲STM32用中断实现串口通信的文章
#include "usermain.h"
#include "usart.h"
#include "Angela.h"
#include "AngelaDecode.h"
unsigned char value;
unsigned char AngelaRx[128]={0x00};
short AngelaRxCNT = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
AngelaRx[AngelaRxCNT] = value;
AngelaRxCNT++;
HAL_UART_Receive_IT(&huart1, &value,1);
if(AngelaRxCNT==128){
AngelaCmdDecode();
AngelaRxCNT = 0;
}
}
}
void AngelaCmdDecode(void){
int i = 0;
memcpy((unsigned char *)&AngelaCmd, (unsigned char *)AngelaRx, sizeof(AngelaRx));
// [重点关注这一句]
if(AngelaCmd.bHeader[0]==0xAA && AngelaCmd.bHeader[1]==0x55){
AngelaCmdExecute();
}else{
return;
}
}
void AngelaCmdExecute(void){
AngelaRxCNT = 0;
}
AngelaCmd是个结构体,其定义如下
struct AngelaCmdstruct AngelaCmd;
AngelaCmdstruct的声明如下
struct AngelaCmdstruct
{
unsigned char bHeader[2]; // 2 2
unsigned char bCmdID;
unsigned char bReserved1; // 2 4
union AngelaCmdPara{
unsigned char b[8];
unsigned short s[4];
int i[2];
float f[2];
double d;
}CmdPara[15]; // 120 124
unsigned char bCrcCheck;
unsigned char bSumCheck;
unsigned char bTail[2]; // 2 128
};
一切的一切看似都很正常, 之前用CCS写DSP的时候,也用过类似的操作,完全没问题。
但,在STM32中,就出问题了。接收到字节数组AngelaRx[128]数据没问题,完全正常。
但,使用
memcpy((unsigned char *)&AngelaCmd, (unsigned char *)AngelaRx, sizeof(AngelaRx));
之后, AngelaCmd里面的数据,就是不对。
已经确认,并且写程序测试过(用sizeof),在STM32中
unsigned char // 占1字节
unsigned short // 占2字节
int // 占4字节
float // 占4字节
double // 占8字节
AngelaCmdstruct它肯定是128字节,断点调试也看了,AngelaRx的数据也是准确无误,且长度为128字节。
好了,揭晓谜底。
#pragma pack (1)
struct AngelaCmdstruct
{
unsigned char bHeader[2]; // 2 2
unsigned char bCmdID;
unsigned char bReserved1; // 2 4
union AngelaCmdPara{
unsigned char b[8];
unsigned short s[4];
int i[2];
float f[2];
double d;
}CmdPara[15]; // 120 124
unsigned char bCrcCheck;
unsigned char bSumCheck;
unsigned char bTail[2]; // 2 128
};
#pragma pack()
在结构体struct AngelaCmdstruct的声明的前后,用#pragma pack (1) 和 #pragma pack()就能解决这个问题。
#pragma pack (1)的意思是
设置结构体的边界对齐为1个字节,也就是所有数据在内存中是连续存储的。
#pragma pack ()的意思是
取消指定对齐,恢复缺省对齐,等价于#pragma pack(pop)
请看下面这个结构体
struct s {
char ch;
int i;
};
如果主函数中写一句:printf("%d", sizeof(struct s));
我们知道,char型占用1个字节,int型占4个字节,那么输出的结果是5吗? 答案是否定的。你可以自己试一下,输出结果为8。
为什么会这样呢?这是因为编译器为了让程序跑得跟快,减少CPU读取数据的指令周期,对结构体的存储进行了优化。实际上第一个char型成员虽然本来只有1个字节,但实际上却占用掉了4个字节,为的是让第二个int型成员的地址能够被4整除。因此实际占用的是8个字节。
而#pragma pack(1)让编译器将结构体数据强制连续排列,这样的话,sizeof(struct s)输出的结果就是5了。