2013-07-16 3 views
1

У меня есть большие проблемы с последовательными запросами.Последовательная связь получает неправильный ответ, когда что-то работает в фоновом режиме (например, просмотр жесткого диска)

Описание от того, что я хочу:

  • установить последовательное соединение, отправить последовательные запросы до 6 температуры датчики один за другим (это делается каждый 0,5 секунды в цикле)

  • вопрос и ответ-адресат хранятся в массиве List

  • каждый запрос запускается в отдельном потоке, поэтому gui не вызывает ошибку , пока программа ждет для датчика-метиз ответить

Моей проблема:

Подключения и запрос работают нормально, но если я просматриваю данные на локальном жесткий диске ответ от датчика-блока разрушаются (отрицательный алгебраический знак или значение от другого датчика или просто неправильное значение). Как это происходит или как я могу это решить?

Где я думаю, что проблема может быть:

  • В частном ничтожной ReceiveThread() класса SerialCommunication

Вот мой код:


Класс CommunicationArray:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Hardwarecommunication 
{ 
    public class CommunicationArray 
    { 
     public string request { get; set; } 
     public object myObject { get; set; } 
     public string objectType { get; set; } 
    } 
} 

SerialCommunication Класс

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Threading; 
using System.IO; 
using System.IO.Ports; 
using System.Windows.Forms; 

namespace Hardwarecommunication 
{ 
    class SerialCommunication 
    { 
     Thread t2; 
     Thread t; 
     private SerialPort serialPort = new SerialPort("COM2", 115200, Parity.Even, 8, StopBits.One); 
     string serialAnswer = ""; 
     private volatile bool _shouldStop; 
     private int counter; 

     List<CommunicationArray> ar = new List<CommunicationArray>(); 

     object[] o = new object[3]; 


     public void addListener(string request, object myObject, string objectType) 
     { 
      CommunicationArray sa = new CommunicationArray(); 

      sa.request = request; 
      sa.myObject = myObject; 
      sa.objectType = objectType; 
      ar.Add(sa); 
     } 

     public void startListen() 
     { 
      t2 = new Thread(() => writeSerialPortThread()); 
      t2.Start(); 
     } 



     public void startSerialPort2() 
     { 

      try 
      { 
       serialPort.Open(); 
       //MessageBox.Show("Connection opend!"); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error); 
       return; 
      } 
     } 

     public void stopSerialPort2() 
     { 
      try 
      { 
       if (serialPort.IsOpen == true) 
        // Connection closed 
        serialPort.Close(); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 
     } 


     private void writeSerialPortThread() 
     { 
      string request = ""; 

      for (int i = 0; i < ar.Count(); i++) 
      { 
       request = ar[i].request; 
       //request = ((object[])ar[0])[0].ToString(); 
       //if (!t.IsAlive) 
       //{ 
       try 
       { 
        t = new Thread(ReceiveThread); 
        _shouldStop = false; 
        //MessageBox.Show("start thread"); 
        t.Start(); 
        serialPort.Write(request); 
        Thread.Sleep(50); 
        _shouldStop = true; 
        t.Join(); 
       } 
       catch 
       { 
       } 
       Label tmpLabelObject = (Label)ar[i].myObject; 
       serialAnswer = serialAnswer.Replace("=", ""); 
       if (tmpLabelObject.InvokeRequired) 
       { 
        MethodInvoker UpdateLabel = delegate 
        { 
         tmpLabelObject.Text = serialAnswer; 
        }; 
        try 
        { 
         tmpLabelObject.Invoke(UpdateLabel); 
        } 
        catch 
        { 
        } 
       } 
      } 
     } 

     private void ReceiveThread() 
     { 
      //MessageBox.Show("in thread"); 
      while (!_shouldStop) 
      { 
       serialAnswer = ""; 
       try   
       { 
        //MessageBox.Show("in thread"); 
        serialAnswer = serialPort.ReadTo("\r"); 
        if (serialAnswer != "") 
        { 
        } 
        return; 
       } 
       catch (TimeoutException) { } 
      } 
     } 
    } 
} 

класса Form1 // установить соединение и начать просить ДАТЧИК

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace Hardwarecommunication 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     private SerialCommunication serialCommunication1 = new SerialCommunication(); 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      //start up serial connection 
      serialCommunication1.startSerialPort2(); 
     } 

     private void buttonStart_Click(object sender, EventArgs e) 
     { 
      timerRecord.Enabled = true; 
      if (this.buttonStart.Text == "Start") 
       this.buttonStart.Text = "Stop"; 
      else 
       this.buttonStart.Text = "Start";    
     } 

     private void timerRecord_Tick(object sender, EventArgs e) 
     { 
      if (this.buttonStart.Text == "Stop") 
      { 
       this.serialCommunication1.startListen(); 
      } 
     } 

     private void buttonFillRequestArray_Click(object sender, EventArgs e) 
     {   
      this.serialCommunication1.addListener("$0BR00\r" + "\r", this.labelResult0, "label0"); //request to the hardware 
      this.serialCommunication1.addListener("$0BR01\r" + "\r", this.labelResult1, "label1"); 
      this.serialCommunication1.addListener("$01R00\r" + "\r", this.labelResult2, "label2"); 
      this.serialCommunication1.addListener("$01R01\r" + "\r", this.labelResult3, "label3"); 
      this.serialCommunication1.addListener("$01R02\r" + "\r", this.labelResult4, "label4");   
     } 
    } 
} 

