本帖最后由 pink__floyd 于 2012-02-22 16:26:18 编辑

解决方案 »

  1.   

    http://topic.csdn.net/u/20120111/18/2dacb0ab-1c29-4ab7-9ef9-f53d5b0a8cd6.html?36258
      

  2.   

    我都看了,大意都明白,具体操作不会修改,原理不太懂。就是提取 自己所需 的4个字节数据时,出现了问题。下位机的是我朋友做的,支持ModBus协议。
      

  3.   


    int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
                    byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
                   
                    comm.Read(buf, 0, n);//读取缓冲数据
                    buffer.AddRange(buf);
                    if (buffer.Count==9)
                    {
                        byte[] binary_data_1 = new byte[9];
                        buffer.CopyTo(0, binary_data_1, 0, 9);
                        buffer.Clear();                    string data = binary_data_1[3].ToString("X2") + binary_data_1[4].ToString("X2") + binary_data_1[5].ToString("X2") + binary_data_1[6].ToString("X2");                    int hex = Convert.ToInt32(data, 16);                    this.Invoke((EventHandler)(delegate { this.textBox2.AppendText(hex.ToString()); }));                 }第二个问题 这样改就好了。加上 buffer.Clear();
    我都不知道为啥。
      

  4.   

    DataRecevied 每次收到的数据可能不一样长,说具体一点就是你认为“ 每次收到的都是9个字节的数据。”其实不是(可能大于也可能小于),不信你在这个代码( int n = comm.BytesToRead;)前面sleep几秒钟试下。还有我以前接触的单片机是,下面给你会数据的时候,你在向串口写数据,人家不会理你的。(就是你快速(没有sleep)的给人家发10桢数据,人家可能给你只回5桢)第一个解决方法,你自己控制收发时间,能保证每次都是收到完整的一帧(数据)没有多收也没有少收。可以定义一个信号变量,第一条收完了在发第二条。第二个解决方法,自己创建一个全局的buffer,每次comm_DataReceived 收到的数据只管往 全局的buffer里面填
    然后在去遍历截取里面完整的一帧帧数据(取出来就remove全部buffer的数据)。然后在去操作取出来的每一帧。
      

  5.   

    是标准的ModBus RTU吧。收发都是十六进制的。
    如果每次都是读同一个寄存器,接受到的数据长度应该不会变,主要是判断一下是否有干扰。(用CRC校验来判断)
    思路是这样:
    if (buffer.Count==9) 改为 if (buffer[0]==0x02&&buffer[1]==0x03) 
    然后 计算 buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]的crc校验是否为 buffer[7]buffer[8],(要分清高位和低位,有次我没注意,一直无法正确校验)。
    如果校验匹配,则 buffer.CopyTo(0, data_1, 0, 9);
    否则 buffer.clear();
      

  6.   


            public byte[] CRC16(byte[] data)
            {
                byte CRC16Lo;
                byte CRC16Hi;   //CRC寄存器 
                byte CL; byte CH;       //多项式码&HA001 
                byte SaveHi; byte SaveLo;
                byte[] tmpData;
                int Flag;
                CRC16Lo = 0xFF;
                CRC16Hi = 0xFF;
                CL = 0x01;
                CH = 0xA0;
                tmpData = data;
                for (int i = 0; i < tmpData.Length; i++)
                {
                    CRC16Lo = (byte)(CRC16Lo ^ tmpData[i]); //每一个数据与CRC寄存器进行异或 
                    for (Flag = 0; Flag <= 7; Flag++)
                    {
                        SaveHi = CRC16Hi;
                        SaveLo = CRC16Lo;
                        CRC16Hi = (byte)(CRC16Hi >> 1);      //高位右移一位 
                        CRC16Lo = (byte)(CRC16Lo >> 1);      //低位右移一位 
                        if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1 
                        {
                            CRC16Lo = (byte)(CRC16Lo | 0x80);   //则低位字节右移后前面补1 
                        }             //否则自动补0 
                        if ((SaveLo & 0x01) == 0x01) //如果LSB为1,则与多项式码进行异或 
                        {
                            CRC16Hi = (byte)(CRC16Hi ^ CH);
                            CRC16Lo = (byte)(CRC16Lo ^ CL);
                        }
                    }
                }
                byte[] ReturnData = new byte[2];
                ReturnData[0] = CRC16Hi;       //CRC高位 
                ReturnData[1] = CRC16Lo;       //CRC低位 
                return ReturnData;
            } 
    给你个crc校验函数。刚测试过,可以的哦。02 03 00 00 00 02 ,计算完就是C4 38