复位也就是重启,使系统回到初始状态;
复位的三种形式:上电复位,系统复位和备份区复位;
系统复位;除了时钟控制器RCC-CSR寄存器中的复位标志位和备份区域中的寄存器以外,系统复位将复位所以的寄存器至他们复位状态;
当触发以下事件时,将会产生一个系统复位:
1.NRST引脚上的低电平(外部复位);
2.窗口看门狗计数终止(WWDG复位);
3.独立看门狗计数终止(IWDG复位);
4.软件复位(SW复位);
5.低功耗管理复位;
对于单片机来说,时钟是具有周期性的脉冲信号,最常用的是占空比为50%的方波;
时钟相当于单片机的心脏,想要使用单片机的外设,必须开启相应的时钟,驱动外设的本质是操作寄存器,而寄存器是由D触发器构成的,而触发器需要时钟才能改写值,所以要想操作寄存器必须开启对应外设的时钟;
对于cpu来说,假设 cpu在一个时钟周期内执行一条指令(二进制代码),若时钟频率越高,而时钟等于1/f为频率的倒数,则时钟周期更短,在相同的时间内CPU可以执行更多的指令,CPU运行速度更快;
时钟的走向及关系很重要;
STM32时钟系统主要的目的是给相对独立的外设模块提供时钟,也是为了降低整个芯片的功耗,所以外设的时钟默认都是关闭状态,当我们要使用某个外设就要开启这个外设的时钟,不同外设所需的时钟频率也不同,没必要所有外设都用高速时钟造成浪费,而且有的外设也接受不了这么高的频率,这也就是为什么STM32有四个时钟源的原因,就是兼容不同速度的外设,STM32的四个时钟源:HSE,HSI,LSE.LSI
来源:HSE外部高速时钟信号由俩种方式产生:
1.HSE外部晶体/陶瓷谐振器;
2.HSE外部用户晶体
作用:可不分频或2分频作为PLL锁相环的输入,还可以直接不分频作为系统时钟输入,128分频作为外设RTC时钟的输入,为了减少时钟输出的失真和缩短启动稳定时间,晶体/陶瓷谐振器和负载电容器必须尽可能地靠近振荡器引脚。负载电容值必须根据所选择的振荡器来调整。
控制:参考手册;
来源:PLL的设置(选择HSI振荡器除2或者HSE振荡器为PLL的输入时钟,和选择倍频因子)必须在其被激活前完成,一旦PLL被激活,这些参数就不能被改动;
作用:内部PLL可以用来倍频HSI RC的输出时钟或者HSE晶体输出时钟,倍频后的PLLCLK可以作为系统时钟源;
如果PLL中断在时钟中断寄存器里被允许,当PLL这准备就绪时,可产生中断申请;
来源:内部芯片,LSI RC担任了一个低功耗时钟源的角色,它可以在停机和待机模式下保存运行,为独立看门狗和自动唤醒单元提供时钟
作用:可用于驱动独立看门狗和通过程序选择驱动RTC;
控制:参考手册;
*RTC用于从停机或者休眠模式下自动唤醒系统;
来源:LSE晶体是一个32.768Khz的低速外部晶体或者陶瓷谐振器,它为实时时钟或者其他定时功能提供了一个低功耗且精确的时钟源;
作用:用来通过程序选择驱动RTC;
控制:参考手册;
当不被使用的时候任何时钟源可被独立的关闭或者启动;
系统时钟:SYSCLK,最高位72M;
来源:HSI,HSE,PLLCLK;
控制:SW,CFGR;
*通常配置:SYSCLK=PLLCLK=72M;
SYSCLK时钟源:
通常配置:
HCLK:AHB高速总线时钟,速度最高位72M;
作用:为AHB总线的外设提供时钟,为Cortex系统定时器提供时钟(Systick)、为内核提供时钟(fclk);
来源:系统时钟分频得到,一般设置HCLK=SYSCKL=72M;
控制:寄存器控制(参考手册);
PCLK1:APB1低速总线时钟,最高位36M;
作用:为APB1总线的外设提供时钟。1或2倍频后为APB1总线的定时器2-7提供时钟,最大位72M;
来源:HCLK分频的来,一般配置位PCLK1=HCLK/2=36M;
PCLK2:APB2高速总线时钟,最高为72MHZ;
作用:为APB2总线的外设提供时钟,为APB2总线定时器1和8提供时钟,最大为72M,还有一路输出供给ADC使用;
来源:HCLK分频的来,一般配置为PCLK2=HCKL=72M;
控制:参考手册;
RTC时钟:为内部的RTC外设提供时钟;
来源:HSE_RTC分频的来,LSE,LSI;
控制:RCC备份控制寄存器(参考手册);
IWDGCLK,LSI提供;
MOC:微控制器时钟输出引脚;由PA复用所得,可以把时钟信号输出供外部使用,也可以用示波器检测时钟信号的参数(峰峰值,频率等)
来源:PLLCLK/2,HSE,HSI,SYSYCLK
打开之前创建的工程,系统启动.s的汇编文件后;
启动上电后,执行启动文件(汇编代码编写)中的复位程序;
执行复位程序:1.调用Systemlnit系统初始化函数完成系统时钟的配置;
2.调用_main函数初始化堆栈指针,然后在调用C库函数main函数,去到C语言的世界;
所以跳转到C语言的main函数时,已经完成了系统时钟SYSCLK的配置;
首先执行的是SystemInit系统初始化函数;
SystemInit系统初始化的功能:设置微控制器系统
* 初始化嵌入式闪存接口和 PLL,并更新
* 系统核心时钟变量。
查看SystemInit内容,右击选择go to 前往
*
对寄存器进行操作,官方固件库提供的函数,实现的时候通过寄存器进行操作,把寄存器操作封装好,提供给用户使用,我们使用时候,只需要调动函数就行了,一般我们不会修改时钟,我们想要修改,就通过修改初始化函数中,该寄存器设置的一些值,来修改它的时钟源和分配系数;
分析:
RCC->CR |= (uint32_t)0x00000001;
将RCC指向的寄存器CR或等(|=)于0x00000001;,把CR寄存器第0位置1,复位RCC时钟,使能了内部高速时钟;
/* 将 RCC 时钟配置重置为默认重置状态(用于调试) */
/* 设置 HSION 位 */
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifnde通过条件编译的写法,如果定义了CL(互联型产品)就执行CL后面的代码,否则就执行后面的代码,CL代表互联型成品,我们选择的不是互联型所以执行
RCC->CFGR &= (uint32_t)0xF0FF0000;
&= (把后面的清0)
0XF0FF0000(一个十六进制位等于四个二进制位)=11110000111111110000000000000000
位10:00即选择HS1作为系统时钟;位32即判断时钟状态
第一位SW相对时钟树种SW选择时钟源对应:
第二位十六进制0对应二进制0000,对应 10987654
代表AHB的预分频选择SYSCLK不分频;
低速APB1预分配:0XX HCLK也不分频
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
通过条件编译的方式来确定时钟源的:如果定义了SYSCLK_FREQ_HSE则执行这个 SetSysClockToHSE();
如何确定走的是那条分支,通过鼠标右击跳转的方式来判断是否定义了;
所以我们go to跳转到这个函数:
分析:在这个函数中设置了系统时钟;
开启了外部的高速时钟,使能了HSE;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
等待外部高速时钟已经准备好退出,等待HSE就绪并作超时处理;
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
如何使能:
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* 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;
使能预取指CPu在FLASH取代码
FLASH->ACR |= FLASH_ACR_PRFTBE;
设置俩个等待周期
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
HCLK设置没有分频
PCLK1,2分频
条件编译如果定义了是互联网产品则执行前面代码,如果不是执行后面代码;我们这里选择的不是互联网产品,所以执行后面的代码
#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}
/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
锁相环配置:PLLCLK=HSE*9=72MHZ;
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
使能PLL;
RCC->CR |= RCC_CR_PLLON;
等待PLL稳定;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
选择PLL作为系统时钟
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
等待PLLCLK切换为系统时钟
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
接的外部晶振是8KHZ,经过PLL九倍频后位72KHZ给到SYSCLK;