尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Keil下载安装配置:MDK/C51与STM32工程调试避坑指南

Keil下载安装配置:MDK/C51与STM32工程调试避坑指南 装机这件事说简单也简单——下载、下一步、装上就完事说麻烦也是真麻烦我见过太多人卡在“装完之后建了工程一编译满屏红线”或者“下载成功但板子毫无反应”。这篇就把 Keil下载、Keil安装、Keil配置这三件事从头到尾捋一遍重点不是把安装向导截图复述一遍而是把每一步背后的取舍讲清楚把那些官方文档里不写、但实际操作中一定会碰到的问题挑出来。内容覆盖 MDK 与 C51 的选型、器件包管理、编译器版本切换、工程配置、下载调试硬件侧的坑以及 Debug 模式下结构体变量“看不见”这类高频疑难。适合谁看刚接触 ARM 单片机、准备用 Keil MDK 跑第一个工程的初学者从 IAR 或 GCC 工具链迁过来、需要快速摸清 µVision 脾气的人以及手上还有 8051 老项目、需要 MDK 和 C51 共存的老工程师。读完之后你应该能独立完成一套干净、可复用的工程模板并且在遇到报错时知道先看哪里。1. 装之前先分清 MDK 和 C51别混着装1.1 µVision、MDK、C51 到底谁是谁很多人第一次接触这套工具时的困惑是Keil 官网列了一堆产品到底该下哪一个。拆开看其实很清楚。µVision 是 IDE 的名字也就是你打开的那个窗口负责工程管理、编辑、编译、调试它只是一个壳真正干活的是后面的编译器。而 MDKMicrocontroller Development Kit是给 ARM Cortex-M 内核准备的整包里面包含 µVision、Arm Compiler、CMSIS 库、RTX 实时内核和中间件C51 则是给 8051 内核准备的独立产品编译器是 C51 编译器IDE 同样叫 µVision但和 MDK 是两个完全独立的安装。关键结论只有一句MDK 和 C51 必须装到不同目录不能覆盖安装。它们的可执行文件同名都是 UV4.exe如果装在同一个路径下后装的会把先装的覆盖掉注册表里的路径信息也会混在一起。我一般会规划成D:\Keil_v5_MDK和D:\Keil_v5_C51两个互不干扰的目录桌面快捷方式手动改名区分。如果你只需要做 Cortex-M 开发那 C51 完全不用装省得后面注册表里多一堆没用的项。1.2 版本号和编译器版本要一起看MDK 的版本号5.36、5.38、5.41 这类逐年往前滚但真正影响你能不能编译老工程的是里面的编译器版本。历史上 MDK 长期自带 Arm Compiler 5命令行叫 armcc从 5.37 这个版本开始官方默认不再随安装包附带 AC5需要单独去下载 Arm Compiler 5 的独立安装包再装上。这件事的后果是很多网上流传的、基于 AC5 编写的例程和库在新版 MDK 里直接编译会报一堆莫名其妙的语法错误。AC5 和 AC6armclang的差异不是小修小补。AC6 基于 LLVM/Clang对语法的要求更严格老代码里常见的__packed、非标准的内联汇编写法、#pragma arm section、以及部分依赖 armcc 专属扩展的启动文件都可能编不过。我一般会在 Options for Target 的 Target 页用下拉框切换编译器版本工程需要哪个就切哪个。场景建议编译器说明全新工程、官方新例程AC6优化更好报错信息更清晰老工程、网上 2020 年前的例程AC5需单独安装 AC5 支持包使用 RTOS 的汇编移植层视 port 而来的RVDS port 走 AC5GCC port 可走 AC6部分厂商 SDK如老版本 HAL 例程AC5直接用 AC6 可能触发兼容性报错1.3 授权方式决定了你撞不撞 32KB 这堵墙装的时候没人提醒你但这个坑几乎人人踩MDK 未激活时处于评估模式编译产物的代码段被限制在 32KB 以内。STM32F103C8T6 这颗芯片 Flash 总共 64KB光一个 HAL 库点灯的工程编译出来往往就已经逼近甚至超过 20KB稍微加个 FreeRTOS、加个浮点打印立刻超限报错信息大意是“代码大小超过评估版限制”。现在的正规路径有两条一是官方提供的免费社区版本面向非商业用途按官方流程申请激活即可二是有正式授权的商业版本。不要用来源不明的第三方授权工具这一点我想多说两句这类工具通常需要替换安装目录下的核心文件改了之后编译器行为可能变得不可预期编译出的固件出问题你根本没法判断是代码的锅还是工具被动过手脚的锅更现实的问题是换台电脑或者升级一次 MDK全部重来一遍。花十几分钟走官方流程省下的是后面反复折腾的时间。还有个小细节这类授权通常对系统时间敏感。如果你为了别的目的把系统时间回到几年前µVision 可能直接启动报错。这属于“看起来很玄学、实际上一查就明白”的问题遇到启动异常先看一眼右下角的日期。2. 下载与安装从安装包到目录规划2.1 安装包从哪拿这一步别图省事安装包的来源只有一个原则走官方渠道。官方站点会同时提供在线安装器和完整离线包两种形式离线包体积在 1GB 上下如果你的网络环境不稳定我更推荐直接下离线包避免安装到一半中断导致文件残缺。判断一个安装包是否可靠可以做个简单校验看它的大小是否和官网标注一致安装过程中是否会额外弹出、安装一些和开发无关的东西。正规安装向导不会要求你填一堆私人信息也不会在系统里塞额外的浏览器插件。另外提醒一句官网上的版本迭代挺快新版本发布后的头几个小版本偶尔会有小毛病。如果你是为了赶项目没必要第一时间尝鲜用一两个被大量验证过的稳定版本更省心。2.2 安装向导里那几个容易被一路回车跳过的选项安装向导大部分步骤都是“下一步”但有两三处值得停一下手。第一处是组件选择列表通常会列出核心组件、器件支持包、调试器驱动等条目。核心组件必须装调试器驱动建议一并勾上即使你手头暂时没调试器装了以后接上新硬件能省一次重装。第二处是安装路径默认给的是系统盘根目录下的固定路径能改就改理由在下一小节细说。第三处是文件关联把.uvprojx、.c、.h关联到 µVision 是方便的但如果你的.c文件平时用别的编辑器打开关掉关联反而更顺手。提示安装阶段最好用管理员权限运行安装程序但日常使用不要长期以管理员身份开 µVision权限混用久了容易出现“某些文件莫名其妙写不进去”的情况。2.3 目录规划为什么我从不装在系统盘默认位置系统盘默认路径有两个隐患。一是路径里带空格和可能的权限限制Program Files 系目录受 UAC 保护某些老的工具链脚本拼接路径时处理不好空格会出现找不到文件的情况二是这类 IDE 会持续产生编译中间文件、Pack 缓存、日志量不小和系统盘抢空间不划算。我的习惯是规划出三个独立目录各管一件事D:\Keil_v5_MDK 安装目录IDE、编译器、调试驱动 D:\Packs 器件支持包根目录可在 Pack Installer 里指定 D:\Projects 工程目录按芯片型号或项目名分文件夹工程目录这一层还有一条硬规矩全路径不要出现中文和空格。编译器、链接脚本、厂商生成的工程文件里路径经常被当作字符串直接拼接遇到中文在某些编码环境下会解析失败。我见过最典型的症状是编译能过但一进调试就报找不到.axf排查半天发现是工程放在桌面一个中文命名的文件夹里。这个坑不值得亲自踩一遍。2.4 装完先别急着建工程把器件包装明白µVision 只是一个壳它凭什么知道 STM32F103C8T6 的 Flash 多大、寄存器在哪、启动文件长什么样答案是器件支持包DFPDevice Family Pack。MDK 5 之后所有芯片支持都通过 CMSIS-Pack 机制管理用工具栏上的 Pack Installer 打开左侧找厂商右侧找系列点 Install 即可。较新版本的 MDK 会把 Pack 默认放在%LOCALAPPDATA%\Arm\Packs也就是C:\Users\你的用户名\AppData\Local\Arm\Packs老版本则放在安装目录的ARM\PACK下。在 Pack Installer 的设置里可以指定根目录不同版本入口位置略有差异我一般统一指向D:\Packs这样重装 IDE 的时候包不用重新下。关于 Pack 版本有个极其实用的经验不是越新越好。工程文件里记录了当初使用的 DFP 版本如果某个老工程依赖旧版 pack 里的头文件而你本地只装了新版可能报找不到定义或宏冲突。稳妥做法是遇到老工程先看它的 README 或工程说明里标注的 pack 版本需要时在 Pack Installer 里同时保留新旧两个版本工程会自动匹配。再说一个交叉场景用瑞萨的配置工具RASC/FSP生成 Keil 工程时它同样依赖对应的 RA 系列 DFP。这类自动生成工程对路径很敏感生成器脚本遇到中文路径或含空格路径会直接失败或生成出错误路径。所以我前面强调的“全英文无空格路径”在跨工具链协作时价值更高。另外要注意生成工程所用的 FSP 版本与本地安装的 DFP 版本是否匹配两者版本对不上时最常见的结果是提示找不到某个外设驱动源文件。3. 授权、编译器、全局偏好这三件收尾工作3.1 授权状态确认装完打开 µVision第一件事是确认授权状态在 Help 菜单里找到授权管理相关的条目看一眼当前是评估版还是已激活。如果是评估版先做一次小的编译测试看看代码量离 32KB 还有多少余量。我的习惯是直接看编译输出的 Program Size 那一行 —— Code、RO-data、RW-data、ZI-data 四个数字Code 加 RO-data 基本就是占用的 Flash 空间严格说还要加上 RW 的初始值部分。如果 CodeRO-data 已经接近 32KB别侥幸先解决授权再往下做。授权信息一般保存在安装目录的配置文件里。换机器或重装之前先确认你的授权类型有些授权需要在旧机器上做释放操作再在新机器上重新激活直接拷贝配置文件往往无效。这部分流程看官方说明最准别信论坛里的偏方。3.2 单独安装 Arm Compiler 5 并让工程用上它如果你确实需要 AC5流程是下载 Arm Compiler 5 的独立安装包安装到一个不含空格的路径然后打开 Options for Target 的 Target 页在 ARM Compiler 下拉框里选择 Use default compiler version 5 或者手动指定外部编译器路径。µVision 会提示你指定编译器所在目录通常指向安装目录下的bin文件夹。这里有两处细节值得记下来。第一AC5 的授权和 MDK 是分开算的某些情况下你需要额外处理编译器本身的使用许可具体以安装时界面提示为准。第二切换编译器后一定要重新全量编译Rebuild不要只点增量编译。因为 AC5 和 AC6 生成的目标文件格式、依赖记录都不一致混着用极容易出现“代码改了但行为没变”的诡异现象这类玄学问题的根源就是增量编译残留了旧编译器产生的对象文件。3.3 编码、字体、自动保存这些顺手就调了有几个全局设置建议装上就调后面能省很多事。编码方面Keil 老版本默认编码对中文注释不友好工程里出现中文注释容易变乱码在 编辑器的 Configuration 里把编码设成 UTF-8 并勾选按此编码保存新老文件统一。显示方面等宽字体加适中字号配合行号显示看汇编和调试时舒服很多。自动保存建议开但间隔别设太短编译过程中的文件变化有时会打断构建。还有一点关于界面的网上流传的各种界面汉化包我个人的建议是不装。一是它本质上替换了 IDE 的核心资源文件换个 MDK 版本就失效甚至出错二是出错信息、菜单名称这些东西全网教程、官方文档、社区问答都是英文的用英文界面查问题效率反而更高。真看不懂某个菜单截图搜一下比装汉化包快。4. 以 STM32F103C8T6 为例搭一个干净的工程模板4.1 目录结构决定你半年后还能不能看懂这个工程新手最常犯的错是把所有文件堆在同一个文件夹里几十个.c/.h混在一起。三个月后回来改一个功能光找文件就要十分钟。我推荐从一开始就用固定分层并且这套结构可以直接复制到下一个项目Project/ ├── App/ 应用层main.c、业务逻辑 ├── Drivers/ │ ├── CMSIS/ 内核头文件、启动文件 │ └── STM32F1xx_HAL_Driver/ 厂商库 ├── BSP/ 板级支持LED、按键、串口封装 ├── Middlewares/ FreeRTOS、FatFs 等中间件 └── MDK-ARM/ .uvprojx 工程文件与编译输出在 µVision 里照着这个结构建 GroupGroup 名字和文件夹名字保持一致。这样做的好处是工程树一眼能看出分层出问题的时候能迅速判断是应用层还是驱动层换芯片时只需替换 Drivers 目录App 和 BSP 基本不动。4.2 Options for Target 逐页配置清单这是整个 Keil 配置里信息密度最高的一页我把它整理成一张表照着填基本不会出问题。注意 F103C8T6 的 Flash 是 64KB、RAM 是 20KB。选项卡关键项建议值TargetARM Compiler按工程需要选 AC5 或 AC6TargetXtal填板上晶振频率只影响仿真时序不影响实际运行TargetUse MicroLIB用 printf 又不想处理半主机时勾选注意它与部分 RTOS 的兼容性差异TargetRead/Write Memory AreasIROM1: 0x08000000, 0x10000IRAM1: 0x20000000, 0x5000OutputCreate HEX File需要用外部烧写器时勾选OutputDebug Information必须勾否则无法调试OutputBrowse Information需要跳转定义、全局符号查找时勾选ListingLinker Listing勾选生成 .map排查内存问题必看C/CDefineUSE_HAL_DRIVER,STM32F103xBC/CInclude Paths按实际目录逐一添加别用相对路径乱跳C/COptimization调试期设 Level 0发布时再调高LinkerUse Memory Layout from Target Dialog默认勾选用自定 .sct 时取消Debug仿真器选择ST-Link Debugger / J-LINK / CMSIS-DAPDebugFlash Download添加对应算法勾选 Reset and RunUtilitiesSettings必须与 Debug 页配置一致最后一行是高频翻车点很多人在 Debug 页配好了下载算法却忘了 Utilities 页还有一套一样的设置结果一按下载就报“找不到 Flash 编程算法”。两页配置不一致时谁生效取决于你按下的是哪个按钮所以最省事的做法是两边配成一模一样。4.3 启动文件、栈堆大小与分散加载启动文件startup_stm32f103xb.s里最上面有两行宏定义Stack_Size和Heap_Size单位是字节。默认值通常给的是 0x400 和 0x200对于裸机点灯够用但一旦上了 FreeRTOS 或者用了动态内存分配、浮点打印堆就很容易不够。症状往往不是编译报错而是运行到某处莫名跑飞或者进 HardFault —— 堆栈溢出属于最难查的一类问题因为现场已经破坏了。我的建议是裸机项目把 Heap 提到 0x400 以上用 RTOS 时直接给到 0x800 甚至更多反正 F103C8T6 有 20KB RAM留足空间比省那几百字节划算得多。改完记得看一下编译输出的 ZI-data 有没有暴涨那说明 RAM 被吃掉了。分散加载文件.sct平时不用碰默认从 Target 页的内存配置生成即可。什么时候需要自定义比如要把某个函数放到固定地址、要把一部分数据放到特定 RAM 区域、或者做 Bootloader 需要把 Flash 划分成两段。一旦在 Linker 页取消了“使用 Target 对话框的内存布局”你就得自己维护 .sct这时工程的内存分配就完全由这个文件说了算Target 页改大小不再生效 —— 这个细节很多人不知道改了半天内存配置没反应就是因为 .sct 在背后接管了。4.4 读 .map 文件找出吃掉 Flash 的元凶链接生成的.map文件有个章节叫 Image component sizes按模块列出了每个.o文件占用的 Code、RO-data、RW-data、ZI-data。当 Flash 快满的时候直接翻到这里找到占用最大的几个模块答案一目了然。我遇到的典型情况是一个点灯工程编译出来 Code 有 18KB翻 map 发现printf系列函数加上浮点格式化占了 6KB 以上。解决方案有两个一是改用精简的串口打印实现不用标准库的格式化二是给 C/C 页加上“每个函数独立成段”的选项配合 Linker 页的“移除未使用段”让链接器把没调用到的函数剔掉通常能省下可观的空间。这个组合拳在老工程瘦身时特别有效。5. 下载与在线调试的硬件侧配置5.1 调试器选型和接线先解决硬件问题ST-Link、J-Link、CMSIS-DAP 这三类是最常见的。ST-Link 便宜、对 STM32 支持好缺点是做些特殊操作时偶尔要做固件升级J-Link 功能强、跨厂商价格高CMSIS-DAP 类通常是开发板自带的调试器通用性最好。选哪个看预算和习惯但有一个共同前提接线必须是 SWD 四线加电源即 SWCLK、SWDIO、GND、3V3或用目标板自身供电此时只接三根信号地。接线时容易忽略的两点一是 GND 必须共地不共地时会表现为“时连时不连”非常难查二是线别太长杜邦线超过 20 厘米就容易出现通信错误尤其是在 SWD 时钟频率设得较高的时候。遇到连接不稳第一步就是把 SWD 时钟从默认的高频率降到 1MHz 试一次很多“玄学连接问题”到这里就结束了。5.2 Debug 页与 Flash 算法的正确配置在 Debug 页选中调试器后点旁边的 Settings会弹出调试器配置窗口。这里有几个关键区域Debug 标签页里的端口选择SWD 还是 JTAG、时钟频率Flash Download 标签页里的编程算法列表。F103C8T6 属于中容量系列对应算法选 STM32F10x Med-density Flash 即可这个算法覆盖 64KB 和 128KB 两种容量。选错算法的典型症状是下载时报地址越界或者下载后校验失败。Flash Download 里还有两个复选框值得关注“Reset and Run”勾上后下载完成自动复位运行省去手按复位键“Verify Code Download”建议保持勾选多花一两秒换来下载结果的确认对于调试初期很有价值。另外如果你的程序在下载后需要保持特定状态比如某些测试场景不希望被复位打乱这两个选项可以暂时取消。5.3 下载成功但程序不跑先查这三处这是我被问得最多的一类问题日志显示下载成功板子一动不动。按概率排序通常出在这三个地方。第一复位方式。有些调试器配置里的复位类型是“不复位”下载完程序停在那儿等着你看到的现象就是没反应。改成硬件复位或系统复位即可。第二SWD 引脚被复用。这是嵌入式开发里的经典陷阱程序初始化时把 PA13、PA14 配成了普通 GPIO 或者其他复用功能结果一运行调试器就和芯片失去通信表现为“第一次能连下载后连不上了”。解决办法是调试器配置里启用“连接时复位”Connect under Reset也就是先在复位保持状态下建立连接再把芯片放开赶在引脚被复用之前拿下控制权。真正彻底的做法是永远不要把 SWD 引脚复用成普通 IO。第三启动模式。F103 的 BOOT0 拉高会进入系统存储器启动程序不跑你写的固件。这个问题一般出现在自己画的板子上开发板很少见。提示如果以上三条都排除了把问题反过来想先写一个只翻转 GPIO 的最小程序去掉所有外设初始化能跑通再逐层加回来。二分法定位在嵌入式里比读代码快得多。6. Debug 模式实战结构体变量怎么会“看不见”6.1 优化等级是第一个嫌疑对象进入 Debug 模式后在 Watch 窗口输入变量名如果显示成“not in scope”或者干脆是空的甚至只显示一个地址而不展开成员九成不是调试器坏了而是编译器把变量优化掉了。编译器在较高的优化等级下会把只在局部使用过的变量直接放进寄存器、或者复用同一块栈空间符号表里就没有可对应的内存位置调试器自然取不到值。解决方法很直接把 Options for Target 里 C/C 页的 Optimization 降到 Level 0或调试友好的等级重新全量编译问题基本消失。代价是代码体积变大、执行变慢所以这是调试期的配置发布前记得改回去。我在工程里习惯建两个 Target一个 DebugLevel 0开调试信息一个 Release高优化切换时只改一下当前 Target 就行不用来回改参数。还有一种情况变量确实存在但显示成optimized out或者值明显不对。这时候检查两件事一是有没有勾上 Debug InformationOutput 页二是这个变量是不是在中断里被改写的。中断改写的变量如果不加volatile编译器可能把它缓存在寄存器里你看到的值就是过期的。这类问题属于“调试器没骗你是你自己写错了”加volatile就好了。6.2 Watch 窗口的几种硬核写法很多人只会把变量名拖进去其实 Watch 窗口支持表达式用好了能省不少事。数组和指针要展开看成员指针变量先展开它自己再展开*p结构体嵌套多层的要逐级点开。如果你想确认某个地址上到底是什么可以直接写*(MyStruct_t*)0x20000020这样的强制类型转换表达式调试器会按你给的类型解析这块内存。如果某个全局变量在 Watch 里看不到变化检查一下 View 菜单里的“周期性刷新窗口”有没有打开有些版本默认是不刷新的你会误以为变量一直没变。还有一个轻量但实用的技巧把所有关心的变量收进一个全局结构体Watch 里只放这一个变量展开就是全部状态比散着看一堆变量清爽得多。这个习惯在大项目里尤其值钱。调试助手窗口里还有其他几个视图配合使用效果更好Memory 窗口按地址看原始数据用于验证结构体内存布局是否符合预期有没有对齐填充反汇编窗口对照 C 代码看优化结果寄存器窗口看内核寄存器。排查内存越界或者结构体对齐问题时这两个窗口的组合几乎能定位所有问题。6.3 断点数量有限制HardFault 定位有套路Cortex-M3 的硬件断点数量是有限的一般只有 6 个左右外加 4 个数据观察点。你在 Flash 里打的断点本质上都是硬件断点 —— 因为 Flash 不能像 RAM 那样被随意改写插入指令。所以断点打多了会提示无法设置断点这时候删掉几个不用的就行别去怀疑调试器坏了。程序跑飞进 HardFault 是另一个高频场景。常规做法是在 HardFault 处理函数里打个断点运行到此处后看调用栈往上翻几层通常能看到出错位置。更专业的做法是直接读故障状态寄存器在 Memory 或 Watch 窗口查看地址0xE000ED28处的值这是 CFSR 寄存器把它拆成二进制看哪一位被置起IMPRECISERR 往往是访问了非法地址PRECISERR 通常和总线错误有关UNDEFINSTR 是取到了非法指令。配合栈指针MSP 或 PSP去栈上找压入的返回地址基本能精确定位到那一行汇编。如果用的是带 RTOS 的工程还要分清故障发生在哪个任务的栈上否则你找到的地址是错的。这时查看 LR 寄存器的值判断当前用的是 MSP 还是 PSP再从对应的栈顶往后翻几帧是比较稳妥的办法。6.4 FreeRTOS 移植时 Keil 侧必须对齐的几项配置把 FreeRTOS 加入 Keil 工程操作本身不难在工程里新建 Group加入tasks.c、queue.c、list.c、timers.c以及按需的event_groups.c再从portable目录下挑对应内核的移植层文件Cortex-M3 对应 ARM_CM3内存管理选heap_4.c这类带碎片合并的方案。头文件路径要加上 FreeRTOS 源码的 include 目录和移植层目录FreeRTOSConfig.h放在自己能管到的位置。真正容易翻车的是三件事。第一是编译器兼容移植层里的汇编和内联汇编写法在 AC5 和 AC6 下表现不同如果换编译器后报汇编相关的语法错误别硬改换编译器或者换对应版本的移植层文件更快。第二是时基冲突。厂商库的延时函数通常也用 SysTick而 FreeRTOS 会接管 SysTick 作为系统节拍两边抢同一个中断会导致延时严重不准。标准做法是把厂商库的时基改到别的定时器或者在 RTOS 里统一用vTaskDelay不要混用两套延时。第三是中断优先级。Cortex-M3 的优先级寄存器实际有效位在高几位写优先级的时候数值要正确对齐同时凡是会调用 RTOS API 的中断其优先级必须低于内核允许的阈值否则一进中断就崩。这个坑最迷惑人的地方在于代码编译完全没问题只在特定中断触发时才崩而且崩在 RTOS 内核里看起来像是内核的错。configASSERT打开后会直接告诉你哪个中断优先级配错了调试期强烈建议打开。任务栈大小和总堆大小要一起调。任务栈以字为单位给得太小会在运行一段时间后栈溢出症状是随机崩溃。开启栈溢出检测并在钩子函数里打个断点或者点个灯能在崩溃的第一现场抓住它比事后猜要高效得多。7. 高发报错的分阶段排查链路7.1 编译阶段找不到器件、AC6 语法不兼容、RTE 冲突编译期最典型的错误是“device not found”或者器件列表里根本没有你的型号。这几乎一定是器件包没装或者装错系列回到 Pack Installer 里确认对应系列的 DFP 是否已安装必要时重启 IDE 让它重新扫描。第二类是 AC6 报出大量语法错误而这些代码在别人那里编译得好好的。这通常意味着原工程是 AC5 时代的产物里面用了 armcc 的扩展语法。判断方法很简单把编译器切回 AC5如果立刻编过问题就定性了。接下来的选择是改代码适配 AC6还是继续用 AC5取决于项目周期和代码量。第三类是 Run-Time EnvironmentRTE相关的冲突提示通常是工程里同时存在手动添加的库和 RTE 添加的组件两边版本不一致。处理方式是打开 Manage Run-Time Environment看有没有黄色的警告标记点解决或统一版本。7.2 链接阶段空间不足、未定义符号、段选择器不匹配链接错误的三个常客。Undefined symbol基本是缺源文件、缺宏定义或者缺少库文件对照符号名到 map 或者头文件里反查它属于哪个模块逐一补齐即可别急着乱加库。No space in execution regions是空间不足按前面讲的方法翻 map 找大户同时检查启动文件里的堆栈大小是否给得过大或者是不是误开了浮点格式化这类吃空间的特性。No section matches selector一般和分散加载文件有关说明链接脚本里指定的段在代码中根本不存在或者启动文件的段名和脚本对不上。常见于从别人那里拿了一套 .sct 直接套用到自己工程的情况。这种时候最简单的解法是先在 Linker 页勾回“使用 Target 对话框的内存布局”确认能编过再逐步引入自定义布局。7.3 下载连接阶段连不上、算法加载失败连不上的排查顺序是先看供电和共地再看 SWD 时钟是否过高再看是不是程序把调试引脚复用了最后考虑用连接时复位的方式强行接管。这四步按顺序走九成问题能解决。“Cannot Load Flash Programming Algorithm” 这类报错先确认 Debug 页和 Utilities 页两处的算法配置是否一致再看算法是否在列表里已经添加。有些情况下是安装目录权限问题导致算法文件无法被读取换个有写权限的目录安装或者以合适权限运行能解决。7.4 运行阶段一进 main 就跑飞、偶发死机、功能时好时坏能下载、能停住但一运行就飞先查栈。把 Stack_Size 调大一倍试试如果问题消失就是栈不够。接着查中断向量表启动文件里的向量表和实际使用的中断号是否对应尤其是自己手写中断处理函数名拼错一个字母的时候行为就是“中断没进或者进了默认死循环”。偶发死机最考验耐心。我的一般思路是先在可能的故障点加计数器或标志位通过调试器观察哪个环节先卡住再考虑是不是栈溢出、堆碎片、中断优先级冲突最后才怀疑硬件。把问题范围缩到最小复现用例比在大工程里反复断点要快一个数量级。功能时好时坏还有个常被忽视的原因外设初始化的顺序或者等待标志位超时处理不当。比如某个外设时钟没使能就去写它的寄存器行为往往是不确定的可能这次跑通下次跑不通。这类问题只能在初始化流程上老老实实按手册顺序来。8. 多版本共存、干净卸载与换机迁移8.1 MDK 和 C51、新旧版本如何和平相处如果同时维护 8051 老项目和 Cortex-M 新项目按前面说的装到两个目录各自的工程用各自的 IDE 打开。需要注意的是工程文件扩展名老版本 C51 的工程放在新版 µVision 里打开会提示转换转换后老版本可能就打不开了所以升级前先备份一份工程这是最基本的保险。同一台机器上装多个 MDK 版本也是可行的各自独立目录即可。但不建议同时在两个版本里打开同一个工程编译输出目录重叠会互相踩。我一般给工程建两个 Target 来区分不同构建配置而不是靠两个版本的 IDE 切换。8.2 卸载与残留清理的正确顺序要彻底卸掉一个 Keil顺序是先在 IDE 里处理掉授权相关的事项如果打算迁移再用系统正常卸载程序卸载然后手动清理残留。残留主要有三类安装目录里没删干净的文件、用户目录下的配置和 Pack 缓存%APPDATA%和%LOCALAPPDATA%\Arm下面、以及注册表里HKCU\Software\Keil之类的键。提示动注册表之前一定先导出备份。多数情况下只清理用户目录下的配置就够了注册表一般不需要大动很多“卸载后重装还是老样子”的问题根源是用户目录下的配置文件没清。8.3 换电脑时这份迁移清单能救你换机器最容易漏的不是代码而是环境。我的清单是这样的工程目录整体打包排除编译输出目录体积能小一个数量级记录当前使用的 MDK 版本、编译器版本、器件包版本导出或记录调试器配置这部分配置站在工程里但调试器的全局设置不跟着走授权按官方流程迁移如果工程依赖厂商配置工具生成的代码比如 RA 系列用配置工具生成的 Keil 工程记录清楚生成工具版本和 FSP 版本必要时用相同版本重新生成一遍避免版本不一致导致的隐性差异。搬到新机器后第一件事不是打开工程编译而是先建一个最小工程验证环境新建空工程、加个空 main、编译、下载、点灯。这一步花十分钟能提早发现环境层面的问题避免你在一个复杂工程里排查半天最后发现是器件包版本不对。我个人最后再分享一个小习惯每配好一套能用的工程模板就把它另存成一份“干净模板”压缩包把编译输出全部清掉只留必需的源文件、工程文件和一份说明当前环境版本的小文本。半年后你回来做新项目直接解压改个名就能开工比重新配一遍 Options for Target 省下的时间远比想象中多。
返回列表