OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6478|回复: 7

PA0唤醒和RTC唤醒

[复制链接]

4

主题

52

帖子

0

精华

初级会员

Rank: 2

积分
195
金钱
195
注册时间
2017-4-24
在线时间
44 小时
发表于 2019-2-21 18:19:26 | 显示全部楼层 |阅读模式
50金钱
楼主需要做两个方式的待机唤醒实验,用的是stm32 F103,初步想达到的实验结果是PA0中断唤醒和RTC闹钟唤醒互相切换:

PA0唤醒后,系统跑一个流程后设置为RTC闹钟唤醒,并将PA0唤醒屏蔽;
RTC闹钟唤醒后,系统跑一个流程后设置为PA0唤醒,不用闹钟唤醒或者将闹钟设置的时间变长;

用到的是原子的例程,函数也是从原子里参考过来的:
发现的问题是PA0单独唤醒和RTC闹钟单独唤醒都是OK的,我在实验中利用了BKP寄存器来保存上一次醒来的方式做判断来切换,
问题是当一次PA0唤醒后,进入待机模式以后,PA0唤醒一直存在,不重启就一直存在,把相应的位禁掉之后不起作用。不知道为什么,代码如下:
                                                                       /*取消备份区写保护*/
                                                                        RCC->APB1ENR|=1<<28;     //使能电源时钟            
                                                                        RCC->APB1ENR|=1<<27;     //使能备份时钟       
                                                                        PWR->CR|=1<<8;           //取消备份区写保护
                                                                        delay_ms(100);

                                                                    /*****读取上次的唤醒方式*********/
                                                                  WKUPMod = BKP_ReadBackupRegister(BKP_DR5);
                                                                      delay_ms(100);
                                                              //***********************************                                                       
        if(WKUPMod==1)//PA0唤醒
        {
                       
                PWR->CSR|=0<<8;                                                            //不设置WKUP用于唤醒               
                BKP_WriteBackupRegister(BKP_DR5,(uint16_t)2);                  //写BKP寄存器
                DelayMod=30;
                RTC_Init();                                  //RTC初始化
                while(RTC_Init())                //RTC初始化        ,一定要初始化成功
            {
                delay_ms(800);
            }               
           rtccnt=RTC->CNTH;//得到闹钟值
           rtccnt<<=16;
           rtccnt|=RTC->CNTL;                                       
           ALARM_CNT_Set(rtccnt+DelayMod);//设置30秒钟后,闹钟唤醒
               
        }
        else//RTC唤醒
        {
               
                PWR->CSR|=1<<8;//设置WKUP用于唤醒
                BKP_WriteBackupRegister(BKP_DR5,(uint16_t)1);               
        }
                       

                                GPIO_ResetBits(GPIOB, PB14);
                                delay_ms(2000);                                               
                                Sys_Enter_Standby();



-------------------------------------------------------------------------------------------------------------------
void Sys_Enter_Standby(void)
{                         
        //关闭所有外设(根据实际情况写)
           RCC->APB2RSTR|=0X01FC;//复位所有IO口
        //关闭所有用到的时钟----串口2NB口
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,DISABLE);
          RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,DISABLE);
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,DISABLE);
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
          RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, DISABLE);
       
       
        Sys_Standby();//进入待机模式
}

---------------------------------------------------------------------------------------------------

//进入待机模式          
void Sys_Standby(void)
{
        SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)
       
                /*取消备份区写保护*/
                                                                        RCC->APB1ENR|=1<<28;     //使能电源时钟            
                                                                        RCC->APB1ENR|=1<<27;     //使能备份时钟       
                                                                        PWR->CR|=1<<8;           //取消备份区写保护
                                                                        delay_ms(100);
        PWR->CR|=1<<2;           //清除Wake-up 标志
        PWR->CR|=1<<1;           //PDDS置位                  
        WFI_SET();                                 //执行WFI指令                 
}       

---------------------------------------------------------------------------------------------------------------------------------
//中断处理函数,清标志即可
void EXTI0_IRQHandler(void)
{                                                                                                  
         
        EXTI->PR=1<<0;  //清除LINE10上的中断标志位
}

---------------------------------------------------------------------------------------------------------------------------


实验现象是:当板子因为RTC闹钟进入待机后,将PA0短接3.3v,然后松开,会启动板子,然后再次进入待机,此时按照我写的程序来说,PA0唤醒应该已经不起作用了,但是此时再次短接PA0和3.3v,板子又会起来,也就是说
PA0启动一次后像记住了一样,一直存在。按下复位键再次启动程序,PA0恢复正常,无法唤醒板子,唤醒一次后,又杀不掉这个唤醒方法了。         


