代码:一旦读取到数据就立即返回给上层。
public string TXandRX(byte[] buffer, string data)//发送
{//RS485专用
start = false;// 状态
try
{
serialPort.Write(buffer, 0, buffer.Length);//串口发送
#region 计时
//====现在时间======================================
StringBuilder ATtime = new StringBuilder(String.Format("{0,9}",
DateTime.Now.Second.ToString() + "s"
+ DateTime.Now.Millisecond.ToString() + "ms:")); //固定长度9 右对齐
#endregion
//ui显示发送的命令
//wt_发送数据(str_发送后记时.Append(data).ToString());//ui显示发送的命令
if (Help_ModBus.Wt_set != null)
{// 数据包,文本
//Help_ModBus.Wt_set(buffer , data);
Help_ModBus.Wt_set(buffer, ATtime.ToString()+data);
}
//=======3 收尾===========================================
#region 等待RX
DateTime startTime = DateTime.Now;//记录开始时间
do//应答帧等待
{
if (start)
{
return get_RXstr;
}
if ((DateTime.Now - startTime).TotalMilliseconds > ReadTimeout)// 超时 1.5s
{
break;// 已经超时
}
} while (true);
#endregion
return null;
}
catch (Exception ex) { throw ex; }//显示错误
}
由接收事件去激活标志位:
// 串口接收事件
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{ //throw new NotImplementedException();
//===进入中断=========================================================================
#region 空数据
if (serialPort.BytesToRead == 0)//空
{
get_中断次数 += 1;
if (get_中断次数 > get_中断MAX次数) get_中断MAX次数 = get_中断次数;
//return;//空数据
throw new NotImplementedException("空包");
}
#endregion
get_中断次数 = 0;
//====现在时间===================================59秒999ms: 长度9
#region 标记时间
StringBuilder str_接收事件记时 = new
StringBuilder(string.Format("{0,9}",
DateTime.Now.Second.ToString() + "s"
+ DateTime.Now.Millisecond.ToString() + "ms:")); //固定长度9 右对齐
AT_Time = str_接收事件记时.ToString();
#endregion
#region 加载数据
byte[] buffer = new byte[serialPort.BytesToRead];//匹配的数据包
serialPort.Read(buffer, 0, serialPort.BytesToRead);//加载数据
//====解码显示=====================================
string data = helpstring.BytesToHexStrings(buffer);
#endregion
get_RXstr=data;
start = true;
if (Help_ModBus.Wt_get != null)//被绑定
{// 数据表, 时间
Help_ModBus.Wt_get(buffer, AT_Time+data); //↑ public event WT_串口接收事件 Wt_串口接收事件;//委托
}
}
using Models;//参数模型
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace help
{
///
/// Help_SerialPort comx = new Help_SerialPort();//串口对象
///
public class Help_SerialPort : SerialPort, Help_RTX
{
#region 全局
//====1定义委托============================================
public delegate void WT_GET_Data(byte[] butes, string data);//ui显示发送命令
public delegate void WT_SET_Data(byte[] butes, string data);//其他能实现发送功能的对象
#endregion
#region 字段
private SerialPort serialPort = null;//using System.IO.Ports;
Help_String helpstring = new Help_String();//文本编辑
int get_中断次数 = 0;
static int get_中断MAX次数;
bool start;
string get_RXstr;
#endregion
#region 属性
static public WT_GET_Data Wt_get;//get至ui层 ↑
static public WT_SET_Data Wt_set;//ui至 终端 ↓
public SerialPort serialport { get => serialPort; set => serialPort = value; }
//================================================================
public int ReadTimeout { get => serialPort.ReadTimeout; set => serialPort.ReadTimeout = value; }
public int rx单帧字节
{// ReceivedBytesThreshold = 5;//过滤合并,帧最小5字节
get { return serialPort.ReceivedBytesThreshold; }
set { serialPort.ReceivedBytesThreshold = value; }
}
public string AT_Time { get; private set; }// 标记时间
#region get参数
//===get===96n81===============================================
public bool isopen { get { return serialPort.IsOpen; } }
public string[] get可用串口 { get { return SerialPort.GetPortNames(); } }
///
/// "110","300","600","1200","2400","4800","9600","14400","28800","19200",
/// "38400","56000","57600","115200","230400","460800","921600"
///
public string[] get波特率 => new string[]{
"110","300","600","1200","2400","4800","9600","14400","28800","19200",
"38400","56000","57600","115200","230400","460800","921600"};
///
/// None Odd Even Mark Space ,
/// None 不发生奇偶校验检查。
/// Odd 设置奇偶校验位,使位数等于奇数。
/// Even 设置奇偶校验位,使位数等于偶数。
/// Mark 将奇偶校验位保留为 1。
/// Space将奇偶校验位保留为 0。
///
public string[] get校验位 { get { return Enum.GetNames(typeof(Parity)); } } // 校验位
///
/// "5", "6", "7", "8"
/// 数据位的值 5至8。默认8
///
public string[] get数据位 { get { return new string[] { "5", "6", "7", "8" }; } }
///
/// None One Two OnePointFive 。
/// 0 1 2 1.5
///
public string[] get停止位 { get { return Enum.GetNames(typeof(StopBits)); } } //
#endregion
#region set参数
//===set===96n81==============================================
///
/// serialPort1.PortName = name;
///
///
public void set串口名(string name)
{
try
{
serialPort.PortName = name;// 设置串口名
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
///
/// serialPort1.BaudRate = Convert.ToInt32(BaudRate, 10);//十进制的
///
///
public void set波特率(string BaudRate)
{
try
{
serialPort.BaudRate = Convert.ToInt32(BaudRate, 10);//十进制的
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
///
/// serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), Parity, true);//true 为忽略大小写
///
///
public void set校验位(string Parity)
{
try
{
serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Parity, true);//true 为忽略大小写
//return Enum.GetNames(typeof(Parity));
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
///
/// serialPort1.DataBits = Convert.ToInt32(DataBits, 10);//十进制的
///
///
public void set数据位(string DataBits)
{
try
{
serialPort.DataBits = Convert.ToInt32(DataBits, 10);//十进制的
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
///
/// serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits, true);
/// "None" "One" "Two" "OnePointFive"
///
/// StopBits.
public void set停止位(string StopBits)
{
try
{
serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits, true);
//return Enum.GetNames(typeof(StopBits));
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
#endregion
#endregion
#region 构造
public Help_SerialPort()
{
serialPort = new SerialPort();//实例对象
serialPort.DataReceived += SerialPort1_DataReceived;//绑定一个委托 接收事件
ReadTimeout = 200;// 等待RX 200ms
rx单帧字节 = 5;
}
// 串口接收事件
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{ //throw new NotImplementedException();
//===进入中断=========================================================================
#region 空数据
if (serialPort.BytesToRead == 0)//空
{
get_中断次数 += 1;
if (get_中断次数 > get_中断MAX次数) get_中断MAX次数 = get_中断次数;
//return;//空数据
throw new NotImplementedException("空包");
}
#endregion
get_中断次数 = 0;
//====现在时间===================================59秒999ms: 长度9
#region 标记时间
StringBuilder str_接收事件记时 = new
StringBuilder(string.Format("{0,9}",
DateTime.Now.Second.ToString() + "s"
+ DateTime.Now.Millisecond.ToString() + "ms:")); //固定长度9 右对齐
AT_Time = str_接收事件记时.ToString();
#endregion
#region 加载数据
byte[] buffer = new byte[serialPort.BytesToRead];//匹配的数据包
serialPort.Read(buffer, 0, serialPort.BytesToRead);//加载数据
//====解码显示=====================================
string data = helpstring.BytesToHexStrings(buffer);
#endregion
get_RXstr=data;
start = true;
if (Help_ModBus.Wt_get != null)//被绑定
{// 数据表, 时间
Help_ModBus.Wt_get(buffer, AT_Time+data); //↑ public event WT_串口接收事件 Wt_串口接收事件;//委托
}
}
public Help_SerialPort(SerialPort comx)//类是引用类型
{
serialPort = comx;
serialPort.DataReceived += SerialPort1_DataReceived;//绑定一个委托:接收事件
}
#endregion
#region 方法
#region 连接
public void open串口()
{
try
{
serialPort.Open();
}
//catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
catch (Exception ex) { throw ex; }
}
#endregion
#region 断开
public void close串口()
{ serialPort.Close(); }
#endregion
#region 发送
///
/// Modbus帧专用发送
///
/// 发送的数据
/// wt_ui参考
public string TXandRX(byte[] buffer, string data)//发送
{//RS485专用
start = false;// 状态
try
{
serialPort.Write(buffer, 0, buffer.Length);//串口发送
#region 计时
//====现在时间======================================
StringBuilder ATtime = new StringBuilder(String.Format("{0,9}",
DateTime.Now.Second.ToString() + "s"
+ DateTime.Now.Millisecond.ToString() + "ms:")); //固定长度9 右对齐
#endregion
//ui显示发送的命令
//wt_发送数据(str_发送后记时.Append(data).ToString());//ui显示发送的命令
if (Help_ModBus.Wt_set != null)
{// 数据包,文本
//Help_ModBus.Wt_set(buffer , data);
Help_ModBus.Wt_set(buffer, ATtime.ToString()+data);
}
//=======3 收尾===========================================
#region 等待RX
DateTime startTime = DateTime.Now;//记录开始时间
do//应答帧等待
{
if (start)
{
return get_RXstr;
}
if ((DateTime.Now - startTime).TotalMilliseconds > ReadTimeout)// 超时 1.5s
{
break;// 已经超时
}
} while (true);
#endregion
return null;
}
catch (Exception ex) { throw ex; }//显示错误
}
public void TX_发送数据(byte[] data)//发送
{
try
{
serialPort.Write(data, 0, data.Length);
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
public void TX_发送数据(string data)//发送
{
try
{
byte[] buffer = Encoding.Default.GetBytes(data);//以计算机的编码发送
serialPort.Write(buffer, 0, buffer.Length);// 开始发送
}
catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
}
#endregion
#endregion
#region old
//public override Socket connect连接(string t1, string t2)
//{
// //base.connect连接(t1, t2);
// open串口();
// return null;
//}
// public override string TX发送(string stringcmd)
// {
// //=======1 准备===========================================
// #region 帧头延时
// delay(delay_帧头等待);
// #endregion
// //=======2 加载===========================================
// //rx_str = null;//清空接收包
// byte[] buffer = TxCMD(stringcmd);//准备报文 //去除空白 StringsToHexBytes
// TXrs485_发送命令(buffer, stringcmd);// TX 发送数据
// #region 帧尾延时10ms
// //帧间隔3.5字符: 1除以波特率,乘以38.5
// //delay((int)(uint)(1000.0 / comx.serialPort.BaudRate * 38.5));//每帧间隔3.5字符
// delay(ReadTimeout);//10ms 伺服手册规定
// #endregion
// //=======3 收尾===========================================
// #region 等待方法
// DateTime startTime = DateTime.Now;//记录开始时间
// do//应答帧等待
// {
// if (get_RXstr != null)
// {
// return get_RXstr;
// }
// if ((DateTime.Now - startTime).TotalMilliseconds > ReadTimeout)// 超时 1.5s
// {
// break;// 已经超时
// }
// } while (true);
// #endregion
//#if (Debug3S)//数据帧节拍调试
// Thread.Sleep(3000);
//#endif
// return null;
// }
//public override void close关闭()
//{
// //base.close关闭();
// close串口();
//}
#endregion
#region 委托
//呼叫委托
void wt_发送数据(string data)
{
#if (WT收发显示)
//====3呼叫委托===========================//发送事件
//if (wt_串口发送事件 != null)
//{
wt_串口发送事件(data);//上层ui显示
//}
//else
//{// null 空对象报警
// throw new NotImplementedException();
//}
#endif
}
//呼叫委托
void wt_接收数据(string data)
{
#if (WT收发显示)
//====3呼叫委托===========================//接收事件
//if (wt_串口接收事件 != null)
//{
wt_串口接收事件(data);//上层ui显示
//}
//else
//{// null 空对象报警
// throw new NotImplementedException();
//}
#endif
}
#endregion
#region 文本处理
#region 字符串转等效数组
///
/// 字符串转等效数组
///
/// 原料
/// 成品
public byte[] StringsToHexBytes(string data)//change转换,string等效的byte[]
{
//清除所有空格
string str = data.Replace(" ", "");
//若字符个数为奇数,补一个0
str += str.Length % 2 != 0 ? "0" : "";
byte[] bytes = new byte[str.Length / 2];//用于返回结果
for (int i = 0, c = bytes.Length; i < c; i++)//获取bytes值
{
bytes[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
}
return bytes;
}
#endregion
#region 数组转等效字符串
///
/// 数组转等效字符串
///
///
///
public string BytesToHexStrings(byte[] data)//change转换 , byte[ ]等效的string
{
string str = string.Empty;
for (int i = 0; i < data.Length; i++)
{
str += data[i].ToString("X2");
}
return str;
}
#endregion
#region 数组计算CRC
///
/// 数组计算CRC
///
/// 原料
/// false小端
///
public byte[] getCRC16(byte[] bytes, bool b)//数组,端向,默认flase小端
{
int len = bytes.Length;
if (len > 0)
{
ushort crc = 0xFFFF;
for (int i = 0; i < len; i++)
{
crc = (ushort)(crc ^ (bytes[i]));
for (int j = 0; j < 8; j++)
{
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
}
}
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
byte lo = (byte)(crc & 0x00FF); //低位置
if (b)//端向
{
return new byte[] { hi, lo };//大端
}
else
{//默认小端
return new byte[] { lo, hi, };//小端
}
}
return new byte[] { 0, 0 };
}
///
/// 字符串计算CRC
///
/// 字符串
/// CRC
public string getCRC16(string cmd)
{
return BytesToHexStrings(getCRC16(StringsToHexBytes(cmd), false));//CRC
}
#endregion
#region StringCMD
///
/// 完整的命令
///
///
///
public string getString帧CRC(string data)//转换 带CRC的命令(用于ui查看)
{
//return data + BytesToHexStrings(getCRC16(StringsToHexBytes(data), false));//命令+CRC
return data + getCRC16(data); // 命令 + CRC
}
#endregion
#region TxCMD
///
/// 发送的数据帧
///
///
///
public byte[] TxCMD(string data)//change转换 串口发送命令
{
data.Replace(" ", "");//去除空白
byte[] buffer = StringsToHexBytes(data);
return buffer;//TX的
}
#endregion
#endregion
#region WT_委托
#endregion
#region 接口
public int connect(T a, T b)
{
try
{
serialPort.PortName = "COM3";
serialPort.BaudRate = 9600;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.DataBits = 8;
serialPort.Open();
return 0;
}
catch (Exception ex)
{
throw ex;
}
}
public object TXs(string cmd)
{
byte[] buffer = TxCMD(cmd);//准备报文 //去除空白 StringsToHexBytes
return TXandRX(buffer, cmd);
}
public object RXs()
{
throw new NotImplementedException();
}
public int Close()
{
serialPort.Close();
return 0;
}
#endregion
}
#region 串口日志
public class RZ_日志
{
#region 字段
//public DateTime sj_数据时间;
public int ff_数据时间;//当前时间的 毫秒
StringBuilder rz_日志生日;
public StringBuilder rz_日志;
#endregion
#region 属性
public int fz负载 { get; set; }
public string ff_最后数据内容 { get; set; }
public int 错误帧数 { get; set; }
#endregion
#region 构造
public RZ_日志()
{
//rz_日志生日 = DateTime.Now.Millisecond;//当前时间 毫秒
rz_日志生日 = new
StringBuilder(string.Format("{0,9}",
DateTime.Now.Hour.ToString() + "时"
+ DateTime.Now.Minute.ToString() + "分"
+ DateTime.Now.Second.ToString() + "秒"
+ DateTime.Now.Millisecond.ToString() + "ms:")); //固定长度9 右对齐
}
#endregion
#region 方法
public void append(string data)
{
StringBuilder sj时间 = new
StringBuilder(string.Format("{0,9}",
DateTime.Now.Second.ToString() + "秒"
+ DateTime.Now.Millisecond.ToString() + "ms:")); //固定长度9 右对齐
sj时间.Append(data);
rz_日志.Append(sj时间 + "\r\n");
}
public string show()
{
return rz_日志.ToString();
}
public void clear()
{
rz_日志.Clear();
}
public string show日志生日()
{
return rz_日志生日.ToString();
}
#endregion
#region 委托
#endregion
}
#endregion
// class Help_BaseData //全局
// {
//#if (STATIC)
// public static SerialPort COMX = new SerialPort();// 字段,全局变量,串口
// //public static event WT_串口发送事件 Wt_串口发送事件;
// //public static event WT_串口接收事件 Wt_串口接收事件;//委托
// public static WT_串口发送事件 Wt_串口发送事件;
// public static WT_串口接收事件 Wt_串口接收事件;//委托
//#else
// public SerialPort COMX = new SerialPort();// 字段,全局变量,串口
// public WT_串口发送事件 Wt_串口发送事件;
// public WT_串口接收事件 Wt_串口接收事件;//委托
//#endif
// }
}