ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Keil 6.12与AC6编译器:从ARMCC 5迁移到GCC工具链的实践指南

Keil 6.12与AC6编译器:从ARMCC 5迁移到GCC工具链的实践指南 简介Keil μVision 6.12版是一款面向单片机开发的集成开发环境特别适合配合郭天祥单片机系列教程从经典8051起步后续可平滑过渡到ARM Cortex-M等主流内核。该版本内置C51与ARM两套编译器可将C语言或汇编源码编译为单片机可执行的机器码集成的调试器支持断点设置、单步执行、寄存器与变量查看等排错操作。CPU模拟器允许学习者在没有实体开发板的前提下先行模拟运行并验证程序逻辑降低入门门槛。硬件调试方面可通过JTAG或USB接口连接开发板实现在线烧录与实时调试同时支持FreeRTOS、μC/OS-II等常见RTOS便于后续开展多任务嵌入式项目。压缩包为zip格式大小约11.17MB整体体量适中下载部署较为方便。已有1012人学习对正准备系统学习单片机或需要稳定IDE环境的开发者是一个可直接上手的实用资源。1. 先搞清楚Keil 6.12到底“新”在哪最近嵌入式开发圈子里Keil 6.12版这几个字被提到的频率非常高。特别是当你在搜索“Keil官网”“Keil最新版本”“Keil mdk”这些关键词的时候会发现很多人在问同一个问题这个版本到底是不是最值得升级的作为一个从ARM7时代就开始用Keil的老用户我想用实际经验把这件事说透。先说结论你现在能看到的各种“Keil 6.12版”说法本质上指的是以MDK 5.38为基底、配合AC6ARM Compiler 6工具链的完整开发环境。版本号里的“6”代表编译器大版本而不是IDE界面的大改版。很多人第一次接触AC6编译器时最大的感受就是怎么编译速度变快了报错信息怎么完全看不懂了这就是因为AC6底层是基于Clang架构的跟过去ARMCC 5时代那套GCC风格报错完全是两个物种。拿我自己举例有个跑了好几年的STM32F407老工程从ARMCC 5切到AC6编译编译时间直接从原来的40多秒干到了12秒左右生成的bin文件体积还小了差不多8%。但代价也实实在在警告信息多了好几倍什么“implicit conversion”“incompatible pointer types”这类Clang特有的提示一开始看得人头皮发麻。所以如果你准备上手Keil 6.12第一件事不是急着装而是想清楚自己手头的项目是否需要这套东西。如果你的芯片是STM32F103这类老器件、用的还是标准外设库代码量也不大继续用ARMCC 5完全没问题没必要折腾。但如果你手里有C项目、需要C11/14甚至20/23特性或者芯片是新出的Cortex-M33/M55内核那AC6就是唯一选择因为ARMCC 5根本不支持这些新内核。1.1 版本号背后的编译器逻辑Keil的版本号体系很容易让人混淆。MDK 5.36、5.37、5.38这些是IDE和整体套件的版本而编译器是另一个独立的组件AC6的小版本从6.15一路走到6.21以上。所谓“Keil 6.12版”这个叫法在圈子里通常就是指MDK 5.38配合AC6.12这个组合也是目前比较稳定的搭配。为什么大家特别关心AC6的版本号因为它直接决定你对C标准的支持程度。AC6.16之前对C17的支持还不完善模板展开经常出诡异错误AC6.18之后C17基本稳定C20的部分特性也能用了。如果你想在Keil里写C20的协程、概念这类语法除了装新版本的AC6没有第二条路。而热搜词里提到的“给Keil配置外部的GCC工具链这样就能获得对C20/23特性的完整支持代价是需要一”这确实是这两年兴起的高级玩法。原理很简单AC6本质上是Clang的前端加ARM的后端它对C标准的支持程度永远慢半拍到一拍。而GCC工具链比如arm-none-eabi-gcc 10.3以上对C20/23的支持反而更积极。在Keil里把编译器换成GCC你就能在MDK的IDE界面里写最新的C语法。我实际试过这个方案步骤不复杂但有几个坑一是GCC的启动文件可能跟Keil的兼容最好直接用芯片厂商提供的GCC版本startup文件二是调试信息格式要对GCC生成的是DWARFKeil的ULINK和J-Link都能识别但前提是GCC编译参数里要加-gdwarf-5三是GCC没有AC6自带的那些CMSIS优化选项外设访问结构体的编译优化要靠你自己开-O2但开了之后运行效率其实比AC6还高点。1.2 为什么大家都在谈AC6搜索引擎里“Keil如何使用6版本编译器”“keil arm compiler的missing compiler version 5编译不了”这类词条热度一直居高不下。背后的痛点很清晰新工程默认AC6但大量老工程的启动文件、库代码、甚至你自己写的汇编文件都是在ARMCC 5语法下写的。直接切到AC6编译直接报错或者链接不过。这里你们要注意一个核心区别ARMCC 5 的汇编器用--cpu和--apcs参数而 AC6 用的是--target和-mcpu语法完全不同。如果你的启动文件是老的.s格式在 AC6 下大概率会报 “unknown directive” 或 “bad instruction”。解决办法有两个一是去芯片厂商官网下载基于 AC6 重写的新版启动文件和 Device 包二是自己手动改汇编把.equ改成.set把LDR r0, SystemInit这种伪指令改成BL SystemInit工作量不小但能治本。不过我觉得更明智的思路是“从新建工程开始就默认 AC6老工程能用就不碰”。不要为了升级而升级嵌入式系统里说得通的升级理由只有一个新功能确实需要。2. 版本升级前需要考虑的几个关键点2.1 pack芯片包与device支持很多用户在用Keil 6.12时遇到的第一道坎是芯片包pack不对。Keil的软件架构是IDE加编译器加Device Pack三件套你装的芯片支持包版本必须跟IDE匹配。比如你新建一个STM32H743工程需要装Keil.STM32H7xx_DFP包如果是老版本2.4.0可能在AC6下编译就报“device is not supported”。最好去Keil官网或芯片厂商官网下载最新的DFP比如Keil.STM32F4xx_DFP.2.13.0.pack这类安装包。有一个很容易被忽略的细节同一颗芯片在不同DFP版本下SVD文件System View Description也不同直接影响你在调试器里看到的寄存器描述和外设名字。如果你从老工程复制代码到新版DFP发现某些寄存器名字变了、位定义少了先查DFP版本大概率是对不上了。下载完成后安装路径不要中文不要有空格放在C:\Keil_v5\ARM\PACK这类纯英文目录下面否则有些外设库代码在编译时会产生莫名其妙的长文件名报错。2.2 ARMCC 5到AC6的迁移成本如果你手头有个几千行的老工程从ARMCC 5切到AC6我建议你先做个简单的代码体检搜索所有#pragma、__asm、__forceinline、__weak这类关键字。AC6对#pragma pack的支持还行但对__asm的支持方式跟ARMCC 5非常不同。AC6环境下更推荐用__NOP()、__WFI()这类内建函数代替内联汇编或者把纯汇编单独放到.s文件用C接口去调用。警告级别的差异也值得注意ARMCC 5对 int 和指针之间的隐式转换往往只给个warningAC6直接给error尤其涉及寄存器地址映射的时候。所以迁移时第一轮编译纯属排雷把每一处警告都当成待办项逐个用显式转换去修。这个过程确实心累但修完之后代码质量是真的提升了我自己的经验是迁移完的代码在后续维护中出现的“灵异问题”少了很多。3. 实操从新建工程到配置AC63.1 新建STM32工程与选择编译器版本我用Keil 6.12建一个新STM32工程的过程基本可以照抄下面这几步换个芯片也通用。1. 打开Keil uVision5点 Project - New uVision Project 2. 选好保存路径建议纯英文无空格路径输入工程名 3. 在弹出的Device窗口搜索芯片型号比如STM32F103C8 4. 点击OK后会弹出Manage Run-Time Environment窗口 如果不需要软件组件直接点OK跳过建议勾选CMSIS - CORE 5. 添加启动文件在Project栏右键 - Add Existing Files 选择Pack目录下的 startup_stm32f103xb.s 6. 配置编译选项 Options for Target - Target - ARM Compiler 选择 Use default compiler version 6如果不选这个就用不了AC6 7. 在 C/C (AC6) 选项卡里Define 填入 USE_STDPERIPH_DRIVER, STM32F10X_MD 8. Include Paths 添加你自己的头文件目录这一步最容易出问题的地方是第6步。新版Keil的Compiler选项下拉菜单里默认就是Use default compiler version 6但如果你的工程之前是用ARMCC 5建的这里是Use default compiler version 5切换后代码全部报错。如果只想用旧的GCC风格就保留但如果确实要体验C新特性就还是切到6。编译选项的设置也有讲究。AC6的优化等级和ARMCC 5不一样-O0适合调试-Os适合发布-O2性能最好但调试信息经常对不上源码头。新手建议先-O0跑通功能最后再切-Os。另外--C99、--cpp11这些参数在AC6里写法变了直接在Misc Controls里写-stdc17这种方式才管用。3.2 把GCC工具链塞进Keil这个操作适合对嵌入式编译器已经比较熟悉、并且确实需要C20/23特性的开发者。我在STM32H743上试验过它跑FreeRTOS效果还是可以的。下载arm-none-eabi-gcc工具链后解压到一个纯英文目录。然后在Keil里做以下配置Project - Manage - Project Items - Folders/Extensions把“Arm Compiler”相关的默认路径改为你的GCC工具链的bin路径在Options for Target - C/C里编译器命令一定要改成arm-none-eabi-gccLinker设置里也要手动指定arm-none-eabi-ld或者直接用gcc做链接驱动同时手动传-T链接脚本参数其中链接脚本是最大的难点。AC6自带分散加载文件.sct而GCC用的是.ld链接脚本两者格式完全不一样。我的做法是从STM32官方GCC示例工程里复制一份STM32H743ZITX_FLASH.ld然后根据自己板子的RAM和FLASH大小修改MEMORY段的配置。修改时注意Flash的起始地址和大小、RAM的起始地址和大小一定要跟芯片型号匹配否则编译通过后一运行就硬件错误而且调试器里看PC指针会指向0xFFFFFFFE之类的地方。调试这一块在Keil里配GCC确实麻烦一点需要指定调试器类型为J-Link或ST-Link并确保GCC生成了DWARF格式的调试信息。实测下来J-Link配合GDB调试器都能正常工作。有点可惜的是Keil自带的Trace、逻辑分析仪、RTX RTOS插件这些高级功能对GCC生成的调试信息支持很有限我一般只在纯算法验证项目里用这个方案。3.3 生成bin文件的方法很多用户在搜索“Keil生成bin文件”“Keil生成bin文件和hex文件”时其实就是想知道怎么在编译完hex之外再导出一个可以烧录的bin。这个方法本身不复杂关键在fromelf命令的用法。推荐在Keil的User选项卡里配置After Build/Rebuild命令fromelf --bin --output.\Output\你的工程名.bin .\Output\你的工程名.axf勾选Run #1这样每次编译成功后就自动在Output目录下生成同名bin文件。对应的想生成hex文件只需要勾选Options for Target里的Create HEX File或者也通过fromelf命令fromelf --i32 --output.\Output\你的工程名.hex .\Output\你的工程名.axf这里有个小坑如果你没有在Output选项卡设置Select Folder for Objects默认会把axf文件放在工程根目录下的Listings或Objects里fromelf的路径就要同步改。我习惯的做法是统一把输出目录指定为.\Output\生成的文件都放一起后面做批量烧录在脚本里调用bin文件时路径不容易出错。还有一个技巧大家搜索“Keil生成bin文件”不一定能搜到如果要把app写进bootloader并做OTA最好让链接器把bin文件里地址0的区域留出来或者直接把bin文件放到一个固定偏移地址生成时用--base调整偏移。这个方法在量产时很实用可以少处理很多半字节对齐的麻烦。4. 日常使用中必须会的几个技巧4.1 关掉自动弹出的Pack Installer没有比这更烦人的事了每次打开Keil都自动弹Pack Installer搜索引擎里“keil mdk打开自动弹出pack installer怎么关闭”的热度一直很高。关法其实就两步打开Pack Installer窗口菜单栏找到View或左下角的设置区域取消勾选“Check for Updates on Startup”如果还是不行直接修改Keil安装目录下的TOOLS.INI文件在[UV2]小节里加一行DisablePackInstaller1另外一个偏门原因有时候是哪个pack安装包损坏了导致每次启动时MDK都要重新扫描pack目录。这种问题用上面的DisablePackInstaller1也可以避开。不过我还是建议平时保持Pack Installer可用毕竟DFP更新它都很方便。4.2 不复位直接进调试很多新手每次点Debug按钮都是重新下载并复位运行在调试一些掉电保持的场景或者在线调试Bootloader跳转App的场景下这真的很麻烦。其实Keil早就留了这样一个开关在Options for Target - Debug - Settings里Flash Download选项卡里有个“Reset and Run”选项把它去掉。这样下载程序后不会自动复位运行而是停在当前PC位置。如果你要调试的App是被Bootloader从某个地址跳转过来的先在仿真器配置里把“Connect under Reset”勾上然后在Debug启动后把PC手动设到跳转目标地址这个技巧在搜“keil不复位直接进调试”时经常出现但真正实操时需要先开System Viewer确认当前内核状态不然容易出不可控的问题。4.3 查看内部RAM值“Keil查看内部RAM值”算是一个入门但又容易踩坑的需求。调试时有两种姿势一是Memory窗口直接在地址栏输入0x20000000这种RAM起始地址手动输入u32或u8类型查看二是使用Watch窗口配合变量名来读取具体变量地址。注意变量加了static或者被编译器优化掉后在Watch窗口里是看不到的所以如果你填入某个变量名但显示不可用先在编译选项里把优化等级降到-O0再用volatile关键字去修饰。还有一个经常被忽略的细节是Keil的System Viewer里可以看到官方SVD定义的整个外设内存布局比如CRC寄存器、DMA描述符、以太网缓冲区这些本质都在访问RAM地址映射区。有了System Viewer的总体视图配合Memory窗口做定位调试效率一下就能上来。5. 常见报错与排查实录5.1 编译器版本5缺失/编译不了“keil arm compiler的missing compiler version 5编译不了”是这几年问得最多的问题。本质上是你装了新版本MDK但工程配置里还在用ARMCC 5而新版MDK默认不再自带ARMCC 5又没有自动切换到AC6。解决办法有三个第一个安装ARMCC 5的兼容包Legacy Support在Pack Installer里的“Legacy”分类可以找到然后工程里指定编译器为ARMCC 5。这个方法适合必须用老工具链的旧项目。但要注意这个兼容包也有版本匹配老项目中的AC5版本与新安装的AC5版本不同也可能出现问题。第二个工程里直接切换编译器到AC6然后逐个修复报错。适合源码在你自己手里、可控性较强的项目。第三个如果你的核心诉求是C新特性那就按前面说的GCC方案配外置工具链。三个方案没有绝对的优劣按项目时间评估就好。5.2 无法正常查询函数“Keil无法正常查询函数”也是老问题。很多时候不是代码问题而是Intellisense代码提示崩了。解决办法是删掉工程目录下的.sc,.crf,.dep这类缓存文件关闭Keil再重新打开工程。如果还不行检查Project Items里的头文件路径很多函数定义在某个.h里但你没有把对应路径加进Include Paths导致编辑器找不到定义所有跳转和查询都是空的。值得留意的是AC6下如果启用了--gnu模式某些标准库函数的声明显得更严格了比如strcpy这种不安全的函数是需要额外宏定义的否则编辑器会标记成未找到或隐式声名。这种问题不是查询功能坏了而是编译选项和代码之间的匹配没做好。5.3 jlink识别不到单片机最后说下“Keil识别不了jlink”和“Keil识别不到单片机”这类烧录问题它同时和驱动、连接、电平都相关。我的排查步骤固定如下确认物理连接SWDIO、SWCLK、GND是否连上建议尽量用短杜邦线。如果线材过长SWD时钟频率太高连接识别就会不稳定。确认在MDK的设置里Debug选项卡选了J-Link而不是ST-Link或ULINK。确认J-Link驱动的版本去Segger官网更新到最新的驱动老驱动的Segger RTT功能经常和新版本MDK的DBG模块冲突。在Options for Target - Debug - Settings页面里点一下“Flash Download”选项卡在“Programming Algorithm”里正确添加芯片对应的算法文件。这步要是漏了或加了错误型号就会出现“Erase Failed”或“Cannot Access Target”这种报错。如果芯片进入低功耗模式或读保护状态第一次连接可能失败。试一下“Connect under Reset”全速下载前先按住复位键点Setting窗口里的Connect再松开。最后根据我个人经验建议每次新建工程或更换电脑后先用一个最简单的LED闪灯工程去测试整套烧录调试链路跑通了再往里面加代码。这样可以避开很多“明明是环境问题却怀疑代码写错”的无效时间。Keil这个工具版本越新功能越多但越新也越需要在动手前梳理清楚自己要什么。搞清楚编译器、芯片包、调试器这几个核心组件的版本匹配关系很多问题在安装阶段就能提前化解而不是等编译报错后再去排查。本文还有配套的精品资源点击获取
返回列表