串口通讯中的超时问题? (高手帮帮忙啊,很急的,再加100分了) (100分)

  • 主题发起人 主题发起人 likezyfish
  • 开始时间 开始时间
L

likezyfish

Unregistered / Unconfirmed
GUEST, unregistred user!
串口通讯中设置了SetCommTimeouts中的读操作总超时后,是从什么时候开始计时的,
是收到第一个字符时还是在readFile执行时?
我现在情况是把总超时固定为5秒,然后读串口,想知道如果此时串口没有接收到任何数据,readFile是怎样执行的,是不停的循环5秒还是直接就返回了阿?
哪位帮帮忙,在线等,多谢

另附超时设置,大家看看有没错误啊
var commtimeouts:TCommTimeouts;

FReadTotalTimeoutConstant:=5000;
GetCommTimeouts( hComm, commtimeouts );
commtimeouts.ReadIntervalTimeout := FReadIntervalTimeout;
commtimeouts.ReadTotalTimeoutMultiplier := FReadTotalTimeoutMultiplier;
commtimeouts.ReadTotalTimeoutConstant := FReadTotalTimeoutConstant;
commtimeouts.WriteTotalTimeoutMultiplier := FWriteTotalTimeoutMultiplier;
commtimeouts.WriteTotalTimeoutConstant := FWriteTotalTimeoutConstant;
SetCommTimeouts( hComm, commtimeouts );
 
没人啊,哪位给个包含超时设置的小程序看看也行啊,多谢了
 
本文提供的实例程序使用简单方便。利用一条串行数据线连接在两台计算机Com2之间就可以进行文本文件传输。对于Delphi的具体编程方法这里不再赘述。实例中有详细注释。



unit comunate;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

Dialogs, Buttons, StdCtrls, ComCtrls;

const

WM_COMMNOTIFY = WM_USER + 1; // 通讯消息

type

TForm1 = class(TForm)

Button1: TButton;

Button2: TButton;

Button3: TButton;

Button4: TButton;

OpenDialog1: TOpenDialog;

Label1: TLabel;

BitBtn1: TBitBtn;

RichEdit1: TRichEdit;

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

procedure Button3Click(Sender: TObject);

procedure Button4Click(Sender: TObject);

private

{ Private declarations }

procedure WMCOMMNOTIFY(var Message :TMessage);message WM_COMMNOTIFY;

public

{ Public declarations }

end;



var

Form1: TForm1;

implementation

{$R *.DFM}

var

hNewCommFile,Post_Event: THandle;

Read_os : Toverlapped;

Receive :Boolean;

ReceiveData : Dword;



procedure AddToMemo(Str:PChar;Len:Dword); // 接收的数据送入显示区

begin

str[Len]:=#0;

Form1.RichEdit1.Text:=Form1.RichEdit1.Text+StrPas(str);

end;



procedure CommWatch(Ptr:Pointer);stdcall; // 通讯监视线程

var

dwEvtMask,dwTranser : Dword;

Ok : Boolean;

Os : Toverlapped;

begin

Receive :=True;

FillChar(Os,SizeOf(Os),0);

Os.hEvent :=CreateEvent(nil,True,False,nil); // 创建重叠读事件对象

if Os.hEvent=null then

begin

MessageBox(0,'Os.Event Create Error !','Notice',MB_OK);

Exit;

end;

if (not SetCommMask(hNewCommFile,EV_RXCHAR)) then

begin

MessageBox(0,'SetCommMask Error !','Notice',MB_OK);

Exit;

end;

while(Receive) do

begin

dwEvtMask:=0;

// 等待通讯事件发生

if not WaitCommEvent(hNewCommFile,dwEvtMask,@Os) then

begin

if ERROR_IO_PENDING=GetLastError then

GetOverLappedResult(hNewCommFile,Os,dwTranser,True)

end;

if ((dwEvtMask and EV_RXCHAR)=EV_RXCHAR) then

begin

// 等待允许传递WM_COMMNOTIFY通讯消息

WaitForSingleObject(Post_event,INFINITE);

