怎么没人回答?串口通讯和线程的困惑,自己研究了好几天,终不得而解,很着急,有能力者请赐教 (100分)

  • 主题发起人 主题发起人 mouse_ingrief
  • 开始时间 开始时间
M

mouse_ingrief

Unregistered / Unconfirmed
GUEST, unregistred user!
是这样的:
程序的目的是能在两个串口间实现收发;我的操作分四步:1、打开发送串口,
2、打开接受串口,3、开始发送(不停的发),4、开始接受(不停的接受)。
但是我运行程序后,会可能出现这样的情况:1、接受不再继续,2、发送不再接受,
3、发送和接受都不再继续。我也不知道是线程挂起了还是线程执行完毕了,
根据我的代码,线程不可能执行完毕
因为在线程的execute中我是while true do。另外我发现只运行一个线程,或发送或读取
上述情况还没有发生。下面是一些代码:
线程类:
TRead=Class(TThread)
Public procedure Execute;override;
public procedure BeforeRead;
Public procedure AfterRead;
end;
TWrite=Class(TThread)
public procedure Execute;override;
public procedure BeforeWrite;
public procedure AfterWrite;
end;
procedure TRead.BeforeRead;
begin
Form1.StatusBar1.Panels[3].Text :='接受中';
end;
procedure TRead.AfterRead;
begin
Form1.Memo2.Text :=FReadBuf;
form1.StatusBar1.Panels[1].Text :='接收完毕: '+IntToStr(FSizeR)+'个字节';
form1.StatusBar1.Panels[3].Text :='接收完毕';
end;
procedure TRead.Execute;
begin
FReadBuf:=Nil;
FreeOnTerminate:=true;
while true do//如果这个true换成一个变量比如:reading,有时候readfile后reading
//的值就自动改变,原来是true ,现在是false,很奇怪。
begin
//EnterCriticalSection(cs);
Synchronize(BeforeRead);
ClearCommError(FComR,Err,@FStat);
if FStat.cbInQue =0 then Continue else FSizeR:=FStat.cbInQue;
if ReadFile(FComR,FReadBuf,FSizeR,FSizeR,Nil) then
begin
Synchronize(AfterRead);
end;
//LeaveCriticalSection(cs);
end;
PurgeComm(FComR,PURGE_RXCLEAR OR PURGE_RXABORT);
end;
procedure TWrite.BeforeWrite;
begin
Form1.StatusBar1.Panels[2].Text :='发送中';
FWriteBuf:=Pchar(Form1.Memo1.Text);
FSizeS:=StrLen(FWriteBuf);
end;
procedure TWrite.AfterWrite;
begin
Form1.StatusBar1.Panels[0].Text :='发送完毕:'+IntToStr(FSizeS)+'个字节';
Form1.StatusBar1.Panels[2].Text :='发送完毕';
end;
procedure TWrite.Execute;
begin
FWriteBuf:=Nil;
FreeOnTerminate:=true;
while true do
begin
//EnterCriticalSection(cs);
Synchronize(BeforeWrite);
if Terminated then Break;
if WriteFile(FComS,FWritebuf,FSizeS,FSizeS,Nil) then
begin
Synchronize(AfterWrite);
end;
//LeaveCriticalSection(cs);
end;
PurgeComm(FComR,PURGE_TXCLEAR OR PURGE_TXABORT);
end;
1、
var
Form1: TForm1;
FComS,FComR:Thandle;//FComS是发送串口句柄,FComR是接受串口句柄
FDcb:TDCB;
FTm:CommTimeOuts;
FReadBuf,FWriteBuf:Pchar;
FSizeS,FSizeR:DWORD;
FStat:TComstat;
err:DWORD;

