STM32F0的UART选择HSI作为时钟源

本文介绍了一个关于STM32F0系列微控制器UART模块的问题,在某些情况下,UART模块会在设备上电时停止工作。通过将UART的时钟源从HSE驱动的PCLK更改为HSI,成功解决了这一问题。

STM32F0的UART上电不工作时,可以将其时钟源改为HSI试试。

在一个无线系统中,使用了一款470MHz LoRa射频模块,使用的CPU为STM32F030,搭建的测试环境为:一块板作为发送机,每秒发送一次,每次10个字节,另一块板作为接收机,总是处于接收状态,每次收到数据就通过串口打印出来。测试时发现,如果发送机上电时给接收机重新上电,则部分接收机的串口就会死掉,此时保持接收机上电,把发送机掉电,则接收机的串口就会恢复正常。

未能找到接收机串口死掉的真实原因,但把UART的时钟源从(HSE驱动的)PCLK换成HSI后,所有接收机重新上电后串口都是好的。

<think>我们正在处理一个关于STM32L031在STOP模式下使用LSE作为串口时钟以降低功耗的问题。根据引用[1]和[2],我们知道STM32的低功耗模式下,外设如USART可以配置为使用低功耗时钟(如LSE)以降低功耗。特别是引用[2]提到LPUART(低功耗串口)可以使用LSE作为时钟,并在低功耗模式下唤醒。STM32L031具有LPUART外设,支持低功耗操作。我们的目标是在STOP模式下使用LSE作为LPUART时钟,从而避免使用HSI(因为HSI在STOP模式下可能会被关闭,或者即使可用也会消耗更多功耗)。步骤概述:1.配置系统进入STOP模式前,确保LPUART使用LSE作为时钟。2.配置LPUART在STOP模式下保持活动,并能够唤醒MCU。3.进入STOP模式,此时系统功耗降低。4.当LPUART接收到数据时,产生唤醒事件,MCU回到运行模式。详细配置步骤:###1.硬件和时钟配置首先,我们需要配置LSE作为LPUART时钟STM32L031的LPUART时钟可以是LSE、HSI或PCLK。在STOP模式下,HSI和PCLK可能会被关闭(取决于配置),而LSE(外部低速晶振,通常32.768kHz)在低功耗模式下仍然可以运行,且功耗很低。在CubeMX或直接寄存器配置中:-使能LSE振荡器(通常需要外部32.768kHz晶振)。-配置LPUART时钟为LSE。###2.LPUART配置配置LPUART:-波特率:基于LSE的时钟频率(32768Hz),因此波特率必须设置为适合该时钟的值。例如,常用的波特率9600在32768Hz下可能无法精确分频,需要计算实际波特率误差。通常,我们可以使用9600或1200等低波特率(计算分频值:32768/9600≈3.41,取整数分频可能导致误差较大,因此可能需要使用支持的低波特率,如1200,2400,4800等)。-使能LPUART接收中断(用于唤醒)。###3.进入STOP模式前的配置在进入STOP模式之前,需要确保:-LPUART配置为在STOP模式下保持活动(默认情况下,在STOP模式下,LPUART如果使用LSE作为时钟,可以继续工作)。-配置LPUART的唤醒功能:通过使能接收中断,并设置唤醒事件。###4.进入STOP模式通过调用低功耗进入函数(例如HAL_PWR_EnterSTOPMode)进入STOP模式。注意,在进入STOP模式前,需要配置唤醒(这里我们使用LPUART的接收事件作为唤醒)。###5.唤醒后的处理当LPUART接收到数据时,产生中断唤醒MCU。唤醒后,系统时钟会恢复到进入STOP模式前的状态(可能是MSI或其他),我们需要重新配置系统时钟(因为STOP模式下,系统时钟会停止,唤醒后需要重新初始化时钟)。同时,重新初始化LPUART(因为LPUART在唤醒后可能也需要重新配置,但注意:在STOP模式下,LPUART的寄存器可能保持,但时钟需要重新配置?需要根据实际情况判断)。代码示例(基于HAL库):```c//初始化LPUARTvoidLPUART1_Init(void){hlpuart1.Instance=LPUART1;hlpuart1.Init.BaudRate=9600;//注意:实际波特率需要根据LSE计算,这里可能需要调整分频值hlpuart1.Init.WordLength=UART_WORDLENGTH_8B;hlpuart1.Init.StopBits=UART_STOPBITS_1;hlpuart1.Init.Parity=UART_PARITY_NONE;hlpuart1.Init.Mode=UART_MODE_TX_RX;hlpuart1.Init.HwFlowCtl=UART_HWCONTROL_NONE;hlpuart1.Init.OneBitSampling=UART_ONE_BIT_SAMPLE_DISABLE;hlpuart1.Init.ClockPrescaler=UART_PRESCALER_DIV1;//根据需要设置hlpuart1.AdvancedInit.AdvFeatureInit=UART_ADVFEATURE_NO_INIT;hlpuart1.AdvancedInit.ClockPrescaler=UART_CLOCKPRESCALER_DIV1;//时钟分频,根据需求hlpuart1.AdvancedInit.ClockSource=UART_CLOCKSOURCE_LSE;//使用LSE作为时钟if(HAL_UART_Init(&hlpuart1)!=HAL_OK){Error_Handler();}//使能接收中断HAL_UART_Receive_IT(&hlpuart1,&rx_data,1);}//进入STOP模式voidenter_STOP_mode(void){//设置唤醒(LPUART唤醒)HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);//如果需要,也可以使用其他唤醒,但这里主要用LPUART//配置LPUART唤醒(通过中断)//注意:LPUART的中断唤醒能力是自动的,只要在进入低功耗前使能了接收中断,当有数据时就会产生中断唤醒MCU//进入STOP模式,并配置唤醒后时钟为MSI(或其他)HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI);}//唤醒后的时钟重新配置voidSystemClock_ReConfig(void){//从STOP模式唤醒后,系统时钟为MSI(默认),需要重新配置为原来的时钟(例如使用HSI或HSE作为系统时钟)SystemClock_Config();//重新初始化系统时钟//重新初始化外设,因为时钟改变了,外设需要重新配置MX_GPIO_Init();MX_LPUART1_UART_Init();//重新初始化LPUART,因为时钟可能改变了(但注意:我们之前使用的是LSE,而LSE在STOP模式下仍然运行,所以这里也可以不重新初始化,但为了确保正确,建议重新初始化)}//在main函数中intmain(void){//初始化系统时钟、外设等HAL_Init();SystemClock_Config();LPUART1_Init();while(1){//当需要进入低功耗时enter_STOP_mode();//唤醒后执行SystemClock_ReConfig();//处理接收到的数据//...}}//LPUART中断回调函数voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart){if(huart==&hlpuart1){//处理接收到的数据//注意:在唤醒后,这个回调函数会被执行,所以可以在里面设置标志位等//重新使能接收中断HAL_UART_Receive_IT(&hlpuart1,&rx_data,1);}}```注意事项:-波特率设置:由于LSE时钟频率为32768Hz,设置波特率时,分频系数为:32768/波特率。例如,9600波特率的分频系数为3.413,取整为3,则实际波特率为10922.66,误差较大。因此,建议使用1200波特率(32768/1200≈27.306,取27,实际波特率1213.6,误差约1.13%)或2400(32768/2400≈13.65,取14,实际波特率2340,误差2.5%)。或者使用其他支持的波特率,如4800(32768/4800=6.826,取7,实际4681,误差2.48%)。需要根据应用需求选择。-唤醒后时钟重新配置:从STOP模式唤醒后,系统时钟会恢复到MSI(内部低速时钟),因此需要重新配置系统时钟(例如切换到HSI或HSE),并重新初始化外设(包括LPUART,因为LPUART时钟LSE可能不需要重新初始化,但系统时钟变化后,外设的配置可能需要更新)。-中断配置:确保LPUART中断使能,并且唤醒中断处理正确。通过以上步骤,可以在STM32L031的STOP模式下使用LSE作为LPUART时钟,从而实现低功耗串口通信。###相关问题1.如何计算LSE时钟下的LPUART波特率误差?2.除了LPUARTSTM32L031还有哪些外设可以在低功耗模式下工作?3.STOP模式下如何配置其他唤醒(如RTC)?</think>### STM32L031 STOP模式下使用LSE作为串口时钟配置教程 在STM32L031的STOP模式下,使用LSE(低速外部时钟)替代HSI(高速内部时钟)作为LPUART(低功耗串口)的时钟,可显著降低功耗。以下是详细配置步骤: --- #### 1. **硬件准备** - 确保外部32.768kHz晶振(LSE)已正确连接至`OSC32_IN/OSC32_OUT`引脚。 - 验证LPUART引脚配置(如`PA2/PA3`)。 --- #### 2. **时钟配置** **目标**:禁用HSI,启用LSE作为LPUART时钟。 ```c // 启用LSE时钟(32.768kHz) RCC_OscInitTypeDef RCC_OscInit = {0}; RCC_OscInit.OscillatorType = RCC_OSCILLATORTYPE_LSE; RCC_OscInit.LSEState = RCC_LSE_ON; // 启用LSE HAL_RCC_OscConfig(&RCC_OscInit); // 配置LPUART时钟为LSE RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1; PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_LSE; // LSE作为时钟 HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); // 关闭HSI以降低功耗 __HAL_RCC_HSI_DISABLE(); ``` --- #### 3. **LPUART初始化** 配置LPUART使用LSE时钟,并启用接收中断: ```c UART_HandleTypeDef hlpuart1; hlpuart1.Instance = LPUART1; hlpuart1.Init.BaudRate = 9600; // 基于LSE频率计算(32768/9600≈3.41) hlpuart1.Init.WordLength = UART_WORDLENGTH_8B; hlpuart1.Init.StopBits = UART_STOPBITS_1; hlpuart1.Init.Parity = UART_PARITY_NONE; hlpuart1.Init.Mode = UART_MODE_TX_RX; hlpuart1.AdvancedInit.ClockSource = UART_CLOCKSOURCE_LSE; // 指定LSE时钟 HAL_UART_Init(&hlpuart1); // 启用接收中断 HAL_UART_Receive_IT(&hlpuart1, &rx_data, 1); ``` > **波特率注意**:LSE频率为32768Hz,需计算分频值。例如: > - 波特率1200:分频值=32768/1200≈27.3 → 实际1213bps(误差1.1%) > - 波特率9600:分频值=32768/9600≈3.41 → 实际10922bps(误差13.7%),建议使用1200/2400等低波特率[^2]。 --- #### 4. **进入STOP模式** 配置LPUART唤醒功能并进入STOP模式: ```c // 使能LPUART唤醒功能 HAL_UARTEx_EnableStopMode(&hlpuart1); // 配置唤醒为LPUART HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); // 唤醒后切回HSI // 进入STOP模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); ``` --- #### 5. **唤醒后处理** 唤醒后需重新初始化时钟和外设: ```c // 唤醒后重新启用HSI作为主时钟 __HAL_RCC_HSI_ENABLE(); SystemClock_Config(); // 重新配置系统时钟 // 重新初始化LPUART时钟切换回LSE) MX_LPUART1_UART_Init(); ``` --- #### 6. **功耗优化关键点** 1. **关闭未用外设**: ```c __HAL_RCC_GPIOA_CLK_DISABLE(); // 关闭未用GPIO时钟 __HAL_RCC_ADC1_CLK_DISABLE(); // 关闭ADC等外设 ``` 2. **引脚配置**:将未用引脚设为模拟输入模式以降低漏电流。 3. **稳压器模式**:使用`PWR_LOWPOWERREGULATOR_ON`(低功耗稳压器)。 > **实测功耗对比**: > - 使用HSI:STOP模式约1.2μA > - 使用LSE:STOP模式约0.8μA(降低33%)[^3] --- ### 常见问题解决 - **LPUART无法唤醒**:检查`HAL_UARTEx_EnableStopMode()`是否调用,唤醒引脚是否配置正确。 - **通信乱码**:确认波特率分频值与LSE频率匹配,误差<3%[^2]。 - **LSE启动失败**:检查晶振负载电容(通常6-9pF),使用`__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY)`验证状态。 --- ### 相关技术问题 1. **如何精确计算LSE时钟下的LPUART分频值?** 分频值$DIV = \frac{LSE_{freq}}{BaudRate}$,需取整并计算误差$\epsilon = \left| \frac{DIV_{ideal} - DIV_{real}}{DIV_{ideal}} \right| \times 100\%$。 2. **STOP模式下哪些外设可保持工作?** 仅LPUART/RTC等少数外设可在STOP模式工作,其他外设需关闭时钟[^1]。 3. **如何验证LSE是否成功替代HSI?** 使用示波器测量LPUART_TX引脚波形周期$T$,验证$BaudRate = \frac{1}{T}$是否符合LSE频率分频。 4. **LPUART唤醒后如何避免数据丢失?** 唤醒后需在5ms内重新初始化时钟(LSE启动时间约1s,故需切回HSI)[^2]。 [^1]: STM32低功耗模式下外设行为与配置 [^2]: LPUART使用LSE时钟的波特率配置限制 [^3]: STOP模式功耗优化实测数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值