【发布时间】:2019-03-03 15:40:29
【问题描述】:
目标
在我的 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() 进程持续,它就会保持高电平,而不是实际数据的传播持续。
问题
- 当我使用 naive 时添加的额外延迟是什么,
QThread::usleep接近,导致脉搏拉长? - 为什么信号槽方法不起作用,因为它是 事件驱动?
- 一般来说,我怎样才能指示引脚仅在 传输数据然后再次降为零,所以我可以接收 奴隶的回复?
【问题讨论】:
-
可能是因为您使用的是正常的操作系统并且日程安排会妨碍您。如果您需要较高的计时精度,请尝试使用实时操作系统
-
我不知道 Qt 的工作原理,但我的猜测是使用
QThread::usleep允许其他线程运行,所以你在你的线程上获得睡眠加上另一个线程上的一些运行时在你回到你的之前。 -
因为Linux不是RTOS,而UART串口数据可以包含字符间空间,不仅会拉长你的延迟,还会导致串口突发,所以你的方法有严重缺陷。 GPIO 控制应在串行驱动程序级别执行,当输入缓冲区和 UART FIFO/TX 变空时将其删除。但这似乎没有必要;这是主从关系。奴隶在被询问之前不应该回复,并且主人将等待(有一些适当的超时)该回复。数据本身已经是流控了。
-
@Clifford “但这似乎没有必要;这是主从关系。”确切地。这也是我尝试第二种方法的原因。写入所有字节后,将方向引脚设置回 0(这样我们现在可以接收从机的回复)。 TBH,我真的看不出这不起作用的原因......
-
使用延迟是有问题的。 Qt 是否有与tcdrain() function 等价的东西?
标签: qt embedded embedded-linux gpio