STM32L053 低功耗采集时,ADC打开与关闭有时出现问题
STM32L053 隔几秒钟采集一次数据。STM32L053 低功耗时,进入停止模式,通过RTC中断唤醒,唤醒后,打开EnableADC()采集数据,采集完成后,关闭DisableADC(),以节省电池电量。但是有时候出现死循环,不知道是怎么回事,也是按参数手册上面做的,还是不行。void EnableADC(void)
{
ADC1->ISR |= ADC_ISR_ADRDY;
ADC->CCR |= (ADC_CCR_VREFEN|ADC_CCR_TSEN);
ADC1->CR |= ADC_CR_ADEN; //使能ADC
if ((ADC1->CFGR1 &ADC_CFGR1_AUTOFF) == 0)
{
while ((ADC1->ISR & ADC_ISR_ADRDY) == 0)
{
//这里可以添加超时管理
/*打开时,这个地方有时候出现死循环*/
}
}
ADC1->CR |= ADC_CR_ADSTART; //启动ADC转换
}
void DisableADC(void)
{
//确保没有转换
if ((ADC1->CR & ADC_CR_ADSTART) != 0)
{
//停止任何正在进行的转换
ADC1->CR |= ADC_CR_ADSTP;
}
//等到ADSTP由硬件复位即停止转换
while ((ADC1->CR & ADC_CR_ADSTP) != 0)
{
//这里可以添加超时管理
}
ADC1->CR |= ADC_CR_ADDIS; //禁用ADC
//等到ADC是完全禁用
while ((ADC1->CR & ADC_CR_ADEN) != 0)
{
//这里可以添加超时管理
/*关闭时,这个地方有时候出现死循环*/
}
ADC1->ISR |= ADC_ISR_ADRDY;
ADC->CCR &= ~(ADC_CCR_VREFEN|ADC_CCR_TSEN);
}
本帖最后由 wgcrdg 于 2018-2-9 09:51 编辑
下面是开始程序时的ADC与DMA的初始化部分。
uint16_t ADC_array;
//这个函数配置ADC的DMA来存储结果序列,转换的结果存储在n个元素数组
void ConfigureDMA(void)
{
//使外围时钟DMA
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
//启用DMA传输ADC
ADC1->CFGR1 |= ADC_CFGR1_DMAEN;
//配置外围数据寄存器地址
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR));
//配置内存地址
DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
//配置待传输的数据数 的数量
DMA1_Channel1->CNDTR = 6;
//配置使能存储器递增模式、存储器16 位模式、外设16 位模式,
//传输错误中断使能和传输完成中断使能
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 \
| DMA_CCR_TEIE | DMA_CCR_TCIE;
//使能DMA
DMA1_Channel1->CCR |= DMA_CCR_EN;
//启用中断DMA通道1
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
//设置优先级的DMA通道1
NVIC_SetPriority(DMA1_Channel1_IRQn,2);
}
voidADC_Init(void)
{
//使外围时钟GPIOA GPIOC
//AD1=PA4=IN4AD2=PA5=IN5AD3=PA0=IN0 AD4=PC3=IN13
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOCEN;
//设置口线为模拟输入
GPIOA->MODER |= (GPIO_MODER_MODE0|GPIO_MODER_MODE4|GPIO_MODER_MODE5);
GPIOC->MODER |= GPIO_MODER_MODE3;
//使外围ADC的时钟
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
//ADCCLK(异步时钟模式)
ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE;
//选择连续转换模式
ADC1->CFGR1 |= ADC_CFGR1_CONT;
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL4 | ADC_CHSELR_CHSEL13 \
| ADC_CHSELR_CHSEL5 | ADC_CHSELR_CHSEL17 | ADC_CHSELR_CHSEL18;
//采样时间选择39.5 个 ADC 时钟周期
ADC1->SMPR = ADC_SMPR_SMP_0 | ADC_SMPR_SMP_2;
//采样时间选择79.5 个 ADC 时钟周期
//ADC1->SMPR = ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2;
//使能溢出中断 OVR 位置 1 时产生中断
ADC1->IER = ADC_IER_OVRIE;
//使能 VREFINT,使能温度传感器
ADC->CCR |= (ADC_CCR_VREFEN|ADC_CCR_TSEN);
//ADC上启用中断
NVIC_EnableIRQ(ADC1_COMP_IRQn);
//为ADC设置中断优先级
NVIC_SetPriority(ADC1_COMP_IRQn,3);
if(vref_vol == 0)
{
//以下几行为ADC 校准
//确保 ADEN=0
if ((ADC1->CR & ADC_CR_ADEN) != 0)
{
ADC1->CR &= (uint32_t)(~ADC_CR_ADEN);
}
//将 ADCAL 置 1
ADC1->CR |= ADC_CR_ADCAL;
//等待,直至 ADCAL=0
while ((ADC1->ISR & ADC_ISR_EOCAL) == 0)
{
}
//校准已完成
ADC1->ISR |= ADC_ISR_EOCAL;
/* 计算内部Vref电压(mV) */
vref_vol = (uint16_t)( 3000.0 * (*(uint16_t *)0x1FF80078) / 4095.0);
Vrefint_cal=(*(uint16_t *)0x1FF80078);
}
ConfigureDMA();//函数配置ADC的DMA
}
本帖最后由 wgcrdg 于 2018-2-9 09:17 编辑
ADC采集数据时,单片机是不进入停止模式的,采集完成后,才进入停止模式,单片机采集数据,采用的是ADC+DMA的方式,DMA中断。ADC与DMA的初始化,在开始程序中完成。ADC打开采集与关闭在唤醒后while(1){ }中使用。 如果低功耗方案 理论上进入低功耗前外设时钟都会关闭的 你这没有阐述什么级别的功耗模式 也不说明前因后果所以提问的同时也要阐明条件 唤醒后延时一下再ADC转换试看看 在重新开始时,是否重新配置了时钟。 本帖最后由 wgcrdg 于 2018-2-9 10:33 编辑
没有重新配置时钟,时钟配置在开始的程序中,已经配置了。唤醒后,打开EnableADC(); 采集完成后,DisableADC();,然后, __WFI();,周而复始。
这种情况只偶尔的出现,可能几百次里面出现一次,但是一次也不行啊。电池供电的,要确保低功耗。 楼主可以试着重新配置一下时钟。我在使用的时候会将时钟关闭,还有很多外设等,用于降低功耗。唤醒后再重新配置时钟。 在停止模式下,所有时钟都关闭了吧。你唤醒后,得重新配置时钟,启动外设时钟吧。
页:
[1]
2