C# Modbus 通讯

C# Modbus 通讯SpSetup类与Globalspace类publicpartialclassSpSetup:Form{#region定义变量///<summary>///发送报文///</summary>publicbyte[]sendData=ne…

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

SpSetup 类  与Globalspace类 

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 
    }

 

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

    }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 如何安装java环境和如何配置java环境

    如何安装java环境和如何配置java环境

    2021年10月23日
  • 第五章《函数》

    第五章《函数》

  • 原生ajax请求的五个步骤

    原生ajax请求的五个步骤什么是ajax?通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。ajax的优点:1.实现局部更新(无刷新状态下)2.减轻了服务器端的压力ajax的缺点:1.破坏了浏览器前进和后退机制(因为ajax自动更新机制)2.一个Ajax请求多了,也会出现页面加载慢的情况。3.搜索引擎的支持程度比较低。4.ajax的安全性问题不太好(可以用数据加密解决)。注:如果要使用ajax必须要有后端环境的支持(服务器端)。

  • OSError: Failed to open file b‘C:\\Users\\\xe6\x96\x87…\\ AppData\\Local\\Temp\\scipy-xxxxx 报错

    OSError: Failed to open file b‘C:\\Users\\\xe6\x96\x87…\\ AppData\\Local\\Temp\\scipy-xxxxx 报错关于使用《FirstOrderMotionModelforImageAnimation》Github项目中所遇到的OSError:Failedtoopenfileb’C:\\Users\\\xe6\x96\x87…\\AppData\\Local\\Temp\\scipy-xxxxx报错原因:路径中包含中文解决方案:修改计算机环境变量中的Temp文件夹路径OSError:Failedtoopenfileb’C:\Users\\xe6\x96\x87…\AppDa

  • 对自己感悟最深的话_感悟句子致自己

    对自己感悟最深的话_感悟句子致自己人的一生中只有七次机会,平均每七年拥有一次,大概在25岁到75岁,第一次通常抓不到,因为太年轻,最后一次也抓不到,因为太老。中途还有2次因为自己错过,所以抓不到。所以对于人来说人真正才会有三次机会,人的一生真正只有三次,只有称为能改变自己命运的机会才可以称作是机会。其实人生的机会很快就会过去。能真正抓住机会的人,首先靠的是自己个人的能力;其次靠的是环境。一个人如果素质不好,行为不好,那么即使你再…

  • WPF 设置透明背景颜色[通俗易懂]

    WPF 设置透明背景颜色[通俗易懂]Backgroud=“Transparent”

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号