一键开关机电路

文章讨论了在数据保存过程中CPU控制的开机和关机的重要性,以防止数据丢失或损坏。提出了一键开关机电路的设计思路,旨在解决意外关机导致的问题。文中还分享了一个可能存在的电路设计,并提供了相关函数代码,用于实现电源的控制。此外,提到了计算机的类似情况以及UPS不间断电源的应用。作者鼓励对电路设计进行改进,以增强系统的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由CPU控制开机或关机,有时很有必要,特别是在需要保存数据的场合,如随时保存数据到EEPROM,FLASH和SD中,正在保存数据时发生误关机,就会导致保存错误,或SD卡中的文件损坏。在实际设计中,我们也想把产品做得很完美,但确实不容易,一不小心就容易触雷了。总结过去,不是我们想布雷,确实是有时候考虑不周或经验不足。CPU控制的”一键开关机电路“,就是为了解决这个问题而设计的。有了它,就可以避免出现上述问题。同样,计算机开机关机原理也是如此。特别是在编写文件时,突然断电,就可能会发现文件损坏,打不开了。有些编译器有自动保存功能,如果正在保存,这时突然断电了,这个文件基本上已经损坏了,也没有办法修复,就只能删除了,再重建。于是,有些重要部门就引用了UPS不间断电源,就是这个原因。希望能在后期的电路设计中,要能体现这个功能。早发现,早治疗,早解决。

以前,有位同事设计过一个一键开关机电路,网上也有类似电路,但问题还有的。有的理论上可以,但实际使用时问题很多。主要表现为是关不了机,或者是荡机。或者电解电容增大,就会有问题。下面是我设计的电路和流程图,供大家一起交流学习。

  

 

 流程图中的VCC_Flag是变量,用来记录电源开,还是电源关闭。Keyin和PWREN连接到CPU引脚,LED灯由CPU控制,告诉外部是开机,还是关机。灯亮表示CPU有电,灯灭通常表示CPU在关机中。

CPU进入工作后,会扫描Keyin引脚,无操作,则退出去执行其他任务。扫描的目的,是检查是否需要执行关机。

前面的电路设计,主要是为了便于理解流程图。电路简化后,可以少用一个CPU引脚,电路如下:

//函数功能:一键电源开关机
void PowerOn_And_PowerOff(void)
{
	u8 ch;

	ch=0;
	if(Keyin==0)ch=1;

	if(ch)//电源按钮被按下
	{
		if(PowerWork!=PowerWork_OnValue)//电源原来处于"关状态"
		{
			PWREN_ON();//开灯,自锁

			while(Keyin==0)//等待按钮松开
			{
				delay_ms(10);
			}

			delay_ms(500);//延时500ms,需要再次确认按钮是否松开
			while(Keyin==0)
			{
				delay_ms(10);
			}

      PowerWork=PowerWork_OnValue;
		}
		else//电源原来处于"开状态"
		{
			PWREN_OFF();//关灯,自锁

			while(Keyin==0)//等待按钮松开
			{
				delay_ms(10);
			}

			delay_ms(1000);//延时1000ms,需要再次确认按钮是否松开
			while(Keyin==0)
			{
				delay_ms(10);
			}

			PowerWork=PowerWork_OffValue;
		}
	}
}

点动按钮开机的缺点:CPU复位时会自动关机,因为CPU引脚通常默认是输入口 

 

 

 

#include "Power.h"
#include "Task_Variable.h"
#include "delay.h"
#include "My_Task_Priority.h"

u8 PWREN_OFF_Flag;

//函数功能:初始化一键开关机的Keyin为输入上拉
void Keyin_Init(void)
{
	GPIO_InitTypeDef   GPIO_InitStructure;
  //使用GPIO_InitTypeDef定义一个结构变量GPIO_InitStructure;

	RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOE, ENABLE ); //在配置外设之前,必须先使能GPIOE的外设时钟
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;                 //选择第12脚
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;          //设置引脚的最高输出速率为50MHz
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;              //输入上拉,按钮输入低电平有效
  GPIO_Init( GPIOE, &GPIO_InitStructure); 
  //根据GPIO_InitStructure结构变量指定的参数初始化GPIOE的外设寄存器
}

