JLink Commander使用教程:脚本化下载与批量操作

AI助手已提取文章相关产品:

JLink Commander实战精讲:从脚本入门到自动化产线构建

在嵌入式开发的世界里,调试工具的选型往往决定了项目推进的效率。你是否曾经历过这样的场景:
深夜赶工修复一个关键 Bug,终于编译出新固件后,却要在 Keil 里手动点击“Download”按钮?
产线批量烧录时,几十块板子排成一列,每一块都要重复插拔、打开IDE、选择文件……

🛠️ “能不能像写 Python 脚本一样,一键完成所有操作?”
✅ 答案是—— 完全可以!而且你已经在用了。

这就是 JLink Commander 的真正价值所在:它不只是 SEGGER 提供的一个命令行调试器,更是一把打开 自动化嵌入式工程大门 的钥匙。轻量、高效、可编程,支持 SWD/JTAG 协议,兼容几乎所有 ARM Cortex-M 架构 MCU,无论是 STM32、NXP Kinetis 还是国产 GD32,都能用同一套脚本搞定。

JLinkExe -device STM32F407VG -if SWD -speed 4000

执行这条命令,你就进入了交互式调试环境。但真正的高手知道,这只是冰山一角。通过 .jlinkscript 文件,你可以让整个烧录流程自动跑起来——连接芯片 → 擦除 Flash → 下载程序 → 校验数据 → 复位运行,全程无需人工干预。

这不仅仅是省时间的问题,更是 工程标准化和质量保障的核心环节 。尤其是在 CI/CD 流水线中,当代码提交后能自动触发硬件级回归测试,那种“一切尽在掌握”的感觉,只有亲历者才懂 😎。


脚本语言设计哲学:为嵌入式而生的 DSL

很多人第一次看到 JLink 脚本时会疑惑:“这不是 C 吗?”、“怎么没有 for 循环?”、“连字符串比较都不支持?”

别急,这些“缺陷”其实是精心取舍的结果。

JLink 的脚本系统本质上是一种 领域特定语言(DSL) ,专为嵌入式底层操作优化。它不追求通用性,而是聚焦于几个核心任务:
- 快速建立与目标设备的通信
- 精确控制内存与寄存器访问
- 实现稳定可靠的固件部署流程
- 支持基本逻辑判断与错误处理

正因为如此,它的语法虽然简单,却异常强大。比如下面这段代码:

VAR NVIC_ISER0 = 0xE000E100
VAR IRQ_NUMBER = 7
VAR mask = 1 << IRQ_NUMBER

Mem32 NVIC_ISER0, 1
W32 NVIC_ISER0, mask

短短五行,就完成了对 Cortex-M 内核中断使能寄存器的操作。这种贴近硬件的设计思维,正是嵌入式工程师最熟悉的表达方式。

命令即动作:直观且不可分割

JLink 脚本中的每一个命令都对应一个明确的动作。例如:

命令 功能
Connect 建立与目标 MCU 的连接
Mem32 addr, n 从指定地址读取 n 个 32 位字
W32 addr, val 向地址写入 32 位值
Reset 触发 CPU 软复位
Go 恢复 CPU 运行

它们就像机器指令一样直接,没有任何抽象层的开销。这也意味着你可以非常精确地预测每条命令的行为,不会因为“隐藏逻辑”导致意外结果。

💡 小贴士:虽然部分命令支持缩写(如 Conn 代替 Connect ),但在团队协作中建议始终使用全称。毕竟,清晰比节省两个字母更重要。

参数传递机制也极为简洁:数字(十进制或十六进制)、字符串、地址标识符。十六进制必须以 0x 开头,字符串可以加引号也可以省略(只要不含空格)。例如:

SetTargetVoltage 3.3
WriteReg R0, 0xABCD1234

注意,这里不能在参数位置进行动态计算,比如 WriteReg R0, 0x100 + 0x20 是非法的。但可以通过变量间接实现:

VAR base = 0x100
VAR offset = 0x20
VAR addr = base + offset
W32 addr, 0xDEADBEEF

这种方式虽然多了一步,但却提升了脚本的可维护性和可读性,尤其适合多人协作项目。

注释与命名:别小看这两件事

良好的注释习惯是专业性的体现。JLink 支持两种注释风格:

; 单行注释:初始化系统时钟
/*
  多行注释示例:
  - 配置PLL
  - 设置AHB/APB总线频率
  - 启用高速Flash访问等待周期
*/

