C#异步数据接收串口操作类

C#异步数据接收串口操作类

  1. 使用C#调用传统32位API实现串口操作,整个结构特别的简单。接收数据只需要定义数据接收事件即可。
  2. 上传源代码我不会,需要源代码的请与我([email protected])联系。你也可以教我怎么上传源代码。
  3. using System;
  4. using System.Runtime.InteropServices;
  5. /// <summary>
  6. /// (C)2003-2005 C2217 Studio  保留所有权利
  7. ///
  8. /// 文件名称:     IbmsSerialPort.cs
  9. /// 文件ID:
  10. /// 文件说明:
  11. ///         封装动态链接库IbmsSerialPort.dll的功能,提供在.NET环境中
  12. ///         串口异步接收和发送数据的功能。
  13. ///
  14. /// 当前版本:   1.0
  15. ///
  16. /// 作者:    邓杨均
  17. /// 创建日期:   2005-2-2
  18. /// 最后修改日期: 2005-2-2
  19. ///
  20. /// 历史修改记录:
  21. ///
  22. /// </summary>
  23. namespace Ibms.Tool.IO
  24. {
  25. /// <summary>
  26. /// 当串口接收到数据时,会产生一个事件。
  27. /// SPRecvDataArgs就是该事件的参数,参数中的RecvData包含接收到的数据。
  28. /// 使用方法:
  29. /// </summary>
  30. public class SPRecvDataArgs:EventArgs
  31. {
  32. /// <summary>
  33. /// 接收到的数据组成的字节数组
  34. /// </summary>
  35. private byte[] recvData;
  36. /// <summary>
  37. /// 构造函数,需要一个包含数据的byte[]作为初始化参数来实例化 SPRecvDataArgs
  38. /// </summary>
  39. /// <param name="recvData">接收到的数据</param>
  40. public SPRecvDataArgs(byte[] recvData)
  41. {
  42. if( recvData == null)
  43. {
  44. throw(new ArgumentNullException());
  45. }
  46. this.recvData = recvData;
  47. }
  48. /// <summary>
  49. /// 返回接收到的数据内容
  50. /// </summary>
  51. public byte[] RecvData
  52. {
  53. get
  54. {
  55. return recvData;
  56. }
  57. }
  58. }
  59. /// <summary>
  60. /// 封装动态链接库IbmsSerialPort.dll的功能,提供在.NET环境中异步
  61. /// 串口接收和发送功能。特别实现的是异步通过信号自动接收数据的模式。
  62. /// </summary>
  63. public class IbmsSerialPort:IDisposable
  64. {
  65. #region 平台调用声明代码
  66. /// <summary>
  67. /// 声明IbmsSerialPort.dll的Ibms_OpenPort函数
  68. /// </summary>
  69. /// <param name="nPort">串口号</param>
  70. /// <param name="nRate">波特率</param>
  71. /// <returns></returns>
  72. [DllImport("IbmsSerialPort.dll")]
  73. public static extern IntPtr Ibms_OpenPort(int nPort, int nRate);
  74. /// <summary>
  75. /// 声明IbmsSerialPort.dll的Ibms_Close函数
  76. /// </summary>
  77. [DllImport("IbmsSerialPort.dll")]
  78. public static extern void Ibms_Close( IntPtr port);
  79. /// <summary>
  80. /// 声明IbmsSerialPort.dll的Ibms_SendData函数
  81. /// </summary>
  82. /// <param name="data"></param>
  83. /// <param name="nDataSize"></param>
  84. /// <returns></returns>
  85. [DllImport("IbmsSerialPort.dll")]
  86. public static extern bool Ibms_SendData( IntPtr port, byte[] data,int nDataSize);
  87. /// <summary>
  88. /// 声明IbmsSerialPort.dll的Ibms_SetFuncHandle函数
  89. /// </summary>
  90. /// <param name="handDataFunc"></param>
  91. [DllImport("IbmsSerialPort.dll")]
  92. public static extern void Ibms_SetFuncHandle( IntPtr port, HandleFunc handDataFunc);
  93. #endregion
  94. #region 定义字段
  95. /// <summary>
  96. /// 定义数据处理委托,作为API的函数指针传入动态链接库
  97. /// </summary>
  98. public delegate void HandleFunc(IntPtr pData, int nDataSize);
  99. /// <summary>
  100. /// 定义数据接收事件的原型
  101. /// </summary>
  102. public delegate void RecvData(object sender,SPRecvDataArgs e);
  103. /// <summary>
  104. /// 定义数据接收事件
  105. /// </summary>
  106. public event RecvData OnRecvData;
  107. /// <summary>
  108. /// 串口处理接收数据的委托
  109. /// </summary>
  110. private HandleFunc _handleDataFunc;
  111. /// <summary>
  112. /// 串口的编号,从1开始的整数,最大255
  113. /// </summary>
  114. private int port;
  115. /// <summary>
  116. /// 串口所支持的波特率,必须是标准波特率之一
  117. /// </summary>
  118. private StanderdRate rate;
  119. /// <summary>
  120. /// 串口当前的打开状态
  121. /// </summary>
  122. private bool openStatus=false;
  123. /// <summary>
  124. /// 串口句柄
  125. /// </summary>
  126. private IntPtr portHandle;
  127. #region 定义标准的串口波特率
  128. /// <summary>
  129. /// 标准的波特率
  130. /// </summary>
  131. public enum StanderdRate
  132. {
  133. R50=50,
  134. R75=75,
  135. R110=110,
  136. R150=150,
  137. R300=300,
  138. R600=600,
  139. R1200=1200,
  140. R2400=2400,
  141. R4800=4800,
  142. R9600=9600,
  143. R19200=19200,
  144. R38400=38400,
  145. R57600=57600,
  146. R76800=76800,
  147. R115200=115200
  148. };
  149. #endregion
  150. #endregion
  151. #region 定义方法
  152. /// <summary>
  153. /// 构造函数
  154. /// </summary>
  155. public IbmsSerialPort()
  156. {
  157. portHandle = (IntPtr)0;
  158. _handleDataFunc = new HandleFunc(OnDllRecvData);
  159. }
  160. /// <summary>
  161. /// 打开串口
  162. /// </summary>
  163. /// <param name="nPort">串口号</param>
  164. /// <param name="nRate">波特率</param>
  165. /// /// <exception cref="ApplicationException">抛出应用程序异常,包换错误描述</exception>
  166. public void Open(int nPort, StanderdRate nRate)
  167. {
  168. if(nPort > 255 || nPort < 0)
  169. {
  170. throw(new ArgumentOutOfRangeException());
  171. }
  172. port = nPort;
  173. rate = nRate;
  174. portHandle = Ibms_OpenPort( port, (int)rate );
  175. if( (IntPtr)0 == portHandle  )
  176. {
  177. throw( new ApplicationException("打开串口失败"));
  178. }
  179. //注册函数指针
  180. Ibms_SetFuncHandle( portHandle, _handleDataFunc );
  181. openStatus = true;
  182. }
  183. /// <summary>
  184. /// 关闭串口
  185. /// </summary>
  186. public void Close()
  187. {
  188. if( openStatus )
  189. {
  190. Ibms_Close( portHandle);
  191. }
  192. openStatus = false;
  193. }
  194. /// <summary>
  195. /// 发送数据
  196. /// </summary>
  197. /// <param name="sendData">数据内容</param>
  198. /// <exception cref="ApplicationException">抛出应用程序异常,包换错误描述</exception>
  199. public void SendData( byte[] data )
  200. {
  201. if( !openStatus )
  202. {
  203. throw( new ApplicationException("串口没有打开,发送数据失败") );
  204. }
  205. if( !Ibms_SendData( portHandle, data, data.Length ) )
  206. {
  207. throw( new ApplicationException("串口发送数据失败") );
  208. }
  209. }
  210. /// <summary>
  211. /// 处理接收到的串口数据
  212. /// </summary>
  213. /// <param name="pData">串口数据接收缓冲区首地址</param>
  214. /// <param name="nDataSize">数据大小,一般数据大小不超过2K</param>
  215. unsafe protected void OnDllRecvData(IntPtr pUnhandleData, int nDataSize)
  216. {
  217. int dataSize= nDataSize ;
  218. byte * pData =(byte *) pUnhandleData;
  219. byte[] data = new byte[dataSize];
  220. //复制数据到byte数组
  221. for(int i=0; i<dataSize; i++)
  222. {
  223. data[i]= pData[i];
  224. }
  225. //激发事件
  226. OnRecvData( this, new SPRecvDataArgs(data) );
  227. }
  228. #endregion
  229. #region 定义属性
  230. /// <summary>
  231. /// 返回当前的串口号
  232. /// </summary>
  233. public int Port
  234. {
  235. get
  236. {
  237. return port;
  238. }
  239. }
  240. /// <summary>
  241. /// 返回当前串口的波特率
  242. /// </summary>
  243. public StanderdRate Rate
  244. {
  245. get
  246. {
  247. return rate;
  248. }
  249. }
  250. /// <summary>
  251. /// 返回当前串口的状态
  252. /// </summary>
  253. public bool OpenStatus
  254. {
  255. get
  256. {
  257. return openStatus;
  258. }
  259. }
  260. #endregion
  261. #region 非托管资源的及时释放
  262. /// <summary>
  263. /// 因为包含了非托管的资源(占用系统串口),必须实现IDisposable接口
  264. /// 在使用完该类的时候,必须记得调用Dispose(),回收系统资源
  265. /// <example>
  266. ///
  267. /// 方法1
  268. /// {
  269. ///  SerialPort port =new SerialPort();
  270. ///  ...
  271. ///  //在try-catch-finaly的finaly中释放资源
  272. ///
  273. ///  port.Dispose();
  274. /// }
  275. ///
  276. /// 方法2
  277. /// using( SerialPort port = new SerialPort())
  278. /// {
  279. ///  ...
  280. /// }
  281. /// 变量超出作用域时会自动调用其Dispose()方法
  282. ///
  283. /// </example>
  284. /// </summary>
  285. ~IbmsSerialPort()
  286. {
  287. Dispose( false );
  288. }
  289. protected virtual void Dispose( bool disposing )
  290. {
  291. if( disposing )
  292. {
  293. //清理托管的对象
  294. }
  295. //清理非托管的资源
  296. Close();
  297. }
  298. #region IDisposable 成员
  299. public void Dispose()
  300. {
  301. // TODO:  添加 SerialPort.Dispose 实现
  302. Dispose( true );
  303. GC.SuppressFinalize(this);
  304. }
  305. #endregion
  306. #endregion
  307. }
  308. }
时间: 2024-12-26 07:04:03

C#异步数据接收串口操作类的相关文章

Util应用程序框架公共操作类(一):数据类型转换公共操作类(介绍篇)

本系列文章将介绍一些对初学者有帮助的辅助类,这些辅助类本身并没有什么稀奇之处,如何能发现需要封装它们可能更加重要,所谓授之以鱼不如授之以渔,掌握封装公共操作类的技巧才是关键,我会详细说明创建这些类的动机和思考过程,以帮助初学者发现和封装自己需要的东西.创建公共操作类的技巧,大家可以参考我的这篇文章——应用程序框架实战十二:公共操作类开发技巧(初学者必读). 封装公共操作类,不仅要把技术上困难的封装进来,还需要不断观察自己的代码,以找出哪些部分可以更加简化.本文将介绍一个容易被大家所忽视的东西——

Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)

上一篇以TDD方式介绍了数据类型转换公共操作类的开发,并提供了单元测试和实现代码,本文将演示通过扩展方法来增强公共操作类,以便调用时更加简化. 下面以字符串转换为List<Guid>为例进行讨论. string input = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A"; var result = Util.Conv.ToGuidList( input ); 观察上面

C#串口操作类,包括串口读写操作

串口进行操作的类,其中包括写和读操作,类可设置串口参数.设置接收函数.打开串口资源.关闭串口资源,操作完成后,一定要关闭串口.接收串口数据事件.接收数据出错事件.获取当前全部串口.把字节型转换成十六进制字符串等功能.这个串口类已经过了调试,可以使用: using System; using System.Collections.Generic; using System.Text; using System.IO.Ports; using System.Globalization; namesp

