Keil MDK STM32系列
- Keil MDK STM32系列(一) 基於標准外設庫SPL的STM32F103開發
- Keil MDK STM32系列(二) 基於標准外設庫SPL的STM32F401開發
- Keil MDK STM32系列(三) 基於標准外設庫SPL的STM32F407開發
- Keil MDK STM32系列(四) 基於抽象外設庫HAL的STM32F401開發
- Keil MDK STM32系列(五) 使用STM32CubeMX創建項目基礎結構
- Keil MDK STM32系列(六) 基於HAL的ADC模數轉換
- Keil MDK STM32系列(七) STM32F4基於HAL的PWM和定時器
- Keil MDK STM32系列(八) STM32F4基於HAL的PWM和定時器輸出音頻
- Keil MDK STM32系列(九) 基於HAL和FatFs的FAT格式SD卡TF卡讀寫
概述
Windows下使用Keil MDK5進行stm32f103c8t6的開發和編譯, 配合ST-LINK工具進行燒錄, 使用標准外設庫SPL.
所需硬件
stm32f103系列開發板
stm32f103c8t6核心板
參數
- ARM 32-bit Cortex-M3
- 72 MHz maximum frequency
- 20k ram, 64k flash 這是一個規格比較低的stm32芯片
- LQFP封裝48pin
stm32f103vct6開發板
參數
- ARM 32-bit Cortex-M3
- 72 MHz maximum frequency
- 48k ram, 256k flash
- LQFP封裝100pin
st-link燒錄器
在燒錄程序到目標芯片以及Debug時需要使用, 自ST-Link V2以來的所有ST-LINK板都帶一個COMLED, 一般是紅綠兩色組合, 也有些是紅藍兩色, 兩色分別有常亮, 常滅, 閃爍等狀態. 不同狀態代表不同的含義:
- 閃爍紅色: 正在PC上創建USB模擬器, 如果持續閃爍有可能驅動未安裝成功
- 紅色: 在PC與ST-Link之間已經建立連接(USB模擬已完成)
- 閃爍交替綠色和紅色: 目標芯片和PC之間正在交換數據
- 綠色: ST-Link與目標芯片通信成功
- 橙色(紅綠同時亮): ST-Link與目標芯片通信失敗。
USB2TTL轉接卡
在觀察串口輸出時需要使用.
安裝說明
文件准備
- mdk525.exe
不建議使用5.12等早期版本, 在更新時窗口容易卡, 且失敗總會彈出需要手工消除. - keygen2032
大部分找到的keygen, 有效期都是2020年的, 沒法用, 必須要能生成2032有效期的版本 - st-link驅動
https://www.st.com/zh/development-tools/stsw-link004.html 不安裝沒法燒錄 - st官方庫
前往https://www.st.com/, 點擊Tools&Software > Embedded Software > MCU & MPU Embedded Software > STM32 Embedded Software > STM32 Standard Peripheral Libraries(鏈接), 下載F1和F4, 解壓備用.- 這里下載的F1的庫文件, Release notes發布日期是2011年, 年代比較久遠
安裝
- 運行mdk525, 安裝
- 安裝完成后Pack Installer會自動運行, 可以讓其自己更新
- 如果使用stlink下載器的, 還需要安裝驅動
注冊
- 以管理員身份運行Keil uVision5
- File->License Management, 復制Computer ID - CID的內容
略
安裝開發包
在Pack Installer中
- 在左側找到STMicroelectronics->STM32F1->STM32F103, 點擊
- 在右側會顯示對應的Packs, 在Device Specific中找到Keil::STM32F1xx_DFP, 點擊Install安裝
- 同理安裝STM32F401
名詞解釋
CMSIS
微控制器軟件接口標准(CMSIS:Cortex Microcontroller Software Interface Standard)是 Cortex-M 處理器系列的與供應商無關的硬件抽象層(A vendor-independent hardware abstraction layer for the Cortex-M processor series and defines generic tool interfaces). 使用CMSIS可以為處理器和外設實現一致且簡單的軟件接口, 從而簡化軟件的重用、縮短微控制器新開發人員的學習過程,並縮短新設備的上市時間
ld, md, hd, xl; cl, vl
- ld(low density), md(medium density), hd(high density), xl(XL-Density) 對應同一個型號線上, 不同flash和ram大小的芯片.
- vl(value line), cl(connectivity line) 指的是同一型號下, 不同的細分型號線
對於stm32f1x, 各名詞的對應關系為
- Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers where the Flash memory density ranges between 16 and 32 Kbytes.
- Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers where the Flash memory density ranges between 64 and 128 Kbytes.
- High-density devices are STM32F101xx and STM32F103xx microcontrollers where the Flash memory density ranges between 256 and 512 Kbytes.
- XL-density devices are STM32F101xx and STM32F103xx microcontrollers where the Flash memory density ranges between 768 Kbytes and 1 Mbyte.
- Connectivity line devices are STM32F105xx and STM32F107xx microcontrollers.
ST官方庫結構說明
STM32F10x_StdPeriph_Lib_V3.5.0
目錄結構及說明
├─Libraries
│ ├─CMSIS
│ │ ├─CM3
│ │ │ ├─CoreSupport # CMSIS核心外設訪問層代碼
│ │ │ └─DeviceSupport
│ │ │ └─ST
│ │ │ └─STM32F10x # stm32f10x相關代碼
│ │ │ └─startup
│ │ │ ├─arm # startup_stm32f10x_ld/md/hd/xl.s文件,
# stm32f103c8t66規格為64k flash, 對應md
│ │ │ ├─gcc_ride7
│ │ │ ├─iar
│ │ │ └─TrueSTUDIO
│ │ └─Documentation
│ └─STM32F10x_StdPeriph_Driver # 對應stm32f10x的外設代碼
│ ├─inc
│ └─src
├─Project
│ ├─STM32F10x_StdPeriph_Examples # 代碼示例
│ └─STM32F10x_StdPeriph_Template # 代碼模板, 需要用到stm32f10x_conf.h, stm32f10x_it.c, stm32f10x_it.h這三個文件(直接復制到新項目的USER目錄)
│ ├─EWARM
│ ├─HiTOP
│ ├─MDK-ARM
│ ├─RIDE
│ └─TrueSTUDIO
├─Utilities
└─_htmresc
開發說明
創建項目
創建目錄並填充文件
以stm32f103為例, 對於項目test001, 創建工作目錄test001, 在工作目錄下創建MDK-ARM, USER這兩個目錄
- 復制開發包下的Libraries整個目錄到當前項目目錄下
- 這個目錄中包含了CMSIS核心外設訪問層代碼
- stm32的外設庫文件
- mdk-arm
用於放置Keil MDK項目文件, 以及項目開發過程中生成的臨時文件 - hardware
用於放置自定義的外設, 例如rfid, esp8266等 - user
- 復制 STM32F10x_StdPeriph_Template下面的stm32f10x_conf.h, stm32f10x_it.c, stm32f10x_it.h三個文件到這個目錄
- 用於放置用戶編寫的代碼
ld,md,hd的選擇
md hd ld 根據芯片FLASH容量決定
- 16K < FLASH < 32K ld
- 64K < FLASH < 128K md
- 256K < FLASH < 512K hd
在Keil uVision5中創建項目
Project -> New uVision Project, 選擇前面的MDK-ARM目錄, 使用名稱test001, 保存- 選擇對應的芯片型號
配置項目
點擊Manage Project Items
- 修改project targets名稱
- 添加groups
- CMSIS
- StdPeriph_Driver
- Hardware
- Startup
- User
對每個group, 添加的文件為
- CMSIS
- core_cm3.c
- system_stm32f10x.c
- StdPeriph_Driver
- 添加 libraries/STM32F10x_StdPeriph_Driver/src 下面的所有c文件
- Hardware
- 添加 hardware目錄下的c文件
- Startup
- 添加 libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/arm 下面對應的s文件
- User
- 添加 user 目錄下的所有c文件
點擊configure target options , 定位到c/c++
- Define: 寫入 USE_STDPERIPH_DRIVER
- 不需要填STM32F10X_MD, STM32F10X_HD 這些配置, 這個變量在前面選擇芯片型號的時候就自動定義了, 不確定的話可以觀察產生的Compiler Control String
- Include Paths: 如果是按上面的目錄結構組織的項目, 可以直接復制下面的配置
..\Libraries\CMSIS\CM3\CoreSupport;..\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x;..\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm;..\Libraries\STM32F10x_StdPeriph_Driver\inc;..\hardware;..\user
在c/c++下能看到完整的編譯Compile control string
-c --cpu Cortex-M3 -D__MICROLIB -g -O0 --apcs=interwork --split_sections -I ../Libraries/CMSIS/CM3/CoreSupport -I ../Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x -I ../Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/arm -I ../Libraries/STM32F10x_StdPeriph_Driver/inc -I ../Libraries/ STM32F10x_StdPeriph_Driver/src -I ../hardware -I ../user
-I./RTE/_test001
-IC:/Keil_v5/ARM/PACK/Keil/STM32F1xx_DFP/2.3.0/Device/Include
-IC:/Keil_v5/ARM/CMSIS/Include
-D__UVISION_VERSION="525" -DSTM32F10X_MD -DUSE_STDPERIPH_DRIVER
-o .\Obj\*.o --omf_browse .\Obj\*.crf --depend .\Obj\*.d
燒錄
stlink與stm32f103c8t6核心板
連接需要4根線, 連接關系為
G -- GND
CLK -- SWCLK
IO -- SWDIO
V3 -- 3.3V
stlink與stm32f103vct6開發板
有些開發板沒有單獨的SWC/SWD接口, 只能連接到JTAG接口, 連接方式為:
- 從PCB板上方俯視, 將JTAG接口座缺口朝上
- PIN1-PIN20為從上至下, 從右至左
- 最右側為PIN1(上), PIN2(下), 都可以接stlink的3.3V
- 從右往左數第4個為PIN7, 接SWDIO, 第5個為PIN9, 接SWCLK
- 最左下角為PIN20, 接GND

