LVR 与 LVD 简单介绍、使用、实际使用LVD侦测多种电压状态(九齐NY8为例)

LVR 与 LVD 简单介绍、使用、实际使用LVD侦测多种电压状态(九齐NY8为例)本次使用九齐 NY8 系列芯片 示例代码使用的芯片为 NY8A051H 其他 NY8 系列芯片的 LVD 使用相差无几 但还请确认不同芯片的芯片手册之间是否有所区别

大家好,欢迎来到IT知识分享网。

本章内容:LVR 与 LVD 介绍,使用方式,代码案例,注意事项,源码解释,LVD侦测多种电压实战

本次使用九齐NY8系列芯片,示例代码使用的芯片为NY8A051H,其他NY8系列芯片的LVD使用相差无几,但还请确认不同芯片的芯片手册之间是否有所区别。

一、LVR

LVR:低电压复位,当供电低于设定的低电压值时,它会自动将芯片复位,以防止异常运行。

(一)设置LVR电压

请添加图片描述

(二)使能LVR

void system_init(void) { 
    //.... //其他初始化操作 PCON |= C_LVR_En; //LVR使能 //.... } 

二、LVD

LVD:低电压检测,它用于检测芯片供电电压是否低于一定值,当电压低于这个值的时候,会将 LVDOUT 置 0

请添加图片描述

(一)代码案例

案例描述:芯片检测电压控制小灯,PB1接绿灯接地,PB2接红灯接地

​ 1.当电压大于4.1V时,绿灯亮,红灯灭

​ 2.当电压低于4.1V时,红灯亮,绿灯灭

#include <ny8.h> #include "ny8_constant.h" /* * 案例代码 */ void main() { 
     DISI(); //禁中断 INTE = 0x00; IOSTB = C_PB_Output; //设置全部PB引脚为输出模式 PORTB = 0x00; //全部PB脚输出低电平 PCON = C_WDT_En; //使能看门狗 //*低电压检测初始化设置* CMPCR = 0x0A; //电压选择控制寄存器 PCONbits.LVDEN = 1; //使能LVD PCON |= C_LVD_4P1V; //设置LVD检测电压为4.1V //* while(1) { 
     //如果PCON1 & C_LVDOUT的值为1,说明当前输入电压大于4.1V if(PCON1 & C_LVDOUT) { 
     PORTBbits.PB1 = 1; //绿灯亮 PORTBbits.PB2 = 0; //红灯灭 } //否则,输入电压小于4.1V else { 
     PORTBbits.PB1 = 0; //绿灯灭 PORTBbits.PB2 = 1; //红灯亮 } CLRWDT(); // 清理看门狗 } } 

(二)注意事项

上述代码很接近官网示例,简单描述了 LVD 初始化以及使用,在第一次使用时,我便踩了不少坑,我先细细盘点我遇到的各种问题:

  1. LVD实际上就是一个比较器,不同芯片对其的封装便可能有区别,有的芯片在低于设定值时,读取LVDOUT会得到0;但是有的芯片在低于设定值时,读取LVDOUT会得到1。所以,确定LVDOUT的输出需要在官网查看官方文档的内部电路结构
  2. LVD也可以侦测不同电压,每改变检测电压时,需要延时特定时间才能得到正确的状态值。这个具体也会在芯片手册中的标题LVD下说明。请添加图片描述

(三)源码解释

//;------------------------------------------------------------  //; PCON1 (0FH) --------- 电源控制寄存器1 //;------------------------------------------------------------ //bit7:为全部中断使能 #define C_All_INT_En 0x80 //启用所有未被屏蔽的中断 //bit6:低压检测器输出 低压为0,非低压为1 #define C_LVDOUT 0x40 //【只读】 //bit[5:2] : 选择LVD电压 (注:必须设置CMPCR为0001010b,即0x0A) #define C_LVD_3P75V 0x3C //电压3.75V  #define C_LVD_3P45V 0x38 //电压3.45V  #define C_LVD_3P2V 0x34 //电压3.2V  #define C_LVD_4P15V 0x30 //电压4.15V  #define C_LVD_2P6V 0x2C //电压2.6V #define C_LVD_4P05V 0x28 //电压4.05V  #define C_LVD_1P95V 0x24 //电压1.95V  #define C_LVD_3P9V 0x20 //电压3.9V  #define C_LVD_3P6V 0x1C //电压3.6V  #define C_LVD_3P3V 0x18 //电压3.3V  #define C_LVD_3P0V 0x14 //电压3.0V #define C_LVD_2P9V 0x10 //电压2.9V  #define C_LVD_2P8V 0x0C //电压2.8V #define C_LVD_2P4V 0x08 //电压2.4V #define C_LVD_2P2V 0x04 //电压2.2V #define C_LVD_2P0V 0x00 //电压2.0V //bit0 : 使能定时器0 #define C_TMR0_En 0x01 // 使能定时器0 #define C_TMR0_Dis 0x00 // 禁用定时器0 

(四)LVD 侦测多种电压

在注意事项中,我提到LVD也可以侦测不同电压,但相对来说还挺复杂,便以一个实战来讲述这个设置方式。

注:NY8A051H 在修改PCON[5:2]时,需要延时50us才能得到正确的状态值,这是通过芯片手册得知,不同芯片可能会有差别

芯片封装:051H合封
在这里插入图片描述
原理图:
在这里插入图片描述
案例描述:
之前用过九齐051H与4054的合封芯片,PB4在芯片内部与4054的CHRG脚连接(充电时CHRG脚低电平,充满或不充时高阻塞),外部有四个引脚(PB0,PB1,PB2,PB3),分别连接了前灯,侧灯,红色LED指示灯,按键
需求说明:
一、充电部分
1.充电时:红灯常亮
2.充满或未充电时:红灯熄灭
3.电池电压低于3V时,红灯闪烁
二、功能要求
1.一档:LED1以780mA亮灯;0-3min:780mA保持;3-6min:电流缓慢下降,6min后,保持500mA。
2.二档:LED1爆闪模式,频率8 Hz。
3.三档:LED2以300mA亮灯;0-3min:300mA保持;3-6min,电流缓慢下降,6min后,保持;
4.四档:关掉所有灯。
三、待机时进入休眠模式
四、其他要求,在充满电后,如果不开灯或者插拔电源,红灯不能再重新亮起
五、低压关断:2.7V
头疼的问题:
充满电后,过了十几分钟4054会重新充电,导致红灯亮起,这不被允许,所以只好加LVD检测4.1V左右电压,以阻止此事发生。



















user_config.h

#ifndef user_config_H #define user_config_H #include <ny8.h> #include "ny8_constant.h" #define u8 unsigned char #define u16 unsigned int #define u32 unsigned long #define ENABLE 1 #define DISABLE 0 #define TRUE 1 #define FALSE 0 #define SET 1 #define RESET 0 #define INC 1 #define DEC 0 #define ON 0 #define OFF 1 #define BIT0 0x01 #define BIT1 0x02 #define BIT2 0x04 #define BIT3 0x08 #define BIT4 0x10 #define BIT5 0x20 #define BIT6 0x40 #define BIT7 0x80 #define BIT8 0x100 #define BIT9 0x200 #define BIT10 0x400 #define BIT11 0x800 #define BIT12 0x1000 #define BIT13 0x2000 #define BIT14 0x4000 #define BIT15 0x8000 #define IO_CHRG PB4 #define IO_KEY PB3 #define IO_COB1 PB2 #define IO_COB2 PB1 #define IO_LEDR PB0 #define TMR0_T 170 //50us #define TMR0_PS C_PS0_Div2 //64分频 #define SYSTEM_5MS BIT0 #define SYSTEM_100MS BIT1 #define CHARGE_OFF 0 //未充电 #define CHARGE_ON 1 //充电中 #define CHARGE_FULL 2 //充满 #define UPDATE_REG(x) __asm__("MOVR _" #x ",F") #endif 

main.c

#include "check.h" #include "pub_config.h" #define KEY_FILTER 6 //按键抖动滤波次数 #define COB_MAX 116 #define COB_MIN 64  #define COB_SEC_DELAY 180 #define COB_CNT_DELAY 200 extern u8 cnt; u8 cob_cnt = 0; //档位1毫秒计数(每5ms加1) u8 cob_sec = 0; //档位秒计数 u8 cob_step = 0; //档位1状况,0-3 78亮,3-6 78->50,6 50 u8 key_scan = 0; //按键状态 u8 key_last = 0; //上一次按键状态 u8 key_filter = 0; //按键抖动计数器 u8 cob_gear = 0; //档位 u8 cob1_duty = 0; //占空比 u8 cob2_duty = 0; //占空比 volatile u8 sleep_delay = 0; volatile u8 system_tick = 0; void System_Init(void); void LED_Show(void); void LED_Task(void); void Key_Task(void); void Sleep_Task(void); /* * 每5ms定时器触发中断 */ void isr() __interrupt(0) { 
     static u8 tick_5ms = 0; static u8 tick_100ms = 0; if(T0IF)//Timer0溢出中断标志 { 
     T0IF = 0;//清除中断标志 TMR0 = TMR0_T; if(++tick_5ms > 100) { 
     tick_5ms = 0; system_tick |= SYSTEM_5MS; if(++tick_100ms >= 20) { 
     tick_100ms = 0; system_tick |= SYSTEM_100MS; } } } if(PBIF) { 
     PBIF = 0; sleep_delay = 0; } } void main(void) { 
     System_Init(); voltage_reset(); CLRWDT(); while(1) { 
     LED_Show(); if(system_tick & SYSTEM_5MS) { 
     CLRWDT(); system_tick &= ~SYSTEM_5MS; Key_Task();//检查按键 LED_Task();//检查灯 } if(system_tick & SYSTEM_100MS) { 
     CLRWDT(); system_tick &= ~SYSTEM_100MS; Check_CHAG_Task(); //检测是否充满电 Sleep_Task(); //休眠 } } } void System_Init(void) { 
     DISI(); //关中断 //GPIO PORTB = 0x00; //全部输出低电平 IOSTB = C_PB3_Input | C_PB4_Input; //PB3 PB4 输入,其他输出 BPHCON = (unsigned char)~(C_PB3_PHB | C_PB4_PHB);//PB3 PB4 上拉 //时钟 PCON1 = C_TMR0_Dis; //关闭时钟 TMR0 = TMR0_T; //初始化Timer0寄存器 T0MD = TMR0_PS; //分频率64 PCON = C_WDT_En | C_LVR_En | C_LVD_En; //使能看门狗 CMPCR = 0x0A; PCONbits.LVDEN = 1; PCON1 = C_TMR0_En | C_LVD_2P9V; //使能时钟  //充电和按键唤醒 BWUCON = C_PB3_Wakeup | C_PB4_Wakeup;//充电和按键唤醒 INTE = C_INT_TMR0 | C_INT_PBKey; //使能Timer0溢出中断和PB输入变化中断 UPDATE_REG(PORTB); INTF = 0; //清除所有中断标志 ENI(); //开中断 } //按键任务 void Key_Task(void) { 
     //当前高电平,却被按下,清除 if (IO_KEY) { 
     if (key_scan) key_filter = 0; key_scan = 0; } //当前低电平,按键状态为0,设置为1,记为按下 else { 
     if (!key_scan) key_filter = 0; key_scan = 1; } //按键抖动计数 if (key_filter < KEY_FILTER) { 
     key_filter++; sleep_delay = 0; } //按键有效 else if (key_last != key_scan) { 
     key_last = key_scan; if (key_scan == 0) return; if (cob_gear == 0) cob_gear = 1; else if (cob_gear == 1) cob_gear = 2; else if (cob_gear == 2) cob_gear = 3; else cob_gear = 0; } } void LED_Show(void) { 
     static u8 pwm_cnt = 0; if(cob_gear) { 
     pwm_cnt++; IO_COB1 = pwm_cnt < cob1_duty ? 1 : 0; IO_COB2 = pwm_cnt < cob2_duty ? 1 : 0; if(pwm_cnt >= 200) pwm_cnt = 0; } else { 
     IO_COB1 = 0; IO_COB2 = 0; } } void LED_Task(void) { 
     switch(cob_gear) { 
     case 0: cob1_duty = 0; cob2_duty = 0; cob_cnt = 0; cob_sec = 0; cob_step = 0; break; case 1: cob2_duty = 0; cob_cnt++; if(cob_cnt >= COB_CNT_DELAY) { 
     cob_cnt=0; cob_sec++; } //每3分钟进入下一步 if(cob_sec >= COB_SEC_DELAY) { 
     cob_sec = 0; if(++cob_step > 2) cob_step = 2; } //根据档位状况,调整占空比 switch(cob_step) { 
     case 0: cob1_duty = COB_MAX; break; case 1: //每6秒调低1%占空比 if(++cob_sec % 6 == 0) { 
     if(--cob1_duty <= COB_MIN) cob_step++; } break; default: cob1_duty = COB_MIN; break; } break; case 2: //清理档位1 cob2_duty = 0; if(++cob_cnt <= 12) cob1_duty = COB_MAX; else if(++cob_cnt <= 25) cob1_duty = 0; else cob_cnt = 0; break; case 3: cob1_duty = 0; cob2_duty = 61; break; default: cob_gear = 0; cob1_duty = 0; cob2_duty = 0; break; } } //休眠 void Sleep_Task() { 
     //如果开着灯或在充电或低压,不休眠 if(cob_gear || charge_state) { 
     sleep_delay = 0; return; } //休眠延时达到,进入休眠 if(++sleep_delay >= 10) { 
     sleep_delay = 0; PCON &= ~C_WDT_En; PCON1 &= ~C_TMR0_En; NOP(); cnt = 0; IO_COB1 = 0; IO_COB2 = 0; IO_LEDR = 0; NOP(); SLEEP(); NOP(); NOP(); PCON = C_WDT_En | C_LVR_En | C_LVD_En; PCON1 = C_TMR0_En | C_LVD_2P9V; } } 

