Всем доброго времени суток,
Возникла следующая проблема:
Есть класс, в нем такие функции для работы с COM портом:
int SerialPort::ReadData(unsigned char *buffer, const int buffer_size) // reads from port into buffer amount of bytes specified //by buffer_size
{
if(idCom == 0) return -1; //port is not openedunsigned long nbread;
Sleep(100); // wait to meet COM port requirementsif(!ReadFile(idCom, buffer, COMMAND_LENGTH, &nbread, NULL)) return -2; //if were errors during readingif(nbread != COMMAND_LENGTH) return -3; //if wrong amount of bytes was readreturn 0;
}
int SerialPort::WriteData(unsigned char *buffer, const int buffer_size) // writes into port from buffer amount of bytes specified by buffer_size
{
if(idCom == 0) return -1; //port not openedunsigned long nbread;
Sleep(100); // wait to meet COM port requirements
PurgeComm(idCom,PURGE_TXCLEAR); // clear output buffer
// serial poolingif(!WriteFile(idCom, buffer, buffer_size, &nbread, NULL)) return -1;
PurgeComm(idCom,PURGE_RXCLEAR); // clear input bufferreturn 0;
}
Отсылаются данные по 4 байта через COM порт на другой компютер
Прога на другом компьютере принимает данные и их же возвращает назад. Прога иденитчная отпраляющей, за исключением того, что первая сначала пишет, потом читает, а вторая наоборот
Все это запускаю в цикле (на двух компах, соединенных через COM-порт — на одном — write\read, на другом -наоборот)
Цикл примерно такой :
int SerialPort::OpenPort(unsigned port)// Opens COM port with number "port"
{
char pcPort [5];
sprintf(pcPort,"%s%i","COM",port);
idCom = CreateFile(pcPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(idCom == INVALID_HANDLE_VALUE) return -1; // if cannot open COM portif(!SetupComm(idCom, 4096, 4096)) return -3; // if cannot set port parameters if(!GetCommState(idCom, &dcb)) return -3; // loading "dcb" by default values
dcb.ByteSize = 8;
dcb.BaudRate = 115200;
// dcb.BaudRate = 1200;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
if(!SetCommState(idCom, &dcb)) return -3; // if cannot set port parameters if(!GetCommState(idCom, &dcb)) return -3; // if cannot set port parameters if(!PurgeComm(idCom,PURGE_RXCLEAR)) return -3; // clear input bufferif(!PurgeComm(idCom,PURGE_TXCLEAR)) return -3; // clear output bufferreturn 0;
}
При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано?
Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально
12.11.04 05:06: Перенесено модератором из 'C/C++' — Павел Кузнецов
Здравствуйте, Alexei_z_, Вы писали:
A__>Функция открытия порта: A__>
A__>int SerialPort::OpenPort(unsigned port)// Opens COM port with number "port"
A__> {
A__> char pcPort [5];
A__> sprintf(pcPort,"%s%i","COM",port);
A__> idCom = CreateFile(pcPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
A__> if(idCom == INVALID_HANDLE_VALUE) return -1; // if cannot open COM port
A__> if(!SetupComm(idCom, 4096, 4096)) return -3; // if cannot set port parameters
A__> if(!GetCommState(idCom, &dcb)) return -3; // loading "dcb" by default values
A__> dcb.ByteSize = 8;
A__> dcb.BaudRate = 115200;
A__>// dcb.BaudRate = 1200;
A__> dcb.Parity = NOPARITY;
A__> dcb.StopBits = ONESTOPBIT;
A__> dcb.fDtrControl = DTR_CONTROL_DISABLE;
A__> if(!SetCommState(idCom, &dcb)) return -3; // if cannot set port parameters
A__> if(!GetCommState(idCom, &dcb)) return -3; // if cannot set port parameters
A__> if(!PurgeComm(idCom,PURGE_RXCLEAR)) return -3; // clear input buffer
A__> if(!PurgeComm(idCom,PURGE_TXCLEAR)) return -3; // clear output buffer
A__> return 0;
A__>}
A__>
A__>При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано? A__>Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально
Определи для порта таймауты.
SetCommTimeouts
Событиями ты не пользуешся, а драйвер должен знать по истечению какого времени
передачу или прием можно считать закончеными.
ЗЫ: похоже что функция чтения возвращается раньше чем получен весь пакет.
Здравствуйте, sva1509, Вы писали:
S>Определи для порта таймауты. S>SetCommTimeouts S>Событиями ты не пользуешся, а драйвер должен знать по истечению какого времени S>передачу или прием можно считать закончеными.
S>ЗЫ: похоже что функция чтения возвращается раньше чем получен весь пакет.
S>С уважением Валерий.
Скорее всего таймауты выставлены по умолчанию, а по умолчанию они очень большие,(на мой взгляд самые оптимальные написаны в примере к MSDN).
А ошибки возникают из — за высокой скорости передачи данных(у меня например были ошибки на такой скорости каждые 40000 байт и даже чаще). Пусть обмен происходит на 48000 бод.
Здравствуйте, sva1509, Вы писали:
S>Здравствуйте, Alexei_z_, Вы писали:
A__>>Функция открытия порта: A__>>
A__>>int SerialPort::OpenPort(unsigned port)// Opens COM port with number "port"
A__>> {
A__>> char pcPort [5];
A__>> sprintf(pcPort,"%s%i","COM",port);
A__>> idCom = CreateFile(pcPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
A__>> if(idCom == INVALID_HANDLE_VALUE) return -1; // if cannot open COM port
A__>> if(!SetupComm(idCom, 4096, 4096)) return -3; // if cannot set port parameters
A__>> if(!GetCommState(idCom, &dcb)) return -3; // loading "dcb" by default values
A__>> dcb.ByteSize = 8;
A__>> dcb.BaudRate = 115200;
A__>>// dcb.BaudRate = 1200;
A__>> dcb.Parity = NOPARITY;
A__>> dcb.StopBits = ONESTOPBIT;
A__>> dcb.fDtrControl = DTR_CONTROL_DISABLE;
A__>> if(!SetCommState(idCom, &dcb)) return -3; // if cannot set port parameters
A__>> if(!GetCommState(idCom, &dcb)) return -3; // if cannot set port parameters
A__>> if(!PurgeComm(idCom,PURGE_RXCLEAR)) return -3; // clear input buffer
A__>> if(!PurgeComm(idCom,PURGE_TXCLEAR)) return -3; // clear output buffer
A__>> return 0;
A__>>}
A__>>
A__>>При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано? A__>>Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально
S>Определи для порта таймауты. S>SetCommTimeouts S>Событиями ты не пользуешся, а драйвер должен знать по истечению какого времени S>передачу или прием можно считать закончеными.
S>ЗЫ: похоже что функция чтения возвращается раньше чем получен весь пакет.
S>С уважением Валерий.
Я устанавливаю параметры на чтение:
int SerialPort::SetReadTimeOut(unsigned long wait_time)//sets maximal time of waiting response from the board
{
if(!GetCommTimeouts(idCom, &timeouts)) return -3; // loading "timeouts" by default values
timeouts.ReadTotalTimeoutConstant = wait_time;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
if(!SetCommTimeouts(idCom, &timeouts))return -3; //setting new timeout valuereturn 0;
}
Потом
p_SerialPort->SetReadTimeOut(5000)
На запись — должны же быть какие-то по умолчанию?
По поводу событий — я использую синхронные версии функций (overlapped 0) — они должны возвращать управление после того как закончат запис в буффер?
Потом, у меня есть предопределенное число байтов, которые нужно считать
Если количество считанных и ожидаемых несовпадает — возвращается ошибка
Такое бывает, но очень редко
Здравствуйте, ArtSh, Вы писали:
AS>Здравствуйте, sva1509, Вы писали:
S>>Определи для порта таймауты. S>>SetCommTimeouts S>>Событиями ты не пользуешся, а драйвер должен знать по истечению какого времени S>>передачу или прием можно считать закончеными.
S>>ЗЫ: похоже что функция чтения возвращается раньше чем получен весь пакет.
S>>С уважением Валерий.
AS>Скорее всего таймауты выставлены по умолчанию, а по умолчанию они очень большие,(на мой взгляд самые оптимальные написаны в примере к MSDN). AS>А ошибки возникают из — за высокой скорости передачи данных(у меня например были ошибки на такой скорости каждые 40000 байт и даже чаще). Пусть обмен происходит на 48000 бод.
Мы менянли скорость на 1200 — не помогло, при этой скорсти почему-то первые байты всегда были искажены
A__>При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано? A__>Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально
Видимо потому что вы использует кабель в котором всего три провода — чтение,запись,общий и не используется
протокол синхронизации XON/XOFF.
На высоких скоростях надо использовать полный кабель с разведенными CTS/DSR/RTS/DTR etc и включить
аппаратную синхронизацию DTR_CONTROL_HANDSHAKE и RTS_CONTROL_HANDSHAKE.
Кстати это все равно не дает гарантии 100% достоверности передаваемых данных — так как
проверка ошибок выполняется с помощью бита четности. Если необходимо обеспечить
100% гарантию — надо реализовывать свой протокол.
Здравствуйте, maq, Вы писали:
A__>>При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано? A__>>Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально
maq>Видимо потому что вы использует кабель в котором всего три провода — чтение,запись,общий и не используется maq>протокол синхронизации XON/XOFF. maq>На высоких скоростях надо использовать полный кабель с разведенными CTS/DSR/RTS/DTR etc и включить maq>аппаратную синхронизацию DTR_CONTROL_HANDSHAKE и RTS_CONTROL_HANDSHAKE.
maq>Кстати это все равно не дает гарантии 100% достоверности передаваемых данных — так как maq>проверка ошибок выполняется с помощью бита четности. Если необходимо обеспечить maq>100% гарантию —
Согласен, всё правда
maq>надо реализовывать свой протокол.
А что HDLC/PPP уже отменили? ИМХО единственный реальный способ собрать на СОМ линии помехоустойчивый поток.
Здравствуйте, Protey, Вы писали:
P>Здравствуйте, maq, Вы писали:
A__>>>При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано? A__>>>Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально
maq>>Видимо потому что вы использует кабель в котором всего три провода — чтение,запись,общий и не используется maq>>протокол синхронизации XON/XOFF. maq>>На высоких скоростях надо использовать полный кабель с разведенными CTS/DSR/RTS/DTR etc и включить maq>>аппаратную синхронизацию DTR_CONTROL_HANDSHAKE и RTS_CONTROL_HANDSHAKE.
maq>>Кстати это все равно не дает гарантии 100% достоверности передаваемых данных — так как maq>>проверка ошибок выполняется с помощью бита четности. Если необходимо обеспечить maq>>100% гарантию —
P>Согласен, всё правда
maq>>надо реализовывать свой протокол.
P>А что HDLC/PPP уже отменили? ИМХО единственный реальный способ собрать на СОМ линии помехоустойчивый поток.
А можно подробнее про последнее? HDLC/PPP и XON/XOFF?
А то все мои знания на эту тему уместятся в два предложения
Или где почитать?
P>А что HDLC/PPP уже отменили? ИМХО единственный реальный способ собрать на СОМ линии помехоустойчивый поток.
В общем конечно да, но это если обе стороны ее поддерживают.
А вот если одной из сторон является некое примитивное устройство, зачастую
самодельное — придется писать какой нибудь протокол самому.
Здравствуйте, Alexei_z_, Вы писали:
A__>Всем доброго времени суток, A__>Возникла следующая проблема: A__>Есть класс, в нем такие функции для работы с COM портом:
случаем buffer на реад и врайт — не один и тот же?
попробуй в кретические секции запихнуть реад и врайт... слип бы я вообще убрал...
Асинхронные линии связи — такие линии связи, в которых потоки данных от устройстав и к устройству в общем случае не зависят друг от друга, либо зависят слабо. Т.е. устройство в любой момент времени может передать пакет байт, либо принять.
Проблемы.
Проблема только одна — нет линий связи с целостностью передаваемой информации = 100%. Отчего, при потере первого байта в пакете, например, случается искажение необходимой информации. Это не есть гут.
Решение.
Оччень простое, в начале пакета передаём некий байт — флаг, далее данные, потом чек-сумму пакета, закрывающий флаг.
Теперь при поере любого байта будет потерян только лишь один пакет, не повлияв на остальные.
Практически имеется много протоколов, наиболее часто используемый — PPP/HDLC.
Читать RFC 1661, 1662. Поле прочтения никто не заставляет писать ВЕСЬ РРР протокол, для прОстых устройств достаточно иплементировать HDLC.
Здравствуйте, Alexei_z_, Вы писали:
A__>При приеме данных переодически возникает искажение данных, иногда потеря. C чем это связано? A__>Если соеденить контакты скрепкой, писать и читать одной программой — все работает идеально