使用go-serial读取Arduino串口时Read调用挂起的问题排查
我来帮你排查并解决这个Go客户端Read调用挂起的问题,核心原因和调整细节如下:
1. 最关键的问题:波特率不匹配
你的Arduino固件里明确设置了Serial.begin(9600),但Go客户端代码里把波特率写成了19200!这直接导致两端通信速率完全不一致:Arduino无法正确解析你发送的read\n指令,自然不会返回任何数据,最终Read()调用会一直阻塞等待。
解决方法:把Go代码里的BaudRate参数改成9600,和Arduino的配置保持一致。
2. MinimumReadSize参数的潜在影响
go-serial库的MinimumReadSize指定了每次Read()调用至少要读取到多少字节才会返回。你的Arduino返回的内容是state + "\r\n"(比如off\r\n共5字节),虽然设置4理论上能覆盖返回长度,但如果通信有延迟或者返回内容有变化,可能会导致不必要的阻塞。建议把这个值设为1,让Read()有数据就返回,和Python代码的行为对齐,方便自己控制读取逻辑。
3. 模拟Python的逐字节读取逻辑(可选优化)
Python代码是逐字节读取直到遇到\r,你可以在Go里实现类似逻辑,避免因返回内容长度不确定导致的阻塞。
修改后的完整Go代码
package main import ( "fmt" "github.com/jacobsa/go-serial/serial" ) func check(err error) { if err != nil { panic(err.Error()) } } func main() { options := serial.OpenOptions{ PortName: "/dev/ttyACM0", BaudRate: 9600, // 修正为和Arduino一致的波特率 DataBits: 8, StopBits: 1, MinimumReadSize: 1, // 设为1,有数据就返回 } port, err := serial.Open(options) check(err) defer port.Close() // 记得退出前关闭串口 _, err = port.Write([]byte("read\n")) check(err) fmt.Println("Command sent successfully") // 模拟Python的逐字节读取逻辑,直到收到结束符\r var resp []byte buf := make([]byte, 1) for { n, err := port.Read(buf) check(err) if n > 0 { resp = append(resp, buf[0]) if buf[0] == '\r' { break } } } fmt.Println("Received response:", string(resp)) }
补充说明:为什么socat环境下能正常工作?
这是因为socat作为串口转发工具,不会严格校验波特率参数,或者你在测试socat时恰好设置了正确的波特率,所以通信能正常进行。但直接连接Arduino时,波特率不匹配的问题就会暴露出来。
内容的提问来源于stack exchange,提问作者Mikhail
相关产品推荐
相关产品推荐

