C#串口=>发送和接收

作用:串口发送命令后,等待下位机应答帧

代码:一旦读取到数据就立即返回给上层。

 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

    //    }



}

你可能感兴趣的:(C#串口,c#)