本人用C#刚接触串口通信不久,在网上找了一些串口通信的资料,按照资料中的讲解做了个串口通信程序,但是在和下位机通信的时候接收到的数据总是不对,不知道是什么原因,哪位懂C#串口通信的大侠能指点下吗?
正确的数据格式应该是这样的:F0 55 AA 04 07 0D 01 00 02 00 03 00 04 0D 00 0F 00 13 00 04 00 14 00 98 00 03 00 0B 00 83 00 7C 00 07 00 7F 00 80 00 88 9C 9C 但是不知道为什么我用程序中的代码接收到的数据格式却是这样的:AA AA 00 00 00 00 00 00 00 AA AA 04 04 04 0F 00 00 00 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 。哪位大侠能告诉我问题出在哪里吗?
下面是我的发送程序的代码:
  //处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)  
                comm.RtsEnable = true;
                //comm.Parity = Parity.Mark;
                Thread.Sleep(2);
               // comm.Parity = Parity.Mark;                
               
                
                byte[] byteBuffer2 = new byte[9];
                byteBuffer2[0] = 0xaa;
                byteBuffer2[1] = 0xaa;
                byteBuffer2[2] = 0x04;
                byteBuffer2[3] = 0x04;
                byteBuffer2[4] = 0x04;
                byteBuffer2[5] = 0x0f;
                byteBuffer2[6] = 0x00;
                byteBuffer2[7] = 0x00;
                byteBuffer2[8] = 0x00;
                
                String strSend2 = byteBuffer2[0].ToString("X2") + " " + byteBuffer2[1].ToString("X2") + " " + byteBuffer2[2].ToString("X2") + " " + byteBuffer2[3].ToString("X2") + " " + byteBuffer2[4].ToString("X2") + " " +
                                   byteBuffer2[5].ToString("X2") + " " + byteBuffer2[6].ToString("X2") + " " + byteBuffer2[7].ToString("X2") + " " + byteBuffer2[8].ToString("X2");
       
                string sendBuf2 = strSend2;
                string sendnoNull2 = sendBuf2.Trim();
                string sendNOComma6 = sendnoNull2.Replace(',', ' ');    //去掉英文逗号  
                string sendNOComma7 = sendNOComma6.Replace(',', ' '); //去掉中文逗号  
                string strSendNoComma8 = sendNOComma7.Replace("0x", "");   //去掉0x  
                strSendNoComma8.Replace("0X", "");   //去掉0X  
                string[] strArray2 = strSendNoComma8.Split(' ');                List<byte> buf2 = new List<byte>();//填充到这个临时列表中  
                //依次添加到列表中  
                int byteBufferLength2 = strArray2.Length;
                for (int i = 0; i < strArray2.Length; i++)
                {
                    byte str2 = byte.Parse(strArray2[i].ToString(), System.Globalization.NumberStyles.HexNumber);
                    buf2.Add(str2);
                   
                }
                
                //转换列表为数组后发送
               
                comm.Write(buf2.ToArray(), 0, buf2.Count);
                Thread.Sleep(60);                comm.RtsEnable = false;
                //Thread.Sleep(16);
                comm.Parity = Parity.Mark;接收部分的代码如下
   void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
           
            //更新界面  
            //this.Invoke((EventHandler)(delegate { richTextBox1.Text = ""; }));
            //buffer.RemoveAt(0);
            Thread.Sleep(500);//此处一定要有,休眠一段 时间利用缓存来接收数据,经测试75秒刚好
            if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环  
            try
            {
                Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。  
                int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致  
                byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据  
                received_count = n;//增加接收计数  
                //richTextBox3.Text = received_count.ToString();
                //MessageBox.Show(received_count.ToString());
                comm.Read(buf, 0, n);//读取缓冲数据  
                builder.Length=0;//清除字符串构造器的内容                  //<协议解析>  
                bool data_1_catched = false;//缓存记录数据是否捕获到 
                buffer.AddRange(buf);
                if (buffer.Count >=9)
                {
                    string data,data1;
                    data = "";
                    data1 = "";
                    //MessageBox.Show(buf[8].ToString("X2"));
                    for (int i = 0; i < n; i++)
                    {
                        data1 += buffer[i].ToString("X2") + " ";
                        data += buf[i].ToString("X2") + " ";
                       // data = n.ToString();
                    }
                    //更新界面  
                    this.Invoke((EventHandler)(delegate { richTextBox4.Text = data; }));
                    this.Invoke((EventHandler)(delegate { richTextBox3.Text = data; }));
 //因为要访问ui资源,所以需要使用invoke方式同步ui。  
                    this.Invoke((EventHandler)(delegate
                    {
                        //判断是否是显示为16禁止  
                        if (checkBox3.Checked)
                        {
                            //依次的拼接出16进制字符串  
                            foreach (byte b in buf)
                            {
                                builder.Append(b.ToString("X2") + " ");
                            }
                        }
                        else
                        {
                            //直接按ASCII规则转换成字符串  
                            builder.Append(Encoding.ASCII.GetString(buf));
                        }
                        //追加的形式添加到文本框末端,并滚动到最后。  
                        richTextBox1.AppendText(builder.ToString());
                       // richTextBox1.Text=builder.ToString();
                        //修改接收计数  
                        //labelGetCount.Text = "Get:" + received_count.ToString();
                    }));  
                
                }
                 
                
                
            }
            finally
            {
                Listening = false;//我用完了,ui可以关闭串口了。  
            }          }

