以下分别是两种串口协议软件实现源代码、逻辑图、逻辑伪代码,针对实现进行讨论:
一、模型A的串口协议及解析
1.1 串口协议
帧头 |
帧计数 |
帧标识 |
有效数据区 |
填充字节 |
CRC校验和 |
数据区长度 |
帧尾 |
0x5A54 |
1Byte |
0x00 |
48Byte |
0x00 |
2Byte |
0x32 |
0x5AFE |
1.2 解析源代码
void appRS422FrameMsg(unsigned char *msgBuffer)
{
int i;
unsigned short checkSum;
unsigned int recvCheckSum;
while(1)
{
UartRecData(RS422_CHANNEL,(char *)(msgBuffer),1); /*采集串口数据帧头*/
if((msgBuffer)[0]!=0x5A)
continue;
UartRecData(RS422_CHANNEL,(char *)(msgBuffer)+1,1); /*采集串口数据帧头*/
if((msgBuffer)[1]!=0x54)
continue;
for(i=0;i<RS422_FRAME_SIZE-2;i++) /*去掉帧头,获取剩余帧数据*/
{
if(!UartRecData(RS422_CHANNEL, (char*)(msgBuffer)+2+i, 1))
{
LOG_ERR(" appRS422FrameMsg error!");
}
}
if((msgBuffer)[RS422_FRAME_SIZE-1] != 0xFE || (msgBuffer)[RS422_FRAME_SIZE-2] != 0x5A || (msgBuffer)[RS422_FRAME_SIZE-3] !=(RS422_FRAME_SIZE-8))
continue; /*判断帧尾*/
/*CRC校验,使用时必须进行初始化处理*/
checkSum=GetCheckSum((msgBuffer)+4,(RS422_FRAME_SIZE-10)); /*计算数据区的校验和*/
recvCheckSum=*((unsigned short*)((msgBuffer)+RS422_FRAME_SIZE-5)); /*获取串口帧中的校验和*/
if(checkSum != recvCheckSum)
{
LOG_ERR(" appRS422FrameMsg CRC checkSum error.");
continue;
}
return;
}
}
1.3 逻辑图
1.4 逻辑图伪代码
@startuml
title RS422Process.c\n <b>appRS422FrameMsg(unsigned char *msgBuffer)</b>
start
repeat
:UartRecData();
if((msgBuffer)[0]==0x5A?) then ( **NO**)
else (**YES**)
:UartRecData();
if((msgBuffer)[0]==0x54?) then ( **NO**)
else (**YES**)
'group collect frame data excpte head
partition #lightGreen "**collect frame data excpte head**"{
:i=0;
repeat
if(!UartRecData()) then (**YES**)
:LOG_ERR(" appRS422FrameMsg error!");
else( **NO**)
endif
repeat while(i++<RS422_FRAME_SIZE-2)
'end group
}
if(FRAME[END]!= 0xFE || FRAME[END-1] != 0x5A || FRAME lens!=(RS422_FRAME_SIZE-8)) then(**NO**)
else (**YES**)
:GetCheckSum();
:recvCheckSum;
if(checkSum != recvCheckSum)
:LOG_ERR(" appRS422FrameMsg CRC checkSum error.");
else
endif
stop
endif
endif
endif
note left
//FRAME[END]!= 0xFE || FRAME[END-1] != 0x5A || FRAME lens!=(RS422_FRAME_SIZE-8) equ A//
//checkSum != recvCheckSum equ B//
end note
repeat while(msgBuffer)[0]!=0x5A? ||msgBuffer)[0]!=0x54? ||A ||B)
@enduml
二、模型B的串口协议及解析
2.1 串口协议
字节号 |
意义 |
说明 |
1 |
0x5A |
帧头 |
2 |
0x54 |
帧头 |
3 |
帧类型 |
数据区 |
4 |
帧序号 |
|
5~n |
帧数据 |
|
n+1 |
0x00 |
校验和 |
n+2 |
累加和 |
|
n+3 |
数据区长度 |
数据区长度 |
n+4 |
0x5A |
帧尾 |
n+5 |
0xFE |
帧尾 |
2.2 解析源代码
int MA_RS422RcvDataCallBack(int chl,unsigned char* buff,int num)
{
#if 1
int i=0,beginI,endI,k,d,isFlag,inFlag,cnt,datak=0;
int length=0,readmax=0,transi=0;
unsigned char temp[2];
memset(temp,0,sizeof(temp));
unsigned short checkSum;
short tempRS422Backinfo;
inFlag=0;/*判断全缓存区是否找到帧头,一旦找到帧头inFlag赋值1,否者将num长度数据区丢弃*/
for (i = 0; i < num; ++i) {
/*-------同步过程,判断是否有帧头帧尾-------------*/
if((buff[i] == 0x5a) && (buff[i+1] == 0x54))
{
inFlag=1; /*表示找到帧头*/
beginI = i; /*帧头位置*/
endI = i+1; /*帧长度位置 */
isFlag = 0; /*找到合格帧头帧尾标志位,0表示没有找到,1表示找到 */
readmax=min(endI+256,num); /*预处理,每次最多处理256字节缓存区*/
while((endI++) && (endI<readmax))
{
/*寻找帧尾:排除转义情况*/
if((buff[endI] != 0x00) && (buff[endI+1] == 0x5a) && (buff[endI+2] == 0xfe))
{
isFlag = 1; /*找到帧尾*/
break;
}
}
if(isFlag==1)
{
/*录入数据*/
if(startRS422RecvLog) /*记录所找到帧的原始帧数据*/
{
LW_InputData(buff + beginI, endI+3-beginI); /*帧起始位beginI,帧长度endI+3-beginI=endI-beginI+1+2*/
}
/*修改已处理的数据长度*/
i+=endI-beginI+3; /*endI-beginI+1+2 表示一帧长度*/
length = endI+2+1; /*返回已经处理的数据区长度*/
/*---------校验过程,判断数据长度和校验和---------*/
d = (int)buff[endI]; /*有效数据字节数*/
if(d<143) /*判断数据长度是否少,如果数据区长度小于标准143字节,不处理*/
{
continue;
}
if((endI-beginI-4)!=d) /*判断实际数据长度是否与帧内标定的数据长度一致,不一致不处理,endI-beginI-4=endI-beginI+1-3-2,即去掉帧头和校验位*/
{
continue;
}
/*对422下行帧累加和进行校验*/
checkSum = 0;
for(cnt=0; cnt<buff[endI]; cnt++)
{
checkSum += buff[beginI+cnt+2];
}
memcpy(temp,&checkSum,sizeof(short));
if(buff[endI-1] != temp[0])
{
continue;
}
/*------------去除转义字符(与143字节不符则抛弃)------------*/
for(k=0;k<d;k++)
{
if((buff[k+beginI+2]==0x00) && (buff[k+beginI+3]==0x5a) && (buff[k+beginI+4]==0xfe))
{
transi++; /*出现转义字符累加*/
continue;
}
RS422DownInfo.Data[datak] = buff[k+beginI+2]; /*转义后的数据填入串口结构体变量*/
datak++; /*datak是串口结构体中Data[143]的索引*/
if(datak>=143) /*1)当datak>=143时,表明原数据区中去除转义后的数据长度不对,退出转义过程,该帧将在后面丢弃不处理*/
{
break;
}
}
if((143+transi)<d) /*与上一条1)联合判断是否有非转义字符造成的数据长度过长,*/
{
continue;
}
transi=0;
datak=0;
u_rs422res_clock = 0;
/*--------数据解析并存入Udp发送的结构体--------*/
do something;
}
else
{
length=beginI;
}
}
}
}
if(0==inFlag)
{
length=num; /*表示扫描全数据区,没有找到帧头,全数据区丢弃*/
}
return length;
#endif
}
2.3 逻辑图
2 .4 逻辑图伪代码
@startuml
title MainApp.c\n <b>int MA_RS422RcvDataCallBack(int chl,unsigned char* buff,int num)b>
start
if(chl == RS422RecChl?) then ( **YES**)
:i=0;
repeat
if((buff[i] == 0x5a) && (buff[i+1] == 0x54)) then ( **YES**)
:readmax=min(endI+256,num);
partition #lightGreen "**collect frame data excpte head**"{
while((endI++) && (endI<readmax)?)
if((buff[endI] != 0x00) && (buff[endI+1] == 0x5a) && (buff[endI+2] == 0xfe)) then ( **YES**)
:isFlag = 1;
break
else (**NO**)
endif
endwhile
}
if(isFlag==1?) then ( **YES**)
if(startRS422RecvLog) then ( **YES**)
:LW_InputData(buff + beginI, endI+3-beginI);
else (**NO**)
endif
:i+=endI-beginI+3;
:length = endI+2+1;
:d = (int)buff[endI];
if(d<143 || (endI-beginI-4)!=d ?) then ( **YES**)
else (**NO**)
partition #lightGreen "**cac check sum**"{
:cnt=0;
repeat
:checkSum += buff[beginI+cnt+2];
repeat while(cnt++<buff[endI]?)
}
if(buff[endI-1] != temp[0] ?) then ( **YES**)
else (**NO**)
partition #lightGreen "**cal ESC 0x00**"{
:k=0;
repeat
if(A ?) then ( **YES**)
:transi++;
else (**NO**)
:RS422DownInfo.Data[datak] = buff[k+beginI+2];
if(datak++>=143?) then( **YES**)
break
else (**NO**)
endif
endif
repeat while(k++<d?)
if((143+transi)<d?) then( **YES**)
else (**NO**)
:udp send data process;
endif
}
endif
endif
else
:length=beginI;
endif
else (**NO**)
endif
repeat while(i++<num )
else (**NO**)
endif
if(0==inFlag?) then ( **YES**)
:length=num;
else (** NO**)
endif
:return length;
stop
@enduml
三、针对两种串口协议实现逻辑进行讨论!
1)可以提出指出以上设计问、编码问题、逻辑图问题等等,并给出优化方案,给出源代码和逻辑图。
2)可以提出自己的实现方法并回复源代码和逻辑图。
版权声明:本文为weixin_39728079原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。