Golang串口通信中的多线程处理

Golang串口通信中的多线程处理 我正在尝试通过Arduino使用多线程从串行端口读取输入。我有两个线程从串行端口读取数据,它们都在读取相同的内容(忽略它们的函数名称)。以下是代码:

for scanner.Scan() {
    log.Printf("%q\n", scanner.Text())
}
time.Sleep(time.Duration(1)*time.Second)

}

func readSecondLine(scanner *bufio.Scanner, port *serial.Port){
    time.Sleep(time.Duration(1)*time.Second)
    for scanner.Scan() {
        log.Printf("%q\n", scanner.Text())
    }


}

func main() {
    usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: 0}
    port, err := serial.OpenPort(usbRead)

    if err != nil {
        log.Fatal(err)
    }

    scanner := bufio.NewScanner(port)

    for true{
    go readFirstLine(scanner, port)
    go readSecondLine(scanner, port)
    time.Sleep(time.Duration(2)*time.Second)

    }
}

我期望的输出应该是这样的:

{"temperature":[26,26],"humidity":[54.2,54.2],"sensor":"DHT22"}
{"temperature":[23.46041,23.46041],"sensor":"LM35DZ"}
{"blink":["true","true"],"actuator":"arduinoLED"}
{"temperature":[26,26],"humidity":[54.2,54.2],"sensor":"DHT22"}
{"temperature":[23.46041,23.46041],"sensor":"LM35DZ"}
{"blink":["true","true"],"actuator":"arduinoLED"}

然而我在期望的输出之间得到了垃圾数据:

"{\"temperature\":[23.46041,23.46041,23.46041],\"sensor\":\"LM35DZ\"}"
"{\"blink\":[\"true\",\"true\",\"true\"],\"actuator\":\"arduinoLED\"}"
"mpeer\x00\x00re\"u:\x00\x00[]6\x00midhui\x00\x00[54\":.\x00\x00sen,\"s\x00\x00:or\"\"TH\x00"
{\"}\"\x00\x00ptemurrate\x003.4[26\x00\x00,\"s1]e\x00\x00\":\"orL\x00\x00Z\"}5D\r\x00\x00\x00"

我认为这些垃圾数据出现是因为我在Arduino没有输出任何内容时仍然在读取串行端口输入。有什么方法可以解决这个问题吗?谢谢。


更多关于Golang串口通信中的多线程处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我编写多线程应用程序来管理物联网设备和其他设备。有些设备发送数据较慢,但其他设备可以通过串行端口以1 Mb/s的速度发送数据,我必须同时管理它们。每个连接都有一个线程,没有丢失任何一个字节。你应该检查一下你的代码。

PCB印刷与组装

更多关于Golang串口通信中的多线程处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的问题确实是由于多个goroutine同时从同一个bufio.Scanner读取数据导致的。bufio.Scanner不是并发安全的,当多个goroutine同时调用Scan()方法时会发生数据竞争和读取错乱。

以下是修正后的代码:

package main

import (
    "bufio"
    "log"
    "time"

    "github.com/tarm/serial"
)

func readFromSerial(scanner *bufio.Scanner, name string) {
    for scanner.Scan() {
        data := scanner.Text()
        if data != "" {
            log.Printf("[%s] %q\n", name, data)
        }
    }
}

func main() {
    usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: time.Millisecond * 100}
    port, err := serial.OpenPort(usbRead)
    if err != nil {
        log.Fatal(err)
    }
    defer port.Close()

    scanner := bufio.NewScanner(port)

    // 只使用一个goroutine来读取串口数据
    go readFromSerial(scanner, "Reader")

    // 保持主程序运行
    select {}
}

如果你确实需要多个消费者处理相同的数据,可以使用通道模式:

package main

import (
    "bufio"
    "log"
    "time"

    "github.com/tarm/serial"
)

func serialReader(scanner *bufio.Scanner, dataChan chan string) {
    for scanner.Scan() {
        data := scanner.Text()
        if data != "" {
            dataChan <- data
        }
    }
    close(dataChan)
}

func dataProcessor(name string, dataChan chan string) {
    for data := range dataChan {
        log.Printf("[%s] %q\n", name, data)
    }
}

func main() {
    usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: time.Millisecond * 100}
    port, err := serial.OpenPort(usbRead)
    if err != nil {
        log.Fatal(err)
    }
    defer port.Close()

    scanner := bufio.NewScanner(port)
    dataChan := make(chan string, 100)

    // 一个读取器,多个处理器
    go serialReader(scanner, dataChan)
    go dataProcessor("Processor1", dataChan)
    go dataProcessor("Processor2", dataChan)

    select {}
}

关键修改点:

  1. 移除了多个goroutine同时读取同一个scanner的设计
  2. 设置了合理的ReadTimeout(100毫秒)
  3. 使用通道来安全地在goroutine间传递数据
  4. 添加了空数据检查

这样应该能消除垃圾数据并得到你期望的输出格式。

回到顶部