zoukankan      html  css  js  c++  java
  • 转 C# 串口编程遇到的问题以及解决方法 武胜

    最近在做的项目中涉及到串口通信编程,队友在做这一模 块的时候遇到了一个相信很多人都可能遇到的问题,那就是接受数据的冲突或者丢失。队友让我帮他调试的时候,足足花了近两个小时才把问题给解决了,现觉得有 必要总结一下以给遇到类似问题的朋友一个思路吧~

          问题是这样的,从相应的硬件设备每隔2秒便发送一个大小为15的字节数据,存的是16进制数据,每条数据以7E开头以7E结尾。例如:7E 09 01 1A ... 7E。但是PC端在接受显示的时候却出现了问题,如前五个数据接受正常,接下来的都是以00填充,而剩下的10个数据却出现在下条数据显示的位置。如下所 示: 

          7E 09 01 1A 5C 00 00 00 00 00 00 00 00 00 00 /////// 03 06 1A 2C 3D 09 6C 32 12 7E 00 00 00 00 00 00/////// ........

          总之感觉错位了,对了,先把PC端代码贴一下吧:      

         


    public partial class Form1 : Form
        {
            
    /// <summary>
            
    /// 接受数据的串口类 
            
    /// </summary>
            SerialPort spReceive;
            
    delegate void ReceivData(byte[] bytes);

            
    public Form1()
            {
                Form1.CheckForIllegalCrossThreadCalls 
    = false;
                InitializeComponent();
              
                spReceive 
    =new SerialPort("COM5"57600, Parity.None, 8, StopBits.One);             
                spReceive.Open();
                
                
    //设置触发 DataReceived事件的阀值,在调试中发现这个不起作用,不解~      
                spReceive.ReceivedBytesThreshold =15;            
                spReceive.DataReceived 
    +=new System.IO.Ports.SerialDataReceivedEventHandler(spReceive_DataReceived);            
            }

            
    /// <summary>
            
    /// 更新接受到得数据到UI 界面显示
            
    /// </summary>
            
    /// <param name="bytes"></param>
            public void UpdateReceiveToUI(byte[] bytes)
            {
                
    if (txtReceive.InvokeRequired)
                {
                    ReceivData dl 
    = new ReceivData(UpdateReceiveToUI);
                    
    object arg = bytes;
                    txtReceive.Invoke(dl, arg);
                }
                
    else
                    txtReceive.Text 
    += "/////////" + BitConverter.ToString(bytes);
            }

            
    /// <summary>
            
    /// 接收到串口数据触发的事 件
            
    /// </summary>
            
    /// <param name="sender"></param>
            
    /// <param name="e"></param>
            public void spReceive_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                
    byte[] recevied = new byte[15];
                
    int size = spReceive.Read(recevied, 0, recevied.Length);

                if (size >0)

                    UpdateReceiveToUI(recevied);

                

            }

        }

           在调试的过程中,当我spReceive_DataReceived函数中的byte[] recevied = new byte[15]; 后面在加上个初始化,如下:

           for( int i=0; i<recevied.Lengthl;i++)

                 recevied[i]=11;

        

           这个时候界面显示的时候,凡是以00显示的地方都被11替换了。这肯定了这些00是由于传送的15个字节数组未被完全填充到我们定义的字节数组中,即 Read(byte [] bytes,int offset,int size)函数未一次性将字节数组填充完,而是分了两次。但是在此过程中我使用的是SerialPort类的DataReceived事件,即没收到一条 数据便会触发,而这儿的现象仿佛是事件被触发了多次。后来自己在SerialPort类的属性里面找了下,突然发现了有个 ReceivedBytesThreshold属性,从这个属性可以看出我们可以控制接受多少个字节触发一次DataReceived事件。于是,我便将 阀值设为15个字节,满以为问题解决了,可是结果却~

           囧啊,可是这个属性也给了我们一些提示,也找到了问题的症结所在。那就是,DataRecevied事件触发的阀值,即接受到多少个字节数触发一次偏小, 结果导致了我们一条大小为15个字节的数据触发了两次DataReceived事件。要解决这个问题,我们可以沿着这个思路走下去,那就是延迟 DataRecevied事件的触发直到我们一条数据接受完毕。

           所以在spReceive_DataReceived事件函数中,我们做如下修改:

           byte[]  receiveBuffer=new byte[15];  

           public void spReceive_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

           {

                  int bytesRead = 0;  

                  spReceive.ReceivedBytesThreshold = 100000;     //延迟DataRecevied事件的再次触发

                  

                 while (true)

                 { 

                       if (bytesRead >= 15)      //这儿的15是我一条数据的大小

                      { 

                            byte[] bytes = new byte[bytesRead]; 

                            Array.Copy(receiveBuffer, 0, bytes, 0, bytesRead);       

                            Array.Clear(receiveBuffer, 0, bytesRead); 

                            UpdateReceiveToUI(bytes);

                            bytesRead = 0; 

                            break; 

                      } 

                      try

                     {

                        receiveBuffer[bytesRead] = (byte)spReceive.ReadByte();

                        ++bytesRead;

                     }

                    catch (Exception ex1)

                    {

                        MessageBox.Show(ex1.Message);

                        break;

                    } 

     

                    bytesRead = 0;

                    spReceive.ReceivedBytesThreshold = 1;            //将延迟改回正常

                 } 

           } 

         

           经过上述的改动,便可以解决读取串口数据冲突与丢失的问题了~不周之处,还望各位斧正~

  • 相关阅读:
    jmeter(46) redis
    jmeter(45) tcp/ip协议
    Codeforces Round #538 (Div. 2)D(区间DP,思维)
    Codeforces Global Round 1D(DP,思维)
    Educational Codeforces Round 57D(DP,思维)
    UPC11073(DP,思维)
    Yahoo Progamming Contest 2019D(DP,思维)
    Atcoder Beginner Contest 118D(DP,完全背包,贪心)
    Xuzhou Winter Camp 1C(模拟)
    Educational Codeforces Round 57 (Rated for Div. 2)D(动态规划)
  • 原文地址:https://www.cnblogs.com/zeroone/p/1700227.html
Copyright © 2011-2022 走看看