Russian Qt Forum

Qt => Общие вопросы => Тема начата: 8Observer8 от Май 27, 2014, 12:16



Название: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 12:16
Привет!

Мне надо освоить работу с COM-портом. Для этого написал самую простейшую программу, которая не работает. Точнее две программы: одна записывает в порт, другая должна прочитать.

Опишу ситуацию подробнее. На ноутбуке нет COM-портов, поэтому я скачал вот эту программу: ссылка (http://virtual-null-modem.com/)  Она позволяет создать два виртуальных COM-порта и замкнуть их, то есть если одна программа пишет в один порт, например в COM7, то другая может прочитать, к примеру, из COM8.

Как я понимаю, что если я записал данные в порт, то они там будут лежать пока из не считают. Если просто писать в порт, то после переполнения буфера - первые данные будут исчезать.

Я создал два замкнутых виртуальных порта: COM7 и COML8. И написал две короткие программки.

Первая программа у меня настраивает порт COM7 и записывает в него данные по клику по кнопке:
Код
C++ (Qt)
void Dialog::on_SendPushButton_clicked()
{
   // Set serial port
   QSerialPort transmitter;
   transmitter.setPortName( ui->PortNumOfTransmitterComboBox->currentText( ) );
   transmitter.setBaudRate( QSerialPort::Baud9600 );
   transmitter.setDataBits( QSerialPort::Data8 );
   transmitter.setParity( QSerialPort::NoParity );
   transmitter.setStopBits( QSerialPort::OneStop );
   transmitter.setFlowControl( QSerialPort::NoFlowControl );
 
   // Open serial port
   if ( !transmitter.open( QIODevice::WriteOnly ) ) {
       QMessageBox::critical( this, "Error", transmitter.errorString() );
       return;
   }
 
   // Write data to the port
   QByteArray data;
   data.append( 0x0f0 );
   transmitter.write(data);
}


Вторая программа - настраивает порт COM8, считывает данные и выводит на экран:
Код
C++ (Qt)
void Dialog::on_GetPushButton_clicked( )
{
   // Set serial port
   QSerialPort receiver;
   receiver.setPortName( ui->PortNumOfReceiverComboBox->currentText( ) );
   receiver.setBaudRate( QSerialPort::Baud9600 );
   receiver.setDataBits( QSerialPort::Data8 );
   receiver.setFlowControl( QSerialPort::NoFlowControl );
   receiver.setStopBits( QSerialPort::OneStop );
   receiver.setParity( QSerialPort::NoParity );
 
   // Open serial port
   if ( !receiver.open( QIODevice::ReadOnly ) ) {
       QMessageBox::critical( this, "Error", receiver.errorString( ) );
       return;
   }
 
   // Read data from serial port
   QByteArray data;
   data = receiver.readAll( );
 
   qDebug() << data.toHex( );
}

Но данные не выводятся. Заранее спасибо за помощь!


Название: Re: Знакомство с последовательным портом
Отправлено: Hellraiser от Май 27, 2014, 12:21
Я так понимаю, что желания ознакомится с примерами из комплекта QSerialPort нет никакого?


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 12:27
Я смотрел. Сложно там. Ничего не понял. Ещё посмотрю. Мне бы попроще. Почему данные в моём примере не читаются?


Название: Re: Знакомство с последовательным портом
Отправлено: Hellraiser от Май 27, 2014, 12:29
И это пишет человек со статусом "Программист"? :FACEPALM:


Название: Re: Знакомство с последовательным портом
Отправлено: gil9red от Май 27, 2014, 12:30
И это пишет человек со статусом "Программист"? :FACEPALM:

Эти статусы определяют количество написанных сообщений, а не знания и опыт :)


Название: Re: Знакомство с последовательным портом
Отправлено: Hellraiser от Май 27, 2014, 12:30
Может, для начала, стоит понять, что COM-порт по природе своей асинхронное устройство и "вот так вот сразу" ничего не выдаст?


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 12:39
Может надо как-то заставить вторую программу "слушать" порт? Как это сделать?

"асинхронное устройство" говорит о том, что есть буфер? То есть необязательно соединение "точка-точка"? К чему Вы клоните?


Название: Re: Знакомство с последовательным портом
Отправлено: Hellraiser от Май 27, 2014, 12:47
Ну понятно - для кого-то слова "асинхронный", "обработка событий" похоже ничего не говорят. Заканчиваю писать в тему - это просто бессмысленно.


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 12:56
Ничего не понимаю. С помощью COMTester данные читаются. Добавил строку для ожидания данных в приёмнике:
Код
C++ (Qt)
   // Read data from serial port
   QByteArray data;
   data = receiver.readAll( );
 
   receiver.waitForReadyRead( -1 );
 
   qDebug() << data.toHex( );
 

Всё равно пусто.


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 12:59
А понял, надо читать после ожидания :)

Код
C++ (Qt)
   // Read data from serial port
   QByteArray data;
 
   receiver.waitForReadyRead( -1 );
 
   data = receiver.readAll( );
 
   qDebug() << data.toHex( );
 


Название: Re: Знакомство с последовательным портом
Отправлено: Kurles от Май 27, 2014, 13:02
Пипец. Кроме флуда ничего не умеем, что ли? Делаешь ресивер и сендер экземплярами класса, оба открываешь (Важно!!! Все настройки порта (чётность, скорость) только после открытия!!!), коннектишь сигнал ридера readyRead co слотом - и там уже читаешь данные. Пипец проблема. :o


Название: Re: Знакомство с последовательным портом
Отправлено: Kurles от Май 27, 2014, 13:03
А понял, надо читать после ожидания :)
Qt - асинаронный фреймворк, нефиг в гуишных потоках вообще чего то ждать. Сигналы и таймеры на это есть.


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 13:05
Kurles, спасибо! Очень много полезной инфы и всё по делу :)


Название: Re: Знакомство с последовательным портом
Отправлено: Hrundel от Май 27, 2014, 13:23
8Observer8, мне приснилось или ты радио-физику изучал? Вроде понятие о сигнале должно быть?!


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 14:55
Как "понятия о сигнале" влияют на работу с COM-портом, как с программным объектом? Думаю, что знания схемотехники здесь не требуются. Только документация на Qt и принципы ООП. Я спрашивал, как работать с COM-портом с точки зрения программиста.


Название: Re: Знакомство с последовательным портом
Отправлено: Bepec от Май 27, 2014, 15:00
Видимо тебе Hrundel пытался довести до внимания само понятие сигнала.
Что сигнал передаётся в течении некоего времени которое равняется длина сообщения умноженная поделённая на скорость передачи.

И даже "программист" не может этого изменить :D Законы физики, увы.


Название: Re: Знакомство с последовательным портом
Отправлено: OKTA от Май 27, 2014, 15:17
Длину умножить на скорость?  :o Может лучше делить?  ;D


Название: Re: Знакомство с последовательным портом
Отправлено: Bepec от Май 27, 2014, 15:26
Таки да, делить :)

Хорошо когда есть кому подправить ^^


Название: Re: Знакомство с последовательным портом
Отправлено: kuzulis от Май 27, 2014, 16:11
Цитировать
На ноутбуке нет COM-портов, поэтому я скачал вот эту программу: ссылка

Эмм.. Как бы софтинка Virtual-Null-Modem не очень удачное решение, даже скажу больше - плохое.
Например, я не смог ее использовать на Win8x32 вообще. При попытке открытия порта любой терминальной прогой (будь то Putty, Termite и прочее), оно нещадно крешилось..
Даже пример Terminal из QtSerialPort крешился, т.к. принимал всякий треш, который по какой-то причине валил после открытия порта..

Поэтому выбрось эту хрень, и попробуй com0com (хотя, сегодня обнаружил, что и эта софтинка имеет касяк), а еще лучше, софт от Eltima Software (триал версию). :)


Название: Re: Знакомство с последовательным портом
Отправлено: Hrundel от Май 27, 2014, 16:15
Видимо тебе Hrundel пытался довести до внимания само понятие сигнала.

И даже "программист" не может этого изменить :D Законы физики, увы.

Именно!
Спасибо Верес.


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 16:30
Я не понял замуту с асинхронными сигналами. Ну да ладно...

kuzulis, спасибо! Очень полезная инфа. Virtual-Null-Modem - тоже триал, так как имеет ограничения на 65 КБ трафика. Буду юзать её, пока не закончится трафик :)

А что за косяк с com0com?

Какое ограничение в триал версии это проги: http://www.eltima.com/products/vspdxp/ Если по времени, то сколько?


Название: Re: Знакомство с последовательным портом
Отправлено: Bepec от Май 27, 2014, 16:55
Установи и узнай. А то что-то прям каждое затруднение длиной в целую минуту заставляет тебя писать на форум :D


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 17:46
Установи и узнай. А то что-то прям каждое затруднение длиной в целую минуту заставляет тебя писать на форум :D
По поводу установки - согласен.

Мне здесь советовали сделать класс Sender. Посмотрите, пожалуйста, всё ли нормально:

Обработчик кнопки:
Код
C++ (Qt)
void Dialog::on_SendPushButton_clicked()
{
   Sender sender( "COM3" );
   QByteArray data;
   data.append( 0x0f0 );
   try {
       sender.send( data );
   } catch( const PortError &e ) {
       QMessageBox::critical( this, "Error", QString( e.what( ) ) );
       return;
   } catch( ... ) {
       QMessageBox::critical( this, "Error", "Error: unknown exception" );
       return;
   }
}
 

Sender.h
Код
C++ (Qt)
#ifndef SENDER_H
#define SENDER_H
 
#include <QString>
#include <QSerialPort>
#include "PortError.h"
 
class Sender {
public:
 
   Sender( QString portName,
           int baudRate = QSerialPort::Baud9600,
           int dataBits = QSerialPort::Data8,
           int parity = QSerialPort::NoParity,
           int stopBits = QSerialPort::OneStop,
           int flowControl = QSerialPort::NoFlowControl ) :
       m_portName( portName ), m_baudRate( baudRate ), m_dataBits( dataBits ),
       m_parity( parity ), m_stopBits( stopBits ), m_flowControl( flowControl )
   {
 
   }
 
   void send( const QByteArray &data ) throw( PortError ) {
       m_serialPort.setPortName( m_portName );
 
       if ( !m_serialPort.open( QIODevice::WriteOnly ) ) {
           throw PortError( m_serialPort.errorString( ).toStdString( ) );
       }
 
       m_serialPort.setBaudRate( QSerialPort::Baud9600 );
       m_serialPort.setDataBits( QSerialPort::Data8 );
       m_serialPort.setParity( QSerialPort::NoParity );
       m_serialPort.setStopBits( QSerialPort::OneStop );
       m_serialPort.setFlowControl( QSerialPort::NoFlowControl );
 
       if ( m_serialPort.write( data ) == -1 ) {
           throw PortError( m_serialPort.errorString( ).toStdString( ) );
       }
   }
 
private:
   QSerialPort m_serialPort;
   QString m_portName;
   int m_baudRate;
   int m_dataBits;
   int m_parity;
   int m_stopBits;
   int m_flowControl;
};
 
#endif // SENDER_H
 

PortError.h
Код
C++ (Qt)
#ifndef PORTERROR_H
#define PORTERROR_H
 
#include <string>
#include <stdexcept>
 
class PortError : public std::runtime_error {
public:
 
   PortError( const std::string &errorText ) : std::runtime_error( "" ) {
       m_message = "Error: " + errorText;
   }
 
   virtual ~PortError( ) throw( ) {
 
   }
 
   virtual const char *what( ) const throw( ) {
       return m_message.c_str( );
   }
 
private:
   std::string m_message;
};
 
#endif // PORTERROR_H
 


Название: Re: Знакомство с последовательным портом
Отправлено: Nidxogg от Май 27, 2014, 18:00
Не удержался
(http://risovach.ru/upload/2013/03/mem/utka_13482282_orig_.jpeg)


Название: Re: Знакомство с последовательным портом
Отправлено: Bepec от Май 27, 2014, 18:06
Я тебя поддерживаю  ;D


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 18:17
Где я накосячил? Может что забыл? Вроде для отправки ничего больше не нужно. Надо только Receiver ещё написать. Вот там интереснее будет.

P.S. Ну, да, согласен, что это всё примитивно. И настоящий программист делает всё это за пару минут. Но мне приходится учиться на кошках :) Пожалуйста, пишите по теме, что именно я забыл в Sender'е?


Название: Re: Знакомство с последовательным портом
Отправлено: Hellraiser от Май 27, 2014, 19:49
Крайне советую изучить вот эту книгу (http://www.prog.org.ru/index.php?topic=765.msg67880#msg67880). А иначе можно еще 100500 постов набить "ниачём", а понимание работы основного механизма Qt - сигналов и слотов (а иначе говоря, обработки событий) не придет. И изучить надо вдумчиво, с разбором как все это работает, а не пролистав всю книгу за денёк-другой. Как-то так...


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 20:30
Крайне советую изучить вот эту книгу (http://www.prog.org.ru/index.php?topic=765.msg67880#msg67880).
Читал я эту книжку по диагонали. Точно знаю, что там нет ничего о COM-портах :)

Я сделал Receiver:
(http://i.pixs.ru/storage/1/1/1/223png_6649005_12294111.png)

Исходники:
Receiver: https://github.com/8Observer8/Receiver
Sender: https://github.com/8Observer8/Sender

P.S. Пожалуйста, посмотрите код. Есть ли в коде какие-нибудь недочёты?


Название: Re: Знакомство с последовательным портом
Отправлено: kuzulis от Май 27, 2014, 21:17
На данный момент ты имеешь "удачу" что твой Sender что-то передает (кстати, благодаря багу, который исправлен в Qt 5.3.1). После обновления на  Qt 5.3.1 у тебя ничо работать не будет (как и в *.nix). Да и что ты все выдумываешь то? Посмотри уже примеры от QtSerialPort... :)


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 27, 2014, 21:23
А почему не будет? Можно чуть подробнее?


Название: Re: Знакомство с последовательным портом
Отправлено: Kurles от Май 27, 2014, 22:06
У меня такое впечатление, что он нас тролит :) Упорно создаёт экземпляры приёмников - передатчиков в куче в слоте обработчика нажатия на кнопку :)


Название: Re: Знакомство с последовательным портом
Отправлено: Bepec от Май 27, 2014, 22:41
Я уже с остывшим любопытством наблюдаю - во что может вылиться отсутствие навыков чтения документации. Судя по всему - очень страшные вещи случаются.


Название: Re: Знакомство с последовательным портом
Отправлено: OKTA от Май 28, 2014, 00:30
нет зверя страшнее программиста  ;D
Обсервер, ты начинаешь понимать всю тяжесть фриланса для начинающего программиста?


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 28, 2014, 04:45
У меня такое впечатление, что он нас тролит :) Упорно создаёт экземпляры приёмников - передатчиков в куче в слоте обработчика нажатия на кнопку :)

Передатчик я создаю не в куче, а в стеке по клику мышки. Что плохого, если я открыл, передал (кстати, забыл закрыть порт)?

Код
C++ (Qt)
void Dialog::on_sendPushButton_clicked()
{
   Sender sender( ui->portNameComboBox->currentText( ) );
   QByteArray data;
   data.append( ui->byteSpinBox->value( ) );
   try {
       sender.send( data );
   } catch( const PortError &e ) {
       QMessageBox::critical( this, "Error", QString( e.what( ) ) );
       return;
   } catch( ... ) {
       QMessageBox::critical( this, "Error", "Error: unknown exception" );
       return;
   }
}

Порт в деструкторе теперь закрываю:
Код
C++ (Qt)
   ~Sender( ) {
       m_serialPort.close( );
   }
 

А приёмник создаю в конструкторе диалогового окна:
Код
C++ (Qt)
   m_receiver = new Receiver( ui->portNameComboBox->currentText( ) );
 
   try {
       m_receiver->run( );
   } catch( const PortError &e ) {
       QMessageBox::critical( this, "Error", QString( e.what( ) ) );
   } catch( ... ) {
       QMessageBox::critical( this, "Error", "Error: unknown exception" );
   }
 
   connect( m_receiver, SIGNAL( receiverData( QByteArray ) ), this, SLOT( showData( QByteArray ) ) );
 


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 28, 2014, 05:04
Я уже с остывшим любопытством наблюдаю - во что может вылиться отсутствие навыков чтения документации. Судя по всему - очень страшные вещи случаются.
Я только и делаю, что читаю документацию и примеры смотрю. Другое дело, что тому кто работал с портом очевидны с первого взгляда логические ошибки в коде.

Обсервер, ты начинаешь понимать всю тяжесть фриланса для начинающего программиста?
Я уже давно понял, что главное много писать и руки выпрямлять :)

Напишите, пожалуйста, в каком конкретном месте есть ошибки (подводные камни работы с COM-портом)? К примеру, то что я обрабатываю исключения в конструкторе диалогового окна - это нормально?


Название: Re: Знакомство с последовательным портом
Отправлено: 8Observer8 от Май 28, 2014, 09:03
На данный момент ты имеешь "удачу" что твой Sender что-то передает (кстати, благодаря багу, который исправлен в Qt 5.3.1). После обновления на  Qt 5.3.1 у тебя ничо работать не будет (как и в *.nix). Да и что ты все выдумываешь то? Посмотри уже примеры от QtSerialPort... :)

Самый главный вопрос: почему мой Sender не будет работать в Qt 5.3.1? Хотя бы намекните :) Может ответ в примерах, но я пока не нашёл.


Название: Re: Знакомство с последовательным портом
Отправлено: Hellraiser от Май 28, 2014, 09:10
А вот (https://qt.gitorious.org/qt/qtserialport/commit/b749c9dc00f22ecfcf4be6684b3596b20f7ae0c4) почему.