check.h

#ifndef check_H #define check_H #include "user_config.h" extern volatile u8 voltage_state; extern volatile u8 charge_state; extern volatile u8 charge_flag; #define CHARGE_OFF 0 //未充电 #define CHARGE_ON 1 //充电中 #define CHARGE_FULL 2 //充满电 typedef enum { 
     VOLTAGE_OFF = 0, VOLTAGE_LOW , VOLTAGE_FULL, }VOLTAGE_TypeDef; void voltage_reset(); void Check_CHAG_Task(void); #endif 

check.c

#include "user_config.h" #include "check.h" #define LVD_CLEAR() PCON1 &= ~(BIT2 | BIT3 | BIT4 | BIT5) #define LVD_SET_OFF() PCON1 |= C_LVD_2P8V  #define LVD_SET_LOW() PCON1 |= C_LVD_2P9V #define LVD_SET_FULL() PCON1 |= C_LVD_4P15V #define CHECK_FILTER 5 //充电抖动滤波次数 u8 cnt = 0; volatile u8 voltage_state = 0; //电压状态 volatile u8 charge_state = 0; //充电状态 volatile u8 charge_flag = 0; u8 charge_last_state = 0; //上一次充电状态 u8 check_filter = 0; //充电抖动计数 extern volatile u8 sleep_delay; extern u8 cob_gear; //档位 void check_set(u8 state) { 
     LVD_CLEAR(); switch(state) { 
     case VOLTAGE_OFF: LVD_SET_OFF(); break; case VOLTAGE_LOW: LVD_SET_LOW(); break; case VOLTAGE_FULL: LVD_SET_FULL(); break; default:break; } } void voltage_reset()//1s { 
     static u8 cnt = 0; u8 check = 0; u8 i = 0; u8 j = 0; voltage_state = VOLTAGE_FULL; while(1) { 
     check_set(voltage_state); //NOP 200 times = delay 100us for(j = 0; j <= 120; j++) { 
     NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP(); } CLRWDT(); if (PCON1 & C_LVDOUT) { 
     return; } if (--voltage_state == VOLTAGE_OFF) return; } } void Check_CHAG_Task(void)//100 { 
     static u8 cnt = 0; static u8 low = 0; static u8 rise = 0; static u16 time = 0; if(PCON1 & C_LVDOUT) { 
     low = 0; if(++rise >= 200) { 
     rise = 0; voltage_reset(); } } else { 
     rise = 0; if(++low >= 20) { 
     low = 0; voltage_reset(); } } if(IO_CHRG) { 
     //chrg拉高后,如果电池电压为满电 if(voltage_state == VOLTAGE_FULL) { 
     charge_state = CHARGE_FULL; } else { 
     charge_state = CHARGE_OFF;//如果电池未满电,则未充电 } if(cob_gear) { 
     charge_state = CHARGE_OFF;//如果开过灯,则状态为未充电 } } else { 
     if(charge_state != CHARGE_FULL)//如果不是充满电状态,则状态改为充电 { 
     charge_state = CHARGE_ON; } } if(charge_state == CHARGE_ON) { 
     IO_LEDR = 1; } else if(voltage_state == VOLTAGE_OFF) { 
     if(++cnt < 5) { 
     IO_LEDR = 1; } else if(cnt < 10) { 
     IO_LEDR = 0; } else { 
     cnt = 0; } } else { 
     IO_LEDR = 0; } } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/132980.html

(0)
上一篇 2025-07-27 15:10
下一篇 2025-07-27 15:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信