Форум программистов, компьютерный форум, киберфорум
Visual Basic .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/13: Рейтинг темы: голосов - 13, средняя оценка - 4.92
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
.NET 4.x

Компонент SerialPort завешивает форму

24.08.2016, 00:24. Показов 2867. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброй ночи!
Есть компонент SerialPort. На него пересылаю данные из внешнего устройства. Если в момент пересылки данных устройством попытаться закрыть порт - форма фризится намертво и с концами. Причем в Try - Catch ничего не приходит... Собственно в такой отлов ошибок у меня заключены все операции с компонентом порта да бы избежать "исключений".
Каким образом закрыть порт так, чтобы в любом случае оно все закрыло и нигде не зависло?
Спасибо.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
24.08.2016, 00:24
Ответы с готовыми решениями:

Цикл завешивает форму
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For Me.X = 1 To 100 Step 1 TextBox1.Text = (0 + X) ...

Скачивание через WebClient завешивает форму
Всем привет! Возникла проблемка: при запуске формы, в эвенте Form_Load Я скачиваю строку из файла ...

Компонент Serialport в VS C++ 2008
Доброго времени суток! Помогите разобраться с компонентом Serialport, в частности как использовать эти события: Void...

17
 Аватар для Splinter_Cell
244 / 134 / 15
Регистрация: 26.12.2012
Сообщений: 267
24.08.2016, 13:57
В данной ситуации при зависании в системе возникает ошибка которая пишется в протокол Windows (независимо от TryCatch программы). Хотелось бы узнать что там написанно?
0
79 / 72 / 4
Регистрация: 05.01.2016
Сообщений: 288
24.08.2016, 14:29
Вот:
https://msdn.microsoft.com/ru-... .110).aspx

Может помажет.
0
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
07.10.2016, 00:44  [ТС]
Splinter_Cell, что это за протокол такой и где это все можно посмотреть?

Добавлено через 3 минуты
17Vasya17, был на этой странице триста раз... Там написано о методе .Close(). Им то я как раз и закрываю порт.
Пишут что перед использованием .Open лучше подождать пока порт закроется... Но меня то это не касается... Пишут про исключения, но, как я и написал выше, туда ничего не приходит...
Больше там ничего не написано.
0
 Аватар для Splinter_Cell
244 / 134 / 15
Регистрация: 26.12.2012
Сообщений: 267
07.10.2016, 00:53
Подробнее здесь: http://www.oszone.net/10680
0
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
07.10.2016, 05:43
Stass48, Не закрывать порт, пока буфер передачи не будет пуст.
0
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
09.10.2016, 02:44  [ТС]
Splinter_Cell, Может я чего-то не досмотрел, конечно, но все же в журнале пусто. Нет никаких событий на время зависания формы...
jkrnd, а подробнее?
Я вот судя по Вашему совету сделал так (по теме строки 2 и 3):
VB.NET
1
2
3
4
5
6
7
8
9
10
            Try
                Me.SerialPort.DiscardInBuffer()
                Me.SerialPort.DiscardOutBuffer()
                Me.SerialPort.Close()
            Catch ex As Exception
                If Me.btnClosePort.Enabled <> True Then Me.btnClosePort.Enabled = True
                If Me.btnOpenPort.Enabled <> False Then Me.btnOpenPort.Enabled = False
                If Me.btnSettings.Enabled <> False Then Me.btnSettings.Enabled = False
                WriteToLog(ex.Message)
            End Try
Но все равно если дрючить его кнопками "Открыть" и "Закрыть", то где-то на десятый раз повисло
Если это не то, что Вы имели ввиду, то напишите пожалуйста подробнее, если можно с кодом...

Вообще странно, что в Майкрософт хреново сделали эту процедуру закрытия порта. Погуглив по Интернету – проблема далеко не единичная. Но решения я так и не нашел...

Добавлено через 5 минут
Добавлю заранее, да бы исключить дальнейшее недопонимания:
Кнопки открытия и закрытия порта у меня реализованы с защитой от повторных вхождений. То есть, нельзя нажать на закрытие порта пока сам порт не будет открыт и наоборот. Так же, нельзя открыть еще раз порт пока он открывается и точно так же с закрытием.

Какие еще у кого будут мысли?
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
09.10.2016, 02:51
Stass48, На работу с Com-портом с помощью элемента управления угробил кучу времени и отказался от его использования. Его поведение в некоторых случаях непонятно, проще и надёжнее использовать класс SerialPort.
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    Sub CloseComPort()
        Using mySerialPort
            If (Not (mySerialPort Is Nothing)) Then
                'COM-порт существует.
                If mySerialPort.IsOpen Then 'Com-порт открыт
                    'Ждать, пока буфер передачи не будет пуст.
                    Do While (mySerialPort.BytesToWrite > 0)
                    Loop
                    'приводим в соответствие с этим событием кнопки открытия-закрытия порта
                    btnClosePort.Enabled = False
                    btnOpenPort.Enabled = True
                Else
                    'Порт не открыт
                End If
            End If
        End Using
    End Sub