虽然看起来很简单,但现实中太多脚本因为缺乏注释而变成“天书”。想象一下半年后再看自己写的脚本:“我当时为什么要在这里 delay 100ms?”——有注释的话,答案就在那里。

变量声明使用 VAR 关键字,作用域为全局。推荐做法是在脚本开头集中声明所有变量,并采用清晰的命名规范:

VAR flashStartAddr    = 0x08000000
VAR sectorSize        = 0x4000
VAR maxRetries        = 3

对于常量,虽然没有 const #define ,但可以通过全大写命名来模拟:

VAR FLASH_ORIGIN = 0x08000000
VAR MAX_RETRY_COUNT = 5

这样即使别人第一次看你的脚本,也能快速理解哪些值是不应该被修改的。


控制流能力解析:有限但够用的智能决策

如果说变量和命令构成了脚本的“肌肉”,那么控制结构就是它的“神经系统”。尽管 JLink 脚本不是图灵完备的语言,但它提供的条件判断、循环和跳转功能足以应对绝大多数实际需求。

条件分支:如何做一次“安全检查”

最常用的条件判断方式是结合 TEST $TEST 使用:

W32 0x20000000, 0xDEADBEEF
Mem32 0x20000000, 1
TEST R0 == 0xDEADBEEF
IF $TEST
    PRINT "Memory write succeeded."
ELSE
    PRINT "Write verification failed!"
ENDIF

这里的 R0 是 JLink 自动将上次读取的值存入的通用寄存器。 TEST 命令会对表达式求值,并将结果保存到隐含变量 $TEST 中,后续的 IF 判断的就是这个值。

⚠️ 注意事项:
- 不支持字符串比较,只能用于数值判断。
- 没有 else if ,需要嵌套 if 来实现多路分支。
- 表达式中不能包含函数调用或其他复杂结构。

但这并不影响实用性。比如我们可以用来检测某个标志位是否已设置,决定是否跳过初始化:

VAR FLAG_REG = 0x20000010
Mem32 FLAG_REG, 1
TEST R0 == 0x5AA5
IF $TEST
    PRINT "System already initialized, skipping..."
ELSE
    CALL init_system
ENDIF

虽然 CALL 并非标准命令(需配合外部脚本或宏定义),但思路是对的:根据运行状态做出不同行为,这是构建健壮系统的基石。

循环结构:轮询外设就这么简单

WHILE 循环是实现重试机制和忙等待的关键。典型应用场景是等待某个外设准备就绪:

VAR TIMEOUT = 1000
VAR counter = 0
VAR STATUS_REG = 0x40023000
VAR READY_BIT = 1 << 3

WHILE (counter < TIMEOUT)
    Mem32 STATUS_REG, 1
    TEST R0 & READY_BIT
    IF $TEST
        BREAK
    ENDIF
    DelayMS 1
    counter = counter + 1
ENDWHILE

IF counter >= TIMEOUT
    PRINT "Timeout waiting for peripheral!"
ENDIF

这段代码实现了带超时的轮询机制。每毫秒检查一次状态寄存器,直到 READY 位被置起或超时为止。非常适合用于 Flash 编程、DMA 传输完成检测等场景。

🧠 思考题:为什么不用 DO...WHILE
因为 JLink 脚本压根不支持 😅。所以你需要用 WHILE + BREAK 来模拟。

GOTO 跳转:慎用但必要

标签跳转(Label/Goto)是一个有争议的功能。有人认为它是“魔鬼的发明”,会让代码变得难以追踪;但也有人觉得在某些情况下,它是唯一可行的选择。

:retry_init
    Connect
    IF $CONNECTED == 0
        DelayMS 100
        GOTO retry_init
    ENDIF

PRINT "Connected successfully."

:error_handler
    PRINT "An error occurred, halting script."
    EXIT

上面的例子展示了两种典型用途:
1. 重试逻辑 :连接失败后自动重试,提高鲁棒性;
2. 统一错误处理入口 :发生严重错误时跳转至统一出口。

✅ 推荐使用场景:
- 重试连接(网络类思维迁移到硬件)
- 异常终止流程
- 模拟状态机跳转(谨慎)

❌ 反模式:
- 任意跳转破坏执行顺序
- 替代函数调用(无栈支持,容易混乱)

一句话总结: GOTO 可以用,但要用得明白,注释清楚,别让它成为别人的噩梦。


