研一上了杨迎泽老师的一门《列车网络与通讯》课程,课程的最后老师给我们分配的小作业居然是写上位机控制一台程控电流源,我在查阅了这台程控电流源的手册后,发现它的通讯方式是串口,而且在串口通讯的基础上制定了一套详细的通讯协议,基于此,我花了小半天的时间做了一个上位机,完成了任务,这里主要分享一下基于QT开发串口助手的一些代码,具体是基于qextserialport的串口通讯开源类库实现的,上位机界面如下图,界面比较简陋。
完整工程点击如下链接:https://download.csdn.net/download/qq_18108083/10798653
(1) main.cpp
#include "mainwindow.h"
#include
int main(int argc, char *argv[])
{
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF8")); //保证正常显示中文
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF8"));
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
(2) mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//创建定时器
timer =new QTimer(this);
//按钮状态初始化
ui->openMyComBtn->setEnabled(true); //打开串口后“打开串口”按钮不可用
ui->closeMyComBtn->setEnabled(false); //打开串口后“关闭串口”按钮可用
ui->sendMsgBtn->setEnabled(false); //打开串口后“发送数据”按钮可用
connect(ui->openMyComBtn,SIGNAL(clicked(bool)),this,SLOT(startSerialPort())); //关联打开串口槽函数
connect(ui->closeMyComBtn,SIGNAL(clicked(bool)),this,SLOT(closeSerialPort())); //关联关闭串口槽函数
connect(ui->sendMsgBtn,SIGNAL(clicked(bool)),this,SLOT(sendMessage())); //关联发送数据槽函数
connect(ui->voltDial,SIGNAL(valueChanged(int)),this,SLOT(voltValueSet(int))); //关联设置电压槽函数
connect(this->timer,SIGNAL(timeout()),this,SLOT(timeOut())); //关联定时器溢出槽函数
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::startSerialPort() //打开串口槽函数
{
/*
//定义一个结构体,用来存放串口各个参数
struct PortSettings myComSetting = {BAUD115200,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,500}; //波特率,数据位,奇偶校验,停止位,数据流控制(延时)等
//定义串口对象,并传递参数,在构造函数里对其进行初始化
myCom = new Win_QextSerialPort("com8",myComSetting,QextSerialBase::EventDriven); //串口
//以可读写方式打开串口
myCom ->open(QIODevice::ReadWrite);
//信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作
connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
//按钮状态转换
ui->openMyComBtn->setEnabled(false); //打开串口后“打开串口”按钮不可用
ui->closeMyComBtn->setEnabled(true); //打开串口后“关闭串口”按钮可用
ui->sendMsgBtn->setEnabled(true); //打开串口后“发送数据”按钮可用
*/
//获取串口名
QString portName = ui->portNameComboBox->currentText();
//定义串口对象,并传递参数,在构造函数里对其进行初始化
myCom = new Win_QextSerialPort(portName,QextSerialBase::EventDriven);
//打开串口
myCom ->open(QIODevice::ReadWrite);
//根据组合框内容对串口进行设置
//设置波特率
QString baudValue=ui->baudRateComboBox->currentText();
baudValue = "BAUD"+baudValue;
ui->debugLabel->setText(baudValue);
if(ui->baudRateComboBox->currentText()==tr("1200"))
myCom->setBaudRate(BAUD1200);
else if(ui->baudRateComboBox->currentText()==tr("2400"))
myCom->setBaudRate(BAUD2400);
else if(ui->baudRateComboBox->currentText()==tr("4800"))
myCom->setBaudRate(BAUD4800);
else if(ui->baudRateComboBox->currentText()==tr("9600"))
myCom->setBaudRate(BAUD9600);
else if(ui->baudRateComboBox->currentText()==tr("14400"))
myCom->setBaudRate(BAUD14400);
else if(ui->baudRateComboBox->currentText()==tr("19200"))
myCom->setBaudRate(BAUD19200);
else if(ui->baudRateComboBox->currentText()==tr("38400"))
myCom->setBaudRate(BAUD38400);
else if(ui->baudRateComboBox->currentText()==tr("57600"))
myCom->setBaudRate(BAUD57600);
else if(ui->baudRateComboBox->currentText()==tr("115200"))
myCom->setBaudRate(BAUD115200);
else if(ui->baudRateComboBox->currentText()==tr("128000"))
myCom->setBaudRate(BAUD128000);
else if(ui->baudRateComboBox->currentText()==tr("256000"))
myCom->setBaudRate(BAUD256000);
//设置数据位
if(ui->dataBitsComboBox->currentText()==tr("8"))
myCom->setDataBits(DATA_8);
else if(ui->dataBitsComboBox->currentText()==tr("7"))
myCom->setDataBits(DATA_7);
//设置奇偶校验
if(ui->parityComboBox->currentText()==tr("无"))
myCom->setParity(PAR_NONE);
else if(ui->parityComboBox->currentText()==tr("奇"))
myCom->setParity(PAR_ODD);
else if(ui->parityComboBox->currentText()==tr("偶"))
myCom->setParity(PAR_EVEN);
//设置停止位
if(ui->stopBitsComboBox->currentText()==tr("1"))
myCom->setStopBits(STOP_1);
else if(ui->stopBitsComboBox->currentText()==tr("2"))
myCom->setStopBits(STOP_2);
//设置数据流控制,我们使用无数据流控制的默认设置
myCom->setFlowControl(FLOW_OFF);
//设置延时
myCom->setTimeout(500);
//信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作
connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
//按钮状态转换
ui->openMyComBtn->setEnabled(false); //打开串口后“打开串口”按钮不可用
ui->closeMyComBtn->setEnabled(true); //打开串口后“关闭串口”按钮可用
ui->sendMsgBtn->setEnabled(true); //打开串口后“发送数据”按钮可用
ui->baudRateComboBox->setEnabled(false); //设置各个组合框不可用
ui->dataBitsComboBox->setEnabled(false);
ui->parityComboBox->setEnabled(false);
ui->stopBitsComboBox->setEnabled(false);
ui->portNameComboBox->setEnabled(false);
isSerialOpen = true;
}
void MainWindow::closeSerialPort() //关闭串口槽函数
{
myCom->close(); //关闭串口,该函数在win_qextserialport.cpp文件中定义
//按钮状态转换
ui->openMyComBtn->setEnabled(true); //关闭串口后“打开串口”按钮可用
ui->closeMyComBtn->setEnabled(false); //关闭串口后“关闭串口”按钮不可用
ui->sendMsgBtn->setEnabled(false); //关闭串口后“发送数据”按钮不可用
ui->baudRateComboBox->setEnabled(true); //设置各个组合框可用
ui->dataBitsComboBox->setEnabled(true);
ui->parityComboBox->setEnabled(true);
ui->stopBitsComboBox->setEnabled(true);
ui->portNameComboBox->setEnabled(true);
}
void MainWindow::sendMessage() //发送数据槽函数
{
//以ASCII码形式将行编辑框中的数据写入串口
// myCom->write()
myCom->write(ui->sendMsgLineEdit->text().toAscii());
}
void MainWindow::readMyCom() //读串口数据槽函数
{
//读取串口缓冲区的所有数据给临时变量temp
QByteArray temp = myCom->readAll();
//将串口的数据显示在窗口的文本浏览器中
ui->textBrowser->insertPlainText(temp+"\n");
ui->textBrowser->moveCursor(QTextCursor::End);
if(serReadMode == 1) //串口读功能的工作模式, 1.读电压 2.读电流 0.正常读
{
QString str = temp;
int size = str.size();
qDebug("index size:%d",size);
if(size > 0)
{
qDebug("str is:%s",str.toLatin1().data()); //将qstring转换成char*
qDebug("str num is:%f",str.toDouble()); //将qstring转换成double
ui->voltValueLcd->display(str.toDouble());
}
//int index = str.indexOf("\n");
//str = str.left(index);
//qDebug("index size:%s",str.toLatin1().data()); //将qstring转换成char*
}
}
void MainWindow::voltValueSet(int volt) //设置电压值槽函数 (带参数)
{
//ui->voltValueLcd->display(volt);
//ui->debugLabel->setText(QString::number(volt,10));
if(isSerialOpen)
{
if(timeoutFlag) //定时器延时已到
{
timeoutFlag = false;
this->timer->stop(); //首先关闭定时器
this->timer->start(100); //开启定时器 单位毫秒
QString setVolt = "VOLTage " + QString::number(volt,10) + "\n";
QString queryVolt = "VOLTage?\n";
//myCom->write(setVolt.toAscii()); //发送获取控制电压命令
//myCom->write(queryVolt.toAscii()); //发送获取控制电压命令
//ui->textBrowser->insertPlainText(setVolt); //将命令添加到工作日志
//ui->textBrowser->insertPlainText(queryVolt);
myCom->write(QString::number(volt,10).toAscii()); //发送获取控制电压命令
serReadMode = 1; //串口读功能的工作模式, 1.读电压 2.读电流 0.正常读
//ui->outputStaLight->setStyleSheet("background-color: #ff3333;");
}
}
else
{
QMessageBox::information(this,"提示:","未打开串口");
}
}
void MainWindow::curValueSet() //设置电流值槽函数
{
}
void MainWindow::timeOut() //定时器溢出
{
this->timer->stop(); //首先关闭定时器
timeoutFlag = true;
// QMessageBox::information(this,"提示:","定时器时间溢出");
}
(3) mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include //保证正常显示中文
#include "win_qextserialport.h" //引入第三方库
#include
#include //定时器
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Win_QextSerialPort *myCom; //声明对象
QTimer *timer; //定义定时器指针
bool isSerialOpen = false; //串口打开标志
bool timeoutFlag = true; //定时器溢出标志
unsigned char serReadMode = 0; //串口读功能的工作模式, 1.读电压 2.读电流 0.正常读
private slots:
void readMyCom(); //添加读槽函数
void startSerialPort(); //打开串口槽函数
void closeSerialPort(); //关闭串口槽函数
void sendMessage(); //发送数据槽函数
void voltValueSet(int volt); //设置电压值槽函数
void curValueSet(); //设置电流值槽函数
void timeOut(); //定时器溢出
};
#endif // MAINWINDOW_H