promelectronshchic
Feb 9 2012, 15:42
Добрый день!
Установил среду разработки Eclipce CDT. Мне необходимо создать простое приложение на С++, под Windows для работы c COM портом.
Осуществлять простые операции "открыть порт - отправить/принять данные"...
Насколько я понимаю мне необходимо подключить определенную библиотеку для работы с портами, работа ведется на ОС Windows7?
MrYuran
Feb 10 2012, 05:02
#include "windows.h"
И почитать доку на WinAPI в части fopen(), fwrite() и fread() применительно к файлу COM-порта.
Статейка была очень доходчивая, "
Работа с СОМ-портом в Windows"
Это для delphy, а та была для си, но суть-то одинаковая.
RabidRabbit
Feb 10 2012, 10:20
Цитата(MrYuran @ Feb 10 2012, 09:02)

И почитать доку на WinAPI в части fopen(), fwrite() и fread() применительно к файлу COM-порта.
Если уж винапи, тогда CreateFile(), ReadFile(), WriteFile(), SetCommState(), SetCommTimeouts()
Спасибо большое за отклик, буду пробовать.
Решил начать с простого приложения, но оказалось, что еще я не могу зайти в режим отладки.
Установил mingw-w64-bin-x86_64-20120127 , также MinGW-5.1.3 и gdb-20040521-1.
У настройках GDB debugger указал gdb, из устан. папки С:\MinGW\bin
GDB command file было .gdbinit - я так и оставил...
Больше ничего не настраивал, проект сам компилится и генерит файл .exe, но когда захожу в отладку Debug prj.exe , то пишет : "No symbol "auto" in current context" и висит ...
Что можете посоветывать?
Операционная система у меня Windows 7 64-x Ultimate.
Оказалось у меня стояла 64 разрядная версия Eclipce, но 32 разрядная версия gcc и gdb...когда я их переустановил на 64-х битные, отладчик заработал.
Но теперь возникли пару других вопросов:
1. Не обновляется .exe файл(конечный файл приложения), когда делаю "Build all" или "Build Project"...обновляется только когда запускаю "Debug" и "Run".
2.Когда я у коде пишу функцию scanf("%i",&x), то при отладке доходя до этой функции происходит висняк, внешняя консоль не появляется для ввода какого-то символа, а когда вводить символы в консоле внизу отладка "Console", то ничего не происходит(приложение висит)...не понятно.
3.Я привык работать с железом, там есть таймеры для придерживания временных интервалов в приложении, в Борланд С++ тоже есть спец. элемент - таймер, а при написании консольных приложений под ПК, какие функции используются для этого, тоже какие-то из ОС Windows ?
Кстати, по ходу открыть порт с помощью winApi получилось, пока не на чем проверить...
Цитата
а при написании консольных приложений под ПК, какие функции используются для этого, тоже какие-то из ОС Windows ?
Угу. Для начала всю работу с портом поместить в поток (_beginthread), потом в нем самом можно делать банальный Sleep()
Я просто в шоке от этого Eclipce CDT, просто жесть, при отладке иногда ругается хотя синтаксис правильный...тонкая штука...вернусь опять на Borland C++, хватит с меня...
Цитата(Twen @ Feb 13 2012, 16:06)

Я просто в шоке от этого Eclipce CDT, ...
Угу ... монстр для ленивых
AHTOXA
Feb 13 2012, 16:32
Цитата(Hmm @ Feb 13 2012, 20:38)

Угу ... монстр для ленивых

Очень точно подмечено - для ленивых он кажется монстром

А если не полениться и как следует освоить этот инструмент, то он оказывается на удивление гибким и удобным.
demiurg_spb
Feb 14 2012, 05:02
Цитата(MrYuran @ Feb 10 2012, 08:02)

