最近有个项目,用到STM32L151,原设计者使用外部8MHz晶振。有一天晚上调试过程中,突然发现程序跑不动了,翻到背面瞧见HSE脱落了~~~再用RCC_GetClocksFreq(&RCC_ClockFreq);观察RCC_ClockFreq.SYSCLK_Frequency,只有2.09MHz。手扶着HSE重新上电,单片机运转正常。看来就是它的锅。: s2 c3 e& U4 z% K % _! y3 u4 s: o( _* `0 I 但是,家里没有电烙铁。 那怎么办呢?只能换用16MHz的HSI了,MSI非整就不考虑了。我从来都只是用SystemInit();初始化的,除了修改一下HSE的频率,从来没碰过里面的其他语句。 一开始,我写了一个HSI倍频到32MHz的程序,替换掉.s文件里的SystemInit,结果失败。可能是因为我写的程序本身有问题。2 i" b0 G5 S1 l d 1 T! \5 N# K0 }" c6 I 后来想想,不如向SystemInit();里面添加HSE启动失败后的代码。它里面负责将HSE倍频到32MHz的程序是% i+ s- ?# X: i% Y 5 n+ P9 }( e# H! ?$ y/ v3 x /* Configure the System clock frequency, AHB/APBx prescalers and Flash settings */ SetSysClock();$ \) u, r6 G# O; T& C0 o: j 0 G! a" }3 I$ Z/ J/ X% Y X$ S + U; A. n/ ~0 v8 _- { 在它里面,除了详细描述了HSE+PLL的启动方式,还有下列注释:# I) G; c4 M* x$ O) ~ 7 W' k% B$ X% R7 G" `" v if (HSEStatus == (uint32_t)0x01) { ……省略……& X' L$ v# P7 J0 V$ N. v+ d } else) w$ n) E, B& L' }& {7 d { /* If HSE fails to start-up, the application will have wrong clock" m% g& e+ }% Y' A( {( X configuration. User can add here some code to deal with this error */ . c6 a4 | b0 ~/ y, h f( L8 G. f //翻译:如果HSE无法启动,程序将以错误的时钟运行。用户可自行添加勘正代码 }4 |8 y4 i1 D; e / i/ Z) B7 X" @- Q% v ST官方竟然提前留好了坑!& z2 V# L: w4 A 于是,仿照着HSE+PLL启动方式,我写了下面的代码,使用HSI+PLL,并添加到else{}中,观察RCC_ClockFreq.SYSCLK_Frequency=32000000,一次性通过。 /* Enable HSI */ RCC->CR |= ((uint32_t)RCC_CR_HSION); /* Wait till HSI is ready and if Time out is reached exit */$ Y/ T% E: j6 A: A do& Z4 f' G( g! h2 q8 g- H {1 Y# |; l4 q5 }' T" c: v! w HSIStatus = RCC->CR & RCC_CR_HSIRDY; StartUpCounter++; } while((HSIStatus == 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT));& t* Q/ n3 p1 T x1 d& {8 k if ((RCC->CR & RCC_CR_HSIRDY) != RESET) { HSIStatus = (uint32_t)0x01;0 S) ]9 z# x! _" U/ h, j) K g } else# e* N1 J" O6 B7 ] {: s" e% L8 A& B* m, T# { HSIStatus = (uint32_t)0x00; } if (HSIStatus == (uint32_t)0x01) { /* Turn OFF the HSE oscillator */6 f& x2 V# x: R" k. \% w) n RCC_HSEConfig( RCC_HSE_OFF ); 9 |* B' v, f) r7 x! Y I /* Enable 64-bit access */6 ^; [& Z# Y# L2 } FLASH->ACR |= FLASH_ACR_ACC64;2 i( L K' N1 I6 h; F - W) p0 e+ K5 P j: T# L /* Enable Prefetch Buffer */ FLASH->ACR |= FLASH_ACR_PRFTEN; H9 |8 U9 T! y7 o* B a 7 ~! @2 ~8 o) S& C+ j. X# b7 e$ c /* Flash 1 wait state */ FLASH->ACR |= FLASH_ACR_LATENCY;0 |# R' h1 W4 H4 d# `- B& X & `! X& I$ _9 N5 V+ C$ R /* Power enable */ RCC->APB1ENR |= RCC_APB1ENR_PWREN;' [. F: [. Z% G/ [& ^- P- S /* Select the Voltage Range 1 (1.8 V) */ PWR->CR = PWR_CR_VOS_0; 9 y! r6 ?) q+ i: |: | /* Wait Until the Voltage Regulator is ready */ while((PWR->CSR & PWR_CSR_VOSF) != RESET) { } /* HCLK = SYSCLK /1*/1 b$ d9 E; u! x RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK /1*/( Q5 p: i2 M0 ]! A$ {8 `, p, c RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; / m; r7 F; V- s( {- o /* PCLK1 = HCLK /1*/ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;' k/ K# ^- a2 I' d 2 y2 j! O6 P r1 Q- V& r- n% u /* PLL configuration */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL | RCC_CFGR_PLLDIV)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL4 | RCC_CFGR_PLLDIV2); ' c1 n6 C) ?! x; P /* Enable PLL */ RCC->CR |= RCC_CR_PLLON;0 {- B0 W) N$ O1 X& k7 m /* Wait till PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } 5 I. J* z1 g& P: c /* Select PLL as system clock source */; E" A/ J- g' A& y RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + y; Z; G# M, W6 W& ] /* Wait till PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)+ n' g( N. ^9 n. O { } } 9 a! ~7 L5 a/ Z# Y 记得在static void SetSysClock(void)的第一行添加HSIStatus的定义,即: __IO uint32_t StartUpCounter = 0, HSEStatus = 0, HSIStatus = 0; |
基于STM32L协议传输数据到阿里云物联网平台
stm32L451比较器使用
在 STM32 F0、 F2、 F3、 F4 和 L1 系列MCU 中使用硬件实时时钟 (RTC)
使用 STM32L1xx 微控制器与外部 I2S 音频编解码器 播放音频文件
STM32L1xx 与 STM32L1xx-A 的差别
从 STM32L1 系列移植到 STM32L4 系列微控制器
如何校准 STM32L1xx 内部 RC 振荡器
使用 STM32L1xx 微控制器与外部 I2S 音频编解码器播放音频文件
STM32L1x 温度传感器应用举例
STM32L1xxx 硬件开发入门