请求评审STM32F401CCU核心基础时钟初始化代码(用于LED闪烁)
STM32F401CCU时钟初始化代码评审
以下是对提交的ClockInit函数的关键问题梳理及修正建议:
核心错误问题
- 函数返回值不匹配:函数声明为
void ClockInit(void),但代码中多处使用return 1;返回整数,会导致编译错误。需将函数声明改为int ClockInit(void),或用全局标志位替代返回值做错误处理。 - HSI关闭操作逻辑错误:HSE就绪后的代码
RCC->CR |= ~(1 << RCC_CR_HSION_Pos);逻辑完全错误,|=会将除HSION位外的所有位置1,违背关闭HSI的意图。正确写法应为RCC->CR &= ~(1 << RCC_CR_HSION_Pos);(用与操作清零目标位)。 - PLL就绪检测逻辑错误:代码
if (1 & (1 << RCC_CR_PLLRDY_Pos))永远返回假,1 << RCC_CR_PLLRDY_Pos是高位值,与1按位与结果为0,导致循环无法退出,这就是你提到的第58行失效的直接原因。正确写法应为if (RCC->CR & (1 << RCC_CR_PLLRDY_Pos))(检测RCC_CR寄存器中的PLLRDY位)。 - 系统时钟切换检测逻辑错误:
if(0x02 & (0x02 << RCC_CFGR_SWS_Pos))无法正确检测时钟是否切换到PLL。正确写法应为if ((RCC->CFGR & RCC_CFGR_SWS_Msk) == (0x02 << RCC_CFGR_SWS_Pos))(通过掩码匹配目标状态)。
潜在风险与优化点
- PLL配置冲突:先对
PLLCFGR赋值0x24003010再逐个或上参数,会覆盖初始赋值的部分位,引发配置混乱。建议先清零寄存器RCC->PLLCFGR = 0;,再逐个设置参数,或直接计算完整寄存器值一次性赋值。 - PLL参数合理性:当前设置
PLLN=0x192(即402),若HSE为8MHz,系统时钟为50.25MHz,虽在允许范围内,但可调整为更常用的84MHz(对应PLLN=336、PLLP=4)。 - 超时处理不完整:PLL超时、时钟切换超时仅关闭PLL和HSI,未关闭HSE,会造成不必要的功耗浪费,建议统一关闭所有已开启的时钟源。
- FLASH等待周期匹配:当前设置2个等待周期对应50MHz时钟合理,若后续调整到84MHz,需改为3个等待周期,否则系统会不稳定。
修正后的关键代码片段示例
int ClockInit(void){ // 修改返回值类型 RCC->CR |= (1 << RCC_CR_HSION_Pos); RCC->CR |= (1 << RCC_CR_HSEON_Pos); __IO int StrtUpcntr; // HSI就绪检测 for (StrtUpcntr = 0; ; StrtUpcntr++){ if(RCC->CR & (1 << RCC_CR_HSIRDY_Pos)) break; if(StrtUpcntr > 0x1000){ RCC->CR &= ~(1 << RCC_CR_HSION_Pos); return 1; } } // HSE就绪检测及HSI关闭 for (StrtUpcntr = 0; ; StrtUpcntr++){ if(RCC->CR & (1 << RCC_CR_HSERDY_Pos)){ RCC->CR &= ~(1 << RCC_CR_HSION_Pos); // 修正为&= break; } if(StrtUpcntr > 0x1000){ RCC->CR &= ~(1 << RCC_CR_HSION_Pos); RCC->CR &= ~(1 << RCC_CR_HSEON_Pos); return 1; } } // PLL配置:先清零再设置 RCC->PLLCFGR = 0; RCC->PLLCFGR |= (1 << RCC_PLLCFGR_PLLSRC_Pos); // 选择HSE作为PLL源 RCC->PLLCFGR |= (336 << RCC_PLLCFGR_PLLN_Pos); // 示例:设置PLLN=336,对应84MHz系统时钟 RCC->PLLCFGR |= (8 << RCC_PLLCFGR_PLLM_Pos); // PLLM=8 RCC->PLLCFGR |= (0x02 << RCC_PLLCFGR_PLLP_Pos); // PLLP=4,84MHz输出 // FLASH等待周期匹配84MHz FLASH->ACR = 0; FLASH->ACR |= (0x03 << FLASH_ACR_LATENCY_Pos); // PLL就绪检测修正 RCC->CR |= (1 << RCC_CR_PLLON_Pos); for(StrtUpcntr = 0; ; StrtUpcntr++){ if (RCC->CR & (1 << RCC_CR_PLLRDY_Pos)){ // 修正检测逻辑 break; } if(StrtUpcntr > 0x1000){ RCC->CR &= ~(1 << RCC_CR_PLLON_Pos); RCC->CR &= ~(1 << RCC_CR_HSEON_Pos); // 新增关闭HSE return 1; } } // 系统时钟切换及检测修正 RCC->CFGR = 0; RCC->CFGR |= (0x00 << RCC_CFGR_HPRE_Pos); // AHB不分频 RCC->CFGR |= (0x00 << RCC_CFGR_PPRE2_Pos); // APB2不分频 RCC->CFGR |= (0x02 << RCC_CFGR_SW_Pos); // 切换到PLL for(StrtUpcntr = 0; ; StrtUpcntr++){ if((RCC->CFGR & RCC_CFGR_SWS_Msk) == (0x02 << RCC_CFGR_SWS_Pos)){ // 修正检测逻辑 break; } if (StrtUpcntr > 0x1000){ RCC->CFGR &= ~(0x02 << RCC_CFGR_SW_Pos); RCC->CR &= ~(1 << RCC_CR_PLLON_Pos); RCC->CR &= ~(1 << RCC_CR_HSEON_Pos); // 新增关闭HSE return 1; } } return 0; }
内容的提问来源于stack exchange,提问作者KosorukiyShiva
相关产品推荐
相关产品推荐

