帧格式:方便自定义长度多种帧标识传输
格式规定
帧标识A 类型 备注
A<=0x0F 短帧 数据长度1字节
A>0x0F 长帧 数据长度2字节
短帧:帧标识 帧标识取反 帧用户数据字节数 用户数据…用户数据
长帧:帧标识 帧标识取反 帧用户数据字节数(高8位) 帧用户数据字节数(低8位) 用户数据…用户数据
注意:
帧标识符应尽量避免使用0x00/0xFF,因为出现概率过高,容易误识别
若需提高准确度,则可以使用此文档的协议通信帧协议解析和发送_裸机
使用方法
#include "stdio.h"
#include "stdint.h"
#include "math.h"
#include "frame_driver.h"
#define dDATA_SIZE 65537
int main()
{
//自定义短帧内容
uint8_t data[dDATA_SIZE] = { 0x01,0x00,0x03,0x01,0x00,\
0x01,dIdentify_Invert(0x01),0x01,0x0A,\
0x02,0x03,0x01,
0x01, dIdentify_Invert(0x01),0x05,0x01,0x02,0x03,0x04,0x05,\
0x01, 0x00, 0x03, 0x01, 0x00, \
0x01, dIdentify_Invert(0x01),0x02,0x01,0x02,\
0x01, 0x00, 0x03, 0x01, 0x00, \
0x01, dIdentify_Invert(0x01),0x03,0x01,0x02,0x03,\
0x01, 0x00, 0x03, 0x01, 0x00, \
0x02, dIdentify_Invert(0x02), 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, \
0x01, 0x00, 0x03, 0x01, 0x00, \
0x03, dIdentify_Invert(0x03), 0x02, 0x01, 0x02, \
0x01, 0x00, 0x03, 0x01, 0x00, \
0x04, dIdentify_Invert(0x04), 0x03, 0x01, 0x02, 0x03, \
0x01, 0x00, 0x03, 0x01, 0x00, \
0x05, dIdentify_Invert(0x05), 0x03, 0x01, 0x02, 0x03, \
0x1F, dIdentify_Invert(0x1F), dDataLength_MSB(2), dDataLength_LSB(2),0x0A,0x0B\
};
uint8_t data2[dDATA_SIZE];
uint32_t i = 0, j = 0, num = 0;
i = 0;
data2[i++] = 0x1F;//定义长帧内容
data2[i++] = dIdentify_Invert(0x1F);
data2[i++] = dDataLength_MSB(dDATA_SIZE - 4);
data2[i++] = dDataLength_LSB(dDATA_SIZE - 4);
for (j = 0; j < dDATA_SIZE - 4; j++)data2[i++] = j % 0x0FF;
frame_handler frame;
if (frame_init(&frame, 5, dDATA_SIZE) < 0)return 0;创建5个帧资源,最大帧长度为dDATA_SIZE
if (frame_identify_add(&frame, 0x01) < 0)return 0;//添加标识符0x01帧
if (frame_identify_add(&frame, 0x02) < 0)return 0;
if (frame_identify_add(&frame, 0x03) < 0)return 0;
if (frame_identify_add(&frame, 0x04) < 0)return 0;
if (frame_identify_add(&frame, 0x1F) < 0)return 0;
frame_identify_add(&frame, 0x05);//超过帧资源添加0x05标识符帧失败
for (i = 0; i < dDATA_SIZE; i++)//查找长帧
{
if (frame_find(&frame, data2[i]) < 0)continue;//帧识别
frame_data_printf(frame.data_rx);//有效帧打印输出,数据只能在此轮使用,下轮会进行内存覆盖,其他地方需要使用可以复制走
}
for (i = 0; i < dDATA_SIZE; i++)//查找短帧
{
if (frame_find(&frame, data[i]) < 0)continue;
frame_data_printf(frame.data_rx);
}
//中途放弃之前的查找
for (i = 0; i < dDATA_SIZE; i++)//查找长帧
{
if (i == 4)frame_find_clear(&frame);//清空查找器
if (frame_find(&frame, data2[i]) < 0)continue;//帧识别
frame_data_printf(frame.data_rx);//有效帧打印输出
}
frame_DeInit(&frame);//销毁帧资源
uint8_t *pdata = NULL, send[6] = {0};
pdata = frame_format_generate(0x0A, 2, send);//生成短帧格式:0x0A 0xF5 0x02 0x00 0x00
if (pdata == NULL)printf("生成失败\n");
else
{
for (i = 0; i < 5; i++)printf("0x%0X,", send[i]);
printf("\n");
}
pdata = frame_format_generate(0x1A, 2, send);//生成长帧格式:0x0A 0xE5 0x00 0x02 0x00 0x00
if (pdata == NULL)printf("生成失败\n");
else
{
for (i = 0; i < 6; i++)printf("0x%0X,", send[i]);
printf("\n");
}
return 0;
}
注意:
for (i = 0; i < dDATA_SIZE; i++)//查找长帧
{
if (frame_find(&frame, data2[i]) < 0)continue;//帧识别
frame_data_printf(frame.data_rx);//有效帧打印输出,数据只能在此轮使用,下轮会进行内存覆盖,其他地方需要使用可以复制走
}
frame_find(&frame, data2[i])查找到数据后必须当轮使用,下一次查找会进行内存覆盖,导致数据丢失,若他地方需要使用可以复制走
源文件
frame_driver.h
#ifndef _frame_driver_H_
#define _frame_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stdio.h"
#define dFrame_LOG(...) printf(__VA_ARGS__) //日志输出
#define dIdentify_Invert(id) ((~id) & 0xFF)//标识符取反
#define dDataLength_MSB(len) ((len>>8)&0xFF)//截取数据长度高8位
#define dDataLength_LSB(len) (len&0xFF)//截取数据长度低8位
#define dDataLength_Merge(MSB,LSB) (((((uint16_t )MSB) << 8)|(uint16_t )LSB) & 0xFFFF)//合并得到长帧的数据长度
typedef struct
{
uint8_t number;//帧种类数
uint8_t pos;//帧标识集可用位置
uint8_t *pbuf;//所有帧标识
}Frame_Identify_StructDef;//帧标识集
typedef struct
{
uint32_t size; //帧缓冲区字节数
uint8_t *pbuf;//缓冲区
uint32_t pos;//位置点
}Frame_Buffer_StructDef;//缓冲区
typedef enum
{
eFrame_DataState_Find = 0,//查找中
eFrame_DataState_Receive,//接收数据
eFrame_DataState_Complete//接收完毕
}Frame_DataState_EnumDef;//帧接收状态
typedef struct
{
Frame_DataState_EnumDef state;//帧接收状态
uint8_t identify;//接收的帧标识
uint32_t size;//用户数据字节数
uint8_t *pbuf;//帧用户数据缓冲区;注:不含帧头、数据字节数
}Frame_Data_StructDef;
typedef struct
{
//内部变量区域:请勿修改
uint8_t state;//帧状态:0--不可用,!0--可用
Frame_Identify_StructDef identify;//帧集合
Frame_Buffer_StructDef rx;//接收缓冲区
//共享变量区域
Frame_Data_StructDef data_rx;//接收的数据
}frame_handler;
extern int frame_init(frame_handler *p, uint8_t number, uint32_t rx_size);
extern void frame_DeInit(frame_handler *p);
extern int frame_identify_add(frame_handler *p, uint8_t identify);
extern int frame_find(frame_handler *p, uint8_t data);
extern int frame_find_clear(frame_handler *p);
extern void frame_data_printf(Frame_Data_StructDef data);
extern uint8_t *frame_format_generate(uint8_t identify, uint32_t size, uint8_t *pbuf);
#ifdef __cplusplus
}
#endif
#endif
frame_driver.c
/**********************************************************************
*file:任意帧收发
*author:残梦
*versions:V2.0
*date:2024.3.20
*note:
格式规定:
帧标识A 类型 备注
A<=0x0F 短帧 数据长度1字节
A>0x0F 长帧 数据长度2字节
短帧:帧标识 帧标识取反 帧用户数据字节数 用户数据...用户数据
长帧:帧标识 帧标识取反 帧用户数据字节数(高8位) 帧用户数据字节数(低8位) 用户数据...用户数据
注意:
帧标识符应尽量避免使用0x00/0xFF,因为出现概率过高,容易误识别
使用方法:
#include "stdio.h"
#include "stdint.h"
#include "math.h"
#include "frame_driver.h"
#define dDATA_SIZE 65537
int main()
{
//自定义短帧内容
uint8_t data[dDATA_SIZE] = { 0x01,0x00,0x03,0x01,0x00,\
0x01,dIdentify_Invert(0x01),0x01,0x0A,\
0x02,0x03,0x01,
0x01, dIdentify_Invert(0x01),0x05,0x01,0x02,0x03,0x04,0x05,\
0x01, 0x00, 0x03, 0x01, 0x00, \
0x01, dIdentify_Invert(0x01),0x02,0x01,0x02,\
0x01, 0x00, 0x03, 0x01, 0x00, \
0x01, dIdentify_Invert(0x01),0x03,0x01,0x02,0x03,\
0x01, 0x00, 0x03, 0x01, 0x00, \
0x02, dIdentify_Invert(0x02), 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, \
0x01, 0x00, 0x03, 0x01, 0x00, \
0x03, dIdentify_Invert(0x03), 0x02, 0x01, 0x02, \
0x01, 0x00, 0x03, 0x01, 0x00, \
0x04, dIdentify_Invert(0x04), 0x03, 0x01, 0x02, 0x03, \
0x01, 0x00, 0x03, 0x01, 0x00, \
0x05, dIdentify_Invert(0x05), 0x03, 0x01, 0x02, 0x03, \
0x1F, dIdentify_Invert(0x1F), dDataLength_MSB(2), dDataLength_LSB(2),0x0A,0x0B\
};
uint8_t data2[dDATA_SIZE];
uint32_t i = 0, j = 0, num = 0;
i = 0;
data2[i++] = 0x1F;//定义长帧内容
data2[i++] = dIdentify_Invert(0x1F);
data2[i++] = dDataLength_MSB(dDATA_SIZE - 4);
data2[i++] = dDataLength_LSB(dDATA_SIZE - 4);
for (j = 0; j < dDATA_SIZE - 4; j++)data2[i++] = j % 0x0FF;
frame_handler frame;
if (frame_init(&frame, 5, dDATA_SIZE) < 0)return 0;创建5个帧资源,最大帧长度为dDATA_SIZE
if (frame_identify_add(&frame, 0x01) < 0)return 0;//添加标识符0x01帧
if (frame_identify_add(&frame, 0x02) < 0)return 0;
if (frame_identify_add(&frame, 0x03) < 0)return 0;
if (frame_identify_add(&frame, 0x04) < 0)return 0;
if (frame_identify_add(&frame, 0x1F) < 0)return 0;
frame_identify_add(&frame, 0x05);//超过帧资源添加0x05标识符帧失败
for (i = 0; i < dDATA_SIZE; i++)//查找长帧
{
if (frame_find(&frame, data2[i]) < 0)continue;//帧识别
frame_data_printf(frame.data_rx);//有效帧打印输出
//查找到数据后必须当轮使用,下一次查找会进行内存覆盖,导致数据丢失,若他地方需要使用可以复制走
}
for (i = 0; i < dDATA_SIZE; i++)//查找短帧
{
if (frame_find(&frame, data[i]) < 0)continue;
frame_data_printf(frame.data_rx);
}
//中途放弃之前的查找
for (i = 0; i < dDATA_SIZE; i++)//查找长帧
{
if (i == 4)frame_find_clear(&frame);//清空查找器
if (frame_find(&frame, data2[i]) < 0)continue;//帧识别
frame_data_printf(frame.data_rx);//有效帧打印输出
}
frame_DeInit(&frame);//销毁帧资源
uint8_t *pdata = NULL, send[6] = {0};
pdata = frame_format_generate(0x0A, 2, send);//生成短帧格式:0x0A 0xF5 0x02 0x00 0x00
if (pdata == NULL)printf("生成失败\n");
else
{
for (i = 0; i < 5; i++)printf("0x%0X,", send[i]);
printf("\n");
}
pdata = frame_format_generate(0x1A, 2, send);//生成长帧格式:0x0A 0xE5 0x00 0x02 0x00 0x00
if (pdata == NULL)printf("生成失败\n");
else
{
for (i = 0; i < 6; i++)printf("0x%0X,", send[i]);
printf("\n");
}
return 0;
}
**********************************************************************/
#include "frame_driver.h"
#include "stdlib.h"
#include "string.h"
static int frame_identify_find(Frame_Identify_StructDef identify, uint8_t id);
/****************************************
@function:匹配帧标识符集合
@param:identify--标识符集合
id--待匹配的标识符
@return:-1--失败,0--成功
@note:
****************************************/
static int frame_identify_find(Frame_Identify_StructDef identify, uint8_t id)
{
uint8_t i = 0;
for (i = 0; i < identify.pos; i++)
{
if (identify.pbuf[i] == id)return 0;
}
return -1;
}
/****************************************
@function:帧资源初始化
@param:p--帧句柄
number--帧种类数,范围[1,255]
rx_size--帧接收缓冲区字节数,等于最大帧长度,范围[4,uint32_t]
@return:
0--成功
-1:参数错误
-2:内存分配失败
@note:
****************************************/
int frame_init(frame_handler *p, uint8_t number, uint32_t rx_size)
{
if ((p == NULL) || (number == 0) || (rx_size < 4))return -1;
p->state = 0;
p->identify.pbuf = (uint8_t *)malloc(number);
if (p->identify.pbuf == NULL)
{
dFrame_LOG("Error[%s-line:%d]:memory allocation failure\n", __func__, __LINE__);
return -2;
}
p->identify.number = number;
p->identify.pos = 0;
p->rx.pbuf = (uint8_t *)malloc(rx_size);
if (p->rx.pbuf == NULL)
{
dFrame_LOG("Error[%s-line:%d]:memory allocation failure\n", __func__, __LINE__);
return -2;
}
p->rx.size = rx_size;
p->rx.pos = 0;
p->data_rx.state = eFrame_DataState_Find;
p->data_rx.identify = 0;
p->data_rx.size = 0;
p->data_rx.pbuf = NULL;
p->state = 1;
return 0;
}
/****************************************
@function:帧资源销毁
@param:p--帧句柄
@return:void
@note:
****************************************/
void frame_DeInit(frame_handler *p)
{
if (p == NULL)return;
p->state = 0;
if (p->identify.pbuf != NULL)free(p->identify.pbuf);
p->identify.pbuf = NULL;
p->identify.number = 0;
p->identify.pos = 0;
if (p->rx.pbuf != NULL)free(p->rx.pbuf);
p->rx.pbuf = NULL;
p->rx.size = 0;
p->rx.pos = 0;
p->data_rx.state = eFrame_DataState_Find;
p->data_rx.identify = 0;
p->data_rx.size = 0;
p->data_rx.pbuf = NULL;
}
/****************************************
@function:添加待查找的帧标识
@param:p--帧句柄
identify--帧标识
格式规定:
帧标识 类型 备注
A<=0x0F 短帧 数据长度1字节
A>0x0F 长帧 数据长度2字节
短帧:帧标识 帧标识取反 数据字节数 数据...数据
长帧:帧标识 帧标识取反 数据字节数(高8位) 数据字节数(低8位) 数据...数据
@return:
0:成功
-1--参数错误
-2:添加失败
@note:添加重复帧标识无效
****************************************/
int frame_identify_add(frame_handler *p, uint8_t identify)
{
uint8_t i = 0;
if (p == NULL)return -1;
if (p->state == 0)return -1;
if (p->identify.pos >= p->identify.number)return -2;
while (i < p->identify.pos)
{
if (p->identify.pbuf[i++] == identify)return -2;
}
p->identify.pbuf[p->identify.pos++] = identify;
return 0;
}
/****************************************
@function:数据接收并匹配帧集合
@param:p--帧句柄
data--新数据
@return:
0:识别到帧数据,数据信息查看p->data_rx结构体
-1:参数异常|帧未初始化
-2:帧查找中
-3:数据接收中
-4:接收缓冲区空间不足,原因:初始化的帧资源大小低于帧总长度
@note:
****************************************/
int frame_find(frame_handler *p, uint8_t data)
{
uint32_t i = 0;
uint16_t len = 0;
if (p == NULL)return -1;
if (p->state == 0)return -1;
if (p->identify.pos == 0)return -1;//没有待识别的帧标识
switch (p->data_rx.state)
{
case eFrame_DataState_Find:
{
p->rx.pbuf[p->rx.pos++] = data;
if (p->rx.pos < 4)return -2;
len = (p->rx.pbuf[0] <= 0x0F) ? p->rx.pbuf[2] : dDataLength_Merge(p->rx.pbuf[2], p->rx.pbuf[3]);
if ((p->rx.pbuf[0] != dIdentify_Invert(p->rx.pbuf[1])) || (len == 0))//帧标识不对|数据长度为0
{
//数据移除1字节
for (i = 1; i < p->rx.pos; i++)p->rx.pbuf[i - 1] = p->rx.pbuf[i];
p->rx.pos--;
return -2;
}
if (frame_identify_find(p->identify, p->rx.pbuf[0]) < 0)
{
//数据移除1字节
for (i = 1; i < p->rx.pos; i++)p->rx.pbuf[i - 1] = p->rx.pbuf[i];
p->rx.pos--;
return -2;
}
p->data_rx.identify = p->rx.pbuf[0];
p->data_rx.size = len;
p->data_rx.pbuf = (p->data_rx.identify > 0x0F) ? (&(p->rx.pbuf[4])) : (&(p->rx.pbuf[3]));
if ((p->data_rx.identify > 0x0F) || (p->data_rx.size > 1))//长帧 或 短帧数据长度为1
{
p->data_rx.state = eFrame_DataState_Receive;
return -3;
}
//数据接收完毕:短帧数据长度1
p->data_rx.state = eFrame_DataState_Complete;
return 0;
}
case eFrame_DataState_Receive:
{
if (p->rx.pos >= p->rx.size)
{
dFrame_LOG("Error[%s-line:%d]:Insufficient receive buffer space\n", __func__, __LINE__);
return -4;
}
p->rx.pbuf[p->rx.pos++] = data;
len = (p->data_rx.identify > 0x0F) ? (p->rx.pos - 4) : (p->rx.pos - 3);
if (len < p->data_rx.size)return -3;//继续接收
p->data_rx.state = eFrame_DataState_Complete;
return 0;
}
case eFrame_DataState_Complete:
{
p->rx.pos = 0;
p->rx.pbuf[p->rx.pos++] = data;
p->data_rx.identify = 0;
p->data_rx.size = 0;
p->data_rx.pbuf = NULL;
p->data_rx.state = eFrame_DataState_Find;
return -2;
}
}
return -1;
}
/****************************************
@function:帧查找器清空
@param:p--帧句柄
@return:void
@note:
****************************************/
int frame_find_clear(frame_handler *p)
{
if (p == NULL)return -1;
if (p->state == 0)return -1;
p->rx.pos = 0;
p->data_rx.state = eFrame_DataState_Find;
p->data_rx.identify = 0;
p->data_rx.size = 0;
p->data_rx.pbuf = NULL;
return 0;
}
/****************************************
@function:帧接收信息打印
@param:data--接收到的帧数据
@return:void
@note:
****************************************/
void frame_data_printf(Frame_Data_StructDef data)
{
uint32_t i = 0;
dFrame_LOG("Identify=0x%0X size=%d", data.identify, data.size);
for (i = 0; i < data.size; i++)
{
if (i == 0)dFrame_LOG(" data{0x%0x", data.pbuf[i]);
else dFrame_LOG(",0x%0x", data.pbuf[i]);
}
if (i != 0)dFrame_LOG("}\n");
else dFrame_LOG("\n");
}
/****************************************
@function:生成帧格式
@param:identify--帧标识符
size--帧用户数据字节数,不能为0
pbuf--帧缓冲区,生成的帧数据放置在此缓冲区,起始位置pbuf[0]
@return:
NULL:生成失败,参数错误
!NULL:帧用户数据起始地址
@note:
注意生成的帧总长度为:
短帧(identify <= 0x0F):(size+3)字节
长帧(identify > 0x0F):(size+4)字节
此函数会清0缓冲区
****************************************/
uint8_t *frame_format_generate(uint8_t identify, uint32_t size, uint8_t *pbuf)
{
if ((pbuf == NULL) || (size < 1))return NULL;
memset(pbuf, 0, (size + ((identify > 0x0F) ? 4 : 3)));
pbuf[0] = identify;
pbuf[1] = dIdentify_Invert(identify);
if (identify > 0x0F)
{
pbuf[2] = dDataLength_MSB(size);
pbuf[3] = dDataLength_LSB(size);
return &pbuf[4];
}
pbuf[2] = size;
return &pbuf[3];
}
网盘下载:
链接:https://pan.baidu.com/s/1CUGxA0JEIBjF0F6YXyMDnA
提取码:pjgp