现假设有一系列产品我们需要使用软件控制其运作,我们可以通过向设备发送各种指令来达到此要求,首先由于产品种类较多,而且有些产品是纵向升级的,升级之后的产品基本上保持原有功能基础上加了些新功能,基于此要求,我们在设计相应类时,可以使用继承的方法,通信基类使用抽象类不允许直接实例化,仅提供一般串口操作的方法,比如发送指令及关串口等操作(初始化串口及打开串口操作在构造函数中完成),这样有任何产品只要从这个类继承即可调用基类函数,而且考虑到产品升级,只要继承相应的基类,重新相应的方法即可,即可以重用代码,结构又比较清晰,下面是一些示例代码
using System;
using System.IO.Ports;
using System.Threading;

namespace TripodDemo


{

/**//// <summary>
/// 串口操作通用类,抽象类防止类别直接实例化
/// </summary>
public abstract class ComPort : IDisposable

{

/**//// <summary>
/// 使用变量锁定对象
/// </summary>
private object objComm = new object();


/**//// <summary>
/// 串口对象
/// </summary>
private SerialPort com;

private bool disposed = false;


SerialPort#region SerialPort
public ComPort()

{
com = new SerialPort("COM1", 9600);
OpenCom();
}

public ComPort(SerialPort sp)

{
com = sp;
OpenCom();
}

private void OpenCom()

{
try

{
if (!com.IsOpen)

{
com.ReadTimeout = 3000;
com.WriteTimeout = 3000;
com.Open();
}
}
catch (Exception ex)

{
throw new Exception(ex.Message);
}
}
#endregion


Dispose & Close#region Dispose & Close
public void Dispose()

{
Dispose(true);
}

private void Dispose(bool disposing)

{
if (!disposed && disposing && com != null && com.IsOpen)

{
com.Close();
disposed = true;
}
}

public void Close()

{
Dispose(true);
}
#endregion


发送数据#region 发送数据

/**//// <summary>
/// 发送数据
/// </summary>
/// <param name="bwrite">写数据</param>
/// <param name="returnDataLen">读数据长度</param>
/// <param name="bread">读数据</param>
/// <param name="msel">超时毫秒</param>
/// <returns>是否执行成功</returns>
public bool SendData(byte[] bwrite, int returnDataLen, out byte[] bread, int msel)

{
lock (objComm)

{
bread = new byte[returnDataLen];
long l = DateTime.UtcNow.Ticks + msel * 10000;
com.DiscardInBuffer();
com.DiscardOutBuffer();
com.Write(bwrite, 0, bwrite.Length);

while (com.BytesToRead < returnDataLen && DateTime.UtcNow.Ticks < l)

{
Thread.Sleep(1);
}

//串口无反应
if (com.BytesToRead < returnDataLen)

{
return false;
}

try

{
com.Read(bread, 0, bread.Length);
return true;
}
catch (TimeoutException)

{
return false;
}
}
}
#endregion
}
}

using System;
using System.IO.Ports;
using System.Text;

namespace TripodDemo


