资讯中心

嵌入式MCU开发全流程:编译、烧录与仿真调试实战指南

📅 2026/9/25 1:14:12
嵌入式MCU开发全流程:编译、烧录与仿真调试实战指南
1. 嵌入式MCU开发流程全景拆解1.1 从一行代码到芯片跑起来中间到底发生了什么很多刚入行的朋友拿到一块STM32或者ESP32的开发板第一反应是打开Keil或者CubeIDE新建工程、写代码、点那个“下载”按钮然后发现板子没反应。这时候就开始怀疑人生是我代码写错了还是板子坏了其实绝大多数情况下问题出在从编译到烧录再到仿真这条链路的某个环节断了而不是代码本身的逻辑问题。嵌入式MCU软件开发跟纯PC端软件开发最大的区别在于你写的代码最终要跑在一颗资源极其有限的芯片上这颗芯片没有操作系统帮你管理内存没有硬盘让你存放文件甚至连一个标准输出都没有。你唯一的调试手段就是通过调试器去观察芯片内部的寄存器状态和内存数据。所以编译、烧录、仿真这三个环节构成了嵌入式开发的核心工作流任何一个环节出问题你的代码就永远停留在文本编辑器里。这套流程涉及的核心概念包括交叉编译在PC上编译出能在MCU上运行的机器码、烧录把编译产物写入MCU的Flash存储器、仿真调试通过SWD等接口实时观察和控制MCU的运行状态。这三个环节环环相扣编译产物的格式决定了烧录工具的选择烧录接口的配置又直接影响仿真调试能否正常进行。这篇文章适合谁看如果你刚开始接触嵌入式开发对Keil、IAR、OpenOCD这些工具的名字有所耳闻但不太清楚它们之间的关系或者你已经能跑通简单的点灯程序但遇到烧录失败、仿真连不上的问题时不知道从何下手排查——那这篇内容就是为你准备的。我会从工具链的选型逻辑讲起把编译、烧录、仿真每个环节的底层原理和实操细节都拆开来讲清楚最后给出常见问题的排查思路。1.2 工具链选型的底层逻辑为什么不是随便选一个就行嵌入式MCU的工具链选择不是拍脑袋决定的它受到三个硬性约束目标芯片架构、调试接口协议、开发效率需求。先看芯片架构。ARM Cortex-M系列的MCU比如STM32F1、GD32、NRF52系列用的是Thumb-2指令集你需要的是arm-none-eabi-gcc或者ARMCC这样的交叉编译器。而ESP32用的是Xtensa架构或者RISC-V架构工具链就变成了xtensa-esp32-elf-gcc或者riscv32-esp-elf-gcc。如果你选错了工具链编译出来的机器码芯片根本不认识烧进去也是白搭。再看调试接口。SWDSerial Wire Debug是ARM Cortex-M系列最常用的两线调试协议只需要SWCLK和SWDIO两根线就能实现烧录和仿真。JTAG虽然功能更强但占用的引脚多在引脚资源紧张的MCU上不太实用。所以现在市面上大多数开发板都默认引出SWD接口对应的调试器就是ST-Link、J-Link、DAPLink这几类。最后看开发效率。Keil MDK和IAR Embedded Workbench是商业IDE的代表优点是开箱即用、调试界面友好、对各家芯片厂商的支持都很完善。缺点是收费而且Keil的编辑器体验确实一般。开源方案以VSCode Cortex-Debug OpenOCD为代表配置起来稍微麻烦一点但胜在免费、灵活、可定制。我个人的建议是新手先用Keil或者CubeIDE把流程跑通建立对整体链路的认知然后再逐步迁移到开源工具链上。这里有一个很容易被忽略的点编译产物的格式。不同的烧录工具支持的固件格式不一样。常见的有格式全称特点典型工具.hexIntel HEX文本格式包含地址信息通用性强Keil、J-Flash.binBinary纯二进制不含地址信息需要指定烧录地址STM32CubeProgrammer.elfExecutable and Linkable Format包含调试信息用于仿真GDB、OpenOCD.s19Motorola S-record文本格式常见于汽车电子和NXP芯片各厂商专用烧录器理解这些格式的区别很重要。比如你用Keil编译生成了.axf文件本质上是ELF格式烧录的时候Keil会自动从中提取出.hex或者.bin写入Flash。但如果你用OpenOCD命令行烧录就需要明确指定文件格式和烧录地址否则就会报错。2. 编译环节从源代码到可执行固件的完整链路2.1 编译原理在MCU开发中的具体体现编译原理这门课讲的是词法分析、语法分析、语义分析、中间代码生成、目标代码生成这一整套流程。在嵌入式MCU开发中这套流程被封装在工具链里你只需要点一下“Build”按钮但理解背后的过程对排查编译错误至关重要。一个典型的MCU编译流程分为四个阶段预处理阶段处理所有以#开头的指令包括#include头文件展开、#define宏替换、#ifdef条件编译。这个阶段最容易出的问题是头文件路径配置错误编译器找不到你引用的.h文件。在Keil中你需要在“Options for Target” - “C/C” - “Include Paths”里添加头文件搜索路径。在GCC工具链中对应的编译选项是-I。编译阶段把预处理后的C/C代码翻译成汇编代码。这个阶段会做语法检查和语义分析你遇到的“expected ‘;’ before ‘}’ token”这类错误就是在这个阶段报出来的。对于嵌入式开发来说还需要注意编译器优化选项的影响。-O0不优化调试最方便-O2或-O3优化程度高代码体积小运行快但调试时变量可能被优化掉单步执行会跳来跳去。汇编阶段把汇编代码翻译成机器码生成目标文件.o或.obj。这个阶段基本不会出错除非你写了内联汇编且语法有问题。链接阶段把所有目标文件和库文件链接在一起按照链接脚本Linker Script的规则分配到具体的存储器地址。链接脚本定义了Flash的起始地址和大小、RAM的起始地址和大小、各个段.text、.data、.bss放在哪里。STM32F103C8T6的Flash起始地址是0x08000000大小64KB这些信息都写在链接脚本里。如果你换了同系列但Flash更大的芯片链接脚本不改的话多出来的Flash空间就用不上。注意编译优化等级和调试体验是矛盾的。我一般建议在开发调试阶段用-O0 -g3发布版本再用-Os优化体积。如果你发现单步调试时某个变量值显示不对先检查是不是开了优化。2.2 Keil MDK编译配置的关键参数Keil MDK是国内嵌入式开发者最常用的IDE之一但很多人只是用它默认的配置遇到问题就抓瞎。这里我把几个关键配置项讲清楚。Target选项卡这里设置芯片的型号和外部晶振频率。芯片型号选错了Keil会加载错误的存储器映射和启动文件编译出来的固件烧进去大概率跑不起来。外部晶振频率影响的是系统时钟配置如果你用的是8MHz晶振但这里填了12MHz串口波特率就会偏差50%通信必然失败。Output选项卡勾选“Create HEX File”会生成.hex格式的烧录文件。勾选“Debug Information”会生成调试信息不勾选的话仿真时无法查看源码。Select Folder for Objects设置中间文件的存放路径建议单独建一个Objects文件夹不要跟源码混在一起。C/C选项卡Define栏里填预处理器宏定义比如USE_HAL_DRIVER, STM32F103xB。这些宏决定了HAL库中哪些代码会被编译进去。Include Paths里添加所有头文件目录注意要添加到最底层的目录不要只添加顶层目录。Debug选项卡选择调试器类型ST-Link Debugger、J-LINK/J-TRACE Cortex等然后点Settings进入详细配置。在Debug页签下选择SWD接口Port选SWMax Clock根据调试器质量选择一般4MHz够用质量好的可以上10MHz。在Flash Download页签下确认烧录算法是否正确STM32F103C8对应的是STM32F10x Med-density Flash算法。Utilities选项卡这里的Settings跟Debug里的Settings是两回事。Utilities里的Settings配置的是烧录时的Flash算法Debug里的Settings配置的是调试时的Flash算法。两者要一致否则会出现“能仿真但不能烧录”或者“能烧录但不能仿真”的怪现象。2.3 开源工具链的编译配置以VSCode GCC为例如果你不想用商业IDEVSCode arm-none-eabi-gcc OpenOCD这套组合是完全可行的而且更灵活。配置的核心是三个文件Makefile、链接脚本、OpenOCD配置文件。Makefile定义了编译规则。一个最简的STM32 Makefile大概长这样TARGET blink BUILD_DIR build SRCS src/main.c src/stm32f1xx_hal_msp.c INC -Iinc -IDrivers/STM32F1xx_HAL_Driver/Inc CFLAGS -mcpucortex-m3 -mthumb -O0 -g3 -Wall $(INC) LDFLAGS -TSTM32F103C8Tx_FLASH.ld -Wl,-Map$(BUILD_DIR)/$(TARGET).map $(BUILD_DIR)/$(TARGET).elf: $(SRCS) arm-none-eabi-gcc $(CFLAGS) $(LDFLAGS) $^ -o $ $(BUILD_DIR)/$(TARGET).hex: $(BUILD_DIR)/$(TARGET).elf arm-none-eabi-objcopy -O ihex $ $关键参数解释-mcpucortex-m3指定目标CPU架构-mthumb启用Thumb指令集-T指定链接脚本-Wl,-Map生成map文件用于分析内存占用。链接脚本定义了存储器布局。STM32F103C8T6的链接脚本核心部分MEMORY { FLASH (rx) : ORIGIN 0x08000000, LENGTH 64K RAM (xrw) : ORIGIN 0x20000000, LENGTH 20K } SECTIONS { .text : { *(.text*) } FLASH .data : { *(.data*) } RAM AT FLASH .bss : { *(.bss*) } RAM }这里有一个容易困惑的点.data段既在RAM中又在FLASH中。原因是.data段存放的是有初始值的全局变量初始值需要存在FLASH里掉电不丢失运行时再拷贝到RAM中。这个拷贝过程由启动文件中的代码完成。OpenOCD配置文件告诉OpenOCD怎么连接目标芯片source [find interface/stlink.cfg] source [find target/stm32f1x.cfg] adapter speed 4000interface/stlink.cfg定义了ST-Link调试器的通信参数target/stm32f1x.cfg定义了STM32F1系列的Flash编程算法和内存映射。adapter speed设置SWD时钟频率4000表示4MHz。实操心得用GCC工具链时编译报错信息比Keil更详细但可读性差一些。建议把编译输出重定向到文件用grep过滤error和warning快速定位问题。另外-Wall一定要开很多潜在问题编译器会提前警告你。3. 烧录环节把固件写入芯片的多种方式与避坑指南3.1 SWD协议烧录的底层机制SWD协议是ARM公司为Cortex-M系列处理器设计的两线调试接口只需要SWCLK和SWDIO两根信号线加上GND和VCC可选就能实现调试和烧录。相比JTAG的五线接口SWD在引脚资源紧张的MCU上优势明显。SWD的通信过程可以类比成两个人对话调试器是主动方MCU是从动方。调试器在SWCLK上产生时钟信号在SWDIO上发送命令和数据。每个时钟周期传输一位数据一个完整的SWD事务包含请求包、应答包和数据包三个阶段。请求包由调试器发出包含APnDP位选择访问Access Port还是Debug Port、RnW位读还是写、地址位和奇偶校验位。MCU收到请求后在应答包中返回OK响应或者FAULT响应。如果是写操作调试器接着发送32位数据如果是读操作MCU返回32位数据。烧录过程本质上就是通过SWD接口访问MCU内部的Flash控制器寄存器按照特定的时序把数据写入Flash存储器。不同厂商的MCUFlash控制器的寄存器定义不同所以OpenOCD需要加载对应的Flash编程算法。这个算法是一段运行在MCU RAM中的代码负责擦除Flash扇区、写入数据、校验写入结果。注意SWDIO和SWCLK两根线一定要接对而且不能接反。我见过不止一个新手把SWDIO接到SWCLK上然后死活连不上排查了半天才发现是线序问题。另外SWD接口对信号完整性有一定要求如果排线太长超过20cm建议降低SWD时钟频率。3.2 Keil ST-Link烧录配置与常见失败原因Keil配合ST-Link烧录STM32是最常见的组合但“Keil5烧录失败”也是搜索频率极高的问题。我把常见的失败原因和解决方法整理成下表失败现象可能原因排查方法No target connectedSWD线序错误、目标板未供电、调试器驱动未安装检查接线、测量目标板电压、设备管理器查看驱动Cannot access target芯片被读保护、SWD引脚被复用为GPIO用STM32CubeProgrammer解除读保护、检查代码中SWD引脚配置Flash Download failedFlash算法选择错误、芯片型号不匹配在Debug Settings中确认Flash算法与芯片一致Error: Flash Download failed - “Cortex-M3”调试器固件版本过旧用ST-Link Utility升级调试器固件烧录成功但程序不运行中断向量表偏移未设置、启动模式错误检查VTOR寄存器设置、BOOT0/BOOT1引脚电平这里重点说一下“芯片被读保护”的情况。STM32的Flash有一个读保护机制开启后调试器无法读取Flash内容表现为“Cannot access target”。解除方法是用STM32CubeProgrammer连接芯片在“Option Bytes”里把Read Out Protection改为Disabled然后执行全片擦除。注意这个操作会清空整个Flash所以确保你手上有源码备份。另一个高频问题是“SWD引脚被复用”。有些工程师在代码里把PA13和PA14配置成了普通GPIO或者复用功能导致调试器无法通过SWD接口连接芯片。解决方法是在系统启动的早期HAL_Init之前不要动这两个引脚或者在代码中加入一段延时给调试器留出连接窗口。3.3 OpenOCD烧录STM32的完整命令与参数解析OpenOCD是一个开源的片上调试工具支持多种调试器和目标芯片。用OpenOCD烧录STM32的基本命令如下openocd -f interface/stlink.cfg -f target/stm32f1x.cfg \ -c program build/blink.elf verify reset exit这条命令做了四件事加载ST-Link接口配置、加载STM32F1目标配置、烧录blink.elf文件并校验、复位芯片后退出。verify选项会逐字节比对写入的数据和源文件确保烧录无误。reset让芯片复位后从新固件开始运行。如果你只有.hex文件没有.elf文件命令要改成openocd -f interface/stlink.cfg -f target/stm32f1x.cfg \ -c program build/blink.hex verify reset exitOpenOCD会自动识别.hex格式并解析其中的地址信息。但如果是.bin文件就必须手动指定烧录地址openocd -f interface/stlink.cfg -f target/stm32f1x.cfg \ -c program build/blink.bin 0x08000000 verify reset exit0x08000000是STM32F1系列Flash的起始地址。如果填错了地址固件会被写到错误的位置芯片无法正常启动。实操心得OpenOCD的配置文件路径在不同操作系统上不一样。Linux下通常在/usr/share/openocd/scripts/Windows下在OpenOCD安装目录的scripts文件夹里。如果找不到配置文件可以用-c script /path/to/config手动指定路径。另外OpenOCD默认的SWD时钟频率可能偏高如果连接不稳定在配置文件里加一行adapter speed 1000把频率降到1MHz试试。3.4 其他烧录方式串口、USB DFU与SD卡除了SWD烧录嵌入式MCU还支持多种烧录方式各有适用场景。串口ISP烧录STM32出厂时内置了Bootloader通过BOOT0拉高、BOOT1拉低进入系统存储器启动模式就可以用串口USART1配合STM32CubeProgrammer或者Flash Loader Demonstrator烧录固件。这种方式不需要调试器只需要一个USB转串口模块成本极低。缺点是烧录速度慢而且占用串口引脚。USB DFU烧录STM32F4和F7系列支持USB Device Firmware Upgrade通过USB接口直接烧录。进入DFU模式需要BOOT0拉高或者应用程序中主动跳转到DFU模式。DFU烧录速度快适合产线批量烧录。SD卡烧录一些高端MCU如STM32F7、H7系列支持从SD卡加载固件。芯片上电后Bootloader会检查SD卡中是否存在特定文件名的固件文件如果有就自动烧录到Flash。这种方式适合现场升级不需要携带调试器。ESP32的烧录方式ESP32系列比较特殊它支持串口烧录和JTAG烧录两种方式。串口烧录通过UART0需要把GPIO0拉低进入下载模式。JTAG烧录需要外接调试器但ESP32的JTAG引脚是复用的需要在eFuse中配置或者通过烧录器强制使能。ESP32-C6-WROOM-1的烧录硬件接口设计需要注意EN引脚需要上拉GPIO0需要下拉进入下载模式GPIO8需要上拉避免启动异常GPIO9需要上拉默认启动模式。4. 仿真调试让代码运行状态可视化4.1 SWD仿真调试的核心原理与配置仿真调试是嵌入式开发中定位问题的终极手段。通过SWD接口调试器可以实时读取和修改MCU的寄存器、内存、变量值可以设置断点暂停程序执行可以单步跟踪代码流程。这些功能的实现依赖于Cortex-M内核内置的调试组件Debug PortDP和Access PortAP。DP负责管理调试器与内核之间的通信链路AP负责访问具体的内存空间和寄存器。Cortex-M内核有两个APAHB-AP用于访问系统内存空间APB-AP用于访问调试组件。调试器通过DP发送命令通过AP读写目标地址的数据。断点的实现方式有两种硬件断点和软件断点。硬件断点利用内核中的断点比较单元FPB最多支持6个硬件断点。软件断点是把目标地址的指令替换成BKPT指令程序执行到BKPT时触发调试异常。硬件断点不修改代码适合在Flash中设置断点软件断点数量不受限制但需要修改RAM中的代码。在Keil中配置仿真调试的步骤Options for Target - Debug - 选择调试器 - Settings - Debug页签选择SWD接口 - Flash Download页签确认烧录算法 - 勾选“Reset and Run”让程序烧录后自动运行。然后在代码中点击行号左侧的灰色区域设置断点按CtrlF5进入调试模式就可以单步执行、查看变量、观察寄存器了。4.2 OpenOCD GDB命令行仿真调试实战不用IDE纯命令行也能完成仿真调试。这套组合是OpenOCD GDB适合在Linux环境下工作或者需要自动化调试的场景。首先启动OpenOCD服务端openocd -f interface/stlink.cfg -f target/stm32f1x.cfgOpenOCD会监听3333端口GDB Server和4444端口Telnet Server。然后启动GDB客户端arm-none-eabi-gdb build/blink.elf在GDB中连接OpenOCD(gdb) target extended-remote localhost:3333 (gdb) monitor reset halt (gdb) load (gdb) break main (gdb) continuemonitor reset halt让芯片复位并暂停在复位向量处load把固件烧录到Flashbreak main在main函数入口设置断点continue让程序运行到断点处暂停。GDB常用命令速查命令简写功能breakb设置断点continuec继续运行nextn单步跳过不进入函数steps单步进入进入函数printp打印变量值info registersi r查看所有寄存器x/16xw 0x20000000-查看内存内容monitor reset halt-复位并暂停monitor flash erase_sector 0 0 7-擦除Flash扇区注意GDB连接OpenOCD时如果报“Remote communication error”通常是OpenOCD没有正常启动或者端口被占用。检查OpenOCD的输出信息确认它已经识别到调试器和目标芯片。另外GDB的load命令会烧录整个ELF文件如果只需要烧录部分数据可以用restore命令指定地址和文件。4.3 仿真调试中的常见问题与排查思路仿真调试连不上是最让人头疼的问题之一。我把典型问题和排查步骤整理如下问题一调试器识别不到目标芯片。先检查硬件连接SWDIO、SWCLK、GND三根线是否接好目标板是否供电。然后用调试器厂商提供的工具如ST-Link Utility测试连接。如果工具也连不上说明是硬件或芯片状态问题不是IDE配置问题。问题二能烧录但不能仿真。这种情况通常是调试信息没有生成。检查编译选项是否包含-gKeil中检查Output选项卡的Debug Information是否勾选。另外如果代码中开启了读保护调试器无法读取Flash中的调试信息也会导致仿真失败。问题三仿真时程序跑飞或者断点不生效。检查优化等级-O2以上优化会导致代码重排断点位置可能偏移。检查中断优先级配置如果调试中断的优先级低于其他中断断点可能被其他中断打断。检查看门狗是否开启看门狗溢出会导致芯片复位仿真会话中断。问题四变量值显示不正确。局部变量在优化后可能被分配到寄存器中GDB无法直接读取。全局变量如果被优化掉也会显示“optimized out”。解决方法是在调试阶段用-O0编译或者用volatile关键字修饰需要观察的变量。问题五OpenOCD报“target not halted”。这通常是因为芯片处于低功耗模式或者时钟未启动。在OpenOCD配置文件中添加reset_config srst_only或者在GDB中用monitor reset halt强制暂停芯片。4.4 仿真平台与硬件仿真的区别除了基于真实硬件的仿真调试还有一些纯软件的仿真平台比如Wokwi、Proteus、QEMU。这些平台不需要真实硬件在PC上就能模拟MCU的运行行为。Wokwi是一个在线仿真平台支持Arduino、ESP32、STM32等常见开发板。你可以在浏览器中搭建电路、编写代码、运行仿真还能看到LED亮灭、串口输出等效果。适合教学演示和快速验证代码逻辑。Proteus是老牌的电路仿真软件支持多种MCU模型和外围电路。它的优势是能仿真模拟电路和数字电路的混合系统比如用STM32控制电机驱动电路可以同时观察MCU引脚波形和电机电流波形。QEMU是一个开源的机器仿真器支持ARM Cortex-M系列的指令级仿真。它的优势是速度快、可脚本化适合自动化测试。但QEMU不仿真外设只能验证纯算法逻辑。需要明确的是软件仿真不能替代硬件仿真。软件仿真无法模拟真实的时序问题、信号完整性问题、电源噪声问题。很多在软件仿真中运行正常的代码烧到真实硬件上就会出现各种奇怪的问题。所以我的建议是软件仿真用于验证算法逻辑硬件仿真用于调试实际系统。5. 全流程串联与效率提升技巧5.1 从编译到仿真的一键化工作流把编译、烧录、仿真三个环节串成一条自动化流水线能大幅提升开发效率。在VSCode中可以通过tasks.json和launch.json配置一键编译和调试。tasks.json定义编译任务{ version: 2.0.0, tasks: [ { label: build, type: shell, command: make, group: { kind: build, isDefault: true } }, { label: flash, type: shell, command: openocd, args: [-f, interface/stlink.cfg, -f, target/stm32f1x.cfg, -c, program build/blink.elf verify reset exit] } ] }launch.json定义调试配置{ version: 0.2.0, configurations: [ { name: Debug (OpenOCD), type: cortex-debug, request: launch, servertype: openocd, device: STM32F103C8, configFiles: [interface/stlink.cfg, target/stm32f1x.cfg], executable: build/blink.elf, preLaunchTask: build } ] }配置好后按F5就能自动编译、烧录、启动调试断点、变量查看、寄存器观察都在VSCode中完成。5.2 版本管理与固件发布规范嵌入式项目的版本管理有一些特殊注意事项。首先编译产物.o、.elf、.hex、.bin不要提交到Git仓库这些文件体积大且每次编译都会变化。用.gitignore排除build目录和Objects目录。其次链接脚本、启动文件、配置文件这些跟芯片强相关的文件必须纳入版本管理。换芯片或者改存储器布局时这些文件的变更要单独提交方便回溯。固件发布时建议同时提供.hex和.bin两种格式附带版本号和编译时间戳。可以在代码中定义一个版本字符串const char firmware_version[] v1.2.3 build __DATE__ __TIME__;这样通过调试器读取内存就能确认芯片中运行的固件版本避免烧错固件的情况。5.3 常见问题速查表环节问题排查方向编译undefined reference to xxx检查是否链接了对应的库文件函数声明和定义是否一致编译region FLASH overflowed代码体积超过Flash容量开启-Os优化或裁剪功能烧录No target connected检查SWD接线、目标板供电、调试器驱动烧录Flash Download failed检查Flash算法选择、芯片型号配置烧录烧录成功但不运行检查BOOT引脚、中断向量表偏移、时钟配置仿真Cannot access target检查读保护状态、SWD引脚是否被复用仿真断点不生效检查优化等级、调试信息是否生成仿真变量显示optimized out用-O0编译或加volatile修饰我在实际项目中踩过最深的坑是Flash算法选择错误。当时用STM32F103C8T6但在Keil的Flash Download配置里选了STM32F10x High-density Flash算法结果烧录总是失败报“Flash Download failed”。排查了很久才发现是算法选错了改成Med-density后一切正常。这个问题的隐蔽性在于芯片型号选对了编译也正常就是烧录不行很容易误以为是硬件问题。另一个坑是SWD引脚复用。有一次在代码里把PA13和PA14配置成了PWM输出结果烧录一次之后再也连不上调试器了。后来是用STM32CubeProgrammer在芯片复位后的短暂窗口期内连接成功把Flash全片擦除才恢复。从那以后我在所有项目的启动代码里都会加一段延时给调试器留出连接时间。最后分享一个提升调试效率的小技巧在main函数开头加一个while循环等待调试器连接volatile uint32_t debug_wait 1; while (debug_wait) { __NOP(); }调试时在while循环里设置断点连接成功后把debug_wait改为0继续运行。这样就不用在芯片刚上电的瞬间抢着连接调试器了。发布版本中把这个循环去掉或者用宏定义控制避免影响正常启动。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案