1.程序
cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Hex2Bin
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 2 || args.Length > 3)
{
ShowHelp();
return;
}
string inputFile = args[0];
string outputFile = args[1];
long startOffset = 0;
long endOffset = long.MaxValue;
// 处理可选的偏移参数
if (args.Length == 3)
{
if (!long.TryParse(args[2], System.Globalization.NumberStyles.HexNumber, null, out startOffset))
{
Console.WriteLine("错误:无效的偏移地址格式");
return;
}
endOffset = long.MaxValue;
}
try
{
ConvertHexToBin(inputFile, outputFile, startOffset, endOffset);
Console.WriteLine($"转换成功!输出文件:{outputFile}");
}
catch (Exception ex)
{
Console.WriteLine($"错误:{ex.Message}");
}
}
static void ShowHelp()
{
Console.WriteLine("Hex2Bin - Intel HEX 转 BIN 格式转换工具");
Console.WriteLine("用法:Hex2Bin <输入文件.hex> <输出文件.bin> [起始偏移地址]");
Console.WriteLine("示例:");
Console.WriteLine(" Hex2Bin firmware.hex firmware.bin");
Console.WriteLine(" Hex2Bin firmware.hex firmware.bin 1000 // 从0x1000开始提取");
}
static void ConvertHexToBin(string hexFile, string binFile, long startOffset, long endOffset)
{
var dataSegments = new Dictionary<long, byte>();
long minAddr = long.MaxValue;
long maxAddr = long.MinValue;
long currentSegmentAddr = 0;
long extendedLinearAddr = 0;
long extendedSegmentAddr = 0;
string[] lines = File.ReadAllLines(hexFile);
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line) || line[0] != ':')
continue;
// 解析HEX行
byte byteCount = Convert.ToByte(line.Substring(1, 2), 16);
ushort address = Convert.ToUInt16(line.Substring(3, 4), 16);
byte recordType = Convert.ToByte(line.Substring(7, 2), 16);
string dataString = line.Substring(9, byteCount * 2);
byte checksum = Convert.ToByte(line.Substring(9 + byteCount * 2, 2), 16);
// 验证校验和
byte calcChecksum = 0;
calcChecksum += byteCount;
calcChecksum += (byte)(address >> 8);
calcChecksum += (byte)(address & 0xFF);
calcChecksum += recordType;
for (int i = 0; i < byteCount; i++)
{
calcChecksum += Convert.ToByte(dataString.Substring(i * 2, 2), 16);
}
calcChecksum = (byte)((~calcChecksum + 1) & 0xFF);
if (calcChecksum != checksum)
{
throw new Exception($"校验和错误:行 {line}");
}
// 计算实际地址
long actualAddress;
switch (recordType)
{
case 0x00: // 数据记录
actualAddress = extendedLinearAddr + address;
if (extendedSegmentAddr != 0)
actualAddress = (extendedSegmentAddr << 4) + address;
// 存储数据
for (int i = 0; i < byteCount; i++)
{
byte data = Convert.ToByte(dataString.Substring(i * 2, 2), 16);
long addr = actualAddress + i;
if (addr >= startOffset && addr <= endOffset)
{
if (!dataSegments.ContainsKey(addr))
dataSegments[addr] = data;
if (addr < minAddr) minAddr = addr;
if (addr > maxAddr) maxAddr = addr;
}
}
break;
case 0x01: // EOF
break;
case 0x02: // 扩展段地址
extendedSegmentAddr = Convert.ToUInt16(dataString, 16);
break;
case 0x03: // 起始段地址
// 忽略
break;
case 0x04: // 扩展线性地址
extendedLinearAddr = Convert.ToUInt32(dataString, 16) << 16;
extendedSegmentAddr = 0;
break;
case 0x05: // 起始线性地址
// 忽略
break;
}
}
if (dataSegments.Count == 0)
{
throw new Exception("没有找到有效的数据记录");
}
// 创建连续的数据缓冲区
long totalSize = maxAddr - minAddr + 1;
byte[] binData = new byte[totalSize];
// 填充数据
foreach (var kvp in dataSegments)
{
binData[kvp.Key - minAddr] = kvp.Value;
}
// 写入BIN文件
File.WriteAllBytes(binFile, binData);
Console.WriteLine($"转换统计:");
Console.WriteLine($" 起始地址:0x{minAddr:X8}");
Console.WriteLine($" 结束地址:0x{maxAddr:X8}");
Console.WriteLine($" 数据大小:{totalSize} 字节");
}
}
}
2. 使用方法
cs
# 基本用法
Hex2Bin.exe input.hex output.bin
# 指定起始地址(十六进制)
Hex2Bin.exe input.hex output.bin 1000
# 显示帮助
Hex2Bin.exe
3.程序特点
-
支持标准Intel HEX格式:
-
数据记录(00)
-
文件结束记录(01)
-
扩展段地址(02)
-
扩展线性地址(04)
-
起始地址记录(03, 05)
-
-
校验和验证:每行HEX数据都会验证校验和
-
地址范围过滤:可选的起始地址参数
-
内存高效:使用字典存储非连续数据段
4.使用示例
假设有HEX文件内容:
bash
:100000000102030405060708090A0B0C0D0E0F101A
:100010001112131415161718191A1B1C1D1E1F2029
:00000001FF
转换后的BIN文件将包含地址0x0000-0x001F的32字节数据。
这个工具适用于嵌入式开发中常见的固件格式转换需求。
