QT串口助手(四):数据发送

作者:zzssdd2

E-mail:zzssdd2@foxmail.com

一、前言

开发环境:Qt5.12.10 + MinGW

实现的功能

  • 串口数据的发送
  • ascii字符与hex字符的相互转换
  • 自动追加回车换行符(\r\n)
  • 发送数据的统计与显示
  • 发送清零
  • 定时发送

涉及的知识点

  • QSerialPort类的使用
  • 数据格式的转换
  • QTimer类的使用
  • 控件QPlainTextEditQCheckBoxQPushButtonQLabel的使用
    在这里插入图片描述

二、功能实现

《QT串口助手(三):数据接收》实现了接收模块的功能,本章讲解发送模块的各个功能。

2.1、字符判断

若勾选了HEX格式发送,那么需要对发送框的字符进行合法判断。这里使用到QPlainTextEdittextChanged信号来监测发送框数据的改变,在槽函数中对数据进行判别:

/*发送文本框信号槽*/
connect(ui->Send_TextEdit, &QPlainTextEdit::textChanged, this, [=](){
    //获取发送框字符
    SendTextEditStr = ui->Send_TextEdit->document()->toPlainText();
    if (SendTextEditStr.isEmpty())
    {
        return;
    }
    //勾选hex发送则判断是否有非法hex字符
    if (ui->HexSend_checkBox->isChecked())
    {
        char ch;
        bool flag = false;
        uint32_t i, len;
        //去掉无用符号
        SendTextEditStr = SendTextEditStr.replace(' ',"");
        SendTextEditStr = SendTextEditStr.replace(',',"");
        SendTextEditStr = SendTextEditStr.replace('\r',"");
        SendTextEditStr = SendTextEditStr.replace('\n',"");
        SendTextEditStr = SendTextEditStr.replace('\t',"");
        SendTextEditStr = SendTextEditStr.replace("0x","");
        SendTextEditStr = SendTextEditStr.replace("0X","");
        //判断数据合法性
        for(i = 0, len = SendTextEditStr.length(); i < len; i++)
        {
            ch = SendTextEditStr.at(i).toLatin1();
            if (ch >= '0' && ch <= '9') {
                flag = false;
            } else if (ch >= 'a' && ch <= 'f') {
                flag = false;
            } else if (ch >= 'A' && ch <= 'F') {
                flag = false;
            } else {
                flag = true;
            }
        }
        if(flag) QMessageBox::warning(this,"警告","输入内容包含非法16进制字符");
    }
    //QString转QByteArray
    SendTextEditBa = SendTextEditStr.toUtf8();
});

[signal]void QPlainTextEdit::textChanged()

This signal is emitted whenever the document’s content changes; for example, when text is inserted or deleted, or when formatting is applied.

Note: Notifier signal for property plainText.

这样我们在进行输入时,如果包含非法字符就会有弹框提示(我这里对’,’、“0x”、"0X"等字符过滤是为了方便有时从代码中直接复制数组数据发送):
在这里插入图片描述

2.2、数据转换

通过是否勾选HEX发送判断使用ascii格式还是hex格式发送数据,使用QCheckBoxstateChanged信号对勾选状态进行检测,然后在对应的槽函数中进行数据格式的转换。

/*HEX发送chexkBox信号槽*/
connect(ui->HexSend_checkBox,&QCheckBox::stateChanged,this,[=](int state){
    if (SendTextEditStr.isEmpty())
    {
        return;
    }
    //asccii与hex转换
    if (state == Qt::Checked)
    {
        //转换成QByteArray -> 转换成16进制数,按空格分开 -> 转换为大写
        SendTextEditBa = SendTextEditBa.toHex(' ').toUpper();
        ui->Send_TextEdit->document()->setPlainText(SendTextEditBa);
    }
    else
    {
        //从QByteArray转换为QString
        SendTextEditStr = SendTextEditBa.fromHex(SendTextEditBa);
        ui->Send_TextEdit->document()->setPlainText(SendTextEditStr);
    }
});

[signal]void QCheckBox::stateChanged(int state)

This signal is emitted whenever the checkbox’s state changes, i.e., whenever the user checks or unchecks it.

state contains the checkbox’s new Qt::CheckState.

在这里插入图片描述

2.3、手动发送

当点击发送按钮时触发QPushButton的点击信号,在对应的槽函数中将发送框的数据按照选定格式发送出去,程序主体如下:

/*
    函   数:on_Send_Bt_clicked
    描   述:发送按键点击槽函数
    输   入:无
    输   出:无
*/
void Widget::on_Send_Bt_clicked()
{
    if (isSerialOpen != false)
    {
        /*将发送框数据发送*/
        SerialSendData(SendTextEditBa);
    }
    else
    {
        QMessageBox::information(this, "提示", "串口未打开");
    }
}

QpushButton继承自QAbstractButton。关于按键点击信号的描述:

[signal]void QAbstractButton::clicked(bool checked = false)

This signal is emitted when the button is activated (i.e., pressed down then released while the mouse cursor is inside the button), when the shortcut key is typed, or when click() or animateClick() is called. Notably, this signal is not emitted if you call setDown(), setChecked() or toggle().

If the button is checkable, checked is true if the button is checked, or false if the button is unchecked.

/*
    函   数:SendData
    描   述:串口发送数据
    输   入:无
    输   出:无
*/
void Widget::SerialSendData(QByteArray baData)
{
    if (baData.isEmpty() != true)
    {
        /*是否加回车换行*/
        if (ui->AddNewLine_Box->isChecked())
        {
            baData.append("\r\n");
        }
        
        if (ui->HexSend_checkBox->isChecked())  // hex发送
        {
            /*获取hex格式的数据*/
            baData = baData.fromHex(baData);
            /*发送hex数据*/
            serial->write(baData);
            /*是否显示时间戳*/
            if (ui->TimeDisp_checkBox->isChecked())
            {
                QString strdata = baData.toHex(' ').trimmed().toUpper();
                ui->Receive_TextEdit->setTextColor(QColor("blue"));
                ui->Receive_TextEdit->append(QString("[%1]TX -> ").arg(QTime::currentTime().toString("HH:mm:ss:zzz")));
                ui->Receive_TextEdit->setTextColor(QColor("black"));
                ui->Receive_TextEdit->insertPlainText(strdata);
            }
        }
        else     //ascii发送
        {
            /*发送ascii数据*/
            serial->write(baData);
            /*是否显示时间戳*/
            if (ui->TimeDisp_checkBox->isChecked())
            {
                QString strdata = QString(baData);
                ui->Receive_TextEdit->setTextColor(QColor("red"));
                ui->Receive_TextEdit->append(QString("[%1]TX -> ").arg(QTime::currentTime().toString("HH:mm:ss:zzz")));
                ui->Receive_TextEdit->setTextColor(QColor("black"));
                ui->Receive_TextEdit->insertPlainText(strdata);
            }
        }
        //移动光标到末尾
        ui->Receive_TextEdit->moveCursor(QTextCursor::End);
        //更新发送计数
        serialDataTotalTxCnt += baData.length();
        ui->TxCnt_label->setText(QString::number(serialDataTotalTxCnt));
    }
    else
    {
        QMessageBox::warning(this, "警告", "数据为空");
    }
}

如果勾选了显示时间戳则在每次数据发送后将数据填充到接收框进行显示;代码中对发送的不同格式数据进行了不同颜色的标记;发送后对发送计数框进行更新。

QSerialPort继承自QIODevice,串口发送数据就是使用QIODevice类的write方法:

qint64 QIODevice::write(const QByteArray&byteArray)

This is an overloaded function.

Writes the content of byteArray to the device. Returns the number of bytes that were actually written, or -1 if an error occurred.

在这里插入图片描述

2.4、定时发送

使用QT中的定时器QTimer按照设定的时间对发送框数据进行自动发送。调用定时器的超时信号来触发槽函数中的发送操作:

/*定时发送定时器*/
TimerSend = new QTimer(this);
/*定时器超时信号槽*/
connect(TimerSend, &QTimer::timeout, this, [=](){
    SerialSendData(SendTextEditBa);
});

[signal]void QTimer::timeout()

This signal is emitted when the timer times out.

Note: This is a private signal. It can be used in signal connections but cannot be emitted by the user.

定时发送被勾选后,会触发QCheckBoxstateChanged信号来设定时间、开启定时器:

/*
    函   数:on_TimeSend_checkBox_stateChanged
    描   述:定时发送框勾选信号对应槽函数
    输   入:无
    输   出:无
*/
void Widget::on_TimeSend_checkBox_stateChanged(int arg1)
{
    int time;

    /*判断串口是否打开*/
    if (false == isSerialOpen)
    {
        if (ui->TimeSend_checkBox->isChecked())
        {
            QMessageBox::information(this, "提示", "串口未打开");
        }
        return;
    }
    /*判断是否有数据*/
    if (ui->Send_TextEdit->document()->isEmpty() == true)
    {
        if (ui->TimeSend_checkBox->isChecked())
        {
            QMessageBox::warning(this, "警告", "数据为空");
        }
        return;
    }
	/*判断勾选状态*/
    if (arg1 == Qt::Checked)
    {
        /*获取设定时间*/
        time = ui->TimeSend_lineEdit->text().toInt();
        if (time > 0) {
            TimerSend->start(time);
        } else {
            QMessageBox::warning(this, "警告", "时间必须大于0");
        }
        ui->TimeSend_lineEdit->setEnabled(false);
    }
    else
    {
        /*停止发送*/
        TimerSend->stop();
        ui->TimeSend_lineEdit->setEnabled(true);
    }
}
  • [slot]void QTimer::start(int msec)

Starts or restarts the timer with a timeout interval of msec milliseconds.

If the timer is already running, it will be stopped and restarted.

If singleShot is true, the timer will be activated only once.

  • [slot]void QTimer::stop()

    Stops the timer.

在这里插入图片描述

三、总结

本章主要讲解数据的发送与格式转换。除了要知道各控件的信号槽应用之外,还应该对QT中数据类型的一些操作方法有所了解。比如上面的代码中使用到的一些QStringQByteArray的常用数据操作方法:QString::replaceQString::atQString::toUtf8QByteArray::toHexQByteArray::fromHex等。

  • 6
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Qt中进行串口通信可以使用Qt串口模块,该模块提供了一些类和函数来实现串口通信的功能。下面是一种常见的查询方式: 1. 首先,需要包含Qt串口头文件: ```cpp #include <QtSerialPort/QSerialPort> #include <QtSerialPort/QSerialPortInfo> ``` 2. 创建一个QSerialPort对象,并设置串口参数: ```cpp QSerialPort serial; serial.setPortName("COM1"); // 设置串口名字,根据实际情况修改 serial.setBaudRate(QSerialPort::Baud9600); // 设置波特率 serial.setDataBits(QSerialPort::Data8); // 设置数据位 serial.setParity(QSerialPort::NoParity); // 设置校验位 serial.setStopBits(QSerialPort::OneStop); // 设置停止位 serial.setFlowControl(QSerialPort::NoFlowControl); // 设置流控制 ``` 3. 打开串口: ```cpp if (serial.open(QIODevice::ReadWrite)) { // 串口打开成功 } else { // 串口打开失败 } ``` 4. 发送查询命令: ```cpp QByteArray requestData = "AT+QUERY\r\n"; // 查询命令,根据实际情况修改 serial.write(requestData); ``` 5. 等待接收数据: ```cpp if (serial.waitForReadyRead(3000)) { // 等待3秒钟 QByteArray responseData = serial.readAll(); // 处理接收到的数据 } else { // 超时,未接收到数据 } ``` 6. 关闭串口: ```cpp serial.close(); ``` 这是一种简单的查询方式,你可以根据实际需求进行修改和扩展。另外,Qt串口模块还提供了信号和槽机制,可以实现异步读取和写入数据,更加灵活和高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值