// 处理WM_COMMNOTIFY消息时不再发送WM_COMMNOTIFY消息

ResetEvent(Post_Event);

// 传递WM_COMMNOTIFY通讯消息

Ok:=PostMessage(Form1.Handle,WM_COMMNOTIFY,hNewCommFile,0);

if (not Ok) then

begin

MessageBox(0,'PostMessage Error !','Notice',MB_OK);

Exit;

end;

end;

end;

CloseHandle(Os.hEvent); // 关闭重叠读事件对象

end;



procedure TForm1.WMCOMMNOTIFY(var Message :TMessage); // 消息处理函数

var

CommState : ComStat;

dwNumberOfBytesRead : Dword;

ErrorFlag : Dword;

InputBuffer : Array [0..1024] of Char;

begin

if not ClearCommError(hNewCommFile,ErrorFlag,@CommState) then

begin

MessageBox(0,'ClearCommError !','Notice',MB_OK);

PurgeComm(hNewCommFile,Purge_Rxabort or Purge_Rxclear);

Exit;

end;

if (CommState.cbInQue>0) then

begin

fillchar(InputBuffer,CommState.cbInQue,#0);

// 接收通讯数据

if (not ReadFile( hNewCommFile,InputBuffer,CommState.cbInQue,

dwNumberOfBytesRead,@Read_os )) then

begin

ErrorFlag := GetLastError();

if (ErrorFlag <> 0) and (ErrorFlag <> ERROR_IO_PENDING) then

begin

MessageBox(0,'ReadFile Error!','Notice',MB_OK);

Receive :=False;

CloseHandle(Read_Os.hEvent);

CloseHandle(Post_Event);

CloseHandle(hNewCommFile);

Exit;

end

else

begin

WaitForSingleObject(hNewCommFile,INFINITE); // 等待操作完成

GetOverlappedResult(hNewCommFile,Read_os,

dwNumberOfBytesRead,False);

end;

end;

if dwNumberOfBytesRead>0 then

begin

Read_Os.Offset :=Read_Os.Offset+dwNumberOfBytesRead;

ReceiveData := Read_Os.Offset;

// 处理接收的数据

AddToMemo(InputBuffer,dwNumberOfBytesRead);

end;

end;

// 允许发送下一个WM_COMMNOTIFY消息

SetEvent(Post_Event);

end;



procedure TForm1.Button1Click(Sender: TObject); // 打开文件用于发送

begin

if OpenDialog1.Execute then

begin

Button3.Enabled :=False;

Button4.Enabled :=False;

RichEdit1.Lines.LoadFromFile(OpenDialog1.FileName);

Form1.Caption := IntToStr(RichEdit1.GetTextLen);

end;

Button1.Enabled :=False;

end;



procedure TForm1.Button2Click(Sender: TObject); // 发送数据

var

dcb : TDCB;

Error :Boolean;

dwNumberOfBytesWritten,dwNumberOfBytesToWrite,

ErrorFlag,dwWhereToStartWriting : DWORD;

pDataToWrite : PChar;

write_os: Toverlapped;

begin

Form1.Caption :='';

// 打开通讯端口COM2

hNewCommFile:=CreateFile( 'COM2',GENERIC_WRITE,0,

nil, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0 );

if hNewCommFile = INVALID_HANDLE_VALUE then

MessageBox(0,'Error opening com port!','Notice',MB_OK);

SetupComm(hNewCommFile,1024,1024); // 设置缓冲区大小及主要通讯参数

GetCommState( hNewCommFile,dcb);

dcb.BaudRate :=9600;

dcb.ByteSize :=8;

dcb.Parity :=NOPARITY;

dcb.StopBits := ONESTOPBIT;

Error := SetCommState( hNewCommFile, dcb );

if ( not Error) then MessageBox(0,'SetCommState Error!','Notice',MB_OK);

dwWhereToStartWriting := 0;

dwNumberOfBytesWritten := 0;

dwNumberOfBytesToWrite :=RichEdit1.GetTextLen;

if (dwNumberOfBytesToWrite=0) then

begin

ShowMessage('Text Buffer is Empty!');

Exit;

end

else

begin

pDataToWrite:=StrAlloc(dwNumberOfBytesToWrite+1);

try

RichEdit1.GetTextBuf(pDataToWrite,dwNumberOfBytesToWrite);

Label1.Font.Color :=clRed;

FillChar(Write_Os,SizeOf(write_os),0);

// 为重叠写创建事件对象

Write_Os.hEvent := CreateEvent(nil,True,False,nil);

SetCommMask(hNewCommFile,EV_TXEMPTY);

Label1.Caption:='正在发送数据...!';

repeat

Label1.Repaint;

// 发送通讯数据

if not WriteFile( hNewCommFile,pDataToWrite[dwWhereToStartWriting],

dwNumberOfBytesToWrite,dwNumberOfBytesWritten,

@write_os ) then

begin

ErrorFlag :=GetLastError;

if ErrorFlag<>0 then

begin

if ErrorFlag=ERROR_IO_PENDING then

begin

WaitForSingleObject(Write_Os.hEvent,INFINITE);

GetOverlappedResult(hNewCommFile,Write_os,

dwNumberOfBytesWritten,False);

end

else

begin

MessageBox(0,'WriteFile Error!','Notice',MB_OK);

Receive :=False;

CloseHandle(Read_Os.hEvent);

CloseHandle(Post_Event);

CloseHandle(hNewCommFile);

Exit;

end;

end;

end;

Dec( dwNumberOfBytesToWrite, dwNumberOfBytesWritten );

Inc( dwWhereToStartWriting, dwNumberOfBytesWritten );

until (dwNumberOfBytesToWrite <= 0); // Write the whole thing!

Form1.Caption:=IntToStr(dwWhereToStartWriting);

finally

StrDispose(pDataToWrite);

end;

CloseHandle(hNewCommFile);

end;

Label1.Font.Color :=clBlack;

Label1.Caption:='发送成功!';

Button1.Enabled :=True;

Button3.Enabled :=True;

Button4.Enabled :=True;

end;



procedure TForm1.Button3Click(Sender: TObject); // 接收处理

var

Ok : Boolean;

dcb : TDCB;

com_thread: Thandle;

ThreadID:DWORD;

begin

ReceiveData :=0;

Button1.Enabled :=False;

Button2.Enabled :=False;

RichEdit1.Clear;

// 打开COM2

hNewCommFile:=CreateFile( 'COM2',GENERIC_READ,0,

nil, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0 );

if hNewCommFile = INVALID_HANDLE_VALUE then

begin

MessageBox(0,'Error opening com port!','Notice',MB_OK);

Exit;

end;

Ok:=SetCommMask(hNewCommFile,EV_RXCHAR);

if ( not Ok) then

begin

MessageBox(0,'SetCommMask Error!','Notice',MB_OK);

Exit;

end;

SetupComm(hNewCommFile,1024,1024);

GetCommState( hNewCommFile, dcb );

dcb.BaudRate :=9600;

dcb.ByteSize :=8;

dcb.Parity :=NOPARITY;

dcb.StopBits := ONESTOPBIT;

Ok := SetCommState( hNewCommFile, dcb );

if ( not Ok) then MessageBox(0,'SetCommState Error!','Notice',MB_OK);

FillChar(Read_Os,SizeOf(Read_Os),0);

Read_Os.Offset := 0;

Read_Os.OffsetHigh := 0;

// Create Event for Overlapped Read

Read_Os.hEvent :=CreateEvent(nil,true,False,nil);

if Read_Os.hEvent=null then

begin

CloseHandle(hNewCommFile);

MessageBox(0,'CreateEvent Error!','Notice',MB_OK);

Exit;

end;

// Create Event for PostMessage

Post_Event:=CreateEvent(nil,True,True,nil);

if Post_Event=null then

begin

CloseHandle(hNewCommFile);

CloseHandle(Read_Os.hEvent);

MessageBox(0,'CreateEvent Error!','Notice',MB_OK);

Exit;

end;

// 建立通信监视线程

Com_Thread:=CreateThread(nil,0,@CommWatch,nil,0,ThreadID);

if (Com_Thread=0) then

MessageBox(Handle,'No CraeteThread!',nil,mb_OK);

EscapeCommFunction(hNewCommFile,SETDTR);

Label1.Font.Color :=clRed;

Label1.Caption:='正在接收数据...!';

end;



procedure TForm1.Button4Click(Sender: TObject); // 停止通讯处理

begin

Label1.Font.Color :=clBlack;

Label1.Caption:='infomation';

Form1.Caption := IntToStr(ReceiveData);

Receive :=False;

CloseHandle(Read_Os.hEvent);

CloseHandle(Post_Event);

CloseHandle(hNewCommFile);

Button1.Enabled :=True;

Button2.Enabled :=True;

end;



end.
 
1。读操作总超时是从readFile开始执行起计时的
2。如果串口没有接收到任何数据,readFile将一直读直到读操作总超时时间用完才返回
 
我现在是点击一个按钮来执行readFile,然后在设定的时间内向这个串口发送数据,可为什么总是什么也接收不到呢?
是不是设置超时的代码有问题啊?
 
点击一个按钮来执行readFile?该不会是直接调用readFile吧,那样哪能收到?
说详细点?
 
应该怎样收啊,如果先发送的话可以收到的。
要不用qq吧,这样太慢:108213032
 
哪位给段有设置超时的代码阿,我怀疑代码写的不对,可又找不到相关的例子,急啊
多谢了
 
还没搞定,找一个SPComm源码看
 
是啊,还没搞定,愁啊
 
你的串口(硬件、串口线)有问题吗?先下载一个串口调试程序在两个串口之间收发一下看看是否正常。然后用串口调试程序发送数据给你的程序,跟踪readfile,可参照:
i:integer;
F:boolean;
for i:=1 to 100 do
begin
F:=Readfile(,,,,); //填入你的配置参数
if F = True then break;
end;
 
串口没问题的,收发都可以。
设置超时的代码好像根本就没有起作用。
 
这是从前看人家做的一段,你看有没有用
procedure TCommThread.Execute;
var
dwErrorFlags, dwLength: DWORD;
ComStat: PComStat;
fReadStat: Boolean;
InChar: Char;
AbIn: string;
XX, YY: double; //file; //经度、纬度
VID: string; //file: //车号
begin
while Connected do
begin
GetMem(ComStat, SizeOf(TComStat));
ClearCommError(CommHandle, dwErrorFlags, ComStat);
if (dwErrorFlags > 0) then
begin
PurgeComm(CommHandle, (PURGE_RXABORT and PURGE_RXCLEAR));
// return 0;
end;
dwLength := ComStat.cbInQue;
if (dwLength > 0) then
begin
fReadStat := ReadFile(CommHandle, InChar, 1, dwLength, nil);
if (fReadStat) then
begin
if (InChar <> Chr(13)) and (Length(abIn) < MAXBLOCK + 5) then AbIn := AbIn + InChar
else
begin
//...{接收完毕,}
end; //if (fReadStat>0){
end; //file: //if (dwLength>0){
FreeMem(ComStat);
end; {while}
end;
end;
 
用readfile 读的时候设定循环的次数大一些,
for i:=1 to 100 do //只读一次可能读不到数据
begin
F:=Readfile(,,,,); //填入你的配置参数
if F = True then break;
end;
 
readFile不是要等到超时后才返回吗,假如在规定时间内发数据的话,应该可以收到的阿
 
to: likezyfish
设置的超时不是Readfile的。
 
应该是在等待的时间里去读端口.API好像在2000下使用有问题.
部分代码如下:
//延时100毫秒;
iWait := 100;
iBegin := GetTickCount;
While (GetTickCount-iBegin < iWait) do
application.ProcessMessages;

filewrite(com,chrin,length(chrin));

iWait := 2000;
iBegin := GetTickCount;
While (GetTickCount-iBegin < iWait) do
begin
application.ProcessMessages;
fileread(com,chrout,length(chrout));
不知道对你有启发没有.
 
多人接受答案了。
 
后退
顶部