Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.99/103: Рейтинг темы: голосов - 103, средняя оценка - 4.99
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1

Правильный подход обмена данных с устройствами через COM-порт. Целостность пакетов и производительность обмена

26.02.2018, 23:52. Показов 21324. Ответов 71
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую вас, коллеги!
Хочу с вами посоветоваться, ибо мне кажется, что я делаю это не совсем правильно, либо что-то не учёл...
Делаю обмен данными с устройством через COM-порт (RS-232) по алгоритму: послал команду в порт (через .Write(...)), поставил задержку (Threading.Sleep(200)), читаю ответ (через .Read(...)). И вот тут меня смущает эта самая задержка. Если ответные пакеты приходят большие (ну например более 60 байтов), то что бы вычитать весь буфер, этой задержки как буд-то не хватает, пакет получаю не весь. Если увеличиваю задержку, то буфер весь вычитывается, однако, во-первых, буфера могут быть разной длины, и для каждого так подбирать задержки - не реально, во-вторых, если с устройством есть возможность обмениваться на разных скоростях (бод), это вообще дур-дом и всякая актуальность, например, выбора более высокой скорости обмена теряется, т.к. задержки будут одинаковыми, если их так железно задавать... В-третьих, когда такая функция обмена, с железно заданным Sleep'ом (подобранным на вскидку, чтоб не потерять большие пакеты), в цикле, например, ведёт обмен, то для более мелких пакетов, такая задержка, опять же, становится не актуальной, т.к. увеличивается драгоценное время простоя, и обмен происходит дольше, чем мог бы быть... Вот по этому я и задаюсь вопросом: как в таком случае правильно следует поступать? Не ужели чем длиннее ответный пакет, тем дольше его нужно ждать, чтоб он вычитался? Как избежать таких диких задержек? У кого был подобный опыт с обменом по СОМ-порту с устройствами, подскажите, пожалуйста, или поделитесь идеями, кто хотя бы понял суть вопроса.

P.S. слышал что-то про подход асинхронного чтения данных из порта, но пока не понял что это и с чем это едят, и мой ли это вообще случай. Если да, то расскажите про такой подход, кто в курсе вообще. Только по понятнее пожалуйста, с примерами, если можно, а то про асинхронные приёмы работы пока вообще не в теме... Особо не доводилось использовать.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.02.2018, 23:52
Ответы с готовыми решениями:

Организация обмена данными через LPT-порт
разработайте программу определения адреса LPT - порта и вывода информации через LPT - порт, При этом светодиоды стенда должны отображать: ...

Функция для обмена HEX данными через COM порт
Помогите реализовать функцию работы с COM портом в консольном приложении. Алгоритм такой: Слушаем порт и при появлении HEX команды,...

Синхронизация обмена данных через LiFi
Здравствуйте. Никак не могу придумать способ реализации обмена через свет. Алгоритмом все вроде бы хорошо: "отмигиваем"...

71
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
07.04.2018, 20:06  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от insite2012 Посмотреть сообщение
все-таки попробуйте для начала просто подход, цикл в 10 итераций с задержкой по 50 мс и проверкой буфера порта при каждой итерации. В принципе, это должно работать как и обычный таймаут в 500 мс для порта.
Благо, перед тем как переписать свой старый алгоритм на метод с двумя таймаутами, я сделал бэкап того проекта. Там функция обмена была по алгоритму, более похожа на то, что вы предложили. Позже на днях сравню и попробую поэкспериментировать с этим вариантом ещё.

Цитата Сообщение от Storm23 Посмотреть сообщение
я всегда использовал другой сериал порт, вот типа такого https://github.com/AnthonyNyst... ommBase.cs
Он работает значительно быстрее (если по ссылке не разберетесь могу скинуть рабочие исходники).
Спасибо! Тоже на недельке попробую с этим вариантом поэкспериментировать. Если будут проблемы, обращусь .
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
09.04.2018, 07:26
Cha1000000, вот обмен на WinAPI с известным размером пакета.
Жёлтый - запрос. Зелёный - ответ.
Второй скриншот - увеличенный участок первого, в районе стрелок.
Скорость 115200.
Миниатюры
Правильный подход обмена данных с устройствами через COM-порт. Целостность пакетов и производительность обмена   Правильный подход обмена данных с устройствами через COM-порт. Целостность пакетов и производительность обмена  
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
09.04.2018, 12:59  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
обмен на WinAPI с известным размером пакета
А размеры ответа какого максимума достигают у вас?
Ну, если я правильно всё понял, то это очень хороший результат!
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
09.04.2018, 13:09
AN3155 - USART protocol used in the STM32 bootloader, команда ReadMemory, до 256 байт примерно.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
09.04.2018, 13:46  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
AN3155 - USART protocol used in the STM32 bootloader
Ошибка по переходу по ссылке... Не находит файл...
Not Found

