先让我们来了解一下“帧”的概念。
“帧”的名词解释:
“帧”:形声字,形旁“巾”,声旁“贞”;量词,一幅字画叫一帧。
相关名词:
Frame:帧;
FCS:Frame Check Sequence,帧校验系列;
ED:End Delimiter,结束分界符;
数据帧:
数据链路层的协议数据(protocol data unit)单元。数据链路层的主要职责是控制相邻系统之间的物理链路,它在传送“比特”信息的基础上,在相邻节点间保证可靠的数据通信。为了保证数据的可靠传输,把用户数据封装成帧。在数据通信领域所说的数据帧是数据在网络上传输时的一个数据单元!
一“帧”数据由帧头、帧数据、帧尾组成,而每部分又由若干字节组成。
帧头:包括起始字节/起始符(侦测到该数据,就表示后面的数据是有效的,就可以接受数据了)和地址(接收方主机/从机物理地址的定位以及其它网络信息)。
帧数据:一个数据体,包括数据长度、控制字、数据等。
帧尾:包括帧校验数据和帧结束符。帧校验数据是对帧数据进行校验的结果,采用的校验方法有很多:CRC循环冗余校验、LRC纵向冗余校验、PC奇偶效验、SC累加和校验等。帧结束符一般为CR(回车符)或ED(END,结束),当然在自定的通信协议中也可以采用其它的字符;帧结束符表示这一帧数据已经发送完毕,等待下一帧数据发送/接受。
说明:也有把数据长度放在地址前面的(例如丹佛斯/海利普变频器的FC通信协议),这样帧头就包括了起始符和数据长度,而帧数据就包括了地址、控制字和数据。
为确保所有参与通信的主体(电脑、PLC、变频器、仪器仪表、其它设备等)能够解释数据帧中的数据,所有参与通信的主体均使用相同的通讯协议。
根据信号传递方向的不同,可以分为发送帧和应答帧。
互联网协议:
互联网使用的通讯协议简称IP,即互联网协议。IP数据体由两部分组成:数据体头部和数据体的数据区。数据体头部包括IP源地址和IP目标地址,以及其它信息。数据体的数据区包括用户数据协议(UDP),传输控制协议(TCP),还有数据包的其它信息。这些数据包都含有附加的进程信息以及实际数据。
差错检测和纠正
??????? 物理过程所引起的差错,在某些介质中通常是突发的而不是单个的。网络设计者已经研究出两种基本的策略来处理差错。一种方法是在每一个要发送的数据块上附加足够的冗余信息,使接收方能够推导出已发出的字符应该是什么。另一种方法是只加足够的冗余位,使接收方知道差错发生,但不知道是什么样的差错,然后要求接收方重新进行传输。前者的策略是使用纠错码(error-correcting code),而后者则使用检错码(error-detecting code)。
1.纠错码
??????? 在了解纠错码之前,先了解一个基本概念:海明距离。通常一帧包括m个数据(报文)位和r个冗余位或者校验位。设整个长度为n(即n=m+r),则此长度为n的单元通常被称作n位码字(codeword)。
给出任意两个码字,如10001001和10110001,可以确定它们有多少个对应位不同。在此例中有3位不同。为了确定有多少位不同,只须对两个码字做异或运算,然后计算结果中1的个数。两个码字中不同位的个数,称为海明距离(Hamming Distance)。其重要性在于,假如两个码字具有海明距离d,则需要d个位差错才能将其中一个码字转换成另一个。
??????? 一种编码的校验和纠错能力取决于它的海明距离。为检测出d比特错,需要使用d+1的编码;因为d个单比特错决不可能将一个有效的码字转变成另一个有效的码字。当接收方看到无效的码字,它纠能明白发生传输错误。同样,为了纠正d比特错,必须使用距离为2d+1的编码,这是因为有效码字的距离远到即使发生d个变化,这个发生了变化的码字仍然比其它码字都接近原始码字。作为纠错码的一个简单例子,考虑如下只有4个有效码字的代码:
0000000000、0000011111、1111100000和1111111111
??????? 这种代码的距离为5,也就是说,它能纠正双比特错。假如码字0000000111到达后,接收方知道原始码字应该为0000011111。但是,如果出现了三位错,而将0000000000变成了0000000111,则差错将不能正确地纠正。
2.检错码
??????? 检错码有时也用于数据传输。例如,当信道为单工方式,无法要求重传的情况下,大多数采用检错码加重传的方式。
假设信道的出错是孤立的,信道的误码率为每位10-6。数据块的大小为100位。为1000位的数据块纠错,需要10个校验位;1兆的数据位将需要10000个校验位。若只需要检测一个数据块的一位错误,每块一个奇偶位就够了。每传送1000个数据块就需要额外传送一个数据块。错误检错+重传方式的整个开销,仅仅是每兆数据只有2001位,而海明码为10000位。
??????? 假若在一个块上只加一个奇偶位,那么块的长的突发错误的检测率就会很糟糕,能够检测到差错的概率只有0.5,这是难以接受的。改进的措施可以采取将每个数据块组成n位宽k行高的长方形矩阵进行发送。对每一列的奇偶位分别进行计算,附加在矩阵上,作为矩阵的最后一行,然后按行进行发送。当块到达后,接收方检测所有的奇偶位。如果其中任何一个出错了,就需要重新传送整个块。
??????? 这种方法能够检测到单个程度为n的突发错误,因为每一列只有一位改变了。然而如果第一位变反,最后一位变反,且所有其它位都正确,则长度为n+1的突发差错将不会被检测到。假如一个块被一个长的突发差错或者短的突发差错所破坏,n列中的每一列的奇偶值碰巧正确的概率为0.5,那么这个出错块被接受的概率不应该是2-n。
??????? 虽然上述方法有时已经足够了,但是在实践中,另一种方法正在被广泛使用,即多项式编码(也叫循环冗余码,或CRC码)。多项式编码是基于将位串看成是系数为0或1的多项式,一个k位帧可以看成是从Xk-1到X0的k-1次多项式的系数序列。如果采用多项式编码的方式,发送方和接收方必须事先商定一个生成多项式G(x),生成多项式的高位和低位必须是1。要计算m位的帧M(x)的校验和,生成多项式必须比该多项式短。基本思想是:将校验和加在帧的末尾,使这个带校验和的帧的多项式能被G(x)除尽。当接收方收到带校验和的帧时,用G(x)去除它,如果有余数,则传输出错。
计算校验和的算法如下:
①.设G(x)为r阶,在帧的末尾附加r个零,使帧为m+r位,则相应的多项式是XrM(x)。
②.按模2除法用对应于G(x)的位串去除对应于XrM(x)的位串。
③.按模2减法从对应于XrM(x)的位串中减去余数。结果就是要传送带校验和的帧,叫多项式T(x)。
以下三个多项式已经成为国际标准:
crc -12 = x^12+x^11+x^3+x^2+x+1
crc -16 = x^16+x^15+x^2+1
crc -ccitt = x^16+x^12+x^5+1
??????? 这三个多项式都包含了x+1作为基本因子。当字符串长度为6位时,使用CRC-12;其余两个多项式用在字符串长度为8位的情况下。一个16位的校验和,如CRC-16或CRC-CCITT,可以捕捉到所有的单位差错和双位差错,所有奇数位数的差错,所有长度小于或等于16位的突发差错,99.997%的长度为17位的突发差错,以及99.998%的长度为18位或多于18位的突发差错。
??????? 虽然计算校验和的计算方法看起来相当复杂,但Peterson和Brown已经给出了一种简单的移位寄存器电路来进行计算,并用硬件来完成对校验和的校验。在实际应用中,几乎都在使用此硬件。
一、CRC循环冗余校验
CRC:Cyclical Redundancy Check,循环冗余校验,简称CRC校验。
下面以实例对这种校验方法做个说明。
台达VFD-M系列变频器的Modbus RTU模式採用CRC偵誤值,CRC偵誤值以下列步驟計算:
步驟1:載入一個內容為FFFFH之16-bit寄存器 (稱為CRC寄存器)。
步驟2:將命令訊息第一個位元組與16-bit CRC寄存器的低次位元組進行Exclusive OR運算(异或运算),並將結果存回CRC 寄存器。
步驟3:將CRC寄存器之內容向右移1 bit,最左bit填入0,檢查CRC寄存器最低位元的值。
步驟4:若CRC寄存器的最低位元為0,則重覆步驟3;否則將CRC寄存器與A001H進行Exclusive OR運算。
步驟5:重覆步驟3及步驟4,直到CRC寄存器之內容已被右移了8 bits。此時,該位元組已完成處理。
步驟6:對命令訊息下一個位元組重覆重覆步驟2至步驟5,直到所有位元組皆完成處理,CRC寄存器的最後內容即是CRC值。當在命令訊息中傳遞CRC值時,低位元組須與高位元組交換順序,亦即,低位元組將先被傳送。
例如,從地址為01H之交流電機驅動器的2102H地址讀取2個字,從ADR至資料數之最後一位元組所計算出之CRC寄存器之最後內容為F76FH,則其命令訊息如下所示,其中6FH於F7H之前傳送。
命令訊息
ADR 01H
CMD 03H
啟始資料地址 21H
02H
資料數(以word 計算) 00H
02H
CRC CHK Low 6FH
CRC CHK High F7H
下例乃以C語言產生CRC值。此函數(function)需要兩個參數:Unsigned char* data:指向訊息緩衝區(buffer)之指標;Unsigned char length:訊息緩衝區中之位元組數目;此函數將傳回unsigned integer型態之CRC值。
unsigned int crc_chk(unsigned char* data, unsigned char length){
int j;
unsigned int reg_crc=0xFFFF;
while(length--){
reg_crc ^= *data++;
for(j=0;j<8;j++){
if(reg_crc & 0x01){ /* LSB(b0)=1 */
reg_crc=(reg_crc>>1) ^ 0xA001;
}else{
reg_crc=reg_crc >>1;
}
}
}
return reg_crc;
}
二、LRC纵向冗余校验
LRC:Longitudinal Redundancy Check,纵向冗余校验,简称LRC校验或纵向校验。
下面以实例对这种校验方法做个说明。
台达VFD-M系列变频器的Modbus ASCII通信模式採用LRC偵誤值。LRC偵誤值乃是將ADR1至最後一個資料內容加總,得到之結果以十进制的256為單位,超出之部分去除(例如得到之結果為十六進位之128H則只取28H(减去了100H,就是减去了256D)),然後計算二次反補後得到之結果即為LRC偵誤值。例如:從地址為01H之交流電機驅動器的0401H地址讀取1個字。
STX ‘:’
ADR 1 ‘0’
ADR 0 ‘1’
CMD 1 ‘0’
CMD 0 ‘3’
啟始資料地址‘0’
‘4’
‘0’
‘1’
資料數 ‘0’
‘0’
‘0’
‘1’
LRC CHK 1 ‘F’
LRC CHK 0 ‘6’
END 1 CR
END 0 LF
01H+03H+04H+01H+00H+01H=0AH, 0AH的二次反補為F6H。
二次反补:取反然后加1B或1H(1B=1H)。
计算方法1:
取反后加1B:把数据转换为二进制,每位取反后再加1B。例如:0AH=00001010B,按位取反后得11110101B,11110101B+1B=11110110B=F6H,0AH的二次反补就是F6H。
取反后加1H:把数据转换为二进制,每位取反后再加1H。例如:0AH=00001010B,按位取反后得11110101B=F5H,F5H+1H=F6H,0AH的二次反补就是F6H。
计算方法2:
有个简单算法就是:这个十六进制值有几位数,就把高于这个位数的最小值减去这个值。如果16进制数有2位,那么高于2位的最小值就是100H,用100H减去这个数就是其二次反补。
??????? 实际上,该方法的原理和方法1相同:以2位16进制数为例,FFH减去那个数就是把那个数取反(FFH的数据为全1,减去那个数的结果就是原来1的位数变为0,原来0的位数变为1),而FFH+1H=100H。所以取反然后加一就等于100H减去这个数。
例如:0AH的二次反补就是:100H-0AH=F6H
五、S-XOR加总异或校验
SUM XOR Check,加总异或校验,也称之为异或校验和、累加异或校验和。在理解加总异或校验之前,我们先来了解一下什么是异或运算。
异或运算:参与运算的两个数各对应的二进位相异或,当两对应的二进位相异时,结果为1。
异或的运算方法是一个二进制运算:
1^1=0
0^0=0
1^0=1
0^1=1
两者相等为0,不等为1.
这样我们发现交换两个整数的值时可以不用第三个参数。
如a=11,b=9.以下是二进制
a=a^b=1011^1001=0010;
b=b^a=1001^0010=1011;
a=a^b=0010^1011=1001;
这样一来a=9,b=13了。