從時鐘樹的分析,看到經過一系列的倍頻、分頻後得到了幾個與我們開發密切相關的時鐘。
SYSCLK:系統時鐘,STM32大部分器件的時鐘來源。主要由AHB預分頻器分配到各個部件。
HCLK:由AHB預分頻器直接輸出得到,它是高速總線AHB的時鐘信號,提供給存儲器,DMA及cortex內核,是cortex內核運行的時鐘,cpu主頻就是這個信號,它的大小與STM32運算速度,數據存取速度密切相關。
FCLK:同樣由AHB預分頻器輸出得到,是內核的“自由運行時鐘”。“自由”表現在它不來自時鐘 HCLK,因此在HCLK時鐘停止時 FCLK 也繼續運行。它的存在,可以保證在處理器休眠時,也能夠採樣和到中斷和跟蹤休眠事件 ,它與HCLK互相同步。
PCLK1:外設時鐘,由APB1預分頻器輸出得到,最大頻率爲36MHz,提供給掛載在APB1總線上的外設。
PCLK2:外設時鐘,由APB2預分頻器輸出得到,最大頻率可爲72MHz,提供給掛載在APB2總線上的外設。
爲什麼STM32的時鐘系統如此複雜,有倍頻、分頻及一系列的外設時鐘的開關。需要倍頻是考慮到電磁兼容性,如外部直接提供一個72MHz的晶振,太高的振盪頻率可能會給製作電路板帶來一定的難度。分頻是因爲STM32既有高速外設又有低速外設,各種外設的工作頻率不盡相同,如同pc機上的南北橋,把高速的和低速的設備分開來管理。最後,每個外設都配備了外設時鐘的開關,當我們不使用某個外設時,可以把這個外設時鐘關閉,從而降低STM32的整體功耗。所以,當我們使用外設時,一定要記得開啓外設的時鐘啊,親。
注意:3.5版本的庫在啓動文件中調用了SystemInit(),所以不必在main()函數中再次調用。但如果使用的是3.0版本的庫則必須在main函數中調用SystemInit(),以設置系統時鐘,因爲在3.0版本的啓動代碼中並沒有調用SystemInit()函數。(具體可以參考啓動代碼)
如果我們用到了I/O的引腳複用功能,還要開啓其複用功能時鐘。
如GPIOC的Pin4還可以作爲ADC1的輸入引腳,現在我們把它作爲ADC1來使用,除了開啓GPIOC時鐘外,還要開啓ADC1的時鐘:
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE);
/*
LED.H
*/
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
/* the macro definition to trigger the led on or off
* 1 - off
- 0 - on
*/
#define ON 0
#define OFF 1
//帶參宏,可以像內聯函數一樣使用
#define LED1(a) if (a) \
GPIO_SetBits(GPIOC,GPIO_Pin_3);\
else \
GPIO_ResetBits(GPIOC,GPIO_Pin_3)
#define LED2(a) if (a) \
GPIO_SetBits(GPIOC,GPIO_Pin_4);\
else \
GPIO_ResetBits(GPIOC,GPIO_Pin_4)
#define LED3(a) if (a) \
GPIO_SetBits(GPIOC,GPIO_Pin_5);\
else \
GPIO_ResetBits(GPIOC,GPIO_Pin_5)
void LED_GPIO_Config(void);
#endif /* __LED_H */
這個頭文件(led.h)的內容不多,但也把它獨立成一個頭文件,方便以後擴展或移植使用。希望讀者養成良好的工程習慣,在寫頭文件的時候,加上類似以下這樣的條件編譯。
#ifndef __LED_H
#define __LED_H
……
#endif
這樣可以防止頭文件重複包含,使得工程的兼容性更好。讀者問爲什麼要加兩個下劃線”__” ?在這裏加兩個下劃線可以避免這個宏標識符與其它定義重名,因爲在其它部分代碼定義的宏或變量,一般都不會出現這樣有下劃線的名字。
規範的位操作方法
由於庫函數的實現涉及到不少位操作,首先爲讀者介紹一下幾個常用的位操作方法,排除閱讀代碼的障礙。
1、將char型變量a的第七位(bit6)清0,其它位不變。
a &= ~(1<<6); //括號內1左移6位,得二進制數:0100 0000
//按位取反,得1011 1111 ,所得的數與a作”位與&”運算,
// a的第7位(bit6)被置零,而其它位不變。
2、同理,將變量a的第七位(bit6)置1,其它位不變的方法如下。
a |= (1<<6); //把第七位(bit6)置1,其它爲不變
3、將變量a的第七位(bit6)取反,其它位不變。
a ^=(1<<6); //把第七位(bit6)取反,其它位不變 ( ^ 爲抑或符號)