解决方案 »

  1.   

    帮你顶下
    那么多3F可能是由于发送了ASCII码以外的字符,但是却是以ASCII码的形式发送的,导致编码为“?”,对应ASCII值为3F
      

  2.   

    应该不是那样的,我的串口程序是和下位机通讯的,当下位机收到我发送的下发指令AA AA 00 00 00 00 00 00 00 AA AA 04 04 04 0F 00 00 00以后会给我的串口程序回传数据,这个数据就是F0 55 AA 04 07 0D 01 00 02 00 03 00 04 0D 00 0F 00 13 00 04 00 14 00 98 00 03 00 0B 00 83 00 7C 00 07 00 7F 00 80 00 88 9C 9C 这种类型的,FO  55 AA是数据头,最后两位是校验位中间部分是数据体,中间部分的内容会根据情况动态变化的,我现在的情况是从缓存中取出来的回传数据全是3F,我感觉是取缓存数据的命令有问题。因为我用我做的这个串口通讯软件通过串口服务器下发给下位机,下位机回传过来的数据 又是正确的,但是通过COM下发给下位机下位机也会正常回答,但是就是回答的数据取出来是错的。不知道是什么原因,能指点下吗?
      

  3.   

    用这个软件:SUDT SerialTrace,跟踪下,看看发的不对还是收的不对。
      

  4.   

    给你一个我刚做的串口  接收public static string aa="";
            private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                string s100 = "";
                System.Threading.Thread.Sleep(100);
                int bytes = serialPort.BytesToRead;
                byte[] buffer = new byte[bytes];
                if (bytes == 0)
                { return; }
                serialPort.Read(buffer, 0, bytes);
                s100 = ww(buffer);//字节数组转为十六进制字符串
                if (s100 != "")
                {                string s = "";
                    int length = Convert.ToInt32( buffer[7].ToString()) - 1;
                    for (int j = 9; j < length+9; j++)
                    {
                        string a= Convert.ToString(buffer[j],16);
                        if(a.Length==1)
                        {
                            a = "0" + a;
                        }
                        s += a;
                    }
                    
                    //s = "";
                   // MessageBox.Show(s100);
                    aa = s100;
                    InvokeHelper.Set(richTextBox2, "Text", aa);
                }
                serialPort.DiscardInBuffer();        }        public string ww(byte[] data)//字节数组转为十六进制字符串
            {
                StringBuilder sb = new StringBuilder(data.Length * 3);
                foreach (byte b in data)
                    sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
                return sb.ToString().ToUpper();
            }
      

  5.   

    我用你说的这个软件截图看了下,发现他回传过来的数据就是3F 3F 3F 3F 3F 3F 3F 3F 3F这些字符,截图说明吧
      

  6.   

    楼主啊,我觉得你读取串口的方法没错啊,就是原始数据啊,只能是下位机发送有误,你读取的根本没问题int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致  
                    byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据  
                    received_count = n;//增加接收计数  
                    comm.Read(buf, 0, n);//读取缓冲数据  
     comm.Read(buf, 0, n);这样读取的话,接收到的什么,读取的就是什么呀,直接看buf里的是什么数据不就完事了吗,别老是怀疑这怀疑那的,你读取的方法没问题,找找下位机的问题吧
      

  7.   

    给串口发送数据时分是ASCILL还是十六进制,两个读取方式我刚刚写过,有需要可以找我
      

  8.   

      List<string> SendDataList = new List<string>();//临时存放HEX字符串数据
                for (int i = 0; i < strX.Length; i = i + 2)
                {
                    SendDataList.Add(strX.Substring(i, 2));//切割成两两一组的字符串
                }
                byte[] SendBytes = new byte[SendDataList.Count];
                for (int j = 0; j < SendBytes.Length; j++)//遍历临时HEX字符串数组,存入byte数组
                {
                    SendBytes[j] = (byte)(Convert.ToInt32(SendDataList[j], 16));
                }
                comm.Write(SendBytes, 0, SendBytes.Length);
    这是其中的一部分,这是十六进制的形式读取
      

  9.   

    你用的是usb转串口线吧可能不稳定原因。usb转的不太稳定。
    你可以用这个测试一下:你用两个com,中间接个转接线。COM1发送,COM2接受。看看发过去之后,回来的是不是原来的(自己发自己收)如果不是,很有可能是usb转串口线不稳定造成的。原来我也遇见过这个问题。建议用原生串口
      

  10.   

    我用的是电脑自带的串口的,就是回传过来的数据全是3F,本来下位机应该回传10个正常的数据的(F0 55 AA 01 08 00 04 00 0D 0D),现在我这也接收到了10个数据,但是是错误的。(3F 3F 3F 3F 3F 3F 3F 3F 3F 3F )我估计是数据在解析的时候出错了,可能是像2楼说的那样,回传了ASCII码以外的字符,但是却是以ASCII码的形式解析的,导致编码为“?”,对应ASCII值为3F 。有没有其他方法把回传的数据解析出来?
      

  11.   


    也许问题根本就不是你接收的数据,是下位机发送的根本就是3F,那你不管怎么接受都是3F的。找找下位机的问题。你说解析出错,有什么好出错的,SerialPort.Read(byte[],int inbuffer,int count),按照这种办法读取缓冲区的数据,串口总线上的数据是什么,读到的就是什么,压根就不是你说的解析的不对。因为这种办法读取串口,是按照十六进制读取的,没有经过任何编码。
    不要只在PC机上找问题,找找下位机的问题。如果PC机读取没有问题,你就是找死了也找不到
      

  12.   

    下面是发送数据的代码:
     private void button1_Click(object sender, EventArgs e)
            {
                int n = 0;
                comm.Encoding = System.Text.Encoding.Unicode;
           
                //16进制发送  
                if (checkBox1.Checked)
                {
                    
                    //处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)  
                    
                    comm.RtsEnable = true;
              
                    Thread.Sleep(2);
                    comm.Parity = Parity.Mark;                //转换列表为数组后发送  
                    byte[] send1 = { 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    comm.Write(send1, 0, send1.Length);
               
                    Thread.Sleep(50);                comm.RtsEnable = false;
                   
                    Thread.Sleep(2);
                    comm.Parity = Parity.Mark;
                   
                    
                    //处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)  
                    comm.RtsEnable = true;
                   
                    Thread.Sleep(2);
                    comm.Parity = Parity.Mark;                //转换列表为数组后发送
                    byte[] send2 = { 0xaa, 0xaa, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00 };
                    comm.Write(send2, 0, send2.Length);
                   
                    Thread.Sleep(50);
                                comm.RtsEnable = false;
                    Thread.Sleep(10);                comm.Parity = Parity.Mark;
                    
                }
                else//ascii编码直接发送  
                {
                    //包含换行符  
                    if (checkBox2.Checked)
                    {
                        comm.WriteLine(richTextBox2.Text);
                       // n = txSend.Text.Length + 2;
                    }
                    else//不包含换行符  
                    {
                        comm.Write(richTextBox2.Text);
                        //n = txSend.Text.Length;
                    }
                }
            }
    下面是我的接收代码
      void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
              
                comm.Parity = Parity.Mark;
                comm = (SerialPort)sender;
                string s100 = "";
                Thread.Sleep(500);//此处一定要有,休眠一段 时间利用缓存来接收数据,经测试75秒刚好
                if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环  
                try
                {
                    Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。                  int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致  
                    byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据  
                    received_count = n;//增加接收计数  
                                 builder.Length=0;//清除字符串构造器的内容                  //<协议解析>  
                    bool data_1_catched = false;//缓存记录数据是否捕获到 
                    buffer.AddRange(buf);
                    if (buffer.Count >=9)
                    {
                        string data,data1;
                        data = "";
                        data1 = "";
                        //MessageBox.Show(buf[8].ToString("X2"));
                        for (int i = 0; i < n; i++)
                        {
                            data1 += Convert.ToString(buf[i],16);
                            data += buf[i].ToString("X2") + " ";
                           // data = n.ToString();
                        }
                        //更新界面  
                        this.Invoke((EventHandler)(delegate { richTextBox4.Text = data; }));
                        this.Invoke((EventHandler)(delegate { richTextBox3.Text = data; }));                  
                        //因为要访问ui资源,所以需要使用invoke方式同步ui。  
                        this.Invoke((EventHandler)(delegate
                        {
                            //判断是否是显示为16禁止  
                            if (checkBox3.Checked)
                            {
                                //依次的拼接出16进制字符串  
                                foreach (byte b in buf)
                                {
                                    builder.Append(b.ToString("X2") + " ");
                                }
                            }
                            else
                            {
                                //直接按ASCII规则转换成字符串  
                                builder.Append(Encoding.ASCII.GetString(buf));
                            }
                            //追加的形式添加到文本框末端,并滚动到最后。  
                            richTextBox1.AppendText(builder.ToString());
                            comm.DiscardInBuffer();
                      
                        }));  
                    
                    }
                     
                    
                    
                }
                finally
                {
                    Listening = false;//我用完了,ui可以关闭串口了。  
                }          }
           //转换列表为数组后发送
    通讯协议是这样的:软件先向下位机下发0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 这几个数据,说明我要开始下发数据了,然后再下发0xaa, 0xaa, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00说明这是我下发的指令,下位机接收到了0xaa, 0xaa, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00指令以后会回传数据,
                     
      

  13.   

    楼主你读取串口的代码呢?这样buf是空的呀int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致  
                    byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据  
                    received_count = n;//增加接收计数  
                  
     
                    builder.Length=0;//清除字符串构造器的内容  
     
                    //<协议解析>  
                    bool data_1_catched = false;//缓存记录数据是否捕获到 
                    buffer.AddRange(buf);
      

  14.   

    上面的代码我少复制了一行,我程序中的代码是这样的
                 int n = comm.BytesToRead;
                    byte[] buf = new byte[n];
                    received_count = n;//增加接收计数  
                 
                    comm.Read(buf, 0, n);//读取缓冲数据 
      

  15.   


    你的3F是在哪里出现的?这是重点呀,是显示的时候?
    comm.Read(buf, 0, n);在这设置一个断点,然后用监视窗口查看buf里的数据
      

  16.   

    我用你说的方法查看数据显示buf里的数据 是63
      

  17.   

    你说的方法我测试了,我是用我电脑自带的COM口用我做的程序下发数据,然后下位机接收到数据以后同时向我电脑的COM和我买的串口服务器回传数据,但是通过串口服务器解析出来的数据是正确的,通过电脑COM口用程序解析出来就是错误的,在BUF中查看到的数据是63
      

  18.   


    我的方法是抛弃硬件的啊。你测试方法中怎么还包含硬件呢。我觉得,如果想排除软件问题,你就软件连接com1,串口助手连接com2  com1,2之间用交叉线连起来。如果软件发送 aaa,串口助手监听到aaa,说明发送没问题。如果串口助手发送bbb,软件收到bbb,则说明软件接受没问题。好了,剩下的八成是你硬件问题了。
      

  19.   


    你按照39楼的办法调试下,用串口助手发送消息给你的软件,看是不是能正确接收。然后再用你的软件发送消息给串口助手,看是不是能正常发送。
    软件的波特率以及Parity的设置跟单片机一样吗?
    另外,你说的串口服务器是什么?
      

  20.   

    我在这郁闷呢,我用我电脑的COM口和另外一台电脑的COM口用串口线交叉连接起来进行通信,然后用串口调试助手互相下发数据,奇怪的是我电脑能接收到另一台电脑发送的数据,但是我电脑发送出去的数据另外一台电脑接收不到。。
      

  21.   

    串口服务器是那种工业上使用的把232信号和485信号互相转换的设备,一般我们的电脑发送的是232的信号,我的下位机是485通信的,需要把232信号转换成485信号通信,串口服务器的作用主要就是一端和电脑直接用TCP/IP通信(通过在电脑上虚拟一个串口来实现的),另外一端和下位机用485通信。
      

  22.   

    给你一个我做的串口的程序吧,C#中有串口控件的。
    using System.IO.Ports;namespace serialPortExample
    {
        public partial class Form1 : Form
        {
                   public Form1()
            {
                InitializeComponent();
            }        private void button1_Click(object sender, EventArgs e)
            {
                if (button1.Text == "打开串口")
                {
                    button1.Text = "关闭串口";
                    serialPort1.Open();
                }
                else
                {
                    button1.Text = "打开串口";
                    serialPort1.Close();
                }        }        private void button3_Click(object sender, EventArgs e)
            {
                if (checkBox2.Checked)
                {
                    string[]sentstring = textBox2.Text.Split(' ');
                    byte[] sendByte = new byte[sentstring.Length];
                    for (int i = 0; i < sentstring.Length; i++)
                    {
                        sendByte[i] = Convert.ToByte(sentstring[i],16);
                    }
                        serialPort1.Write(sendByte, 0, sendByte.Length); 
                }
                else
                {
                    string sentstring = textBox2.Text;                serialPort1.Write(sentstring);
                }
            }
            
            delegate void delegate1();
            
           
            string s;
            private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                if (checkBox1.Checked)
                {
                    byte[] tempDate = new byte[serialPort1.BytesToRead];
                    int length = serialPort1.Read(tempDate, 0, serialPort1.BytesToRead);
                    delegate1 receivedelegate1 = new delegate1(datareceive);
                    
                    for (int i = 0; i < length; i++)
                    {
                        s += Convert.ToString(tempDate[i], 16)+" ";
                    }                this.Invoke(receivedelegate1);
                }            else
                {                delegate1 receivedelegate2 = new delegate1(datareceive);                s += serialPort1.ReadExisting();
                    this.textBox1.Invoke(receivedelegate2);
                    /*new MethodInvoker//这是直接调用MethodInvoker委托
                   (
                   这是匿名委托
                       delegate
                       {
                           this.textBox1.AppendText(serialreadstring);
                            
                       }
                   )*/            }        }
            
            public void datareceive()
            {
                //this.textBox1.AppendText(serialreadstring);
                this.textBox1.Text += s;
            }
                    private void button2_Click(object sender, EventArgs e)
            {
                textBox1.Clear();
            }        private void checkBox3_CheckedChanged(object sender, EventArgs e)
            {
                if (checkBox3.Checked)
                {
                    timer1.Interval = Convert.ToInt32(textBox3.Text);
                    timer1.Enabled = true;
                }
                else
                    timer1.Enabled = false;
            }        private void timer1_Tick(object sender, EventArgs e)
            {
                button3_Click(null, null);
            }        
           
           
        }
    }
      

  23.   

    “串口服务器的作用主要就是一端和电脑直接用TCP/IP通信(通过在电脑上虚拟一个串口来实现的)”看来问题在这,下位机发送数据用的是TCP/IP协议(这个协议我就不懂啦- -)
    你的下位机对数据进行了处理,也许是按照TCP/IP协议,通过你的串口服务器可以还原真实数据。但是通过串口转换器得到的数据只是下位机经过处理后的。
    你的这个串口服务器是和单片机一起提供的吗?这两个是由同个厂商提供的?
    楼主是不是想以后不买串口服务器就可以直接从单片机接收数据呀
      

  24.   

    哈哈,今天终于把这个问题解决了,高兴哈,非常感谢各位给出的回复,谢谢大家了哈。
    原来是我们的该死的下位机程序在那做怪,发现我们的下位机是这样设置的:串口程序在向下位机下发数据之前要先设置为MARK验证,数据发送完以后在接收的时候要设置为NONE验证,真是坑人啊!还好,终于把问题解决了,哈哈,今天心情真是好啊