C# 使用.net自带SerialPort类设计串口通讯程序2008-10-08 17:04:20|
分类: C# .NET | 标签:serialport
c# .net 串口
通讯 通信 程序
字号:大中小 订阅
一.概述
在Visual Studio 6.0中编写串口通讯程序,一般都使用Microsoft Communication
Control(简称MSComm)的通讯控件,只要通
过对此控件的属性和事件进行相应编程操作,就可以轻松地实现串口通讯。但在Microsoft.Net技术广泛应用的今天,Visual
Studio.Net没有将此控件加入控件库,所以人们采用了许多方法在Visual Studio.Net来编写串口通讯程序:
第一种方法是通过采用Visual Studio
6.0中原来的MSComm控件这是最简单的,最方便的方法,但需要注册;
第二种方法是采用微软在.NET推出了一个串口控件,基于.NET的P/Invoke调用方法实现;第三种方法是自己用API写串口通信,虽然难度高,但可以方便实现自己想要的各种功能。
现在微软推出了最新版本的Visual Studio 2005开发工具,可以不再采用第三方控件的方法来设计串口通讯程序。NET
Framework 2.0 类库包含了SerialPort
类,方便地实现了所需要串口通讯的多种功能,为了使MSComm编程方法快速转换到以SerialPort类为核心的串口通讯的设计方法,本文着重讨论了Visual
Studio 6.0的MSComm控件和SerialPort 类设计方法的异同点。
二.SerialPort常用属性、方法和事件
1.命名空间
System.IO.Ports命名空间包含了控制串口重要的SerialPort类,该类提供了同步 I/O 和事件驱动的
I/O、
对管脚和中断状态的访问以及对串行驱动程序属性的访问,所以在程序代码起始位置需加入Using
System.IO.Ports。
2.串口的通讯参数
串口通讯最常用的参数就是通讯端口号及通讯格式(波特率、数据位、停止位和校验位),在MSComm中相关的属性是CommPort和Settings。
SerialPort类与MSComm有一些区别:
a.通讯端口号
[PortName]属性获取或设置通信端口,包括但不限于所有可用的 COM
端口,请注意该属性返回类型为String,
不是Mscomm.CommPort的short类型。通常情况下,PortName正常返回的值为COM1、
SerialPort类最大支持的端口数突破了CommPort控件中CommPort属性不能超过16的限止,大大方便了用户串口设备的配置。
b. 通讯格式
SerialPort类对分别用[BaudRate]、[Parity]、[DataBits]、[StopBits]属性设置通讯格式中的波特率、数据位、停止位和校验位,
其中[Parity]和[StopBits]分别是枚举类型Parity、StopBits,Parity类型中枚举了Odd(奇)、Even(偶)、Mark、None、Space,StopBits枚举了None、One、OnePointFive、Two。
SerialPort类提供了七个重载的构造函数,既可以对已经实例化的SerialPort对象设置上述相关属性的值,
也可以使用指定的端口名称、波特率和奇偶校验位数据位和停止位直接初始化 SerialPort 类的新实例。
3.串口的打开和关闭
SerialPort类没有采用MSComm.PortOpen=True/False设置属性值打开关闭串口,相应的是调用类的Open()和Close()方法。
4. 数据的发送和读取
Serial类调用重载的Write和WriteLine方法发送数据,其中WriteLine可发送字符串并在字符串末尾加入换行符,
读取串口缓冲区的方法有许多,其中除了ReadExisting和ReadTo,其余的方法都是同步调用,
线程被阻塞直到缓冲区有相应的数据或大于ReadTimeOut属性设定的时间值后,引发ReadExisting异常。
5.DataReceived事件
该事件类似于MSComm控件中的OnComm事件,DataReceived事件在接收到了[ReceivedBytesThreshold]设置的字符个数或接收到了
文件结束字符并将其放入了输入缓冲区时被触发。其中[ReceivedBytesThreshold]相当于MSComm控件的[Rthreshold]属性,
该事件的用法与MsComm控件的OnComm事件在CommEvent为comEvSend和comEvEof时是一致的。
三.SerialPort的使用
对于熟悉MSComm控件的程序设计者,SerialPort类是相当容易上手的。在进行串口通讯时,一般的流程是设置通讯端口号及波特率、
数据位、停止位和校验位,再打开端口连接,发送数据,接收数据,最后关闭端口连接这样几个步骤。
数据接收的设计方法在这里比较重要,采用轮询的方法比较浪费时间,在Visual
Basic中的延时方法中一般会调用API并用DOEvents方法来处理,
但程序不易控制,建议采用DataReceived事件触发的方法,合理的设置ReceivedBytesThreshold的值,若接收的是定长的数据,
则将ReceivedBytesThreshold设为接收数据的长度,若接收数据的结尾是固定的字符或字符串则可采用ReadTo的方法或在DataReceived事件中判断接收的字符是否满足条件。
SerialPort类读取数据的许多方法是同步阻塞调用,尽量避免在主线程中调用,
可以使用异步处理或线程间处理调用这些读取数据的方法。
由于DataReceived事件在辅线程被引发,当收到完整的一条数据,返回主线程处理或在窗体上显示时,请注意跨线程的处理,
C#可采用控件异步委托的方法Control.BeginInvoke及同步委托的方法Invoke。
四.结束语
在.NET平台下熟练使用SerialPort
类,可以很好地开发出串口通讯类程序,对于过去使用MSComm控件设计了一些通讯程序,
也可以将MSComm控件替换为SerialPort类,当然为了避免对以前的项目做大的改动,可以使用SerialPort类设计一些与MSComm控件具有相同接口的类,
在今后工业控制中,SerialPort类将广泛地应用于串口通讯程序的设计中,发挥着与MSComm控件一样的作用。
C# SerialPort 串口通信
1 简介
随着USB的流行,串口通讯已经应用到日常生活的很多方面了,USB是一种高速的串口通讯协议,USB接口非常复杂,
通常被用在需要传输大量数据数据的地方,如U盘、相机、打印机等。除了USB这种较为奢侈的串口外,在工控和嵌入式行业,
大量被使用的是另一种古老的串口协议,RS-232串口。RS-232是一种非常简洁的低速串口通讯接口,它可以同时进行数据接收和发送的工作。
2 .NET 2.0对串口的支持
.NET
2.0提供了对串口通信功能的支持,有关类可以在命名空间System.IO.Ports下找到,这其中最为重要的是SerialPort类。
通过创建一个新的SerialPort 对象,我们就可以在.NET程序中控制串口通讯的全过程。
3 使用 SerialPort 设置串口属性
进行串口通讯时,需要设置一些相关参数,可以通过设置SerialPort 类的属性来进行。串口属性主要包括
.PortName 串口名称,COM1, COM2等。
.BaudRate
波特率,也就是串口通讯的速度,进行串口通讯的双方其波特率需要相同,如果用PC连接其他非PC系统,一般地,波特率由非PC系统决定。
.Parity 奇偶校验。可以选取枚举Parity中的值
.DataBits 数据位
.StopBits 停止位,可以选取枚举StopBits中的值
.Handshake 握手方式,也就是数据流控制方式,可以选取枚举Handshake中的值
4 打开与关闭串口
在创建一个SerialPort 对象,设置串口属性后,可以通过
Open()方法打开串口。数据读写完成后,可以通过Close()方法关闭串口。
根据经验,对于有些系统,在打开串口后,还需要将RtsEnable设置为True,这样才能读写数据,否则不能正常读写数据。
5 读写行数据
双方通讯时,一般都需要定义通讯协议,即使最简单的通过串口发送文本聊天的程序。
通常是在当一方按下回车时,将其所数据的文本连同换行符发给另一方。在这个通讯事例中,协议桢是通过换行符界定的,
每一桢数据都被换行符隔开,这样就很容易识别出通讯双发发送的信息。
在以上的例子中,可以用WriteLine()来发送数据,用ReadLine()来读取数据。WriteLine发送完数据后,会将换行符作为数据也发送给对方。
ReadLine()读取数据时,直至遇到一个换行符,然后返回一个字符串代表一行信息。换行符可以通过SerialPort
的属性NewLine来设置。
一般地,Windows将CrLn作为换行符,而在Linux下,换行符则只用一个Ln表示。
ReadLine()方法是阻塞的,直至遇到一个换行符后返回。在读取数据时,如果一直没有遇到换行符,那么在等待ReadTimeout时间后,
抛出一个TimeoutException。默认情况下,ReadTimeout为InfiniteTimeout。这样,ReadLine一直处于阻塞状态,直至有新一行数据到达。
WriteLine()方法也是阻塞的,如果另一方不能及时接收数据,就会引起TimeoutException异常。
由于ReadLine()和WriteLine()方法都是阻塞式的,在程序使用SerialPort
进行串口通讯时,一般应该把读写操作交由其他线程处理,
避免因为阻塞而导致程序不响应。
6 读写字节或字符数据
对于字节或字符数据,用Read()方法来读数据,该方法需要一个字节或字符数组作为参数来保存读取的数据,结果返回实际读取的字节或字符数。
写数据使用Write()方法,该方法可以将字节数组、字符数据或字符串发送给另一方。
如果通讯双方交换的数据位字节流数据,要构建一个使用的串口通讯程序,那么双方应该定义数据桢格式。通常数据桢由桢头和桢尾来界定。
发送数据比较简单,只需要将构造好的数据用Write()方法发送出去即可。
接收数据则比较复杂,通讯是以字节流的形式到达的,通过调用一次Read()方法并不能确保所读取的数据就是完整一桢。
因此需要将每次读取的数据整合在一起,对整合后的数据进行分析,按照定义的桢格式,通过桢头和桢尾,将桢信息从字节流中抽取出来,
这样才能获取有意义的信息。
除了利用Read()方法来读数据,还可以使用ReadExisting()方法来读取数据。该方法读取当前所能读到的数据,以字符串的形式返回。
7 事件
SerialPort
提供了DataReceived事件。当有数据进入时,该事件被触发。该事件的触发由操作系统决定,当有数据到达时,
该事件在辅助线程中被触发。辅助线程的优先级比较低,因此并不能确保每个字节的数据到达时,该事件都被触发。
在使用该事件接收数据时,最好对定义通讯协议格式,添加桢头和桢尾。在DataReceived事件中接收数据时,
把数据放在数组中或字符串中缓冲起来,当接收的包含桢头和桢尾的完整数据时,在进行处理,另外,为了有效地接收数据,
可以在每次读取数据后,加入System.Threading.Thread.Sleep方法进行演示。
8 其他
用跳线使串口的第2、3针连接,可以在本地计算机上实现串口通信,所以,通过串口的第2、3针的连接可以对程序进行检测。
.BytesToRead 该属性返回能够读到的字节数。
方 法 名 称
说 明
Close
关闭端口连接,将 IsOpen 属性设置为False,并释放内部 Stream
对象
Open
打开一个新的串行端口连接
Read
从 SerialPort 输入缓冲区中读取数据字节数
ReadByte
从 SerialPort 输入缓冲区中同步读取一个字节
ReadChar
从 SerialPort 输入缓冲区中同步读取一个字符
ReadLine
一直读取到输入缓冲区中的 NewLine 值
ReadTo
一直读取到输入缓冲区中指定 value
的字符串
Write
已重载。将数据写入串行端口输出缓冲区
WriteLine
将指定的字符串和 NewLine 值写入输出缓冲区
DiscardInBuffer
DiscardOutBuffer
清空接收缓冲区数据
清空输出缓冲去数据
属性说明
名 称
说 明
BaseStream
获取 SerialPort 对象的基础 Stream 对象
BaudRate
获取或设置串行波特率
BreakState
获取或设置中断信号状态
BytesToRead
获取接收缓冲区中数据的字节数
BytesToWrite
获取发送缓冲区中数据的字节数
CDHolding
获取端口的载波检测行的状态
CtsHolding
获取“可以发送”行的状态
DataBits
获取或设置每个字节的标准数据位长度
DiscardNull
获取或设置一个值,该值指示 Null 字节在端口和接收缓冲区之间传输时是否被忽略
DsrHolding
获取数据设置就绪 (DSR) 信号的状态
DtrEnable
获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号
Encoding
获取或设置传输前后文本转换的字节编码
Handshake
获取或设置串行端口数据传输的握手协议
IsOpen
获取一个值,该值指示 SerialPort 对象的打开或关闭状态
NewLine
获取或设置用于解释 ReadLine( )和WriteLine( )方法调用结束的值
Parity
获取或设置奇偶校验检查协议
ParityReplace
获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节
PortName
获取或设置通信端口,包括但不限于所有可用的 COM 端口
ReadBufferSize
获取或设置 SerialPort 输入缓冲区的大小
ReadTimeout
获取或设置读取操作未完成时发生超时之前的毫秒数
ReceivedBytesThreshold
获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数
RtsEnable
获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号
StopBits
获取或设置每个字节的标准停止位数
WriteBufferSize
获取或设置串行端口输出缓冲区的大小
WriteTimeout
获取或设置写入操作未完成时发生超时之前的毫秒数
注意:C#中SerialPort类对串口供电需要设置DtrEnable和RtsEnable两个属性在开发中有些串口设备需要串口供电,
使用C#中的SerialPort类默认情况下不会出发DataReceived函数,但使用超级终端却可以接收到数据,
这是因为SerialPort类的DtrEnable和RtsEnable两个属性默认是false,设为true即可接收数据了,如下:
this.m_SerialPort.DtrEnable = true; //启用控制终端就续信号
我用VS 2005 C#写串口 在打开串口就有问题 帮忙看看啊
public partial class Form1 :
Form
{
myCom1 comm = new
myCom1();
parameter p = new
parameter();
public Form1()
{
InitializeComponent();
}
public class myCom1
{
public event SerialDataReceivedEventHandler
Received;
public event SerialErrorReceivedEventHandler
Error;
public bool ReceiveEventFlag = false; //接收事件是否有效
false表示有效
public SerialPort SpCom1 ;
public SerialPort SpCom2 ;
//初始化串口
public myCom1()
{
SpCom1 = new
SerialPort("COM1", 19200, Parity.None, 8,
StopBits.One);
SpCom1.RtsEnable =
true;
SpCom1.ReadTimeout =
3000;
SpCom1.DataReceived += new
SerialDataReceivedEventHandler(DataReceived1);
SpCom1.ErrorReceived += new
SerialErrorReceivedEventHandler(ErrorEvent);
SpCom2 = new
SerialPort("COM2", 19200, Parity.None, 8,
StopBits.One);
SpCom2.RtsEnable =
true;
SpCom2.ReadTimeout =
3000;
SpCom2.DataReceived += new
SerialDataReceivedEventHandler(DataReceived2);
SpCom2.ErrorReceived += new
SerialErrorReceivedEventHandler(ErrorEvent);
}
~myCom1()
{
Close1();
Close2();
}
//
public SerialPort SpCom1 = new SerialPort("COM1", 19200,
Parity.None, 8, StopBits.One);
//public SerialPort SpCom2 = new
SerialPort("COM2", 19200, Parity.None, 8,
StopBits.One);
//打开串口
public void Open1()
{
if
(!SpCom1.IsOpen)
SpCom1.Open();
}
public void Open2()
{
if
(!SpCom2.IsOpen)
SpCom2.Open();
}
private void Form1_Load(object sender, EventArgs
e)
{
this.MaximizeBox = false;
//
comm.Open1();
}
//打开串口
private void Bt_Open_Click(object sender,
EventArgs e)
{
comm.Open1();
comm.Open2();
}
在监控器中显示发送两遍
Read:
Baud rate set to 19200
StopBits: 1 stop bit, Parity: No parity, WordLength:
8
Baud rate set to 19200
StopBits: 1 stop bit, Parity: No parity, WordLength:
8
Port closed
write:
Port opened
Baud rate set to 19200
StopBits: 1 stop bit, Parity: No parity, WordLength:
8
Baud rate set to 19200
StopBits: 1 stop bit, Parity: No parity, WordLength:
8
Port closed
RtsEnable false
SerialPort类的属性和方法
|
名 称
|
说 明
|
|
BaseStream
|
获取 SerialPort 对象的基础 Stream 对象
|
|
BaudRate
|
获取或设置串行波特率
|
|
BreakState
|
获取或设置中断信号状态
|
|
BytesToRead
|
获取接收缓冲区中数据的字节数
|
|
BytesToWrite
|
获取发送缓冲区中数据的字节数
|
|
CDHolding
|
获取端口的载波检测行的状态
|
|
CtsHolding
|
获取“可以发送”行的状态
|
|
DataBits
|
获取或设置每个字节的标准数据位长度
|
|
DiscardNull
|
获取或设置一个值,该值指示 Null
字节在端口和接收缓冲区之间传输时是否被忽略
|
|
DsrHolding
|
获取数据设置就绪 (DSR) 信号的状态
|
|
DtrEnable
|
获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR)
信号
|
|
Encoding
|
获取或设置传输前后文本转换的字节编码
|
|
Handshake
|
获取或设置串行端口数据传输的握手协议
|
|
IsOpen
|
获取一个值,该值指示 SerialPort 对象的打开或关闭状态
|
|
NewLine
|
获取或设置用于解释 ReadLine( )和WriteLine(
)方法调用结束的值
|
|
Parity
|
获取或设置奇偶校验检查协议
|
|
名 称
|
说 明
|
|
ParityReplace
|
获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节
|
|
PortName
|
获取或设置通信端口,包括但不限于所有可用的 COM 端口
|
|
ReadBufferSize
|
获取或设置 SerialPort 输入缓冲区的大小
|
|
ReadTimeout
|
获取或设置读取操作未完成时发生超时之前的毫秒数
|
|
ReceivedBytesThreshold
|
获取或设置 DataReceived
事件发生前内部输入缓冲区中的字节数
|
|
RtsEnable
|
获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS)
信号
|
|
StopBits
|
获取或设置每个字节的标准停止位数
|
|
WriteBufferSize
|
获取或设置串行端口输出缓冲区的大小
|
|
WriteTimeout
|
获取或设置写入操作未完成时发生超时之前的毫秒数
|
方法
|
方 法 名 称
|
说 明
|
|
Close
|
关闭端口连接,将 IsOpen 属性设置为False,并释放内部
Stream 对象
|
|
Open
|
打开一个新的串行端口连接
|
|
Read
|
从 SerialPort 输入缓冲区中读取
|
|
ReadByte
|
从 SerialPort 输入缓冲区中同步读取一个字节
|
|
ReadChar
|
从 SerialPort 输入缓冲区中同步读取一个字符
|
|
ReadLine
|
一直读取到输入缓冲区中的 NewLine 值
|
|
ReadTo
|
一直读取到输入缓冲区中指定 value 的字符串
|
|
Write
|
已重载。将数据写入串行端口输出缓冲区
|
|
WriteLine
|
将指定的字符串和 NewLine 值写入输出缓冲区
|
加载中,请稍候......