最近在做学校的课设,用qt做一个简易的无人机地面站,需要使用串口接收单片机发来的数据。我实现串口的读取是开启一个线程来不断读取串口,有并发安全的需求,所以对serial库进行了简易的封装。
导包
import (
"github.com/tarm/goserial"
"io"
"time"
)
创建一个串口连接器(封装了操作串口的相关变量)
//串口连接器
type SerialConnection struct {
S *io.ReadWriteCloser
Ch *chan []byte//开启线程用于往外发送数据的channel
StopCh *chan struct{}//用于管理线程的channel,关闭这个channel就关闭了串口的读取线程
}
连接到串口
连接到串口号为name,波特率为baud的串口,超时时间设定为100ms
超时时间的设定关乎到数据是否能成帧显示。连接串口成功后要对两个channel进行初始化,否则会出现空指针。这两个channel是控制线程的重要工具,同时也是极易出现错误的地方
//连接串口
func (sc *SerialConnection) ConnectToSerial(name string, baud int) (err error) {
//设置串口编号
c := &serial.Config{Name: name, Baud: baud, ReadTimeout: time.Millisecond * 100}
ch := make(chan []byte, 128)
c2 := make(chan struct{}, 10)
sc.Ch = &ch
//打开串口,初始化指针
s, err := serial.OpenPort(c)
if err != nil {
return err
}
sc.S = &s
sc.StopCh = &c2
return nil
}
读取串口内容
func (sc *SerialConnection) ReadSerial() {
var num int
for {
select {
case <-(*sc.StopCh): //关闭线程
return
default:
buffer := make([]byte, MAXRWLEN) //优化,如何在运行过程中清空数组从而不用重复分配内存
num, _ = (*sc.S).Read(buffer)
if num > 0 {
(*sc.Ch) <- buffer
//fmt.Println(string(buffer))
}
}
}
}
func (sc *SerialConnection) ReadSerialLoop() {
go func() {
sc.ReadSerial()
}()
}
接收信息
这个函数要开一个协程来跑
//监听串口信息,并打印到TextBrowser
func (c *MainWindow) ListenShow(s *serialController.SerialConnection) {
var buffer []byte
for {
select {
case <-(*s.StopCh):
c.TextBrowser.Append("close Serial Port")
return
case buffer = <-(*s.Ch):
c.TextBrowser.Append(string(buffer)) //显示通道的信息
}
}
}