高分求解并口接收数据问题,急急急!(300分)

  • 主题发起人 主题发起人 qinqijun
  • 开始时间 开始时间
Q

qinqijun

Unregistered / Unconfirmed
GUEST, unregistred user!
现有一程控电话交换机,当有通话发生时会通过并口线向打印机发送数据。每次发送一行,
内容有起始时间、结束时间、电话号码等。现在要求不用打印机,用电脑来接收交换机发送
过来的数据。由于电脑和交换机的并行接口都是凹的,所以在下就自己做了一跟并口线,两
头都是凸的,里的的铜芯线跟据颜色对应焊接起来的。
有哪位高手做过的请指教,最好能提供现成的控件(DELPHI6)版的。
有示例程序或控件请附带使用说明发至信箱:qinqijun@163.com或qinqijun@163.net。
调试通过马上划分!
 
用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.

 
提醒你注意一点,dte和dce的通讯连接的方法是不一样的。如果你按照一一对应的方式
连接是不行的。请参考pc 与 pc 之间并口互连线的制作方法。

甲机25针并口
连接到
乙机25针并口

第2针
连接到
第15针

第3针
连接到
第13针

第4针
连接到
第12针

第5针
连接到
第10针

第6针
连接到
第11针

第11针
连接到
第6针

第10针
连接到
第5针

第12针
连接到
第4针

第13针
连接到
第3针

第15针
连接到
第2针

 
rainxy2002,我是问的是并口,串口通讯用CreateFile()函数进行操作我已经做过了。
而且你好象是抄书的吧?
 
Zero_Cool,多谢你担提醒我这个错误,不过我不知道从哪边数起。
七针在上,八针在下,从焊接的一头看我的接头如下图(几个E表示那八针是焊在一起的):
--------------
ABCDEEEEEEEE
FGHIJKLMNOPQR
--------------
随便说明一下,我不是要两台机子对联,我是要把电脑当成打印机来接收电话交换机发送过来的打印数据,这样子真的行得通吗?
 
qinqijun:
早上是你发的邮件么? 例子和接线发给你了
 
Zero_Cool,前面我说错了,电脑和交换机的并口是凸的,线两端的接口是凹的。这个我想没什么影响的吧?
 
tseug你说的是并口接收数据的例子吗?
 
tseug。
邮件已收到,但是不懂得怎么接线。你能象我之前发的一贴那样用图示说明一下子吗?
 
我也正在做一个通过并口从一个集成块中读数据的程序,用SmallPort控件,还不知道能否实现。
哪位做过类似的程序?SmallPort能对并口的各个管脚都读和写吗?我明天才能测试一下。
 
楼上研究出来了也发一份给我呀?
 
我不会并口操作,但我遇到过类似程控计费问题(还是DOS时代),
俺用一个傻办法解决,买一个并转串的转换器即可。
 
呵呵,人人做计费都是串口的了。哪会用并口。
235-237接线。
 
gong666,你真的是我的救星!去哪里有并串口转换器买呀?
 
TO kkyy
我不是做计费,我只是用电脑接收传给打印机的打印数据!
 
并口作为输出时有三种模式:spp,epp,ecp,
spp模式下d0-d8只能用于输出,不能输入,此时一般用其控制信号线作为输入(原来dos
6.0下有一个软件就是这样工作的);
ECP/EPP为增强模式,d0-d8可以用于输入,但对于打印机来说,原交换机输出信号中
有一部分控制信号也需要检测,因此要把接收计算机的输出信号接交换机的输入
信号,输入信号脚接交换机的输出,就是用计算机模拟打印机,产生一定的信号
使交换机认为打印机准备好并向其输出。

要使并口进入ecp模式,首先要在计算机CMOS中设置为ECP模式,然后才能对并口进行
操作。
但读写地址不同:在spp下数据口地址为378H,控制地址为379H,状态检测地址为37AH
(后两个可能反了,我记得不太清楚了),而ECP的地址在数据口地址为378H+0AH,实际
还有几个命令地址要写入使其开始工作。
找一下老书,找本关于用计算机模拟打印机的文章看看就OK了。

还有个建议,做一个小电路用2051就足够了,把并口输入获取后(d0-d8,7个控制信号)
要处理的信号不多,把控制信号处理后,把d0-d8通过串口给计算机。
我以前就是这样解决一个程控记费的问题。用单片机模拟打印机在不少51的微机原理
书上有。
 
并口转串口纯属胡说,解析打印输出的数据流需要耐心,
我还没用见过类似的工具,而且这样的实现在nt/2000平台上必须开驱动程序
 
一种方式使用25->9针的方式试试(若他们使用的数据流正好和9针的时候一样)
 
发给打印机的数据你转成串口就可以接收了,
因为一般交换机输出的都是纯文本,串口收和并口收是一样的。
只有华为的那些乱七八糟的东西发十六进制东西,你可要好好看了。呵呵。。
 
后退
顶部