STM32自动化烧写

目的与适用范围

  1. 项目已经固定,每次烧写程序只会更改很少量的信息。比如设备编号,日期等信息,但每台设备这些信息都是不相同的。
  2. 每次更改设备必须打开keil更改编号,再次编译,烧写,过程繁琐。于是就想可不可以直接更改hex文件,改好后直接烧写进板子拉?

使用到工具

  1. python
  2. pylink(python实现的一个stm32模块)
  3. JLinkARM库(这个是C/C++实现的底层库)

步骤

  1. 找到不同设备号更改时hex改变位置
  2. 使用python实现自动更改
  3. 使用pylink烧写进去

具体操作

  1. 找出hex文件更改位置
    1. keil编译生成两个不同设备号的hex文件,并使用比较命令找出更改位点。这里说下hex文件保存位置项目根目录\Output\下面会有一个.hex文件,这个文件就是要下载到STM32的程序。复制出来保存到你喜欢的文件夹下。
    /* 第一个文件编号如下 */
    #define ID_Number       2018080120
    /* 保存的hex文件命名为old.hex */
    /* 第二个文件编号 */
    #define ID_Number       2018080300
    /* 保存为new.hex */
    /* 更改编号后一定要点编译,不然两个文件都完全一样了 */
   /* linux 比较两个文件 */
   diff old.hex new.hex
   1329c1329
   < :1052F0006846FCF7F1FB1CBD2C7649781CB50446CA
   ---
   > :1052F0006846FCF7F1FB1CBD787549781CB504467F
   /* 显示1329行不同并分别列出了不同的行 */
   /* windows CMD 比较两个文件 */
   FC new.hex old.hex
   ***** new.hex
   :1052E0002088ADF800006088ADF802000248019007
   :1052F0006846FCF7F1FB1CBD2C7649781CB50446CA
   :105300002088ADF800006088ADF802000548B0F8CC
   ***** OLD.HEX
   :1052E0002088ADF800006088ADF802000248019007
   :1052F0006846FCF7F1FB1CBD787549781CB504467F
   :105300002088ADF800006088ADF802000548B0F8CC
   *****
   /* window FC命令给出了不同行和上下各一行所以是3行,但没有说明是那一行,可以复制搜索下,也能确认是第1329行 */
   /* 仔细数一下可以更加明确的那几列不同,因为我们到时候更改hex文件必须定位到那一行,那一列 */
  1. 使用python更改
    1. 分析下hex文件那几列不同
      linux的diff比较结果很容易的看出来2C76和7875是不同的,行尾两个留后面说。使用计算器进制转化计算下我们的设备编号十六进制是什么?
      2018080120对应0x78497578,2018080300对应0x7849762C
      可以对比下发现最后四位数字不同7578和762C刚好和我们用diff比较出来结果对上只是前后两位对换,这种对换应该是因为计算机存储的关系。再对比下文件就可以发现2C764978对应2018080300, 78754978对应2018080120。这里的存储顺序需要特别留意下,因为使用python暴力更改文件必须一一对应。
      比较下可以发现除这个数字不同外最后两位也是不一样的,这又是什么鬼?
      intel hex文件格式这里做了比较细的描述,总结下就是最后两位是对每一行前面计算得到的,用于检测这一行有没有错漏。
    2. 更改hex文件
   import os

   # 定义一些变量
   file_name = "data.hex"          # 写入hex文件文件名
   row = 1329                      # 编号行
   line = 23                       # 编号列
   No_row_str = list()             # 编号行字符串
   current_No = 0                  # 当前编号十进制
   next_No = 0                     # 下台设备号

   # 打开文件
   	if not os.access(file_name, os.F_OK|os.R_OK|os.W_OK):
   print(file_name,"文件权限受限\n")
