踐指南)
簡介Keil μVision 6.12版是一款面向單片機(jī)開發(fā)的集成開發(fā)環(huán)境特別適合配合郭天祥單片機(jī)系列教程從經(jīng)典8051起步后續(xù)可平滑過渡到ARM Cortex-M等主流內(nèi)核。該版本內(nèi)置C51與ARM兩套編譯器可將C語言或匯編源碼編譯為單片機(jī)可執(zhí)行的機(jī)器碼集成的調(diào)試器支持?jǐn)帱c(diǎn)設(shè)置、單步執(zhí)行、寄存器與變量查看等排錯(cuò)操作。CPU模擬器允許學(xué)習(xí)者在沒有實(shí)體開發(fā)板的前提下先行模擬運(yùn)行并驗(yàn)證程序邏輯降低入門門檻。硬件調(diào)試方面可通過JTAG或USB接口連接開發(fā)板實(shí)現(xiàn)在線燒錄與實(shí)時(shí)調(diào)試同時(shí)支持FreeRTOS、μC/OS-II等常見RTOS便于后續(xù)開展多任務(wù)嵌入式項(xiàng)目。壓縮包為zip格式大小約11.17MB整體體量適中下載部署較為方便。已有1012人學(xué)習(xí)對(duì)正準(zhǔn)備系統(tǒng)學(xué)習(xí)單片機(jī)或需要穩(wěn)定IDE環(huán)境的開發(fā)者是一個(gè)可直接上手的實(shí)用資源。1. 先搞清楚Keil 6.12到底“新”在哪最近嵌入式開發(fā)圈子里Keil 6.12版這幾個(gè)字被提到的頻率非常高。特別是當(dāng)你在搜索“Keil官網(wǎng)”“Keil最新版本”“Keil mdk”這些關(guān)鍵詞的時(shí)候會(huì)發(fā)現(xiàn)很多人在問同一個(gè)問題這個(gè)版本到底是不是最值得升級(jí)的作為一個(gè)從ARM7時(shí)代就開始用Keil的老用戶我想用實(shí)際經(jīng)驗(yàn)把這件事說透。先說結(jié)論你現(xiàn)在能看到的各種“Keil 6.12版”說法本質(zhì)上指的是以MDK 5.38為基底、配合AC6ARM Compiler 6工具鏈的完整開發(fā)環(huán)境。版本號(hào)里的“6”代表編譯器大版本而不是IDE界面的大改版。很多人第一次接觸AC6編譯器時(shí)最大的感受就是怎么編譯速度變快了報(bào)錯(cuò)信息怎么完全看不懂了這就是因?yàn)锳C6底層是基于Clang架構(gòu)的跟過去ARMCC 5時(shí)代那套GCC風(fēng)格報(bào)錯(cuò)完全是兩個(gè)物種。拿我自己舉例有個(gè)跑了好幾年的STM32F407老工程從ARMCC 5切到AC6編譯編譯時(shí)間直接從原來的40多秒干到了12秒左右生成的bin文件體積還小了差不多8%。但代價(jià)也實(shí)實(shí)在在警告信息多了好幾倍什么“implicit conversion”“incompatible pointer types”這類Clang特有的提示一開始看得人頭皮發(fā)麻。所以如果你準(zhǔn)備上手Keil 6.12第一件事不是急著裝而是想清楚自己手頭的項(xiàng)目是否需要這套東西。如果你的芯片是STM32F103這類老器件、用的還是標(biāo)準(zhǔn)外設(shè)庫代碼量也不大繼續(xù)用ARMCC 5完全沒問題沒必要折騰。但如果你手里有C項(xiàng)目、需要C11/14甚至20/23特性或者芯片是新出的Cortex-M33/M55內(nèi)核那AC6就是唯一選擇因?yàn)锳RMCC 5根本不支持這些新內(nèi)核。1.1 版本號(hào)背后的編譯器邏輯Keil的版本號(hào)體系很容易讓人混淆。MDK 5.36、5.37、5.38這些是IDE和整體套件的版本而編譯器是另一個(gè)獨(dú)立的組件AC6的小版本從6.15一路走到6.21以上。所謂“Keil 6.12版”這個(gè)叫法在圈子里通常就是指MDK 5.38配合AC6.12這個(gè)組合也是目前比較穩(wěn)定的搭配。為什么大家特別關(guān)心AC6的版本號(hào)因?yàn)樗苯記Q定你對(duì)C標(biāo)準(zhǔn)的支持程度。AC6.16之前對(duì)C17的支持還不完善模板展開經(jīng)常出詭異錯(cuò)誤AC6.18之后C17基本穩(wěn)定C20的部分特性也能用了。如果你想在Keil里寫C20的協(xié)程、概念這類語法除了裝新版本的AC6沒有第二條路。而熱搜詞里提到的“給Keil配置外部的GCC工具鏈這樣就能獲得對(duì)C20/23特性的完整支持代價(jià)是需要一”這確實(shí)是這兩年興起的高級(jí)玩法。原理很簡單AC6本質(zhì)上是Clang的前端加ARM的后端它對(duì)C標(biāo)準(zhǔn)的支持程度永遠(yuǎn)慢半拍到一拍。而GCC工具鏈比如arm-none-eabi-gcc 10.3以上對(duì)C20/23的支持反而更積極。在Keil里把編譯器換成GCC你就能在MDK的IDE界面里寫最新的C語法。我實(shí)際試過這個(gè)方案步驟不復(fù)雜但有幾個(gè)坑一是GCC的啟動(dòng)文件可能跟Keil的兼容最好直接用芯片廠商提供的GCC版本startup文件二是調(diào)試信息格式要對(duì)GCC生成的是DWARFKeil的ULINK和J-Link都能識(shí)別但前提是GCC編譯參數(shù)里要加-gdwarf-5三是GCC沒有AC6自帶的那些CMSIS優(yōu)化選項(xiàng)外設(shè)訪問結(jié)構(gòu)體的編譯優(yōu)化要靠你自己開-O2但開了之后運(yùn)行效率其實(shí)比AC6還高點(diǎn)。1.2 為什么大家都在談AC6搜索引擎里“Keil如何使用6版本編譯器”“keil arm compiler的missing compiler version 5編譯不了”這類詞條熱度一直居高不下。背后的痛點(diǎn)很清晰新工程默認(rèn)AC6但大量老工程的啟動(dòng)文件、庫代碼、甚至你自己寫的匯編文件都是在ARMCC 5語法下寫的。直接切到AC6編譯直接報(bào)錯(cuò)或者鏈接不過。這里你們要注意一個(gè)核心區(qū)別ARMCC 5 的匯編器用--cpu和--apcs參數(shù)而 AC6 用的是--target和-mcpu語法完全不同。如果你的啟動(dòng)文件是老的.s格式在 AC6 下大概率會(huì)報(bào) “unknown directive” 或 “bad instruction”。解決辦法有兩個(gè)一是去芯片廠商官網(wǎng)下載基于 AC6 重寫的新版啟動(dòng)文件和 Device 包二是自己手動(dòng)改匯編把.equ改成.set把LDR r0, SystemInit這種偽指令改成BL SystemInit工作量不小但能治本。不過我覺得更明智的思路是“從新建工程開始就默認(rèn) AC6老工程能用就不碰”。不要為了升級(jí)而升級(jí)嵌入式系統(tǒng)里說得通的升級(jí)理由只有一個(gè)新功能確實(shí)需要。2. 版本升級(jí)前需要考慮的幾個(gè)關(guān)鍵點(diǎn)2.1 pack芯片包與device支持很多用戶在用Keil 6.12時(shí)遇到的第一道坎是芯片包pack不對(duì)。Keil的軟件架構(gòu)是IDE加編譯器加Device Pack三件套你裝的芯片支持包版本必須跟IDE匹配。比如你新建一個(gè)STM32H743工程需要裝Keil.STM32H7xx_DFP包如果是老版本2.4.0可能在AC6下編譯就報(bào)“device is not supported”。最好去Keil官網(wǎng)或芯片廠商官網(wǎng)下載最新的DFP比如Keil.STM32F4xx_DFP.2.13.0.pack這類安裝包。有一個(gè)很容易被忽略的細(xì)節(jié)同一顆芯片在不同DFP版本下SVD文件System View Description也不同直接影響你在調(diào)試器里看到的寄存器描述和外設(shè)名字。如果你從老工程復(fù)制代碼到新版DFP發(fā)現(xiàn)某些寄存器名字變了、位定義少了先查DFP版本大概率是對(duì)不上了。下載完成后安裝路徑不要中文不要有空格放在C:\Keil_v5\ARM\PACK這類純英文目錄下面否則有些外設(shè)庫代碼在編譯時(shí)會(huì)產(chǎn)生莫名其妙的長文件名報(bào)錯(cuò)。2.2 ARMCC 5到AC6的遷移成本如果你手頭有個(gè)幾千行的老工程從ARMCC 5切到AC6我建議你先做個(gè)簡單的代碼體檢搜索所有#pragma、__asm、__forceinline、__weak這類關(guān)鍵字。AC6對(duì)#pragma pack的支持還行但對(duì)__asm的支持方式跟ARMCC 5非常不同。AC6環(huán)境下更推薦用__NOP()、__WFI()這類內(nèi)建函數(shù)代替內(nèi)聯(lián)匯編或者把純匯編單獨(dú)放到.s文件用C接口去調(diào)用。警告級(jí)別的差異也值得注意ARMCC 5對(duì) int 和指針之間的隱式轉(zhuǎn)換往往只給個(gè)warningAC6直接給error尤其涉及寄存器地址映射的時(shí)候。所以遷移時(shí)第一輪編譯純屬排雷把每一處警告都當(dāng)成待辦項(xiàng)逐個(gè)用顯式轉(zhuǎn)換去修。這個(gè)過程確實(shí)心累但修完之后代碼質(zhì)量是真的提升了我自己的經(jīng)驗(yàn)是遷移完的代碼在后續(xù)維護(hù)中出現(xiàn)的“靈異問題”少了很多。3. 實(shí)操從新建工程到配置AC63.1 新建STM32工程與選擇編譯器版本我用Keil 6.12建一個(gè)新STM32工程的過程基本可以照抄下面這幾步換個(gè)芯片也通用。1. 打開Keil uVision5點(diǎn) Project - New uVision Project 2. 選好保存路徑建議純英文無空格路徑輸入工程名 3. 在彈出的Device窗口搜索芯片型號(hào)比如STM32F103C8 4. 點(diǎn)擊OK后會(huì)彈出Manage Run-Time Environment窗口 如果不需要軟件組件直接點(diǎn)OK跳過建議勾選CMSIS - CORE 5. 添加啟動(dòng)文件在Project欄右鍵 - Add Existing Files 選擇Pack目錄下的 startup_stm32f103xb.s 6. 配置編譯選項(xiàng) Options for Target - Target - ARM Compiler 選擇 Use default compiler version 6如果不選這個(gè)就用不了AC6 7. 在 C/C (AC6) 選項(xiàng)卡里Define 填入 USE_STDPERIPH_DRIVER, STM32F10X_MD 8. Include Paths 添加你自己的頭文件目錄這一步最容易出問題的地方是第6步。新版Keil的Compiler選項(xiàng)下拉菜單里默認(rèn)就是Use default compiler version 6但如果你的工程之前是用ARMCC 5建的這里是Use default compiler version 5切換后代碼全部報(bào)錯(cuò)。如果只想用舊的GCC風(fēng)格就保留但如果確實(shí)要體驗(yàn)C新特性就還是切到6。編譯選項(xiàng)的設(shè)置也有講究。AC6的優(yōu)化等級(jí)和ARMCC 5不一樣-O0適合調(diào)試-Os適合發(fā)布-O2性能最好但調(diào)試信息經(jīng)常對(duì)不上源碼頭。新手建議先-O0跑通功能最后再切-Os。另外--C99、--cpp11這些參數(shù)在AC6里寫法變了直接在Misc Controls里寫-stdc17這種方式才管用。3.2 把GCC工具鏈塞進(jìn)Keil這個(gè)操作適合對(duì)嵌入式編譯器已經(jīng)比較熟悉、并且確實(shí)需要C20/23特性的開發(fā)者。我在STM32H743上試驗(yàn)過它跑FreeRTOS效果還是可以的。下載arm-none-eabi-gcc工具鏈后解壓到一個(gè)純英文目錄。然后在Keil里做以下配置Project - Manage - Project Items - Folders/Extensions把“Arm Compiler”相關(guān)的默認(rèn)路徑改為你的GCC工具鏈的bin路徑在Options for Target - C/C里編譯器命令一定要改成arm-none-eabi-gccLinker設(shè)置里也要手動(dòng)指定arm-none-eabi-ld或者直接用gcc做鏈接驅(qū)動(dòng)同時(shí)手動(dòng)傳-T鏈接腳本參數(shù)其中鏈接腳本是最大的難點(diǎn)。AC6自帶分散加載文件.sct而GCC用的是.ld鏈接腳本兩者格式完全不一樣。我的做法是從STM32官方GCC示例工程里復(fù)制一份STM32H743ZITX_FLASH.ld然后根據(jù)自己板子的RAM和FLASH大小修改MEMORY段的配置。修改時(shí)注意Flash的起始地址和大小、RAM的起始地址和大小一定要跟芯片型號(hào)匹配否則編譯通過后一運(yùn)行就硬件錯(cuò)誤而且調(diào)試器里看PC指針會(huì)指向0xFFFFFFFE之類的地方。調(diào)試這一塊在Keil里配GCC確實(shí)麻煩一點(diǎn)需要指定調(diào)試器類型為J-Link或ST-Link并確保GCC生成了DWARF格式的調(diào)試信息。實(shí)測下來J-Link配合GDB調(diào)試器都能正常工作。有點(diǎn)可惜的是Keil自帶的Trace、邏輯分析儀、RTX RTOS插件這些高級(jí)功能對(duì)GCC生成的調(diào)試信息支持很有限我一般只在純算法驗(yàn)證項(xiàng)目里用這個(gè)方案。3.3 生成bin文件的方法很多用戶在搜索“Keil生成bin文件”“Keil生成bin文件和hex文件”時(shí)其實(shí)就是想知道怎么在編譯完hex之外再導(dǎo)出一個(gè)可以燒錄的bin。這個(gè)方法本身不復(fù)雜關(guān)鍵在fromelf命令的用法。推薦在Keil的User選項(xiàng)卡里配置After Build/Rebuild命令fromelf --bin --output.\Output\你的工程名.bin .\Output\你的工程名.axf勾選Run #1這樣每次編譯成功后就自動(dòng)在Output目錄下生成同名bin文件。對(duì)應(yīng)的想生成hex文件只需要勾選Options for Target里的Create HEX File或者也通過fromelf命令fromelf --i32 --output.\Output\你的工程名.hex .\Output\你的工程名.axf這里有個(gè)小坑如果你沒有在Output選項(xiàng)卡設(shè)置Select Folder for Objects默認(rèn)會(huì)把a(bǔ)xf文件放在工程根目錄下的Listings或Objects里fromelf的路徑就要同步改。我習(xí)慣的做法是統(tǒng)一把輸出目錄指定為.\Output\生成的文件都放一起后面做批量燒錄在腳本里調(diào)用bin文件時(shí)路徑不容易出錯(cuò)。還有一個(gè)技巧大家搜索“Keil生成bin文件”不一定能搜到如果要把a(bǔ)pp寫進(jìn)bootloader并做OTA最好讓鏈接器把bin文件里地址0的區(qū)域留出來或者直接把bin文件放到一個(gè)固定偏移地址生成時(shí)用--base調(diào)整偏移。這個(gè)方法在量產(chǎn)時(shí)很實(shí)用可以少處理很多半字節(jié)對(duì)齊的麻煩。4. 日常使用中必須會(huì)的幾個(gè)技巧4.1 關(guān)掉自動(dòng)彈出的Pack Installer沒有比這更煩人的事了每次打開Keil都自動(dòng)彈Pack Installer搜索引擎里“keil mdk打開自動(dòng)彈出pack installer怎么關(guān)閉”的熱度一直很高。關(guān)法其實(shí)就兩步打開Pack Installer窗口菜單欄找到View或左下角的設(shè)置區(qū)域取消勾選“Check for Updates on Startup”如果還是不行直接修改Keil安裝目錄下的TOOLS.INI文件在[UV2]小節(jié)里加一行DisablePackInstaller1另外一個(gè)偏門原因有時(shí)候是哪個(gè)pack安裝包損壞了導(dǎo)致每次啟動(dòng)時(shí)MDK都要重新掃描pack目錄。這種問題用上面的DisablePackInstaller1也可以避開。不過我還是建議平時(shí)保持Pack Installer可用畢竟DFP更新它都很方便。4.2 不復(fù)位直接進(jìn)調(diào)試很多新手每次點(diǎn)Debug按鈕都是重新下載并復(fù)位運(yùn)行在調(diào)試一些掉電保持的場景或者在線調(diào)試Bootloader跳轉(zhuǎn)App的場景下這真的很麻煩。其實(shí)Keil早就留了這樣一個(gè)開關(guān)在Options for Target - Debug - Settings里Flash Download選項(xiàng)卡里有個(gè)“Reset and Run”選項(xiàng)把它去掉。這樣下載程序后不會(huì)自動(dòng)復(fù)位運(yùn)行而是停在當(dāng)前PC位置。如果你要調(diào)試的App是被Bootloader從某個(gè)地址跳轉(zhuǎn)過來的先在仿真器配置里把“Connect under Reset”勾上然后在Debug啟動(dòng)后把PC手動(dòng)設(shè)到跳轉(zhuǎn)目標(biāo)地址這個(gè)技巧在搜“keil不復(fù)位直接進(jìn)調(diào)試”時(shí)經(jīng)常出現(xiàn)但真正實(shí)操時(shí)需要先開System Viewer確認(rèn)當(dāng)前內(nèi)核狀態(tài)不然容易出不可控的問題。4.3 查看內(nèi)部RAM值“Keil查看內(nèi)部RAM值”算是一個(gè)入門但又容易踩坑的需求。調(diào)試時(shí)有兩種姿勢一是Memory窗口直接在地址欄輸入0x20000000這種RAM起始地址手動(dòng)輸入u32或u8類型查看二是使用Watch窗口配合變量名來讀取具體變量地址。注意變量加了static或者被編譯器優(yōu)化掉后在Watch窗口里是看不到的所以如果你填入某個(gè)變量名但顯示不可用先在編譯選項(xiàng)里把優(yōu)化等級(jí)降到-O0再用volatile關(guān)鍵字去修飾。還有一個(gè)經(jīng)常被忽略的細(xì)節(jié)是Keil的System Viewer里可以看到官方SVD定義的整個(gè)外設(shè)內(nèi)存布局比如CRC寄存器、DMA描述符、以太網(wǎng)緩沖區(qū)這些本質(zhì)都在訪問RAM地址映射區(qū)。有了System Viewer的總體視圖配合Memory窗口做定位調(diào)試效率一下就能上來。5. 常見報(bào)錯(cuò)與排查實(shí)錄5.1 編譯器版本5缺失/編譯不了“keil arm compiler的missing compiler version 5編譯不了”是這幾年問得最多的問題。本質(zhì)上是你裝了新版本MDK但工程配置里還在用ARMCC 5而新版MDK默認(rèn)不再自帶ARMCC 5又沒有自動(dòng)切換到AC6。解決辦法有三個(gè)第一個(gè)安裝ARMCC 5的兼容包Legacy Support在Pack Installer里的“Legacy”分類可以找到然后工程里指定編譯器為ARMCC 5。這個(gè)方法適合必須用老工具鏈的舊項(xiàng)目。但要注意這個(gè)兼容包也有版本匹配老項(xiàng)目中的AC5版本與新安裝的AC5版本不同也可能出現(xiàn)問題。第二個(gè)工程里直接切換編譯器到AC6然后逐個(gè)修復(fù)報(bào)錯(cuò)。適合源碼在你自己手里、可控性較強(qiáng)的項(xiàng)目。第三個(gè)如果你的核心訴求是C新特性那就按前面說的GCC方案配外置工具鏈。三個(gè)方案沒有絕對(duì)的優(yōu)劣按項(xiàng)目時(shí)間評(píng)估就好。5.2 無法正常查詢函數(shù)“Keil無法正常查詢函數(shù)”也是老問題。很多時(shí)候不是代碼問題而是Intellisense代碼提示崩了。解決辦法是刪掉工程目錄下的.sc,.crf,.dep這類緩存文件關(guān)閉Keil再重新打開工程。如果還不行檢查Project Items里的頭文件路徑很多函數(shù)定義在某個(gè).h里但你沒有把對(duì)應(yīng)路徑加進(jìn)Include Paths導(dǎo)致編輯器找不到定義所有跳轉(zhuǎn)和查詢都是空的。值得留意的是AC6下如果啟用了--gnu模式某些標(biāo)準(zhǔn)庫函數(shù)的聲明顯得更嚴(yán)格了比如strcpy這種不安全的函數(shù)是需要額外宏定義的否則編輯器會(huì)標(biāo)記成未找到或隱式聲名。這種問題不是查詢功能壞了而是編譯選項(xiàng)和代碼之間的匹配沒做好。5.3 jlink識(shí)別不到單片機(jī)最后說下“Keil識(shí)別不了jlink”和“Keil識(shí)別不到單片機(jī)”這類燒錄問題它同時(shí)和驅(qū)動(dòng)、連接、電平都相關(guān)。我的排查步驟固定如下確認(rèn)物理連接SWDIO、SWCLK、GND是否連上建議盡量用短杜邦線。如果線材過長SWD時(shí)鐘頻率太高連接識(shí)別就會(huì)不穩(wěn)定。確認(rèn)在MDK的設(shè)置里Debug選項(xiàng)卡選了J-Link而不是ST-Link或ULINK。確認(rèn)J-Link驅(qū)動(dòng)的版本去Segger官網(wǎng)更新到最新的驅(qū)動(dòng)老驅(qū)動(dòng)的Segger RTT功能經(jīng)常和新版本MDK的DBG模塊沖突。在Options for Target - Debug - Settings頁面里點(diǎn)一下“Flash Download”選項(xiàng)卡在“Programming Algorithm”里正確添加芯片對(duì)應(yīng)的算法文件。這步要是漏了或加了錯(cuò)誤型號(hào)就會(huì)出現(xiàn)“Erase Failed”或“Cannot Access Target”這種報(bào)錯(cuò)。如果芯片進(jìn)入低功耗模式或讀保護(hù)狀態(tài)第一次連接可能失敗。試一下“Connect under Reset”全速下載前先按住復(fù)位鍵點(diǎn)Setting窗口里的Connect再松開。最后根據(jù)我個(gè)人經(jīng)驗(yàn)建議每次新建工程或更換電腦后先用一個(gè)最簡單的LED閃燈工程去測試整套燒錄調(diào)試鏈路跑通了再往里面加代碼。這樣可以避開很多“明明是環(huán)境問題卻懷疑代碼寫錯(cuò)”的無效時(shí)間。Keil這個(gè)工具版本越新功能越多但越新也越需要在動(dòng)手前梳理清楚自己要什么。搞清楚編譯器、芯片包、調(diào)試器這幾個(gè)核心組件的版本匹配關(guān)系很多問題在安裝階段就能提前化解而不是等編譯報(bào)錯(cuò)后再去排查。本文還有配套的精品資源點(diǎn)擊獲取