如何读写串口

首先定义一个串口管理类的脚本,来进行串口管理。

数据定义

 public delegate void ProcessMsgDelegate(List<byte> recvMsg_);
    /// <summary>
    /// 串口数据包(消息)处理
    /// </summary>
    public event ProcessMsgDelegate OnProcessMsg;
    /// <summary>
    /// 数据包长度
    /// </summary>
    private const int dataLength = 8;
    //!串口资源
    SerialPort mSerialPort = null;
    Thread serialPortThread_ = null;
    static volatile bool isSerialPortRunning_ = true;
    static volatile bool isSerialPortFinished_ = true;

    //!读取的锁
    Object readLockObject_ = new Object();
    //!在串口线程接收到的消息
    List<List<byte>> allRecvMsgs_ = new List<List<byte>>();
    //!写入的锁
    Object writeLockObject_ = new Object();
    //!发送到串口中的消息
    List<List<byte>> allSendMsgs_ = new List<List<byte>>();
    enum eReadState
    {
        //!FF的消息头
        eRS_ReadHead_FF,
        //!AA的消息头
        eRS_ReadHead_AA,
        //!消息的数据
        eRS_Msg_Data,
        //!开始消息读取
        eRS_Msg_Start,
    }
    private eReadState readState_ = eReadState.eRS_Msg_Start;
    private volatile string errorMsg_ = "";

    //!ReadTimeOut cout
    /// <summary>
    /// 计算超时次数
    /// </summary>
    private int readTimeOutCout = 0;

开始监听串口:

   /// <summary>
    /// 开始监听串口
    /// </summary>
    /// <param name="portName"></param>
    public void StartListning(string portName)
    {
        try
        {
            mSerialPort = new SerialPort(portName, 115200, Parity.None, 8, StopBits.One);//使用指定的方式进行初始化串口,指定COM口和端口和方式
            mSerialPort.ReadTimeout = 1;
            mSerialPort.WriteTimeout = 1000;

            if (mSerialPort.IsOpen == false)
            {
                mSerialPort.Open();
            }
            serialPortThread_ = new Thread(new ThreadStart(serialPortRunning));
            serialPortThread_.Start();
        }
        catch(System.Exception ex)
        {
            Debug.LogError("initialize serial port failed:" + ex.ToString());
        }
    }

串口处理:

    /// <summary>
    /// 监听线程
    /// 只接受FF AA 开头的数据包
    /// 其他为异常数据
    /// </summary>
    void serialPortRunning()
    {
        //!读取的数据缓冲区
        List<byte> recvMsg_ = new List<byte>();
        isSerialPortRunning_ = true;
        isSerialPortFinished_ = false;
        while (isSerialPortRunning_)
        {
            try
            {
                lock (writeLockObject_)
                {
                    if (allSendMsgs_.Count != 0)
                    {
                        List<byte> sndMsg_ = allSendMsgs_[0];
                        mSerialPort.Write(sndMsg_.ToArray(), 0, sndMsg_.Count);
                        allSendMsgs_.RemoveAt(0);
                    }
                }
                byte rByte_=System.Convert.ToByte(mSerialPort.ReadByte());
                
                if (rByte_ == 0xFF)
                {
                    readState_ = eReadState.eRS_ReadHead_FF;
                    recvMsg_.Add(rByte_);
                }
                else if (rByte_ == 0xAA)
                {
                    if (readState_ == eReadState.eRS_ReadHead_FF && (recvMsg_.Count <= 2 || recvMsg_.Count > 8))//防止中间数据有FF AA头
                    {
                        readState_ = eReadState.eRS_ReadHead_AA;
                        recvMsg_ = new List<byte>();
                        recvMsg_.Add(0xFF);
                        recvMsg_.Add(0xAA);
                    }
                    else
                    {
                        recvMsg_.Add(rByte_);
                    }
                }
                else
                {
                    if (readState_ != eReadState.eRS_Msg_Data)
                    {
                        readState_ = eReadState.eRS_Msg_Data;
                    }
                    recvMsg_.Add(rByte_);
                }

                if (recvMsg_.Count > 0x03)//接收到数据头,和数据长度,根据数据长度读取对应长度的消息
                {
                    if (recvMsg_.Count == recvMsg_[2] + 2)
                    {
                        readTimeOutCout = 0;
                        if (recvMsg_[0] == 0xFF && recvMsg_[1] == 0xAA)//这个地方本应该还要处理消息的校验,暂时忽略 && CheckOutDate(recvMsg_)
                        {
                            lock (allRecvMsgs_)
                            {
                                allRecvMsgs_.Add(recvMsg_);
                            }
                            recvMsg_ = new List<byte>();
                        }
                        else
                        {
                            string msg_ = "";
                            foreach (byte data_ in recvMsg_)
                            {
                                msg_ += string.Format("0x{0:x} ", data_);
                            }
                            errorMsg_ = "invalid msg:" + msg_;
                            UnityEngine.Debug.LogError(errorMsg_);
                        }
                    } 
                }
            }
            catch (System.Exception ex)
            {
                if ((ex.GetType() != typeof(System.TimeoutException)))  //忽略读取数据超时异常
                {
                    Debug.Log("serial port exception:" + ex.ToString());
                }
                else
                {
                    readTimeOutCout++;
                    if(readTimeOutCout>=3000)  //串口超时处理
                    {
                        ReadDataTimeOut();
                        Debug.Log("serial port exception:" + ex.ToString());
                    }
                }

            }
            //Debug.Log("循环中");
        }
        isSerialPortFinished_ = true;
    }
 /// <summary>
    /// 当收到一条完整消息后开始执行消息段
    /// </summary>
    void Update()
    {
        lock (allRecvMsgs_)
        {
            if (allRecvMsgs_.Count > 0)
            {
                foreach (List<byte> recvMsg_ in allRecvMsgs_)
                {
                    if (OnProcessMsg!=null) OnProcessMsg(recvMsg_);
                }
                allRecvMsgs_.Clear();
            }
        }
    }

