stm32最小系统板实现停机模式与唤醒(二)

初学者分享,各位大佬指正!!

项目:stm32f103c8t6停机模式与唤醒

库:标准库

停机/唤醒条件:stm32最小系统板实现停机模式与唤醒(一)-CSDN博客

功能/现象:(加入定时器中断进行控制,逻辑与之前(一)不同)

正常模式:PA1(LED)常灭,按下PB5(给一个高电平),小灯亮一下,灯灭;

停机模式:按键不动,5秒自动停机;

唤醒:按PB5 一下,灯亮,实现唤醒,PA1灭亮;


接线图(配件使用的是江科大)


代码:(看过stm32最小系统板实现停机模式与唤醒(一),代码可以)

mian.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Key.h"
#include "LED.h"
#include "Stop.h"
#include "Timer.h"

uint8_t Key = 0;
extern u8 set ;

int main(void)
{
	GPIO_Config();
	LED_Init();
	WKUP_Init();
	Timer_Init();
	
	while (1)
	{
		if(set == 1)
		{

			Sys_Enter_Stop(); // 进入停机模式
			SystemInit();
			set = 0;
		}
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_1,Bit_RESET);
	}
}


Stop.c

#include "stm32f10x.h" 
#include "Stop.h"
#include "Delay.h"
#include "Key.h"
#include "LED.h"
extern uint16_t Num;
u8 set = 0;


//停机模式
void Sys_Stop(void)
{  
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);	//使能PWR外设时钟
	PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFE);	
}

//系统进入停机模式
void Sys_Enter_Stop(void)
{			 
	//RCC_APB2PeriphResetCmd(0x01fc,DISABLE);//复位
	Sys_Stop();//启动待机模式
}


判断按键
u8 Check_key(void) 
{
	while(1)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)!=Bit_SET)//按下,判断按键,给出一个高电平
		{
			Num= 0;//Num要放在这里清零,如果放在定时器在1秒按的很快内可能检测不到
			Delay_ms(30);
			GPIO_WriteBit(GPIOA, GPIO_Pin_1,Bit_RESET);
		}
		else 
		{
			
			return 0;
		}

	}
}  


//中断
void EXTI9_5_IRQHandler(void)
{ 
    if(EXTI_GetITStatus(EXTI_Line5) != RESET) //确保是否产生了EXTI Line中断
	{
		EXTI_ClearITPendingBit(EXTI_Line5); // 清除中断标志位
        if (Check_key()) // 检查按键
        {        
			
        }
	}
}


void WKUP_Init(void)
{	
    GPIO_InitTypeDef  GPIO_InitStructure;  		  
	NVIC_InitTypeDef NVIC_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
 
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOA和复用功能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
 
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5;	
	GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU; 
	GPIO_Init(GPIOB, &GPIO_InitStructure);	

    //使用外部中断方式
 	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5);	//中断线5连接GPIOB.5
 
    EXTI_InitStructure.EXTI_Line = EXTI_Line5;	//设置按键所有的外部线路
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//设外外部中断模式:EXTI线路为中断请求
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //上升沿触发
   	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);	// 初始化外部中断
 
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按键所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级2级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 


Timer.c(根据江科大代码配置,修改了中断函数)

#include "stm32f10x.h"                  // Device header

extern u8 set ;
uint16_t Num=0;			//定义在定时器中断里自增的变量

/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  */
void Timer_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	
	
	/*中断输出配置*/
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

//中断
void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==Bit_SET)//未被按下
        {  
			Num++;
		
			if (Num >= 5) // 5秒计数
			{
				set = 1; // 设置标志位
				Num = 0; // 计数器清零
			}
			
		}	
	
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

Key.c(与(一)相同,未改变)

#include "stm32f10x.h"                  // Device header
#include "Delay.h"


