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)


相关推荐

  • CSS自定义鼠标指针样式「建议收藏」

    CSS自定义鼠标指针样式「建议收藏」还记得Web1.0时代的那些苦逼岁月吗?你想尽一切办法来优化你的网站.还要饱受IE6惨无人道的虐待,举个栗子,IE中那些害死人不偿命的滚动条,我一直记得第三方类库CometCursor.CometCursor非常强悍,主要用来创建和加载自定义鼠标光标样式。现在可能你会觉得当初的那些实现手段特别老土,但有时又确实需要定制一下光标图案,那么一起来看看CSS怎么实现吧,It’sSoEasy,哪里不会点哪里!

  • 并行编程中的lock free技术

    并行编程中的lock free技术lockfree(中文一般叫“无锁”,一般指的都是基于CAS指令的无锁技术)是利用处理器的一些特殊的原子指令来避免传统并行设计中对锁(lock)的使用。众所周知,锁在解决并行过程中资源访问问题的同时可能会引入诸多新的问题,比如死锁(deadlock),另外锁的申请/释放对性能也有不小的影响,当然最大的问题还在于使用锁的代码模块通常难以进行组合。lockfree的目标就是要消除锁对编程

  • 京东抢购Python脚本

    京东抢购Python脚本京东购物车抢购商品Python代码1.准备工作2.代码1.准备工作环境要求:Python3.8.1;Firefox浏览器插件安装:1.安装Python相关库(在Windows的cmd里面安装) pipinstallselenium pipinstalldatetime2.安装Firefox浏览器驱动:GeckoDriver提取码:e4tv(确保电脑已经有Firefox),…

  • matlab做kmo检验的代码,急求 KMO测度和Bartlett 的球形度检验的计算原公式[通俗易懂]

    matlab做kmo检验的代码,急求 KMO测度和Bartlett 的球形度检验的计算原公式[通俗易懂]1、关于KMO公式,您从如下matlab源程序代码中不难得出,我已经用Excel就计算出来了,跟SPSS的计算结果完全一致。iX=inv(X);%X是原始数据的相关系数矩阵R,而inv表示求X的逆矩阵iXS2=diag(diag((iX.^-1)));%将iX的对角线的元素取倒数,其余元素都变为0,得到矩阵S2AIS=S2*iX*S2;%anti-image…

  • dirsearch安装教程「建议收藏」

    dirsearch安装教程「建议收藏」dirsearch安装教程dirsearch是一个用python开发的网站目录扫描工具github下载地址笔者安装在windows上下载的是zip包因为需要用到python直接解压到安装python环境的位置打开cmd进入dirsearch目录后,输入命令进行安装pythonsetup.py安装成功后就可以直接使用了pythondirsearch.py-uip命令详解dirsearch-h到这里就结束了…

  • 「 运动控制 」“ADRC自抗扰控制技术”(Active Disturbance Rejection Control)研究

    「 运动控制 」“ADRC自抗扰控制技术”(Active Disturbance Rejection Control)研究近年来,虽然现代控制理论取得了一系列成果,但是在工业领域的应用并没有代替PID控制。这说明现代控制理论在实际应用的过程中受到一定的限制,控制理论与生产生活实际仍然存在一定的代沟。对此,韩京清总结为基于“模型论”的控制理论在解决问题时没有以生产生活中的不确定性作为重点,没有抓住生产生活实践中所切实需要的核心。韩京清先生针对生产生活实践中存在的问题潜心研究,积极探索,逐步分析PID理论与现代控…

发表回复

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

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