STM32開發環境(工具)之Keil MDK 介紹
STM32微處理器基於ARM核,所以很多基於ARM嵌入式開發環境都可用於STM32開發平臺。開發工具都可用於STM32開發。選擇合適的開發環境可以加快開發進度,節省開發成本。本章將先對STM32常用的開發工具Keil MDK和IAR EWARM進行簡單介紹,然後結合STM32_SK模擬評估板和STM32F103C的開發板講解STM32片上資源使用,最後給出一個基於STM32的資料採集器的應用例項。
5.1 Keil MDK介紹
Keil是德國知名軟體公司Keil(現已併入ARM 公司)開發的微控制器軟體開發平臺,是目前ARM核心微控制器開發的主流工具。Keil提供了包括C編譯器、巨集彙編、聯結器、庫管理和一個功能強大的模擬偵錯程式在內的完整開發方案,通過一個整合開發環境(uVision)將這些功能組合在一起。uVision當前最高版本是uVision3,它的介面和常用的微軟VC++的介面相似,介面友好,易學易用,在除錯程式,軟體模擬方面也有很強大的功能。因此很多開發ARM應用的工程師,都對它十分喜歡。
5.1.1 開發過程及整合開發環境簡介
1. Keil的軟體開發週期
使用Keil來開發嵌入式軟體,開發週期和其他的平臺軟體開發週期是差不多的,大致有以下幾個步驟:
1. 建立一個工程,選擇一塊目標晶片,並且做一些必要的工程配置。
2. 編寫C或者彙編原始檔。
3. 編譯應用程式。
4. 修改源程式中的錯誤。
5. 聯機除錯。
下面這種結構圖完整描述了Keil開發軟體的整個過程。
2. uVision3 整合開發環境
uVision3 IDE是一款集編輯,編譯和專案管理於一身的基於視窗的軟體開發環境。uVision3集成了C語言編譯器,巨集編譯,連結/定位,以及HEX檔案產生器。uVision3具有如下特性:
功能齊全的原始碼編輯器,
用於配置開發工具的裝置庫,
用於建立工程和維護工程的專案管理器,
所有的工具配置都採用對話方塊進行,
集成了原始碼級的模擬偵錯程式,包括高速CPU和外設模擬器,
用於往Flash ROM下載應用程式的Flash程式設計工具,
完備的開發工具幫助文件,裝置資料表和使用者使用嚮導。
uVision3具有良好的介面風格,下圖是一個典型的除錯時的視窗。
工程區:用於訪問檔案組和檔案,除錯是可以檢視CPU暫存器。
輸出視窗:顯示編譯結果,以便快速查詢錯誤的地方,同時還是除錯命令輸入輸出視窗,也可以用於顯示查詢結果。
記憶體視窗:顯示指定地址內村裡的內容。
檢視和呼叫棧視窗:用於檢視和修改變數的值,並且現實當前函式呼叫樹。
程式碼視窗:用於檢視和編輯原始檔。
外設對話方塊:檢查微控制的片上外設的狀態。
3. ULINK USB-JTAG介面介面卡
ULINK USB-JTAG是一個用於連線PC USB口和開發板JTAG口的小硬體介面卡。通過ULINK你可以在真實的目標板上建立,下載和測試嵌入式應用。ULINK支援如下操作:
下載目標程式。
檢查記憶體和暫存器。
單步執行程式。
插入多個斷點。
實時執行程式
燒寫FLASH儲存器
5.1.2 工程管理
在專案開發中,並不是僅有一個源程式就行了,還要為這個專案選擇CPU(Keil支援數百種CPU,而這些CPU的特性並不完全相同),確定編譯、彙編、連線的引數,指定除錯的方式,有一些專案還會有多個檔案組成等,為管理和使用方便,Keil使用工程(Project)這一概念,將這些引數設定和所需的所有檔案都加到一個工程中,只對工程而不是對單一的源程式進行編譯(彙編)和連線等操作。下面我們就以一個簡單的例子HelloWorld來講解如何建立工程和配置工程。在這個例子裡,我們將實現開發板上的LED1閃爍,本例使用STM32F103C開發板為目標板。
5.1.2.1 新建工程
點選選單“Project”,選擇“New uVision Project”,這是將會出現一個對話方塊,要求給將要建立的工程起一個名字。
選擇你要儲存的路徑,輸入工程檔案的名字,這裡我們就叫HelloWorld,uVision3工程檔案的字尾為“.uv2”,然後點選“Save”。 這時會彈出一個對話方塊要求你選擇目標裝置的型號。
你可以根據你使用的處理器來選擇,如果您所使用的處理器型號在列表中找不到,也可以找一款與您使用的相相容的型號來代替。這裡我們選擇STM32F103C8,如圖所示,右邊一欄是對這個晶片的基本的說明,然後點選“OK”。
有些晶片會提供啟動程式碼,我們這個時候點選“Yes”,到此一個工程就建立好了。
5.1.2.2 配置工程
工程建立好了之後,還要對工程進行進一步的設定,以滿足要求。
首先用滑鼠右鍵(注意用右鍵)點選左邊工程視窗的“Target 1”,會出現一個選單,選擇“Options for Target 'Target 1'”(也可以通過點選工程視窗的Target 1”,然後使用選單“Project”->“Options for Target 'Target 1'”),即出現工程配置的對話方塊,如下圖所示:
這個對話方塊很複雜,而且根所選擇的晶片有關,這裡共有10個頁面,絕大多數選擇預設配置即可,下面將對一些需要注意的配置簡單介紹一下。
1. Output標籤頁的設定
Select Folder for Objects:選擇編譯之後的目標檔案儲存在哪個目錄裡,預設位置為工程檔案的目錄裡。
Name of Executable:生成的目標檔案的名字,預設是工程的名字。
Create Executable:生成OMF以及HEX檔案。OMF檔名同工程檔名但沒有帶副檔名。
Debug Information:用於Debug版本,生成除錯資訊,否則的話無法進行單步除錯。
Create Batch File:生成用於實現整個編譯過程的批處理檔案,使用這個檔案可以脫離IDE對省程式進行編譯。
Create Hex File:這個選項預設情況下未被選中,如果要寫片做硬體實驗就必須選中該項。這一點是初學者易疏忽的,在此特別提醒注意一定要要選中,否則編譯之不生成Hex檔案。
Big Endian:編碼格式,與CPU相關,如果CPU採用的是Big Endian編碼則勾選上。
Browse Information:產生用於在原始檔快速定位的資訊。
Create Library:生成lib庫檔案,預設不選。
在我們剛剛新建的HelloWorld工程中,更改了三個地方,在工程目錄下新建了一個Output目錄儲存目標檔案,以避免和原始檔混在一起。另外選中了Create Hex File和Browse Information,如上圖所示。
2. C/C++標籤頁的設定
Include Paths:指定標頭檔案的查詢路徑,可以新增多個。
這裡我們所有的選擇保持預設選擇就可以了。
3. Debug標籤頁的設定
左邊是對應uVision3的模擬環境,右邊是針對模擬器,這裡選擇右邊的ULINK Cortex Debugger模擬器為例進行說明。
如果已經將ULINK模擬器連線到你的電腦,點選“Settings”你將進入ARM Target Driver Setup 介面。
ULINK - JTAG/SWD Adapter:
Serial No:列出了當前連線到主機的所有ULINK介面卡的串號,你可以通過列表選擇要使用的ULINK介面卡。
ULINK Version,Device Family以及Firmware Version分別列出了當前選擇的ULINK介面卡的版本,裝置家族和韌體版本。
SWJ,Port:根據和開發板介面的型別選擇埠,有JTAG和SW兩種,勾選SWJ表示支援兩種方式。
Max Clock:指定和開發板的最高通訊時鐘。
JTAG Device Chain:顯示當前通過介面卡連線上的開發板。
Automatic Detection:自動監測,選擇系統將自動檢測連線上的開發板,建議使用。
Manual Configuration:手動配置,通過手動設定ID CODE,Device Name和IR len等屬性來查詢裝置。
Debug:
Cache Options:
Cache Code:通知偵錯程式已經下載的程式程式碼不會改變,選中的話uVision將不會從目標系統讀取程式程式碼。
Cache Memory:決定除錯程式期間程式停止執行的時候,是否更新儲存器顯示。
Download Options:
Verify Code Download:比較目標儲存器和偵錯程式上的應用程式的內容。
Download to Flash:將程式碼下載到所有的儲存器區域,如果不選中,偵錯程式不會把程式碼下載到Flash Download Setup中制定的儲存器地址範圍。
Misc Options:
Use Reset at Startup:選中的時候,偵錯程式在開始除錯的時候會發起一次CPU復位。
Load Application at Startup:將Output標籤中指定的可執行檔案匯入到偵錯程式的起始地址。
Run to Main:開始除錯時執行到Main函式入口暫停執行。
Initialization File:指定一個包含一組除錯命令的檔案,這組命令是偵錯程式開始工作或者除錯函式在除錯期間要使用的。
Restore Debug Session Settings:使用上一次除錯過程對Breakpoints,Watchpoints,Memory Display和Toolbox(如果這些項被選中的話)。
Driver DLL – Parameter:由Device Database設定的目標驅動DLL,不要修改。
Dialog DLL – Parameter:由Device Database設定的對話方塊DLL,不要修改。
這裡我們修改了兩個地方,選中了Use ULINK和Run to Main,對ULINK的設定進行了一些調整,具體的設定圖5.11所示。
4. Utilities標籤頁的設定
Configure Flash Menu Command
Use Target Driver for Flash Programming:列表選擇和除錯介面一致的驅動。Init File的設定也和前面除錯設定一致。點選Settings將進入Flash Download Setup介面。
Download Function:定義了Flash燒寫的時候進行的操作。
Erase Full Chip:前面三項要選一,燒寫程式之前擦除整個Flash儲存器。
Erase Sectors:燒寫程式之前擦除程式要使用的扇區。
Do not Erase:不進行擦除操作
Program:使用當前uVision工程的程式燒寫ROM。
Verify:驗證Flash ROM的內容和當前工程中的程式一致。
Reset and Run:在燒寫和驗證完成之後復位開發板並且執行程式。
RAM for Algorithm:指定用於燒寫程式的RAM區域,通常是微控制器上的一段片上空間。
Start:起始地址。
Size:大小。
可以通過點選Add新增,點選Add你將看到如下的選擇列表,可以根據你選用的晶片選擇合適的,也可以自己手動新增。
Use External Tool for Flash Programming:使用第三方的工具進行Flash下載。
Command:要使用的Flash燒寫工具的命令檔案(通常是一個.exe檔案)。
Arguments:傳遞給Flash燒寫工具的引數。
Run Independent:當選中的時候,uVision不等待Flash燒寫完成。不選中的時候uVision要等待Flash燒寫完成並且在輸出視窗顯示燒寫結果。
在HelloWorld裡面修改了Flash Download Setup,具體的設定如上圖所示。到此工程設定就結束了。
5.1.2.3 開啟工程
通過選單“Project”->“Open Project”來開啟一個現有工程,這時將彈出一個開啟檔案對話方塊讓我們選擇要開啟的工程檔案。
選擇你要開啟的工程的路徑,然後點選“Open”開啟工程。我們還可以和開啟其他檔案一樣,找到一個字尾為“uv2”的uVision3工程檔案,直接雙擊,Windows會自動呼叫uVision3開啟這個檔案,前提是你電腦已經安裝了uVision3並且和“uv2”檔案建立了關聯。
5.1.3 編寫源程式
選擇選單“File”->“New”或者點選工具欄的新建檔案按鈕,即可在專案視窗的右側開啟一個新的文字編輯視窗,在該視窗可以輸入程式程式碼。
需要說明的是,原始檔就是一般的文字檔案,不一定使用Keil軟體編寫,可以使用任意文字編輯器編寫,而且Keil的編輯器對漢字的支援不好,建議使用UltraEdit之類的編輯軟體進行源程式的輸入。
每一個程式至少有一個原型為int main(void)的主函式,這是程式的入口地址,程式將從這裡開始執行。此外,我們還需要對開發板做一些時鐘和中斷方面的初始化工作,這些工作將在函式RCC_Configuration和NVIC_Configuration中完成。原始檔的程式碼清單如下所示。
- #include "stm32f10x_lib.h"
- GPIO_InitTypeDef GPIO_InitStructure;
- void Delay (vu32 nCount);
- /******************************************************************************* Function Name : main
- * Description : 主程式
- * Input : None
- * Output : None
- * Return : None
- ******************************************************************************/
- int main (void)
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ GPIOB, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init (GPIOB, &GPIO_InitStructure);
- while (1)
- {
- GPIO_WriteBit (GPIOB, GPIO_Pin_9,
- (BitAction)(1-GPIO_ReadOutputDataBit (GPIOB, GPIO_Pin_9)));
- Delay (1000000);
- }
- }
- void Delay (vu32 nCount)
- {
- for (; nCount != 0; nCount--);
- }
程式碼編輯完成之後,我們可以儲存原始檔,選擇選單“File”->“Save”或者點選工具欄的儲存檔案按鈕,可以用來儲存原始檔。
這時會出現一個儲存檔案的檔案對話方塊,選擇你要儲存的路徑,輸入檔名HelloWorld.c。注意一定要輸入副檔名,如果是c程式副檔名為.c,如果是彙編副檔名為.s,習慣.asm的也可以儲存為.asm。註解說明檔案可以儲存為.txt的副檔名。
原始檔編輯完成之後我們還需要將原始檔加入到工程中,工程建好之後,在工程視窗的檔案頁中,將會出現“Target 1”,前面有個“+”號,點選“+”號展開,可以看到下一層的“Source Group 1”,我們需要向這個裡面加入原始檔,點選“Source Group 1”使其反白顯示,然後,點選滑鼠右鍵,出現一個下拉選單,如下圖如示。
選中其中的“Add file to Group ‘Source Group 1’”,出現一個對話方塊,要求尋找原始檔,如下圖所示。
注意,該對話方塊下面的“檔案型別”預設為C source file(*.c),我們可以通過調整這個來選擇過濾我們想要格式的檔案,從而幫助我們快速查詢檔案。如果是彙編檔案,就選擇“asm source file”;如果是目標檔案,選擇“Object file”;如果是庫檔案,選擇“Library file”。最後點選“Add”,也可以雙擊要新增的檔案進行加入。注意:點選“Add”之後,視窗不會消失,如果要新增多個檔案,可以不斷新增,新增完畢此時再點選“Close”關閉該視窗。初學者時常誤認為操作沒有成功而再次雙擊同一檔案或者再次點選“Add”,這時會出現如下的對話方塊。
在這裡我們把剛新建的HelloWorld.c新增進去,檔案新增進去之後,我們點選“Source Group 1”前面的“+”號,就會發現我們剛剛新增的檔案HelloWrold.c已在其中了,雙擊檔名,即在程式碼區開啟該源程式檔案。
除了新增檔案,我們還可以新增新的Group,操作和新增檔案類似,出現下拉選單之後我們選擇“New Group”,這時就會在工程視窗看到新加的Group。對Group和新增檔案的操作我們還可以通過點選工具欄上的彩色品字按鈕進入“Components,Environment and Books”視窗,如下圖所示。
雙擊列表中的項可以對該項進行重新命名操作,點選空白處可以新增新的項,虛方框按鈕也可以新增新的項,紅叉表示刪除選中的項,上下箭頭用於調整當前選中項在列表中的位置,“Add Files”可以新增新的原始檔,操作過程和前面新增檔案的操作是一樣的。
5.1.4 編譯程式
程式程式碼寫好之後就進入編譯程式階段,可以通過選單,工具欄和浮動選單多種方式來發起編譯過程,也可以通過批處理檔案進行,關於這個批處理檔案在Output標籤頁的設定中提到過。
紅線圈起來的區域就是對應的選單編譯命令和工具欄編譯命令。各命令的含義如下:
Clean target:清除編譯結果。
Build target:編譯被修改的檔案並且編譯應用程式。
Rebuild all target files:重新編譯所有的原始檔並且編譯應用程式。
Batch Build:通過前面輸出的批處理檔案進行編譯。
Translate **.*:編譯某個原始檔,**.*代表要編譯的原始檔。
Stop build:只有編譯進行過程中這一項才有效。
通過在工程視窗“Target 1”上點選右鍵,也可以彈出相應的編譯選單,各命令含義和上面一致。
現在就讓我們來編譯我們的“HelloWorld”,如下圖所示,編譯的結果會在輸出視窗顯示。
很遺憾,有不少錯誤,也許你早就發現我們的程式碼中使用了很多我們沒有定義的而且也不屬於標準C的一些函式,沒錯這就是ST韌體庫給我們提供的函式,我們要做的就是把韌體庫新增到我們的工程中,和其他的開發環境一下,我們可以直接新增韌體庫的原始檔和工程一起編譯,也可以通過新增已經編譯好的靜態連線庫(*.lib)檔案。這裡我們以後者為例,這些庫在我們安裝好Keil開發環境的時候已經提供了,路徑一般在你安裝目錄下的ARM/RV31/LIB/中,例如我這裡的路徑是D:/Keil/ARM/RV31/LIB/ST。這裡我們將新增一個新的Group,取名為FWLIB。然後將庫檔案新增到這個Group中,具體的操作過程可以參照編寫源程式章節。新增庫之後我們再次編譯。
問題解決了,當出現“0 Error(s), 0 Warning(s)”的時候也就意味著我們的程式已經通過了語法檢查,有時候一些Warning也不影響程式執行,但是我們要慎重對待,仔細分析每一個Warning。如果是源程式中有語法錯誤或者警告,我們可以通過雙擊輸出視窗的該行,快速定位到出錯的位置。
5.1.5 除錯程式
編譯通過只是說明我們的程式碼沒有語法錯誤,至於源程式中存在的其他錯誤,必須通過除錯才能發現並解決,事實上,除了極簡單的程式以外,絕大部分的程式都要通過反覆除錯才能得到正確的結果,因此,除錯是軟體開發接下來我們需要執行我們的程式來驗證是否達到了預期的目的。也就是程式除錯,程式除錯往往是程式開發過程中最難的階段,尤其是對一些比較大型的程式。下面我們就來看看uVision3對除錯的支援。
5.1.5.1 常用的除錯命令
在對工程成功進行彙編、連線之後,按Ctrl+F5或者使用選單Debug->Start/Stop Debug Session即可進入除錯狀態。進入除錯狀態後,介面與編輯狀態相比有明顯的變化,Debug才單項中原來不能用的命令現在已經可以使用了,工具欄會多出一個用於執行和除錯的工具欄,如下圖所示,Debug選單上的大部分命令可以在此找到對應的快捷按鈕。
常用的Debug選單命令如下所示:
Start/Stop Debug Session:開始或者停止除錯。
Run:一直執行下一個活動的斷點。
Step:單步執行。
Step Over:過程單步執行,即將一個函式作為一個語句來執行。
Step out of current Function:跳出當前的函式。
Run to Cursor line:執行到游標所在的行。
Stop Running:停止執行。
Breakpoints:開啟斷點對話方塊。
Insert/Remove Breakpoint:在當前行插入/刪除一個斷點。
Enable/Disable Breakpoint:啟用當前行的斷點或者使斷點無效。
Disable All Breakpoints:使程式中所有的斷點都無效。
Kill all Breakpoints:刪除程式中所有的斷點。
學習程式除錯,必須明確兩個重要的概念,即單步執行與全速執行。全速執行是指一行程式執行完了以後緊接著執行下一行程式,中間不停止,這樣程式執行的速度就很快,並可以看到該段程式執行的總體效果,即最終結果正確還是錯誤,但如果程式有錯,則難以確認錯誤出現在哪些程式行。單步執行是每次執行一行程式,執行完該行程式執行完以後即停止,等待命令執行下一行程式,此時我們可以觀察該行程式執行完以後得到的結果,是否與我們寫程式行所想要得的結果相同,藉此可以找到程式中問題所在。程式除錯中,這兩種執行方式都要用到,要靈活應用,可以大大提高除錯效率。
在除錯視窗中,我們可以看到一個黃色的除錯箭頭,指向了當前執行到的程式行。
5.1.5.2 斷點設定
程式除錯時,有些程式行往往很難確認什麼時候能夠執行到,這類問題就不適合單步除錯,這是我們需要使用程式除錯中另一種非常重要的方法——斷點設定。斷點設定的方法有多種,常用的是在某一程式行設定斷點,設定好斷點之後可以全速執行程式,一旦執行到該程式行即停止,可在此觀察有關的變數值,以確定問題所在。設定斷點的命令請參考上一節常用除錯命令介紹。一旦某一行被設定了斷點,我們可以在程式行的左端看到一個紅色方框(如圖5.24除錯視窗圖所示),如果該斷點被禁用,方框將會變為白色。
除了在某程式行設定斷點這一基本方法以外,uVision3還提供了多種設定斷點的方法,按Debug->Breakpoints,即出現一個對話方塊,該對話方塊用於對斷點進行詳細的設定,如下圖所示。
圖5.26中的Expression後的編輯框用於輸入表示式,該表示式用於確定程式停止執行的條件,功能強大,涉及到uVision3內建的一套除錯演算法,這裡不做詳細說明,請查閱相關幫助文件。
5.1.5.3 除錯視窗
前面講了除錯的一些方法,裡面多次提到檢查程式的執行狀態。除錯視窗就是用於檢視程式執行狀態的。uVision3提供了多種除錯視窗,如暫存器視窗,儲存器視窗,反彙編視窗,外設視窗等,下面將會一一作介紹。
1. 暫存器視窗
圖5.26是工程視窗暫存器頁的內容,暫存器頁包含了當前所有的工作暫存器和系統暫存器,每當程式中執行到對某個暫存器的操作時,該暫存器會反色顯示,用滑鼠單擊然後按F2(滑鼠連續單擊兩次),即可修改該值。
2. 儲存器視窗
儲存器視窗可以顯示系統中各種記憶體中的值,通過在Address後的編輯框中輸入“字母:數字”即可顯示相應記憶體值,其中字母C、D、I、X,分別代表程式碼儲存空間、直接定址的片記憶體儲空間、間接定址的片記憶體儲空間、擴充套件的外部RAM單元值、鍵入C:0即可顯示從0開始的ROM單元中的值,即檢視程式的二進位制程式碼。該視窗的顯示值可以以各種形式顯示,如十進位制、十六進位制、字元型等。改變顯示方式的方法是點滑鼠右鍵,在彈出的快捷選單中選擇。除了顯示,還可以修改記憶體中的值,如下圖所示。
3. 檢視和呼叫棧視窗
這個視窗可以幫助我們檢視當前呼叫樹的情況,我們還可以通過這個視窗檢視和修改一些變數的值。滑鼠停留在某個變數的時候點右鍵,在彈出的浮動選單中選擇Add ***to Watch window,Local 視窗顯示當前一些區域性變數的值,變數值的現實方式可以在十六進位制和十進位制之間切換,方式是在檢視視窗點右鍵,在某個變數的Value欄用滑鼠單擊然後按F2(滑鼠連續單擊兩次),即可修改該值。如下圖所示。
4. 反彙編視窗
點選View->Dissambly Window可以開啟反彙編視窗,該視窗可以顯示反彙編後的程式碼、原始碼和相應反彙編程式碼的混合程式碼,可以在該視窗進行線上彙編、利用該視窗跟蹤已找行的程式碼、在該視窗按彙編程式碼的方式單步執行。點選滑鼠右鍵,出現快捷選單,如圖5.29所示,其中Mixed Mode是以混合方式顯示,Assembly Mode是以返回編碼方式顯示。
5. 外設視窗
為了能夠比較直觀地瞭解微控制器中各種外設的使用情況,uVison3提供了一個外圍介面對話方塊。通過Peripherals選單,下拉選單中的內容和你選擇的晶片有關,會列出你所選擇的晶片上所有的外設。選擇一項你可以進入檢視或修改該外設的一些狀態。例如在這裡我們是通過GPIO中的PB9來控制LED閃爍,我們可以開啟GPIOB的狀態對換框,如圖5.30所示。
現在我們可以除錯我們的HelloWorld了。程式執行時,你將看到開發板上的L1不停閃爍。