对于小型化的设备,特别是对时钟要求不高且出货量大的产品,每一颗物料都要精打细算,省下来的都是成本。如果不要晶振,每个产品都能省下一颗晶振和两颗电容,量变引起质变,嗯~还是有必要的。
此次勒裤腰带的是STM32F0,现在晶振可不便宜(好像一直都不便宜),而且日本厂商还宣布电容涨价。能省就省吧。而且经过测试,STM32的内部晶振还是很可靠的,如果不使用精准的计时,这个晶振真的可以摘。
static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSIStatus = 0;
RCC->CR &= ~((uint32_t)RCC_CR_HSEON); //关闭外部时钟
RCC->CR |= ((uint32_t)RCC_CR_HSION); //使能内部时钟 HSI
do //等待内部时钟起振
{
HSIStatus = RCC->CR & RCC_CR_HSIRDY; // 设置RCC
StartUpCounter++; //启动计数器
}
while((HSIStatus== 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT)); // 等待 HSE 启动稳定
if ((RCC->CR & RCC_CR_HSIRDY) != RESET) //判断启动状态
{
HSIStatus = (uint32_t)0x01;
}
else
{
HSIStatus = (uint32_t)0x00; //启动不成功
}
if (HSIStatus == (uint32_t)0x01) //启动成功
{
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY; //flash总线时钟使能
/* HCLK = SYSCLK */ //AHB总线时钟HCLK(是系统时钟SYSCLK经过AHB分频器分频后得到的时钟,
//一般设置1分频,HCLK=SYSSCLK=48MHz;
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //AHB总线时钟 HCLK = SYSCLK/1=48MHz
/* PCLK = HCLK */ //APB总线时钟PCLK等于AHB总线时钟/1 PCLK=HCLK/1
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1; // PCLK=HCLK/1=48M/1=48M
/* PLL configuration = HSI/2 * 12= 48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL14);
//RC时钟2分频后 进行12倍频
//=8M/2*12=48M
RCC->CR |= RCC_CR_PLLON; //使能锁相环倍频开关 /* Enable PLL */
while((RCC->CR & RCC_CR_PLLRDY) == 0) //等待锁相环就绪
{ }
//选择锁相环输出时钟作为系统时钟
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{ } //等待锁相环输出时钟已经成为系统时钟
}
else
{ } //启动失败,在此写代码
}
修改时钟配置在system_stm32f0xx.c文件中进行。主要修改SetSysClock(void)这个函数,该函数默认使用外部晶振,上电会尝试启动外部时钟,通过while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL) 来判断是否启动成功,如果启动失败则会进入else尝试启动内部时钟,但是官方的库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 */
// HSI 内部时钟做为PLL时钟源并配置PLL 56M做为系统时钟
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
// PLL configuration = (HSI/2) * 12 = 48 MHz
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_14); // 8M/2 * 14 = 56M
/* 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_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // PLL 做系统时钟
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
将上述内容填充进else便可,只需修改RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_14);中的RCC_PLLMul_14参数便可修改主频。
为了切换内外部时钟方便,可在函数开头加
屏蔽上面一行则使用内部时钟,屏蔽下面一行则使用外部时钟。
我贴的代码是使用内部时钟并超频到56M,标准是48M。
下面贴上所有代码:
static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
/* Enable HSE */
//修改为内部晶振
//RCC->CR |= ((uint32_t)RCC_CR_HSEON);
RCC->CR &= ~((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
/* PLL configuration = HSE * 6 = 48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL7);
/* 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)RCC_CFGR_SWS_PLL)
{
}
}
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 */
// HSI 内部时钟做为PLL时钟源并配置PLL 56M做为系统时钟
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
// PLL configuration = (HSI/2) * 12 = 48 MHz
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_14); // 8M/2 * 14 = 56M
/* 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_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // PLL 做系统时钟
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}
}
|