问题1:如何不断的从串口读取数据
2:如何判断首字节是不是0XFF
3:如何判断第首字节后面的第84个字节是不是0XFF
4:如何累加校验
5:等会再来问

解决方案 »

  1.   

    使用SerialPort类
    里面的read方法可以直接读取byte数组,判断的话直接判断buffer[0]和buffer[83]的16进制大小就行了
      

  2.   

    C# 封装了操作串口的类:serialPort
    可以实时读取Com数据
    调serialPort_DataReceived()这个事件就可以了..
    把读取的数据转出来取第一个字节与转换成十六进制做判断
      

  3.   

    嗯。像我这个问题,是要连续的读呢?还是一次读84个字节?
    如何判断第几个是0XFF?如果不是的话,移到下一个自己判断?
      

  4.   

            //初始化开始线程及串口
            public DataBase()
            {
                comm.ReceivedBytesThreshold = 164;
                comm.DataReceived += new SerialDataReceivedEventHandler(comm_DataReceived);
            }        //打开端口设置通讯端口号及波特率、数据位、停止位和校验位。
            public void OpenPort(string strcom, int nBot)
            {
                try
                {
                    comm.PortName = strcom; //端口名称
                    comm.BaudRate = nBot;   // 波特率
                    comm.DataBits = 8;      // 每个字节的标准数据位长度。
                    comm.StopBits = StopBits.One; //停止一位
              //      comm.Parity = Parity.Even;    //偶校验
                    comm.ReadTimeout = 500; //接收延时ms
                    comm.Open();
                }
                catch (Exception ex)
                {
                    //Application.Exit();//退出应用程序
                    MessageBox.Show("“" + ex.Message + "”设置硬件功能不可用!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            public Boolean commStatus() 
            {
                if (comm.IsOpen)
                    return true;
                return false;
            }
            //  接收数据
            public void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                if (comm.IsOpen)
                {
                    byte[] readData = new byte[84];     //获取接收缓冲区中数据的字节数。
                    comm.Read(readData, 0, readData.Length);//从SerialPort 输入缓冲区中读取。
                    if ((readData.Length != 0) &&( readData.Length <= 84))
                    {
                        try
                        {
                            //MessageBox.Show(index.ToString());
                            //  把接收到的数据按照协议来处理
                            if ((readData[0] != 255)&&readData[83]!=255)
                            {
                                MessageBox.Show("数据不正确");
                            }
                            else
                            {
                                int index = readData[1];
                                int count = 0;
                                for (int i = 1; i <= 82; i += 2)
                                {
                                    data.Main[index-1].Sub[count / 8].Row[count % 8] = (float)(((readData[i + 2] * 256 + readData[i + 3]) / 32768) * 90 - 20); //40个点
                                    line[count] = (float)(((readData[i + 2] * 256 + readData[i + 3]) / 32768) * 90 - 20);//40个点 
                                    count++;
                                }
                                if (!createFile(index))
                                {
                                    MessageBox.Show("创建文件失败");
                                }
                                creatData(index);    //保存distance长度的数据
                                line = null;
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                        jishu++;
                    }
                    else 
                    {
                        MessageBox.Show("数据包不正确");
                    }
                    readData = null;
                }
            }这是我的代码 提示说数组越界!串口是35ms发送一组数据
      

  5.   

    for (int i = 1; i <= 82; i += 2)
    当i=82的时候,i+2=84了吧?数组长度是84,访问readData[i + 2]的时候不就越界了么?
      

  6.   


    嗯嗯 是啊是啊,发现了,应该for (int i = 0; i <= 79; i += 2)哎 那么那么 接下来的问题呢,怎么判断首字节是不是0XFF,如果不是,那么就判断下一个是不是,以及接下来的第84位是不是0XFF
      

  7.   

    楼主,建议你加个CRC的校验,这样保证数据的准确性。
    然后根据你数据协议的长度来处理:
    先把buf里数据全取出来放在一个list里,然后看长度够不够,不够继续取数据追加在LIST里,
    如果长度够了,就校验下,如果正确,那么直接取第一个和84个字节就行。
    如果校验不对,就把list里的第一个数据删除掉,继续取你需要长度的数据校验,直到校验对了。
    然后移除你的数据长度的数据。
    然后继续
      

  8.   


    Answer:
    1:DataReceived事件中获取串口接收数据;
    2:在串口DataReceived事件中起一个接收数据的缓冲区(譬如byte[] ReadBuff),这个缓冲区尽量大些,不要产生越界问题(当然异步加载也可以避免越界问题,毕竟这只是个读取缓冲区);判断ReadBuff的每个字节是否是0xFF,如果是则开始往解析缓冲区(譬如byte[] RefBuff)内填后续数据,而RefBuff[0]则是你需要的首字节,至于什么时候结束填入看协议要求;
    3:当一次数据全部填入解析缓冲区的时候,判断RefBuff[84]是不是0XFF;
    4:将需要校验的位累加,RefBuff[0]+RefBuff[1]+...+RefBuff[n]
    5:随时恭候....ps:在串口通信中DataReceived事件属于硬中断事件所以尽量在此做少的操作,此时间中只做数据接收,而数据解析判断等操作尽量放入其他线程中去做,建议使用多线程异步操作来实现。
      

  9.   


    首先对你表示感谢,很认真的对待我的问题,我有困惑的就是下面这个问题,也就是你说的第二点我不知道怎么如果是则开始往解析缓冲区(譬如byte[] RefBuff)内填后续数据
    ,我的做法是先读取了84个字节,但是这样做是不正确的,如果第一个不是0XFF 那么怎么在判断第二个的时候,删掉前面那个,再在后面读进一个,保持84个字节的长度始终不变。。在串口DataReceived事件中起一个接收数据的缓冲区(譬如byte[] ReadBuff),这个缓冲区尽量大些,不要产生越界问题(当然异步加载也可以避免越界问题,毕竟这只是个读取缓冲区);判断ReadBuff的每个字节是否是0xFF,如果是则开始往解析缓冲区(譬如byte[] RefBuff)内填后续数据,而RefBuff[0]则是你需要的首字节,至于什么时候结束填入看协议要求;
      

  10.   

    串口通信第一步是要做接数据,第二步是要判断数据完整性,第三步是解析数据内容接收数据,每次从串口内读取N字节,serialPort1.Read(ReadBuff,0,Length(每次读取长度));能够实现,(当然也可以逐一字节来读取,这样可能会慢一点,但是准确性更高;)来判断N字节中是否有你需要的数据,就像说有没有0xff,如果有则将数据丢弃掉读取缓冲区内数据ReadBuff.Clean();如果有0xff则开始向RefBuff内逐一赋值,至于什么时候赋值完成,看你接收数据结束的条件,对RefBuff赋值完成后将ReadBuff数据丢弃,继续接收,此时异步验证RefBuff的数据完整性(判断校验和等等操作),数据完整则做解析等操作,不完整则丢弃,如此循环,大概意思就是这样吧。
      

  11.   


    是啊是啊,就是这样,我现在接收数据这里 不会处理啊!这段话 我理解,但是不会实现,结束的条件是 开始为0XFF 再读84个字节,再判断一下是不是0XFF,如果是则有效,可以接下去处理,如果不是,原先0XFF 开始后一位继续判断

    说有没有0xff,如果有则将数据丢弃掉读取缓冲区内数据ReadBuff.Clean();如果有0xff则开始向RefBuff内逐一赋值,至于什么时候赋值完成,看你接收数据结束的条件,对RefBuff赋值完成后将ReadBuff数据丢弃,继续接收
      

  12.   

            //  接收数据
            public void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                if (comm.IsOpen)
                {
                    readData = new byte[84];  //获取接收缓冲区中数据的字节数。
                    comm.Read(readData, 0, readData.Length);//从SerialPort 输入缓冲区中读取。                try
                    {
                        if ((readData.Length != 0) && (readData.Length == 84))
                        {
                            //for (int i = 2; i < readData.Length - 1; i++)
                            //{
                            //    list.Add(readData[i]);
                            //    int t = 0;
                            //    t += readData[i];
                            //}
                            //  把接收到的数据按照协议来处理
                            if ((readData[0] == 255) && readData[83] == 255)
                            {
                                if (true)  //累加校验
                                {
                                    writeData(); //处理这条数据包
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }            
                    jishu++;
                    readData = null;
            }
    这是我现在接收数据的代码。帮忙看看有什么问题
      

  13.   

    1:if (comm.IsOpen)不该放在这里,如果串口没有打开,这里永远不会执行,搞清逻辑关系;
    2:readData = new byte[84];  缓冲区定义成全局的,不要每次都实例化,更不要每次在这里实例化;
    3:if ((readData.Length != 0) && (readData.Length == 84))这个判断永远都会成立,你自己想想
    4:if ((readData[0] == 255) && readData[83] == 255)如果readData[1]=0xFF;那么你这个判断等于没有
    5:MessageBox.Show(ex.Message);这会让你的串口堵死,堵得很死,导致你程序崩溃;简单看了下,就这几点吧,在3处判断每个字节是不是0Xff,4所作的事情去异步处理,不要在这处理,这里只做接收~
      

  14.   


            //  接收数据
            public void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                comm.Read(readData, 0, readData.Length);//从SerialPort 输入缓冲区中读取。            for (int i = 0; i < readData.Length; i++)
                {
                    //判断,是否为有效数据
                    if (readData[i] == 255) //是否为数据头0XFF
                    {
                        //开始向RefBuff内逐一赋值,直到满84个                    if (readData[i + 82] == 255) //是否为结束字符0XFF
                        {
                            //累加校验,并处理数据.....
                            dealData(readData);
                        }
                        else 
                        {
                            //这84个数据清空,全部丢弃
                        }
                    }
                    else 
                    {
                       //向后移动一位,前面的丢弃;
                    }
                }
            }        //处理数据
            public void dealData(byte[] readData) 
            {
                float add = 0;
                for (int i = 2; i <= 82; i++) 
                {
                    add += readData[i];
                }
                if (add == readData[83])
                {
                    //保存这条数据包
                    writeData();
                }
                jishu++;
            }
            //保存数据
            public void writeData()
            { 
                line = new float[40];
                int index = readData[1];
                int count = 0;
                for (int i = 0; i <= 79; i += 2)
                {
                    data.Main[index - 1].Sub[count / 8].Row[count % 8] = (float)(((readData[i + 2] * 256 + readData[i + 3]) / 32768) * 90 - 20); //40个点
                    line[count] = (float)(((readData[i + 2] * 256 + readData[i + 3]) / 32768) * 90 - 20);//40个点 
                    count++;
                }
                createFile(index);    //创建文件
                saveData(index);    //保存distance长度的数据
                line = null;
            }
    这个是现在改的,很多都还是不会,主要是判断每个字节是不是0Xff。怎样去读数据,还有我的readData是byte数组,没有清空的啊,哎,麻烦你了这个数据格式是这样的
    0XFF+组别位+40组数据(由高低两个字节组成,共80个字节)+累加校验位(40组数据位全部相加)+结束0XFF  共84个字节
      

  15.   

    一个例子数据包 共84字节16位
    FF 01 8E FF 8F FD 8F FC 8F FB 8F FA 8F F9 8F F8 8F F7 8F F6 8F F5 8F F4 8F F3 8F F2 8F F1 8F F0 8F EF 8F EE 8F ED 8F EC 8F EB 8F EA 8F E9 8F E8 8F E7 8F E6 8F E5 8F E4 8F E3 8F E2 1F E1 8F E0 7F DF 8F DE 8F DD 8F DC 8F DB 8F DA 8F D9 8F D8 8F D7 8A FF
      

  16.   

    我的Code来了,准备给我分
    /// <summary>
            /// 串口接受数据并显示
            /// </summary>
            private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)//Getting data from Comm Port
            {
                if (IClosing) return;
                try
                {
                    timeoutFlag = false;
                    Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。         
                    int n = SerialPort1.BytesToRead;
                    byte[] buf = new byte[n];
                    SerialPort1.Read(buf, 0, n);//读取缓冲数据     
                    bool data_1_catched = false;//缓存记录数据是否捕获到    
                    buffer.AddRange(buf);
                    while (buffer.Count >= 12)
                    {
                        byte CRCH, CRCL;
                        byte[] crcTemp = new byte[10];
                        buffer.CopyTo(0, crcTemp, 0, 10);                    CRCData.CalculateCrc16(crcTemp, out CRCH, out CRCL);
                        if (buffer[10] != CRCH && buffer[11] != CRCL)
                        {
                            buffer.RemoveAt(0);
                            continue;//继续下一次循环   
                        }
                        buffer.CopyTo(0, binary_data_1, 0, 12);//复制一条完整数据到具体的数据缓存   
                        data_1_catched = true;
                        buffer.RemoveRange(0, 12);//正确分析一条数据,从缓存中移除数据。     
                    }
                    if (data_1_catched)
                    {
                        foreach (byte data in binary_data_1)
                            RecText = RecText + data.ToString();
                        bl = true;                    byte[] dataTemp = new byte[2];// for Hex to singal.                    this.Invoke((EventHandler)(delegate
                        {
                            for (int i = 0; i < 4; i++)
                            { 
                                dataTemp[0]=binary_data_1[i*2+3];
                                dataTemp[1]=binary_data_1[i*2+2];                            switch(i)
                                {
                                    case 0:
                                        textBox1.Text = BitConverter.ToSingle(dataTemp, 0).ToString();
                                        break;
                                    case 1:
                                        textBox2.Text = BitConverter.ToSingle(dataTemp, 0).ToString();
                                        break;
                                    case 2:
                                        textBox3.Text = BitConverter.ToSingle(dataTemp, 0).ToString();
                                        break;
                                    case 3:
                                        textBox4.Text = BitConverter.ToSingle(dataTemp, 0).ToString();
                                        break;
                                    default:
                                        break;
                                }                        }
                                
                            
                        }));
                    }
                }
            }
      

  17.   

    private List<byte> buffer = new List<byte>(256);//默认分配1/16页内存,并始终限制不允许超过  
    补上那个buffer的定义
      

  18.   

    a 接收数据,你也可以使用comm.BytesToRead,根据缓冲区内字节数定义要接收的长度
    b 将接收的数据里开始循环找协议头(copy到另外一个大的数组里),如果找到头,从协议头开始读取84个字节判断尾和校验和
    c 如果接收的不够84个,判断缺多少,再次接收后从接收数据的头开始补上缺少的位数,补位的时候可以用Buffer.BlockCopy();
    d 如果接收的大于84或者多条协议,在b方法里继续判断     以上内容纯属虚构
      

  19.   

    请问一下 我用ArrayList 可以吗?
      

  20.   


    再问一下,我定义了comm.ReceivedBytesThreshold = 84;意味着缓冲区有84个字节了我再读一次再用comm.Read()读84个字节,将这个byte数组添加到ArrayList中去,这样可行吗?接下在逐个判断头数据是不是也一样做
      

  21.   

    清空数组数据:Array.Clean(bytename,index,length)if(buff[i] == 0xFF)
    {
       //开始填充解析缓冲区
       ……
       //填充完成从填充完的序号再开始循环
    }建议读取缓冲区定的大些,这样更好
      

  22.   

           using System.Threading;       /// <summary>
            /// 读取缓冲区
            /// </summary>
            private byte[] buff_Read = new byte[1024];//定义比较大
            /// <summary>
            /// 解析缓冲区
            /// </summary>
            private byte[] buff_Reso = new byte[90];//比实际需求量少大,防止边界值误操作溢出
            /// <summary>
            /// 解析线程
            /// </summary>
            private Thread Reso_Thread;
            /// <summary>
            /// 指示当前解析缓冲区是否可用
            /// </summary>
            private bool IsUse = true;        private void COMPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                COMPort.Read(buff_Read, 0, 1000);//从SerialPort 输入缓冲区中读取。            for (int cnt = 0; cnt < 1000; cnt++)
                {
                    //判断,是否为有效数据
                    if (buff_Read[cnt] == 0xFF) //是否为数据头0XFF
                    {
                        while (!IsUse)
                        {
                            Thread.Sleep(10);
                        }
                        int cnt_In = 0;
                        //开始向RefBuff内逐一赋值,直到满84个
                        for (cnt_In = 0; cnt_In < 84; cnt_In++)
                        {
                            buff_Reso[cnt_In] = buff_Read[cnt + cnt_In];
                        }
                        cnt += cnt_In;
                        IsUse = false;
                        Reso_Thread = new Thread(new ThreadStart(Reso_Fuction));
                        Reso_Thread.Start();
                    }
                }
            }        /// <summary>
            /// 解析线程方法
            /// </summary>
            private void Reso_Fuction()
            {
                byte[] buff_test = new byte[100];
                buff_Reso.CopyTo(buff_test,0);
                IsUse = true;
                //判断buff_test中数据校验
                //……
                //对buff_test中数据进行各种操作(也可另起一个新线程操作)
            }大概意思吧,具体的你自己修改~
      

  23.   

    使用SerialPort类
    里面的read方法可以直接读取byte数组,判断的话直接判断buffer[0]和buffer[83]的16进制大小就行了
      

  24.   


    这样写可以不?
    protected void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
    System.Threading.Thread.Sleep(150);
                    byte bytData;
                    int bytnum;
                    bytnum = serialPort1.BytesToRead;
                    rebyte = bytnum;
                    byte[] message = new byte[bytnum];
                    for (int k = 0; k <= (bytnum - 1); k++)
                    {
                        bytData = (byte)serialPort1.ReadByte();
                        this.Invoke(interfaceUpdateHandle, bytData);
                        message[k] = bytData;
                    }
    }
      

  25.   


    写的好高深啊,for循环里面做什么的