我在Go写了一个简短的程序,通过串口与传感器通信:
package main
import (
"fmt"
"github.com/tarm/goserial"
"time"
)
func main() {
c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600}
s, err := serial.OpenPort(c)
if err != nil {
fmt.Println(err)
}
_, err = s.Write([]byte("\x16\x02N0C0 G A\x03\x0d\x0a"))
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second/2)
buf := make([]byte, 40)
n, err := s.Read(buf)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(buf[:n]))
s.Close()
}
它工作正常,但在写入端口后我必须等待大约半秒才能开始读取它。我想使用while循环而不是time.Sleep
来读取所有传入的数据。我的尝试不起作用:
buf := make([]byte, 40)
n := 0
for {
n, _ := s.Read(buf)
if n > 0 {
break
}
}
fmt.Println(string(buf[:n]))
我想在每次循环传递后都会覆盖buf
。有什么建议吗?
答案 0 :(得分:10)
你的问题是Read()
只要有数据就会返回 - 它不会等待所有数据。有关详细信息,请参阅io.Reader specification
您要做的是阅读,直到您达到某个分隔符。我不确切地知道您尝试使用哪种格式,但看起来\x0a
可能是结束分隔符。
在这种情况下,您可以使用bufio.Reader这样的
reader := bufio.NewReader(s)
reply, err := reader.ReadBytes('\x0a')
if err != nil {
panic(err)
}
fmt.Println(reply)
在第一个\x0a
之前读取数据。
答案 1 :(得分:1)
我猜每次循环传递后buf都会被覆盖。有什么建议吗?
是的,每次拨打buf
都会覆盖Read()
。
文件句柄的超时将是我采取的方法。
s, _ := os.OpenFile("/dev/ttyS0", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NONBLOCK, 0666)
t := syscall.Termios{
Iflag: syscall.IGNPAR,
Cflag: syscall.CS8 | syscall.CREAD | syscall.CLOCAL | syscall.B115200,
Cc: [32]uint8{syscall.VMIN: 0, syscall.VTIME: uint8(20)}, //2.0s timeout
Ispeed: syscall.B115200,
Ospeed: syscall.B115200,
}
// syscall
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(s.Fd()),
uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&t)),
0, 0, 0)
// Send message
n, _ := s.Write([]byte("Test message"))
// Receive reply
for {
buf := make([]byte, 128)
n, err = s.Read(buf)
if err != nil { // err will equal io.EOF
break
}
fmt.Printf("%v\n", string(buf))
}
另请注意,如果没有更多数据读取且没有错误,os.File.Read()将返回错误io.EOF
,
as you can see here.