在Keil uvision5中
- 點擊configure target options , 定位到Debug, Use選擇ST-Link Debuger, 點擊Settings
- 如果Debug Adapter里時空白沒有顯示ST-LINK/V2, 去windows設備管理器看下設備是否正常
- 切換到Flash Download標簽, 勾選Reset and Run
- 點擊Download按鈕, 或者按F8, 進行燒錄
Debug調試說明
在F7編譯完代碼, F8將程序通過ST-Link燒錄至開發板后, 就可以對程序進行調試
快捷鍵匯總
- 進入/跳出Debug模式:
Ctrl + F5 - 繼續運行
F5 - 逐步運行
F10 - 單步執行(會跳入)
F11 - 從函數內跳出運行
Ctrl + F11 - 運行到光標所在處
Ctrl + F10 - 插入/移除斷點
F9 - 移除所有斷點
Ctrl + Shift + F9
調試要點
- 點擊
Start/Stop Debug Session或Ctrl+F5進入Debug模式, 在進入Debug模式后, 會重啟程序, 並暫停程序運行 - 這時候可以按
F5往下執行, 或者按F10或F11一步一步執行, 或者Ctrl + F10跳到光標指定的行 - 通過Reset按鈕, 可以將程序恢復到初始的暫停狀態
- 常用的調試小窗口
- Watch窗口: 選中變量 -> 右鍵 -> Add xxx to ->Watch1
- System Viewer窗口: 可以實時查看外設寄存器值, 通過View->System View -> 指定外設 打開.
stm32開發說明
代碼結構
項目的目錄結構比較自由, 只要包含的C文件正確, 包含的頭文件路徑正確, 再加上正確的編譯變量如USE_STDPERIPH_DRIVER, 編譯就沒問題. 但是在項目中還是需要注意目錄結構, 建議將平時不需改動的代碼, 需要頻繁修改的代碼, 以及IDE相關的文件, 編譯中間產生的文件, 都按目錄分隔開.
在項目中最終采的代碼結構
├─Libraries
│ ├─CMSIS
│ ├─Hardware
│ └─STM32F10x_StdPeriph_Driver
├─MDK-ARM
└─User
- 其中Libraries直接用開發庫的原始文件結構, CMSIS和STM32F10x_StdPeriph_Driver是開發中不需要修改的
- 將自定義的外設代碼都放在單獨的Hardware目錄中, 這個目錄可以放在Libraries下, 也可以放在最外層與Libraries平級
- 外設代碼的頭文件中, 不應當包含全局頭文件
include.h, 而是包含stm32f10x.h, 以及其他需要用到的Hardware頭文件.
- 外設代碼的頭文件中, 不應當包含全局頭文件
- 項目相關的代碼, 例如main.c都放在User目錄下
- 創建一個
include.h, 用於包含整體的項目頭文件,stm32f10x.h以及用到的Hardware頭文件, 在main.c中引用include.h - 創建一個
config.h, 用於放置環境相關的變量, 在main.c以及需要用到的hardware中引用, 這個文件要加到.gitignore
- 創建一個
- IDE相關以及編譯中間產生的文件, 都放在MDK-ARM目錄下, 這個目錄需要添加到.gitignore
代碼邏輯
STM32F10x是基於ARM Cortex-M3 的32位內核, F4是基於M4的內核, M3跟M4比就是不帶FPU和DSP指令集. 在STM32上的開發思路, 和一般的軟件項目開發思路不太一樣. STM32上跑的程序, 基本上就是圍繞着它的外設進行的, 主要的外設包括 DMA, ETH, GPIO, TIM, U(S)ART, SPI, I2C, ADC等.
代碼的套路一般是這樣的
- 初始化需要的外設, 包括內建的定時器, GPIO, UART, SPI, I2C, 中斷以及自定義的外設, 例如RFID, ESP8266等
- 對於自定義的外設, 需要自己編寫外設驅動, 處理與STM32內建外設之間的通信
- 做一個while(1)循環, 在循環中完成業務邏輯
- 主體單進程, 在進程中通過各種中斷, 觸發和處理外設之間的通信
需要注意的地方
- 每個外設, 都有對應的總線, 對應的編號, 以及對應的PIN腳, 這些會直接體現到代碼中
- 要根據總線頻率, 自己控制時間, 定時和延遲都是自己控制的
- 傳輸是以byte為單位的, 一個中斷可能只產生1個byte的數據
- 外設的初始化, 中斷位的判斷和清除, 都是固定用法
- 內存是有限的, 對每個byte都要計算精確, 不能浪費
內存管理
stm32f103c8t6的flash為64k, ram為20k, 容量都很小. 編譯結果中的信息
Program Size: Code=8788 RO-data=424 RW-data=72 ZI-data=2328
與這兩部分相關聯的關系為
- FLASH占用 = Code + RO Data + RW Data
- RAM占用 = RW Data + ZI Data + Stack_Size + Heap_Size
實際測試發現, 不論RW Data + ZI Data多大, 運行中可以通過malloc+memset申請的內存只有500個字節, 只要申請的內存超過這個數量, 運行就會卡住.
在代碼中, 盡量不要用malloc, 而應該直接聲明為固定長度的數組, 這樣聲明的內存, 可以觀察到會增長到ZI Data中去, 這種方式能使用的空間比500字節大得多.
問題排查
當遇到問題時, 例如引腳不工作, 不輸出, 輸出不正確, 需要通過各種手段檢查和排查
- 引腳不工作, 要檢查對應的模塊是否正確初始化, 是否使能. STM32中GPIO, UART, NVIC這些模塊的啟動基本上都是固定套路
- 對於串口等外設語句上需要檢查, AHB1, APB1, APB2 與外設對應關系是否正確, 是否錯誤使用RCC_APB1去啟用RCC_APB2了
- 是否在main中調用初始化方法了
- 串口輸出和輸入的問題排查
- 首先是在debug界面, 查看串口外設的寄存器值, 看看有沒有初始化成功
- 通過USB2TTL轉接卡, 將信號輸入輸出轉移到putty/xshell中進行檢查
- 排除連線斷路的問題
- 字符串輸入輸出. 因為有
\r,\n等格式符號的存在, 會導致輸出字符顯示較亂, 當需要嚴格對照時, 需要將每個字符打印成雙位16進制輸出%02X - 程序執行卡住, 有可能是變量申請的內存過大超出了內存限制