print(file_name,"加载中......")
while 1 :
   file_ptr = open(file_name, "r+")
		# 获取当前设备号
		def get_current_No(file):
    # 定位编号位置,包含行,起始列
    global No_row_str
    i = row
    while i != 0:
        read_line = file.readline();
        i = i - 1;
    No_row_str = list(read_line)
    # 定位到上一行,方便后而写入
    size = len(read_line)
    file.seek((file.tell() - size - 1), 0)
    return x_to_10(read_line[25:33])

		# 16进制转化为10进制
    def x_to_10(str):
        global current_No
        inpu = ['0', 'x']
        list_str = list(str)
        inpu = inpu + list_str[6:8] + list_str[4:6] + list_str[2:4] + list_str[0:2]
        No_str = ''.join(inpu)
        current_No = int(No_str, 16);
		# 将文件中的设备编号更新为新设备编号
   def update_No(new_No):
       global No_row_str
       #get new no hex string list;
       no_hex = list(hex(new_No))
       #update string to the No cur str;
       No_row_str[line + 2 + 6] = no_hex[2];
       No_row_str[line + 2 + 7] = no_hex[3];
       No_row_str[line + 2 + 4] = no_hex[4];
       No_row_str[line + 2 + 5] = no_hex[5];
       No_row_str[line + 2 + 2] = no_hex[6];
       No_row_str[line + 2 + 3] = no_hex[7];
       No_row_str[line + 2 + 0] = no_hex[8];
       No_row_str[line + 2 + 1] = no_hex[9];
       ver_str = tohex(vertify(No_row_str))
       No_row_str[41] = ver_str[2]
       No_row_str[42] = ver_str[3]
       No_row_str[43] = '\r'
       return (''.join(No_row_str))
   		# python有一个十进制转16进制的hex不能直接用,因为数字转化的位数不确定会根据数字不同长度不同,这里表现就是有的转化后会是0xa1,有的又会是0xf。后面的会少一位,需要的是0x0f这样的形式。因此自己写一个.
   		def tohex(number):
   	      rst = ['0','x']
   	      rst.append(hex(int(number / 16))[2])
   	      rst.append(hex(number % 16)[2])
   	      return rst
   		# 计算验证码
   		def vertify(row_line):
   		    if row_line == "":
   		        print("不能验证空行")
   		        return
   		    size = len(row_line)
   		    sum = 0
   		    vertify = 0
   		    for cur_pos in range(1, size-3, 2):
   		        temp = ''.join(No_row_str[cur_pos:(cur_pos + 2)])
   		        sum = sum + int(temp, 16)
   		    vertify = 256 - (sum % 256)
   	    return vertify
		实现效果:
		当前设备编号: 2020080301
		默认下台设备编号: 2020080302
		下台设备编号(使用默认编号直接按Enter)
		正在更改设备编号为 2020080302 ......


		
		当前设备编号: 2020080302
		默认下台设备编号: 2020080303
		下台设备编号(使用默认编号直接按Enter)
		正在更改设备编号为 2020080303 ......


		
		当前设备编号: 2020080303
		默认下台设备编号: 2020080304
		下台设备编号(使用默认编号直接按Enter)
		正在更改设备编号为 2020080304 ......


		
		当前设备编号: 2020080304
		默认下台设备编号: 2020080305
		下台设备编号(使用默认编号直接按Enter)
		正在更改设备编号为 2020080305 ......
  1. 写入板子
    使用pylink写入。但pylink国内使用的还真不多,于是又是各种找用法,本来是想用人家提供API自己写,但无耐文档是真的坑,只能直接使用提供的命令行。说说遇到的坑:
    1. 开门不利,安装。要求我安装Microsoft Visual C++ 14.0,更神奇的是给我网页是认我安装visual studio。我安装一个python部件你叫我安装一个IDE,只想骂人。装了最新的你还提示找不到。只能找网友帮忙了。安装模块报错,因为我是psutil安装不上,直接<Ctrl + f>搜索psutil,下载安装OK。
    2. pylink.JLink()错误连不上,百度搜的文档我压根儿都没看到JLinkARM啥事。连又连接不上,没法只能上github看看。github上说的很明确JLinkARM.dll要放在指定目录才可以,于是把keil下面的JLinkARM放windows,sys32,sys,当前目录,但没有一个可用的。仔细阅读github说明,要在这里下载JLinkARM.dll。下载下来写的有三个目录可以放,当前目录、windows目录、windows/sys32目录,我放在sys32好像是可以了,也不知道是因为放在sys32下面还是因为path中加入新安装软件的运行目录的原因。反正就是可以用了
    3. 打开设备pylink.JLink().open()。要一个参数,这参数文档也不写。自己摸索发现win10设备管理器里面的事件里会有一行"已配置设备 USB\VID_1366&PID_0101\000000123456。",使用123456试试,还可以。
    4. 打开了准备用flash_file写进去说我没有连接target,好吧只能用connect连接,连接又要用到设备名,这个设备名又不用有说只能自己摸索。这次使用设备管理器救不了我了,keil才能帮助我,keil的每个项目都要选择一个Device类型,比如STM32F103RC,现在想来感觉当时傻不知道用这个,但文档不说我怎么知道用那一串字符表示啊。
    5. 到这里我其实还是没有成功运行connect,还是会提示pylink.errors.JLinkException: J-Link DLL is not open.,但我发现一个好东西,可以完全放弃它的API,使用命令行就可以了。pylink提供了一个pylink命令,所以转而使用他的命令就可以了,我又不用管什么效率,它API也不一定带来什么效率。
    6. 命令行就友好太多了想办法填满见个参数就好了。我确定设备名就是使用命令行确定STM32F103RC可用的
			$ pylink emulator -s STM32F103RC
			Device Name: STM32F103RC
			Core ID: 1000342647
			Flash Address: 134217728
			Flash Size: 262144 bytes
			RAM Address: 536870912
			RAM Size: 49152 bytes
			Manufacturer: ST
			# 对于不可用的设备只会显示 
			STM32F103R is not supported :(

说说烧写命令

			pylink flash -a 8000000 -t SWD -d STM32F103RC -s 123456 data.hex

这里还是有坑,-a/address是写入地址,这个可以keil里面项目中找到一般都0x8000000或以上,但都知道0x8000000是一个16进制数,我还特意计算了下它的十进制数,用不了。文档中写要用int数。试试直接8000000,可以用。好吧没啥说的。
-t 是下载方式就两种JTA和SWD和你板子的接线有关
-s/serial 就是设备管理器”事件“里面查到的那个
-d/device 就是设备名,keil项目里面有
最后是hex文件
有了以上命令就可以使用python写入了,但还有一点要注意写入前hex文件要关闭状态,pylink会去读hex文件,所以pylink写必须在file.close()后面。

使用脚本烧写的好处

  1. 自动完成自加操作,懒人必备
  2. 防止输入出错,写入重复编号
  3. 可以自己加入日志功能,实现自动记录烧写日期,烧写编号
  4. 还可以加入导出到excl功能,可定制程度相当高
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