关于串口接收并解析数据

yalunwang123 2014-11-11 05:57:43
接收就是在SerialPort类的rececivedata里面接收


int a=comm.ByteToRead;
byte []buf=new byte[a];
comm.Read(buf,0,a);

现在的情况是,接收到数据是不固定的长度,协议是起始是AA AA 结束是DE D0
接收到的数据有可能是AA AA 08 56 82 44 DE DO
也可能是AA AA 08 56 82 44 AA AA 55 63 1A 55 AA AA 55 99 33 77 DE D0要做的是将接到的数据处理解析。
1、串口接收的数据不是一次性接完的。比如第一次buf收到了AA AA 08 56 第二次buf才收到82 44 DE DO
怎么把他们装到一个新数组里面。
我用的ArragList LIST=new ArragList();为什么不行啊,因为我判断的是if(LIST[2]==0x69)调试提示object 和int不能。
2、解析时我想处理的AA AA 08 56 82 44 和AA AA 55 63 1A 55和 AA AA 66 99 33 77 DE D0分开处理。这个怎么做啊。
例如 if(buf[2]==0x08) {执行相应的事情}
if(buf[2]==0x55) {执行相应的事情}
求大神给个指导
...全文
21433 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
接收到的信息(list中的内容),不一定只有一个命令(例如发消息的设备很多、发送速度远比上位机处理速度快),可能有多2个甚至多个。你的程序是假设每一次接收到“一个”命令,只执行一次命令就结束。 你的程序并不能保证正确,只是说你现在的测试环境“恰好”设备比较慢、而双绞线距离比较短、主机比较空闲,因此基本上都能恰好每当设备发来一条消息时能够满足 list[list.account-1]==0xD0&&list[list.account-2]==0xDE 这个条件。如果你能兼容“收到多条命令”的形式(甚至你能发挥想象力先来制造一个此类测试,然后再解决bug),程序将来用到实际的各种生产环境中才会比较可靠。 在你的程序中,既然执行 list.Clear(),那么前边其实就不需要执行 list.removerange(0,6)。 但是list.Cear()其实是不对的,因此最终还是应该保留 list.removerange 而删掉 list.Celar。 另外将来让程序变成一个教正规、可为中型应用而扩展的“设计升级”的建议: 1. DataReceive中的程序,应该清晰地是处理这个Receive流程的。你应该把判断任务类型和调用处理程序的代码,从这段程序中分离出去,不应该在这里出现一堆的 if...else 判断。 2. 将来还是要在子线程中执行命令解析和调用处理程序过程,而 Receive程序应该仅仅在从list中去掉一条条命令之后,立刻返回(不等命令执行就返回)。以免造成通讯延迟、甚至程序死锁。
yalunwang123 2014-11-18
  • 打赏
  • 举报
回复
感谢上面那位大大,虽然没看太懂,主要是我水平未够。经过努力,我已经做成功了。下面分享下: 1、对于第一个问题: 首先定义全局变量
List <byte> list =new List<byte>() //必须定义为全局
int b=0
      
然后在
private void comm_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
          int a=comm.ByteToRead;
          byte []buf=new byte[a];
          comm.Read(buf,0,a);   
          for(i=0;i<a;i++)//用来将buf的数据拼接到list数组,以保证把完整的一帧数据加到一个数组里面
           {
                   list.Insert(b,buf[i]);
                   b++;
               }  
           if(list[list.account-1]==0xD0&&list[list.account-2]==0xDE)//判断数据是否收完;DE和D0为帧结束符在下面处理数据
           {
              对于第2个问题,利用LIST.Removerange(int ,length)//在指定索引处删除一定的长度
             if(list[2]==0x08)
               {
              做相应处理;
               list.removerange(0,6);

                }
               if(list[2]==0x55)
               {
              做相应处理;
               list.removerange(0,6);

                }
               if(list[2]==0x66)
               {
              做相应处理;
      

                }
            list.Clear();//清空list用来下次接收
            b=0;
           }
           


}
详细的根据自己的通信协议按这个框架应该是可以的。 分享下,csdn就是分享知识的社区,yeah!
yalunwang123 2014-11-18
  • 打赏
  • 举报
