You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中调用ORSSerialPort.send无法连接串口向Arduino发送数据

问题修复方案

代码核心问题

  • 未给ORSSerialPort设置delegate:你虽然声明了遵守ORSSerialPortDelegate协议,但没有给串口实例赋值delegate,ORSSerial的部分底层通信逻辑依赖delegate配置
  • 端口打开状态判断逻辑错误:if ((serialPort?.isOpen) != nil)仅能判断串口实例存在,无法确认端口真的打开,实际只要serialPort不为空,这个判断永远为真
  • 实例生命周期管理错误:SwiftUI视图的普通存储属性会随着视图重绘被反复销毁重建,你的myPort实例刚初始化打开端口,可能立刻触发deinit关闭端口,自然无法正常发送数据
  • 发送时机不符合Arduino特性:绝大多数Arduino开发板在串口连接建立时会自动重启,重启耗时约1-2秒,刚打开端口就发数据,Arduino还没完成启动,根本收不到指令

修复后完整代码

import SwiftUI 
import ORSSerial

// 继承ObservableObject让SwiftUI可以稳定管理实例生命周期
class MyPort: NSObject, ORSSerialPortDelegate, ObservableObject {
    var serialPort: ORSSerialPort?
    let myData = "2".data(using: .utf8)

    override init(){
        super.init()
        // 初始化串口
        guard let port = ORSSerialPort(path: "/dev/cu.usbmodem14101") else {
            print("Error: 获取串口失败,请检查设备路径是否正确")
            return
        }
        serialPort = port
        // 必须设置delegate
        serialPort?.delegate = self
        serialPort?.baudRate = 9600
        serialPort?.numberOfDataBits = 8
        serialPort?.numberOfStopBits = 1
        serialPort?.parity = .none
        serialPort?.usesRTSCTSFlowControl = false
        print("正在打开串口...")
        serialPort?.open()
    }
    
    // 监听串口打开成功的回调,在回调中处理发送逻辑
    func serialPortWasOpened(_ serialPort: ORSSerialPort) {
        print("串口已打开,等待Arduino重启完成后发送数据...")
        // 延迟1.5秒发送,等待Arduino重启完成
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
            guard let self = self, let data = self.myData else { return }
            self.serialPort?.send(data)
            print("已发送数据: \(String(describing: data))")
        }
    }
    
    func serialPortWasRemovedFromSystem(_ serialPort: ORSSerialPort) {
        print("Error: 串口被拔出")
        self.serialPort = nil
    }
    
    // 新增错误回调方便排查问题
    func serialPort(_ serialPort: ORSSerialPort, didEncounterError error: Error) {
        print("串口出错: \(error.localizedDescription)")
    }

    deinit {
        serialPort?.close()
        print("串口已关闭")
    }
}

struct ContentView: View {
    // 用@StateObject修饰,保证实例生命周期和视图绑定,不会被意外销毁
    @StateObject var sendArduino = MyPort()
    var body: some View {
        VStack(spacing: 20){
            Text("串口通信测试")
            // 新增手动发送按钮方便调试
            Button("手动发送指令") {
                guard let data = sendArduino.myData, let port = sendArduino.serialPort, port.isOpen else {
                    print("串口未打开,发送失败")
                    return
                }
                port.send(data)
                print("手动发送成功")
            }
        }
        .frame(width: 400, height: 400)
    }
}

调试提示

  • 如果仍运行失败,先确认串口路径是否正确,路径会随USB口插入位置变化,可以在终端执行ls /dev/cu.usbmodem*查看当前设备路径
  • 确认Arduino代码的波特率、校验位、停止位参数和Swift代码设置完全一致
  • 可以先打开Arduino IDE的串口监视器发送2测试硬件逻辑正常后,再运行SwiftUI代码测试

内容的提问来源于stack exchange,提问作者fredlock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 00:12:03