• c# 串口


    记录一下事件经过。

    现在的项目是采集仪表的数据。以前都是配置好串口,波特率,数据位,停止位,校验位然后就可以接受仪表发送来的数据进行解析了。

    现在遇到了一种新的仪表,分为两个模式。一个是数据模式,像其他仪表一样,将仪表的数据主动发送给串口,但是不能接受命令数据。一种是命令模式,可以接受命令数据,但是不会主动发送数据。也就是说你想要实现远程控制仪表,给他发送命令的话,就需要主动发送获取数据的命令去主动读数。

    /// <summary>
    /// 串口类
    /// </summary>
    private SerialPort _spCom;  这是微软提供的串口类

    /// <summary>
            ///     打开串口,并注册数据接收方法
            /// </summary>
            /// <returns></returns>
            public bool Open()
            {
                var rtn = false;
                if (_curWeightCfg != null)//_curWeightCfg 是从配置文件中读取配置的串口信息,COM口,波特率,数据位,停止位,校验位
                {
                    WeightDeviceLogger.Debug(
                        string.Format("设置串口参数。ComPort={0},Baudrate={1},DataBits={2}, Parity={3},StopSize={4}",
                            _curWeightCfg.ComPort, _curWeightCfg.Baudrate, _curWeightCfg.ByteSize, _curWeightCfg.Parity,
                            _curWeightCfg.StopSize));
    
                    _spCom = new SerialPort(_curWeightCfg.ComPort, int.Parse(_curWeightCfg.Baudrate))
                    {
                        DataBits = _curWeightCfg.ByteSize,
                        ReadBufferSize = 100
                    };
                   
                    //奇偶校验
                    if (_curWeightCfg.Parity == ParityType.Even)
                    {
                        _spCom.Parity = Parity.Odd;
                    }
                    else if (_curWeightCfg.Parity == ParityType.Odd)
                    {
                        _spCom.Parity = Parity.Even;
                    }
                    else
                    {
                        _spCom.Parity = Parity.None;
                    }
                    //停止位
                    if (_curWeightCfg.StopSize == StopBitsType.One)
                    {
                        _spCom.StopBits = StopBits.One;
                    }
                    else if (_curWeightCfg.StopSize == StopBitsType.OnePointFive)
                    {
                        _spCom.StopBits = StopBits.OnePointFive;
                    }
                    else if (_curWeightCfg.StopSize == StopBitsType.Two)
                    {
                        _spCom.StopBits = StopBits.Two;
                    }
                    else
                    {
                        _spCom.StopBits = StopBits.None;
                    }
    
                    _spCom.DataReceived += new SerialDataReceivedEventHandler(_spCom_DataReceived);
                    try
                    {
                        WeightDeviceLogger.Debug("表头打开串口。IsOpen=" + _spCom.IsOpen);
                        _spCom.Open();
                        _closeComPort = false;
    
                        ThreadStart ts1 = GetWeight;// 开启一个线程,发送读取数据命令,之后读取数据,解析数据,再通过委托事件传递给程序
                        _threadWeight1 = new Thread(ts1)
                        {
                            IsBackground = true,//表示后台线程
                        };
                        _threadWeight1.Start();
    
                        WeightDeviceLogger.Debug("启动表头获取数据线程成功。");
                        
                        rtn = true;
                    }
                    catch (Exception ex)
                    {
                        WeightDeviceLogger.Error("打开表头失败。", ex);
                        ShowErrorMsg(ErrorType.Error, "打开串口失败.");
                    }
                }
                else
                {
                    WeightDeviceLogger.Error("表头配置信息不存在。");
                    ShowErrorMsg(ErrorType.Error, "配置信息不存在.");
                }
                return rtn;
            }
    /// <summary>
            ///     提取重量数据
            /// </summary>
            private void GetWeight()
            {
                while (true)
                {
                    if (_spCom.IsOpen)
                    {
                        if (isclearzero)
                        {
                            continue;
                        }
    
                        try
                        {
                            Thread.Sleep(100);
    
                            ComSend(s1);//发送获取数据命令  s1是仪表厂家提供的读数命令16进制字符"01 03 00 01 00 04 15 C9"
    
                            var readDataLen = _spCom.BytesToRead;//获取接受缓冲区的字节数
                            var buf = new byte[readDataLen];//创建一个和接收区字节数一样的字节数组用来接收数据
                            _isDataReceiving = true;
                            Thread.Sleep(100);//发送读数命令之后要等一会再读取数据
                            var length = _spCom.Read(buf, 0, readDataLen);//从缓冲区读取readDataLen长度的数据写入buf字节数组
                            _isDataReceiving = false;
                            if (length <= 0) continue;
    
                            var aaa = System.Text.Encoding.Default.GetString(buf);//将字节数组转换成字符串
                            var weightTemp = aaa.Substring(3, 7);//从字符串中截取使用的那几位数据
    
                            if (!_canRaiseWeightDataEvent) continue;//判断程序是否暂停取数
    
                            OnGetWeightData(weightTemp, "");//将数据发送给程序使用
                        }
                        catch(Exception e)
                        {
                            WeightDeviceLogger.Debug("读取数据线程出现错误"+e.Message);
                        }
    
                    }
                }
                
            }
    private void ComSend(string obj)//发送数据 独立线程方法 发送数据时UI可以响应
            {
                if (Sending)
                {
                    return;
                }
                //lock (this)//由于send()中的if (Sending == true) return,所以这里不会产生阻塞,如果没有那句,多次启动该线程,会在此处排队
                {
                    Sending = true;//正在发生状态字
                    byte[] sendBuffer = null;//发送数据缓冲区
                    string sendData = obj;//复制发送数据,以免发送过程中数据被手动改变
                    if (true)//16进制发送
                    {
                        try //尝试将发送的数据转为16进制Hex
                        {
                            sendData = sendData.Replace(" ", "");//去除16进制数据中所有空格
                            sendData = sendData.Replace("
    ", "");//去除16进制数据中所有换行
                            sendData = sendData.Replace("
    ", "");//去除16进制数据中所有换行
                            if (sendData.Length == 1)//数据长度为1的时候,在数据前补0
                            {
                                sendData = "0" + sendData;
                            }
                            else if (sendData.Length % 2 != 0)//数据长度为奇数位时,去除最后一位数据
                            {
                                sendData = sendData.Remove(sendData.Length - 1, 1);
                            }
    
                            List<string> sendData16 = new List<string>();//将发送的数据,2个合为1个,然后放在该缓存里 如:123456→12,34,56
                            for (int i = 0; i < sendData.Length; i += 2)
                            {
                                sendData16.Add(sendData.Substring(i, 2));
                            }
                            sendBuffer = new byte[sendData16.Count];//sendBuffer的长度设置为:发送的数据2合1后的字节数
                            for (int i = 0; i < sendData16.Count; i++)
                            {
                                sendBuffer[i] = (byte)(Convert.ToInt32(sendData16[i], 16));//发送数据改为16进制
                            }
                        }
                        catch //无法转为16进制时,出现异常
                        {
                            WeightDeviceLogger.Debug("无法转为16进制时,出现异常");
                            Sending = false;//关闭正在发送状态
                            //_spCom.Abort();//终止本线程
                            return;//输入的16进制数据错误,无法发送,提示后返回  
                        }
    
                    }
                    else //ASCII码文本发送
                    {
                        sendBuffer = System.Text.Encoding.Default.GetBytes(sendData);//转码
                    }
                    try//尝试发送数据
                    {//如果发送字节数大于1000,则每1000字节发送一次
                        //int sendTimes = (sendBuffer.Length / 1000);//发送次数
                        //for (int i = 0; i < sendTimes; i++)//每次发生1000Bytes
                        //{
                        //    //_spCom.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);
                        //    _spCom.Write(sendBuffer, 0, sendBuffer.Length); //发送sendBuffer中从第i * 1000字节开始的1000Bytes
                        //}
                        //if (sendBuffer.Length % 1000 != 0)//发送字节小于1000Bytes或上面发送剩余的数据
                        //{
                        //    //_spCom.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);
                        //    _spCom.Write(sendBuffer, 0, sendBuffer.Length);
                        //}
                        _spCom.Write(sendBuffer, 0, sendBuffer.Length);
                    }
                    catch(Exception ex)//如果无法发送,产生异常
                    {
                        WeightDeviceLogger.Debug("指令发送错误"+ex.Message);
                    }
                    //sendScrol.ScrollToBottom();//发送数据区滚动到底部
                    Sending = false;//关闭正在发送状态
                }
    
            }
  • 相关阅读:
    LeetCode第三题:Longest Substring Without Repeating Characters
    LeetCode第二题:Add Two Numbers
    LeetCode第一题:Two Sum
    第五章 单体内置对象
    第五章 引用类型 基本包装类型
    第五章 引用类型 Function 类型
    第五章 引用类型 RegExp 类型
    第五章 引用类型 Date类型
    第五章 引用类型 Array类型
    第五章 引用类型 Object类型
  • 原文地址:https://www.cnblogs.com/big-lll/p/9235167.html
Copyright © 2020-2023  润新知