Enviar carácteres con un botón por el puerto serial
-
Buen día, estoy intentando enviar simples carácteres por el puerto serial presionando botones en una GUI pero no sé como programar el puerto serial, ya revisé los pocos ejemplos que incluye la IDE pero son algo rebuscados para lo que necesito.
Alguien me podría dar un código de ejemplo para mandar la letra "a" con un botón al puerto "COM3".
Gracias. -
Si vas a usar una GUI a la par que el puerto serie puedes tener problemas. El puerto serie te va a bloquear la interfaz de usuario mientras esté recibiendo o enviando datos.
No es un problema si envías o recibes pocos datos o con grandes intervalos de tiempo. En ese caso puedes tenerlo todo junto.
Si no quieres que te pase eso, la programación de la GUI y la del puerto la separas. Ejecuta el puerto serie en un hilo diferente y comunica ambos (GUI y puerto serie) mediante señales y slots.
Es muy sencillo. Cuando pulses el botón haz que se lance una señal con la cadena que quieras enviar como argumento. Esa señal debe estar conectada al slot de la clase que maneja el puerto serie y que se ejecuta en un hilo diferente.
El slot llama al método enviar datos por el puerto serie y le pasa la cadena. Esperas a recibir respuesta si quieres y cuando la recibas o se supere el tiempo de espera, lanzas otrá señal con los datos recibidos como respesta. Esta señal la conectas a un slot de la clase que maneja la GUI. Cuando se ejecute este ultimo slot, muestras en la interfaz gráfica la respuesta que has recibido por el puerto serie.
| ----> EnviaEsto("miCadena") -------> | GUI | | PUERTO_SERIE | <----- HeRecibido("estaRespuesta") <---- | hilo principal segundo hilo
/* * Para configurar el puerto serie. Tendrás que meterlo en la clase que crees para ejecutarlo en * un hilo diferente al de la GUI */ portSerial = new QSerialPort; portSerial->setPortName(comUART); if(!portSerial->open(QIODevice::ReadWrite)) { qDebug() << " Error al abrir en modo lectura y escritura"; return; } if(!portSerial->setBaudRate(baudrate)) { qDebug() << " Error al establecer la velocidad de transmisión"; } if(!portSerial->setDataBits(QSerialPort::Data8)) { qDebug() << " Error al establecer el tamaño de los datos"; } if(!portSerial->setStopBits(QSerialPort::OneStop)) { qDebug() << " Error al establecer el bit/s de parada"; } if(!portSerial->setParity(QSerialPort::EvenParity)) { qDebug() << " Error al establecer la paridad"; } if(!portSerial->setFlowControl(QSerialPort::NoFlowControl)) { qDebug() << " Error al configurar el control de flujo"; } // Código para enviar datos. Tan simple como esto: bytesWritten = portSerial->write("datos_a_enviar"); // Mira la documentación para ver el tipo de datos // Código para leer datos. Igual de simple: if (portSerial->waitForReadyRead(timeofwait)) { buffer = portSerial->readAll(); }
El código que te acabo de poner tendrás que meterlo en los métodos correspondientes que crees. No hace falta configurar el puerto serie cada vez que quieras eviar algún dato... por ejemplo.
Para más información de todas las opciones que tiene QSerialPort mira la documentación oficial.
Espero que te ayude
-
@Jonathan77 Hola, tengo otras pequeñas dudas con el programa,¿ donde debo configurar el puerto serial en el main.cpp o en el mainwindow.cpp? si lo configuro en el main.cpp como conecto los datos que mande con los botones que estan en el mainwindow.cpp con el puerto que esta en main.cpp.
Es decir si en el mainwindow.cpp pongo;void MainWindow::boton_clicked() { serial->write ("hola"); }
lo mande al main.cpp que es donde esta configurado el serial
#include "mainwindow.h" #include <QApplication> #include <QTextStream> #include <QCoreApplicatio> #include <QtCore> #include <QStringList> #include <QIODevice> #include <iostream> #include <QtSerialPort/QSerialPort> #include <QElapsedTimer> QT_USE_NAMESPACE int main(int argc, char *argv[]) { QElapsedTimer timer; QApplication a(argc, argv); MainWindow w; QSerialPort serial; serial.setPortName ("COM3"); serial.open (QIODevice::ReadWrite); serial.setBaudRate (QSerialPort::Baud9600); serial.setDataBits (QSerialPort::Data8); serial.setParity(QSerialPort::NoParity); serial.setStopBits (QSerialPort::OneStop); serial.setFlowControl (QSerialPort::NoFlowControl); QByteArray output; return a.exec(); }
ya intente configurar el puerto serial en el mainwindow.cpp pero no lo compila
me podrias dar un ejemplo que haga esto por favor -
Yo personalmente, cada cual lo puede hacer de forma diferente, lo que haría sería crearme una clase que contenga la configuración y los métodos del puerto serie.
Se puede hacer en archivos diferentes si quieres. Así en el futuro podrás reutilizarlo.
Por ejemplo:
class mySerial:public QObject { Q_OBJECT public: mySerial(); ~mySerial(); public slots: void sendData(QString data); signals: void receibedData(QString data); private: // los métodos privados que quieras };
En el mainwindow.cpp en el constructor o en alguna función que se vaya ejecutar antes de usar el puerto serie por primera vez (con ejecutarla una vez basta):
QThread *miOtroHilo = new QThread; mySerial *serie = new mySerial; // Movemos el objeto 'serie' al "otro" hilo de ejecución mySerial->moveToThread(miOtroHilo); // Señales que conectan tu interfaz gráfica con el objeto "puerto serie" connect(this, SIGNAL(botonPulsado(QString), serie, SLOT(sendData(QString)); connect(serie, SIGNAL(receibedData(QString), this, SLOT(receptorGUI(QString)); // Las otras señales que necesites para manejar el otro hilo. miOtroHilo->start(); // inicio del hilo que ejecuta el puerto serie
Más o menos es lo que necesitas hacer a groso modo.
En la documentación oficial puedes encontrar toda la información sobre los hilos tal. Hay unos cuantos ejemplos. Lo que te puesto de ejemplo también se puede hacer de otras no te limites solo a este ejemplo.
Lo complicado de la programación no es aprender un lenguaje o "framework" concreto sino el saber cómo hacer las cosas... yo sigo aprendiendo cada día.
Suerte! y ya nos cuentas como te va.
-
@Jonathan77 Buenas la verdad que estoy muy interesado en lo que has puesto, pero no entiendo muy bien el significado, no se si el hilo secundario se actualiza cíclicamente o por el contrario solo cuando enviamos o recibimos datos. Esto es lo que mas me interesa pues estoy desarrollando una interfaz gráfica para un programa de control.
Lo que querría es que leyera continuamente los puertos para actualizar la información de los sensores y del control en la GUI. Y solo envíar datos al micro cada vez que pulsaramos la interfaz.Para ello había pensado tener unos timer que fueran leyendo el puerto en el hilo secundario(para así poder monitorizar la interfaz en el primario) y poder refrescar la comunicación continuamente. Pero nose si el hilo secundario es cíclico o tengo que hacerlo yo ciclico con los timer.
El bucle de control se realizará en un PLC de arduino. También habia pensado en comunicar un inversor con el Qt mediante Modbus TCP, pero creo que no hay librerias en Qt que lo permitan.Nose si me he explicado bien.
Muchas gracias