2013-07-11 52 views
6

我已經寫在圍棋一個簡短的程序通過串口與傳感器進行通信:從串口讀取與while循環

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每一個循環後傳被覆蓋。有什麼建議麼?

回答

8

你的問題是,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

謝謝您的建議。到目前爲止,它工作正常,但我仍然必須使用'time.Sleep',否則我會遇到'恐慌:EOF',因爲讀取時緩衝區是空的。 (順便說一句:最後的分隔符是\ x03',之後是兩個十六進制字節的校驗和。) – laserbrain

+0

奇怪 - 我不會認爲串行設備應該給EOF,它絕對不應該只是因爲緩衝區是空的。我能想到的唯一可能就是丟棄DTR/DSR。確保您使用的電纜僅連接了引腳2和引腳3(Rx和Tx),將所有其他握手線路斷開。您可能必須將DTR循環回設備上的DSR,但不必在PC上。 –

+0

您可能需要檢查並查看您使用的軟件包是否具有阻止的Read調用,或者可能是阻塞的「WaitForData」調用。 「沒有數據」和「永遠不會有更多的數據」(後者是EOF表示的)是有區別的,所以我很困惑他們爲什麼給你EOF - 他們不應該這樣做。在任何情況下,如果實施,阻止呼叫可能會做你正在尋找的東西。 – joshlf

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.