怎样用mscomm控件发送和接收不定长的数据呢?(100分)

  • 主题发起人 主题发起人 tswhq
  • 开始时间 开始时间
T

tswhq

Unregistered / Unconfirmed
GUEST, unregistred user!
当C客户端通过modem与S服务器连通后,C/S之间发送 命令+数据结构;怎样在MSComm1Comm事件中判断并接收呢?由于不定长下面的属性怎样设定呢?
RThreshold:该属性为一阀值,它确定当接收缓冲区内的字节个数达到或超过该值后就产生代码为ComEvReceive的OnComm事件。

spcomm怎么拨号呀?
 
RThreshold设置为1,【命令+数据结构+结束标志】,每次触发接收事件时,把收到的数据放到自己定义的缓冲区,从缓冲区中查找第一个结束标志,如果有,则处理前面的数据,后把处理过的数据从你的缓冲区中拿掉,继续循环,直到找不到结束标志为止,然后等待下一此接收事件触发。

建议使用TurboPower Async Professional中的TApdComPort控件。
 
to 京酱肉丝
有例子吗?
 
定义全局
const END_MARK = '|'; // 可以是其它,最好设置的特殊一些或长一些,避免和数据包中的数据重复;
var Buffer: string;
数据触发事件: procedure xxxxx....;
var
P: Integer;
tmpStr: string;
begin
Buffer:= Buffer + 接收字符函数,根据控件不同,方法不一;
P:= Pos(END_MARK, Buffer);
while P > 0 do
begin
tmpStr:= Copy(Buffer, 1, P - 1);
Delete(Buffer, 1, Length(tmpStr + END_MARK));
PutStr(tmpStr);//这个过程是处理数据包:命令+数据结构的,也可以直接在这里处理数据,这样写是为了代码更清楚一些;
P:= Pos(END_MARK, Buffer);
end;
end;
end;
 
to 京酱肉丝
看了你的例子有点明白了,不过我想能不能这样
发送时:标志+结构 一起发送;
接收时:先读标志,然后根据标志,判断出结构的长度,再读取结构
 
TApdComPort控件非常好用,mscomm控件有一些问题,比如特殊的波特率就不能使用,象230400
 
可以啊,就看你的程序怎样处理,方法有很多种,重要的是要保证数据包的完整,因为你的数据包是不定长的。
 
