标签: 无标签
仪表的现场总线通讯--modbus(4)
<!--[if !supportLists]-->1 <!--[endif]-->数据传送模式
MODBUS允许两种传送模式:ASCII模式和RTU模式。传送模式由主机决定。在ASCII模式,消息由7位ASCII字符组成。在RTU模式,消息由8位二进制字符组成。MODBUS拥有几种不同的错误校验,ASCII模式使用LRC校验,RTU模式使用CRC校验。
下表给出ASCII模式和RTU模式的比较:
|
ASCII模式(7bits)
|
RTU模式(8bits)
|
代码系统
|
十六进制(ASCII字符0-9,A-F)
|
8位二进制
|
位个数
|
起始位
|
1
|
1
|
数据位
|
7
|
8
|
校验位
|
1
|
1
|
停止位
|
1或2
|
1或2
|
错误校验
|
LRC
|
CRC
|
<!--[if !supportLists]-->1.1 <!--[endif]-->ASCII模式消息帧
在ASCII模式,每个消息帧都包括一个起始符、一个地址栏、一个功能栏、一个数据栏、一个校验栏和一个结束符。
冒号符(:)作为起始符,回车符(CR)和换行符(LF)是结束符。
ASCII模式允许在两个字符之间有最长1秒的时间间隔。
下图举例说明一个ASCII模式消息帧:
帧起始 |
地址栏 |
功能栏 |
数据栏 |
校验栏 |
帧结束 |
准备就绪 |
2字符模式 |
: |
2字符 |
2字符 |
N个4字符 |
2字符 |
回车 |
换行 |
16位模式 |
: |
16位 |
16位 |
N个16位 |
16位 |
回车 |
换行 |
<!--[if !supportLists]-->1.2 <!--[endif]-->RTU模式消息帧
在RTU模式,每个消息帧都包括一个地址栏、一个功能栏、一个数据栏和一个校验栏。
一帧消息传送完毕后,必须等待可发送3?个字符的时间,这一时间间隔用来同步MODBUS RTU通讯。
下图举例说明一个RTU模式消息帧:
流逝时间 |
地址栏 |
功能栏 |
数据栏 |
校验栏 |
流逝时间 |
大于发送3?个字符的时间 |
(8位) 1字符 |
(8位) 1字符 |
(8位) 1字符 |
(8位) 1字符 |
大于发送3?个字符的时间 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!--[if !supportLists]-->1.3 <!--[endif]-->错误检查
错误检查包括硬件奇偶校验、ASCII模式的LRC校验和RTU模式的CRC校验.
<!--[if !supportLists]-->1.3.1 <!--[endif]-->硬件奇偶校验
偶校验
数据位与校验位的和为偶数。
奇校验
数据位与校验位的和为奇数。
<!--[if !supportLists]-->1.3.2 <!--[endif]-->ASCII模式的LRC校验
LRC校验数与ASCII模式消息帧的地址栏、功能栏、数据栏的总和为零。
在计算时,不包括起始符冒号(:)和结束符回车(CR)与换行(LF)。
下面给出LRC的计算程序:
static unsigned char LRC(auchMsg, usDataLen)
unsigned char *auchMsg ; /* message to calculate LRC upon */
unsigned short usDataLen ; /* quantity of bytes in message */
{
unsigned char uchLRC = 0 ; /* LRC char initialized */
while (usDataLen––) /* pass through message buffer */
uchLRC += *auchMsg++ ; /* add buffer byte without carry */
return ((unsigned char)(–((char)uchLRC))) ; /* return twos complement */
}
<!--[if !supportLists]-->1.3.3 <!--[endif]-->RTU模式的CRC校验
产生CRC校验值的过程
<!--[if !supportLists]-->1、 <!--[endif]-->调用一个16位寄存器,写入十六进制数FFFF。我们称这一寄存器为CRC寄存器。
<!--[if !supportLists]-->2、 <!--[endif]-->异或消息帧的第一个8位数,结果存在CRC寄存器。
<!--[if !supportLists]-->3、 <!--[endif]-->将CRC寄存器右移一位,最高位(MSB)填零,然后检查移出位。
<!--[if !supportLists]-->4、 <!--[endif]-->如果移出位为0,则重复第3步(继续右移);
如果移出位为1,CRC寄存器异或十六进制数A0001;
<!--[if !supportLists]-->5、 <!--[endif]-->重复步骤3、4直到8次右移结束。
<!--[if !supportLists]-->6、 <!--[endif]-->异或消息帧的下一个8位数,结果存在CRC寄存器。
<!--[if !supportLists]-->7、 <!--[endif]-->重复步骤3~6直到消息帧的所有数据被处理。
<!--[if !supportLists]-->8、 <!--[endif]-->最后得到的2字节数(16位)就是CRC校验值。
下面给出CRC的计算程序:
//***CRC Calculation for MODBUS Protocol for VC++***//
//数组snd为地址等传输字节,num为字节数//
unsigned int mb_crc(BYTE *snd,int num)
{ int i,j;
unsigned int c,crc=0xFFFF
for (i=0;i
{ c=str[i] & 0x00FF;
crc^=c;
for(j=0,j<8,j++)
{ if (crc & 0x0001)
{crc>>=1;crc^=0xA001;}
else crc>>=1
}
}
return(crc);
}