我正在与Golang建立串行通讯。我为此使用了https://github.com/jacobsa/go-serial库。 Golang代码是主设置。因此,它必须写入串行端口并收听回复。当一切都按预期方式工作时,这非常有用。因此,成功写入串行端口,并成功检索到答复。
但是,当回复错误1次,或者从属服务器没有响应时,Golang io.Reader无法恢复自身。然后,每条消息都是错误的,因为它会丢失一些字节。我已经使用了示波器来尝试找出问题所在,但是来自主服务器的请求和来自从服务器的答复都是正确的。
我正在使用基于Arduino的PCB的RS485通讯。交流没有错,只有Golang代码。
通信结构如下:
STX |目的地|来源字节数数据CRC16
STX始终为0x02,因此指示消息的开始。目的和源是32位,字节数是16位,数据取决于字节数,CRC是16位。就像我说的那样,该数据已成功传输。
我已经在Golang中制作了一些软件,该软件可以打开端口,并使用“ for”循环写入数据并等待新数据。这在下面添加。我仅在以下示例中使用了“ Peek”功能。但是我还尝试了ReadByte和UnreadByte,甚至ReadByte,并且ReadMessage函数不会等待0x02。而且我已经在没有bufio阅读器的情况下进行了尝试,但是没有任何结果。
我添加了代码以重现它,并且可能注意到了我的错误:
package main
import (
"bufio"
"encoding/binary"
"errors"
"fmt"
"log"
"time"
"github.com/jacobsa/go-serial/serial"
)
func main() {
options := serial.OpenOptions{
PortName: "/dev/ttyAMA0",
BaudRate: 57600,
DataBits: 8,
StopBits: 1,
ParityMode: 0,
MinimumReadSize: 1,
}
port, err := serial.Open(options)
if err != nil {
log.Fatalf("serial.Open: %v", err)
}
defer port.Close()
writeBytes := []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x92}
b := bufio.NewReader(port)
for {
_, err = port.Write(writeBytes)
if err != nil {
log.Fatalf("port.Write: %v", err)
}
recievedSTX := make(chan bool, 1)
go func(buf *bufio.Reader) {
gotSTX := false
for {
n, err := b.Peek(1)
if err != nil {
// Got error while peeking
break
}
// Check if peek output is STX
// This goes wrong very often when communication didn't go as expected once
if n[0] == 0x02 {
gotSTX = true
break
}
}
recievedSTX <- gotSTX
}(b)
select {
case stx := <-recievedSTX:
if stx == true {
// Function to read whole message
message, err := ReadMessage(b)
if err != nil {
// Error while reading whole message
// When 0x02 is read before, and communication didn't go as expected once, this is always going wrong
fmt.Println(err)
} else {
// Message Successful!
fmt.Println(message)
}
} else {
// STX not found, so just sleep like the timeout did
time.Sleep(time.Duration(500) * time.Millisecond)
}
case <-time.After(time.Duration(500) * time.Millisecond):
// Timeout while reading, so stopping. 500Ms for testing purposes
fmt.Println("TIMEOUT")
}
}
}
func ReadMessage(b *bufio.Reader) ([]byte, error) {
var message []byte
var getNumberOfBytes int
var countOfBytes int
messageComplete := make(chan error, 1)
go func() {
STX := make([]byte, 1)
getNumberOfBytes = len(STX)
countOfBytes = 0
for countOfBytes < getNumberOfBytes {
n, err := b.ReadByte()
if err != nil {
messageComplete <- err
}
if n == 0x02 {
STX[countOfBytes] = n
message = append(message, n)
break
} else {
fmt.Println("STX BYTE", n)
messageComplete <- errors.New("First byte is not a STX byte (0x02)")
}
}
Destination := make([]byte, 4)
getNumberOfBytes = len(Destination)
countOfBytes = 0
for countOfBytes < getNumberOfBytes {
n, err := b.ReadByte()
if err != nil {
messageComplete <- err
}
Destination[countOfBytes] = n
message = append(message, n)
countOfBytes++
}
Source := make([]byte, 4)
getNumberOfBytes = len(Source)
countOfBytes = 0
for countOfBytes < getNumberOfBytes {
n, err := b.ReadByte()
if err != nil {
messageComplete <- err
}
Source[countOfBytes] = n
message = append(message, n)
countOfBytes++
}
Length := make([]byte, 2)
getNumberOfBytes = len(Length)
countOfBytes = 0
for countOfBytes < getNumberOfBytes {
n, err := b.ReadByte()
if err != nil {
messageComplete <- err
}
Length[countOfBytes] = n
message = append(message, n)
countOfBytes++
}
NumberOfBytes := binary.LittleEndian.Uint16(Length)
getNumberOfBytes = int(NumberOfBytes)
countOfBytes = 0
for countOfBytes < getNumberOfBytes {
n, err := b.ReadByte()
if err != nil {
messageComplete <- err
}
message = append(message, n)
countOfBytes++
}
CRC := make([]byte, 2)
getNumberOfBytes = 2
countOfBytes = 0
for countOfBytes < getNumberOfBytes {
n, err := b.ReadByte()
if err != nil {
messageComplete <- err
}
CRC[countOfBytes] = n
message = append(message, n)
countOfBytes++
}
messageComplete <- nil
}()
select {
case mComplete := <-messageComplete:
if mComplete != nil {
return message, mComplete
}
return message, nil
case <-time.After(time.Duration(200) * time.Millisecond):
return message, errors.New("TIMEOUT: Could not read any more bytes")
}
}
预期结果是,每当一条消息发送到以0x02开头的主服务器时,它将读取整个消息。每当该消息完成时,它都必须打印整个消息。或打印错误。如果写后未收到任何字节,则必须在200ms之后打印“ TIMEOUT”。
实际结果是,一开始,当从站插入主站时,我会收到从站的所有回复。但是,当我从最短的时间拔下Slave并重新插入时,我只会超时,因为Golang代码再也看不到0x02了。因此所有消息都将被完全忽略。
当我添加另一个未连接的从站ID时,也会发生同样的情况,因此它尝试与两个从站进行通信。 (首先是从站1,然后是从站2,然后又是从站1,依此类推),但与以前一样。
我已经尝试了所有已知的知识,甚至使用了另一台Master PC和另一个连接护罩,但是硬件签出了。示波器告诉我一切都很好。我真的没有主意,任何帮助将不胜感激。