Добавлено через 1 минуту
это нарыто в сети (не моё творчество). У меня проблем подобных Вашей не было.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
09.10.2016, 04:07
источник информации
Вложения
Тип файла: pdf Access-Serial-Ports.pdf (7.00 Мб, 27 просмотров)
1
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
17.10.2016, 13:57  [ТС]
jkrnd, проверил все намного раньше, но написать могу только сейчас. В общем, дела такие.
Класс работает еще хуже, чем порт, видимо, компонент продуман получше класса (что и логично, так как используя класс, тебе дают больше возможности писать код самому). В моем случае проблема лежит скорее всего гораздо глубже. В своем устройстве, которое "общается" с компьютером, в качестве интерфейса-пеобразователя TTL/UART->USB я использую микросхему от Prolific. Точнее, китайский переходник на базе этой микросхемы. Сама же микросхема – китайская подделка и не работает с последними версиями официальных драйверов (так как в них уже ввели проверку подлинности чипа и этот чип ее, естественно, не проходит). Работает оно только когда ставишь драйвера постарее (где данной проверки еще нет). Но это драйвера еще времен Windows 7, как Вы понимаете с тех времен уже давно могли устранить все баги. К слову, даже когда я тупо выдергиваю USB, в диспетчере устройств ничего не пропадает, ком-порт так там и остается. Всунул еще раз и высунул – оп, пропал. Когда порт остается в системе при вытянутом устройстве, программа спокойно может его открывать и, по-моему, даже закрывать... Короче полный бред.
Я вижу только два пути решения этой проблемы:
1) Очевидный. Идти в магазин и заказывать оригинальные чипы вплоть до FTDI, цены на которые, увы, не радуют и паять на базе них нормальный преобразователь.
2) А что если этот порт не закрывать вообще? Суть моей программы заключается просто в управлении компьютером с моего внешнего устройства и ведении логов всех действий. То есть эта программа будет помещена в автозагрузку и стартовать при запуске системы. Закрывать ее никто и никогда не будет (по идее). Закрываться она будет только при завершении работы винды. Но разве винда такая тупая что не закроет все порты сама перед выключением?)

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

Добавлено через 54 минуты
Цитата Сообщение от Splinter_Cell Посмотреть сообщение
В данной ситуации при зависании в системе возникает ошибка которая пишется в протокол Windows
В данном случае ничего не пишется, потому что не зависает. В диспетчере задач приложение числится как отвечающее и никакие клики по зафриженной форме не могут заставить винду предложить мне вырубить приложение.
1
Эксперт .NET
 Аватар для Rius
13131 / 7691 / 1677
Регистрация: 25.05.2015
Сообщений: 23,468
Записей в блоге: 14
17.10.2016, 16:05
Цитата Сообщение от Stass48 Посмотреть сообщение
А что если этот порт не закрывать вообще?
Проблема есть и она всплывёт, когда это меньше всего будет нужно.

Помимо Prolific, у FTDI большой выбор чипов. И есть ещё Silicon Labs CP210x.

Можно взять чип от ST со встроенным USB, тогда никакой USB-UART мост вообще не понадобится.
2
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
18.10.2016, 20:38  [ТС]
Да уже понял что FTDI это самый "жирный" вариант хотя и недешевый. Но что поделать?
Да, у них большой выбор чипов и как я понял цена в основном зависит от скорости. Мне же нужно просто принять на комп несколько команд Uart (с ADC и прерывания по кнопке контроллера Atmega8A), то есть скорость тут как я думаю, мне не сильно важна. Поглядываю в строну FT232RL, но может быть есть что подешевле из этой линейки, которое мне подойдет?
Если нет, возьму преобразователь на этой микре, благо на Космодроме пишут что у них преобразователи на оригинальных чипах...
По поводу ST, я никогда не делал ничего на других чипах, кроме AVR, под них есть Bascom AVR на котором можно состряпать прошивочку. Уж сильно люблю VB
Хотя данный язык имеет ряд недостатков (попробовать только дизассемблировать этот код, много лишнего ).
1
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
25.10.2016, 11:52  [ТС]
Итак, проблема решена!
Купил у себя рядышком в городе FDTI FT232RL, спаял на коленке преобразователь. Работает и ничего нигде не виснет! Хоть двадцать раз тыкай и во время пересылки данных! Судя по слухам в Интернете, с FTDI тоже есть проблемы в плане подделок. Но, судя по тому что у меня она завелась с официальными драйверами с сайта (драйвера если видят подделку – выводят ее со строя), то я купил именно оригиналки!
Вывод: Китайцы – пи*орасы!
1
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
23.01.2018, 02:18  [ТС]
UPDATE !!!

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

