如何使用GPIO引脚通过Qt进行串行流控制?

时间:2018-09-27 16:54:52

标签: qt embedded embedded-linux gpio

目标

在Qt应用程序中,我需要控制GPIO引脚,具体取决于通过串行总线发送的数据。因此,只要传输数据,就需要将其设置为HIGH,传输结束后立即将其设置为LOW。将其视为串行通信流控制引脚,当设置为1时,它将启用发送,而设置为0时,则将允许接收数据。整个系统是半双工的,并且以主从方式进行通信。

问题

我设法接近解决方案,即将任何传输之前将其设置为HIGH,根据波特率引入一定的延迟(我使用QThread:usleep()),然后再次将其设置为低,但是当我用示波器进行可视化时,得到的是随机的脉冲“拉伸”(保持高电平的时间长于应有的时间)。

尝试的解决方案

好吧,似乎有些“魔术”正在发生,这除了我手动定义的延迟之外,还增加了一些额外的延迟。为了消除这种可能性,我使用了bytesWritten()信号,因此当我们将实际数据写入端口时,可以触发setPinLow()插槽。所以我的代码现在看起来像这样:

classTTY::classTTY(/*someStuff*/) : port(/*some other stuff*/)
{
    s_port = new QSerialPort();
    connect(s_port, SIGNAL(bytesWritten(qint64)), this, SLOT(setPinLow()));

    if(GPIOPin->open(QFile::ReadWrite | QFile::Truncate | QFile::Text | QFile::Unbuffered)) {
        qDebug() << "GPIO pin ready to switch.";
    } else {
        qDebug() << "Failed to access GPIO pin";
    }

bool classTTY::sendData(data, replyLength)
{
    directionPinEnable(true);

    if(m_port->isOpen()) {
        s_expectedReplyLength = replyLength;
        s_receivedData.clear();

        s_port->flush();
        s_port->write(data);

        return true;
    }

return false;
}

void classTTY::setPinLow()
{
    gpioPinEnable(false);
}

void classTTY::gpioPinEnable(bool enable){

    if(enable == true){
        GPIOPin->write("1");
    } else if (enable == false) {
        GPIOPin->write("0");
    }
}

在实现它之后,该引脚开始真正发出短脉冲,更像是“尖峰”,这暗示着(我认为)现在只要Qt write()持续,它就会一直保持高电平,而不是数据的实际传播持续进行。

问题

  1. 使用天真时,会增加多少延迟? QThread::usleep方法会导致脉冲展宽?
  2. 为什么信号时隙方法不起作用,因为它可以 是事件驱动的?
  3. 通常,我如何指示该引脚仅在 传输数据,然后再次降为零,这样我就可以接收 奴隶的答复?

1 个答案:

答案 0 :(得分:0)

  
      
  1. 当我使用朴素的QThread :: usleep方法时,会导致脉搏延长的额外延迟是什么?
  2.   

Linux不是实时操作系统,线程睡眠会在不小于指定时间的情况下暂停进程。在休眠期间,其他线程和进程可能会运行,并且可能不会在比您的休眠周期更长的时间内产生处理器,或者可能根本不产生并消耗它们分配给操作系统的整个时间片。除此之外,内核驱动程序中断处理程序将始终抢占用户级进程。 Linus有一个用于实时调度的构建选项,但是保证仍然不够可靠,以至于真正的实时操作系统和延迟通常会变差。

还要注意,不仅线程的挂起时间可以长于睡眠时间,而且传输的扩展量可能超过波特率的位数-内核驱动程序可以被其他驱动程序抢占并引入内部-您无法控制的字符间距。

  
      
  1. 为什么信号时隙方法是不起作用的,因为它是事件驱动的?
  2.   

QSerialPort::waitForBytesWritten()的文档说明:

  

此函数将阻塞,直到至少一个字节已写入串行端口并且已发出bytesWritten()信号为止。

因此很明显,其语义是“已写入 一些数据”,而不是“ 所有数据”已写”。每当写入字节时,它将返回,然后再次调用,如果继续写入字节,它将很可能立即返回(因为QSerialPort被缓冲并且将独立于应用程序写入数据)。

  
      
  1. 一般来说,如何指示引脚在数据传输期间仅处于活动状态,然后再次下降到零,这样我才能收到从设备的答复?
  2.   

不幸的是,Qt并不是答案。此行为需要在串行端口内核驱动程序中实现,或者至少在Qt的较低级别实现。 Qt QSerialPort抽象不能为您提供控制或深入了解所需的“在线”实际发生情况的级别。从硬件上来说,它有些距离了-有充分的理由。

但是,有一个简单的解决方案-不用担心!似乎完全没有必要。这是主从通信,因此数据本身是 流控制。从属设备直到讲话后才开始说话,而主控器必须等待并等待答复。为什么奴隶除了说话所暗示的以外还需要其他任何说话的权限?