一、协议处理的API设计与应用
PCT 通信协议简介
从机常作为执行单元,用于处理一些具体的事务,而主机(如
Windows 、 Linux 、 Android 和 emWin 平台等)常用于与从机进行交互,向
从机发送命令,或处理来自从机的数据,如下图所示。
PCT 通信协议格式
在主机与从机的通信过程中,主机和从机有一个共同的模块,即打包解
包模块( PackUnpack ),该模块遵循某种通信协议。通信协议有很多种,本
实验采用的 PCT 通信协议。 PCT 通信协议的数据包格式。
PCT 通信协议打包过程
第 1 步,准备原始数据,原始数据由模块 ID ( 0x00 ~ 0x7F )、二级ID 、数据 1 、数据 2 、数据 3 、数据 4 、数据 5 和数据 6 组成,如下图所示。其中,模块 ID 的取值范围为 0x00 ~ 0x7F ,二级 ID 和数据的取值范围为0x00 ~ 0xFF 。
第 2 步,依次取出二级 ID 、数据 1~ 数据 6 的最高位 bit7 ,将其存放于数据头的低 7 位,按照从低位到高位的顺序依次存放二级 ID 、数据 1 、数据2 、数据 3 、数据 4 、数据 5 和数据 6 的最高位 bit7 ,如下图所示。
第 3 步,对模块 ID 、数据头、二级 ID 、数据 1 、数据 2 、数据 3 、数据 4 、数据 5 和数据 6 的低 7 位求和,取求和结果的低 7 位,将其存放于校验和的低 7 位。
第 4 步,将数据头、二级 ID 、数据 1 、数据 2 、数据 3 、数据 4 、数据 5 、数据 6 和校验和的最高位置为 1 ,如下图所示。
PCT 通信协议解包过程
第 1 步,准备解包前的数据包,原始数据包由模块 ID 、数据头、二级ID 、数据 1 、数据 2 、数据 3 、数据 4 、数据 5 、数据 6 、校验和组成,如下图所示。其中,模块 ID 的最高位为 0 ,其余字节的最高位均为 1 。
第 2 步,对模块 ID 、数据头、二级 ID 、数据 1 、数据 2 、数据 3 、数据 4 、数据 5 和数据 6 的低 7 位求和,如下图所示,取求和结果的低 7 位与数据包的校验和低 7 位对比,如果两个值的结果相等,则说明校验正确。
第 3 步,数据头的最低位 bit0 与二级 ID 的低 7 位拼接之后作为最终的二级 ID ,数据头的 bit1 与数据 1 的低 7 位拼接之后作为最终的数据 1 ,数据头的 bit2 与数据 2 的低 7 位拼接之后作为最终的数据 2 ,以此类推。
第 4 步,下图所示即为解包后的结果,由模块 ID 、二级 ID 、数据 1 、数据 2 、数据 3 、数据 4 、数据 5 和数据 6 组成。其中,模块 ID 的取值范围为 0x00 ~ 0x7F ,二级 ID 和数据的取值范围为 0x00 ~ 0xFF 。
/*********************************************************************************************************
* 模块名称: PackUnpack.c
* 摘 要: PCT协议的打包解包模块
* 内 容:
* (1)数据包格式:模块ID+数据头+二级ID+数据1...数据6+校验和
* 数据包都有校验和,由1个字节模块ID、1个字节数据头,1个字节二级ID,6个字节数据
* 和1个字节校验和构成,因此,数据包长度为10个字节,数据包的数据容量为6个
* (2)模块ID的最高位BIT7为0,数据头、二级ID、数据以及校验和的最高位为1,所有包的数据头依次包含
* 数据字节的最高位,如数据头的BIT0为二级ID的BIT7,数据头的BIT1为数据1的BIT7,数据头的BIT2
* 为数据2的BIT7,数据头的BIT6为数据6的BIT7
* (3)参数板协议的简易版
* 注 意:
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "PackUnpack.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
/*********************************************************************************************************
* 内部变量
*********************************************************************************************************/
//以下四个参数在打包和解包的时候使用
static StructPackType s_ptPack; //数据包,1字节模块ID,1字节数据头,1字节二级ID,6字节数据,1字节校验和
static u8 s_iPackLen; //数据包长度,用来判断数据长度是否为10,不为10为错误包
static u8 s_iGotPackId; //获取到ID的标志
static u8 s_iRestByteNum; //剩余字节数
/*********************************************************************************************************
* 内部函数声明
*********************************************************************************************************/
static void PackWithCheckSum(u8* pPack); //带校验和的数据打包
static u8 UnpackWithCheckSum(u8* pPack); //带校验和的数据解包
/*********************************************************************************************************
* 内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称: PackWithCheckSum
* 函数功能: 带校验和的数据打包
* 输入参数: 待打包的数据pPack的首地址
* 输出参数: 打包好的数据pPack的首地址
* 返 回 值: void
* 创建日期: 2021年03月01日
* 注 意: 如数据头的BIT0为二级ID的BIT7,数据头的BIT1为数据1的BIT7,数据头的BIT2为数据2的BIT7,数据头的
* BIT6为数据6的BIT7
*********************************************************************************************************/
static void PackWithCheckSum(u8* pPack)
{
u8 i;
u8 dataHead; //数据头,在数据包的第2个位置,即ModuleID之后
u8 checkSum; //校验和,在数据包的最后一个位置
checkSum = *(pPack); //取出ModuleID,加到校验和
dataHead = 0; //数据头清零
for(i = 8; i > 1; i --)
{
//数据头左移,后面数据的最高位位于dataHead的靠左,如数据6的最高位位于dataHead的BIT6
dataHead <<= 1;
//取出原始数据的最高位,与dataHead相或
dataHead |= (*(pPack + i) & 0x80) >> 7;
//对数据进行最高位置1操作
*(pPack + i) = *(pPack + i) | 0x80;
//数据加到校验和
checkSum += *(pPack+i);
}
//数据头在数据包的第二个位置,仅次于包头,数据头的最高位也要置为1
*(pPack+1) = dataHead | 0x80;
//将数据头加到校验和
checkSum += *(pPack+1);
//校验和的最高位也要置为1
*(pPack+9) = checkSum | 0x80;
}
/*********************************************************************************************************
* 函数名称: UnpackWithCheckSum
* 函数功能: 带校验和的数据解包
* 输入参数: 待解包的数据pPack的首地址,打包后的数据长度
* 输出参数: 解包好的数据pPack的首地址
* 返 回 值: 0-解包不成功,1-解包成功
* 创建日期: 2021年03月01日
* 注 意:
*********************************************************************************************************/
static u8 UnpackWithCheckSum(u8* pPack)
{
u8 i;
u8 dataHead; //数据头,在数据包的第2个位置,即ModuleID之后
u8 checkSum; //校验和,在数据包的最后一个位置
checkSum = *(pPack); //取出模块ID,加到校验和
dataHead = *(pPack + 1); //取出数据包的数据头,赋给dataHead
checkSum += dataHead; //将数据头加到校验和
for(i = 2; i < 9; i++)
{
checkSum += *(pPack + i); //将数据依次加到校验和
//还原二级ID和6位数据
*(pPack + i) = (*(pPack + i) & 0x7f) | ((dataHead & 0x1) << 7);
dataHead >>= 1; //数据头右移一位
}
//判断模块ID、数据头、二级ID和数据求和的结果(低七位)是否与校验和的低七位相等,如果不等返回0
if((checkSum & 0x7f ) != ((*(pPack + 9)) & 0x7f))
{
return 0;
}
return 1;
}
/*********************************************************************************************************
*