R中serial::read.serialConnection()返回空值问题求助
R serial包read.serialConnection读取ESP8266串口返回空值的问题及解决方案
问题背景
- 长期使用
serial::read.serialConnection()读取USB连接的ESP8266串口输出,2024年6月26日起在两台Windows 11设备上均返回空值 - Arduino软件、Python脚本读取同一串口均正常,排除硬件及串口本身故障
- 重装R及serial包后问题仍存在
serial::nBytesInQueue()显示缓冲区数据正常增长,但直接执行tcltk::.Tcl("gets ${sdev_COM7}")返回空值
原运行代码:
library(serial) con <- serialConnection(port = "COM7" ,mode = "115200,n,8,1" ,newline = 1 ,translation = "crlf" ) open(con) read.serialConnection(con, n = 0)
临时修复(需修改包内函数)
查看read.serialConnection源码,将第26行的:
comStr <- paste("gets ${sdev_", con$var, "}", sep = "")
替换为:
comStr <- paste("read ${sdev_", con$var, "}", sep = "")
修改后函数可恢复正常,但该操作需要修改包内部代码,不适合低R经验用户。
无需修改包函数的替代解决方案
方案1:指定读取字节数并自行处理换行
放弃n=0(默认读取到换行符)的调用方式,指定具体读取字节数,再手动分割行数据:
library(serial) con <- serialConnection(port = "COM7" ,mode = "115200,n,8,1" ,translation = "crlf" ) open(con) # 循环读取并处理行数据 buffer <- "" while(TRUE) { # 每次读取64字节 chunk <- read.serialConnection(con, n = 64) if(nchar(chunk) > 0) { buffer <- paste0(buffer, chunk) # 按CRLF分割行 lines <- strsplit(buffer, "\r\n")[[1]] if(length(lines) > 1) { # 输出完整行,保留未完成的部分到缓冲区 for(line in lines[-length(lines)]) { print(line) } buffer <- lines[length(lines)] } } Sys.sleep(0.01) }
方案2:自定义读取函数调用Tcl的read命令
封装一个替代读取函数,直接调用Tcl的read命令而非原函数的gets命令:
library(serial) library(tcltk) read_serial_fix <- function(con, n = 0) { if(n == 0) { # 读取缓冲区所有可用数据 com_str <- paste("read ${sdev_", con$var, "}", sep = "") } else { # 读取指定字节数 com_str <- paste("read ${sdev_", con$var, "}", n, sep = " ") } result <- .Tcl(com_str) # 按原连接配置转换换行符 if(con$translation == "crlf") { result <- gsub("\r\n", "\n", result) } return(result) } # 使用示例 con <- serialConnection(port = "COM7" ,mode = "115200,n,8,1" ,translation = "crlf" ) open(con) # 读取所有可用数据 read_serial_fix(con)
方案3:切换至其他串口包
改用uart包(底层实现不依赖Tcl/Tk),避免原serial包的Tcl命令兼容问题:
install.packages("uart") library(uart) # 打开串口 con <- uart_open("COM7", baudrate = 115200, parity = "none", databits = 8, stopbits = 1) # 读取所有可用数据 data <- uart_read(con, n = 0) print(data) # 关闭连接 uart_close(con)
问题根源推测
原函数使用Tcl的gets命令读取串口,该命令会等待换行符才返回数据。可能由于Tcl版本更新、ESP8266输出的换行符格式细微变化,导致gets无法识别换行符,一直处于等待状态而返回空值;而Tcl的read命令会直接读取缓冲区所有可用数据,不受换行符限制,因此能正常返回结果。
内容的提问来源于stack exchange,提问作者Gabriel Silva Pires
相关产品推荐
相关产品推荐

