Introdução
No terceiro ano, comecei a praticar em uma das empresas do setor doméstico de foguetes e espaço. Eu era um estagiário ambicioso e bastante ativo
até ver o trabalho de rotina em uma empresa estatal russa e, a meu pedido, fui designado para o departamento envolvido no desenvolvimento
de equipamentos de teste (a seguir
KPA ). A propósito, grande parte do desenvolvimento do
CPA está escrevendo a parte do software para o equipamento. Incluindo, para verificar o hardware que está sendo desenvolvido, o departamento possui vários
dispositivos de controle e medição , todos eles conectados a uma rede comum. Como resultado, uma das minhas primeiras tarefas foi escrever um aplicativo para controlar um gerador de sinal.
Isso será discutido no artigo.
Iniciar
Todos os aplicativos no departamento são desenvolvidos usando C ++ e a biblioteca Qt. Eu tinha experiência com essa estrutura, então não havia dificuldades neste lado. Além disso, o Qt possui documentação extensa e você sempre pode
copiar e colar o código do StackOverflow para consultar um curador.
Como todos os dispositivos estão conectados à mesma rede, a questão de como se conectar a eles também foi resolvida muito rapidamente - usamos a parte de rede do Qt na forma de QTcpSocket.
A questão mais interessante surgiu quando tive que decidir exatamente como me comunicar com esses dispositivos, como ativar uma ou outra função, para transferir um ou outro valor. Aconteceu que tudo é bastante trivial: existe um protocolo de comandos padrão para instrumentos programáveis - SCPI. Ele permite o uso de comandos padrão para controlar quaisquer dispositivos que suportem esse padrão.
Comece a codificar
Tudo é padrão e desinteressante no arquivo de cabeçalho:#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
Foi decidido fazer a interface assim:

É bastante simples e intuitivo. Nas edições de duas linhas, o host e a porta do dispositivo são definidos na parte superior. Também é possível selecionar valores padrão, e eles terão o seguinte formato:
port = 5025; host = "192.168.1.109";
A seguir, é apresentada a caixa de texto do log, a resposta do dispositivo (os erros serão enviados para lá, se houver). Um pouco mais baixos são os botões para conectar ao dispositivo, enviar um comando, verificar erros. Nas últimas três edições de linha, você pode definir seu próprio comando e enviá-lo ao dispositivo ou definir separadamente a frequência e a amplitude. O botão de opção à direita liga / desliga a saída de RF. O botão giratório ajusta a frequência quando a caixa de seleção está desativada e a amplitude quando ativada.
Continuamos e terminamos
Toda a diversão começa no arquivo .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" ); } }
Depois de ler
Entendo que o artigo pode parecer divorciado da vida e da realidade para um grande número de leitores, mas o controle remoto da instrumentação no campo da engenharia é um tópico bastante comum que traz muitos benefícios e conveniência (por exemplo, você não precisa correr para dispositivos e pressionar botões) .
De resto, este artigo é de natureza informativa e divertida e visa mais provavelmente entusiastas e pessoas envolvidas no desenvolvimento e teste de placas e outros hardwares. Gostaria apenas de contar ao resto sobre minha pouca experiência no desenvolvimento de software para fins específicos.