前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C# Modbus 通讯

C# Modbus 通讯

作者头像
全栈程序员站长
发布2022-09-14 11:01:13
1.7K0
发布2022-09-14 11:01:13
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

SpSetup 类 与Globalspace类

代码语言:javascript
复制
public partial class SpSetup : Form
    {
        #region 定义变量
        /// <summary>
        /// 发送报文
        /// </summary>
        public byte[] sendData = new byte[8];
        #endregion
        #region 构造读取状态报文
        /// <summary>
        /// 构造读取状态报文
        /// </summary>
        public void GetSendData()
        {
            byte[] data = new byte[6];
            byte[] Address = Globalspace.intToHexByte(Globalspace.startAddress);
            byte[] nubmer = Globalspace.intToHexByte(Globalspace.registerNumber);
            data[0] = Globalspace.ID;                                                   //从机地址
            data[1] = Convert.ToByte(Globalspace.modbusPointType.readHoldingRegister);  //功能号 - 读取保持寄存器
            data[2] = Address[0];                                                       //数据地址
            data[3] = Address[1];                                                       //数据地址
            data[4] = nubmer[0];                                                        //数据
            data[5] = nubmer[1];                                                        //数据
            for (int i = 0; i < 6; i++)
            {
                sendData[i] = data[i];                                                  //报文是用串口发送的
            }
            Byte[] CRC = new Byte[2];
            CRC = Globalspace.CRC_16(data);                                             //进行CRC效验
            sendData[6] = CRC[0];
            sendData[7] = CRC[1];
        }
        #endregion 
    }
