C#串口接收的数据进行轮询处理,能否根据图片写一个轮询代码

K.S and 猫 2023-02-06 12:39:59

 接收的数据的数组变量您字节写一个把,长度您定,把轮询的中间数据放在一个数组里或二维数组,或泛型集合都有。

还请大佬们help一下。

 

...全文
Hello World
拼手气红包 10.00元
1212 13 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
wanghui0380 2023-02-07
精选
  • 打赏
  • 举报
回复

算了,还是给个例子把。我随手写了一个demo

using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Linq;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;



namespace ConsoleApp4
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //环境:为了表明这些东西是net通用技术,我这里特地不使用netcore
            //所以环境是net4.62的控制台,
            //nuget包:system.io.pipelines //官方管道流--数据流--用来处理流式数据的本地环形内存处理
            
            //System.Threading.Channels //因为读是读,写是写,分析是分析。自然而然我需要把结果通知也独立出来

            //我们先写测试,为了表示这些是通用技术,我先不打算对接串口,也不打算对接tcp,只用byte数组
            //我们先来模拟流式接收数据这种大小不定的情况
            //这里理论上是2条完整封包数据,我特地拆成3条大小不一的数据块
            List<byte[]> lst = new List<byte[]>();
            lst.Add(new byte[] {0x5a,0x54,0x01});
            lst.Add(new byte[]{0x5a,0xfe,0x5a});
            lst.Add(new byte[]{0x54,0x02,0x5a,0xfe});

            Pipe pipe = new Pipe();
            PipeWriter writer = pipe.Writer;
            PipeReader reader = pipe.Reader;

            Task.Run(async () =>
            {
                while (true)
                {
                    var package = await channel.Reader.ReadAsync();
                    Console.WriteLine("已解析出封包:"+BitConverter.ToString(package));
                }
                
            });
           Task.WhenAll(writerTask(lst, writer), ReaderTask(reader));

         
            Console.ReadKey();

        }


        static void ttt(ref ReadOnlySequence<byte> da)
        {
            var a = da;
            a = a.Slice(0, 1);
            da = a;
        }

        private static Channel<byte[]> channel = Channel.CreateUnbounded<byte[]>();
        static async Task writerTask(List<byte[]> source,PipeWriter writer)
        {
            foreach (var bytes in source)
            {
                Console.WriteLine("写入数据:"+BitConverter.ToString(bytes));
                writer.Write(bytes); //我特地选一个默认不带刷新的
                writer.FlushAsync();//自己刷新数据通知reader去处理
                //为了模拟随机不定长,我这里用延时模拟
                await Task.Delay(1000);
            }
        }

        static async Task ReaderTask(PipeReader reader)
        {
            //为了只描述核心逻辑,我这里不写那些异常控制
            while (true)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;
                while (TryParsePackage(ref buffer,out var package))
                {
                    channel.Writer.WriteAsync(package.Value.ToArray());
                }

                reader.AdvanceTo(buffer.Start, buffer.End);

            }
        }
       static byte[] head = new byte[] { 0x5a, 0x54 };
       static byte[] end = new byte[] { 0x5a, 0xfe};

       static bool TryParsePackage(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte>? package)
       {
           
           package = null;
           var _buffer = buffer;
           
           var p1 = TryGetLette(ref _buffer, head);
           if (p1 == null)
               return false;
           var p2 = TryGetLette(ref _buffer, end);
           if (p2 == null)
               return false;
          var endp=  buffer.GetPosition(end.Length, p2.Value);
           package = buffer.Slice(p1.Value,endp);
          buffer = buffer.Slice(package.Value.End);
            return true;
       }
       
        static SequencePosition? TryGetLette(ref ReadOnlySequence<byte> buffer, ReadOnlySpan<byte> delimiters,
            bool advancePastDelimiter = true)
        {

            var _buffer = buffer;
            SequencePosition? p = null;
            while (_buffer.Length>delimiters.Length)
            {
                var p1 = _buffer.PositionOf(delimiters[0]);
                if(p1==null)
                    break;
                _buffer = _buffer.Slice(p1.Value);
                if(_buffer.Length<delimiters.Length)
                    break;
                var t = buffer.Slice(p1.Value, delimiters.Length);
                //演示,就不讲究性能,直接用内存直接比较,toarray会重新分配内存
                //不过问题不大,通常delimiters标识位长度就几位,重新分配问题也不大
                var res = t.ToArray().SequenceEqual(delimiters.ToArray());
                if (res)
                {
                    p = p1;
                    break;
                }
               
                
            }

            if (p != null && advancePastDelimiter)
            {
                buffer = buffer.Slice(buffer.GetPosition(1,p.Value));

            }
            return p;

        }




    }
}


K.S and 猫 2023-02-10
  • 举报
回复
@wanghui0380 感谢老师,这几天我对这个进一步学习,对这个管道使用有些小结果了
wanby1982 2023-02-06
精选
  • 打赏
  • 举报
回复 1

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;

