串口通信中QByteArray的数据转换

原文链接:https://blog.csdn.net/qq_34322603/article/details/106457231

QByteArray在串口通讯中经常被使用,通信处理过程中,经常会涉及到数据格式的转换,有一定必要较为全面详细的对QByteArray数据转换与处理部分进行阐述。本文通过以下几个部分加以介绍:

1 字符串发送与十六进制发送的区别

在使用串口发送数据时可以选择字符串发送或者十六进制发送,通常情况下我们习惯选用字符串发送数据。关于两者的区别,需要从计算机存储数据的格式说起。
在计算机中,数据是以二进制的形式存储的,例如十进制 1(10)在计算机中用 0000 0001(2)来表示。在使用字符串方式发送数据的时候,串口软件首先将待数据转换为对应的ASCII码,然后再将这些ASCII码按照二进制的方式一位一位的发送出去;而使用十六进制方式发送数据的时候,串口直接将数据以二进制的方式一位一位的发送出去。
例如我们在串口软件发送框输入 “FF012345”,分别以字符串和十六进制两种方式发送:

1.1 字符串发送

串口以字符串发送数据,首先将字符串转化为ASCII码对应的二进制,格式如下

在这里插入图片描述
串口发送了8个字节,若在接收端选择字符串接收,则会接收到FF0123456这个字符串;若在接收端选择十六进制接收,则会接收到:
0100 0110 | 0100 0110 | 0011 0000 | 0011 0001 | 0011 0010 | 0011 0011 | 0011 0100 | 0011 0101 这一串数字

1.2 十六进发送

串口以十六进制发送数据,首先将发送框中数据转化为如下格式:
在这里插入图片描述
串口发送了4个字节,若在接收端选择十六进制接收,则会在接收框显示FF 01 23 45;若在接收端选择字符串接收,则会接收到乱码

仔细对照接收结果就很容易明白字符串发送和十六进制发送的区别了。

2 QByteArray数据转换与处理

从串口读取到的QByteArray数据,一般需要进行提取和解析,此时就需要QByteArray转换为各类型数据。常用转换包括:

1、字符与十六进制转换,例如串口接收到的数据,用字符方式表达,或者将字符串对应的十六进制数据流转化为字符串;

2、转为不同进制数值并显示,如二进制、八进制、十进制和十六进制等;

3、转为整型、浮点型等数值类型;

4、大小写转换;

5、转为字符串类型;

2.1 十六进制-字符

把Hex编码的数据流转换为char存储到QByteArray:

QByteArray text = QByteArray::fromHex("517420697320677265617421");
text.data();            //  "Qt is great!"

把QByteArray数据转换为字符串:

QByteArray ba;
ba.resize(3);
ba[0] = 0x30;
ba[1] = 0x31;
ba[2] = 0x32;
qDebug() << ba.toHex(); //return "303132"

2.2 数值转换与输出

尽管QByteArray是一个集合,但也可以作为一个特殊形式的数值用,其灵活的转换格式,可大大方便各种格式数据转换与显示的需求。如显示二进制和十六进制、显示科学计数和指定小数位的数值。示例如下:
把单个字符转为2-36进制数据格式:

int n = 63;
qDebug()<<QByteArray::number(n);              // returns "63"
qDebug()<<QByteArray::number(n, 16);          // returns "3f"
qDebug()<<QByteArray::number(n, 16).toUpper();  // returns "3F"
qDebug()<<QByteArray::number(n, 2);          // returns "111111"
qDebug()<<QByteArray::number(n, 8);          // returns "77"

按照指定进制格式直接复制,其中n可以是各类常见数值类型:

int n = 63;
qDebug()<<QByteArray::number(n);              // returns "63"
qDebug()<<QByteArray::number(n, 16);          // returns "3f"
qDebug()<<QByteArray::number(n, 16).toUpper();  // returns "3F"
qDebug()<<QByteArray::number(n, 2);          // returns "111111"
qDebug()<<QByteArray::number(n, 8);          // returns "77"

按照指定进制格式直接复制,其中n可以是各类常见数值类型:

QByteArray ba;
int n = 63;
ba.setNum(n);           // ba == "63"
ba.setNum(n, 16);       // ba == "3f"

把数值按指定格式和小数位转换输出,小数位四舍五入:

QByteArray ba1 = QByteArray::number(12.3456, 'E', 3);
QByteArray ba2 = QByteArray::number(12.3456, 'f', 3);
qDebug()<<ba1;  // returns "1.235E+01"
qDebug()<<ba2;  // returns "12.346"

2.3 字符串数值转为各类数值

QByteArray若为数值,可通过to**方法转为各种类型数据,示例如下:

QByteArray strInt("1234");
bool ok0;
qDebug() << strInt.toInt();   // return 1234
qDebug() << strInt.toInt(&ok0,16);   // return 4660, 默认把strInt作为16进制的1234,对应十进制数值为4660
 
QByteArray string("1234.56");
bool ok1;
qDebug() << string.toInt();   // return 0, 小数均视为0
qDebug() << string.toInt(&ok1,16);   // return 0, 小数均视为0
qDebug() << string.toFloat();   // return 1234.56
qDebug() << string.toDouble();   // return 1234.56
 
