シリアルポート間のデータ送信アルゴリズム
序文
C++では、演算ミスを防ぐために以下の方法で変数のスコープを取得することができます。
#include "limits" //获取变量的范围
qDebug()<<"unsigned char 的范围(0x00-0xFF):"<<std::numeric_limits<unsigned char>::min()<<"~"<<std::numeric_limits<unsigned char>::max();
【1】Qtインターフェース設計図
処理: char、shortt、intをそれぞれスロットに転送し、シリアルポート間のデータ解析をシミュレートします。
【2】シリアルポートのchar型の例
符号なし1バイトの例
unsigned char value;
unsigned char 的范围(0x00-0xFF): 0 ~ 255
value 十进制 = "255"
value 十六进制 = "0xff"
value 二进制 = "11111111"
注: unsigned char 型は 0 ~ 255 の 10 進数を保存できます。バイト配列を作成してさらに多くの整数を保存し、MCU シリアル ポートから Qt ホスト コンピューターのシリアル ポートに送信できます。
unsigned char sendSerialdatas[5] = {
0}; //MCU
現在のシリアル ポート データは、1 バイト文字タイプに変換することによってのみ送受信できることを知っておく必要があります。これは最も便利な操作でもあります。
シリアルポートによる正の数値の送受信の例
安全ではない、可読性が低い、実装が早い
MCU
// 第一种正数为例
unsigned char value = 255;
unsigned char sendSerialdatas[5] = {
0};
// MCU将255这个数值传给UI怎么做,如下:
// 写法1 数据打包
sendSerialdatas[0] = value; //直接将一个字节,八位的数赋值给一个字节,你可以选择十进制形式或者十六进制。
sendSerialdatas[1] = 254;
sendSerialdatas[2] = 253;
sendSerialdatas[3] = 2;
sendSerialdatas[4] = 1;
// 发送到Qt端
sendToLinuxQt(arrayname,len);
Qt
// Qt UI直接解析MCU数据即可,因为1字节已经是串口传输的最小数据了。
// 假定读取串口数据存入字节组
QByteArray data = 获取串口所有数据;
quint8 recvSerialdatas[32] = {
0};
for (int i =0; i < data.size(); i++) {
recvSerialdatas[i] = (unsigned char)data.at(i); //在qt中最好强制转化以下,根据你上传的数据类型一一对应。
}
印刷データは以下の通りです
安全、読みやすい、実装に時間がかかる
最大サイズは 255 までしか格納できません、& 演算
1&1=1;
1&0=0;
0&1=0;
0&0=0; 乗算と同様
& 0xFF 説明: 値のデータ型に関係なく、必要なのは下位 8 ビットだけです。たとえば、割り当て: 1111 1111 1111 1110、明らかに 16 ビットであれば、バイト配列は最大でも 0xFF までしか到達できず、0xFF は下位 8 ビットであるため、必要なのは 1111 1110 だけです。したがって、バイト配列の範囲を超える値をバイト配列に直接代入しないでください。
明確
1111 1111 1111 1110
&
000 0000 1111 1111
——————————
0000 0000 1111 1110 --》》保留1111 1110
MCU
// 写法2 安全的操作,隐含会将十进制转化为二进制在内存存储。
sendSerialdatas[0] = value & 0xFF;
sendSerialdatas[1] = 254 & 0xFF;
sendSerialdatas[2] = 253 & 0xFF;
sendSerialdatas[3] = 2 & 0xFF;
sendSerialdatas[4] = 1 & 0xFF;
Qt
// Qt UI直接解析MCU数据即可,因为1字节已经是串口传输的最小数据了。
// 假定读取串口数据存入字节组
QByteArray data = 获取串口所有数据;
// UI直接解析即可,因为1字节已经是串口传输的最小数据了。
quint8 recvSerialdatas1[32] = {
0};
for (int i = 0; i < data1.length(); i++) {
recvSerialdatas1[i] = (unsigned char)data1.at(i);
ui->plainTextEdit_2->appendPlainText(QString("recvSerialdatas[%1] = %2").arg(i).arg(recvSerialdatas1[i] & 0xFF)); //解析并显示,&0xFF代表接收的数必须是1字节范围内。
}
印刷データは以下の通りです
シリアルポート経由で負の数値を送受信する例
C では、char 型の範囲は、符号付きか符号なしかに応じて、-128 ~ 127 (signed char) または 0 ~ 255 (unsigned char) です。
負の数の場合は、元のコードと補数コードが何であるかを理解する必要があります。
`
假设我们使用8位二进制表示法,以下是一个正数的原码、反码和补码的举例:
原码:00110110
反码:00110110
补码:00110110
其中原码、反码和补码都表示十进制数54。符号位是0(最高位)
`
`
假设使用8位二进制表示法,以-3为例:
原码:10000011
反码:11111100
补码:11111101
符号位1(最高位)
`
それで、何に気づきましたか。。。
正の数か負の数かを判断する条件:符号ビット。
MCUとUIを組み合わせた例
//实现串口数据的收发 1字节数组为例
void MainWindow::on_pb_char_clicked()
{
// MCU上传负数
char value = -128;
char sendSerialdatas[5] = {
0}; //MCU
// 写法2 MCU数据打包
sendSerialdatas[0] = value;
sendSerialdatas[1] = -127;
sendSerialdatas[2] = 126;
sendSerialdatas[3] = 2;
sendSerialdatas[4] = -1;
// MCU数据作为串口1
for (int i = 0; i < 5; ++i) {
ui->plainTextEdit_1->appendPlainText("转为十进制显示 = "+ QString::number(sendSerialdatas[i]));
}
// 假定UI读取串口数据存入字节组
QByteArray data1;
for (int i = 0; i < 5; ++i) {
data1.append(sendSerialdatas[i]);
}
// UI直接解析即可,因为1字节已经是串口传输的最小数据了。
char recvSerialdatas1[32] = {
0};
for (int i = 0; i < data1.length(); i++) {
recvSerialdatas1[i] = (char)data1.at(i);
ui->plainTextEdit_2->appendPlainText(QString("recvSerialdatas[%1] = ").arg(i)+ QString::number(recvSerialdatas1[i],10));
}
}
実行結果
【3】シリアルポートショートタイプの例
符号なし2バイトの例
unsigned short 的范围(0x00-0xFFFF): 0 ~ 65535
value 十进制 = "65535"
value 十六进制 = "0xffff"
value 二进制 = "1111111111111111"
バイト配列が 1 バイトしか格納できないことを知るには、2 バイトを 2 つの部分に分けて格納する必要があります。
誰が上位 8 ビットを格納し、誰が下位 8 ビットを格納するかに関係なく、これはビッグ エンディアンとリトル エンディアンに関するものです。
ビッグエンディアンとリトルエンディアン
ビッグ エンディアンとリトル エンディアンはデータを指します
在内存中存储的方式
。0x12345678 を例として挙げると、メモリ内のそのストレージは次のようになります。
ビッグエンディアン:
高位字节(0x12)在前,低位字节(0x78)在后。
リトルエンディアン:低位字节(0x78)在前,高位字节(0x12)在后。
たとえば、値 0x12345678 を格納する 32 ビット整変数 x があるとします。
マシンがビッグエンディアンの場合、x は次のようにメモリに格納されます。
+----+----+----+----+
| 12 | 34 | 56 | 78 |
+----+----+----+----+
buf[0] buf[1] buf[2] buf[3]
マシンがリトル エンディアンの場合、x は次のようにメモリに格納されます。
+----+----+----+----+
| 78 | 56 | 34 | 12 |
+----+----+----+----+
buf[0] buf[1] buf[2] buf[3]
シリアルポートによる正の数値の送受信の例
肯定的な例
方法 1 は間違っています 方法 2 は正しいです
// 实现串口数据的收发 2字节数组为例
void MainWindow::on_pb_shorft_clicked()
{
ui->plainTextEdit_1->appendPlainText(QString("方法1直接将2字节十进制数存入字节数组通过串口发给UI(会有警告,只能获取2字节中的低字节的八位)"));
// MCU上传UI正负数
// 第一种正数为例(错误示范)
unsigned short value;
qDebug()<<"unsigned short 的范围(0x00-0xFFFF):"<<std::numeric_limits<unsigned short>::min()<<"~"<<std::numeric_limits<unsigned short>::max();
value = 65535;
qDebug()<<"value 十进制 = "<<QString::number(value,10)<<" value 十六进制 = "<<"0x"+QString::number(value,16)<<" value 二进制 = "<<QString::number(value,2);
unsigned char sendSerialdatas[6] = {
0}; //MCU
// MCU将65535这个数值传给UI怎么做,如下:
// 写法1 错误示范
sendSerialdatas[0] = value; //直接将2字节数赋值给一个字节
sendSerialdatas[1] = 65534; //FFFE ->>1111 1111 (低八位)1111 1110 = 255
sendSerialdatas[2] = 65533; //FFFD-> = 254
sendSerialdatas[3] = 257; //0001 (低八位)0000 0001 = 1
sendSerialdatas[4] = 256; //0001 (低八位)0000 0000 = 0
// MCU数据作为串口1
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[0] = %1 ->十六进制=%2->二进制=%3").arg(value).arg(QString::number(value,16)).arg(QString::number(value,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[1] = %1 ->十六进制=%2->二进制=%3").arg(65534).arg(QString::number(65534,16)).arg(QString::number(65534,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[2] = %1 ->十六进制=%2->二进制=%3").arg(65533).arg(QString::number(65533,16)).arg(QString::number(65533,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[3] = %1 ->十六进制=%2->二进制=%3").arg(257).arg(QString::number(257,16)).arg(QString::number(257,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[3] = %1 ->十六进制=%2->二进制=%3").arg(256).arg(QString::number(256,16)).arg(QString::number(256,2)));
ui->plainTextEdit_1->appendPlainText(QString("方法2,将2字节(16位2进制)十进制数 & 0xFFFF,并且分成两部分(高位1字节和低位1字节)保存字节数组存储的是1个字节范围内"));
// 假定读取UI串口数据存入字节组
QByteArray data;
for (int i = 0; i < 6; ++i) {
data.append(sendSerialdatas[i]);
}
// UI直接解析错误,无法获取原数据
ui->plainTextEdit_2->appendPlainText(QString("方法1 UI通过获取2字节数组,显示2字节的十进制在界面(数值解析错误)"));
quint16 quint16recv = 0;
for (int i = 0; i < data.size(); i++) {
quint16recv = (unsigned char)data.at(i);
ui->plainTextEdit_2->appendPlainText(QString("quint16recv[%1]= %2").arg(i).arg(quint16recv)); //解析并显示
}
ui->plainTextEdit_2->appendPlainText(QString("方法2,将2字节字节数组通过 移位和 &0xFFFF 还原成无符号短整型"));
//======================================================
// 写法2 安全的
value = 65535;
sendSerialdatas[0] = (value>>8) & 0xFFFF; //存储高八位(255),转为二进制后的前八位,总共16位
sendSerialdatas[1] = value; //存储低8位(255) 你也可以写成 (value & 0xFFFF)
value = 65534;
sendSerialdatas[2] = (value>>8) & 0xFFFF;
sendSerialdatas[3] = value;
value = 256;
sendSerialdatas[4] = (value>>8) & 0xFFFF;
sendSerialdatas[5] = value;
// MCU数据作为串口1
ui->plainTextEdit_1->appendPlainText(QString("sendSerialdatas[0] = (65535>>8) & 0xFFFF"));
ui->plainTextEdit_1->appendPlainText(QString("sendSerialdatas[1] = 65535;"));
ui->plainTextEdit_1->appendPlainText(QString("sendSerialdatas[2] = (65534>>8) & 0xFFFF;"));
ui->plainTextEdit_1->appendPlainText(QString("sendSerialdatas[3] = 65534"));
ui->plainTextEdit_1->appendPlainText(QString("sendSerialdatas[4] = (256>>8) & 0xFFFF;"));
ui->plainTextEdit_1->appendPlainText(QString("sendSerialdatas[5] = 256;"));
// 假定读取UI串口数据存入字节组
QByteArray data1;
for (int i = 0; i < 6; ++i) {
data1.append(sendSerialdatas[i]);
}
// UI直接解析即可,1字节数数组无法存储2字节数字,需要分成两部分。( (recvSerialdatas1[i]<<8) | recvSerialdatas1[i]) & 0xFFFF)
//255<<8 = 1111 1111 0000 0000 | 1111 1111 = 1111 1111 1111 1111 = 65535
quint8 recvSerialdatas1[32] = {
0};
for (int i = 0; i < data1.length(); i++) {
recvSerialdatas1[i] = (unsigned char)data1.at(i);
}
// UI还原MCU数据
quint16 UIshorft = 0;
UIshorft = ((sendSerialdatas[0]<<8) | sendSerialdatas[1]) &0xFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UIshorft = ((sendSerialdatas[0]<<8) | sendSerialdatas[1]) &0xFFFF = %2").arg(UIshorft));
UIshorft = ((sendSerialdatas[2]<<8) | sendSerialdatas[3]) &0xFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UIshorft = ((sendSerialdatas[2]<<8) | sendSerialdatas[3]) &0xFFFF = %2").arg(UIshorft));
UIshorft = ((sendSerialdatas[4]<<8) | sendSerialdatas[5]) &0xFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UIshorft = ((sendSerialdatas[4]<<8) | sendSerialdatas[5]) &0xFFFF = %2").arg(UIshorft));
}
実行結果
方法1
方法 2
シリアルポート経由で負の数値を送受信する例
C 言語では、次の方法を使用して、16 ビットの short 型の値を 2 つの unsigned char 変数に格納し、同時に正の数と負の数を区別できます。
short value = -32768;
unsigned char highByte = (unsigned char)(value >> 8); //80 ->1000 0000
unsigned char lowByte = (unsigned char)value; //0 ->0000 0000
if (value < 0) {
highByte |= 0x80; // 如果值为负,则设置符号位
}
这里使用了移位运算符 >> 把高位和低位分别赋值给两个unsigned char类型的变量。如果原来的short类型值是负数,则通过将高字节的最高位(即符号位)设为1来标识它是个负数。
2 つの unsigned char 変数から short 値を解析するには、次のコードを使用できます。
unsigned char highByte = 80;
unsigned char lowByte = 0;
short value = ((short)highByte << 8) | lowByte; //
if (highByte & 0x80) {
value = -(short)((~value) + 1); // 如果设置了符号位,则将其恢复
}
符号ビットは 1 の負の数です
~値
-(短い)((~値) + 1)
这里使用了移位运算符 << 将高字节左移8位,并使用按位或运算符|将低字节合并到一起。如果高字节的最高位被设置为1,则表示这是个负数,因此需要恢复符号位并转换为相应的负数值。
//实现串口数据的收发 2字节数组为例
void MainWindow::on_pb_shorft_clicked()
{
//MCU上传UI负数
//第一种负数为例
short value;
qDebug()<<"short 的范围(0x00-0xFFFF):"<<std::numeric_limits<short>::min()<<"~"<<std::numeric_limits<short>::max();
value = -32768;
qDebug()<<"value = -32768; \n十进制 = "<<QString::number(value,10)<<"\n十六进制 = "<<"0x"+QString::number(value,16)<<"\n二进制 = "<<QString::number(value,2);
value = 32767;
qDebug()<<" value = 32767; \n十进制 = "<<QString::number(value,10)<<"\n十六进制 = "<<"0x"+QString::number(value,16)<<"\n二进制 = "<<QString::number(value,2);
unsigned char sendSerialdatas[6] = {
0}; //MCU
ui->plainTextEdit_1->appendPlainText(QString("方法2,将2字节(16位2进制)十进制数 ,并且分成两部分(高位1字节和低位1字节)保存字节数组存储的是1个字节范围内"));
ui->plainTextEdit_2->appendPlainText(QString("方法2,将2字节字节数组还原成有符号短整型"));
//写法2 安全的操作,隐含会将十进制转化为二进制在内存存储。
value = -32768;
sendSerialdatas[0] = ((short)value>>8) ;
sendSerialdatas[1] = (short)value;
value = 32767;
sendSerialdatas[2] = ((short)value>>8);
sendSerialdatas[3] = (short)value;
value = -1;
sendSerialdatas[4] = ((short)value>>8);
sendSerialdatas[5] = (short)value;
ui->plainTextEdit_1->appendPlainText(""
"short value = -32768;\n"
"sendSerialdatas[0] = (value>>8) ;\n"
"sendSerialdatas[1] = value;\n"
"value = 32767;\n"
"sendSerialdatas[2] = (value>>8);\n"
"sendSerialdatas[3] = value;\n"
"value = -1;\n"
"sendSerialdatas[4] = (value>>8);\n"
"sendSerialdatas[5] = value;\n"
);
//MCU数据作为串口1
ui->plainTextEdit_1->appendPlainText(" sendSerialdatas[0] = " + QString::number(sendSerialdatas[0],16));
ui->plainTextEdit_1->appendPlainText(" sendSerialdatas[1] = " + QString::number(sendSerialdatas[1],16));
ui->plainTextEdit_1->appendPlainText(" sendSerialdatas[2] = " + QString::number(sendSerialdatas[2],16));
ui->plainTextEdit_1->appendPlainText(" sendSerialdatas[3] = "+ QString::number(sendSerialdatas[3],16));
ui->plainTextEdit_1->appendPlainText(" sendSerialdatas[4] = " + QString::number(sendSerialdatas[4],16));
ui->plainTextEdit_1->appendPlainText(" sendSerialdatas[5] = "+ QString::number(sendSerialdatas[5],16));
//假定读取串口数据存入字节组
QByteArray data1;
for (int i = 0; i < 6; ++i) {
data1.append(sendSerialdatas[i]);
}
quint8 recvSerialdatas1[32] = {
0};
for (int i = 0; i < data1.length(); i++) {
recvSerialdatas1[i] = (unsigned char)data1.at(i);
}
short fvalue = ((short)sendSerialdatas[0] << 8) | sendSerialdatas[1];
qDebug ()<< " fvalue = "<<fvalue;
if ( (sendSerialdatas[0] & 0x80) == 1) {
//负数
fvalue = -(short)((~fvalue) + 1);
}
ui->plainTextEdit_2->appendPlainText("-(short)((~fvalue) + 1); = "+ QString::number(fvalue,'f',0));
//这里不用经过上面这步也可以解析成功
qint16 UI = 0;
UI = (((short)sendSerialdatas[0]<<8) | sendSerialdatas[1]) &0xFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UI = ((sendSerialdatas[0]<<8) | sendSerialdatas[1]) &0xFFFF = %2").arg(UI));
UI = (((short)sendSerialdatas[2]<<8) | sendSerialdatas[3]) &0xFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UI = ((sendSerialdatas[2]<<8) | sendSerialdatas[3]) &0xFFFF = %2").arg(UI));
UI = (((short)sendSerialdatas[4]<<8) | sendSerialdatas[5]) &0xFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UI = ((sendSerialdatas[4]<<8) | sendSerialdatas[5]) &0xFFFF = %2").arg(UI));
}
効果
【4】シリアルポート int 型の例
シリアルポートによる正の数値の送受信の例
//实现串口数据的收发 4字节数组为例
void MainWindow::on_pb_int_clicked()
{
ui->plainTextEdit_1->appendPlainText(QString("方法1直接将4字节十进制数存入字节数组通过串口发给UI(会有警告,只能获取4字节中的最低字节的八位)"));
//MCU上传UI正负数
//第一种正数为例
unsigned int value;
value = 4294967295;
qDebug()<<"unsigned int value 的范围(0x00-0xFFFFFFFF):"<<std::numeric_limits<unsigned int>::min()<<"~"<<std::numeric_limits<unsigned int>::max();
qDebug()<<"value 十进制 = "<<QString::number(value)<<" value 十六进制 = "<<"0x"+QString::number(value,16)<<" value 二进制 = "<<QString::number(value,2);
unsigned char sendSerialdatas[32] = {
0}; //MCU
//MCU将65535这个数值传给UI怎么做,如下:
//写法1
sendSerialdatas[0] = value; //直接将4字节数赋值给一个字节,11111111111111111111111111111111
sendSerialdatas[1] = 4294967294; //FFFE ->>1111 1111 (低八位)1111 1111 = 255
sendSerialdatas[2] = 4294967293; //FFFD-> = 254
sendSerialdatas[3] = 65537; //0001 (低八位)0000 0001 = 1
sendSerialdatas[4] = 65536; //0001 (低八位)0000 0000 = 0
//MCU数据作为串口1
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[0] = %1 ->十六进制=%2->二进制=%3").arg(value).arg(QString::number(value,16)).arg(QString::number(value,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[1] = %1 ->十六进制=%2->二进制=%3").arg(4294967294).arg(QString::number(4294967294,16)).arg(QString::number(4294967294,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[2] = %1 ->十六进制=%2->二进制=%3").arg(4294967293).arg(QString::number(4294967293,16)).arg(QString::number(4294967293,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[3] = %1 ->十六进制=%2->二进制=%3").arg(65537).arg(QString::number(65537,16)).arg(QString::number(65537,2)));
ui->plainTextEdit_1->appendPlainText(QString(" sendSerialdatas[3] = %1 ->十六进制=%2->二进制=%3").arg(65536).arg(QString::number(65536,16)).arg(QString::number(65536,2)));
ui->plainTextEdit_1->appendPlainText(QString("方法2,将4字节(32位2进制)十进制数 & 0xFFFFFFFF,并且分成两部分(高位1字节和低位1字节)保存字节数组存储的是1个字节范围内"));
//假定读取串口数据存入字节组
QByteArray data;
for (int i = 0; i < 6; ++i) {
data.append(sendSerialdatas[i]);
}
ui->plainTextEdit_2->appendPlainText(QString("方法1 UI通过获取4字节数组,显示4字节的十进制在界面(数值解析错误)"));
quint16 quint16recv = 0;
for (int i = 0; i < data.size(); i++) {
quint16recv = (unsigned char)data.at(i);
ui->plainTextEdit_2->appendPlainText(QString("quint16recv[%1]= %2").arg(i).arg(quint16recv)); //解析并显示
}
ui->plainTextEdit_2->appendPlainText(QString("方法2,将4字节字节数组通过 移位和 &0xFFFFFFFF 还原成无符号短整型"));
//写法2 安全的操作,隐含会将十进制转化为二进制在内存存储。
value = 4294967295;
sendSerialdatas[0] = (value>>24) & 0xFFFFFFFF; //存储32位中的最高八位
sendSerialdatas[1] = (value>>16) & 0xFFFFFFFF; //存储32位中的中高八位
sendSerialdatas[2] = (value>>8) & 0xFFFFFFFF; //存储32位中的中低八位
sendSerialdatas[3] = value & 0xFFFFFFFF; //存储32位中的最低八位
value = 4294967294;
sendSerialdatas[4] = (value>>24) & 0xFFFFFFFF; //存储32位中的最高八位
sendSerialdatas[5] = (value>>16) & 0xFFFFFFFF; //存储32位中的中高八位
sendSerialdatas[6] = (value>>8) & 0xFFFFFFFF; //存储32位中的中低八位
sendSerialdatas[7] = value & 0xFFFFFFFF; //存储32位中的最低八位
value = 65536;
sendSerialdatas[8] = (value>>24) & 0xFFFFFFFF; //存储32位中的最高八位
sendSerialdatas[9] = (value>>16) & 0xFFFFFFFF; //存储32位中的中高八位
sendSerialdatas[10] = (value>>8) & 0xFFFFFFFF; //存储32位中的中低八位
sendSerialdatas[11] = value & 0xFFFFFFFF; //存储32位中的最低八位
//MCU数据作为串口1
ui->plainTextEdit_1->appendPlainText(QString("value = 4294967295;\r\n"
"sendSerialdatas[0] = (value>>24) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[1] = (value>>16) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[2] = (value>>8) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[3] = value & 0xFFFFFFFF;"));
ui->plainTextEdit_1->appendPlainText(QString("value = 4294967294;\r\n"
"sendSerialdatas[0] = (value>>24) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[1] = (value>>16) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[2] = (value>>8) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[3] = value & 0xFFFFFFFF;"));
ui->plainTextEdit_1->appendPlainText(QString("value = 65536;\r\n"
"sendSerialdatas[0] = (value>>24) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[1] = (value>>16) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[2] = (value>>8) & 0xFFFFFFFF;\r\n"
"sendSerialdatas[3] = value & 0xFFFFFFFF;"));
//假定读取串口数据存入字节组
QByteArray data1;
for (int i = 0; i < 6; ++i) {
data1.append(sendSerialdatas[i]);
}
quint8 recvSerialdatas1[32] = {
0};
for (int i = 0; i < data1.length(); i++) {
recvSerialdatas1[i] = (unsigned char)data1.at(i);
}
quint32 UIint = 0;
UIint = ((sendSerialdatas[0]<<24) | sendSerialdatas[1]<<16 | sendSerialdatas[2]<<8 | sendSerialdatas[3]) & 0xFFFFFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UIint = ((sendSerialdatas[0]<<24) | sendSerialdatas[1]<<16 | sendSerialdatas[2]<<8 | sendSerialdatas[3]) &0xFFFFFFFF = %2").arg(UIint));
UIint = ((sendSerialdatas[4]<<24) | sendSerialdatas[5]<<16 | sendSerialdatas[6]<<8 | sendSerialdatas[7]) & 0xFFFFFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UIint = ((sendSerialdatas[4]<<24) | sendSerialdatas[5]<<16 | sendSerialdatas[6]<<8 | sendSerialdatas[7]) & 0xFFFFFFFF = %2").arg(UIint));
UIint = ((sendSerialdatas[8]<<24) | sendSerialdatas[9]<<16 | sendSerialdatas[10]<<8 | sendSerialdatas[11]) & 0xFFFFFFFF;
ui->plainTextEdit_2->appendPlainText(QString("UIint = ((sendSerialdatas[8]<<24) | sendSerialdatas[9]<<16 | sendSerialdatas[10]<<8 | sendSerialdatas[11]) & 0xFFFFFFFF = %2").arg(UIint));
}
効果
シリアルポート経由で負の数値を送受信する例
C 言語では、unsigned char を使用して 32 ビット int 型メソッドを格納します。
// 假设要存储的32位int为num
unsigned char bytes[4]; // 数组长度为4,每个元素是一个字节
bytes[0] = (num >> 24) & 0xFF; // 取出num的高8位存入bytes的第1个元素
bytes[1] = (num >> 16) & 0xFF; // 取出num的次高8位存入bytes的第2个元素
bytes[2] = (num >> 8) & 0xFF; // 取出num的次低8位存入bytes的第3个元素
bytes[3] = num & 0xFF; // 取出num的低8位存入bytes的第4个元素
上記のコードは、32 ビット int 数値を unsigned char 配列にビッグエンディアン順 (上位バイトが最初に、下位バイトが後に続きます) で格納します。
正の数と負の数を解析する方法は次のとおりです。
// 假设已经从unsigned char数组中读取了4个字节存入bytes数组
int num;
if (bytes[0] & 0x80) {
// 如果最高位为1,则表示这是一个负数
num = ((int)bytes[0] << 24) | ((int)bytes[1] << 16) | ((int)bytes[2] << 8) | (int)bytes[3];
} else {
num = ((int)(bytes[0] & 0x7F) << 24) | ((int)bytes[1] << 16) | ((int)bytes[2] << 8) | (int)bytes[3];
}
上記のコードは、最上位ビットが符号ビットであると想定しています。最上位ビットが 1 の場合、これは負の数であることを意味します。実際の値を取得するには、バイト配列のすべての要素を反転し、1 を加算する必要があります。
ソースコードの例:
#include <stdio.h>
void print_bytes(unsigned char *bytes, int len) {
for (int i = 0; i < len; i++) {
printf("%02X ", bytes[i]);
}
printf("\n");
}
int main() {
int num = -123456789;
unsigned char bytes[4];
bytes[0] = (num >> 24) & 0xFF;
bytes[1] = (num >> 16) & 0xFF;
bytes[2] = (num >> 8) & 0xFF;
bytes[3] = num & 0xFF;
printf("原始数值: %d\n", num);
printf("字节序列: ");
print_bytes(bytes, 4);
if (bytes[0] & 0x80) {
num = ((int)bytes[0] << 24) | ((int)bytes[1] << 16) | ((int)bytes[2] << 8) | (int)bytes[3];
} else {
num = ((int)(bytes[0] & 0x7F) << 24) | ((int)bytes[1] << 16) | ((int)bytes[2] << 8) | (int)bytes[3];
}
printf("解析结果: %d\n", num);
return 0;
}
正と負の数値を送受信するためのシリアル ポート (簡易バージョンを推奨)
1バイト、2バイト、4バイトが使用可能
//实现串口数据的收发 4字节数组为例
void MainWindow::on_pb_int_clicked()
{
qDebug()<<"int 的范围(0x00-0xFFFF):"<<std::numeric_limits<int>::min()<<"~"<<std::numeric_limits<int>::max();
int value = -2147483648;
qDebug()<<"value = -2147483648; \n十进制 = "<<QString::number(value,10)<<"\n十六进制 = "<<"0x"+QString::number(value,16)<<"\n二进制 = "<<QString::number(value,2);
value = 2147483647;
qDebug()<<" value = 2147483647; \n十进制 = "<<QString::number(value,10)<<"\n十六进制 = "<<"0x"+QString::number(value,16)<<"\n二进制 = "<<QString::number(value,2);
int num = -2147483648;
unsigned char bytes[8];
//MCU
bytes[0] = (num >> 24) & 0xFF;
bytes[1] = (num >> 16) & 0xFF;
bytes[2] = (num >> 8) & 0xFF;
bytes[3] = num & 0xFF;
value = 2147483647;
bytes[4] = (value >> 24) & 0xFF;
bytes[5] = (value >> 16) & 0xFF;
bytes[6] = (value >> 8) & 0xFF;
bytes[7] = value & 0xFF;
qDebug("\n\n原始数值: %d %d\n", num,value);
qDebug("字节序列: ");
for (int i = 0; i < 8; i++) {
qDebug("%02X ", bytes[i]);
}
//UI
int v1,v2;
if ( bytes[0] & 0x80 ) {
// 如果最高位为1,则表示这是一个负数
v1 = ((int)bytes[0] << 24) | ((int)bytes[1] << 16) | ((int)bytes[2] << 8) | (int)bytes[3];
qDebug()<<"负数";
} else {
//正数
v1 = ((int)(bytes[0] & 0x7F) << 24) | ((int)bytes[1] << 16) | ((int)bytes[2] << 8) | (int)bytes[3];
qDebug()<<"正数";
}
qDebug()<<"=======================================";
if ( bytes[4] & 0x80 ) {
// 如果最高位为1,则表示这是一个负数
v2 = ((int)bytes[4] << 24) | ((int)bytes[5] << 16) | ((int)bytes[6] << 8) | (int)bytes[7];
qDebug()<<"负数";
} else {
//正数
v2 = ((int)(bytes[4] & 0x7F) << 24) | ((int)bytes[5] << 16) | ((int)bytes[7] << 8) | (int)bytes[7];
qDebug()<<"正数";
}
qDebug("解析结果: v1 = %d v2 = %d\n", v1,v2);
}
演算結果
-2147483648
2147483647
int 的范围(0x00-0xFFFF): -2147483648 ~ 2147483647
原始数值: -2147483648 2147483647
字节序列:
80
00
00
00
7F
FF
FF
FF
负数
=======================================
正数
解析结果: v1 = -2147483648 v2 = 2147483647
【5】浮動小数点の考え方
整数に変換してから浮動小数点数に変換します
未検証、効果表示なし
可以使用联合体将32位的float类型强制转换为unsigned char数组来存储。具体实现可以使用移位运算符将每个字节读取出来,并根据符号位判断正负数。
以下是一个示例源码:
union float_converter {
float f;
unsigned char bytes[4];
};
void store_float(float f, unsigned char* buffer) {
union float_converter converter;
converter.f = f;
int sign_bit = (converter.bytes[3] >> 7) & 0x01;
if (sign_bit == 1) {
// 负数
for (int i = 0; i < 4; i++) {
buffer[i] = ~converter.bytes[i];
}
} else {
// 正数
for (int i = 0; i < 4; i++) {
buffer[i] = converter.bytes[i];
}
}
}
float parse_float(unsigned char* buffer) {
union float_converter converter;
int sign_bit = (buffer[3] >> 7) & 0x01;
if (sign_bit == 1) {
// 负数
for (int i = 0; i < 4; i++) {
converter.bytes[i] = ~buffer[i];
}
converter.bytes[3] += 1;
} else {
// 正数
for (int i = 0; i < 4; i++) {
converter.bytes[i] = buffer[i];
}
}
return converter.f;
}
使用示例:
float f = -123.45f;
unsigned char buffer[4];
store_float(f, buffer);
float parsed_f = parse_float(buffer);
[6] qDebugリダイレクトキャプチャ出力
//安装消息器第一步
qInstallMessageHandler(myMessageOutput);
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//消息静态函数
static void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
private slots:
void on_pb_char_clicked();
void on_pb_shorft_clicked();
void on_pb_int_clicked();
private:
Ui::MainWindow *ui;
};
コード内で qDebug が使用される場所は msg 内になることがわかります。
void MainWindow::myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
Q_UNUSED(context);
// 获取对主窗口的引用
QMainWindow *mainWindow = qobject_cast<QMainWindow *>(qApp->topLevelWidgets().at(0));
// 获取对文本编辑器的引用
QPlainTextEdit *plainTextEdit = mainWindow->findChild<QPlainTextEdit *>("plainTextEdit_3");
// 将该消息附加到文本编辑器中
plainTextEdit->appendPlainText(msg);
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
break;
case QtInfoMsg:
break;
case QtWarningMsg:
break;
case QtCriticalMsg:
break;
case QtFatalMsg:
break;
}
}