在TL3562平台上使用Qt实现ADC采集显示和内部温度曲线实时监控,可以通过使用轻量级的第三方库QCustomPlot绘制动态曲线,并结合Linux系统的ADC驱动读取数据
实现功能
- 实时显示 2 路 ADC 和温度数据
- 动态波形绘制(支持缩放/平移)
完整的代码结构
qt_adc/
├── qt_adc.pro
├── main.cpp
├── adc_tempmonitor.h
├── adc_tempmonitor.cpp
└── waveformwidget.h
└── waveformwidget.cpp
界面布局
+-------------------------------------------+
| [ADC 通道0] 进度条 | LCD显示 (0.00 V) |
| [ADC 通道1] 进度条 | LCD显示 (0.00 V) |
| [温度] 进度条 | LCD显示 (00.0 ℃) |
| |
| 波形显示区域 (QCustomPlot/QChart) |
+-------------------------------------------+
| 采样控制按钮 [开始/停止] |
+-------------------------------------------+
1、获取QCustomPlot源码
wget https://www.qcustomplot.com/release/2.1.1/QCustomPlot.tar.gz
tar -xvf QCustomPlot.tar.gz
2、adc_tempmonitor类
adc_tempmonitor.h
#ifndef ADC_TEMPMONITOR_H
#define ADC_TEMPMONITOR_H
#include <QWidget>
#include <QTimer>
#include <QVBoxLayout>
#include <QProgressBar>
#include <QLabel>
#include <QPushButton>
#include "qcustomplot.h"
#include <QLCDNumber>
class ADC_TempMonitor : public QWidget {
Q_OBJECT
public:
explicit ADC_TempMonitor(QWidget *parent = nullptr);
private slots:
void updateSensorData();
private:
QWidget* createSensorRow(QProgressBar *bar, QLCDNumber *lcd);
QProgressBar *m_adc0Bar;
QProgressBar *m_adc1Bar;
QProgressBar *m_tempBar;
QLCDNumber *m_adc0Lcd;
QLCDNumber *m_adc1Lcd;
QLCDNumber *m_tempLcd;
QPushButton *m_controlBtn;
QCustomPlot *m_plot;
QTimer *m_timer;
bool m_isSampling = false;
double readADC(int channel);
double readTemperature();
void initUI();
};
#endif
adc_tempmonitor.cpp
ADC_TempMonitor::ADC_TempMonitor(QWidget *parent)
: QWidget(parent) {
initUI();
}
void ADC_TempMonitor::initUI() {
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QGroupBox *sensorGroup = new QGroupBox("传感器数据");
QFormLayout *formLayout = new QFormLayout(sensorGroup);
m_adc0Bar = new QProgressBar();
m_adc0Bar->setRange(0, 4095);
m_adc1Bar = new QProgressBar();
m_adc1Bar->setRange(0, 4095);
m_tempBar = new QProgressBar();
m_tempBar->setRange(-20, 100);
m_adc0Lcd = new QLCDNumber(this);
m_adc0Lcd->setDigitCount(5);
m_adc0Lcd->setSegmentStyle(QLCDNumber::Flat);
m_adc0Lcd->setStyleSheet("background: black; color: green;");
m_adc1Lcd = new QLCDNumber(this);
m_adc1Lcd->setDigitCount(5);
m_adc1Lcd->setSegmentStyle(QLCDNumber::Filled);
m_adc1Lcd->setStyleSheet("background: black; color: green;");
m_tempLcd = new QLCDNumber(this);
m_tempLcd->setDigitCount(5);
m_tempLcd->setStyleSheet("background: black; color: red;");
m_adc0Lcd->setStyleSheet(R"(
QLCDNumber {
background: black;
color: #00FF00; /* 绿色 */
border: 2px solid gray;
border-radius: 5px;
}
)");
QPalette pal = m_tempLcd->palette();
pal.setColor(QPalette::WindowText, Qt::red);
m_tempLcd->setPalette(pal);
formLayout->addRow("ADC 通道0:", createSensorRow(m_adc0Bar, m_adc0Lcd));
formLayout->addRow("ADC 通道1:", createSensorRow(m_adc1Bar, m_adc1Lcd));
formLayout->addRow("温度:", createSensorRow(m_tempBar, m_tempLcd));
m_plot = new QCustomPlot();
m_plot->addGraph();
m_plot->addGraph();
m_plot->addGraph();
m_plot->graph(0)->setPen(QPen(Qt::blue));
m_plot->graph(1)->setPen(QPen(Qt::red));
m_plot->graph(2)->setPen(QPen(Qt::green));
m_plot->xAxis->setLabel("时间 (s)");
m_plot->yAxis->setLabel("数值");
m_controlBtn = new QPushButton("开始采样");
connect(m_controlBtn, &QPushButton::clicked, [this](){
m_isSampling = !m_isSampling;
m_controlBtn->setText(m_isSampling ? "停止采样" : "开始采样");
m_isSampling ? m_timer->start(100) : m_timer->stop();
});
mainLayout->addWidget(sensorGroup);
mainLayout->addWidget(m_plot);
mainLayout->addWidget(m_controlBtn);
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &ADC_TempMonitor::updateSensorData);
}
QWidget* ADC_TempMonitor::createSensorRow(QProgressBar *bar, QLCDNumber *lcd) {
QWidget *widget = new QWidget();
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(bar, 70);
layout->addWidget(lcd, 30);
return widget;
}
void ADC_TempMonitor::updateSensorData() {
double adc0 = readADC(0);
double adc1 = readADC(1);
double temp = readTemperature();
if(temp > 60.0) {
m_tempLcd->setStyleSheet("background: black; color: red;");
} else {
m_tempLcd->setStyleSheet("background: black; color: green;");
}
m_adc0Bar->setValue(adc0 * 4096 / 3.3);
m_adc1Bar->setValue(adc1 * 4096 / 3.3);
m_tempBar->setValue(temp);
m_adc0Lcd->display(QString::number(adc0, 'f', 2));
m_adc1Lcd->display(QString::number(adc1, 'f', 2));
m_tempLcd->display(QString::number(temp, 'f', 1));
static QVector<double> time, adc0Data, adc1Data, tempData;
static double t = 0;
t += 0.1;
time.append(t);
adc0Data.append(adc0);
adc1Data.append(adc1);
tempData.append(temp);
if (time.size() > 100) {
time.removeFirst();
adc0Data.removeFirst();
adc1Data.removeFirst();
tempData.removeFirst();
}
m_plot->graph(0)->setData(time, adc0Data);
m_plot->graph(1)->setData(time, adc1Data);
m_plot->graph(2)->setData(time, tempData);
m_plot->rescaleAxes();
m_plot->replot();
}
double ADC_TempMonitor::readADC(int channel) {
char path[256];
snprintf(path, sizeof(path), "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw", channel);
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) return 0;
return file.readAll().trimmed().toDouble() * 3.3 / 4096;
}
double ADC_TempMonitor::readTemperature() {
QFile file("/sys/class/thermal/thermal_zone0/temp");
if (!file.open(QIODevice::ReadOnly)) return 0;
return file.readAll().trimmed().toDouble() / 1000;
}
3、waveformwidget类
waveformwidget.h
#include <QWidget>
#include <QVector>
#include <QPen>
class WaveformWidget : public QWidget {
Q_OBJECT
public:
explicit WaveformWidget(QWidget *parent = nullptr);
void addData(double adc0, double adc1, double temp);
protected:
void paintEvent(QPaintEvent *) override;
private:
QVector<double> m_adc0Data, m_adc1Data, m_tempData;
QPen m_adc0Pen{Qt::blue}, m_adc1Pen{Qt::red}, m_tempPen{Qt::green};
int m_maxPoints = 100;
};
waveformwidget.cpp
#include "waveformwidget.h"
#include <QPainter>
WaveformWidget::WaveformWidget(QWidget *parent) : QWidget(parent) {
setMinimumHeight(150);
}
void WaveformWidget::addData(double adc0, double adc1, double temp) {
m_adc0Data.append(adc0);
m_adc1Data.append(adc1);
m_tempData.append(temp);
if (m_adc0Data.size() > m_maxPoints) {
m_adc0Data.removeFirst();
m_adc1Data.removeFirst();
m_tempData.removeFirst();
}
update();
}
void WaveformWidget::paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.fillRect(rect(), Qt::black);
if (m_adc0Data.isEmpty()) return;
double xStep = width() / static_cast<double>(m_maxPoints);
double yScale = height() / 3.3;
painter.setPen(m_adc0Pen);
for (int i = 1; i < m_adc0Data.size(); ++i) {
painter.drawLine(
(i-1)*xStep, height() - m_adc0Data[i-1]*yScale,
i*xStep, height() - m_adc0Data[i]*yScale
);
}
painter.setPen(m_adc1Pen);
for (int i = 1; i < m_adc1Data.size(); ++i) {
painter.drawLine(
(i-1)*xStep, height() - (m_adc1Data[i-1]+1.5)*yScale,
i*xStep, height() - (m_adc1Data[i]+1.5)*yScale
);
}
painter.setPen(m_tempPen);
for (int i = 1; i < m_tempData.size(); ++i) {
double tempNorm = m_tempData[i] / 100.0 * 3.3;
painter.drawLine(
(i-1)*xStep, height() - tempNorm*yScale,
i*xStep, height() - tempNorm*yScale
);
}
}
4、qt_adc.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
CONFIG += c++11
INCLUDEPATH += ./qcustomplot
SOURCES += \\
adc_tempmonitor.cpp \\
main.cpp \\
waveformwidget.cpp
HEADERS += \\
adc_tempmonitor.h \\
waveformwidget.h
HEADERS += ./qcustomplot/qcustomplot.h
SOURCES += ./qcustomplot/qcustomplot.cpp
TRANSLATIONS += \\
qt_test1_zh_CN.ts
CONFIG += embed_translations
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
5、main.cpp
#include "mainwindow.h"
#include "adc_tempmonitor.h"
#include <QApplication>
#include <QLocale>
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "qt_test1_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
a.installTranslator(&translator);
break;
}
}
ADC_TempMonitor monitor;
monitor.resize(800, 600);
monitor.setWindowTitle("ADC & Temperature Monitor");
monitor.show();
return a.exec();
}
6、关键说明
1)传感器读取
double ADC_TempMonitor::readADC(int channel) {
char path[256];
snprintf(path, sizeof(path), "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw", channel);
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) return 0;
return file.readAll().trimmed().toDouble() * 3.3 / 4096;
}
double ADC_TempMonitor::readTemperature() {
QFile file("/sys/class/thermal/thermal_zone0/temp");
if (!file.open(QIODevice::ReadOnly)) return 0;
return file.readAll().trimmed().toDouble() / 1000;
}
2)采样控制
通过 QTimer 实现定时采集:
m_timer->start(100)
connect(m_timer, &QTimer::timeout, this, &ADC_TempMonitor::updateSensorData)
3)项目文件 (.pro) 配置
增加qcustomplot相关
INCLUDEPATH += ./qcustomplot
SOURCES += qcustomplot.cpp
HEADERS += qcustomplot.h