目錄
- 1 時鐘系統結構圖
- 2 STM32時鐘系統(一)
- 3 STM32時鐘系統(二)
- 4 RCC寄存器
- 4.1 時鐘控制寄存器(RCC_CR)
- 4.2 時鐘配置寄存器(RCC_CFGR)
- 4.3 時鐘中斷寄存器(RCC_CIR)
- 4.4 APB2外設復位寄存器(RCC_APB2RSTR)
- 4.5 APB1外設復位寄存器(RCC_APB1RSTR)
- 4.6 AHB外設時鐘使能寄存器(RCC_AHBENR)
- 4.7 APB2外設時鐘使能寄存器(RCC_APB2ENR)
- 4.8 APB1外設時鐘使能寄存器(RCC_APB1ENR)
- 4.9 備份域控制寄存器(RCC_BDCR)
- 4.10 控制/狀態寄存器(RCC_CSR)
- 4.11 AHB外設時鐘復位寄存器(RCC_AHBRSTR)
- 4.12 時鐘配置寄存器2(RCC_CFGR2)
- 4.13 RCC寄存器地址映像
- 5 時鐘系統初始化C語言代碼實現
- 6 結束
1 時鐘系統結構圖
2 STM32時鐘系統(一)
2.1 各個時鐘源
① STM32有5個時鐘源:HSI、HSE、 LSI、 LSE、 PLL
- HSI是高速內部時鐘,RC振盪器,頻率爲8MHz,精度不高
- HSE是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率範圍爲4MHz ~ 16MHz
- LSI是低速內部時鐘,RC振盪器,頻率爲40kHz,提供低功耗時鐘
- LSE是低速外部時鐘,接頻率爲32.768kHz的石英晶體
- PLL爲鎖相環倍頻輸出,其時鐘輸入源可選擇爲HSI/2、HSE或者HSE/2,倍頻可選擇爲2~16倍,但是其輸出頻率最大不得超過72MHz
② 系統時鐘SYSCLK可來源於三個時鐘源:
- HSI振盪器時鐘
- HSE振盪器時鐘
- PLL時鐘
④ 舉例: Keil編寫程序是默認的時鐘爲72Mhz:
- 外部晶振(HSE)提供的8MHz,通過PLLXTPRE分頻器
- 進入PLLSRC選擇開關,通過PLLMUL鎖相環進行倍頻(x9),爲系統提供72MHz的系統時鐘(SYSCLK)
- AHB預分頻器對時鐘信號進行分頻,爲低速外設提供時鐘
③ 注意:
- 獨立時鐘源爲4個,因爲PLL本身不能提供時鐘
- LSI一般作爲IWDGCLK(獨立看門狗)時鐘源和RTC時鐘源
- 系統時鐘最大頻率爲72MHz
2.2 時鐘信號輸出到外部
STM32可以選擇一個時鐘信號輸出到MCO腳(PA8)上,可以選擇爲PLL輸出的2分頻、HSI、HSE、或者系統時鐘。可以把時鐘信號輸出供外部使用
2.3 AHB分頻器
系統時鐘通過AHB分頻器給外設提供時鐘,系統時鐘 -> AHB分頻器 -> 各個外設分頻倍頻器 -> 外設時鐘的設置
AHB分頻器可選擇1、2、4、8、16、64、128、256、512分頻,輸出的時鐘輸送給5大模塊使用:
- 內核總線:輸送給AHB總線、內核、內存和DMA使用的HCLK時鐘
- Tick定時器:通過8分頻後送給Cortex的系統定時器時鐘
- I2S總線:直接送給Cortex的空閒運行時鐘FCLK
- APB1外設:送給APB1分頻器。APB1分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB1外設使用(PCLK1,最大頻率36MHz),另一路送給通用定時器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器2-7使用
- APB2外設:送給APB2分頻器。APB2分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB2外設使用(PCLK2,最大頻率72MHz),另一路送給高級定時器。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器1和定時器8使用
2.4 APB1和APB2的對應外設
APB1上面連接的是低速外設,包括電源接口、備份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等
而APB2上面連接的是高速外設,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等
3 STM32時鐘系統(二)
3.1 時鐘安全系統(CSS)
如果HSE時鐘發生故障,HSE振盪器被自動關閉,時鐘失效事件將被送到高級定時器(TIM1和TIM8)的剎車輸入端,併產生時鐘安全中斷CSSI,允許軟件完成營救操作。此CSSI中斷連接到Cortex™-M3的NMI中斷(不可屏蔽中斷)
一旦CSS被激活,並且HSE時鐘出現故障,CSS中斷就產生,並且NMI也自動產生。NMI將被不斷執行,直到CSS 中斷掛起位被清除。因此,在NMI的處 理程序中必須通過設置時鐘中斷寄存器(RCC_ CIR) 裏的CSSC位來清除CSS中斷
如果HSE振盪器被直接或間接地作爲系統時鐘,(間接的意思是:它被作爲PLL輸入時鐘或通過PLL2,並且PLL時鐘被作爲系統時鐘),時鐘故障將導致系統時鐘自動切換到HSI振盪器,同時外部HSE振盪器被關閉。在時鐘失效時,如果HSE振盪器時鐘(直接的或通過PLL2)是作爲PLL的輸入時鐘,PLL也將被關閉
3.2 RTC時鐘
通過設置 備份域控制寄存器(RCC_BDCR)裏的RTCSEL[1:0]位,RTCCLK時鐘源可以由HSE/128、LSE或LSI時鐘提供
3.3 看門狗時鐘
如果獨立看門狗已經由硬件選項或軟件啓動,LSI振盪器將被強制在打開狀態,並且不能被關閉。在LSI振盪器穩定後,時鐘供應給IWDG
3.4 USB時鐘
STM32中有一個全速功能的USB模塊,其串行接口引擎需要一個頻率爲48MHz的時鐘源。該時鐘源只能從PLL輸出端獲取(唯一的),可以選擇爲1.5分頻或者1分頻,也就是,當需要使用USB模塊時,PLL必須使能,並且時鐘頻率配置爲48MHz或72MHz
4 RCC寄存器
4.1 時鐘控制寄存器(RCC_CR)
4.2 時鐘配置寄存器(RCC_CFGR)
4.3 時鐘中斷寄存器(RCC_CIR)
4.4 APB2外設復位寄存器(RCC_APB2RSTR)
4.5 APB1外設復位寄存器(RCC_APB1RSTR)
4.6 AHB外設時鐘使能寄存器(RCC_AHBENR)
4.7 APB2外設時鐘使能寄存器(RCC_APB2ENR)
4.8 APB1外設時鐘使能寄存器(RCC_APB1ENR)
4.9 備份域控制寄存器(RCC_BDCR)
4.10 控制/狀態寄存器(RCC_CSR)
4.11 AHB外設時鐘復位寄存器(RCC_AHBRSTR)
4.12 時鐘配置寄存器2(RCC_CFGR2)
4.13 RCC寄存器地址映像
5 時鐘系統初始化C語言代碼實現
參考正點原子STM32F103教程寄存器版本代碼
工程下載鏈接:鏈接: https://pan.baidu.com/s/1fBTO_HOrW13mPI97cJkqJg 提取碼: jywj
步驟:
定義一個RCC結構體指針,按照RCC_TypeDef類型指向RCC的基地址;STM32訪問寄存器的方式是通過基地址加偏移地址來實現的
/*
C語言書籍這樣定義volatile關鍵字:volatile提醒編譯器它後面所定義的變量隨時都有可能改變,因此編譯後的程序每次需要存儲或
讀取這個變量的時候,告訴編譯器對該變量不做優化,都會直接從變量內存地址中讀取數據,從而可以提供對特殊地址的穩定訪
問。。如果沒有volatile關鍵字,則編譯器可能優化讀取和存儲,可能暫時使用寄存器中的值,如果這個變量由別的程序更新了的
話,將出現不一致的現象。(簡潔的說就是:volatile關鍵詞影響編譯器編譯的結果,用volatile聲明的變量表示該變量隨時可能發
生變化,與該變量有關的運算,不要進行編譯優化,以免出錯)
*/
#define __IO volatile /*!< defines 'read / write' permissions */
typedef unsigned int uint32_t;
//所有外設基地址
#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
//AHB總線基地址
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
//RCC寄存器基地址
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
//使用這個結構體,不用再給每一個寄存器初始化其物理地址
//只需要知道RCC寄存器地址即可,利用了結構體對齊的優點
//即指針只要指過來,就可以訪問到該寄存器實際地址了
//參考本文的 4.13 -> RCC寄存器地址映像 左邊兩列
typedef struct
{
__IO uint32_t CR; ////HSI,HSE,CSS,PLL等的使能和就緒標誌位,用於等待時鐘開始和穩定
__IO uint32_t CFGR; ////PLL等的時鐘源選擇,分頻係數設定
__IO uint32_t CIR; //// 清除/使能 時鐘就緒中斷
__IO uint32_t APB2RSTR; //APB2線上外設復位寄存器
__IO uint32_t APB1RSTR;//APB1線上外設復位寄存器
__IO uint32_t AHBENR;//DMA,SDIO等時鐘使能
__IO uint32_t APB2ENR; //APB2線上外設時鐘使能
__IO uint32_t APB1ENR; //APB1線上外設時鐘使能
__IO uint32_t BDCR; //備份域控制寄存器
__IO uint32_t CSR; //控制狀態寄存器
} RCC_TypeDef;
#define RCC ((RCC_TypeDef *) RCC_BASE)
定義一個函數來複位初始化所有時鐘寄存器、配置向量表
//不能在這裏執行所有外設復位!否則至少引起串口不工作.
//把所有時鐘寄存器復位
void MYRCC_DeInit(void)
{
RCC->APB1RSTR = 0x00000000;//復位
RCC->APB2RSTR = 0x00000000;//復位
RCC->AHBENR = 0x00000014; //睡眠模式閃存和SRAM時鐘使能.其他關閉.
RCC->APB2ENR = 0x00000000; //外設時鐘關閉.
RCC->APB1ENR = 0x00000000;
RCC->CR |= 0x00000001; //使能內部高速時鐘HSION,系統默認
RCC->CFGR &= 0xF8FF0000; //復位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]
RCC->CR &= 0xFEF6FFFF; //復位HSEON,CSSON,PLLON
RCC->CR &= 0xFFFBFFFF; //復位HSEBYP
RCC->CFGR &= 0xFF80FFFF; //復位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
RCC->CIR = 0x00000000; //關閉所有中斷
//配置向量表
#ifdef VECT_TAB_RAM
MY_NVIC_SetVectorTable(0x20000000, 0x0);
#else
MY_NVIC_SetVectorTable(0x08000000,0x0);
#endif
}
定義一個可供調用的系統時鐘初始化函數
//系統時鐘初始化函數
//pll:選擇的倍頻數,從2開始,最大值爲16
void Stm32_Clock_Init(u8 PLL)
{
unsigned char temp=0;
MYRCC_DeInit(); //復位並配置向量表
RCC->CR|=0x00010000; //外部高速時鐘使能HSEON
while(!(RCC->CR>>17));//等待外部時鐘就緒(位17 值1:外部4-16MHz振盪器就緒)
RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
PLL-=2; //抵消2個單位(因爲是從2開始的,設置0就是2)
RCC->CFGR|=PLL<<18; //設置PLL值 2~16
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x32; //FLASH 2個延時週期
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));//等待PLL鎖定
RCC->CFGR|=0x00000002;//PLL作爲系統時鐘
while(temp!=0x02) //等待PLL作爲系統時鐘設置成功
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
}
在main函數調用,設置系統時鐘爲72MHz
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
int main(void)
{
Stm32_Clock_Init(9); //系統時鐘設置
delay_init(72); //延時初始化
LED_Init(); //初始化與LED連接的硬件接口
while(1)
{
LED0=0;
LED1=1;
delay_ms(300);
LED0=1;
LED1=0;
delay_ms(300);
}
}
6 結束
如有錯誤,還望指正🤞