C# 485通讯读取和写入设备遇到的问题。
1,调用读取方法时,如果设备里面的值超过了256时,读取出来的内容是错误的。
2,调用写入方法时,当写入的值超过256时,写进设备的值也是错误的。
代码是我从CSDN上东拼西凑过来的,所以不介意修改这里面的代码,只要能满足需求。在此预祝大家新年快乐工作顺利。
源代码如下:
操作界面代码↓
using System;
using System.Linq;
using System.IO.Ports;
using System.Windows.Forms;
using System.Collections.Generic;
namespace PLCTest
{
public partial class Form1 : Form
{
private ModbusRTU modbusRTU;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
modbusRTU = new ModbusRTU("COM5", 9600, Parity.None, 8, StopBits.One);
}
/// <summary>
/// 打开端口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnOpen_Click(object sender, EventArgs e)
{
bool isSuccess = modbusRTU.Open();
if (isSuccess)
{
MessageBox.Show("端口打开成功");
}
else
{
MessageBox.Show("端口打开失败");
}
}
/// <summary>
/// 关闭端口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClose_Click(object sender, EventArgs e)
{
bool isSuccess = modbusRTU.Close();
if (isSuccess)
{
MessageBox.Show("端口关闭成功");
}
else
{
MessageBox.Show("端口关闭失败");
}
}
/// <summary>
/// 读取数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRead_Click(object sender, EventArgs e)
{
//读取参数说明:2=站点,1002=起始位置,1=读取长度
modbusRTU.ReadMethod("2", 1002, 1);
ModbusRTU.Result result = modbusRTU.GetReceivedData();
if (result.IsSuccess)
{
MessageBox.Show("读取成功,值:" + result.RefMsg);
}
else
{
MessageBox.Show("读取失败");
}
}
/// <summary>
/// 写入数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnWrite_Click(object sender, EventArgs e)
{
//写入参数说明:2=站点,1005=起始位置,0=写入的数据
modbusRTU.WriteMethod("2", 1005, 0);
}
}
}
ModbusRTU.cs代码↓
using System;
using System.Linq;
using System.IO.Ports;
using System.Threading;
using System.Collections.Generic;
namespace PLCTest
{
internal class ModbusRTU
{
private Result refResult;
private SerialPort serialPort;
int p; int m = 0;
byte[] TxData2 = new byte[] { };
bool ReadResult = true;
//读取结果封装内部类
public class Result
{
public bool IsSuccess;
public string RefMsg;
}
/// <summary>
/// 构建对象
/// </summary>
/// <param name="PortName">串口</param>
/// <param name="baudRate">波特率</param>
/// <param name="parity">奇偶验证位</param>
/// <param name="dataBits">数据位</param>
/// <param name="stopBits">停止位</param>
public ModbusRTU(string PortName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
this.serialPort = new SerialPort() { PortName = PortName, BaudRate = baudRate, DataBits = dataBits, Parity = parity, StopBits = stopBits };
//订阅SerialDataReceivedEventHandler事件
this.serialPort.DataReceived += new SerialDataReceivedEventHandler(this.DataReceived);
}
/// <summary>
/// 打开串口
/// </summary>
/// <returns></returns>
public bool Open()
{
try { if (!this.serialPort.IsOpen) this.serialPort.Open(); }
catch { return false; }
return true;
}
/// <summary>
/// 关闭串口
/// </summary>
/// <returns></returns>
public bool Close()
{
try { if (this.serialPort.IsOpen) this.serialPort.Close(); }
catch { return false; }
return true;
}
/// <summary>
/// 读取数据的方法
/// </summary>
/// <param name="deviceAddress">站点</param>
/// <param name="startAddress">起始位置</param>
/// <param name="length">读取长度</param>
public void ReadMethod(string deviceAddress, int startAddress, int length)
{
refResult = new Result();
ReadResult = false;
int n = 6;
byte[] buf = new byte[n];
buf[0] = Convert.ToByte(deviceAddress);
buf[1] = Convert.ToByte(3);
if (startAddress <= 255)
{
buf[2] = Convert.ToByte(0);
buf[3] = Convert.ToByte(startAddress);
}
else
{
if (Convert.ToString(startAddress, 16).Length < 4)
{
int b = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(0, 1), 16);
buf[2] = Convert.ToByte(b);
int c = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(1, 2), 16);
buf[3] = Convert.ToByte(c);
}
else
{
int b = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(0, 2), 16);
buf[2] = Convert.ToByte(b);
int c = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(2, 2), 16);
buf[3] = Convert.ToByte(c);
}
}
if (length <= 255)
{
buf[4] = Convert.ToByte(0);
buf[5] = Convert.ToByte(length);
}
else
{
if (Convert.ToString(length, 16).Length < 4)
{
int d = Convert.ToInt32(Convert.ToString(length, 16).Substring(0, 1), 16);
buf[4] = Convert.ToByte(d);
int f = Convert.ToInt32(Convert.ToString(length, 16).Substring(1, 2), 16);
buf[5] = Convert.ToByte(f);
}
else
{
int d = Convert.ToInt32(Convert.ToString(length, 16).Substring(0, 2), 16);
buf[4] = Convert.ToByte(d);
int f = Convert.ToInt32(Convert.ToString(length, 16).Substring(2, 2), 16);
buf[5] = Convert.ToByte(f);
}
}
p = length * 2 + 5;
byte[] buf1 = new byte[n + 2];
byte[] ReturnData = new byte[2];
ReturnData = CRC16_C(buf);
for (int i = 0; i < n; i++)
{
buf1[i] = buf[i];
}
buf1[n] = ReturnData[1];
buf1[n + 1] = ReturnData[0];
//buf1是要写入的数据, 0是写入数据的起始位置,n + 2是要写入的数据长度。
serialPort.Write(buf1.ToArray(), 0, n + 2);
}
/// <summary>
/// 写入数据的方法
/// </summary>
/// <param name="deviceAddress">站点</param>
/// <param name="startAddress">起始位置</param>
/// <param name="value">写入值</param>
/// <returns></returns>
public bool WriteMethod(string deviceAddress, int startAddress, int value)
{
int n = 6;
byte[] buf = new byte[n];
buf[0] = Convert.ToByte(deviceAddress);
buf[1] = Convert.ToByte(6); // 写入命令的功能码为6
if (startAddress <= 255)
{
buf[2] = Convert.ToByte(0);
buf[3] = Convert.ToByte(startAddress);
}
else
{
if (Convert.ToString(startAddress, 16).Length < 4)
{
int b = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(0, 1), 16);
buf[2] = Convert.ToByte(b);
int c = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(1, 2), 16);
buf[3] = Convert.ToByte(c);
}
else
{
int b = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(0, 2), 16);
buf[2] = Convert.ToByte(b);
int c = Convert.ToInt32(Convert.ToString(startAddress, 16).Substring(2, 2), 16);
buf[3] = Convert.ToByte(c);
}
}
if (value <= 255)
{
buf[4] = Convert.ToByte(0);
buf[5] = Convert.ToByte(value);
}
else
{
if (Convert.ToString(value, 16).Length < 4)
{
int d = Convert.ToInt32(Convert.ToString(value, 16).Substring(0, 1), 16);
buf[4] = Convert.ToByte(d);
int f = Convert.ToInt32(Convert.ToString(value, 16).Substring(1, 2), 16);
buf[5] = Convert.ToByte(f);
}
else
{
int d = Convert.ToInt32(Convert.ToString(value, 16).Substring(0, 2), 16);
buf[4] = Convert.ToByte(d);
int f = Convert.ToInt32(Convert.ToString(value, 16).Substring(2, 2), 16);
buf[5] = Convert.ToByte(f);
}
}
byte[] buf1 = new byte[n + 2];
byte[] ReturnData = new byte[2];
ReturnData = CRC16_C(buf);
for (int i = 0; i < n; i++)
{
buf1[i] = buf[i];
}
buf1[n] = ReturnData[1];
buf1[n + 1] = ReturnData[0];
serialPort.Write(buf1, 0, n + 2);
return true;
}
/// <summary>
/// 获取数据接收事件反馈的结果
/// </summary>
/// <returns></returns>
public Result GetReceivedData()
{
while (!ReadResult)
{
Thread.Sleep(100);
}
return refResult;
}
/// <summary>
/// 数据接收事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
refResult = new Result();
int n = serialPort.BytesToRead;
byte[] TxData = new byte[n];//声明一个临时数组存储当前来的串口数据
serialPort.Read(TxData, 0, n); //读取缓冲数据
m = m + n;
Array.Resize(ref TxData2, m);//改写数组大小
TxData.CopyTo(TxData2, m - TxData.Length);
if (m == p)
{
byte[] data = new byte[p - 2];
for (int i = 0; i < TxData2.Length - 2; i++)
{
data[i] = TxData2[i];
}
byte[] data2 = new byte[2];
data2[0] = TxData2[TxData2.Length - 2];
data2[1] = TxData2[TxData2.Length - 1];
byte[] data1 = new byte[2];
data1 = CRC16_C(data);
if (data1[0] == data2[1] && data1[1] == data2[0])
{
string result = string.Empty;
for (int j = 3; j <= m - 4; j = j + 2)
{
string s1 = TxData2[j].ToString();
string s2 = TxData2[j + 1].ToString();
string s = s1 + s2;
int g = Convert.ToInt32(s, 10);
string h = g.ToString();
result += h;
}
refResult.RefMsg = result;
refResult.IsSuccess = true;
}
else
{
refResult.IsSuccess = false;
}
m = 0;
}
ReadResult = true;
}
/// <summary>
/// 转换
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public byte[] CRC16_C(byte[] data)
{
byte CRC16Lo;
byte CRC16Hi;
byte CL; byte CH;
byte SaveHi; byte SaveLo;
byte[] tmpData;
int Flag;
CRC16Lo = 0xFF;
CRC16Hi = 0xFF;
CL = 0x01;
CH = 0xA0;
tmpData = data;
for (int i = 0; i < tmpData.Length; i++)
{
CRC16Lo = (byte)(CRC16Lo ^ tmpData[i]);
for (Flag = 0; Flag <= 7; Flag++)
{
SaveHi = CRC16Hi;
SaveLo = CRC16Lo;
CRC16Hi = (byte)(CRC16Hi >> 1);
CRC16Lo = (byte)(CRC16Lo >> 1);
if ((SaveHi & 0x01) == 0x01)
{
CRC16Lo = (byte)(CRC16Lo | 0x80);
}
if ((SaveLo & 0x01) == 0x01)
{
CRC16Hi = (byte)(CRC16Hi ^ CH);
CRC16Lo = (byte)(CRC16Lo ^ CL);
}
}
}
byte[] ReturnData = new byte[2];
ReturnData[0] = CRC16Hi;
ReturnData[1] = CRC16Lo;
return ReturnData;
}
}
}