Member 13627097 Ответов: 4

Отправка нескольких команд на последовательный порт и ожидание ответа перед отправкой другой команды


Всем Привет,

обратитесь за помощью к данным последовательного порта datarecevied.

У меня в файле хранится несколько команд.
Мне нужно отправить команду одну за другой в последовательный порт и дождаться ответа и отображения для продолжения отправки другой команды.

Я использую thread.sleep между каждой командой send, но это не работает.

пожалуйста помочь.

Спасибо

Что я уже пробовал:

I'm using thread.sleep between each command send but it does not work. 

4 Ответов

Рейтинг:
2

OriginalGriff

Хватит играть с нитками.Сон: это, вероятно, не поможет вам.
Я бы сделал это так: создал очередь команд и использовал событие DataReceived для получения ответа. Когда ответ будет завершен, возьмите следующую команду из очереди и отправьте ее, и пусть событие DataReceived обработает ее ответ, когда он прибудет.
Когда очередь пуста, набор команд завершен.


Member 13627097

Я прочитаю список команд из файла и отправлю каждую команду с помощью цикла foreach.
Я заметил, что каким-то образом перед получением / отображением данных отправляется следующая команда. И я считаю, что это вызвало проблему, увидев несколько команд, отправленных и получивших ответ одновременно.
Могу я узнать, как работает очередь?
Есть примеры кода?

Рейтинг:
2

Jochen Arndt

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

В вашем случае вам понадобится по крайней мере один поток для получения ответов и передачи команд в очереди.

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

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

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

Вы можете поместить отправку и получение в один или два потока.

Псевдокод для приема (предполагая текстовые данные):

// Check for kill (terminate thread) event (wait with no timeout)
while (!KillEvent)
{
    do 
    {
        // Blocking call until a character is available
        // Should have a timeout and corresponding handling (break here)
        rxChar = ReceiveChar();
        Buffer += rxChar;
    }
    while (rxChar != '\n');
    // Signal other threads that a response has been received
    // Pass a copy of Buffer to the main thread for display
}

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

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


Рейтинг:
1

Pawel Wzietek

Мой SerialDevice класс здесь:
Многопоточная связь для GPIB/Visa/последовательных интерфейсов[^]
реализует именно тот процесс, который описан в решении 2 выше: с асинхронными командами ввод-вывод выполняется в отдельном потоке, который использует простые блокирующие вызовы для записи/чтения.

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


Рейтинг:
1

Member 13627097

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

Но не уверен, что это правильный способ сделать.
Пример:
Писать();
Прочитай();


Pawel Wzietek

Конечно, это будет работать, единственная проблема заключается в том, что "Read()" будет блокировать поток до тех пор, пока не будет получен ответ (пользовательский интерфейс не будет отвечать), поэтому мы используем события. Но даже без использования обработчика DataReceived вы можете сделать приложение более отзывчивым, если установите короткий тайм-аут и повторите чтение до тех пор, пока не получите данные, что-то вроде:

последовательный порт.ReadTimeout=1;
строковый ответ = null;
делать
Приложение.DoEvents(); //держите пользовательский интерфейс отзывчивым
пробовать
{ответ = последовательный порт.С readline();}
поймать (исключение timeoutexception ){}
а (ответ == значение null &&усилителя; !аборт); //может добавить "отбой" переменной