文章目录
- 原版代码工程
- 增加QCustomplot实时画图的源码工程
- 源码
原版代码工程
源码下载链接:
链接:https://pan.baidu.com/s/15pWzadPwOx_OfJGtvL-MjA
提取码:lief
–来自百度网盘超级会员V5的分享
增加QCustomplot实时画图的源码工程
源码:
链接:https://pan.baidu.com/s/1DJKV7RY3C_1nQ1K2iNP61w
提取码:lief
–来自百度网盘超级会员V5的分享
下位机arduino测试代码:
#include <Arduino.h>
unsigned char data_to_send[100] = {0};
int acc_data[3] = {0};
int gyro_data[3] = {0};
/**********为了匿名四轴上位机的协议定义的变量****************************/
//cup为小端模式存储,也就是在存储的时候,低位被存在0字节,高位在1字节
#define BYTE0(dwTemp) (*(char *)(&dwTemp)) //取出int型变量的低字节
#define BYTE1(dwTemp) (*((char *)(&dwTemp) + 1)) // 取存储在此变量下一内存字节的内容,高字节
#define BYTE2(dwTemp) (*((char *)(&dwTemp) + 2))
#define BYTE3(dwTemp) (*((char *)(&dwTemp) + 3))
/*
发送给上位机的数据帧定义
@桢头--功能字--长度--数据(一个或多个,具体看协议说明)-校验
@前2个字节为帧头0xAAAA
@第3个字节为帧ID,应设置为0xF1~0xFA中的一个
@第4个字节为报文数据长度(dlc)
@第5个字节开始到第5+dlc-1个字节为要传输的数据内容段,每个数据场为高字节在前,地字节在后
@第5+dlc个字节为CheckSum,为第1个字节到第5+dlc-1个字节所有字节的值相加后,保留结果的低八位作为CheckSum
*/
void Data_Send_Senser(unsigned int pst) //按照协议的要求处理数据,pst为包含多个数据的数组,但这里为一个数据
{
unsigned char _cnt=0;
unsigned char i=0;
unsigned int j=0,temp;
unsigned char sum = 0;
//char 类型为两个字节
data_to_send[_cnt++]=0xAA; //桢头
data_to_send[_cnt++]=0xAA;
data_to_send[_cnt++]=0x02; //功能字
data_to_send[_cnt++]=0; //需要发送数据的字节数,暂时给0,后面在赋值。
data_to_send[_cnt++]=pst&0x00ff; //数据的低8位
data_to_send[_cnt++]=pst>>8; //数据的高8位
data_to_send[3] = _cnt-4; //长度
for(i=0; i<_cnt; i++)
{
sum = sum+ data_to_send[i]; //校验位
}
data_to_send[_cnt++] =sum; //计算校验位
Serial.write(data_to_send,_cnt);
}
/*
发送给上位机的数据帧定义
@桢头--功能字--长度--数据(一个或多个,具体看协议说明)-校验
@前2个字节为帧头0xAAAA
@第3个字节为帧ID,应设置为0xF1~0xFA中的一个
@第4个字节为报文数据长度(dlc)
@第5个字节开始到第5+dlc-1个字节为要传输的数据内容段,每个数据场为高字节在前,地字节在后
@第5+dlc个字节为CheckSum,为第1个字节到第5+dlc-1个字节所有字节的值相加后,保留结果的低八位作为CheckSum
*/
void data_to_computer(int* acc_data,int* gyro_data)
{
unsigned char data_to_send[23] = {0};
unsigned char i = 0;
unsigned char cnt = 0;
unsigned char sum = 0;
data_to_send[cnt++]=0xAA; //帧头:AAAA
data_to_send[cnt++]=0xAA;
data_to_send[cnt++]=0x02; //功能字:OXF2
data_to_send[cnt++]=0; //需要发送数据的字节数,暂时给0,后面在赋值。
data_to_send[cnt++] = BYTE1(acc_data[0]);//取data[0]数据的高字节,
data_to_send[cnt++] = BYTE0(acc_data[0]);
data_to_send[cnt++] = BYTE1(acc_data[1]);
data_to_send[cnt++] = BYTE0(acc_data[1]);
data_to_send[cnt++] = BYTE1(acc_data[2]);
data_to_send[cnt++] = BYTE0(acc_data[2]);
data_to_send[cnt++] = BYTE1(gyro_data[0]);//取data[0]数据的高字节,
data_to_send[cnt++] = BYTE0(gyro_data[0]);
data_to_send[cnt++] = BYTE1(gyro_data[1]);
data_to_send[cnt++] = BYTE0(gyro_data[1]);
data_to_send[cnt++] = BYTE1(gyro_data[2]);
data_to_send[cnt++] = BYTE0(gyro_data[2]);
data_to_send[cnt++]=0;
data_to_send[cnt++]=0;
data_to_send[cnt++]=0;
data_to_send[cnt++]=0;
data_to_send[cnt++]=0;
data_to_send[cnt++]=0;
data_to_send[3] = cnt-4;//计算总数据的字节数。
for(i=0;i<cnt;i++) //对于for语句,当不写大括号的时候,只执行到下面第一个分号结束。
{
sum+=data_to_send[i];
}
data_to_send[cnt++] = sum; //计算校验位
Serial.write(data_to_send,cnt);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
randomSeed(analogRead(0));
pinMode(8,OUTPUT);
}
void loop() {
// unsigned char buff[6];
// unsigned char i;
// for(i = 0;i<6;i++)
// {
// buff[i] = random(65535);
// }
// acc_data[0] = (buff[0] << 8) | buff[1];//x轴高8位左移8位或上低8位
// acc_data[1] = (buff[2] << 8) | buff[3];
// acc_data[2] = (buff[4] << 8) | buff[5];
// for(i = 0;i<6;i++)
// {
// buff[i] = random(65535);
// }
// gyro_data[0] = (buff[0] << 8) | buff[1];//x轴高8位左移8位或上低8位
// gyro_data[1] = (buff[2] << 8) | buff[3];
// gyro_data[2] = (buff[4] << 8) | buff[5];
// data_to_computer(acc_data, gyro_data);
digitalWrite(8,HIGH);
// unsigned int num = random(100);
// Data_Send_Senser(num);
for(int i = 0; i < 255; i++)
{
Data_Send_Senser(i);
delay(2); // ms
}
digitalWrite(8,LOW);
//delayMicroseconds(1500); // us
}
源码
mainwindows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() <<"main" <<QThread::currentThread();
qRegisterMetaType<serialportplus::Settings>("serialportplus::Settings");
initUI();
initSerialPort();
}
MainWindow::~MainWindow()
{
delete ui;
}
/*
* 函数功能:完成对串口助手界面的初始化
*/
void MainWindow::initUI()
{
//增加端口号选择项
for (int i = 1; i <= 15; i++)
{
ui->cboPortName->addItem(QString("COM%1").arg(i));
}
//设置端口号波特率
ui->cboBaudrate->addItem(QString("1200"),QSerialPort::Baud1200);
ui->cboBaudrate->addItem(QString("2400"),QSerialPort::Baud2400);
ui->cboBaudrate->addItem(QString("4800"),QSerialPort::Baud4800);
ui->cboBaudrate->addItem(QString("9600"),QSerialPort::Baud9600);
ui->cboBaudrate->addItem(QString("19200"),QSerialPort::Baud19200);
ui->cboBaudrate->addItem(QString("38400"),QSerialPort::Baud38400);
ui->cboBaudrate->addItem(QString("57600"),QSerialPort::Baud57600);
ui->cboBaudrate->addItem(QString("115200"),QSerialPort::Baud115200);
//设置端口数据位数
ui->cboDataBit->addItem("8",QSerialPort::Data8);
ui->cboDataBit->addItem("7",QSerialPort::Data7);
ui->cboDataBit->addItem("6",QSerialPort::Data6);
ui->cboDataBit->addItem("5",QSerialPort::Data5);
//设置端口校验方式
ui->cboParity->addItem("Odd",QSerialPort::OddParity);
ui->cboParity->addItem("Even",QSerialPort::EvenParity);
ui->cboParity->addItem("None",QSerialPort::NoParity);
//设置端口停止位
ui->cboStopBit->addItem("1",QSerialPort::OneStop);
ui->cboStopBit->addItem("1.5",QSerialPort::OneAndHalfStop);
ui->cboStopBit->addItem("2",QSerialPort::TwoStop);
//设置端口流控制
ui->cboFlowContral->addItem("None",QSerialPort::NoFlowControl);
ui->cboFlowContral->addItem("RTS/CTS",QSerialPort::HardwareControl);
ui->cboFlowContral->addItem("XON/XOFF",QSerialPort::SoftwareControl);
//设置定时重发时间,单位ms
ui->lineEdit->setText("1000");
//定时时间到,则执行timeup函数
connect(&m_timer, &QTimer::timeout, this,&MainWindow::timeUp);
}
/*
* 函数功能:完成对串口的初始化,设置串口子线程
*/
void MainWindow::initSerialPort()
{
//将串口对象的相关操作,放入子线程
m_serial.moveToThread(&m_thread);
//子线程启动
m_thread.start();
/*分别是界面对串口发出的启动、停止和发送数据的信号*/
connect(this, &MainWindow::sigStart,&m_serial, &serialportplus::startPort);
connect(this, &MainWindow::sigStop,&m_serial, &serialportplus::stopPort);
connect(this, &MainWindow::sigSend,&m_serial, &serialportplus::sendData);
/*分别是串口对界面发出的启动、停止和接收数据的信号*/
connect(&m_serial, &serialportplus::sigStarted,this, &MainWindow::started);
connect(&m_serial, &serialportplus::sigStop,this, &MainWindow::stoped);
connect(&m_serial, &serialportplus::sigReceived,this, &MainWindow::receiveData);
}
/*
* 函数功能:当界面关闭时,子线程也要进行关闭
*/
void MainWindow::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
//打印界面主线程地址
qDebug() <<"main" <<QThread::currentThread();
//向发送串口发送串口停止的信号
emit sigStop();
//串口子线程关闭
m_thread.quit();
//等待串口子线程完全关闭
m_thread.wait();
}
/*
* 函数功能:根据串口打开按钮判断是否打开串口,
* 当串口打开时,对串口参数进行设置,并向串口子线程发出串口打开信号,否则发出关闭信号
*/
void MainWindow::on_btnOpenPort_clicked()
{
//获取串口打开按钮的文本
QString text= ui->btnOpenPort->text();
//当按钮关闭时,打开串口,并设置相关参数,向串口子线程发送串口打开信号
if(text == QString::fromLocal8Bit("打开串口"))
{
serialportplus::Settings s;
s.name= ui->cboPortName->currentText();
s.baudRate= (QSerialPort::BaudRate)ui->cboBaudrate->currentData().toInt();
s.dataBits = (QSerialPort::DataBits)ui->cboDataBit->currentData().toInt();
s.stopBits= (QSerialPort::StopBits)ui->cboStopBit->currentData().toInt();
s.parity= (QSerialPort::Parity)ui->cboParity->currentData().toInt();
s.flowControl = (QSerialPort::FlowControl)ui->cboFlowContral->currentData().toInt();
emit sigStart(s);
}
//当按钮打开时,关闭串口,向串口子线程发送串口关闭信号
else
{
emit sigStop();
}
}
/*
* 函数功能:点击发送按钮时,执行串口发送
*/
void MainWindow::on_btnSend_clicked()
{
//获取所要发送的文本
QString strSend = ui->SendplainTextEdit->toPlainText();
//将所要发送的文本存入arr变量
QByteArray arr = strSend.toUtf8();
//将arr变量通过信号发给串口子线程
emit sigSend(arr);
}
/*
* 函数功能:接收串口子线程发出启动的信号,对串口的按钮和参数设置的界面进行管理
*/
void MainWindow::started()
{
//串口打开按钮文本切换,切换为“关闭串口”
ui->btnOpenPort->setText(QString::fromLocal8Bit("关闭串口"));
//串口参数处于不可更改的状态
ui->groupBox->setEnabled(false);
}
/*
* 函数功能:接收串口子线程发出停止的信号,对串口的按钮和参数设置的界面进行管理
*/
void MainWindow::stoped(int status)
{
Q_UNUSED(status);
//串口打开按钮文本切换,切换为“打开串口”
ui->btnOpenPort->setText(QString::fromLocal8Bit("打开串口"));
//串口参数处于可更改的状态
ui->groupBox->setEnabled(true);
}
/*
* 函数功能:接收串口子线程发出数据接收的信号,界面接收串口子线程发送的数据,并将其显示到界面上
*/
void MainWindow::receiveData(QByteArray data)
{
//将接收的数据进行转换
QString strText = QString(data);
//获取当前接收数据的时间
QDateTime current_date_time = QDateTime::currentDateTime();
//显示当前接收数据的时间
QString t = current_date_time.toString("yyyy-MM-dd hh:mm:ss.zzz : ");
//显示当前接收的数据
ui->RecveeiveplainTextEdit->appendPlainText( t + strText + "\n" );
}
/*
* 函数功能:定时发送状态改变响应函数
*/
void MainWindow::on_checkBox_stateChanged(int arg1)
{
//当定时发送被勾选时
if(arg1)
{
//定时器启动
m_timer.start(ui->lineEdit->text().toInt());
}
//当定时发送未被勾选时
else
{
//定时器停止
m_timer.stop();
}
}
/*
* 函数功能:定时时间到时,执行串口发送函数
*/
void MainWindow::timeUp()
{
qDebug() << "timeup";
//串口发送函数
on_btnSend_clicked();
}
mainwindows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QSerialPort>
#include<QDateTime>
#include<QTimer>
#include<QDebug>
#include<QThread>
#include"serialportplus.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//界面初始化函数
void initUI();
//端口初始化函数
void initSerialPort();
//界面关闭事件
void closeEvent(QCloseEvent *event);
private:
Ui::MainWindow *ui;
//创建一个自定义的串口类对象
serialportplus m_serial;
//创建一个线程对象
QThread m_thread;
//创建一个定时器对象
QTimer m_timer;
signals:
// 分别是界面对串口发出的启动、停止和发送数据的信号
void sigStart(serialportplus::Settings s);
void sigStop();
void sigSend(QByteArray data);
public slots:
// 分别是串口对界面发出的启动、停止和接收数据的信号时,所要执行的操作
void started();
void stoped(int status);
void receiveData(QByteArray data);
private slots:
void timeUp();
void on_btnOpenPort_clicked();
void on_btnSend_clicked();
void on_checkBox_stateChanged(int arg1);
};
#endif // MAINWINDOW_H
serialportplus.cpp
#include "serialportplus.h"
/*
* 函数功能:对串口接收到数据的信号进行响应,并向界面主线程发送接收到的数据
*/
serialportplus::serialportplus()
{
//当串口子线程接收到数据时,向界面主线程发出数据接收的信号
connect(this, &QSerialPort::readyRead, [this]()
{
qDebug() << QString::fromLocal8Bit ("接收") << QThread::currentThread();
//读取串口接收的数据
QByteArray arr = readAll();
//将数据通过信号发给界面主线程
emit sigReceived(arr);
});
}
/*
* 函数功能:接收界面主线程发出开始信号,接收串口参数并对设置,
* 同时根据串口状态发出启动或停止信号。
*/
void serialportplus::startPort(serialportplus::Settings sets)
{
/*设置串口参数*/
setPortName(sets.name);
setParity(sets.parity);
setBaudRate(sets.baudRate);
setDataBits(sets.dataBits);
setStopBits(sets.stopBits);
setFlowControl(sets.flowControl);
qDebug() << QString::fromLocal8Bit ("启动") <<QThread::currentThread();
//判断串口是否处于可读写状态
if(open(QIODevice::ReadWrite))
{
//串口处于可读写状态,发出向界面主线程启动信号
emit sigStarted();
}
else
{
//串口不处于可读写状态,发出向界面主线程停止信号
emit sigStop(1);
}
}
/*
* 函数功能:接收界面主线程发送的停止信号,串口关闭
*/
void serialportplus::stopPort()
{
qDebug() << QString::fromLocal8Bit ("停止") <<QThread::currentThread();
//判断串口是否关闭
if(isOpen())
{
//关闭串口
close();
}
//向界面主线程发出停止信号
emit sigStop(0);
}
/*
* 函数功能:接收界面主线程发出的数据发送信号,串口进行数据发送
*/
void serialportplus::sendData(QByteArray arr)
{
qDebug() << QString::fromLocal8Bit ("发送") <<QThread::currentThread();
//判断串口是否关闭
if(isOpen())
{
//发送数据
write(arr);
}
}
serialportplus.h
#ifndef SERIALPORTPLUS_H
#define SERIALPORTPLUS_H
#include <QSerialPort>
#include<QThread>
#include<QDebug>
class serialportplus : public QSerialPort
{
Q_OBJECT
public:
//串口接收数据的函数
serialportplus();
//串口设置
struct Settings
{
QString name;//端口名称COM1、COM2
BaudRate baudRate;//波特率
DataBits dataBits;//数据位
Parity parity;//奇偶校验
StopBits stopBits;//停止位
FlowControl flowControl;//流控制
};
public slots:
// 分别是界面对串口发出的启动、停止和发送数据的信号时,所要执行的操作
void startPort(Settings sets);
void stopPort();
void sendData(QByteArray arr);
signals:
// 分别是串口对界面发出的启动、停止和接收数据的信号
void sigStarted();
void sigStop(int status);
void sigReceived(QByteArray data);
};
#endif // SERIALPORTPLUS_H