文件 I/O 与系统交互:打通主机与目标的桥梁

真正让 JLink 脚本脱离“玩具”范畴的,是它与主机系统的交互能力。通过文件读写、日志输出、延迟控制等功能,它可以成为一个完整的自动化节点。

文件操作:不只是记录日志那么简单

VAR fp = FileOpen("dump.bin", "w")
IF fp != 0
    VAR addr = 0x20000000
    VAR size = 0x1000
    FileWrite fp, addr, size
    FileClose fp
    PRINT "Memory dumped to dump.bin"
ELSE
    PRINT "Failed to open file!"
ENDIF

这段代码的作用是将目标设备 RAM 中的一段数据保存到主机磁盘上。听起来普通?但在故障诊断时意义重大!

想象一下产品在现场崩溃了,客户把板子寄回来,你接上 JLink,运行脚本提取关键内存区域,离线分析变量状态、堆栈内容、异常码……这比靠猜强太多了。

📌 应用场景包括:
- 上电自检日志导出
- 故障现场快照采集
- 固件版本信息备份
- 生产测试数据归档

而且 FileWrite 写的是 目标设备的内存地址 ,不是主机内存!这意味着你可以直接把 MCU 的 SRAM 内容持久化下来。

内存与寄存器 API:裸机调试的灵魂

JLink 提供了极其丰富的底层访问接口:

命令 功能
Mem8/16/32 读取内存(8/16/32位)
W8/16/32 写入内存
ReadReg reg_name 读取 CPU 寄存器(R0-R15, MSP, PSP 等)
WriteReg reg_name, value 写入寄存器
SaveBinfile addr, size, filename 将内存块保存为 BIN 文件

例如,在 OTA 升级前备份中断向量表:

SaveBinfile 0x08000000, 0x200, "vector_table_backup.bin"

或者模拟一段内存拷贝(无 DMA 时备用方案):

VAR src = 0x20000000
VAR dst = 0x20001000
VAR len = 0x100
VAR i = 0

WHILE i < len
    VAR byte = Mem8(src + i, 1)
    W8 dst + i, byte
    i = i + 1
ENDWHILE

虽然效率远不如 DMA,但在 Bootloader 或 Recovery 模式下,这种“土办法”往往是唯一的希望。

时间控制与状态检测:让脚本学会“等待”

精确的时间控制对硬件初始化至关重要。JLink 提供两个主要延迟函数:

  • DelayMS n :延迟 n 毫秒
  • DelayUS n :延迟 n 微秒

精度依赖于主机系统调度,通常误差在 ±1ms 以内,足够应付大多数轮询场景。

W32 0x08000000, 0xFFFFFFF  ; 发送擦除命令(假设)
DelayMS 50                   ; 等待擦除完成

此外, GetHaltReason 可用于查询 CPU 停止原因:

GetHaltReason
PRINT "Halt reason: ", $GETHALTREASON

返回值含义如下:

代码 含义
0 正常运行
1 断点触发
2 硬件故障(HardFault)
3 外部调试请求(EXTDEBUG)

这个功能特别适合构建自动故障分类系统。比如当检测到 HardFault 时,自动提取堆栈指针、PC、LR 等寄存器值并保存日志,极大提升调试效率。


错误处理与日志机制:打造生产级脚本

再完美的计划也可能出错。电源波动、接触不良、固件损坏……现实世界充满了不确定性。因此,一个合格的 JLink 脚本必须具备 感知错误、反馈信息、优雅退出 的能力。

返回码体系:每个命令都有“心跳”

每次命令执行后,JLink 会更新内部状态码 $LASTRESULT 。成功通常返回 0,非零表示错误。

Connect STM32F407VG
IF $LASTRESULT != 0
    PRINT "Connection failed with code: ", $LASTRESULT
    GOTO error_exit
ENDIF

常见错误码包括:

错误码 含义
-1 通用错误
-2 目标未响应
-4 驱动加载失败
-5 USB通信异常
-7 芯片型号不匹配

虽然官方文档并未完全公开所有错误码,但我们可以通过实验积累经验库。建议在关键步骤后插入状态检查,形成 防御性编程习惯

🔍 实战技巧:可以在脚本中加入“健康检查”阶段,先读取一个已知地址(如主 Flash 起始处),确认能正常通信后再继续。

日志输出:不只是为了看,更是为了追溯

