как считать данные с ком-порта?
вот кусок текста(почти весь)
но не могу прочитать данные записанные с ком порта(
за этапе чтения прога выснет (
на этапе записи 100% работает.
компилил на VC++2005
main()
{
char szCom[10];
memset(szCom,0,sizeof(szCom));
strcpy(szCom,"COM1");
//устанавливаем порт
hPortCom =CreateFile(szCom,GENERIC_WRITE|GENERIC_READ,0
,NULL,OPEN_EXISTING,0,NULL);
if( INVALID_HANDLE_VALUE == hPortCom ) exit(1) ;
else printf("go get\n");
//Получаем текущие установки
if ( FALSE == GetCommState(hPortCom,&dcb) )
{ CloseHandle(hPortCom);
exit(1);
}
else printf("go build\n");
//ZeroMemory(&dcb,sizeof(dcb));
_getch();
//Изменяем установки
dcb.BaudRate=CBR_9600; // скорость CBR_57600
dcb.ByteSize=8; //число бит данных
dcb.Parity=NOPARITY; // бит паритета
dcb.StopBits=1;// стоп -бит
if ( FALSE == BuildCommDCB(szCom,&dcb) )
{ CloseHandle(hPortCom);
exit(1);
}
else printf("go set\n");
//Устанавливаем новое состояние порта
if ( FALSE == SetCommState(hPortCom,&dcb) )
{ CloseHandle(hPortCom);
printError('4');// ошибка
}
else printf("go write\n");
_getch();
DWORD nb;
char Mem[20] ;
memset(Mem,'+',sizeof(Mem));
strcpy(Mem,"123456789098765432");
printf(" memory : %s\n",Mem);
if ( FALSE == WriteFile(hPortCom, Mem, sizeof(Mem), &nb, NULL))
{ CloseHandle(hPortCom);
exit(1);
}
else printf("go read_ \n");
//---2------- чтение данных из сом порта в память ---------------
char buff[19];
memset(buff,'-',sizeof(buff));
nb=0;
if ( FALSE == ReadFile(hPortCom,buff,1,&nb,NULL) )
{ CloseHandle(hPortCom);
exit(1);
}
else {
printf(" In buffer [ %s ]\n",buff);
printf("\n Close Com_Port \n ");
CloseHandle(hPortCom);// закрываем порт
}
...
}
//Ставим до первого WriteFile
COMMTIMEOUTS ct;
ct.ReadIntervalTimeout=2;//Для 9600 так - это тот зазор между байтами который можно потерпеть , если устройство может передавать не сплошным потоком а с небольшими перерывами (контроллер может какое прерывание обрабатывать), то тут надо побольше поставить
ct.ReadTotalTimeoutMultiplier=3;
ct.ReadTotalTimeoutConstant=Time_out;//Тут ставим время в мс в которое должен уложиться отвечающий прибор, скажем 10 сек будет так 10000
ct.WriteTotalTimeoutConstant=0;//Чтобы не зависла функция WriteFile
ct.WriteTotalTimeoutMultiplier=0;//если в dcb будет выставлено управление потоком (а это может быть запросто от предыдущего приложения)
SetCommTimeouts(port,&ct);//Собственно ставим тайм ауты
После этого ваша программа может упроститься:
ReadFile(hPortCom,buff,18,&nb,NULL) ;
CloseHandle(hPortCom);
и далее ваш print
Ваш кусочек зависает тут:
....
if ( FALSE == ReadFile(...
Я столкнулся с тем, что ReadFile возвращает ВСЕГДА false (уточню , что вижу это в синхронном режиме под ME). Почему, я не понимаю. Это явная лажа и похоже что тут функция не работает как описана. А на msdn уже пишут тока про 2000 XP и Vista :))))) Впрочем у меня ив описании для 98 написано что вроде должна возвращать и true и false.
Лучше всего за ReadFile следите по значению nb, если там 0 - ничего не было. И если ваш цикл организовать с контролем nb - все будет работать. Только надо будет все же время считать а то ежели ничего и не прийдет - то и так тоже зависним. Время в таком случае можно считать по GetLocalTime или просто по инкременту переменной , но тут уж получится просто для страховки а не для точного измерения тайм аута.
....
if ( FALSE == ReadFile(...
Если б тут ReadFile вернул FALSE, то программа бы закончила работу, а не зависла. Разве нет?
эх...стиль кода в этом месте мне не нравится. Я привык писать что-то типа if (!ReadFile(...
Там вроде в порядке.
Там целые дела до вызова CreateFile получаются. И все из-за того чтобы строчку "COM1" прописать в параметрах функции. Я просто в этом месте у себя делаю несколько if-ов на каждый номер порта и честно пишу в параметрах функции "COM1" и т.п. Думаю что по объему кода почти одинаково получается а приключений точно меньше.
и я бы еще в инициализацию dcb добавил бы вот такие строчки:
dcb.fNull=FALSE;//Нулевые байты не отбрасываем при передаче
dcb.fOutxCtsFlow=FALSE;//Не следим за CTS
dcb.fOutxDsrFlow=FALSE;//Не следим за DSR
dcb.fDtrControl=DTR_CONTROL_DISABLE;//Не управляем линией DTR
dcb.fDsrSensitivity=FALSE;//Не следим за DSR
dcb.fOutX=FALSE;//Не управляем потоком
dcb.fInX=FALSE;//Не управляем потоком
dcb.fRtsControl=RTS_CONTROL_DISABLE;//Не управляем линией RTS
dcb.fAbortOnError=FALSE;//Не выходим их функции при возникновении ошибки
Стал проверять своё предыдущее утверждение на опыте и обнаружил, что хоть команда printf(" In buffer [ %s ]\n",buff); выводит крокозябры из-за того что в строке buff затерт нулевой байт - к зависанию программы в большинстве случаев это не приводит.
Остается согласиться, что неправильно используется команда CreateFile. Только ошибка в установлении предпоследнего параметра. Вместо
CreateFile(szCom,GENERIC_WRITE|GENERIC_R,NULL,OPEN_EXISTING,0,NULL);
при синхронном доступе к порту надо б написать
CreateFile(szCom,GENERIC_WRITE|GENERIC_R,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
port=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
поскольку по "или" к предпоследнему аргументу ничего не пристегнуто это одинаковые записи.
port=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
поскольку по "или" к предпоследнему аргументу ничего не пристегнуто это одинаковые записи.
Не понял, при чем тут "или", но, хотя в литературе (книга П.Агурова) пишут делать как я написал, вроде можно действительно 0 поставить ибо
http://msdn2.microsoft.com/en-us/library/aa363201(VS.85).aspx
Всё. Устал я тут копать теоретически, а нужного железа под рукой нет...
FILE_ATTRIBUTE_NORMAL
128
0x80
The file does not have other attributes set. This attribute is valid only if used alone.
Почитать лучше статью Олега Титова - там все расписано про порт.
записываю в ком порт 1 символ - все нормально
а читает 0 байт (
компилю в VS2005
SetupComm(port,1024,1024);//это когда порт настраиваете
PurgeComm(port,PURGE_TXCLEAR|PURGE_RXCLEAR);//а эту всегда перед передачей
#include <iostream>
#include <conio.h>
#include <winbase.h>
#include <winError.h>
#include <string.h>
using namespace std;
HANDLE hPortCom;
DCB dcb;//структура DCB для настройки ком-порта
int main()
{ cout<<"Start work ... \n";
_getch();
//устанавливаем порт
hPortCom =CreateFile("COM1",GENERIC_WRITE|GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if( INVALID_HANDLE_VALUE == hPortCom )
{ cout<<"Error : 1\n";
_getch();
return 1;
}
else cout<<"1 get\n";
//Получаем текущие установки
if ( !GetCommState(hPortCom,&dcb) )
{ CloseHandle(hPortCom);
cout<<"Error : 2\n";
_getch();
return 2;
}
else cout<<"2 build\n";
_getch();
//Изменяем установки
dcb.DCBlength=sizeof(DCB);
dcb.BaudRate=CBR_9600;
dcb.Parity=NOPARITY;
dcb.ByteSize=8;
dcb.StopBits=ONESTOPBIT;
dcb.EvtChar=EV_RXCHAR;
dcb.fParity=true;
dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.fRtsControl=RTS_CONTROL_ENABLE;
dcb.XonChar=11;
dcb.XoffChar=13;
dcb.XonLim=0;
dcb.XoffLim=0;
dcb.fBinary=true;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SetupComm(hPortCom,1024,1024);//это когда порт настраиваете
//Устанавливаем новое состояние порта
if ( !SetCommState(hPortCom,&dcb) )
{ CloseHandle(hPortCom);
cout<<"Error : 3\n";
_getch();
return 3;// ошибка
}
else cout<<"3 write\n";
_getch();
COMMTIMEOUTS timeout;
timeout.ReadIntervalTimeout=2;
timeout.ReadTotalTimeoutConstant=1000;
timeout.ReadTotalTimeoutMultiplier=3;
timeout.WriteTotalTimeoutConstant=0;
timeout.WriteTotalTimeoutMultiplier=0;
SetCommTimeouts(hPortCom,&timeout);
DWORD wnb=0,rnb=0;
char Mem='S' ;
cout<<"4 Mem : "<<Mem<<'\n';
PurgeComm(hPortCom,PURGE_TXCLEAR|PURGE_RXCLEAR);//а эту всегда перед передачей
if ( ! WriteFile(hPortCom, &Mem, 1, &wnb, NULL))
{ CloseHandle(hPortCom);
cout<<"Error : 4\n";
_getch();
return 4;// ошибка записи!
}
else cout<<"5 read port \n";
PurgeComm(hPortCom,PURGE_TXCLEAR|PURGE_RXCLEAR);//а эту всегда перед передачей
char Buff='_';
if ( ! ReadFile(hPortCom,&Buff,18,&rnb,NULL))
{ CloseHandle(hPortCom);
cout<<"Error : 5\n";
_getch();
return 5;// ошибка чтения!
}
else {
cout<<"6 Buff : "<<Buff<<" bate= "<<rnb<<'\n';
cout<<"7 Close Com_Port \n ";
_getch();
CloseHandle(hPortCom);// закрываем порт
}
_getch();
return 0;
}
вот что написал но все равно не работает (
- эту строчку перед передачей а не перед приемом!!!
И отключить на всякий случай управление потоком которое в dcb включено:
dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.fRtsControl=RTS_CONTROL_ENABLE;
в заремаренном правильно было.
Удачи!
Вот чтобы правильно ее использовать напишу уточнение:
В синхронном режиме , когда мы в нее попадаем , то если нет ничего принятого , мы остаемся в этой функции до исчерпания времени timeout.ReadTotalTimeoutConstant
Дальше рассматриваем условия исходя из того что время timeout.ReadTotalTimeoutConstant еще не вышло:
Если пришел хотя бы один символ, то начинается счет времени между каждыми символами. Если с момента прихода очередного символа прошло времени более чем timeout.ReadIntervalTimeout, мы выходим из функции.
Если с начала появления первого символа прошло время более чем timeout.ReadTotalTimeoutMultiplier*(число запрошенных на прием символов ) или общее число пришедших символов превышает запрошенное для приема - выходим из функции.
Поэтому вокруг самой функции ничего лепить не надо - просто задав все времена аккуратно, мы практически весь прием организуем одной строчкой!
Если очень хочется не использовать такую организацию функции (она ориентирована на запрос-ответ) ,а хочется честный терминал сделать который бы все время бы показывал что в порту твориться, то эту функцию действительно можно зациклись с if , но смотреть приэтом число принятых символов. Как не ноль - читаем и добавляем в конец специально организованного массива (или строки , это как удобнее оперировать)Добавили - и опять крутимся дальше, при этом уже не надо буфер чистить . Если ноль - ничего не делаем - продолжаем крутиться.
Можете дать ссылку на источник информации о том, что ReadFile всегда возвращает false? Или это утверждение основывается на личном неудачном опыте?
Тут прежде чем копать дальше, требуется уточнить с чем работает программа. Она может работать с:
1. Другим компьютером, где работает аналогичная программа.
2. Прибором, в котором записано ПО, которого мы не знаем.
3. Работа производится с дуплексным портом (например, RS-232, т.е. стандартным COM-портом) на который установлена закоротка с выхода на вход.
В последнем случае, можно для начала перестать колдовать с настройками и использовать только CreateFile, WriteFile, ReadFile. При этом в диспетчере устройств лучше убрать всякий аппаратный контроль.
Да, мне ни разу не удалось получить от ReadFile true. Осторожно уточню что в синхронном режиме. И это, кстатит, не единственный фокус в работе функции.
Если удалось получить true, напишите в каких условиях.
В последнем случае, можно для начала перестать колдовать с настройками и использовать только CreateFile, WriteFile, ReadFile. При этом в диспетчере устройств лучше убрать всякий аппаратный контроль.
Абсолютно согласен - все лишнее убрать надо и добиться работы.
Если удалось получить true, напишите в каких условиях.
Я свою программу делал не для консоли. Но если написать для для консоли, то наверно будет что-то типа того (не проверял, так как нет нужного железа):
DWORD codeError;
BYTE B = 0;
DWORD realRead;
while(B == 0)
{
ClearCommError(comHandle, &codeError, &comStat);
if (comStat.cbInQue) // есть полученные,
// но не прочитанные данные
{
if (ReadFile(comHandle, &B, 1, &realRead, NULL))
{
cout << "ReadFile return true" << endl;
}
else
{
cout << "ReadFile return false" << endl;
}
cout << "codeError: " << codeError << endl;
break;
}
cout << "Data not received" << endl;
Sleep(1000);
}
я старую сом-мышь (рабочию) подключаю.но ничего не работает - на чтение виснет.
может закоротку между выводами передачи и приема сделать ?
весь код
компилю в VS2005
#include <iostream>
#include <conio.h>
#include <string.h>
using namespace std;
HANDLE port;
DCB dcb={0};//структура DCB для настройки ком-порта
int main()
{ cout<<"Start work ... \n";
_getch();
cout<<" go!\n ";
DCB *dcb;
COMMTIMEOUTS ct;
HANDLE port;
DWORD bc=0, mask;
char buf_out[50]="_Test_string";
char buf_in[50]="\0" ;
//с помощью функции HeapAlloc, выделяется и заполняется нулями область памяти для DCB
dcb=(DCB*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DCB));
dcb->DCBlength=sizeof(DCB);
BuildCommDCB("baud=9600 parity=N data=8 stop=1",dcb);
dcb->fNull=TRUE;
ct.ReadIntervalTimeout=10;
ct.ReadTotalTimeoutMultiplier=ct.ReadTotalTimeoutConstant=0;
ct.WriteTotalTimeoutMultiplier=ct.WriteTotalTimeoutConstant=0;
port=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
SetCommState(port,dcb);
SetCommTimeouts(port,&ct);
PurgeComm(port,PURGE_TXCLEAR|PURGE_RXCLEAR);
SetupComm(port,256,256);
WriteFile(port,buf_out,(DWORD)strlen(buf_out),&bc,NULL);
ReadFile(port,buf_in,(DWORD)strlen(buf_out),&bc,NULL);
cout<<"buf_in="<<buf_in<<"\nbuf_out="<<buf_out<<"\n "<<bc<<'\n';
HeapFree(GetProcessHeap(),0,buf_in);
HeapFree(GetProcessHeap(),0,dcb);//освобождение памяти из кучи
CloseHandle(port);
cout<<"end work.\n";
_getch();
return 0;
}
1. Вы не знаете, какое ПО зашито в мышь и на какой сигнал она должна ответить.
2. Скорее всего Windows сам захочет поуправлять мышью и не даст это делать вашей программе (хотя тут лучше уточнить у более опытных форумчан).
3. Насколько я помню, мышь типа Microsoft Mouse (и скорее всего других типов тоже) обменивается со скоростью 1200 бит/с. И это только один параметр, который не совпадает с вашими настройками.
Это было бы правильно для начала, но тут надо подходить с умом. В сравнительно новых компах наверно есть защита от коротких замыканих, но лучше сто раз подумать. Естественно, паять провод прямо к компу не следует - надо купить в магазине электроники разъем DB9 (мама, если не ошибаюсь) и паяться к нему.
Если хотитите с мышью работать как с источником смгналов то она должна быть воткнута в порт только после старта операционной системы. При этом на нее должны быть правильно поданы напряжения питания.
А по хорошему если хотите разбираться с портом то подключите терминальную программу с другой стороны.
Как начальный шаг действительно можно 23 контакты перемкнуть. Но если начинаете с портом работать - работайте серьезно.
Я со многими программистами работал которые брались за общение с устройствами и как только начинают без паяльника и осциллографа работать - бесполезная трата времени - фигня получается. Поэтому все в чем есть обмен - только сам пишу.