QT realizes serial port debugging assistant (two): realizes basic serial port functions

 

Project source code: https://github.com/zhangfls/QT_UartAnalysisTool

 

Previous:

QT realizes serial debugging assistant (1)

 

One, import the library

1. Add serialport to the project .pro file

QT       += core gui
QT       += serialport

2. Introduce the header files needed for serial communication in qt

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

Two, configure serial port initialization

1. Search for available serial ports.

By creating a comobox, the list of available serial ports is displayed and used to select the serial port to be connected during configuration

//查找可用串口,刷新串口信息
void MainWindow::GetAveriablePort()
{
     ui->uartReadPlain->insertPlainText("串口初始化:\r\n");

     //先清除所有串口列表
      ui->portBox->clear();

    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        QSerialPort serial;
        serial.setPort(info);

        if(serial.open(QIODevice::ReadWrite))
        {
            ui->uartReadPlain->insertPlainText("可用:"+serial.portName()+"\r\n");
            ui->portBox->addItem(serial.portName());
            serial.close();
        }
        else
        {
            ui->uartReadPlain->insertPlainText("不可用:"+serial.portName()+"\r\n");
        }
    }
}

 

2. Configure the serial port.

(1) The configuration of the serial port should include at least the serial port number, baud rate, data bit, stop bit, parity bit, and flow control, all of which can be configured by calling the function of the serial port instance. You can add several comoboxes or text boxes to choose, or you can configure it when you initialize by default.

//配置串口初始化
void MainWindow::PortConfigureInit()
{
    //填入串口选项
    ui->rateBox->addItem("115200","115200");
    ui->rateBox->addItem("38400","38400");
    ui->rateBox->addItem("19200","19200");
    ui->rateBox->addItem("9600","9600");

    ui->dataBox->addItem("8",8);
    ui->dataBox->addItem("7",7);

    ui->checkBox->addItem("无校验",0);

    ui->stopBox->addItem("1位",1);
    ui->stopBox->addItem("2位",2);

}

(2) Add a button to open and close the serial port. When the text shows "open serial port", click to close the serial port. The text display "Close serial port" is the opposite.
(3) When opening the serial port, disable all the boxes of the configuration items to make them unmodifiable, and restore them when closed

//串口开关按钮
void MainWindow::on_openSerialButton_clicked()
{
    //尝试打开串口
    if(ui->openSerialButton->text() == tr("打开串口"))
    {
        if(ui->portBox->currentText() == "" )
        {
            QMessageBox::warning(NULL, "警告", "无可开启串口!\r\n\r\n");
            return;
        }

        serial = new QSerialPort;
        //设置串口名
        serial->setPortName(ui->portBox->currentText());
        //打开串口
        serial->open(QIODevice::ReadWrite);
        //设置波特率
        serial->setBaudRate(ui->rateBox->currentText().toInt());
        //设置数据位
        switch (ui->dataBox->currentData().toInt())
        {
            case 8:
                serial->setDataBits(QSerialPort::Data8);
                break;
            case 7:
                serial->setDataBits(QSerialPort::Data7);
                break;
            default:
                break;
        }
        //设置校验位
        switch (ui->checkBox->currentIndex())
        {
            case 0:
                serial->setParity(QSerialPort::NoParity);
                break;
            default:
                break;
        }
        //设置停止位
        switch(ui->stopBox->currentIndex())
        {
            case 0:
                serial->setStopBits(QSerialPort::OneStop);
                break;
            case 1:
                serial->setStopBits(QSerialPort::TwoStop);
                break;
            default:
                break;
        }
        //设置流控制
        serial->setFlowControl(QSerialPort::NoFlowControl); //设置为无流控制

        //关闭设置菜单使能
        ui->portBox->setEnabled(false);
        ui->dataBox->setEnabled(false);
        ui->checkBox->setEnabled(false);
        ui->stopBox->setEnabled(false);
        ui->rateBox->setEnabled(false);
        ui->openSerialButton->setText("关闭串口");

        fTimeCounter.restart();  //计时器重新计数

        //连接信号和槽函数,串口有数据可读时,调用ReadData()函数读取数据并处理。
        QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);
    }
    else
    {
        uartRecDataTimer->stop () ; //定时器停止

        if(serial->isOpen())       //原先串口打开,则关闭串口
        {
            serial->close();
        }

        //释放串口
        delete serial;
        serial = NULL;

        //恢复使能
        ui->portBox->setEnabled(true);
        ui->rateBox->setEnabled(true);
        ui->dataBox->setEnabled(true);
        ui->checkBox->setEnabled(true);
        ui->stopBox->setEnabled(true);
        ui->openSerialButton->setText("打开串口");
    }
}

Three, read the serial port data

1. In order to read data, create a timer and a timer. Because there are two problems to be solved, one is that we need a timeout interval, which is used to judge the completion of one reception when the serial port fails to receive data for a certain period of time, process the data and clear the buff. Second, we need a count to count how long the serial port has been continuously received. Even if the data is continuous, we must forcefully judge the completion of a reception at a fixed time point, process the data and clear the buff, otherwise the data may never be processed. .

1. Initialize the timer

    //设置uart接收缓冲超时定时器
    uartRecDataTimer = new QTimer(this);
    uartRecDataTimer->stop();
    uartRecDataTimer->setInterval(uartRecOvertimeCount*1000);                     //设置定时周期,单位:毫秒
    uartRecDataTimer->setSingleShot(true);                                        //设置为单次触发
    connect(uartRecDataTimer,SIGNAL(timeout()),this,SLOT(uartRec_timeout()));     //设置槽

2. Implement ReadData. After the timer exceeds a specified interval, the received buff buffer is forced to be processed, and the data is put into the buffer for the rest of the time, and the timer is restarted

//读取串口接收消息
void MainWindow::ReadData()
{
    //串口可读数据长度
    int byteLen = serial->bytesAvailable();
    if(byteLen < 0)
    {
        return;
    }

    rec_buf_len += byteLen;
    uart_rec_ss.append(serial->readAll());  //读取数据

    //计时器超过最大间隔仍未填入数据,强制填入
    if(fTimeCounter.elapsed() >2000 && uart_rec_ss.size()>0)
    {
        ui->uartReadPlain->moveCursor(QTextCursor::End);        //光标移动到结尾
        ui->uartReadPlain->insertPlainText(uart_rec_ss);
        ui->uartReadPlain->moveCursor(QTextCursor::End);        //光标移动到结尾
        uart_rec_ss.clear();
    }

    //定时器开始工作、定时器重启
    uartRecDataTimer->start();
}

3. The timer reception is completed (there is no data reception for a period of time, and the timer expires)

According to whether the timestamp is selected, fill in the data content and insert it into the text box where the data is stored

//定时器触发打印串口数据
void MainWindow::uartRec_timeout()
{
    if(!uart_rec_ss.isEmpty())
    {
        curDateTime = QDateTime::currentDateTime();
        ui->uartReadPlain->moveCursor(QTextCursor::End);            //光标移动到结尾

        if(ui->timeZoneCheckBox->isChecked())
        {
            ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"R:");
            ui->uartReadPlain->moveCursor(QTextCursor::End);        //光标移动到结尾
            ui->uartReadPlain->insertPlainText(uart_rec_ss);
        }
        else
        {
            ui->uartReadPlain->insertPlainText(uart_rec_ss);
        }
        ui->uartReadPlain->moveCursor(QTextCursor::End);            //光标移动到结尾
        uart_rec_ss.clear();
        fTimeCounter.restart();
        ui->RXLenLabel->setText(QString::number(rec_buf_len)+"bytes");
    }
}

4. At the same time, we need an option to configure the timeout interval

(1) Add a configuration box during initialization

    //设置时间输入框只允许使用数字
    ui->overTimeRecEdit->setValidator(new QRegExpValidator(QRegExp("^([0-9]{1,4}(.[0-9]{1,3})?)$")));
    ui->overTimeRecEdit->setText(QString::number(uartRecOvertimeCount));

(2) Configure the timeout interval during operation

//超时间隔设置
void MainWindow::on_overTimeRecEdit_returnPressed()
{
    if(ui->overTimeRecEdit->text().toFloat()>60)
    {
        QMessageBox::warning(NULL,"警告","超时时间不要超过1分钟");
        ui->overTimeRecEdit->setText("0.1");
        return;
    }
    uartRecOvertimeCount = ui->overTimeRecEdit->text().toFloat();
    ui->uartReadPlain->insertPlainText("设置超时时间为:"+QString::number(uartRecOvertimeCount*1000)+"ms");
    uartRecDataTimer->setInterval(uartRecOvertimeCount*1000);                       //设置定时周期,单位:毫秒

    fTimeCounter.restart();
    uartRecDataTimer->start();
}

Four, send data

Simply send data without any additional configuration, just call the write function, you can do some configuration or verification processing according to your actual situation. Such as adding carriage return and line feed or something

//发送串口数据
void MainWindow::on_sendDataButton_clicked()
{
    //未打开串口则不准发送
    if(ui->openSerialButton->text() == "打开串口")
    {
        QMessageBox::warning(NULL, "警告", "未打开可用串口,无法发送数据!\r\n\r\n");
        return;
    }

    //获取发送的命令,并选择在结尾加上换行,AT的命令结尾必须有回车换行
    QString command = ui->uartWritePlain->toPlainText();
    if(ui->changeLineCheckBox->isChecked())
    {
        command += "\r\n";
    }

    if(ui->timeZoneCheckBox->isChecked())
    {
         curDateTime = QDateTime::currentDateTime();
         ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"SEND:"+command);
    }

    send_buf_len += command.length();
    ui->TXLenLabel->setText(QString::number(send_buf_len)+"bytes");

    serial->write(command.toLatin1());
}

At this point, a most basic serial port debugging tool is completed, the following is to add functions and optimizations to it

 

Next:

QT realizes serial port debugging assistant (3)

 

Guess you like

Origin blog.csdn.net/zhangfls/article/details/109593287