
Настройка, подключение, чтение символов. Взаимодействие с Arduino через последовательный порт (COM) в Qt. Часть 1
В предыдущих статьях мы рассмотрели установку среды разработки Arduino и загрузку простых скетчей в устройство.
Сегодня мы рассмотрим работу с последовательным портом (COM) в QT5. Соединяться через COM-порт мы будем с Arduino UNO.
Для начала установим среду разработки и драйвера для Arduino.
Мы уже рассматривали, в предыдущих статьях процесс установки под Windows.
Подключим Arduino к ПК. И загрузим на него тестовый скетч Blink.
Изменим скетч, таким образом, чтобы через COM-порт отправлялась информация. В нашем случае это будет ноль раз в одну секунду.
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for a second
Serial.println("0");
}
Загрузим скетч на устройство. В среде разработки выберем Инструменты -> Монитор порта
Как видите, в COM-порт передается некоторая информация.
Проверка отправки данных в COM-порт
Проверим, что операционная система имеет доступ к последовательному порту.
Обязательно закроем Монитор порта.
Запустим Putty
Укажем номер порта, в моем случае это COM4.
Настроем как указано на рисунке, дополнительных настроек на данном этапе не требуется:.
Нажмем Open
Как видите, в COM-порт с устройства передается информация.
Обратите внимание, в Windows к последовательному порту одновременно может обращаться только одна программа. Если вы сейчас, не закрывая Putty, попробуете загрузить новый скетч в Arduino, то получите сообщение об ошибке:
avrdude: ser_open(): can't open device "\\.\COM4": �������� � �������.
Problem uploading to board
Так что вам придется закрывать программу перед заливкой нового скетча или использовать отдельный шилд для подключения к последовательному порту.
Можно использовать виртуальный делитель последовательного порта, но об этом мы поговорим в одной из следующих статей.
Теперь, когда мы уверены, что устройство передает информацию, а операционная система имеет к ней доступ, мы можем приступит к написанию программы на QT5.
Создание проекта в QtCreator
Создадим новый проект Qt Windgets Application
Назовем его
BasicSerial
Откроем файл BasicSerial.pro
Изменим строку
QT += core gui
На
QT += core gui serialport
Обязательно запустим сборку проекта, чтобы инициализировать его с новыми библиотеками!
Добавим в начало файла mainwindows.h:
#include <QSerialPort>
Добавим в класс MainWindow приватное поле
QSerialPort serialPort;
Добавим в конец конструктора
MainWindow::MainWindow(QWidget *parent)
Код:
const QString serialPortName = "COM4";
serialPort.setPortName(serialPortName);
serialPort.setBaudRate(QSerialPort::Baud9600);
bool result = serialPort.open(QIODevice::ReadOnly);
if (!result) {
qDebug() << "Failed to open port: " << serialPortName << ", error: " << serialPort.errorString();
} else {
qDebug() << "Connected to COM4";
}
serialPort.close();
Здесь нет ничего сложного мы создаем экземпляр класса QSerialPort, используемого для работы с последовательным портом.
Задаем имя порта и скорость передачи.
Connected to COM4
И открываем соединения в режиме только для чтения.
Проверяем результат, если он False, то при открытии произошла ошибка, иначе выводим подтверждение подключения.
В конце вызываем метод close() чтобы освободить порт.
Если мы запустим этот код, при запущенном Putty, подключенном к порту COM4 мы получим сообщение
Failed to open port: "COM4" , error: "Отказано в доступе."
При свободном последовательном порте сообщение:
Connected to COM4
Это важно помнить, чтобы не тратить время на поиск причин невозможности подключиться к порту.
Мы успешно подключились к порту COM4, пришла пора прочитать из него данные.
Класс SerialPortManager
Для упрощения инициализации последовательного порта добавим новый класс:
SerialPortManager
Заголовок:
#ifndef SERIALPORTMANAGER_H
#define SERIALPORTMANAGER_H
#include <QSerialPort>
class SerialPortManager
{
public:
SerialPortManager(QString portName,
qint32 baud = QSerialPort::Baud9600,
QSerialPort::DataBits bits = QSerialPort::Data8,
QSerialPort::StopBits sbits = QSerialPort::OneStop,
QSerialPort::Parity parity = QSerialPort::NoParity,
QSerialPort::FlowControl flow = QSerialPort::NoFlowControl);
~SerialPortManager();
QSerialPort *getSerialPort() const;
private:
QSerialPort *serialPort;
QString portName;
};
#endif // SERIALPORTMANAGER_H
Реализация
#include "serialportmanager.h"
#include <QDebug>
SerialPortManager::SerialPortManager(QString portName,
qint32 baud,
QSerialPort::DataBits bits,
QSerialPort::StopBits sbits,
QSerialPort::Parity parity,
QSerialPort::FlowControl flow)
{
this->serialPort = new QSerialPort();
this->portName = portName;
this->serialPort->setPortName(portName);
this->serialPort->setBaudRate(baud);
this->serialPort->setDataBits(bits);
this->serialPort->setStopBits(sbits);
this->serialPort->setParity(parity);
this->serialPort->setFlowControl(flow);
bool result = this->serialPort->open(QIODevice::ReadOnly);
if (!result) {
qDebug() << "Failed to open port: " << this->portName << ", error: " << this->serialPort->errorString();
} else {
qDebug() << "Connected to " << this->portName;
}
}
SerialPortManager::~SerialPortManager()
{
this->serialPort->close();
}
QSerialPort *SerialPortManager::getSerialPort() const
{
return this->serialPort;
}
Я добавил дополнительные параметры для настройки соединения по умолчанию.
Чтобы соединиться с последовательным портом добавим в MainWindow:
private:
SerialPortManager *sm;
Удалим из конструктора класса MainWindow весь добавленный код и добавим:
sm = new SerialPortManager("COM4");
Запустим, результат не изменится!
Читаем данные из COM-порта
Чтобы прочитать данные из последовательного порта, создадим новый класс:
QSerialIO
Заголовок:
#ifndef QSerialIO_H
#define QSerialIO_H
#include <QSerialPort>
class QSerialIO : public QObject
{
Q_OBJECT
public:
explicit QSerialIO(QSerialPort *serialPort, QObject *parent = nullptr);
public slots:
void handleRead();
void handleError(QSerialPort::SerialPortError serialPortError);
private:
QByteArray data;
QSerialPort *serialPort = nullptr;
};
#endif // QSerialIO_H
Реализация:
#include "QSerialIO.h"
#include <QDebug>
QSerialIO::QSerialIO(QSerialPort *serialPort, QObject *parent) :
QObject(parent)
{
this->serialPort = serialPort;
connect(serialPort, SIGNAL(readyRead()), this, SLOT(handleRead()));
connect(serialPort, SIGNAL(errorOccurred(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
}
void QSerialIO::handleRead()
{
QByteArray d = serialPort->readAll();
QString ds = d;
qDebug() << d << ds.simplified();
}
void QSerialIO::handleError(QSerialPort::SerialPortError serialPortError)
{
if (serialPortError == QSerialPort::ReadError) {
qDebug() << "I/O error on port" << serialPort->portName() << serialPort->errorString();
}
}
Чтобы работа с портом не блокировала программу мы используем слоты, подключаемые к сигналам класса QSerialPort.
Таким образом, обработчики вызываются только в том случае, если из порта прочитаны данные.
Добавим в MainWindow:
QSerialIO *serialRdr;
Добавим в конец конструктора класса MainWindow строку:
serialRdr = new QSerialIO(sm->getSerialPort());
Запустим:
Connected to "COM4"
"0\r\n0\r\n" "0 0"
"0\r\n" "0"
"0\r\n" "0"
"0\r\n" "0"
"0\r\n" "0"
"0\r\n" "0"
Обратите внимание, в зависимости от скорости запуска или загруженности системы в момент запуска, у вас в первой строке может быть выведено следующее:
"0\r\n0\r\n" "0 0"
Это происходит из-за того, что между соединением к порту и запуском обработчика проходит больше 1 секунды. В результате класс QSerialPort успевает принять два символа через последовательный порт до того, как программа начинает считывать их из буфера.
Сегодня мы не будем рассматривать, как с этим бороться, в данным момент это не принципиально.
Вот и всё, мы написали программу, которая считывает данные из последовательного (COM) порта.
Заключение
Сегодня мы рассмотрели подключение к последовательному порту в QT5 к Arduino.
Установили среду разработки Arduino.
Загрузили в Arduino скетч выводящий 0 в последовательный порт.
Проверили работу скетча с помощью putty.
Создали новый проект в QT5.
Добавили в него поддержку serialport.
Добавили код для инициализации соединения с COM-портом.
Проверили статус соединения.
Добавили класс SerialPortManager для облегчения работы с последовательным портом.
Добавили класс QSerialIO в котором реализовали чтение вывод в консоль строк, отправленных с Arduino.
Запустили и проверили, что программа действительно читает данные из последовательного порта.
В следующей части мы усовершенствуем класс QSerialIO – добавим поддержку сигналов и слотов.
Скачать исходный код вы можете с GitFlic
Добавить комментарий