Cannot serve request to /content/ccc/resource/technical/document/application_note/51/5f/03/1e/bd/9b/45/be/CD00264342.pdf/

ApacheSling/2.4 (jetty/9.2.9.v20150224, Java HotSpot(TM) 64-Bit Server VM 1.8.0_45, Linux 4.9.85-37.55.amzn1.x86_64 amd64)
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
09.04.2018, 13:50
Хм. Вот так http://www.st.com/resource/en/... 264342.pdf
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
09.04.2018, 15:37  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Вот так
Да так открывается. Только пока не совсем понял, чем мне эта документация может помочь?
Вы привели скриншоты с WinAPI. Это вы на нём обмен реализовали, или как? Его как-то в коде C# можно применить?
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
09.04.2018, 15:43
На нём. Нативная библиотека, работающая с WinAPI. Сама вызывается из C#. Я вам об этом ранее говорил.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
09.04.2018, 16:07  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Я вам об этом ранее говорил.
Попробую найти упоминания об этом в истории... Но на всякий случай, если не затруднит, можно реальный пример кода, как в C# её вызывать и использовать?
0
Эксперт .NET
 Аватар для Rius
13375 / 7830 / 1695
Регистрация: 25.05.2015
Сообщений: 23,833
Записей в блоге: 14
09.04.2018, 18:54
В ЛС от 2018-03-01 11:37 мск.
Попробуйте применить то, что выше советовали: Правильный подход обмена данных с устройствами через COM-порт. Целостность пакетов и производительность обмена
Это проще.

Добавлено через 8 минут
Код мой вам не поможет: весь я показать не могу, а часть - лишь верхушка айсберга.
Непосредственно чтение на самом нижнем уровне выглядит так:
C++
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
BOOL SerialPort::read(BYTE *buffer, DWORD bytesToRead, DWORD *bytesReaded, DWORD timeout)
{
    BOOL result = FALSE;
 
    *bytesReaded = 0;
    DWORD dwRead, dwWait;
    OVERLAPPED sync = { 0 };
 
    // Создаём событие для контроля за асинхронным чтением
    sync.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
    // Если событие создано без ошибок
    if (sync.hEvent != NULL) {
        // Начинаем чтение…
        if (ReadFile(this->mPort, buffer, bytesToRead, &dwRead, &sync)) {
            // Операция чтения уже завершилась,
            // можно обрабатывать полученные данные
            *bytesReaded = dwRead;
            result = TRUE;
        } else {
            if (GetLastError() != ERROR_IO_PENDING) {
                // Ошибка чтения данных
            } else {
                // Ожидаем завершение операции чтения
                dwWait = WaitForSingleObject(sync.hEvent, timeout);
 
                switch (dwWait) {
                    case WAIT_OBJECT_0: { // Операция чтения закончена
                        if (GetOverlappedResult(this->mPort, &sync, &dwRead, FALSE)) {
                            // Обработка полученных данных
                            *bytesReaded = dwRead;
                            result = TRUE;
                        } else {
                            // Ошибка выполения операции
                        }
 
                        break;
                    }
 
                    case WAIT_TIMEOUT: {
                        // Операция чтения данных ещё не закончилась
                        // можно занятся чем-нибудь полезным
                        break;
                    }
 
                    default: {
                        // Ошибка выполнения WaitForSingleObject
                        break;
                    }
                }
            }
        }
 
        CloseHandle(sync.hEvent);
    }
 
    return (result);
}
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
09.04.2018, 21:25  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Попробуйте применить то, что выше советовали...
Это проще.
Да, я как раз собирался этот вариант попробовать, ещё просто не успел. А вот на, продемонстрированный вами код, я тут уже где-то натыкался, пока бродил по схожим темам) Да, вряд-ли он мне особо поможет. Но всё равно спасибо

