用于与串口设备通讯的NET基类CommBase

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

转:使用P/Invoke来开发用于与串行设备通讯的.NET基类=true#Post本文相关代码下载:NetSerialComm.exe(89KB)导引:在.NET环境下编写与RS252串口通信的应用程序的唯一方法,就是引用过时了的并且有点限制的MSCommActiveX控件。这篇文章介绍了用C#安全代码编写一个多线程的,且时尚的与RS232通讯的基础类库。这个类库使用平台调用服务(即PlatformInvocationServices)来与Win32API直接交互。程序员可以通过继承在任何.NET语言下使用这个类库;这个文章还探讨了一些用C#和VisualBasic.NET写的示例程序。微软.NET框架类库(FCL)提供了相当全面广泛的功能来替代在Win32@API编程下原有的功能,特别是C#与VisualBasic@.NET语言的可互访性。尽管如此,RS232串口通讯是.NET框架类库是明显未被涉及的方面之一。从而很正常的,很多人就把这些接口当成了遗弃物。目前,你还是通过软件层与串行调制解调器进行通讯,比如TAPI与PPP。其它从前使用这些接口的设备现在正在向USB接口移植。不过,一些专业的RS232设备的驱动程序仍然有通讯的需要,比如GPS接收器,barcodeandswipecardreaders,可编程控制器和一些可预见的程序员将来继续使用的设备。(关于RS232接口的规格信息,可以参看HardwareSpecs.)平台调用服务(P/Invoke)是能够使用托管的CLR代码调用非托管DLLs的.NET技术,包括那些实现Win32API的DLLs。在这篇文章里,我将用C#把与RS232通信的API封装到CLR托管的代码中去。生成的基类库将使用.NET语言开发特定设备的驱动变得相对容易。完整的代码和示例可以从这篇文章顶部的链接中下载到。设计原理在把Win32串口通讯功能封装到托管类的时候,这里至少有四种实现方式让你选择:1.使用P/Invoke把API函数、常数、结构作为静态成员封装到托管类中。虽然我在里面使用了这种方法,但没有这个类暴露给程序员。2.写一个流的处理角色。这是.NET框架对文件、控制台、网络通讯的一般地、可扩充的提取。咋一看,这个很有吸引力,但近距离审视的时候,这个更适用于传统的调制解调器,而不适合于现在基于命令响应语法的设备。3.做一个直接替换MSCommOLEControlExtension(OCX)控件的替代品。换句话说,新建一个封装了API文件处理并提供许多基本的方法和事件(比如,Open,Close,Read,Write等等)。你可以在应用程序类里初始化这个类库里的一个对象来达到重用的目的――那就是说,通过COM-style的集合。4.写一个应用程序需要继承的基类。这是一个充分体现.NET优点――运行时对不同语言继承的无关性――的面向对象的方法。这些基础的方法被继承进应用程序对象中,虚方法将被使用,而不是使用事件。这个应用程序对象将巧妙地提供一个适用于真实RS232设备公共接口(比如,一个GPS接收器驱动可能拥有一些关于经度和纬度的公共属性)。我将采用第四种方法。这个类库将会包含两个被生明为抽象类的基类(它们不能被示例化),但我将使用继承来把它们作为实现某些特定应用的基类。图1表明了这种继承的层次关系。图1继承层次第一个库类,CommBase,对数据格式化、更容易开启与关闭通讯接口、发送与接收字节数据、输入与输出交互的控制等都不提供任何实现。第二个库类,CommLine,继承自CommBase,并且做了两个实现:接收与发送的字节是ASCII编码并使用一个保留的ASCII控制编码来标记数据行数的可变长度,能够接收与传输字符串。当然,这个模型是可扩展的;比如,你可以编写可选的Unicode版的CommLine。使用基类两个应用程序的例子,BaseTerm和LineTerm,可以下载的到。他们可以用于与任何串口设备进行一般用途的交流,包括调制解调器。我先从一个用户的观点来简单的看一下BaseTerm,然后再更细致地分析一个LineTerm的源代码。图2BaseTermBaseTerm(参看图2)是一个完全基于Windows@Form的应用程序,它继承自CommBase并提供一个基于字节的可调节终端。点击Settings按纽可以打开了一个对话框来对通讯设置的全部参数进行设置(参看图3)。这个窗口上菜单可以帮助用户以结构化的XML文件来保存或加载这些设置参数,也保存大量用于普通流控制模式的设置。提示解释了各个设置项的用法。一旦保存为XML,当你再次启动这个程序的时候,你可以在命令行格式下设定这个文件。一旦连上线,打出的字符就可以立即被传送到远端设备中支。键盘上的按键发送合适的ASCII字节,如果你想发送键盘上没有的编码,你可以使用“escapefacility”.图3Comm设置可以通过输入符号来开启“escape”.然后,输入任一个ASCII控制码名字或一个位于0或255之间的十进制数。可通过输入一个符号来结束这个“escape”,它可以把一个合适的ASCII码立即发送过去。当需要传输符号时可以通过把它输入两次的方式进行。你可以在设置对话框中标记为”XonCode”的下拉框中查看所有有效的ASCII控制符的名称,站点还提供其它有用的信息。在终端窗口上大的文本框上将显示所有的ASCII形式或16进制形式(没进一步分析)的字节。你可以在接收到一个规定ASCII字符或一定数量的字符后使用显示设置对话框来中止接收行。点击状态按纽将提供所传输以及接收队列的情况。LineTerm使用CommLine作为它的基类,并在源码中声明了如何使用这个库。因为没有创建用户界面用于设置,你需要在VisualStudio.NET环境下来运行它。在VisualStudio.NET中,建立一个新的VisualBasic控制台应用程序。从项目中移除默认的模块。拷贝LineTerm.vb,CommBase.dll和CommBase.xml三个文件到项目文件夹(其中的XML文件这个库文件提供了智能提示信息)。使用项目浏览器中的添加现有项把LineTerm.vb添加到项目中,并通过添加引用把CommBase.dll添加到引用中。现在你可以编译并运行这个项目了。ImportsJH.CommBasePublicClassLineTermInheritsCommLinePublicSubSendCommand(ByValsAsString)Send(s)EndSubPublicSubTransactCommand(ByValsAsString)DimrAsStringr=Transact(s)Console.WriteLine(RESPONSE:+r)Prompt()EndSubPublicSubPrompt()Console.WriteLine(TypestringtosendandpressENTER.Emptystringtoclosecommport.)EndSubProtectedOverridesFunctionCommSettings()AsCommBaseSettingsDimcsAsNewCommLineSettings()cs.SetStandard(COM1:,19200,Handshake.none)cs.rxFilter=NewASCII(){ASCII.LF,ASCII.SOH}cs.rxTerminator=ASCII.CRcs.txTerminator=NewASCII(){ASCII.CR}Setup(cs)ReturncsEndFunctionProtectedOverridesSubOnRxLine(ByValsAsString)Console.WriteLine(RECEIVED:+s)Prompt()EndSubProtectedOverridesSubOnTxDone()Console.WriteLine(TRANSMISSIONCOMPLETE)Prompt()EndSubEndClassModuleModule1SubMain()DimtAsNewLineTerm()DimcAsStringConsole.WriteLine(PressENTERtoopencomport)Console.ReadLine()Ift.Open()ThenConsole.WriteLine(COMPORTOPEN)t.Prompt()WhileTruec=Console.ReadLine().TrimIfc=ThenExitWhilet.SendCommand(c)'t.TransactCommand(c)EndWhilet.Close()EndIfConsole.WriteLine(COMPORTCLOSED)Console.WriteLine(PressENTERtocloseprogram.)Console.ReadLine()EndSubEndModule图四LineTerm示例代码图4向我们展示了这个例子的完整源代码。在这第一行,我引入了库的命名空间。然后我建立了一个新的类,LineTerm,它继承自CommLine。它提供了打开和关闭这两个公共方法(实际上是继承自CommBase类),还有保护型方法发送,且我把它做成公共的当作为SendCommand的时候。在我的新类里,我重载了基类中大量的虚方法。在打开窗口配置通讯端口时调用了CommSettings方法;它会返回一个已经初始化了的CommBaseSettings对象。这里我实际上使用了CommLineSettings,因为它继承自CommBaseSettings.在这个方法的最后两行,首先我传递了一个继承自CommLine的对象给Setup方法,并把它返回给CommBase类。所有的设置项都是公共的成员,可以直接被设定,但这里也有一个辅助方法,SetStandard,它可以把CommBase类自动配置成最常用的配置。你也许需要编辑这个方法及终端线、过滤成员的参数来适合你的可用于测试的设备。应用程序的主方法只是简单的创建了一个我的类的实例,并调用了Open方法,并提供了一个可用于发送字符串和显示所收到的字符串的命令行界面。共有两个方法来完成这个,阻塞(blocking)和非阻塞(non-blocking)。使用SendCommand来启动非阻塞通讯。这个方法立刻返回,不久发送结束,重载的OnTxDone方法将报告结果。稍后,当远端设备完成了一个响应信号的输入,重载的OnExLine方法会在控制台上显示出结果。此时,主进程等待用户输入,但也可能它正在进行其它的工作。如果你注释掉SendCommand并用TransactCommand来替代,将会同样地使用阻塞式通信。此时,主进程会一直处于阻塞模式,直到出现有效地回应。你可以静静地等着从OnTxDone方法返回的结果信息,但代替从OnRxLine方法返回的收到的消息,你将看到从TransactCommand方法返回的回应的信息。图5GPS的流控制在一个真正的应用程序中,比如GPS接收器的驱动程序,你不可能让它像我在示例中所仅实现的Send和Transact公共方法一样。相反,你需要提供那些能够表现这个设备功能的所有公有方法和属性(比如,速度和强度属性,或者比如PositionChanged的事件)。这些方法必须集合必要的命令。使用Transact方法,并把回应释放转化出返回值。图5就是介绍用于这类设备的流控制的。发送在串口通信中,在大多数情况下,发送信息比接收信息容易多了。对于接收信息,你也许正对远端设备胡思乱想,然而对于传输,你仍然可以控制时间。尽管如此,一般的位于2到20000波特的传输速率与计算

1 / 9
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功