Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> COM порт, задержки чтения, Проблема 
V
    Опции темы
TheDestroyer
Дата 6.5.2009, 11:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 5.11.2007

Репутация: нет
Всего: нет



Здравствуйте
Ситуация: 2 компьютера (master и slave), 1 микроконтроллер (МК). Все общается по COM-портам. Микроконтроллер по запросу от компьютера slave передает ему информацию.
Компьютер slave по запросу от master-а передает ему информацию. Программа на оба компьютера одна, у нее есть режим master и slave.
Обмен с микроконтроллером в режиме slave крутится в отдельном потоке. Обмен компьютеров друг с другом в режимах master и slave тоже крутится в отдельных потоках.
Следующая проблема: 
Все работает, но в какие-то моменты на master-е чтение из COM порта занимает время, больше обычного раза в два.
Замеряю время с помощью точного таймера:
Код

LARGE_INTEGER startTime, stopTime;
LARGE_INTEGER freq;
long int time;

QueryPerformanceCounter(&startTime);
// код, время выполнения которого замеряем
QueryPerformanceCounter(&stopTime);
QueryPerformanceFrequency(&freq);
__int64 d = (__int64)freq.QuadPart/1000000; // f(MHz)
time = __int64(stopTime.QuadPart - startTime.QuadPart)/d;  // t(us)


Инициализация порта:
Код

void COMOpen()
{
 String portname;  
 DCB dcb;
 COMMTIMEOUTS timeouts;

 portname = Form1->ComboBox1->Text;    

 COMport = CreateFile(portname.c_str(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
// COMport = CreateFile(portname.c_str(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);

 if(COMport == INVALID_HANDLE_VALUE)     
  {
   Form1->SpeedButton1->Down = false;     
   Form1->StatusBar1->Panels->Items[0]->Text = "Íå óäàëîñü îòêðûòü ïîðò";   
   return;
  }

 dcb.DCBlength = sizeof(DCB); 
 if(!GetCommState(COMport, &dcb))    
  {
   COMClose();
   Form1->StatusBar1->Panels->Items[0]->Text  = "Íå óäàëîñü ñ÷èòàòü DCB";
   return;
  }

 dcb.BaudRate = StrToInt(Form1->ComboBox2->Text);   
 dcb.fBinary = TRUE;                                  
 dcb.fOutxCtsFlow = FALSE;                     
 dcb.fOutxDsrFlow = FALSE;                      
 dcb.fDtrControl = DTR_CONTROL_DISABLE;    
 dcb.fDsrSensitivity = FALSE;                       
 dcb.fNull = FALSE;                                 
 dcb.fRtsControl = RTS_CONTROL_DISABLE;          
 dcb.fAbortOnError = FALSE;               
 dcb.ByteSize = 8;                         
 dcb.Parity = 0;                              
 dcb.StopBits = 0;                             
 //dcb.EvtChar = EV_TXEMPTY;

 if(!SetCommState(COMport, &dcb))    
  {
   COMClose();
   Form1->StatusBar1->Panels->Items[0]->Text  = "Íå óäàëîñü óñòàíîâèòü DCB";
   return;
  }

 timeouts.ReadIntervalTimeout = 100;    
 timeouts.ReadTotalTimeoutMultiplier = 15;    
 timeouts.ReadTotalTimeoutConstant = 100;      
 timeouts.WriteTotalTimeoutMultiplier = 15;    
 timeouts.WriteTotalTimeoutConstant = 100;        

 if(!SetCommTimeouts(COMport, &timeouts))    
  {
   COMClose();
   Form1->StatusBar1->Panels->Items[0]->Text  = "Íå óäàëîñü óñòàíîâèòü òàéì-àóòû";
   return;
  }

 SetupComm(COMport,2000,2000);
 //SetupComm(COMport,50,50);

 handle = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);

 if(handle==-1)    
  {
   Form1->StatusBar1->Panels->Items[1]->Text = "Îøèáêà îòêðûòèÿ ôàéëà";
   Form1->Label6->Hide();      
   Form1->CheckBox3->Checked = false;    
   Form1->CheckBox3->Enabled = false;
  }
 else { Form1->StatusBar1->Panels->Items[0]->Text = "Ôàéë îòêðûò óñïåøíî"; } 
 PurgeComm(COMport, PURGE_RXCLEAR);
 if (slave_mode)
 {
  Thread_sl_h = CreateThread(NULL, 0, Thread_sl, NULL, 0, NULL); // ñîçäàåì ïîòîê îáìåíà â ðåæèìå slave
  Init_slave();
 }
} // void COMOpen()


Поток чтения на master-е выглядит следующим образом:
Код

DWORD WINAPI Thread_ms(LPVOID)
{
LARGE_INTEGER startTime, stopTime;
LARGE_INTEGER freq;

 DWORD Error, bytes_read, mask, signal;
 int bytes_to_read = 0;
 overlapped.hEvent = CreateEvent(NULL, true, true, NULL);    
 SetCommMask(COMport, EV_RXCHAR); 

DWORD bytes_written;
int bytes_to_write = 0;
long int time1, time2, time3, time4;
bool info_read;

QueryPerformanceFrequency(&freq);
__int64 d = (__int64)freq.QuadPart/1000000; // f(MHz)


stopfl = false;
overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL);
bytes_to_write = Bytes_to_write_ms;
bytes_to_read = Bytes_to_read_ms;

info_read = true;


while (!stopfl)
{

 if (info_read)
{
 info_read = false;

 QueryPerformanceCounter(&startTime);
Proccess_write_ms();
 QueryPerformanceCounter(&stopTime);
 time1 = __int64(stopTime.QuadPart - startTime.QuadPart)/d;  // t(us)

QueryPerformanceCounter(&startTime);
PurgeComm(COMport, PURGE_TXCLEAR);
 QueryPerformanceCounter(&stopTime);
 time2 = __int64(stopTime.QuadPart - startTime.QuadPart)/d;  // t(us)

 QueryPerformanceCounter(&startTime);
//WriteFile(COMport, bufwrHEX, bytes_to_write, &bytes_written, NULL);  

WriteFile(COMport, bufwrHEX, bytes_to_write, &bytes_written, &overlappedwr);  
signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE);    
if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlappedwr, &bytes_written, true)))    
{
//Bytes_written += bytes_written;
}

 QueryPerformanceCounter(&stopTime);
 time3 = __int64(stopTime.QuadPart - startTime.QuadPart)/d;  // t(ìêñ)

 QueryPerformanceCounter(&startTime);
