太阳集团tcy8722

当前位置: 首页 >应用方案 >技术应用 >

嵌入式开发遇到数据转换解决数据流过大的解决办法

痛苦!数据流过大?数据转换各种组包拆包?指针数组你试过没!

今天的是干货,是真的干。作为一个从业4年,工龄6年的嵌入式开发程序员,在做通讯设备领域时最痛苦的事莫过于数据流过大问题,以及数据转换时各种组包拆包等问题,特别是在控制器内存资源有限时。这种问题更加突出。

拿以太网+串口传输modbus指令举例:

以太网数据收发时以太网的协议栈占用内存约20Kbyte,单个SOCKET传输数据时最少预留了532byte字节的缓存空间,当取出网络下传的数据时,需要拆掉网络传输头并在末尾增加CRC,串口上行数据时,需要增加网络传输数据头以及去掉末尾CRC值,如果此时碰到惯用for循环copy数据或者使用memcpy函数进行数据组包的大佬,内存空间基本就是捉襟见肘。

解决以上问题的办法之一就是使用指针配合数组进行组包与拆包,如下图;

预留包头46字节

数据部分536字节

末尾预留10字节

网络端向串口发送:声明数组时申明比实际数据所需空间更大的数组unsigned char Buff[592],以及一个指针unsigned char *datapoint;将datapoint指向Buff[46]的位置,读入数据,将数据从指针datapoint指向的位置开始存入数组,同时使用另外的变量unsigned int length存储当次读入的数据的长度,进行数据拆包操作时(去包头6字节),直接将指针datapoint指向Buff[52]的位置,随后将计算所得CRC2byte)值从Buff[46 + length]位置存入数组,并得出最终需要传输的长度length+2,串口发送数据只需要输入起始地址datapoint,长度length,将数据存入串口发送环形队列即可完成发送。

代码如下

unsigned char Buff[592];

unsigned char *datapoint;

unsigned int length;

datapoint = & Buff[46];//指针指向数组中间

net_dataread(datapoint,& length);//读取数据,获得数据长度

CRC(&Buff[46+length],datapoint,& length);//获取校验值并存入数组

Uart_send(datapoint,length+2);

串口向网络发送时,数据从环形队列读出,需要加上TCP modbus协议的包头部分(6byte),去掉CRC校验,同样声明数组以及指针、长度变量,将datapoint指向Buff[46]的位置,读入数据,将数据从指针datapoint指向的位置开始存入数组;将指针指向当前指向地址的前6个地址位置存入6字节,然后按照新的datapoint位置,长度length+4将数据从网络发出;

代码如下

unsigned char Buff[592];

unsigned char *datapoint;

unsigned int length;

datapoint = & Buff[46];//指针指向数组中间

uart_read(datapoint,& length);//读取数据,获得数据长度

datapoint = datapoint-6;

memcpy(datapoint,包头暂存数组首地址,6);

Uart_send(datapoint,length+4);

以上实例简单说明了利用指针组包的简单应用,但是在实际应用中可能由于设备需要使用多种协议,组包方式不同,例如包头之前加入注册包等,数据实际读取完成之后不是直接操作而是直接传入子函数,进行组包与拆包,此时仅需要传入datapoint与长度,进子函数,由于datapoint指向的数组前后均有预留空间,子函数内依然可以使用指针,且在Buff[]数组的范围内,指针可以前后自由移动,在不需要进行大量数据拷贝的前提下完成数组的拆组包过程,同时也避免了反复拷贝数据对空间的浪费。

      以上就是指针的简单应用之一,指针除了对数组,还可以对函数操作,结合结构体,基本上可以在C语言中实现类似C++中类功能。

今天的分享就到这里啦,EBYTE每一天都致力于更好的助力物联化、智能化、自动化的发展,提升资源利用率,更多产品及相关资料,感兴趣的小伙伴可以登录我们的太阳集团tcy8722官网进行了解,也可以直接拨打400电话咨询技术专员!


太阳集团tcy8722