namespace WpfApp1.Read
{
    public class ReadSW
    {
        private bool isopen = false;
        public delegate void BarCodeDelegate(byte[] data);
        public event BarCodeDelegate BarCodeEvent;
        private SerialPort locksp;
        volatile private bool isread = false;

        List<byte> data = null;//数据

        //记录未处理的接收数据,主要考虑接收数据分段
        byte[] m_btAryBuffer = new byte[10];
        //记录未处理数据的有效长度
        int m_nLenth = 0;
        volatile private bool isdata = false;//是否是数据


        public bool Isopen { get => isopen; }

        public bool openPort(string com, int btl)
        {
            try
            {
                if (isopen == false)
                {
                    isread = false;
                    data = new List<byte>();
                    locksp = new SerialPort(com, btl);
                    locksp.StopBits = StopBits.One;
                    locksp.DataBits = 8;
                    locksp.Parity = Parity.None;
                    locksp.ReadTimeout = -1;
                    locksp.RtsEnable = true;
                    locksp.ReceivedBytesThreshold = 1;
                    locksp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
                    locksp.Open();
                    isopen = true;

                    return isopen;
                }
                else
                {
                    return isopen;
                }
            }
            catch
            {
                return isopen;
            }
        }
        public void closePort()
        {
            if (isopen)
            {
                isopen = false;
                locksp.Close();
                locksp.Dispose();
            }
        }
        
