串口操作与线程的应用(涘,没有分了。)(0分)

N

nzfboy

Unregistered / Unconfirmed
GUEST, unregistred user!
(我用的spcomm)
我该如何在一线程中监视端口进入数据,
又如何在另一线程中发送数据,
又如何协调两个线程的关系?
请大虾给出范例。不胜感激!!
 
这样你其实就可以采用一个线程发送就可以了!
下面是采用一个线程和api发送信息,希望对你有用!
unit comm_sendfileunit;
interface
uses
Classes,windows,SysUtils;
type
threadsendfile = class(TThread)
private
fname:string;
hwriteEvent:THandle;
hcomfile: THandle;
protected
procedure Execute;
override;
public
constructor create(sendfilename:string);
function initcom: integer;//初始化
function sendbuffer(buffer: Pchar;
count: integer): boolean;//发送字符
function sendfl: integer;//发送文件
function closecomfile: integer;
end;

implementation
uses wait;
{ Important: Methods and properties of objects in VCL can only be used in a
method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure sendfile.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
}
{ sendfile }
constructor threadsendfile.create(sendfilename:string);
begin
fname:=sendfilename;
inherited create(false);
end;
function threadsendfile.closecomfile: integer;
begin
CloseHandle(hComFile);
CloseHandle(hwriteEvent);
result:=1;
end;
function threadsendfile.sendfl: integer;
var
buf:array[1..512] of Char;
buffer:pChar;
FromF: file;
NumRead,i,len: Integer;
label endlabel;
begin
result:=0;
if initcom >10 then
begin
result:=998;
exit;
end;
buf[1]:=#3;
buf[2]:=#3;
buffer:=PChar(@buf);
sendbuffer(buffer,2);
result:=0;
AssignFile(FromF,fname);
Reset(FromF, 1);
len:=FileSize(FromF);
len:=(len+511) div 512;
waitform.ProgressBar1.Min:=0;
waitform.ProgressBar1.Max:=len;
len:=0;
repeat
begin
fillchar(Buf,sizeof(Buf),#0);
BlockRead(FromF, buf, SizeOf(Buf), NumRead);
buffer:=PChar(@buf);
for i:=1 to 3do
begin
if Terminated then
goto endlabel;
if sendbuffer(buffer,NumRead) then
break;
end;
if i>3 then
begin
result:=1;
//raise ERangeError.Create( '传输失败!' );
break;
end;
//len:=len+NumRead;
waitform.ProgressBar1.Position:=waitform.ProgressBar1.Position+1;
//memo1.Lines.Add('已经发送的字节:'+inttostr(len));
end;
until ((NumRead = 0) or (NumRead<SizeOf(Buf)));
buf[1]:=#4;
buffer:=PChar(@buf);
sendbuffer(buffer,1);
endlabel:
CloseFile(FromF);
closecomfile;
end;

function threadsendfile.initcom: integer;
var
commtimeouts: TCommTimeouts;
dcb: Tdcb;
commprop: TCommProp;
fdwEvtMask: DWORD;
begin
hwriteEvent:= CreateEvent( nil, True, False, nil );
hcomfile:=CreateFile( PChar('com1'),GENERIC_READ or GENERIC_WRITE,
0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
//if hcomfile = INVALID_HANDLE_VALUE then
// raise ERangeError.Create( 'Error opening serial port' );
if hcomfile = INVALID_HANDLE_VALUE then
begin
result:=998;
exit;
end;

if GetFileType( hcomfile ) <> FILE_TYPE_CHAR then
begin
CloseHandle( hcomfile );
raise ERangeError.Create( 'File handle is not a comm handle ' );
end;
GetCommState( hcomfile, dcb );
//SetCommMask( hcomfile, EV_RXCHAR);
SetCommMask( hcomfile,EV_TXEMPTY);
SetupComm( hcomfile, 4096, 4096 );
PurgeComm( hcomfile, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR ) ;
//填写超时
commtimeouts.ReadIntervalTimeout :=0;
commtimeouts.ReadTotalTimeoutMultiplier :=0;
commtimeouts.ReadTotalTimeoutConstant :=0;
commtimeouts.WriteTotalTimeoutMultiplier :=100;
commtimeouts.WriteTotalTimeoutConstant :=0;
SetCommTimeouts( hcomfile, commtimeouts );
{dcb.fAbortOnError := False;
NOT VALID}
dcb.DCBlength:=sizeof( DCB );
//dcb.BaudRate := CBR_115200;
dcb.BaudRate := CBR_57600;
dcb.Flags := dcb.Flags or 1;
// Enable fBinary
dcb.Flags := dcb.Flags or 2;
// 进行校验
//DCB.wReserved1:=65;
//DCB.wReserved:=0;
//dcb.Flags := dcb.Flags or $10;
//dcb.Flags := dcb.Flags or $1000;
{dcb.XonLim :=10;
dcb.XoffLim :=10;
dcb.XonChar :=#0;
dcb.XoffChar :=#0;}
dcb.ByteSize :=8;
dcb.Parity := EVENPARITY;
dcb.StopBits :=ONESTOPBIT;
SetCommState( hcomfile, dcb );
EscapeCommFunction(hcomfile, SETDTR );
//closehandle(hcomfile);
//hcomfile:=CreateFile( PChar('com1'),GENERIC_READ or GENERIC_WRITE,
//0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
sleep(100);
result:=0;
end;
function threadsendfile.sendbuffer(buffer: Pchar;
count: integer): boolean;
var
sendbuf:pchar;
sendbool:boolean;
truewr,dwLastError,dwErrors:DWORD;
i:integer;
dwModemStat,dwritek,StartWriting:DWORD;
ctsbool:boolean;
modd:integer;
sendcount:integer;
begin
result:=false;
sendbuf:=buffer;
sendcount:=count;
dwModemStat:=0;
GetCommModemStatus(hcomfile,dwModemStat);
if(MS_CTS_ON= dwModemStat and MS_CTS_ON) then
ctsbool:=true
else
ctsbool:=false;
i:=0;
while (not(ctsbool) and (i<30))do
begin
if Terminated then
exit;
sleep(10);
GetCommModemStatus(hcomfile,dwModemStat);
if(MS_CTS_ON= dwModemStat and MS_CTS_ON) then
ctsbool:=true;
i:=i+1;
end;
if i>=30 then
begin
exit;
end;

dwritek:=0;
StartWriting:=0;
i:=0;
sendbool:=WriteFile( hComFile,sendbuf^,sendcount,dwritek,nil);
sleep(50);
if not(sendbool) then
begin
dwLastError := GetLastError;
if dwLastError <> ERROR_IO_PENDING then
begin
while (WaitForSingleObject(hwriteEvent,500)=WAIT_TIMEOUT)do
begin
dwLastError := GetLastError;
if(dwLastError <> ERROR_IO_INCOMPLETE) then
begin
ClearCommError(hComFile,dwErrors, nil);
break;
end;
end;
end
else
begin
ClearCommError(hComFile,dwErrors, nil);
end;
end
else
result:=true;
end;

procedure threadsendfile.Execute;
begin
if fileexists(fname) then
if sendfl>10 then
begin
waitform.Label1.Caption:=' 端口已经被占用!';
waitform.ProgressBar1.hide;
waitform.Label1.visible:=true;
exit;
end;
waitform.close;
end;

end.
 
下面是我采用spcomm发送文件的!!!!!!!!!!
procedure TForm1.Comm2ReceiveData(Sender: TObject;
Buffer: Pointer;
BufferLength: Word);
var
sendchar:pchar;
fnamelen,i,sumchar,size,j,divint,fileeof:integer;
fsize:array[1..4] of integer;
sendbuf:array[1..254] of char;
recchar,NumRead:integer;
begin
Move(Buffer^,PChar(@rbuf)^,BufferLength);
fileeof:=0;
if sendfilecoun=sendfile.Count then
begin
//结束文件的发送
comm2.StopComm;
form2.close;
end;

if (start=1) then
start:=2;
recchar:=rbuf[1];

if ((recchar=11) and (start=2) or (recchar=10) and (start=3)) then
begin
//发送文件长度
if start=2 then
start:=3;
savefilename:=SENDFILE.Strings[sendfilecoun];
AssignFile(savefile,savefilename);
Reset(savefile, 1);
size:=FileSize(savefile);
sendfilesize:=size;
sumchar:=0;
for i:=1 to 4do
begin
divint:=1;
for j:=4do
wnto i+1do
divint:=divint*256;
fsize:=size div (divint);
sbuf:=chr(fsize);
sumchar:=(sumchar+ord(sbuf)) mod 256;
size:=size-fsize*divint;
end;
sbuf[5]:=chr(sumchar);
sendchar:=@sbuf;
comm2.WriteCommData(sendchar,5);
exit;
end;
if (((recchar=12) and (start=4)) or ((recchar=9) and (start=5)) or ((recchar=11) and (start=5)))then
begin
//start=4 表示开始发送文件
if start=4 then
start:=5;
if recchar=9 then
begin
for i:=1 to sendagainnumdo
begin
comm2.WriteCommData(@rbufchar,1);
//一个一个字符的发送
sleep(1);
end;
end
else
begin
try
BlockRead(savefile,sendbuf,sizeof(sendbuf), NumRead);
except
fileeof:=1;
end;
IF ((fileeof=1) or (NumRead=0)) then
begin
sendfilecoun:=sendfilecoun+1;
if sendfilecoun>=sendfile.Count then
begin
try
closefile(savefile);
except
end;
comm2.WriteCommData(#0,1);
comm2.WriteCommData(#16,1);
comm2.StopComm;
form2.close;
exit;
end
else
begin
try
closefile(savefile);
except
end;
start:=2;
comm2.WriteCommData(#0,1);
//sleep(1);
comm2.WriteCommData(#15,1);
exit;
end;
end;
//结束文件
sumchar:=0;
for i:=1 to numreaddo
begin
rbufchar[i+1]:=sendbuf;
sumchar:=(sumchar+ord(sendbuf)) mod 256;
end;
rbufchar[1]:=chr(numread+1);
rbufchar[numread+2]:=chr(sumchar);
sendagainnum:=numread+2;
//sendchar:=@rbufchar;
//form2.ProgressBar1.Position:=(form2.ProgressBar1.Position+20) mod 101;
for i:=1 to numread+2do
begin
comm2.WriteCommData(@rbufchar,1);
//一个一个字符的发送
sleep(1);
end;
//comm2.WriteCommData(sendchar,numread+2);//发送串
end;
end;

//发送文件名
if (((recchar=12) and (start=3)) or ((recchar=10) and (start=4))) then
begin
if start=3 then
start:=4;
//
savefilename:=SENDFILE.Strings[sendfilecoun];
//
//showmessage(savefilename);
sleep(100);
fnamelen:=length(savefilename);
form2.ProgressBar1.Position:=form2.ProgressBar1.Position+20;
sumchar:=0;
for i:=1 to fnamelendo
begin
sbuf[i+1]:=savefilename;
sumchar:=(sumchar+ord(savefilename)) mod 256;
end;
sbuf[1]:=chr(fnamelen+1);
sbuf[fnamelen+2]:=chr(sumchar);
sendchar:=@sbuf;
comm2.WriteCommData(sendchar,fnamelen+2);
end;
end;
怎么没有分!!!!!!!!!!!!!!!
 
大哥,如果在你的发送过程中要发送两个消息,
而你要发送的第二个消息又要依赖于第一个消息发出后从端口返还的消息。该怎么办?
现实情况好像是:第一个消息发送完,不论第一个消息接受什么或发送成功于否,第二个都会发送出去,但这个现象不是我希望看到的。
故以上两位大虾的,有待完善。
 
如果你要对方返回消息的话,就要和对方约定好了
收到后发送一个什么样的消息给你,
也就是要定一个通讯规约了
否则是不可能知道的
 
上面例子已经很清楚了,收到前面正确的字符#06,才发送后面的,否则#05就发送
 
DCSDCS:在你的程序中,那里有#06或#05呀?
我的程序是如此做的:
全局变更SRS用来标识发送是否成功
procedure SendData(.....);发送子程序,肯定没有问题。
begin
end
procedure Spcomm Recedive()//spcomm的接收程序
begin
//发送完成后给全局变更SRS赋值:11
SRS:=11;
end;
procedure form1.button1click()
begin
SRS=10;
senddata(...);//第一次发送
if SRS=11 then

SendData(....);第二次发送
end;
我的程序在做完第一次发送后,按想像,SRS应该被接受程序改为11,
可实际并不是如此,而是SRS依然是10。
如何解决?
 
mei
分可以找我要啊
 
这个当然错误!
SRS=10;
senddata(...);//第一次发送,这里立即返回!!!!!!正在发送
if SRS=11 then
//这里当然就是10了
SendData(....);
将第二次发送写在procedure Spcomm Recedive()//spcomm的接收程序
 
DCSDCS:
写在接受程序中当然可以了。但在我的程序中写在接受过程中却不满足领导要求,
我要写在外部,搞不掂所以才请大家帮助。
 
采用线程,弹出提示框就可以了!!!!!!!!!!!
只有想不到!
 
程序设计有两种问题,技术和非技术的,技术的可以绕过去,非技术的实际上在很大程度上决定软件的成功与失败!!!!!!!!!!
 
弟子愚昧,请DcsDcs老师讲详细一点,线程如何应用到我的实际工作中
 
你讲的弹出堤示框具体如何应用?
 
比如:弹出一个form,然后将发送的百分比显示成滚动条!就象安装文件的开始一样!!
 
其实你这样用一个全局变量也是可以的,但是由于是动态变化的,所以你监测这个值
是否变化是不应该写在button得click事件中的。你应该采用线程。如果你对时间和
速度要求不是很高,也可以考虑用定时器,但那是实在没办法时使用的。
在线程中你可以一直在监测这个全局变量,直到它在返回时被更改为止
比如在线程的execute中
while srs<>10do
begin
sleep(10)
end;
这样你就能等到srs=10的情况,然后你再发送第二个消息。
事实上,用全局变量也不能算是正规的做法,我常采用的方法是使用waitforsingle
object而一般情况下线程也是用它或类是的函数来同步。
你要做的是:
创建一个handle, 利用CreateMutex函数(互斥体),同样把这个作为全局变量。
在发送完第一个消息时,把这个句柄(互斥体)占住,利用waitforsingleobject,
记住不要释放,然后在接受到指定的符合你要求的东冬后,释放,利用函数
ReleaseMutes???(对不起,记不清了)。同样的方法,你可以在发送第二次数据前
试着LOCK这个句柄,直到成功,你才发送,否则你别发送


 
LVXq:
隐约觉得你老讲的很正点,应该是正解。
谢谢你了。
但苦于我从VB转到delphi时间不长,你的理论我付于实践比较有难度。
可以再讲详细一点吗?
学生有礼了。
 
另外,你讲的你常用的方法从宏观从理解是否是这样的:
srs全局变更依然存在。
接受函数中对SRS变更的更改依然有效
我在主程序中:
for i=1 to 3do
begin

生成互拆体;
先发送第N串消息;
锁住句柄;
if srs=11 then

释放句柄;
endfor
 
我和你刚相反,现在玩vb了。
其实是否要采用互斥体是因人而异,因场合而异的。我也没心情看你上面的代码,因为它
实在太长了,所以不知道你for i=1 to 3do
里要干吗,但是在你这里生成互斥体是很
容易出错的,除非你这样做
var
COMLOCK: array [1..3] of THandle;
....
for i=1 to 3do

....
COMLOCK=CreateMutex("THISISACOMLOCK"+IntToSTr(i));
....

事实上,我自己最喜欢做的是利用现成的控件,比如spcomm,它已经为你封装好线程
只要你做到再接受到信息以后根据判断再发送,应该不会出错。如果你需要同时处理
3种信息,(我只是根据你的for i=1 to 3推测),那你可以设置消息的类别,比如
在发送和接受时要求指定位置的值标出消息是哪一种,比如我以往的经验一般是这样
做的:
先定义好彼此的协议,比如所有消息必须以FB打头,FE结尾
FB 05 01 XX XX XX XX XX XX pp FE
比如上面的一串东东,根据协议可以理解成
1: 以FB打头
2: 05 代表实际有意义的字节为5个
3: 01 代表消息类型,根据需要,你可以定义多种消息,比如01代表确认桢
02代表错误,即要求重发的,。。。。。。。
4: 这里的PP可以代表校验字节,比如你可以对发送的内容进行和校验或异或校验
5: FE代表桢结束
。。。。。。
`你还可以更加丰富你的通讯协议,这样你可以只用一个控件,或者你自己做线程,难吗??
不难!!
 
顶部