LogEnable 1
LogToFile "jlink_log.txt"
PRINT "Starting firmware update..."
; ... 其他命令
LogToFile ""
LogEnable 0

开启详细日志后,你会得到一份包含每条命令执行详情、耗时、返回码的日志文件。这对后期审计和问题回溯非常有用。

特别是当你把这套系统交给产线工人使用时,一旦出错,他们只需要把日志文件发给你,你就能还原整个过程。

📌 日志级别说明:

级别 启用方式
基础输出 默认开启
详细调试信息 LogEnable 1
通信级日志 SetLogFileLevel 3 (需 SDK 支持)

合理使用日志功能,可以在不打断执行的前提下收集足够诊断信息,是生产环境部署的重要保障。


构建完整的固件加载流程:从零开始写一个专业脚本

现在我们来动手实践,把前面学到的知识整合成一个完整的固件下载与初始化脚本。

整个流程分为三个阶段:
1. 连接设备并识别型号
2. 加载固件镜像至指定地址
3. 复位并启动用户程序

第一步:建立稳定连接

// === 自动化固件加载脚本 ===
echo "正在连接目标设备..."
Exec Connect
  Device = AUTO
  Speed = 4000
  Interface = SWD
  AutoConnect = 1

这里使用 Exec Connect 调用内置连接器,参数说明如下:

参数 可选值 说明
Device AUTO / 具体型号 AUTO 模式适合通用脚本
Speed 100~12000 (kHz) 建议 4000 左右平衡速度与稳定性
Interface SWD / JTAG SWD 更常用,引脚少
AutoConnect 0 / 1 是否启用自动探测

连接失败怎么办?

if $?$ != 0
  echo "连接失败,请检查硬件连接"
  exit
endif

echo "连接成功,芯片型号:" $_ConnectedDeviceName

$? 获取上一条命令的返回状态, $_ConnectedDeviceName 是 JLink 内置变量,存储识别到的芯片名称。

第二步:加载固件文件

支持两种格式:

  • BIN 文件 :纯二进制,需指定基地址
  • HEX 文件 :自带地址信息,适合多段映像
// 检查文件是否存在
FileOpen "firmware.bin"
if $?$ == 0
  LoadFile "firmware.bin", 0x08000000
else
  echo "错误:固件文件不存在!"
  exit
endif

💡 提示:HEX 文件无需指定地址,JLink 会自动解析并写入对应区域。

第三步:正确复位并启动

不要直接断电重启!要精确控制启动流程:

// 步骤1:软复位CPU
r

// 步骤2:暂停CPU运行
h

// 步骤3:设置PC指向Reset Handler
SetReg PC, *(Addr=0x08000004)

// 步骤4:恢复运行
g

解释一下:
- r :软复位,让 Core 从复位向量重新开始
- h :halt,进入调试暂停状态
- SetReg PC, *(Addr=...) :从向量表中读取复位处理函数地址
- g :go,继续执行

另一种更简洁的方式是使用 LoadAndRun

LoadAndRun "firmware.bin", 0x08000000

它内部封装了上述所有步骤,适合常规场景。但对于高级用途(如跳过 Bootloader),仍推荐手动分步。


多阶段初始化:超越基础烧录的高阶操作

真实项目中,烧录只是开始。你还可能需要:

  • 配置系统时钟
  • 擦除 Flash 扇区
  • 设置写保护与读出保护
  • 注入唯一序列号

CPU 与时钟初始化

STM32F407 默认运行在 HSI(16MHz),若要达到 168MHz,必须配置 PLL:

// 启用HSE(8MHz晶振)
Mem32 0x40023800 = 0x00010000

// 等待HSE就绪
do
  $hse_ready = Mem32 0x40023800 & 0x00020000
while $hse_ready == 0

// 配置PLL:HSE * 21 / 2 = 168MHz
Mem32 0x40023804 = 0x2000A808

// 使能PLL
Mem32 0x40023800 = 0x01010000

// 等待PLL锁定
do
  $pll_locked = Mem32 0x40023800 & 0x02000000
while $pll_locked == 0

// 切换系统时钟源至PLL
Mem32 0x40023808 = 0x00000002

⚠️ 风险提示:直接操作时钟寄存器可能导致 CPU 停机,请务必在调试阶段充分验证。

Flash 擦除自动化

$base_addr = 0x08000000
$sector_size = 16384
$idx = 0

