Форум программистов, компьютерный форум, киберфорум
Visual Basic .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/29: Рейтинг темы: голосов - 29, средняя оценка - 4.52
178 / 68 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
1

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

30.09.2016, 12:47. Показов 5858. Ответов 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
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.09.2016, 12:47
Ответы с готовыми решениями:

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

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

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

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

39
Эксперт .NET
10559 / 6485 / 1504
Регистрация: 25.05.2015
Сообщений: 19,648
Записей в блоге: 14
30.09.2016, 13:07 2
Цитата Сообщение от jkrnd Посмотреть сообщение
Нужно чтобы каждую секунду запрос в порт посылался, и ответ возвращался с отображением на форме.
Запускается отдельный поток.
В потоке отправляется запрос, читается ответ, по кругу.

В .Net есть свой класс для работы с последовательным портом.
1
178 / 68 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 16:49  [ТС] 3
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
10559 / 6485 / 1504
Регистрация: 25.05.2015
Сообщений: 19,648
Записей в блоге: 14
30.09.2016, 16:51 4
Не так то, что глобальная и локальная переменные, даже если у них одно имя, это разные переменные.
1
178 / 68 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 17:07  [ТС] 5
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
10559 / 6485 / 1504
Регистрация: 25.05.2015
Сообщений: 19,648
Записей в блоге: 14
30.09.2016, 17:19 6
Лучший ответ Сообщение было отмечено jkrnd как решение

Решение

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

Добавлено через 1 минуту
это всё вместе, включая два байта контрольной суммы
0
178 / 68 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 21:11  [ТС] 17
Sklifosofsky, на всякий случай выложу проект. он реально работает, но как я уже говорил, что то в моей программе влияет на работу прибора и он периодически возвращает вместо реальных данных нули. А газ то расходуется. Это считается нештатной ситуацией, фиксируется внутри прибора и инфа передаётся в Межрегионгаз.
Вложения
Тип файла: rar Ver1.5 (CTRL, ХуИрвис пошли нештатки).rar (49.7 Кб, 18 просмотров)
0
178 / 68 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
30.09.2016, 21:14  [ТС] 18
протокол
Вложения
Тип файла: pdf rs4_protocol_ri3.pdf (240.8 Кб, 19 просмотров)
0
Эксперт .NET
10559 / 6485 / 1504
Регистрация: 25.05.2015
Сообщений: 19,648
Записей в блоге: 14
01.10.2016, 11:04 19
У вас по одному таймеру посылается запрос, по другому читается ответ. Эти события вполне могут рассинхронизироваться.
Если modbus в приборе работает совместно с аппаратным управлением потоком, то рассинхронизация чтения и записи может как-то повлиять.
Запись и чтение должны происходить в одной функции последовательно.
1
178 / 68 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
01.10.2016, 13:08  [ТС] 20
Rius, то есть работа моей программы повлияла на правильность работы прибора. Я немного в этом сомневался, но факты упрямая вещь, да и Вы подтвердили. В документации к прибору есть целый раздел про modbus.
Вопрос: контрол SerialPort здесь не причём? Или это и его глюки.
0
01.10.2016, 13:08
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.10.2016, 13:08
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru