Ayb_ice 发表于 2025-3-10 08:46
中断里还死等
中断只开机长按使用,应该没事吧 huaruolong 发表于 2025-3-11 14:04
还不错,这适用于单独工作的按键,如果有多个工作似乎不实用,比如如果有称重模块,计数模块等等,那个延时 ...
多个模块就需要用定时器了,先做个最基础的起来,后面可以再加 wszjw2 发表于 2025-3-11 16:40
中断只开机长按使用,应该没事吧
这样还好 谢谢分享 wszjw2 发表于 2025-3-11 16:41
多个模块就需要用定时器了,先做个最基础的起来,后面可以再加
谢谢分享,静等楼主更好的模块。 {:qiang:} 这段程序测试感觉已经完成了,但是为什么把这段程序封装成BUTTON.C之后让main调用它就不稳定,会出现双击识别不了,关机后得多次长按才行
#include <STC8H.H>
#include <intrins.h>
// 硬件配置
sbit KEY_PIN = P3^2; // 按键接P3.2
sbit LIGHT=P1^0;
//
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
// 宏定义
#define DEBOUNCE_MS 20 // 消抖时间20ms
#define DOUBLE_PRESS 300 // 双击间隔300ms
#define LONG_PRESS 10000
#define MAIN_LOOP_CYCLE 10 // 主循环周期10ms
#define MAIN_Fosc 24000000L //定义主时钟
// 全局变量
static u8 key_event = 0; // 按键事件(1=单击,2=双击)
static u8 key_state = 0; // 按键状态机
static u8 power_flag=0;
static u8 wake_flag=0;
u8 mode=0;
void power_off();
voiddelay_ms(u16 ms)
{
u16 i;
do
{
i = MAIN_Fosc / 10000;
while(--i) ;
}while(--ms);
}
void key_scan() {
static u16 release_timer = 0;
static u8click_count = 0;
static bit last_pin_state = 1;
static u16 press_counter=0;
// 状态机处理
switch(key_state) {
case 0: // 初始状态
if(KEY_PIN == 0 && last_pin_state == 1)// 检测到下降沿
{
delay_ms(DEBOUNCE_MS);
if(KEY_PIN == 0)
{ // 确认按下
key_state = 1;
click_count+=1;
press_counter=0;
}
}
break;
case 1: // 已按下,等待释放
press_counter+=MAIN_LOOP_CYCLE;
if(KEY_PIN == 1) // 检测到释放
{
delay_ms(DEBOUNCE_MS);
if(KEY_PIN == 1)
{
key_state = 2;
release_timer = 0; // 启动双击检测窗口
}
}
else if(press_counter>LONG_PRESS)
{
key_event=3; //长按
click_count=0;
key_state=0;
press_counter=0;
}
break;
case 2: // 释放状态,检测双击窗口
release_timer += MAIN_LOOP_CYCLE;
if(release_timer >= DOUBLE_PRESS) { // 超时处理
if(click_count == 1) {
key_event = 1; // 单击
}
click_count = 0;
key_state = 0;
} else if(KEY_PIN == 0) { // 再次按下
delay_ms(DEBOUNCE_MS);
if(KEY_PIN == 0) {
click_count+=1;
key_state = 3;
}
}
break;
case 3: // 第二次按下,等待释放
if(KEY_PIN == 1) {
delay_ms(DEBOUNCE_MS);
if(KEY_PIN == 1) {
if(click_count >= 2) {
key_event = 2; // 双击
}
click_count = 0;
key_state = 0;
}
}
break;
}
last_pin_state = KEY_PIN; // 更新引脚状态
}
void power_off()
{
power_flag=0; //关机标志置0
P1IE=0X00;
P2IE=0X00;
P3IE=0X04; //关闭除P32外的数字输入
IT0=1;
EX0=1;
EA=1; //关机时打开外部中断,进行初始化,下降沿触发
PCON |=PD; //进入掉电模式
NOP1();
}
void wake_init()
{
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;//初始化端口,设置为双向口
EX0=0;
EA=0; //开机时关闭中断
wake_flag=0; //唤醒初始化完成,唤醒标志置0
}
/**/
// 主函数
void main()
{
power_off(); //上电默认为低功耗模式
while(1)
{
key_scan();
if(power_flag==1) //
{
if(wake_flag==1)wake_init();
P25=0;
switch(key_event)
{
case 1:
P21=~P21;
key_event=0;
break;
case 2:
P24=~P24;
key_event=0;
break;
case 3:
P25=1;power_off();
key_event=0;
break;
}
}
else{power_off();P25=1;}
delay_ms(10);
}
}
void exint0() interrupt 0
{
u16 hold_cnt = 0;// 改为16位计数器
// 长按检测(不依赖延时函数)
while(KEY_PIN == 0) {
if(++hold_cnt > (LONG_PRESS/10)) { // 每10ms计数
power_flag = 1;
wake_flag=1;
P23=~P23;
return;
}
delay_ms(10);// 仅用于粗略计时
}
}
页:
1
[2]