G32R501与PyOCD的进阶应用:一键GUI+打包EXE,让烧写更优雅
> **前情回顾**> 在上一篇《G32R501与pyocd:一顿饭搞定的适配流程》中,我们讲解了如何让 PyOCD 正确适配 G32R501,关注点是“如何让 PyOCD 认识 M52 内核、如何加载目标脚本、并在命令行里快速完成Flash下载”。
>
> 可是,仅仅在命令行里敲命令,远远不能满足“产线/测试人员”的友好度需求。想象一下,产线上每天要烧写几十到几百次固件,一不小心输错命令就很尴尬。
>
> 本篇给各位小伙伴分享:①如何给 PyOCD 加一个 Python 写的图形界面(GUI),让烧写操作一键点按;②如何利用 PyInstaller 把这个 Python 项目打包成 EXE,从而让大家在没有安装 Python 的电脑上也能轻松使用。
---
# 1. 为什么要做GUI与打包EXE
1. **更友好、更直观**
如果我们给同事展示一个命令行,他们可能会有点“吓人”:mad: 的感觉,担心忘记或输错参数。而一个UI界面则是一目了然,“选择固件→点击下载”这样的流程几乎零学习成本。
2. **无需安装Python**
经常在产线或测试环境中,电脑系统可能很久不会升级,也没有装Python。要想让他们去装Python+库依赖,就比较麻烦:dizzy: 。
而如果能打包成EXE,所有Python解释器、第三方模块都内置其中,对外只需要双击文件即可启动GUI。一旦配置好,就可以在任何Windows机器上复用。
3. **可延伸的封装思路**
有了GUI后,我们还可以更进一步添加“固件版本管理”“设备自动识别”“烧写统计”等功能,把它变成一个灵活的产线工具:lol: 。
---
# 2. 实现GUI的思路与技术选型
在Python里做GUI并不复杂,一般常见选项是:
1. **Tkinter**(Python标准库自带,轻量基础)
2. **PyQt/PySide**(功能强大,界面美观,但相对体量大)
3. **wxPython**、**Kivy**等其他选项
对于“简单的产线烧写工具”来说,Tkinter 足够胜任,所以本篇使用 Tkinter 作演示。
---
# 3. 设计功能需求:“又简单又够用”
为了在界面上实现基本的烧写操作,我们梳理了下面几项功能:
1. **选择自定义脚本**
用户可以选择自定义脚本,因为G32R501核心DCS功能需要特定的脚本进行KEY写入,这个我们需要关注。
2. **选择固件**
用户能通过文件对话框,选择 `.hex` 或 `.bin` 格式固件。
3. **擦除操作**
一键擦除Flash,让G32R501的存储空间干净如新。
4. **下载操作**
把选定的固件文件下载到目标芯片中,并可通过进度提示或成功/失败信息告诉用户结果。
5. **仿真器识别**
如果电脑插着多个调试器或多个板子,可以列出来让用户选。
---
# 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
```python
"""
实现对目标芯片的全擦除函数 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
```python
"""
实现下载固件函数 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}"
```
最终启动效果:
!(data/attachment/forum/202507/05/182452k85tkrd7pg04e8cd.png "image-20250705181352892.png")
# 5. 打包成EXE:PyInstaller“一键搞定”
下面进入本篇文章最重要的部分:**如何把这个GUI打包成一个单独可执行文件**。
## 5.1 为什么选用PyInstaller
- **使用简单**:只需写一个 `spec`文件,或者直接 `pyinstaller xxx.py`就能包装出 `dist`文件夹;
- **依赖收集**:它会自动收集 `.py` 文件、第三方依赖、`.dll`文件等,打包到一起;
- **常规方案**:是Python社区里最常见、成熟度高的打包工具之一。
## 5.2 PyInstaller打包我们的exe
### (1) 命令行打包
只需在命令行(在main.py同级目录下启动)中执行以下命令:
```bash
pyinstaller --onefile --noconsole --name PyOCDDownloadToolGUI main.py
```
命令解释:
1. **--onefile**:生成一个单文件EXE,启动时会自解压到临时目录里。
2. **--noconsole**:不弹出额外的命令行窗口,让界面更干净;如果想看调试信息,可以去掉此参数。
3. **--name PyOCDDownloadToolGUI**:指定生成的 EXE 文件名;如省略则默认与脚本同名。
4. **main.py**:我们的GUI入口脚本。
执行完该命令后,PyInstaller 会在当前目录下生成一个 `dist`文件夹,里面就有 `PyOCDDownloadToolGUI.exe`。
我们生成的PyOCDDownloadToolGUI.exe在已经安装好pyocd的Windows电脑上就可以使用啦。
### (2) 打包pyocd
PyOCD也带有 `pyocd.exe` 命令行工具。如果我们把它也打包到和 `PyOCDDownloadToolGUI.exe`同一目录,下次就可以不再额外安装pyocd或python。
打包方法如下:
1. 从 https://codeload.github.com/pyocd/pyOCD/zip/refs/tags/v0.37.0 下载 pyOCD 的压缩包。
2. 解压后在根目录会看到 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 文件夹的“父目录”里。
3. 在存放 pyocd.spec 的目录(即刚才所述的本地 pyocd 同级目录)启动 cmd,输入命令:`pyinstaller pyocd.spec`
4. 等待一段时间打包完成后,就会在 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环境下的演示:
!(data/attachment/forum/202507/05/182510uncqd6cj1erzqee5.gif "PixPin_2025-07-05_18-09-04.gif")
---
# 7. 更多可能
1. **进度条**
如果想做酷一点,可以在下载的时候显示一个进度条,PyOCD的Flash API并非默认回调进度,但我们可以自己在 `flash.flash_binary()` 之前拆分写入,或在PyOCD的 `session` 里加一层钩子。
2. **日志记录或错误捕获**
产线常需要把烧写记录保存到日志文件。可以加一个 `log_operation.py`来记录每次烧写信息和结果。
3. **更多的功能扩展**
设置校验、批量烧录、与数据库联动等等……只要我们会玩Python,这些都能实现。
非常感谢阅读这篇文章,如果有任何困难或疑问,欢迎在评论区留言。让我们一起让G32R501的烧写过程越来越好玩、越来越好用!
这里是源码和打包后的exe,请各位玩玩哦(#^.^#)。
1. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part01.rar](forum.php?mod=attachment&aid=2420926 "attachment")
2. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part02.rar](forum.php?mod=attachment&aid=2420928 "attachment")
3. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part03.rar](forum.php?mod=attachment&aid=2420930 "attachment")
4. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part04.rar](forum.php?mod=attachment&aid=2420932 "attachment")
5. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part05.rar](forum.php?mod=attachment&aid=2420934 "attachment")
6. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part06.rar](forum.php?mod=attachment&aid=2420936 "attachment")
7. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part07.rar](forum.php?mod=attachment&aid=2420938 "attachment")
8. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part08.rar](forum.php?mod=attachment&aid=2420940 "attachment")
9. [!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:pyocd_501_download_ui.part09.rar](forum.php?mod=attachment&aid=2420942 "attachment")
#申请原创#@21小跑堂
这个可以实现调试不? lulugl 发表于 2025-7-7 09:10
这个可以实现调试不?
这个小上位机只是一个思路:有个下载界面。不做调试功能(≧w≦) 你写的文章怎么都这么优秀,厉害。 哈哈,这个好是高级啊!
Python的界面倒是真丑,不过真的实用 涡流远见者 发表于 2025-7-17 16:20
哈哈,这个好是高级啊!
Python的界面倒是真丑,不过真的实用
哈哈,丑到不忍直视{:titter:} dffzh 发表于 2025-7-17 16:04
你写的文章怎么都这么优秀,厉害。
一起探讨,向各位大佬学习{:lol:} 给大佬点赞 [鑫森淼焱垚] 发表于 2025-7-22 14:31
给大佬点赞
感谢支持,一起学习 使用简单:只需写一个 spec文件,或者直接 pyinstaller xxx.py就能包装出 dist文件夹;
支持原创
页:
[1]