热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

基于API函数的串口通信编程(转载)

基于API函数的串口通信编程用到的串口通信编程方法有:使用通信控件、在高级语言中嵌入汇编以及使用API函数。在这几种方法中&

基于API函数的串口通信编程

 

 

 

用到的串口通信编程方法有:使用通信控件、在高级语言中嵌入汇编以及使用API函数。在这几种方法中,使用API函数编写的串口通信程序最为高效、灵活。串口通信编程将用到三种API函数——串口通信相关API函数、多线程API函数和实现消息机制的API函数,下面将分别介绍这几种API函数。

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

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

  1.1 打开串口

  Win32操作系统把串口看作一个文件,因此打开串口我们将要用到CreateFile函数。该函数第一个参数指明要打开的文件名称,对串口操作来说,就是COM1、COM2等。第二个参数为读写模式设置,因为要对串口进行读写,所以该参数应设为GENERIC_READ|GENERIC_WRITE。第三个参数值必须为0,表示不将串口与其他应用程序共享。第四个参数指向一个Security Attribute结构,通常设为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结构中的五个成员,然后调用SetCommTimeouts函数设置超时值。Commtimeouts结构的五个成员分别是:读串口间隔超时、读串口总超时乘数、读串口总超时常数(ms)、写串口总超时乘数、写串口总超时常数(ms)。

  1.3 读写串口

  设置工作完成后,即可用ReadFile和WriteFile对串口进行读写操作。在调用读写操作函数之前,应先用ClearCommError函数清除错误标志和获取当前串口状态。读写操作分为同步和重叠I/O(异步)。同步执行时,函数直到操作完成后才返回;重叠I/O操作时,即使操作尚未完成,调用的函数也会立即返回,费时的I/O操作在后台进行。可见,同步操作线程被阻塞,效率低,只能用在对通信要求比较低的场合,我们一般用到的都是效率较高的重叠I/O操作。前面提到的CreateFile函数第六个参数设置为FILE_FLAG_OVERLAPPED即可指定Read File和WriteFile函数为重叠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等待操作结束后,用GetOverlap-pedResult得到操作结果。

  1.4 关闭串口

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

  2 多线程API函数

  Windows是多线程(multi-threaded)、抢先多任务的(preemptible )。Windows中,一个可执行程序的运行时刻实例称为进程(process)。一个进程可以有多个线程(thread),Windows是按照线程分配CPU时间片的,而分配的机制就是抢先多任务方式。

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

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

  创建线程函数为CreateThread,用SuspendThread和ResumeThread函数来挂起和唤醒线程。创建事件函数为CreateEvent,用SetEvent和ResetEvent函数来将事件置为信号态和非信号态,以此来同步线程。串口通信的辅助线程管理经常还要用到SetCommMask和WaitCommEvent函数。SetCommMask用来指定一系

 

  列事件监视串口,比如监视串口是否有数据收到;WaitCommEvent则用来等待指定的事件发生。笔者在实际应用中,就是在辅助线程中用SetCommMask指定串口监视接收数据事件,然后用WaitCommEvent等到串口真的接收到数据时,用PostMessage发出消息通知主线程,由主线程处理接收到的数据。

  3 实现消息机制的API函数

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

 

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

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

  前一节已经提到在串口通信编程中对消息机制的利用,这里将继续说明怎样实现消息机制。由于笔者使用的编程工具是Borland公司的C++ Builder(BCB),因此对于消息机制的实现有其特殊之处。在BCB中实现消息的方法有三种:使用消息映射Message Map重载TObject的Dispatch虚成员函数;重载TControl的WndProc方法;重载Appli

 

  cation的OnMessage方法。其中以第三种方法最快,因为一般情况下,BCB会为每个程序自动生成一个TApplication类的实例,消息到达BCB程序时,最先得到它们的就是TApplication对象。经由TApplication之后,才传递给Form的。前两种方法都是重载TForm的方法,显然比直接重载Application的OnMessage方法要晚一些收到消息。我们要做的只是定义好自己的消息处理函数:

  void __fastcall TForm1MyOnMessagetagMSG &Msg

bool &Handled

  

  TMessage Message

  switch(Msg.message)

  

  case WM_COMMNOTIFY

  Message.Msg=Msg.message;

  Message.WParam=Msg.wParam;

  Message.LParam=Msg.lParam;

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

  Handled=true;

  break;

    

  

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

  void __fastcall TForm1FormCreate(TObject Sender)

  

  Application->OnMessage = MyOnMessage;

  

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

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

 

  4 结束语

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

  参考文献

  1 范逸之.江文贤.陈立元.C++ Builder与RS-232串行通信控制[M].清华大学出版社,2002

  2 黄军等.Delphi串口通信编程[M].人民邮电出版社,2001

3   张志明.李蓉艳.王磊.WIN32环境下串行通信编程技术研究[J].《计算机应用研究》 2002;9

 

转:https://www.cnblogs.com/enterBeijingThreetimes/archive/2008/12/18/1357550.html



推荐阅读
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • SAP羞辱国产软件商:技术停在10年前
    SAP中国研究院总裁芮祥麟表示,国产软件厂商过于热衷概念炒作,技术水平停留在10年前的客户端架构水平。他认为,国内厂商推出基于SOA的产品或转型SAAS模式是不可能的,研发新架构需要时间。当前最热门的概念是云计算,芮祥麟呼吁国产厂商应该潜心研发底层架构。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
author-avatar
嘻嘻2502891803
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有