ningshuxia
2022-10-28 3ccb7c60e1ed8b6748ed7fb8b64b1dbe50d62abf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IStation.DataDockingSocket
{
    //ModBus RTU标准:
    static public class ModBusRtuHelper
    {
        /// <summary>
        /// 得到16位的CRC检验码:低位在前[0],高位在后[1]
        /// </summary>
        /// <param name="message4PT">注意输入的消息长度要求包含CRC的2位,否则计算出来CRC不正确</param>
        /// <param name="CRC"></param>
        public static void GetCRC16(byte[] message, ref byte[] CRC)
        {
            //Function expects a modbus message4PT of any length as well as a 2 byte CRC array in which to 
            //return the CRC values:
            if (CRC == null)
                CRC = new byte[2];
 
            ushort CRCFull = 0xFFFF;
            byte CRCHigh = 0xFF, CRCLow = 0xFF;
            char CRCLSB;
 
            for (int i = 0; i < (message.Length) - 2; i++)
            {
                CRCFull = (ushort)(CRCFull ^ message[i]);
 
                for (int j = 0; j < 8; j++)
                {
                    CRCLSB = (char)(CRCFull & 0x0001);
                    CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);
 
                    if (CRCLSB == 1)
                        CRCFull = (ushort)(CRCFull ^ 0xA001);
                }
            }
            CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
            CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
        }
 
        //
        // 摘要:
        //     构建查询消息
        //
        // 参数:
        //    address设备地址,注意是byte格式,最大255
        //    func功能码
        //    startRegister 寄存器开始地址(用十进制的地址)
        //    numRegister   寄存器数量
        //    
        // 返回结果
        //    消息List类型,不成功返回NULL
        public static void BuildSendMessage(byte address, byte func, ushort start, ushort registers, ref byte[] message)
        {
            //构建消息 message数据长度要求包含最后2位的校验码
            message = new byte[8];
            message[0] = address;
            message[1] = func;
            message[2] = (byte)(start >> 8);
            message[3] = (byte)start;
            message[4] = (byte)(registers >> 8);
            message[5] = (byte)registers;
 
            //计算16位的CRC校验码 
            byte[] CRC = new byte[2];
            GetCRC16(message, ref CRC);
 
            //赋值校验码
            message[message.Length - 2] = CRC[0];
            message[message.Length - 1] = CRC[1];
        }
 
        /// <summary>
        /// 写入多个
        /// </summary>
        /// <param name="address"></param>
        /// <param name="start"></param>
        /// <param name="registers"></param>
        /// <param name="v"></param>
        /// <param name="message"></param>
        public static void BuildSendMessage16(byte address, ushort start, ushort registers, float v, ref byte[] message)
        {
            byte[] bytes4Float = BitConverter.GetBytes(v);
 
            //        09-03-08-40-40-00-00-40-40-00-00-EE-57
            //构建消息 message数据长度要求包含最后2位的校验码
            message = new byte[12];
            message[0] = address;
            message[1] = 0x10;
            message[2] = (byte)(start >> 8);
            message[3] = (byte)start;
            message[4] = (byte)(registers >> 8);
            message[5] = (byte)registers;
            message[6] = (byte)04;//2个就*2
            message[7] = bytes4Float[3];//要倒过来 0x40;
            message[8] = bytes4Float[2];//要倒过来0x80;
            message[9] = bytes4Float[1];//要倒过来0x00;
            message[10] = bytes4Float[0];//要倒过来0x00;
 
            //计算16位的CRC校验码 
            byte[] CRC = new byte[2];
            GetCRC16(message, ref CRC);
 
            //赋值校验码
            message[message.Length - 2] = CRC[0];
            message[message.Length - 1] = CRC[1];
        }
 
        /// <summary>
        /// 写入单个
        /// </summary>
        /// <param name="address"></param>
        /// <param name="start"></param>
        /// <param name="registers"></param>
        /// <param name="v"></param>
        /// <param name="message"></param>
        public static void BuildSendMessage06(byte address, ushort start, ushort registers, int v, ref byte[] message)
        {
            byte[] bytes4Value = BitConverter.GetBytes(v);
 
            //构建消息 message数据长度要求包含最后2位的校验码
            message = new byte[8];
            message[0] = address;
            message[1] = 0x06;
            message[2] = (byte)(start >> 8);
            message[3] = (byte)start;
 
            message[4] = bytes4Value[1];//要倒过来0x00;
            message[5] = bytes4Value[0];//要倒过来0x00;
 
            //计算16位的CRC校验码 
            byte[] CRC = new byte[2];
            GetCRC16(message, ref CRC);
 
            //赋值校验码
            message[message.Length - 2] = CRC[0];
            message[message.Length - 1] = CRC[1];
        }
 
        /**
    * 将int数值转换为占四个字节的byte数组,本方法适用于(低位在前,高位在后)的顺序。 和bytesToInt()配套使用
    * @param value
    *            要转换的int值
    * @return byte数组
    */
        public static byte[] intToBytes(int value)
        {
            byte[] src = new byte[2];
 
            src[1] = (byte)((value >> 8) & 0xFF);
            src[0] = (byte)(value & 0xFF);
            return src;
        }
        /**
        * 将int数值转换为占四个字节的byte数组,本方法适用于(高位在前,低位在后)的顺序。  和bytesToInt2()配套使用
        */
        public static byte[] intToBytes2(int value)
        {
            byte[] src = new byte[2];
 
            src[2] = (byte)((value >> 8) & 0xFF);
            src[3] = (byte)(value & 0xFF);
            return src;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <param name="func"></param>
        /// <param name="start"></param>
        /// <param name="registers"></param>
        /// <returns></returns>
        public static byte[] BuildSendMessage(byte address, byte func, ushort start, ushort registers)
        {
            byte[] message = null;
            BuildSendMessage(address, func, start, registers,ref message);
            return message;
        }
 
        /// <summary>
        /// 得到收到的信息中的数据
        /// </summary>
        /// <param name="byteMessage"></param>
        /// <param name="rValueArray"></param>
        /// <returns></returns>
        public static int GetReceivedDatas(byte[] byteMessage, out double[] rValueArray)
        {
            rValueArray = null;
 
            string strMessage = BitConverter.ToString(byteMessage, 0, byteMessage.Length); // byte[] -> 16进制字符串
            string[] strValueList = strMessage.Split('-');
 
            int iReadAddress = -1;
            if (strValueList.Length <= 6)
            {
                //!数据没有收完,直接返回
                return -1;
            }
            try
            {
                iReadAddress = int.Parse(strValueList[0]); //!获得设备ID
 
                //int iFunID = int.Parse(strValueList[1]);//!读取功能吗
 
                int dataNum = int.Parse(strValueList[2]) / 2;//!获得数据长度(除以2就是数据个数)
                if (dataNum < 1)
                    return -1;
 
                List<double> rValueList = new List<double>();
                for (int i = 0; i < dataNum; i++)
                {
                    string strHigh = strValueList[3 + 2 * i];
                    string strLow = strValueList[3 + 2 * i + 1];
 
                    byte byteHigh = Convert.ToByte(strHigh);
                    byte byteLow = Convert.ToByte(strLow);
 
                    double rValue = byteHigh * 256.0 + byteLow;
 
                   // rValue = rValue * 10000 / Math.Pow(10, GetDecimalPlaces(1));
                    rValueList.Add(rValue);
                }
 
                rValueArray = rValueList.ToArray();
            }
            catch
            {
                return -1;
            }
 
            return iReadAddress;
        }
 
        //
        // 摘要:
        //     检查收到的信息的校验码是否正确
        //
        // 参数:
        //      得到的二进制数据
        //
        // 返回结果:
        //    是否成功
        public static bool CheckReceivedMessage(byte[] byteMessage)
        {
            //计算校验码
            byte[] CRC = new byte[2];
            GetCRC16(byteMessage, ref CRC);
 
            //比较是否和消息中的校验码一致
            if (CRC[0] == byteMessage[byteMessage.Length - 2] && CRC[1] == byteMessage[byteMessage.Length - 1])
                return true;
            else
                return false;
        }
 
    }
 
}