从QT中的串行端口阅读时输出异常
Abnormal output when reading from serial port in QT
我正在使用qt和 QCustomPlot
来创建一个实时绘图工具,并且从Arduino Uno板上读取绘图的数据。当数据完全混乱时,我的应用程序成功地绘制了。这是我下面的代码(某些代码来自qcustomplot网站):
void Dialog::realtimeDataSlot()
{
bool currentPortNameChanged = false;
QString currentPortName;
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
}
QString currentRequest = request;
QSerialPort serial;
if (currentPortNameChanged) {
serial.close();
serial.setPortName(currentPortName);
if (!serial.open(QIODevice::ReadOnly)) {
return;
}
}
static QTime time(QTime::currentTime());
// calculate two new data points:
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{
// add data to lines:
if(serial.waitForReadyRead(-1)){
data = serial.readAll();
QTextStream(stdout) << "HERE:" << data.toDouble() << endl;
customPlot->graph(0)->addData(key, data.toDouble());
customPlot->graph(0)->rescaleValueAxis(); //rescale value (vertical) axis to fit the current data:
lastPointKey = key;
customPlot->xAxis->setRange(key, 8, Qt::AlignRight);
customPlot->replot();
static double lastFpsKey;
static int frameCount;
++frameCount;
if (key-lastFpsKey > 2) // average fps over 2 seconds
{
lastFpsKey = key;
frameCount = 0;
}
}
}
// calculate frames per second:
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
} else {
currentPortNameChanged = false;
}
}
当我尝试打印出从串行端口读取的数据时,我找到了以下内容:
HERE:1
HERE:15
HERE:150
HERE:149
HERE:149
HERE:149
HERE:150
HERE:150
HERE:15
HERE:150
HERE:149
HERE:49
HERE:150
HERE:150
HERE:1
HERE:150
值约150的值是正常的,而其他值为0,其他值则不是。另外,它不会以稳定的速度打印出来。我不知道发生了什么事,感谢任何人可能会有所帮助,如果有更好的方法可以实施此事,我将不胜感激。
这里的问题是不能保证一次收到串行传输。因此,最好让串行在其他地方进行处理:
// in the class definition
QSerialPort serialPort;
private slots:
void handleReadyRead();
private:
QByteArray serialBuffer;
volatile double lastSerialValue;
// In the initialization part (not the realtimeDataSlot function)
lastSerialValue = qQNaN();
serialPort.setPortName(currentPortName);
connect(&serialPort, &QSerialPort::readyRead, this, &Dialog::handleReadyRead, Qt::UniqueConnection);
if (!serialPort.open(QIODevice::ReadOnly)) {
return;
}
serialBuffer.clear();
// Other functions:
void Dialog::realtimeDataSlot()
{
...
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{
if (!qIsNaN(lastSerialData))
{
// use lastSerialValue as the data.toDouble() you had before, then, at the end
lastSerialValue = qQNaN();
}
...
}
void Dialog::handleReadyRead()
{
serialBuffer.append(serialPort.readAll());
int serPos;
while ((serPos = serialBuffer.indexOf('n')) >= 0)
{
bool ok;
double tempValue = QString::fromLatin1(serialBuffer.left(serPos)).toDouble(&ok);
if (ok) lastSerialValue = tempValue;
serialBuffer = serialBuffer.mid(serPos+1);
}
}
说明:每当您从Arduino那里收到某些内容时,字节就会附加到缓冲区。然后将字节数组解析为寻找终结器,如果发现字节阵列将被拆分并分析。当另一个功能需要数据时,它只是将最新的一个保存在变量中。
。注意1:我看到您使用了二进制传输。问题在于您没有任何方法可以以这种方式确定数据的开始和结束。例如,如果您收到0x01 0x02 0x03 0x04,并且您知道有3个字节,它们是01..03或02..04或03、04和一个缺失的或...吗?我实施的版本要求您使用新线终结器以字符串格式发送数据(最简单的版本,您只需在Arduino代码中编写Serial.println(doubleValue);
),但是如果您需要二进制版本,我可以给您一些提示
注2:我编写的代码不是线程安全的。仅当Realtimedataslot和HandlereDyread在同一线程中调用时才起作用。请注意,如果它们属于同一对象并通过信号调用,则可以保证。
现在,这应该起作用。但是我极大地阻止您这样做。我不知道谁需要致电realtimeDataSlot()
,但我认为最正确的版本就是这样:
// in the class definition
QSerialPort serialPort;
private slots:
void handleReadyRead();
void receivedData(double val);
private:
QByteArray serialBuffer;
signals:
void newData(double data);
// In the initialization part (not the realtimeDataSlot function)
serialPort.setPortName(currentPortName);
connect(&serialPort, &QSerialPort::readyRead, this, &Dialog::handleReadyRead, Qt::UniqueConnection);
connect(this, &Dialog::newData, this, &Dialog::receivedData, Qt::UniqueConnection);
if (!serialPort.open(QIODevice::ReadOnly)) {
return;
}
serialBuffer.clear();
// Other functions:
void Dialog::receivedData(double val)
{
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{
QTextStream(stdout) << "HERE:" << data.toDouble() << endl;
customPlot->graph(0)->addData(key, data.toDouble());
customPlot->graph(0)->rescaleValueAxis();
...
}
}
void Dialog::handleReadyRead()
{
serialBuffer.append(serialPort.readAll());
int serPos;
while ((serPos = serialBuffer.indexOf('n')) >= 0)
{
bool ok;
double tempValue = QString::fromLatin1(serialBuffer.left(serPos)).toDouble(&ok);
if (ok) emit newData(tempValue);
serialBuffer = serialBuffer.mid(serPos+1);
}
}
因此,将图表保持对事件的响应(已接收到新数据),而不是对计时器。
还有一件事:我故意删除了端口更改。我建议您以另一种方式处理它:放一个按钮启动并停止串行,并且启动串行端口时,请阻止用户更改端口名称。这样,用户需要明确需要在需要更改端口时将其关闭。但是,如果您需要版本,请不要将其包含在代码中,而是要在需要更改端口名称时单独使用插槽来打电话:
void changeSerialPortName(QString newName)
{
if (newName != serialPort.portName()) {
if (serialPort.isOpen())
serialPort.close();
serialPort.setPortName(newName);
if (!serialPort.open(QIODevice::ReadOnly)) {
return;
}
}
}
- C++ 异常处理错误输出
- std::out_of_range异常奇怪的输出
- 是什么导致异常输出以及如何修复
- basic_string::替换的超出范围异常,而在范围内,正如调试相同参数的输出所证明的那样
- 从QT中的串行端口阅读时输出异常
- c++运算符=工作异常(函数内部输出正常,但返回后错误)
- C++日志异常到文件,不同的输出
- C++ 中窗口线程的异常输出
- 在简单的文件处理程序中获得异常输出
- C/C++:在异常终止前刷新输出
- 正在捕获输入和输出文件的异常
- 格式化的输出运算符标准iostream对象可以抛出什么样的异常
- 为什么这是此异常堆栈的输出
- 将char[]传递给另一个函数时出现异常输出
- 打印值0x89(-119)时出现异常输出
- 为什么这个程序不能输出正确的异常?
- Android OpenCV imread 标志致命异常,imread 在没有标志的情况下工作正常,像素输出与 MATLAB 不匹配
- 双指针输出数组参数异常
- c++程序输出整数时异常退出
- 尝试在打开的总账中创建空白窗口时出现异常输出