打印
[应用相关]

stm32的掉电检测机制——PVD

[复制链接]
188|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
有时在一些应用中,我们需要检测系统是否掉电了,或者要在掉电的瞬间需要做一些处理。

STM32内部自带PVD功能,用于对MCU供电电压VDD进行监控。

STM32就有这样的掉电检测机制——PVD(Programmable Voltage Detecter),即可编程电压检测器。通过PVD我们可以设定一个基准电压,当芯片的供电电压高于或低于该基准电压时便产生PVD中断,我们可以在PVD中断里做一些处理。

本文以STM32L051为例,来说明PVD的使用。

以下是STM32L051用户手册中对PVD的描述,根据这张图我们可以知道,PVD中断在内部是连接在中断线16的,软件上可以配置



PVD总共可以设置7个等级, 可以通过PWR_CR寄存器的PLS[2:0]来设置。 通过电源控制寄存器中的PLS[2:0]位可以用来设定监控电压的阀值,通过对外部电压进行比较来监控电源。当条件触发,需要系统进入特别保护状态,执行紧急关闭任务:对系统的一些数据保存起来,同时对外设进行相应的保护操作。

下面是PLS的描述, 其中最后一个等级是特殊的, 它使用PB7引脚的电压和内部基准电压进行比较, 使用这一等级时, PB7必须设置成模拟输入。 一般而言, 我们用前6个等级就足够了, 具体选择哪个等级需要根据自己板子的实际情况来定夺, 例如当MCU是3.3V供电且电源非常稳定时, 就可以选择将阈值设置成3.1V, 这样在掉电时就可以更早的触发PVD中断做紧急处理。



同时也要注意电路上储能电容是否够大, 这会影响PVD中断能处理多少代码, 因为系统很快就要完全断电了。


在软件编程上, PVD的使用非常的简单, 下面是一份HAL库的例子。 PVD的初始化只需要提供2个参数, 一个是PVDLevel, 也就是上文提到的7个等级; 另一个参数是Mode, 即中断的边沿选择或事件的边沿选择, 一般用中断就足够了, 事件没用过。 当设置为双边沿中断时, 可以通过PWR_CSR的PVDO位来判断是上升沿还是下降沿, HAL库已经封装好了相应的宏:
__HAL_PWR_GET_FLAG, 通过__HAL_PWR_GET_FLAG( PWR_FLAG_PVDO )就可以获取PVDO位的状态, 为0则是VDD高于阈值(上电的情况), 为1则是VDD小于阈值(掉电的情况) 。
实测在掉电时, MCU会多次进入PVD中断, 这应该是因为掉电瞬间电压不稳定导致的。 因此如果在掉电前要做一些紧急操作, 要记得加个静态变量标记, 使紧急操作只执行一次。




操作流程:使用HAL库版本

/* 初始化PVD */
void PVD_Init(void)
{
        PWR_PVDTypeDef PvdStruct;
        HAL_PWR_EnablePVD(); /* 使能PVD */

        PvdStruct.PVDLevel = PWR_PVDLEVEL_6;  /* PVD阈值3.1V */
        PvdStruct.Mode = PWR_PVD_MODE_IT_RISING; /* 检测掉电 */
        HAL_PWR_ConfigPVD(&PvdStruct);  


        HAL_NVIC_SetPriority(PVD_IRQn, 0, 0);  /* 配置PVD中断优先级 */
        HAL_NVIC_EnableIRQ(PVD_IRQn);  /* 使能PVD中断 */

}

/* PVD中断处理 */
void PVD_IRQHandler(void)
{

        if(__HAL_PWR_GET_FLAG( PWR_FLAG_PVDO )) /* 1为VDD小于PVD阈值,掉电情况 */
        {   
        /* 掉电前的紧急处理 */
        }
}

操作流程:不使用HAL库版本

1)、系统启动后启动PVD,并开启相应的中断。

PWR_PVDLevelConfig(PWR_PVDLevel_2V8); // 设定监控阀值

PWR_PVDCmd(ENABLE); // 使能PVD

EXTI_StructInit(&EXTI_InitStructure);