// 初始化GPIO
void GPIO_Config(void) 
{
    // 使能GPIOA和GPIOB时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  
    GPIO_InitTypeDef GPIO_InitStructure;
  
    // 配置PB5为浮空输入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}


uint8_t Key_GetNum(void)
{
	uint8_t Keyum = 0;
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 1)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 1);
		Delay_ms(20);
		Keyum = 1;
	}
	
	
	return Keyum;
}

 

LED.c(与(一)相同,未改变)

#include "stm32f10x.h"                  // Device header

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}


1设计要求 要求系统按如下方式进入和退出睡眠模式: 在系统启动2秒后,将RTC在3秒钟之后配置为产生一个报警事件,接着通过WFI指令使系统进入停机模式。 如果要唤醒系统到正常模式,可通过按Key按钮;否则,在3秒钟后,会产生RTC报警中断自动将系统唤醒。 一旦退出停机模式,系统时钟被配置成先前的状态(在停机模式下,外部高速振荡器HSE和PLL是不可用的)。 经过一段延时之后,系统将再次进入停机状态,并可按上述操作无限重复。 2 硬件电路设计 硬件电路采用与7.1小节应用实例一样硬件电路,可见图7-10。其中Key按钮用于通过PB9产生一个外部中断, LED1、LED2、LED3、LED4则用于显示处理器所处的模式和中断触发情况。 3 软件程序设计 根据任务要求,程序内容主要包括: (1) 配置GPIOB口,配置RTC,配置外部中断; (2) 配置PB口第9个引脚作为外部中断,下降延触发;配置RTC报警中断,上升沿触发; (3) 两个中断服务子程序的内容分别是:切换LED2和LED3灯的状态; 整个工程包含3个源文件:STM32F10x.s、stm32f10x_it.c和main.c,其中STM32F10x.s为启动代码,所有中断 服务子程序均在stm32f10x_it.c中,其它函数则在main.c中。下面分别介绍相关的函数,具体程序清单见参考程序。 函数SYSCLKConfig_STOP用于当处理器从停机模式唤醒之后,配置系统时钟、使能HSE和PLL,并以PLL作为系统时钟源。当处理器处理停机模式的时候,HSE、PLL是不可用的。 函数GPIO_Configuration用于配置GPIO的PC6、PC7、PC8、PC9和PB9。 函数EXTI_Configuration用于配置外部中断线9(PB9)和17(RTC报警)。 函数NVIC_Configuration配置NVIC及中断向量表,这里主要是配置外部中断线9和17。 函数EXTI9_5_IRQHandler处理按钮Key(PB9)所触发的中断,其主要作用是将LED2灯的状态翻转一次。 函数RTCAlarm_IRQHandler处理RTC报警所触发的中断,其主要作用事将LED3 灯的状态翻转一次,如果设置了唤醒标志则清除之。 运行过程: (1) 使用Keil uVision3 通过ULINK 2仿真器连接EduKit-M3实验平台,打开实验例程目录PWR_TEST子目录下的PWR.Uv2 例程,编译链接工程; (2) 选择软件调试模式,点击MDK 的Debug菜单,选择Start/Stop Debug Session项或Ctrl+F5键,在逻 辑分析仪中添加GPIOC_ODR.6、GPIOC_ODR.7、GPIOC_ODR.8、GPIOC_ODR.9,点击Run按钮即可在逻辑分析 仪中看到如图7-14,还可用Peripherals-General Port-GPIOB来模拟KEY按钮的动作; (3) 选择硬件调试模式,选择Start/Stop Debug Session项或Ctrl+F5键,下载程序并运行,观察LED灯 的变化情况。注意,当目标系统进入停机模式之后,将无法使用仿真器进行调试了; (4) 退出Debug模式,打开Flash菜单>Download,将程序下载到EduKit-M3实验平台的Flash中,按RESET键复位,观察 LED灯的情况,正常情况应为:系统处于运行模式时LED1亮、LED4灭;系统处于停机状态时LED1灭、LED4亮; 当按下KEY按钮时LED2灯状态发生反转;当发生RTC报警时LED3状态发生反转。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值