上位机如触摸屏采用ModbusRTU或ModbusTCP通讯协议与下位机如单片机通过串口或网络通信时,需要解析上位机报文
Modbus寄存器读写的单位是字Word,读写Map表元素长度必须为字的整数倍,同时注意使用内存下标对齐时务必注意使用内存按字对齐
支持功能码03/06/10
0x03 | 读保持寄存器 | |||||||||||||
设备地址 | 功能码 | 起始地址 | 寄存器数量 | CRC校验 | ||||||||||
请求 | 0x01 | 0x03 | 高字节 | 低字节 | 高字节 | 低字节 | 高字节 | 低字节 | ||||||
注释 | 十六进制 | 0x0000至0xFFFF | 1至125(0x7D) | |||||||||||
样例 | 0x01 03 00 6B 00 03 17 74 | //请求读寄存器108-110的实例 | ||||||||||||
设备地址 | 功能码 | 字节数 | 寄存器值(N*2个字节) | CRC校验 | ||||||||||
响应 | 0x01 | 0x03 | N*2 | n=1高字节 | n=1低字节 | n=2高字节 | n=2低字节 | … | n=N高字节 | n=N低字节 | 高字节 | 低字节 | ||
注释 | 十六进制 | N=寄存器数量 | ||||||||||||
样例 | 0x01 03 06 02 2B 00 00 00 64 7A 05 | |||||||||||||
设备地址 | 差错码 | 异常码 | ||||||||||||
错误 | 0x01 | 0x83 | 01或02或03或04 | |||||||||||
注释 | 十六进制 | 功能码+0x80 | ||||||||||||
样例 | 0x01 83 01/02/03/04 |
0x06 | 写单个寄存器 | |||||||||||||
设备地址 | 功能码 | 寄存器地址 | 寄存器值 | CRC校验 | ||||||||||
请求 | 0x01 | 0x06 | 高字节 | 低字节 | 高字节 | 低字节 | 高字节 | 低字节 | ||||||
注释 | 十六进制 | 0x0000至0xFFFF | 0x0000至0xFFFF | |||||||||||
样例 | 0x01 06 00 01 00 03 0B 98 | //请求将十六进制00 03写入寄存器2的实例 | ||||||||||||
设备地址 | 功能码 | 输出寄存器地址 | 输出寄存器值 | CRC校验 | ||||||||||
响应 | 0x01 | 0x06 | 高字节 | 低字节 | 高字节 | 低字节 | 高字节 | 低字节 | ||||||
注释 | 十六进制 | 0x0000至0xFFFF | 0x0000至0xFFFF | |||||||||||
样例 | 0x01 06 00 01 00 03 0B 98 | |||||||||||||
设备地址 | 差错码 | 异常码 | ||||||||||||
错误 | 0x01 | 0x86 | 01或02或03或04 | |||||||||||
注释 | 十六进制 | 功能码+0x80 | ||||||||||||
样例 | 0x01 86 01/02/03/04 |
0x10(16) | 写多个寄存器 | ||||||||||||||||||||||
设备地址 | 功能码 | 起始地址 | 寄存器数量 | 字节数 | 寄存器值(N*2个字节) | CRC校验 | |||||||||||||||||
请求 | 0x01 | 0x10 | 高字节 | 低字节 | 高字节 | 低字节 | N*2 | n=1高字节 | n=1低字节 | n=2高字节 | n=2低字节 | … | n=N高字节 | n=N低字节 | 高字节 | 低字节 | |||||||
注释 | 十六进制 | 0x0000至0xFFFF | 0x0001至0x0078 | N=输入寄存器的数量 | |||||||||||||||||||
样例 | 0x01 10 00 01 00 02 04 00 0A 01 02 30 92 | //请求将十六进制00 0A和01 02 写入以2开始的两个寄存器的实例 | |||||||||||||||||||||
设备地址 | 功能码 | 起始地址 | 寄存器数量 | CRC校验 | |||||||||||||||||||
响应 | 0x01 | 0x10 | 高字节 | 低字节 | 高字节 | 低字节 | 高字节 | 低字节 | |||||||||||||||
注释 | 十六进制 | 0x0000至0xFFFF | 1至123(0x7B) | ||||||||||||||||||||
样例 | 0X01 10 00 01 00 02 08 10 | ||||||||||||||||||||||
设备地址 | 差错码 | 异常码 | |||||||||||||||||||||
错误 | 0x01 | 0x10 | 01或02或03或04 | ||||||||||||||||||||
注释 | 十六进制 | 功能码+0x80 | |||||||||||||||||||||
样例 | 0x01 10 01/02/03/04 |
#pragma pack(2)
typedef struct tagRGV_MAP
{
u16 a,
u32 b,
float c,
int d,
}RGV_MAP;
#pragma pack()
RGV_MAP MyRGV_Map;
/**
* @brief 处理触摸屏消息Modbus协议
* @param Uart_Ch 数据通道
* @param uLen 数据长度
* @param p 接收数据区
* @param pT 发送数据区
*/
void DealUartMessgae( u8 Uart_Ch, u16 uLen, u8 *p, u8 *pT )
{
u8 uPlcAdr;
u8 uCommand;
u16 uRegAdr,uRegLen;
u8 uBytes;
u16 uInx,uInt,i;
u16 *pAdr;
uPlcAdr = p[0];
uCommand = p[1];
uRegAdr = p[2]<<8 | p[3];
uRegLen = p[4]<<8 | p[5];
#define MODBUS_R_REG 0x03 // 读寄存器
#define MODBUS_W_HOLDREG 0x06 // 写寄存器
#define MODBUS_W_HOLDREG_M 0x10 // 写多个寄存器
switch(uCommand)
{
case MODBUS_R_REG://读寄存器
Refresh_RGV_Map_Read();
uInx = 0;
pT[uInx++] = uPlcAdr;
pT[uInx++] = uCommand;
pT[uInx++] = 2*uRegLen;
pAdr = (u16*)&MyRGV_Map + uRegAdr;
uInx = 3;
for(i=0;i<uRegLen;i++)
{
uInt = *pAdr++;
pT[uInx++] = uInt>>8;
pT[uInx++] = uInt;
}
ModBusCRC(pT,uInx,1);
StartModbusTranst_CH(Uart_Ch,uInx+2);
break;
case MODBUS_W_HOLDREG://写寄存器
uInt = p[4]<<8 | p[5];
pAdr = (u16*)&MyRGV_Map + uRegAdr;
*pAdr = uInt;
uInx = 0;
pT[uInx++] = uPlcAdr;
pT[uInx++] = uCommand;
pT[uInx++] = uRegAdr>>8;
pT[uInx++] = uRegAdr;
pT[uInx++] = uInt>>8;
pT[uInx++] = uInt;
ModBusCRC(pT,uInx,1);
StartModbusTranst_CH(Uart_Ch,uInx+2);
Deal_HMI_Message();
break;
case MODBUS_W_HOLDREG_M:
uInx = 0;
pT[uInx++] = uPlcAdr;
pT[uInx++] = uCommand;
pT[uInx++] = uRegAdr>>8;
pT[uInx++] = uRegAdr;
pT[uInx++] = uRegLen>>8;
pT[uInx++] = uRegLen;
ModBusCRC(pT,uInx,1);
StartModbusTranst_CH(Uart_Ch,uInx+2);
uBytes = p[6];
if(uBytes!=2*uRegLen){
break;
}
pAdr = (u16*)&MyRGV_Map + uRegAdr;
uInx = 7;
for(i=0;i<uRegLen;i++)
{
uInt = p[uInx]<<8 | p[uInx+1];
uInx += 2;
*pAdr++ = uInt;
}
Deal_HMI_Message();
break;
default:
break;
}
}