RS-232 errati c поведение - PullRequest
       14

RS-232 errati c поведение

0 голосов
/ 24 февраля 2020

Windows 10-64. Прошлой осенью я запрограммировал небольшое приложение VB для управления последовательным устройством «PR-705» через порт RS-232. Это сработало без нареканий. Теперь, когда я запускаю этот код, PR-705 не так хорошо реагирует? Первоначально я использовал адаптер USB-RS232 на базе FTDI (Thunderlinx 1000), который работал отлично. Я понял, проблема может быть связана с «драйвером»? Поэтому я добавил карту последовательного порта PCI- Express от StarTech к своему P C. Результат: без улучшений - такое же ошибочное c поведение? Из любопытства этим утром я запустил свой верный Windows HyperTerminal, и он работал безупречно (из порта PCI-e)! Так что я знаю, что проблема не в самом устройстве (вздох!), А где-то в цепочке коммуникаций.

Проблема, с которой я сталкиваюсь, заключается в следующем (надеюсь, вы сможете обнаружить «шаблон»):

a) Открыть последовательный порт b) Отправить команду на порт в виде строки ASCII (например, «M1») <- Устройство отвечает отправкой данных обратно, однако для получения ВСЕХ данных от устройства, Я должен отправить дополнительные команды: c) "D2" d) "D3" e) "D4" f) "D5" </p>

Когда я запускаю эти команды из HyperTerminal, я получаю звездное поведение.

Однако в моем приложении дополнительные команды ("D2", "D3", "D4" и "D5") не проходят через устройство, как-нибудь? Например, когда я отправляю «D2», я получаю данные «XYZ», и это нормально. Но когда я продолжаю "D3", я все еще получаю те же данные "XYZ" обратно? Как будто новая команда («D3») никогда не достигла устройства?

Мой (некрасивый) обходной путь - повторно отправить ту же команду, и ТОГДА я получаю новые данные (большую часть времени).

Вот мой код:

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()

Я знаю, что значение TimeOut является «экстремальным», но на ответ устройства может потребоваться до 15 минут, в зависимости от обстоятельств. Я не могу закрыть порт, пока устройство не ответит, иначе я получу сообщение об ошибке, что-то связанное с CTS, и затем устройство автоматически перезагрузится - не идеально. Я не специалист по RS-232, но я делаю все возможное, обладая небольшими знаниями.

1 Ответ

0 голосов
/ 25 февраля 2020

Нашел частичный ответ на мою проблему с последовательным портом, но это решение не без собственных проблем. Я нашел некоторый код c#, который я адаптировал, когда последовательный порт «Получен» разделен на свое собственное «событие». Это работает очень хорошо. Как вы увидите в коде ниже, он делает свою работу. Но теперь я сталкиваюсь с вопросом о том, как go о "последовательном" опросе порта, чтобы получить все данные, возвращаемые прибором?

Вот сначала код 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;
            }          
        }  
    }
}

В моей основной форме у меня есть четыре кнопки и текстовое поле. Кнопка M1 используется для измерения (отправить команду «M1» на прибор). Кнопки D2, D3 и D4 используются для извлечения данных из инструмента.

В моем старом приложении VB я использовал такой код для последовательного извлечения данных из инструмента:

myPort.WriteLine("M1")

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

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

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

Это было, но я не знаю, как сделать sh то же самое, используя «отдельный» подход в c#? Я попытался объединить операции чтения в той же подпрограмме «событие», что и кнопка 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);
}

Но это не работает, я получаю только «последний» последовательный порт «Чтение», D4. Код никогда не проходит через D2 и D3.

Как бы вы посоветовали мне go по этому поводу? Я еще не показал вам 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

Я собираюсь попытаться решить свою проблему самостоятельно, но я был бы признателен за предложения.

...