#include "windows.h"
И почитать доку на WinAPI в части fopen(), fwrite() и fread() применительно к файлу COM-порта.
ИМХО нынче логичнее взять буст или кутэ там есть модули для работы с портами.
Как бонус и на линухе софтинка жить будет.
Хотел еще уточнить по поводу правильного приема данных из COM порта.
Такой вариант, что-то не совсем работает:
do {
if(i++ > 20) {
break;
}
ClearCommError(handle, &temp, &ComState);
} while (ComState.cbInQue != in_numbytes);
if((i < 20) & (!temp)) {
ReadFile(handle, buf_in, in_numbytes, &numbytes_ok, &Overlap);
А так некоректно писать :
sleep(1);
ReadFile(handle, buf_in, in_numbytes, &numbytes_ok, &Overlap);
Цитата
Хотел еще уточнить по поводу правильного приема данных из COM порта.
Запускаете отдельную нить чтения с COM порта. В ней, обычными блокирующими ReadFile'ами читаете ваш порт. Перед этим необходимо настроить timeout'ы чтения с порта, что бы ReadFile периодически выходил
А что значит запустить отдельную нить чтения...я просто с СОМ под ПК...да даже сприложениями под ПК мало работал, я обычно с железом...
Вот смотрите, я так инициализировала порт:
void ComInit(void)
{
DWORD temp;
uint16_t SizeBuffer = 1024;
COMMTIMEOUTS CommTimeOuts;
DCB dcb;
//handle = SetUpCom();
//асинхронный режим работы Com - порта
handle = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
//if(handle == INVALID_HANDLE_VALUE) Status = 1;
//else Status = 0;
SetupComm(handle, SizeBuffer, SizeBuffer);
GetCommState(handle, &dcb);//заполняем поля структуры по умолчанию
dcb.BaudRate = CBR_115200;
dcb.fBinary = TRUE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = 1;
SetCommState(handle, &dcb);
//0 - в слечае ошибки
/*
* Если интервал между двумя последовательными
* символами превысит заданное значение,
* операция чтения завершается и все данные,
* накопленные в буфере, передаются в программу.
* ReadIntervalTimeout — максимальное временной промежуток (в миллисекундах),
* допустимый между двумя считываемыми
* с коммуникационной линии последовательными
* символами.
*/
CommTimeOuts.ReadIntervalTimeout= 10;
/*
ReadTotalTimeoutMultiplier — задает множитель (в миллисекундах),
используемый для вычисления общего тайм-аута операции чтения.
Для каждой операции чтения данное значение умножается
на количество запрошенных для чтения символов.
*/
CommTimeOuts.ReadTotalTimeoutMultiplier = 1;
// значений этих тайм – аутов вполне хватает для уверенного приема
// даже на скорости 110 бод
/*
* ReadTotalTimeoutConstant — задает константу (в миллисекундах),
* используемую для вычисления общего тайм-аута операции чтения.
* Для каждой операции чтения данное значение плюсуется к
* результату умножения ReadTotalTimeoutMultiplier на количество
* запрошенных для чтения символов. Нулевое значение полей
* ReadTotalTimeoutMultiplier и ReadTotalTimeoutConstant означает,
* что общий тайм-аут для операции чтения не используется.
*/
CommTimeOuts.ReadTotalTimeoutConstant = 100;
// используется в данном случае как время ожидания посылки
/*
* WriteTotalTimeoutMultiplier — задает множитель (в миллисекундах),
* используемый для вычисления общего тайм-аута операции записи.
* Для каждой операции записи данное значение умножается
* на количество записываемых символов.
*/
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
/*
* WriteTotalTimeoutConstant — задает константу (в миллисекундах),
* используемую для вычисления общего тайм-аута операции записи.
* Для каждой операции записи данное значение прибавляется к результату умножения
* WriteTotalTimeoutMultiplier на количество записываемых символов.
* Нулевое значение полей WriteTotalTimeoutMultiplier и WriteTotalTimeoutConstant
* означает, что общий тайм-аут для операции записи не используется.
*/
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(handle, &CommTimeOuts);
/*
* После открытия порта первым делом необходимо сбросить его,
* так как в буферах приема и передачи может находиться “мусор”.
* Поэтому в конце примера мы применили ранее
* не известную нам функцию PurgeComm:
*/
PurgeComm(handle, PURGE_RXCLEAR);
PurgeComm(handle, PURGE_TXCLEAR);
ClearCommError(handle, &temp, &ComState);
if(!temp) {
printf("ok");
} else {
printf("error");
}
}
Мне нужен ком порт для работы через него по хмодему, после того как я отправляю пакет размером 128 байт, то я получаю символ С , а не AСK, прои повторных передачах тоже...не понятно, может это из-за того что я принимаю данные вот так:
sleep(1);
ReadFile(handle, buf_in, in_numbytes, &numbytes_ok, &Overlap);
Кажется что-то нашел по многопоточности
здесь. Нос потоками никогда не работал...это вроде как задачи у операционной системе?
Что должно делать ваше приложение на РС? Возможно вам и многопоточность не понадобится (и OVERLAPPED режим работы COM порта)
Я уже немного понял о многопоточности, скачал пример и переделал.
У приложении я использую 3 потока(у примере было 2: чтение и запись).
Первый - чтение;
Второй - запись;
Третий - это выполнение моей программы.
Сначала запускается поток на чтение, второй и третий потоки находятся в ожидании.
По нажатии на кнопку я делаю ResumeThread(task);
У функции я делаю запись, чтение, то есть вызываются другие потоки (происходит передача данных по xmodem) после этого вызываю suspend.
Вроде заработало вроде...
Цитата
Вроде заработало вроде...
Пока не видно где у вас что то работает одновременно. Похоже, что все потоки у вас выполняются строго последовательно. Если это так, то потоки вам вообще не нужны.
Еще раз спрашиваю - что должна делать программа?
Цитата
А если не полениться и как следует освоить этот инструмент, то он оказывается на удивление гибким и удобным.
Нет уж. Все, что мне нужно я готовлю сам.
Мне нужно реализовать протокол x-modem. Я взял модуль работы с х-модемом и добавил две функции запись и чтение, но как я писал они у меня не совсем корректно работали...я писал высшее можете ли вы подсказать как правильно считывать с порта...У протоколе нужно отправлять данные и смотреть на входные(читать и писать в порт)...
Виснет устройство, наверное неправильно делаю чтение или запись :
Sleep(100);
ClearCommError(handle, &temp, &ComState);
ReadFile(handle, buf_in, in_numbytes, &numbytes_ok, &Overlap);
Блин уже вожусь...не знаю даже...
Цитата
Мне нужно реализовать протокол x-modem.
Если вам нужен
только xmodem, то никакие потоки, OVERLAPPED чтения и пр. вам не нужны. Вам нужен банальный блокирующий ReadFile и WriteFIle и больше ничего
Я понимаю все должно быть банально, я опять вернулся к варианту программы без потоков. Смотрите объясню свою проблему детальнее.
Отправка в порт происходит нормально а вот прием...иногда принимает , иногда нет , когда я исползую REadFile,
вот смотрите:
Вот две функции чтения и записи, которые нужно реализовать:
функция вывода работает вроде нормально...
void outbyte(uint8_t value)
{
uint32_t i = 0;
DWORD temp;
buf_out[0] = value;
out_numbytes = 1;
ClearCommError(handle, &temp, &ComState);
if(!temp) {
WriteFile(handle, buf_out, out_numbytes, &numbytes_ok, &Overlap);
}
do {
if(i++ > 40) {
break;
}
ClearCommError(handle, &temp, &ComState);
for (unsigned int i = 0; i < 40; i++);
} while (ComState.cbOutQue > 0);
}
а вот функция приема иногда не принимает, хотя снифером я смотрю что данные поступают...
uint8_t inbyte(uint8_t timeout)
{
DWORD temp;
uint32_t i = 0;
uint16_t in_ok;
in_numbytes = 1; //количество ожидаемых принятых данных
do {
if(i++ > 50) {
break; //вот здесь вылетает
}
ClearCommError(handle, &temp, &ComState);//получаю состоянии порта
for (unsigned int i = 0; i < 40; i++); //задержка
} while (ComState.cbInQue != in_numbytes);
if((i < 50) & (!temp)) {
ReadFile(handle, buf_in, in_numbytes, &numbytes_ok, &Overlap);
}
}
Как корректно пользоваться функциями ReadFile, WriteFile, ClearCommError чтобы порт не выс и корректно принимал байты.
.
Уберите флаг OVERLAPPED при открытии порта. Уберите параметр &Overlap (подайте NULL) при вызове ReadFile и WriteFile.
После этого вызовы ReadFile и WriteFile будут блокироваться пока не примут/отправят заданное количество байтов, либо пока не случится таймаут, заданный при настройке открытого порта
И лучше принимать/передавать не по 1 байту за раз, а сразу несколько
Тогда получается ненужно никаких циклов ожидания...а тогда функцию ClearCommError() обязательно вызывать перед чтением или записью?
Буду пробовать, спасибо.
Цитата(Twen @ Feb 19 2012, 15:07)

Тогда получается ненужно никаких циклов ожидания...
Точно
Цитата
а тогда функцию ClearCommError() обязательно вызывать перед чтением или записью?
Нет, Ее надо звать после того, как функции Read/WriteFile вернутся с ошибкой, что бы можно было
еще раз попробовать передать/принять данные из COM порта.
XVR Спасибо большое за советы!
Все вроде бы работает, но заметил один момент...
Когда я включаю компьютер и запускаю свою программу для работы с COM-портом, то при выводе выводятся нули...снифером смотрю, ком открыт и передаются не нули, но на плату, которая подключена к ПК приходят нули, снифер показывается нормальные данные. Но когда я открываю ком-порт программкой для работы с СОМ "Hercules", потом закрываю и запускаю свою программу на ПК и данные начинают идти нормальные. То есть выходит если я один раз открою порт другой программой и закрою, то потом моя программа работает корректно...Фантастика!
Что же я упустил, может нужно еще как-то выходной драйвер кома настраивать?
Уберите вызов GetCommState и заполните явно все поля структуры dcb
Может поможет
Ок, попробую...интересно, интересно, что у функции :
ReadFile(handle, (uint8_t *)buf, numbytes, &numbytes_ok, NULL);
значение numbytes - количество ожидаемых байт не может быть больше 255, так как тип char...
мне просто нужно 256 )), приходится два раза вызывать...
Genadi Zawidowski
Feb 29 2012, 13:26
Цитата(Twen @ Feb 29 2012, 16:45)

Ок, попробую...интересно, интересно, что у функции :
ReadFile(handle, (uint8_t *)buf, numbytes, &numbytes_ok, NULL);
значение numbytes - количество ожидаемых байт не может быть больше 255, так как тип char...
мне просто нужно 256 )), приходится два раза вызывать...
где тип char? Откройте winbdows.h (или где оно там описано) и посмотрите прототип. Или любой хелп.
зы: и что вы будете делать, если данные вдруг начнуться не с границы Вашего буфера в 256 байт?
ps2: при некоторых настройках timeouts число прочитанных может быть меньше ожидаемых байт.
ps3: делать приведение типа перед присвоением к "void *" это сильно улучшает читабельность, наверное?