STM32运行中动态修改时钟

有一个项目,需要在启动的时候根据eeprom的某个参数来配置时钟,最开始的做法是按正常模式配置时钟,然后读取eeprom的参数,然后根据参数配置时钟,在仿真的时候却发现,系统时钟还是最开始设置的,后来并没有改变,找了一圈,说要关闭pll后再配置,结果还是无效。

解决办法:先使用内部时钟HIS,不开启pll,最开始的时钟仅仅保证eeprom可以读取参数或者其他方式确定后续需要设置的时钟,然后读取eeprom,得到后续该设置的时钟,然后用预置的函数进行时钟初始化。

void SystemClock_Config_BeforeInit(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
	RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
	RCC_PeriphCLKInitTypeDef RTCPeriphClkInitStruct = {0};

	/**Configure the main internal regulator output voltage 
	*/
	__HAL_RCC_PWR_CLK_ENABLE();
	__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
	/**Initializes the CPU, AHB and APB busses clocks 
	*/
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;    //使用内部HSI
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;    //不使用PLL
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
	RCC_OscInitStruct.PLL.PLLM = 25;
	RCC_OscInitStruct.PLL.PLLN = 384;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
	RCC_OscInitStruct.PLL.PLLQ = 8;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		Error_Handler();
	}

	/**Activate the Over-Drive mode 
	*/
	if (HAL_PWREx_EnableOverDrive() != HAL_OK)
	{
		Error_Handler();
	}
	/**Initializes the CPU, AHB and APB busses clocks 
	*/
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
							  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
	{
		Error_Handler();
	}

}

在进行以上时钟初始化以后,就可以利用低速的时钟先读取eeprom的参数,然后根据参数选择需要配置的时钟

	_SETTING init_setting = {0};
	/* 选择时钟 */
	delay_tim_init();        //延时函数定时器初始化
	i2c3_init();             //I2C3初始化
	setting_init();          //SETTING初始化
	setting_read(&init_setting);
	switch(init_setting.sysclk)
	{
		case SETTING_SYSCLK_180MHz:
			SystemClock_Config_192MHz();
			break;
		case SETTING_SYSCLK_192MHz:
			SystemClock_Config_192MHz();
			break;
		case SETTING_SYSCLK_240MHz:
			SystemClock_Config_240MHz();
			break;
		default:
			break;
	}

这里使用的是STM32F429,配置了180,192,240 三种频率配置模式。

我们只要在程序中选择对应的频率设置,参数会保存到eeprom,然后重启即可用新的频率运行。

### 动态调整 STM32 主频的方法 STM32 的主频由其内部的时钟系统控制,主要通过配置 PLL(Phase-Locked Loop)、HSE(High-Speed External Clock)、HSI(High-Speed Internal Clock)以及 LSI/LSE 来实现。如果需要在运行过程中动态调整主频,则可以通过重新配置这些时钟源来完成。 以下是具体的操作方式: #### 配置 RCC 寄存器 RCC(Reset and Clock Control)模块负责管理 STM32时钟树结构。要动态改变主频,通常需要操作以下几个寄存器: - **RCC_CFGR**:用于设置系统的时钟源和分频系数。 - **RCC_CR**:用于使能或禁用 HSE/HSI 和 PLL。 - **RCC_PLLCFGR**:用于配置 PLL 输入频率、倍频因子以及其他参数。 为了安全地更改主频,需遵循以下原则[^1]: - 始终备份当前的时钟配置状态以便恢复。 - 确保新的时钟配置不会违反外设的工作范围。 - 使用 HAL 库或者 LL 库可以简化复杂的寄存器操作过程。 #### 示例代码 下面是一个基于 HAL 库的示例程序,展示如何动态切换到不同的主频: ```c #include "stm32f1xx_hal.h" void ChangeSystemClock(uint32_t pllm, uint32_t pllsrc, uint32_t plln, uint32_t pllp) { RCC_OscInitTypeDef OscInitStruct; RCC_ClkInitTypeDef ClkInitStruct; // Disable interrupts to avoid conflicts during clock switching __disable_irq(); // Backup current configuration (optional but recommended) HAL_RCC_GetOscConfig(&OscInitStruct); HAL_RCC_GetClockConfig(&ClkInitStruct); // Configure the new PLL settings OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI; OscInitStruct.PLL.PLLMUL = pllm; // Set multiplier value OscInitStruct.PLL.PLLSource = pllsrc; // Select source as HSE or HSI if (HAL_RCC_OscConfig(&OscInitStruct) != HAL_OK) { Error_Handler(); } // Update system clock with updated values ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { // Adjust flash latency accordingly Error_Handler(); } // Re-enable interrupts after successful change __enable_irq(); } // Example usage: Switching to a different frequency dynamically int main(void) { HAL_Init(); // Initialize HAL Library SystemClock_Config(); // Initial default clock setup while (1) { // Dynamically adjust the system clock every second ChangeSystemClock(RCC_PLL_MUL9, RCC_PLL_SOURCE_HSE, 8, RCC_PLLP_DIV2); // Example setting HAL_Delay(1000); } } ``` 上述代码展示了如何利用 `ChangeSystemClock` 函数动态修改主频。需要注意的是,每次调用此函数前应确认新设定是否满足目标应用的需求,并适当调整闪存延迟 (`FLASH LATENCY`) 参数以匹配更高的工作频率。 #### 注意事项 - 不同型号的 STM32 支持的最大主频不同,请查阅对应的数据手册获取准确信息。 - 修改主频可能会影响某些依赖精确定时的功能(如 UART 波特率),因此需要同步更新相关初始化代码。 - 如果使用外部晶振作为时钟源,确保该晶振已稳定启动后再启用 PLL。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值