Форум программистов, компьютерный форум, киберфорум
Visual Basic .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
7 / 6 / 3
Регистрация: 03.12.2020
Сообщений: 301

Почему пропадают/искажаются сообщения SerialPort?

06.03.2025, 17:09. Показов 758. Ответов 11

Author24 — интернет-сервис помощи студентам
Программа должна обмениваться данными с несколькими платами Arduino(сейчас подключаю 3 шт., планируется больше, но проблемы появляются и ни одной шт., и на двух…).
В тестовом режиме режиме я отправляю “99/0/0/0” – плата считывает это сообщение и отправляет обратно. В мониторе порта программы Arduino все работает четко и стабильно, без каких-либо сбоев (во всяком случае, мне не удалось такое обнаружить).
Но вот когда подключаю написанную программу – начинаются проблемы:
часто вместо отправленного сообщения программа получает не отображаемые символы, в кодировке Asc номера: 13, 10. Иногда программа вообще не получает никакого ответа.
В программе использованы библиотеки:
VB.NET Скопировано
1
2
3
4
5
6
Imports System.IO.Ports
Imports System.Threading
Imports System.Runtime.InteropServices
Imports System.Windows.Forms.Design
Imports System.IO
Imports System.Text
Программа формирует коллекцию COM-портов:
VB.NET Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
Public oNameCol As New Dictionary(Of [String], [String])() ' массив СОМ-портов с номерами ответов плат
Public oNunbCol As New Dictionary(Of [String], [String])() ' массив номеров плат с СОМ-портами
Public oNPlat As Integer = 0 '  счетчик количества подключенных плат 
Public oComPort As New List(Of SerialPort) ' коллекция СОМ-портов
Public oComSpeed As Integer = 250000 ' скорость сомпорта
Public oReadCom As String ' переменная для чтения ответа из COM-порта
Dim WithEvents mySerialPort As SerialPort
 
    Private Sub ButtR_Click(sender As System.Object, e As System.EventArgs) Handles ButtR.Click
        ReadNameCom()
     End Sub
 
    Private Sub ReadNameCom()
        Dim oPorts As String() = SerialPort.GetPortNames()
        oNPlat = 0
        oNameCol.Clear()
        oNunbCol.Clear()
        If oComPort.Count > 0 Then
            Try
                For i = 0 To oComPort.Count - 1
                    oComPort(i).Close()
                Next
            Catch ex As Exception
            End Try
        End If
        oComPort.Clear()
        For Each oName In oPorts
            If oName <> "COM1" Then
                Try
                    Try
                        Try
                            mySerialPort.Close()
                        Catch ex3 As Exception
                        End Try
                        mySerialPort = New SerialPort(oName)
                        With mySerialPort
                            .BaudRate = oComSpeed '57600 '9600
                            .Parity = Parity.None
                            .StopBits = StopBits.One
                            .DataBits = 8
                            .Handshake = Handshake.None
                            .RtsEnable = True
                            .Open()
                        End With
                    Catch ex As Exception
                    End Try
                    oReadCom = ""
                    mySerialPort.WriteLine("97/0/0/0")
                    Thread.Sleep(90)
                    oReadCom = mySerialPort.ReadExisting()
                    If oReadCom = "" Then
                        Thread.Sleep(50)
                        oReadCom = mySerialPort.ReadExisting()
                    End If
                    mySerialPort.Close()
                Catch ex2 As Exception
                End Try
                If oReadCom <> "" Then
                    oNameCol.Add(oName, oReadCom) 
                    oNunbCol.Add(oReadCom, oName) 
                    oNPlat = oNPlat + 1
                End If
            End If
        Next
        Try
            If oNunbCol.Count > 0 Then
                For i = 1 To oNunbCol.Count
                    If oNunbCol.ContainsKey(i.ToString) Then
                        ListBox1.Items.Add(i.ToString & "  -  " & oNunbCol(i.ToString))
                        oComPort.Add(New SerialPort(oNunbCol(i.ToString)))
                        With oComPort(i - 1) ' нумерация от 0
                            .BaudRate = oComSpeed '57600
                            .Parity = Parity.None
                            .StopBits = StopBits.One
                            .DataBits = 8
                            .Handshake = Handshake.None
                            .RtsEnable = True
                        End With
                    Else
                    End If
                Next
            End If
        Catch ex As Exception
            ButtR.BackColor = Color.Red
        End Try
    End Sub
