Introducción
En el tercer año, llegué a practicar en una de las empresas de la industria nacional de cohetes y espacio. Era un interno ambicioso y bastante activo
hasta que vi la rutina en una empresa estatal rusa y, a petición mía, me asignaron al departamento involucrado en el desarrollo de
equipos de
control y prueba (en adelante
CPA ). Por cierto, una gran parte del desarrollo del
CPA es la redacción de la parte de software para el equipo. Incluyendo, para verificar el hardware que se está desarrollando, el departamento tiene varios
dispositivos de control y medición , todos ellos conectados a una red común. Como resultado, como una de mis primeras tareas fue escribir una aplicación para controlar un generador de señal.
Esto se discutirá en el artículo.
Inicio
Todas las aplicaciones en el departamento se desarrollan utilizando C ++ y la biblioteca Qt. Tenía experiencia con este marco, por lo que no hubo dificultades en este lado. Además, Qt tiene una extensa documentación, y siempre puede
copiar y pegar el código de StackOverflow para consultar a un curador.
Dado que todos los dispositivos están conectados a la misma red, la cuestión de cómo conectarse a ellos también se resolvió muy rápidamente: utilizamos la parte de red de Qt en forma de QTcpSocket.
La pregunta más interesante surgió cuando tuve que decidir cómo comunicarme con estos dispositivos, cómo activar una u otra función, transferir uno u otro valor. Luego resultó que todo es bastante trivial: hay un protocolo de comandos estándar para instrumentos programables: SCPI. Permite usar comandos estándar para controlar cualquier dispositivo que admita este estándar.
Comience a codificar
Todo es estándar y poco interesante en el archivo de encabezado:#ifndef SIGGENCONTROL_H #define SIGGENCONTROL_H #include <QMainWindow> #include <QTcpSocket> #include <QString> namespace Ui { class sigGenControl; } class sigGenControl : public QMainWindow { Q_OBJECT public: explicit sigGenControl(QWidget *parent = 0); ~sigGenControl(); // , QString host; //= "192.168.1.109"; ip int port;// = 5025; void clearErr(); // bool rfOn; // bool pset = false; bool hset = false; private: Ui::sigGenControl *ui; QTcpSocket* socket; private slots: //, .cpp void connectToHostSlot(); void sendToHostSlot(); void readyReadSlot(); void setFreq(); void setPow(); void activateRF(); void checkErrSlot(); void setPort(); void setHost(); void setDefault(); void dialValChangedSlot(); }; #endif // SIGGENCONTROL_H
Se decidió hacer la interfaz así:

Es bastante simple e intuitivo. En las dos ediciones de línea, el host y el puerto del dispositivo se configuran en la parte superior. También es posible seleccionar valores estándar, luego tomarán la siguiente forma:
port = 5025; host = "192.168.1.109";
El siguiente es el cuadro de texto para el registro, la respuesta del dispositivo (los errores se enviarán allí, si corresponde). A continuación hay botones para conectarse al dispositivo, enviar un comando y verificar errores. En las últimas tres ediciones de línea, puede configurar su propio comando y enviarlo al dispositivo, o configurar por separado la frecuencia y la amplitud. El botón de radio a la derecha enciende / apaga la salida de RF. El control giratorio ajusta la frecuencia cuando la casilla de verificación está desactivada y la amplitud cuando se activa.
Continuamos y terminamos
Toda la diversión comienza en el archivo .cpp: #include "siggencontrol.h" #include "ui_siggencontrol.h" #include "qdebug.h" #include <QTime> sigGenControl::sigGenControl(QWidget *parent) : QMainWindow(parent), ui(new Ui::sigGenControl) { ui->setupUi(this); ui->history->setReadOnly(true); ui->history->setText("host : not set\nport : not set"); ui->history->append(QTime::currentTime().toString() + " : No connection"); socket = new QTcpSocket(this); // // - // , // connect(ui->connPb,QPushButton::clicked,this,sigGenControl::connectToHostSlot); connect(ui->sendToHostPb,QPushButton::clicked,this,sigGenControl::sendToHostSlot); connect(ui->input,QLineEdit::returnPressed,this,sigGenControl::sendToHostSlot); connect(socket,QTcpSocket::readyRead,this,sigGenControl::readyReadSlot); connect(ui->freqEdit,QLineEdit::returnPressed,this,sigGenControl::setFreq); connect(ui->amptdEdit,QLineEdit::returnPressed,this,sigGenControl::setPow); connect(ui->radioButton,QRadioButton::clicked,this,sigGenControl::activateRF); connect(ui->errPb,QPushButton::clicked,this,sigGenControl::clearErr); connect(ui->hostEdit,QLineEdit::returnPressed,this,sigGenControl::setHost); connect(ui->portEdit,QLineEdit::returnPressed,this,sigGenControl::setPort); connect(ui->checkBox,QCheckBox::clicked,this,sigGenControl::setDefault); connect(ui->dial, QDial::valueChanged,this,sigGenControl::dialValChangedSlot); ui->hist->setReadOnly(true); QString deactRF = ":OUTP 0\n"; // SCPI , socket->write(deactRF.toLocal8Bit()); // this->rfOn = false; // ui->input->setReadOnly(true); ui->freqEdit->setReadOnly(true); ui->amptdEdit->setReadOnly(true); ui->radioButton->setEnabled(false); ui->sendToHostPb->setEnabled(false); ui->errPb->setEnabled(false); ui->connPb->setDisabled(true); } sigGenControl::~sigGenControl() { delete ui; } void sigGenControl::connectToHostSlot(){ socket->connectToHost(host,port); // // qDebug() if (socket->waitForConnected(1000)) qDebug("Connected!"); ui->history->append(QTime::currentTime().toString() + " : Connected"); // ui->input->setReadOnly(false); ui->freqEdit->setReadOnly(false); ui->amptdEdit->setReadOnly(false); ui->radioButton->setEnabled(true); ui->sendToHostPb->setEnabled(true); ui->errPb->setEnabled(true); ui->input->setText("*IDN?"); // } void sigGenControl::sendToHostSlot(){ // socket->write(ui->input->text().toLocal8Bit()+"\n"); } void sigGenControl::readyReadSlot(){ // qDebug("ready read!"); QByteArray dataArr; // dataArr = socket->readAll(); // ui->hist->append(QTime::currentTime().toString() + " " + dataArr); } void sigGenControl::clearErr(){ // , , , QString errTxt = ":SYST:ERR?\n"; socket->write(errTxt.toLocal8Bit()); } void sigGenControl::setFreq(){ QString fr = " kHz"; QString cmd = ":FREQ "; // QString command = cmd+ui->freqEdit->text()+fr+"\n"; // qDebug() << command; socket->write(command.toLocal8Bit()); // } void sigGenControl::setPow(){ QString amp = " dBm"; QString cmd = ":POW "; // socket->write(cmd.toLocal8Bit() + ui->amptdEdit->text().toLocal8Bit() + amp.toLocal8Bit() + "\n"); // } void sigGenControl::activateRF(){ // // QString actRF = ":OUTP 1\n"; // QString deactRF = ":OUTP 0\n"; // if(this->rfOn == false){ socket->write(actRF.toLocal8Bit()); rfOn = true; }else{ socket->write(deactRF.toLocal8Bit()); rfOn = false; } } void sigGenControl::checkErrSlot(){ clearErr(); } void sigGenControl::setHost(){ // this->host = ui->hostEdit->text(); ui->history->append("host: " + host); ui->checkBox->setEnabled(true); hset = true; // if((pset && hset) == true){ ui->connPb->setEnabled(true); } } void sigGenControl::setPort(){ // this->port = ui->portEdit->text().toInt(); ui->history->append("port: " + QString::number(port)); ui->checkBox->setEnabled(true); pset = true; // if((pset && hset) == true){ ui->connPb->setEnabled(true); } } void sigGenControl::setDefault(){ // port = 5025; host = "192.168.1.109"; ui->history->append(QTime::currentTime().toString() + " " + "host: " + host); ui->history->append(QTime::currentTime().toString() + " " + "port: " + QString::number(port)); ui->checkBox->setDisabled(true); ui->connPb->setEnabled(true); ui->hostEdit->setText(host); ui->portEdit->setText(QString::number(port)); } void sigGenControl::dialValChangedSlot(){ // , qDebug()<< "value : " << ui->dial->value(); if(ui->amplCheckBox->isChecked() == false){ // , ui->dial->setMinimum(100); ui->dial->setMaximum(20000000); QString fr = " kHz"; QString cmd = ":FREQ "; // QString command = cmd+QString::number(ui->dial->value())+fr+"\n"; qDebug() << command; socket->write(command.toLocal8Bit()); ui->label->setText("FREQUENCY :" + QString::number(ui->dial->value()) + " kHz" ); }else if(ui->amplCheckBox->isChecked() == true){ // , ui->dial->setMinimum(-130); ui->dial->setMaximum(15); QString pw = " dBm"; QString cmd = ":POW "; // QString command = cmd+QString::number(ui->dial->value())+pw+"\n"; qDebug() << command; socket->write(command.toLocal8Bit()); ui->label->setText("AMPLITUDE :" + QString::number(ui->dial->value()) + " dBm" ); } }
Despues de leer
Entiendo que el artículo puede parecer divorciado de la vida y la realidad para una gran cantidad de lectores, pero el control remoto de la instrumentación en el campo de la ingeniería es un tema bastante común que brinda muchos beneficios y conveniencia (por ejemplo, no es necesario ejecutar dispositivos y presionar botones) .
Por lo demás, este artículo es de naturaleza informativa y entretenida y está dirigido más probablemente a los entusiastas y a las personas involucradas en el desarrollo y prueba de tableros y otro hardware. Solo me gustaría contarles al resto sobre mi poca experiencia en el desarrollo de software para fines tan específicos.