C/S模型在WinCE串口编程中的应用
扫描二维码
随时随地手机看文章
引言
与传统的Windows串口编程技术相比较,WinCE串口编程中不具备串口复用的功能,这给在WinCE系统中实现对串口的复杂操作增加了技术难度。本文介绍一种使用在信息平台软件中常用的C/S模型技术,模拟串口复用的动作来实现WinCE操作系统串口复用的问题。
本方法实现所使用的函数大部分都是嵌入式开发中最常使用的C/C++函数,所有的函数都具有一定的通用性,稍加改动即可应用到其他嵌入式操作系统中;并且该方法实现的思路对于解决其他嵌入式编程中资源复用的难题具有一定参考价值。
1 软件结构及工作原理
1.1 软件结构及特点
为了使WincE操作系统的串口操作支持复用,在本方法中,采用了一种类式信息平台开发经常使用的C/S结构,利用此结构来模拟实现类似于Windows串口的复用功能,即在数据与串口硬件实际控制之间增加了一个C/S结构的中间层。系统整个结构主要包括控制协议、客户端程序和服务器端程序三部分。客户端和服务器端的程序复杂程度与串口操作的复杂程度成正比,在直观上也与控制协议的复杂程度成正比。软件结构图如图1所示。
1.2 控制协议
控制协议的实现属于基础部分,复杂程度与串口的操作复杂程度有关,本文中提到的编程方法只是解决串口的复用部分,即同时对串口发生读写时在编程上的实现。因此在本方法中,实现串口复用的控制协议只需要两部分——串口+数据。串口指的是发生读写动作的串口(co m1,com2,…,comn),数据指的是需要用串口通信的数据。
1.3 服务器端程序流程及工作原理
服务器端程序流程图如图2所示。
从图2中可以看出,整个服务器端程序是由两个线程组成。一个线程用来处理由客户端发起的发送数据请求,符合控制协议的数据先存入预先定义好的发送缓冲区,同时判断对应串口的使用情况。当该串口被占用(串口正在处理上一个发送数据请求或者是正在接收数据)时,此次请求将被挂起一直到串口恢复到空闲状态;串口恢复到空闲状态后该线程将处理最先挂起的请求,将最先存入发送缓冲区的数据通过串口发走。
同时,服务器端程序还要用一个线程来实时监视该串口,将由该串口接收到的符合控制协议的数据存入预先定义好的接收缓冲区,同时通知数据处理线程。
1.4 客户端程序流程及工作原理
客户端程序流程图如图3所示。客户端程序只需将要发送的数据按照控制协议要求整合,将符合控制协议的数据提交给服务器端的程序即可。
2 关键技术
2.1 结构体定义
为实现服务器端程序所有线程的管理,同时方便所有线程之间数据的共享,在创建线程时,对线程传递参数的定义就变得尤为重要。在本方法的实现中定义了一个线程传递参数,定义如下:
2.2 CMapStringToPtr类
CMapStringToPtr类是MFC集合类中的一个模板类,也称为“字典”,就像一种只有曲列的表格,一列是关键字,一列是数据项,它们是一一对应的。关键字是唯一的,给出一个关键字,映射表类会很快找到对应的数据项。映射表的查找是以哈希表的方式进行的,因此在映射表中查找数值项的速度很快。该类最适用丁需要根据以CString对象为关键字进行快速检索的场合。
为便于缓冲区和句柄的索引,在本方法的实现中使用CMapStringToPtr类的对象来管理线程和缓冲区的句柄。
2.3 CEvent类
CEvent类的一个对象,表示一个“事件”——一个允许一个事件发生时线程通知另一个线程的同步对象。在一个线程需要了解何时执行任务时,事件是十分有用的。例如,拷贝数据到数据文档时,线程应被通知何时数据是可用的。当新数据可用时,通过运用CEvent对象来通知拷贝线程,线程才可能尽快地执行。
另一个使用CEvent对象的方法是添加一个CEvent类型的变量,使之成为希望控制的类的一个数据成员。在控制对象被构造期间,可调用CEvent数据成员的构造函数,它指明时间是否是最初就被标记、需要的事件对象类型、事件名称(如果在进程中要使用)和所希望的安全属性。
此外CEvent对象还可以保护控制的资源,使该资源在一个时间里只可被一个线程访问;使用时要先在资源访问成员函数中构造一个CEvent类型的变量,然后调用封锁对象的Lock成员函数。此时,线程要么等待资源释放后访问;要么等待资源释放而超时,访问资源失败。在各种情况下,资源都被以线程安全方式访问。
总之,该方法实现的关键技术主要包含3个线程、结构体定义、CMapStringToPtr成员、CEvent成员和控制协议。
3 实现和应用
基于上面的讲述,为了使用方便,将其所有的数据成员和方法封装成一个类。本文所有代码的实现使用的开发环境为EVC4.0,由于篇幅的关系,新建类的方法和开发环境的使用细节请详阅参考文献;对于在代码中出现的API函数的一些用法和参数说明可以详阅参考文献;想对WinCE嵌入式系统有进一步了解,可以仔细阅读参考文献。
使用EVC4.0的Class wizrd插入一个新类,之后将上述代码加入,使用时只需在程序开始时涮用AfxGetSerMsgQ()->Open()函数来打开串口,此时即可对相应的串口数据进行实时处理,同时不影响其他线程对该串口的使用;当其他线程使用该串口时,只需调用AfxGetSerMsgQ()->WriteBuffer()函数来发送数据,调用AfxGetSerMsgQ()->ReadData()函数来读取数据即可。同时,这两个函数的调用不会影响相应串口数据的实时接收,完全实现了串口的复用功能。
结语
本文提到的方法不但解决了WinCE操作系统不支持串口复用的问题,而且实现代码简单、通用性强,对于解决其他资源复用问题同样有效。本文提到的方法已经在实际产品中应用,解决了实际的工程问题。该方法实现的代码具有通用性,只需修改少量代码就可以应用到其他嵌入式系统软件代码设计当中。