Форум: "Начинающим";
Текущий архив: 2010.09.19;
Скачать: [xml.tar.bz2];
Внизсбои в асинхронном приеме с сом порта Найти похожие ветки
← →
Who_is_you? © (2010-06-22 12:48) [0]Посылаю устройству команду прислать данные в комп. Смотрю: светодиод мигает, что данные идут.
Но данные то читаются, то нечитаются. Такое ощущение, что проблема во временах и реакции на событие.
Вот настройки порта и программа чтения:
procedure TForm1.SetupOpenPort(Sender: TObject); //Setup & open порт
Var
TimeOuts : TCommTimeouts; // таймауты порта
begin
ComX:= PChar("COM" + IntToStr(NumCom));
//создание порта и получение его хэндла в асинхронном режиме
hCom:=CreateFile(PChar("\\.\COM" + IntToStr(NumCom)),Generic_Read or GENERIC_WRITE,0,nil,Open_Existing,
File_Attribute_normal or FILE_FLAG_OVERLAPPED,0);
if hCom=Invalid_handle_Value then
begin
ShowMessage("Не могу открыть порт. Задайте параметры порта.");
CloseHandle(hCom); //закрытие порта
end;
PurgeComm(hCom,PURGE_TXABORT or PURGE_RXABORT or
PURGE_TXCLEAR or PURGE_RXCLEAR);
//устанавливаем маску эвентов (фактически маску прерываний)
//в данном случае будем иметь возникновение эвентов по принятию
//хотя бы одного байта и возможности записи в порт еще байт(ов)
if not (SetCommMask(hCom,EV_RXCHAR or EV_DSR or EV_CTS)
//устанавливаем размер внутренних буферов приема-передачи в драйвере порта
and SetupComm(hCom,256,256)
// SetupComm(hCom,BufSize_rd,BufSize_rd);
//получаем текущее DCB порта
//построение DCB и иницализация порта
//что бы не заполнять всю структуру самим,
// сначалf считываем ее, потом поменяем нужные поля
and GetCommState(hCom,DCB)
)
then begin
CloseHandle(hCom);
ShowMessage("Порт не настроен");
Exit;
end;
with DCB do
begin
BaudRate:=9600;
ByteSize:=8;
Parity:=NoParity;
StopBits:=OneStopBit;
end;
if not SetCommState(hCom,DCB) then //устанавливаем DCB
begin
CloseHandle(hCom);
ShowMessage("Порт не настроен");
end;
//получаем текущие параметры таймаутов
GetCommTimeouts(hCom,TimeOuts);
//настраиваем текущие параметры таймаутов таким образом,
//чтобы ReadFile и WriteFile возвращали значения немедленно
TimeOuts.ReadIntervalTimeout := MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier := 0;
TimeOuts.ReadTotalTimeoutConstant := 0;
TimeOuts.WriteTotalTimeoutMultiplier := 0;
TimeOuts.WriteTotalTimeoutConstant := 0;
//выполняем настройку порта с новыми таймаутами
if not SetCommTimeouts(hCom,TimeOuts) then
begin
CloseHandle(hCom);
ShowMessage("Tаймауты порта не настроены.");
Exit;
end;
//опускаем флаг завершения дочернего потока
CloseReadComm := False;
end;
procedure ReadComm;
var
i :byte;
Trans, ModemState : DWord;
begin
i_wr:= 0;
//выполняем инициализацию структуры для асинхронного режима
FillChar(Ovr,SizeOf(TOverlapped),0);
Ovr.hEvent := CreateEvent(nil,TRUE,FALSE,#0);
while not CloseReadComm do
begin
for i:=1 to BufSize_Data_rd do Data_rd[i]:=0; // ??
//**
Mask := 0;
if not WaitCommEvent(hCom,Mask,@Ovr) then //ждем
begin
if ERROR_IO_PENDING = GetLastError() then
begin
//это случай, когда ожидание переводится в фоновый режим
//и для получения маски эвентов нужно дождаться
//выставления эвента Ovr.hEvent в сигнальное состояние
//и вызвать GetOverlappedResult
if WaitForSingleObject(Ovr.hEvent,INFINITE)= WAIT_OBJECT_0 then
GetOverlappedResult(hCom,Ovr,Trans,False);
end;
end;
if CloseReadComm then break;
if (Mask and EV_RXCHAR)=EV_RXCHAR then //проверяем нужное событие
begin
FlagRead:=true; //Прием данных
ClearCommError(hCom,Errs,@Stat);//сбрасываем флаг, читаем Stat
byteRead := Stat.cbInQue;
ReadFile(hCom,Data_rd,byteRead,byteRead,@Ovr);//читаем
// обработка принятой информации из Data_rd
if byteRead > BufSize_Data_rd then
byteRead:=BufSize_Data_rd;
for i:=1 to byteRead do
begin
i_wr := i_wr+1;
Data_wr[i_wr]:=Data_rd[i];
end;
if (i_wr=i_wrEND) or (i_wr>i_wrEND) then //??
begin
i:=3;
while i<i_wrEND do //меняем байт в файле данных старший на младший
begin
noChet:=Data_wr[i];
Chet :=Data_wr[i+1];
Data_wr[i]:=Chet;
Data_wr[i+1]:=noChet;
inc(i,2);
end;
FlagReadData:=true; //пришли данные
FlagRead:=false; //Завершился прием данных
byte_wr:= BufSize_wr;
ErrChannel :=1; // "0" - ошибка № канала
WriteFile(hOutFile,ErrChannel,1,Shapka_byte,nil);
WriteFile(hOutFile,Data_wr,i_wrEND,byte_wr,nil);
FlushFileBuffers(hOutFile);
i_wr:= 0;
end;
if CloseReadComm then break;
end;//mask
//получаем состояние модемных линий
// GetCommModemStatus(cId,ModemState);
// if then EscapeCommFunction(cId, SETRTS)
// else EscapeCommFunction(cId, CLRRTS);
//проверяем маску эвентов на эвент изменения модемных линий
if ((Mask and EV_DSR) = EV_DSR) or
((Mask and EV_CTS) = EV_CTS) then
begin
if CloseReadComm then break;
//получаем состояние модемных линий
GetCommModemStatus(hCom,ModemState);
//запоминаем состояние модемных линий
State_DSR_ON := (ModemState and MS_DSR_ON)= MS_DSR_ON;
State_CTS_ON := (ModemState and MS_CTS_ON)= MS_CTS_ON;
end; //end состояние модемных линий
end;//while
end;
← →
RWolf © (2010-06-22 13:15) [1]а обязательно использовать Overlapped-режим? это нужно только, если пишем в файл из двух и более потоков.
← →
Who_is_you? © (2010-06-22 14:53) [2]Ранее работал в синхронном режиме с СОМ портом, но тоже были подобные проблемы в ХР.
Сейчас перешел на асинхронный, а он задается через FILE_FLAG_OVERLAPPED.
Насколько я понимаю синхронный всегда в ожидании,
а асинхронный по приходу события: потому меньше загружает комп.
← →
Вариант (2010-06-22 14:54) [3]
> Who_is_you? © (22.06.10 12:48)
Проблемный код, слишком много разной по функциональности логики в одной процедуре ReadComm. Удобней было бы разбить на разные функции, читать тяжело.
Почти нигде нет анализа возврата функций на возвращаемое значение (не предусматривается возможность возврата ошибки)
КРоме того есть вопрос к тому что я заметил:Ovr.hEvent := CreateEvent(nil,TRUE,FALSE,#0);
-что бы создать неименованный Event, надо передать nil, а не #0 Не знаю как это будет ли это валидным именем в NT подобных системах, поэтому если и ты не знаешь, то думаю следует заменить. Далее
> if WaitForSingleObject(Ovr.hEvent,INFINITE)= WAIT_OBJECT_0
> then
> GetOverlappedResult(hCom,Ovr,Trans,False);
А если не равно WAIT_OBJECT_0....??? То все равно продолжим выполнение кода без GetOverlappedResult.ClearCommError(hCom,Errs,@Stat);//сбрасываем флаг, читаем Stat
byteRead := Stat.cbInQue;
ReadFile(hCom,Data_rd,byteRead,byteRead,@Ovr);//читаем
Какое значение вернули функции мы не знаем. И хотя скорее всего true для ClearCommError, и хотя скорее всего ReadFile вернет true, так как читаем уже то, что есть в буфере - но дать 100 % за это я не могу. А потому следовало бы делать проверку.if byteRead > BufSize_Data_rd then
byteRead:=BufSize_Data_rd;
Не знаю бывает ли у тебя ситуация, когда число пришедших из порта байт больше буфера.... но если да, ты просто взял и выкинул часть данных.... Насколько это верно?
Да и вызывают сомнение переменные типаFlagReadData:=true; //пришли данные
Где они потом используются и как? Это сигнализация в другой поток? Если да, то как там эта переменная используется, если она там пишется - то это уже не правильно....
← →
RWolf © (2010-06-22 14:58) [4]
> синхронный всегда в ожидании,а асинхронный по приходу события:
> потому меньше загружает комп.
синхронный ReadFile всегда в ожидании, именно поэтому он не загружает процессор вовсе.
← →
Вариант (2010-06-22 15:14) [5]
> RWolf © (22.06.10 14:58) [4]
В синхронном режиме WaitCommEvent проблемный вызов из-за возможностью долго висеть.... и так и не отвиснуть. Его можно не использовать конечно, но overlapped режим все же удобнее(гибче) для COM порта когда надо действительно отслеживать несколько типов событий, и конечно когда правильно им пользуешься, .
← →
RWolf © (2010-06-22 15:21) [6]
> Вариант (22.06.10 15:14) [5]
> синхронном режиме WaitCommEvent
> проблемный вызов из-за возможностью долго висеть.... и так
> и не отвиснуть.
Чтобы WaitCommEvent завершился с кодом ошибки, достаточно закрыть переданный ему хэндл в любом из работающих потоков.
← →
Вариант (2010-06-22 15:24) [7]
> RWolf © (22.06.10 15:21) [6]
ПРобовал?
← →
RWolf © (2010-06-22 15:51) [8]
> Вариант (22.06.10 15:24) [7]
Попробовал — не работает, и даже вешает весь процесс. Увы мне.
Нелогично, конечно — из ReadFile/WriteFile выкидывает, а из WaitCommEvent — нет.
← →
tesseract © (2010-06-22 15:51) [9]
> ПРобовал?
Да. Возвращает ошибку типа "операция прервана".
← →
Вариант (2010-06-22 15:54) [10]
> RWolf © (22.06.10 15:51) [8]
Увы это так, в свое время что только не пробовал, и маску менять ... но это такой неприятный факт для NT систем,для 95 и 98 уже не помню как
> tesseract © (22.06.10 15:51) [9]
В синхронном режиме WaitCommEvent ?
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.09.19;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.004 c