Добавлено через 1 час 48 минут
Цитата Сообщение от Storm23 Посмотреть сообщение
если по ссылке не разберетесь могу скинуть рабочие исходники
По ссылке с кодом ознакомился. Вот только метода чтения там что-то не нашёл. А половина тех функций мне скорее всего не пригодится.
А вот за "рабочие исходники" © был бы признателен! Хочется наглядно посмотреть, как правильно на деле вы применяете методы (и какие именно) этого класса... Особенно интересует метод чтения, а то что-то я его не заметил там...
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
10.04.2018, 11:20
Цитата Сообщение от Cha1000000 Посмотреть сообщение
По ссылке с кодом ознакомился. Вот только метода чтения там что-то не нашёл.
Как же не нашли? Там есть виртуальный метод
C#
1
protected virtual void OnRxChar(byte ch) {}
Он переопределяется в наследнике, и он будет вызван при получении байта из порта.

Вот нашел исходный код и пересобрал его (см присоединенный файл NETSerialComm.zip). Это COM терминал сделанный поверх CommBase.
В нем есть класс BaseTerm который унаследован от CommBase. В нем есть переопределенный метод OnRxChar, который принимает входящие байты.


Кроме того я нашел у себя еще один класс SerialClient. Это обертка поверх стандартного SerialPort. Он также работает быстрее стандартного SerialPort. В эттейче - пример (WindowsFormsApplication226.zip - это исходник принимающий данные с камеры, прием данных происходит в событии OnReceiving).

Цитата Сообщение от Rius Посмотреть сообщение
Обёртка над тем самым трушным WinAPI.
Жаль лицензия не указана.
В readme тип лицензии не указан, значит можно считать ее свободной.
Кроме того, этот код публиковался в MSDN Magazine, поэтому думаю с использованием проблем не должно быть.
Вложения
Тип файла: zip NETSerialComm.zip (223.3 Кб, 265 просмотров)
Тип файла: zip WindowsFormsApplication226.zip (91.8 Кб, 241 просмотров)
2
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
10.04.2018, 12:05  [ТС]
Цитата Сообщение от Storm23 Посмотреть сообщение
нашел исходный ко
Ооо! Премного благодарю! Поковыряю, поизуйчаю
Цитата Сообщение от Storm23 Посмотреть сообщение
еще один класс SerialClient. Это обертка поверх стандартного SerialPort. Он также работает быстрее стандартного SerialPort.
А всё такие какой надёжнее и быстрее: CommBase или SerialPort? Есть какие-то плюсы / минусы в сравнении?
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
10.04.2018, 13:51
Цитата Сообщение от Cha1000000 Посмотреть сообщение
А всё такие какой надёжнее и быстрее: CommBase или SerialPort? Есть какие-то плюсы / минусы в сравнении?
Не знаю, я редко занимаюсь железом. В своих проектах я использовал оба.
SerialClient - простой в использовании. Но он решает только проблему временных задержек стандартного SerialPort. Если проблема только с задержками - можно попробовать его.
CommBase - более сложный. Но он низкоуровневый, на WinAPI, соответственно в нем можно сделать все что хочешь.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
10.04.2018, 14:20  [ТС]
Цитата Сообщение от Storm23 Посмотреть сообщение
я использовал оба
Спасибо, буду экспериментировать.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
16.04.2018, 12:43  [ТС]
Storm23, добрый день! Ещё раз спасибо за эти два отличных примера. Поизучав их на днях, долго не мог решить, каким из них всё же попробовать воспользоваться для изменения алгоритма обмена в своём проекте... Честно, даже до сих пор толком не определился, но думаю попробовать применить второй вариант. В связи с чем у меня появилась парочка вопросов по логике работы вашего примера.
1) Если я правильно понял, то в этой программе вы сначала настраиваете СОМ-порт на определённые настройки, после чего открываем порт и держим его открытым на протяжении всей работы программы? Если, как вы сообщили, эта программа принимает данные с камеры (непрерывно видимо), то это логично. А вот на сколько такой подход целесообразен, если приём данных в программе происходит только тогда, когда пользователь нажмёт соответствующие кнопки и пакеты при этом могут быть как единоразовыми (пакет с посылкой →, ответный пакет ←), так и вида: пакет с посылкой →, цикл ответных пакетов ← ? В моём нынешнем варианте я каждый раз открываю порт перед отправкой пакета в устройство и получением ответа (ответов), а по окончании обмена закрываю. Можно ли оставить такую концепцию, или всё стоит держать порт открытым пока программа запущена?
2) По обмену: опять же, если я всё правильно понял, отправка пакета осуществляется функцией void Transmit(byte[] packet), тайм-ауты приёма по умолчанию отсутствуют вообще (= -1), а для приёма нужно подписываться на событие OnReceiving, таким образом: com.OnReceiving += new EventHandler<RTSerialCom.DataStreamEvent Args>(com_OnReceiving); Всё верно? А в этом событии чтение в отдельном потоке происходит, так? И по этому нет ни тайма-аутов, не слипов?

