2016-05-09 9 views
2

Я очень новичок в общении с оборудованием. В настоящее время я создаю GUI в C#, используя Windows Forms. Я использую последовательный порт/usb для взаимодействия с аппаратным устройством. То, что я пытаюсь достичь, состоит в том, чтобы несколько потоков опросили устройство в разное время. Некоторые данные, такие как температура, ток, мощность и т. Д., Должны регулярно восстанавливаться (по крайней мере каждую секунду) и обновляться в графическом интерфейсе пользователя. В то время как другие данные будут извлекаться только тогда, когда пользователь нажимает кнопку в форме. Будет ли многопоточность правильной подходом к решению этой проблемы? Если нет, то что было бы лучшим решением? Примеры были бы весьма полезны. Спасибо за ваше время, ребята!Каков правильный способ опроса нескольких потоков на одном и том же последовательном порту?

Обновление: Я пытаюсь использовать событие SerialPort.DataReceived, как многие из вас предложили, и символ терминатора '\ r' для разбора отдельных ответов из последовательного порта. Затем я вызываю метод DisplayText для обработки этой строки. Моя проблема в том, что я не знаю, как понять, что представляет строка. Имеет ли она представляет собой температуру, ток и т.д.

private char terminator = '\r'; 
private void SerialPorts_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
     try 
     { 
      output += serialPort1.ReadExisting(); 
      if (output.IndexOf((char)this.terminator) > -1) 
      { 
       string workingString = output.Substring(0, output.IndexOf(terminator)); 

       output = output.Substring(output.IndexOf(terminator) + 1); 

       this.Invoke(new EventHandler((s, a)=>DisplayText(s, a, workingString))); 
      } 

     } 

     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 

    private void DisplayText(object sender, EventArgs e, string s) 
    { 
     Console.WriteLine(s); // for testing only 
     richTextBox1.AppendText(s); // for testing only 
    } 
+0

это могло бы помочь: https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived%28v=vs.110%29.aspx –

+0

Имеется ли у части оборудования несколько портов ввода/вывода? Это простой микроконтроллер, такой как Arduino? Если это так, вам не понадобится многопоточность – Sean

+0

@SPrashad да, это простой микроконтроллер с одним портом ввода-вывода. Так что было бы лучшим решением? Моя главная задача - попытаться опросить устройство в одно и то же время и тем самым заполнить буфер мусором. (создание условия гонки) –

ответ

0

Вы можете защитить все функции доступа к последовательному порту с помощью мьютекса и спроектировать свое приложение таким образом, чтобы последовательный порт закрывался после каждой дискретной операции (например, считывания температуры). Один из возможных способов сделать это было бы написать обертку API из-рода, которая:

  • Проверьте мьютекс разблокируется (и вернуться с кодом ошибки, если он заблокирован),

  • Откройте последовательный порт

  • Прочитайте требуемое значение

  • Закрыть последовательный порт и очистить семафор

  • Возврат считанное значение

Однако, вы открываете себя для всех видов тупиков с этим решением, и вам придется осуществлять дополнительные проверки на уровне приложения, чтобы предотвратить это.

Как было предложено выше, лучшим решением было бы, чтобы один поток периодически опроса последовательного порта и постоянно обновлял все значения в структуре данных по вашему выбору.

Для значений, которые нужно читать только после ввода пользователем, вам необходимо будет выполнить MessageQueue для запроса этих данных.


Обновление в ответ на ФОС редактировать

Я бы рекомендовал либо из следующих 2 способов приблизиться к коммуникации в устройстве:

  1. Реализовать механизм запроса/ответа где вы отправляете запрос на заданное значение (например, ток) через последовательный порт на ваше устройство, устройство анализирует этот запрос и возвращает соответствующее значение
  2. Имейте ваше устройство, чтобы вернуть все значения в "фрейме", например. [SOF] [D0 ... Dn] [EOF], где «D0 ... Dn» - это все ваши данные в предопределенной последовательности ; SOF и EOF могут быть любыми значениями вашего , выбирая (вы также можете пропустить их полностью и полагаться на количество байтов для ).

В случае, если вы не имеете возможность изменения кода в устройстве, должно быть какое-то порядок, в котором значения сообщается устройство таким образом поддерживая порядковый номер Полученные данные были бы правильными. Но, не зная подробностей о том, что делает ваше устройство, было бы сложно предложить решение.

+0

Спасибо за быстрый ответ! Как вы и предполагали, я попытался использовать SerialPort.DataReceived Event, чтобы без проблем получить все возвращаемые значения из последовательного порта. Но теперь я понятия не имею, как я могу различать все данные, которые возвращаются. –

+0

Я обновил свой оригинальный вопрос с помощью фрагмента кода. Взгляни, пожалуйста. Благодаря! –

+0

Вы не рассказали о том, как ваше устройство обменивается данными опроса, поэтому я собираюсь обновить свой ответ с помощью некоторых основных протоколов/методов связи, которые вы могли бы попробовать. – schaazzz

1

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

Лучше иметь один поток, который выполняет опрос и который хранит все значения в каком-либо «среднем» объекте (singleton, статические поля, что вам нравится) и синхронизирует доступ к этому хранилищу.

Таким образом, один поток опросает порт, собирает значения и сохраняет их где-то, чем другие потоки получают значения оттуда.

+0

Но если я использую таймер для 1-го опроса данных, которые необходимо регулярно обновлять, и пользователь нажимает кнопку, которая будет запускать другой опрос устройства в то же самое время, когда таймер проводит опрос устройства, не будет ли заполняемый входной буфер мусором? Может ли семафорный объект решить эту проблему? –

+0

У вас может быть очередь «запросов», к которой обращаются запросы каждую секунду от таймера и запросы от пользователя, чем один поток проходит через очередь до тех пор, пока он не будет пустым, и в этом случае он блокирует и ждет другого запроса, запрос может быть объектом со встроенным событием, которое может быть вызвано последовательным портом, как только выполняется запрос - таким образом запросы на последовательный порт сериализуются через очередь – pigster

0

Моя проблема сейчас, я не знаю, как понять, что представляет строка . Представляет собой температуру, ток и т. Д.

Используйте простой протокол для отправки температуры, тока и т. Д.

SOH + DATA + + ETX ВСС

SOH = 0x02;

ETX = 0x03;

BCC = 0x00-0xFF, значение XOR для всех DATA + ETX.

DATA = use ';' в качестве разделителя между температурой (Temp) и тока (Curr)

Пример:

TempCmd = 0x01

TempValue = 32 Цельси = 0x20

CurrCmd = 0x02

Результат CurrValue = 1,4 ampere = 0x0E -> должен делиться с 10 на приемнике.

SOH + DATA + + ETX ВСС

SOH + TempCmd: TempValue; CurrCmd: CurrValue + ETX + БЦК

02 + 01: 20; 02: 0E + 03 + БЦК

ВСС = 01 XOR ':' XOR 20 XOR ';' исключающий 02 исключающее ':' исключающего 0E исключающего 03

  • Отправить данные из микроконтроллера "0201: 20; 02: 0E03; XX" (отправить в виде строки)

  • Прием данных в компьютере:

    1. Обнаружение SOH и ETX в пакете
    2. Проверка ВСС верно (завершено пакет) или ложная (пунктирная упаковка)
    3. Синтаксических ДАННЫХ с; в качестве разделителя // data1 = 1:20 data2 = 02: 0E03
    4. Синтаксический data1 и data2 с: в качестве разделителя // data1 = 20 data2 = 0E03
    5. Преобразование шестнадцатеричной в десятичную и разбивают data2 с 10 для получения тока с поплавком формат.