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); } |
下面是开始程序时的ADC与DMA的初始化部分。
uint16_t ADC_array[6];
//这个函数配置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);
}
void ADC_Init(void)
{
//使外围时钟GPIOA GPIOC
//AD1=PA4=IN4 AD2=PA5=IN5 AD3=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
}
ADC采集数据时,单片机是不进入停止模式的,采集完成后,才进入停止模式,单片机采集数据,采用的是ADC+DMA的方式,DMA中断。ADC与DMA的初始化,在开始程序中完成。ADC打开采集与关闭在唤醒后while(1){ }中使用。
评分
查看全部评分
评分
查看全部评分
评分
查看全部评分
没有重新配置时钟,时钟配置在开始的程序中,已经配置了。唤醒后,打开EnableADC(); 采集完成后,DisableADC();,然后, __WFI();,周而复始。
评分
查看全部评分