简体   繁体   English

RS-232 异常行为

[英]RS-232 erratic behavior

Windows 10-64.视窗 10-64。 I coded a small VB application last fall, to drive a "PR-705" serial device from the RS-232 port.去年秋天,我编写了一个小型 VB 应用程序,以从 RS-232 端口驱动“PR-705”串行设备。 It worked flawlessly.它完美无缺。 Now, whenever I fire that code, the PR-705 is not responding so nicely?现在,每当我触发该代码时,PR-705 的响应都不是很好? I originally used a FTDI-based USB to RS232 adapter (Thunderlinx 1000) which worked perfect.我最初使用的是基于 FTDI 的 USB 转 RS232 适配器(Thunderlinx 1000),它运行良好。 I figured, the problem might have to do with the "driver"?我想,问题可能与“驱动程序”有关? So I added a PCI-Express serial port card from StarTech to my PC.所以我在我的电脑上加了一块 StarTech 的 PCI-Express 串口卡。 The result: no improvement - same erratic behavior?结果:没有改善——同样的不稳定行为? Out of curiosity, this morning, I fired my trusty Windows HyperTerminal and it worked flawlessly (out of the PCI-e port)!出于好奇,今天早上,我启动了我可信赖的 Windows 超级终端,它完美地运行(在 PCI-e 端口之外)! So I know the trouble does not come from the device itself (sigh!) but somewhere in the chain of communications.所以我知道问题不是来自设备本身(叹气!)而是通信链中的某个地方。

The problem I run into is as follows (hopefully, you can detect a "pattern"):我遇到的问题如下(希望您可以检测到“模式”):

a) Open the serial port b) Send a command to the port, in an ASCII string (eg "M1") <- Device responds by sending data back In order to obtain ALL data from device, however, I have to send additional commands: c) "D2" d) "D3" e) "D4" f) "D5" a) 打开串行端口 b) 以 ASCII 字符串(例如“M1”)向端口发送命令 <- 设备通过发回数据进行响应 但是,为了从设备获取所有数据,我必须发送其他命令: c) "D2" d) "D3" e) "D4" f) "D5"

When I run these commands from HyperTerminal, I get stellar behavior.当我从超级终端运行这些命令时,我得到了出色的行为。

In my application, however, the additional commands ("D2", "D3", "D4" and "D5") are not getting THROUGH to the device, somehow?然而,在我的应用程序中,附加命令(“D2”、“D3”、“D4”和“D5”)没有通过设备,不知何故? When I send "D2", for example, I get "XYZ" data back, which is OK.例如,当我发送“D2”时,我会返回“XYZ”数据,这没问题。 But when I follow-up with "D3", I still get the same "XYZ" data back?但是当我跟进“D3”时,我仍然得到相同的“XYZ”数据? It is as though the new command ("D3") never reached the device?好像新命令(“D3”)从未到达设备?

My (ugly) workaround is to resend the same command over and THEN I get the new data (most of the time).我的(丑陋的)解决方法是重新发送相同的命令,然后我获得新数据(大部分时间)。

Here is some of my code:这是我的一些代码:

Dim myPort As New IO.Ports.SerialPort("COM2") With {
            .BaudRate = 9600,
            .DataBits = 8,
            .StopBits = IO.Ports.StopBits.One,
            .Parity = IO.Ports.Parity.None,
            .Handshake = IO.Ports.Handshake.RequestToSend,
            .RtsEnable = True,
            .DtrEnable = True,
            .ReadTimeout = 1000000,
            .WriteTimeout = 10000
            }


myPort.Open()
myPort.WriteLine("M1")
myPort.WriteLine("D2")
Incoming = myPort.ReadLine() 

myPort.WriteLine("D2")
Incoming = myPort.ReadLine()

myPort.WriteLine("D3")
Incoming = myPort.ReadLine() 

myPort.WriteLine("D4")
Incoming = myPort.ReadLine() 

myPort.WriteLine("D5")
Incoming = myPort.ReadLine()

I know the TimeOut value is "extreme" but the device can take up to 15 minutes to reply, depending on the circumstances.我知道 TimeOut 值是“extreme”,但设备最多可能需要 15 分钟才能回复,具体取决于具体情况。 I can't close the port before the device responds back otherwise I'll get an error, something to do with CTS, and then device automatically reboots -- not ideal.我无法在设备响应之前关闭端口,否则我会收到错误消息,这与 CTS 有关系,然后设备会自动重新启动——这并不理想。 I'm not a RS-232 expert but I do the best I can with the little knowledge I have.我不是 RS-232 专家,但我尽我所能用我所拥有的一点知识。

Found a partial answer to my serial port problem but this solution is not without its own problems.找到了我的串行端口问题的部分答案,但该解决方案并非没有问题。 I found some c# code I adapted where the serial port "Received" is separated into its own "event".我发现了一些我改编的 C# 代码,其中串行端口“Received”被分离成它自己的“事件”。 This works very well.这非常有效。 As you'll see in the code below, it does the job.正如您将在下面的代码中看到的,它完成了这项工作。 But now I'm facing the question of how to go about "successively" polling the port to get all the data returned by the instrument?但是现在我面临的问题是如何“连续”轮询端口以获取仪器返回的所有数据?

