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

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管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版