Russian Qt Forum

Qt => Вопросы новичков => Тема начата: TestUser013 от Август 11, 2014, 15:54



Название: QSerialPort и Parity
Отправлено: TestUser013 от Август 11, 2014, 15:54
Доброго времени суток.
Пытаюсь разобраться с СОМ портом. Возникла проблема...
Нужно отправлять байты изменяя бит четности. Если верить документации, то следующий код должен отправить байт 08 сначала с битом четности 1, а потом с битом четности 0.

Код:
void MainWindow::on_pushButton_clicked()
{
    QByteArray paket;
    paket.resize(1);
    paket[0] = 0x08;
    int temp;

    port.setParity(QSerialPort::MarkParity);
    ui->log->setPlainText(ui->log->toPlainText()+tr("Parity %1.\n").arg(port.parity()));
    temp = port.write(paket);
    ui->log->setPlainText(ui->log->toPlainText()+tr("Packet send. Size = %2 byte.\n").arg(temp));

    port.setParity(QSerialPort::SpaceParity);
    ui->log->setPlainText(ui->log->toPlainText()+tr("Parity %1.\n").arg(port.parity()));
    temp = port.write(paket);
    ui->log->setPlainText(ui->log->toPlainText()+tr("Packet send. Size = %2 byte.\n").arg(temp));
}


В PlainText выводится верная информация
Цитировать
Parity 5.
Packet send. Size = 1 byte.
Parity 4.
Packet send. Size = 1 byte.

А вот на экране осциллографа совсем другая ситуация.


Вот фотография, когда сначала идет Mark, а потом Space.
(http://ipic.su/img/img7/tn/Mark-Space.1407761511.jpg) (http://ipic.su/img/img7/fs/Mark-Space.1407761511.jpg)

Вот фотография, когда сначала идет Space, а потом Mark.
(http://ipic.su/img/img7/tn/Space-Mark.1407761531.jpg) (http://ipic.su/img/img7/fs/Space-Mark.1407761531.jpg)


Если посылать в режиме только Mark или только Space, то все хорошо. Вот фото.
Mark:
(http://ipic.su/img/img7/tn/Mark.1407761548.jpg) (http://ipic.su/img/img7/fs/Mark.1407761548.jpg)

Space:
(http://ipic.su/img/img7/tn/Space.1407761584.jpg) (http://ipic.su/img/img7/fs/Space.1407761584.jpg)

Собственно 2 вопроса, почему так происходит и как правильно сделать?


Название: Re: QSerialPort и Parity
Отправлено: kuzulis от Август 11, 2014, 22:22
1. Нужно сначала открывать порт, а потом менять паритет и прочее (в приведенном примере я вообще не вижу чтобы он открывался).

2. Сразу после port.write() нельзя менять паритет, т.к. реально данные еще могут не отправиться. Метод port.write() гарантирует только то, что данные будут записаны во внутренний буффер класса, и все! Реальная отправка будет позже.

Для того чтобы проверить то, что данные были отправлены, можно косвенно использовать сигнал bytesWritten(qint64).
Но он также не гарантирует то, что все данные будут полностью переданы в линию (т.к. некоторые могут находится еще в SHIFT регисте микросхемы и прочее..). Этот сигнал гарантирует (вроде-как) то, что буфер драйвера опустел (т.е. из драйвера в микруху все передано).

3. В приведенном коде метод on_pushButton_clicked() отправит сразу два пакета с паритетом SpaceParity. Т.к. цепочка из двух port.write(paket) просто добавит данные во внутренний буффер класса (т.е. там будет два пакета сразу). И по выходе из on_pushButton_clicked() отправятся все данные сразу (с SpaceParity - т.к. он был последним).

В общем, для реализации того чего надо, надо примерно делать так:
Код
C++ (Qt)
 
enum State { SendWithMark, SendWitchSpace };
 
State st = SendWithMark;
 
connect(port, SIGNAL(bytesWritten(qint64)), this, SLOT(checkByets(qint64)));
 
Foo::sendPacket(const Packet &pkt)
{
       port->setParity(st == SendWitchSpace ? SpaceParity : MarkParity);
       port->write(packet);
}
 
Foo::checkByets(qint64 bytes);
{
   if (bytes < packet.size())
       return; // do nothing
 
   if (st == SendWithMark)
       st = SendWitchSpace;
 
   sendPacket(pkt);
}
 
void MainWindow::on_pushButton_clicked()
{
   sendPacket(pkt);
}
 
 





Название: Re: QSerialPort и Parity
Отправлено: TestUser013 от Август 12, 2014, 10:57
kuzulis, огромное СПАСИБО за объяснение. Теперь все стало на свои места. После прочтения вашего сообщения обратил внимание на метод QSerialPort::flush(), думаю в моем случаи лучше использовать его. Еще раз спасибо, без вашей помощи был бы дальше в ступоре :)


Название: Re: QSerialPort и Parity
Отправлено: TestUser013 от Август 12, 2014, 15:11
Да уж. Все не так просто как мне показалось...

Написал код и он не срабатывает.
Код:
void MainWindow::on_pushButton_clicked()
{
    QByteArray paket;
    paket.resize(1);
    paket[0] = 0x08;

    port.setParity(QSerialPort::MarkParity);
    port.write(paket);
    port.flush();
    port.setParity(QSerialPort::SpaceParity);
    port.write(paket);
    port.flush();
}
Каждый раз при вызове on_pushButton_clicked() на осциллографе другая картинка, то 1 байт, то 2 байта (как надо), то снова 1 байт, или 2 байта (но биты парности неверно стоят). Сейчас вообще полтора байта нарисовалось О_о
(http://ipic.su/img/img7/tn/ppc.1407844859.jpg) (http://ipic.su/img/img7/fs/ppc.1407844859.jpg)

И ваш код реализовать не получилось :( Программа уходит в бесконечный цикл отправки пакетов... Ничего не понимаю...


Название: Re: QSerialPort и Parity
Отправлено: kuzulis от Август 12, 2014, 15:52
Цитировать
После прочтения вашего сообщения обратил внимание на метод QSerialPort::flush(), думаю в моем случаи лучше использовать его

Нет. Flush должен просто делать сброс данных из внутреннего буфера класса в драйвер (вызывает WriteFile) и все. Он асинхронный и ничего не блокирует (не ждет пока данные передадутся).
Здесь также не факт что данные успеют передаться.

Но еще и дело в том, что на текущий момент метод flush() не реализован корректно, т.е. не работает вообще и все портит. Нельзя его использовать.

Лучше всего использовать сигнал bytesWritten(qint64) (где считать кол-во отправленных байт) + еще некоторую задержку по таймеру (singleShot()) после него, перед тем как передавать новую порцию данных с новым паритетом.


Название: Re: QSerialPort и Parity
Отправлено: TestUser013 от Август 16, 2014, 14:56
Спасибо, бит четности меняется как надо. Но возникла новая проблема... Задержка между байтами получается слишком большой. Подключаемое устройство не реагирует на команды :(

Протокол устройства требует, чтоб ид команды отправлялось с битом четности Mark, а остальная часть команды с битом четности Space. И без задержки между ид и остальной частью команды.

Не знаю что делать... Нет желания писать прогу для доса :(


Название: Re: QSerialPort и Parity
Отправлено: kuzulis от Август 16, 2014, 18:30
Ну, это уже хитрый подвыподверт, нереальный для реализации в Windows и прочее. Нужно разработчикам таких железяк гвозди в бошки заколачивать (шутка) :)


Название: Re: QSerialPort и Parity
Отправлено: Bepec от Август 16, 2014, 18:39
Так я и думал.