Добавлено через 1 час 49 минут
Кстати. Немного доработал вашу функцию bool OpenConn() (в модуле FastSerial): после открытия порта ( _serialPort.Open(); ), добавил очистку буфера приёма/передачи:
C#
1
2
_serialPort.DiscardInBuffer();
_serialPort.DiscardOutBuffer();
Не знаю на сколько это будет полезным, но, как говорится, на всякий случай.
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
18.04.2018, 10:22
Цитата Сообщение от Cha1000000 Посмотреть сообщение
А вот на сколько такой подход целесообразен, если приём данных в программе происходит только тогда, когда пользователь нажмёт соответствующие кнопки и пакеты при этом могут быть как единоразовыми (пакет с посылкой →, ответный пакет ←), так и вида: пакет с посылкой →, цикл ответных пакетов ← ? В моём нынешнем варианте я каждый раз открываю порт перед отправкой пакета в устройство и получением ответа (ответов), а по окончании обмена закрываю. Можно ли оставить такую концепцию, или всё стоит держать порт открытым пока программа запущена?
Я бы держал порт открытым. Он почти не потребляет ресурсов, если данные не поступают.
Цитата Сообщение от Cha1000000 Посмотреть сообщение
а для приёма нужно подписываться на событие OnReceiving, таким образом: com.OnReceiving += new EventHandler<RTSerialCom.DataStreamEvent Args>(com_OnReceiving); Всё верно?
Да.
Цитата Сообщение от Cha1000000 Посмотреть сообщение
А в этом событии чтение в отдельном потоке происходит, так? И по этому нет ни тайма-аутов, не слипов?
Да, прием делается в отдельном потоке. А слип там есть, в методе SerialReceiving. А на стороне обработчика слип не нужен.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
18.04.2018, 13:00  [ТС]
Storm23, Ну вроде реализовал данный подход. Но со слипами всё равно какая-то хрень. Для пакетов поменьше хватает и 100мс, а для пакетов побольше приходится подбирать разные (и 200, и 400 и 600)... И как-то не особо стабильно ведёт себя: то успевает за это время задержки принять пакет, то нет... Пока не пойму, но делать большие слипы мне не нравится... Либо я что-то не так делаю?

