基于API函数的串口通信(方法讲解)

来源:互联网 发布:淘宝电脑版怎么找相似 编辑:程序博客网 时间:2024/05/17 07:37

 

用到的串口通信编程方法有:使用通信控件、在高级语言中嵌入汇编以及使用API函数。在这几种方法中,使用API函数编写的串口通信程序最为高效、灵活。串口通信编程将用到三种API函数

——串口通信相关API函数、多线程API函数和实现消息机制的API函数,下面将分别介绍这几种API函数。

1与串口通信有关的API函数

  Windows系统通信一般都以 Windows开放式服务体系 型为基础,在此模型中位于上层的应用程序通过调用各种通信API下层的设备驱动程序进行数据交换。下面将按一般串口通信程序的流程顺序介绍这些API。

1.1打开串口

  Win32操作系统把串口看作一个文件,因此打开串口我们将要用到Createfile函数。该函数第一个参数指明要打开的文件名称,对串口操作来说,就是COM1/COM2等。第二个参数为读写模式设置,因为要对串口进行读写,所以该参数应设为GENERIC_READ/GENERIC_WRITE 。第三个参数值必须为0,表示不将串口与其他应用程序共享。第四个参数指向一个SECURITY_ARRTIBUTE结构,通常设为NULL。第五个参数指定如何打开文件,在打开设备(串口是一种设备)时,此参数必须指定为OPEN_EXISTING第六个参数指定文件属性及相关标  志,但是对于串行口,唯一有意义的设置是FILE__FLAG_OVERLAPPED 或0;最后一个参数必须为NULL。若该函数打开串口成功,则返回创建的句柄,该句柄供随后对串行口的设置、读写等操作用;否则返回INVALID_HANDLE_VALUE。

1.2设置串口

  串口打开后,即可进行一系列初始化设置。最基本的初始化设置将通过 GetCommState和SetCommState函数来实现。先调用GetCommState函数获取当前串口配置填充设备控制块(DCB),然后将DCB结构中几个重要参数如波特率、数据位、停止位、校验位改成符合实际设计要求的值,最后用SetCommState将刚刚所做的改动重新设置串口。

   串口I/O缓冲区的大小用SetUpComm函数设置。通信速率越高,缓冲区应设置得越大,但不能超出设备驱动程序所能 处理的范围。另一个很重要的设置是串口超时设置。通信中因未知原因将出现不可预测的事件,譬如:接收数据过程中突然被中断,或者发送数据突然停止等。如果不认真对待,这些情况可能会引起I/O线程挂起或者线程被无限阻塞。Windows对于这类问题提供了安全措施,它可通过超时设置来决定通信是否异常并作相应处理,因此超时设置在串行通信中显得尤为重要。超时设置过程分为两步,首先设置CommtimeOuts结构中的五个成员,然后调用SetCommOuts函数设置超时值。CommtimeOuts结构的五个成员分别是:读串口间隔超时、读串口总超时乘数、读串口总超时常数(ms)、写串口总超时乘数、写串口总超时常数(ms)。

1.3读写串口

  设置工作完成后,即可用ReadFile和WriteFile对串口进行读写操作。在调用读写操作函数之前,应先用ClearCommError 函数清除错误标志和获取当前串口状态。

    分为同步和重叠I/O(异步)。同步执行时,函数直到操作完成后才返回;重叠I/O操作时,即使操作尚未完成,调用的函数也会立即返回,费时的I/O操作在后台进行。可见,同步操作线程被阻塞,效率低,只能用在对通信要求比较低的场合,我们一般用到的都是效率较高的重叠I/O操作。前面提到的CreateFile函数第六个参数设置为FILE_FLAG_OVERLAPPED即可指定WriteFile 和 ReadFile函数为重叠I/O执行。使用重叠I/O还需为读写函数指定一个OverLapped结构,该结构有五个数据成员,对串口通信来说,其中的OffSet和hEvent成员是很重要的。OffSet指示文件指针偏移量,在重叠I/O操作时系统不能自动维护文件指针,所以要靠OffSet在程序中手动调整文件指针。而hEvent标志读写操作是否完成。若操作完成,则将hEvent置为信号态;否则即置为非信号态。最后要说明的是,在重叠I/O操作时,读写函数返回值是FALSE并不能说明操作失败,应该调用GetLastError函数分析返回结果。如果 此时GetLastError 函数返回值是ERROR_IO_PENDING,则说明操作未完成(并不是操作失败)。

      我们将用等待函数来等待操作的完成。典型的两个等待函数有WaitForSingleObject和GetOverLappedResult。函数的相同之处为都是等待读写操作指定的OverLapped结构hEvent成员置为信号态(即代表操作完成);不同之处是WaitForSingleObject 是可设置超时,但无法得到重叠I/O操作的结果,GetOverLappedResult用来得到重叠I/O操作的结果,但无法设置超时。因此,我们经常两者结合起来使用,在用WaitForSingleObject等待操作结束后,用GetOverLappedResult得到操作结果。

