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

    }

 

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JavaWeb-过滤器Filter学习(四)敏感词过滤实例

    JavaWeb-过滤器Filter学习(四)敏感词过滤实例通过Filter来实现留言板的敏感词过滤…思路很简单,我们这里的敏感词是直接先放进去的,实际项目中,肯定是存在数据库中。在Filter过滤器中,我们先拿到用户提交的留言,如果出现了敏感词,我们就用*号来替换。代码演示:index.jsp:<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@taglibur

    2022年5月27日
    31
  • SSL探03

    SSL探03

    2022年1月11日
    59
  • source insight3.5 注册码:SI3US-361500-17409[通俗易懂]

    source insight3.5 注册码:SI3US-361500-17409[通俗易懂]直接安装,启动后输入注册码即可。

    2022年10月3日
    0
  • Centos7下载和安装教程

    Centos7下载和安装教程1.CentOS下载CentOS是免费版,推荐在官网上直接下载,网址:https://www.centos.org/download/DVDISO:普通光盘完整安装版镜像,可离线安装到计算机硬盘上,包含大量的常用软件,一般选择这种镜像类型即可。EverythingISO:包含了完整安装版的内容,并对其进行补充,集成了所有软件。MinimalISO:这个版本为精简版的镜像,可以安…

    2022年6月13日
    32
  • LARS算法的几何意义

    LARS算法的几何意义1  LARS算法简介  Efron于2004年发表在AnnalsofStatistics的文章LEASTANGLEREGRESSION中提出LARS算法,其核心思想是提出一种新的solutionpath(求解路径),即在已经入选的变量中,寻找一个新的路径,使得在这个路径上前进时,当前残差与已入选变量的相关系数都是相同的,直到找出新的比当前残差相关系数最大的

    2022年6月23日
    23
  • perl正则表达式练习[通俗易懂]

    perl正则表达式练习[通俗易懂]perl正则表达式初级练习网站:https://regexone.com/

    2022年5月27日
    25

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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