Добавлено через 1 час 0 минут
Storm23, что бы не гадать, я пожалуй покажу, что у меня получилось, а вы может свежим взглядом увидите, что я возможно делаю не правильно. Т.к. мне кажется, я не совсем понял механизм уведомления завершения приёма каждого отдельного ответного пакета. В вашем примере я так понимаю, включаем поток чтения один раз и больше его не перезапускаем, и вертимся в нем, накапливая буфер, и по ходу разбирая его... В своём алгоритме же я каждый раз, перед отправкой команды в устройство, вызываю метод RestartComPort(), тем самым запустив поток чтения, а после принятия ответного пакета в обработчике ответа дёргаю флаг, что пакет полностью принят и закрываю соединение, отписываясь вместе с тем от события обработки чтения... Но вот тут как раз я и не уверен, во-первых в целесообразности такого "передёргивания" порта и сессии чтения)), а во-вторых тут как раз и не совсем понятно, как сообщить из обработчика чтения, что пакет успешно принят, и передать управление коду дальше???
В общем вот мой вариант представления:
C#
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    public const byte STX = 0x02;                   // начало текста данных
        public const byte ETX = 0xff;                   // конец данных
 
        public static byte[] RxBuf = new byte[255];     // буфер, принимаемый из устройства
        public static byte[] TxBuf = new byte[255];     // буфер, передаваемый в устройство 
        public static byte[] ReadData;                  // буфер "основных" данных ответа
        public static byte ErrorCode = 0x00;            // код ошибки: 0 - ошибок нет
        public static byte retCode;                     // код команды, возвращаемый устройством 
        public static string TextBuf = "";              // вспомогательный буфер текста
        public static string Str_Port;                  // имя COM-порта
        public static string Str_Baude;                 // скорость обмена
        public static bool ch_port = false;             // признак выбора COM-порта
        public static bool pr_Error = false;            // признак ошибки выполнения комманды
        public static bool needTryCRC = true;           // признак проверки CRC ответа 
        
        private static List<byte> buffer = new List<byte>();
        public static bool readOK;                      // признак принятого пакета
        private static int RespLen = 0;                 // длина ответного пакета
        
        //_________________ Событие чтения данных из COM-порта _______________________//
        static void com_OnReceiving(object sender, RTSerialCom.DataStreamEventArgs e)
        {
            ///  Структура ответа:   ///
            // № байта |   Описание
            /*   0     -  STX 0x02    *
             *   1     -  длина       *
             *   2     -  код_команды *
             *   3     -  код_ошибки  *
             *   4     -  № буфера    *
             * с 5     -  Данные      *
             * RespLen -  СRC         *
             */
            ///***********************///                        
            foreach (var b in e.Response)
            {
                buffer.Add(b);
                if (buffer.Count > 1)
                {
                    if (buffer.Count == 2)
                        RespLen = buffer[1];    // длина ответного пакета
                    
                    if (buffer.Count == RespLen + 3)
                    {
                        retCode = buffer[2];    // код команды
                        ErrorCode = buffer[3];  // код ошибки
                        ReadData = new byte[buffer.Count - 6];
                        Array.Copy(buffer.ToArray(), 5, ReadData, 0, RespLen-3); // поле Data ответа ККМ
                        RxBuf = new byte[buffer.Count];
                        RxBuf = buffer.ToArray();
 
                        //Проверяем контрольную сумму
                        if (needTryCRC)
                        {
                            int sLen = RespLen + 1;
                            byte CRC = 0;
                            for (int i = 1; i <= sLen; i++)
                                CRC += (byte)RxBuf[i];
                            if (CRC != RxBuf[RespLen + 2])
                            {
                                ErrorCode = 0x01;
                                pr_Error = true;  // признак ошибки
                                MessageBox.Show("Ошибка контрольной суммы ответа ККМ", "Ошибка",
                                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return;
                            }
                        }
                        readOK = true;
                        buffer.Clear();
                        break;
                    }
                }
            }
        }
        
        //****************************** Обмен данными ПК <-> Устройство **********************************//
        #region SendCommand
        /// <summary>
        /// Посылка данных в ККМ (приём-ответ)
        /// </summary>
        /// <param name="buf_len">Длина буфера данных</param>
        /// <param name="CmdCode">Код команды</param>
        /// <param name="ErrorCode">Код ошибки</param>
        /// <param name="bufnum">Номер буфера</param>
        /// <param name="Buf_Data[]">Буфер данных, передаваемых в устройство</param>
        /// <param name="tm">Время задержки после отправки команды (мс)</param>
        /// <returns></returns>
        public static void SendCommand(int buf_len, byte CmdCode, int bufnum, byte[] Buf_Data, int tm = 200)
        {
            int i, j;
            int len_command;            
            byte CRC = 0;
            pr_Error = false;
            //////////            
            TxBuf = new byte[255];
            len_command = buf_len + 3; //Длина посылки: от Кода_команды до CRC
            try
            {
                ////////////////////////   Подготовка пакета к отправке  ///////////////////////            
                TxBuf[0] = STX;
                TxBuf[1] = (byte)len_command;
                TxBuf[2] = CmdCode;
                TxBuf[3] = ErrorCode;
                TxBuf[4] = (byte)bufnum;
                // присоединение данных
                if (Buf_Data == null)
                    Buf_Data = new byte[1];
 
                Array.Copy(Buf_Data, 0, TxBuf, 5, buf_len);
                // присоединение контрольной суммы CRC
                for (i = 1; i <= len_command + 1; i++)
                    CRC += TxBuf[i];
                TxBuf[len_command + 2] = CRC;
 
                Array.Resize(ref TxBuf, len_command + 3);
                ///////////////////////////// Обмен данными /////////////////////////////////////
                readOK = false;
                RestartComPort();
                Thread.Sleep(10);
                com.Transmit(TxBuf);  // Посылка пакета в ККТ
                Thread.Sleep(tm);
            }
            catch (Exception ex)
            {
                CloseComPort();
                MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                pr_Error = true;// признак ошибки
            }
            finally
            {
                CloseComPort();
            }
        }
        #endregion
        
        //----------------------------------------------------------------------------------------------
        public static void RestartComPort()
        {
            try
            {
                if (com != null)
                {
                    com.CloseConn();
                    com.Dispose();
                }
                com = new RTSerialCom.SerialClient(Str_Port, int.Parse(Str_Baude));                
                com.OnReceiving += new EventHandler<RTSerialCom.DataStreamEventArgs>(com_OnReceiving);
                com.OpenConn();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }    
        public static void CloseComPort()
        {
            if (com != null)
            {
                com.OnReceiving -= new EventHandler<RTSerialCom.DataStreamEventArgs>(com_OnReceiving);
                com.CloseConn();
                com.Dispose();
            }
        }
        //----------------------------------------------------------------------------------------------
Пример вызова функции обмена:
C#
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
    private void bt_ReadSettings_Click(object sender, EventArgs e)
        {
            int k, iByte;
            int bufnum = 1;
            byte cmdCod = 0x14;
            byte[] RESP = new byte[25];
            Program.ErrorCode = 0x00;
 
            try
            {
                this.Enabled = false;
                Program.SendCommand(0, cmdCod, bufnum, null, 500); // Command -> Device
                if (Program.readOK)
                {
                    // обработка данных из ответного буфера ...
                }
                else
                {
                    this.Enabled = true;
                    this.Activate();
                    return;//ошибка
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Enabled = true;
                this.Activate();
                return;
            }
            finally
            {
                this.Enabled = true;
                this.Activate();
            }
        }
0
18.04.2018, 19:59

Не по теме:

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

0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
18.04.2018, 21:43  [ТС]
Цитата Сообщение от Storm23 Посмотреть сообщение
я не занимаюсь железом и не эксперт в этой области
Да тут даже не в железе дело...
Тут бы понять каким образом передавать управление основному потоку из потока чтения, когда посылка считана. Тогда не придётся подбирать слипы наугад...
В вашем примере случайно не через Invoke такой механизм осуществляется? Спрашиваю потому, что этим инструментом ещё пользоваться не доводилось и только лишь интуиция мне подсказывает, что возможно именно он для этого и используется...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
18.04.2018, 21:43

Виртуальный COM-порт на STM32, скорость обмена.
Всем привет. Прошу помощи :) Экспериментирую с USB - CDC-класс, стоит задача передать данные в хост на максимально возможной скорости....

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

COM-порт, работа с двумя формами и одним буфером обмена
Доброго времени суток. Обращаюсь с вопросом, который повторяли, наверно, сотню и один раз. Но ответа, подходящего под специфическую...

Запретить вставку текста в TEdit из буфера обмена через Ctrl+V или через контекстное меню
Добрый день! Есть такой вопрос: Что нужно сделать, чтобы в TEdit не было возможности вставить текст из буфера обмена при помощи CTRL+V...

Обмена информации через сокеты
Здравствуйте, уважаемые форумчани. Пожалуйста, помоги сделать эту задачу: В среде Visual C++ написать клиентскую и серверную программы...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
сукцессия 30. Фосфорный и азотный замки по "честному" закону лимитирования Либиха
anaschu 16.07.2026
Основные достижения за последние дни 1. Механизм отложенного высвобождения фосфора Добавлен специальный пул для медленного разложения меланизированных гиф ЕСМ Реализована разная скорость. . .
Запрет пометки на удаление и отмены проведения
Maks 16.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "ПутевойЛист" разработанного в КА2. Задача: запретить помечать на удаление и отменять проведения путевого листа при условии, если он сдан. . .
Как надо было делать правильно - вообще не слушать ИИ, его дело - текст.
Hrethgir 15.07.2026
А вообще надо было делать не так, чтобы не исправлять ошибку https:/ / www. cyberforum. ru/ blogs/ 223907/ 10996. html , правильно было : удалил кнопку, а потом добавил её. Всё это стресс конечно. Почему?. . .
Знаете, от чего появляется стресс?
kumehtar 15.07.2026
Стресс появляется оттого, что вы, зная как поступить правильно, делаете наоборот. Ларри Уингет
Нас бьют, а мы крепчаем? Какая чушь!
kumehtar 15.07.2026
Вот это вот бытующее мнение, что человек меняется только под действием проблем, всегда считал вредоносным. Поверь, от проблем у людей появляются не изменения, а нервное расстройство и ПТСР. А. . .
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru