本篇文章介紹了使用Keil來(lái)對(duì)STM32F103C8芯片進(jìn)行初始工程搭建,以及開(kāi)發(fā)與工程調(diào)試的完整過(guò)程,幫助讀者能夠在實(shí)戰(zhàn)中體會(huì)到Keil這個(gè)開(kāi)發(fā)環(huán)境的使用方法,了解一個(gè)嵌入式工程從無(wú)到有的過(guò)程,并且具備快速搭建一個(gè)全新芯片對(duì)應(yīng)最小軟件工程的基本能力思路。文章首先介紹了基礎(chǔ)工程搭建的過(guò)程,包括代碼的組織以及Keil嵌軟工程配置,然后講述了一個(gè)簡(jiǎn)單功能的開(kāi)發(fā),最后介紹了Keil環(huán)境下提供的代碼調(diào)試工具以及一些常用工具配置項(xiàng)。
目錄
Keil概念
工程搭建
代碼組織
Keil配置
開(kāi)發(fā)與調(diào)試
下載調(diào)試準(zhǔn)備
串口打印開(kāi)發(fā)?
代碼調(diào)試
Keil概念
Keil(全稱(chēng)Keil μVision IDE)是一款集成開(kāi)發(fā)環(huán)境(IDE),主要用于嵌入式系統(tǒng)的開(kāi)發(fā)。Arm Keil MDK(Microcontroller Development Kit)是面向基于Arm的微控制器的最全面的軟件開(kāi)發(fā)解決方案,包括創(chuàng)建、構(gòu)建和調(diào)試嵌入式應(yīng)用所需的所有組件。主要可以分為MDK(IDE以及芯片對(duì)應(yīng)編譯器等)、Softwarepacks(可以隨時(shí)添加軟件包,這使得新的設(shè)備支持和中間件更新獨(dú)立于工具鏈)、Debug Probes(MDK 支持許多不同的調(diào)試和跟蹤適配器)。
下面介紹一下后面工程搭建以及開(kāi)發(fā)調(diào)試涉及的相關(guān)概念。
-
STM32F10x_StdPeriph_Lib_V3.6.0:芯片底層庫(kù)文件,我們這里使用的是STM芯片F(xiàn)10系列,響應(yīng)的庫(kù)文件可以從ST官網(wǎng)找到,點(diǎn)擊這里可直接跳轉(zhuǎn)并下載。Libraries中主要包含CMSIS和STM32F10x_StdPeriph_Driver。Project中主要包含STM32F10x_StdPeriph_Template和STM32F10x_StdPeriph_Examples。,前者是,后者為不同芯片內(nèi)部外設(shè)使用示例。
- CMSIS:全稱(chēng)為Cortex Microcontroller Software Interface Standard,其中startup文件夾包含了對(duì)應(yīng)芯片類(lèi)型的啟動(dòng)代碼core_cm3.c,包括復(fù)位處理程序和異常向量;CoreSupport文件夾中包含了STM32F10系列芯片使用的Cortex-M3內(nèi)核外設(shè)接入層startup_stm32f10x_md.s(md表示芯片容量)。
- STM32F10x_StdPeriph_Driver:STM32F10系列標(biāo)準(zhǔn)的外設(shè)驅(qū)動(dòng)庫(kù),提供諸如ADC,CAN,GPIO等芯片內(nèi)外設(shè)驅(qū)動(dòng)。
- STM32F10x_StdPeriph_Template:工程必備的不同IDE文件以及相關(guān)代碼源文件模板,其中stm32f10x_conf.h包含了外設(shè)庫(kù)頭文件以及參數(shù)檢查宏定義,stm32f10x_it.c包含了所有的中斷服務(wù)函數(shù)定義,system_stm32f10x.c包含了芯片時(shí)鐘配置。
- STM32F10x_StdPeriph_Examples:芯片內(nèi)部外設(shè)不同的使用示例,可以根據(jù)實(shí)際項(xiàng)目使用參考終端服務(wù)函數(shù)以及main.c中的相關(guān)外設(shè)配置,例如您如果用到了3ADCs并使用DMA,則可以參考STM32F10x_StdPeriph_Examples\ADC\3ADCs_DMA下的代碼進(jìn)行配置。
- JLink仿真器:德國(guó)SEGGER公司推出基于JTAG的仿真器。簡(jiǎn)單地說(shuō),是給一個(gè)JTAG協(xié)議轉(zhuǎn)換盒,即一個(gè)小型USB到JTAG的轉(zhuǎn)換盒,其連接到計(jì)算機(jī)用的是USB接口,而到目標(biāo)板內(nèi)部用的還是jtag協(xié)議。它完成了一個(gè)從軟件到硬件轉(zhuǎn)換的工作。我們使用它連接電腦與板卡實(shí)現(xiàn)程序燒錄和在線(xiàn)調(diào)試。
工程搭建
代碼組織
建立工程文件夾,在工程文件夾下建立以下目錄結(jié)構(gòu),組織工程代碼(可根據(jù)公司規(guī)定對(duì)工程目錄結(jié)構(gòu)進(jìn)行統(tǒng)一修改)。
目錄名稱(chēng) | 存放文件 | 文件來(lái)源 |
Startup | startup_stm32f10x_md.s | STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\CMSIS\CM3\ DeviceSupport\ST\STM32F10x\startup\arm |
CMSIS | core_cm3.c、core_cm3.h | STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\CMSIS\CM3 \CoreSupport |
Libraries | 芯片外設(shè)標(biāo)準(zhǔn)庫(kù)文件 | STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\STM32F10x _StdPeriph_Driver |
App | 1.用戶(hù)編寫(xiě)的業(yè)務(wù)代碼,可根據(jù)業(yè)務(wù)創(chuàng)建子目錄。 2.main.c、stm32f10x_conf.h、stm32f10x_it.c、system_stm32f10x.c |
1.用戶(hù)編寫(xiě)/移植。 2.STM32F10x_StdPeriph_Lib_V3.6.0\Project\STM32F10x_ StdPeriph_Template |
Bulid | 用來(lái)存放編譯生成文件 | Keil編譯生成。 |
Keil配置
首先打開(kāi)Keil5,新建工程,芯片型號(hào)選擇STM32F103C8。隨后彈出在線(xiàn)添加庫(kù)文件,關(guān)閉即可。如下圖所示。
然后點(diǎn)擊三色塊用來(lái)添加工程目錄,并添加相關(guān)目錄,增加待編譯源文件。如下圖所示。
?最后,單擊魔術(shù)棒進(jìn)行配置,這部分的配置比較多,下面分步逐一進(jìn)行介紹。
- 配置目標(biāo)屬性,晶振等信息,因?yàn)槲椰F(xiàn)在用的單片機(jī)晶振為8M的,所以改為8M;下面調(diào)試需要用到printf函數(shù),需要勾選MicroLIB庫(kù)。
- 輸出文件夾改到Bulid文件夾,勾選生成hex文件。
- 修改編譯信息,包括添加條件編譯宏定義和頭文件路徑等。
- 配置Flash類(lèi)型。
最后,如果配置正確,相關(guān)的文件也都正確添加至工程內(nèi),編譯之后就會(huì)在Build Output看到生成了可以下載執(zhí)行的hex文件,如果沒(méi)有需要我們根據(jù)錯(cuò)誤信息來(lái)逐步解決。?
開(kāi)發(fā)與調(diào)試
下載調(diào)試準(zhǔn)備
首先我們需要安裝JLINK驅(qū)動(dòng)(segger上或者百度),如果驅(qū)動(dòng)安裝成功,將設(shè)備usb接口插到電腦上后,綠燈轉(zhuǎn)為常亮,電腦的設(shè)備管理在通用串行控制器中能夠識(shí)別到仿真器。然后我們需要按照J(rèn)TAG接口引腳定義正確將仿真器與板卡相連。
?
最后,我們需要在Keil中根據(jù)我們仿真器類(lèi)型正確配置Debug信息如下,并選擇相關(guān)仿真器窗口。
?
這是如果仿真器能夠正常連接到板卡,綠燈會(huì)閃爍,點(diǎn)擊Settings摁扭能看到識(shí)別到的芯片核心,如果不正常則會(huì)為空白。
?
串口打印開(kāi)發(fā)?
我們開(kāi)發(fā)一個(gè)串口打印的功能,因?yàn)橹皇且粋€(gè)demo,所以我們將串口初始化的部分也放到main.c里,下面是main.c的代碼。
#include "stm32f10x.h"
#include "usart.h"
void uart_init(u32 bound){
//GPIO端口設(shè)置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時(shí)鐘
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//搶占優(yōu)先級(jí)0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子優(yōu)先級(jí)1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器
//USART 初始化設(shè)置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長(zhǎng)為8位數(shù)據(jù)格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個(gè)停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//無(wú)奇偶校驗(yàn)位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無(wú)硬件數(shù)據(jù)流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開(kāi)啟串口接受中斷
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler(void)
{
u8 Data;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
{
Data = USART1->DR;
}
}
///重定向c庫(kù)函數(shù)printf到串口,重定向后可使用printf函數(shù)
int fputc(int ch, FILE *f)
{
/* 發(fā)送一個(gè)字節(jié)數(shù)據(jù)到串口 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待發(fā)送完畢 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
int main(void)
{
uart_init(9600);
while(1)
{
printf("STM32\n");
}
}
然后點(diǎn)擊編譯,生成可執(zhí)行文件之后點(diǎn)擊下載到板卡。
最后正確連接板卡上的串口線(xiàn)到串口小板(TTL轉(zhuǎn)USB),打開(kāi)串口調(diào)試助手,就能看到板卡打印出來(lái)的串口信息。
代碼調(diào)試?
點(diǎn)擊紅色那個(gè)上面有個(gè)紅色字母d的小放大鏡摁扭,就會(huì)下載程序并進(jìn)入仿真模式,這個(gè)時(shí)候程序停在起始位置。
?
?按照上圖的標(biāo)號(hào),我們介紹一下相關(guān)區(qū)域的作用。
- 重啟執(zhí)行摁扭:從左到右第一個(gè)為系統(tǒng)復(fù)位,程序回到起始位置并停止執(zhí)行。第二個(gè)為全速執(zhí)行摁扭,一般跟預(yù)先設(shè)置的斷點(diǎn)配合使用。
- 單步調(diào)試摁扭:從左到右依次是進(jìn)入執(zhí)行(會(huì)進(jìn)入調(diào)用函數(shù)),逐行執(zhí)行(不進(jìn)入調(diào)用函數(shù)),跳出執(zhí)行(執(zhí)行到跳出此函數(shù)),執(zhí)行到光標(biāo)處(執(zhí)行到藍(lán)色光標(biāo)處)。代碼走查常用。
- 寄存器窗口:這個(gè)串口可以看到ARM核心的一些特殊寄存器,不知道用法的可以移步到《【硬件】嵌入式電子設(shè)計(jì)基礎(chǔ)之單片機(jī)》文章去了解一下。這個(gè)頁(yè)簽中還有很多別的功能可供發(fā)掘,諸如可以通過(guò)system中的系統(tǒng)變量sec來(lái)查看程序運(yùn)行所用時(shí)間,將兩個(gè)地方的所用時(shí)間相減,即可得到所間隔的時(shí)長(zhǎng)。
- 匯編代碼窗口:當(dāng)前運(yùn)行程序?qū)?yīng)的匯編代碼行,可以在更細(xì)的層面調(diào)試程序。
-
C代碼窗口:黃色光標(biāo)指向當(dāng)前運(yùn)行到行,在左側(cè)深灰處雙擊即可添加斷點(diǎn),可以看到紅色小圓點(diǎn)
?。
- 命令窗口:Keil提供命令窗口可以在調(diào)試過(guò)程中執(zhí)行命令,諸如SAVE E:\Debug\DATA.txt 0x20004A18,0x20004A3A這段命令即可將0x20004A18~0x20004A3A這段內(nèi)存區(qū)存儲(chǔ)到文件中。
- 調(diào)用棧:調(diào)用棧信息顯示了當(dāng)前代碼處的完整調(diào)用關(guān)系,有的時(shí)候當(dāng)在中斷服務(wù)函數(shù)中時(shí),無(wú)法看到進(jìn)入中斷之前的調(diào)用棧信息,需要結(jié)合其他寄存器信息直接從??臻g中查找相關(guān)調(diào)用信息。
還有一些比較常用的調(diào)試窗口。memory窗口可以看指定區(qū)域的存儲(chǔ)器數(shù)值,正如上面提到的存儲(chǔ)指令,我們也可以通過(guò)memory窗口看到對(duì)應(yīng)的內(nèi)容。
?
還有就是Watch窗口,可以添加一些變量,在調(diào)試過(guò)程中觀(guān)察變量的變化。
?
最后一個(gè)常用的就是系統(tǒng)外設(shè)窗口,在調(diào)試過(guò)程中可以看到具體對(duì)應(yīng)外設(shè)的寄存器值。
?
Keil環(huán)境補(bǔ)充說(shuō)明
keil默認(rèn)無(wú)法顯示中文,輸入中文時(shí),出現(xiàn)的是問(wèn)號(hào)??梢詫dit-->Configuration中的編碼改成GB2312解決這個(gè)問(wèn)題,同時(shí)在這個(gè)頁(yè)簽中可以將Tab設(shè)置為4個(gè)空格。在Configuration還有更多諸如字體等環(huán)境配置,讀者可以根據(jù)自己的喜好來(lái)進(jìn)行調(diào)整。
十六宿舍 原創(chuàng)作品,轉(zhuǎn)載必須標(biāo)注原文鏈接。
?2023 Yang Li. All rights reserved.文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-745831.html
歡迎關(guān)注?『十六宿舍』,大家喜歡的話(huà),給個(gè)??,更多關(guān)于嵌入式相關(guān)技術(shù)的內(nèi)容持續(xù)更新中。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-745831.html
到了這里,關(guān)于【嵌入式開(kāi)發(fā)工具】STM32+Keil實(shí)現(xiàn)軟件工程搭建與開(kāi)發(fā)調(diào)試的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!