Провожу тест в цикле:
VB.NET Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    Private Sub ButStart_Click(sender As System.Object, e As System.EventArgs) Handles ButStart.Click
            For i = 1 To 100
                    SubStart()
            Next
    End Sub
 
    Private Sub SubStart()
        Dim oText As String = ""
        oText = ComsRead() ' ОТПРАВКА ЗАПРОСА
        Debug.Print(oText)
    End Sub
 
    Public oActivText As String ' переменная содержит последний ответ полученный в событии COM-порта
 
    Function ComsRead() As String ' функция отправки и получения ответа из COM-порта
        ComsRead = ""
        Try
            Dim oCallP2 As Integer = 1 ' номер платы чтения сигнала
            Dim oMess1 As String ' тест сообщения в COM-порт подачи сигнала
            oActivText = ""
            AddHandler oComPort(oCallP2).DataReceived, AddressOf DataReceivedHandler ' включение события 
            If oCallP2 = 1 Then
                oMess1 = "99/0/0/0"
                oComPort(oCallP2).WriteLine(oMess1)
            End If
            Dim oText As String = ""
            Thread.Sleep(5)
            For i = 1 To 50
                Thread.Sleep(10)
                oText = oActivText
                If oText <> "" Then
                    i = 999
                End If
            Next i
            RemoveHandler oComPort(oCallP2).DataReceived, AddressOf DataReceivedHandler 
            oComPort(oCallP2).DiscardInBuffer()
            If InStr(oText, "99") = 0 Then
                If oText <> "" Then ' просмотр кодов нештатных ответов
                    TextPin.Text = ""
                    For i = 1 To oText.Length
                        TextPin.Text = TextPin.Text & "  " & Asc(Mid(oText, i, 1))
                        Debug.Print(i.ToString & "=" & Asc(Mid(oText, i, 1)))
                    Next
                End If
            If InStr(oText, "99") = 0 Then
                oText = ""
                oComPort(oCallP2).Close()
                oComPort(oCallP2).Open()
                If oCallP2 = 1 Then
                    oMess1 = "99/0/0/0" 
                    oComPort(oCallP2).WriteLine(oMess1)
                End If
                Thread.Sleep(100) 
                oText = oComPort(oCallP2).ReadExisting()
                If oText = "" Then
                    Thread.Sleep(50) 
                    oText = oComPort(oCallP2).ReadExisting()
                End If
            End If
            ComsRead = oText
        Catch ex As Exception
        End Try
    End Function
 
    Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
        Try
            Dim sp As SerialPort = CType(sender, SerialPort)
            Dim indata As String = sp.ReadExisting()
            oActivText = indata
        Catch ex As Exception
            oActivText = "Error DataReceivedHandler"
        End Try
    End Sub
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
06.03.2025, 17:09
Ответы с готовыми решениями:

Visual studio 2019. Компонент SerialPort, почему не активен, не добавляется?
Добрый день. Установил Visual studio 2019. Пишу программу для работы с последовательным портом. В примерах, ктр видел, люди перетаскивают...

Visual studio 2019. Элемент serialport, почему нет метода getportnames?
В общем установил я вижуал студио 2019 и решил накидать простую программку для работы с серийным портом но оказалось что метод с помощью...

Почему пропадают элементы в конструкторе формы?
Добрый день. Не могу понять почему пропадают элементы в конструкторе формы. Что делал до этого: У меня есть форма с необходимыми...

11
2228 / 1549 / 393
Регистрация: 26.06.2017
Сообщений: 4,497
Записей в блоге: 1
07.03.2025, 09:15
У вас скорее всего это из-за блокировки UI потока.
Например в этом участке кода поток отпускается совсем не надолго:
VB.NET Скопировано
1
2
3
4
5
6
7
8
Thread.Sleep(5)
            For i = 1 To 50
                Thread.Sleep(10)
                oText = oActivText
                If oText <> "" Then
                    i = 999
                End If
            Next i

Не по теме:

Код настолько (даже не знаю как назвать) линейный что ли, что даже те объекты, вроде СОМ-порта, которые пытаются работать в события, то ломаются об блокировку. filat18, вам реально надо изменить код под паттерн наблюдатель.



Добавлено через 5 минут
Вместо блокировки потока, вроде той, на которую я указал, запускайте таймер ожидания ответа.
Также измените название, а лучше разделите функционал метода ComsRead. Дело в том, что этот метод не только читает, что можно подумать на основании его названия, но и создаёт порты, пишет в них, обрабатывает нештатные ситуации. Короче, метод делает много чего и это много надо декомпозировать.
0
7 / 6 / 3
Регистрация: 03.12.2020
Сообщений: 301
07.03.2025, 10:29  [ТС]
А в чем смысл задержек ReadTimeout и WriteTimeout - стоит ли их задавать?
И стоит ли очищать буферы DiscardInBuffer/DiscardOutBuffer перед отправкой-чтением?
0
2228 / 1549 / 393
Регистрация: 26.06.2017
Сообщений: 4,497
Записей в блоге: 1
07.03.2025, 11:52
Я не сильно разбираюсь в СОМ-портах, поэтому не подскажу.
0
7 / 6 / 3
Регистрация: 03.12.2020
Сообщений: 301
07.03.2025, 12:06  [ТС]
Цитата Сообщение от Uswer Посмотреть сообщение
Код настолько (даже не знаю как назвать) линейный что ли
Абсолютно верное замечание и я с ним полностью согласен! Предложенный материал по паттерну написан на C#, а я его синтаксис туго понимаю, может кто подкинет пример реализации на VB?
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
07.03.2025, 12:25
У вас способ обмена запрос-ответ?
0
7 / 6 / 3
Регистрация: 03.12.2020
Сообщений: 301
07.03.2025, 12:36  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
У вас способ обмена запрос-ответ?
Да.

Я вот хэлп еще раз почитал... Вроде получилось пример кода применить:
VB.NET Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim readThread As New Thread(AddressOf Read)
 
        _serialPort = New SerialPort()
 
        _serialPort.PortName = "COM14" ' SetPortName(_serialPort.PortName)
        _serialPort.BaudRate = 250000 ' SetPortBaudRate(_serialPort.BaudRate)
        _serialPort.Parity = Parity.None ' SetPortParity(_serialPort.Parity)
        _serialPort.DataBits = 8 'SetPortDataBits(_serialPort.DataBits)
        _serialPort.StopBits = StopBits.One ' SetPortStopBits(_serialPort.StopBits)
        _serialPort.Handshake = Handshake.None ' SetPortHandshake(_serialPort.Handshake)
 
        _serialPort.Open()
        readThread.Start()
        For i = 1 To 100
            _continue = True
            'Thread.Sleep(5)
            While _continue
                If InStr(oTvet, "99") > 0 Then
                    Debug.Print(i.ToString)
                    _continue = False
                Else
                    oTvet = ""
                    _serialPort.WriteLine("99/0/0/0")
                End If
            End While
        Next i
        _serialPort.DiscardInBuffer()
        _serialPort.DiscardOutBuffer()
        _serialPort.Close()
        TextBox1.Text = TextBox1.Text & "+"
 
        readThread.Join()
        'readThread.Interrupt()
        'readThread.Abort()
    End Sub
 
    Public Shared oTvet As String
 
    Public Shared Sub Read()
        While _continue
            '    If _serialPort.IsOpen = True Then
            Try
                oTvet = _serialPort.ReadLine()
            Catch ex As Exception
            End Try
        End While
    End Sub
Вот только поток закрывается с ошибкой в строке oTvet = _serialPort.ReadLine(). Можно ли его закрыть корректно?
Пробовал добавить условие: If _serialPort.IsOpen = True Then, но без результатно...
0
2228 / 1549 / 393
Регистрация: 26.06.2017
Сообщений: 4,497
Записей в блоге: 1
10.03.2025, 08:27
filat18, у СОМ-порта есть события при получении данных. Вам надо использовать их вместо постоянного чтения.
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
10.03.2025, 08:34
Для запрос-ответ не надо. Лучше write и read с правильными таймаутами.
0
7 / 6 / 3
Регистрация: 03.12.2020
Сообщений: 301
10.03.2025, 09:48  [ТС]
Цитата Сообщение от Uswer Посмотреть сообщение
у СОМ-порта есть события при получении данных
Да я знаю и не против бы, но как Вы выше правильно отметили: прямолинейность кода не позволяет ему планомерно (без искажений и потерь) выдавать ответы в основной поток.
Цитата Сообщение от Rius Посмотреть сообщение
write и read с правильными таймаутами.
Очень интересное замечание! Как определить какие таймауты правильные?
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
10.03.2025, 09:52
Как определить какие таймауты правильные?
Есть время ожидания ответа, пока прибор думает, что ответить. Между отправкой запроса и первым байтом ответа. Указывается в документации, смотрится на осциллографе или логическом анализаторе, находится опытным путём.
И есть время таймаута посылки. Например, равное времени передачи 3-5 байт на используемой скорости. Если оно истекло, то пакет завершён.
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
10.03.2025, 16:24
Code Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
массив_байт отправить_и_принять(массив_байт):
    очищаем буферы чтения и записи порта
    пишем отправляемый массив в порт
 
    ставим таймаут чтения 1 секунду
    читаем один байт
 
    если вылетело исключение по таймауту:
        возвращаем пустой массив
 
    добавляем считанный байт в массив результата
 
    ставим таймаут чтения равный времени передачи 3 байт на используемой скорости
 
  повтор чтения:
    читаем 4096 байт из порта в буфер
    добавляем в массив результата столько, сколько считалось
 
    если считалось 0:
        возвращаем массив результата
 
    если вылетело исключение по таймауту:
        возвращаем массив результата
 
    перейти к повтору чтения
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.03.2025, 16:24
Помогаю со студенческими работами здесь

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

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

