Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
1 / 1 / 0
Регистрация: 19.02.2016
Сообщений: 20
1

Изменение номера com-порта без перезапуска приложения

11.04.2016, 12:32. Показов 632. Ответов 12
Метки нет (Все метки)

Добрый день. Снова проблема. Есть form1 с основной программой опроса порта и есть form2 с comboboxами для выбора номера и скорости порта. При первом запуске программа берет настройки, присвоенные переменным char port [5] и int rate в коде на form1. При вызове form2 и возможном изменении текста в comboboxах, данные уходят в ini-файл, и form1 берет их оттуда, но только после перезапуска. Попытки с присвоением в extern char port и extern int rate по нажатию btbtn безуспешны, form1 не реагирует. Либо продолжает работать при правильном порте, либо ждет соединения при неправильном. Ошибок при компиляции нет. Как изменить порт не делая перезапуск программы ? Помогите пожалуйста.
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.04.2016, 12:32
Ответы с готовыми решениями:

Изменение страници без перезапуска.
Задача следующая. Нужно изменять часть странички при использовании меню. <? session_start();...

Как применить настройки без перезапуска приложения
Здравствуйте! Ситуация следующая, в процессе работы программа записывает некоторую информацию в...

Сценарий перезапуска приложения
Суть проблемы такова: Есть приложение, которое должно работать 24/7. Необходимо написать Bat-ник,...

Создать кнопку перезапуска приложения
Привет, друзья. Полистал гугл по этому сайту, но все мои поиски упираются в темы относящиеся к цпп...

12
Модератор
3331 / 2115 / 343
Регистрация: 13.01.2012
Сообщений: 8,243
11.04.2016, 15:38 2
Цитата Сообщение от Merphy Посмотреть сообщение
Помогите пожалуйста
закрыть порт. считать новую конфигурацию (если ее уже нет в памяти), открыть порт.
0
Практикантроп
4680 / 2600 / 496
Регистрация: 23.09.2011
Сообщений: 5,580
11.04.2016, 20:19 3
Цитата Сообщение от Merphy Посмотреть сообщение
данные уходят в ini-файл, и form1 берет их оттуда
Так сделайте, чтоб форма2 брала из ини-файла значения для бокса, а форма1 считывала значения из формы2:
C++
1
String PortName = Form2->ComboBoxPortName->Text;
0
1 / 1 / 0
Регистрация: 19.02.2016
Сообщений: 20
27.04.2016, 09:02  [ТС] 4
Цитата Сообщение от vxg Посмотреть сообщение
закрыть порт. считать новую конфигурацию (если ее уже нет в памяти), открыть порт.
Вот думал я об этом. Только мозга не хватает на реализацию. Все операции с инициализацией, открытием и закрытием порта происходят на form1, а операции c ченджем порта - на form2. Думаю, может как-то надо следить за изменением переменных, в которых хранятся значения скорости и номера используемого порта, и во время их изменения, делать закрытие и тут же открытие порта. Только на какое событие это вешать... Вопрооос.
0
Модератор
3331 / 2115 / 343
Регистрация: 13.01.2012
Сообщений: 8,243
27.04.2016, 09:38 5
Цитата Сообщение от Merphy Посмотреть сообщение
как-то надо следить
-на форме 1 что то делается и при этом идут обращения к порту.
-на форме 2 задается что же это за порт.
для меня очевидно что на форме 1 должна быть кнопочка начать опрос или открыть порт или начать что то делать после нажатия которой происходит открытие порта и начинается обращения к нему. ясно что после нажатия на эту кнопочку пускать человека на форму 2 нельзя ибо это не имеет смысла. то есть кнопочка "настройки порта" открывающая форму 2 должна стать недоступной и разблокироваться только тогда когда человек остановит деятельность (прекратится обмен и закроется порт).
0
1 / 1 / 0
Регистрация: 19.02.2016
Сообщений: 20
27.04.2016, 12:17  [ТС] 6
на форме 1 должна быть кнопочка
При запуске exe сразу начинается опрос. Если с портом беда, то ошибка, иди открывай меню, вызывай форм2 и исправляй. Нет кнопочки. Намеренно нет. В данный момент выкручиваюсь перезапуском проги по нажатию BtBtn на форм2 после всех манипуляций с портом, но должен же быть какой-то умный программный ход.
0
Модератор
3331 / 2115 / 343
Регистрация: 13.01.2012
Сообщений: 8,243
27.04.2016, 19:22 7
Merphy, повесить на открытие меню закрытие опроса и порта
0
1 / 1 / 0
Регистрация: 19.02.2016
Сообщений: 20
04.07.2016, 06:23  [ТС] 8
Загнал я себя в яму, в общем. Надо по нажатию на пункт меню перезапустить порт без перезапуска приложения. Вешал Comport_open() на разные события формы и меню, пока безрезультатно.

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
TForm1 *Form1;
//---------------------------------------------------------------------------
char m_sComPort[5];
int baud_rate;                          //скорость обмена
int Error_nom;                          //номер ошибки
HANDLE hCom = NULL;                     //дескриптор порта, создаётся и используется для всех операций с портом
DCB dcb;                                //установки управляющие работой порта
COMMTIMEOUTS cto;                       //структура задающая тайм-ауты последовательного порта
DWORD numbyte, temp, numbytes_ok, mask;
COMSTAT comstat;
 
HANDLE writer;                          //дескриптор потока записи в порт
DWORD WINAPI WriteThread(LPVOID);
 
HANDLE reader;                          //дескриптор потока чтения из порта
DWORD WINAPI ReadThread(LPVOID);
 
void ReadRx(void);
 
OVERLAPPED overlapped;              //будем использовать для операций чтения (см. поток ReadThread)
OVERLAPPED overlappedwr;                //будем использовать для операций записи (см. поток WriteThread)
       
#define BUFSIZE 255                     //ёмкость буфера
uint32_t counter;                   //счётчик принятых байтов, обнуляется при каждом открытии порта
uint8_t bufrd[1024];                    //приёмный буфер
 
HANDLE hTxPort, hData;
uint32_t TXX = 0;
 
//---------------------------------------------------------------------------
unsigned char buf_out[BUFSIZE];
unsigned char buf_in[BUFSIZE];
 
uint8_t USART_TxBuffer[BUFSIZE];
uint8_t USART_RxBuffer[BUFSIZE];
uint32_t USART_NbrOfDataToTransfer;
uint32_t USART_RxCounter;
 
int32_t count;
 
uint8_t bit_error, error_sys;   //р-ры ошибок ВИБ
//---------------------------------------------------------------------------
бла...бла..бла...
//---------------------------------------------------------------------------
int Comport_open(void)
                        //ошибки программы
                        //2- порт не существует
                        //3- ошибка записи порта
                        //4- ошибка чтения порта
                        //0- нет ошибок
{
 Error_nom = 0;
 hCom = CreateFile(m_sComPort, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 if ((hCom == INVALID_HANDLE_VALUE) || (hCom == NULL))
  {
  //Если порт не открывается
   MessageBox(NULL, "Порт отсутствует или используется другим приложением", "Reader", MB_OK | MB_ICONSTOP);
   Error_nom = 2; //установили ошибку
 goto end;
  } // end if
 
  // Установка параметров обмена
  memset(&dcb,0,sizeof(dcb));                 // Выделение места в памяти
  dcb.DCBlength=sizeof(dcb);                  // Присвоение структуре места
  dcb.BaudRate=baud_rate;                     // Скорость обмена
  dcb.ByteSize=8;                             // 8 бит
  dcb.Parity=0;                               // без контроля четности
  dcb.StopBits=ONESTOPBIT;                    // 1 стоп бит
  dcb.fBinary=TRUE;                           // Обмен двоичными числами
  dcb.fOutxCtsFlow=TRUE;                      // Сигнал CTS отслеживать
  dcb.fOutxDsrFlow=FALSE;                     // Сигнал DSR не отслеживать
  dcb.fDtrControl=DTR_CONTROL_ENABLE;         // Контроль с помощью сигнала DTR разрешить
  dcb.fDsrSensitivity=FALSE;                  // Сигнал DSR на коммуникационный драйвер не влияет
  dcb.fOutX=FALSE;                            // Управление выходным потоком символами XON/XOFF отключить
  dcb.fInX=FALSE;                             // Управление входным потоком символами XON/XOFF отключить
  dcb.fErrorChar=FALSE;                       // Ошибочные байты не заменять
  dcb.fNull=FALSE;                            // Нулевые байты не отбрасывать
  dcb.fRtsControl=RTS_CONTROL_TOGGLE;         // Разрешить RTS
  dcb.fAbortOnError=FALSE;                    // Не прекращать ввод-вывод при ошибках
  //dcb.wReserved=0;                          // Зарезервировано - должен быть 0
  SetCommState(hCom,&dcb);                    // Установить параметры порта с дескриптором hPort из структуры dcb
  cto.ReadIntervalTimeout = 0;                // Максимальное время между чтением байт, мс
  cto.ReadTotalTimeoutMultiplier = 0;         // Множитель для вычисления общего времени чтения
  cto.ReadTotalTimeoutConstant = 0;//70;      // Время ожидания начала приема, мс
  cto.WriteTotalTimeoutMultiplier = 0;//10;   // Множитель для вычисления общего времени записи, мс
  cto.WriteTotalTimeoutConstant = 0;//100;    // Время ожидания начала записи, мс
  SetCommTimeouts(hCom, &cto);                // Установить тайм-ауты из структуры cto
  SetupComm(hCom, 2000, 2000);                // Очистить внутренние буферы порта и установить их длину
  PurgeComm(hCom, PURGE_RXCLEAR);             // Очистить принимающий буфер порта
  reader = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);            //создаём поток чтения, который сразу начнёт выполняться (предпоследний параметр = 0)
  writer = CreateThread(NULL, 0, WriteThread, NULL, CREATE_SUSPENDED, NULL); //создаём поток записи в остановленном состоянии (предпоследний параметр = CREATE_SUSPENDED)
 end: return Error_nom;
}
//------------------------------------------------------------------------------
//главная функция потока, выполняет передачу байтов из буфера в COM-порт
 DWORD WINAPI WriteThread(LPVOID)
{
 DWORD temp, signal;    //temp - переменная-заглушка
 overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL);   //создать событие
  while(1)
  {
   //записать байты в порт (перекрываемая операция!)
   WriteFile(hCom, USART_TxBuffer, USART_NbrOfDataToTransfer, &temp, &overlappedwr);
   //приостановить поток, пока не завершится перекрываемая операция WriteFile
   signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE);
   //если операция завершилась успешно
   if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(hCom, &overlappedwr, &temp, true)))
     {
       ReleaseSemaphore( hTxPort, 1, NULL );
       TXX = 0;
     }
   //иначе вывести в строке состояния сообщение об ошибке
   else
    {
     PurgeComm(hCom, PURGE_TXCLEAR | PURGE_TXABORT);
     ReleaseSemaphore( hTxPort, 1, NULL );
     TXX = 0;
    }
   SuspendThread(writer);
  }
}
//---------------------------------------------------------------------------
//главная функция потока, реализует приём байтов из COM-порта
DWORD WINAPI ReadThread(LPVOID)
{
 DWORD btr, temp, mask, signal;           //переменная temp используется в качестве заглушки
 
 //создать сигнальный объект-событие для асинхронных операций
 overlapped.hEvent = CreateEvent(NULL, true, true, NULL);
 
 SetCommMask(hCom, EV_RXCHAR);           //установить маску на срабатывание по событию приёма байта в порт
 while(1)                //пока поток не будет прерван, выполняем цикл
  {
   WaitCommEvent(hCom, &mask, &overlapped);                 // ожидать события приёма байта
                                // (это и есть перекрываемая операция)
   signal = WaitForSingleObject(overlapped.hEvent, INFINITE);   //приостановить поток до прихода байта
   if(signal == WAIT_OBJECT_0)                      //если событие прихода байта произошло
    {
     //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
     if(GetOverlappedResult(hCom, &overlapped, &temp, true))
       if((mask & EV_RXCHAR)!=0)                    //если произошло именно событие прихода байта
       {
        ClearCommError(hCom, &temp, &comstat);              //нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                              //и получить из неё количество принятых байтов
        if(btr)                                     //если действительно есть байты для чтения
        {
         ReadFile(hCom, bufrd, btr, &temp, &overlapped);        //прочитать байты из порта в буфер программы
         counter+=btr;                                          //увеличиваем счётчик байтов
         ReadRx();                                      //вызываем функцию для вывода данных
        }
      }
    }
  }
}
//---------------------------------------------------------------------------
void Comport_Close(void)
 {//закрываем порт
 //завершить поток чтения из порта, проверка if(reader) обязательна, иначе возникают ошибки
 if(reader)
  {
   TerminateThread(reader,0);
   CloseHandle(overlapped.hEvent);  //нужно закрыть объект-событие
   CloseHandle(reader);
  }
 //завершить поток записи в порт, проверка if(writer) обязательна, иначе возникают ошибки
 if(writer)
  {
   TerminateThread(writer,0);
   CloseHandle(overlappedwr.hEvent);    //нужно закрыть объект-событие
   CloseHandle(writer);
  }
 PurgeComm(hCom,PURGE_RXABORT|PURGE_TXABORT);
 CloseHandle(hCom);                     //закрыть порт
 hCom = 0;                      //обнулить переменную для дескриптора порта
}
//---------------------------------------------------------------------------
бла...бла..бла...
//---------------------------------------------------------------------------
 __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
if (!Comport_open())// Timer1 -> Enabled = true; //открыли СОМ порт
    {
     // Wait indefinetly for a free semaphore
     WaitForSingleObject( hTxPort, 500);
     PurgeComm(hCom, PURGE_TXCLEAR);              //очистить передающий буфер порта
     USART_TxBuffer[0] = 'A';
     USART_TxBuffer[1] = 'T';
     USART_TxBuffer[2] = 0x0D;
     USART_TxBuffer[3] = 0;
     USART_NbrOfDataToTransfer = strlen(USART_TxBuffer);
     ResumeThread(writer);                        //активировать поток записи данных в порт
 
     Timer2 -> Enabled = true;                    //ждем ответа модема если он есть
    }
 hTxPort=CreateSemaphore( NULL, 1, 1, NULL );
 hData=CreateSemaphore( NULL, 1, 1, NULL );
}
//---------------------------------------------------------------------------
бла...бла..бла...
//---------------------------------------------------------------------------
void __fastcall TForm1::N7Click(TObject *Sender)
{
 Comport_Close();
 AnsiString asNCom = "COM1";
 strcpy(m_sComPort, asNCom.c_str());
 TIniFile *Ini;
 Ini = new TIniFile(ExtractFilePath(Application -> ExeName) + "options.ini");
 Ini -> WriteString("Port", "Номер", "COM1");
 TMenuItem *mi = static_cast <TMenuItem*> (Sender);
 for (int i = 0; i < mi -> Parent -> Count; i++)
  {
   mi -> Parent -> Items[i] -> Checked = false;
  }
   mi -> Checked = true;
 Ini-> WriteInteger("Port", "Индекс", mi -> MenuIndex);
 Ini -> UpdateFile();
 delete Ini;
}
0
Модератор
3331 / 2115 / 343
Регистрация: 13.01.2012
Сообщений: 8,243
04.07.2016, 06:48 9
Merphy, очевидно при наступлении события требующего смены порта (например нажатия на пункт меню) надо прибить потоки, закрыть порт, открыть новый, создать потоки
0
1 / 1 / 0
Регистрация: 19.02.2016
Сообщений: 20
04.07.2016, 07:31  [ТС] 10
Порт закрывается по выбору пункта меню, там же, согласно функции, умирают потоки. Но по вызову событием, например, ActiveForm, функции Comport_open(), происходит ничего... Похоже надо DWORD WINAPI ReadThread(LPVOID) и DWORD WINAPI WriteThread(LPVOID) снова запустить ?

