前情回顾
在上一篇《G32R501与pyocd:一顿饭搞定的适配流程》中,我们讲解了如何让 PyOCD 正确适配 G32R501,关注点是“如何让 PyOCD 认识 M52 内核、如何加载目标脚本、并在命令行里快速完成Flash下载”。
可是,仅仅在命令行里敲命令,远远不能满足“产线/测试人员”的友好度需求。想象一下,产线上每天要烧写几十到几百次固件,一不小心输错命令就很尴尬。
本篇给各位小伙伴分享:①如何给 PyOCD 加一个 Python 写的图形界面(GUI),让烧写操作一键点按;②如何利用 PyInstaller 把这个 Python 项目打包成 EXE,从而让大家在没有安装 Python 的电脑上也能轻松使用。
1. 为什么要做GUI与打包EXE
- 更友好、更直观
如果我们给同事展示一个命令行,他们可能会有点“吓人”:mad: 的感觉,担心忘记或输错参数。而一个UI界面则是一目了然,“选择固件→点击下载”这样的流程几乎零学习成本。
- 无需安装Python
经常在产线或测试环境中,电脑系统可能很久不会升级,也没有装Python。要想让他们去装Python+库依赖,就比较麻烦:dizzy: 。
而如果能打包成EXE,所有Python解释器、第三方模块都内置其中,对外只需要双击文件即可启动GUI。一旦配置好,就可以在任何Windows机器上复用。
- 可延伸的封装思路
有了GUI后,我们还可以更进一步添加“固件版本管理”“设备自动识别”“烧写统计”等功能,把它变成一个灵活的产线工具:lol: 。
2. 实现GUI的思路与技术选型
在Python里做GUI并不复杂,一般常见选项是:
- Tkinter(Python标准库自带,轻量基础)
- PyQt/PySide(功能强大,界面美观,但相对体量大)
- wxPython、Kivy等其他选项
对于“简单的产线烧写工具”来说,Tkinter 足够胜任,所以本篇使用 Tkinter 作演示。
3. 设计功能需求:“又简单又够用”
为了在界面上实现基本的烧写操作,我们梳理了下面几项功能:
- 选择自定义脚本
用户可以选择自定义脚本,因为G32R501核心DCS功能需要特定的脚本进行KEY写入,这个我们需要关注。
- 选择固件
用户能通过文件对话框,选择
.hex
或 .bin
格式固件。
- 擦除操作
一键擦除Flash,让G32R501的存储空间干净如新。
- 下载操作
把选定的固件文件下载到目标芯片中,并可通过进度提示或成功/失败信息告诉用户结果。
- 仿真器识别
如果电脑插着多个调试器或多个板子,可以列出来让用户选。
4. 代码层级:分文件设计
以下是示例代码,思路供参考。我们可以根据项目规模或个人习惯决定是否拆分成多个 .py
文件;也可以使用一个 .py
文件简单粗暴写齐。这里分拆成若干功能模块,好处是层次更清晰,也便于后续维护。
4.1 文件结构概览
假设我们有个目录“PyOCDDownloadToolGUI”,内部结构大概是:
PyOCDDownloadToolGUI/
├─ main.py # 程序入口 - 启动GUI、Tkinter界面逻辑
├─ download_operation.py # 下载功能
├─ erase_operation.py # 擦除功能
├─ file_selector.py # 打开文件对话框
├─ get_debuggers.py # 获取当前CMSIS-DAP设备列表
└─ get_supported_targets.py # 获取当前pyocd支持芯片列表
下面我们聚焦主要内容,展示部分代码,以下两段代码演示了如何调用 pyocd 的命令行。
erase_operation.py
"""
实现对目标芯片的全擦除函数 erase_chip()。
若用户勾选了自定义脚本路径,则在命令行中附加 --script=<脚本路径>。
"""
import subprocess
import sys
def erase_chip(target_name, user_script=None):
"""
Perform chip erase using pyOCD command.
- target_name: e.g. 'g32r501dxx'
- user_script: path to user script, or None if not used
Return the command output for logging or error info.
"""
cmd = ["pyocd", "erase", "--chip", "--target", target_name]
if user_script:
cmd.append(f"--script={user_script}")
try:
if sys.platform.startswith("win"):
# Windows专用
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = 0 # 0 对应 SW_HIDE
result = subprocess.run(
cmd,
startupinfo=si,
capture_output=True,
text=True,
check=False
)
else:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=False
)
return result.stdout + result.stderr
except Exception as e:
return f"Error executing erase_chip: {e}"
download_operation.py
"""
实现下载固件函数 download_firmware(),
针对 .bin 文件可附加 --format bin 和 --base-address 参数;
针对 .hex 文件则直接 pyocd load -t <target> <file_path>。
"""
import subprocess
import sys
def download_firmware(target_name, file_path, file_type, user_script=None, base_address=None):
"""
Download firmware to target chip using 'pyocd load'.
- target_name: e.g. 'g32r501dxx'
- file_path: absolute path of the firmware
- file_type: 'bin' or 'hex'
- user_script: if not None, specify '--script=xxx'
- base_address: for .bin format, required if user wants to specify
Return the command output for logging.
"""
cmd = ["pyocd", "load", "-t", target_name]
# If user_script is specified
if user_script:
cmd.append(f"--script={user_script}")
# If it's bin, add extra options
if file_type == "bin":
cmd.extend(["--format", "bin"])
# If user provided base address
if base_address is not None:
cmd.extend(["--base-address", str(base_address)])
# Finally, add the firmware file path
cmd.append(file_path)
try:
if sys.platform.startswith("win"):
# Windows专用
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = 0 # 0 对应 SW_HIDE
result = subprocess.run(
cmd,
startupinfo=si,
capture_output=True,
text=True,
check=False
)
else:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=False
)
return result.stdout + result.stderr
except Exception as e:
return f"Error executing download_firmware: {e}"
最终启动效果:

5. 打包成EXE:PyInstaller“一键搞定”
下面进入本篇文章最重要的部分:如何把这个GUI打包成一个单独可执行文件。
5.1 为什么选用PyInstaller
- 使用简单:只需写一个
spec
文件,或者直接 pyinstaller xxx.py
就能包装出 dist
文件夹;
- 依赖收集:它会自动收集
.py
文件、第三方依赖、.dll
文件等,打包到一起;
- 常规方案:是Python社区里最常见、成熟度高的打包工具之一。
5.2 PyInstaller打包我们的exe
(1) 命令行打包
只需在命令行(在main.py同级目录下启动)中执行以下命令:
pyinstaller --onefile --noconsole --name PyOCDDownloadToolGUI main.py
命令解释:
- --onefile:生成一个单文件EXE,启动时会自解压到临时目录里。
- --noconsole:不弹出额外的命令行窗口,让界面更干净;如果想看调试信息,可以去掉此参数。
- --name PyOCDDownloadToolGUI:指定生成的 EXE 文件名;如省略则默认与脚本同名。
- main.py:我们的GUI入口脚本。
执行完该命令后,PyInstaller 会在当前目录下生成一个 dist
文件夹,里面就有 PyOCDDownloadToolGUI.exe
。
我们生成的PyOCDDownloadToolGUI.exe在已经安装好pyocd的Windows电脑上就可以使用啦。
(2) 打包pyocd
PyOCD也带有 pyocd.exe
命令行工具。如果我们把它也打包到和 PyOCDDownloadToolGUI.exe
同一目录,下次就可以不再额外安装pyocd或python。
打包方法如下:
-
从 https://codeload.github.com/pyocd/pyOCD/zip/refs/tags/v0.37.0 下载 pyOCD 的压缩包。
-
解压后在根目录会看到 pyocd.py、pyocd.spec 等文件,将这两个文件复制到我们已经完成了 G32R501 适配工作的本地 pyocd 所在目录(注意:这个目录与 pyocd 同级,而不是放到它的子目录下)。比如默认 Python 的 site-packages 路径:
C:\Users\<用户名>\AppData\Local\Programs\Python\Python312\Lib\site-packages\pyocd
我们就需要把下载解压后的 pyocd.py、pyocd.spec 放到上述 pyocd 文件夹的“父目录”里。
-
在存放 pyocd.spec 的目录(即刚才所述的本地 pyocd 同级目录)启动 cmd,输入命令: pyinstaller pyocd.spec
-
等待一段时间打包完成后,就会在 dist 文件夹下生成一个针对 pyocd 的可执行文件及其相关资源,以后就可以直接通过这个打包结果来使用 pyocd 命令行。这样就不必再单独安装 Python 或在其它电脑上安装 pyocd 依赖了。
6. 运行与演示
当我们完成打包后,dist\PyOCDDownloadToolGUI\
下会出现 PyOCDDownloadToolGUI.exe
(名称取决于spec里定义)。把这整个文件夹+我们打包好的pyocd.exe文件夹,拷贝到一台没有Python的Windows电脑上,插上我们的G32R501开发板+调试器,直接双击 PyOCDDownloadToolGUI.exe
,理论上就能弹出我们的烧写GUI。
试着点击“Download/Erase/Verify”按钮,看看是否可以正常工作。
下面是我直接安装的Windows10 电脑,在无python,无pyocd环境下的演示:

7. 更多可能
-
进度条
如果想做酷一点,可以在下载的时候显示一个进度条,PyOCD的Flash API并非默认回调进度,但我们可以自己在 flash.flash_binary()
之前拆分写入,或在PyOCD的 session
里加一层钩子。
-
日志记录或错误捕获
产线常需要把烧写记录保存到日志文件。可以加一个 log_operation.py
来记录每次烧写信息和结果。
-
更多的功能扩展
设置校验、批量烧录、与数据库联动等等……只要我们会玩Python,这些都能实现。
非常感谢阅读这篇文章,如果有任何困难或疑问,欢迎在评论区留言。让我们一起让G32R501的烧写过程越来越好玩、越来越好用!
这里是源码和打包后的exe,请各位玩玩哦(#^.^#)。
附件:pyocd_501_download_ui.part01.rar
附件:pyocd_501_download_ui.part02.rar
附件:pyocd_501_download_ui.part03.rar
附件:pyocd_501_download_ui.part04.rar
附件:pyocd_501_download_ui.part05.rar
附件:pyocd_501_download_ui.part06.rar
附件:pyocd_501_download_ui.part07.rar
附件:pyocd_501_download_ui.part08.rar
附件:pyocd_501_download_ui.part09.rar