打印

雕虫小技 --- 结构体的一个简单应用

[复制链接]
1248|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
假如我们需要使用单片机的串口与外设模块通讯,串口的通讯协议如下图所示,我们可以怎么设计这个数据结构以方便单片机操作从串口接收或者发送的数据呢。


这里,我介绍两种方法,一种是使用数组来构建满足协议的数据结构,另一种是使用结构体来构建满足协议的数据结构,我们看看哪种方法更适合处理上述问题。

首先看看使用数组来构建数据结构的方法,如下代码所示。

//用于存放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;

综合来看,为了更好的让单片机的程序组织或者引用协议数据,使用结构体要比使用数组更好,不论从清晰,方便以及可扩展上都更具优势。





使用特权

评论回复

相关帖子

沙发
会笑的星星|  楼主 | 2020-3-22 16:36 | 只看该作者

使用特权

评论回复
板凳
叶春勇| | 2020-3-23 13:04 | 只看该作者
记得以前看到 过程编程的概念       软件=数据+算法
从很多编程语言来看,偏向数据的语言,面向对象搞起,组件编程搞起。
偏向算法的语言,来自学院派的函数式编程,居然抵触变量数据。适合并发。

从c语言的角度,写软件库,都是围绕一个结构来了。
typedef struct
{
} pro_t;
然后:
init(pro_t *p)
do_something(pro_t *p,....)

使用特权

评论回复
地板
kingsleych| | 2020-3-23 13:44 | 只看该作者
通信中本来就大量使用结构体去组包呀,还是各种,union里面包结构体,

使用特权

评论回复
5
songchenping| | 2020-3-24 17:20 | 只看该作者
又学了一招。

使用特权

评论回复
6
Kevion_lin| | 2020-5-17 10:07 | 只看该作者
很喜欢看星星的发帖,教科书式的教你加上启发,是在不藏私用心的教你。

使用特权

评论回复
7
ayb_ice| | 2020-5-18 08:37 | 只看该作者
枚举个索引号一样可以的

enum{
        INDEX_ID0 = 0,
        INDEX_ID1 = 1,
        INDEX_ID2 = 2,
        ...
};

        if (Buf[INDEX_ID0] == 0x01 && ...)

使用特权

评论回复
8
chengyabcd| | 2020-5-19 10:51 | 只看该作者
这个要注意结构体占用字节数量问题,如果结构体中有2字节或者4字节变量,就要用__packed封装,否则一个字节的变量占用空间并不是一个字节,地址对其问题。

使用特权

评论回复
9
andy520520| | 2020-12-8 09:22 | 只看该作者
你这可不是雕虫小技,是雕虫大技 !!!

使用特权

评论回复
10
一路向北lm| | 2020-12-9 11:36 | 只看该作者
写的不赖,感谢分享

使用特权

评论回复
11
MagicSquare834| | 2020-12-12 10:55 | 只看该作者
这就是面对对象编程的方法了

使用特权

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

本版积分规则

31

主题

96

帖子

16

粉丝