目录
2、使用HM NIS Edit编辑器与NSIS编译器更深层次打包
一、前言
给大家安利一款自己编写的串口调试助手小软件,使用QT5.5编写,在windows下可正常使用,Linux环境下没测试过,可能会出现乱码,因为windows环境下的字符编码是ANSI(在中文系统中ANSI就是GBK编码),而Linux环境下字符编码是UTF-8,调试助手中发送和接收的数据也都是按照GBK编码转换的。比如:
字符 |
GBK编码 |
Unicode编码 |
UTF-8 |
"123学习" |
31 32 33 D1 A7 CF B0 |
31 32 33 5B 66 4E 60 |
31 32 33 E5 AD A6 E4 B9 A0 |
1、关于字符集编码的延伸阅读
6、QT字符编码
2、关于字符编码的几点总结
1、字符就是一堆文字符号,每个国家都会有自己的语言文字,这些字符在计算机中怎么存储呢?计算机中都是以01二进制存储的,把这些字符转成其对应且唯一的二进制码不就行了。也就出现了各种编码,比如英文的ASCII、中文的GDB编码、日文的Shift-JIS编码等等
2、ASCII码:上个世纪60年代, 美国制定了一套字符编码, 对英语字符与二进制位之间的关系, 做了统一规定,这被称为ASCII码,ASCII码一共规定了128个字符的编码。只占用了一个字节的后面7位, 最前面的1位统一规定为0
3、GBK码:英语用128个符号编码就够了, 但是用来表示其他语言, 128个符号是不够的,于是就使用两个字节表示一个汉字, 所以理论上最多可以表示256x256=65536个符号
4、Unicode:世界上存在着多种编码方式, 同一个二进制数字可以被解释成不同的符号,要想打开一个文本文件, 就必须知道它的编码方式, 否则用错误的编码方式解读, 就会出现乱码。为了解决不统一的问题,有个国际组织就出来制定了包含世界上所有语言字符的编码,这就是Unicode编码。Unicode通常用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只需要把高字节全部填为0就可以。但是 Unicode只是一个符号集, 它只规定了符号的二进制代码, 却没有规定这个二进制代码应该如何存储,如果用Unicode来表示1字节的ASCII优点浪费内存,而且也出现了不同存储方式的Unicode
5、UTF-8编码 :UTF-8就是在互联网上使用最广的一种unicode的实现方式. 其他实现方式还包括UTF-16和UTF-32。UTF-8最大的一个特点, 就是它是一种变长的编码方式. 它可以使用1~6个字节表示一个符号, 根据不同的符号而变化字节长度.
二、功能与效果
1、效果
废话不多说,先看效果
2、功能
1、记录和保存串口的配置信息,便于下次打开时直接使用上次的配置
2、保存串口接收区的数据(可以是串口接收的的也可以是串口发送的)
3、一键清除接收窗口和发送窗口的数据
4、接收时,可以选择16进制显示还是字符显示,可以选择显示当前的时间和发送的数据
5、发送时,可以选择定时发送以及发送新行,可以发送文件数据。需要注意的是,选择或不选择16进制发送只是在发送区字符显示的切换,发送的数据都是ANSI编码的字节数据;勾选16进制时就将字符转成ANSI编码(这里是GBK编码)显示,不勾选16进制就显示字符或是将16进制数据根据ANSI编码转成字符
6、可以显示当前的串口状态、发送的字节数、接收的字节数、当前的时间
三、实现过程
1、创建QMainWindow窗口与UI设计
创建后在 .pro 工程管理文件中添加 QT += serialport,这样才能使用串口
2、代码实现
源码连接:https://github.com/denghengli/qt_study/tree/master/17_SerialPort
划重点:
1、信号和槽的关联方式
方法一:
0)如果是自定义的信号,需要在.h中声明
1)在.h中声明槽函数
2)在.cpp中实现槽函数
3)使用connect将信号和槽函数进行连接:
QObject::connect(ui->pushbutton,SIGNAL( clicked() ),this,SLOT( on_pushBuuton_clicked() );
方法二:
在.ui文件中,右击按钮,选择''go to slot''选项,选择信号"clicked",单机确定按钮。系统自动生成槽函数声明和定义,并建立内部映射。只需在槽函数体内编写槽函数体内编写槽函数的功能即可,添加语句如方法一中的步骤2.
方法三:
在.ui界面,选择"改变信号/槽"选项,单击"+"添加新的槽函数,确定完成槽函数的添加,最后重复方法一中的步骤1和步骤2完成槽函数声明和定义.
2、文件发送和文件保存
通过QFileDialog类提供的文件对话框,来选择要发送的文件和新建保存的文件
openfile_path = QFileDialog::getOpenFileName(this, "打开文件", "", "Text File(*.txt)");
savefile_path = QFileDialog::getSaveFileName(this,"另存为", savefile_path, "Text File(*.txt)");
3、配置信息的保存
每一次在配置完串口、波特率、停止位等后,打开串口时,通过QSettings类将这些配置信息以key-value的形式保存到预先规定的文件中;在每次打开软件时也先读取这个配置文件的数据,再设置串口
//创建ini配置文件
void SerialPort::configiniInit()
{
iniPath = new QDir;
iniFilename = iniPath->currentPath() + "/SerialPort.ini";
//构造一个QSettings对象,用于访问存储在名为iniFilename的文件中的设置。如果文件不存在,就创建它
configini = new QSettings(iniFilename, QSettings::IniFormat);
}
//读取ini配置文件,设置下拉框的项目
void SerialPort::configiniRead()
{
configini->beginGroup("SETUP");
int i_port = configini->value("COM").toInt();
int i_baudrate = configini->value("baudrate").toInt();
int i_databit = configini->value("databit").toInt();
int i_checkbit = configini->value("checkbit").toInt();
int i_stopbit = configini->value("stopbit").toInt();
configini->endGroup();
ui->CB_port->setCurrentIndex(i_port);
ui->CB_baudrate->setCurrentIndex(i_baudrate);
ui->CB_databit->setCurrentIndex(i_databit);
ui->CB_checkbit->setCurrentIndex(i_checkbit);
ui->CB_stopbit->setCurrentIndex(i_stopbit);
}
//写ini配置文件,将下拉框的项目索引写入ini文件
void SerialPort::configiniWrite()
{
configini->beginGroup("SETUP");
configini->setValue("COM", ui->CB_port->currentIndex());
configini->setValue("baudrate", ui->CB_baudrate->currentIndex());
configini->setValue("databit", ui->CB_databit->currentIndex());
configini->setValue("checkbit", ui->CB_checkbit->currentIndex());
configini->setValue("stopbit", ui->CB_stopbit->currentIndex());
configini->endGroup();
}
4、字符与16进制编码字符的互相转换
不要弄混了,是字符与ANSI(这里是GBK)16进制编码字符的互相转换;
例如:“123学习” <----> "31 32 33 D1 A7 CF B0"
原因是,textEdit控件显示的是QString字符,在显示时需要在字符和16进制之间切换。
“123学习” ----> "31 32 33 D1 A7 CF B0" 步骤:
//1、获取发送数据 QString = "123学习"
QString sendstr = ui->textEdit_tx->toPlainText();
//2、"123学习" --> GBK编码:31 32 33 D1 A7 CF B0
QByteArray sendarray = sendstr.toLocal8Bit();//"123学习"在QT中是UTF8编码的,所以这里需要使用toLocal8Bit转成Winds中的GBK编码
//3、GBK编码:31 32 33 D1 A7 CF B0 --> GBK编码字符:"31 32 33 D1 A7 CF B0"
QDataStream out(&sendarray,QIODevice::ReadWrite); //将字节数组读入
while(!out.atEnd())
{
qint8 outChar = 0;
out>>outChar; //每字节填充一次,直到结束
QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0'));
str = str.toUpper();
ui->textEdit_tx->insertPlainText(str + " ");//在当前光标处插入文本
//返回表示当前可见游标的QTextCursor副本。对返回游标的更改不会影响QTextEdit的游标;使用setTextCursor()更新可见的游标
QTextCursor cursor = ui->textEdit_tx->textCursor();
cursor.movePosition(QTextCursor::End);//将光标移动到文档的最后
ui->textEdit_tx->setTextCursor(cursor);//更新光标
}
"31 32 33 D1 A7 CF B0" ----> “123学习” 步骤:
//1、获取发送数据 QString = "31 32 33 D1 A7 CF B0"
QString sendstr = ui->textEdit_tx->toPlainText();
QByteArray sendarray;
//2、GBK编码字符:"31 32 33 D1 A7 CF B0" --> GBK编码:31 32 33 D1 A7 CF B0
QStringtoHex(sendarray, sendstr);
//3、GBK编码:31 32 33 D1 A7 CF B0 --> Unicode编码 --> "123学习"
QString str1 = QString::fromLocal8Bit(sendarray);//实现了从本地字符集GBK到Unicode的转换,解决中文显示乱码问题
ui->textEdit_tx->setText(str1);
可以看到 QStringtoHex(QByteArray& sendData,QString str)函数比较关键,但是实现起来也比较简单
char SerialPort::ConvertHexChar(char c)
{
if(c>='a'&&c<='f'){
return c-'a'+10;
}
else if(c>='A'&&c<='F'){
return c-'A'+10;
}
else if(c>='0'&&c<='9'){
return c-'0';
}
else{
return -1;
}
}
//"31 32 33 D1 A7 CF B0" --> 31 32 33 D1 A7 CF B0
void SerialPort::QStringtoHex(QByteArray& sendData,QString str)
{
char hstr,lstr,hdata,ldata;
int len = str.length();
int sendnum = 0;
QByteArray temp;
temp.resize(len/2);//设置大小,len/2会大于实际16进制字符
for(int i=0;i<len;)
{
//QString转QByteArray的方法,Latin1代表ASCII。'3' --> 3
hstr = str[i].toLatin1();
if(hstr == ' '){
++i; continue;
}
if(++i >= len) break;
lstr = str[i].toLatin1();
hdata = ConvertHexChar(hstr);
ldata = ConvertHexChar(lstr);
if(-1 == hdata || -1 == ldata)
break;
++i;
temp[sendnum] = hdata<<4|ldata;
sendnum++;
}
sendData.reserve(sendnum);//重新调整大小
sendData = temp.left(sendnum);//返回一个 字节数组,其中包含这个字节数组最左边的len字节。去掉多余字符
}
3、工程打包发布
1、使用QT自带的windeployqt.exe打包
1、选择 release,构建工程
2、将 .exe文件拷贝到任意路径下,将其进行打包,这样在任意一台没有安装QT环境的电脑也可以运行,打包前首先要确保QT的安装目录下有 windeployqt.exe
3、打开终端,进入到.exe目录下(快捷方式:在文件夹中,点击空白处,shift+右键,选择“在此处打开窗口”),输入 windeployqt.exe 文件
4、生成成功后,会在当前目录下生成一些文件,将此文件夹拷贝到任意没有QT环境的电脑上也能运行
2、使用HM NIS Edit编辑器与NSIS编译器更深层次打包
1、先使用QT自带的windeployqt.exe打包,生成可执行文件和需要的动态库
2、下载安装 NSIS 和 NIS Edit 这两个软件
3、根据 NIS Edit安装向导的使用 步骤,将windeployqt.exe 打包后的文件再打包生成一个 Setup.exe 的安装向导文件;使用NIS EDIT安装时,有个需要注意的地方,在选择应用程序的文件时,要选择需要打包的文件夹
完成后就可以通过这个Setup.exe来安装并使用串口调试助手了。在安装 Setup.exe 的时候根据提示下一步下一步就可以了。这样逼格是不是都提高了 哈哈
四、功能测试
1、下载一个虚拟串口的工具,我下载的是 VSDP ,当然其他的也行,只要能在本地虚拟出串口就行,如下图,COM1和COM2就可以互联了;"Add pair "添加新的虚拟串口
2、用serialport打开COM2,随便用一个串口调试助手(我这里用的XCOM)打开COM1,测试互相发送数据都是ok的