VB.NET串口通信例子--我的回忆录

2023-05-16

这是我3年前的一个例子,最近翻出来回忆一下。

串口是计算机上一种非常通用设备通信的协议。大多数计算机包含两个基于RS232的串口,现在配电脑好像只有一个。串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS-232口。同时,串口通信协议也可以用于获取远程采集设备的数据。串口通信在工控领域用途很广。

串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。

典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配:
a,波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。
c,停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位位1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。

串口通信还有一个参数是单工、半双工和双工。

如果在通信过程的任意时刻,信息只能由一方A传到另一方B,则称为单工。

如果在任意时刻,信息既可由A传到B,又能由B传A,但只能由一个方向上的传输存在,称为半双工传输。

如果在任意时刻,线路上存在A到B和B到A的双向信号传输,则称为全双工。

电话线就是二线全双工信道。 由于采用了回波抵消技术,双向的传输信号不致混淆不清。双工信道有时也将收、发信道分开,采用分离的线路或频带传输相反方向的信号,如回线传输。

在调试时可以用串口助手和windows的超级终端,不要带电插拔串口,容易烧毁。

在VB.NET中提供了IO.Ports类,是我们的编程变得很简单,下面是我的例子:

Form1.vb

Imports System.IO.Ports

Public Class Form1

    Dim WithEvents RS232 As SerialPort
    Delegate Sub SetTextCallback(ByVal InputString As String)       '声明一个代理

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each sp As String In SerialPort.GetPortNames()
            cmbCom.Items.Add(sp)
        Next
        cmbCom.Sorted = True
        cmbCom.SelectedIndex = 0
    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        Dim mBaudRate As Integer
        Dim mParity As IO.Ports.Parity
        Dim mDataBit As Integer
        Dim mStopBit As IO.Ports.StopBits
        Dim mPortName As String

        mPortName = cmbCom.SelectedItem.ToString
        mBaudRate = 9600
        mParity = Parity.None
        mDataBit = 8
        mStopBit = StopBits.One

        RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopBit)

        If Not RS232.IsOpen Then
            RS232.Open()
            btnSend.Enabled = True
            RS232.ReceivedBytesThreshold = 1        '设置引发事件的门限值
        Else
            MsgBox("通讯端口打开错误!", MsgBoxStyle.Critical)
        End If
    End Sub


    Private Sub RS232_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles RS232.DataReceived
        Dim InByte() As Byte, ReadCount As Integer, strRead As String
        If RS232.BytesToRead <= 0 Then Exit Sub
        ReDim InByte(RS232.BytesToRead - 1)
        ReadCount = RS232.Read(InByte, 0, RS232.BytesToRead)
        strRead = ""
        If ReadCount = 0 Then
            Exit Sub
        Else
            For Each bData As Byte In InByte
                strRead += bData.ToString & vbCrLf     '若有数据则加到接收文本框
                DisplayText(strRead)
            Next
        End If


    End Sub
    '*************************************************
    '代理子程序
    '处理上述通信端口的接收事件
    '由于欲将数据显示到接收文本框中,因此必须检查
    '是否由另外得Thread所调用的,若是,则必须先
    '建立代理对象
    'Invoke用于在拥有控件基础窗口控制代码的线程上
    '运行代理
    '*************************************************
    Private Sub DisplayText(ByVal comData As String)
        '如果调用txtReceive的另外的线程,返回true
        If Me.txtReceive.InvokeRequired Then
            '利用代理类型建立对象,并指定代理的函数
            Dim d As New SetTextCallback(AddressOf DisplayText)
            Me.Invoke(d, New Object() {comData})    '以指定的自变量列表调用函数
        Else '相同的线程
            'showstring(comData)     '将收到的数据填入接收文本框中
            Me.txtReceive.Text += comData
        End If
    End Sub

    Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
        If RS232 Is Nothing OrElse Not RS232.IsOpen Then   '尚未打开
            MsgBox("通讯端口尚未打开", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel)
        Else
            RS232.Close()
            btnStart.Enabled = False
            btnClose.Enabled = False
            RS232 = Nothing
        End If
    End Sub

    Private Sub btnEnd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnd.Click
        If Not RS232 Is Nothing Then
            If RS232.IsOpen Then RS232.Close()
        End If
        End
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Dim bDataOut(0) As Byte
        Try
            bDataOut(0) = CType(Me.txtSend.Text, Byte)        '将类型转换为字节
            RS232.Write(bDataOut, 0, 1)
        Catch ex As Exception
            MessageBox.Show("输入数值错误:" + ex.ToString, "错误通知:", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Private Sub cmbCom_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCom.KeyPress
        e.KeyChar = ChrW(0)             '禁止用户在其中输入任何文字
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Hide()
        Form2.Show()
    End Sub
End Class
Form2.vb

'**************************************************************
'时间:2008-11-08
'作者:lincyang
'实际应用中,串行通信的数据可能一次发送大量的数据,
'发送之前就必须将数据先编码,
'将其编成我们需要的字节数组数据,
'才能将这些数据以字节的方式发送出去
'目前操作系统使用的字符数据是Unicode:所有的字符均使用
'两个字节来表示一个字符
'**************************************************************

Imports System.IO.Ports
Imports System.Text
Public Class Form2
    Dim RS232 As SerialPort
    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each sp As String In SerialPort.GetPortNames()
            cmbCom.Items.Add(sp)
        Next
        cmbCom.Sorted = True
        cmbCom.SelectedIndex = 0
    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        Dim mBaudRate As Integer
        Dim mParity As IO.Ports.Parity
        Dim mDataBit As Integer
        Dim mStopBit As IO.Ports.StopBits
        Dim mPortName As String

        mPortName = cmbCom.SelectedItem.ToString
        mBaudRate = 9600
        mParity = Parity.None
        mDataBit = 8
        mStopBit = StopBits.One

        RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopBit)

        If Not RS232.IsOpen Then
            RS232.Open()
            btnSend.Enabled = True
            Timer1.Interval = 100
            Timer1.Enabled = True
        Else
            MsgBox("通讯端口打开错误!", MsgBoxStyle.Critical)
        End If
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim InByte() As Byte, ReadCount As Integer
        If RS232.BytesToRead <= 0 Then Exit Sub
        ReDim InByte(RS232.BytesToRead - 1)
        ReadCount = RS232.Read(InByte, 0, RS232.BytesToRead)

        If ReadCount = 0 Then
            Exit Sub
        Else
            For Each bData As Byte In InByte
                Me.txtReceive.Text += bData.ToString & vbCrLf     '若有数据则加到接收文本框

            Next
        End If
    End Sub

    Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
        If RS232 Is Nothing OrElse Not RS232.IsOpen Then   '尚未打开
            MsgBox("通讯端口尚未打开", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel)
        Else
            RS232.Close()
            btnStart.Enabled = False
            btnClose.Enabled = False
            Timer1.Enabled = False
            RS232 = Nothing
        End If
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Dim bDataOut() As Byte, Buf As String
        Dim iSentCount As Integer
        Dim Encode1 As Encoding = Encoding.ASCII         '声明编码对象,使用ASCII

        Try
            Buf = txtSend.Text.Trim()
            bDataOut = Encode1.GetBytes(Buf)      '将字符串转换为字节数组
            iSentCount = bDataOut.GetLength(0)     '发送总字节数
            '显示出总字节数
            lblSentCount.Text = "总传输量:" & iSentCount.ToString & "字节"
            RS232.Write(bDataOut, 0, iSentCount)
        Catch ex As Exception
            MessageBox.Show("输入数值错误:" + ex.ToString, "错误通知", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Private Sub btnEnd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnd.Click
        If Not RS232 Is Nothing Then
            If RS232.IsOpen Then RS232.Close()
        End If
        End
    End Sub

    Private Sub cmbCom_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCom.KeyPress
        e.KeyChar = ChrW(0)             '禁止用户在其中输入任何文字
    End Sub
End Class

开发环境是VB2008,源码下载 猛击这里!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VB.NET串口通信例子--我的回忆录 的相关文章

  • 查找文本中所有关键字的有效算法

    我有很多字符串 其中包含许多不同拼写的文本 我通过搜索关键字来标记这些字符串 如果找到关键字 我将使用该关键字的关联文本 假设搜索字符串可以包含文本 schw schwa 和 施瓦茨 我有三个关键字 全部解析为文本 schwarz 现在我正
  • .NET 中有什么方法可以以编程方式侦听 HTTP 流量吗?

    我正在使用浏览器自动化来测试网站 但我需要验证来自浏览器的 HTTP 请求 即图像 外部脚本 XmlHttpRequest 对象 有没有一种方法可以以编程方式实例化代理以供浏览器使用以查看其发送的内容 我已经在使用 Fiddler 来监视流
  • 急切操作和短路操作之间的区别? (| 与 || 以及 & 与 &&)

    我 仍在 学习 C 我认为我理解两者之间的区别 也 然而 在阅读了另一篇指南后 很明显我不明白 我写了一个小真值表 正如我所想 它们返回相同的结果 从我读到的内容来看 使用双符号听起来是一种更好的解决方案 但我对其中的差异有点困惑 想知道是
  • 如何读取 Excel XML (C#)

    我想知道是否有一种简单的方法来读取Excel 2010 XML 该 XML 的结构与我以前阅读的不同 特别是 ss index 属性 ss Index 7 使事情变得更加复杂 EDIT 为了更好地解释 我有一个带有 XML 扩展名的文件 可
  • 检查有效的 IMEI

    有人知道如何检查有效的 IMEI 吗 我找到了一个可以检查此页面的功能 http www dotnetfunda com articles article597 imeivalidator in vbnet aspx http www do
  • 每 4 个循环新表行

    如何在 Razor 视图中每 4 个循环创建一个新表行 这是为 4 之前的每个数字创建一个新行 然后停止创建新行 int i 0 foreach var item in ViewBag ProgramIdList if i 4 0 tr t
  • 在生产服务器上安装 VS.NET 是否安全且可以接受? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通常 我们在生产服务器上安装 VS NET 以便在必要时轻松解决我们产品的问题 这是好主意还是坏主意 调试和开发应该在 安全 环境中完成 这不是
  • VS 2010、NUNit 和“当前不会命中断点。尚未为此文档加载任何符号”

    使用 Windows 7 32 位 VS 2010 NET 4 DLL NUnit 2 5 5 对应用程序进行单元测试 我目前收到以下错误 看了很多帖子并尝试了以下方法 重启机器 重启VS 删除 bin obj 并重新加载 清理 重建 但我
  • 如何获取我的应用程序已创建的应用程序域的列表?

    我有一个服务应用程序 它在长时间运行的任务的使用过程中创建AppDomain 我一直通过将它们存储在具有唯一 ID 的哈希表中来跟踪它们 任务完成后 服务应用程序会卸载分配给该任务的 AppDomain 然后将其从 appdomain 哈希
  • Silverlight本地存储

    您可能知道 Silverlight 支持本地存储 我们正在考虑创建可在离线模式下工作的 Sl 应用程序 该应用程序可能需要在客户端缓存相当多的数据 显而易见的解决方案 由于性能问题 使用具有某种基于 XMl 结构的本地存储将无法像我们的 P
  • COM 互操作注册

    我有一个正在暴露的 NET 程序集COM http en wikipedia org wiki Component Object Model 该程序集有两个公共接口和一个公共类 当我构建程序集时 我收到此警告 AssemblyName dl
  • 去除字符串的最佳方法是什么?

    我需要具有最佳性能的想法来删除 过滤字符串 I have string Input view 512 3 159 删除 view 和 的最佳性能方法是什么 和引号 我可以做这个 Input Input Replace view Replac
  • 如何查找局域网中所有主机上正在运行的程序的所有实例?

    出于实际目的 SqlDataSourceEnumerator 的作用是查找在 LAN 上的各个 PC 上运行的 SQL Server 的所有实例 是否有等效的方法可以查找任意应用程序的运行实例 编辑 好的 所以这只有效 因为这些应用程序有预
  • C# .Net Serial DataReceived 事件响应对于高速数据来说太慢

    我已经设置了一个 SerialDataReceivedEventHandler 并在 VS2008 Express 中使用基于表单的程序 我的串口设置如下 115200 8N1 Dtr 和 Rts 已启用 接收字节阈值 1 我有一个通过蓝牙
  • 为什么我的 COM 对象不显示组件服务中的方法?

    我正在尝试创建一个 COM 对象并将其注册到 COM 下 一切似乎都很顺利 但是当我查看组件服务并深入了解时 控制台根目录 组件服务 电脑 我的电脑 COM 应用程序 测试通讯 组件 TestCom Com MyCom 接口 MyCom 方
  • IL 的仿制药?

    是否可以在 IL 生成器中使用泛型 DynamicMethod method new DynamicMethod GetStuff typeof int new Type typeof object ILGenerator il metho
  • 分层架构中的异常处理

    我们正在分层设计中重构 当然还有重新设计 我们的服务 我们有服务操作层 BLL 网络抽象层 gt 处理网络代理 数据抽象层 但我们对我们的异常处理策略有点困惑 我们不想向外界透露太多 BLL 的信息 从其他层到bll就可以了 我们不想让 t
  • MySql 最后插入 ID,连接器 .net

    我正在使用 MySql Connector net 我需要获取最后一个查询生成的插入 id 现在 我假设返回值是MySqlHelper ExecuteNonQuery应该是最后一个插入id 但它只返回1 我正在使用的代码是 int inse
  • 如何将智能感知添加到我的应用程序中?

    我们的一款产品拥有一种专有的宏语言 通过我们的 Windows 软件进行编辑 我想添加智能感知 但我不知道如何去做 至少不完全重新发明轮子 是否有任何示例代码或第 3 方包至少可以让我开始 它不一定是免费的 该应用程序使用 NET 用 C
  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu

随机推荐

  • React生命周期及事件详解

    一 组件的详细说明和生命周期ComponentSpecs and Lifecycle 组件的详细说明 xff08 Component Specifications xff09 当通过调用 React createClass 来创建组件的时候
  • Eclipse代码提示功能失效

    Eclipse 代码提示功能失效问题解决 Windows gt preferences gt java gt Editor gt Code Assist中Auto Activetion中的Enable auto activetion选项要勾
  • VM-tools选项为灰色无法安装的问题

    安装虚拟机VMware时 xff0c 桌面上没有vmware tools的安装光盘 虚拟机 gt 重新安装vmware tools选项为灰色 xff0c 也无法选择 尝试了将CD DVD SATA 的使用ISO映像文件改为物理驱动器 自动检
  • 数据库学习 - like(模糊查询)

    模糊查询问题 比如查询姓张的同学 xff0c 查询张某某等这类型问题 xff0c 在 select语句中通过查询条件中加入运算符 like 来表示 xff1b 含有 like运算符的表达式 列名 not like 字符串 xff08 表示其
  • 蓝桥杯2022年第十三届省赛真题-X进制减法(超详细解析)

    转自作者弗莱 详细解析和分享经验 进制规定了数字在数位上逢几进一 X 进制是一种很神奇的进制 xff0c 因为其每一数位的进制并不固定 xff01 例如说某种 X 进制数 xff0c 最低数位为二进制 xff0c 第二数位为十进制 xff0
  • WearOS复杂数据的刷新

    表盘可以通过setDefaultSystemComplicationProvider int watchFaceComplicationId int systemProvider int type 来设置要显示的系统复杂数据 一 系统支持哪
  • VMware下使用Gparted对系统盘扩容

    第一步 xff0c 下载Gparted的iso镜像文件 xff0c 这里对应下载相应的32或者64位版本 第二步 xff0c 设置虚拟机 xff0c 将硬盘容量扩容为指定的容量 xff0c 保存 第三步 xff0c 设置虚拟机 xff0c
  • Android系统深度游

    项目原因 xff0c 让我们必须深入探索Android系统 xff0c 完成对之前的我们来说比较艰巨的任务 这样 xff0c 我们开启了Android深度游 Android这个系统 xff0c 应用层开发还是比较舒服的 xff0c Goog
  • IT痴汉的工作现状56-耳鸣

    自从这个项目启动 xff0c 与客户方的沟通就逐渐多了起来 xff0c 沟通的方式是语音会议 也不知从什么时候起 xff0c 每天的会议时间变得很长很长 尤其是定位复杂问题时 xff0c 一个会议就要4个小时 张伟是从项目开始买的耳机 xf
  • 我的2020---熬过去

    恰逢周末 xff0c 本人自认为过了一个美好的圣诞节之后 xff0c 在深圳图书馆开始思考我的第十一个年终总结了 提笔之前 xff0c 我翻看了去年的总结 xff0c 想到了我还有一套书没有读完 xff0c 那就是 大败局 2020结束还有
  • 我的2022-工程师文化的思考

    没有想到 xff0c 今年大环境的变化可谓是大开大合 xff0c 超出想象 各行各业都遭到强大的挑战 xff0c 是泯灭还是苟活 xff0c 亦或是再创辉煌 xff0c 时也命也 在此情况下的个人 xff0c 最好的选择是跟公司抱团取暖 x
  • 用户名 不在 sudoers文件中,此事将被报告。

    继续昨天的故事 话说昨天新建了一个帐号linc xff0c 今天在执行sudo时回显一个很吓人的信息 xff1a sudo password for linc linc 不在 sudoers 文件中 此事将被报告 这是要去哪儿报告呢 xff
  • Git冲突:commit your changes or stash them before you can merge.

    今天用git pull来更新代码 xff0c 遇到了下面的问题 xff1a error Your local changes to the following files would be overwritten by merge xxx
  • Android问题集锦之二十八:You need to use a Theme.AppCompat theme (or descendant) with this activity.

    错误描述为 xff1a java lang IllegalStateException You need to use a Theme AppCompat theme or descendant with this activity 起因
  • Docker实践6:Cannot connect to the Docker daemon.

    正在免费适用着Aliyun主机 xff0c 当然要用docker来部署我的服务器啦 但是今天碰到了题目的问题 xff0c 细节如下 xff1a span class hljs comment docker info span FATA sp
  • DFS与BFS总结

    总结 bfs多用于在一次选择中可以有多种情况的选择 而dfs是确定唯一性如唯一路径 xff0c 也就是深度 当问题是全盘式的搜索 xff0c 不在乎形式或者具体情况呈现还是详细过程的 xff0c 使用bfs 当问题是要求具体过程 xff0c
  • 一个简单的自定义通信协议(socket)

    转自 xff1a http vtrtbb javaeye com blog 849336 这是转自javaeye的一篇文章 xff0c 作者是vtrtbb 按照网络通信的传统 xff0c 我们都会自定义协议 xff0c 这有很多好处 xff
  • ImageView 设置图片

    android doc中是这样描述的 xff1a public void setImageResource int resId 这是其中的一个方法 xff0c 参数resld是这样 xff1a ImageView setImageResou
  • Android问题集锦之八:调用其他程序中的activity和Permission Denial: starting Intent 错误解决办法

    今天想调试多个task中栈的情况 xff0c 在测试程序中调用另一个程序的activity xff0c 代码片段如下 xff1a btnStartX 61 Button findViewById R id btnStartX btnStar
  • VB.NET串口通信例子--我的回忆录

    这是我3年前的一个例子 xff0c 最近翻出来回忆一下 串口是计算机上一种非常通用设备通信的协议 大多数计算机包含两个基于RS232的串口 xff0c 现在配电脑好像只有一个 串口同时也是仪器仪表设备通用的通信协议 xff1b 很多GPIB