你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L053 低功耗采集时,ADC打开与关闭有时出现问题

[复制链接]
wgcrdg 提问时间:2018-2-9 08:23 /
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);
}
555.JPG
222.png

点评

帮你把第二张图改了,留了一大块空白看着多难受  发表于 2018-2-9 09:17

评分

参与人数 1 ST金币 -2 收起 理由
Tcreat -2 建议楼主把前提条件叙述清楚

查看全部评分

收藏 评论17 发布时间:2018-2-9 08:23

举报

17个回答
wgcrdg 回答时间:2018-2-9 09:25:58
本帖最后由 wgcrdg 于 2018-2-9 09:51 编辑

下面是开始程序时的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
}
wgcrdg 回答时间:2018-2-9 09:09:36
本帖最后由 wgcrdg 于 2018-2-9 09:17 编辑

ADC采集数据时,单片机是不进入停止模式的,采集完成后,才进入停止模式,单片机采集数据,采用的是ADC+DMA的方式,DMA中断。ADC与DMA的初始化,在开始程序中完成。ADC打开采集与关闭在唤醒后while(1){   }中使用。
Tcreat 回答时间:2018-2-9 08:44:26
如果低功耗方案 理论上进入低功耗前外设时钟都会关闭的 你这没有阐述什么级别的功耗模式 也不说明前因后果  所以提问的同时  也要阐明条件

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

wenyangzeng 回答时间:2018-2-9 09:52:35
唤醒后延时一下再ADC转换试看看

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

废鱼 回答时间:2018-2-9 09:53:38
在重新开始时,是否重新配置了时钟。

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

wgcrdg 回答时间:2018-2-9 10:32:34
本帖最后由 wgcrdg 于 2018-2-9 10:33 编辑

没有重新配置时钟,时钟配置在开始的程序中,已经配置了。唤醒后,打开EnableADC(); 采集完成后,DisableADC();,然后, __WFI();,周而复始。


wgcrdg 回答时间:2018-2-9 10:35:29
这种情况只偶尔的出现,可能几百次里面出现一次,但是一次也不行啊。电池供电的,要确保低功耗。
废鱼 回答时间:2018-2-9 10:38:36
楼主可以试着重新配置一下时钟。我在使用的时候会将时钟关闭,还有很多外设等,用于降低功耗。唤醒后再重新配置时钟。
hello_bug 回答时间:2018-2-9 10:44:33
在停止模式下,所有时钟都关闭了吧。你唤醒后,得重新配置时钟,启动外设时钟吧。

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

wgcrdg 回答时间:2018-2-9 10:48:30
本帖最后由 wgcrdg 于 2018-2-9 10:53 编辑

好的,试下,唤醒后再重新配置时钟。我是这样使用的。
int main(void)
{
    ......
   
    LCD_Init();
    RTC_Init();   //RTC定时唤醒停止模式下的单片机
    ADC_Init();
    ......
    while (1)
    {
         ......                                      if(采集数据=1)
        {
          采集数据=0;
          采集完成=0;  
          EnableADC();
        }
        ......
        if(采集完成=1)
        {
          采集完成=0;
          DisableADC();
        }      
        ......        
        if(无数据采集)
        {        
          __WFI();        
        }
    }
}






wgcrdg 回答时间:2018-2-9 11:04:11
又看了下参考手册,进入停止模式后,所有高速时钟都停止。退出停止模式时保持其相应配置,我使用的是HSI16。
666.JPG
Tcreat 回答时间:2018-2-9 11:37:24
本帖最后由 Tcreat 于 2018-2-9 11:39 编辑
wgcrdg 发表于 2018-2-9 11:04
又看了下参考手册,进入停止模式后,所有高速时钟都停止。退出停止模式时保持其相应配置,我使用的是HSI16 ...

是保持配置,你可以不重新配置时钟, 但是相应外设的时钟还是需要自己开启的 ,
wgcrdg 回答时间:2018-2-9 11:56:49
本帖最后由 wgcrdg 于 2018-2-9 12:01 编辑

我在开始初始化的程序中,外设时钟打开,进入停止模式时,没有关闭相应的外设时钟,刚才我试了下,进入停止模式时,关闭相应外设时钟,退出停止模式时,打开相应外设时钟,电流是一样的, 我的RTC+LCD时,停止模式时,电流是28 uA,不知道你们可以最低降到多少。我也感觉电流大了,但是降不下来了。
//程序完成后将调试线置为模拟
  GPIOA->MODER |= (GPIO_MODER_MODE13 |GPIO_MODER_MODE14);

  //禁止 PVD 电源电压检测器
  CLEAR_BIT(PWR->CR, PWR_CR_PVDE);

  //使超低功率模式 VREFINT 在低功耗模式下关闭
  //SET_BIT(PWR->CR, PWR_CR_ULP);
  //从超低功率模式使快醒来
  SET_BIT(PWR->CR, PWR_CR_FWU);
  //(HSI) 振荡器作为从停止模式唤醒时钟
  MODIFY_REG(RCC->CFGR,RCC_CFGR_STOPWUCK, (uint32_t)(RCC_CFGR_STOPWUCK) );     

  RCC->CFGR |= RCC_CFGR_STOPWUCK;  //(HSI) 振荡器作为从停止模式唤醒时钟
  //CLEAR_BIT(PWR->CR, PWR_CR_LPRUN);
  CLEAR_BIT(PWR->CR, (PWR_CR_PDDS | PWR_CR_LPSDSR |PWR_CR_LPRUN));  //清除标志
  SET_BIT(PWR->CR, (PWR_CR_LPSDSR|PWR_CR_LPRUN));  //设置标志  低功率运行模式下调压器进入低功耗模式
  // SET_BIT(PWR->CR, PWR_CR_LPRUN);
  SET_BIT(SCB->SCR, SCB_SCR_SLEEPDEEP_Msk);
  SET_BIT(SCB->SCR, SCB_SCR_SLEEPONEXIT_Msk);
  __WFI();


chi1997 回答时间:2018-2-11 18:02:05
你可以用Jlink调试看看哪里的问题,看看时钟有没有再次打开,或者ADC转换有没有延时

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

12下一页

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版