{
public class SerialQ01 : ComPort

{

构造函数#region 构造函数
public SerialQ01()
: base()

{
//constructor
}

public SerialQ01(SerialPort sp)
: base(sp)

{
//constructor
}
#endregion


读时间#region 读时间
public bool ReadDeviceTime(byte macno, out string time)

{
int retLen = 10;
byte[] bread;

//构建命令
byte b1 = 0xAA;
byte b2 = 0x00;
byte b3 = 0x32;


byte[] bwrite =
{ b1, b2, b2, macno, macno, b3, b3 };
bool bRet = SendData(bwrite, retLen, out bread, 1000);

#if DEBUG
foreach (byte b in bread)

{
System.Diagnostics.Debug.WriteLine(b.ToString("X2"));
}
#endif

time = string.Empty;
if (bRet)

{
if (bread[0] == 0xCC && bread[1] == 0x30 && bread[2] == 0x30)

{
time = string.Format("20{0}-{1}-{2} {3}:{4}", bread[3].ToString("X2"), bread[4].ToString("X2"), bread[5].ToString("X2"), bread[6].ToString("X2"), bread[7].ToString("X2"));
return true;
}
else

{
return false;
}
}
else

{
return false;
}
}
#endregion


设置时间#region 设置时间
public bool SetDeviceTime(byte macno, DateTime time)

{
int retLen = 10;
byte[] bread;

//构建命令
byte b1 = 0xAA;
byte b2 = 0x00;
byte b3 = 0x31;

byte year = Convert.ToByte(time.Year.ToString().Substring(2, 2), 16);
byte month = Convert.ToByte(time.Month.ToString(), 16);
byte day = Convert.ToByte(time.Day.ToString(), 16);
byte hour = Convert.ToByte(time.Hour.ToString(), 16);
byte min = Convert.ToByte(time.Minute.ToString(), 16);
byte sec = Convert.ToByte(time.Second.ToString(), 16);

byte xor = (byte)(year ^ month ^ day ^ hour ^ min ^ sec);


byte[] bwrite =
{ b1, b2, b2, macno, macno, b3, b3, year, month, day, hour, min, sec, xor };
bool bRet = SendData(bwrite, retLen, out bread, 1000);

#if DEBUG
foreach (byte b in bread)

{
System.Diagnostics.Debug.WriteLine(b.ToString("X2"));
}
#endif

if (bRet)

{
if (bread[0] == 0xCC && bread[1] == 0x30 && bread[2] == 0x30)

{
return true;
}
else

{
return false;
}
}
else

{
return false;
}
}
#endregion


发卡#region 发卡
public bool IssueCard(byte macno, string cardNo)

{
if (cardNo.Length < 8) return false;

int retLen = 10;
byte[] bread;

//构建命令
byte b1 = 0xAA;
byte b2 = 0x00;
byte b3 = 0x45;

byte cardNo1 = Convert.ToByte(cardNo.Substring(0, 2), 16);
byte cardNo2 = Convert.ToByte(cardNo.Substring(2, 2), 16);
byte cardNo3 = Convert.ToByte(cardNo.Substring(4, 2), 16);
byte cardNo4 = Convert.ToByte(cardNo.Substring(6, 2), 16);

byte xor = (byte)(cardNo1 ^ cardNo2 ^ cardNo3 ^ cardNo4);


byte[] bwrite =
{ b1, b2, b2, macno, macno, b3, b3, cardNo1, cardNo2, cardNo3, cardNo4, xor };
bool bRet = SendData(bwrite, retLen, out bread, 1000);

#if DEBUG
foreach (byte b in bwrite)

{
System.Diagnostics.Debug.WriteLine(b.ToString("X2"));
}
#endif

if (bRet)

{
if (bread[0] == 0xCC && bread[1] == 0x30 && bread[2] == 0x30)

{
return true;
}
else

{
return false;
}
}
else

{
return false;
}
}
#endregion

}
}

using System;
using System.IO.Ports;
using System.Text;

namespace TripodDemo


{

/**//// <summary>
/// 产品Q01的长升级版本,大部分功能同Q01,但发卡模块增加有效期
/// </summary>
public class SerialQ01A : SerialQ01

{

构造函数#region 构造函数
public SerialQ01A()
: base()

{
//constructor
}

public SerialQ01A(SerialPort sp)
: base(sp)

{
//constructor
}
#endregion


发卡#region 发卡
public bool IssueCard(byte macno, string cardNo, DateTime bTime, DateTime eTime)

{
if (cardNo.Length < 8) return false;

int retLen = 10;
byte[] bread;

//构建命令
byte b1 = 0xAA;
byte b2 = 0x00;
byte b3 = 0x45;

byte cardNo1 = Convert.ToByte(cardNo.Substring(0, 2), 16);
byte cardNo2 = Convert.ToByte(cardNo.Substring(2, 2), 16);
byte cardNo3 = Convert.ToByte(cardNo.Substring(4, 2), 16);
byte cardNo4 = Convert.ToByte(cardNo.Substring(6, 2), 16);

byte bYear = Convert.ToByte(bTime.Year.ToString(), 16);
byte bMonth = Convert.ToByte(bTime.Month.ToString(), 16);
byte bDay = Convert.ToByte(bTime.Day.ToString(), 16);

byte eYear = Convert.ToByte(eTime.Year.ToString(), 16);
byte eMonth = Convert.ToByte(eTime.Month.ToString(), 16);
byte eDay = Convert.ToByte(eTime.Day.ToString(), 16);

byte xor = (byte)(cardNo1 ^ cardNo2 ^ cardNo3 ^ cardNo4 ^ bYear ^ bMonth ^ bDay ^ eYear ^ eMonth ^ eDay);


byte[] bwrite =
{ b1, b2, b2, macno, macno, b3, b3, cardNo1, cardNo2, cardNo3, cardNo4, bYear, bMonth, bDay, eYear, eMonth, eDay, xor };
bool bRet = SendData(bwrite, retLen, out bread, 1000);

#if DEBUG
foreach (byte b in bwrite)

{
System.Diagnostics.Debug.WriteLine(b.ToString("X2"));
}
#endif

if (bRet)

{
if (bread[0] == 0xCC && bread[1] == 0x30 && bread[2] == 0x30)

{
return true;
}
else

{
return false;
}
}
else

{
return false;
}
}
#endregion
}
}

源码示例:
/Files/chenzz/TripodDemo_cs.zip
/Files/chenzz/TripodDemo.zip