Java TCP异步数据接收

之前一直采用.Net编写服务端程序,最近需要切换到Linux平台下,于是尝试采用Java编写数据服务器.TCP异步连接在C#中很容易实现,网上也有很多可供参考的代码.但Java异步TCP的参考资料较少,网上例程多是阻塞多线程方法,由于线程的开销较大,当客户端较多时系统资源的消耗也较大. 综合网上和书本的相关知识,本文给出一个Java TCP异步接收数据的代码示例,并给出相关的注释. /** * TcpAsyncServer.java */ import java.nio.ByteBuffer;

C#----串口数据接收发送

虚拟串口驱动工具,创建俩个虚拟串口,如图: 创建两个Console模拟串口的发送接收数据 C#串口数据接收发送,类空间: using System.IO.Ports; C# 串行端口 接收数据,代码如下: //遍历串行端口名称数组 foreach (string port in System.IO.Ports.SerialPort.GetPortNames()) { Console.WriteLine(port); } byte[] b = new byte[32]; SerialPort sp

WebService(二)发送数据+接收数据并进行处理操作

(一)使用WebService发送数据 1.定义webService接口 import java.util.List; import javax.jws.WebParam; import javax.jws.WebService; import com.mxz.fvp.dto.ADto; @WebService public interface MxzReceiveService { public boolean addExpressBarRecord(@WebParam(name = "rec

【转】C# 串口操作系列(3) -- 协议篇,二进制协议数据解析

我们的串口程序,除了通用的,进行串口监听收发的简单工具,大多都和下位机有关,这就需要关心我们的通讯协议如何缓存,分析,以及通知界面. 我们先说一下通讯协议.通讯协议就是通讯双方共同遵循的一套规则,定义协议的原则是尽可能的简单以提高传输率,尽可能的具有安全性保证数据传输完整正确.基于这2点规则,我们一个通讯协议应该是这样的:头+数据长度+数据正文+校验 例如:AA 44 05 01 02 03 04 05 EA 这里我假设的一条数据,协议如下: 数据头:     AA 44 数据长度: 05 数据

C# 串口操作系列(3) -- 协议篇,二进制协议数据解析

C# 串口操作系列(3) -- 协议篇,二进制协议数据解析 标签: c#bufferobject通讯byte硬件驱动 2010-05-27 09:54 51565人阅读 评论(215) 收藏 举报  分类: 通讯类库设计(4)  版权声明:本文为博主原创文章,未经博主允许不得转载. 我们的串口程序,除了通用的,进行串口监听收发的简单工具,大多都和下位机有关,这就需要关心我们的通讯协议如何缓存,分析,以及通知界面. 我们先说一下通讯协议.通讯协议就是通讯双方共同遵循的一套规则,定义协议的原则是尽可

C# 串口操作系列(4) -- 协议篇,文本协议数据解析

C# 串口操作系列(4) -- 协议篇,文本协议数据解析 标签: c#uiobjectstringbyte 2010-06-09 01:50 19739人阅读 评论(26) 收藏 举报  分类: 通讯类库设计(4)  版权声明:本文为博主原创文章,未经博主允许不得转载. 上一篇已经介绍了协议的组成,一个协议,一般具有 :协议头+长度+数据+校验 , 文本格式可以直观的定义回车换行是协议的结尾,所以我们可以省略数据长度,增加协议尾.即: 协议头 + 数据 + 校验 + 数据尾 . 文本方式的数据比