ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用SOCKET 实现 Modbus TCP 读写

2022-07-22 20:09:52  阅读:145  来源: 互联网

标签:return SOCKET int res CString TCP Modbus strRecv socket


将ASCII字符串写入到保持寄存器中,16个寄存器

读16个寄存器,把十六进制的值再转成ASCII

读写一个保持寄存器的值

要实现socket 十六进制发送功能,ASCII和十六进制字符串互转功能

 

此代码共用到Modbus TCP的3个功能码 03 06 10 功能码

03功能码

 

 06功能码

 

10功能码

 

 

 

#include <WS2tcpip.h>
SOCKET m_socket;
sockaddr_in addr;     //定义套接字地址结构变量

代码

  1 BOOL socketTcpConnect(CString strIP, int iPort)
  2 {
  3     WSADATA wsa = { 0 };
  4     WSAStartup(MAKEWORD(2, 2), &wsa);
  5     //初始化socket
  6     m_socket = socket(AF_INET, SOCK_STREAM, 0);
  7     u_long mode = 1;
  8     ioctlsocket(m_socket, FIONBIO, &mode);//设置为非阻塞
  9     if (m_socket == INVALID_SOCKET)
 10     {
 11         AfxMessageBox(_T("初始化 socket error"));
 12         return FALSE;
 13     }
 14     addr.sin_family = AF_INET;
 15     InetPton(AF_INET, strIP, &addr.sin_addr.s_addr);
 16     addr.sin_port = ntohs(iPort);
 17 
 18     //设置connect超时时间
 19     struct timeval timeout;
 20     fd_set r;
 21     int ret;
 22     connect(m_socket, (sockaddr*)&addr, sizeof(addr));
 23     FD_ZERO(&r);
 24     FD_SET(m_socket, &r);
 25 
 26     timeout.tv_sec = 5;
 27     timeout.tv_usec = 0;
 28     ret = select(0, 0, &r, 0, &timeout);
 29 
 30     if (ret <= 0)
 31     {
 32         closesocket(m_socket);
 33         return FALSE;
 34     }
 35     return TRUE;
 36 }
 37 
 38 
 39 
 40 BOOL socketTcpClose()
 41 {
 42     closesocket(m_socket);
 43     return TRUE;
 44 }
 45 
 46 
 47 
 48 void strAsciiTostrHex(char *strAscii, char *strHex, int iAsciiLen)
 49 {
 50     int i = 0;
 51     int j = 0;
 52     for (i = 0, j = 0; i < iAsciiLen; i++, j += 2)
 53     {
 54         sprintf((char*)(strHex + j), "%02X", strAscii[i]);
 55     }
 56 }
 57 
 58 
 59 //一位十六进制转换为十进制
 60 int HexChar(char c)
 61 {
 62     if ((c >= '0') && (c <= '9'))
 63         return c - 0x30;
 64     else if ((c >= 'A') && (c <= 'F'))
 65         return c - 'A' + 10;
 66     else if ((c >= 'a') && (c <= 'f'))
 67         return c - 'a' + 10;
 68     else
 69         return 0x10;
 70 }
 71 
 72 
 73 int strTohex(CString str, char *data)
 74 {
 75     int t, t1;
 76     int rlen = 0;
 77     int len = str.GetLength();
 78     for (int i = 0; i < len; )
 79     {
 80         char l;
 81         char h = str[i];
 82         if (h == ' ')
 83         {
 84             i++;
 85             continue;
 86         }
 87         i++;
 88         if (i >= len)
 89         {
 90             break;
 91         }
 92         l = str[i];
 93         t = HexChar(h);
 94         t1 = HexChar(l);
 95         if ((t == 16) || (t1 == 16))
 96         {
 97             break;
 98         }
 99         else
100         {
101             t = t * 16 + t1;
102         }
103         i++;
104         data[rlen] = (char)t;
105         rlen++;
106     }
107     return rlen;
108 }
109 
110 
111 CString getHexrecv(CHAR *str, int len)
112 {
113     BYTE c_temp;
114     CString str_temp;
115     CString str_res;
116     for (int i = 0; i < len; i++)
117     {
118         c_temp = str[i];
119         str_temp.Format(_T("%02X"), c_temp);
120         str_res = str_res + str_temp;
121     }
122     return str_res;
123 }
124 
125 
126 BOOL socketTcpWrite16Value(int iAddr, CString strHex)
127 {
128     int iZroFillNumber = 0;
129     iZroFillNumber = 64 - strHex.GetLength();
130     CString strZroFill;
131     for (int i = 0; i < iZroFillNumber; i++)
132     {
133         strZroFill += "0";
134     }
135     strHex += strZroFill;
136     CString strAddr, strWrite;
137     strAddr.Format(_T("%04X"), iAddr);
138 
139     strWrite.Format(_T("0000000000270110%s001020%s"), strAddr, strHex);
140     //AfxMessageBox(_T("写命令:") + strWrite);
141     char arraybuf[1024] = { 0 };
142     int len = strTohex(strWrite, arraybuf);
143     send(m_socket, arraybuf, len, 0);//执行转发
144     CString strRecv;
145     memset(arraybuf, 0, 1024);
146     int iCount = 0;
147     while (1)
148     {
149         if (iCount >= 150)
150         {
151             break;
152         }
153         Sleep(20);
154         iCount++;
155         int iRecv = recv(m_socket, arraybuf, 1024, 0);
156         strRecv = getHexrecv(arraybuf, iRecv);
157         if (!strRecv.IsEmpty())
158         {
159             CString strRecvFlag;
160             strRecvFlag.Format(_T("0000000000060110%s0010"), strAddr);
161             if (strRecv == strRecvFlag)
162             {
163                 CString strMsg;
164                 strMsg.Format(_T("写地址%d值%s成功"), iAddr, strHex);
165                 //AfxMessageBox(strMsg);
166                 return TRUE;
167                 break;
168             }
169         }
170     }
171 
172     return FALSE;
173 }
174 
175 
176 
177 int hexcharToInt(char c)
178 {
179     if (c >= '0' && c <= '9') return (c - '0');
180     if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
181     if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
182     return 0;
183 }
184 
185 void strHexTostrAscii(char *strAscii, char *strHex, int iHexLen)
186 {
187     for (int i = 0; i < iHexLen; i += 2)
188     {
189         strAscii[i / 2] = (char)((hexcharToInt(strHex[i]) << 4) | hexcharToInt(strHex[i + 1]));
190     }
191 }
192 
193 
194 //开始位置  长度寄存器个数   一个寄存器保存2个字节
195 BOOL socketTcpReadAsciiValue(int iAddr, int iReadLen)
196 {
197     CString strAddr, strWrite, strReadLen;
198     strAddr.Format(_T("%04X"), iAddr);
199     strReadLen.Format(_T("%04X"), iReadLen);
200 
201     strWrite.Format(_T("0000000000060103%s%s"), strAddr, strReadLen);
202     //AfxMessageBox(_T("读命令:") + strWrite);
203 
204     char arraybuf[1024] = { 0 };
205     int len = strTohex(strWrite, arraybuf);
206     send(m_socket, arraybuf, len, 0);//执行转发
207     CString strRecv;
208     memset(arraybuf, 0, 1024);
209     int iCount = 0;
210     while (1)
211     {
212         if (iCount >= 150)
213         {
214             break;
215         }
216         Sleep(20);
217         iCount++;
218         int iRecv = recv(m_socket, arraybuf, 1024, 0);
219         strRecv = getHexrecv(arraybuf, iRecv);
220         if (!strRecv.IsEmpty())
221         {
222             //AfxMessageBox(strRecv);
223             //获取长度字节数
224             CString strRecvHexLen;
225             strRecvHexLen = strRecv.Mid(16, 2);
226             int iRecvHexLen = _tcstoll(strRecvHexLen, 0, 16);
227             if (iRecvHexLen != (iReadLen * 2))
228             {
229                 AfxMessageBox(_T("返回数据长度不正确"));
230                 return FALSE;
231             }
232             CString strHex;
233             strHex = strRecv.Right(strRecv.GetLength() - 18);
234             //AfxMessageBox(strHex);
235             //前2个是0 后2个是0 4个全是0
236             char cArrAscii[40] = { 0 };
237             char cArrHex[80] = { 0 };
238             sprintf(cArrHex, strHex.GetBuffer(0));
239             //这里会自动忽略后面的0
240             strHexTostrAscii(cArrAscii, cArrHex, strlen(cArrHex));
241 
242             CString strMsg;
243             strMsg.Format(_T("%s"), cArrAscii);
244             //AfxMessageBox(strMsg);
245             sOutParaArray.SetAt(0, cArrAscii);
246             return TRUE;
247             break;
248         }
249     }
250 
251     return FALSE;
252 }
253 
254 //开始位置  长度寄存器个数   一个寄存器保存2个字节
255 BOOL socketTcpReadValue(int iAddr, int iReadLen)
256 {
257     CString strAddr, strWrite, strReadLen;
258     strAddr.Format(_T("%04X"), iAddr);
259     strReadLen.Format(_T("%04X"), iReadLen);
260 
261     strWrite.Format(_T("0000000000060103%s%s"), strAddr, strReadLen);
262     //AfxMessageBox(_T("读命令:") + strWrite);
263 
264     char arraybuf[1024] = { 0 };
265     int len = strTohex(strWrite, arraybuf);
266     send(m_socket, arraybuf, len, 0);//执行转发
267     CString strRecv;
268     memset(arraybuf, 0, 1024);
269     int iCount = 0;
270     while (1)
271     {
272         if (iCount >= 150)
273         {
274             break;
275         }
276         Sleep(20);
277         iCount++;
278         int iRecv = recv(m_socket, arraybuf, 1024, 0);
279         strRecv = getHexrecv(arraybuf, iRecv);
280         if (!strRecv.IsEmpty())
281         {
282             //AfxMessageBox(strRecv);
283             //获取长度字节数
284             CString strRecvHexLen;
285             strRecvHexLen = strRecv.Mid(16, 2);
286             int iRecvHexLen = _tcstoll(strRecvHexLen, 0, 16);
287             if (iRecvHexLen != (iReadLen * 2))
288             {
289                 AfxMessageBox(_T("返回数据长度不正确"));
290                 return FALSE;
291             }
292             CString strHex;
293             strHex = strRecv.Right(strRecv.GetLength() - 18);
294             //AfxMessageBox(strHex);
295             if (iAddr == 98)
296             {
297                 CString strFault;
298                 strFault = AnalysisFault(strHex);
299                 //AfxMessageBox(strFault);
300                 sOutParaArray.SetAt(0, strFault);
301             }
302             else if(iAddr == 106)
303             {
304                 CString strState;
305                 strState = GetChargeState(strHex);
306                 //AfxMessageBox(strState);
307                 sOutParaArray.SetAt(0, strState);
308             }
309 
310             return TRUE;
311             break;
312         }
313     }
314 
315     return FALSE;
316 }
317 
318 
319 
320 BOOL socketTcpWriteValue(int iAddr, int value)
321 {
322     CString strAddr, strWrite, strIndex, strValue;
323     strAddr.Format(_T("%04X"), iAddr);
324     strValue.Format(_T("%04X"), value);
325 
326     strWrite.Format(_T("0000000000060106%s%s"), strAddr, strValue);
327     //AfxMessageBox(_T("写命令:") + strWrite);
328     char arraybuf[1024] = { 0 };
329     int len = strTohex(strWrite, arraybuf);
330     send(m_socket, arraybuf, len, 0);//执行转发
331     CString strRecv;
332     memset(arraybuf, 0, 1024);
333     int iCount = 0;
334     while (1)
335     {
336         if (iCount >= 150)
337         {
338             break;            
339         }
340         Sleep(20);
341         iCount++;
342         int iRecv = recv(m_socket, arraybuf, 1024, 0);
343         strRecv = getHexrecv(arraybuf, iRecv);
344         if (!strRecv.IsEmpty())
345         {
346             if (strWrite == strRecv)
347             {
348                 CString strMsg;
349                 strMsg.Format(_T("写地址%d值%d成功"), iAddr, value);
350                 //AfxMessageBox(strMsg);
351                 return TRUE;
352                 break;
353             }
354         }
355     }
356 
357     return FALSE;
358 }

