A. 關於modbus tcp,通過modbus tcp協議給用戶界面傳數據
int CModTCP::Modbust()
{
//創建本地套接字,Create()函數不帶參數,默認創建流式套接字
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;
}
}