ReadFile(COMport, bufrdHEX, bytes_to_read, &bytes_read, &overlapped);
//ReadFile(COMport, bufrdHEX, bytes_to_read, &bytes_read, NULL);
Error = GetLastError();
if (Error == ERROR_IO_PENDING)
{
  GetOverlappedResult(COMport, &overlapped, &bytes_read, true);  // true - Specifies whether the function should wait for the pending overlapped operation to be completed
}
   if(bytes_read)  
   {
   info_read = true;
   QueryPerformanceCounter(&stopTime);

   time_MainThr = __int64(stopTime.QuadPart - startTime.QuadPart)/d;  // t(ìêñ)

   time4 = time1 + time2 + time3 + time_MainThr;

   Proccess_read_ms();
   } // if(bytes_read)
} // if (info_read)
} // while (!stopfl)
Thread_ms_stop();
} //  DWORD WINAPI MainThread_2(LPVOID)


Переменные time1-time4, time_MainThr использую для замера времени выполнения кусков кода.
Обычно получается time1 = 14мкс, time2 = 20мкс, time3= 1360мкс, time_MainThr = 2700мкс
Общее время time4 =4100мкс
Проблема в том, что time_MainThr примерно раз в 10 циклов = 5400мкс, а то и 8000мкс, т.е. проблема именно в том, что чтение из порта замедляется.
Пробовал не в overlapped режиме, но результат тотже.
Может замер времени происходит неправильно, а скорее замедляется чтение.
Подскажите, пожалуйста, в чем может быть проблема? 

PM MAIL   Вверх
xvr
Дата 6.5.2009, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Возможно сцепляются переданные пакеты и мастер их читает за одно чтение. Т.е. если 2 пакета будет принято зараз, то общее время как раз увеличится в 2 раза. Пакеты при приеме разделяются по timeout'у

PM MAIL   Вверх
TheDestroyer
Дата 6.5.2009, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 5.11.2007

Репутация: нет
Всего: нет



