📄 modbus.c
字号:
break;
}
default: //错误
{
FaultProcess();
return(0);
}
}
return(1);
}
/********************************************************************************************************
* 作者 :冯子龙
* 日期 :200709
* 名称 :Data_anlysis_ASCII()
* 功能 :ASCII模式 接收分析
* 返回 :FRM_ERR,CMD_ERR,1
* 备注 :分析结果存放在*dest中
*********************************************************************************************************/
char Data_anlysis_ASCII( int *dest,uchar *src,uint start_address)
{
uchar tmp[256];
uint lenth;
uint i, j;
char shift;
//将ASCII码串去除起始符和结束符后转换为二进制
lenth = ASCII2RTU(tmp,src);
if ( lenth==0) return FRM_ERR;
switch (tmp[1])//命令解析
{
case READ_COIL://01读取线圈状态
{
for ( i=0; i<tmp[2]; i++)
{
shift = 1;
for ( j=0; j<8; j++)
{
*(dest+start_address+i*8+j) = shift & tmp [i+3];
tmp [i+3] >>= 1;
}
}
break;
}
case READ_DI: //02读取开关量输入
{
for ( i=0; i<tmp[2]; i++)
{
shift = 1;
for (j=0; j<8; j ++)
{
*(dest+start_address+i*8+j)= shift & tmp [i+3];
tmp [i+3]>>=1;
}
}
break;
}
case READ_HLD_REGs://03读取保持寄存器
{
for (i=0; i<tmp[2]; i+=2)
{
*(dest + start_address+ i/2) = tmp[i+3]*256 + tmp[i+4] ;
}
#ifdef operatorDEBUG
if(*( src+2)==2)//手持操作器显示用,因为手持仅进行每次读一个字的操作。连接ABB测试用
{
para_val = *(src+i+3)*256 + *(src+i+4);
}
#endif
break ;
}
case READ_AI://04读取模拟量输入
{
for (i=0; i<tmp[2]; i+=2)
{
*(dest+start_address+ i/2) = tmp[i+3]*256 + tmp[i+4] ;
}
break;
}
case SET_COIL://05强制单个线圈进行
{
break;
}
case SET_HLD_REG://06写单个寄存器
{
break;
}
case SET_COILs://15强制多个线圈进行
{
break;
}
case SET_HLD_REGs: //16写多个寄存器
{
break;
}
case READ_SET_HLD_REGs: //23读写多个寄存器
{
break;
}
default: //功能码错误
{
FaultProcess();
break;
}
}
return(1);
}
/********************************************************************************************************
* 作者 :冯子龙
* 日期 :200709
* 名称 :cmd01_ReadCoilStatus()
* 功能 :读取继电器状态:CMD == 1
* 返回 :成功返回1,否则返回0
* 备注 :Tested
请求命令:[设备地址] [命令号01] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8位] [CRC校验的低8位] [CRC校验的高8位]
设备响应:[设备地址] [命令号01] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校验的高8位]
*********************************************************************************************************/
uchar cmd01_ReadCoilStatus(uchar DeviceID,uint start_address,uint lenth)
{
uchar tmp[256],tmp_lenth;
tmp[0] = DeviceID; //从设备地址
tmp[1] = 0x01; //命令
tmp[2] = wordHByte(start_address);//起始地址 高字节
tmp[3] = wordLByte(start_address);//起始地址 低字节
tmp[4] = wordHByte(lenth);//读取数据量 高字节
tmp[5] = wordLByte(lenth);//读取数据量 低字节
tmp_lenth = 6; //二进制包长度
if(Modbus_mode)
{
construct_ascii_frm (Tx_Buffer, tmp, tmp_lenth);//对以上数据构成ASCII码串
TxBytes = 2*tmp_lenth+2; //有效Modbus数据长度,用于中断发送完成判断
}
else
{
construct_rtu_frm ( Tx_Buffer, tmp, tmp_lenth);
TxBytes = tmp_lenth+2;
}
comSend();//发送请求
if(comReceive())//获取应答;对应答数据分析;对接收到的应答数据分析
{
if(Rx_Buffer[1] == 0x01) //通信正常,数据处理
{
if(CheckCRC(Rx_Buffer,RxBytes))
{
switch(Rx_Buffer[2])//返回字节数
{
case 0x02:
{
break;
}
case 0x04:
{
break;
}
case 0x06:
{
break;
}
case 0x08:
{
para_val = Rx_Buffer[3]*256 + Rx_Buffer[4];
break;
}
default:
{
break;
}
}
return(1);
}
else //CRC校验不一致;可重新发送请求或作其他处理
{
Rx_Buffer[2] = 0x09;
FaultProcess();
return(0);
}
}
else //通信异常0x83,查询异常码,可重新发送请求或作其他处理
{
FaultProcess();
return(0);
}
}
else //通信异常
{
Rx_Buffer[2] = 255;//异常码填充
FaultProcess();
return(0);
}
}
/********************************************************************************************************
* 作者 :冯子龙
* 日期 :200709
* 名称 :cmd02_ReadInStatus()
* 功能 :读取开关量输入:CMD == 2
* 返回 :成功返回1,否则返回0
* 备注 :全局变量Modbus_mode,Tx_Buffer[],TxBytes,Rx_Buffer[],RxBytes
请求命令:[设备地址] [命令号02] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8位] [CRC校验的低8位] [CRC校验的高8位]
设备响应:[设备地址] [命令号02] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校验的高8位]
*********************************************************************************************************/
uchar cmd02_ReadInStatus(uchar DeviceID, uint start_address, uint lenth)
{
uchar tmp[256], tmp_lenth;
tmp[0] = DeviceID;//从设备地址
tmp[1] = 0x02; //命令
tmp[2] = wordHByte(start_address);//起始地址 高字节
tmp[3] = wordLByte(start_address);//起始地址 低字节
tmp[4] = wordHByte(lenth);//读取数据量 高字节
tmp[5] = wordLByte(lenth);//读取数据量 低字节
tmp_lenth = 6; //二进制包长度
if(Modbus_mode)
{
construct_ascii_frm (Tx_Buffer, tmp, tmp_lenth);//对以上数据构成ASCII码串
TxBytes = 2*tmp_lenth+2; //有效Modbus数据长度,用于中断发送完成判断
}
else
{
construct_rtu_frm(Tx_Buffer, tmp, tmp_lenth);
TxBytes = tmp_lenth+2;
}
comSend();//发送请求
if(comReceive())//获取应答;对应答数据分析;对接收到的应答数据分析
{
if(Rx_Buffer[1] == 0x02) //通信正常,数据处理
{
if(CheckCRC(Rx_Buffer,RxBytes))
{
switch(Rx_Buffer[2])//返回字节数
{
case 0x02:
{
break;
}
case 0x04:
{
break;
}
case 0x06:
{
break;
}
case 0x08:
{
para_val = Rx_Buffer[3]*256 + Rx_Buffer[4];
break;
}
default:
{
break;
}
}
return(1);
}
else //CRC校验不一致;可重新发送请求或作其他处理
{
Rx_Buffer[2] = 0x09;
FaultProcess();
return(0);
}
}
else //通信异常0x83,查询异常码,可重新发送请求或作其他处理
{
FaultProcess();
return(0);
}
}
else //通信异常
{
Rx_Buffer[2] = 255;//异常码填充
FaultProcess();
return(0);
}
}
/********************************************************************************************************
* 作者 :冯子龙
* 日期 :200709
* 名称 :cmd03_ReadHldreg()
* 功能 :读取保持寄存器:CMD == 3
* 返回 :成功返回1,否则返回0
* 备注 :Tested
请求命令:[设备地址] [命令号03] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8位] [CRC校验的低8位] [CRC校验的高8位]
设备响应:[设备地址] [命令号03] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校验的高8位]
*********************************************************************************************************/
uchar cmd03_ReadHldreg(uchar DeviceID, uint start_address, uint lenth)
{
uchar tmp[256], tmp_lenth;
int tmmp[256];
tmp[0] = DeviceID;//从设备地址
tmp[1] = 0x03;//命令
tmp[2] = wordHByte(start_address);//起始地址 高字节
tmp[3] = wordLByte(start_address);//起始地址 低字节
tmp[4] = wordHByte(lenth);//读取数据量 高字节
tmp[5] = wordLByte(lenth);//读取数据量 低字节
tmp_lenth = 6;
if(Modbus_mode)
{
construct_ascii_frm (Tx_Buffer, tmp, tmp_lenth);//对以上数据构成ASCII码串
TxBytes = 2*tmp_lenth+2; //有效Modbus数据长度,用于中断发送完成判断
}
else
{
construct_rtu_frm(Tx_Buffer, tmp, tmp_lenth);
TxBytes = tmp_lenth+2;
}
comSend();//发送请求
if(comReceive())//获取应答;对应答数据分析;对接收到的应答数据分析
{
if(Modbus_mode)
{
//data_anlys_ascii();
Data_anlysis_ASCII(tmmp,Rx_Buffer,start_address);
}
else
{
// data_anlys_rtu();
Data_anlysis_RTU(tmmp,Rx_Buffer,start_address,RxBytes);
}
/*
if(Rx_Buffer[1] == 0x03) //通信正常
{
if(CheckCRC(Rx_Buffer,RxBytes))//数据处理
{
switch(Rx_Buffer[2])//返回字节数
{
case 0x02:
{
para_val = Rx_Buffer[3]*256 + Rx_Buffer[4]; //提取数据
break;
}
case 0x04:
{
break;
}
case 0x06:
{
break;
}
case 0x08:
{
break;
}
default:
{
para_val = RxBytes; //显示接收到的字节数:测试用
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -