复位
系统复位
系统复位有5个来源
- NRST引脚的低电平
- IWDG
- WWDG
- 软件复位SW
- 低功耗管理复位
如果设置了nRST_STDBY和nRST_STOP=1,则进入待机和停止模式时,将产生复位。- 在进入待机模式时产生复位
- 进入停止模式时产生复位
可以通过查看寄存器来知道复位的来源
电源复位
产生电源复位可能是上电和掉电,POR/PDR或者是从待机模式返回,芯片内部有一个20us的脉冲发出,此时可以保证芯片的复位。
备份域复位
备份区域的复位只影响备份区域,可以通过软件,或者VDD和VBAT两者都掉电的时候进行复位,这就是为什么要进行备份重启时,我们要取掉电池。
时钟
- 三种时钟可以驱动系统时钟,HSE,HSI和PLL,内部有一个40KHZ的RC,用来保证看门狗的时钟RTC,RTC在停机后的自动唤醒。另外驱动RTC的时钟也可以选择内部的32.768KHZ的时钟。
-
简单来说,外部的高速时钟就是晶振,低速时钟是32.768时钟,而内部的高速时钟是8M,低速时钟是40KHZ。
HSE时钟
外部高速时钟可以直接输入时钟,或者用晶振产生。
HSI时钟
时钟的精度不够,并且最大只有64M,不太推荐使用。
PLL
如果要用到USB接口,时钟必须设置为48M或者72M,可以优先选择72M
LSE
32.768KHZ的时钟,启动以后,要等待释放信号再进行下一步,和上面的晶振的要求一样。也可以用外部的32.768来提供,此时为旁路模式。
LSI
内部的低速时钟主要用于产生低功耗,在停机和待机模式下运行,提供看门狗和唤醒时钟。所有的内部时钟都有一个校准,可以用TIM5来进行校准。
系统时钟选择
系统复位后,HSI被选择为系统时钟,这个时候如果我们用到了HSE,需要进行切换。
时钟安全系统
如果系统出现故障,比如外部时钟坏了,此时首先关闭高级定时器的刹车,放置出现烧毁器件,同时将外部时钟通道关闭,并自动的切换到内部时钟。
RTC时钟
RTC是重要的时钟源,可以有三个来源,内部40K,外部32.768K和外部高速时钟的分频。
- 32.768时钟时,重要电池还可以用,RTC都会运行
- 内部40K,此时VDD如果没电,不能保证提供。
- 外部高速时钟分频:当然不工作啦。
看门狗时钟
如果看门狗启动,40K的时钟强制打开。
时钟输出
如果设置为72M,相当于可以通过GPIO给外面输出:
- 72M
- 晶振时钟
- 8M
- PLL/2时钟
我们先来看一个典型的时钟配置的程序调用。
- 在MAIN函数中,最先调用BSP_Init
- 在BSP中,最先进行SystemInit
- 系统初始化函数中,调用了SetSysClock函数,里面根据不同的SYSCLK_FREQ_HSE调用了SetSysClockToHSE();
- 如果调用的是SetSysClockTo72,将时钟设置为72M
时钟都在system_stm32f10x.h里面进行了设置,标准的RCC库函数还有如下的函数可以使用:另外,还需要特别注意一下的符号的意义:
- PCLK1 最大36,APB1的时钟
- PCLK2 最大72M,APB2的时钟
- HCLK 提供给外设的时钟,最大72M
- SYSCLK 经AHB分频以后给HCLK,最大为72M
ADC时钟配置:ADCCLKConfig
分频设置
AdjustHSICalibrationValue
内部高速时钟校准,内部时钟不准。
AHBPeriphClockCmd
外设时钟设置,其中APB1PeriphClockCmd 和 APB2包括了哪些外设,要稍微留意一下。
备份寄存器复位:BackupResetCmd
清复位源的标志:ClearFlag
清中断ClearITPendingBit
如果设置时钟的中断, 比如:RCC_IT_LSIRDY: LSI ready interrupt
安全系统开启:ClockSecuritySystemCmd
去初始化DeInit
获取时钟频率GetClocksFreq
包括ADC,HCLK,PCLK1,PCLK2,SYSCLK
GetFlagStatus
GetITStatus
获取系统时钟源GetSYSCLKSource
HCLKConfig
也就是SYSCLK到HCLK的分频
HSEConfig LSEConfig
旁路还是用晶振
HSICmd LSICmd
内部8M是否使能
ITConfig
时钟输出:MCOConfig
PCLK1Config 外设时钟设置
PLLCmd PLL是否使能 PLLConfig
RTCCLKConfig RTCCLKCmd
三个时钟源
SYSCLKConfig 系统时钟
USBCLKConfig
WaitForHSEStartUp 等待晶振稳定
我们为了防止晶振坏了而导致系统直接挂调,可以设置一个RCC_USEHSI,再一次强调,此时钟又慢又不准!
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; //对要使用的端口引脚设定
X.GPIO_Mode = GPIO_Mode_Out_PP; //对要使用的端口引脚模式设定PP为推挽输出
X.GPIO_Speed = GPIO_Speed_50MHz; //对要使用的端口引脚频率设定50MHz
GPIO_Init(GPIOD, &X); //初始化GPIOD寄存器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE ); //对端口D分配APB2高速时钟,并开启端口
//PD1_OSC_OUT
X.GPIO_Pin = GPIO_Pin_1; //对要使用的端口引脚设定
X.GPIO_Mode = GPIO_Mode_Out_PP; //对要使用的端口引脚模式设定PP为推挽输出
X.GPIO_Speed = GPIO_Speed_50MHz; //对要使用的端口引脚频率设定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(); //将外设 RCC寄存器重设为缺省值
RCC_HSICmd(ENABLE); //使能或者失能内部高速晶振(HSI)
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){} //HSI 晶振就绪 HSI内部晶振 HSE外部晶振
if(1) //始终执行,方便关闭,内部时钟设置
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能预取指缓存
FLASH_SetLatency(FLASH_Latency_2); //设置代码延时值为2个延时周期
RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置 AHB 时钟(HCLK)
RCC_PCLK1Config(RCC_HCLK_Div2); //设置低速 AHB 时钟(PCLK1)
RCC_PCLK2Config(RCC_HCLK_Div1); //设置高速 AHB 时钟(PCLK2)
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_2); //设置 PLL 时钟源及倍频系数
RCC_PLLCmd(ENABLE);//如果PLL被用于系统时钟,那么它不能被失能 //使能或者失能 PLL,这个参数可以取:ENABLE或者DISABLE
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} //等待指定的 RCC 标志位设置成功 等待PLL初始化成功
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //设置系统时钟(SYSCLK)设置PLL为系统时钟源
while(RCC_GetSYSCLKSource() != 0x08){} //等待PLL成功用作于系统时钟的时钟源
}
}