使用go.bug.st/serial读取串口数据时,无新数据如何终止Read()?
串口无结束符数据流读取解决方案
问题背景
我正在使用github.com/go.bug.st/serial库读取串口输入,等待外部设备发送数据流。该设备完成测试后会一次性发送一批数据,但数据流无结束符,仅以停止发送表示传输完成,且数据行数不固定。
串口数据格式示例:
10.2,1 10,2 9.8,2 9.9,3
原代码使用bufio.Scanner持续扫描串口,但因无结束符导致循环无法退出,无法执行后续数据处理逻辑。考虑用定时器实现“2秒无新输入则终止读取”,希望找到Go语言的最优实现方式。
原简化代码(存在问题):
port := OpenPort() scanner := bufio.NewScanner(port) // 数据按行传输 scanner.Split(bufio.ScanLines) mydata := make([]string, 0) for scanner.Scan() { line := scanner.Text() // 此处需要添加逻辑:启动定时器,无新数据时停止扫描 mydata := append(mydata, line) // 错误:重复声明mydata } // 永远无法执行到这里,因为扫描循环不会终止 // 后续数据处理逻辑 graphFile := MakeGraph(mydata) err := graph.Render(chart.PNG, graphFile) if err != nil {panic(err)}
解决方案
在Go语言中,定时器+通道+goroutine是处理这类异步超时场景的惯用方案,能优雅实现“超时无数据则终止读取”的逻辑。核心思路是:
- 用goroutine单独负责串口扫描,将读取到的行数据发送到通道
- 主goroutine通过
select监听通道数据和定时器超时事件,每次收到数据就重置定时器,超时则终止读取
修正后的完整代码
port := OpenPort() defer port.Close() // 确保端口最终关闭 scanner := bufio.NewScanner(port) scanner.Split(bufio.ScanLines) mydata := make([]string, 0) lineChan := make(chan string, 10) // 带缓冲通道,适配数据突发传输 errChan := make(chan error, 1) // 启动goroutine负责扫描串口数据 go func() { defer close(lineChan) for scanner.Scan() { lineChan <- scanner.Text() } // 扫描结束或出错时,传递错误信息 if err := scanner.Err(); err != nil { errChan <- err } }() // 初始化定时器:2秒无数据则超时 timeout := time.NewTimer(2 * time.Second) defer timeout.Stop() for { select { case line, ok := <-lineChan: if !ok { // 通道关闭,说明扫描已结束 goto endRead } // 收到新数据,重置定时器 if !timeout.Stop() { <-timeout.C // 确保定时器的通道已排空 } timeout.Reset(2 * time.Second) mydata = append(mydata, line) case err := <-errChan: // 扫描出错,终止读取并处理错误 panic(err) case <-timeout.C: // 超时无新数据,终止读取 goto endRead } } endRead: // 执行后续数据处理逻辑 graphFile := MakeGraph(mydata) err := graph.Render(chart.PNG, graphFile) if err != nil { panic(err) }
关键逻辑说明
- goroutine拆分扫描任务:将串口扫描放在单独goroutine中,避免阻塞主逻辑,同时通过通道传递数据和错误。
- 定时器重置机制:每次收到新数据时,先停止旧定时器(若未触发则排空通道),再重置为2秒超时,确保超时判断的准确性。
- 通道关闭与超时退出:当串口扫描结束(通道关闭)或超时触发时,跳出循环进入数据处理阶段。
- 资源清理:使用
defer确保串口端口和定时器资源被正确释放。
内容的提问来源于stack exchange,提问作者Jadefox10200
相关产品推荐
相关产品推荐

