1.理论知识
1.1 示例文件展示
以下为同一个MCU程序的HEX文件(分为ASCII码查看和二进制查看)和BIN文件内容
文件大小:bin为41K,hex为116K
![sss](https://i-blog.csdnimg.cn/direct/7a0676360bb1440b93e2c9eedc78f03a.png)
![](https://i-blog.csdnimg.cn/direct/9916aca7a14a49c4a855bdd69685d287.png)
![](https://i-blog.csdnimg.cn/direct/3f166c7457734518b7f11e75ce2a318a.png)
1.2 Hex文件讲解
HEX文件内容分析
1)数据长度
表示有效数据的字节数,即0x0800,共2个字节(是ASCII的两个字节,实际二进制的4个字节)
2)数据类型
00:数据记录
01:文件结束记录
02:扩展段地址记录
03:开始段地址记录
04:扩展线性地址记录,即表示后面的数据是地址偏移量
05:开始线性地址记录
第一行为0x04,即偏移量,也就是说第二行数据的实际地址是0x08040000,
而第三行原本地址为0x0001的,偏移以后实际为0x08040001
3)数据地址
为每行数据的地址,对于数据类型为0x00的行,相邻上下两行的地址差值为0x0010,即16个数,正好对应数据长度为0x10.
4)校验
CheckSum = 0x100 - (Sum & 0xFF)
以第一行“:020000040804EE”为例
Sum= 02 + 00 +00 + 04 + 08 +04 = 0x12,
CheckSum = 0x100 - (0x12&0xFF)=0xEE,正好跟最后一个字节对应。
1.3 HEX与BIN的关系
从示例图可以看出,ASCII类型HEX第二行的实际数据的16个字节,正好与BIN文件第一行完全对应。
而每行的分割字符为0X0D和0x0A,即“\r\n”
这么看只要把数据类型为0的行中的冒号、数据长度、数据地址、数据类型、校验都干掉,只保留真实数据,然后把ASCII码每2字节转为1字节即可。
具体步骤:
①把HEX提取到QByteArray中。
②把QByteArray中的所有数据提取到QStringList中,里面每行为一个QString元素。提取的分割字符为0x0D0A。
③根据规则只要其中的32个字符。
④把这每行的32个字符两两转换为一个字节,并存入新的QByteArray
⑤保存QByteArray结果到bin文件中
2 关键代码
QString path=QFileDialog::getOpenFileName(this,"请选择新程序bin文件","../",tr("bin (*.hex)"));
LE_HexFile->setText(path);
if(path.isEmpty()==false){//如果非空
QFile Frimware(path);
if (!Frimware.open (QFile::ReadOnly)){
printf("Frimware.open_Wrong!\n"); //打开文件
qDebug() << "Frimware.open_Wrong!\n";
return;
}
QDataStream BinFileData(&Frimware);
BinFileData.readRawData(pBuff,static_cast<int>(Frimware.size()));
Array_Hex = QByteArray(pBuff,static_cast<int>(Frimware.size()));
qDebug() << "文件总字节数:"<<Array_Hex.size();
//把Array_Hex中的数据,提取bin数据后存入extractedData
QByteArray extractedData;
QString dataString(Array_Hex);
QStringList lines ;
lines = dataString.split("\r\n", QString::SkipEmptyParts);
quint32 expectedAddress = 0x0000; // Starting address
for (const QString &line : lines) {
// 冒号(1byte)+长度 (2 bytes), 地址 (4 bytes), CMD (2 bytes), Data (length * 2 bytes), 和校验 (2 bytes)
bool ok;
int length = line.mid(1, 2).toInt(&ok, 16);
qDebug()<<"lenth:"<<length;
quint32 address = line.mid(3, 4).toUInt(&ok, 16);
quint32 mode = line.mid(7, 2).toUInt(&ok, 16);
if(mode==0){
if (address == expectedAddress ) {
QString dataPart = line.mid(9, length*2);
QByteArray dataBytes = hexStringToByteArray(dataPart);
extractedData.append(dataBytes);
expectedAddress += 16;
}
else {
qWarning() << "无效地址:" << address<<"length:"<<length<<line;
}
}else{
qDebug()<<"无效数据";
}
}
Array_HexToBin = extractedData;
//把extractedData每16个字节一行写入到TE_HexFile中进行显示。
qDebug() << "HEX转BIN文件总字节数:"<<extractedData.size();
QString temp_string;
for (int i=0;i<extractedData.size();i++) {
if((i%16)==0){
temp_string = QString::fromLatin1("%1")
.arg(static_cast<quint8>(extractedData.at(i)), 2, 16, QLatin1Char('0')).toUpper();
}else if(((i+1)%8)==0){
temp_string += QString::fromLatin1(" %1 ")
.arg(static_cast<quint8>(extractedData.at(i)), 2, 16, QLatin1Char('0')).toUpper();
}else{
temp_string += QString::fromLatin1(" %1")
.arg(static_cast<quint8>(extractedData.at(i)), 2, 16, QLatin1Char('0')).toUpper();
}
if((((i+1)%16)==0)||((i+1)==extractedData.size())){
TE_HexFile->append(temp_string);
}
}
if(ChecBox_AutoSave->checkState()==Qt::Checked){
save_bin(extractedData,path);
if(ChecBox_AutoOpen->checkState()==Qt::Checked){
open_folder(path);
}
}
}
3 完成效果
功能1:自动保存到HEX文件目录,勾选此选项后,打开HEX以后自动会在HEX文件目录生成一个bin文件,文件名为HEX文件名基础上添加时间。
功能2:保存完毕自动打开BIN目录,勾选此选项后,手动或自动保存完HEX以后,会自动打开BIN所在目录。
功能3:可以手动选择要保存的路径和名称,然后保存bin文件
4 结论
生成的文件与KEIL自动生成的BIN对比完全一样。
5 源码地址
https://download.csdn.net/download/Running_A/89535727
吐槽一下CSDN审核源码的人员,效率太低了,12号上传的,19号才审核完!!!