本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发
目录
前言
待机模式
代码
wkup.h
wkup.c
main.c
使用注意
前言
建议先阅读下面的博客中待机模式部分。本博客主要分享代码-基于待机模式WKUP引脚的上升沿实现类似长按开机与关机的功能
【STM32】PWR电源控制(低功耗模式)_stm32进入待机模式-CSDN博客
待机模式
待机模式时可选择功能
待机模式下的输入/输出端口状态
在待机模式下,所有的I/O引脚处于高阻态(浮空输入),除了以下的引脚(微控制器从待机模式退出):
● 复位引脚(始终有效)
● 当被设置为防侵入或校准输出时的TAMPER引脚
● WKUP引脚的上升沿、RTC闹钟事件的上升沿、NRST引脚上外部复位、IWDG复位
从待机唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位。 从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚、读取复位向量等)。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出
代码
PWR_WakeUpPinCmd(ENABLE); //使能唤醒管脚功能
EWUP:使能WKUP引脚
0:WKUP引脚为通用I/O。WKUP引脚上的事件不能将CPU从待机模式唤醒
1:WKUP引脚用于将CPU从待机模式唤醒,WKUP引脚被强置为输入下拉的配置(WKUP引脚上的上升沿将系统从待机模式唤醒)
注:在系统复位时清除这一位。
代码思路
不按按键PA0,下载程序后,在WKUP初始化函数中默认进入待机模式,执行不到while内,长按PA0,系统复位,程序从头执行。执行到WKUP初始化函数时,不进入待机模式,可以执行到while内,长按按键PA0,在中断函数里进入待机模式,如此重复下去,便可实现WKUP上升沿模拟开机与关机
wkup.h
#ifndef __WKUP_H
#define __WKUP_H
#define WK_UP GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) //检测外部WK_UP按键是否按下
void WKUP_Init(void); //PA0 WKUP唤醒初始化
uint8_t Check_WKUP(void); //检测WKUP脚的信号
void Sys_EnterStandby(void); //系统进入待机模式
#endif
wkup.c
#include "stm32f10x.h" // Device header
#include "wkup.h"
#include "LED.h"
#include "Delay.h"
void Sys_Standby(void);//系统进入待机模式
//PA0初始化作为普通IO口并开启外部中断,中断服务函数内检测到边沿进入待机模式
void WKUP_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOA和复用功能时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA.0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//使用外部中断方式
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //中断线0连接GPIOA.0
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI0线路为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
if(Check_WKUP() == 0) Sys_Standby(); //默认进入待机模式 ,除非该语句执行前长按WKUP
}
//PA0设置作为WKUP引脚,且系统进入待机模式
void Sys_Standby(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外设时钟
PWR_WakeUpPinCmd(ENABLE); //使能唤醒管脚功能
PWR_EnterSTANDBYMode(); //进入STANDBY模式
}
//关闭外设后系统进入待机模式
void Sys_EnterStandby(void)
{
RCC_APB2PeriphResetCmd(0X01FC, DISABLE); //复位所有GPIO口
/*
此处关闭其他外设
*/
Sys_Standby();
}
//检测WKUP脚的信号
//返回值 1:连续按下3s以上;0:错误的触发
uint8_t Check_WKUP(void)
{
uint8_t t = 0; //记录按下的时间
LED1_ON(); //亮灯
while(1)
{
if(WK_UP)
{
t++; //已经按下了
Delay_ms(30);
if(t >= 100) //按下超过3秒钟
{
LED1_ON(); //点亮
return 1; //按下3s以上了
}
}else
{
LED1_OFF();
return 0; //按下不足3秒
}
}
}
//检测到PA0脚的一个上升沿进入中断
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0); // 清除EXTI0的标志位
if(Check_WKUP())//连续按下3s以上
{
Sys_EnterStandby(); //关机
}
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "wkup.h"
#include "LED.h"
int main(void)
{
OLED_Init();
LED_Init();
WKUP_Init();//默认进入待机模式;WK_UP上升沿唤醒待机模式,程序从头执行,必须长按WK_UP才不进入待机模式,相当于开机
while (1)
{
//while循环内,通过外部中断检测WK_UP高电平时间进入待机模式
LED2_Turn();
Delay_ms(300);
LED2_Turn();
Delay_ms(300);
}
}
使用注意
中断函数中Check_WKUP( )函数延时过多,建议用定时器中断检测按键时间,不阻塞其他程序的执行。
//检测到PA0脚的一个上升沿进入中断
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0); // 清除EXTI0的标志位
if(Check_WKUP())//连续按下3s以上
{
Sys_EnterStandby(); //关机
}
}
在 void Sys_EnterStandby(void)函数里面,我们要在进入待机模式前把所有开启的外设全部关闭,我们这里仅仅复位了所有的 IO 口,使得 IO 口全部为浮空输入。其他外设(比如 ADC 等),大家根据自己所开启的情况进行一一关闭就可,这样才能达到最低功耗!
void Sys_EnterStandby(void)
{
RCC_APB2PeriphResetCmd(0X01FC, DISABLE); //复位所有GPIO口
/*
此处关闭其他外设
*/
Sys_Standby();
}