写程序直接用串口传文件能达到的最大速率!(50分)

  • 主题发起人 主题发起人 Jack.wu
  • 开始时间 开始时间
J

Jack.wu

Unregistered / Unconfirmed
GUEST, unregistred user!
好象看了一下Windows内对串口的设置最大只能至!28kbps(这里有个疑问,b是指Bit还
Byte),要是Bit那不是很慢,并口呢?我在这里问了好长时间并口通讯方面的东东,为什
么都没人回答啊?
 
应该是115200bPS,是bit,确实不快。
 
老兄串口并口WINDOWS直接支持联网的,为什么不先联网再说其他呢?
PS:串口并口都很慢的,如果不用网卡的话,也该用USB啊。重新考虑一下你的方案吧。
 
To lps:
我的目的不是为了联网,
我是要作一个简单的网络隔离的一个程序,
两台PC间用文件交换,不用任何的网络协议,
现在市场上USB连线好象都要有专用的程序才能传文件,
他们提供开发库吗?
我在上海,
你有QQ或是MSN吗?急切想与您讨论!
 
To lps:
已给您发信,请收!
 
》》我是要作一个简单的网络隔离的一个程序
我还是不太明白你要做什么
网络有协议。串口、并口、USB也需要协议(就算是自己的协议也不可能没有)。那么
你[red]为什么不用协议[/red]呢?
 
可能是我没表述清楚,
我说的协议是指TCP/IP,IPX等,
我想你指的串口、并口、USB的协议应该是驱动程序吧?
为什么不用协议我想不需要在这表述,
反证我现在需求就是直接用并口 or 串口 or USB直接在两台PC间传文件,
两台PC上不能安装任何的网络协议(如TCP/IP,IPX之类;
 
应该是115200bPS,bit
但是这个速度也是不可靠的,所以传输速度在这个速度的2/3比较合适
要根据下位机的情况确定
 
1.方案
请思考一下为什么不能安装任何的网络协议(如TCP/IP,IPX之类)?有这个必要吗?
2.传送文件
比如A机的文件发至B机,A、B两机则各要一个程序,他们通信,A机读磁盘文件,把
数据组装(类似帧,姑且称帧),和B机通信,一次发送一帧或多帧,B机收到发确认帧,
收完后再把帧拆分成文件,写入磁盘。这不是协议是什么?有必要自己搞一个吗协议?
3.控件
我不知道有无这种控件的,但我们传送文件完全可以在网络的基础上开发,搞出来的
东西不会太复杂或稳定性还无法保证。并口 or 串口 or USB都提供了网络的支持,本来就
是应该这样二次开发。请考虑一下!
 
To lps:
如果你做过证券方面的开发,
你就会很能理解为什么不能用任何网络协议,
其实这只是个非常简单的网络硬件隔离的概念,
只是我们用的方法是比较土,但是最简单,最廉价的。
你说的2,我懂,我原来一直都是用Socket做数据采集的,
所以我原来的文件传送协议比你这个定的要复杂的多。
 
下面摘自《Delphi之未经证实的葵花宝典version 2.1》,由hubdog整理,供你参考
PS:[blue]网络硬件隔离[/blue],我上网查了一下,觉得你的思路也谈不上网络硬件隔离
-------------------------------------------------------------------
用DELPHI进行 Win32环境下串行通讯的程序设计
张秀德 姜新通 张冬生


摘要 由于在Delphi环境中没有提供通讯控件,本文介绍了用Delphi4.0实现的Win32环境下基于线程的串行通讯程序设计,能适当降低数据丢失率以及提高系统可靠性,并给出了一个通讯程序实例。

关键词 串行通讯 多线程 程序设计

在自动化工业控制应用中,经常需要计算机与外围设备进行数据通讯。而异步串行通讯是一种常用的通讯手段。在单任务操作系统中,不能同时处理两件以上不同的任务。Win32是基于线程的多任务操作系统,使得应用程序能同时执行多个任务,即在一个进程中可同时运行多个线程。利用Win32的这个特点,在通讯过程中可以适当降低数据丢失率,提高系统可靠性。

随着Win95系统的逐步普及,程序员们更愿意在Win95下编程。而Delphi也越来越为广大程序员所喜爱。然而,令人遗憾的是在Delphi环境中没有象其它的一些编程语言一样提供标准通讯控件。因此,利用Delphi进行通讯程序设计时,不但要掌握多线程编程技术,还要了解一些与通讯相关的API函数的使用。

一 多线程基本概念

首先介绍进程概念。一个进程通常定义为程序的一个实例。在Win32中,进程占据4GB地址空间。实际上,一个进程可以包含几个线程,它们可以同时执行进程的地址空间中的代码。为了运行所有这些线程,操作系统以轮转方式为每个独立线程分配一些CPU时间片。这给人一种假象,好像这些线程是在同时运行。创建一个Win32进程时,它的第一个线程称为主线程,由系统自动生成。然后可由主线程生成其它的线程,这些线程又可生成更多的线程。

线程描述了进程内的执行,是组成进程的基本单位。每次初始化一个进程时,系统创建一个主线程。通常对于许多应用程序,主线程是应用程序的唯一线程。但是,进程也可以创建额外的线程,目的在于尽可能充分合理的利用CPU时间。线程可以使用CreateThread()函数来创建。

在有若干线程并行运行的环境里,同步各不同线程活动的能力是非常重要的,这样可以避免对共享资源的访问冲突。事件对象是同步线程的最基本形式,它用以向其它线程发信号以表示某一操作已经完成。例如,一个进程可能运行了两个线程。第一个线程从文件读数据到内存缓冲区中。每当数据已被读入,第一个线程就发信号给第二个线程它可以处理数据了。当第二个线程完成了对数据的处理时,它可能需要再次给第一个线程发信号以让第一个线程能够从文件中读入下一块数据。事件可以使用CreateEvent()函数来创建。线程和事件在任何时候都处于两种状态之一:有信号和无信号。当线程被创建和正在运行时,它是无信号的。一旦线程终止,它就变成有信号的。线程可以通过使用SetEvent()和ResetEvent()函数来将事件置成有信号和无信号。

除了以上介绍的概念和函数,在通讯程序中还要用到等待函数WaitForSingleObject()和重叠I/O操作。等待函数能使线程阻塞自身执行,而重叠I/O操作能使费时的操作在后台中运行。

二 通讯程序设计

在Windows环境下,对于串行通讯的控制是通过中断机制驱动的,由系统自行处理。Windows禁止应用程序直接和硬件打交道,程序员只能使用Windows提供的标准函数通过通讯驱动程序与硬件接口。首先,用CreateFile()函数打开通讯端口,然后通过SetupComm() 函数给通讯的输入输出队列分配一定大小的内存缓冲区,接着通过BuildCommDCB()函数 和SetCommState()等函数对主要通讯参数进行设置。初始化完成后就可以利用ReadFile()函数和 WriteFile() 函数对通讯端口进行读写操作了。程序界面如图所示。

本文提供的实例程序使用简单方便。利用一条串行数据线连接在两台计算机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.Windows95 Windows NT3.5高级编程技术 Jeffrey Richter著

2.基于Windows 95&amp;NT的串行通信编程 李柯 <<微电脑世界>> 1997。5

3.Windows 95中的串行通信 王齐 <<微电脑世界>> 1997。3


 
看来只有试试串口了
 
try this

http://www.51delphi.com/delphi/soft?type=通信
 
后退
顶部