Here's the c# code first:首先是c#代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace WindowsApplication14
{  
    public partial class Form1 : Form
    {
        string Operation, MesureM1, MesureD2, MesureD3, MesureD4;
        SerialPort _serialPort;

        // delegate is used to write to a UI control from a non-UI thread
        private delegate void SetTextDeleg(string text);

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                if (!_serialPort.IsOpen)
                    _serialPort.Open();

                _serialPort.Write("PR705\r\n");
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error opening serial port :: " + ex.Message, "Error!");
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _serialPort = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
            _serialPort.Handshake = Handshake.RequestToSend;
            _serialPort.RtsEnable = true;
            _serialPort.DtrEnable = true;
            _serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
            _serialPort.ReadTimeout = 500;
            _serialPort.WriteTimeout = 500;
            _serialPort.Open();

            _serialPort.Write("PR705\r\n");

        }

        private void btnM1_Click(object sender, EventArgs e)
        {
            Operation = "M1";
            _serialPort.Write("M1\r\n");    // 0000,111,3.896e+002,0.3371,0.3563
            Thread.Sleep(500);
        }

        private void btnD2_Click(object sender, EventArgs e)
        {
            Operation = "D2";
            _serialPort.Write("D2\r\n");   
            Thread.Sleep(500);
        }

        private void btnD3_Click(object sender, EventArgs e)
        {
            Operation = "D3";
            _serialPort.Write("D3\r\n");   
            Thread.Sleep(500);
        }

        private void btnD4_Click(object sender, EventArgs e)
        {
            Operation = "D4";
            _serialPort.Write("D4\r\n");
            Thread.Sleep(500);
        }

        void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(500);
            string data = _serialPort.ReadLine();
            this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
        }

        private void si_DataReceived(string data)
        {
            String Result = data.Trim();
            textBox1.Text = Result; 

            switch (Operation)
            {
                case "M1":
                    MesureM1= Result; // MesureBase = "0000,111,3.884e+002,0.3377,0.3570"
                    break;
                case "D2":
                    MesureD2 = Result;  // MesureD2 = "0000,111,3.674e+002,3.884e+002,3.322e+002"
                    break;
                case "D3":
                    MesureD3 = Result;  // MesureD3 = "0000,111,3.884e+002,0.2044,0.4862"
                    break;
                case "D4":
                    MesureD4 = Result;  //
                    break;
                default:                
                    break;
            }          
        }  
    }
}

In my main form, I have four buttons and a textbox.在我的主窗体中,我有四个按钮和一个文本框。 Button M1 is used to take a measurement (send "M1" command to the instrument).按钮M1用于进行测量(向仪器发送“M1”命令)。 Buttons D2, D3 and D4 are used to retrieve data from the instrument.按钮 D2、D3 和 D4 用于从仪器中检索数据。

In my old VB application, I used code like this, to successively retrieve data from the instrument:在我的旧 VB 应用程序中,我使用这样的代码来连续从仪器中检索数据:

myPort.WriteLine("M1")

myPort.WriteLine("D2")
Incoming = myPort.ReadLine()

myPort.WriteLine("D3")
Incoming = myPort.ReadLine()    

myPort.WriteLine("D4")
Incoming = myPort.ReadLine()

That was but I don't know how to accomplish the same thing using the 'separate' approach in c#?那是,但我不知道如何使用 c# 中的“单独”方法来完成同样的事情? I tried lumping the read operations in the same "event" sub as the M1 button, like this :我尝试将读取操作集中在与 M1 按钮相同的“事件”子中,如下所示:

private void btnM1_Click(object sender, EventArgs e)
{
    Operation = "M1";
    _serialPort.Write("M1\r\n");    // 0000,111,3.896e+002,0.3371,0.3563
    Thread.Sleep(500);

    Operation = "D2";
    _serialPort.Write("D2\r\n");
    Thread.Sleep(500);

    Operation = "D3";
    _serialPort.Write("D3\r\n");
    Thread.Sleep(500);

    Operation = "D4";
    _serialPort.Write("D4\r\n");
    Thread.Sleep(500);
}

But it does not work, I only get the "last" serial port "Read", the D4.但它不起作用,我只得到了“最后一个”串行端口“读取”,即 D4。 The code never goes through D2 and D3.代码永远不会通过 D2 和 D3。

How would you suggest I go about this?你建议我怎么做? I have not shown you D5 yet… The D5 operation is the most involved as I have to do "two reads", one for one piece of data and then 201 successive reads, to retrieve wavelength data, like this :我还没有向您展示 D5……D5 操作是最复杂的,因为我必须进行“两次读取”,一次读取一份数据,然后连续读取 201 次,以检索波长数据,如下所示:

myPort.WriteLine("D5")
Incoming = myPort.ReadLine() 

Temp = Split(Incoming, ",")
PeakWL = Convert.ToDouble(Temp(2))

For i = 1 To 201
   Incoming = myPort.ReadLine()  
   Temp = Split(Incoming, ",")
   nmValue(i) = CDbl(Temp(0))
   SpectralValue(i) = CDbl(Temp(1))
Next

I'm going to try to solve my problem myself but I would appreciate suggestions.我将尝试自己解决我的问题,但我会很感激建议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM