Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Работа с RS-232


Автор: mishapk 11.7.2012, 16:28
Всем привет!
Помогите разобраться с примером взятого со http://www.piclist.ru/S-COM-THREAD-RUS/S-COM-THREAD-RUS.html

Код

//главная функция потока, реализует приём байтов из COM-порта
void __fastcall ReadThread::Execute()
{
 COMSTAT comstat;        //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
 DWORD btr, temp, mask, signal;    //переменная temp используется в качестве заглушки

 overlapped.hEvent = CreateEvent(NULL, true, true, NULL);    //создать сигнальный объект-событие для асинхронных операций
 SetCommMask(COMport, EV_RXCHAR);                            //установить маску на срабатывание по событию приёма байта в порт
 while(!Terminated)                        //пока поток не будет прерван, выполняем цикл
  {
   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)                                  //если действительно есть байты для чтения
        {
         EscapeCommFunction(COMport,CLRRTS);
         ReadFile(COMport, bufrd, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
         counter+=btr;                                          //увеличиваем счётчик байтов
         Synchronize(Printing);
          //вызываем функцию для вывода данных на экран и в файл
        }
       }
    }
  }
 CloseHandle(overlapped.hEvent);        //перед выходом из потока закрыть объект-событие
}


//--------------------------------------------------------------------------------------------------------------------------------
void __fastcall ReadThread::Printing()
{
// Form1->Caption=TimeToStr(Now());
 Form1->Memo1->Lines->Add((char*)bufrd); //выводим принятую строку в Memo
 Form1->StatusBar1->Panels->Items[2]->Text = "Всего принято " + IntToStr(counter) + " байт";    //выводим счётчик в строке состояния

 if(Form1->CheckBox3->Checked == true)  //если включен режим вывода в файл
  {
   write(handle, bufrd, size_send); //записать в файл данные из приёмного буфера
  }
 memset(bufrd, 0, BUFSIZE);            //очистить буфер (чтобы данные не накладывались друг на друга)
}


Все хорошо работает, просто замечательно. Но есть одно "Но": Ответ приходит через раз по частям.
То есть может быть вот так:
Ответ1: "0123456789" - правильно.
Ответ2:"0123" - не правильно.
Ответ3: "456789" - не правильно.
и т.д.

Как это исправить? В чем может быть причина в функции опроса или в функции вывода?



Автор: Dem_max 11.7.2012, 19:41
У тебя же асинхронная операция чтения данных с порта так что варианты
Ответ1: "0123456789" - правильно.
Ответ2:"0123" - правильно.
Ответ3: "456789" - правильно.

Если тебе нужно принять 10 байт, то принимай 10 байт по частям как в Ответ2 и Ответ3, а потом "склеивай" Ответ2 и Ответ3 и получишь те же 10 байт.

Автор: sawfish 12.7.2012, 07:50
А вообще, лучше уйти от асинхронного приема. 
Если ждете ответ от устройства, после передачи запроса поставьте небольшую задержку и потом читайте (в синхронном режиме) с хорошим запасом таймаута.

Автор: mishapk 12.7.2012, 09:13
Я поставил маленькую задержку перед определением количества байт в буфере, теперь все успевает полностью.
Код

 Sleep(25);
        ClearCommError(COMport, &temp, &comstat);        //нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                           //и получить из неё количество принятых байтов
        if(btr)                                  //если действительно есть байты для чтения

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)