串口控件是我们与硬件对接的常用控件,很多PLC都会转为串口来与PC通信、传输数据,所以学习好串口控件是非常重要的事。
属性:
属性名称 | 说明 |
BaseStream |
获取 Stream 对象的基础 SerialPort 对象。 |
BaudRate |
获取或设置串行波特率。 |
BreakState |
获取或设置中断信号状态。 |
BytesToRead |
获取接收缓冲区中数据的字节数。 |
BytesToWrite |
获取发送缓冲区中数据的字节数。 |
CDHolding | 获取端口的载波检测行的状态。 |
CtsHolding |
获取“可以发送”行的状态。 |
DataBits |
获取或设置每个字节的标准数据位长度。 |
DiscardNull |
获取或设置一个值,该值指示 null 字节在端口和接收缓冲区之间传输时是否被忽略。 |
DsrHolding |
获取数据设置就绪 (DSR) 信号的状态。 |
DtrEnable |
获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号。 |
Encoding | 获取或设置传输前后文本转换的字节编码。 |
Handshake | 使用 Handshake 中的值获取或设置串行端口数据传输的握手协议。 |
IsOpen |
获取一个值,该值指示 SerialPort 对象的打开或关闭状态。 |
NewLine |
获取或设置用于解释 ReadLine() 和 WriteLine(String) 方法调用结束的值。 |
Parity | 获取或设置奇偶校验检查协议。 |
ParityReplace |
获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节。 |
PortName |
获取或设置通信端口,包括但不限于所有可用的 COM 端口。 |
ReadBufferSize |
获取或设置 SerialPort 输入缓冲区的大小。 |
ReadTimeout |
获取或设置读取操作未完成时发生超时之前的毫秒数。 |
ReceivedBytesThreshold |
获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数。 |
RtsEnable |
获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号。 |
StopBits |
获取或设置每个字节的标准停止位数。 |
WriteBufferSize |
获取或设置串行端口输出缓冲区的大小。 |
WriteTimeout |
获取或设置写入操作未完成时发生超时之前的毫秒数。 |
方法:
方法名称 | 说明 |
Close() | 关闭端口连接,将 IsOpen 属性设置为 false,并释放内部 Stream 对象。 |
DiscardInBuffer() |
丢弃来自串行驱动程序的接收缓冲区的数据。 |
DiscardOutBuffer() |
丢弃来自串行驱动程序的传输缓冲区的数据。 |
Dispose(Boolean) | 释放由 SerialPort 占用的非托管资源,还可以另外再释放托管资源。 |
GetPortNames() |
获取当前计算机的串行端口名的数组。 |
Open() | 打开一个新的串行端口连接。 |
Read(Byte[], Int32, Int32) | 从 SerialPort 输入缓冲区读取一些字节并将那些字节写入字节数组中指定的偏移量处。 |
Read(Char[], Int32, Int32) | 从 SerialPort 输入缓冲区中读取一些字符,然后将这些字符写入字符数组中指定的偏移量处。 |
ReadByte() |
从 SerialPort 输入缓冲区中同步读取一个字节。 |
ReadChar() |
从 SerialPort 输入缓冲区中同步读取一个字符。 |
ReadExisting() |
在编码的基础上,读取 SerialPort 对象的流和输入缓冲区中所有立即可用的字节。 |
ReadLine() |
一直读取到输入缓冲区中的 NewLine 值。 |
ReadTo(String) |
一直读取到输入缓冲区中的指定 value 的字符串。 |
Write(Byte[], Int32, Int32) | 使用缓冲区中的数据将指定数量的字节写入串行端口。 |
Write(Char[], Int32, Int32) | 使用缓冲区中的数据将指定数量的字符写入串行端口。 |
Write(String) | 将指定的字符串写入串行端口。 |
WriteLine(String) |
将指定的字符串和 NewLine 值写入输出缓冲区。 |
事件:
事件名称 | 描述 |
DataReceived |
指示已通过由 SerialPort 对象表示的端口接收了数据。 |
ErrorReceived |
指示由 SerialPort 对象表示的端口上发生了错误。 |
PinChanged |
指示由 SerialPort 对象表示的端口上发生了非数据信号事件。 |
下面我们就常用属性和方法演示一下如何串口控件。
第一步,先按照下面的布局创建一个窗口及相应的控件。
第二步,下拉窗体窗体的列表项设置一下初始值
第三步,在命令按钮、窗体、SerialPort控件的相关事件中写下下面的代码。
Vb.Net |
Imports System Imports System.Text Imports System.IO Imports System.Data Imports System.Drawing Imports System.Drawing.Drawing2D Imports System.Drawing.Imaging Imports System.Drawing.Text Imports System.Diagnostics Imports System.Collections Imports System.Collections.Generic Imports System.Runtime.InteropServices Imports System.Collections.Specialized Imports System.Windows.Forms Imports System.Reflection Imports Microsoft.CSharp Imports Microsoft.VisualBasic Imports sanMuSoft.Utility Imports sanMuSoft.Data.Pivot Imports System.Linq Imports System.Threading Imports System.Threading.Tasks Imports System.Xml Imports System.Data.Common Imports System.Net.Http Imports C1.C1Excel Imports C1.C1Zip Imports C1.Win.C1Command Imports C1.Win.C1FlexGrid Imports C1.Win.C1Input Imports C1.Win.C1Ribbon Imports C1.Win.C1Themes Imports sanMuSoft.CS.Framework Imports sanMuSoft.CS.Framework.Editor Imports sanMuSoft.CS.Framework.FormDesigner Imports sanMuSoft.CS.Framework.DropDownForms Imports sanMuSoft.CS.WinForm Imports sanMuSoft.CS.WinForm.Editor Imports sanMuSoft.CS.WinForm.Controls Imports sanMuSoft.CS.WinForm.Controls.Grid Imports sanMuSoft.CS.WinForm.Controls.BoxControls Imports sanMuSoft.CS.Workflow Imports sanMuSoft.CS.Report Imports sanMuSoft.Data Imports sanMuSoft.Data.TableBuilder Imports sanMuSoft.CS.ShareFunc Imports Newtonsoft.Json.Linq Imports Newtonsoft.Json Imports Aliyun.OSS Imports System.IO.Ports Namespace FormEvents Public Class Form3ea7b7bb7a3f4cdca664a0f59ff54243 Inherits FormEventsBase Private rdoHex As SmRadioButton Private rdoText As SmRadioButton Private txtSend As SmTextBox Private txtGetHex As SmTextBox Private txtGetString As SmTextBox Private SerialPort1 As System.IO.Ports.SerialPort Private cmbBaudRate As SmComboBox Private cmbDataBits As SmComboBox Private cmbParity As SmComboBox Private cmbPorts As SmComboBox Private cmbStopBits As SmComboBox Private lblStatus As SmLabel Private btnClose As SmButton Private btnOpen As SmButton Public Sub SerialPortHelp_Load(sender As Object,e As System.EventArgs) '给私有字段赋值,方便在其他事件中方便引用 rdoHex=Me.SmForm.ControlDictionary()("rdoHex") rdoText=Me.SmForm.ControlDictionary()("rdoText") txtSend=Me.SmForm.ControlDictionary()("txtSend") txtGetHex=Me.SmForm.ControlDictionary()("txtGetHex") txtGetString=Me.SmForm.ControlDictionary()("txtGetString") SerialPort1=Me.SmForm.Components.Components("SerialPort1") cmbBaudRate=Me.SmForm.ControlDictionary()("cmbBaudRate") cmbDataBits=Me.SmForm.ControlDictionary()("cmbDataBits") cmbParity=Me.SmForm.ControlDictionary()("cmbParity") cmbPorts=Me.SmForm.ControlDictionary()("cmbPorts") cmbStopBits=Me.SmForm.ControlDictionary()("cmbStopBits") lblStatus=Me.SmForm.ControlDictionary()("lblStatus") btnClose=Me.SmForm.ControlDictionary()("btnClose") btnOpen=Me.SmForm.ControlDictionary()("btnOpen") '获取计算机有效串口 RefreshSerialPortList() '初始化界面,设置一个默认连接参数 cmbBaudRate.Text = 9600 cmbDataBits.Text = 8 cmbParity.Text = "N" cmbStopBits.Text = 1 btnClose.Enabled = False btnOpen.Enabled = True End Sub Public Sub btnSend_Click(sender As Object,e As System.EventArgs) Try '如果发送文本不为空,则执行发送动作 If txtSend.Text.Length > 0 Then If rdoHex.Checked = True Then '如果按照十六进制发送 '将十六进制文本转换成字节数组 Dim aa As Byte() = Crypt.HexStringToBytes(txtSend.Text) SerialPort1.Write(aa, 0, aa.Length) ElseIf rdoText.Checked = True Then '如果按照文本改善 '直接发送文本内容 SerialPort1.Write(txtSend.Text) End If End If Catch ex As Exception UnhandledExceptionManager.ShowAndSaveLog(ex) End Try End Sub Public Sub btnRefreshSerialPort_Click(sender As Object,e As System.EventArgs) '刷新界面上串口的清单 RefreshSerialPortList() End Sub '刷新界面上串口的清单 Private Sub RefreshSerialPortList() '先清空当前清单 cmbPorts.Items.Clear() '遍历所有系统中的串口 For Each port As String In Sys.Ports.SerialPortNames Me.cmbPorts.Items.Add(port) '向combobox中添加项 Next port '如果只有一个串口,则自动填充到当前串口引用 If cmbPorts.Items.Count = 1 Then cmbPorts.Text = cmbPorts.Items(0) End If End Sub Public Sub btnOpen_Click(sender As Object,e As System.EventArgs) Try '如果当前选择了相应的串口及相关参数,如果设置好了则将相应的参数赋值给SerialPort1对象 If Serial_PortOpen() = True Then '打开串口的监测 SerialPort1.Open() '将串口的状态显示出来,同时控制按钮的可用状态 If SerialPort1.IsOpen = True Then lblStatus.BackColor = Color.Green btnClose.Enabled = True btnOpen.Enabled = False End If End If Catch ex As Exception UnhandledExceptionManager.ShowAndSaveLog(ex) End Try End Sub Public Sub btnClose_Click(sender As Object,e As System.EventArgs) Try SerialPort1.Close() '关闭串口 '将串口的状态显示出来,同时控制按钮的可用状态 If SerialPort1.IsOpen = False Then lblStatus.BackColor = Color.Red txtGetHex.Text = "" txtGetString.Text = "" End If btnOpen.Enabled = True Catch ex As Exception UnhandledExceptionManager.ShowAndSaveLog(ex) End Try End Sub Public Sub SerialPort1_DataReceived(sender As Object,e As System.IO.Ports.SerialDataReceivedEventArgs) '使用窗体的Invoke方法,让Sp_Receiving方法在窗体的主线程执行,要不然因为当前事件异步执行而无法正常将结果赋值到界面控件中 Me.SmForm.Invoke(New EventHandler(AddressOf Sp_Receiving)) '调用接收数据函数 End Sub '接收数据 Private Sub Sp_Receiving(ByVal sender As Object, ByVal e As EventArgs) Try '如果读取到了数据 If SerialPort1.BytesToRead > 0 Then Threading.Thread.Sleep(100) '添加的延时,给数据传递一点发送时间,如果不加此句,有可能会读不到数据 '读取数据 Dim ReceivedData As Byte() ReDim ReceivedData(SerialPort1.BytesToRead - 1) SerialPort1.Read(ReceivedData, 0, ReceivedData.Length) '清空缓存 SerialPort1.DiscardInBuffer() '将读取到的数据转换成字符串 Dim strR As String = Crypt.BytesToHexString(ReceivedData) '将结果显示到界面 txtGetHex.Text = strR txtGetString.Text = Encoding.ASCII.GetString(ReceivedData) End If Catch ex As Exception UnhandledExceptionManager.ShowAndSaveLog(ex) End Try End Sub ''' <summary> ''' 如果当前选择了相应的串口及相关参数,如果设置好了则将相应的参数赋值给SerialPort1对象 ''' </summary> ''' <returns></returns> Private Function Serial_PortOpen() As Boolean '设置串口参数 If cmbPorts.Text.Length = 0 Then MessageBox.Show("请先选择好相应的串口后,再执行此操作!", "提示") Return False End If If cmbStopBits.Text.Length = 0 Then MessageBox.Show("请先选择好相应的停止位后,再执行此操作!", "提示") Return False End If If cmbBaudRate.Text.Length = 0 Then MessageBox.Show("请先选择好相应的波特率后,再执行此操作!", "提示") Return False End If If cmbDataBits.Text.Length = 0 Then MessageBox.Show("请先选择好相应的数据位后,再执行此操作!", "提示") Return False End If If cmbParity.Text.Length = 0 Then MessageBox.Show("请先选择好相应的校验位后,再执行此操作!", "提示") Return False End If SerialPort1.BaudRate = CInt(cmbBaudRate.Text) '波特率 SerialPort1.PortName = cmbPorts.Text '串口名称 SerialPort1.DataBits = CInt(cmbDataBits.Text) '数据位 SerialPort1.ReadBufferSize = 4096 '读取缓存大小 '设置校验位 Select Case cmbParity.Text Case "E" SerialPort1.Parity = Parity.Even Case "M" SerialPort1.Parity = Parity.Mark Case "N" SerialPort1.Parity = Parity.None Case "O" SerialPort1.Parity = Parity.Odd Case "S" SerialPort1.Parity = Parity.Space End Select '设置停止位 Select Case cmbStopBits.Text Case "1" SerialPort1.StopBits = IO.Ports.StopBits.One Case "2" SerialPort1.StopBits = IO.Ports.StopBits.Two End Select Return True End Function End Class End Namespace |
C# |
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Text; using System.Threading.Tasks; using Microsoft.VisualBasic; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Drawing.Text; using System.Collections; using System.Runtime.InteropServices; using System.Collections.Specialized; using System.Windows.Forms; using Microsoft.CSharp; using sanMuSoft.Utility; using sanMuSoft.Data.Pivot; using System.Threading; using System.Xml; using System.Data.Common; using System.Net.Http; using C1.C1Excel; using C1.C1Zip; using C1.Win.C1Command; using C1.Win.C1FlexGrid; using C1.Win.C1Input; using C1.Win.C1Ribbon; using C1.Win.C1Themes; using sanMuSoft.CS.Framework; using sanMuSoft.CS.Framework.Editor; using sanMuSoft.CS.Framework.FormDesigner; using sanMuSoft.CS.Framework.DropDownForms; using sanMuSoft.CS.WinForm; using sanMuSoft.CS.WinForm.Editor; using sanMuSoft.CS.WinForm.Controls; using sanMuSoft.CS.WinForm.Controls.Grid; using sanMuSoft.CS.WinForm.Controls.BoxControls; using sanMuSoft.CS.Workflow; using sanMuSoft.CS.Report; using sanMuSoft.Data; using sanMuSoft.Data.TableBuilder; using sanMuSoft.CS.ShareFunc; using Newtonsoft.Json.Linq; using Newtonsoft.Json; using Aliyun.OSS; using System.IO.Ports; namespace FormEvents { public class Form3ea7b7bb7a3f4cdca664a0f59ff54243 : FormEventsBase { private SmRadioButton rdoHex; private SmRadioButton rdoText; private SmTextBox txtSend; private SmTextBox txtGetHex; private SmTextBox txtGetString; private System.IO.Ports.SerialPort SerialPort1; private SmComboBox cmbBaudRate; private SmComboBox cmbDataBits; private SmComboBox cmbParity; private SmComboBox cmbPorts; private SmComboBox cmbStopBits; private SmLabel lblStatus; private SmButton btnClose; private SmButton btnOpen; public void SerialPortHelp_Load(object sender, System.EventArgs e) { // 给私有字段赋值,方便在其他事件中方便引用 rdoHex = this.SmForm.ControlDictionary()["rdoHex"] as SmRadioButton; rdoText = this.SmForm.ControlDictionary()["rdoText"] as SmRadioButton; txtSend = this.SmForm.ControlDictionary()["txtSend"] as SmTextBox; txtGetHex = this.SmForm.ControlDictionary()["txtGetHex"] as SmTextBox; txtGetString = this.SmForm.ControlDictionary()["txtGetString"] as SmTextBox; SerialPort1 = this.SmForm.Components.Components["SerialPort1"] as SerialPort; cmbBaudRate = this.SmForm.ControlDictionary()["cmbBaudRate"] as SmComboBox; cmbDataBits = this.SmForm.ControlDictionary()["cmbDataBits"] as SmComboBox; cmbParity = this.SmForm.ControlDictionary()["cmbParity"] as SmComboBox; cmbPorts = this.SmForm.ControlDictionary()["cmbPorts"] as SmComboBox; cmbStopBits = this.SmForm.ControlDictionary()["cmbStopBits"] as SmComboBox; lblStatus = this.SmForm.ControlDictionary()["lblStatus"] as SmLabel; btnClose = this.SmForm.ControlDictionary()["btnClose"] as SmButton; btnOpen = this.SmForm.ControlDictionary()["btnOpen"] as SmButton; // 获取计算机有效串口 RefreshSerialPortList(); // 初始化界面,设置一个默认连接参数 cmbBaudRate.Text = 9600; cmbDataBits.Text = 8; cmbParity.Text = "N"; cmbStopBits.Text = 1; btnClose.Enabled = false; btnOpen.Enabled = true; } public void btnSend_Click(object sender, System.EventArgs e) { try { // 如果发送文本不为空,则执行发送动作 if (txtSend.Text.Length > 0) { if (rdoHex.Checked == true) { // 将十六进制文本转换成字节数组 byte[] aa = Crypt.HexStringToBytes(txtSend.Text); SerialPort1.Write(aa, 0, aa.Length); } else if (rdoText.Checked == true) // 直接发送文本内容 SerialPort1.Write(txtSend.Text); } } catch (Exception ex) { UnhandledExceptionManager.ShowAndSaveLog(ex); } } public void btnRefreshSerialPort_Click(object sender, System.EventArgs e) { // 刷新界面上串口的清单 RefreshSerialPortList(); } // 刷新界面上串口的清单 private void RefreshSerialPortList() { // 先清空当前清单 cmbPorts.Items.Clear(); // 遍历所有系统中的串口 foreach (string port in Sys.Ports.SerialPortNames) this.cmbPorts.Items.Add(port);// 向combobox中添加项 // 如果只有一个串口,则自动填充到当前串口引用 if (cmbPorts.Items.Count == 1) cmbPorts.Text = cmbPorts.Items(0); } public void btnOpen_Click(object sender, System.EventArgs e) { try { // 如果当前选择了相应的串口及相关参数,如果设置好了则将相应的参数赋值给SerialPort1对象 if (Serial_PortOpen() == true) { // 打开串口的监测 SerialPort1.Open(); // 将串口的状态显示出来,同时控制按钮的可用状态 if (SerialPort1.IsOpen == true) { lblStatus.BackColor = Color.Green; btnClose.Enabled = true; btnOpen.Enabled = false; } } } catch (Exception ex) { UnhandledExceptionManager.ShowAndSaveLog(ex); } } public void btnClose_Click(object sender, System.EventArgs e) { try { SerialPort1.Close(); // 关闭串口 // 将串口的状态显示出来,同时控制按钮的可用状态 if (SerialPort1.IsOpen == false) { lblStatus.BackColor = Color.Red; txtGetHex.Text = ""; txtGetString.Text = ""; } btnOpen.Enabled = true; } catch (Exception ex) { UnhandledExceptionManager.ShowAndSaveLog(ex); } } public void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { // 使用窗体的Invoke方法,让Sp_Receiving方法在窗体的主线程执行,要不然因为当前事件异步执行而无法正常将结果赋值到界面控件中 this.SmForm.Invoke(new EventHandler(Sp_Receiving)); // 调用接收数据函数 } // 接收数据 private void Sp_Receiving(object sender, EventArgs e) { try { // 如果读取到了数据 if (SerialPort1.BytesToRead > 0) { System.Threading.Thread.Sleep(100); // 添加的延时,给数据传递一点发送时间,如果不加此句,有可能会读不到数据 // 读取数据 byte[] ReceivedData; ReceivedData = new byte[SerialPort1.BytesToRead - 1 + 1]; SerialPort1.Read(ReceivedData, 0, ReceivedData.Length); // 清空缓存 SerialPort1.DiscardInBuffer(); // 将读取到的数据转换成字符串 string strR = Crypt.BytesToHexString(ReceivedData); // 将结果显示到界面 txtGetHex.Text = strR; txtGetString.Text = Encoding.ASCII.GetString(ReceivedData); } } catch (Exception ex) { UnhandledExceptionManager.ShowAndSaveLog(ex); } } /// <summary> ///如果当前选择了相应的串口及相关参数,如果设置好了则将相应的参数赋值给SerialPort1对象 ///</summary> ///<returns></returns> private bool Serial_PortOpen() // 设置串口参数 { if (cmbPorts.Text.Length == 0) { MessageBox.Show("请先选择好相应的串口后,再执行此操作!", "提示"); return false; } if (cmbStopBits.Text.Length == 0) { MessageBox.Show("请先选择好相应的停止位后,再执行此操作!", "提示"); return false; } if (cmbBaudRate.Text.Length == 0) { MessageBox.Show("请先选择好相应的波特率后,再执行此操作!", "提示"); return false; } if (cmbDataBits.Text.Length == 0) { MessageBox.Show("请先选择好相应的数据位后,再执行此操作!", "提示"); return false; } if (cmbParity.Text.Length == 0) { MessageBox.Show("请先选择好相应的校验位后,再执行此操作!", "提示"); return false; } SerialPort1.BaudRate = System.Convert.ToInt32(cmbBaudRate.Text); // 波特率 SerialPort1.PortName = cmbPorts.Text; // 串口名称 SerialPort1.DataBits = System.Convert.ToInt32(cmbDataBits.Text); // 数据位 SerialPort1.ReadBufferSize = 4096; // 读取缓存大小 // 设置校验位 switch (cmbParity.Text) { case "E": { SerialPort1.Parity = Parity.Even; break; } case "M": { SerialPort1.Parity = Parity.Mark; break; } case "N": { SerialPort1.Parity = Parity.None; break; } case "O": { SerialPort1.Parity = Parity.Odd; break; } case "S": { SerialPort1.Parity = Parity.Space; break; } } // 设置停止位 switch (cmbStopBits.Text) { case "1": { SerialPort1.StopBits = System.IO.Ports.StopBits.One; break; } case "2": { SerialPort1.StopBits = System.IO.Ports.StopBits.Two; break; } } return true; } } } |
最后执行窗体看看最终效果。如果此时我们电脑上有串口连接相关的硬件的话,就可以看到相应的清单了,我们就可以根据相应的协议传递相应的命令来获得相应的数据返回。