&nb, sp;, ; ,
以读取6路温度数据(下表中红色粗体)为例。通信前请先确认模块的Modbus地址,通讯配置默认为:9600,N,8,1(9600bps,无校验位,8个数据位,一个停止位)
举例:读寄存器0x0000H-0x0005H,即六路温度测量值(负值按补码表示)
测量值寄存器:
寄存器 |
功能号 |
功能说明 |
读/写 |
0x0000 |
04 |
通道0测量值 |
读 |
0x0001 |
04 |
通道1测量值 |
读 |
0x0002 |
04 |
通道2测量值 |
读 |
0x0003 |
04 |
通道3测量值 |
读 |
0x0004 |
04 |
通道4测量值 |
读 |
0x0005 |
04 |
通道5测量值 |
读 |
Modbus-RTU数据格式
Modbus协议RTU 模式是一种二进制协议,要求每一帧的起始和结束都以至少3.5个字符为间隔。由于收到的每个字节都有可能成为一帧数据的最后一个字节,因此,每接收一个字节,关闭上一个已经开启的3.5个字符时间和1.5个字符时间的定时器,处理完接收到得数据后再次启动3.5个字符时间和1.5个字符时间的定时器,以检测该帧数据的结束。
请求:01 04 00 00 00 06 70 08(8个字节)
从机地址 |
1字节 |
0x01 |
功能号 |
1字节 |
0x04 |
起始地址 |
2字节 |
0x0000 |
寄存器数量 |
2字节 |
0x0006 |
校验 |
2字节 |
0x7008 |
响应:01 04 0C 00 63 80 00 80 00 80 00 80 00 80 00 3C BA(17个字节)
从机地址 |
1字节 |
0x01 |
功能号 |
1字节 |
0x04 |
有效字节数 |
1字节 |
0x0C |
数据 |
12字节 |
0x00(第0路温度高字节) |
|
|
0x63(第0路温度低字节) |
|
|
0x80(第1路温度高字节) |
|
|
0x00(第1路温度低字节) |
|
|
0x80(第2路温度高字节) |
|
|
0x00(第2路温度低字节) |
|
|
0x80(第3路温度高字节) |
|
|
0x00(第3路温度低字节) |
|
|
0x80(第4路温度高字节) |
|
|
0x00(第4路温度低字节) |
|
|
0x80(第5路温度高字节) |
|
|
0x00(第5路温度低字节) |
校验 |
2字节 |
0x3CBA |
在RTU 模式中采用CRC(循环冗余检测)校验。具体的方法是将信息域中地址域、功能码、数据域的所有字节按规定的方式进行位移并进行XOR(异或)计算,得到2 字节的CRC码。校验码在信息帧作为一连续的流进行传输。从站在收到该信息帧时按同样的方式进行计算.并将结果同收到双字节校验码比较,如果一致就认为通信正确,否则认为通信有误,从站将发送错误应答。以下为校验的示意程序。
当接收到设备返回的17个字节数据后,进行以下crc计算操作,其中num(输入参数2)= 17
//--------------------------------------------------------------------------------------
//CRC计算C51语言函数如下
//输入参数1:snd,待校验的字节数组名
//输入参数2:num,待校验的字节总数(包括CRC校验的2个字节)
//函数返回值:校验失败时返回非0值。校验成功返回0。
//--------------------------------------------------------------------------------------
unsigned int calc_crc16 (unsigned char *snd, unsigned char num)
{
unsigned char i, j;
unsigned int c,crc=0xFFFF;//crc初始化为0xFFFF
for(i = 0; i < num; i ++)
{
c = snd[i] & 0x00FF;//待发送的字节和0x00FF进行“与”操作
crc ^= c; //crc与c做“异或”操作,结果存储于crc中
for(j = 0;j < 8; j ++)
{
if (crc & 0x0001) //检查crc最低位是否为1
{
crc>>=1; //crc右移一位
crc^=0xA001; //crc与0xA001做“异或”操作,结果存储于crc中
}
else
{
crc>>=1; //crc右移一位
}
}
}
return(crc);//返回crc校验结果
}
得到返回结果为0时那么校验成功,如果校验失败返回为非零值。
校验成功后,使用以下公式计算温湿度(负值以补码表示):
第0路温度= (0x00*256+0x63)/10 = 99/10 = 9.9℃
第1路温度= ((0xFF*256+0x00)-0xFFFF-0x01)/10 = -3276.8℃(未连接传感器的值或者异常值)
第2路温度= ((0xFF*256+0x00)-0xFFFF-0x01)/10 = -3276.8℃(未连接传感器的值或者异常值)
第3路温度= ((0xFF*256+0x00)-0xFFFF-0x01)/10 = -3276.8℃(未连接传感器的值或者异常值)
第4路温度= ((0xFF*256+0x00)-0xFFFF-0x01)/10 = -3276.8℃(未连接传感器的值或者异常值)
第5路温度= ((0xFF*256+0x00)-0xFFFF-0x01)/10 = -3276.8℃(未连接传感器的值或者异常值)
负值的判断与处理:如果返回值的二进制最高位为1,那么表明返回的数据是负数,假设返回的值是0xFF05 (16进制,补码),那么其二进制表示为:0b 1111111100000101,其最高位为1,那么表明这个返回值是负数。处理数值时第一字节高字节为0xFF,第二字节低字节为0x 05,那么温度测量值为((0xFF*256+0x05)-0xFFFF-0x01)/10 =(0xFF05-0xFFFF-0x01)/10=-25.1摄氏度。
如果校验不成功,说明传输过程发生错误,应放弃此次采集到的数据,重新采集。