1、基本概念
MS在 .NET FrameWork2.0中对串口通讯进行了封装,我们可以在.net2.0及以上版本开发时直接使用SerialPort类对串口进行读写操作。
SerialPort类的属性主要包括:
串口名称(PortName)
波特率(BaudRate)
数据位 DataBits
停止位 StopBits
奇偶校验 Parity
握手协议 Handshake
SerialPort类的事件主要包括:
DataReceived:用于异步接收串口数据
SerialPort类的方法主要包括:
Open();Close();Read();Write()等。
相关内容可以参考MSDN或者博文
http://www.cnblogs.com/tony-yang/archive/2009/06/03/learnserialport.html
http://www.cnblogs.com/hocylan/archive/2008/03/13/1103624.html
2、需求和场景介绍
本文是基于之前开发的一个油站项目,主要功能是实现对加油机数据的采集和对加油机的一些控制,例如停开机、设置单价、定量定额加油等操作。
系统通过PC机串口,与下位机进行通讯,下位机和加油机进行通讯,负责采集加油机数据和控制加油机的操作。
3、设计思想
(1)在界面设计上,由于系统启动后要始终实时监控加油数据,采用了SDI展示方式。
截图如下:
(2)在系统设计方面,加油机监控软件具有一定的实时性、稳定性和数据并发的非功能性需求。所以在对加油数据采集时,使用事件DataReceived,用于异步接收串口数据。使用watchdog方式监控系统消息,通过缓存池对数据进行过滤,减轻数据库的压力,提高系统性能。
4、代码演示
系统采用CS结构,使用SerialPort类进行串口通讯。对SerialPort类进行了封装,以保证多个窗体间对串口实例的调用。
封装的串口通讯类参考:http://blog.csdn.net/yefanqiu/archive/2007/03/27/1543187.aspx
串口通讯类:SerialPortDao.cs /* ---------------------------------------------------------------- // Copyright (C) 北京****科技有限公司 // 版权所有。 // // 文件名:SerialPortDao // 文件功能描述:封装串口组件,实现对串口的统一访问和操作 // // // 创建标识:** 2009-5-23 // // 修改标识:** // 修改描述://---------------------------------------------------------------- */ using System; using System.Collections.Generic; using System.Text; using System.IO.Ports; namespace LY.FuelStationPOS.Protocol{ /// <summary> /// 提供对串口的统一访问 /// </summary> public sealed class SerialPortDao { #region 事件和字段定义 public event PortDataReceivedEventHandle Received; public SerialPort serialPort = null ; public bool ReceiveEventFlag = false ; // 接收事件是否有效 false表示有效 private static readonly SerialPortDao instance = new SerialPortDao(); #endregion #region 属性定义 private string protName; public string PortName { get { return serialPort.PortName; } set { serialPort.PortName = value; protName = value; } } #endregion #region 构造函数 private SerialPortDao() { LoadSerialPort(); } private void LoadSerialPort() { serialPort = new SerialPort(); serialPort.BaudRate = 9600 ; serialPort.Parity = Parity.Even; serialPort.DataBits = 8 ; serialPort.StopBits = StopBits.One; serialPort.Handshake = Handshake.None; serialPort.RtsEnable = true ; serialPort.ReadTimeout = 2000 ; serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived); } #endregion #region 串口操作集合 /// <summary> /// 返回串口对象的单个实例 /// </summary> /// <returns></returns> public static SerialPortDao GetSerialPortDao() { return instance; } /// <summary> /// 释放串口资源 /// </summary> ~ SerialPortDao() { Close(); } /// <summary> /// 打开串口 /// </summary> public void Open() { try { if ( ! serialPort.IsOpen) { serialPort.Open(); } } catch (Exception ex) { throw ex; } } /// <summary> /// 关闭串口 /// </summary> public void Close() { if (serialPort.IsOpen) { serialPort.Close(); } } /// <summary> /// 串口是否打开 /// </summary> /// <returns></returns> public bool IsOpen() { return serialPort.IsOpen; } /// <summary> /// 数据发送 /// </summary> /// <param name="data"> 要发送的数据字节 </param> public void SendData( byte [] data) { try { serialPort.DiscardInBuffer(); serialPort.Write(data, 0 , data.Length); } catch (Exception ex) { throw ex; } } /// <summary> /// 发送命令 /// </summary> /// <param name="SendData"> 发送数据 </param> /// <param name="ReceiveData"> 接收数据 </param> /// <param name="Overtime"> 超时时间 </param> /// <returns></returns> public int SendCommand( byte [] SendData, ref byte [] ReceiveData, int Overtime) { if (serialPort.IsOpen) { try { ReceiveEventFlag = true ; // 关闭接收事件 serialPort.DiscardInBuffer(); // 清空接收缓冲区 serialPort.Write(SendData, 0 , SendData.Length); System.Threading.Thread.Sleep( 50 ); int num = 0 , ret = 0 ; while (num ++ < Overtime) { if (serialPort.BytesToRead >= ReceiveData.Length) { break ; } System.Threading.Thread.Sleep( 50 ); } if (serialPort.BytesToRead >= ReceiveData.Length) { ret = serialPort.Read(ReceiveData, 0 , ReceiveData.Length); } else { ret = serialPort.Read(ReceiveData, 0 , serialPort.BytesToRead); } ReceiveEventFlag = false ; // 打开事件 return ret; } catch (Exception ex) { ReceiveEventFlag = false ; throw ex; } } return - 1 ; } /// <summary> /// 数据发送 /// </summary> /// <param name="data"> 要发送的数据字符串 </param> public void SendData( string data) { // 禁止接收事件时直接退出 if (ReceiveEventFlag) { return ; } if (serialPort.IsOpen) { serialPort.Write(data); } } /// <summary> /// 将指定数量的字节写入输出缓冲区中的指定偏移量处。 /// </summary> /// <param name="data"> 发送的字节数据 </param> /// <param name="offset"> 写入偏移量 </param> /// <param name="count"> 写入的字节数 </param> public void SendData( byte [] data, int offset, int count) { // 禁止接收事件时直接退出 if (ReceiveEventFlag) { return ; } if (serialPort.IsOpen) { serialPort.Write(data, offset, count); } } /// <summary> /// 数据接收 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void DataReceived( object sender, SerialDataReceivedEventArgs e) { // 禁止接收事件时直接退出 if (ReceiveEventFlag) { return ; } try { byte [] data = new byte [serialPort.BytesToRead]; serialPort.Read(data, 0 , data.Length); if (Received != null ) { Received(sender, new PortDataReciveEventArgs(data)); } } catch (Exception ex) { // throw ex; } } }} 串口通讯数据类:PortDataReciveEventArgs /* ---------------------------------------------------------------- // Copyright (C) 北京****科技有限公司 // 版权所有。 // // 文件名:PortDataReciveEventArgs // 文件功能描述:重写PortDataReciveEventArgs参数类 // // // 创建标识:** 2009-5-23 // // 修改标识: // 修改描述: // // 修改标识: // 修改描述://---------------------------------------------------------------- */ using System; using System.Collections.Generic; using System.Text; namespace LY.FuelStationPOS.Protocol{ public delegate void PortDataReceivedEventHandle( object sender, PortDataReciveEventArgs e); public class PortDataReciveEventArgs : EventArgs { private byte [] data; public byte [] Data { get { return data; } set { data = value; } } public PortDataReciveEventArgs() { this .data = null ; } public PortDataReciveEventArgs( byte [] data) { this .data = data; } }}
转载于:https://www.cnblogs.com/deepwishly/archive/2010/04/23/2551246.html
相关资源:JAVA上百实例源码以及开源项目