串行端口通信:接收缓冲区问题 [英] Serial Port Communication: Receive buffer issue

查看:101
本文介绍了串行端口通信:接收缓冲区问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好,

我从串行端口读取数据并将其显示在富文本框中时遇到问题.

以下是从我的串口接收到的数据事件处理程序:

Hello,

I have an issue with reading data from the serial port and displaying it to a rich textbox.

The following is from my serial port received data event handler:

void comPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string msg = String.Empty;
            try
            {
                msg = comPort.ReadExisting();

             
            }
            catch (IOException ex)
            {
                //process any errors

               
            }
            //Display the data size of msg
            DisplayDataSize(Encoding.ASCII.GetByteCount(msg));

            //Display Data
            DisplayData(MessageType.Incoming, msg + '\n');


        }



一切正常,除了当我向设备发送某些命令时,我会在多个触发器中获得设备的响应.例如,如果我发送命令以获取设备的版本,则它应显示"VERSION 1.400240242 ....",但我正在获取
版本
1.40024 ..."

这很奇怪.我尝试创建一个读取函数,而不是使用具有确切代码的事件处理程序,并在主程序中的写入函数之后立即调用读取函数.当我将命令发送到设备时,不会得到任何响应(例如,空字符串).然后,当我再次向设备发送命令时,我从两次发送中都获得了响应(例如"VERSION 1.42 ..... \ n VERSION 1.42 ...").

同样,在调试模式下逐行运行它时,所有内容也会正确显示.
我使用backgroundWorker线程来编写和接收代码的数据部分.

有人知道我的问题可能的解决方法吗?

谢谢

-dbzx



Everything works fine except when I send certain commands to the device, I get the device''s response in several triggers. For example, if I send a command to get the version of the device, it should display "VERSION 1.400240242....", but I am getting
"VERSION
1.40024..."

which is something odd. I tried creating a read function instead of using an event handler with the exact code and call the read function right after the write function in my main program. When I send the command to the device, I would get no response(eg. empty string). Then when I send command to the device again, I get the response back from both sends (eg. "VERSION 1.42.....\n VERSION 1.42...").

Also when running it in debug mode line by line, everything is displayed correctly.
I used backgroundWorker thread for the writing and receiving data portion of my code.

Does anyone know a possible fix for my problem?

Thank you

-dbzx

推荐答案

在buttonStart_Click()中,我们首先设置端口名称和波特率.在我们的示例中,PortName为COM1,但您可以将其设置为计算机上可用的任何其他端口.注意,PortName是一个字符串,必须用引号引起来.波特率必须与串行连接另一端的波特率一致.然后,我们调用Open()函数.如果端口打开确定,我们将禁用开始"按钮,启用停止"按钮,并允许在textBox1中写入.



In buttonStart_Click( ), we begin by setting the port name and baud rate. In our example PortName is COM1 but you can set it to any other port available on your computer. Notice the PortName is a string and must be in quotes. The baud rate must agree with the baud rate of whatever is on the other end of the serial connection. We then call the Open( ) function. If the port opened OK, we disable the Start button, enable the Stop button, and allow writing in textBox1.



private void buttonStart_Click(object sender, EventArgs e)
  {
      serialPort1.PortName = "COM1";
      serialPort1.BaudRate = 9600;
  
      serialPort1.Open();
      if (serialPort1.IsOpen)
      {
          buttonStart.Enabled = false;
          buttonStop.Enabled = true;
          textBox1.ReadOnly = false;
      }
  }




一旦serialPort1打开,任何传入的串行字符都将引发DataReceived事件.在事件处理程序内部,我们将内部串行接收缓冲区中的所有现有字符读入字符串RxString.下一部分很关键,并不明显. serialPort1在幕后在其自己的单独线程中运行.该线程无法直接调用应用程序主线程中的任何函数.但是,可以使用特殊功能Invoke().因此,我们使用Invoke调用DisplayText()函数. RxString是两个线程均可访问的全局字符串变量.




Once the serialPort1 is open, any incoming serial characters will cause a DataReceived event to fire. Inside the event handler we read all existing characters from the internal serial receive buffer into string RxString. The next part is critical and not obvious. serialPort1 runs in it own separate thread behind the scenes. This thread cannot directly call any functions in the main thread of our application. However, a special function, Invoke( ), will allow it. So we use Invoke to call our DisplayText( ) function. RxString is the global string variable accessable by both threads.

private void serialPort1_DataReceived
  (object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    RxString = serialPort1.ReadExisting();
    this.Invoke(new EventHandler(DisplayText));
}



我们的DisplayText()函数很简单.我们只是将RxString中的文本附加到textBox1中已经存在的任何内容.




Our DisplayText( ) function is simple. We just append the text in RxString to whatever is already in textBox1.


private void DisplayText(object sender, EventArgs e)
  {
      textBox1.AppendText(RxString);
  }



textbox1 KeyPress()函数捕获键入到textBox1中的字符,并将其写入serialPort1. Write()只能从char类型的数组中发送字符,因此我们声明一个长度为[1]的字符,并为其分配KeyChar值.通过Write()中的参数,我们告诉它发送buff中的字符,将0个字符偏移到数组中,并将长度为1个字符.我们将事件设置为"Handled",以防止键入的字符出现在textBox1中.如果要显示它(本地回显),请省略该行.



The textbox1 KeyPress( ) function captures characters typed into textBox1 and writes them to serialPort1. Write( ) can only send characters from a char type array so we declare one with a length of [1] and assign the KeyChar value to it. With the arguments in Write( ), we tell it to send the characters in the buff, offset of 0 chars into the array, and a length of 1 char. We set the event to "Handled" to prevent the typed character from appearing in textBox1. If you want it to appear (local echo), omit the line.

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    // If the port is closed, don't try to send a character.
    if(!serialPort1.IsOpen) return;

    // If the port is Open, declare a char[] array with one element.

    char[] buff = new char[1];

    // Load element 0 with the key character.
    buff[0] = e.KeyChar;

    // Send the one character buffer.
    serialPort1.Write(buff, 0, 1);

    // Set the KeyPress event as handled so the character won't
    // display locally. If you want it to display, omit the next line.

    e.Handled = true;
}



单击停止按钮将调用buttonStop_Click().如果serialPort1已打开,我们将关闭端口并将按钮enable和textBox1 ReadOnly状态设置回其先前的值.




Clicking the Stop button calls buttonStop_Click( ). If serialPort1 is open, we close the port and set the button enables and textBox1 ReadOnly state back to their previous value.


private void buttonStop_Click(object sender, EventArgs e)
 {
      if (serialPort1.IsOpen)
      {
          serialPort1.Close();
          buttonStart.Enabled = true;
          buttonStop.Enabled = false;
          textBox1.ReadOnly = true;
      }
 }




最后但并非最不重要的一点是,如果在打开serialPort1的同时关闭了应用程序,则必须先关闭该端口,否则程序将挂起.





Last but not least, if the application is closed while serialPort1 is open, the port must be closed first or the program will hang.


private void Form1_FormClosing(object sender, FormClosingEventArgs e)
 {
     if (serialPort1.IsOpen) serialPort1.Close();
 }


这篇关于串行端口通信:接收缓冲区问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