Добавлено через 6 минут
Хотя, нет, создаются эти потоки в функции Comport_open(). Как быть ?
0
Модератор
3331 / 2115 / 343
Регистрация: 13.01.2012
Сообщений: 8,243
04.07.2016, 08:07 11
Merphy, как быть я написал. Не совсем понятны ваши сложности. Слово событие я произносил в бытовом смысле. Для облегчения жизни рекомендую на бумаге написать по строчкам четко и ясно желаемое поведение
0
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
08.07.2016, 16:45 12
У вас есть функция открытия COM порта, стандартная, красивая и понятная. И функция закрытия, которая сама же порт ваш закрывает, потоки обрубает, лишнее подчищает.
Всего-то в вашем коде строка
C++
1
strcpy(m_sComPort, asNCom.c_str());
Которая пишет в файл название COM порта, перенаправьте ее на какой-нибудь элемент вовода с формы. Со скоростью, если нужно, то же самое сделайте. Вот все ваши переменные для базового управления портом.
C++
1
2
char m_sComPort[5];
int baud_rate;                          //скорость обмена
Обеспечьте их заполнение с полей Edit или ComboBox, на ваш вкус, и все.
Вообще товарищ vxg дельно говорит, представьте для себя алгоритм программы удобным для вас способом.
0
1 / 1 / 0
Регистрация: 19.02.2016
Сообщений: 20
11.07.2016, 06:37  [ТС] 13
Уважаемый Zerorc.
Делаю
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void __fastcall TForm1::N7Click(TObject *Sender)
{
 Comport_Close();
 TIniFile *Ini;
 Ini = new TIniFile(ExtractFilePath(Application -> ExeName) + "options.ini");
 Ini -> WriteString("Port", "Номер", "COM1");
 TMenuItem *mi = static_cast <TMenuItem*> (Sender);
 for (int i = 0; i < mi -> Parent -> Count; i++)
  {
   mi -> Parent -> Items[i] -> Checked = false;
  }
   mi -> Checked = true;
 Ini -> WriteInteger("Port", "Индекс", mi -> MenuIndex);
 Ini -> UpdateFile();
 delete Ini;
 Comport_Open();
}
Из INI при первом запуске читается нормально и работает, но при изменении порта в меню действия приведенные ниже не происходят вновь без перезапуска приложения
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 if (!Comport_Open())
    {
     WaitForSingleObject( hTxPort, 500);
     PurgeComm(hCom, PURGE_TXCLEAR);              //очистить передающий буфер порта
     USART_TxBuffer[0] = 'A';
     USART_TxBuffer[1] = 'T';
     USART_TxBuffer[2] = 0x0D;
     USART_TxBuffer[3] = 0;
     USART_NbrOfDataToTransfer = strlen(USART_TxBuffer);
     ResumeThread(writer);                        //активировать поток записи данных в порт
     Form1 -> Label21 -> Caption = "Порт открыт";
     Form1 -> Timer2 -> Enabled = true;                    //ждем ответа модема если он есть
    }
  hTxPort = CreateSemaphore( NULL, 1, 1, NULL );
  hData = CreateSemaphore( NULL, 1, 1, NULL );
}
отсюда, мне кажется и проблема. Голову сломал себе уже. Горепрограммист.

Добавлено через 24 минуты
Всем спасибо. Проблема решилась добавлением
C++
1
ResumeThread(writer);
после
C++
1
Comport_Open();
в
C++
1
void __fastcall TForm1::N7Click(TObject *Sender)
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.07.2016, 06:37

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Сохранение информации после перезапуска приложения
Всем здравствуйте, возник такой вопрос нужна переменная в которой будет храниться какая либо...

SharedPreferences стираются после перезапуска приложения
Доброго времени суток. В моем приложении пробую хранить его данные конфигурации (адрес сервера ,...

Сохранение элементов после перезапуска приложения
Как сделать, чтобы по нажатию кнопки в приложении создавалась новая кнопка, и после перезапуска она...

Изменение цвета Checkbox и сохранение после перезапуска
День добрый, как реализовать чтобы выделенные чекбоксы после нажатия на &quot;Красный&quot; или &quot;Зеленый&quot;...


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.