假如我们需要使用单片机的串口与外设模块通讯,串口的通讯协议如下图所示,我们可以怎么设计这个数据结构以方便单片机操作从串口接收或者发送的数据呢。
这里,我介绍两种方法,一种是使用数组来构建满足协议的数据结构,另一种是使用结构体来构建满足协议的数据结构,我们看看哪种方法更适合处理上述问题。
首先看看使用数组来构建数据结构的方法,如下代码所示。
//用于存放6个字节的协议数据
unsigned char arr[6];
unsigned char len;
len = sizeof(arr);
//当串口缓冲区(假设是一个名为ser的数组)来了数据后,我们需要把串口数据复制到arr数组中
memcpy(arr, ser, len);
//拷贝完成后,我们需要校验、检查这些数据
unsigned char sum = 0;
unsigned char *p;
p = arr;
while(--len> 0)
{
sum += *p++;
}
//校验
if(sum == arr[5])
{
//检查收到的数据ID是否是我的目的ID
if(arr[0] == 0x01 && arr[1] == 0x02 && a[2] == 0x03)
{
//检查类型,确认是否是我的目标类型
if(arr[3] == 0x05)
{
//检查事件并做相应的动作.....
}
}
}
从上述代码可以看出,对于接收到数据保存在arr后,需要指定索引才能准确的引用你需要的字节数据,这样做除了不方便以外,还容易出错。假如此时串口协议变更,比如我们需在ID3与类型之间扩充一个字节,此时你的代码肯定要改动,因为arr数组中arr[3]对于的位置已经不是类型了,arr[5]对应的也不是校验和了。显然,这种方法虽然可以用来处理串口数据,但是扩展性不好,程序引用相应的数据也不方便。那怎么办呢,用结构体就可以很好的解决这些问题,我们先来看代码。
typedef struct
{
unsigned char id[3];
unsigned char type;
unsigned char event;
unsigned char sum;
}pro_t;
pro_t pro;
unsigned char len;
len = sizeof(pro_t);
//当串口缓冲区(假设是一个名为ser的数组)来了数据后,我们需要把串口数据复制到pro结构体中
memcpy((unsigned char *)&pro, ser, len);
//拷贝完成后,我们需要校验、检查这些数据
unsigned char sum = 0;
unsigned char *p;
p = (unsigned char *)&pro;
while(--len > 0)
{
sum += *p++;
}
//校验
if(sum == pro.sum)
{
//检查收到的数据ID是否是我的目标ID
if(pro.id[0] == 0x01 && pro.id[1] == 0x02 && pro.id[2] == 0x03)
{
//检查类型,确认是否是我的目标类型
if(pro.type == 0x05)
{
//检查事件并做相应的动作.....
}
}
}
从上述代码可以看出,程序引用协议数据相比数组结构更为方便而且清晰不易出错,当需要在ID3以及类型之间插入一个字节时,我们只需要更改pro_t类型的数据结构,而不需要变更我们已经写好的程序,如下图所示。
typedef struct
{
unsigned char id[3];
unsigned char extend;
unsigned char type;
unsigned char event;
unsigned char sum;
}pro_t;
综合来看,为了更好的让单片机的程序组织或者引用协议数据,使用结构体要比使用数组更好,不论从清晰,方便以及可扩展上都更具优势。
|