因为网上很少人做模拟看门狗的实验,所以资料比较少.要实现模拟看门狗,要有以下几个条件.
- 只能检测一个通道或者监测所有通道.
- 监测过程其实也是ADC不断转换过程.
- 设置高低门限,再门限内不会发生中断,再门限外发生中断.
- 在发生中断时候,中断不会自己清除.
可以把电源监测中的PVD理解成一个特殊的ADC模拟看门狗中断,只不过PVD的精度比较低,只有8档比较,而且不能比较过高的问题,ADC可以从0~4095全量程可以比较.比如监测220V电压的稳定性,然后给出报警,通过调理电路得出0 - 4095映射0 - 240V,那么0.1V的变化都可以被监测到.
好了,废话挺多的,我们实验做一个LED触发,如果模拟引脚接了GND或者接了VCC,都会亮灯,悬空不会亮灯.在数字电路上,怎么处理呢,可以试着内部数字上拉,看看当前电平是否为高,再试着内部下拉,看当前电平是否为低,如果内部上拉读为低或者内部下拉读取为高,肯定是非悬空,当然也可能外部的拉能力特别小.(电流输入小)
这个程序实现了门限检测,如果AIN接入GND/VCC都会导致PB3亮灯,悬空不会亮灯.
#include "stm32l0xx.h" __IO uint32_t uwTick; void SysTick_Delay(__IO uint32_t Delay) { uint32_t tickstart = 0U; tickstart = uwTick; while((uwTick - tickstart) < Delay) { } } void RCC_Init(void) { /* LSE OFF,LSI DEFAULT,MSI OFF,HSI ON,PLL ON,SYSCLK = 32MHz,CK_PWR = FCLK = HCLK = SysTick = APB1 = APB2 = 32MHz.*/ FLASH->ACR = FLASH_ACR_PRE_READ | FLASH_ACR_PRFTEN; MODIFY_REG(PWR->CR, PWR_CR_VOS, (PWR_CR_VOS_0)); MODIFY_REG(RCC->CR, RCC_CR_HSION | RCC_CR_HSIDIVEN , RCC_CR_HSION); while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == RESET); MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSITRIM, (uint32_t)(16) << 8U); CLEAR_BIT(RCC->CR, RCC_CR_PLLON); while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != RESET); MODIFY_REG(RCC->CFGR, RCC_CFGR_PLLMUL | RCC_CFGR_PLLDIV | RCC_CFGR_PLLSRC, (uint32_t)((RCC_CFGR_PLLMUL4) | (RCC_CFGR_PLLDIV2) | (RCC_CFGR_PLLSRC_HSI))); SET_BIT(RCC->CR, RCC_CR_PLLON); while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == RESET); MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (uint32_t)(0x01U)); MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_CFGR_HPRE_DIV1); MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL); while ((uint32_t)(RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_CFGR_PPRE1_DIV1); MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_CFGR_PPRE1_DIV1) << 3)); CLEAR_BIT(RCC->CR, RCC_CR_MSION); /* SysTick CLK = 4MHz,Reload = 1kHz. */ SysTick->LOAD = (uint32_t)0x00000F9FUL; NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); SysTick->VAL = 0UL; SysTick->CTRL = SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* SysTick->CTRL = SysTick_CTRL_TICKINT_Msk; */ } void ADC1_COMP_IRQHandler(void) { /* 检查模拟看门狗 */ if(READ_BIT(ADC1->ISR, ADC_ISR_AWD) && READ_BIT(ADC1->IER, ADC_IER_AWDIE)) { /* 设置LED表示警报. */ SET_BIT(GPIOB->ODR, GPIO_ODR_OD3); /* 清标志位 */ SET_BIT(ADC1->ISR, ADC_ISR_AWD); } } void ADC_GetVDD_Voltage(void) { /* 初始化时钟 */ SET_BIT(RCC->APB2ENR, (RCC_APB2ENR_ADC1EN)); SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN); SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOBEN); /* 上电没配置过,默认除了JTAG外引脚都是模拟引脚,所以懒得配置了. */ /* PB3 LED */ MODIFY_REG(GPIOB->MODER, GPIO_MODER_MODE3, GPIO_MODER_MODE3_0); CLEAR_BIT(GPIOB->ODR, GPIO_ODR_OD3); /* 初始化相关寄存器 */ ADC1->CFGR1 = 0x00C0B000; /* 连续采样 + OVR覆盖(数据不用,只用作比较.) + AUTO OFF(自动降低功耗) + 看门狗监测单通道 */ ADC1->CFGR2 = 0x40000000; /* 连续采样模式,这样就不用每次都Start. */ ADC->CCR = 0x00000000; /* None */ ADC1->SMPR = 0x00000007; /* 采样时间寄存器,0 = 1.14Msps,1 = 1Msps,2 = 800Ksps,3 = 640Ksps,4 = 500Ksps,5 = 308Ksps,6 = 174Ksps,7 = 92ksps, @ 16MHz */ ADC1->CHSELR = 0x00000001; /* PA0 */ ADC1->TR = 0x0FA00014; /* 上门限0x0FA0(4000),下门限0x0014(20). */ /* 校准ADC */ SET_BIT(ADC1->CR, ADC_CR_ADCAL); while(READ_BIT(ADC1->CR, ADC_CR_ADCAL)); /* 设置看门狗 */ SET_BIT(ADC1->IER, ADC_IER_AWDIE); SET_BIT(ADC1->CR, ADC_CR_ADEN | ADC_CR_ADSTART); NVIC_SetPriority(ADC1_COMP_IRQn, 0); NVIC_EnableIRQ(ADC1_COMP_IRQn); } int main(void) { RCC_Init(); ADC_GetVDD_Voltage(); while (1) { SysTick_Delay(1000); CLEAR_BIT(GPIOB->ODR, GPIO_ODR_OD3); } }