C#写的Hex转Bin格式的工具
首页 > C#   作者:皮皮华  2021年3月25日 13:49 星期四  热度:2703°  字号:   评论:0 条
时间:2021-3-25 13:49   热度:2703°  评论:0 条 

    在STM32单片机的开发中,经常需要将生成的HEX文件转换成bin文件烧录至单片机。

    而我负责的大多项目是基于FreeRTOS的并且支持IAP固件升级的,简单原理就是将单片机的程序存储区分为Boot、A、B一共3个区域,Boot为启动区,A为用户程序,B为升级包缓存区。正常情况下,开机先运行启动区程序,再运行A区的用户程序;当需要升级时,将新的用户程序暂存至B区,下一次开机启动程序检测到需要升级,则将B区的用户程序拷贝至A程序,再重启运行新的用户程序。从而达到远程固件升级的功能,当然本文重点不在于这个具体如何实现的。

    从上可知,在我的运用场景中,需要烧录2次,第一次先烧录Boot程序,第二次烧录用户程序。但这样很麻烦,所以以前的方式是将这2个Hex文件合并之后再转换Bin文件再烧录。但对于懒散的皮皮华来说还是过于麻烦。百度了一大堆转换工具,并没有我想要的很简单的工具,大部分需要设置多个文件,设置起始地址等等特别麻烦。于是就决定自己手写一个EXE执行程序,一步到位。

    那么首先我们需要做的第一件事当然是了解HEX文件的组成,参考百度百科<hex文件格式>,简单理解就是每一行的数据都符合以下格式,很类似我们开发与平台GPRS通讯的各种TCP/UDP通讯协议。

    数据类型有6种

    所以需要我们重点去提取00类型的数据。

    下面开始上正菜。我们先来看看软件成品:


    下面开始介绍如何去实现这些功能,首先是打开按钮,其作用仅仅是为了获取需要转换文件的完整路径:

        private void btnOpenHex_Click(object sender, EventArgs e)
        {
            try
            {
                pbConvert.Value = 0;
                if (openHexDlg.ShowDialog() == DialogResult.OK) //打开转换的目标文件
                {
                    tbHexPath.Text = openHexDlg.FileName;
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
再是输出按钮,与打开按钮一致:
        private void btnOut_Click(object sender, EventArgs e)
        {
            try
            {
                if (saveBinDlg.ShowDialog() == DialogResult.OK)
                {
                    tbBinPath.Text = saveBinDlg.FileName;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
重点就在于转换按钮:
        private void btnConvert_Click(object sender, EventArgs e)
        {
            //转换时使3个按钮不可以点击
            btnOpenHex.Enabled = false;
            btnOut.Enabled = false;
            btnConvert.Enabled = false;
            try
            {
                Int32 i;
                Int32 j = 0;
                String szTxt = "";//合并HEX文件的数据
                String szLine = "";//Hex文件每行的数据
                String szHex = "";//bin文件的HEX字符串数据
                int startAdr = 0;//起始地址
                int endAdr = 0;   //用于判断hex地址是否连续,不连续补充0xFF
                int lineLenth;//当前行的数据长度
                bool FirstLineFlag;//起始行标志位
                bool FirstAddrFlag;//起始地址标志位
                szHexPath = tbHexPath.Text;//HEX文件路径
                szBinPath = tbBinPath.Text;//Bin文件路径
                if (szHexPath == "")
                {
                    MessageBox.Show("请选择需要转换的hex文件!         ", "提示");
                    return;
                }
                pbConvert.Maximum = 100;
                #region 读取并处理Boot.hex
                if (MergeBoot.Checked == true)//读取启动文件
                {
                    if (!File.Exists(@"Boot.hex"))
                    {
                        MergeBoot.Checked = false;
                        MessageBox.Show("请在当前程序目录放入启动hex文件并命名为Boot.hex", "提示");
                        return;
                    }
                    pbConvert.Value = 10;
                    StreamReader BootHexReader = new StreamReader("Boot.hex");
                    FirstAddrFlag = true;
                    while (true)
                    {
                        szLine = BootHexReader.ReadLine(); //读取Hex中一行
                        if (szLine == null) { break; } //读取完毕,退出
                        if (szLine.Substring(0, 1) == ":") //判断首字符是”:”
                        {
                            if (szLine.Substring(7, 2) == "00")//数据记录
                            {
                                if (SaveMergeHex.Checked == true)
                                {
                                    szTxt += szLine + "\r\n";
                                }
                                lineLenth = Int32.Parse(szLine.Substring(1, 2), System.Globalization.NumberStyles.HexNumber); // 获取一行的数据个数值
                                startAdr = Int32.Parse(szLine.Substring(3, 4), System.Globalization.NumberStyles.HexNumber); // 获取地址值
                                if (FirstAddrFlag)
                                {
                                    endAdr = startAdr;
                                }
                                else
                                {
                                    FirstAddrFlag = false;
                                }
                                for (i = 0; i < startAdr - endAdr; i++) // 补空位置
                                {
                                    szHex += "FF";
                                }
                                szHex += szLine.Substring(9, lineLenth * 2); //读取有效字符
                                endAdr = startAdr + lineLenth;
                            }
                            else if (szLine.Substring(7, 2) != "01")//不为结束标识
                            {
                                if (SaveMergeHex.Checked == true)
                                {
                                    szTxt += szLine + "\r\n";
                                }
                            }
                        }
                    }
                    BootHexReader.Close(); //关闭目标文件
                }
                pbConvert.Value = 20;
                #endregion

                #region 读取并处理需要转换的hex文件
                pbConvert.Value = 30;
                StreamReader HexReader = new StreamReader(szHexPath);
                FirstLineFlag = true;
                FirstAddrFlag = true;
                while (true)
                {
                    szLine = HexReader.ReadLine(); //读取Hex中一行
                    if (szLine == null) { break; } //读取完毕,退出
                    if (szLine.Substring(0, 1) == ":") //判断首字符是”:”
                    {
                        if (szLine.Substring(7, 2) == "00")//数据记录
                        {
                            if (MergeBoot.Checked == true && SaveMergeHex.Checked == true)
                            {
                                szTxt += szLine + "\r\n";
                            }
                            lineLenth = Int32.Parse(szLine.Substring(1, 2), System.Globalization.NumberStyles.HexNumber); // 获取一行的数据个数值
                            startAdr = Int32.Parse(szLine.Substring(3, 4), System.Globalization.NumberStyles.HexNumber); // 获取地址值
                            if(MergeBoot.Checked == true){//合并文件则不需要初始化结束地址
                                FirstAddrFlag = false;
                            }else{
                                if (FirstAddrFlag)
                                {
                                    endAdr = startAdr;
                                    FirstAddrFlag = false;
                                }
                            }
                            if (startAdr == 0x1A90)
                            {
                            ;
                            }
                            for (i = 0; i < startAdr - endAdr; i++) // 补空位置
                            {
                                szHex += "FF";
                            }
                            szHex += szLine.Substring(9, lineLenth * 2); //读取有效字符
                            endAdr = startAdr + lineLenth;
                        }
                        else if (szLine.Substring(7, 2) == "04")//起始标识
                        {
                            if (FirstLineFlag)
                            {
                                FirstLineFlag = false;
                            }
                            else if (MergeBoot.Checked == true && SaveMergeHex.Checked == true)
                            {
                                szTxt += szLine + "\r\n";
                            }
                        }
                        else
                        {
                            if (MergeBoot.Checked == true && SaveMergeHex.Checked == true)
                            {
                                szTxt += szLine + "\r\n";
                            }
                        }
                    }
                }
                HexReader.Close(); //关闭目标文件
                pbConvert.Value = 50;
                #endregion

                #region 输出合并的Hex文件
                if (MergeBoot.Checked == true && SaveMergeHex.Checked == true)
                {
                    string MergeHexPath = Path.GetDirectoryName(szHexPath) + "\\" + Path.GetFileNameWithoutExtension(szHexPath) + "_Merge.hex";
                    FileStream MergeHex = new FileStream(MergeHexPath, FileMode.OpenOrCreate); //实例化一个文件流,指定文件完整路径,设置模式为打开或在不存在时创建
                    StreamWriter MergeHexStr = new StreamWriter(MergeHex);//实例化文本写入器,指定写入的完全路径,确认写入
                    MergeHexStr.Write(szTxt);
                    MergeHexStr.Close();
                    MergeHexStr.Dispose();
                    MergeHex.Close();//关闭文件流
                    MergeHex.Dispose();//清除文件流
                }
                #endregion

                #region 将hex数据转换为字节数据
                Int32 Length = szHex.Length;
                byte[] szBin = new byte[Length / 2];
                pbConvert.Maximum = Length / 2;

                for (i = 0; i < Length; i += 2) //两字符合并成一个16进制字节
                {
                    szBin[j] = (byte)Int16.Parse(szHex.Substring(i, 2), NumberStyles.HexNumber);
                    j++;
                    pbConvert.Increment(i);
                }
                #endregion

                #region 输出Bin文件
                if (szBinPath == "")//如果没设置输出路径则默认为hex文件路径
                {
                    szBinPath = Path.ChangeExtension(szHexPath, "bin");
                    tbBinPath.Text = szBinPath;
                }
                FileStream fBin = new FileStream(szBinPath, FileMode.OpenOrCreate); //创建文件BIN文件
                BinaryWriter BinWrite = new BinaryWriter(fBin); //二进制方式打开文件
                BinWrite.Write(szBin, 0, szBin.Length);//写入字节
                BinWrite.Flush();//释放缓存
                BinWrite.Close();//关闭文件
                fBin.Close();//关闭文件流
                fBin.Dispose();//清除文件流
                #endregion

                btnOpenHex.Enabled = true;
                btnOut.Enabled = true;
                btnConvert.Enabled = true;
                MessageBox.Show("文件转换完成!        ", "提示");
                pbConvert.Value = 0;//清除进度显示
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }
    一共分为4个步骤:

 

    而下面这个则实现了拖入hex文件自动转换的功能:

        private void frMain_DragEnter(object sender, DragEventArgs e)                                         //获得“信息”
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.All;                                                              //重要代码:表明是所有类型的数据,比如文件路径
            else
                e.Effect = DragDropEffects.None;
        }
        private void frMain_DragDrop(object sender, DragEventArgs e) //拖拽文件
        {
            string path = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();    //获得路径
            tbHexPath.Text = path;           //由一个textBox显示路径
            if (Path.GetExtension(path) == ".hex" || Path.GetExtension(path) == ".HEX")
            {
                btnConvert.PerformClick();//直接转换
            }
        }
以及使用快捷键操作软件
        private void frMain_BtnPress(object sender, KeyEventArgs e)//按键触发
        {
            if(e.KeyValue == 112)//F1
            {
                btnOpenHex.PerformClick();//直接打开文件
            }
            else if (e.KeyValue == 113)//F2
            {
                btnOut.PerformClick();//直接输出
            }
            else if (e.KeyValue == 115)//F4
            {
                btnConvert.PerformClick();//直接转换
            }
        }

最后完整的源码就在这里啦。https://github.com/BigPiPiHua/Hex2Bin



 您阅读这篇文章共花了: 
捐赠支持:如果觉得这篇文章对您有帮助,请“扫一扫”鼓励作者!
 本文无需标签!
二维码加载中...
本文作者:皮皮华      文章标题: C#写的Hex转Bin格式的工具
本文地址:http://huazai.eleuu.com/?post=38
版权声明:若无注明,本文皆为“皮皮华博客”原创,转载请保留文章出处。

发表吐槽

你肿么看?

你还可以输入 250 / 250 个字

嘻嘻 大笑 可怜 吃惊 害羞 调皮 鄙视 示爱 大哭 开心 偷笑 嘘 奸笑 委屈 抱抱 愤怒 思考 日了狗

评论信息框


既然没有吐槽,那就赶紧抢沙发吧!