C#使用SerialPort类实现串口通信
原文转自: https://www.cnblogs.com/hbtmwangjin/articles/9146299.html
主要用于学习记录
如果需要了解更多的信息请登录http://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport(VS.80).aspx查看。
在.NET Framework 2.0中提供了SerialPort类,该类主要实现串口数据通信等。
下面主要介绍该类的主要属性(表1)和方法(表.2)
表1 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 |
获取或设置写入操作未完成时发生超时之前的毫秒数 |
表2 SerialPort类的常用方法
方 法 名 称 |
说 明 |
Close |
关闭端口连接,将 IsOpen 属性设置为False,并释放内部 Stream 对象 |
Open |
打开一个新的串行端口连接 |
Read |
从 SerialPort 输入缓冲区中读取 |
ReadByte |
从 SerialPort 输入缓冲区中同步读取一个字节 |
ReadChar |
从 SerialPort 输入缓冲区中同步读取一个字符 |
ReadLine |
一直读取到输入缓冲区中的 NewLine 值 |
ReadTo |
一直读取到输入缓冲区中指定 value 的字符串 |
Write |
已重载。将数据写入串行端口输出缓冲区 |
WriteLine |
将指定的字符串和 NewLine 值写入输出缓冲区 |
使用SerialPort类的方法:
方法一:
首先要添加
using System.IO;
using System.IO.Ports;
1...在类的内部定义SerialPort com;
2...打开串口
com = new SerialPort();
com.BaudRate = 115200;
com.PortName = "COM1";
com.DataBits = 8;
com.Open();//打开串口
3...发送数据
Byte[] TxData ={1,2,3,4,5,6,7,8 };
com.Write(TxData, 0, 8);
4...接收数据
4.1使用事件接收
this.com.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
4.2使用线程接收
接收数据启动一个线程,使其接收。
在类的内部定义
Thread _readThread;
bool _keepReading;
打开串口后启动线程
_keepReading = true;
_readThread = new Thread(ReadPort);
_readThread.Start();
线程函数
- private void ReadPort()
- {
- while (_keepReading)
- {
- if (com.IsOpen)
- {
- byte[] readBuffer = new byte[com.ReadBufferSize + 1];
- try
- {
- // If there are bytes available on the serial port,
- // Read returns up to "count" bytes, but will not block (wait)
- // for the remaining bytes. If there are no bytes available
- // on the serial port, Read will block until at least one byte
- // is available on the port, up until the ReadTimeout milliseconds
- // have elapsed, at which time a TimeoutException will be thrown.
- int count = com.Read(readBuffer, 0, com.ReadBufferSize);
- String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);
- if (count != 0)
- //byteToHexStr(readBuffer);
- ThreadFunction(byteToHexStr(readBuffer,count));
- }
- catch (TimeoutException) { }
- }
- else
- {
- TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
- Thread.Sleep(waitTime);
- }
- }
- }
方法二:使用C#自带的SerialPor控件。
1...在“工具箱”的“组件”中选择SerialPor控件添加。
2...设置串口并打开
serialPort1.PortName = "COM1";
serialPort1.BaudRate = 9600;
serialPort1.Open();
3...写入数据可以使用Write或者下面的函数
serialPort1.WriteLine(str);
4...添加数据接收的事件
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
使用中的一些常见问题
C#中SerialPort类中DataReceived事件GUI实时处理方法(来自wanglei_wan@yahoo.com.cn 的看法)
MSDN:从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。由于此事件在辅助线程而非主线程上引发,因此尝试修改主线程中的一些元素(如 UI 元素)时会引发线程异常。如果有必要修改主 Form 或 Control 中的元素,必须使用 Invoke 回发更改请求,这将在正确的线程上执行.进而要想将辅助线程中所读到的数据显示到主线程的Form控件上时,只有通过Invoke方法来实现
下面是代码实例:
- private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
- {
- int SDateTemp = this.serialPort1.ReadByte();
- //读取串口中一个字节的数据
- this.tB_ReceiveDate.Invoke(
- //在拥有此控件的基础窗口句柄的线程上执行委托Invoke(Delegate)
- //即在textBox_ReceiveDate控件的父窗口form中执行委托.
- new MethodInvoker(
- /*表示一个委托,该委托可执行托管代码中声明为 void 且不接受任何参数的任何方法。 在对控件的 Invoke 方法进行调用时或需要一个简单委托又不想自己定义时可以使用该委托。*/
- delegate{
- /*匿名方法,C#2.0的新功能,这是一种允许程序员将一段完整代码区块当成参数传递的程序代码编写技术,通过此种方法可 以直接使用委托来设计事件响应程序以下就是你要在主线程上实现的功能但是有一点要注意,这里不适宜处理过多的方法,因为C#消息机制是消息流水线响应机制,如果这里在主线程上处理语句的时间过长会导致主UI线程阻塞,停止响应或响应不顺畅,这时你的主form界面会延迟或卡死 */
- this.tB_ReceiveDate.AppendText(SDateTemp.ToString());//输出到主窗口文本控件
- this.tB_ReceiveDate.Text += " ";}
- )
- );
- }
如何知道当前电脑有哪个串口
在窗体上添加一个comboBox控件。
然后使用comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames()); 或者
string[] portList = System.IO.Ports.SerialPort.GetPortNames();
for (int i = 0; i < portList.Length; ++i)
{
string name = portList[i];
comboBox1.Items.Add(name);
}