初学者分享,各位大佬指正!!
项目: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);
}