//函数功能:初始化一键开关机的PWREN为输出口
void PWREN_Init(void)
{
	GPIO_InitTypeDef   GPIO_InitStructure;
  //使用GPIO_InitTypeDef定义一个结构变量GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //使能GPIOD的外设时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;            //选择第11脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      //设置引脚工作模式为推挽输出方式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //设置引脚的最高输出速率为50MHz
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	//根据GPIO_InitStructure结构变量指定的参数初始化GPIOD的外设寄存器
}

//函数功能:初始化一键开关机的Keyin为输入上拉,PWREN为输出口
void Power_Init(void)
{
	PWREN_Init();//初始化一键开关机的PWREN为输出口
	Keyin_Init();//初始化一键开关机的Keyin为输入上拉
	PWREN_OFF_Flag=0;
}

const char POWER_ON_Str[]="\r\nPOWER ON";
const char POWER_OFF_Str[]="\r\nPOWER OFF";
//函数功能:一键电源开关机
void PowerOn_And_PowerOff(void)
{
	u8 ch;

	if(Keyin==0)//电源按钮被按下,开机
	{
		if(PowerWork!=PowerWork_OnValue)//电源原来处于"关状态"
		{
			PWREN_ON();//开灯,自锁
      PowerWork=PowerWork_OnValue;
			printf("%s",POWER_ON_Str);
		}
	}

	if(PowerWork==PowerWork_OnValue)
	{
	  ch=0;
	  if(Keyin)//电源按钮被释放,开始关机
	  {
		  ch=1;
		  delay_ms(200);
			IWDG_ReloadCounter();  //喂狗
		  printf("%s",POWER_OFF_Str);
	  }
	  if(Keyin)//电源按钮被释放,开始关机
	  {
		  ch=(u8)(ch<<1);
		  delay_ms(200);
			IWDG_ReloadCounter();  //喂狗
		  printf("%s",POWER_OFF_Str);
	  }
	  if(Keyin)//电源按钮被释放,开始关机
	  {
		  ch=(u8)(ch<<1);
		  delay_ms(200);
			IWDG_ReloadCounter();  //喂狗
		  printf("%s",POWER_OFF_Str);
	  }
	  if(Keyin)//电源按钮被释放,开始关机
	  {
		  ch=(u8)(ch<<1);
		  delay_ms(200);
			IWDG_ReloadCounter();  //喂狗
		  printf("%s",POWER_OFF_Str);
	  }
	  if(ch==0x08)//经过多次判断,确实要关机
	  {
			PWREN_OFF_Flag=1;
			while(PWREN_OFF_Flag==1)
			{
			  delay_ms(200);
			  IWDG_ReloadCounter();  //喂狗
				printf("%s",POWER_OFF_Str);
			}
		  PWREN_OFF();//关灯,自锁
		  vTaskSuspend(V9203_Task_Handler);//挂起V9203_Task_Handler任务
		  vTaskSuspend(LCD_DISPLAY_Task_Handler);//挂起LCD_DISPLAY_Task_Handler任务
		  vTaskSuspend(GPRS_And_ZigBee_Task_Handler);//挂起GPRS_And_ZigBee_Task_Handler任务
		  PowerWork=PowerWork_OffValue;
		  while(1)
		  {
			  delay_ms(200);
			  IWDG_ReloadCounter();  //喂狗
				printf("%s",POWER_OFF_Str);
		  }
	  }
  }
}
#ifndef _Power_H
#define _Power_H

#include "stm32f10x.h"
#include "sys.h"

#define Keyin    PEin(12)  //PE12
#define Keyin_OFF() GPIO_SetBits(GPIOE,GPIO_Pin_12)  //定义Keyin输出高电平
#define Keyin_ON() GPIO_ResetBits(GPIOE,GPIO_Pin_12) //定义Keyin输出低电平

#define PWREN    PDout(11)  //PD11
#define PWREN_ON() GPIO_SetBits(GPIOD,GPIO_Pin_11)  //定义PWREN点亮
#define PWREN_OFF() GPIO_ResetBits(GPIOD,GPIO_Pin_11) //定义PWREN关闭