调用16个寄存器读写

        
//写ASCII字符串到保持寄存器
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        char cArrAscii[40] = { 0 };
        sprintf(cArrAscii, strValue.GetBuffer(0));
        char cArrHex[70] = { 0 };
        strAsciiTostrHex(cArrAscii, cArrHex, strValue.GetLength());
        CString strHex;
        strHex.Format(_T("%s"), cArrHex);

        res = socketTcpWrite16Value(iAddr, strHex);
        if (!res)
        {
            sprintf(pError, "设置充电桩号失败");
            return 0;
        }
        //关闭socket
        socketTcpClose();

//读16个寄存器中的值转换成ASCII字符串
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        res = socketTcpReadAsciiValue(iAddr, 16);
        if (!res)
        {
            sprintf(pError, "读取充电桩号失败");
            return 0;
        }
        //关闭socket
        socketTcpClose();

调用1个寄存器读写

//写一个寄存器的值        
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        res = socketTcpWriteValue(iAddr, 0);
        if (!res)
        {
            sprintf(pError, _T("停止充电失败"));
            return 0;
        }
        //关闭socket
        socketTcpClose();

//读一个寄存器的值
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        res = socketTcpReadValue(iAddr, 1);
        if (!res)
        {
            sprintf(pError, _T("读取充电状态失败"));
            return 0;
        }
        //关闭socket
        socketTcpClose();

 

标签:return,SOCKET,int,res,CString,TCP,Modbus,strRecv,socket
来源: https://www.cnblogs.com/ckrgd/p/16507853.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有