当前位置:   article > 正文

GD32F130之LVD低压检测_单片机lvd

单片机lvd

简介

LVD的功能是检测 单片机VDD / VDDA 引脚上的供电电压是否低于低电压检测阈值,该阈值由电源控制寄存器(PMU_CTL)中的LVDT[2:0]位进行配置。有以下几种阈值可选:

低压检测阈值选择LVDT[2:0] 

  • 000:2.2V
  • 001:2.3V
  • 010:2.4V
  • 011:2.5V
  • 100:2.6V
  • 101:2.7V
  • 110:2.8V
  • 111:2.9V

LVD的检测结果就是以标志位LVDF的形式体现的,当芯片的VDD 和VDDA引脚输入的电压低于PMU_CTL寄存器中的LVDT[2:0]位进行配置的阈值电压时,LVDF标志硬件置1,否则LVDF硬件清0。可见LVDF标志只读,完全由硬件改写

以下是简化后的LVD阈值波形图。手册上的图强调了LVD有100mV的迟滞电压,也就是说在掉电阶段,实际触发低压检测事件的阈值是比设置的阈值低100mV左右的。为了方便理解,这里忽略这个因素。

从下图可以发现,在上电阶段,电源引脚电压上升,LVDF会从1变为0,但是我们一般不检测这个阶段,所以可以忽略。在断电阶段,电源引脚电压下降,LVDF会从0变为1,触发低压事件。

PMU的配置

LVD低压检测属于电源管理单元(PMU)中的一部分,所以要使用LVD,需要打开PMU的外设时钟。

rcu_periph_clock_enable(RCU_PMU);        //使能电源管理单元时钟

LVD的配置

LVD的寄存器很简单。RCU模块中,与LVD相关的只有3处寄存器位段:PMU_CTL.LVDT[2:0] 、 PMU_CTL.LVDEN 以及 PMU_CS.LVDF。

  • PMU_CTL.LVDT[2:0]:配置低压检测阈值
  • PMU_CTL.LVDEN:用于使能或者关闭LVD功能
  • PMU_CS.LVDF:低压事件标志位,由硬件设置,软件只读

标准库中提供了一个函数用于配置LVD,如下:

  1. //文件:gd32f1x0_pmu.c
  2. //功能:设置低压检测阈值,并使能LVD功能
  3. void pmu_lvd_select(uint32_t lvdt_n)
  4. {
  5. PMU_CTL &= ~PMU_CTL_LVDEN; /* disable LVD */
  6. PMU_CTL &= ~PMU_CTL_LVDT; /* clear LVDT bits */
  7. PMU_CTL |= lvdt_n; //设置LVD检测阈值
  8. PMU_CTL |= PMU_CTL_LVDEN; //使能低压检测机制
  9. }

通过EXTI来使用LVD中断

LVD事件连接至EXTI的第16线,用户可以通过配置EXTI的第16线产生相应的中断,即通过低压标志位LVDF的高和低的变化来触发EXTI Line16的中断。所以LVD中断必须借助EXTI去完成。EXTI Line16只用于服务LVD,没有其他的触发源可选。

由于我们通常只关注掉电阶段的低压检测事件,因此应该配置EXTI的检测沿为上升沿触发

注意,虽然LVD中断是通过EXTI 来实现的,但是其中断在名义上却是LVD中断:要开启LVD中断使能,并编写LVD中断服务函数。

  1. nvic_irq_enable(LVD_IRQn,2,0); //使能LVD检测中断
  2. //LVD中断函数
  3. void LVD_IRQHandler(void)
  4. {
  5. //LVD紧急操作,例如写入重要数据到Flash做掉电存储
  6. }

使用LVD中断来实现掉电数据保护

在许多应用场景中,都有在单片机断电前及时将关键数据写入到非易失存储器中保存,以便下次开机再次恢复关键数据的需求。这种需求可以使用LVD中断来实现。当单片机电源断开时,必定导致其VDD/VDDA引脚上的电压缓慢下降,最终为0。尤其是当单片机电源加了大电容时,掉电过程会更加缓慢。那么单片机在触发LVD中断后,就会有更充足的时间去执行数据紧急存储操作。

