QSerialPort

最近公司项目正在由BCB转移到Qt。之前用的串口通信程序是BCB写的一个叫Victor的控件,印象中出现过挺多问题的。

Victor控件

它的实现就是用一个线程专门读,一个线程专门写。上层应用调用read,write函数,操作的其实是它的内部存储。也就是说write函数返回,数据有没有从串口发送出去,这个就不知道了。
后来,我们自己改过一次。就是将数据写入内部存储之后,等待write线程将数据写入串口之后,write函数再返回。其实这地方一直有隐患,就是如果write线程长时间无法写入数据,那么调用write函数的线程(一般就是UI线程)就会嗝屁。

Qt的QSerialPort


  1. QSerialPort中与读写相关的函数有下面几个:

  • read()
  • write()
  • readLine()
  • readAll()
  • waitForReadyRead()
  • waitForBytesWritten()
  • read,write

    这两个函数都是从QIODevice继承而来。它们也只是从内部存储中读取或写入数据,并没有真正与串口驱动沟通

  • waitForReadyRead()

    阻塞当前线程,直到有新的数据可以读,readyRead()信号被触发,或者达到设置的超时时间。如果超时时间设为-1,那么就不会出现超时
    有可读数据返回true,否则返回false,此时表示操作超时或者有错误发生
    该函数可以在没有事件循环时运行。当写一个非GUI应用,或使用非GUI线程操作IO时,可以使用该函数
    如果在一个连接到readyRead信号的槽函数中调用waitForReadyRead,将不会再次出发readyRead信号
    注意:在主线程中调用该函数,会使得UI无法响应任何请求

  • waitForBytesWritten

    对于带有缓存的device,该函数会在缓存数据被写入device,bytesWritten()信号被触发之后,或者达到超时时间后返回。
    对于不带缓存的device,它会立即返回
    如果数据被写入device,返回true
    该函数可以在没有事件循环时运行。当写一个非GUI应用,或使用非GUI线程操作IO时,可以使用该函数
    如果在一个连接到bytesWritten信号的槽函数中调用该函数,将不会再次出发bytesWritten信号
    Calling this function from the main (GUI) thread might cause your user interface to freeze.

  • 注意:

    做了个实验验证一下,发现两个wait函数确实要等到信号对应的槽函数响应之后才能返回。所以我觉得waitXXX和槽函数最好不要一起使用
    readyRead和bytesWritten对应的槽函数是在主线程运行的

  • 封装QSerialPort

    我们的应用是这样的:上层应用,发送完命令之后,为了得到ack,会在指定时间内循环读取,直到获得指定字节的数据,或者超时。底层需要做的就是封装QSerialPort,并提供read、write接口。并且write接口返回时,一定要保证确实写入了串口

    1. 使用信号与槽

      1. 实现方法
        1. write调用QSerialPort::write写入缓存,waitForBytesWritten等待写完。
        2. 定义一个槽函数,将其连接到readyRead信号。在槽函数中,保存数据到内存buffer中
        3. read函数每次从buffer中读取数据,返回给上层应用
      2. 实验结果
        1. 发送一次command,上层应用无法再指定时间内得到ack。有时候再发送一次,才可以得到。而且第二次write时,会出现“重叠 I/O 事件不在信号状态中”的错误
        2. 后来想到看一下槽函数的线程Id是怎样的。发现槽函数就直接运行在主线程中。这TM就尴尬了。这样肯定无法及时获得数据
        3. 所以这种方法不行啊

    2.read,write阻塞
    后续补充实验结果
    3. write阻塞,read使用线程
    后续补充实验结果

    你可能感兴趣的:(Qt)