通信协议(modbus–RTU) 仪表设置:pst 01——中TF = 1,D39系列要选命令方式2
一、老协议 兼容老协议
1.主机读仪表数据
等待 | 字节0 | 1 | 2 | 3 |
四个字节的时间 | 1~247 | x03 | 启始地址高8 | 低8 |
仪表地址 | 功能代码 | 所要读的寄存器开始地址 |
4 | 5 | 6 | 7 | 等待 |
N/2个字节高8 | 低8 | CRC16低8 | CRC16高8 | 三个字节的时间 |
发送数量 | CRC16校验 |
数据以ASII传送
2.仪表返馈
正常回应
字节0 | 1 |
1~247 | 0x03 |
仪表地址 | 功能代码 |
2 | 3 | 3+n | 3+n | ||
N | 数据0 | …… | 数据N(偶数) | CRC16L | CRC16h |
数据长度 | 数据 |
1)称重数据读取指令
功能 | 所要读的寄存器开始地址(地址高8位) | 所要读的寄存器开始地址(地址低8位) | |
1 | 读毛重 | 0x00 | 0x01 |
2 | 读皮重 | 0x00 | 0x02 |
3 | 读净重 | 0x00 | 0x03 |
4 | 读总内码 | 0x00 | 0x07 |
5 | 读第i号传感器内码异常时得到-999999 | 0x00 | 0x0A+i(i=1~16) |
发送
0 | 1 | 2 | 3 | 4 |
仪表地址 | 0x03 | 地址高8位 | 地址低8位 | 0x00 |
5 | 6 | 7 |
0x04 | CRC16L | CRC16H |
返回
0 | 1 | 2 | 3 | 5 | 6 |
仪表地址 | 0x03 | 0x08 | 符号-或data6 | Data5 | Data4 |
7 | 8 | 9 | 10 | 11 |
Data3 | Data2 | Data1 | Data0 | 小数点(右至左) |
12 | 13 |
CRC16L | CRC16H |
例子:
1、读取当前毛重
发送:01 03 00 01 00 04 15 C9
接收:若当前毛重为0
01 03 08 30 30 30 30 30 30 30 30 F8 2F (最后两个字节为CRC16校验码)
若当前毛重为1240
01 03 08 30 30 30 31 32 34 30 30 85 96
2、远程置零
发送: 01 06 00 01 00 17 98 04
接收: 01 06 00 01 00 17 98 04
常见问题:
1、仪表连续发送(如TF=0)时,电脑串口能收到数据,但用指令方式仍无响应
原因: 1)仪表参数错误,D2008、D12系列仪表TF = 1;D39系列仪表为命令方式2
2)仪表串口故障,可通过test 08 进行自检。
3)电脑串口故障,将接串口2和3短路,然后通过串口工具发送数据,看其能否收到自己发送的相同的数据。
4)接线问题,仪表9芯的3号脚(RXD)为接收脚,需要与电脑的2号脚(TXD)连接
5)仪表虽支持modbus RTU 协议,但modbus 发指令时有要求,如读毛重,其寄存器地址为40001.此时必须一次性读4个字(40001~40004),否则无应答。
2、数据如何解释
以下为读毛重
地址 | 内容 | 举例(重量1234567) | 举例(重量-23456.7) |
40001 | 符号-或data6,Data5 | 0x31,0x32 | 0x2d,0x32 |
40002 | Data4,Data3 | 0x33,0x34 | 0x33,0x34 |
40003 | Data2,Data1 | 0x35,0x36 | 0x35,0x36 |
40004 | Data0,小数点+0x30 | 0x37,0x30 | 0x37,0x31 |
以下为读净重
地址 | 内容 | 举例(重量1234567) | 举例(重量-23456.7) |
40003 | 符号-或data6,Data5 | 0x31,0x32 | 0x2d,0x32 |
40004 | Data4,Data3 | 0x33,0x34 | 0x33,0x34 |
40005 | Data2,Data1 | 0x35,0x36 | 0x35,0x36 |
40006 | Data0,小数点+0x30 | 0x37,0x30 | 0x37,0x31 |
以下是西门子 200 smart 的示例:
读毛重:
特别要注意:以上40002对应仪表的40001.
接下来再写个子程序:
子程序接口:
代码:(部分)
二、新协议
只有以下版本支持:
仪表:D2008型(DF)、D12-YF–V09版本 D2008-W —V13版本,KL-MPLC的com2协议1
寄存器地址 | |
40060 | 状态Bit0:开机零点确认中 0:已确认 1:正在确认中Bit1:超载 0:正常 1:超载Bit2:稳定 0:不稳定 2:稳定 Bit3:去皮 0:没有去皮 1:去皮状态Bit4:零点 0:没在零点 1:零位区Bit5:计量数据有效 0:无效 1:有效 Bit6: 传感器出错 0:通讯正常 1: 异常Bit7: 备用Bit8~15: 传感器个数 |
40061 | 传感器状态 0:正常 1:异常 Bit16:1号 Bit17:2号…Bit31:16号 |
40062-40063 | 毛重:float |
40064-40065 | 皮重:float |
40066-40067 | 净重:float |
40068-40069 | 第1个传感器内码:float |
40070-40071 | 第2个传感器内码:float |
… | … |
40098-40099 | 第16个传感器内码:float |
40100 | 传感器状态 0:正常 1:异常 Bit16:17号 Bit17:18号…Bit31:32号 |
40101-40102 | 第17号传感器内码:float |
40103-40104 | 第18号传感器内码:float |
… | … |
40131-40132 | 第32号传感器内码:float |
约定:
当秤台计量数据无效:仪表的净重为-999999,如果小数点为3位,则为-999.999
置零:向地址40001写0x0017;
2、Modbus主机配置:
第一项:选择为RTU
第二项:
如:
第三项:float显示格式设置:
第三项:全部显示例子:
3、相关解码代码:接收字节转化为浮点型
定义数据结构:
typedef union noneTYPE32DATABYTE { struct{ INT32U onebyte0:8; INT32U onebyte1:8; INT32U onebyte2:8; INT32U onebyte3:8; }onebyte; INT32U One32data; FP32 FP32data; }TYPE32DATABYTE; 代码: 原如接收4个字节 (按接收顺序)--Rdata[0],Rdata[1],Rdata[2]和Rdata[3] float FP32data; TYPE32DATABYTE P_temp; P_temp.onebyte.onebyte1 = Rdata[0]; P_temp.onebyte.onebyte0 = Rdata[1]; P_temp.onebyte.onebyte3 = Rdata[2]; P_temp.onebyte.onebyte2 = Rdata[3]; F_temp = P_temp.FP32data;//F_temp就是结果
在西门子 200smart中字节转浮点型操作如下:
例:浮点数 123.456 对应[0]=0x79 0xe9,0xf6,[3]=0x42
PLC梯形图转化:
效果:
常用例子1:读毛重
仪表显示毛重68,皮重为0
发:01 03 00 42 00 02 64 1F
收: 01 03 04 00 00 42 88 CA F5
常用例子2:远程置零
发送: 01 06 00 01 00 17 98 04
接收: 01 06 00 01 00 17 98 04
CRC16校验码算法:
/* CRC 高位字节值表 */ const unsigned char auchCRCHi[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 } ; /* CRC低位字节值表*/ const unsigned char auchCRCLo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 } ; /****************************************************** 函数名: INT16U crc16(unsigned char *puchMsg, INT16U usDataLen) 功能: 根据字符串puchMsg 及长度产生一个CRC16 输入:unsigned char *puchMsg 字符串 usDataLen 长度 输出:INT16U CRC16 *******************************************************/ INT16U crc16(unsigned char *puchMsg, INT16U usDataLen) //根据字符串puchMsg 及长度产生一个CRC16 { unsigned char uchCRCHi = 0xFF ; /* 高CRC字节初始化 */ unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */ unsigned long uIndex ; /* CRC循环中的索引 */ while (usDataLen--) /* 传输消息缓冲区 */ { uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */ uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ; uchCRCLo = auchCRCLo[uIndex] ; } return (uchCRCHi << 8 | uchCRCLo) ; } //=======================================================
应用:假设要发送读毛重指令(16进制)
01 03 00 01 00 04
产生校验码的方式
//TXD_C_temps[]存了01 03 00 01 00 04 (6个字节)
INT16U crcData ;
ByteCount = 6;//数据为6字节
crcData = crc16(TXD_C_temps,ByteCount );
TXD_C_temps[byteCount] = crcData >> 8;
byteCount++;
TXD_C_temps[byteCount] = crcData & 0xff;
//此时字符串
01 03 00 01 00 04 15 C9
putchars2_8th(TXD_C_temps,byteCount+1);//通过串口发送