用C++Builder4.0编写Win 95下的串行异步通信程序 姜滨 ·串口操纵的基本方法· 在Win32下，对串口的操作就如同对文件一样打开或关闭，对串行数据的读写可在用户定义的读写缓冲区中进行。具体使用的函数为： 首先用CreateFile( )打开通信串口，其中参数lpFileName指向串口逻辑名，如“COM1”或“COM2”等，参数dwDesiredAccess定义文件的读写权限，一般设为GENERIC—READ|GENERIC—WRITE；参数dwShareMode定义资源共享方式，此处必须设为0，为独占方式；lpSecurityAttributes定义安全属性，Win 95下为NULL；dwCreationDistribution定义文件创建方式；dwFlagsAndAttributes定义文件属性和标记，应设为FILE—FLAG—OVERLAPPED，表示异步通信方式；hTemplateFile 指向一个模板文件的句柄，在 Windows 95下为NULL。 然后用BuildCommDCB( )和SetCommState( )函数通过通信设备控制块DCB（Device Control Block）设置串口通信参数(如波特率、停止位、数据位、校验位等)，其中BuildCommDCB( )中的字符串参数lpDef 定义同DOS命令中MODE的参数格式，关于DCB更具体的设置需要根据用户对数据流定义、握手信号及通信控制要求具体定义，参见有关Windows技术资料。用GetCommState()可以得到当前的DCB参数值。如果需要还可通过SetCommTimeouts()和GetCommTomeouts()重新设置读写的超时参数；读写缓冲区的设置使用SetupComm()，参数dwInQueue和 dwOutQueue分别定义为输入和输出缓冲区的大小。 在串口初始化完毕后，还要建立与通信有关的事件对象。一般使用CreateEvent()函数，它返回一事件句柄，其中参数lpEventAttributes指向安全属性结构地址，在Win 95（无安全属性）中为NULL；布尔参数bManualReset 定义事件重置方式，true 表示手工重置，false表示自动重置（相关函数为SetEvent()和ResetEvent()）；参数bInitialState定义事件初始状态，true表示发信号，否则为不发信号；lpName是为多进程设置的事件名，对于单进程定义为NULL。然后用SetCommMask()定义用户程序可监视的通信事件类别。 以上设置完成后，用户程序就可以等待通信事件的产生，一般调用函数WaitCommEvent()监视通信事件，其中参数lpEvtMask指向产生事件的掩码地址，用于判断事件产生的性质，lpOverlapped指向重叠结构地址，可简单定义为NULL。对于串口事件的响应一般有四种方式：查询、同步I/O、异步I/O和事件驱动I/O，需要根据用户不同控制要求而定。查询方式占用较长的计算机时间，同步I/O方式直到读取完指定的字节数或超时时才返回，容易造成线程阻塞，异步I/O用于后台处理，事件驱动是由系统通知用户程序发生的事件并进行串口操作。 比较而言事件驱动I/O方式较灵活。 当有通信事件产生时，就可用函数ReadFile()和WriteFile()直接对串口缓冲区进行读写操作了。其中lpBuffer 指向读写缓冲区，nNumberOfBytes为要读写的字节数，lpNumberOfBytes为实际读写的字节数，lpOverlapped指定同步或异步操作。通信结束后，调用函数CloseHandle()将串口关闭。 ·应用实例说明· 使用以上的API函数，笔者给出了简化后的串口初始化的实例。图1为使用C＋＋ Builder 组件生成的串口通信基本参数设置的界面实例。 HANDLE hcom; //定义句柄 DCB dcb; OVERLAPPED e; //定义重叠结构 void —fastcall TForm1::OkBtnClick(TObjectSender) { hcom=CreateFile("COM2",GENERIC—READ|GENERIC—WRITE,0,NULL,OPEN—EXISTING, FILE—ATTRIBUTE—NORMAL|FILE—FLAG—OVERLAPPED,NULL); //打开通讯口 BuildCommDCB("9600,O,8,1",＆dcb); //第一个字符串参数实际使用时由图1选择后组合，这里仅简单说明其格式 SetCommState(hcom,＆dcb); SetupComm(hcom,512,512);//设置读写缓冲区 e.hEvent=CreateEvent(NULL,false,false,NULL); //设置事件 SetCommMask(hcom,EV—RXCHAR| EV—TXEMPTY); //设置事件掩码 OkBtn－〉Enabled=false;}