extern u8 PWREN_OFF_Flag;

extern void Power_Init(void); /* Power 端口初始化 */
extern void PowerOn_And_PowerOff(void);
#endif
#include "Power_Task.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "delay.h"

#include "RTC.h"

#include "My_Task_Priority.h"
#include "Task_Variable.h"

#include "Power.h"
#include "Relay.h"

void Power_Task(void *pvParameters);

uint8_t PowerTask_cnt;

const char Power_rn_REG[]="\r\n";
const char Power_Initialise_REG[]="Power Initialise";
const char PowerTask_cnt_REG[]="PowerTask_cnt=";

void Power_Task(void *pvParameters)
{
	printf("%s",Power_rn_REG);
	printf("%s",Power_Initialise_REG);

	Power_Init();
	Relay_Init();

	PowerTask_cnt=0;
	while(1)
	{
		PowerTask_cnt++;
		if(PowerTask_Second_Flag)
		{
           PowerOn_And_PowerOff();//一键电源开关机

/每秒种任务执行多少次///
			printf("%s",Power_rn_REG);
			printf("%s",PowerTask_cnt_REG);
			printf("%u",PowerTask_cnt);
			PowerTask_cnt=0;
			PowerTask_Second_Flag=FALSE;
	  }

		vTaskDelay(50);
		IWDG_ReloadCounter();  //喂狗
	}
}

 

 

欢迎大家多提意见,我也正准备使用这种电路。

### 单片机实现一键开关机电路设计方案 #### 设计概述 单片机实现的一键开关机电路通常由按键、MOS管、三极管以及单片机构成。其核心原理是利用按键触发信号,通过单片机控制外部元件的状态来完成设备的开/关操作[^3]。 #### 控制流程描述 当按下按键时,三极管 Q1 导通,使得单片机获得供电并复位进入工作状态。随后,单片机会检测按键输入 K-IN 是否处于低电平。如果是,则单片机输出端口 K-OUT 输出高电平,使另一只三极管 Q2 导通,从而模拟按键长按的效果。此时 LED 指示灯点亮,表示系统已启动完毕。 在运行过程中,如果再次按下按键超过一定时间(例如 1 秒),单片机将识别为关机指令,并将 K-OUT 设置为低电平,切断 Q2 的导通路径。LED 熄灭后,释放按键会使 Q1 截止,最终导致单片机失去供电而关闭。 以下是基于上述逻辑的一个典型硬件连接方式: ```plaintext +-------------------+ | | | PMOS (Q2) |-----> 板载电源供应 (+Vcc) | | +-------+-----------+ | v R_pullup | v +---------+ | G| | Single-|---> K_OUT (GPIO Pin of MCU) | Chip |---> K_IN (Input GPIO Pin with Pull-up Resistor) | S| +---------+ | v GND ``` 其中 `R_pullup` 是用于上拉 K-IN 输入引脚的电阻;PMOS 负责切换主电源供给线路。 #### 关于零功耗待机功能 为了达到真正的零功耗待机效果,在实际应用中可结合光耦隔离技术或者专用芯片进一步优化设计。比如采用 CD4013 构建双稳态触发电路作为辅助部分,能够有效减少静态电流消耗[^4]。 #### 示例代码片段 下面给出一段针对 PIC16F84A 微控制器编写的基础 C 语言伪码,展示如何判断按键动作及时序管理: ```c #include <pic.h> #define DELAY_TIME_MS 1000 // 定义延时时长为一秒 void main() { TRISB = 0b00000001; // 配置 RB0 为输入模式,其余皆设为输出. while(1){ if(PORTBbits.RB0 == 0){ // 如果检测到按钮被按下... delay_ms(DELAY_TIME_MS); // 延迟一段时间 if(PORTBbits.RB0 == 0 && !is_power_on()){ turn_on_system(); // 执行开机命令 }else if(is_long_press()){ turn_off_system(); // 否则执行关机命令 } } } } ``` 注意以上仅为示意性质的功能框架,具体实现需依据所选用型号调整寄存器配置及相关参数设置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值