STM32之一步一步點(diǎn)亮led
入手stm32以來,一直想快速上手,所以在各大論壇閑逛,各個達(dá)人的blog上學(xué)習(xí),正所謂欲速則不達(dá),心急是吃不了熱豆腐的!有木有?
最終決定使用st官網(wǎng)的庫開發(fā),據(jù)大俠們寫道使用庫可以快速上手,貌似的確如此,一個個教程寫的那么好,直接拿過來用就是了??墒悄敲炊鄠€庫,聰明的你請告訴到底選擇哪一個???My God!實(shí)話實(shí)說,我被這些庫折騰了個夠!好吧,我最后還是承認(rèn)最后用的是v3.4的庫,是很方便!
切入正題,點(diǎn)亮LED。
硬件:紅牛開發(fā)板,STM32F103ZET6(144封裝).
軟件:RealView MDK 4.12
stm32固件庫:v3.4 附上自己整理后的庫:V3.4_clean.rar
根據(jù)官網(wǎng)庫自己整理了下,新建了工程模板如下圖:(主要參考文章《在KeilMDK+環(huán)境下使用STM32V3.4庫.pdf》)在KeilMDK+環(huán)境下使用STM32V3.4庫.pdf
入圖所示:新建一個目錄01_ProLed,建議放在英文路徑下,避免不必要的麻煩。將上面的庫v3.4解壓到此目錄,再新建一個project目錄,存放工程。
說明:
CMSIS:最底層接口。StartUp:系統(tǒng)啟動文件。StdPeriph_Lib:stm32外圍設(shè)備驅(qū)動文件。Project:工程文件。User:用戶文件。新建工程步驟:此處略去300字。
簡單說明:
1.core_cm3.c/core_cm3.h
該文件是內(nèi)核訪問層的源文件和頭文件,查看其中的代碼多半是使用匯編語言編寫的。在線不甚了解。--摘自《在KeilMDK+環(huán)境下使用STM32V3.4庫》
2.stm32f10x.h
該文件是外設(shè)訪問層的頭文件,該文件是最重要的頭文件之一。就像51里面的reg51.h一樣。例如定義了 CPU是哪種容量的 CPU,中斷向量等等。除了這些該頭文件還定義了和外設(shè)寄存器相關(guān)的結(jié)構(gòu)體,例如:
typedef struct
{
__IO uint32_t CR;
__IO uint32_t CFGR;
__IO uint32_t CIR;
__IO uint32_t APB2RSTR;
__IO uint32_t APB1RSTR;
__IO uint32_t AHBENR;
__IO uint32_t APB2ENR;
__IO uint32_t APB1ENR;
__IO uint32_t BDCR;
__IO uint32_t CSR;
#ifdef STM32F10X_CL
__IO uint32_t AHBRSTR;
__IO uint32_t CFGR2;
#endif/*STM32F10X_CL*/
#ifdefined(STM32F10X_LD_VL)||defined(STM32F10X_MD_VL)||defined(STM32F10X_HD_VL)
uint32_t RESERVED0;
__IO uint32_t CFGR2;
#endif/*STM32F10X_LD_VL||STM32F10X_MD_VL||STM32F10X_HD_VL*/
}RCC_TypeDef;
包含了那么多寄存器的定義,那么在應(yīng)用文件中(例如自己編寫的 main 源文件)只需要包含
stm32f10x.h即可,而不是以前固件庫的需要包含 stm32f10x_conf.h這個頭文件。--摘自《在KeilMDK+環(huán)境下使用STM32V3.4庫》
3.system_stm32f10x.c/h
該頭文件也可以稱為外設(shè)訪問層的頭文件和源文件。在該文件中可以定義系統(tǒng)的時鐘頻率,定義低速時鐘
總線和高速時鐘總線的頻率,其中最關(guān)鍵的函數(shù)就是 SystemInit()了,這個后面會詳細(xì)介紹??傊@兩
個文件是新固件庫的重點(diǎn),有了它糧也大大簡化了使用 stm32的初始化工作。--摘自《在KeilMDK+環(huán)境下使用STM32V3.4庫》
4.stm32f10x_conf.h
這個文件和 V2 版本的庫的內(nèi)容是一樣的,需要使用哪些外設(shè)就取消哪些外設(shè)的注釋。例如需要使用 GPIO功能,但不使用 SPI功能,就可以這樣操作。--摘自《在KeilMDK+環(huán)境下使用STM32V3.4庫》
#include"stm32f10x_gpio.h"
/*#include"stm32f10x_spi.h"*/
5.main.c
這個文件就不用多說了,自己編寫。--摘自《在KeilMDK+環(huán)境下使用STM32V3.4庫》
6.stm32f10x_it.c/h
這兩個文件包含了 stm32中斷函數(shù),在源文件和頭文件中并沒有把所有的中斷入口函數(shù)都寫出來,而
只寫了 ARM內(nèi)核的幾個異常中斷,其他的中斷函數(shù)需要用戶自己編寫。--摘自《在KeilMDK+環(huán)境下使用STM32V3.4庫》
OK,開始寫代碼了。
由于3.4的庫在啟動的時候已經(jīng)設(shè)置好時鐘了(將在后面有講述),所以我們只需設(shè)置好對應(yīng)的GPIO即可。
查看硬件連接:
來點(diǎn)亮PF6.
新建led.c與led.h,添加到User Code下面。
led.h
#ifndef _LED_H_
#define _LED_H_
void Delay(uint32_t times);
void LedInit(void);
#endif
led.c
#include"stm32f10x.h"
/************************************************************************
*函數(shù)名:LedInit(void)
*描述:
*輸入 :無
*輸出 :無
*返回 :無
************************************************************************/
void LedInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*初始化 GPIOF的 Pin_6為推挽輸出*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOF,&GPIO_InitStructure);
}
/************************************************************************
*函數(shù)名:Delay(uint32_t times)
*描述:延時函數(shù)
*輸入 :uint32_t times
*輸出 :無
*返回 :無
************************************************************************/
void Delay(uint32_t times)
{
while(times--)
{
uint32_t i;
for(i=0;i<0xffff;i++)
;
}
}
在main.c中加入led初始化與點(diǎn)亮關(guān)閉即可。
/*!
thisisdone through SystemInit()functionwhichiscalled from startup
file(startup_stm32f10x_xx.s)beforetobranchtoapplication main.
Toreconfigure the default setting of SystemInit()function,referto
system_stm32f10x.c file
*/
/*Add your application code here
*/
/*初始化 GPIOF時鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);
LedInit();
/*Infiniteloop*/
while(1)
{
/*關(guān)閉 LED1*/
GPIO_SetBits(GPIOF,GPIO_Pin_6);
/*延時*/
Delay(50);
/*點(diǎn)亮 LED1*/
GPIO_ResetBits(GPIOF,GPIO_Pin_6);
/*延時*/
Delay(50);
}
認(rèn)真學(xué)習(xí)下這段代碼,其實(shí)也非常簡單,參考自《在KeilMDK+環(huán)境下使用STM32V3.4庫》。我想請大家注意的是前面的一段英文注釋,這段英文注釋什么意思呢?!霸谶\(yùn)行 main 函數(shù)之前,系統(tǒng)時鐘已經(jīng)完成初始化工作,在main函數(shù)之前,通過調(diào)用啟動代碼運(yùn)行了 SystemInit函數(shù),而這個函數(shù)位于system_stm32f10x.c”。根據(jù)文中的提示我們回到 system_stm32f10x.c 看看 SystemInit如何初始化系統(tǒng)的。在 system_stm32f10x.c 的開頭便定義了系統(tǒng)的時鐘頻率,從下面的這段代碼可以看出系統(tǒng)的頻率被定
義為 72MHZ,這也是絕大多數(shù) STM32運(yùn)行時的頻率。
#ifdefined(STM32F10X_LD_VL)||(defined STM32F10X_MD_VL)||(defined STM32F10X_HD_VL)
/*#define SYSCLK_FREQ_HSE HSE_VALUE*/
#define SYSCLK_FREQ_24MHz 24000000
#else
/*#define SYSCLK_FREQ_HSE HSE_VALUE*/
/*#define SYSCLK_FREQ_24MHz 24000000*/
/*#define SYSCLK_FREQ_36MHz 36000000*/
/*#define SYSCLK_FREQ_48MHz 48000000*/
/*#define SYSCLK_FREQ_56MHz 56000000*/
#define SYSCLK_FREQ_72MHz 72000000
#endif
緊接著根據(jù)這個宏定義程序試圖把系統(tǒng)時鐘初始化為 72MHz,代碼有點(diǎn)冗長,這里就不一一列出。在
SystemInit 函數(shù)中,調(diào)用了 SetSysClock 函數(shù),如果設(shè)定時鐘的頻率為 72MHZ 則 SetSysCloc 調(diào)用
SetSysClockTo72函數(shù),該函數(shù)和 V2 版本固件庫中的各范例中的 RCC_Configuration很相似,主要完
成把外部時鐘 9 倍頻后分配給系統(tǒng)時鐘,APB1 時鐘和 APB2又由系統(tǒng)時鐘分頻獲得。關(guān)鍵代碼如下:
/*HCLK=SYSCLK*/
RCC->CFGR|=(uint32_t)RCC_CFGR_HPRE_DIV1;
/*PCLK2=HCLK*/
RCC->CFGR|=(uint32_t)RCC_CFGR_PPRE2_DIV1;
/*PCLK1=HCLK*/
RCC->CFGR|=(uint32_t)RCC_CFGR_PPRE1_DIV2;
從上面的分析可以看出,SystemInit 并不需要用戶調(diào)用,啟動代碼會自動執(zhí)行,這樣相當(dāng)于少了一
個 RCC_Configuration 函數(shù)的絕大多數(shù)內(nèi)容。請大家注意是絕大多數(shù)內(nèi)容而不是全部,但是請大家格外
注意使用到的外設(shè)還是要第一時間使得該外設(shè)的時鐘,像這樣的一句千萬不要忘了
/*初始化 GPIOF時鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);