向串口发送数据:

    /// <summary>
    /// 向串口发送数据
    /// </summary>
    /// <param name="writeBuffer"></param>
    public void SendData(byte[] writeBuffer)
    {
        lock (writeLockObject_)
        {
            try
            {
                List<byte> sndMsg_ = new List<byte>(writeBuffer);
                allSendMsgs_.Add(sndMsg_);
            }
            catch(System.ArgumentNullException ex)
            {
                UnityEngine.Debug.LogError("SendData to io:" + ex.Message);
            }
        }
    }
    /// <summary>
    /// 停止监听串口,但是有缺陷,会随着线程的阻塞而阻塞主进程(这里还需要改进一下)
    /// </summary>
    public void StopListning()
    {
        isSerialPortRunning_ = false;
        while (!isSerialPortFinished_) { }

        if (mSerialPort != null)
        {
            try
            {
                mSerialPort.Close();
            }
            catch (System.Exception ex)
            {
                Debug.LogError("串口关闭异常:" + ex.Message);
            }
        }
        mSerialPort = null;
    }

超时处理:

    /// <summary>
    /// 串口超时的处理
    /// </summary>
    public void ReadDataTimeOut()
    {
        readTimeOutCout = 0;
    }

 

最后的是检验方法,很多时候不大需要

 /// <summary>
    /// 对一条完整的消息进行校验
    /// 校验方法:取数据段和的低位和最后一段消息比较,相等即有效消息
    /// 消息头两段,命令一段,消息校验一段,内容最少一段,最少大于五段消息
    /// </summary>
    /// <param name="Mes"></param>
    /// <returns></returns>
    private bool CheckOutDate(List<byte> Mes)
    {
        int count = Mes.Count;
        string hexadecimalStr = "";
        long dateSum = 0;
        if (count < 6 )
            return false;
        for (int i = 3; i < count - 1; i++)
        {
            dateSum += Mes[i];
        }
        hexadecimalStr = System.Convert.ToString(dateSum, 16);
        if (System.Convert.ToInt32(hexadecimalStr.Substring(hexadecimalStr.Length - 2 > 0 ? (hexadecimalStr.Length - 2) : 0),16) == Mes[count - 1])
        {
            return true;   
        }
        else
        {
            return false;
        }
    }
    /// <summary>
    /// 生成校验位
    /// </summary>
    /// <returns></returns>
    private void CreateCheckOutDate(ref byte[] date)
    {
        int byteSum = 0; string hexadecimalStr = "";
        for (int i = 2; i < date.Length-1; i++)
        {
            byteSum += date[i];
        }
        hexadecimalStr = System.Convert.ToString(byteSum, 16);
        date[date.Length - 1] = (byte) System.Convert.ToInt32(hexadecimalStr.Substring(hexadecimalStr.Length - 2 > 0 ? (hexadecimalStr.Length - 2) : 0), 16);
        //return date[date.Length - 1];
    }

 

转载于:https://www.cnblogs.com/jenke/p/4784827.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值