求大神解释下是什么原因。


最佳答案

查看完整内容[请看2#楼]

我最后的处理办法是: 在判断是唤醒状态的程序段后面, 加一句: NVIC_SystemReset(); 只能算勉强解决问题.
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
86
金钱
86
注册时间
2019-9-21
在线时间
7 小时
发表于 2019-2-21 18:19:27 | 显示全部楼层
我最后的处理办法是:
在判断是唤醒状态的程序段后面, 加一句:
    NVIC_SystemReset();
只能算勉强解决问题.
回复

使用道具 举报

4

主题

52

帖子

0

精华

初级会员

Rank: 2

积分
195
金钱
195
注册时间
2017-4-24
在线时间
44 小时
 楼主| 发表于 2019-2-21 18:23:40 | 显示全部楼层
帖子中的是主要代码,闹钟唤醒的相关设置我在其他帖子中看多,好使,PA0唤醒时参考原子的例程,把按键什么的去掉了,一个上升沿就能启动
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-2-22 02:06:52 | 显示全部楼层
帮顶
回复

使用道具 举报

4

主题

52

帖子

0

精华

初级会员

Rank: 2

积分
195
金钱
195
注册时间
2017-4-24
在线时间
44 小时
 楼主| 发表于 2019-2-22 10:11:09 | 显示全部楼层
请问大家谁做过类似的实验,可以交流一下
回复

使用道具 举报

4

主题

52

帖子

0

精华

初级会员

Rank: 2

积分
195
金钱
195
注册时间
2017-4-24
在线时间
44 小时
 楼主| 发表于 2019-3-1 17:47:15 | 显示全部楼层
有没有大神做过类似的实验,求助啊
回复

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
86
金钱
86
注册时间
2019-9-21
在线时间
7 小时
发表于 2019-11-30 15:16:39 | 显示全部楼层
我也遇到类似问题:
一个简单的小试验, 用PA0脚接地进入Standby, 再将PA0接高电平唤醒STM32.
结果唤醒后, 如果PA0不一直接高电平, 处理器又会进入Standby状态.
看起来好像是唤醒后的PA0内部上拉没有起作用.
用硬件复位就能正常运行.

以下是代码:

#include "stm32f0xx.h"
#include <stdio.h>

#define Working_LED     GPIOA, GPIO_Pin_4
#define Input0_Pin      GPIOA, GPIO_Pin_0

void GPIO_Config( void );
void delay_ms( int );

int main( void )
{
  RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR, ENABLE );
  GPIO_Config();

  if( PWR_GetFlagStatus( PWR_CSR_WUF ) )
  {
    PWR_ClearFlag( PWR_CSR_WUF );
    // 如果是唤醒状态,则LED亮3秒
    GPIO_ResetBits( Working_LED );      // 点亮LED灯
    delay_ms( 3000 );
  }

  while ( GPIO_ReadInputDataBit( Input0_Pin ) )
  {
    GPIO_SetBits( Working_LED );        // 熄灭LED灯
    delay_ms( 300 );
    GPIO_ResetBits( Working_LED );      // 点亮LED灯
    delay_ms( 300 );
  }

  PWR_WakeUpPinCmd( PWR_WakeUpPin_1, ENABLE );  // 使能唤醒引脚,默认PA0
  PWR_EnterSTANDBYMode();                       // 进入Standby模式
  // 进入Standby状态后就执行不到这里了
}

void GPIO_Config( void )
{
  GPIO_InitTypeDef GPIO_InitStructure;
  //LED
  RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA, ENABLE );
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init( GPIOA, &GPIO_InitStructure );
  //Input Pin
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init( GPIOA, &GPIO_InitStructure );
}

void delay_ms( int msec )
{  
  unsigned long int i,j;
  j = (unsigned long)( SystemCoreClock / 6000 * msec );
  for ( i=0; i<j; i++ );
}

难道是唤醒后, 有些寄存器没有恢复Reset状态?
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2020-7-24
在线时间
1 小时
发表于 2020-7-24 14:06:31 | 显示全部楼层
lab216 发表于 2019-2-21 18:19
我最后的处理办法是:
在判断是唤醒状态的程序段后面, 加一句:
    NVIC_SystemReset();

也在实验,看手册上说,唤醒后必须重新设置时钟。
所以这应该是最正确的方式。
不知道我的理解对不对。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-19 02:31

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表