使用LVD来做掉电存储的优点是无需外加复杂的断电检测电路,同时也避免反复写Flash或者EEPROM存储器,降低存储器寿命,因为只需要在掉电的时候写存储器就行了。

下面是一个例子,使用flag变量来决定LED闪烁的快慢,flag在每次掉电时,取反后存储到片上Flash。每次上电时从Flash读取到变量中。其结果是每断电上电一次,LED的闪烁频率就会改变一次。

  1. #include "gd32f1x0.h"
  2. #include <stdio.h>
  3. void delay_ms(uint32_t n)
  4. {
  5. uint32_t j;
  6. while(n--)
  7. {
  8. j=18888;
  9. while(j--);
  10. }
  11. }
  12. #define LED13_ON gpio_bit_set(GPIOC,GPIO_PIN_13)
  13. #define LED13_OFF gpio_bit_reset(GPIOC,GPIO_PIN_13)
  14. #define LED13_TOG \
  15. do{ \
  16. if(gpio_output_bit_get(GPIOC,GPIO_PIN_13)) \
  17. gpio_bit_reset(GPIOC,GPIO_PIN_13); \
  18. else \
  19. gpio_bit_set(GPIOC,GPIO_PIN_13); \
  20. }while(0)
  21. void RCU_config(void)
  22. {
  23. rcu_periph_clock_enable(RCU_GPIOC); //打开GPIOC外设时钟
  24. rcu_periph_clock_enable(RCU_PMU); //使能电源管理单元时钟
  25. }
  26. void NVIC_config(void)
  27. {
  28. nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
  29. nvic_irq_enable(LVD_IRQn,2,0); //使能LVD检测中断
  30. }
  31. void LVD_config(void)
  32. {
  33. while(RESET != pmu_flag_get(PMU_FLAG_LVD)) ; //越过上电阶段
  34. pmu_lvd_select(PMU_LVDT_7); //配置检测阈值,使能LVD功能
  35. }
  36. void EXTI_config(void)
  37. {
  38. //EXTI Line 16 for LVD
  39. exti_flag_clear(EXTI_16);
  40. exti_init(EXTI_16,EXTI_INTERRUPT,EXTI_TRIG_FALLING); //检测下降沿
  41. }
  42. void GPIO_config(void)
  43. {
  44. //配置PC13推挽输出
  45. gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
  46. gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_13);
  47. }
  48. //掉电存储数据的起始Flash Page
  49. #define USER_FLASH_S_ADDR (0x08000000 + 32*1024)
  50. volatile uint32_t flag;
  51. int main(void)
  52. {
  53. RCU_config(); //外设时钟初始化
  54. NVIC_config(); //NVIC初始化
  55. LVD_config(); //LVD初始化
  56. EXTI_config(); //EXTI 初始化
  57. GPIO_config(); //GPIO初始化
  58. flag = REG32(USER_FLASH_S_ADDR); //从Flash加载数据到内存变量flag
  59. //擦除flag所在的page,为掉电存储做准备
  60. fmc_unlock();
  61. fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
  62. fmc_page_erase(USER_FLASH_S_ADDR);
  63. fmc_lock();
  64. while(1)
  65. {
  66. LED13_TOG;
  67. if(flag==0){
  68. delay_ms(100);
  69. }
  70. else{
  71. delay_ms(500);
  72. }
  73. }
  74. }
  75. //LVD中断函数
  76. void LVD_IRQHandler(void)
  77. {
  78. __disable_irq();
  79. //将flag取反然后写入到Flash掉电存储
  80. fmc_unlock();
  81. fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
  82. fmc_word_program(USER_FLASH_S_ADDR,!flag);
  83. fmc_lock();
  84. __enable_irq();
  85. exti_interrupt_flag_clear(EXTI_16); //清除EXTI Line中断标志
  86. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/427487
推荐阅读
相关标签
  

闽ICP备14008679号