SUPER_CRJ 发表于 2019-10-15 12:42:44

(开源-C#)分享一个自己写的HEX2BIN源代码

本帖最后由 SUPER_CRJ 于 2019-10-15 12:44 编辑

RT
C#写的,把HEX转换为bin文件。没有用的部分用的是0填充。
大神轻拍。
解决昨天提到的,部分HEX文件没有按照地址顺序排列。
https://www.amobbs.com/thread-5720131-1-1.html
另外:我从网上下载几个HEX2BIN文件都不能解析地址乱的问题,我写的这个可以解决。
(具体思路是:定义一个大数组,数组地址就相当于HEX文件地址,然后进行解析填充,最后再进行截断生成一个bin文件)
(另外有帖子提到,可以先进行HEX地址排序,但是如果存在线性附加地址的话,实现比较麻烦,排序出来可能就乱了。)
可以使用到STM8/STM32生成的HEX生成BIN文件。



s_path = txb_SouceBinPath.Text;

            FileInfo myFile = new FileInfo(s_path);
            string fileExtension = Path.GetExtension(myFile.FullName).ToLower();// 用来获取扩展名,而且变为小写返回,因为扩展名会存在大小写的情况

            if (fileExtension == ".hex")// 日后会增加各种文件的支持,hex文件的解析需要用点时间
            {
                FileStream fs;
                try
                {
                  fs = new FileStream(s_path, FileMode.Open);//open file
                }
                catch
                {
                  MessageBox.Show("文件访问错误,请检查是否设置读保护以及文件是否被占用!", "错误");
                  return;
                }
                StreamReader HexReader = new StreamReader(fs);    //读取数据流
                string szLine = "";// 因为Hex文件是以每行为单位的,所以也就是说读取可以用读取行的方式来操作
                                     //string szHex = "";   // 这个用的是string类别
                StringBuilder szHex0 = new StringBuilder();// 比直接读取string要快许多。
                startAddress = 0xFFFFFFFF;// 最大的地址,需要一直减小
                endAddress = 0;// 最大的地址,需要一直减小
                UInt32 currentAddress = 0;// 当前地址,用于严谨的判断:防止地址不连续的时候出现,因为会有人使用Boot+App,然后拼接的形式生成HEX文件,用于下载。
                UInt32 currentAddressEnd = 0;
                UInt32 addressPrefix = 0; // 当前地址前缀,因为HEX文件的特性,使得前缀会被另外的放置。
                while (true)
                {
                  szLine = HexReader.ReadLine();
                  if (szLine == null) { break; }          //读取完毕,退出
                  if (szLine.Substring(0, 1) == ":")    //判断首字符是”:”,理论是这个是一定会的
                  {
                        switch (szLine.Substring(8, 1))
                        {
                            case "0":// 数据纪录,表示是数据,注意其中含有2个字节地址。
                              { // 重点处理
                                    currentAddress = addressPrefix + Convert.ToUInt32(szLine.Substring(3, 4), 16);// 找到当前的地址。
                                    currentAddressEnd = currentAddress + Convert.ToUInt32(szLine.Substring(1, 2), 16);   //
                                    {
                                        if( currentAddress <= startAddress )
                                        {
                                          startAddress = currentAddress;
                                        }
                                        if( currentAddressEnd >= endAddress )
                                        {
                                          endAddress = currentAddressEnd;
                                        }
                                    }
                                    {// 进行数据填充
                                        for( int i = (int)currentAddress , j = 0 ; i<currentAddressEnd;i++ ,j++)
                                        {
                                          enoughDataFile = Convert.ToByte(szLine.Substring(9+j*2, 2), 16);
                                        }
                                    }

                              }
                              break;
                            case "1":// 文件线束记录
                              break;
                            case "4":// 扩展线性地址记录,这个在STM32中遇到过。
                              addressPrefix = (UInt32)(Convert.ToUInt16(szLine.Substring(9, szLine.Length - 11), 16) << 16);
                              break;

                              // 下面几个都没有遇到过!但是到目前为止,只用上面3个也一直没有出过问题。
                            case "2":// 扩展段地址记录,这个没有遇到到。
                                       // 这个是<<4位,相对于04的<<8位,这个只移动了一半。
                              addressPrefix = (UInt32)(Convert.ToUInt16(szLine.Substring(9, szLine.Length - 11), 16) << 4);
                              break;
                            case "3":// 开始段地址记录,这个没有遇到过。
                                       // 好像用不到
                              break;
                            case "5":// 开始线性地址记录,这个没有遇到过。
                                       // 好像用不到
                              break;
                            default:
                              break;
                        }
                  }
                  else
                  {
                        break;
                  }
                }
                { // 关闭文件访问
                  HexReader.Close();
                }
               
                {// 处理截断数据
                  binFileData.Clear();
                  bindataLen = endAddress - startAddress;
                  for (UInt32 i = startAddress; i < endAddress; i++)
                        binFileData.Add(enoughDataFile);

                  byte[] buffer_Temp = new byte;
                  for (int tmp0 = 0; tmp0 < binFileData.Count; tmp0++)
                  {
                        buffer_Temp = binFileData;
                  }
                  tmpSumValue = GetSumOf16Bit(buffer_Temp, binFileData.Count);
               
               // 进行显示操作:
                  label4.Text = "0x"+ startAddress.ToString("X");
                  label5.Text = "0x" + endAddress.ToString("X");
                  label6.Text = "0x" + bindataLen.ToString("X");
                  label7.Text = "0x" + tmpSumValue.ToString("X");
               
                // 进行文件输出操作。
                  FileStream fBin = new FileStream(txb_targetBinPath.Text, FileMode.Create);
                  BinaryWriter BinWrite = new BinaryWriter(fBin);
                  BinWrite.Write(buffer_Temp, 0, buffer_Temp.Length); //
                  BinWrite.Flush();//释放缓存
                  BinWrite.Close();//关闭文件
                  MessageBox.Show("文件转换完成!      ", "提示");
                }
            }

tomzbj 发表于 2019-10-15 14:28:13

直接用各种gcc binutils里附带的objcopy不就完了...

SUPER_CRJ 发表于 2019-10-15 14:44:51

tomzbj 发表于 2019-10-15 14:28
直接用各种gcc binutils里附带的objcopy不就完了...

是真的不会。。。一直写的嵌入式,C#用的都头疼。这个代码正好集成在配置软件里面

tomzbj 发表于 2019-10-15 15:21:16

SUPER_CRJ 发表于 2019-10-15 14:44
是真的不会。。。一直写的嵌入式,C#用的都头疼。这个代码正好集成在配置软件里面 ...

objcopy是个可执行文件, 运行objcopy -I ihex -O binary xxx.hex xxx.bin, 就完事了.
mingw里有, winavr里有, stm32的各种yagarto/sourcery之类gcc包里也都有, 随便哪个都能用.

kv2004 发表于 2019-10-15 15:56:18

记下2楼的objcopy。

saccapanna 发表于 2019-10-15 15:58:24

如果不需要BIN文件的加密,或者需要添加其他信息,一般编译器可以直接编译生成BIN文件。

heimareed 发表于 2019-10-25 11:37:19

多谢分享,回来再弄个加密,给后面IAP用~

health 发表于 2019-10-25 11:44:14

楼主有才,我一般是用各种烧录下载软件代替。
例如STC-ISP,打开hex文件,然后另存为bin文件。
并不限于烧录软件本身支持的MCU型号。

SUPER_CRJ 发表于 2019-10-25 12:00:23

health 发表于 2019-10-25 11:44
楼主有才,我一般是用各种烧录下载软件代替。
例如STC-ISP,打开hex文件,然后另存为bin文件。
并不限于烧 ...

因为这个要给别人用,你让他自己转换下,他会觉得麻烦,所以还是写吧。

way2888 发表于 2019-10-25 12:43:44

如果遇到空间地址不连续怎么办,新塘的0x0000~0xffff,0x100000~0x1003fff这样你的bin文件怎么处理呢

SUPER_CRJ 发表于 2019-10-25 13:18:09

way2888 发表于 2019-10-25 12:43
如果遇到空间地址不连续怎么办,新塘的0x0000~0xffff,0x100000~0x1003fff这样你的bin文件怎么处理呢 ...

你看我的楼主位说明的方法,这边用的是填充法。没有的地址填充0

way2888 发表于 2019-10-25 19:10:41

SUPER_CRJ 发表于 2019-10-25 13:18
你看我的楼主位说明的方法,这边用的是填充法。没有的地址填充0

要这样填充,那个bin文件就太大了,还是hex格式最灵活

SUPER_CRJ 发表于 2019-10-25 20:59:34

way2888 发表于 2019-10-25 19:10
要这样填充,那个bin文件就太大了,还是hex格式最灵活

bin文件不带有地址信息,除非拆分成两个。

way2888 发表于 2019-10-26 03:39:44

SUPER_CRJ 发表于 2019-10-25 20:59
bin文件不带有地址信息,除非拆分成两个。

如果一个文件拆分成2个文件,而且无法自动识别它的地址的时候,只能通过用文件名称来标识分别,这样反而累赘了,这就是我一直用hex格式而不用bin格式的原因了

BS_good200xy 发表于 2021-1-26 08:54:38

多谢分享,正在研究HexToBin.

xyz543 发表于 2021-1-26 10:02:27

SUPER_CRJ 发表于 2019-10-25 13:18
你看我的楼主位说明的方法,这边用的是填充法。没有的地址填充0

刚看了一下这被挖出来的古文,想建议楼主若可能的话,在于没有用的部分空间应给使用者一个可以输入自订值来进行填充,
或是采用一般预设值的那 0xFF 来填充,因为在于 Flash 或 EPROM 等储存器清为零时就都为 1,故为 Byte 表示时应为 0xFF。
上述仅供楼主参考,谢谢。

waymcu 发表于 2021-1-26 10:06:26


多谢分享,
页: [1]
查看完整版本: (开源-C#)分享一个自己写的HEX2BIN源代码