【QT串口助手】串口接收数据并显示 您所在的位置:网站首页 qt串口编程要学什么 【QT串口助手】串口接收数据并显示

【QT串口助手】串口接收数据并显示

2024-07-08 13:35| 来源: 网络整理| 查看: 265

前言 没用到线程,实现过程比较笨比,凑合看看得了。 正文 首先知道串口助手大概一般都会有三个功能:发送串口数据,接收串口数据,数据解析显示。 也许有的人觉得显示不算,但还是可以拿出来讲讲。 新建工程时脑海里会想到一个串口助手会有什么功能,每个功能需要怎么实现,然后再对应这些需求添加槽函数。

找串口打开串口关闭串口收数据发数据延时串口读数据

大概就是这样的。 先做个界面,创建几个label和几个comboBox,分别用来提示是什么端口、波特率… …并用下拉框给选择。 labelandcombobox 然后下拉框的选项添加可以双击这个组件然后添加(左下角加号)你要的选择项,完事就确定。

编辑组合框 不过波特率这些不是随便加的,C++里有个SerialPort的库,里面的类方法都是写好的,等下看代码。 这几个按键分别对应代码里的:

ui.open_serial ui.off_serial ui.query_button ui.clear_button ui.push_button

串口部分按键 然后根据上面列出来的功能创建几个按键,基本就是打开/关闭/发送串口这三个按键,创建完后按键基本就差不多了,然后可以放两个显示框,就用edittext。 发送接收显示框 关于这个发送框,记得在ui里头把readonly的勾选给去掉,我这边默认是勾选的,以至于一开始一直无法写入东西… … 去掉只读勾选

到这里界面就布置得差不多了,想要连接按键、显示框这些控件和代码逻辑的关系,可以使用connect,我这里用的全都是connect。有了这些,就表示上位机界面的控件和想要的逻辑连接起来了,连接的信号就是clicked(),this表示触发的事件只在本界面发生。 比如:

connect(ui.refreshbtn, SIGNAL(clicked()), this, SLOT(find_port()));//刷新串口的按钮 connect(ui.open_serial, SIGNAL(clicked()), this, SLOT(on_open_port_clicked())); connect(ui.off_serial, SIGNAL(clicked()), this, SLOT(on_close_port_clicked())); connect(ui.query_button, SIGNAL(clicked()), this, SLOT(query_data()));//这行不用管,query_data函数里写的是板子数据上报要发送的指令 connect(ui.clear_button, SIGNAL(clicked()), this, SLOT(on_clear_button1_clicked())); connect(ui.push_button, SIGNAL(clicked()), this, SLOT(on_send_button_clicked()));

比较关键的就是接收串口然后显示到接收框的部分了,因为收到串口数据之后要及时显示到接收框,所以需要定义一定时器连接到读数据的槽函数中。

timerserial = new QTimer(); QObject::connect(timerserial, SIGNAL(timeout()), this, SLOT(Read_Data()));

接下来是开始找串口,打开串口和关闭串口这三个功能,首先定义这三个功能的槽函数。 函数 声明 接着完善这三个功能的逻辑,这三个功能可以在网上找到很多参考,像打开串口serialport->*这里可以根据自己的需要来添加,有代码补全的话会方便很多,总的来说就是多看官网文档,它的这些功能都是封装好的,看懂了直接用就好了。

void Serial2418::find_port() { foreach(const QSerialPortInfo & info, QSerialPortInfo::availablePorts()) { QSerialPort serial; serial.setPort(info); if (serial.open(QIODevice::ReadWrite)) { ui.com_2->clear(); const auto COMinfos = QSerialPortInfo::availablePorts(); //用auto自动获取变量类型 for (const QSerialPortInfo& COMInfo : COMinfos) //cpp11范围遍历 { QStringList COMInfo_Str_Analysis; COMInfo_Str_Analysis serialport->close(); } delete serialport; }

如上,关闭上位机的时候记得关闭删除串口。

通过和同事交流发现寻找串口其实只需要创建一个串口列表并把可用串口的信息放进去,然后再遍历端口号就行,就是每次寻找串口之前都要先清空一遍下拉框里的串口名称,不然每次刷新串口或者新加入串口就会添加重复端口名称,并且拔掉串口模块之后刷新串口也不会清除已经下线的串口号。

void Serial2418::find_port() { ui.com_2->clear(); QList serialinfo = QSerialPortInfo::availablePorts(); for (int i = 0; i update(); sleep(100); //初始化串口 serialport->setPortName(ui.com_2->currentText()); //设置串口名 if (serialport->open(QIODevice::ReadWrite)) { serialport->setBaudRate(ui.baud_2->currentText().toInt()); //设置波特率 switch (ui.bit->currentIndex()) //设置数据位数 { case 8:serialport->setDataBits(QSerialPort::Data8); break; default: break; } switch (ui.jiaoyan->currentIndex()) //设置奇偶校验 { case 0: serialport->setParity(QSerialPort::NoParity); break; case 1: serialport->setParity(QSerialPort::OddParity); break; case 2: serialport->setParity(QSerialPort::EvenParity); break; default: break; } switch (ui.stopbit->currentIndex()) //设置停止位 { case 1: serialport->setStopBits(QSerialPort::OneStop); break; case 2: serialport->setStopBits(QSerialPort::TwoStop); break; default: break; } serialport->setFlowControl(QSerialPort::NoFlowControl); // 设置控件可否使用 ui.clear_button->setEnabled(true); ui.off_serial->setEnabled(true); ui.query_button->setEnabled(true); ui.open_serial->setEnabled(false); ui.push_button->setEnabled(true); //QMessageBox::information(this, tr("Success"), tr("Open successfully.")); } else //打开失败提示 { sleep(100); QMessageBox::information(this, tr("Error"), tr("Open the failure.")); find_port();//打开失败了要刷新一下串口,有可能串口信息没更新 } } //关闭串口 void Serial2418::on_close_port_clicked() { Data.START = 0x00; serialport->clear(); //清空缓存区 serialport->close(); //关闭串口 find_port();//更新串口列表 ui.query_button->setEnabled(false); ui.open_serial->setEnabled(true); ui.off_serial->setEnabled(false); ui.clear_button->setEnabled(true); ui.push_button->setEnabled(false); }

上面的关闭串口后本人设定了许多按键都false,直接禁止它们的操作可以防止上位机可能会出现各种奇怪的bug… … 清除数据很简单,只要把相应的几个数据框里的内容用clear掉就好了。

void Serial2418::on_clear_button1_clicked() { ui.send_text_window->clear(); ui.receive_text_window->clear(); ui.distedit->clear(); ui.eneredit->clear(); ui.addredit->clear(); ui.maxedit->clear(); ui.minedit->clear(); ui.displayedit->clear(); }

串口设置函数部分已经完成了,接下来就是发送和接收串口传来的数据。写代码的时候发现过一个问题,就是接收数据的时候是一个字节一个字节接收并处理的,比如说我这里的指令是16进制的,发送框发送的是68 41 AA AA AA AA AA AA AA 26 00 00 75 16,没有on_send_button_clicked里的那层转换时,串口接收到的数据就是 36‘6’ 38‘8’ 34‘4’ 31‘1’… … 要把6和8连起来就需要先把他们从ascii变为hex,再定义一个数组,把这些分开的数字分为高位和低位加起来。

//发送数据:hex void Serial2418::on_send_button_clicked() { uint8_t utmp[1024]; uint8_t utmp2[50]; memset(utmp, 0, sizeof(utmp)); memset(utmp2, 0, sizeof(utmp2)); QString sen = ui.send_text_window->toPlainText(); int len = ui.send_text_window->document()->characterCount(); int i, j, k; double tlen=0; if (!sen.isEmpty()) { //if (ui.checkhex->isChecked() == false)//ascii,这一段if也可以用如果想要让串口发送中文的话可以把这段if的注释消去。 //{ // sendBuf = sen.toLocal8Bit(); //} //else if (ui.checkhex->isChecked() == true)//hex //{ //if (sen.contains(" ")) sen.remove(QRegularExpression("\\s")); sen = sen.toLocal8Bit(); j = 0; tlen = 0; for (i = 0; i utmp[i] = (uint8_t)(sen[j].toLatin1()); } else if (sen[j] == ' ')//判断是否有空格,如果发送的是“68 41 21 43... ...”这样的指令就会把中间的空格忽略掉,如果发送的是“68412143... ...”就不会执行这一段代码 { j++; i--;//哈哈 continue; } j++; if (j >= len-1) { tlen = i; break; } } for (i = 0; i utmp2[k] = (utmp[i * 2 + 0] hex = ch - '0'; } else if ((ch >= 'A') && (ch hex = ch - 'a' + 10; } else { hex = 0; } return hex; } void Serial2418::Read_Data() { ui.displayedit->clear(); ui.receive_text_window->clear();//这里习惯读数据之前先清空接收框里的上一次数据,按需添加 uint8_t len = 0; timerserial->stop();//停止定时器 qDebug() //串口读数据周期时间(s),t=单个串口最大字节数/波特率=2062/115200=17.9ms //本来给的18,现在直接给100 timerserial->start(100); buffer.append(serialport->readAll());//读串口的所有数据并且把读到的数据累加到buffer上 }

这里的获取系统时间也是抄的CSDN上的代码,个人觉得还挺好懂的,可以自己看看,了解一下然后把他放到自己需要的地方就好了。

void Serial2418::updateData() { // 获取当前系统时间 QDateTime currentTime = QDateTime::currentDateTime(); QString currentTimeString = currentTime.toString(Qt::ISODate); QString addrtmp = (char*)set_addr; QString disttmp = QString::number(dist,'f',6); QString enertmp = QString::number(ener,'f',6); // 将数据保存到数据结构中 QString dataString = QString("%1,%2,%3,%4") //字符串处理函数 .arg对应前方的%1等占位符位置 .arg(currentTimeString) .arg(addrtmp) .arg(disttmp) .arg(enertmp); //qDebug() 5000) //缓存区最大保存5000组数据,超出5000后会自动停止接收数据 { serialport->clear(); //清空缓存区 serialport->close(); //关闭串口 QMessageBox::information(this, "Info", "The data cache is too large. Please save the data and reopen the serial port"); //SaveRecvDataFile(); } ui.receive_text_window->setText(currentTimeString); std::cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有