        private void sp_DataReceived(object sender, EventArgs e)
        {
            try
            {
                if (!isread)
                {
                    isread = true;
                    do
                    {
                        if (locksp.BytesToRead > 0)
                        {
                            try
                            {
                                //将收到的数据放入数组btAryReceiveData
                                byte[] btAryReceiveData = new byte[locksp.BytesToRead];
                                locksp.Read(btAryReceiveData, 0, btAryReceiveData.Length);

                                //将收到的数据和上次剩余的数据组成新数据
                                int nCount = btAryReceiveData.Length;
                                byte[] btAryBuffer = new byte[nCount + m_nLenth];
                                if (m_nLenth != 0)
                                {
                                    Array.Copy(m_btAryBuffer, btAryBuffer, m_nLenth);
                                }
                                Array.Copy(btAryReceiveData, 0, btAryBuffer, m_nLenth, btAryReceiveData.Length);

                                m_btAryBuffer = new byte[10];
                                m_nLenth = 0;

                                   
                                for (int nLoop = 0; nLoop < btAryBuffer.Length; nLoop++)
                                {
                                    if (isdata == false)//判断现在接收的是否为中间数据默认为false
                                    {
                                        if (btAryBuffer[nLoop] == 0x5A)//判断第一位是否是0x5A 是就判断下一位,不是就丢弃
                                        {
                                            if (nLoop + 1 < btAryBuffer.Length)//没有下一位了就把0x5A放入零时数据
                                            {
                                                if (btAryBuffer[nLoop + 1] == 0x54)//判断头的第二位是否为0x54 如果不是就丢弃
                                                {
                                                    isdata = true;
                                                    nLoop++;
                                                }
                                            }
                                            else
                                            {
                                                m_nLenth = btAryBuffer.Length - nLoop;
                                                Array.Copy(btAryBuffer, nLoop, m_btAryBuffer, 0, m_nLenth);
                                                break;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        if (btAryBuffer[nLoop] == 0x5A)//判断结束符号第一位是否是0x5A,如果是就有可能是结束符号,在判断第二位,不是就放入带返回的data中
                                        {
                                            if (nLoop + 1 < btAryBuffer.Length)//没有下一位了,没有就把当前放入零时数据中,等有新数据了在判断
                                            {
                                                if (btAryBuffer[nLoop + 1] == 0xFE)//判断结束符号的第二位是否为0xFE 如果不是就丢弃
                                                {
                                                    isdata = false;//说明一整数据接收完整了
                                                    nLoop++;
                                                    BarCodeEvent?.Invoke(data.ToArray());//返回一个完整数据
                                                    data.Clear();
                                                }
                                                else//说明还是数据
                                                {
                                                    data.Add(btAryBuffer[nLoop]);

                                                }
                                            }
                                            else
                                            {
                                                m_nLenth = btAryBuffer.Length - nLoop;
                                                Array.Copy(btAryBuffer, nLoop, m_btAryBuffer, 0, m_nLenth);
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            data.Add(btAryBuffer[nLoop]);
                                        }
                                    }
                                    
                                }
                            }
                            catch
                            {
                            }
                        }
                    }
                    while (locksp.BytesToRead > 0);
                    isread = false;
                }
            }
            catch
            {
            }
        }


        public bool sendMessage(byte[] msg)
        {
            if (isopen)
            {
                try
                {
                    locksp.Write(msg, 0, msg.Length); //发送数据内容
                    return true;
                }
                catch
                {
                    return false;
                }

            }
            else
            {
                return false;
            }
        }
    }
}

K.S and 猫 2023-02-10
  • 举报
回复
@wanby1982 老师谢谢您,这几天没回您的帖子,是因为想把您的逻辑思维好好学习了一下,也把io.pipelins好好学习了一下,有点东西了再回复您
wanby1982 2023-02-10
精选
  • 举报
回复
@K.S and 猫 SunnyUI.FrameDecoder你可以看下这个库。更简单 SunnyUI.FrameDecoder - 流式数据解码库
K.S and 猫 2023-02-10
  • 举报
回复
@wanby1982 好的,老师,我看看这个
2条回复
wanghui0380 2023-02-06
精选
  • 打赏
  • 举报
回复 1

已经回复过了,看样子你还是坚持非园子不用策略

你要的东西其实呢就是system.io.pipelins,那个玩意就是你口里“缓冲”,你口里的“数组”,你口里“拼接”

来看看原来那个文章的代码在干嘛

async Task ProcessLinesAsync(Socket socket)
{
//生成一个管道,他就是你要的“缓存”
    var pipe = new Pipe();
    Task writing = FillPipeAsync(socket, pipe.Writer); //writer 是数据写入器
    Task reading = ReadPipeAsync(pipe.Reader); //reader 数据读取器
 
    await Task.WhenAll(reading, writing); //启动两个任务,一个不定从socket读取数据,当然你可以替换成从串口读取数据
}
 
async Task FillPipeAsync(Socket socket, PipeWriter writer)
{
    const int minimumBufferSize = 512;
 //这里的while就是不停从串口读取数据,这里是while,你可以替换成串口的触发事件
    while (true)
    {
        // Allocate at least 512 bytes from the PipeWriter.
        Memory<byte> memory = writer.GetMemory(minimumBufferSize);
        try
        {
            int bytesRead = await socket.ReceiveAsync(memory, SocketFlags.None);
            if (bytesRead == 0)
            {
                break;
            }
            // Tell the PipeWriter how much was read from the Socket.
          //把读取到的数据写到管道里,当然这里有好几个重载,你可以按需替换
         //目前这代码内置了上个帖子有人告诉你的通知,不过有些方法没有内置,需要你手动 flush一下通知reader有新数据来了
            writer.Advance(bytesRead);
        }
        catch (Exception ex)
        {
            LogError(ex);
            break;
        }
 
        // Make the data available to the PipeReader.
        FlushResult result = await writer.FlushAsync();
 
        if (result.IsCompleted)
        {
            break;
        }
    }
 
//这个结合上面代码的意思,如果有异常出现,通知整个管道结束,让reader停止
     // By completing PipeWriter, tell the PipeReader that there's no more data coming.
    await writer.CompleteAsync();
}
async Task ReadPipeAsync(PipeReader reader)
{
//这里你你要的“拼接后的数据”
    while (true)
    {
 //这里是异步等待操作,writer通知你有数据了,他就会往下执行,没有数据则异步等待在此行
        ReadResult result = await reader.ReadAsync();
        ReadOnlySequence<byte> buffer = result.Buffer;
        while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
        {
            // Process the line.
            ProcessLine(line); //分析数据,按下面代码,这个封包按\n分割,你可以替换成你自己的分析过程
        }

        // Tell the PipeReader how much of the buffer has been consumed.
//这句也是你要了,上面已经分析出一行大小,这里就是告诉管道有多少个是我已经确定分析完毕并提取了
//假设里面有10字节,我已经分析出前7个是我要了,那么这句话就是告诉管道请把前7个移除,我不需要了。此时管道里还剩下3个字节
//留待和下一次的数据拼接到一起分析
        reader.AdvanceTo(buffer.Start, buffer.End);
        // Stop reading if there's no more data coming.
        if (result.IsCompleted)
        {
            break;
        }
    }
 
    // Mark the PipeReader as complete.
    await reader.CompleteAsync();
}
 
bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
{
    // Look for a EOL in the buffer.
    SequencePosition? position = buffer.PositionOf((byte)'\n');
 
    if (position == null)
    {
        line = default;
        return false;
    }
 
    // Skip the line + the \n.
    line = buffer.Slice(0, position.Value);
    buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
    return true;


K.S and 猫 2023-02-06
  • 举报
回复
@wanghui0380 不是的老师,您给我的文章我看了几遍,也是在那片文章基础上想出了这个今天帖子的内容,就是,我这几天自己写来着,没编出来,因为刚开始学习C#,没有那个比较更高级一点的逻辑思维,这不您今天又来指导我啦
ziqi0716 2023-04-12
  • 打赏
  • 举报
回复

我字儿也丑,但我努力学习编程来吃饭,其中一项重要的技能就是打字要快.

赵4老师 2023-02-07
  • 打赏
  • 举报
回复

了解一下有限状态自动机

wanby1982 2023-02-06
  • 打赏
  • 举报
回复 2

使用

 ReadSW sw = new ReadSW();
            sw.BarCodeEvent += Sw_BarCodeEvent;
            sw.openPort("COM1", 9600);

private void Sw_BarCodeEvent(byte[] data)
        {
            这里每次接收到的就是一串中间数据
        }

111,102

社区成员

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

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

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