代码语言:javascript
复制
class Globalspace
    {
        #region 定义变量
        /// <summary>
        /// 定义串口
        /// </summary>
        public static SerialPort sp = new SerialPort();
        /// <summary>
        /// Modbus 通讯地址
        /// </summary>
        public static byte ID = 2;
        /// <summary>
        /// Modbus 功通讯能码  
        /// </summary>
        public enum modbusPointType
        {
            readCoilStatus = 01,       //读取线圈状态
            readInputStatus = 02,      //读取输入状态
            readHoldingRegister = 03,  //读取保持寄存器
            readInputRegister = 04,    //读取输入寄存器
            writeSingleCoil = 05,      //强置单线圈
            writeSingleRegister = 06,  //保持寄存器写入(仅一点)
            writeMultipleCoil = 15,    //强置多线圈
            writeMultipleRegister = 16,//预置多寄存器
        };
        /// <summary>
        /// 起始地址
        /// </summary>
        public static int startAddress = 99;//读D100地址内容
        /// <summary>
        /// 读取数量
        /// </summary>
        public static int registerNumber = 1;//读一个
        /// <summary>
        /// 读写标志位 true —读;false —写。
        /// </summary>
        public static bool readORwrite = true;
        /// <summary>
        /// 读完成标志
        /// </summary>
        public static bool readDone = true; //读取数据完成后,清零
        /// <summary>
        /// 写完成标志
        /// </summary>
        public static bool writeDone = true;//写入数据完成后,清零
        /// <summary>
        /// 创建发送表
        /// </summary>
        public static ArrayList sendList = new ArrayList();//创建发送表
        /// <summary>
        /// 创建接收表
        /// </summary>
        public static ArrayList receivedList = new ArrayList();//创建接收表
        /// <summary>
        /// 读数据定时器
        /// </summary>
        public static System.Timers.Timer readTimer = new System.Timers.Timer(2000);
        /// <summary>
        /// 写数据定时器
        /// </summary>
        public static System.Timers.Timer writeTimer = new System.Timers.Timer(2000);

        public static string Info = "";
        /// <summary>
        /// 监听
        /// </summary>
        public static TcpListener listener;
        /// <summary>
        /// TCP/IP连接标志
        /// </summary>
        public static bool TcpIP = false;
        public static bool TH_SP = false;
        /// <summary>
        /// PLC通讯标志
        /// </summary>
        public static bool PLC = false;
       /// <summary>
       /// 接收数据
       /// </summary>
        public static ArrayList receivedDataList= new ArrayList();
        /// <summary>
        /// 检测结果
        /// </summary>
        public static string testResult;  //1-通过;0-失败;2-定位失败!

        #endregion

        #region  CRC_16计算
        /// <summary>
        /// CRC_16计算
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns>返回CRC值</returns>
        public static Byte[] CRC_16(Byte[] data) //CRC验证码计算
        {
            Byte[] CRC = new byte[2];
            UInt16 Reg_Crc = 0xFFFF;
            for (int i = data.Length; i > 0; i--)
            {
                Reg_Crc ^= data[data.Length - i];
                for (int j = 0; j < 8; j++)
                {
                    if ((Reg_Crc & 0x01) == 1)
                    {
                        Reg_Crc >>= 1;
                        Reg_Crc ^= 0xA001;
                    }
                    else
                    {
                        Reg_Crc >>= 1;
                    }
                }
            }
            CRC[0] = (byte)(Reg_Crc & 0xFF);
            CRC[1] = (byte)(Reg_Crc >>= 8);
            return CRC;
        }

        public static Byte[] CRC_16(ArrayList sendData) //CRC验证码计算
        {
            byte[] send = new byte[sendData.ToArray().Length];
            Object[] obj = Globalspace.sendList.ToArray();
            for (int i = 0; i < sendData.ToArray().Length; i++)
            {
                send[i] = (byte)obj[i];
            }
            Byte[] CRC = new byte[2];
            UInt16 Reg_Crc = 0xFFFF;
            for (int i = send.Length; i > 0; i--)
            {
                Reg_Crc ^= send[send.Length - i];
                for (int j = 0; j < 8; j++)
                {
                    if ((Reg_Crc & 0x01) == 1)
                    {
                        Reg_Crc >>= 1;
                        Reg_Crc ^= 0xA001;
                    }
                    else
                    {
                        Reg_Crc >>= 1;
                    }
                }
            }
            CRC[0] = (byte)(Reg_Crc & 0xFF);
            CRC[1] = (byte)(Reg_Crc >>= 8);
            return CRC;
        }


        #endregion

        #region 接收数据完成事件
        /// <summary>
        /// 接收数据完成事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                Control.CheckForIllegalCrossThreadCalls = false;
                int n = sp.BytesToRead;                      //接收字节数
                receivedList.Clear();                        //清空接收缓存
                byte[] Buuf = new byte[n];                  //接收字符串
                byte[] Data = new byte[n - 2];
                byte[] Data_CRC = new byte[2];
                sp.Read(Buuf, 0, n);

                if (n <= 8)
                {
                    for (int i = 0; i < n; i++)
                    {
                        if (i < n - 2)
                        {
                            Data[i] = Buuf[i];               //分离CRC重构字符串
                        }
                        receivedList.Add(Buuf[i]);
                    }
                    Data_CRC = CRC_16(Data);                //计算CRC_16校验码
                    //WriteLog();

                    if (Data[0] == ID)
                    {
                        if (readORwrite)
                        {
                           byte[] temp = ReadData(Data, Data_CRC, Buuf, n);
                           if(Buuf[2]>2)  //读处理
                           {
                               receivedDataList.Clear();
                               for(int i=0;i<temp.Length;i++)
                               {
                                   receivedDataList.Add(temp[i]);
                               }
                           }
                           else
                           {
                               if(temp[1]==(byte)0x01)
                               {
                                   PLC = true;
                               }
                               else
                               {
                                   PLC = false;
                               }
                           }
                        }
                        else
                        {
                            //WriteData(Data, Data_CRC, Buuf, n);//写处理
                            writeDone = true;
                        }
                    }
                    else
                    {
                        //MessageBox.Show("通讯错误:设备地址错误!", "系统提示");
                    }
                }
            }
            catch (Exception err)
            {
                //MessageBox.Show(err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
        #endregion
        
        #region 读状态方法
        /// <summary>
        /// 读状态
        /// </summary>
        /// <param name="Data">数据</param>
        /// <param name="Data_CRC">CRC 验证码</param>
        /// <param name="Buuf">接收数据</param>
        /// <param name="n">数据长度</param>
        private static byte[] ReadData(byte[] Data, byte[] Data_CRC, byte[] Buuf, int n)
        {
            byte[] dataTemp = new byte[Buuf.Length-5];
            if(n > 6) //小于7抛弃报文
            {
                if (Data[1] == Convert.ToByte(modbusPointType.readHoldingRegister))
                {
                    if (Buuf[n - 2] == Data_CRC[0] && Buuf[n - 1] == Data_CRC[1])
                    {
                        for (int i = 0; i < dataTemp.Length;i++ )
                        {
                            dataTemp[i] = Buuf[i + 3];
                        }
                        readDone = true;
                        return dataTemp;
                    }
                    else
                    {
                        MessageBox.Show("通讯错误:读取CRC校验码错误!", "系统提示");
                        return dataTemp;
                    }
                }
                else
                {
                    MessageBox.Show("通讯错误:读取功能码错误!", "系统提示");
                    return dataTemp;
                }
            }
            else
            {
                readDone = false;
                return dataTemp;
            }

        }
        #endregion

        #region 写数据方法
        /// <summary>
        /// 写数据
        /// </summary>
        /// <param name="Data">数据</param>
        /// <param name="Data_CRC">CRC_16校验码</param>
        /// <param name="Buuf">收到报文</param>
        /// <param name="n">收到数据长度</param>
        private static void WriteData(byte[] Data, byte[] Data_CRC, byte[] Buuf, int n)
        {
            if (n > 6)
            {
                if (Data[1] == Convert.ToByte(modbusPointType.writeMultipleRegister) || Data[1] == Convert.ToByte(modbusPointType.writeSingleRegister))
                {
                    if (Buuf[n - 2] == Data_CRC[0] && Buuf[n - 1] == Data_CRC[1])
                    {
                        writeDone = true;
                    }
                    else
                    {
                        MessageBox.Show("通讯错误:写入CRC校验码错误!", "系统提示");
                    }
                }
                else
                {
                    MessageBox.Show("通讯错误:写入功能码错误!", "系统提示");
                }
            }
        }
         #endregion

        #region int转换byte
        /// <summary>
        /// int转换byte
        /// </summary>
        /// <param name="inInt"></param>
        /// <returns></returns>
        public static byte[] intToHexByte(int inInt)
        {
            string hexString = inInt.ToString("x4");        //X:代表16进制   //4:代表每次的数据位数,当位数不足时自动补0
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
            {
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return returnBytes;
        }

        public static byte[] intToHexByte2(int inIt)
        {
            byte[] returnByte = BitConverter.GetBytes(inIt);
            return returnByte;
        }

        #endregion

        #region short转换byte
        /// <summary>
        /// short转换byte
        /// </summary>
        /// <param name="inShort"></param>
        /// <returns></returns>
        public static byte[] shortToByte(short inShort)
        {
            byte[] abyte0 = new byte[2];
            abyte0[1] = (byte)(0xff & inShort);
            abyte0[0] = (byte)((0xff00 & inShort) >> 8);
            return abyte0;
        }

        public static byte[] shortToByte2(short inShort)
        {
            byte[] returnBytes = BitConverter.GetBytes(inShort);
            return returnBytes;
        }
        #endregion

        #region 通讯超时处理
        /// <summary>
        /// 通讯超时处理
        /// </summary>
        public static void Timeout()
        {
            if (readORwrite)
            {
                readTimer.Elapsed += new System.Timers.ElapsedEventHandler(ReadOut);//到达时间的时候执行事件;
                readTimer.AutoReset = true;//设置是执行一次(false)还是一直执行(true);
                readTimer.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;
            }
            else
            {
                writeTimer.Elapsed += new System.Timers.ElapsedEventHandler(WriteOut);//到达时间的时候执行事件;
                writeTimer.AutoReset = false;//设置是执行一次(false)还是一直执行(true);
                writeTimer.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;
            }
        }
        /// <summary>
        /// 读超时事件
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        public static void ReadOut(object source, System.Timers.ElapsedEventArgs e)
        {
            readDone = true;
        }
        /// <summary>
        /// 写超时事件
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        public static void WriteOut(object source, System.Timers.ElapsedEventArgs e)
        {
            writeDone = true;
        } 
        #endregion

        #region 报文日志
        /// <summary>
        /// 入日志文件
        /// </summary>
        /// <param name="data">报文</param>
        public static void WriteLog()
        {
            FileStream tempStream = new FileStream(Environment.CurrentDirectory + @"\Log.txt", FileMode.Append);
            StreamWriter writer = new StreamWriter(tempStream);
            string[] data = new string[receivedList.Count];

            string st = null;
            for (int j = 0; j < receivedList.Count; j++)
            {
                data[j] = receivedList[j].ToString();
                st = st + data[j] + " ";
            }
            writer.WriteLine("接收数据:" + st + "\n");
            writer.Close();
            tempStream.Close();
           
        }
        #endregion

        #region 配置文件操作
        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="patch">文件路径</param>
        /// <param name="line">行数</param>
        /// <returns>返回字符串</returns>
        public static string ReadeFile(string patch, int line)
        {
            string readstr;
            string strTemp = "";
            FileStream tempStream = new FileStream(patch, FileMode.Open);
            StreamReader reader = new StreamReader(tempStream);
            for (int i = 1; !reader.EndOfStream; i++)
            {
                if (i == line)
                {
                    strTemp = reader.ReadLine();
                }
                else
                {
                    reader.ReadLine();
                }
            }
            reader.Close();
            reader.Dispose();
            readstr = strTemp;
            return readstr;
        }

        /// <summary>
        /// 更改数据
        /// </summary>
        /// <param name="curLine">修改的行数</param>
        /// <param name="newLineValue">保存的值</param>
        /// <param name="patch">文件的路径</param>
        public static void EditFile(int curLine, string newLineValue, string patch)
        {
            FileStream fs = new FileStream(patch, FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("utf-8"));
            string line = sr.ReadLine();
            StringBuilder sb = new StringBuilder();
            for (int i = 1; line != null; i++)
            {
                sb.Append(line + "\r\n");
                if (i != curLine - 1)
                    line = sr.ReadLine();
                else
                {
                    sr.ReadLine();
                    line = newLineValue;
                }
            }
            sr.Close();
            fs.Close();
            FileStream fs1 = new FileStream(patch, FileMode.Open, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs1);
            sw.Write(sb.ToString());
            sw.Close();
            fs.Close();
        }
        #endregion

    }

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157958.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年7月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档