优化串口数据接收处理 [英] Optimise serialport data recieved handling

查看:97
本文介绍了优化串口数据接收处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,



我每秒收到5个数据包并丢失数据包,因为处理收到的数据事件和处理数据需要花费太多时间。



如何改进我的代码?

这是相关代码:





  private   void  portCs_Datarecieived( object  sender,SerialDataReceivedEventArgs e)
// 固定框架19字节
// < stx>< dle>< 16 data bytes> < etx>
{
if (!comportCcs.IsOpen) return < /跨度>;

while (comportCcs.BytesToRead)
{
int indata = comportCcs.ReadByte();

if (indata ==( int )stx&& readBuffer .Count == 0 // 检查startbyte = stx
{
readBuffer.Add(( byte )indata);
indata = comportCcs.ReadByte(); // 读取下一个字节
}
if (indata ==( int )dle&& readBuffer.Count == 1 // 检查
// 数据分隔符dle
{
readBuffer.Add((< span class =code-keyword> byte
)indata);
indata = comportCcs.ReadByte(); // 读取下一个字节
}
else
{
comportCcs.DiscardInBuffer(); // 重新开始
readBuffer = new List< byte>();
}
while (readBuffer.Count < 18 // > ????用于粘贴

{
readBuffer.Add(( byte )indata);
indata = comportCcs.ReadByte(); // 读取下一个字节
}
if (readBuffer.Count == 18 )indata ==( int )etx) // 检查字节[19] = etx
{
readBuffer.Add(( byte )indata);
processCsData(); // 这需要一些时间,
// 已经使用线程优化
readBuffer = new List< byte>();
}
其他 // 重新开始
{

readBuffer = new List< byte> ;;();
}
}
}

private void processCsData()
{
CsreceivedBytes = new byte [ 19 ];
CsreceivedBytes = readBuffer.ToArray();
Ccs1 = bytesToInt(CsreceivedBytes, 2 3 );
Ccs2 = bytesToInt(CsreceivedBytes, 4 5 );
Ccs3 = bytesToInt(CsreceivedBytes, 6 7 );
Ccs4 = bytesToInt(CsreceivedBytes, 8 9 );
Ccs5 = bytesToInt(CsreceivedBytes, 10 11 );
Ccs6 = bytesToInt(CsreceivedBytes, 12 13 );
Ccs7 = bytesToInt(CsreceivedBytes, 14 15 );
Ccs8 = bytesToInt(CsreceivedBytes, 16 17 );
PaintCcs();
paintBoxxes();
}

private static int bytesToInt( byte [] buffer, int index1, int index2)
{
int numLow =( INT )(缓冲液[索引2]);
int numHigh =( int )(buffer [index1]);
int value = 256 * numHigh + numLow;
return value ;
}

< pre> private void PaintCcs()
{
Color red = Color.Red;
颜色白= Color.White;
BzBitmapBuffer = new 位图(simuPnlBz.Width,simuPnlBz.Height);
AzBitmapBuffer = new 位图(simuPnlAz.Width,simuPnlAz.Height);

Task.Factory.StartNew(()= >
{
using (Graphics bufferGrphBZ = Graphics.FromImage(BzBitmapBuffer),
bufferGrphAZ = Graphics.FromImage(AzBitmapBuffer))
{

// 此处计算和
// 创建2位图
}
simuPnlAz.Invoke( new Action(()= >
{
simuPnlAz.Invalidate();
simuPnlAz.Update();
}));

simuPnlBz.Invoke(行动(()= >
{
simuPnlBz.Invalidate();
simuPnlBz.Update();
}));
});
}

private void paintBoxxes()
{
PanelShiftBuffer = new 位图(panelShift.Width,panelShift.Height);
Task.Factory.StartNew(()= >
{
使用(Graphics bufferGrph = Graphics.FromImage(PanelShiftBuffer))
{
SolidBrush redBrush = new SolidBrush(Color.Red);
SolidBrush greenBrush = new SolidBrush(Color.Green);
SolidBrush myBrush = new SolidBrush (Color.Transparent);
// int count = 0;
< span class =code-comment> //
foreach(环中的UInt16元素)
// {
count + = 1 ;
if (count% 2 == 0 )myBrush = redBrush;
else myBrush = greenBrush;
bufferGrph.FillRectangle(myBrush, new 矩形( 4 * 30 4 25 20 ));
// }
}
panelShift.Invoke( new EventHandler( delegate
{
panelShift.Invalidate();
panelShift .Update();
}));
});

}









我希望有人可以提高我的代码速度,



GrooverFromHolland;

解决方案

只是一些建议,但他们可能会是一个解决性能问题的关键和丢失数据的问题。



在一个单独的线程中进行所有串口通信并仅使用同步读取。当发送的数据尚未到达时,您的线程应该在读取呼叫时被阻止。



而不是使用 ReadByte 尝试使用 int来读取更大的块。使用System.IO.Ports.SerialPort.Read(byte [],int,int)

http://msdn.microsoft.com/en-us/ library / ms143549%28v = vs.110%29.aspx [ ^ ]。



读取一个块将引入一个与阻塞和在唤醒线程时,不会丢失一些未从电缆另一端传送的数据。在我最近的回答中,我详细解释了使用它的人。请参阅:

thread.suspend,thread.resume方法 [ ^ ]。



不,上面提到的问题不是关于线程暂停/恢复,这是关于你所拥有的那个问题的串口问题。 :-)



-SA


大家好,



已经测试了30分钟,每秒50个数据包(数据包19个字节),没有数据丢失。

速度越高,我得到一个异常:发生System.InvalidOperationException消息=对象目前正在其他地方使用。 Source = System.Drawing



这对我来说没有问题,因为速度比需要高10倍并且与串口无关。



这是我修改过的serialport_Datareceived事件:



  private   bool  sync =  false ; 

private void portCs_Datarecieived(对象 sender,SerialDataReceivedEventArgs e)

// 固定帧19字节
// < stx>< dle>< 16>< etx>

{
if (!comportCcs.IsOpen) return ;
如果(同步) // 一个完整的已收到有效数据包
{
byte [] buffer = new byte [ 19 ]; // 数据包大小
int bytes = comportCcs.BytesToRead;
if (bytes > 18 // 检查是否至少有一个包已到达
{
comportCcs.Read(buffer, 0 19 );
if (缓冲区[ 0 ] == stx&& buffer [ 1 ] == dle&& buffer [ 18 ] == etx)
{
sync = true ; // 数据包有效
CsreceivedBytes = new byte [ 19 ];
CsreceivedBytes = buffer;
processCsData(CsreceivedBytes);
}
其他 // 我忘记了
{
comportCcs.DiscardInBuffer(); // 重新开始
sync = false ;
if (readBuffer.Count > 0 )readBuffer = new List< byte>();
}
}
}

如果(!sync) // 读取,直到收到一个完整的有效数据包
{
while (comportCcs.BytesToRead > 0
{
< span class =code-keyword> int
indata = comportCcs.ReadByte();

if (indata ==( int )stx&& readBuffer .Count == 0 // 检查startbyte stx
{
readBuffer.Add(( byte )indata);
indata = comportCcs.ReadByte(); // 读取下一个字节
}
else
{
comportCcs.DiscardInBuffer(); // 重新开始
sync = false ;
if (readBuffer.Count > 0 )readBuffer = new List< byte>();
}
if (indata ==( int )dle&& readBuffer.Count == 1 // 检查数据delimiter dle
{
readBuffer.Add(( byte )indata);
indata = comportCcs.ReadByte(); // 读取下一个字节
}
else
{
comportCcs.DiscardInBuffer(); // 重新开始
sync = false ;
if (readBuffer.Count > 0 )readBuffer = new List< byte>();
}
while (readBuffer.Count > 1 && readBuffer.Count < 18 // 读取数据
{
readBuffer.Add((字节)INDATA);
indata = comportCcs.ReadByte(); // 读取下一个字节
}
if (readBuffer.Count == 18 && indata ==( int )etx) // 检查最后一个字节(19)= etx
{
sync = true ; // 有效且完整的数据包
readBuffer.Add(( byte )indata);
CsreceivedBytes = new byte [ 19 ];
CsreceivedBytes = readBuffer.ToArray();
processCsData(CsreceivedBytes); // 这需要一些时间,已经使用线程优化
readBuffer = new List< byte>();
}
其他 // 重新开始
{
sync = false ;
readBuffer = new List< byte>();
}
}
}
}





我希望这个可以帮助别人和谢尔盖+5,让我朝着正确的方向前进。



问候,



GrooverFromHolland


Hi all,

I am receiving 5 data packets per second and loosing packets because handling the data received event and processing data takes too much time.

How can I improve my code?
This is the relevant code:


private void portCs_Datarecieived(object sender, SerialDataReceivedEventArgs e)
      // Fixed frame 19 bytes      
      //<stx><dle><16 data bytes><etx>
      {
          if (!comportCcs.IsOpen) return;

          while (comportCcs.BytesToRead)
          {
              int indata = comportCcs.ReadByte();

              if (indata == (int)stx && readBuffer.Count == 0)//Check startbyte = stx
              {
                  readBuffer.Add((byte)indata);
                  indata = comportCcs.ReadByte();//Read next byte
              }
                  if (indata == (int)dle &&readBuffer.Count==1)//Check for
                                                              //Data delimiter dle
              {
                  readBuffer.Add((byte)indata);
                  indata = comportCcs.ReadByte();// Read next byte
              }
              else
              {
                  comportCcs.DiscardInBuffer();//Start over
                  readBuffer = new List<byte>();
              }
              while (readBuffer.Count < 18)//>???? for pasting

              {
                  readBuffer.Add((byte)indata);
                  indata = comportCcs.ReadByte();// Read next byte
              }
              if (readBuffer.Count == 18)indata == (int)etx)// Check byte[19] = etx
              {
                  readBuffer.Add((byte)indata);
                  processCsData();// This takes some time,
                                  //is already optimized with threading
                  readBuffer = new List<byte>();
              }
              else //Start over
              {

                  readBuffer = new List<byte>;();
              }
          }
      }

 private void processCsData()
        {
            CsreceivedBytes = new byte[19];
            CsreceivedBytes = readBuffer.ToArray();
            Ccs1 = bytesToInt(CsreceivedBytes, 2, 3);
            Ccs2 = bytesToInt(CsreceivedBytes, 4, 5);
            Ccs3 = bytesToInt(CsreceivedBytes, 6, 7);
            Ccs4 = bytesToInt(CsreceivedBytes, 8, 9);
            Ccs5 = bytesToInt(CsreceivedBytes, 10, 11);
            Ccs6 = bytesToInt(CsreceivedBytes, 12, 13);
            Ccs7 = bytesToInt(CsreceivedBytes, 14, 15);
            Ccs8 = bytesToInt(CsreceivedBytes, 16, 17);
            PaintCcs();
            paintBoxxes();
        }

 private static int bytesToInt(byte[] buffer, int index1, int index2)
        {
            int numLow = (int)(buffer[index2]);
            int numHigh = (int)(buffer[index1]);
            int value = 256 * numHigh + numLow;
            return value;
        }

<pre> private void PaintCcs()
        {            
            Color red = Color.Red;
            Color white = Color.White;             
            BzBitmapBuffer = new Bitmap(simuPnlBz.Width, simuPnlBz.Height);
            AzBitmapBuffer = new Bitmap(simuPnlAz.Width, simuPnlAz.Height);

            Task.Factory.StartNew(() =>
                {
                    using (Graphics bufferGrphBZ = Graphics.FromImage(BzBitmapBuffer),
                        bufferGrphAZ = Graphics.FromImage(AzBitmapBuffer))
                    {
                       
                        //Here calculations and
                        // Creating 2 bitmaps
                    }
                    simuPnlAz.Invoke(new Action(() =>
                    {
                        simuPnlAz.Invalidate();
                        simuPnlAz.Update();       
                    }));

                    simuPnlBz.Invoke(new Action(() =>
                    {
                        simuPnlBz.Invalidate();
                        simuPnlBz.Update();
                    }));
                });            
        }

        private void paintBoxxes()
        {
            PanelShiftBuffer = new Bitmap(panelShift.Width,panelShift.Height);
             Task.Factory.StartNew(() =>
            {
            using (Graphics bufferGrph = Graphics.FromImage(PanelShiftBuffer))
            {
                SolidBrush redBrush = new SolidBrush(Color.Red);
                SolidBrush greenBrush = new SolidBrush(Color.Green);
                SolidBrush myBrush = new SolidBrush(Color.Transparent);
                //int count = 0;
                //foreach (UInt16 element in ring)
                //{
                    count += 1;
                    if ( count % 2 == 0)myBrush = redBrush ;
                    else myBrush = greenBrush;
                    bufferGrph.FillRectangle(myBrush, new Rectangle(4 * 30, 4, 25, 20));
                //}
            }
            panelShift.Invoke(new EventHandler(delegate
            {
                panelShift.Invalidate();
                panelShift.Update();
            }));
            });

        }





I hope someone can improve my code for speed,

GrooverFromHolland;

解决方案

Just some recommendations, but they might be a key solving your performance problem and the problem with loosing data.

Do all serial port communications in a separate thread and use only the synchronous read. Your thread is supposed to be blocked at the reading calls when the data sent is not yet arrived.

Instead of using ReadByte try to read by bigger blocks by using int System.IO.Ports.SerialPort.Read(byte[], int, int):
http://msdn.microsoft.com/en-us/library/ms143549%28v=vs.110%29.aspx[^].

The reading of a block will introduce a delicate problem related to blocking and not loosing some data not delivered from the other end of the cable at the moment of waking up your thread. In my recent answer I explained who to work with it in detail. Please see:
thread.suspend, thread.resume methods[^].

No, the question referenced above is not about thread suspend/resume, this is about the same serial port problem close to the one you have. :-)

—SA


Hi all,

Have been testing for 30 minutes at 50 packets per second (packet 19 bytes)and no data lost.
At higher speed I get an exception: System.InvalidOperationException occurred Message = Object is currently in use elsewhere. Source=System.Drawing

This is no problem for me as speed is 10 times higher than needed and has nothing to do with serial port.

Here is my modified serialport_Datareceived event:

private bool sync = false;

       private void portCs_Datarecieived(object sender, SerialDataReceivedEventArgs e)

       // Fixed frame 19 bytes
       //<stx><dle><16><etx>

       {
           if (!comportCcs.IsOpen) return;
           if (sync) //one complete and valid packet was received
           {
               byte[] buffer = new byte[19];// packet size
               int bytes = comportCcs.BytesToRead;
               if (bytes > 18) //check if at least one packet has arrived
               {
                   comportCcs.Read(buffer, 0, 19);
                   if (buffer[0] == stx && buffer[1] == dle && buffer[18] == etx)
                   {
                       sync = true;//packet was valid
                       CsreceivedBytes = new byte[19];
                       CsreceivedBytes = buffer;
                       processCsData(CsreceivedBytes);
                   }
                   else// this I forgot
                   {
                       comportCcs.DiscardInBuffer();//Start over
                       sync = false;
                       if (readBuffer.Count > 0) readBuffer = new List<byte>();
                   }
               }
           }

           if (!sync)//read until one complete valid packet is received
           {
               while (comportCcs.BytesToRead > 0)
               {
                   int indata = comportCcs.ReadByte();

                   if (indata == (int)stx && readBuffer.Count == 0)//Check for startbyte stx
                   {
                       readBuffer.Add((byte)indata);
                       indata = comportCcs.ReadByte();//Read next byte
                   }
                   else
                   {
                       comportCcs.DiscardInBuffer();//Start over
                       sync = false;
                       if (readBuffer.Count > 0) readBuffer = new List<byte>();
                   }
                   if (indata == (int)dle && readBuffer.Count == 1) //Check for data delimiter dle
                   {
                       readBuffer.Add((byte)indata);
                       indata = comportCcs.ReadByte();// Read next byte
                   }
                   else
                   {
                       comportCcs.DiscardInBuffer();//Start over
                       sync = false;
                       if (readBuffer.Count > 0) readBuffer = new List<byte>();
                   }
                   while (readBuffer.Count > 1 && readBuffer.Count < 18)// Read data
                   {
                       readBuffer.Add((byte)indata);
                       indata = comportCcs.ReadByte();// Read next byte
                   }
                   if (readBuffer.Count == 18 && indata == (int)etx)// Check if last byte (19) = etx
                   {
                       sync = true;//valid and complete packet
                       readBuffer.Add((byte)indata);
                       CsreceivedBytes = new byte[19];
                       CsreceivedBytes = readBuffer.ToArray();
                       processCsData(CsreceivedBytes);// This takes some time, is already optimized with threading
                       readBuffer = new List<byte>();
                   }
                   else //Start over
                   {
                       sync = false;
                       readBuffer = new List<byte>();
                   }
               }
           }
       }



I hope this can help others and +5 for Sergey, leading me in the right direction.

Regards,

GrooverFromHolland


这篇关于优化串口数据接收处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