熟悉QT开发的朋友应该都知道,在开发QT串口应用程序的时,会遇到接收数据不完整的情况,这是因为串口是异步收发,而默认情况下QSerialPort没有对串口收进行阻塞,所以才会出现串口数据接收不完整的情况。

解决办法很简单:在接收槽那儿开一个定时器,做一段小延时OK 了,即延时接收,时间大概10~30ms,看自己的程序进行微调

连接槽函数并扫描计算机串口设备:

//连接槽
connect(&timer, SIGNAL(timeout()), this, SLOT(serialRead()));   //连接定时器槽,计时结束读出所有串口缓冲器数据;

//获取计算机上所有串口并添加到comboBox中
QList<QSerialPortInfo>  infos = QSerialPortInfo::availablePorts();
if(infos.isEmpty())
{
    ui->serialCom->addItem("无可用串口");
    return;
}
ui->textBrowser->appendPlainText("发现可用串口:");
foreach (QSerialPortInfo info, infos) {

    ui->serialCom->addItem(info.portName());

    Serial_list.append(info.portName());
    ui->textBrowser->appendPlainText(info.portName());

}

初始化并打开串口:


//初始化并打开串口
void Widget::on_serialConnect_clicked()
{
    QSerialPortInfo info;
    QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
    int i = 0;

    ui->disConnect->setEnabled(true);       //使能断开按钮
    ui->serialConnect ->setEnabled(false);  //失能连接按钮

    //初始化串口;
    if(i != infos.size ()){//can find
        ui->textBrowser->appendPlainText("串口打开成功"+tr("\n"));
        serial.setPortName(ui->serialCom->currentText());
        serial.open(QIODevice::ReadWrite);          //读写打开

          serial.setBaudRate(QSerialPort::Baud9600);  //波特率
          serial.setDataBits(QSerialPort::Data8);     //数据位
          serial.setParity(QSerialPort::NoParity);    //无奇偶校验
          serial.setStopBits(QSerialPort::OneStop);   //无停止位
          serial.setFlowControl(QSerialPort::NoFlowControl);  //无控制

          serial_flag = 1;      //打开串口,标志为1;
          ui->connectStatus->setText(tr("串口已打开"));

          QMessageBox::information(this, tr("串口配置"), tr("串口已打开!"));

    }else{
        serial.close();
        ui->textBrowser->appendPlainText("串口打开失败");
    }
}

开启定时器,延时接收:

void Widget::com_delay()
{

    //启动定时器,延时15~30ms 等待数据接收完成;
    timer.start(15);
    datagram.append(serial.readAll());
    qDebug() << tr("开始串口接收");

}

读出并打印数据:

void Widget::serialRead()
{

    const char toHex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    //定时器停止
    timer.stop();
    qDebug() << tr("串口接收完成!");

    if(datagram.length() != 0)
        {
            ui->textBrowser->insertPlainText(tr("\n\n【收到数据来自:")+serial.portName()+tr(":")+tr("】\n"));

            //循环打印接收到的数据;
            for(int i=0;i<datagram.size();i++){       //for 循环解析、打印;
                char ch = datagram.at(i);
                QString tmpStr="";
                tmpStr.append(toHex[(ch&0xf0)/16]);
                tmpStr.append(toHex[ch&0x0f]);
                tmpStr.append(" ");
                ui->textBrowser->insertPlainText(tmpStr);
            }
        qDebug() << datagram;
        }
  //  QMessageBox::warning (this,tr("提示信息"),tr("串口接收成功"));
    rcvDataCnt+=datagram.size();
    ui->ReceiveEdit->setText(QString::number(rcvDataCnt,10));

    datagram.clear();         //读取完成之后需要对接收数组进行清空操作;
}

总结:

  以上代码就是针对QT串口延时接收数据的操作,其中toHex数组加入的目的是为了显示十六进制的流式数据,因为在QT的打印串口中,显示的数据类型是QString类型,我这里使用了一个for循环,遍历转换数据类型,非常方便实用,很有参考意义。

最后修改:2020 年 05 月 15 日
您的支持就是我持续更新的动力!