Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.54/13: Рейтинг темы: голосов - 13, средняя оценка - 4.54
-13 / 6 / 6
Регистрация: 04.08.2015
Сообщений: 622

Не работает Com порт в асинхронном режиме

12.10.2016, 11:07. Показов 2900. Ответов 20
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Крайне необходимо небольшое приложение для Com порта работающее в асинхронном режиме. Принял некоторое переменное количество байт и сразу передал некоторое конечное количество байт.
Для реализации решил воспользоваться предложенным вариантом http://piclist.ru/S-COM-THREAD... D-RUS.html Составил небольшой проект в C++ Builder 6 на WinAPI
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
 
#define BUFSIZE 1000     //ёмкость буфера
 
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}
//---------------------------------------------------------------------------
// Глобальные переменные
 
//---------------------------------------------------------------------------
AnsiString portname;
HANDLE COMport;
DWORD WINAPI ReadThread(LPVOID);
DWORD WINAPI WriteThread(LPVOID);
 
//дескриптор потока чтения из порта
HANDLE reader;
//дескриптор потока записи в порт
HANDLE writer;
//приёмный и передающий буферы
unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE];
 
//структура OVERLAPPED необходима для асинхронных операций, при этом для операции чтения и записи нужно объявить разные структуры
//эти структуры необходимо объявить глобально, иначе программа не будет работать правильно
OVERLAPPED overlapped;      //будем использовать для операций чтения (см. поток ReadThread)
OVERLAPPED overlappedwr;    //будем использовать для операций записи (см. поток WriteThread)
int handle;                 //дескриптор для работы с файлом с помощью библиотеки <io.h>
//  bool fl=0;  //флаг, указывающий на успешность операций записи (1 - успешно, 0 - не успешно)
DWORD bc;
DCB *dcb;
// счетчик приемов
unsigned long counterRX;
 
//---------------------------------------------------------------------------
 
// Функции
 
//---------------------------------------------------------------------------
// Вывод принятых байтов на экран
 
void ReadPrinting(DWORD btr)
{
  String stroka, temp_str;
  for(UINT32 i=0; i<btr ; i++)
    stroka = stroka + IntToHex(bufrd[i], 2) + ' '; // Перенос буфера в строку.
 
  Form1->Memo1->Lines->Add(stroka); // Вывод.
  Form1->Label1->Caption = "Всего принято: " + IntToStr(counterRX);
  memset(bufrd, 0, BUFSIZE); // Очистить буфер (чтобы данные не накладывались друг на друга).
}
 
//---------------------------------------------------------------------------
// Поток чтения ReadThead
 
//главная функция потока, реализует приём байтов из COM-порта
DWORD WINAPI ReadThread(LPVOID)
{
  COMSTAT comstat;        // структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
  DWORD btr, temp, mask, signal;  // переменная temp используется в качестве заглушки
 
  overlapped.hEvent = CreateEvent(NULL, true, true, NULL); // создать сигнальный объект-событие для асинхронных операций
  SetCommMask(COMport, EV_RXCHAR);                     // установить маску на срабатывание по событию приёма байта в порт
  while(1)
  //while(!flag)                       // пока поток не будет прерван, выполняем цикл
  {
    WaitCommEvent(COMport, &mask, &overlapped);                   //ожидать события приёма байта (это и есть перекрываемая операция)
    signal = WaitForSingleObject(overlapped.hEvent, INFINITE);    //приостановить поток до прихода байта
    if(signal == WAIT_OBJECT_0)                       //если событие прихода байта произошло
    {
      if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
        if((mask & EV_RXCHAR)!=0)                 //если произошло именно событие прихода байта
        {
          ClearCommError(COMport, &temp, &comstat); // нужно заполнить структуру COMSTAT
          btr = comstat.cbInQue;                    // и получить из неё количество принятых байтов
          if(btr)                                   // если действительно есть байты для чтения
          {
            ReadFile(COMport, bufrd, btr, &temp, &overlapped); // прочитать байты из порта в буфер программы
            counterRX+=btr;                                      // увеличиваем счётчик байтов
            ReadPrinting(btr);                                    // вызываем функцию для вывода данных на экран и в файл
          }
        }
    }
  }
//CloseHandle(overlapped.hEvent);
//flag2=1;
}
 
//---------------------------------------------------------------------------
// Поток записи WriteThread
 
//главная функция потока, выполняет передачу байтов из буфера в COM-порт
DWORD WINAPI WriteThread(LPVOID)
{
  DWORD temp, signal;   //temp - переменная-заглушка
 
  overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL);      //создать событие
  while(1)
  {
    //записать байты в порт (перекрываемая операция!)
    WriteFile(COMport, bufwr, strlen(bufwr), &temp, &overlappedwr);
 
    //приостановить поток, пока не завершится перекрываемая операция WriteFile
    signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE);
 
    //если операция завершилась успешно
    if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlappedwr, &temp, true)))
    {
      //вывести сообщение об этом в строке состояния
      Form1->Panel2->Caption = "Передача прошла успешно";
    }
    //иначе вывести в строке состояния сообщение об ошибке
    else {Form1->Panel2->Caption = "Ошибка передачи";}
 
    SuspendThread(writer);
  }
}
 
//---------------------------------------------------------------------------
// установки Com порта
 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Form1->Panel1->Caption = "";
  DCB dcb;
  COMMTIMEOUTS timeouts;
 
  // Открытие порта
//  portname += "\\\\.";  // com_port.c_str()
//  portname += ComboBox1->Text;
  //portname = ChoiceCOM->Text;
  portname = Form1->ComboBox1->Text;
  COMport=CreateFile(portname.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  //здесь:
  // - portname.c_str() - имя порта в качестве имени файла,
  //   c_str() преобразует строку типа String в строку в виде массива типа char, иначе функция не примет
  // - GENERIC_READ | GENERIC_WRITE - доступ к порту на чтение/записть
  // - 0 - порт не может быть общедоступным (shared)
  // - NULL - дескриптор порта не наследуется, используется дескриптор безопасности по умолчанию
  // - OPEN_EXISTING - порт должен открываться как уже существующий файл
  // - FILE_FLAG_OVERLAPPED - этот флаг указывает на использование асинхронных операций
  // - NULL - указатель на файл шаблона не используется при работе с портами
 
  if(COMport==INVALID_HANDLE_VALUE)
  {
    Panel1->Font->Color = clRed;
    Panel1->Caption = " Не удалось открыть последовательный порт " + AnsiString(portname.c_str()) + ".";
    return;
  }
  else
  {
    Panel1->Font->Color = clGreen;
    Panel1->Caption = " Открыт порт " + AnsiString(portname.c_str());
    return;
  }
 
  // Инициализация порта
  //dcb=(DCB*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DCB)); // Выделение области памяти для DCB из кучи и заполнение этой области нулями.
  dcb.DCBlength=sizeof(DCB);
 
  if(!GetCommState(COMport, &dcb)) // Эта функция заполняет DCB информацией о текущем состоянии устройства, точнее о его настройках.
  {
  // Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния.
//  HeapFree(GetProcessHeap(),0,dcb); // Освобождение памяти из кучи.
    CloseHandle(COMport);
    Panel1->Font->Color = clRed;
    Panel1->Caption = "Не удалось считать DCB";
    return;
  }
 
  // Инициализация структуры DCB.
  dcb.BaudRate = StrToInt(Form1->ComboBox2->Text); //задаём скорость передачи 115200 бод
  dcb.fBinary = TRUE;                              //включаем двоичный режим обмена
  dcb.fOutxCtsFlow = FALSE;                        //выключаем режим слежения за сигналом CTS
  dcb.fOutxDsrFlow = FALSE;                        //выключаем режим слежения за сигналом DSR
  dcb.fDtrControl = DTR_CONTROL_DISABLE;           //отключаем использование линии DTR
  dcb.fDsrSensitivity = FALSE;                     //отключаем восприимчивость драйвера к состоянию линии DSR
  dcb.fNull = FALSE;                               //разрешить приём нулевых байтов
  dcb.fRtsControl = RTS_CONTROL_DISABLE;           //отключаем использование линии RTS
  dcb.fAbortOnError = FALSE;                       //отключаем остановку всех операций чтения/записи при ошибке
  dcb.ByteSize = 8;                                //задаём 8 бит в байте
  dcb.Parity = 0;                                  //отключаем проверку чётности
  dcb.StopBits = 0;                                //задаём один стоп-бит
 
  // Загрузить структуру DCB в порт.
  if(!SetCommState(COMport, &dcb))
  {// Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния.
//  HeapFree(GetProcessHeap(),0,dcb); // Освобождение памяти из кучи.
    CloseHandle(COMport);
    Panel1->Font->Color = clRed;
    Panel1->Caption = "Не удалось установить DCB.";
    return;
  }
 
  // Установка таймаутов.
  timeouts.ReadIntervalTimeout = 0;     // таймаут между двумя символами
  timeouts.ReadTotalTimeoutMultiplier = 0;  // общий таймаут операции чтения
  timeouts.ReadTotalTimeoutConstant = 0;    // константа для общего таймаута операции чтения
  timeouts.WriteTotalTimeoutMultiplier = 0; // общий таймаут операции записи
  timeouts.WriteTotalTimeoutConstant = 0;   // константа для общего таймаута операции записи
 
  // Загрузить структуру таймаутов в порт.
  if(!SetCommTimeouts(COMport, &timeouts))
  {// Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния.
    CloseHandle(COMport);
    Panel1->Font->Color = clRed;
    Panel1->Caption = "Не удалось установить тайм-ауты.";
    return;
  }
 
  // Установить размеры очередей приёма и передачи
  SetupComm(COMport,2000,2000);
 
  PurgeComm(COMport,PURGE_RXCLEAR); // Очистка буферов порта.
 
  Button1->Enabled = false;
  Button2->Enabled = true;
 
  // Создание потоков на WINAPI:
 
  // Cоздаём поток чтения, который сразу начнёт выполняться (предпоследний параметр = 0).
  reader = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);
 
  // Cоздаём поток записи в остановленном состоянии (предпоследний параметр = CREATE_SUSPENDED).
  writer = CreateThread(NULL, 0, WriteThread, NULL, CREATE_SUSPENDED, NULL);
 
  counterRX = 0;
}
//---------------------------------------------------------------------------
// завершение по закрытию формы
 
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  if(writer)
  {
    TerminateThread(writer,0);
    CloseHandle(overlappedwr.hEvent);   //нужно закрыть объект-событие
    CloseHandle(writer);
  }
  //завершить поток чтения из порта, проверка if(reader) обязательна, иначе возникают ошибки
  //if(reader) reader->Terminate();
  //завершить поток записи в порт, проверка if(writer) обязательна, иначе возникают ошибки
//  if(writer)writer->Terminate();
  if(COMport) CloseHandle(COMport);  //закрыть порт
//  if(handle) close(handle);      //закрыть файл, в который велась запись принимаемых данных
 
  if(reader)
  {
    TerminateThread(reader,0);
    CloseHandle(overlappedwr.hEvent);   //нужно закрыть объект-событие
    CloseHandle(reader);
  }
 
}
//---------------------------------------------------------------------------
// передача данных 
 
void __fastcall TForm1::Button2Click(TObject *Sender)
{
  memset(bufwr,0,BUFSIZE); //очистить программный передающий буфер,
    //чтобы данные не накладывались друг на друга
  PurgeComm(COMport, PURGE_TXCLEAR);            //очистить передающий буфер порта
  strcpy(bufwr,Form1->Edit1->Text.c_str());     //занести в программный передающий буфер строку из Edit1
 
  ResumeThread(writer);               //активировать поток записи данных в порт
}
//---------------------------------------------------------------------------
Но ничего не работает ни на передачу ни на прием. Хотя порт по нажатию Button1 открывается.
Подскажите пожалуйста что в коде не так. Может кто сталкивался буду признателен за код рабочих функций приема и передачи по Com в асинхронном режиме.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
12.10.2016, 11:07
Ответы с готовыми решениями:

COM-порт в асинхронном режиме
Настраиваю COM-порт для работы в асинхронном режиме с использованием API. К порту подключаю RS-232 переходник и смотрю сигналы на выводах....

Работа с COM-портом в асинхронном режиме
Пробую разобраться с работой COM порта. Получилось запустить в синхронном режиме. Стало ясно, что в этом режиме, вызывая функцию чтения...

Не работает 32к кварц в асинхронном режиме таймера
ATmega8A, таймер2 настроил на счет от внешнего кварца (32к с кондерами 22пФ): ASSR = 1&lt;&lt;AS2; /* XTAL (32k...

20
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
17.10.2016, 17:04
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от VlGuvin Посмотреть сообщение
Нет. Прием затем ответ. Интерфейс rs485 предполагает обязательный адаптер или преобразователь в rs232. Полудуплекс это значит прием и передача обязательно разделены во времени. Полный дуплекс когда передачу ответа можно вести одновременно с приемом. Это rs232 или rs422.
Я знаю что такое дуплек, полудуплекс, я же про логику работы программы.

Цитата Сообщение от VlGuvin Посмотреть сообщение
Вобщем один раз в секунду сначала прием 800...4800 (скорость 115200) байт затем сразу после получения всех содержащихся в одном непрерывном пакете байт - ответ 128 байт.
Ищите описание протокола, а то по формулировке понятно что это выдумано в диком угаре.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.10.2016, 17:04
Помогаю со студенческими работами здесь

ADO в асинхронном режиме.
Ну вот, и я решил задать вопрос, может кто-то натолкнет на мысль. Суть непонятки в следующем: while...

Проблема работы COM- в асинхронном режиме
Задача написать WPF приложение, работающее с пулом COM-портов, к которым подключены модемы. Вначале выбирается свободный модем: ...

Таймер Т2 в асинхронном режиме, Атмега8
Здравствуйте, сил нет и мысли кончились. Простите за такую преамбулу. Делаю простой и незатейливый код на Атмеге8, для начала просто...

Записать данные в файл в асинхронном режиме
Добрый день. Подскажите как записать данные в файл в асинхронном режиме.

Выполнение запроса к БД MSSQL в асинхронном режиме
Вопрос такой : в PHP 5 при использовании драйверов ODBC по неизвестной причине запрос типа 'SELECT * FROM ...' выполняется асинхронно, а...


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

Или воспользуйтесь поиском по форуму:
21
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru