I am trying to adapt a c++ program to work with my DC Load
in the program I have 2 measure lines
port.write("MEAS:CURR?/r");
port.write("MEAS:VOLT?/r");
Is there a way to append an "A" to the current output when being read that is easy? (I am a total programming noob)
The reason why is that later in the program it's looking for this "A". The load it was originally used for gave its measurements with the unit (V, A), but my load just returns numbers for each.
double value = 0;
bool isCurrent = false;
QString tmp = port.readAll();
tmp = tmp.left(tmp.length() - 1);
if (tmp.at(tmp.length() - 1) == 'A')
isCurrent = true;
Thank you everyone who replied.
ledtester I will look at sprintf and see what it does. Part of this process is to force me to learn and c++ might not be the best first choice but this program does exactly what I want but for another similar device.
AlfBaz
I was looking at QString obviously because it's already in there. the /r and /n don't get returned in the output they are jus CR and newline
The output from those commands both look like this
OK
XX.XXXX
With the X representing a numeral
langwadt
I have to have some wqay to differentiate the amerage and the voltage. If V = 0 or V= (X) a variable I set the program terminates the test and graphs the results.
When the test starts it reads it can't tell V from A , of course A = 0 at the start of the test so it terminates.
I guess I should show the code, I got it on github
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string>
void MainWindow::update()
{
//qDebug() << "On timer";
port.write("MEAS:CURR?/r");
port.write("MEAS:VOLT?/r");
time.start();
}
void MainWindow::readyRead()
{
int addms = time.elapsed();
double value = 0;
bool isCurrent = false;
QString tmp = port.readAll();
tmp = tmp.left(tmp.length() - 1);
if (tmp.at(tmp.length() - 1) == 'A')
isCurrent = true;
value = tmp.left(tmp.length() - 1).toDouble();
if (isCurrent)
{
lastCurrent = value;
if (lastCurrent > highestCurrent)
highestCurrent = lastCurrent;
return;
} else
if (value <= ui->sbCutVolts->value())
{
on_btnStop_clicked();
QMessageBox msgBox;
msgBox.setText("Measurement finished.");
msgBox.setInformativeText(QString("Voltage %1 reached cut value %2. Result is: %3mAh").arg(value).arg(ui->sbCutVolts->value()).arg(ah));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
return;
}
lastVoltage = value;
if (value > highestVolt)
highestVolt = value;
ah += ((lastCurrent * (1 + addms / 1000)) / 60 / 60) * 1000;
seriesVolts->append(ah, lastVoltage);
seriesCurrent->append(ah, lastCurrent);
axisX->setRange(-2, ah + 2);
axisY->setRange(ui->sbCutVolts->value(), highestVolt + 0.5);
axisY2->setRange(0, highestCurrent + 0.5);
ui->lblResult->setText(QString("%1 mAh").arg(ah));
timer->start();
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ah = 0;
highestVolt = 0;
highestCurrent = 0;
lastCurrent = 0;
lastVoltage = 0;
for (int i = 0; i < QSerialPortInfo::availablePorts().count(); i++)
ui->cbPort->addItem(QSerialPortInfo::availablePorts().at(i).portName());
timer = new QTimer(this);
timer->setInterval(1000);
timer->setSingleShot(true);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
connect(&port, SIGNAL(readyRead()), this, SLOT(readyRead()));
QChart *chart = new QChart();
seriesVolts = new QLineSeries();
seriesVolts->setName("Battery voltage");
seriesCurrent = new QLineSeries();
seriesCurrent->setName("Battery current");
chart->addSeries(seriesVolts);
chart->addSeries(seriesCurrent);
chart->setTitle("Discharge chart");
axisX = new QValueAxis;
axisX->setTitleText("Capacity (mAh)");
chart->addAxis(axisX, Qt::AlignBottom);
seriesVolts->attachAxis(axisX);
seriesCurrent->attachAxis(axisX);
axisY = new QValueAxis;
axisY->setLabelFormat("%.2f");
axisY->setTitleText("Voltage (V)");
chart->addAxis(axisY, Qt::AlignLeft);
seriesVolts->attachAxis(axisY);
axisY2 = new QValueAxis;
axisY2->setLabelFormat("%.2f");
axisY2->setTitleText("Current (A)");
chart->addAxis(axisY2, Qt::AlignRight);
seriesCurrent->attachAxis(axisY2);
chartView = new QChartView(chart);
ui->verticalLayout->insertWidget(1, chartView);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnStart_clicked()
{
ah = 0;
highestVolt = 0;
lastCurrent = 0;
lastVoltage = 0;
ui->lblResult->setText("0");
seriesVolts->clear();
seriesCurrent->clear();
port.write(":INPUT OFF\n");
port.write(":CURR 0\n");
port.write(":MODE CC\n");
port.write(QString(":CURR %1\n").arg(double(ui->sbCurrent->value()) / 1000).toStdString().c_str());
port.write(":INPUT ON\n");
timer->start();
ui->btnStop->setEnabled(true);
ui->btnStart->setEnabled(false);
}
void MainWindow::on_btnOpen_clicked()
{
port.setPortName(ui->cbPort->currentText());
port.setBaudRate(QSerialPort::Baud115200);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setStopBits(QSerialPort::OneStop);
port.setFlowControl(QSerialPort::NoFlowControl);
port.open(QSerialPort::ReadWrite);
if (port.isOpen())
{
ui->btnOpen->setEnabled(false);
ui->btnClose->setEnabled(true);
ui->btnStart->setEnabled(true);
}
}
void MainWindow::on_btnClose_clicked()
{
on_btnStop_clicked();
Sleep(1000);
port.close();
if (port.isOpen() == false)
{
ui->btnOpen->setEnabled(true);
ui->btnClose->setEnabled(false);
ui->btnStart->setEnabled(false);
}
}
void MainWindow::on_btnStop_clicked()
{
timer->stop();
port.write(":INPUT OFF\n");
port.write(":CURR 0\n");
port.write(":MODE CC\n");
port.write(":INPUT OFF\n");
ui->btnStart->setEnabled(true);
ui->btnStop->setEnabled(false);
}
void MainWindow::on_btnRequest_clicked()
{
}
Example output from a terminal
I was mainly interested to see how port was declared.
line 58 QSerialPort port;
The QString tmp = port.readAll(); reads directly from your DC Load.
It appears the DC Load just returns the value without any indication of what was requested???
The update() requests both current and voltage values and then waits for a response from the DC Load of both values.
void MainWindow::update()
{
port.write(":MEAS:CURR?\r\n");
port.write(":MEAS:VOLT?\r\n");
}
You really need to separate these two requests and keep track of each request.
Request the current and wait for response. Then, request the voltage and wait for that response.
Probably the best way would be to setup a flag of what the request was in the update() and then clear that flag in the readyRead().
(i.e. The update() function would alternate its requests and insuring a response.)
void MainWindow::readyRead()
{
if (tmp.at(tmp.length() - 1) == 'A')
isCurrent = true;
if (isCurrent)
{
} else
if (value <= ui->sbCutVolts->value())
{
}
}
Replace isCurrent with an enumeration flag
(i.e. flag is 0=none, 1=current, 2=current_received, 3=voltage, 4=voltage_received).
void MainWindow::update()
{
if (flag==0 || flag==4) {
port.write(":MEAS:CURR?\r\n");
flag = 1;
}
else if (flag==2) {
port.write(":MEAS:VOLT?\r\n");
flag = 3;
}
}
void MainWindow::readyRead()
{
QString tmp = port.readAll();
switch (flag)
{
case 1: // Current
flag = 2;
break;
case 3: // Voltage
flag = 4;
break;
}
timer->start();
}
MarkF
This was very helpful, thank you. My program is still not working correctly but I am learning a lot.
Most of the issues now stem from the fact that when I query the load it always answers with an "OK", sometimes twice before it returns the value I want.
Probably should try to redo this in Python, but even as a noob the whitespace thing drives me crazy :)
I am going to contact Amrel and see if there is a way to suppress the OK message as it is really unnecessary. There is no way to do it listed in documentation.
Just ignore the 'OK' response and continue waiting.
Or check the response for 'isNumber()'. (This may not be the exact function name. It's been a long time since I've used Qt.)
void MainWindow::readyRead()
{
QString tmp = port.readAll();
if (tmp != "OK") { // you might need to fix this syntax here
switch (flag)
{
case 1: // Current
flag = 2;
break;
case 3: // Voltage
flag = 4;
break;
}
}
timer->start();
}