stm32正在使用,如果是带充电电池的,是可以不靠断电关机的.有些就完全不关机.比如摩托车的远程启动. 这里是一个休眠的方法.休眠后的耗电量的非常小的几乎可以忽略不计.
引入
#include "stm32f10x_exti.h"//并在stdPeriph_Driver里引入
#include "stm32f10x_pwr.h"
还要引入一个按钮, 常开按键
main.c
c
#include "Store.h" //把store.c .h和myflash.c.h四个文件加入 且魔法棒的c的include paths也加入,然后stdPeriph_dirver里add ..._flash.c
#define BUTTON_PORT GPIOB //注意要改Button_Init
#define BUTTON_PIN GPIO_Pin_0 // 你的开关接 PB0
#define BUTTON_EXTI EXTI_Line0
#define BUTTON_IRQ EXTI0_IRQn
void Delay (uint32_t nCount)
{
/* SysTick 简易延时,72MHz 主频下大约 1ms */
while (nCount--)
{
volatile uint32_t count = 7200;
while (count--);
}
}
/* -------- 按键 GPIO + EXTI 初始化 -------- */
void Button_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
/* 1. 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
/* 2. PA0 配置为上拉输入 */
GPIO_InitStruct.GPIO_Pin = BUTTON_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
/* 3. 将 PB0 映射到 EXTI Line0 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
/* 4. EXTI 配置:下降沿触发(按键按下 = 拉低) */
EXTI_InitStruct.EXTI_Line = BUTTON_EXTI;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
/* 5. NVIC 配置 */
NVIC_InitStruct.NVIC_IRQChannel = BUTTON_IRQ;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
/* -------- EXTI0 中断服务函数 -------- */
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus(BUTTON_EXTI) != RESET)
{
EXTI_ClearITPendingBit(BUTTON_EXTI);
/* 中断里不做复杂操作,唤醒即可返回 */
}
}
/* -------- 进入 STOP 模式 -------- */
static void Enter_Stop_Mode(void)
{
/*
* STOP 模式特点:
* - 所有时钟停止,1.8V 域关闭
* - SRAM 和寄存器内容保持不变
* - 可通过 EXTI 中断唤醒
* - 唤醒后默认使用 HSI(8MHz),需重新配置 PLL 恢复 72MHz
*/
/* 关闭 LED,降低功耗 */
GPIO_SetBits(LED_PORT, LED_PIN);
/* 清除 EXTI 挂起位,防止残留中断立刻唤醒 */
EXTI_ClearFlag(BUTTON_EXTI);
/* 进入 STOP 模式
* 参数 1:PWR_Regulator_ON 保持调压器正常运行,唤醒速度快但休眠功耗稍高;PWR_Regulator_LowPower 调压器进入低功耗模式,功耗更低但唤醒时间会长一些。
对于按键唤醒这种对速度不敏感的场景,用 PWR_Regulator_LowPower 就好
* 参数 2:入口方式 ------ PWR_STOPEntry_WFI 等待中断 */
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
}
/* -------- STOP 唤醒后恢复系统时钟(72MHz HSE + PLL) -------- */
static void SYSCLK_Restore(void)
{
/*
* 从 STOP 模式唤醒后,系统时钟默认切换到 HSI(8MHz)。
* 如果之前使用 HSE + PLL 跑到 72MHz,这里需要重新配置。
*/
ErrorStatus HSEStartUpStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2); /* 72MHz 需要 2 个等待周期 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* 8MHz × 9 = 72MHz */
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08);
}
}
int main(void)
{
int16_t count = 0;
uint8_t is_sleeping = 0;
/* 开启 PWR 时钟(进入低功耗模式前必须开启) */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/* Infinite loop */
while (1){
if (GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN) == Bit_RESET)
{
Delay(20); /* 消抖 */
if (GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN) == Bit_RESET)
{
/* 等待按键释放,避免松手时再次触发 */
while (GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN) == Bit_RESET);
Delay(20);
/* --- 代码收尾 ---*/
printf("sleep \n");
SaveFlush();
res = f_mount(0, NULL); // 卸载SD 卡
SD_DeInit();//关闭 SD 卡 SPI 外设
/* ---- 进入休眠 ---- */
Enter_Stop_Mode();
/* ====== 从这里开始是唤醒后的代码 ====== */
/* 恢复 72MHz 系统时钟 */
SYSCLK_Restore();
/* 重新初始化外设(时钟恢复后需要重配) */
SD_Init();
LED_Init();
Button_Init();
//hx711初始化
GPIO_hx711_Config();
HX711_Init();
f_mount(0,&fs);
printf("waked up \n");
Delay(100);
}
}
//count = count + 1;//检验全局变量在休眠后是否丢失 (即使可以,重要变量还是存内部flash)(不会丢失)(最好用static)
//printf("%d\n",count);
Delay(10);
}
表现: 按一下, 就会进入休眠.打印sleep. 再按一下唤醒打印waked up.
sleep的状态下,
//printf("%d\n",count); Delay(10);
这块代码是不会执行的
内部flash
比较简单,单独说
c
#include "Store.h" //把store.c .h和myflash.c.h四个文件加入 且魔法棒的c的include paths也加入,然后stdPeriph_dirver里add ..._flash.c
Store_Init(); //参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失
while(1)
{
i = Store_Data[1]; //读取内部flash
printf("i: %d\n", i);
OSTimeDlyHMSM(0,0,0,400,OS_OPT_TIME_HMSM_STRICT,&err); //延时400ms
Store_Data[1] = i + 1;
Store_Save(); //存储内部flash
}