QByteArray str("FF");
bool ok2;
qDebug() << str.toInt(&ok2, 16);     // return 255, ok2 == true
qDebug() << str.toInt(&ok2, 10);     // return 0, ok == false, 转为十进制失败

2.4 大小写转换

QByteArray若为带大小写的字符串,可通过toUpper()和toLower()方法实现大小写转换,示例如下:

QByteArray x("Qt by THE QT COMPANY");
QByteArray y = x.toLower();
// y == "qt by the qt company"
 
QByteArray z = x.toUpper();
// z == "QT BY THE QT COMPANY"

2.5 与字符串互转

QByteArray与QString互转极为简单,二者从本质上类似,都是连续存储,区别是前者可以存无法显示的字符,后者只存可显示的字符。如QByteArray可以存0x00-0x19,而QString则存储如0x30等可显示字符(0x20-0x7E)。可显示字符可参见ASCII表,链接如下:ASCII可显示字符

QByteArray转为QString示例:

QByteArray ba("abc123");
QString str = ba; 
//或str.prepend(ba);
qDebug()<<str ;
//输出:"abc123"

QString转为QByteArray示例:

QString str("abc123");
QByteArray ba = str.toLatin1();
qDebug()<<ba;
//输出:"abc123"

3 实际使用示例

(用于读取textEdit中的字符串数据,并转换为16进制数据,用于串口通信)
例:如果某次传输的数据为0x30 0x38 0x0D 0x32(二进制原始数据),从输入控件textEdit中输入30 38 0D 32,此时从textEdit读取的为字符串"30 38 0D 32",所以要将其转换为二进制0x30 0x38 0x0D 0x32,存入QByteArray中。

QString str1 = ui->lineEdit_SendCmd->text();
QByteArray cmd = QByteArray::fromHex(str1.toLatin1().data()); //按照十六进制编码接入文本

同理:将二进制数据转换为字符串:

ba.resize(3);
ba[0] = 0x30;
ba[1] = 0x31;
ba[2] = 0x32;
qDebug() << ba.toHex(); //return "303132"
//注意收发两端文本要使用对应的编解码
const QByteArray recv_test = socket->readAll();
dataParse(recv_test);
//qDebug()<<"recv msg:"<<recv_test;
QString ret;
QByteArray ba = recv_test.toHex(' ');
qDebug()<<"ba: "<<ba;
//for (int i=0; i<recv_test.count(); ++i) {
//ret.append(tr("%1 ").arg((quint8)recv_test.at(i),2,16,QLatin1Char('0')).toUpper());
//}
ui->textEdit_message->append(ba.toUpper()); // ret换成ba

在这里插入图片描述

//接收串口数据以字符和十六进制数据显示 
    QByteArray temp = myCom->readAll(); 
    //读取串口缓冲区的所有数据给临时变量temp 
    ui.textBrowser->insertPlainText(temp); 
    ui.textEdit_2->insertPlainText(temp.toHex()); 
    //将串口的数据显示在窗口的文本浏览器中 
在使用串口进行通信时,需要确保发送端和接收端的串口通信配置和数据格式一致,否则就会出现通信错误。 串口通信的配置包括波特率、数据位、校验位、停止位等参数。发送端和接收端的串口通信配置必须一致,才能正常进行通信。你可以使用 `QSerialPort` 类的函数来设置串口参数,例如: ``` serialport.setBaudRate(QSerialPort::Baud115200); serialport.setDataBits(QSerialPort::Data8); serialport.setParity(QSerialPort::NoParity); serialport.setStopBits(QSerialPort::OneStop); ``` 这样就设置了波特率为 115200,数据位为 8,无校验位,停止位为 1 的串口通信参数。需要根据实际情况进行设置。 串口通信数据格式可以是二进制数据或者文本数据。如果使用文本数据进行通信,需要确保发送端和接收端使用相同的字符编码方式,例如 ASCII 编码或 UTF-8 编码。如果发送端和接收端使用不同的编码方式,就会出现乱码等问题。 在读取串口数据时,可以使用 `bytesAvailable()` 函数查询串口接收缓冲区数据长度,然后再使用 `read()` 函数读取指定长度的数据。例如: ``` if(serialport.bytesAvailable() >= 22) { QByteArray data = serialport.read(22); // 读取 22 个字节的数据 QString msg = QString::fromLatin1(data); // 转换为 QString 类型 // ... } ``` 其的 `fromLatin1()` 函数可以将字节数组转换为 ASCII 编码的字符串。如果使用 UTF-8 编码,可以使用 `fromUtf8()` 函数。 需要注意,当串口接收缓冲区数据长度不足时,`read()` 函数会阻塞等待,直到有足够的数据可读。因此,如果需要实现非阻塞读取数据,可以使用 `waitForReadyRead()` 函数等待一段时间,或者使用信号槽机制实现数据接收。 最后,建议在进行串口通信时,先使用简单的数据格式和通信协议进行测试,确保通信能够正常进行。如果需要使用复杂的数据格式和通信协议,可以考虑使用现有的通信协议库,例如 Modbus、CANopen 等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值