STM32-基本知识梳理3-时钟系统详解\重写时钟模块MCO输出

一、时钟系统综述:

1,时钟系统在STM32中,相当于人的心脏,内核及外设,根据时钟的频率执行各位的模块;

2,时钟树,下面分开进行说明:

①HSE使用外置的8MHZ晶振,在PLLXTPRE中,通过配置寄存器设置,输出8MHZ还是4MHZ;

②在这块,通过配置寄存器 PLLSRC选择:①中输出的时钟、还是HSI内部时钟/2;一般选择前者

③PLL锁相环模块,在这个模块中,对②产生的时钟,进行倍频处理,一般选用9倍频;

④通过SW寄存器配置,选择SYSCLK系统时钟的时钟源,一般选用PLLCLK,即72MHZ

⑤在④产生的SYSCLK模块,进入AHB总线中,通过AHB预分频器处理,这里一般选用 1分频;

⑥在AHB总线处理后,进入到APB1预分频器处理,一般选用2分频,得到36mhz

⑦进入到APB2预分频器处理,一般选用1分频,得到72mhz

到此,基本时钟模块配置完,核心的时钟线路配置完成;

 STM32-基本知识梳理3-时钟系统详解\重写时钟模块MCO输出_第1张图片

 二、时钟模块固件库实现

整体逻辑:

 * 使用HSE时,设置系统时钟的步骤
 * 1、开启HSE ,并等待 HSE 稳定
 * 2、设置 AHB、APB2、APB1的预分频因子
 * 3、设置PLL的时钟来源,和PLL的倍频因子,设置各种频率主要就是在这里设置
 * 4、开启PLL,并等待PLL稳定
 * 5、把PLLCK切换为系统时钟SYSCLK
 * 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟

1- 使用__IO,即VOlatie,不被编译器优化。HSEStartUpStatus用于接受HSE的启动状态;

并复位处理,开启外部HSE模块,等待HSE准备就绪

void HSE_SetSysClock(uint32_t pllmul)
{
	__IO uint32_t  HSEStartUpStatus = 0;//使用__IO,即VOlatie,不被编译器优化
	// 把RCC外设初始化成复位状态,这句是必须的;
原因在启动文件中,在进入到main前,时钟就已经配置好了,此处进行复位得到对于RCC模块的寄存器复位,相当于没有配置(具体可以在库函数中寻找到这函数)
  RCC_DeInit();



  //使能HSE,开启外部晶振
  RCC_HSEConfig(RCC_HSE_ON);
 // 等待 HSE 启动稳定
如果 HSEStartUpStatus为0,则表示HSE并未准备好;
如果是SUCCEES,则表示已经准备好
  HSEStartUpStatus = RCC_WaitForHSEStartUp();
 if (HSEStartUpStatus == SUCCESS)
{




}

2-到flash中进行预取指运行

// 使能FLASH 预存取缓冲区
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    // SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
		// 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
		// 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
		// 0:0 < SYSCLK <= 24M
		// 1:24< SYSCLK <= 48M
		// 2:48< SYSCLK <= 72M
    FLASH_SetLatency(FLASH_Latency_2);

3-配置AHB\APB2\APB1分频(本质上是操作各模块的分频寄存器数据)

 // AHB预分频因子设置为1分频,HCLK = SYSCLK 
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
  
    // APB2预分频因子设置为1分频,PCLK2 = HCLK
    RCC_PCLK2Config(RCC_HCLK_Div1); 

    // APB1预分频因子设置为1分频,PCLK1 = HCLK/2 
    RCC_PCLK1Config(RCC_HCLK_Div2);

4-配置PLL的时钟源和倍频因子

    // 设置PLL时钟来源为HSE,设置PLL倍频因子
		// PLLCLK = 8MHz * pllmul
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);

5-开启PLL时钟,并且配置SYSCLK模块的时钟源是PLL

    // 开启PLL 
    RCC_PLLCmd(ENABLE);

    // 等待 PLL稳定
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    // 读取时钟切换状态位,确保PLLCLK被选为系统时钟
    while (RCC_GetSYSCLKSource() != 0x08)
    {
    }

至此时钟源模块配置完成,为了检查配置,在MCO输出,并可以通过示波器检查数据的时钟周期

三、MCO配置输出SYSCLK

整体逻辑:

1,配置GPIO模块,PA8,复用推挽输出(不能配置直接推挽)

2,开始MCO模块,并配置时钟源为SYSCLK

配置GPIO,老一套了,注意是复用推挽输出即可

void MCO_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// 开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 选择GPIO8引脚
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	
	//设置为复用功能推挽输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	
	//设置IO的翻转速率为50M
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	// 初始化GPIOA8
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

配置MCO

	RCC_MCOConfig(RCC_MCO_SYSCLK);		

最后main函数中配置

/* 
 * 配置MCO引脚:PA8 对外提供时钟,最高频率不能超过IO口的翻转频率50MHZ
 * MCO 时钟来源可以是:PLLCLK/2 ,HSI,HSE,SYSCLK
 */
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_clkconfig.h"
#include "bsp_mcooutput.h"

//  软件延时函数,使用不同的系统时钟,延时不一样
void Delay(__IO u32 nCount); 


int main(void)
{	
	// 程序来到main函数之前,启动文件:statup_stm32f10x_hd.s已经调用
	// SystemInit()函数把系统时钟初始化成72MHZ
	// SystemInit()在system_stm32f10x.c中定义
	// 如果用户想修改系统时钟,可自行编写程序修改
	
	// 重新设置系统时钟,这时候可以选择使用HSE还是HSI
	
	// 使用HSE时,SYSCLK = 8M * RCC_PLLMul_x, x:[2,3,...16],最高是128M
	HSE_SetSysClock(RCC_PLLMul_9);
	

	// MCO 引脚初始化
	MCO_GPIO_Config();
	
	// 设置MCO引脚输出时钟,用示波器即可在PA8测量到输出的时钟信号,
	// 我们可以把PLLCLK/2作为MCO引脚的时钟来检测系统时钟是否配置准确
	// MCO引脚输出可以是HSE,HSI,PLLCLK/2,SYSCLK	
	//RCC_MCOConfig(RCC_MCO_HSE);	             	        
	//RCC_MCOConfig(RCC_MCO_HSI);	                   
	//RCC_MCOConfig(RCC_MCO_PLLCLK_Div2);    	
	RCC_MCOConfig(RCC_MCO_SYSCLK);		      
	
	// LED 端口初始化
	LED_GPIO_Config();
	while (1)
	{
		LED1( ON );			  // 亮
		Delay(0x0FFFFF);
		LED1( OFF );		  // 灭 
		Delay(0x0FFFFF);		
	}
}


//  软件延时函数,使用不同的系统时钟,延时不一样
void Delay(__IO uint32_t nCount)	
{
	for(; nCount != 0; nCount--);
}

你可能感兴趣的:(stm32,单片机,嵌入式硬件)