BOD
Brown-Out Detection,又称掉电检测,一般用来检测单片机电源掉到一定电压之后执行相应操作。
有些产品由于受外围电路的影响,在断电时会存在残余电压,使得单片机仍能运行(一般情况下是外设停止,但内核运行),这样变会出现单片机无法正常复位,更严重点如果电压不稳会导致内核pc指针跑飞,造成程序灾难。
为了避免这个现象,我们可以在单片机程序中加入BOD检测功能,使单片机在检测到掉电到一定电压后,能够执行复位操作。
BOD分为几个等级:如下
#define BOD_INT_RESV (0 << 2) /* Reserved */
#define BOD_INT_LVL1 (1 << 2) /* 2.3 ~2.4 */
#define BOD_INT_LVL2 (2 << 2) /* 2.6 ~2.7 */
#define BOD_INT_LVL3 (3 << 2) /* 2.8 ~2.9 */
/* BOD复位电压 */
#define BOD_RST_RESV (0 << 0) /* Reserved */
#define BOD_RST_LVL1 (1 << 0) /* 2.1 ~2.2 */
#define BOD_RST_LVL2 (2 << 0) /* 2.4 ~2.5 */
#define BOD_RST_LVL3 (3 << 0) /* 2.6 ~2.8 */
我们可以根据自己的需要选择不同的等级,需要考虑的是外设的工作电压,如E2Prom,Flash等。
BOD初始化代码如下,一般放置在main函数的初始进行初始化。笔者用的是NXP的一款芯片。
void BODInit(void)
{
LPC_SYSCON->BODCTRL = BOD_INT_LVL3 | /* BOD中断电压2.8 ~ 2.9 */
BOD_RST_LVL2 | /* BOD复位电压2.4 ~ 2.5 */
BOD_RST_ENABLE; /* BOD复位功能使能 */
NVIC_EnableIRQ(BOD_IRQn); /* 打开BOD中断 */
}
int main (void)
{
SystemInit(); /* 初始化目标板,切勿删除 */
GPIOInit(); /* GPIO初始化 */
BODInit(); /* BOD初始化 */
if ((LPC_SYSCON->SYSRSTSTAT & BOD_RESET) == BOD_RESET) { /* 掉电复位,LED闪烁 */
LPC_SYSCON->SYSRSTSTAT |= BOD_RESET; /* 清除掉电复位标志位 */
while (1) {
LPC_GPIO_PORT->PIN[0] &= ~LED; /* 点亮LED */
myDelay(100); /* 延时 100ms */
LPC_GPIO_PORT->PIN[0] |= LED; /* 熄灭LED */
myDelay(100); /* 延时 100ms */
}
} else {
while (1) {
LPC_GPIO_PORT->PIN[0] &= ~LED; /* 上电复位,点亮LED */
}
}
}
关于BOD汇编启动
既然我们可以在初始化的时候配置BOD的参数,那为什么还需要用汇编启动呢?
考虑之一是单片机内核从启动代码启动到运行到main函数的时候,需要有及ms的延时,虽然时间在ms级,但是对于一些严格要求的程序和产品,芯片在上电时由于电压抖动会导致芯片PC值跑飞,由于此时还没有初始化BOD,因此无法完成复位。
解决办法之一便是在启动代码中增加BOD初始化,使BOD在运行在main函数之前便完成初始化,可防止上电电压抖动造成的不必要的影响。
启动代码中汇编BOD的初始化代码如下。
首先声明BOD初始化程序。
; Cortex-M version
;
MODULE ?cstartup
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3)
SECTION .intvec:CODE:NOROOT(2)
EXTERN __iar_program_start
EXTERN SystemInit
EXTERN BODInit //声明BOD函数
EXTERN IRC_Only_SystemInit
PUBLIC __vector_table
PUBLIC __vector_table_0x1c
DATA
__vector_table
DCD sfe(CSTACK) ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
然后在程序执行main之前加入执行BODinit的代码段。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Default interrupt handlers.
;;
THUMB
PUBWEAK Reset_Handler
SECTION .text:CODE:REORDER:NOROOT(2)
Reset_Handler
LDR R0, =BODInit //加入BODInit 此函数体在main中
BLX R0
LDR R0, =SystemInit
BLX R0
LDR R0, =__iar_program_start
BX R0
这样便可完成BOD的汇编启动。