Структура обмена такая:
запрос от master, ответ от slave
Т.е. без запроса slave не пошлет информацию.
Также в функции ReadFile явно указано количество байт для чтения (19  байт), соответственно читаться в два раза больший объем не может.
Выключил в биосе компьютера функцию динамического изменения частоты, чтобы избежать проблем с подсчетом тактов процессора для таймера, всеравно проблема осталась. Соответственно замедляется чтение. Почему пока не могу понять...
PM MAIL   Вверх
xvr
Дата 6.5.2009, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Попробуй поднять приоритет нитям обмена с COM портом (можно до realtime).

PM MAIL   Вверх
J0ker
Дата 6.5.2009, 19:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: -1
Всего: 14



частота некотторых просессоров может меняться в зависимости от нагрузки
при этом даже частота ядер одного и того-же процессора и частота процессоров на многопроцессорных системах может не совпадать в конкретный момент времени


--------------------
user posted image
PM MAIL   Вверх
xvr
Дата 6.5.2009, 19:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(J0ker @ 6.5.2009,  19:39)
частота некотторых просессоров может меняться в зависимости от нагрузки

Но скорость COM порта от этого меняться не должна  smile Возможно у автора чтение висит не на самом порте, а на обработке (из за высокой скорости и маленького размера пакета). 
2 TheDestroyer - какая скорость порта? time_MainThr этой скорости соотвествует?
Еще может сыграть встроенный FIFO в порте, он как раз чуть меньше размера пакета и таймаут по его заполнению может иногда срабатывать

PM MAIL   Вверх
J0ker
Дата 6.5.2009, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: -1
Всего: 14



Цитата(xvr @  6.5.2009,  19:57 Найти цитируемый пост)
Но скорость COM порта от этого меняться не должна  

может не скорость мняется, а время некорректно вычисляется


--------------------
user posted image
PM MAIL   Вверх
GremlinProg
Дата 6.5.2009, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



TheDestroyer, пробуй использовать GetTickCount, либо вычисляй частоту (QueryPerformanceFrequency) всякий раз перед замером (перед каждым стартовым отрезком замера: startTime)
просто на разных участках обработки буферов у тебя может быть и разная производительность, а ты ее всю под одну гребенку меришь, вот и выходят такие разрывы


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
xvr
Дата 7.5.2009, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(J0ker @ 6.5.2009,  20:27)
Цитата(xvr @  6.5.2009,  19:57 Найти цитируемый пост)
Но скорость COM порта от этого меняться не должна  

может не скорость мняется, а время некорректно вычисляется

Да, это может быть.
Хотя автор писал, что 
Цитата

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

Возможно не до конца выключил, или Винда включила обратно   smile 
PM MAIL   Вверх
J0ker
Дата 7.5.2009, 09:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: -1
Всего: 14



вообще не стоит расчитывать в многозадачной системе на постоянное время - ещеж куча задач крутится
максимум что можно сделать - выставить процессу realtime приоритет - но и в этом случае есть еще системные задачи - например по обслуживанию железа


--------------------
user posted image
PM MAIL   Вверх
TheDestroyer
Дата 12.5.2009, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 5.11.2007

Репутация: нет
Всего: нет



Спасибо за советы.
Приоритеты на потоки поставил:
Код

SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
SetThreadPriority(Thread_ms_h,THREAD_PRIORITY_TIME_CRITICAL);

Проверил, выставились нормально. Спонтанные задержки в чтении пропали только после того, как на обоих (master и slave) компьютерах выставил realtime приоритет потоков. 
Интересно то, что при стандартном приоритете потока цикл while(1) {i++;} занимает ровно 50% процессорного времени (двухядерный процессор), но оба ядра загружены неравномерно, то одно больше, то другое. При наивысшем приоритете этот цикл занимает тоже ровно 50% процессорного времени, но одно ядро загружено всегда на 100%, а второе почти не грузится.

Замер времени показал, что сильная задержка возникала в 
Код

if (Error == ERROR_IO_PENDING)
{
  GetOverlappedResult(COMport, &overlapped, &bytes_read, true);  // true - Specifies whether the function should wait for the pending overlapped operation to be completed
}

т.е. шло ожидание окончания чтения.
Спасибо большое за советы, xvr и J0ker по "плюсу", но пока постов недостаточно




PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0871 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.