做工业通信有很长时间了,特别是串口(232/485),有VB/VC/C各种版本的串口操作代码,这些代码也经过了多年的现场考验,应该说是比较健壮的代码,但是目前却没有C#相对成熟的串口操作代码,最近用Moxa的设备开发基于WinCE5.0的串口操作代码,所以就扩充完善了一下串口操作,特别是SendCommand函数,这是我比较常用的主从通信代码,不喜欢用事件或线程接数据,在规定的超时时间内直接循环判断要接收的数据。
下面是具体的代码:
public
class
PortData
{
public
event
PortDataReceivedEventHandle Received;
public
event
SerialErrorReceivedEventHandler Error;
public
SerialPort port;
public
bool
ReceiveEventFlag
=
false
;
//
接收事件是否有效 false表示有效
public
PortData(
string
sPortName,
int
baudrate,Parity parity,SerialInterface.SerialMode mode)
{
port
=
new
SerialPort(sPortName, baudrate, parity,
8
, StopBits.One);
port.RtsEnable
=
true
;
port.ReadTimeout
=
3000
;
port.DataReceived
+=
new
SerialDataReceivedEventHandler(DataReceived);
port.ErrorReceived
+=
new
SerialErrorReceivedEventHandler(ErrorEvent);
}
~
PortData()
{
Close();
}
public
void
Open()
{
if
(
!
port.IsOpen)
{
port.Open();
}
}
public
void
Close()
{
if
(port.IsOpen)
{
port.Close();
}
}
//
数据发送
public
void
SendData(
byte
[] data)
{
if
(port.IsOpen)
{
port.Write(data,
0
, data.Length);
}
}
public
void
SendData(
byte
[] data,
int
offset,
int
count)
{
if
(port.IsOpen)
{
port.Write(data, offset, count);
}
}
//
发送命令
public
int
SendCommand(
byte
[] SendData,
ref
byte
[] ReceiveData,
int
Overtime)
{
if
(port.IsOpen)
{
ReceiveEventFlag
=
true
;
//
关闭接收事件
port.DiscardInBuffer();
//
清空接收缓冲区
port.Write(SendData,
0
, SendData.Length);
int
num
=
0
,ret
=
0
;
while
(num
++
<
Overtime)
{
if
(port.BytesToRead
>=
ReceiveData.Length)
break
;
System.Threading.Thread.Sleep(
1
);
}
if
(port.BytesToRead
>=
ReceiveData.Length)
ret
=
port.Read(ReceiveData,
0
, ReceiveData.Length);
ReceiveEventFlag
=
false
;
//
打开事件
return
ret;
}
return
-
1
;
}
public
void
ErrorEvent(
object
sender, SerialErrorReceivedEventArgs e)
{
if
(Error
!=
null
) Error(sender, e);
}
//
数据接收
public
void
DataReceived(
object
sender, SerialDataReceivedEventArgs e)
{
//
禁止接收事件时直接退出
if
(ReceiveEventFlag)
return
;
byte
[] data
=
new
byte
[port.BytesToRead];
port.Read(data,
0
, data.Length);
if
(Received
!=
null
) Received(sender,
new
PortDataReciveEventArgs(data));
}
public
bool
IsOpen()
{
return
port.IsOpen;
}
}
public
delegate
void
PortDataReceivedEventHandle(
object
sender, PortDataReciveEventArgs e);
public
class
PortDataReciveEventArgs : EventArgs
{
public
PortDataReciveEventArgs()
{
this
.data
=
null
;
}
public
PortDataReciveEventArgs(
byte
[] data)
{
this
.data
=
data;
}
private
byte
[] data;
public
byte
[] Data
{
get
{
return
data; }
set
{ data
=
value; }
}
}
【附注】1~9 串口的名称是 "COMx:",>9的以前用////.//COMx:比较好使,但是在moxa 661设备上却不行,要用如下格式"$device//COM" + PortNo.ToString() + "/0",也许这是moxa修改了相应的串口驱动。