procedure TForm1.Button1Click(Sender: TObject);
begin
comm1.StartComm;
comm1.WriteCommData('ATDT8001'+#13+#10,10);
end;
spcomm控件为何不拨号???
 
比如你读到一个标志,其中的数据包长度是100,可是后面的数据不够100个,那就要等待下一次触发时处理,因为数据每次到达的长度不是固定的,长度不够的数据不能丢弃,这一点要注意。
 
不拨号不是控件的原因,可能和你的Modem有关,你要查一下Modem的AT指令,有些Modem的指令是比较特殊的,比如拨号要用ATAD8001加上一个分号: 'ATAD8001;'+#13#10
 
我用的
ZTE_MC315的拨号命令AT为: 'AT+CDV' + PhoneNumber + ';' + #13
PANDA_PM98A的拨号命令AT为:'ATD' + PhoneNumber + ';' + #13
 
同样的设备
Form1.MSComm.Output:='ATDT'+PhoneCode+#13; 可以拨号!!!
comm1.WriteCommData('ATDT8001'+#13+#10,10); 没有反映???

comm1是Spcomm控件
 
comm1是个什么控件?
 
用Delphi写Windows程序,尽量不要用OCX,最好用有源代码的VCL控件,这样比较安全一些,我一直是这样做的,没有源码的东西最好不要用,万一系统开发出来的,所有的代码都是围绕这个控件开发的,某一天出现了这个东西过期了,那就惨了,我就碰上类似的问题,可把俺给害苦了,呵呵!
 
Spcomm是个很滥的东西,建议你不要用了,还是用TurboPower Async Professional中的TApdComPort控件,有源码的,很爽,又有好多例子,这组套件是目前世界上最好的异步通讯套件。
 
comm1是Spcomm控件
我也想改过来,可是spcomm不拨号,TApdComPort哪有下载的
 
http://www.2ccc.com/article.asp?articleid=381
注册一个用户就可以下载
 
自己定义通讯协议
 
话题1159088的标题是: 在CSDN上很久没人理,还是回到大富翁来。(还是串口通信问题) (150分)
分类:局域网 / 通讯 moodboy (2002-06-12 15:38:00)
1.MScomm输入缓冲区怎么设置好?(30分)
我发现设置大小不同,接收到的数据大小也不同。举例说:
我接收的数据最大有64K,但不知道到底是多少,当我设成1024时统计了一下,
约接收到2K多,设成128字节时,约1K多,设成最大时又比设成1024时多。
2.spcomm的使用(120分)
我的要求是把Memo1中的不定长字符串转换成十六进制发送给外设,
外设发回的十六进制数据再转换成字符串在Memo2中显示。
我用全文检索找了很久,发现以前看到的一些好贴子找不到了,只好请高手再花点时间。
谢谢!



moodboy (2002-06-12 16:21:00)
好失望。
怎样给问题加分?

qdyoung (2002-06-12 16:25:00)
function TForm1.Send(Text: string): Boolean;
var
s: string;
begin
s := '';
for i := 1 to Length(Text) do
s := s + IntToHex(Byte( Text);
Result := SpComm.WriteCommData(PChar(s), Length(s));
end;

procedure TForm1.CommReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
sBuffer, s: string;
begin
sBuffer := '';
SetLength(sBuffer, BufferLength);
StrLCopy(PChar(sBuffer), Buffer, BufferLength);
s := '';
for i := 0 to BufferLength div 2 do
s := s + HexToInt('$' + Copy(sBuffer, i * 2 + 1, 2));
ShowMessage(s);
end;


------
http;//www.8421.org

SupermanTm (2002-06-12 16:26:00)
问题一:
串行口控件的输入缓冲区是与你读它的频率有关的,传输1M的数据并不是需要1M的缓冲区,
如果通讯速率(波特率)是9600,那么每秒将会有960字节的数据,如果你对控件的读间隔
时间不大于一秒,那么1024字节的缓冲区就够了,不管你的报文是1M还是10M;
问题二:
把报文读进一个 String 变量,然后定义一个 PByteAry 型的指针
TByteAry = array [0..1] of Byte;
PByteAry = ^TByteAry;
让这个指针变量指向字符串的第一个字符
var P: PByteAry;
begin
P:= @S[1];
...
然后,就 for I:= 1 to length(S) do P^...


御键飞天 (2002-06-12 16:31:00)
呵呵!moodboy不好意思,赚了你不少分,问题却没给你怎么解决.
第一个问题说明白点,好吗?
第二个问题
var //字符串转为16进制;
Send:array of Byte;
Chr1,Chr2:Char;
Byte1,Byte2:Byte;
I:Integer;
begin
Byte1:=0;
Byte2:=0;
SetLength(Send,(Length(String) div 2));
for I:=1 to Length(String) div 2 do
begin
Chr1:=Str[2*I-1];
Chr2:=Str[2*I];
if (Chr1 in['0'..'9']) then
Byte1:=Ord(Chr1)-48
else
if (Chr1 in['A'..'f']) then
Byte1:=Ord(Chr1)-55;
if (Chr2 in['0'..'9']) then
Byte2:=Ord(Chr2)-48
else
if (Chr2 in['A'..'F']) then
Byte2:=Ord(Chr2)-55;
Send:=Byte1*16+Byte2;
end;
end;
16进制转为字符串用IntToHex函数;
你有QQ吗?聊一聊?

peng_qs (2002-06-12 16:50:00)
你MEMO1,MEMO2中都是数字吗,只有数值才有16进制的,转换可以用FORMAT函数实现.只要是
字符串了,收发自然不在话下.

moodboy (2002-06-12 17:08:00)
多谢大家的帮忙!
to 卸健飞天:
我没有QQ,只有信箱:mumuhai@sohu.com
第一个问题,我也不知道怎样表达了,我向单片机发出命令后就等着它自己接收,结果发现
不同的缓冲区大小,接收到的数据大小也不同。大概如supmermanTm所说。
还有,我只用了2、3、5线,这样对传输速率是否有影响?spcomm是否比较快?
希望大家继续关注。

qdyoung (2002-06-12 17:28:00)
spcomm比mscomm好

moodboy (2002-06-12 17:32:00)
to qdyoung:
能否发一份Demo给我?我对spcomm太陌生,加上我水平低,调试不出。谢谢!
to all:
谁还有什么办法使MScomm接收速率快点?其实我很不想改控件了,改了后代码又不同,到
时候CRC还得重新做。

御键飞天 (2002-06-12 17:36:00)
是不是你缓冲区每次没有取尽或计算机读数据的时间间隔过大,造成缓冲区溢出?
亦或是你说的无线通讯中,数据出错?

qdyoung (2002-06-12 17:57:00)
一个磁卡机的例子,还是要自己看懂程序,自己慢慢调试吧:
type
TWriteCardForm = class(TForm)
Comm: TComm;
procedure FormDestroy(Sender: TObject);
procedure CommReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
bWriteCard, bWriteCardResult: Boolean;
function OpenComm: Boolean;
function WriteCard(sText: string): Boolean;
public
{ Public declarations }
end;

implementation

{$R *.DFM}
uses
Utils;

{ 磁卡机状态:
1. 三个灯都亮:电源打开而串口没有打开
2. 绿灯亮:准备好读磁卡
3. 黄灯亮:准备好写磁卡,20秒后超时
4. 红灯亮:出现错误
5. 声音:读写成功或收到电脑信息响一声,失败三声
}

procedure TWriteCardForm.FormCreate(Sender: TObject);
begin
bWriteCard := False;
OpenComm;
end;

procedure TWriteCardForm.FormDestroy(Sender: TObject);
begin
Comm.StopComm;
end;

procedure TWriteCardForm.CommReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
p: array[0..256] of Char;
sText: string;
i: Integer;
begin
if BufferLength < 256 then
begin
Dec(BufferLength); //最后一个BCC字符不要
StrLCopy(p, Buffer, BufferLength);
p[BufferLength] := #0;
sText := '';
for i := 0 to BufferLength - 1 do
if not (p in [#2, #3, '%', ';', '+', '?']) then
sText := sText + p; //从接收到的字符中去掉控制符,得到实际内容
if p[1] = #21 then //错误标志:#2 15h #3 BCC
begin
if bWriteCard then
begin
bWriteCardResult := False;
ShowError('出现错误,写卡失败。请重试!');
end
else ShowError('读卡失败')
end
else
begin
if bWriteCard then
begin
bWriteCardResult := True;
ShowMessage('写卡成功,写的内容是:' + sText);
end
else
begin
if Assigned(ReadCardEdit) and ReadCardEdit.Focused then
begin
ReadCardEdit.Text := sText;
if Assigned(ReadCardEdit.OnEnterPress) then
ReadCardEdit.OnEnterPress(ReadCardEdit);
end
else ShowMessage('从磁卡读到:' + sText);
end;
end;
end
else
begin
if bWriteCard then bWriteCardResult := False;
ShowError('接收的信息超过系统估计的256个字符');
end;
bWriteCard := False;
end;

function TWriteCardForm.OpenComm: Boolean;
begin
Result := True;
if Comm.Handle = 0 then
try
Comm.StartComm;
except
on E: Exception do
begin
Result := False;
ShowError('写卡机故障:' + E.Message, True);
end;
end;
end;

function TWriteCardForm.WriteCard(sText: string): Boolean;
var
sBuffer: string;
BCC: Byte;
i: Integer;
dw: DWord;
begin
Result := OpenComm;
if not Result then Exit;
sBuffer := ';' + sText + '?'#3; //第一轨起始符&quot;%&quot;、第二轨起始符&quot;;&quot;、第三轨起始符&quot;+&quot;、结束符都是&quot;?&quot;,所有数据结束符#3
BCC := 0; //求异或和
for i := 1 to Length(sBuffer) do //
BCC := BCC xor Byte(sBuffer); //
sBuffer := #2 + sBuffer + Char(BCC); //所有数据以#2起始,BCC结束
Result := Comm.WriteCommData(PChar(sBuffer), Length(sBuffer));
if not Result then ShowMessage('系统错误,无法启动写卡过程')
else
begin
Result := False;
BeginWait('开始写卡,请把磁卡划过写卡机...');
bWriteCard := True; //进入写卡状态
bWriteCardResult := False; //写卡结果
dw := GetTickCount;
repeat
Sleep(1);
Application.ProcessMessages;
until not bWriteCard or (GetTickCount - dw > 20000); //超时或完成
EndWait;
if bWriteCard then
ShowError('超时,写卡失败。请重试!') //超时
else Result := bWriteCardResult;
bWriteCard := False; //退出写卡状态
end;
end;


moodboy (2002-06-12 18:01:00)
to 卸健飞天:
怎样才算取尽?我现在还只是人工方式调试,发一次命令就接收一次数据。
数据应该不会有错,我是控制单片机,再由单片机控制无线通讯设备的。单片机发送的
数据为每62字节加一个校验码,前面加一个帧头,最大数据达到64K。我还没有把数据分开
来校验。但接收其它的小数据,校验后是对的。(有很多种数据)

moodboy (2002-06-13 8:43:00)
to qdyoung:
你的发送函数里这句不能通过:s := s + IntToHex(Byte( Text));
下面的代码
procedure TForm1.CommReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
sBuffer, s: string;
begin
sBuffer := '';
SetLength(sBuffer, BufferLength);
StrLCopy(PChar(sBuffer), Buffer, BufferLength);
s := '';
for i := 0 to BufferLength div 2 do
s := s + HexToInt('$' + Copy(sBuffer, i * 2 + 1, 2));
ShowMessage(s);
end;
没有hexToint这个函数吧?

qdyoung (2002-06-13 8:47:00)
s := s + IntToHex(Byte( Text));
->
s := s + IntToHex(Byte( Text), 2);

HexToInt -> StrToInt

moodboy (2002-06-13 9:03:00)
to qdyoung:
strtoint得到整型,s为字符串,怎么行?

moodboy (2002-06-13 9:15:00)
请看看以下代码怎么没反应?是这样发送吗?

procedure TsendForm.Button2Click(Sender: TObject);
var
s: string;
j:integer;
text:string;
begin
text:=memo2.text;
s := '';
for j := 1 to Length(Text) do
s := s + IntTohex(Byte( Text[j]),2);
Comm1.WriteCommData(PChar(s), Length(s));
end;

procedure TsendForm.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
sBuffer, s: string;
i:integer;
begin
sBuffer := '';
SetLength(sBuffer, BufferLength);
StrLCopy(PChar(sBuffer), Buffer, BufferLength);
s := '';
for i := 0 to BufferLength div 2 do
s := s +('$'+Copy(sBuffer, i * 2 + 1, 2));
ShowMessage(s);
end;



qdyoung (2002-06-13 9:19:00)
Chr(StrToInt('$'+Copy(sBuffer, i * 2 + 1, 2)));

moodboy (2002-06-13 12:03:00)
烦,服务器罢工老半天,上来后又说非法操作!
终于上来了!

moodboy (2002-06-13 14:25:00)
本以为中午休息一下醒来后就没事了,看来还是我水平太低。
qdyoung,你调试过吗?

qdyoung (2002-06-13 14:36:00)
还有哪儿有错

moodboy (2002-06-13 14:59:00)
语法没有错,但发送后什么也看不到。
多谢你一直关注!

moodboy (2002-06-13 15:04:00)
qdyoung,能否抽点时间调试一下自发自收?

qdyoung (2002-06-13 15:07:00)
怎么自发自收,串口1连串口2?我没直连线
不可能串口1连串口1
你调试一下看发送的字符对不对,然后检查硬件

moodboy (2002-06-13 15:59:00)
qdyoung,你把一个串口的2、3脚短接就可自收自发了。
硬件不会错,我用MScomm正在调试,能正确收发。只是速度好慢!:(
想不通我的程序到底哪里有错。

moodboy (2002-06-13 16:09:00)
我就用下面的代码调试,结果一点反应也没有。我在Memo2里输入12345,看到发送的s为3132333435,
发送的字符应该没错啊,只是没接收?
procedure TsendForm.Button2Click(Sender: TObject);
var
s: string;
j:integer;
text:string;
begin
text:=memo2.text;
s := '';
for j := 1 to Length(Text) do
s := s + IntTohex(Byte( Text[j]),2);
Comm1.WriteCommData(PChar(s), Length(s));
end;

procedure TsendForm.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
sBuffer, s: string;
i:integer;
begin
sBuffer := '';
SetLength(sBuffer, BufferLength);
StrLCopy(PChar(sBuffer), Buffer, BufferLength);
s := '';
for i := 0 to BufferLength div 2 do
s := s +chr(strtoint('$'+Copy(sBuffer, i * 2 + 1, 2)));
memo1.Text :=s;
ShowMessage(s);
end;



SupermanTm (2002-06-13 16:19:00)
发送对了,hex(1),hex(2)...

qdyoung (2002-06-13 16:29:00)
我这儿没有条件测试,我以前用spcomm很正常的,下面是以上pas代码的form代码
你看看我的属性设置:
object WriteCardForm: TWriteCardForm
Left = 263
Top = 277
BorderIcons = [biSystemMenu]
BorderStyle = bsSingle
Caption = 'WriteCardForm'
ClientHeight = 104
ClientWidth = 330
Color = clBtnFace
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = '宋体'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 12
object Comm: TComm
CommName = 'COM1'
BaudRate = 9600
ParityCheck = True
Outx_CtsFlow = False
Outx_DsrFlow = False
DtrControl = DtrEnable
DsrSensitivity = False
TxContinueOnXoff = False
Outx_XonXoffFlow = False
Inx_XonXoffFlow = False
ReplaceWhenParityError = False
IgnoreNullChar = False
RtsControl = RtsHandshake
XonLimit = 500
XoffLimit = 500
ByteSize = _7
Parity = Odd
StopBits = _1
XonChar = #17
XoffChar = #19
ReplacedChar = #0
ReadIntervalTimeout = 100
ReadTotalTimeoutMultiplier = 0
ReadTotalTimeoutConstant = 0
WriteTotalTimeoutMultiplier = 0
WriteTotalTimeoutConstant = 0
OnReceiveData = CommReceiveData
Left = 24
Top = 32
end
end


moodboy (2002-06-13 18:04:00)
各位高手,问题相当严重!
我用一个VB的调试工具,发现单片机发送完数据后,它就接收完了,在Memo上显示出来。
而我的程序则在单片机发送完后很久才有反应,而且------我的程序竟然没有接收完数据!
我以64个字节为单位校验,发现后面的经常出错,经查,原来是有数据丢失,但用VB的工具
又没有数据丢失。是不是读取缓冲区的问题(MScomm)?
那位愿帮我,我还有几百分全给他,看看我前面的贴就知道了,决不食言。
关于spcomm的问题简直让我吐血!它默认的端口是COM2。不过还是有点问题:
执行到 s := s +chr(strtoint('$'+Copy(sBuffer, i * 2 + 1, 2))); 后提示
“$ is not a valid integer value”
我是不是该走人了?我真的没办法了,希望大家帮帮我。


SupermanTm (2002-06-13 18:08:00)
先不要急,我认为不应该使用SPCOMM,干脆用TCOMPORT算了,MSCOMM的控件在Delphi上用
有问题的

御键飞天 (2002-06-13 20:21:00)
哎!我建议你最好不要用控件了,我好像看过书说MScomm在接收大数据量时可能发生错误,
最好使用底层的API函数吧,给你一段代码,编译一下就行了.
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.


moodboy (2002-06-13 21:07:00)
卸健飞天,你原来做项目的时候有没有这种情况?我用你的接收代码也是一样的慢。是不是
我有哪个属性没设置不对?请指点重要属性设置。
还有,难道VB调试工具没有用自带的MScomm?我学Delphi三个月了,进步很慢,现在转用API
我不知道来得及否,因为还要涉及到CRC校验的问题,我好不容易才搞定字符串的校验啊。


御键飞天 (2002-06-14 8:56:00)
VB是微软的,API也是微软的,它,当然能玩的转了.转用API也并不太难,只是要了解一下函数的意义.
CRC校验只是一些字符的处理,移植起来完全没问题.

moodboy (2002-06-14 9:42:00)
我还是先把贴结了吧。若还不能搞定,下星期再发贴,希望大家继续支持。

moodboy (2002-06-14 9:46:00)
多人接受答案了。

moodboy (2002-06-14 10:34:00)
卸健飞天:
我在richedit1中输入1234而已,点发送后再点接收处理,怎么很久都还在处理中?
它把接收的数据怎样处理?我看不懂。
请各位继续,有价值的我会开贴给分。


qdyoung-60,SupermanTm-30,御键飞天-60,的回答最终被接受。
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部