板入門指南:從環(huán)境搭建到第一個程序)
STM32F103的開發(fā)板到手了接下來該干什么板子剛拆封那會兒我盯著那塊藍色PCB看了半天——STM32F103C8T672MHz主頻64KB Flash20KB SRAM板載了ST-Link和USB接口還引出了所有GPIO。說實話這玩意兒比當年我用的51單片機強太多了但隨之而來的問題是從哪兒下手網上教程鋪天蓋地有講寄存器的有講標準庫的有講HAL的還有直接上RTOS的看多了反而不知道該聽誰的。這篇文章就是寫給剛拿到STM32F103開發(fā)板、想系統(tǒng)入門但不想被各種教程繞暈的人。我會從板子到手后的第一件事開始把環(huán)境搭建、工程創(chuàng)建、第一個程序燒錄、常見問題排查這條完整鏈路講清楚中間穿插我自己踩過的坑和總結出來的經驗。不管你是電子專業(yè)的學生還是轉行做嵌入式的開發(fā)者跟著這條路徑走至少能少走兩三個月的彎路。1. 拿到板子先別急著寫代碼這幾件事決定了后面順不順1.1 確認板子型號和核心芯片的具體參數STM32F103這個系列下面有非常多型號C8T6、RCT6、ZET6、VET6等等封裝不同、引腳數不同、Flash和RAM大小也不同。我手里這塊是C8T6LQFP48封裝64KB Flash、20KB SRAM屬于入門級里最經典的配置。為什么要先確認這個因為后面你選芯片包、配工程、寫鏈接腳本的時候都要跟具體型號對應。比如你拿的是RCT6256KB Flash、48KB SRAM卻按C8T6的配置去建工程編譯可能沒問題但燒錄后跑起來會出各種莫名其妙的問題。板子上一般會印型號如果沒有看主控芯片表面的絲印。另外注意板子的晶振頻率——大部分F103板子用的是8MHz外部晶振經過PLL倍頻到72MHz作為系統(tǒng)時鐘。也有少數板子用12MHz晶振這個在配置時鐘樹的時候要特別留意配錯了串口波特率會全亂。1.2 檢查板載的調試器和供電方式現在市面上很多F103開發(fā)板都板載了ST-Link或者DAP-Link調試器直接用一根USB線就能完成供電、下載、調試三件事。但有些便宜的板子只留了SWD排針需要你外接調試器。拿到板子后先確認這一點因為它決定了你后面用什么方式燒錄程序。如果板載了調試器插上USB后設備管理器里應該能看到對應的調試器設備。如果沒看到可能需要裝驅動。ST-Link的驅動在ST官網可以下載DAP-Link的話Win10以上一般免驅。這里有個細節(jié)有些板子的USB接口只負責供電調試接口是另外一個Type-C或者Micro-USB口別插錯了。注意插上USB后如果板子上的電源燈不亮先換一根USB線試試。很多便宜的USB線只有充電功能沒有數據線芯這個坑我見過太多次了。1.3 準備好必要的軟件工具鏈STM32開發(fā)常用的IDE有Keil MDK、IAR EWARM、STM32CubeIDE這幾種。Keil在國內用得最多資料也最全但需要單獨安裝芯片包Pack。STM32CubeIDE是ST官方推出的免費IDE基于Eclipse集成了CubeMX配置工具適合不想折騰License的開發(fā)者。VS Code加PlatformIO或者EIDE插件也是一條路適合習慣輕量級編輯器的朋友。我的建議是入門階段用Keil MDK或者STM32CubeIDE先把流程跑通別一上來就折騰VS Code的各種插件配置。等你對編譯、鏈接、燒錄這些環(huán)節(jié)有了直觀感受之后再換工具也不遲。芯片包的安裝后面會詳細講這里先有個概念就行。2. 開發(fā)環(huán)境搭建從零到編譯通過的完整路徑2.1 Keil MDK的安裝與芯片包配置Keil MDK的安裝本身沒什么難度一路Next就行。關鍵是裝完之后要安裝STM32F1系列的Device Family Pack。這個包不在Keil安裝包里需要單獨下載。打開Keil后點擊Pack Installer圖標在左側找到STMicroelectronics展開后找到STM32F1 Series點擊對應的Pack進行安裝。如果網絡環(huán)境不好導致在線安裝失敗也可以去Keil官網手動下載Pack文件然后雙擊安裝。Pack文件的后綴是.pack安裝路徑一般會自動識別Keil的安裝目錄。裝完之后新建工程時才能在芯片列表里找到STM32F103C8這類型號。這里有個常見問題有些人裝完Pack后新建工程還是找不到芯片原因通常是Pack版本和Keil版本不匹配。比如Keil MDK 5.36配STM32F1的Pack 2.3.0一般沒問題但如果Keil版本太老比如5.14可能需要用舊版的Pack。遇到這種情況要么升級Keil要么降級Pack沒有別的辦法。2.2 使用STM32CubeMX生成初始化代碼STM32CubeMX是ST官方出的圖形化配置工具可以幫你生成引腳配置、時鐘樹、外設初始化的代碼。對于新手來說它能大幅降低入門門檻因為你不需要一上來就對著參考手冊寫寄存器。具體流程是這樣的新建工程選擇芯片型號STM32F103C8Tx然后配置時鐘源。在RCC里把HSE設為Crystal/Ceramic Resonator然后在Clock Configuration里把HCLK拉到72MHz。接著配置調試接口在SYS里把Debug設為Serial Wire這樣SWD接口才能正常工作。最后配置你要用的外設比如GPIO、USART、TIM等。生成代碼的時候注意選對工具鏈。如果你用Keil就選MDK-ARM如果用STM32CubeIDE就選STM32CubeIDE。生成的代碼會包含main.c、stm32f1xx_hal_msp.c、stm32f1xx_it.c等文件以及HAL庫的驅動文件。提示CubeMX生成的代碼里用戶代碼要寫在/* USER CODE BEGIN/和/USER CODE END */之間否則下次重新生成代碼時會被覆蓋掉。這個規(guī)則一定要記住我見過太多人因為把代碼寫錯位置重新生成后全部丟失的。2.3 標準庫工程模板的手動搭建雖然HAL庫現在是主流但很多老教程和項目還在用標準庫Standard Peripheral Library。標準庫的好處是代碼量小、執(zhí)行效率高、貼近寄存器操作適合想深入理解底層的人。但ST已經不再維護標準庫了新建工程需要手動拷貝庫文件。手動搭建標準庫工程的步驟大致是新建工程目錄在里面創(chuàng)建Startup、Library、User、Output等文件夾。把啟動文件startup_stm32f10x_md.s、系統(tǒng)文件system_stm32f10x.c、內核文件core_cm3.c/h以及STM32F10x_StdPeriph_Driver里的外設驅動文件拷貝到對應目錄。然后在Keil里新建工程添加這些文件配置頭文件包含路徑最后在Options for Target里設置好Output和Listing路徑。這個過程比較繁瑣但做一遍之后你對STM32工程的組成結構會有非常清晰的認識。網上有很多現成的標準庫工程模板可以下載但建議至少自己手動搭一次知道每個文件是干什么用的。3. 第一個程序從點亮LED到串口輸出3.1 GPIO輸出實驗點亮板載LED點亮LED是嵌入式開發(fā)的Hello World。F103的GPIO配置流程是使能GPIO時鐘、配置GPIO模式、設置輸出電平。用HAL庫的話代碼大概長這樣// 使能GPIOC時鐘 __HAL_RCC_GPIOC_CLK_ENABLE(); // 配置PC13為推挽輸出 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_13; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, GPIO_InitStruct); // 在主循環(huán)里翻轉電平 while (1) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); HAL_Delay(500); }這里有個細節(jié)很多F103最小系統(tǒng)板的板載LED接在PC13上而且是低電平點亮。也就是說你寫HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET)的時候LED是亮的寫SET的時候是滅的。這個跟硬件電路有關拿到板子后最好用萬用表測一下LED的正負極方向或者直接看原理圖。3.2 串口通信實驗printf重定向串口是調試過程中最重要的工具之一。F103一般用USART1引腳是PA9TX和PA10RX。配置好波特率常用115200、數據位、停止位、校驗位之后就可以收發(fā)數據了。為了能用printf輸出調試信息需要重定向fputc函數int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, HAL_MAX_DELAY); return ch; }然后在Keil的Options for Target里勾選Use MicroLIB否則printf可能無法正常工作。這個坑非常經典很多人寫了重定向代碼但串口沒輸出就是因為沒勾MicroLIB。串口調試助手可以用SSCOM、XCOM或者PuTTY。注意波特率、數據位、停止位、校驗位要和代碼里配置的一致否則收到的全是亂碼。3.3 定時器實驗精準延時與PWM輸出HAL_Delay()函數用的是SysTick定時器精度一般而且在中斷里調用會有問題。如果需要更精準的延時或者PWM輸出就要用通用定時器TIM2~TIM5。配置定時器的時候要算好預分頻系數PSC和自動重裝載值ARR。比如系統(tǒng)時鐘72MHz想要1ms的定時周期可以設PSC71ARR999這樣定時器時鐘就是72MHz/(711)1MHz計數1000次就是1ms。PWM輸出的配置稍微復雜一點需要設置PWM模式、占空比、極性等。用CubeMX配置的話選好定時器和通道設置好PSC和ARR然后在代碼里用__HAL_TIM_SET_COMPARE()宏來動態(tài)調整占空比。4. 燒錄與調試程序怎么進到芯片里4.1 ST-Link燒錄的接線與配置SWD接口需要四根線VCC、GND、SWDIO、SWCLK。有些板子還引出了SWO和NRST但最基本的四根線就能完成燒錄和調試。接線的時候注意VCC的電壓F103是3.3V供電別接5V。在Keil里配置ST-Link調試器Options for Target - Debug - 選擇ST-Link Debugger - Settings - 確認Port是SW能識別到芯片ID。然后在Flash Download選項卡里確認編程算法是STM32F10x Medium-density Flash對應64KB/128KB的型號。如果識別不到芯片先檢查接線再檢查板子是否上電最后檢查SWD引腳是否被程序禁用了。有些程序會把SWD引腳配置成普通GPIO導致下次無法燒錄。遇到這種情況需要把BOOT0拉高讓芯片從系統(tǒng)存儲器啟動然后重新燒錄。4.2 常見燒錄失敗原因排查燒錄失敗是新手最常遇到的問題原因五花八門。我整理了一個排查表現象可能原因解決辦法找不到芯片接線錯誤或板子沒供電檢查SWD四根線確認電源燈亮找不到芯片SWD引腳被禁用BOOT0拉高重新上電后再燒錄燒錄報錯Flash Download failed編程算法選錯確認芯片型號對應的Flash算法燒錄成功但不運行復位電路問題檢查NRST引腳嘗試手動復位燒錄成功但不運行時鐘配置錯誤檢查HSE晶振是否起振還有一個經典問題VS Code里編譯成功但怎么也燒錄不進開發(fā)板。這種情況通常是燒錄工具配置不對或者OpenOCD的配置文件跟芯片不匹配。建議先用Keil或者STM32CubeProgrammer確認能正常燒錄再回頭調VS Code的配置。4.3 使用STM32CubeProgrammer進行獨立燒錄STM32CubeProgrammer是ST官方的燒錄工具支持ST-Link、UART、USB、OTA等多種方式。它的好處是不依賴IDE可以單獨用來燒錄hex或者bin文件。批量生產的時候特別有用。用ST-Link連接后選擇對應的端口加載hex文件點擊Download就行。如果要燒錄bin文件需要手動指定起始地址一般是0x08000000。燒錄完成后可以點擊Verify校驗確保數據寫入正確。5. 入門之后往哪走幾個值得深入的方向5.1 中斷系統(tǒng)與NVIC配置STM32的中斷系統(tǒng)比51復雜得多有優(yōu)先級分組、搶占優(yōu)先級、響應優(yōu)先級等概念。F103的NVIC支持16個優(yōu)先級通過NVIC_PriorityGroupConfig()來設置分組。分組決定了搶占優(yōu)先級和響應優(yōu)先級各占幾位。舉個例子如果你設置分組為NVIC_PriorityGroup_2那么搶占優(yōu)先級和響應優(yōu)先級各占2位取值范圍都是0~3。搶占優(yōu)先級高的可以打斷搶占優(yōu)先級低的中斷相同搶占優(yōu)先級下響應優(yōu)先級高的先執(zhí)行但不能打斷。外部中斷EXTI的配置流程是使能GPIO和AFIO時鐘、配置GPIO為輸入模式、配置EXTI觸發(fā)方式、配置NVIC、編寫中斷服務函數。按鍵中斷是最典型的應用場景。5.2 定時器輸入捕獲與超聲波測距超聲波測距模塊HC-SR04是很多STM32項目的標配。原理很簡單Trig引腳發(fā)一個10us的高電平脈沖模塊發(fā)出超聲波Echo引腳變高收到回波后變低。Echo高電平的持續(xù)時間就是超聲波往返的時間除以2再乘以聲速就是距離。用定時器的輸入捕獲功能可以精準測量Echo引腳的高電平時間。配置TIM的某個通道為輸入捕獲模式上升沿觸發(fā)在中斷里記錄CNT值然后切換為下降沿觸發(fā)再次記錄CNT值兩次之差就是高電平時間。這里有個經驗超聲波測距的精度受溫度影響比較大聲速在0度時是331m/s每升高1度增加0.6m/s。如果要做高精度測量需要加溫度補償。另外測量周期不要太短HC-SR04建議至少60ms一次否則會有回波干擾。5.3 USB虛擬串口與設備開發(fā)F103的USB外設是Full Speed的可以做成虛擬串口CDC、HID設備、大容量存儲等。用CubeMX配置USB Device的時候選擇Communication Device Class生成代碼后安裝ST的VCP驅動電腦上就會多出一個串口。USB虛擬串口的好處是不需要額外的USB轉串口芯片一根線就能搞定通信。但要注意F103的USB和CAN共用引腳不能同時使用。另外USB的時鐘必須精確配置為48MHz否則枚舉會失敗。5.4 基于標準庫和HAL庫的取舍標準庫和HAL庫各有優(yōu)劣。標準庫代碼精簡、執(zhí)行效率高、寄存器操作直觀適合資源緊張或者需要精細控制的場景。HAL庫抽象程度高、跨系列移植方便、配合CubeMX開發(fā)效率高但代碼體積大、執(zhí)行效率相對低。我的建議是入門階段用HAL庫CubeMX快速建立信心和整體認知。等你有了一定基礎再回頭研究標準庫或者直接操作寄存器理解底層原理。實際項目中兩者可以混用比如用CubeMX生成初始化代碼然后關鍵部分用寄存器操作優(yōu)化性能。6. 那些教程不會告訴你的實操經驗6.1 關于延時函數卡死的問題HAL_Delay()卡死是新手經常遇到的現象。原因通常是SysTick中斷優(yōu)先級配置不當或者在中斷服務函數里調用了HAL_Delay()。SysTick的中斷優(yōu)先級默認是最低的如果某個高優(yōu)先級中斷一直在執(zhí)行SysTick中斷就無法觸發(fā)HAL_Delay()就會一直等待。解決辦法是不要在中斷里調用HAL_Delay()如果確實需要延時用簡單的循環(huán)延時或者硬件定時器。另外檢查一下NVIC的優(yōu)先級分組確保SysTick的優(yōu)先級沒有被意外設得太低。6.2 關于JTAG和SWD引腳復用F103的PA13、PA14、PA15、PB3、PB4這幾個引腳默認是JTAG功能。如果你想把它們當普通GPIO用需要禁用JTAG只保留SWD。用標準庫的話調用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)就行。用HAL庫的話在CubeMX的SYS配置里把Debug設為Serial Wire生成的代碼會自動處理。這個坑很隱蔽因為引腳看起來能用但輸出電平不對。我當初調一個SPI屏幕PB3和PB4死活不出信號查了半天才發(fā)現是JTAG沒禁用。6.3 關于電源和復位電路的細節(jié)有些便宜的F103板子為了省成本復位電路只放了一個電容沒有上拉電阻。這種板子上電后可能不復位或者復位不可靠。表現就是程序有時候跑有時候不跑或者燒錄后要手動按復位鍵才運行。如果遇到這種情況可以在NRST引腳和VCC之間加一個10K的上拉電阻再并一個100nF的電容到地。這是ST官方推薦的標準復位電路。另外BOOT0引腳最好也加一個10K下拉電阻避免懸空導致啟動模式不確定。6.4 關于芯片包安裝失敗的替代方案Keil的Pack Installer有時候會因為網絡問題下載失敗。除了手動下載Pack文件之外還有一個辦法是用離線Pack。在Keil的Pack Installer里選擇File - Import然后選擇下載好的.pack文件。如果連官網都打不開可以去一些國內的電子論壇找網友分享的Pack文件注意核對版本號和文件完整性。STM32CubeIDE的話芯片包是集成在安裝包里的一般不需要單獨安裝。但如果你需要更新到最新版的HAL庫可以在Help - Manage Embedded Software Packages里在線更新。6.5 關于開發(fā)板掛載Ubuntu后的權限問題有些朋友喜歡在Ubuntu下用OpenOCD或者STM32CubeProgrammer燒錄。插上ST-Link后可能會提示權限不足這是因為普通用戶沒有USB設備的訪問權限。解決辦法是添加udev規(guī)則sudo nano /etc/udev/rules.d/99-stlink.rules在里面寫入SUBSYSTEMusb, ATTR{idVendor}0483, ATTR{idProduct}3748, MODE0666然后重新加載udev規(guī)則sudo udevadm control --reload-rules sudo udevadm trigger不同版本的ST-Link的idProduct可能不同可以用lsusb命令查看。這個配置做一次就行以后插上就能直接用。板子到手只是開始真正有意思的是后面把一個個外設調通、把一個個項目做出來的過程。F103雖然老但資料全、生態(tài)好、價格便宜作為入門第一塊STM32開發(fā)板再合適不過。我到現在還會用F103做一些小項目它的性能和資源對于大多數控制類應用來說完全夠用。先把GPIO、串口、定時器、中斷這幾個基礎外設玩熟后面學RTOS、文件系統(tǒng)、網絡協(xié)議棧都會順很多。遇到問題別慌先查手冊、再查論壇、最后動手驗證嵌入式開發(fā)就是這樣一步步積累起來的。