from程序段
using ModbusRTULib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Modbus通信
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ModbusRTU objModbus = new ModbusRTU();//创建ModBusd对象
ushort dataType = 0;//数据类型:0 Signed;1 Usigned
///
/// 连接串口
///
///
///
private void btn_Connect_Click(object sender, EventArgs e)
{
try
{
objModbus.Connect(this.cbx_PortName.Text, Convert.ToInt32(this.cbx_BaudRate.Text), (Parity)(Convert.ToInt32(this.cbx_Parity.Text)), Convert.ToInt32(this.cbx_DataBits.Text), (StopBits)Convert.ToInt32(this.cbx_StopBits.Text));
if (objModbus.ConnectState == true)
{
MessageBox.Show("连接成功!");
}
}
catch(Exception ex)
{
MessageBox.Show("连接失败:"+ex.ToString());
}
}
///
/// 断开串口
///
///
///
private void btn_DisConnect_Click(object sender, EventArgs e)
{
try
{
objModbus.DisConnect();
}
catch(Exception ex)
{
MessageBox.Show("串口关闭失败:" + ex.ToString());
}
}
///
/// 读写操作
///
///
///
private void btn_WR_Click(object sender, EventArgs e)
{
if(objModbus.ConnectState==false)
{
MessageBox.Show("串口没有连接!");
return;
}
switch(this.cbx_RWSelect.Text)
{
case "01 读取输出线圈":
ReadOutputStatus();
break;
case "02 读取输入线圈":
ReadInputStatus();
break;
case "03 读取保持寄存器":
ReadHoldRegister();
break;
case "04 读取输入寄存器":
ReadInputRegister();
break;
case "05 写入单个输出线圈":
WriteSingleOutputStatus();
break;
case "06 写入单个保持寄存器":
WriteSingleHoldRegister();
break;
case "15 写入多个输出线圈":
WriteMultiOutputStatus();
break;
case "16 写入多个保持寄存器":
WriteMultiHoldRegister();
break;
default:
break;
}
}
///
/// 读取输出线圈01H
///
private void ReadOutputStatus()
{
try
{
byte[] result = objModbus.ReadOutputStatus(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), Convert.ToUInt16(this.txt_RWCount.Text));
//数据解析
if (result != null)
{
bool[] boolResult = GetBitArrayFromByteArray(result);
string WRResult = string.Empty;
for (int i = 0; i < Convert.ToUInt16(this.txt_RWCount.Text); i++)
{
WRResult += boolResult[i].ToString() + " ";
}
this.rtb_ReadData.AppendText(WRResult.Trim() + Environment.NewLine);
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:"+ex.ToString());
return;
}
}
///
/// 读取输入线圈02H
///
private void ReadInputStatus()
{
try
{
byte[] result = objModbus.ReadInputStatus(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), Convert.ToUInt16(this.txt_RWCount.Text));
//数据解析
if (result != null)
{
bool[] boolResult = GetBitArrayFromByteArray(result);
string WRResult = string.Empty;
for (int i = 0; i < Convert.ToUInt16(this.txt_RWCount.Text); i++)
{
WRResult += boolResult[i].ToString() + " ";
}
this.rtb_ReadData.AppendText(WRResult.Trim() + Environment.NewLine);
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 读取保持寄存器03H
///
private void ReadHoldRegister()
{
try
{
byte[] result = objModbus.ReadHoldRegister(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), Convert.ToUInt16(this.txt_RWCount.Text));
//解析数据
if (result != null)
{ //将字节数组转化为16位的short类型数据
switch(dataType)
{
case 0://Signed
for (int i = 0; i < Convert.ToUInt16(this.txt_RWCount.Text); i++)
{
int calResult = result[2 * i] * 256 + result[2 * i + 1];//16位word转换为int
if (calResult>32767)//如果是负数:1、减1;2、按位取反;3、转换为整型;4、加负号;
{
calResult = calResult - 1;
byte hi = (byte)(calResult / 256);
byte lo = (byte)(calResult % 256);
hi = (byte)~hi ;
lo = (byte) ~lo;
calResult = hi * 256 + lo;
this.rtb_ReadData.AppendText("-" + calResult + " ");
}
else//如果是正数
{
this.rtb_ReadData.AppendText(result[2 * i] * 256 + result[2 * i + 1] + " ");
}
}
this.rtb_ReadData.AppendText(Environment.NewLine);
break;
case 1://Unsigned
for (int i = 0; i < Convert.ToUInt16(this.txt_RWCount.Text); i++)
{
this.rtb_ReadData.AppendText(result[2 * i] * 256 + result[2 * i + 1] + " ");
}
this.rtb_ReadData.AppendText(Environment.NewLine);
break;
}
}
}
catch(Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 读取输入寄存器04H
///
private void ReadInputRegister()
{
try
{
byte[] result = objModbus.ReadInputRegister(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), Convert.ToUInt16(this.txt_RWCount.Text));
if (result != null)
{ //将字节数组转化为16位的short类型数据
switch (dataType)
{
case 0://Signed
for (int i = 0; i < Convert.ToUInt16(this.txt_RWCount.Text); i++)
{
int calResult = result[2 * i] * 256 + result[2 * i + 1];//16位word转换为int
if (calResult > 32767)//如果是负数:1、减1;2、按位取反;3、转换为整型;4、加负号;
{
calResult = calResult - 1;
byte hi = (byte)(calResult / 256);
byte lo = (byte)(calResult % 256);
hi = (byte)~hi;
lo = (byte)~lo;
calResult = hi * 256 + lo;
this.rtb_ReadData.AppendText("-" + calResult + " ");
}
else//如果是正数
{
this.rtb_ReadData.AppendText(result[2 * i] * 256 + result[2 * i + 1] + " ");
}
}
this.rtb_ReadData.AppendText(Environment.NewLine);
break;
case 1://Unsigned
for (int i = 0; i < Convert.ToUInt16(this.txt_RWCount.Text); i++)
{
this.rtb_ReadData.AppendText(result[2 * i] * 256 + result[2 * i + 1] + " ");
}
this.rtb_ReadData.AppendText(Environment.NewLine);
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 写入单个输出线圈05H
///
private void WriteSingleOutputStatus()
{
try
{
if (this.rbx_WriteData.Text == "")
{
MessageBox.Show("写入数据为空!");
return;
}//拆分数据并移除空格字符
string[] writeData = this.rbx_WriteData.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
//写入单个输出线圈必须只能有一个数据
if (writeData.Length != 1)
{
MessageBox.Show("写入方式选择错误!");
}//每一个布尔量写入长度必须为1
for (int i = 0; i < writeData.Length; i++)
{
if (writeData[i].Length != 1 || (!(writeData[i] == "0" || writeData[i] == "1")))
{
MessageBox.Show("写入布尔数据格式错误!");
}
}
bool boolValue = writeData[0] == "1" ? true : false;
bool result = objModbus.WriteSingleOutputStatus(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), 1, boolValue);
if (result != true)
{
MessageBox.Show("单个线圈写入失败!");
return;
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 写入单个保持寄存器06H
///
private void WriteSingleHoldRegister()
{
try
{
if(this.rbx_WriteData.Text=="")
{
MessageBox.Show("写入数据为空!");
return;
}//拆分数据并移除空格字符
string[] writeData = this.rbx_WriteData.Text.Split(new char[] { ' ' },StringSplitOptions.RemoveEmptyEntries);
if(writeData.Length != 1)
{
MessageBox.Show("写入方式选择错误!");
}
int intValue = Convert.ToInt32(writeData[0]);
//判断输入的是Signed还是Unsigned
if ((dataType==1&&intValue<0)||(dataType == 0 && intValue > 32767))
{
MessageBox.Show("选择的数据类型和输入数据类型不匹配!");
return;
}
//负数转换
byte[] writeBytes = new byte[2];//存储单个寄存器的值
if (intValue < 0)
{
intValue = -intValue;
writeBytes[0] = (byte)(intValue / 256);//高位
writeBytes[1] = (byte)(intValue % 256);//低位
writeBytes[0] = (byte)~writeBytes[0];
writeBytes[1] = (byte)~writeBytes[1];
intValue = writeBytes[0] * 256 + writeBytes[1] + 1;
}
writeBytes[0] = (byte)(intValue / 256);//高位
writeBytes[1] = (byte)(intValue % 256);//低位
bool result = objModbus.WriteSingleHoldRegister(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text),writeBytes);
if (result == false)
{
MessageBox.Show("单个寄存器写入失败!");
return;
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 写入多个输出线圈0FH
///
private void WriteMultiOutputStatus()
{
try
{
if (this.rbx_WriteData.Text == "")
{
MessageBox.Show("写入数据为空!");
return;
}//拆分数据并移除空格字符
string[] writeData = this.rbx_WriteData.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
//写入单个输出线圈必须只能有一个数据
if ((writeData.Length % 8) != 0)
{
MessageBox.Show("写入的数据不是8的整数倍!");
return;
}//每一个布尔量写入长度必须为1
for (int i = 0; i < writeData.Length; i++)
{
if (writeData[i].Length != 1 || (!(writeData[i] == "0" || writeData[i] == "1")))
{
MessageBox.Show("写入布尔数据格式错误!");
return;
}
}
List<byte> boolValue = new List<byte>();
//解析数据
for(int i=0;i<writeData.Length/8;i++)
{
int calResult=0;
for(int j=0;j<8;j++)
{
calResult += Convert.ToInt32(Math.Pow(2,j)*Convert.ToInt16(writeData[8 * i + j]));
}
boolValue.Add((byte)calResult);
}
bool result = objModbus.WriteMultiOutputStatus(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), 1, boolValue);
if (result != true)
{
MessageBox.Show("多个线圈写入失败!");
return;
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 写入多个保持寄存器10H
///
private void WriteMultiHoldRegister()
{
try
{
if (this.rbx_WriteData.Text == "")
{
MessageBox.Show("写入数据为空!");
return;
}//拆分数据并移除空格字符
string[] writeData = this.rbx_WriteData.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
List<byte> writeList = new List<byte>() ;//存储多个寄存器的值
for (int i=0;i<writeData.Length;i++)
{
int intValue = Convert.ToInt32(writeData[i]);
//判断输入的是Signed还是Unsigned
if ((dataType == 1 && intValue < 0) || (dataType == 0 && intValue > 32767))
{
MessageBox.Show("选择的数据类型和输入数据类型不匹配!");
return;
}
//负数转换
byte[] writeBytes = new byte[2];
if (intValue < 0)
{
intValue = -intValue;
writeBytes[0] = (byte)(intValue / 256);//高位
writeBytes[1] = (byte)(intValue % 256);//低位
writeBytes[0] = (byte)~writeBytes[0];
writeBytes[1] = (byte)~writeBytes[1];
intValue = writeBytes[0] * 256 + writeBytes[1] + 1;
}
writeList.Add((byte)(intValue / 256));//高位
writeList.Add((byte)(intValue % 256));//低位
}
bool result = objModbus.WriteMultiHoldRegister(Convert.ToByte(this.txt_SlaveAddr.Text), Convert.ToUInt16(this.txt_StartAddr.Text), writeList);
if (result == false)
{
MessageBox.Show("单个寄存器写入失败!");
return;
}
}
catch (Exception ex)
{
MessageBox.Show("读写失败:" + ex.ToString());
return;
}
}
///
/// 将一个字节转换成布尔数组
///
/// 字节
/// 位顺序
/// 布尔数组
private bool[] GetBitArrayFromByte(byte b,bool reverse=false)
{
bool[] array = new bool[8];
if(reverse)
{
for(int i=7;i>=0;i--)
{ //对于byte的每一位进行判定
array[i] = (b & 1) == 1; //判定byte的最后一位是否为1,若位1,则是true,否则是false
b = (byte)(b >> 1); //将byte右移1位
}
}
else
{
for (int i = 0; i <= 7; i++)
{ //对于byte的每一位进行判定
array[i] = (b & 1) == 1;//判定byte的最后一位是否为1,若位1,则是true,否则是false
b = (byte)(b >> 1); //将byte右移1位
}
}
return array;
}
///
/// 将一个字节数组转换成布尔数组
///
/// 字节数组
/// 位顺序
/// 布尔数组
private bool[] GetBitArrayFromByteArray(byte[] b, bool reverse = false)
{
List<bool> result = new List<bool>();
foreach(var item in b)
{
result.AddRange(GetBitArrayFromByte(item, reverse));
}
return result.ToArray();
}
///
/// 将一个字节数组转换成整型数组
///
/// 字节数组
/// 整型数组
private int[] GetIntArrayFromByteArray(byte[] b)
{
List<int> result = new List<int>();
for (int i=0;i<b.Length/2; i++)
{
result.Add(BitConverter.ToInt16(b, 2*i));
}
return result.ToArray();
}
///
/// 窗体加载
///
///
///
private void Form1_Load(object sender, EventArgs e)
{
#region 获取设备当前所有的串口
string[] iAllPortName = null;
try
{
iAllPortName = SerialPort.GetPortNames();
}
catch(Exception ex)
{
MessageBox.Show("获取设备串口失败:"+ex.ToString());
}
this.cbx_PortName.Items.AddRange(iAllPortName);
if(this.cbx_PortName.Items.Count>0)
{
this.cbx_PortName.SelectedIndex = 0;
}
#endregion
#region 波特率
this.cbx_BaudRate.Items.Add("9600");
this.cbx_BaudRate.Items.Add("19200");
if (this.cbx_BaudRate.Items.Count > 0)
{
this.cbx_BaudRate.SelectedIndex = 0;
}
#endregion
#region 校验
this.cbx_Parity.Items.Add("0");
this.cbx_Parity.Items.Add("1");
this.cbx_Parity.Items.Add("2");
if (this.cbx_Parity.Items.Count > 0)
{
this.cbx_Parity.SelectedIndex = 0;
}
#endregion
#region 数据位
this.cbx_DataBits.Items.Add("8");
this.cbx_DataBits.Items.Add("7");
if (this.cbx_DataBits.Items.Count > 0)
{
this.cbx_DataBits.SelectedIndex = 0;
}
#endregion
#region 停止位
this.cbx_StopBits.Items.Add("0");
this.cbx_StopBits.Items.Add("1");
this.cbx_StopBits.Items.Add("2");
if (this.cbx_StopBits.Items.Count > 0)
{
this.cbx_StopBits.SelectedIndex = 1;
}
#endregion
#region 读写选择
this.cbx_RWSelect.Items.Add("01 读取输出线圈");
this.cbx_RWSelect.Items.Add("02 读取输入线圈");
this.cbx_RWSelect.Items.Add("03 读取保持寄存器");
this.cbx_RWSelect.Items.Add("04 读取输入寄存器");
this.cbx_RWSelect.Items.Add("05 写入单个输出线圈");
this.cbx_RWSelect.Items.Add("06 写入单个保持寄存器");
this.cbx_RWSelect.Items.Add("15 写入多个输出线圈");
this.cbx_RWSelect.Items.Add("16 写入多个保持寄存器");
if (this.cbx_RWSelect.Items.Count > 0)
{
this.cbx_RWSelect.SelectedIndex = 0;
}
#endregion
#region 数据类型
this.cbx_DataType.Items.Add("Signed");
this.cbx_DataType.Items.Add("Unsigned");
if (this.cbx_DataType.Items.Count > 0)
{
this.cbx_DataType.SelectedIndex = 0;
}
#endregion
}
///
/// 数据类型选择切换
///
///
///
private void cbx_DataType_SelectedIndexChanged(object sender, EventArgs e)
{
switch (this.cbx_DataType.SelectedItem.ToString())
{
case "Signed":
dataType = 0;
break;
case "Unsigned":
dataType = 1;
break;
default:
break;
}
}
///
/// 功能码选择
///
///
///
private void cbx_RWSelect_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
ModbusRTULib的DLL文件代码
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ModbusRTULib
{
public class ModbusRTU
{
#region Field
private SerialPort MyCom;//创建串口对象
#endregion
#region Property
//超时时间
public int RcvTimeOut { get; set; } = 2000;
//连接状态
public bool ConnectState { get; set; } = false;
#endregion
#region Methods
///
/// 串口连接
///
/// 串口号
/// 波特率
/// 奇偶校验
/// 数据位
/// 停止位
public void Connect(string iPortName, int iBaudRate, Parity iParity, int iDataBits, StopBits iStopBits)
{
//实例化串口对象
MyCom = new SerialPort();
MyCom.PortName = iPortName;
MyCom.BaudRate = iBaudRate;
MyCom.Parity = iParity;
MyCom.DataBits = iDataBits;
MyCom.StopBits = iStopBits;
if (MyCom.IsOpen)
{
MyCom.Close();
}
MyCom.Open();
if(MyCom.IsOpen)
{
ConnectState = true;
}
}
///
/// 串口断开
///
public void DisConnect()
{
if(MyCom.IsOpen)
{
MyCom.Close();
ConnectState = false;
}
}
///
/// 读取输出线圈01H
///
/// 从站号
/// 起始地址
/// 读取线圈数量
///
public byte[] ReadOutputStatus(byte iDevAddr, ushort iStartAddr, ushort iLength)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x01);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//线圈数量
sendCommand.Add((byte)(iLength / 256));
sendCommand.Add((byte)(iLength % 256));
//CRC校验:
//1、查表的方式;
sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
/*byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);*/
byte[] response = null;
int byteLength = iLength % 8 == 0 ? iLength / 8 : iLength / 8 + 1;
if(SendAndReceive(sendCommand.ToArray(),ref response))
{
//验证报文
if(response.Length==5+byteLength)
{
if(response[0]==iDevAddr&&response[1]==0x01&&response[2]==byteLength&&CheckCRC(response))
{
return GetByteArray(response, 3, response.Length-5);
}
}
}
else
{
return null;
}
return null;
}
///
/// 读取输入线圈02H
///
/// 从站号
/// 起始地址
/// 读取线圈数量
///
public byte[] ReadInputStatus(byte iDevAddr, ushort iStartAddr, ushort iLength)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x02);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//线圈数量
sendCommand.Add((byte)(iLength / 256));
sendCommand.Add((byte)(iLength % 256));
//CRC校验:
//1、查表的方式;
sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
/*byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);*/
byte[] response = null;
int byteLength = iLength % 8 == 0 ? iLength / 8 : iLength / 8 + 1;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 5 + byteLength)
{
if (response[0] == iDevAddr && response[1] == 0x02 && response[2] == byteLength && CheckCRC(response))
{
return GetByteArray(response, 3, response.Length - 5);
}
}
}
else
{
return null;
}
return null;
}
///
/// 读取保持性寄存器03H
///
/// 从站号
/// 起始地址
/// 读取寄存器数量
///
public byte[] ReadHoldRegister(byte iDevAddr, ushort iStartAddr, ushort iLength)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x03);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//寄存器数量
sendCommand.Add((byte)(iLength / 256));
sendCommand.Add((byte)(iLength % 256));
//CRC校验
//1、查表法CRC计算
//sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);
byte[] response = null;
int byteLength = iLength * 2;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 5 + byteLength)
{
if (response[0] == iDevAddr && response[1] == 0x03 && response[2] == byteLength && CheckCRC(response))
{
return GetByteArray(response, 3, response.Length - 5);
}
}
}
else
{
return null;
}
return null;
}
///
/// 读取输入寄存器04H
///
/// 从站号
/// 起始地址
/// 读取寄存器数量
///
public byte[] ReadInputRegister(byte iDevAddr, ushort iStartAddr, ushort iLength)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x04);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//寄存器数量
sendCommand.Add((byte)(iLength / 256));
sendCommand.Add((byte)(iLength % 256));
//CRC校验
//1、查表法CRC计算
//sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);
byte[] response = null;
int byteLength = iLength * 2;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 5 + byteLength)
{
if (response[0] == iDevAddr && response[1] == 0x04 && response[2] == byteLength && CheckCRC(response))
{
return GetByteArray(response, 3, response.Length - 5);
}
}
}
else
{
return null;
}
return null;
}
///
/// 写入单个输出线圈05H
///
/// 从站号
/// 起始地址
/// 写入线圈数量
/// 写入线圈值
///
public bool WriteSingleOutputStatus(byte iDevAddr, ushort iStartAddr, ushort iLength, bool iValue)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x05);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//线圈值
byte[] outputStatus = new byte[2];
if(iValue==true)
{
sendCommand.Add(0xFF);
sendCommand.Add(0x00);
outputStatus[0] = 0xFF;
outputStatus[1] = 0x00;
}
else
{
sendCommand.Add(0x00);
sendCommand.Add(0x00);
outputStatus[0] = 0x00;
outputStatus[1] = 0x00;
}
//CRC校验:
//1、查表的方式;
sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
/*byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);*/
byte[] response = null;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 8)
{
if (response[0] == iDevAddr && response[1] == 0x05 && response[2] == ((byte)(iStartAddr / 256)) && response[3] == ((byte)(iStartAddr % 256))&& response[4]== outputStatus[0] && response[5] == outputStatus[1] && CheckCRC(response))
{
return true;
}
}
}
else
{
return false;
}
return false;
}
///
/// 写入单个字保持性寄存器06H
///
/// 从站号
/// 起始地址
/// 写入单个字寄存器数量
///
public bool WriteSingleHoldRegister(byte iDevAddr, ushort iStartAddr, byte[] iWriteByte)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x06);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//需要写入的数据
sendCommand.Add(iWriteByte[0]);
sendCommand.Add(iWriteByte[1]);
//CRC校验
//1、查表法CRC计算
//sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);
byte[] response = null;
int byteLength = 2;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 6 + byteLength)
{
if (response[0] == iDevAddr && response[1] == 0x06 && response[2] == (iStartAddr / 256) && response[3] == (iStartAddr % 256) && CheckCRC(response))
{
return true;
}
}
}
else
{
return false;
}
return false;
}
///
/// 写入多个输出线圈0FH
///
/// 从站号
/// 起始地址
/// 写入线圈数量
/// 写入线圈值
///
public bool WriteMultiOutputStatus(byte iDevAddr, ushort iStartAddr, ushort iLength, List<byte> iValue)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x0F);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//线圈数量
sendCommand.Add((byte)((iValue.Count * 8) / 256));
sendCommand.Add((byte)((iValue.Count * 8) % 256));
//字节数
sendCommand.Add((byte)(iValue.Count));
//线圈值
for (int i=0;i<iValue.Count;i++)
{
sendCommand.Add(iValue[i]);
}
//CRC校验:
//1、查表的方式;
sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
/*byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);*/
byte[] response = null;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 8)
{
if (response[0] == iDevAddr && response[1] == 0x0F && response[2] == ((byte)(iStartAddr / 256)) && response[3] == ((byte)(iStartAddr % 256)) && response[4] == ((byte)iValue.Count*8/256) && response[5] == ((byte)iValue.Count*8%256) && CheckCRC(response))
{
return true;
}
}
}
else
{
return false;
}
return false;
}
///
/// 写入多个字保持性寄存器10H
///
/// 从站号
/// 起始地址
/// 写入多个字寄存器数量
///
public bool WriteMultiHoldRegister(byte iDevAddr, ushort iStartAddr, List<byte> iWriteByte)
{
//报文拼接
//站号
List<byte> sendCommand = new List<byte>();
sendCommand.Add(iDevAddr);
//功能码
sendCommand.Add(0x10);
//起始地址
sendCommand.Add((byte)(iStartAddr / 256));
sendCommand.Add((byte)(iStartAddr % 256));
//写入数据的数量
int writeCount = iWriteByte.Count / 2;
sendCommand.Add((byte)(writeCount / 256));
sendCommand.Add((byte)(writeCount % 256));
//写入字节计数
sendCommand.Add((byte)(iWriteByte.Count));
//需要写入的数据
for(int i=0;i< writeCount;i++)
{
sendCommand.Add(iWriteByte[2*i]);
sendCommand.Add(iWriteByte[2*i+1]);
}
//CRC校验
//1、查表法CRC计算
//sendCommand.AddRange(Crc16(sendCommand.ToArray(), sendCommand.Count));
//2、根据CRC算法进行编写
byte hi, lo;//CRC校验的高位和低位
CalculateCRC(sendCommand.ToArray(), sendCommand.Count, out hi, out lo);
//低位在前,高位在后
sendCommand.Add(lo);
sendCommand.Add(hi);
byte[] response = null;
int byteLength = 2;
if (SendAndReceive(sendCommand.ToArray(), ref response))
{
//验证报文
if (response.Length == 6 + byteLength)
{
if (response[0] == iDevAddr && response[1] == 0x10 && response[2] == (iStartAddr / 256) && response[3] == (iStartAddr % 256) && response[4] == (writeCount / 256) && response[5] == (writeCount % 256) && CheckCRC(response))
{
return true;
}
}
}
else
{
return false;
}
return false;
}
///
/// 截取数组
///
///
///
///
///
private byte[] GetByteArray(byte[] source, int start, int count)
{
if (source == null || source?.Length <= 0) return null;
if (start < 0 || count < 0) return null;
if (source.Length < start + count) return null;
byte[] result = new byte[count];
Array.Copy(source, start, result, 0, count);
return result;
}
///
/// CRC校验
///
///
///
private bool CheckCRC(byte[] response)
{
byte[] crc = Crc16(response, response.Length - 2);
if(crc[0]==response[response.Length-2]&&crc[1]==response[response.Length-1])
{
return true;
}
else
{
return false;
}
}
///
/// 发送并接收报文
///
///
///
///
private bool SendAndReceive(byte[] send, ref byte[] response)
{
try
{
MyCom.Write(send, 0, send.Length);
byte[] buffer = new byte[1024];
MemoryStream ms = new MemoryStream();
DateTime start = DateTime.Now;
//串口的接收事件:
while (true)
{
Thread.Sleep(20);
if (MyCom.BytesToRead > 0)
{
int count = MyCom.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, count);
}
else
{
if ((DateTime.Now - start).TotalMilliseconds > this.RcvTimeOut)
{
ms.Dispose();
return false;
}
else if (ms.Length > 0)
{
break;
}
}
}
response = ms.ToArray();
return true;
}
catch
{
return false;
}
}
#region CRC校验
#region 查表法
///
/// 高位表
///
private static readonly byte[] aucCRCCHi =
{
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x01,0xc0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x01,0xc0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xc1,0x81,0x40
};
///
/// 低位表
///
private static readonly byte[] aucCRCCLo =
{
0x00,0xc0,0xc1,0x01,0xc3,0x03,0x02,0xc2,0xc6,0x06,0x07,0xc7,
0x05,0xc5,0xc4,0x04,0xcc,0x0c,0x0d,0xcd,0x0f,0xcf,0xce,0x0e,
0x0a,0xca,0xcb,0x0b,0xc9,0x09,0x08,0xc8,0xd8,0x18,0x19,0xd9,
0x1b,0xdb,0xda,0x1a,0x1e,0xde,0xdf,0x1f,0xdd,0x1d,0x1c,0xdc,
0x14,0xd4,0xd5,0x15,0xd7,0x17,0x16,0xd6,0xd2,0x12,0x13,0xd3,
0x11,0xd1,0xd0,0x10,0xf0,0x30,0x31,0xf1,0x33,0xf3,0xf2,0x32,
0x36,0xf6,0xf7,0x37,0xf5,0x35,0x34,0xf4,0x3c,0xfc,0xfd,0x3d,
0xff,0x3f,0x3e,0xfe,0xfa,0x3a,0x3b,0xfb,0x39,0xf9,0xf8,0x38,
0x28,0xe8,0xe9,0x29,0xeb,0x2b,0x2a,0xea,0xee,0x2e,0x2f,0xef,
0x2d,0xed,0xec,0x2c,0xe4,0x24,0x25,0xe5,0x27,0xe7,0xe6,0x26,
0x22,0xe2,0xe3,0x23,0xe1,0x21,0x20,0xe0,0xa0,0x60,0x61,0xa1,
0x63,0xa3,0xa2,0x62,0x66,0xa6,0xa7,0x67,0xa5,0x65,0x64,0xa4,
0x6c,0xac,0xad,0x6d,0xaf,0x6f,0x6e,0xae,0xaa,0x6a,0x6b,0xab,
0x69,0xa9,0xa8,0x68,0x78,0xb8,0xb9,0x79,0xbb,0x7b,0x7a,0xba,
0xbe,0x7e,0x7f,0xbf,0x7d,0xbd,0xbc,0x7c,0xb4,0x74,0x75,0xb5,
0x77,0xb7,0xb6,0x76,0x72,0xb2,0xb3,0x73,0xb1,0x71,0x70,0xb0,
0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,
0x55,0x95,0x94,0x54,0x9c,0x5c,0x5d,0x9d,0x5f,0x9f,0x9e,0x5e,
0x5a,0x9a,0x9b,0x5b,0x99,0x59,0x58,0x98,0x88,0x48,0x49,0x89,
0x4b,0x8b,0x8a,0x4a,0x4e,0x8e,0x8f,0x4f,0x8d,0x4d,0x4c,0x8c,
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,
0x41,0x81,0x80,0x40
};
///
/// 查表的方式CRC校验
///
///
///
///
private byte[] Crc16(byte[] pucFrame, int usLen)
{
int i = 0;
byte[] res = new byte[2] { 0xff, 0xff };
UInt16 iIndex = 0x0000;
while(usLen-->0)
{
iIndex = (UInt16)(res[0] ^ pucFrame[i++]);
res[0] = (byte)(res[1] ^ aucCRCCHi[iIndex]);
res[1] = aucCRCCLo[iIndex];
}
return res;
}
#endregion
#region 计算法
///
/// 计算CheckSum
///
///
///
///
private void CalculatepCheckSum(byte[] pByte, int nNumberOfBytes, out ushort pCheckSum)
{
int nBit;
ushort nShiftedBit;
pCheckSum = 0xFFFF;
for(int nByte=0; nByte<nNumberOfBytes; nByte++)
{
pCheckSum ^= pByte[nByte];
for(nBit=0; nBit<8; nBit++)
{
if((pCheckSum & 0x1)==1)
{
nShiftedBit = 1;
}
else
{
nShiftedBit = 0;
}
pCheckSum >>= 1;
if(nShiftedBit!=0)
{
pCheckSum ^= 0xA001;
}
}
}
}
///
/// 算法的方式CRC校验
///
///
///
///
///
private void CalculateCRC(byte[] pByte,int nNumberOfBytes, out byte hi, out byte lo)
{
ushort sum;
CalculatepCheckSum(pByte, nNumberOfBytes, out sum);
lo = (byte)(sum & 0xff);
hi = (byte)((sum & 0xFF00) >> 8);
}
#endregion
#endregion
#endregion
}
}