Я woud быть рад любой попытаться исправить проблема. Я также могу загрузить решение в формате .zip, но вы не можете его полностью протестировать, потому что у вас нет аппаратного обеспечения датчика.

+2

Ваша программа, вероятно, очень чувствительны к времени. Это то, что вы получаете, когда начинаете добавлять Thread.Sleep() в свой код, чтобы заставить его работать. Нет никакой гарантии, что метод ReceiveThread() даже вызовет serialPort.ReadTo(), он немедленно выйдет, когда он запустится с опозданием. Тайм-аут глотания Исключение без какой-либо диагностики также крайне неразумно. Начните с удаления этого потока, он не служит никакой полезной цели, кроме как сбой вашего кода. –

+2

Вам нужно использовать детерминированный подход к потоковому использованию. У вас нет шансов на успех в вашем текущем подходе. Сроки не могут использоваться для управления программой. – usr

+0

Привет, мне приятно посмотреть, как это выглядит как маленький пример. Thx – kimliv

ответ

1

Примечание: serialPort.Write(string) является неблокирующим хранилищем в выходной буфер.

Это означает следующее не будет гарантировать, вы даже закончили писать свой запрос, прежде чем остановить прослушивание ответа:

serialPort.Write(request); 
Thread.Sleep(50); 
_shouldStop = true; 

Вы можете добавить:

while(serialPort.BytesToWrite > 0) Thread.Sleep(1); // force blocking 

но это нецелесообразно ,

Единственное, что мне интересно. Здесь есть только один последовательный порт. Почему вы хотите, чтобы с ним работал много разных потоков, когда вы могли управлять всем взаимодействием последовательного порта с одним потоком? (Или, что хуже, 1 нить для входной 1 резьбы для вывода)

Для меня гораздо больше смысла хранить запросы в какой-то очереди, а затем очищать их по одному за один раз для обработки в одном нить. Ответы могут быть аналогично поставлены в очередь или запущены как события обратно вызывающему абоненту.

EDIT: Если вы не возражаете один цикл чтения/записи в то время, вы можете попробовать:

string response; 
lock(serialPort) { 
    // serialPort.DiscardInBuffer(); // only if garbage in buffer. 
    serialPort.Write(request); 
    response = serialPort.ReadTo("\r"); // this call will block till \r is read. 
             // be sure \r ends response (only 1) 
} 
+0

привет, THX для ответа, я дам ему попробовать завтра. Я думаю, что проблема заключается не в отправке запроса, а в получении ответа. – kimliv

+0

thx до сих пор, но если в запросе есть ошибка или ошибка в передаче, то не будет ответа от устройства. Поэтому мне нужно запустить новый запрос через некоторое время и просто игнорировать первый запрос. Процесс будет следующим: запрос на запись; читать до ("\ r"); но если в течение следующих 100 мс нет («\ r»), запустите следующий запрос. – kimliv

+0

@kimliv Попытка: 'serialPort.ReadTimeout = 100;' примерно в то время, когда вы открываете последовательный порт. (вы наверняка поймаете исключение в какой-то момент, там вы можете опционально '.DiscardInBuffer()', но только если вы останетесь в 'lock()' будет ли это безопасная операция.) –

 Смежные вопросы

  • Нет связанных вопросов^_^