1.4关闭串口

  串行口是非共享资源,某应用程序打开串行口后,即独占该资源,使其它应用程序无法再访问,直到该应用程序释放串口。所以对串口操作完成后,一定要关闭串口。关闭串口使用CloseHandle函数,该函数唯一参数即为用CreateFilee打开串口时所创建的句柄。

2多线程API函数

  Windows是多线程 、抢先多任务的 。Windows中,一个可执行程序的运行时刻实例称为进程。

一个进程可以有多个线程,Windows是按照线程分配CPU时间片的,而分配的机制就是抢先多任务方式。

  对于读写串口这种耗时的工作,使用多线程技术,创建辅助线程来管理串口是一个常用的方案。这样在进行串口读写的同时,能对读入的数据进行处理。如果使用单线程,就需要等待串口读写操作完成,整个进程都被阻塞。而使用多线程就可以避免这种情况。

  多线程也会带来一些新的问题,其中的一个问题就是线程的同步,如果同步问题解决不好,程序的稳定性会受到很大的影响。通常用到的几种线程同步的方法有互斥体对象、利用信号、利用事件对象和设置临界区。笔者在实际应用中使用的是事件对象结合Windows消息机制使线程同步,收到了很好的效果。

  创建线程函数为CreateThread,用SuspendThread和ResumeThread函数来挂起和唤醒线程。创建事件函数为CreateEventt,用SetEvent和ResetEvent函数来将事件置为信号态和非信号态,以此来同步线程。串口通信的辅助线程管理经常还要用到SetComMask和WaitCommEvent函数。SetComMask用来指定一系列事件监视串口,比如监视串口是否有数据收到;WaitCommEvent则用来等待指定的事件发生。笔者在实际应用中,就是在辅助线程中用SetComMask指定串口监视接收数据事件,然后用WaitCommEvent等到串口真的接收到数据时,用PostMessage发出消息通知主线程,由主线程处理接收到的数据。

  3 实现消息机制的API函数

  Windows是一个消息驱动操作系统,简单的说消息就是指通过输入设备向程序发出的指令以要求

  其执行某个操作。具体的操作由消息处理函数实现。用户可以自定义消息在线程之间传递。把WM_USER(它的值等于0*0400)当作基数,然后顺序地去加序号,譬如:

  WM_COMMNOTIFYequ WM_USER+100h(小于WM_USER的值是Windows系统的保留值,大于该值留给用户来使用)。

  前一节已经提到在串口通信编程中对消息机制的利用,这里将继续说明怎样实现消息机制。由于笔者使用的编程工具是Borland公司的C++Builde(BCB)r,因此对于消息机制的实现有其特殊之处。在BCB中实现消息的方法有三种:使用消息映射 MeaageMap 重载TObject的Dispatch虚成员函数;重载TControl的Wndpro方法;重载Application的OnMessage方法。其中以第三种方法最快,因为一般情况下, 会为每个程序自动生成一个TApplication类的实例,消息到达BCB程序时,最先得到它们的就是TApplication对象。经由TApplication之后,才传递给Form的。前两种方法都是重载TForm的方法,显然比直接重载Application的OnMessage方法要晚一些收到消息。我们要做的只是定义好自己的消息处理函数:

  void__fastcall TForm1 MyOnMessage tagMSG &Msg

bool&Handled 

  TMessageMessage

  switch(Msg.message) 

  caseWM_COMMNOTIFY

  Message.Msg=Msg.message;

  Message.WParam=Msg.wParam;

  Message.LParam=Msg.lParam;

  //此处添加处理该消息的代码

 Handle:=true;

Break;  

  然后在窗口创建时用自定义的消息处理函数重载Application 的OnMessage方法:

  void__fastcall TForm1 FormCreate(TObject Sender) 

  Application->OnMessage =MyOnMessage  ;

  这样就可以在程序中收到自定义的消息并作出相应处理。

  值得注意的是,使用Application->OnMessage并不能捕获非队列消息,它无法捕获使用SendMessage直接发送给窗口的消息,这是因为其不通过消息队列。但可以使用另一个发送消息的API函数——PostMessage,该函数发出的消息是队列消息。

  4 结束语

  利用多线程、消息机制和重叠I/O的API函数进行串口编程的方法,可实现串口通信的实时高效,为开发Windows系统下串口驱动程序提供了有益参考。

0 0
原创粉丝点击