Дело в БАГЕ класса SerialPort! Баг этот известен уже очень давно, с годов так 2007-х. Microsoft признала баг, но устранять его почему-то не захотела. Видимо, потому, что его можно обойти!

Мне удалось найти два пути решения проблемы. Но о них позже. Сначала, давайте разберемся, почему форма зависает.

VB.NET
1
SerialPort.Close()
При выполнении ожидает завершения операций чтения из порта.
То есть, он ждет окончания операции ReadLine()

Самое первое, что приходит в голову человеку при использовании класса или компонента (не важно) SerialPort, так это просто взять событие DataReceived и поместить в него инвок с выводом куда-то, например так:

VB.NET
1
2
3
Sub dtRes() Handles myPort.DataReceived
   Invoke(Sub() TextBox1.Text = myPort.ReadLine())
End Sub
Инвок ждет пока запишутся данные в текстбокс (то есть, myPort.ReadLine() не закончит свое выполнение до тех пор, пока текст не запишется в TextBox).

Если мы в это время вызовем myPort.Close(), то мы завесим поток формы, а так как ReadLine() тоже будет ждать пока данные не запишутся в текстбокс, то вот он – ДЕДЛОК!

Теперь о решениях.
1) Можно использовать вместо метода Invoke, метод BeginInvoke. В этом случае ReadLine() не будет дожидаться реакции от основного потока и спокойно сможет завершиться даже если основной поток формы будет приостановлен. Следовательно, зависания не произойдет.
Однако, любые попытки работы ReadLine() асинхронно, работают как-то нестабильно. Где-то раз на 100 или даже 1000 чтений, читает либо две строки в одной, либо только часть строки, в общем, как я понял, лучше все таки синхронно (пробовал Producer-Consumer в реализации через BlockingCollection). Поэтому, метод 2.

2) Вызвать метод MyPort.Close() не из основного потока формы, а из постороннего. В таком случае метод Close() не будет блокировать поток формы и дедлока не произойдет.

Вопрос лишь в том, как написать некоторую надстройку типа:

VB.NET
1
2
3
4
5
6
7
8
9
10
11
Public Function ClosePortFixed(ByRef ErrDescr As String) As Boolean
   Try
      MyPort.Close()
   Catch ex As Exception
      Err = ex.Message
      Return False
   End Try
 
   Err = String.empty
   Return True
End Function
Которую можно было бы выполнить синхронно как в коде, так и по закрытию формы.

Уже неделю бьюсь, не могу осилить! Всё либо костыли, либо криво. В общем, мне не понравилось.
Может кто другой осилит?
0
Эксперт .NET
 Аватар для Rius
13131 / 7691 / 1677
Регистрация: 25.05.2015
Сообщений: 23,468
Записей в блоге: 14
23.01.2018, 08:12
Stass48, просто не используйте ни ReadLine, ни DataReceived.
Чтение с последовательного порта без использования Sleep
1
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
24.01.2018, 13:18  [ТС]
Лучший ответ Сообщение было отмечено OwenGlendower как решение

Решение

Rius, может быть в каких-то серьезных задачах Ваше решение и имеет право на существование, но, конкретно в моем случае, считаю, что это уж слишком заморочно и неоправданно сложно. Единственное, в чем я сомневаюсь (хотя наверное я ошибаюсь), так как событие DataReceived срабатывает по нескольку раз за строку, а ReadLine() стопорит выполнение до момента получение символа NewLine, то у нас может начать копиться очередь из событий DataReceived. Одновременно этой моей паранойе успокаивает мысль, что в момент, когда строка все таки получена, а новая передаваться еще не начала, то программа бегом успевает прогнать всю очередь. Так что скорее всего, она не должна накапливаться постоянно.
В крайнем случае, у ReadLine() есть возможность таймаута. Это чтобы уж совсем наверняка.

Вместо Ваших методов, предлагаю свой вариант решения. Прикрепляю проект (кому надо, тот по аналогии сможет использовать этот код или написать класс). Дрюкал порт как мог кнопками открыть-закрыть одновременно передавая данные с FT232RL и в результате смог обнаружить только два вида порчи данных:
1) Когда приходит только концовка. Что не удивительно, ведь внешнее устройство уже начало передачу данных, а мы только открыли порт и начали принимать данные. Понятное дело, что мы сможем принять только то, что успеем. Пример:
Передавали "Sample", получили "mple" или подобное.

