Как использовать вывод GPIO для управления последовательным потоком с помощью Qt? - PullRequest
0 голосов
/ 27 сентября 2018

ЦЕЛЬ

В моем приложении Qt мне нужно управлять выводом GPIO в зависимости от данных, передаваемых по последовательной шине.Итак, мне нужно установить его на ВЫСОКИЙ, пока я передаю данные, и на НИЗКИЙ, сразу после окончания передачи.Рассмотрим его как вывод управления потоком последовательной связи, который при значении 1 разрешает передачу, а при значении 0 - прием данных.Вся система является полудуплексной и взаимодействует как ведущий-ведомый.

ПРОБЛЕМА

Мне удалось приблизиться к решению, установив его в ВЫСОКОЕнепосредственно перед любой передачей, вводя некоторую постоянную задержку (я использовал 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(), а не пока продолжается фактическое распространение данных.

ВОПРОС (S)

  1. Что это за дополнительнаядобавляется ли задержка, когда я использую наивный, QThread::usleep подход, который вызывает растяжение импульса?
  2. Почему не работает подход со слотом сигнала, так как он управляется событиями?
  3. В общем, как я могу дать команду выводу активироваться ТОЛЬКО во время передачи данных, а затем снова сбросить его до нуля, чтобы я мог получить ответ раба?

1 Ответ

0 голосов
/ 28 сентября 2018
  1. Что за дополнительная задержка добавляется, когда я использую наивный подход QThread :: usleep, который вызывает растяжение импульса?

Linux - этоне в операционной системе реального времени спящий поток приостанавливает процесс на не менее чем указанного времени.Во время сна другие потоки и процессы могут работать и могут не дать процессору дольше, чем ваш период ожидания, или могут вообще не работать и использовать весь выделенный ОС промежуток времени.Кроме того, обработчики прерываний драйвера ядра всегда будут вытеснять процесс пользовательского уровня.У Linus есть опция сборки для планирования в реальном времени, но гарантии остаются менее надежными, чем реальная ОСРВ и задержки, как правило, хуже.

Обратите также внимание, что не только ваш поток может быть приостановлен на более длительный период, чем период ожидания, нопередача может быть увеличена более чем на количество бит по скорости передачи данных - драйвер ядра может быть вытеснен другими драйверами и ввести межсимвольные промежутки, над которыми у вас нет контроля.

Почему не работает подход со слотом для сигналов, поскольку он управляется событиями?

В документации для QSerialPort::waitForBytesWritten() указано:

Эта функция блокируется до тех пор, пока в последовательный порт не будет записан хотя бы один байт и не будет отправлен сигнал bytesWritten ().

Таким образом, ясно, что семантика этого« некоторые данные были записаны » вместо « все данные были записаны ».Он будет возвращаться всякий раз, когда записывается байт, затем, если вы вызовете его снова, он, скорее всего, сразу же вернется, если байты продолжают записываться (потому что QSerialPort буферизуется и будет записывать данные независимо от вашего приложения).

В общем, как я могу дать команду выводу активироваться ТОЛЬКО во время передачи данных, а затем снова сброситься до нуля, чтобы я мог получить ответ ведомого?

Qt isне к сожалению ответ;это поведение должно быть реализовано в драйвере ядра последовательного порта или, по крайней мере, на более низком уровне, чем Qt.Абстракция Qt QSerialPort не дает вам необходимого уровня контроля или понимания фактического события "на проводе".Это несколько руки от оборудования - по уважительной причине.

Однако есть простое решение - не беспокойтесь!это кажется совершенно ненужным.Это связь ведущий-ведомый, и поэтому сами данные являются контролем потока.Раб не разговаривает, пока с ним не разговаривают, и хозяин должен ожидать и ждать ответа после того, как он произнес.Почему рабу требуется какое-либо разрешение, чтобы говорить иначе, чем подразумевается, когда с ним разговаривают?

...