EXTI_InitStructure.EXTI_Line = EXTI_Line16; // PVD连接到中断线16上

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //使用中断模式

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Raising;//电压低于阀值时产生中断

EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中断线

EXTI_Init(&EXTI_InitStructure); // 初始

EXTI_InitStructure.EXTI_Trigger的赋值可选项:

EXTI_Trigger_Rising---表示电压从高下降到低于设定阀值时产生中断;

EXTI_Trigger_Falling---表示电压从低上升到高于设定阀值时产生中断;

EXTI_Trigger_Rising_Falling---表示电压上升或下降越过设定阀值时都产生中断。

2)、当工作电压低于设定阀值时,将产生PVD中断,在中断程序中进行相应的处理: void PVD_IRQHandler(void)

{

EXTI_ClearITPendingBit(EXTI_Line16);

…… // 用户添加紧急处理代码处

}

最后顺便说下哪些应用场合会用到PVD, 以下是我工作中遇到过得一些场景。
1.记录设备掉电时间。 这个很好理解, 可能业务上就有这个需求, 或者可以利用这一点来完成低功耗设备的待机时长测试。

2.通知其他处理离线。 假如设备中有由干电池供电的MCU1和由锂电池供电的MCU2, MCU1的部分功能可能需要MCU2来完成, MCU1需要知道MCU2是否离线(因为锂电池可拔插, 可能随时被拔) 。 这种情况就可以在MCU2上利用PVD来通知MCU1。 通知的方式有很多, 例如串口直接通知另一方自己将要断电了。 不过要注意低功耗下的使用场景, 例如STM32进入STOP模式时, 系统时钟是关闭的, 此时串口发送的数据波特率可能不是期望的波特率, 被通知方收到的数据可能是错的, 因此建议将通知方的串口时钟源配置成HSI, 并且将低功耗唤醒后的默认时钟配成HSI, 这样一旦在低功耗状态下进入PVD, 串口发送的数据也不会有问题。

3.PVD所对应的时钟需要使能;对于stm32的外设或者模块的操作(配置、使用),在前期的配置中,基本上都是需要使能相应的时钟。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/ddidi111/article/details/144886385

使用特权

评论回复
沙发
公羊子丹| | 2025-1-6 07:43 | 只看该作者
看完感觉PVD真是个强大的功能,特别是在掉电保护这块,实用性拉满!

使用特权

评论回复
板凳
周半梅| | 2025-1-6 07:43 | 只看该作者
请问PVD初始化时,如果阈值选错了,会不会导致中断触发的不稳定?

使用特权

评论回复
地板
帛灿灿| | 2025-1-6 07:43 | 只看该作者
这个紧急处理部分要怎么优化才能尽量保证处理时间?毕竟掉电后储能时间很有限。

使用特权

评论回复
5
童雨竹| | 2025-1-6 07:43 | 只看该作者
学到了,原来PVD还能用来记录设备掉电时间,确实是个好思路!

使用特权

评论回复
6
万图| | 2025-1-6 07:44 | 只看该作者
看到中断优先级的配置部分,请问PVD中断的优先级一般建议设置多少?

使用特权

评论回复
7
Wordsworth| | 2025-1-6 07:44 | 只看该作者
实测掉电多次触发中断的情况确实头疼,用静态变量标记确实是个好办法。

使用特权

评论回复
8
Bblythe| | 2025-1-6 07:44 | 只看该作者
我这边也是用3.3V供电,看来设3.1V的阈值比较合适,稳妥!

使用特权

评论回复
9
Pulitzer| | 2025-1-6 07:44 | 只看该作者
请教一下,如果用事件模式而不是中断模式,有什么场景会更合适?

使用特权

评论回复
10
Uriah| | 2025-1-6 07:44 | 只看该作者
对于多个MCU间的掉电通知,这个串口波特率问题要多加注意了,之前还真没想到。

使用特权

评论回复
11
Clyde011| | 2025-1-6 07:45 | 只看该作者
学习到了PVD的很多应用场景,尤其是和低功耗结合的用法,太实用了!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

20

帖子

0

粉丝