2) Очень и очень редко, но получалось так, что соединяло часть первой строки с полностью второй строкой. Пример:
"SampSample". Это я объяснить не смог. Но вроде бы после того как я ввел принудительную очистку буфера при открытии порта, этот глюк прекратился.

Напомню, что все, что написано выше, происходит только при открытии и закрытии порта и одновременно этому – передачи данных. Поэтому:
1) Глюки вполне оправданы
2) Последствия глюков легко можно обрабатывать в функции, которая будет парсить принятые данные (такая функция будет присутствовать в 99% проектов, разве что кто-то будет писать свое приложение-терминал).

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

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

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

P. S.: Прошу модераторов отметить этот пост как "лучший ответ", так как он является одним из вариантов решения данной проблемы.
Вложения
Тип файла: zip SerialPort_Probe.zip (62.9 Кб, 27 просмотров)
1
Эксперт .NET
 Аватар для Rius
13131 / 7691 / 1677
Регистрация: 25.05.2015
Сообщений: 23,468
Записей в блоге: 14
24.01.2018, 13:32
Цитата Сообщение от Stass48 Посмотреть сообщение
1) Глюки вполне оправданы
2) Последствия глюков легко можно
Короче, здесь костыли, так как другие проблемы в корне и не решены. А может и не встречены пока.
Через ваш вариант я проходил годы назад, в ходе отладки разнообразных способов.
Но, как говорится, моё дело предложить, ваше - отказаться.
1
22 / 22 / 7
Регистрация: 26.05.2011
Сообщений: 256
24.01.2018, 14:33  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Короче, здесь костыли, так как исходная проблема в корне и не решена.
Через ваш вариант я проходил годы назад, в ходе отладки разнообразных способов.
Но, как говорится, моё дело предложить, ваше - отказаться.
Говорю сразу, ссориться и спорить не буду!

Но... Читайте внимательно.
Первое – вообще не глюк! Как можно претендовать на данные, которые были переданы раньше, чем был открыт порт?
Второе – сейчас существует скорее только у меня в голове, так как я сколько не пробовал, то не смог воспроизвести данный глюк повторно (после корректировки кода).

Костыли будут в любом случае, так как исходную проблему "в корне", как Вы говорите, смогут решить только авторы класса. Наша задача – обойти проблему. Но сделать это нужно грамотно и как можно менее костыльно (полностью некостыльно и в то же время просто – не получится). У Вас ведь тоже те же костыли, согласитесь и это нормально, потому что выбора нам с Вами разработчики не оставили и нашего мнения не спросили

Не забывайте, что речь идет о методе, который позволяет корректно принять ТОЛЬКО ЦЕЛУЮ СТРОКУ, а не каждый символ или бит по отдельности (как например, когда мы вводим данные с клавиатуры в терминале вручную или передаем файл по ком-порту)! Может быть, Ваши методы имеют возможность работать идеально во всех условиях, но какой смысл усложнять код ради получение возможности, которая никогда не будет использоваться (по крайней мере у меня)?
Данные передаются и принимаются исправно, проверено! Все работает очень стабильно...

По сути, мое решение заключается лишь в том, что буферизирует уже принятые строки с целью избежания дедлока по закрытию порта. И тема у меня имеет соответствующее название. Так что пусть будет)
Я считаю, что для обмена строками Компьютер – Микроконтроллер, этого многим хватит за глаза. А проверку на ошибки приема данных придется делать по-любому, причем с обеих сторон. Мало ли, напряжение в сети скаконуло и полетел какой-то мусор...

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

Подведем итоги:
В данной теме была представлена проблема случайного зависания приложения при выполнении метода SerialPort.Close(). Проблема была детально изучена, приведены причины и объяснения почему она возникает. Так же, приведены варианты решения данной проблемы, а так же, конкретные примеры готовой реализации. Каждое решение по-своему хорошо и не претендует на истинность, предоставляется "как есть".
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
24.01.2018, 14:33
Помогаю со студенческими работами здесь

Приём данных через компонент serialport
Доброго времени суток, подскажите. каким образом осуществляется чтение данных с ком порта посредством данного компонента? У serialport есть...

Можно ли взять с toolbox компонент serialport и внутри него написать значение com порта
Добрый день, форумчане! Мои друзья-программисты посоветовали Ваш форум, сказали что тут довольно дружный норад. Мне сразу это понравилось и...

Serialport.write и serialport.basestream.write - в чем разница
в чем разница между следующими способами отправки данных на ком-порт?: serPort.BaseStream.Write(data,0,datalen); ...

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

Программно добавить на форму компонент
Здравствуйте! Подскажите, пожалуйста, как программно добавить компоненту на форму при выборе определенного значения из КомбоБоск в этой...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru