Форум программистов, компьютерный форум, киберфорум
Visual Basic .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.59/34: Рейтинг темы: голосов - 34, средняя оценка - 4.59
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648

Как организовать непрерывный опрос Com-порта?

30.09.2016, 12:47. Показов 6188. Ответов 39
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем здравствуйте.
Приведенный ниже код работает так: кликнули по кнопке - отправили в порт набор байт, кликнули по другой - получили ответ.
Нужно чтобы каждую секунду запрос в порт посылался, и ответ возвращался с отображением на форме.

Пример взят из книги Архангельского (Delphi). На всякий случай прикрепляю проект.
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
    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        'запись сообщения в порт
        Dim n As Integer
        Dim s As String = Format(Now, "hh:mm:ss") 'Это передаваемый текст
        Dim SPnt As IntPtr = Marshal.StringToCoTaskMemAnsi(s)
        FlushFileBuffers(portHandle)   'очищаем буфер порта
        WriteFile(portHandle, SPnt, Len(s), n, lpOVERLAPPED)
        If GetLastError <> ERROR_IO_PENDING Then
            MsgBox("Ошибка")
        Else
            Timer1.Start()
        End If
    End Sub
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim n As Integer
        If GetOverlappedResult(portHandle, lpOVERLAPPED, n, False) Then
            Label3.Text = "Получены/переданы новые данные - " & n.ToString & " байт"
            Dim V As New System.Text.UTF8Encoding()
            Label4.Text = V.GetString(buf)
            Timer1.Stop()
        Else
            Label3.Text = "Новых данных нет"
        End If
    End Sub
    Private Sub btnReceived_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReceived.Click
        'чтение сообщения из порта
        Dim n As Integer
        Dim mPnt As IntPtr = GCHandle.Alloc(buf, GCHandleType.Pinned).AddrOfPinnedObject()
        FlushFileBuffers(portHandle) 'очищаем буфер порта
        ReadFile(portHandle, mPnt, 128, n, lpOVERLAPPED)
        'проверяем отсутствие ошибки
        If GetLastError <> ERROR_IO_PENDING Then
            MsgBox("Ошибка")
        Else
            Timer1.Start()
        End If
    End Sub
Вложения
Тип файла: rar Ver2.1 (API).rar (29.0 Кб, 20 просмотров)
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.09.2016, 12:47
Ответы с готовыми решениями:

ATtiny13, непрерывный опрос АЦП, прерывание
Всем привет. Столкнулся со странным поведением контроллера в симуляторе. Хотелось бы знать, это косяк симулятора, или на железе та же фигня...

Как организовать непрерывный обмен между сокетами без переподключения?
Есть примеры синхронных клиента и сервера с использованием сокетов. А мне нужно организовать обмен данных по таймеру. Объём данных за цикл...

Как настроить опрос COM-порта по прерыванию int 14h?
Мне нужно инициализировать сом порт и затем по прерыванию int 14h считывать данные из ком порта. Инициализацию на с++ сделал по простому ...

39
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 13:07
Цитата Сообщение от jkrnd Посмотреть сообщение
Нужно чтобы каждую секунду запрос в порт посылался, и ответ возвращался с отображением на форме.
Запускается отдельный поток.
В потоке отправляется запрос, читается ответ, по кругу.

В .Net есть свой класс для работы с последовательным портом.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 16:49  [ТС]
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
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
Imports System.IO.Ports
 
Public Class Form1
    Private mySerialPort As New SerialPort
    Private comBuffer As Byte()
    Private Delegate Sub UpdateFormDelegate()
    Private UpdateFormDelegate1 As UpdateFormDelegate
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'автоопределение всех последовательных портов в системе и заполнение ими поля со списком cboPortName.
        Dim ArrPort As Array  'Com-порты обнаруженные в системе будут храниться здесь
        ArrPort = SerialPort.GetPortNames() 'Получить все доступные Com-порты
        cboPortName.DropDownStyle = ComboBoxStyle.DropDownList 'пользователь не должен иметь возможность вводить ошибочные значения названий портов
        For i = 0 To UBound(ArrPort)
            cboPortName.Items.Add(ArrPort(i))
        Next
        cboPortName.Text = cboPortName.Items.Item(0)    'Присвоим свойству Text элемента cboPortName  имя первого обнаруженого com-порта 
        'заполнение поля со списком cboBaudRate возможными константами:
        cboBaudRate.DropDownStyle = ComboBoxStyle.DropDownList 'пользователь не должен иметь возможность вводить ошибочные значения Baud Rate
        cboBaudRate.Items.Add(4800)
        cboBaudRate.Items.Add(9600)
        cboBaudRate.Items.Add(19200)
        cboBaudRate.Items.Add(38400)
        cboBaudRate.Items.Add(57600)
        cboBaudRate.Items.Add(115200)
        cboBaudRate.Text = cboBaudRate.Items.Item(0)    'Присвоим свойству Text элемента cboBaudRate первую испольуемую скорость передачи данных из списка
        'Изначально отключить кнопку btnClosePort
        btnClosePort.Enabled = False
        AddHandler mySerialPort.DataReceived, AddressOf mySerialPort_DataReceived
    End Sub
    Private Sub btnOpenPort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpenPort.Click
        OpenComPort()
    End Sub
 
    Private Sub btnClosePort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClosePort.Click
        CloseComPort()
    End Sub
    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        'запись сообщения (массива байт) в порт
        Dim s As String = Format(Now, "hh:mm:ss") 'Это передаваемый текст
        Dim buffer() As Byte = System.Text.Encoding.Default.GetBytes(s) 'Преобразуем строку в массив байт
        Dim offset As Integer = 0 'смещение
        Dim count As Integer = buffer.Length  'количество передаваемых байт
        mySerialPort.Write(buffer, offset, count)
    End Sub
 
    Private Sub btnReceived_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReceived.Click
        'чтение сообщения (массива байт) из порта
        Dim buffer(127) As Byte
        Dim offset As Integer
        Dim count As Integer
        Dim returnValue As Integer 'количество считанных из порта байт
        returnValue = mySerialPort.Read(buffer, offset, count)
    End Sub
    Sub OpenComPort()
        Try
            If Not mySerialPort.IsOpen Then 'если порт ещё не открыт
                'Имя Com-порта:
                mySerialPort.PortName = cboPortName.SelectedItem.ToString
                'Скорость передачи данных:
                mySerialPort.BaudRate = CInt(cboBaudRate.Text)
                'Остальные параметры:
                mySerialPort.Parity = Parity.None
                mySerialPort.DataBits = 8
                mySerialPort.StopBits = StopBits.One
                mySerialPort.Handshake = Handshake.None
                mySerialPort.ReadTimeout = 3000
                mySerialPort.WriteTimeout = 5000
                'Открываем Com-порт
                mySerialPort.Open()
                'приводим в соответствие с этим событием кнопки открытия-закрытия порта
                btnClosePort.Enabled = True
                btnOpenPort.Enabled = False
            Else
                'порт уже открыт и проинициализирован
            End If
        Catch ex As InvalidOperationException
            MessageBox.Show(ex.Message)
        Catch ex As UnauthorizedAccessException
            MessageBox.Show(ex.Message)
        Catch ex As System.IO.IOException
            MessageBox.Show(ex.Message)
        End Try
    End Sub
    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
 
    Private Sub mySerialPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)  'Handles serial port data received events
        UpdateFormDelegate1 = New UpdateFormDelegate(AddressOf UpdateDisplay)
        Dim n As Integer = mySerialPort.BytesToRead 'find number of bytes in buf
        Dim comBuffer As Byte() = New Byte(n - 1) {} 're dimension storage buffer
        mySerialPort.Read(comBuffer, 0, n) 'read data from the buffer
        Me.Invoke(UpdateFormDelegate1) 'call the delegate
    End Sub
    Private Sub UpdateDisplay()
        'Label3.Text = CStr(comBuffer(0))
        'Преобразовываем массив байт в строку
        Dim V As New System.Text.UTF8Encoding()
        Label4.Text = V.GetString(comBuffer)  'здесь возникает исключение "Массив не может быть неопределенным."
    End Sub
End Class
возникает исключение в строке 114 "Массив не может быть неопределенным."
Код передрал со статьи один к одному. Что не так?
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 16:51
Не так то, что глобальная и локальная переменные, даже если у них одно имя, это разные переменные.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 17:07  [ТС]
Rius, понял сработало
VB.NET Скопировано
1
comBuffer = New Byte(n - 1) {}
вместо
VB.NET Скопировано
1
Dim comBuffer As Byte() = New Byte(n - 1) {}
Спасибо.
А приведенный пример - это асинхронная работа с портом или нет?

Добавлено через 3 минуты
наверное API вообще не стоит трогать раз такая халява есть. или здесь ещё что-то всплывёт непонятное? а если у меня возвращаемый массив сотни байт и за 1 раз весь не вернётся, кто это обрабатывает класс или я?
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 17:19
Лучший ответ Сообщение было отмечено jkrnd как решение

Решение

Я бы сказал, что это на основе событий (DataReceived). Может быть оно и асинхронное в основе своей.
Не такая уж и халява. Класс не всегда удобен. Если сотни байт, событие может вылететь... как повезёт.
И вообще через событие получается криво, IMHO. Посмотрите другие варианты https://www.cyberforum.ru/blog... g4357.html.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 17:29  [ТС]
Rius, а на VB примера нет?
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 17:32
Нет, я не VB не пишу. Но можете воспользоваться converter.telerik.com или рефлексией готовой сборки в ILSpy.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 18:24  [ТС]
Rius, у меня VS2010, пересобрал ваш проект SerialStreamTest (архив прилагается)
формы нет. Перед тем как конвертировать хотелось бы попробовать. Хотелось бы видеть нечто похожее на пример в посте#1. Как всё это запустить?
Вложения
Тип файла: rar WindowsFormsApplication1.rar (51.8 Кб, 10 просмотров)
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 18:53
Вот.
Этот метод я на практике пока ещё не применяю. Проверен был только раз на одном приборе.
Вложения
Тип файла: zip WindowsFormsApplication1.zip (23.6 Кб, 15 просмотров)
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 19:12  [ТС]
Rius, а какой применяете? я собрал проект на основе контрола SerialPort, похоже это тот же класс SerialPort. Я там тоже использовал DataReceived. У меня за 8-10 часов непрерывной работы (опрос текущих данных) на несколько минут вместо данных возвращаются нули, затем всё само собой восстанавливается. Прибор (счётчик газа) в это время фиксирует нештатную ситуацию. а это штраф. Я не знаю почему это происходит, но это никуда не годится. Поэтому и взялся за API.
Не могли бы Вы выложить проект WindowsForm стабильно работающий: Отправляем в порт массив байт - получаем массив байт.
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 19:17
Пока что применяю первый из блога в посте 6. Отправка как обычно через запись в порт, чтение как там.
Проекта нет - дома нет прибора с RS-232 для проверки.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 19:27  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
дома нет прибора с RS-232 для проверки
и у меня нет. Я RxD замкнул на TxD - что отправил, то и получил.
Цитата Сообщение от Rius Посмотреть сообщение
первый из блога в посте 6
там куча ссылок, нельзя ли поконкретнее, а лучше пересобрать под VS2010 и с выводом работы на форму.
0
 Аватар для Sklifosofsky
1082 / 912 / 213
Регистрация: 29.09.2015
Сообщений: 1,015
30.09.2016, 19:48
jkrnd, вопрос. Сколько байт должен возвращать порт за цикл?
1
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
30.09.2016, 19:52
jkrnd,
Вложения
Тип файла: zip WindowsFormsApplication1.zip (42.9 Кб, 12 просмотров)
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 21:03  [ТС]
Цитата Сообщение от Sklifosofsky Посмотреть сообщение
Сколько байт должен возвращать порт за цикл?
37 байт (это ответ на запрос текущих данных), другие запросы чуть больше но не намного.

Добавлено через 1 минуту
это всё вместе, включая два байта контрольной суммы
0
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 21:11  [ТС]
Sklifosofsky, на всякий случай выложу проект. он реально работает, но как я уже говорил, что то в моей программе влияет на работу прибора и он периодически возвращает вместо реальных данных нули. А газ то расходуется. Это считается нештатной ситуацией, фиксируется внутри прибора и инфа передаётся в Межрегионгаз.
Вложения
Тип файла: rar Ver1.5 (CTRL, ХуИрвис пошли нештатки).rar (49.7 Кб, 18 просмотров)
0
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 21:14  [ТС]
протокол
Вложения
Тип файла: pdf rs4_protocol_ri3.pdf (240.8 Кб, 19 просмотров)
0
Эксперт .NET
 Аватар для Rius
11422 / 7302 / 1617
Регистрация: 25.05.2015
Сообщений: 22,072
Записей в блоге: 14
01.10.2016, 11:04
У вас по одному таймеру посылается запрос, по другому читается ответ. Эти события вполне могут рассинхронизироваться.
Если modbus в приборе работает совместно с аппаратным управлением потоком, то рассинхронизация чтения и записи может как-то повлиять.
Запись и чтение должны происходить в одной функции последовательно.
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
01.10.2016, 13:08  [ТС]
Rius, то есть работа моей программы повлияла на правильность работы прибора. Я немного в этом сомневался, но факты упрямая вещь, да и Вы подтвердили. В документации к прибору есть целый раздел про modbus.
Вопрос: контрол SerialPort здесь не причём? Или это и его глюки.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.10.2016, 13:08
Помогаю со студенческими работами здесь

Как организовать цикличный опрос устройства
Здравствуйте, подскажите, пожалуйста, решение задачи: На данный момент есть программа без внешнего интерфейса но с иконкой в трее,...

Как организовать опрос матричной клавиатуры + DS18B20?
Господа, подскажите, пожалуйста, каким образом организовать опрос матричной клавиатуры и при этом не испортить тайминги 1-wire для датчика...

Опрос COM-порта
Здравствуйте. Я пишу прогу, которая должна принимать данные из COM-порта. Я просто взят и в бесконечном цикл while вставил команду чтения...

Опрос LPT порта
Есть LPT порт и два контакта. Необходимо написать программу которая при замыкании контактов в счетчик прибавляла 1. Контакты могут...

Опрос состояния порта принтера
Помогите выполнить сабж


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Результаты исследования от команды 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
Выделить код Копировать код Сохранить код Нормальный размер Увеличенный размер