while $idx < 4
  $addr = $base_addr + ($idx * $sector_size)
  Flash.EraseSector $addr
  if $?$ != 0
    echo "扇区擦除失败:地址 0x" $_ToString($addr, 16)
    exit
  endif
  $idx = $idx + 1
endwhile

支持的擦除命令:

命令 说明
Flash.EraseSector addr 擦除指定地址所在扇区
Flash.EraseRange start, end 擦除地址范围
Flash.EraseAll 整片擦除(慎用,会清除 Option Bytes)

安全策略实施

// 启用前两个扇区写保护
Exec EnableFlashWriteProtection 0, 1

// 设置读出保护等级
echo "警告:即将启用Level 2安全保护,设备将永久锁定!"
echo "按回车继续,Ctrl+C取消..."
Input
Exec SetSecurityBits 2

安全级别说明:

级别 效果
Level 0 无保护
Level 1 禁止调试访问,保留 BOOT 模式
Level 2 完全锁死,需 Mass Erase 才能恢复

🔐 特别提醒:Level 2 一旦启用,除非执行整片擦除,否则无法恢复!请务必确认后再操作。


批量烧录与自动化测试:迈向智能制造

当你要处理上百块板子时,手动操作已经不可接受。必须借助批处理框架实现自动化。

Bat/Shell 脚本封装多次调用

Windows 示例( batch_flash.bat ):

@echo off
set JLINK_PATH="C:\Program Files\SEGGER\JLink\JLinkExe"
set SCRIPT_DIR=.\scripts
set LOG_DIR=.\logs
set FIRMWARE=.\firmware\app_v1.2.0.hex

if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"

for /L %%i in (1,1,5) do (
    echo [INFO] 正在为设备 %%i 烧录固件...
    %JLINK_PATH% -CommanderScript "%SCRIPT_DIR%\flash_device.jlink" -Device STM32F407VG -If SWD -Speed 4000 > "%LOG_DIR%\device_%%i.log"

    findstr /C:"Programming flash" "%LOG_DIR%\device_%%i.log" >nul
    if errorlevel 1 (
        echo [ERROR] 设备 %%i 烧录失败,请检查连接状态!
    ) else (
        echo [SUCCESS] 设备 %%i 烧录成功。
    )
)

Linux Bash 版本更灵活,支持 CSV 控制流和模板替换:

#!/bin/bash

JLINK="/opt/SEGGER/JLink/JLinkExe"
TEMPLATE="./templates/flash_template.jlink"
DEVICE_LIST="./devices.csv"

while IFS=, read -r serial mac_address firmware; do
    TEMP_SCRIPT="./temp/device_${serial}.jlink"
    cp "$TEMPLATE" "$TEMP_SCRIPT"

    sed -i "s/{SERIAL}/${serial}/g" "$TEMP_SCRIPT"
    sed -i "s/{MAC_ADDR}/${mac_address}/g" "$TEMP_SCRIPT"
    sed -i "s|{FIRMWARE}|${firmware}|g" "$TEMP_SCRIPT"

    $JLINK -CommanderScript "$TEMP_SCRIPT" -Device STM32H743ZI -If SWD -Speed 4000 >> "./logs/${serial}.log" 2>&1

    if grep -q "Verification OK" "./logs/${serial}.log"; then
        echo "✅ 设备 $serial 烧录成功"
    else
        echo "❌ 设备 $serial 烧录失败"
    fi
done < <(tail -n +2 "$DEVICE_LIST")

并行处理:榨干 USB 带宽

串行太慢?那就并发!

MAX_JOBS=4

compile_and_flash() {
    local serial=$1
    local firmware=$2
    local port=$3

    local log_file="./logs/parallel_${serial}.log"
    local script_file="${SCRIPT_DIR}/${serial}.jlink"

    cat > "$script_file" << EOF
si SWD
speed 4000
device STM32F407VG
tolerance 5
loadfile "${firmware}" 0x08000000
r
g
exit
EOF

    "$JLINK" -CommanderScript "$script_file" -SelectEmuBySN "$port" >> "$log_file" 2>&1

    if grep -q "Download completed successfully" "$log_file"; then
        echo "[OK] $serial 成功"
    else
        echo "[FAIL] $serial 失败"
    fi
}

export -f compile_and_flash
cat device_tasks.txt | xargs -P $MAX_JOBS -n 3 bash -c 'compile_and_flash "$@"'

性能对比(10块板):

