简体   繁体   English

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

[英]How to use a GPIO pin, for serial flow control with Qt?

THE GOAL 目标

In my Qt application, I need to control a GPIO pin, depending on data being sent over the serial bus. 在我的Qt应用程序中,我需要控制GPIO引脚,具体取决于通过串行总线发送的数据。 So, I need to set it to HIGH for as long as I transmit data, and to LOW, immediately after the transmission ends. 因此,只要传输数据,就需要将其设置为HIGH,传输结束后立即将其设置为LOW。 Consider it as a serial communication flow control pin, which when set to 1 it enables transmission, and when set to 0 enables receive of data. 将其视为串行通信流控制引脚,当设置为1时,它将启用发送,而设置为0时,则将允许接收数据。 The entire system is half-duplex and communicates in a master-slave fashion. 整个系统是半双工的,并且以主从方式通信。

THE PROBLEM 问题

I managed to come close to a solution, by setting it to HIGH immediately before any transmission, introducing some constant delay (I used QThread:usleep() ) depending on the baud rate and then setting it to low again, but I was getting random "stretchings" of the pulse (staying HIGH longer than it should) when I was visualizing it with an oscilloscope. 我设法接近解决方案,即将任何传输之前将其设置为HIGH,根据波特率引入了一些恒定的延迟(我使用了QThread:usleep() ),然后再次将其设置为低,但是我变得随机了。当我用示波器观察脉冲时,脉冲“伸展”(保持高电平的时间长于应有的时间)。

ATTEMPTED SOLUTIONS 尝试的解决方案

Well, it seems that some "magic" is taking place, which adds some extra delay, on top of the one I have manually defined. 好吧,似乎有些“魔术”正在发生,这在我手动定义的延迟的基础上增加了一些额外的延迟。 In order to get rid of that possibility, I used the bytesWritten() signal, so I can fire my setPinLow() slot when we finish writing the actual data to the port. 为了消除这种可能性,我使用了bytesWritten()信号,因此在将实际数据写入端口后,可以触发setPinLow()插槽。 So my code now looks like this: 所以我的代码现在看起来像这样:

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");
    }
}

After implementing it the pin started to give really short pulses, much more like "spikes", which implies (I think) that now it stays HIGH for as long as the Qt write() process lasts, and not while the actual propagation of the data lasts. 实施该引脚后,该引脚开始发出非常短的脉冲,更像是“尖峰脉冲”,这意味着(我认为)现在只要Qt write()过程持续,它就会一直保持高电平,而不是在实际传播时。数据持续。

THE QUESTION(S) 问题

  1. What is that extra delay being added when I use the naive, QThread::usleep approach, that causes the stretch of the pulse? 当我使用幼稚的QThread::usleep方法时,会导致脉宽延长的额外延迟是什么?
  2. Why the signal-slot approach is not working, since it is event-driven? 为什么信号插槽方法是事件驱动的,所以为什么不起作用?
  3. In general, how can I instruct the pin to go active ONLY during the transmission of data and then drop again to zero, so I can receive the slave's reply? 通常,如何指示引脚在数据传输过程中仅变为活动状态,然后再次下降为零,以便接收从设备的答复?
  1. What is that extra delay being added when I use the naive, QThread::usleep approach, that causes the stretch of the pulse? 当我使用幼稚的QThread :: usleep方法时,会导致脉宽延长的额外延迟是什么?

Linux is not a real-time operating system a thread sleep suspends the process fo no less than the time specified. Linux不是实时操作系统,线程睡眠会以至少指定的时间暂停进程。 During the sleep, other threads and processes may run and may not yield the processor for a longer time than your sleep period, or may not yield at all and consume their entire OS allocated time-slice. 在休眠期间,其他线程和进程可能会运行,并且可能不会在比您的休眠周期更长的时间内产生处理器,或者可能根本不产生并消耗它们分配给操作系统的整个时间片。 Beside that kernel driver interrupt handlers will always preempt a user-level process. 除此之外,内核驱动程序中断处理程序将始终抢占用户级进程。 Linus has a build option for real-time scheduling, but the guarantees remain less robust that a true RTOS and latencies typically worse. Linus有一个用于实时调度的构建选项,但是保证仍然不够可靠,以至于真正的实时操作系统和延迟通常会更糟。

Note also that not only can your thread be suspended for longer than the sleep period, but the transmission may be extended by more than the number of bits over baud-rate - the kernel driver can be preempted by other drivers and introduce inter-character gaps over which you have no control. 还要注意,不仅线程的挂起时间比睡眠时间长,而且传输的扩展量可能超过波特率上的位数-内核驱动程序可能会被其他驱动程序抢占并引入字符间的间隙您无法控制。

  1. Why the signal-slot approach is not working, since it is event-driven? 为什么信号插槽方法是事件驱动的,所以为什么不起作用?

The documentation for QSerialPort::waitForBytesWritten() states: QSerialPort::waitForBytesWritten()的文档指出:

This function blocks until at least one byte has been written to the serial port and the bytesWritten() signal has been emitted. 该函数将阻塞,直到至少一个字节已写入串行端口并且已发出bytesWritten()信号为止。

So it is clear that the semantics of this are that " some data has been written " rather than " all data has been written ". 因此很明显,其语义是“ 已写入一些数据 ”而不是“ 已写入所有数据 ”。 It will return whenever a byte is written, then if you call it again, it will likely return immediatly if bytes are continuing to be written (because QSerialPort is buffered and will write data independently of you application). 每当写入一个字节时,它都会返回,然后再次调用,如果继续写入字节,它可能会立即返回(因为QSerialPort已缓冲并且将独立于应用程序写入数据)。

  1. In general, how can I instruct the pin to go active ONLY during the transmission of data and then drop again to zero, so I can receive the slave's reply? 通常,如何指示引脚在数据传输过程中仅变为活动状态,然后再次下降为零,以便接收从设备的答复?

Qt is not unfortunately the answer; 不幸的是,Qt并不是答案。 this behaviour needs to be implemented in the serial port kernel driver or at least at a lower-level that Qt. 此行为需要在串行端口内核驱动程序中实现,或者至少在Qt的较低级别实现。 The Qt QSerialPort abstraction does not give you the level of control or insight into the actual occurrence "on the wire" that you need. Qt QSerialPort抽象不能为您提供控制或深入了解所需的“在线”实际发生情况的级别。 It is somewhat arms-length from the hardware - for good reason. 从硬件上来说,它有些距离了-这是有充分理由的。

However there is a simple solution - don't bother! 但是,有一个简单的解决方案-不用担心! it seems entirely unnecessary. 似乎完全没有必要。 It is a master-slave communication, and as such the data itself is flow control. 它是主从通信,因此数据本身流控制。 The slave does not talk until spoken to, and the master must expect and wait for a reply after it has spoken. 从属设备直到讲话后才开始说话,而主控器必须等待并等待答复。 Why does the slave need any permission to speak other than that implied by being spoken to? 为什么奴隶除了说话所暗示的以外还需要其他任何说话的权限?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM