QT는 직렬 포트 디버깅 지원을 실현합니다 (2) : 기본 직렬 포트 기능을 실현합니다.

 

프로젝트 소스 코드 : https://github.com/zhangfls/QT_UartAnalysisTool

 

이전:

QT는 직렬 디버깅 도우미를 실현합니다. (1)

 

하나, 라이브러리 가져 오기

1. 프로젝트 .pro 파일에 직렬 포트 추가

QT       += core gui
QT       += serialport

2. qt에서 직렬 통신에 필요한 헤더 파일을 소개합니다.

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

둘째, 직렬 포트 초기화 구성

1. 사용 가능한 직렬 포트를 검색합니다.

comobox를 생성하면 사용 가능한 직렬 포트 목록이 표시되고 구성 중에 연결할 직렬 포트를 선택하는 데 사용됩니다.

//查找可用串口,刷新串口信息
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. 직렬 포트를 구성합니다.

(1) 직렬 포트의 구성에는 적어도 직렬 포트 번호, 전송 속도, 데이터 비트, 정지 비트, 패리티 비트 및 흐름 제어가 포함되어야하며, 모두 직렬 포트 인스턴스의 기능을 호출하여 구성 할 수 있습니다. 선택할 여러 comobox 또는 텍스트 상자를 추가하거나 기본적으로 초기화 할 때 구성 할 수 있습니다.

//配置串口初始化
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) 시리얼 포트를 열고 닫는 버튼을 추가하고, "open serial port"라고 표시되면 클릭하여 시리얼 포트를 닫습니다. 텍스트 디스플레이 "Close serial port"는 반대입니다.
(3) 직렬 포트를 열 때 구성 항목의 모든 상자를 비활성화하여 수정할 수 없도록하고 닫았을 때 복원합니다.

//串口开关按钮
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("打开串口");
    }
}

셋, 직렬 포트 데이터 읽기

1. 데이터를 읽기 위해 타이머와 타이머를 생성합니다. 해결해야 할 두 가지 문제가 있기 때문에 하나는 시리얼 포트가 일정 시간 동안 데이터를 수신하지 못한 경우 하나의 수신 완료를 판단하고 데이터를 처리하고 버프를 제거하는 데 사용되는 타임 아웃 간격이 필요하다는 것입니다. . 둘째, 시리얼 포트가 지속적으로 수신 된 시간을 세는 카운트가 필요합니다. 데이터가 연속적이라하더라도 고정 된 시점에 수신 완료를 강제로 판단하고 데이터를 처리하고 버프를 제거해야합니다. 데이터는 처리되지 않을 수 있습니다.

1. 타이머 초기화

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

2. ReadData를 구현합니다. 타이머가 지정된 간격을 초과하면 수신 된 버프 버퍼를 강제로 처리하고 나머지 시간 동안 데이터를 버퍼에 넣고 타이머를 다시 시작합니다.

//读取串口接收消息
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. 타이머 수신 완료 (일정 시간 동안 데이터 수신이 없으면 타이머 만료)

타임 스탬프 선택 여부에 따라 데이터 내용을 입력하고 데이터가 저장된 텍스트 상자에 삽입합니다.

//定时器触发打印串口数据
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. 동시에 시간 제한 간격을 구성하는 옵션이 필요합니다.

(1) 초기화 중 구성 상자 추가

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

(2) 작동 중 타임 아웃 간격 설정

//超时间隔设置
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();
}

넷, 데이터 보내기

추가 구성없이 데이터를 전송하고 쓰기 기능을 호출하기 만하면 실제 상황에 따라 일부 구성 또는 검증 처리를 수행 할 수 있습니다. 캐리지 리턴 및 줄 바꿈 추가 등

//发送串口数据
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());
}

이 시점에서 가장 기본적인 직렬 포트 디버깅 도구가 완성되었으며 다음은 여기에 기능과 최적화를 추가하는 것입니다.

 

다음:

QT는 직렬 포트 디버깅 도우미를 실현합니다. (3)

 

추천

출처blog.csdn.net/zhangfls/article/details/109593287