回复
引用 10 楼 sp1234 的回复:
接收到的信息(list中的内容),不一定只有一个命令(例如发消息的设备很多、发送速度远比上位机处理速度快),可能有多2个甚至多个。你的程序是假设每一次接收到“一个”命令,只执行一次命令就结束。 你的程序并不能保证正确,只是说你现在的测试环境“恰好”设备比较慢、而双绞线距离比较短、主机比较空闲,因此基本上都能恰好每当设备发来一条消息时能够满足 list[list.account-1]==0xD0&&list[list.account-2]==0xDE 这个条件。如果你能兼容“收到多条命令”的形式(甚至你能发挥想象力先来制造一个此类测试,然后再解决bug),程序将来用到实际的各种生产环境中才会比较可靠。 在你的程序中,既然执行 list.Clear(),那么前边其实就不需要执行 list.removerange(0,6)。 但是list.Cear()其实是不对的,因此最终还是应该保留 list.removerange 而删掉 list.Celar。 另外将来让程序变成一个教正规、可为中型应用而扩展的“设计升级”的建议: 1. DataReceive中的程序,应该清晰地是处理这个Receive流程的。你应该把判断任务类型和调用处理程序的代码,从这段程序中分离出去,不应该在这里出现一堆的 if...else 判断。 2. 将来还是要在子线程中执行命令解析和调用处理程序过程,而 Receive程序应该仅仅在从list中去掉一条条命令之后,立刻返回(不等命令执行就返回)。以免造成通讯延迟、甚至程序死锁。
关于list.removerange(0,6)和 list.Celar()。是这样的。因为,收到的数据的长度是不固定的,有可能是AA AA 08 56 82 44 DE DO也可能是AA AA 08 56 82 44 AA AA 55 63 1A 55 DE D0因为我每次判断的都是list[2],所以判断完08要把AA AA 08 56 82 44这段删掉,才能用list[2]来继续判断list[2]是否为55; 另外,if。。。else这个处理速度应该很快吧。你指的意思是在Receive程序里面开启一个线程吗,在这个线程里用来处理数据吗。
yalunwang123 2014-11-12
  • 打赏
  • 举报
回复
引用 3 楼 yalunwang123 的回复:
串口接收不开线程行不行
所有的线程都可以不开。 实际的系统是为了性能和用户(UI交互时)操作体验而设计的。如果你只是完成基本逻辑,永远也不用考虑使用线程的。所以说,如果你在“还看不懂基本逻辑”的时候,你只要把 ThreadPool.QueueUserWorkItem(...) 这句话外边的“壳儿”去掉、仅留下里边的代码,就行了。[/quote]你只要把 ThreadPool.QueueUserWorkItem(...) 这句话外边的“壳儿”去掉、是把ProcessCommand()函数去掉吗,看不太懂啊
yalunwang123 2014-11-12
  • 打赏
  • 举报
回复
没人了,求指导
  • 打赏
  • 举报
回复
程序我临时写的,没有测试,只是保证不会出现语法错误而已。如果有执行错误,你自己调试、改一下。 关键是数据结构和流程问题,只要你看懂就行了。
  • 打赏
  • 举报
回复
我们只是习惯了而已,设计一个通讯程序,首先会定下“哪个操作必须异步执行”的规则,然后写程序。并不是所有人都习惯使用线程。
  • 打赏
  • 举报
回复
引用 3 楼 yalunwang123 的回复:
串口接收不开线程行不行
所有的线程都可以不开。 实际的系统是为了性能和用户(UI交互时)操作体验而设计的。如果你只是完成基本逻辑,永远也不用考虑使用线程的。所以说,如果你在“还看不懂基本逻辑”的时候,你只要把 ThreadPool.QueueUserWorkItem(...) 这句话外边的“壳儿”去掉、仅留下里边的代码,就行了。
yalunwang123 2014-11-11
  • 打赏
  • 举报
回复
串口接收不开线程行不行
  • 打赏
  • 举报
回复
ProcessCommand完成得很快(通常只有几毫秒),所以不会卡住读取线程。不需要等待命令执行,就开始读取新的数据。 命令使用(系统系统线程池上的)子线程并发执行。
  • 打赏
  • 举报
回复
private List<byte> RevBuffer = new List<byte>();

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    lock (RevBuffer)
    {
        var buffer = new byte[4000];
        var len = 0;
        while ((len = serialPort1.Read(buffer, 0, buffer.Length)) > 0)
            RevBuffer.AddRange(buffer.Take(len));
        ThreadPool.QueueUserWorkItem(h =>         //不等ProcessCommand执行完,立即重新读取串口新数据
        {
            while (ProcessCommand()) ;      //处理收到的所有消息,直到再没有任务
        });
    }
}

private bool ProcessCommand()
{
    lock (RevBuffer)
    {
        var len = 查找一个命令的长度(RevBuffer);
        if (len == 0)      //不包含任何完整的任务(比如说还没有接受到第一个消息的结束标志
            return false;

        var command = new byte[len];
        Array.Copy( RevBuffer.ToArray() , command, len );
        RevBuffer.RemoveRange(0, len );       //从接收缓冲区移除第一个消息内容
        ThreadPool.QueueUserWorkItem(h => 执行一条命令(command));
        return true;    //通知调用程序,收到了一个任务
    }
}

110,618

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