FRead:TRead;
FWrite:TWrite;
writing,reading:boolean;
2、创建线程,并且挂起
procedure TForm1.FormCreate(Sender: TObject);
begin
FRead:=TRead.Create(true);
FWrite:=TWrite.Create(true);
reading:=true;
writing:=true;
end;
3、打开发送串口
procedure TForm1.OpenSendPortClick(Sender: TObject);
begin
FComS:=CreateFile(Pchar('Com'+Combobox1.text),GENERIC_READ or GENERIC_WRITE,0,Nil,OPEN_EXISTING,0,0);
if FComS = INVALID_HANDLE_VALUE then begin Showmessage('Open Com Port Error!');exit;end;
BuildCommDcb(Pchar(edit1.Text),FDcb);
FillChar(FTm,5,0);
FTm.WriteTotalTimeoutMultiplier :=5;
FTM.WriteTotalTimeoutConstant :=100;
SetCommTimeOuts(FComS,FTM);
OpenSendPort.Enabled :=false;
end;
4、打开接受串口
procedure TForm1.OpenRecivePortClick(Sender: TObject);
begin
FComr:=CreateFile(Pchar('Com'+Combobox2.text),GENERIC_READ or GENERIC_WRITE,0,Nil,OPEN_EXISTING,0,0);
if FComr = INVALID_HANDLE_VALUE then begin Showmessage('open com Error');exit;end;
BuildCommDcb(Pchar(edit2.Text),FDcb);
FillChar(FTm,5,0);
FTm.ReadIntervalTimeout :=0;
FTm.ReadTotalTimeoutMultiplier :=5;
FTm.ReadTotalTimeoutConstant :=1000;
SetCommTimeOuts(FComr,FTM);
OpenRecivePort.Enabled :=false;
end;
5、开始发送
procedure TForm1.AutoSendClick(Sender: TObject);
begin
AutoSend.Enabled :=false;
StatusBar1.Panels[2].Text :='自动发送中';
writing:=true;
FWrite.Resume;
end;
6、开始接受
procedure TForm1.BeginReciveClick(Sender: TObject);
begin
reading:=true;
FRead.Resume;
BeginRecive.Enabled :=false;
StatusBar1.Panels[3].Text :='接受中';
end;
贴子太长了,希望各位能心平气和的开完,帮我解答。我自己实在无能为力了。

 
我也在做串口软件,帮你提前一下
 
问题不够明白,还是......
两天了,怎么都没有人回答!
斑竹,也帮帮忙嘛!
 
实现你说的功能能不能用spcomm式一下啊?
我用过还可以,在加上timer控件,控制自动发送地周期就可以了
 
你接收和发送的串口是用什么?都没问题吧!
 
发送用线程发可能不行哦
有发不出去的情况
硬件缓冲写满就发不出去了
 
sorry,没看的清
 
是不是线程同步的问题?
 
to toplucky01
我也搞不清了
 
代码太多,一时不能分析清楚,不过你可以试试找一个工具软件
1、你用你的程序始终发,用工具软件监听
2、你用工具软加发,用你的软件监听
速度由慢至快
 
to liweijiang:
我用串口调试助手试过了,我的程序发,工具软件收,工具软件可以收到,只不过是
乱七八糟的东西,工具软件发送,我的程序收,我的程序没反应,我单步跟踪,发现在
procedure TRead.AfterRead;
begin
Form1.Memo2.Text :=FReadBuf;
form1.StatusBar1.Panels[1].Text :='接收完毕: '+IntToStr(FSizeR)+'个字节';
form1.StatusBar1.Panels[3].Text :='接收完毕';
end;
中,程序不执行任何语句,以至于整个读线程好像被挂起了。
 
兄弟也在学习使用!帮你顶吧!
 
呵呵,你怎么可以调用线程中的com控件呢?
我现在用Apro控件做 无线点菜的程序,使用串口与收发器交互
我的线程没有使用的进程中的Com控件,其他的大概一样,没问题的
 
to whtsuperant:
我没有调用线程的Com控件呀,因为我没有用什么Com控件。能吧你的意思说的明白一些吗!
 
有许多控件 而且有源码
为什么还要写
 
我用的是台湾范逸之先生的TCOMM控件,相当好用。
有全部源码,已经作好线程,不用自己写。
建议你使用,望多交流。
aynes@sohu.com
 
由于时间有限,我只看了一下你的发送程序,现提出几点建议
1、初始化串口时最好连校验位,数据长度,停止位等关键dcb参数设置上
2、在从meno控件中取发送串时好像有问题
3、因串口是一个很慢的外设(对CPU说),所以写入缓冲区后应查询是否已经发送完毕再开始新的发送任务。我试着在你的程序中每次发送前加一点延时结果发送单子节数据正确,延时去掉,发送有错误
由于今天有事只能试这些,明天有时间再帮你查找原因
 
线程访问VCL组件需要同步!!!

Form1.Memo2.Text :=FReadBuf;
form1.StatusBar1.Panels[1].Text :='接收完毕: '+IntToStr(FSizeR)+'个字节';
form1.StatusBar1.Panels[3].Text :='接收完毕';
 
为什么不用spcomm,我就是这样编写一个
边收边发
在添加一个定时器。。
没有一点问题
QQ:13089269
 
后退
顶部