復(fù)位
系統(tǒng)復(fù)位
系統(tǒng)復(fù)位有5個來源
- NRST引腳的低電平
- IWDG
- WWDG
- 軟件復(fù)位SW
- 低功耗管理復(fù)位
如果設(shè)置了nRST_STDBY和nRST_STOP=1,則進入待機和停止模式時,將產(chǎn)生復(fù)位。- 在進入待機模式時產(chǎn)生復(fù)位
- 進入停止模式時產(chǎn)生復(fù)位
可以通過查看寄存器來知道復(fù)位的來源
電源復(fù)位
產(chǎn)生電源復(fù)位可能是上電和掉電,POR/PDR或者是從待機模式返回,芯片內(nèi)部有一個20us的脈沖發(fā)出,此時可以保證芯片的復(fù)位。
備份域復(fù)位
備份區(qū)域的復(fù)位只影響備份區(qū)域,可以通過軟件,或者VDD和VBAT兩者都掉電的時候進行復(fù)位,這就是為什么要進行備份重啟時,我們要取掉電池。
時鐘
- 三種時鐘可以驅(qū)動系統(tǒng)時鐘,HSE,HSI和PLL,內(nèi)部有一個40KHZ的RC,用來保證看門狗的時鐘RTC,RTC在停機后的自動喚醒。另外驅(qū)動RTC的時鐘也可以選擇內(nèi)部的32.768KHZ的時鐘。
-
簡單來說,外部的高速時鐘就是晶振,低速時鐘是32.768時鐘,而內(nèi)部的高速時鐘是8M,低速時鐘是40KHZ。
RCC1.png
HSE時鐘
外部高速時鐘可以直接輸入時鐘,或者用晶振產(chǎn)生。
HSI時鐘
時鐘的精度不夠,并且最大只有64M,不太推薦使用。
PLL
如果要用到USB接口,時鐘必須設(shè)置為48M或者72M,可以優(yōu)先選擇72M
LSE
32.768KHZ的時鐘,啟動以后,要等待釋放信號再進行下一步,和上面的晶振的要求一樣。也可以用外部的32.768來提供,此時為旁路模式。
LSI
內(nèi)部的低速時鐘主要用于產(chǎn)生低功耗,在停機和待機模式下運行,提供看門狗和喚醒時鐘。所有的內(nèi)部時鐘都有一個校準(zhǔn),可以用TIM5來進行校準(zhǔn)。
系統(tǒng)時鐘選擇
系統(tǒng)復(fù)位后,HSI被選擇為系統(tǒng)時鐘,這個時候如果我們用到了HSE,需要進行切換。
時鐘安全系統(tǒng)
如果系統(tǒng)出現(xiàn)故障,比如外部時鐘壞了,此時首先關(guān)閉高級定時器的剎車,放置出現(xiàn)燒毀器件,同時將外部時鐘通道關(guān)閉,并自動的切換到內(nèi)部時鐘。
RTC時鐘
RTC是重要的時鐘源,可以有三個來源,內(nèi)部40K,外部32.768K和外部高速時鐘的分頻。
- 32.768時鐘時,重要電池還可以用,RTC都會運行
- 內(nèi)部40K,此時VDD如果沒電,不能保證提供。
- 外部高速時鐘分頻:當(dāng)然不工作啦。
看門狗時鐘
如果看門狗啟動,40K的時鐘強制打開。
時鐘輸出
如果設(shè)置為72M,相當(dāng)于可以通過GPIO給外面輸出:
- 72M
- 晶振時鐘
- 8M
- PLL/2時鐘
我們先來看一個典型的時鐘配置的程序調(diào)用。
- 在MAIN函數(shù)中,最先調(diào)用BSP_Init
- 在BSP中,最先進行SystemInit
- 系統(tǒng)初始化函數(shù)中,調(diào)用了SetSysClock函數(shù),里面根據(jù)不同的SYSCLK_FREQ_HSE調(diào)用了SetSysClockToHSE();
- 如果調(diào)用的是SetSysClockTo72,將時鐘設(shè)置為72M
時鐘都在system_stm32f10x.h里面進行了設(shè)置,標(biāo)準(zhǔn)的RCC庫函數(shù)還有如下的函數(shù)可以使用:另外,還需要特別注意一下的符號的意義:
- PCLK1 最大36,APB1的時鐘
- PCLK2 最大72M,APB2的時鐘
- HCLK 提供給外設(shè)的時鐘,最大72M
- SYSCLK 經(jīng)AHB分頻以后給HCLK,最大為72M
ADC時鐘配置:ADCCLKConfig
分頻設(shè)置
AdjustHSICalibrationValue
內(nèi)部高速時鐘校準(zhǔn),內(nèi)部時鐘不準(zhǔn)。
AHBPeriphClockCmd
外設(shè)時鐘設(shè)置,其中APB1PeriphClockCmd 和 APB2包括了哪些外設(shè),要稍微留意一下。
備份寄存器復(fù)位:BackupResetCmd
清復(fù)位源的標(biāo)志:ClearFlag
清中斷ClearITPendingBit
如果設(shè)置時鐘的中斷, 比如:RCC_IT_LSIRDY: LSI ready interrupt
安全系統(tǒng)開啟:ClockSecuritySystemCmd
去初始化DeInit
獲取時鐘頻率GetClocksFreq
包括ADC,HCLK,PCLK1,PCLK2,SYSCLK
GetFlagStatus
GetITStatus
獲取系統(tǒng)時鐘源GetSYSCLKSource
HCLKConfig
也就是SYSCLK到HCLK的分頻
HSEConfig LSEConfig
旁路還是用晶振
HSICmd LSICmd
內(nèi)部8M是否使能
ITConfig
時鐘輸出:MCOConfig
PCLK1Config 外設(shè)時鐘設(shè)置
PLLCmd PLL是否使能 PLLConfig
RTCCLKConfig RTCCLKCmd
三個時鐘源
SYSCLKConfig 系統(tǒng)時鐘
USBCLKConfig
WaitForHSEStartUp 等待晶振穩(wěn)定
我們?yōu)榱朔乐咕д駢牧硕鴮?dǎo)致系統(tǒng)直接掛調(diào),可以設(shè)置一個RCC_USEHSI,再一次強調(diào),此時鐘又慢又不準(zhǔn)!
void RCC_USEHSI(void)
{
GPIO_InitTypeDef X;
//PD0 PD1分配時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE ); //對端口D分配APB2高速時鐘,并開啟端口 重映射OSC_IN(PD0) OSC_OUT(PD1)
//PD0_OSC_IN
X.GPIO_Pin = GPIO_Pin_0; //對要使用的端口引腳設(shè)定
X.GPIO_Mode = GPIO_Mode_Out_PP; //對要使用的端口引腳模式設(shè)定PP為推挽輸出
X.GPIO_Speed = GPIO_Speed_50MHz; //對要使用的端口引腳頻率設(shè)定50MHz
GPIO_Init(GPIOD, &X); //初始化GPIOD寄存器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE ); //對端口D分配APB2高速時鐘,并開啟端口
//PD1_OSC_OUT
X.GPIO_Pin = GPIO_Pin_1; //對要使用的端口引腳設(shè)定
X.GPIO_Mode = GPIO_Mode_Out_PP; //對要使用的端口引腳模式設(shè)定PP為推挽輸出
X.GPIO_Speed = GPIO_Speed_50MHz; //對要使用的端口引腳頻率設(shè)定50MHz
GPIO_Init(GPIOD, &X); //初始化GPIOD寄存器
GPIO_ResetBits(GPIOD, GPIO_Pin_0); //OSC_IN
GPIO_ResetBits(GPIOD, GPIO_Pin_1); //OSC_OUT
GPIO_PinRemapConfig(GPIO_Remap_PD01, ENABLE); //重映射OSC_IN OSC_OUT
RCC_DeInit(); //將外設(shè) RCC寄存器重設(shè)為缺省值
RCC_HSICmd(ENABLE); //使能或者失能內(nèi)部高速晶振(HSI)
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){} //HSI 晶振就緒 HSI內(nèi)部晶振 HSE外部晶振
if(1) //始終執(zhí)行,方便關(guān)閉,內(nèi)部時鐘設(shè)置
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能預(yù)取指緩存
FLASH_SetLatency(FLASH_Latency_2); //設(shè)置代碼延時值為2個延時周期
RCC_HCLKConfig(RCC_SYSCLK_Div1); //設(shè)置 AHB 時鐘(HCLK)
RCC_PCLK1Config(RCC_HCLK_Div2); //設(shè)置低速 AHB 時鐘(PCLK1)
RCC_PCLK2Config(RCC_HCLK_Div1); //設(shè)置高速 AHB 時鐘(PCLK2)
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_2); //設(shè)置 PLL 時鐘源及倍頻系數(shù)
RCC_PLLCmd(ENABLE);//如果PLL被用于系統(tǒng)時鐘,那么它不能被失能 //使能或者失能 PLL,這個參數(shù)可以取:ENABLE或者DISABLE
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} //等待指定的 RCC 標(biāo)志位設(shè)置成功 等待PLL初始化成功
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //設(shè)置系統(tǒng)時鐘(SYSCLK)設(shè)置PLL為系統(tǒng)時鐘源
while(RCC_GetSYSCLKSource() != 0x08){} //等待PLL成功用作于系統(tǒng)時鐘的時鐘源
}
}
