当前位置:首页 > 嵌入式 > 嵌入式软件
[导读] 串行通讯接口是目前十分流行的通讯接口之一,串口通讯也已是普遍的标准而被大家广为熟悉。基本架构在WinCE中,串口的驱动实现是有固定模型的,其串口模型遵循ISO/OSI网络通

 串行通讯接口是目前十分流行的通讯接口之一,串口通讯也已是普遍的标准而被大家广为熟悉。

基本架构

在WinCE中,串口的驱动实现是有固定模型的,其串口模型遵循ISO/OSI网络通讯模型。在典型的应用中,serialAPI与间接通过TAPI或直接与ActiveSync交互,组成CE网络的一部分。其实整个驱动模型是相当复杂的,好在驱动仅仅使用到SerialAPI这一层,在这个层次上串口的行为相对比较简单。在WinCE中,串口驱动模型是作为Stream来实现的(即:流设备驱动),其架构如图所示:

串口驱动本身分为MDD层和PDD层。

MDD提供框架性的实现,负责提供OS所需的基本实现,它对上层的设备管理器,提供了标准的流设备驱动接口(COM_xxx);而PDD提供了对硬件操作相应的代码,它实现了HWOBJ结构及结构中若干针对于串口硬件操作的函数指针。

DDSI是指MDD与PDD两个部分之间的接口,这个接口是人为的规定的,在串口驱动中实际上就是指HWOBJ,PDD层会传给MDD层一个HWOBJ的结构指针,这样MDD层就可以调用PDD层的函数来操作串口。在实际的驱动应用中仅仅需要实现HWOBJ相关的一系列函数,而无需从驱动顶层完全开发。

通常的串行连接有3wire和9wire两种。3wire的接线方式下定义了发送、接收和地三根连接。而在9wire中将串行连接定义为如下形式。

针号

1

2

3

4

[!--empirenews.page--]5

6

7

8

9

缩写

DCD

RXD

TXD[!--empirenews.page--]

DTR

GND

DSR

RTS

CTS

DELL

功能说明

数据载波检测[!--empirenews.page--]

接收数据

发送数据

数据终端就绪

信号地

数据设备就绪

请求发送

清除发送

振铃指示[!--empirenews.page--]

这就是在原3wire的基础上增加了DCD、DTR、DSR、RTS、CTS、DELL六个控制线。其中RTS/CTS用于流控制,另外的DCD和DELL则留作连接modem使用。有了专门的硬件流控制引脚也就使得流控制成为可能,以完成收发两端的匹配使得数据可以可靠的传输,即实现了流控制,保障了数据传输的完备性。

其他几个引脚都是与modem相关的,DSR数据装置准备好用于表明MODEM处于可以使用的状态。

函数分析

1、HWOBJ

HWOBJ是相应的硬件设备操作的抽象集合,实现了对串口硬件的操作,并在MDD层被调用。

typedef struct __HWOBJ {

ULONG BindFlags;.

DWORD dwIntID;

PHW_VTBL pFuncTbl;

} HWOBJ, *PHWOBJ;

其中,BandFlags用于控制MDD层指定IST的启动时间,MDD正是通过这些函数来访问具体的PDD操作。

dwInitID是系统的中断号。

pFuncTbl则是指向一个PHW_VTBL结构,该结构中包含一个函数指针列表,这些函数指针指向串口硬件操作函数,用于操作串口。

2、MDD

MDD层向上提供了流设备接口,用于管理串口,由Device.exe直接调用。

? COM_Init (ULONG Identifier):

它是该驱动的初始化函数,通过硬件抽象接口HWInit初始化硬件。如果驱动被设备管理器加载,参数Identifier包含一个注册表键值在“HKEY_LOCAL_MACHINE\Drivers\Active”的路径下。

? COM_Deinit(void):

当驱动被称被卸下的时候该事件启动,用作与COM_Init相反的操作。停止在MDD中的所有IST,释放内存资源和临界区等系统资源。

? COM_Open(HANDLE pContext, DWORD AccessCode, DWORD ShareMode):

COM_Oepn在CreateFile后被调用,用于以读/写模式打开设备,并初始化所需要的空间/资源等,创建相应的实例。Open操作完成后,驱动就进入了工作状态。

? COM_Close(DWORD pContext):

COM_Close释放COM_Open所使用的系统资源,停止IST线程,恢复驱动状态。

? COM_Read(HANDLE pContext, PUCHAR pTargetBuffer,

ULONG BufferLength, PULONG pBytesRead):

COM_Read是获取串口所接收到数据的操作,在前面的IST中没有看到对RX buffer进行修改Read标记的操作,也就是这儿来完成的。

? COM_Write(HANDLE pContext, PUCHAR pSourceBytes,

ULONG NumberOfBytes):

COM_Write是与COM_Read相对应的操作,是写串口数据的。应用程序调用WriteFile函数写串口的时候,该函数被调用。在程序的开始,同样也是参数检查,内容与COM_Read一致。其中pContext参数是COM_Open函数返回的Handle。pSourceBytes指向一个Buffer,该Buffer包含要写入串口的数据。NumberOfBytes表示要写入串口的数据的大小。

? COM_PowerUp/ COM_PowerDown (HANDLE pContext):

这两个函数的调用都由CE的电源事件来引发,MDD并没有对这两个函数进行处理,仅仅是将其传递给PDD。

? COM_IOControl (DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DOWRD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut):

该函数主要实现了一些串口的IO控制,他会被应用层的一些串口函数调用来获得或者设置串口的状态。

3、PDD

实际上,在PDD层的主要工作就2个:一是控制硬件;二是和上层打好关系。先说上层接口,上层用了GetSerialHead()来获得接口,所以PDD里面要实现GetSerialHead()的函数,并且将接口返回给上层。

GetSerialObject( DWORD DeviceArrayIndex )

{

PHWOBJ pSerObj;

pSerObj=(PHWOBJ)LocalAlloc( LPTR ,sizeof(HWOBJ) );

if ( !pSerObj )

return (NULL);

pSerObj->BindFlags = THREAD_IN_PDD;

pSerObj->dwIntID = DeviceArrayIndex;

pSerObj->pFuncTbl = (HW_VTBL *) & IoVTbl;

return (pSerObj);

}

PDD层的函数主要是实现了对串口硬件的操作,函数不少,可以参考以下列表:

序号

函数[!--empirenews.page--]

说明

1

GetSerialObject

返回一个指向HWOBJ结构的指针,该结构包含了相关硬件接口函数的函数指针

2

HWClearBreak

清除串口中断状态,用于串口从中断状态恢复

3[!--empirenews.page--]

HWClearDTR

设置串口的DTR管脚为低

4

HWClearRTS

设置串口的RTS管脚为低

5

HWClose

关闭由HWInit函数初始化的设备[!--empirenews.page--]

6

HWDisableIR

禁用串口的红外模式

7

HWEnableIR

启用串口的红外模式

8

HWGetCommProperties[!--empirenews.page--]

重新获得当前串口设备的硬件属性

9

HWGetIntrType

获得当前的中断类型

10

HWGetModemStatus

获得Modem的状态

11[!--empirenews.page--]

HWGetRxBufferSize

获得串口硬件接收Buffer的大小

12

HWGetRxStart

返回硬件接收Buffer的起始位置

13

HWGetStatus

获得硬件状态信息[!--empirenews.page--]

14

HWInit

初始化串口硬件设备

15

HWIoctl

执行I/O控制

16

HWLineIntrHandler[!--empirenews.page--]

线路状态信息中断处理函数

17

HWOpen

打开串口设备

18

HWPowerOff

串口硬件进入Suspend模式

19[!--empirenews.page--]

HWPowerOn

串口硬件从Suspend模式恢复到工作模式

20

HWSetDCB

设置串口硬件设备信息

21

HWSetDTR

设置串口的DTR管脚为高[!--empirenews.page--]

22

HWSetRTS

设置串口的RTS管脚为高

23

HWPurgeComm

清除串口硬件buffer的信息

24

HWPutBytes[!--empirenews.page--]

通过写数据到硬件中来直接发送数据

25

HWReset

复位串口硬件

26

HWRxIntrHandler

接收数据中断处理函数

27[!--empirenews.page--]

HWSetBreak

设置串口为中断状态,停止发送接收数据

28

HWTxIntrHandler

串口发送中断处理函数

非独占式串口驱动

用过串口进行过开发的兄弟们都知道,串口驱动是一个典型的独占设备。简单点来说,就是在成功地调用CreateFile打开串口之后,没有通过CloseHandle进行关闭,是无论如何都不能再次调用CreateFile来再次打开相同的串口,这样做可以避免产生数据丢失,也避免获取数据的线程是反复读取。

但是现在的嵌入式设备功能都非常多,需要非独占式串口驱动,也就是虚拟串口驱动。它主要是处理数据的分发,可以和具体的硬件分开,优势也很明显,可以不用理会具体的硬件规格,只要采用的是WinCE系统,虚拟串口驱动就能正常工作。

在设计驱动的时候需要注意,同一时间只能有一个进程对外输出数据,其余进程只能在该进程输出完毕之后才能进行。当然,程序不应该主动调用ReadFile来轮询获取数据,而是通过WaitCommEvent进行检测。为了不丢失数据,缓冲大小一定要等于或大于READ_BUFFER_LENGTH。

在写代码的时候需要注意一点,WaitCommEvent函数只能被一个线程调用,同一时间只有唯一的一个线程通过WaitCommEvent函数进入等待状态。因此对于IOCTL_SERIAL_WAIT_ON_MASK控制码的处理,可以通过调用WaitForSingleObject进行线程等待。这时虚拟串口驱动会额外开放一个线程,该线程主要是通过调用WaitCommEvent来获取原生串口的状态,当状态有通知时,再发送event给等待的线程。

switch(xxxx){

...

case IOCTL_SERIAL_WAIT_ON_MASK:

{ if(dwBufOutSize < sizeof(DWORD) ||

WaitForSingleObject(g_hEventComm,INFINITE) == WAIT_TIMEOUT)

{ *pBytesReturned = 0;

return FALSE;

} else {

InterlockedExchange(reinterpret_cast(pBufOut), dwEvtMask);

*pBytesReturned = sizeof(DWORD);

return TRUE;

}

}...

多串口扩展

在WinCE应用环境中,对扩展的多串口的编程方法,实际上与标准的串口应用程序完全一样。[!--empirenews.page--]

注意在打开串口号大于9的串口时,需要使用“\\$device\\COMxx”,而不是通常的“COMx:”。

考虑到共享中断的异步特性,各个串口可能同时请求中断,从而产生极高的中断频率,所以建议客户把低波特率的串口通道,如9600bps或以下的波特率,配置在扩展串口上,以均衡CPU对各个硬件设备的开销;相应地把需要使用高波特率的通道配置到嵌入式主板自带的串口通道上,比如:EM9360的COM2-COM7,这些串口均配置有独立的硬件中断。

在WinCE标准的串口驱动程序中,为每个串口分配了2KB的接收数据缓冲区,所以各个串口上层处理线程可参考buffer的深度,采用合适的响应方式,以最大限度的避免线程空转所带来的CPU时间的无谓消耗。

WinCE下的驱动开发减少了开发者的工作量,不过其中还存在很多细节性的问题,动手实践中就能慢慢体会到了。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