A. 关于modbus tcp,通过modbus tcp协议给用户界面传数据
int CModTCP::Modbust()
{
//创建本地套接字,()函数不带参数,默认创建流式套接字
if(s.Create ()==FALSE)
{
AfxMessageBox("创建套接字失败!");
return 1;
}
//发送连接请求
//s_addr = inet_addr(ip_adrs); //连接ip地址
if(s.Connect (strIp,502)==FALSE)
{
AfxMessageBox("建立连接失败!");
s.Close ();
return 1;
}
//组织发送帧并发送
BYTE sendBuf[120];
sendBuf[0]=0;//前两位为传输标志,2个字节,故占用数组的两个位置,
sendBuf[1]=0;//标志某个Modbus询问/应答的传输,由客户端生成
sendBuf[2]=0;//协议标志,两个字节,0为Modbus协议,1为UNI-TE协议
sendBuf[3]=0;
sendBuf[4]=0;//长度字段(前半部分字节)
//sendBuf[5]=11+atoi(argv[7])*2;//随后字节数
sendBuf[5]=41;//随后字节数
sendBuf[6]=255;//单元标志,定义连接目的节点的其他设备
//atoi把字符型转化成整形
//字符型为8位,整形为16位
sendBuf[7]=23;//Modbus功能码,读/写寄存器操作。
//sendBuf[8]=atoi(argv[4]) >> 8; //读取寄存器起始地址高字节
sendBuf[8]=0; //读取寄存器起始地址高字节
//sendBuf[9]=atoi(argv[4]) & 0xff; // 寄存器起始低地址
sendBuf[9]=100 & 0xff; // 读寄存器起始低地址
//sendBuf[10]=atoi(argv[5]) >> 8; // 寄存器长度高位
sendBuf[10]=0; // 寄存器长度高位
//sendBuf[11]=atoi(argv[5]) & 0xff; // 寄存器长度低位
sendBuf[11]=43& 0xff; // 寄存器长度低位 %MW100-%MW139 向上位机传递数据
//sendBuf[12]=atoi(argv[6]) >> 8;//写数据寄存器起始地址高字节
sendBuf[12]=0;//写数据寄存器起始地址高字节
//sendBuf[13]=atoi(argv[6]) & 0xff; //写数据寄存器起始地址低字节
sendBuf[13]=200 & 0xff; //写数据寄存器起始地址低字节
//PLC中INT型占16位数,即一个字两个字节。所以argv[7]中为写入的指令字
//sendBuf[14]=atoi(argv[7]) >> 8; //写数据长度字数的高字节(用于写的指令数)
sendBuf[14]=0; //写数据长度字数的高字节(用于写的指令数)
//sendBuf[15]=atoi(argv[7]) & 0xff; //写数据长度字数的低字节
sendBuf[15]=15& 0xff; //写数据长度字数的低字节 从%MW200-%MW214
//sendBuf[16]=atoi(argv[7])*2 & 0xff; //数据长度字节数(B=2*用于写的指令数)
sendBuf[16]=30 & 0xff; //数据长度字节数(B=2*用于写的指令数)
//for (int i = 0; i < (atoi(argv[7])*2)-1; i+=2)//用于写入的寄存器值
for (int i = 0; i < 17; i+=2)//用于写入的寄存器值(写INT型)。%MW为16位的INT型
{
//sendBuf[i+17] = atoi(argv[8+(i/2)])>> 8 ;//写的第一个字的高字节
sendBuf[i+17] = (argv[(i/2)]>> 8) & 0xff;//写的第一个字的高字节
//sendBuf[i+18] = atoi(argv[8+(i/2)])& 0xff;//写的第一个字的低字节
sendBuf[i+18] = argv[(i/2)]& 0xff;//写的第一个字的低字节
}
for (int i =0; i < 11; i+=4)//用于写入的寄存器值(写DINT型)
{
//sendBuf[i+17] = atoi(argv[8+(i/2)])>> 8 ;//写的第一个字的高字节
sendBuf[i+35] = argv[9+(i/4)]>> 24 ;//写的第一个字的高字节
//sendBuf[i+18] = atoi(argv[8+(i/2)])& 0xff;//写的第一个字的最高8位
sendBuf[i+36] = (argv[9+(i/4)]>> 16)& 0xff;//写的第一个字的中高8位数
sendBuf[i+37] = (argv[9+(i/4)]>> 8)& 0xff;//写的第一个字的中低8位数
sendBuf[i+38] = argv[9+(i/4)]& 0xff;//写的第一个字的低8位数
}
int iSend=s.Send(sendBuf,47,0);
if(iSend==SOCKET_ERROR)
{
AfxMessageBox("发送数据失败!");
s.Close ();
return 1;
}
unsigned char Recv[260];
int iRecv=s.Receive (Recv,260,0);
if(iRecv<9)//8位数只到功能码处.byte 7:功能码。byte 8:字节数Byte Count(B=2*用于读的指令长度(argc[5]).byte 2-(B+1):寄存器值
//如果小于9,即最多读到第8位,只有功能吗,而没有字节数
{
if(iRecv==0)
{
AfxMessageBox("意外的关闭远端的连接!");
}
else
{
AfxMessageBox("响应帧太短!");
}
}
else
{
BYTE a=Recv[7]&0x80;
if(a!=0)
{
switch(a)
{
case 1:
AfxMessageBox("非法的功能!");
break;
case 2:
AfxMessageBox("非法的数据地址!");
break;
case 3:
AfxMessageBox("非法的数据值!");
break;
case 4:
AfxMessageBox("非法的响应长度!");
break;
case 5:
AfxMessageBox("确认!");
break;
case 6:
AfxMessageBox("从站设备忙!");
break;
case 8:
AfxMessageBox("存储器奇偶校验错误!");
break;
case 10:
AfxMessageBox("网管通路不可用!");
break;
case 11:
AfxMessageBox("网关目标设备响应失败!");
break;
}
}
else
{
else if (iRecv != (9+2*atoi(argv[5]))
//argv[5]为用于读的指令数,*2表示用于读的字节数
{
printf("不正确的响应大小!");
}
else//接受数据的处理
{
//int t = atoi(argv[4]); //读取数地址
//int t = 100; //读取数地址
//for (int i=0;i<atoi(argv[5]);i++)
for (int i=0;i<31;i++)
{
receiv[i]= (Recv[9+i+i]<<8) + Recv[10+i+i];
}
for (int i=0;i<6;i++)//argv[5]为用于读的指令数。读DINT型
{
receiv[31+i] = (Recv[71+4*i] <<24) + (Recv[72+4*i] <<16)+ (Recv[73+4*i]<<8)+ (Recv[74+4*i]);
}
}
}
s.Close ();
return 0;
}
}