我这个串口程序读取的时候正常,但是写入时就有问题,或者说我的思路有问题,请教指
namespace 串口
{
public partial class Form1 : Form
{
private SerialPort MyModbus;
private byte[] OutputStatus;
private byte[] InputStatus;
private byte[] HoldRegister;
private byte[] InputeRegister;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
#region 连接关闭串口
private void btn_Connect_Click(object sender, EventArgs e)
{
if (btn_Connect.Text == "Connect")
{
try
{
MyModbus = new SerialPort(cbx_Address.Text, 9600, Parity.None, 8, StopBits.One);
if (MyModbus.IsOpen)
{
MyModbus.Close();
}
MyModbus.Open();
btn_Connect.Text = "DisConnect";
MessageBox.Show("连接成功!!!", "提示");
Task.Run(new Action(() =>
{
while (true)
{
try
{
OutputStatus = GetOutputStatus(1, 0x01, 0, 10);
InputStatus = GetOutputStatus(1, 0x02, 0, 10);
HoldRegister = GetHoldRegister(1, 0x03, 0, 10);
Task.Run(new Action(() =>
{
bool[] b = GetByteArrayToBoolArray(OutputStatus, 10);
string str = GetBoolArrayToString(b, 10);
bool[] bb = GetByteArrayToBoolArray(InputStatus, 10);
string st = GetBoolArrayToString(bb, 10);
txt_in.Text = str + "\r\n" + st; ;
ushort us = GetByteArrayToUshort(HoldRegister, 0);
txt_out.Text = (Convert.ToString(us));
}));
}
catch (Exception)
{
return;
}
}
}));
}
catch (Exception ex)
{
MessageBox.Show("连接失败!!!" + ex.Message, "提示");
}
}
else
{
MyModbus.Close();
btn_Connect.Text = "Connect";
}
}
#endregion
#region 串口数据写入
private void btn_Set_Click(object sender, EventArgs e)
{
SetOutputStatus(1, 0x05, Convert.ToUInt16(txt_Set.Text), true);
}
#endregion
#region 读写数据
/// <summary>
/// 读取输入输出线圈状态(0x01)(0x02)
/// </summary>
/// <param name="Address">从站地址</param>
/// <param name="FunctionCode">功能码</param>
/// <param name="StartAddress">起始地址</param>
/// <param name="Length">数据长度</param>
/// <returns>字节数组</returns>
private byte[] GetOutputStatus(byte Address, byte FunctionCode, ushort StartAddress, ushort Length)
{
//1、拼接报文
List<byte> SendComand = new List<byte>();
SendComand.Add(Address);//从站地址
SendComand.Add(FunctionCode);//功能码
SendComand.Add((byte)(StartAddress / 256)); //起始地址
SendComand.Add((byte)(StartAddress % 256));
SendComand.Add((byte)(Length / 256)); //数据长度
SendComand.Add((byte)(Length % 256));
SendComand.AddRange(CRC16_Check(SendComand.ToArray()));//CRC校验
//2、发送报文
MyModbus.Write(SendComand.ToArray(), 0, SendComand.Count);
//3、接收报文
Thread.Sleep(50);//延时20MS
int ReadLength = MyModbus.BytesToRead;//获取接收缓冲区大小
byte[] ReadBuffer = new byte[ReadLength];//创建数据缓冲区
MyModbus.Read(ReadBuffer, 0, ReadBuffer.Length);//将数据读取到数据缓冲区
//4、验证报文
int bitLength = Length % 8 == 0 ? Length / 8 : Length / 8 + 1;//返回数据字节数
byte[] DataValue = new byte[bitLength];//读取的数据
if (ReadBuffer.Length == 5 + bitLength)
{
if (CheckCRC(ReadBuffer))
{
//5、解析报文
Array.Copy(ReadBuffer, 3, DataValue, 0, DataValue.Length);
}
}
return DataValue;
}
/// <summary>
/// 读取保持寄存器(0x03)输入寄存器(0x04)
/// </summary>
/// <param name="Address">从站地址</param>
/// <param name="FunctionCode">功能码</param>
/// <param name="StartAddress">起始地址</param>
/// <param name="Length">读取长度</param>
/// <returns>字节数组</returns>
private byte[] GetHoldRegister(byte Address, byte FunctionCode, ushort StartAddress, ushort Length)
{
//1、拼接报文
List<byte> SendComand = new List<byte>();
SendComand.Add(Address);//从站地址
SendComand.Add(FunctionCode);//功能码
SendComand.Add((byte)(StartAddress / 256)); //起始地址
SendComand.Add((byte)(StartAddress % 256));
SendComand.Add((byte)(Length / 256)); //数据长度
SendComand.Add((byte)(Length % 256));
SendComand.AddRange(CRC16_Check(SendComand.ToArray()));//CRC校验
//2、发送报文
MyModbus.Write(SendComand.ToArray(), 0, SendComand.Count);
//3、接收报文
Thread.Sleep(50);//延时20MS
int ReadLength = MyModbus.BytesToRead;//获取接收缓冲区大小
byte[] ReadBuffer = new byte[ReadLength];//创建数据缓冲区
MyModbus.Read(ReadBuffer, 0, ReadBuffer.Length);//将数据读取到数据缓冲区
//4、验证报文
int ByteLength = Length * 2;//返回数据字节数
byte[] DataValue = new byte[ByteLength];//读取的数据
if (ReadBuffer.Length == 5 + ByteLength)
{
if (CheckCRC(ReadBuffer))
{
//5、解析报文
Array.Copy(ReadBuffer, 3, DataValue, 0, DataValue.Length);
}
}
return DataValue;
}
/// <summary>
/// 写单个线圈(0x05)
/// </summary>
/// <param name="Address">从站地址</param>
/// <param name="FunctionCode">功能码</param>
/// <param name="SetAddress">写入地址</param>
/// <param name="SetValue">写入值</param>
/// <returns>字节数组</returns>
private bool SetOutputStatus(byte Address, byte FunctionCode, ushort SetAddress, bool SetValue)
{
ushort Value = 0;
if (SetValue == true)
{
Value = 0xff00;
}
else
{
Value = 0;
}
//1、拼接报文
List<byte> SendComand = new List<byte>();
SendComand.Add(Address);//从站地址
SendComand.Add(FunctionCode);//功能码
SendComand.Add((byte)(SetAddress / 256)); //写入地址
SendComand.Add((byte)(SetAddress % 256));
SendComand.Add((byte)(Value / 256)); //数据长度
SendComand.Add((byte)(Value % 256));
SendComand.AddRange(CRC16_Check(SendComand.ToArray()));//CRC校验
//2、发送报文
MyModbus.Write(SendComand.ToArray(), 0, SendComand.Count);
//3、接收报文
Thread.Sleep(50);//延时20MS
int ReadLength = MyModbus.BytesToRead;//获取接收缓冲区大小
byte[] ReadBuffer = new byte[ReadLength];//创建数据缓冲区
MyModbus.Read(ReadBuffer, 0, ReadBuffer.Length);//将数据读取到数据缓冲区
//4、验证报文
if (ReadBuffer.Length == 8 && CheckCRC(ReadBuffer))
{
//5、解析报文
return true;
}
else
{
return false;
}
}
/// <summary>
/// 写单个寄存器(0x06)
/// </summary>
/// <param name="Address">从站地址</param>
/// <param name="FunctionCode">功能码</param>
/// <param name="SetAddress">写入地址</param>
/// <param name="SetValue">写入值</param>
/// <returns>字节数组</returns>
private bool SetHoldRegister(byte Address, byte FunctionCode, ushort SetAddress, ushort SetValue)
{
//1、拼接报文
List<byte> SendComand = new List<byte>();
SendComand.Add(Address);//从站地址
SendComand.Add(FunctionCode);//功能码
SendComand.Add((byte)(SetAddress / 256)); //起始地址
SendComand.Add((byte)(SetAddress % 256));
SendComand.Add((byte)(SetValue / 256)); //数据长度
SendComand.Add((byte)(SetValue % 256));
SendComand.AddRange(CRC16_Check(SendComand.ToArray()));//CRC校验
//2、发送报文
MyModbus.Write(SendComand.ToArray(), 0, SendComand.Count);
//3、接收报文
Thread.Sleep(50);//延时20MS
int ReadLength = MyModbus.BytesToRead;//获取接收缓冲区大小
byte[] ReadBuffer = new byte[ReadLength];//创建数据缓冲区
MyModbus.Read(ReadBuffer, 0, ReadBuffer.Length);//将数据读取到数据缓冲区
//4、验证报文
if (ReadBuffer.Length == 8 && CheckCRC(ReadBuffer))
{
//5、解析报文
return true;
}
else
{
return false;
}
}
#endregion
#region CheckCRC
/// <summary>
/// 接收报文CRC验证
/// </summary>
/// <param name="buffer">接收的字节数组</param>
/// <returns>布尔值(true数据正常/false数据异常)</returns>
private bool CheckCRC(byte[] buffer)
{
if (buffer == null) return false;
if (buffer.Length <= 2) return false;
int length = buffer.Length;
byte[] Value = new byte[length - 2];
Array.Copy(buffer, 0, Value, 0, Value.Length);
byte[] CRCbuf = CRC16_Check(Value);
return CRCbuf[0] == buffer[length - 2] && CRCbuf[1] == buffer[length - 1];
}
#endregion
#region CRC校验
/// <summary>
/// CRC16校验
/// </summary>
/// <param name="data">字节数组</param>
/// <returns>16位字节数组</returns>
public static byte[] CRC16_Check(byte[] data)
{
byte CRC16Lo;
byte CRC16Hi; //CRC寄存器
byte CL; byte CH; //多项式码&HA001
byte SaveHi; byte SaveLo;
byte[] tmpData;
//int I;
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]); //每一个数据与CRC寄存器进行异或
for (Flag = 0; Flag <= 7; Flag++)
{
SaveHi = CRC16Hi;
SaveLo = CRC16Lo;
CRC16Hi = (byte)(CRC16Hi >> 1); //高位右移一位
CRC16Lo = (byte)(CRC16Lo >> 1); //低位右移一位
if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1
{
CRC16Lo = (byte)(CRC16Lo | 0x80); //则低位字节右移后前面补1
} //否则自动补0
if ((SaveLo & 0x01) == 0x01) //如果LSB为1,则与多项式码进行异或
{
CRC16Hi = (byte)(CRC16Hi ^ CH);
CRC16Lo = (byte)(CRC16Lo ^ CL);
}
}
}
byte[] ReturnData = new byte[2];
ReturnData[0] = CRC16Lo; //CRC高位
ReturnData[1] = CRC16Hi; //CRC低位
return ReturnData;
}
#endregion
#region 数据转换
/// <summary>
/// 将字节数组转换为布尔数组
/// </summary>
/// <param name="buffer">字节数组</param>
/// <param name="Length">布尔数组长度</param>
/// <returns>布尔数组</returns>
public static bool[] GetByteArrayToBoolArray(byte[] buffer, int Length)
{
bool[] b = new bool[Length];
if (Length <= buffer.Length * 8)
{
BitArray array = new BitArray(buffer);
for (int i = 0; i < Length; i++)
{
b[i] = array[i];
}
return b;
}
else
{
return null;
}
}
/// <summary>
/// 字节数组转换为16位无符号整型
/// </summary>
/// <param name="buffer">字节数组</param>
/// <param name="index">起始字节索引</param>
/// <returns>16位无符号短整型</returns>
public static ushort GetByteArrayToUshort(byte[] buffer, int index = 0)
{
byte[] data = new byte[2];
Array.Copy(buffer, index, data, 0, 2);
data = data.Reverse().ToArray();
ushort us = BitConverter.ToUInt16(data, 0);
return us;
}
/// <summary>
/// 将布尔数组转换为字符串
/// </summary>
/// <param name="b">布尔数组</param>
/// <param name="Count">数据个数</param>
/// <returns>字符串</returns>
public static string GetBoolArrayToString(bool[] b, int Count)
{
string str = string.Empty;
if (b != null)
{
bool[] buffer = new bool[Count];
Array.Copy(b, 0, buffer, 0, Count);
for (int i = 0; i < Count; i++)
{
str += buffer[i].ToString() + " ";
}
return str;
}
else
{
return str = "转换失败!!!";
}
}
#endregion