C# SerialPort Неполный прием сообщений
Добрый день. Долго искал решение своей проблемы, но поиски оказались тщетны. Задача: организовать обмен сообщениями между железом и...

Почему не приходит сообщение группе SignalR?
Методы из хаба. public void UserConnect(string message) { Clients.Group(&quot;managers&quot;).notifyManager(Context.ConnectionId, message);...

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


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

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
Результаты исследования от команды MCM (март 2025 г.)
Programma_Boinc 07.04.2025
Результаты исследования от команды MCM (март 2025 г. ) В рамках наших текущих исследований мы продолжаем изучать гены, которые имеют наибольшую вероятность развития рака легких, выявленные в рамках. . .
Рекурсивные типы в Python
py-thonny 07.04.2025
Рекурсивные типы - это типы данных, которые определяются через самих себя или в сочетании с другими типами, которые в свою очередь ссылаются на исходный тип. В мире программирования такие структуры. . .
C++26: Объединение и конкатенация последовательностей и диапазонов в std::ranges
NullReferenced 07.04.2025
Работа с последовательностями данных – одна из фундаментальных задач, с которой сталкивается каждый разработчик. C++ прошел длинный путь в эволюции средств для манипуляции коллекциями – от. . .
Обмен данными в микросервисной архитектуре
ArchitectMsa 06.04.2025
Когда разработчики начинают погружаться в мир микросервисов, они часто сталкиваются с парадоксальным правилом: "два сервиса не должны делить один источник данных". Эта мантра звучит повсюду в. . .
PostgreSQL в Kubernetes: Автоматизация обслуживания с CNPG
Mr. Docker 06.04.2025
Администраторы баз данных сталкиваются с целым рядом проблем при обслуживании PostgreSQL в Kubernetes: как обеспечить правильную репликацию данных, как настроить автоматическое переключение при. . .
Async/await в TypeScript
run.dev 06.04.2025
Асинхронное программирование — это подход к разработке программного обеспечения, при котором операции выполняются независимо друг от друга. В отличие от синхронного выполнения, где каждая последующая. . .
Многопоточность в C#: Синхронизация потоков
UnmanagedCoder 06.04.2025
Многопоточное программирование стало неотъемлемой частью разработки современных приложений на C#. С появлением многоядерных процессоров возможность выполнять несколько задач параллельно значительно. . .
TypeScript: Классы и конструкторы
run.dev 06.04.2025
TypeScript, как статически типизированный язык, построенный на основе JavaScript, привнес в веб-разработку новый уровень надежности и структурированности кода. Одним из важнейших элементов этой. . .
Многопоточное программирование: Rust против C++
golander 06.04.2025
C++ существует уже несколько десятилетий и его поддержка параллелизма постепенно наращивалась со временем. Начиная с C++11, язык получил стандартную библиотеку для работы с потоками, а в последующих. . .
std::vector в C++: от основ к оптимизации производительности
NullReferenced 05.04.2025
Для многих программистов знакомство с std::vector происходит на ранних этапах изучения языка, но между базовым пониманием и подлинным мастерством лежит огромная дистанция. Контейнер std::vector. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru
Выделить код Копировать код Сохранить код Нормальный размер Увеличенный размер