模式 总耗时 CPU利用率 USB负载
串行 180s ~15%
并行(4路) 48s ~60% 中等
并行(8路) 75s ~90% 高(丢包)

建议控制在 4~6 路以内,避免通信异常。


CI/CD 集成与工厂部署:从实验室到生产线

真正的考验,是把这套系统放进 Jenkins 流水线。

pipeline {
    agent { label 'embedded-builder' }

    environment {
        JLINK_EXE = 'C:\\Program Files\\SEGGER\\JLink\\JLinkExe.exe'
        PROJECT_DIR = 'src/stm32_project'
        BUILD_OUTPUT = "${PROJECT_DIR}/build/app.bin"
    }

    stages {
        stage('Clean & Build') {
            steps {
                sh 'make clean && make all'
            }
        }

        stage('Deploy to Target') {
            steps {
                script {
                    def devices = ['DEV01', 'DEV02']
                    for (dev in devices) {
                        sh """
                            ${env.JLINK_EXE} -CommanderScript ./jlink/deploy.jlink \
                                -Device STM32F407VG \
                                -If SWD \
                                -Speed 4000 \
                                -LogFile ./logs/jlink_${dev}.log
                        """

                        def logContent = readFile("./logs/jlink_${dev}.log")
                        if (!logContent.contains("Download completed successfully")) {
                            error "烧录失败:${dev}"
                        }
                    }
                }
            }
        }

        stage('Run Hardware Test') {
            steps {
                sh './test_scripts/run_gpio_test.sh'
                sh './test_scripts/check_uart_response.py'
            }
        }

        stage('Archive Reports') {
            steps {
                archiveArtifacts artifacts: 'reports/*.xml, logs/*.log', allowEmptyArchive: true
            }
        }
    }
}

配合 Python 脚本监听串口输出:

import serial
import re

def wait_for_boot_complete(port):
    with serial.Serial(port, 115200, timeout=30) as ser:
        while True:
            line = ser.readline().decode().strip()
            if re.match(r'^BOOT: OK \[CRC=0x[A-F0-9]+\]$', line):
                return True
            elif "FAULT" in line:
                return False

最终生成 JUnit XML 报告,集成进 Jenkins UI,实现真正的“代码即测试”。


高级技巧与疑难排查

自定义 Flash 算法注入

遇到国产 APM32、GD32 等非标准 Flash?别慌:

ExecSetFlashDevice = "MyCustomFlash"
ExecLoadFlashAlgo = "C:\JLink\MyFlashAlgo.bin", 0x20000000, 0x4000
ExecFlashWrite = 0x08000000, 0x10000, "firmware.bin"

算法必须由厂商提供 .bin 文件,并确保兼容当前架构。

低电压调试技巧

电池供电设备工作在 1.8V?试试:

SetTargetVoltage 1.8
Wait 100
Connect

强制 J-Link 输出 1.8V 作为参考电平,提升信号识别率。

分片下载超大镜像

固件超过 16MB?分块写入:

Dim ChunkSize = 0x200000  // 2MB
Dim BaseAddr = 0x08000000
Dim TotalSize = 0xA00000  // 10MB

FileHandle = FileOpen("large_fw.bin")
Offset = 0

While (Offset < TotalSize)
    FileRead FileHandle, BaseAddr + Offset, ChunkSize
    Wait 100
    Offset = Offset + ChunkSize
EndWhile

每批次后加 Wait 100 ,缓解 USB 缓冲压力。


最佳实践准则:让脚本走得更远

最后分享几条团队协作建议:

  1. 命名规范
    proj_stm32h7_flash_v1.2.jlink

  2. 版本控制
    gitignore *.log temp_*.jlink

  3. 权限安全
    - 禁止使用 Erase=all
    - 替换为明确地址范围

  4. 文档模板
    jlinkscript // =================================================== // Author: zhang@iot-dev.com // Date: 2025-04-05 // Desc: APM32F103CBT6首次烧录 // Risk: 启用读保护,请谨慎使用 // ===================================================


JLink Commander 不只是一个调试工具,它是 现代嵌入式自动化体系的基石 。从单人开发到千级节点部署,从实验室原型到智能工厂流水线,它都能胜任。

当你下次面对一堆待烧录的板子时,不妨问一句:
🤖 “我能用脚本解决这个问题吗?”
大概率—— 可以

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

您可能感兴趣的与本文相关内容

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值