目录
2.1 串口接收回调函数slots_serialRxCallback()
2.2 串口接收插入时间戳insertTimeStramp(QByteArray &tmp)
2.3 接收显示函数slots_rxDisplayTxt()
三、清空接收文本框on_btnClear_clicked()
工程下载链接:温度助手下载链接
一、复位接收/发送计数器
在temperassistant.h的private slots:自动声明
void on_pushButton_clicked();//复位接收/发送计数器
在temperassistant.h的public:手动声明接收字节数变量
qint32 rxCount = 0; // 接收字节计数
在temperassistant.c中写入代码。
/**
* @brief TemperAssistant::on_pushButton_clicked 复位接收/发送计数器
*/
void TemperAssistant::on_pushButton_clicked()
{
rxCount = 0;//清零
txCount = 0;
ui->lblrxCnt->setText(QString("%1").arg(rxCount));//在ui文本上显示0
ui->lbltxCnt->setText(QString("%1").arg(rxCount));
}
二、串口接收数据程序
2.1 串口接收回调函数slots_serialRxCallback()
在temperassistant.h的public slots:手动声明
void slots_serialRxCallback();//串口接收回调函数
在temperassistant.h的public:手动声明接收标志位和接收时间戳
bool rxFlag = false ;//接收标志位
QTime rxTimeStamp; // 接收数据时间戳
在temperassistant.c中写入代码。
/**
* @brief TemperAssistant::slots_serialRxCallback 接收函数处理
*/
void TemperAssistant::slots_serialRxCallback()
{
rxFlag = true;//接收标志位为真
rxTimeStamp = QTime::currentTime();//添加当前时间戳
}
2.2 串口接收插入时间戳insertTimeStramp(QByteArray &tmp)
在temperassistant.h的public:手动声明插入时间戳
void insertTimeStramp(QByteArray &tmp);// 插入时间戳
在temperassistant.c中写入代码。
/**
* @brief TemperAssistant::insertTimeStramp 插入时间戳
* @param tmp 在tmp前面插入接收时间戳
*/
void TemperAssistant::insertTimeStramp(QByteArray &tmp)
{
QString currentTime = rxTimeStamp.toString("[hh:mm:ss.zzz]Rx:\r\n");//生成当前时间戳的格式
tmp.prepend( currentTime.toLocal8Bit() );//将时间戳放到接收字节的前面
}
2.3 接收显示函数slots_rxDisplayTxt()
在temperassistant.h的public slots:手动声明接收数据处理函数
void slots_rxDisplayTxt();//接收数据处理函数
在temperassistant.h的public:手动声明接收缓存
QByteArray rxBuffer; // 接收缓存
在temperassistant.h的public:手动声明接收缓冲区大小
qint32 rxBufSize = 1024*1024; // 1M buffer
在temperassistant.c中初始化函数中将接收缓冲区设置为设定大小。
currentPort->setReadBufferSize(rxBufSize);//将QSerialPort的内部读取缓冲区的大小设置为rxBufSize大小字节。
在temperassistant.h的public:手动声明ui定时更新时间
QTimer txtFlashTime; // ui定时更新
在temperassistant.c中初始化函数中将定时时间设置为10ms。
txtFlashTime.start(10);//定时时间为10毫秒
并将其与接收显示函数关联
connect(&txtFlashTime,SIGNAL(timeout()),this,SLOT(slots_rxDisplayTxt()));
在temperassistant.c中写入代码。
/**
* @brief TemperAssistant::slots_rxDisplayTxt 接收显示函数
*/
void TemperAssistant::slots_rxDisplayTxt()
{
if(rxFlag)//如果接收标志位为真
{
disconnect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));// 可读缓冲区有数据可用,启用接收数据回调
QByteArray tmp = currentPort->readAll();//读取所有数据返回字节
qDebug()<<"receive tmp:"<<tmp;
/* 读取数据,empty代表没有再接收到数据 */
if( tmp.isEmpty() )//如果接收字节数组为零,返回真
{
if(rxBuffer.isEmpty())return;//接收缓存为零,返回
tmp = rxBuffer;//将接收缓存赋给返回的字节变量
if(ui->chkDisplayHex->isChecked())//如果先择了HEX显示
{
tmp = tmp.toHex(' ').toUpper();//将字节转化为HEX格式并大写
}
QString str ;//定义字符串变量
if(ui->checkBox_2->isChecked())//如果点击了增加时间戳
{
this->insertTimeStramp( tmp );//引用加入接收时间戳函数
if( ui->rdbGB18030->isChecked() )//如果选择了GB18030显示方式
{
QTextCodec *codec = QTextCodec::codecForName("GB18030");
str = codec->toUnicode(tmp);
}
else //否则显示UTF8显示格式
{
str = QString::fromUtf8(tmp);
}
ui->textBrower->appendPlainText(str);
}
else//否则不加入时间戳
{
if( ui->rdbGB18030->isChecked() )
{
QTextCodec *codec = QTextCodec::codecForName("GB18030");
str = codec->toUnicode(tmp);
}
else
{
str = QString::fromUtf8(tmp);
}
ui->textBrower->insertPlainText(str);
}
if( txtStreamSave != NULL )
{
txtStreamSave->operator<<( str );
}
rxBuffer.clear();
rxFlag = false;// 标记为false,只有在下一次触发readyRead信号的时候才会进入这里
connect(currentPort, SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));// 接收数据回调
}
else
{
rxBuffer.append(tmp);
rxCount += tmp.size();//接收字符计数
if( rxCount > rxBufSize )//如果接收计数大于定义的接收缓冲区1M Buffer,则全部清零
{
rxBuffer.clear();
rxCount = 0;
}
}
}
ui->lblrxCnt->setText( QString::number(rxCount) );//显示接收字符数
}
注意:这么写入,在执行程序的时候由于接收标志位rxFlag = false,所以正常执行slots_rxDisplayTxt()是不会进入处理的,所以需要进行一个初始化配置。也就是需要将rxFlag = true,我们看到slots_serialRxCallback()
可以实现标志位的功能,并且只有当接收到数据的时候才会进入这个接收回调函数,我们将接收数据信号和接收回调函数用这个程序实现:
connect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));
而这句程序放在配置串口参数的configPort()函数中:如下
/**
* @brief TemperAssistant::configPort配置端口的波特率\数据位\奇偶校验\停止位
*/
void TemperAssistant::configPort()
{
QVariant tmpVariant;
/* 设置波特率 */
tmpVariant = ui->cbbBaud->currentData(); // 读取控件的当前项的值
currentPort->setBaudRate(tmpVariant.value < BaseSerialComm::BaudRate > () );
/* 设置数据位 */
tmpVariant = ui->cbbDataBit->currentData();
currentPort->setDataBits( tmpVariant.value <BaseSerialComm::DataBits > () );
/* 设置校验位 */
tmpVariant = ui->cbbVerify->currentData();
currentPort->setParity (tmpVariant.value < BaseSerialComm::Parity > () );
/* 设置停止位 */
tmpVariant = ui->cbbStopBit->currentData();// 某些情况不支持1.5停止位
if(currentPort->setStopBits (tmpVariant.value < BaseSerialComm::StopBits > () ) == false ){
ui -> cbbStopBit->clear();
BaseSerialComm::listStopBit ( ui -> cbbStopBit );
QMessageBox::information(NULL, tr("不支持的设置"), tr("该串口设备不支持当前停止位设置,已修改为默认的设置"), 0, 0);
}
currentPort->setDataTerminalReady(false);
currentPort->setRequestToSend(false);
connect(currentPort ,SIGNAL(readyRead()),this,SLOT( slots_serialRxCallback()));
qDebug()<<"进入串口配置函数";
}
所以在打开串口按钮的程序中,我们打开串口,就配置了等待接收数据的信号,如果数据接收,则发送信号,直接关联到接收回调函数,使标志位rxFlag = true,
我们在初始化程序中用定时器不断定时进入slots_rxDisplayTxt()接收数据处理并显示槽函数。
具体流程如下:
三、清空接收文本框on_btnClear_clicked()
在temperassistant.h的private slots:自动声明清空接收文本函数
void on_btnClear_clicked();//清空接收文本框
在temperassistant.c中写入代码。
/**
* @brief TemperAssistant::on_btnClear_clicked 清空接收文本框和缓存
*/
void TemperAssistant::on_btnClear_clicked()
{
ui->lblrxCnt->clear();
ui->lbltxCnt->clear();
ui->textBrower->clear();
rxBuffer.clear();
rxCount = 0;
txCount = 0;
ui->lblrxCnt->setText(QString("%1").arg(rxCount));
ui->lbltxCnt->setText(QString("%1").arg(rxCount));
}