發(fā)環(huán)境搭建與配置實(shí)戰(zhàn)指南)
1. 嵌入式開(kāi)發(fā)環(huán)境搭建的起點(diǎn)搞嵌入式開(kāi)發(fā)繞不開(kāi)的第一個(gè)坎就是裝工具鏈。不管你后面是要點(diǎn)燈、調(diào)串口、跑RTOS還是搞USB協(xié)議棧第一步永遠(yuǎn)是讓編譯器和調(diào)試器在電腦上跑起來(lái)。MDK-ARM 5大家更習(xí)慣叫它Keil 5就是ARM Cortex-M系列MCU開(kāi)發(fā)里用得最廣的一個(gè)集成開(kāi)發(fā)環(huán)境沒(méi)有之一。它把編輯器、編譯器、鏈接器、調(diào)試器、燒錄工具全部打包在一起裝完之后基本可以做到“開(kāi)箱即用”不需要你再去手動(dòng)拼湊GCC、OpenOCD、GDB那一套。這篇內(nèi)容適合誰(shuí)看如果你是剛?cè)胄械那度胧叫率质掷锬弥粔KSTM32或者GD32的開(kāi)發(fā)板完全不知道從哪下手那這篇就是寫給你的。如果你是從IAR或者老版本Keil 4遷移過(guò)來(lái)的老手也可以看看里面關(guān)于Pack Installer和器件支持包的細(xì)節(jié)能幫你少走彎路。我會(huì)從下載、安裝、激活、器件包管理、工程創(chuàng)建、編譯配置、調(diào)試器設(shè)置這幾個(gè)環(huán)節(jié)一步步拆開(kāi)講把每個(gè)步驟背后的原因也一并說(shuō)清楚讓你不只是“照著點(diǎn)”而是真正理解這套工具鏈?zhǔn)窃趺催\(yùn)轉(zhuǎn)的。需要提前說(shuō)明的是Keil 5和Keil 4最大的區(qū)別在于器件支持包Device Family Pack簡(jiǎn)稱DFP的引入。Keil 4時(shí)代你裝一個(gè)版本就固定支持那幾家的芯片想換芯片型號(hào)往往要重裝或者打補(bǔ)丁。Keil 5把內(nèi)核、編譯器、器件支持徹底解耦了IDE本體只負(fù)責(zé)框架具體芯片的支持通過(guò)Pack Installer在線下載。這個(gè)設(shè)計(jì)思路很像現(xiàn)代瀏覽器的插件機(jī)制好處是靈活壞處是新手第一次裝完之后發(fā)現(xiàn)“怎么找不到我的芯片”其實(shí)只是包沒(méi)裝而已。2. 安裝前的準(zhǔn)備工作與版本選擇2.1 安裝包從哪里獲取Keil MDK-ARM 5的官方安裝包只有一個(gè)來(lái)源就是Keil官網(wǎng)現(xiàn)在歸屬Arm旗下。搜索“MDK-ARM”就能找到下載頁(yè)面填寫一個(gè)簡(jiǎn)單的表單姓名、郵箱、公司、國(guó)家之后就能拿到下載鏈接。安裝包是一個(gè)大概800MB到1GB左右的exe文件版本號(hào)格式類似MDK537.exe這種前面的5代表Keil 5后面的數(shù)字是具體版本。這里有個(gè)經(jīng)驗(yàn)不建議盲目追最新版本。我踩過(guò)的坑是某些新版本剛發(fā)布時(shí)對(duì)老器件的支持包兼容性會(huì)有問(wèn)題尤其是那些已經(jīng)停產(chǎn)的Cortex-M0/M3老芯片。如果你做的是新項(xiàng)目用最新版沒(méi)問(wèn)題如果是維護(hù)老項(xiàng)目建議用比項(xiàng)目立項(xiàng)時(shí)間晚半年到一年的版本穩(wěn)定性最好。比如項(xiàng)目是2020年做的用MDK 5.30到5.33這個(gè)區(qū)間通常比較穩(wěn)。另外要注意官網(wǎng)下載的是MDK-ARM完整版不是那個(gè)免費(fèi)的MDK-Lite。完整版安裝后如果不激活會(huì)以Lite模式運(yùn)行代碼大小限制在32KB。對(duì)于學(xué)習(xí)點(diǎn)燈、串口收發(fā)這種小工程完全夠用但一旦你的工程超過(guò)32KB編譯就會(huì)報(bào)錯(cuò)。所以后面激活這一步是必須做的。2.2 系統(tǒng)環(huán)境要求Keil 5對(duì)系統(tǒng)要求不算高但也有幾個(gè)硬性條件項(xiàng)目最低要求推薦配置操作系統(tǒng)Windows 7 SP1Windows 10/11 64位處理器1GHz2GHz以上多核內(nèi)存2GB8GB以上硬盤空間2GB可用10GB以上Pack包很占地方顯示器1024x7681920x1080特別提醒兩點(diǎn)。第一安裝路徑絕對(duì)不要帶中文和空格。默認(rèn)路徑是C:\Keil_v5這個(gè)就很好別手賤改成D:\我的軟件\Keil 5后面編譯時(shí)各種莫名其妙的路徑錯(cuò)誤能把你逼瘋。第二如果你電腦上已經(jīng)裝了Keil 4或者更早的版本建議先卸載干凈再裝Keil 5兩個(gè)版本共存雖然理論上可以但注冊(cè)表里的編譯器路徑會(huì)打架導(dǎo)致編譯時(shí)調(diào)用了錯(cuò)誤的armcc。2.3 安裝過(guò)程中的關(guān)鍵選項(xiàng)雙擊安裝包之后前面幾步都是常規(guī)的下一步到了選擇組件的界面要留意一下。安裝程序會(huì)列出幾個(gè)可選項(xiàng)Core核心組件必裝包含IDE本體和ARM編譯器。Device Specific器件相關(guān)的示例和庫(kù)可以不裝后面用Pack Installer按需下載。Pack Installer器件包管理器必裝這是Keil 5的靈魂。CMSISARM官方的一套軟件接口標(biāo)準(zhǔn)建議裝很多庫(kù)依賴它。我的建議是Core、Pack Installer、CMSIS三個(gè)勾上Device Specific不勾。原因很簡(jiǎn)單Device Specific里預(yù)置的那些示例工程往往版本很老你后面從Pack Installer下載的才是最新的裝了反而占地方還容易混淆。安裝過(guò)程大概需要5到10分鐘取決于硬盤速度。裝完之后第一次啟動(dòng)IDE會(huì)提示你安裝Pack這時(shí)候先別急著裝把激活搞定再說(shuō)。3. 激活與License管理3.1 為什么必須激活前面說(shuō)了不激活就是Lite模式32KB代碼限制。這個(gè)限制在什么概念呢一個(gè)簡(jiǎn)單的HAL庫(kù)點(diǎn)燈工程編譯出來(lái)大概6到8KB加上串口打印、定時(shí)器、中斷可能到15KB一旦你上了RTOS或者USB協(xié)議棧輕松突破32KB。所以只要你不是純粹玩玩激活是必須的。激活需要申請(qǐng)一個(gè)License。Keil提供幾種License類型個(gè)人學(xué)習(xí)可以申請(qǐng)免費(fèi)的社區(qū)版Community Edition商業(yè)用途需要購(gòu)買。社區(qū)版的申請(qǐng)流程很簡(jiǎn)單在Keil官網(wǎng)注冊(cè)賬號(hào)填寫用途說(shuō)明一般幾個(gè)工作日內(nèi)會(huì)收到License文件。3.2 激活操作步驟拿到License之后打開(kāi)Keil 5點(diǎn)擊菜單欄的File-License Management會(huì)彈出一個(gè)對(duì)話框。對(duì)話框里有一個(gè)CIDCustomer ID字段這是一串基于你電腦硬件生成的唯一標(biāo)識(shí)。把CID復(fù)制出來(lái)粘貼到Keil官網(wǎng)的License申請(qǐng)頁(yè)面提交后會(huì)生成一個(gè)License字符串再把它粘貼回對(duì)話框的New License ID Code輸入框點(diǎn)擊Add LIC就完成了。注意CID是和電腦硬件綁定的換主板或者重裝系統(tǒng)后CID會(huì)變需要重新申請(qǐng)License。所以建議把License文件備份好換系統(tǒng)后直接重新添加即可。激活成功后對(duì)話框上方會(huì)顯示License的過(guò)期日期和代碼大小限制看到Unlimited就說(shuō)明搞定了。3.3 常見(jiàn)激活問(wèn)題有時(shí)候添加License會(huì)提示“Invalid License”大概率是CID復(fù)制時(shí)帶了空格或者換行。解決方法是把CID粘貼到記事本里確認(rèn)是一串連續(xù)的字符再?gòu)?fù)制過(guò)去。還有一種情況是License已經(jīng)綁定到其他電腦了社區(qū)版一般允許綁定兩臺(tái)設(shè)備如果超了需要先在官網(wǎng)解綁舊設(shè)備。4. Pack Installer與器件支持包管理4.1 Pack Installer是什么Pack Installer是Keil 5區(qū)別于Keil 4的核心組件。你可以把它理解成一個(gè)應(yīng)用商店里面按芯片廠商分類列出了各家MCU的支持包。每個(gè)支持包DFP里包含該系列芯片的啟動(dòng)文件startup_xxx.s外設(shè)寄存器定義頭文件系統(tǒng)初始化代碼system_xxx.cFlash燒錄算法調(diào)試配置文件示例工程沒(méi)有裝對(duì)應(yīng)的DFP你在新建工程時(shí)就找不到那顆芯片編譯也會(huì)報(bào)錯(cuò)說(shuō)找不到器件。4.2 如何安裝器件包打開(kāi)Pack Installer工具欄上那個(gè)綠色小盒子圖標(biāo)左側(cè)是廠商列表右側(cè)是包列表。找到你用的芯片廠商比如STMicroelectronics展開(kāi)后找到對(duì)應(yīng)的系列比如STM32F1 Series再找到具體型號(hào)的DFP點(diǎn)擊Install。這里有個(gè)坑Pack Installer的下載服務(wù)器在國(guó)外國(guó)內(nèi)下載速度可能很慢甚至超時(shí)。解決辦法是使用離線包。各家廠商的DFP也可以從官網(wǎng)單獨(dú)下載下載下來(lái)是一個(gè).pack文件雙擊就能安裝不需要通過(guò)Pack Installer在線下載。我一般會(huì)提前把常用的幾個(gè)系列的pack文件都下載好放在本地?fù)Q電腦時(shí)直接雙擊安裝比在線等快得多。4.3 器件包版本選擇同一個(gè)系列可能有多個(gè)版本的DFP比如STM32F1系列有2.3.0、2.4.0等。選哪個(gè)原則是選新不選舊但別選太新。新版本通常修復(fù)了bug、增加了新器件支持但偶爾會(huì)引入兼容性問(wèn)題。如果你用的是比較成熟的芯片型號(hào)用比最新版早一兩個(gè)小版本的DFP通常最穩(wěn)。安裝完DFP之后新建工程時(shí)在Device選擇框里就能搜到你的芯片了。如果搜不到檢查一下是不是Pack Installer里沒(méi)裝對(duì)應(yīng)的包或者裝完之后沒(méi)有重啟IDE。5. 新建工程與編譯配置5.1 從零創(chuàng)建一個(gè)工程點(diǎn)擊Project-New uVision Project選擇一個(gè)空文件夾作為工程目錄。注意工程路徑同樣不能有中文和空格。然后會(huì)彈出器件選擇窗口搜索你的芯片型號(hào)選中后點(diǎn)擊OK。接下來(lái)會(huì)彈出一個(gè)“Manage Run-Time Environment”窗口這是Keil 5的另一個(gè)特色功能叫RTERun-Time Environment。它允許你直接勾選需要的軟件組件比如CMSIS Core、Device Startup、HAL庫(kù)等IDE會(huì)自動(dòng)把對(duì)應(yīng)的源文件和頭文件路徑添加到工程里。對(duì)于新手來(lái)說(shuō)這個(gè)功能非常方便省去了手動(dòng)添加文件的過(guò)程。不過(guò)我的習(xí)慣是不用RTE手動(dòng)管理文件。原因有兩個(gè)一是RTE自動(dòng)添加的文件路徑很深工程遷移時(shí)容易出問(wèn)題二是手動(dòng)添加能讓你清楚知道每個(gè)文件是干什么的對(duì)理解工程結(jié)構(gòu)有幫助。當(dāng)然如果你只是想快速跑個(gè)Demo用RTE也沒(méi)問(wèn)題。5.2 手動(dòng)添加啟動(dòng)文件和庫(kù)文件一個(gè)最簡(jiǎn)的STM32工程需要哪些文件啟動(dòng)文件startup_stm32f103xb.s根據(jù)具體型號(hào)選系統(tǒng)文件system_stm32f1xx.c鏈接腳本STM32F103xB_FLASH.ldKeil用的是.sct分散加載文件在Options里配置庫(kù)文件標(biāo)準(zhǔn)外設(shè)庫(kù)或者HAL庫(kù)的.c文件主文件main.c把這些文件添加到工程的不同Group里比如Startup、CMSIS、Library、User結(jié)構(gòu)清晰后面維護(hù)方便。5.3 編譯選項(xiàng)配置點(diǎn)擊Options for Target魔術(shù)棒圖標(biāo)有幾個(gè)關(guān)鍵配置Target標(biāo)簽頁(yè)設(shè)置晶振頻率Xtal這個(gè)值影響調(diào)試時(shí)的時(shí)序計(jì)算填你板子上的實(shí)際晶振頻率比如8MHz或者12MHz。Output標(biāo)簽頁(yè)勾選Create HEX File這樣編譯后會(huì)生成hex文件方便用其他工具燒錄。Debug Information也勾上調(diào)試時(shí)需要。C/C標(biāo)簽頁(yè)在Define里填入宏定義比如STM32F103xB, USE_HAL_DRIVER。在Include Paths里添加所有頭文件所在目錄。這里有個(gè)技巧頭文件路徑要加到最底層的公共目錄而不是每個(gè)子目錄都加否則路徑列表會(huì)非常長(zhǎng)。Debug標(biāo)簽頁(yè)選擇調(diào)試器比如ST-Link Debugger或者J-LINK。旁邊的Settings里可以配置燒錄算法和調(diào)試接口SWD還是JTAG。5.4 編譯與常見(jiàn)報(bào)錯(cuò)配置好之后按F7編譯。常見(jiàn)的報(bào)錯(cuò)和解決方法報(bào)錯(cuò)信息原因解決方法cannot open source input file xxx.h頭文件路徑?jīng)]加在Include Paths里添加對(duì)應(yīng)目錄undefined symbol xxx源文件沒(méi)加到工程把對(duì)應(yīng)的.c文件添加進(jìn)來(lái)region RAM overflowed內(nèi)存不夠優(yōu)化代碼或換更大內(nèi)存的芯片L6218E: Undefined symbol函數(shù)聲明了但沒(méi)實(shí)現(xiàn)檢查是否漏了.c文件Error: Flash Download failed燒錄算法沒(méi)選對(duì)在Debug Settings里選正確的Flash算法編譯通過(guò)后Output窗口會(huì)顯示0 Error(s), 0 Warning(s)并給出代碼大小信息。如果Warning很多別忽視很多運(yùn)行時(shí)的問(wèn)題都是Warning積累出來(lái)的。6. 調(diào)試器配置與程序燒錄6.1 調(diào)試器選型常見(jiàn)的調(diào)試器有ST-Link、J-Link、DAPLink等。ST-Link是ST官方出的便宜好用支持SWD接口配合STM32芯片很穩(wěn)。J-Link性能更強(qiáng)支持更多芯片但價(jià)格貴。DAPLink是開(kāi)源的性價(jià)比高適合DIY。在Keil里配置調(diào)試器Options for Target-Debug下拉框里選對(duì)應(yīng)的調(diào)試器。然后點(diǎn)Settings在Debug標(biāo)簽頁(yè)里確認(rèn)能識(shí)別到芯片ID。如果識(shí)別不到檢查接線SWD需要接SWCLK、SWDIO、GND、VCC四根線有時(shí)候還需要接RESET。6.2 Flash燒錄算法配置在Settings的Flash Download標(biāo)簽頁(yè)里需要添加對(duì)應(yīng)的Flash算法。比如STM32F103xB的算法是STM32F10x High-density Flash。如果列表里沒(méi)有說(shuō)明DFP沒(méi)裝好或者版本不對(duì)。選好算法后下面的地址范圍會(huì)自動(dòng)填充確認(rèn)起始地址是0x08000000STM32的Flash起始地址。提示如果燒錄時(shí)提示“Flash Download failed - Target DLL has been cancelled”大概率是Flash算法選錯(cuò)了或者芯片處于讀保護(hù)狀態(tài)。前者換算法后者需要用工具解除讀保護(hù)。6.3 在線調(diào)試技巧配置好調(diào)試器后按CtrlF5進(jìn)入調(diào)試模式。常用的調(diào)試操作斷點(diǎn)在代碼行號(hào)旁邊點(diǎn)擊出現(xiàn)紅點(diǎn)就是斷點(diǎn)。程序運(yùn)行到斷點(diǎn)會(huì)暫停。單步執(zhí)行F11是Step Into進(jìn)入函數(shù)F10是Step Over跳過(guò)函數(shù)。查看變量把鼠標(biāo)懸停在變量上或者把變量拖到Watch窗口。查看寄存器在View菜單里打開(kāi)Registers窗口可以看R0-R15、SP、PC等。查看內(nèi)存View - Memory Windows輸入地址可以查看內(nèi)存內(nèi)容。我個(gè)人的經(jīng)驗(yàn)是調(diào)試時(shí)優(yōu)先看外設(shè)寄存器的值比看變量更直接。比如串口沒(méi)輸出先看USART的CR1寄存器里UE位和TE位有沒(méi)有置1再看BRR寄存器的分頻值對(duì)不對(duì)基本就能定位問(wèn)題。7. 實(shí)操心得與避坑指南7.1 工程目錄結(jié)構(gòu)規(guī)范我見(jiàn)過(guò)太多新手把所有的.c和.h文件堆在一個(gè)文件夾里工程大了之后根本沒(méi)法維護(hù)。建議的目錄結(jié)構(gòu)Project/ ├── CMSIS/ # 內(nèi)核相關(guān)文件 ├── Drivers/ │ ├── STM32F1xx_HAL_Driver/ # HAL庫(kù) │ └── CMSIS/ # 器件頭文件 ├── Inc/ # 用戶頭文件 ├── Src/ # 用戶源文件 ├── Startup/ # 啟動(dòng)文件 └── MDK-ARM/ # Keil工程文件這樣分的好處是換IDE或者遷移工程時(shí)只需要改MDK-ARM目錄其他源碼目錄可以原封不動(dòng)。7.2 編譯速度優(yōu)化Keil默認(rèn)是單線程編譯工程大了之后編譯一次要幾分鐘??梢栽贠ptions for Target-Output里勾選Browse Information關(guān)掉能省不少時(shí)間。另外C/C標(biāo)簽頁(yè)里的Optimization級(jí)別調(diào)試階段用Level 0不優(yōu)化方便單步跟蹤發(fā)布階段用Level 3最高優(yōu)化代碼體積和速度都更好。7.3 常見(jiàn)問(wèn)題速查問(wèn)題一編譯提示“cannot open source input file core_cm3.h”這是CMSIS核心頭文件找不到。解決方法是確認(rèn)DFP裝好了并且在Include Paths里添加了CMSIS/Include目錄。問(wèn)題二燒錄后程序不運(yùn)行先檢查啟動(dòng)文件里的堆棧大小是否夠用再檢查中斷向量表是否偏移正確。如果是BootloaderApp的結(jié)構(gòu)App的向量表需要重映射。問(wèn)題三調(diào)試時(shí)進(jìn)不了main函數(shù)大概率是啟動(dòng)文件里的Reset_Handler有問(wèn)題或者時(shí)鐘初始化卡住了??梢栽赟ystemInit函數(shù)里加個(gè)斷點(diǎn)看能不能走到。問(wèn)題四Pack Installer下載速度極慢用離線pack文件前面說(shuō)過(guò)了。另外Pack Installer的緩存目錄在C:\Users\用戶名\AppData\Local\Arm\Packs可以把下載好的pack文件直接拷進(jìn)去重啟IDE就能識(shí)別。7.4 版本遷移注意事項(xiàng)從Keil 4遷移到Keil 5最大的變化是器件包管理方式。Keil 4的工程文件.uvproj不能直接在Keil 5里打開(kāi)需要先轉(zhuǎn)換成.uvprojx格式。轉(zhuǎn)換過(guò)程中器件選擇、頭文件路徑、庫(kù)文件引用都可能需要手動(dòng)調(diào)整。我的建議是不要直接轉(zhuǎn)換而是新建工程把源碼文件重新添加一遍這樣能順便清理掉一些歷史遺留的冗余配置。從標(biāo)準(zhǔn)外設(shè)庫(kù)遷移到HAL庫(kù)也是類似的情況。HAL庫(kù)的API和標(biāo)準(zhǔn)庫(kù)完全不同函數(shù)名、參數(shù)、返回值都不一樣直接替換文件是編譯不過(guò)的。需要逐個(gè)外設(shè)重寫初始化代碼。這個(gè)過(guò)程很痛苦但HAL庫(kù)的跨系列兼容性更好長(zhǎng)期來(lái)看是值得的。8. 工具鏈的延伸與擴(kuò)展Keil 5裝好之后其實(shí)還有很多可以折騰的地方。比如可以配置外部編輯器VS Code、Sublime Text來(lái)寫代碼Keil只負(fù)責(zé)編譯和調(diào)試。方法是在Options for Target-Output里勾選Browse Information然后在VS Code里裝Keil Assistant插件就能在VS Code里直接調(diào)用Keil的編譯命令。還可以配置版本控制把工程里的.uvprojx、.uvoptx、源碼文件納入Git管理但Objects、Listings、DebugConfig這些編譯產(chǎn)物目錄要加到.gitignore里。這樣多人協(xié)作時(shí)每個(gè)人拉下來(lái)代碼就能直接編譯不會(huì)因?yàn)槁窂絾?wèn)題打架。另外Keil 5支持命令行編譯用UV4.exe -b project.uvprojx -o build.log就能在CI流水線里自動(dòng)編譯。這個(gè)對(duì)于需要持續(xù)集成的項(xiàng)目很有用每次提交代碼后自動(dòng)編譯一遍能及早發(fā)現(xiàn)編譯錯(cuò)誤。最后分享一個(gè)我個(gè)人的習(xí)慣每裝好一個(gè)環(huán)境先跑一個(gè)最小系統(tǒng)驗(yàn)證。不要急著上復(fù)雜功能先寫一個(gè)空的main函數(shù)編譯燒錄確認(rèn)能進(jìn)調(diào)試、能看變量、能單步執(zhí)行。這個(gè)最小系統(tǒng)跑通了說(shuō)明工具鏈沒(méi)問(wèn)題后面再出問(wèn)題就是代碼問(wèn)題排查范圍小很多。這個(gè)習(xí)慣幫我省了無(wú)數(shù)次“到底是環(huán)境問(wèn)題還是代碼問(wèn)題”的糾結(jié)。