|
#1
|
|||
|
|||
Не работает поток
Доброго времени суток. Помогите пожалуйста разобраться с потоком, сталкиваюсь с этим впервые. Дело в том, что первый пакет данных проходит успешно, маркер определяется, получаю пакет, а затем поток как-то зависает и программа перестает получать данные с ком порта. Если я прохожу по циклу в режиме откладки, то все работает на ура.....
Код:
unit ReadPort; interface uses Classes,Windows, Messages, SysUtils, Variants, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls; type RdThread = class(TThread) Private Protected Procedure Execute; override; // Procedure UpdateGenFormnReadLabel; End; var RC: array [1..38]of byte; i2:integer; implementation uses Gen; Var RCBuffer:Array of Byte; nToRead:Cardinal; nRead:Cardinal; ComStat:TcomStat; Errs:Cardinal; RdOvr:TOverlapped; Mask:DWord; Procedure RDthread.Execute; var i:integer; Begin i2:=0; FillChar(RdOvr,SizeOf(TOverlapped),0); RdOvr.hEvent:=CreateEvent(nil, true, false, nil ); SetCommMask(Port, EV_RXFLAG); while not Terminated Do Begin WaitCommEvent(Port, mask, @rdOvr ); FreeMem(RCBuffer,nToRead); WaitForSingleObject(RdOvr.hEvent,INFINITE); GetOverlappedResult(Port,RdOvr,nRead,false); ClearCommError(Port,Errs,@ComStat); nToRead:=ComStat.cbInQue; GetMem(RcBuffer,nToRead); If not ReadFile(Port,RCBuffer[0],nToRead,nRead,@RdOvr) Then Else If nToRead = 8 Then Begin For i:=0 to nToRead-1 do Begin i2:=i2+1; RC[i2]:=RCBuffer[i]; end; end Else Begin If nToRead = 31 Then Begin i2:=8; For i:=0 to nToRead-1 do Begin i2:=i2+1; RC[i2]:=RCBuffer[i]; Gen.GenForm.Label4.Caption:=IntToStr(i2); end; Begin i2:=0; Gen.PortDataRecived; End; End; end; i2:=0; End; End; Код не доработан в плане обработки пакета т.к. Нет стабильного приема. Последний раз редактировалось M.A.D.M.A.N., 12.02.2013 в 08:13. |
#2
|
||||
|
||||
На первый вгляд, а есть увененность, что RXFlag выставляется, сделай CHAR для проверки, посмотри будут ли данные приходить.
Ну и обращения к VCL компонентам из кода потока убери. Нельзя так делать. Некоторые программисты настолько ленивы, что сразу пишут рабочий код. Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты. Последний раз редактировалось Aristarh Dark, 12.02.2013 в 08:28. |
#3
|
|||
|
|||
Прошу прощения за некорректное оформление кода. С телефона сижу)))
Данные приходят, флаг вроде отрабатывает. Попробую реализовать совет. Как сделаю, отпишусь Попсавил rxchar, как советовали. Все приходит, изменений нет. Я только не понял про VCL. Что не так? MAD: Вам что, в прикол постить по 10 сообщений подряд? Последний раз редактировалось M.A.D.M.A.N., 13.02.2013 в 08:38. Причина: Объединил сообщения |
#4
|
||||
|
||||
Подобные вызовы:
Код:
Gen.GenForm.Label4.Caption:=IntToStr(i2); Некоторые программисты настолько ленивы, что сразу пишут рабочий код. Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты. |
#5
|
|||
|
|||
А как передать данные из потока? Поток в отдельном юните реализован
|
#6
|
||||
|
||||
Если быть внимательным, то при создании юнита для потока там была написана вот такая интересная информация:
Код:
{ Important: Methods and properties of objects in visual components can only be used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure qwdqwd.UpdateCaption; begin Form1.Caption := 'Updated in a thread'; end; or Synchronize( procedure begin Form1.Caption := 'Updated in thread via an anonymous method' end ) ); where an anonymous method is passed. Similarly, the developer can call the Queue method with similar parameters as above, instead passing another TThread class as the first parameter, putting the calling thread in a queue with the other thread. } Некоторые программисты настолько ленивы, что сразу пишут рабочий код. Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты. |
#7
|
|||
|
|||
Возможно из-за этого цикл не мог завершится и зависал?
|
#8
|
||||
|
||||
Не исключено, там поведение вообще неожыданное может быть.
Некоторые программисты настолько ленивы, что сразу пишут рабочий код. Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты. |
#9
|
|||
|
|||
А вот переменная nToRead каким образом получает значения? И можно как-то задать постоянное значение, а то приходится массив из трех частей собирать. В сумме все равно получается нужное значение байт, просто Не удобно как-то...((
И значения разные. Порой закономерности вообще ни какой... После того, как первый пакет принят, поток перестает получать данные с порта. Вообще не реагирует(((( Последний раз редактировалось defen, 14.02.2013 в 03:54. |
#10
|
||||
|
||||
Вообще, как показывает моя практика, асинхронный прием данных из последовательного порта чаще всего не нужен (мне вообще ни разу не понадобился). За время работы с внешними устройствами через последовательный порт я набросал небольшой модуль для работы с портом (открыть/закрыть, чтение/запись, некоторые доп. функции) и успешно им пользуюсь. Работу строю так: в основном цикле потока данные постоянно вычитываются из потра, если что-то приходит - обработка и ответ. Если что-то ножно отправить - сообщение потоку из главной нить приложения о необходимости выполнения определенных действий. Этого вполне хватает. Модуль с функциями для порта ниже.
Код:
unit COMUtils; interface uses SysUtils, Classes; function OpenPort(AName: string; BaudRate: integer; var Handle: THandle): Boolean; function ClosePort(var AHandle: THandle): Boolean; function COMRead(AHandle: THandle; Data: PByteArray): Cardinal; overload; function COMWrite(AHandle: THandle; Data: PByteArray; ALength: Cardinal) : Cardinal; overload; function ChangeSpeed(AHandle: THandle; NewSpeed: integer): Boolean; {$IFDEF VER220} // для delphi xe function COMRead(AHandle: THandle): RawByteString; overload; function COMWrite(AHandle: THandle; Data: RawByteString): Cardinal; overload; {$ELSE} function COMRead(AHandle: THandle): String; overload; function COMWrite(AHandle: THandle; Data: string): Cardinal; overload; {$ENDIF} procedure GetComList(List: TStrings; ExtendedList:Boolean=False); implementation uses Windows, Registry; const bufferlength = 2048; function DCBSettings(AHandle: THandle; ABaudrate: integer): Boolean; var DCB: TDCB; begin Result := False; FillChar(DCB, SizeOf(TDCB), 0);; if not(GetCommState(AHandle, DCB)) then Exit; DCB.Flags := DCB.Flags or (RTS_CONTROL_ENABLE shl 12); DCB.BaudRate := ABaudrate; DCB.Parity := NOPARITY; DCB.ByteSize := 8; DCB.StopBits := 0; Result := SetCommState(AHandle, DCB); end; function OpenPort(AName: string; BaudRate: integer; var Handle: THandle): Boolean; begin Result := False; Handle := CreateFile(PChar('\\.\' + AName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if Handle = INVALID_HANDLE_VALUE then Exit; if not DCBSettings(Handle, BaudRate) then Exit; if not SetupComm(Handle, bufferlength, bufferlength) then Exit; if not PurgeComm(Handle, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR) then Exit; EscapeCommFunction(Handle, CLRRTS); EscapeCommFunction(Handle, CLRDTR); Result := True; end; function ClosePort(var AHandle: THandle): Boolean; begin Result := CloseHandle(AHandle); if Result then AHandle := INVALID_HANDLE_VALUE; end; function COMRead(AHandle: THandle; Data: PByteArray): Cardinal; var ComStat: TComStat; Error: Cardinal; begin Result := 0; if not ClearCommError(AHandle, Error, @ComStat) then Exit; if ComStat.cbInQue > 0 then begin try ReadFile(AHandle, Data^[0], ComStat.cbInQue, Result, nil); except Result := $FFFFFFFF; end; end; end; {$IFDEF VER220} function COMRead(AHandle: THandle): RawByteString; {$ELSE} function COMRead(AHandle: THandle): string; {$ENDIF} var Data: TByteArray; Len: Cardinal; begin Result := ''; Len := COMRead(AHandle, @Data); if Len > 0 then begin SetLength(Result, Len); Move(Data[0], Result[1], Len); end; end; function COMWrite(AHandle: THandle; Data: PByteArray; ALength: Cardinal) : Cardinal; begin try WriteFile(AHandle, Data^[0], ALength, Result, nil); except Result := $FFFFFFFF; end; end; {$IFDEF VER220} function COMWrite(AHandle: THandle; Data: RawByteString): Cardinal; {$ELSE} function COMWrite(AHandle: THandle; Data: String): Cardinal; {$ENDIF} begin Result := COMWrite(AHandle, @Data[1], Length(Data)); end; function ChangeSpeed(AHandle: THandle; NewSpeed: integer): Boolean; begin Result := DCBSettings(AHandle, NewSpeed); end; function GetDecimal(Value:string):Integer; var decimal:string; flag:Boolean; i: Integer; begin decimal:=''; flag:=False; for i := 1 to Length(Value) do if CharInSet(Value[i],['0'..'9']) then begin flag:=true; decimal:=decimal+Value[i]; end else if flag then Break; Result:=StrToInt(decimal); end; function COMSort(List:TStringList; Index1, Index2:Integer):integer; var val1,val2:Integer; begin val1:=GetDecimal(List[Index1]); val2:=GetDecimal(List[Index2]); if val1=val2 then Result:=0 else if val1<val2 then Result:=-1 else Result:=1; end; procedure GetComList(List: TStrings; ExtendedList:Boolean); var reg:TRegistry; sl,sl1:TStringList; i:integer; flag:Boolean; begin List.Clear; sl:=TStringList.Create; sl1:=TStringList.Create; reg := TRegistry.Create(KEY_READ); reg.RootKey := HKEY_LOCAL_MACHINE; reg.OpenKey('hardware\devicemap\serialcomm', false); reg.GetValueNames(sl); if sl.Count>0 then begin for i := 0 to sl.Count - 1 do if ExtendedList then begin flag:=pos('SILAB',AnsiUpperCase(sl[i]))>0; if flag then sl1.AddObject('#'+reg.ReadString(sl[i])+'[CP2102]',pointer(flag)) else sl1.AddObject(reg.ReadString(sl[i]),pointer(flag)); end else begin sl1.Append(reg.ReadString(sl[i])); end; sl1.Sort; if ExtendedList then begin for i := 0 to sl1.Count-1 do if Boolean(sl1.Objects[i]) then begin sl1[i]:=Copy(sl1[i],2,Length(sl1[i])-1); end; end; sl1.CustomSort(COMSort); List.Text:=sl1.Text; end; reg.CloseKey; reg.free; sl1.Free; sl.Free; end; end. Некоторые программисты настолько ленивы, что сразу пишут рабочий код. Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты. |
#11
|
|||
|
|||
Попробую припаять чтение из порта. Растройки и отправка уже имеются
|
#12
|
|||
|
|||
Цитата:
|
#13
|
||||
|
||||
Цитата:
Некоторые программисты настолько ленивы, что сразу пишут рабочий код. Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты. |
Этот пользователь сказал Спасибо Aristarh Dark за это полезное сообщение: | ||
Dalt (29.03.2013)
|
#14
|
|||
|
|||
А что такое CharInSet? Delphi ругается, что переменная не продикларирована, но как я понял charinset водит в sysutils, а он подключен...
Последний раз редактировалось defen, 04.04.2013 в 09:44. |
#15
|
||||
|
||||
F1
______________ — Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |