马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
1、基本概念
MS在 .NET FrameWork2.0中对串口通讯进行了封装,我们可以在.net2.0及以上版本开发时直接使用SerialPort类对串口进行读写操作。
SerialPort类的属性主要包括:
串口名称(PortName)
波特率(BaudRate)
数据位 DataBits
停止位 StopBits
奇偶校验 Parity
握手协议 Handshake
SerialPort类的事件主要包括:
DataReceived:用于异步接收串口数据
SerialPort类的方法主要包括:
Open();Close();Read();Write()等。
相关内容可以参考MSDN或者博文
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;
}
}
}
5、声明
本文来源于实际项目,并且系统的串口通讯很稳定,各位朋友可以放心使用。本文的参考内容都已经标示,如果有任何问题欢迎回复。
接下来准备要分享的内容包括:
|