这儿以串口作为传输前言,介绍下怎样来发送接纳一个完好的数据包。进程涉及到封包与解包。规划一个杰出的包传输机制很有利于数据传输的稳定性以及正确性。串口仅仅一种传输前言,这种包机制一起也能够用于SPI,I2C的总线下的数据传输。在单片机通讯体系(多机通讯以及PC与单片机通讯)中,是很常见的问题。
一、依据帧头帧尾或许帧长检测一个数据帧
1、帧头+数据+校验+帧尾
这是一个典型的计划,可是对帧头与帧尾在规划的时分都要留意,也便是说帧头、帧尾不能在所传输的数据域中呈现,一旦呈现或许就被误判。假如用中止来接纳的话,程序根本能够这么完结:
unsigned char recstatu;//表明是否处于一个正在接纳数据包的状况
unsigned charccnt; //计数
unsigned char packerflag;//是否接纳到一个完好的数据包标志
unsigned charrxbuf[100];//接纳数据的缓冲区
void UartHandler()
{
unsigned char tmpch;
tmpch = UARTRBR;
if(tmpch 是包头) //检测是否是包头
{
recstatu = 1;
ccnt = 0 ;
packerflag = 0;
return ;
}
if(tmpch是包尾) //检测是否是包尾
{
recstatu = 0;
packerflag = 1; //用于奉告体系现已接纳到一个完好的数据包
return ;
}
if(recstatu ==1) //是否处于接纳数据包状况
{
rxbuf[ccnt++] = tmpch;
}
}
上面也便是接纳一个数据包,可是再次提示,包头和包尾不能在数据域中呈现,一旦呈现将会呈现误判。别的一个。数据的校验算法是很必要的,在数据传输中,由于遭到搅扰,很不免有时呈现数据过错,加上校验码可在发现数据传输过错时,能够要求数据的另一方从头发送,或是进行简略的丢掉处理。校验算法纷歧定要很杂乱,一般的加和,异或,以及循环冗余都是能够的。我上面的接纳程序在接纳数据时,现已将包头和包尾去掉,这些能够依据自己的需求加上,关键是要了解原理。
上述包协议呈现了以下的几种变种:
1.1 帧头+数据长度+数据+校验值
1.2包长+校验值
上面两种其实都是知道了数据包的长度,然后依据接纳字节的长度来判别一个完好的数据包。例如,界说一个数据包的长度为256字节,那咱们就能够一向接纳,直到接纳到256个字节,就以为是一个数据包。可是,会不会存在问题呢?比方说从机向主机发送数据,发送了一半,掉电,重启,开机后持续发送,这很明显接纳到的数据就不对了,所以此刻很有必要界说一个超限时刻,比方咱们能够保护下面这样的一个结构体。
struct uartrd{
char rd[ 256];
unsigned int timeout;
}
成员变量rd用来寄存接纳到的数据字节;成员变量timeout用来保护超时值,这儿首要评论这个。这个数值怎样保护呢,能够用一个定时器来保护,以能够放在一般的滴答中止里边来保护,也能够依据体系运转一条指令的周期,在自己的循环中来保护,给其设置个初值,比方说100,当有第一个数据到来今后,timeout在指定的时刻就会削减1,削减到0时,就以为超时,不管是否接纳到满足的数据,都应该扔掉。
二、依据接纳超时来判别一个数据包
2.1 数据+校验
中心思维是假如在到达必定的时刻没有接遭到数据,就以为数据包接纳完结。modbus协议里就有经过时刻距离来判别帧完毕的。详细完结是要运用一个定时器,在接纳到第一个数据时分,敞开定时器,在接纳到一个数据时分,就将定时器清零,让定时器从头开始计时,假如设定的超时时刻到(超时时刻长度能够设置为5个正常接纳的周期),则以为在这一段时刻内没有接遭到新的数据,就以为接纳到一个完好的数据包了。流程大体如下图所示:
进行一个简略的小的总结,上述几种办法都仍是较为常用的,在详细的完结上,能够依据详细的实际情况,规划出详细的通讯协议。数据校验位,有时分感觉不出来其重要性,可是必定要加上,对数据进行一个相关的验证仍是必要的。现在很在MCU都带有FIFO,DMA等功能,所以有时分利用上这些特性,能够规划出更好的通讯方法。有的人问在承受串口数据时分是应该中止一次接纳一个,仍是进入中止后接纳一段数据呢,我以为应该中止接纳一个,由于CPU是很快的,至少关于串口是这样,在承受每个数据的距离期间,处理器仍是能够做些其他作业的。这是在裸机下的模型。在多线程中,那就能够直接树立一个数据接纳线程。