Russian Qt Forum
Ноябрь 26, 2024, 02:41 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QSerialPort и Parity  (Прочитано 4664 раз)
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.


Вот фотография, когда сначала идет Space, а потом Mark.



Если посылать в режиме только Mark или только Space, то все хорошо. Вот фото.
Mark:


Space:


Собственно 2 вопроса, почему так происходит и как правильно сделать?
« Последнее редактирование: Август 11, 2014, 15:56 от TestUser013 » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #1 : Август 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);
}
 
 



Записан

ArchLinux x86_64 / Win10 64 bit
TestUser013
Гость
« Ответ #2 : Август 12, 2014, 10:57 »

kuzulis, огромное СПАСИБО за объяснение. Теперь все стало на свои места. После прочтения вашего сообщения обратил внимание на метод QSerialPort::flush(), думаю в моем случаи лучше использовать его. Еще раз спасибо, без вашей помощи был бы дальше в ступоре Улыбающийся
Записан
TestUser013
Гость
« Ответ #3 : Август 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 байта (но биты парности неверно стоят). Сейчас вообще полтора байта нарисовалось О_о


И ваш код реализовать не получилось Грустный Программа уходит в бесконечный цикл отправки пакетов... Ничего не понимаю...
« Последнее редактирование: Август 12, 2014, 15:29 от TestUser013 » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Август 12, 2014, 15:52 »

Цитировать
После прочтения вашего сообщения обратил внимание на метод QSerialPort::flush(), думаю в моем случаи лучше использовать его

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

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

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

ArchLinux x86_64 / Win10 64 bit
TestUser013
Гость
« Ответ #5 : Август 16, 2014, 14:56 »

Спасибо, бит четности меняется как надо. Но возникла новая проблема... Задержка между байтами получается слишком большой. Подключаемое устройство не реагирует на команды Грустный

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

Не знаю что делать... Нет желания писать прогу для доса Грустный
« Последнее редактирование: Август 16, 2014, 17:49 от TestUser013 » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #6 : Август 16, 2014, 18:30 »

Ну, это уже хитрый подвыподверт, нереальный для реализации в Windows и прочее. Нужно разработчикам таких железяк гвозди в бошки заколачивать (шутка) Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
« Ответ #7 : Август 16, 2014, 18:39 »

Так я и думал.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.136 секунд. Запросов: 22.