新增兼容两种墙壁开关

This commit is contained in:
xushaoxiang
2026-07-22 11:37:38 +08:00
parent 360697296c
commit 440c4b622c
93 changed files with 1851 additions and 1657 deletions
@@ -234,11 +234,11 @@ void scan_433(void)
long_timer--;
}
if(rf433_sw_flag==1)
{
rf433_sw_flag=0;
}
else if(rf433_sw_flag==2)
// if(rf433_sw_flag==1)
// {
// rf433_sw_flag=0;
// }
if(rf433_sw_flag==2)
{
rf433_sw_flag=0;
power=4;
@@ -1,429 +1,587 @@
#include "switch_s.h"
#include "xc_drv_gpio.h"
#include "rf433.h"
// ==================== GPIO1 检测 ====================
uint8_t trig1_cnt = 0; // 连续触发次数
uint16_t trig1_timeout = 0; // 300ms 倒计时
uint8_t trig1_wait = 0; // 0=空闲 1=连续出触发
// ==================== GPIO19 检测 ====================
uint8_t trig2_cnt = 0; // 连续触发次数
uint16_t trig2_timeout = 0; // 300ms 倒计时
uint8_t trig2_wait = 0; // 0=空闲 1=连续出触发
/*
* ============================================================
* GPIO1 / S1 检测变量
* ============================================================
*/
uint8_t trig1_cnt = 0;
uint16_t trig1_timeout = 0;
uint8_t trig1_wait = 0;
uint8_t rf433_sw_flag=0; //进入对码标志
/*
* ============================================================
* RF433 对码标志
* ============================================================
*
* 0:无对码
* 2:GPIO1 快速按 5 次及以上进入对码
*/
uint8_t rf433_sw_flag = 0;
/*
* ============================================================
* 防抖状态机变量
* ============================================================
*/
static volatile debounce_state_t s1_state = DB_IDLE;
static volatile debounce_state_t s2_state = DB_IDLE;
static volatile uint16_t s1_debounce_cnt = 0;
static volatile uint16_t s2_debounce_cnt = 0;
/*
* ============================================================
* 按下持续时间计数
* ============================================================
*/
static volatile uint16_t s1_press_cnt = 0;
/*
* ============================================================
* 长按普通开关已处理标志
* ============================================================
*/
static volatile uint8_t s1_long_press_done = 0;
/*
* ============================================================
* 回弹点击标志
* ============================================================
*/
static volatile uint8_t s1_return_click_flag = 0;
/*
* ============================================================
* 5次对码失效标志
* ============================================================
*
* 作用:
* 快速拨动达到 5 次后,如果最后一次停留在打开状态超过 200ms,
* 则本次 5 次对码序列失效。
*
* 这样可以避免:
* 快速拨动 5 次后停留在打开一段时间,再关闭,仍然进入对码。
*/
static volatile uint8_t s1_pair_invalid_flag = 0;
/*
* ============================================================
* 防抖时间
* ============================================================
* trigger_check_process() 如果 10ms 调用一次:
* DEBOUNCE_MS = 2 表示 20ms 防抖
*/
#define DEBOUNCE_MS 2
/*
* ============================================================
* 释放标志
* ============================================================
*/
uint8_t switch1_RELEASE_flag = 0;
/*
* ============================================================
* 普通不回弹开关第一次按下标志
* ============================================================
*/
uint8_t s1_first_press_flag = 0;
/*
* ============================================================
* 上电时开关状态
* ============================================================
*/
uint8_t S1_first_on_state = 0;
#define DEBOUNCE_MS 2 //消抖时间40ms
//uint16_t switch1_debounce = 0;
//uint16_t switch2_debounce = 0;
uint8_t switch1_RELEASE_flag=0;
uint8_t switch2_RELEASE_flag=0;
uint8_t s1_first_press_flag = 0; //S2首次按下标志
uint8_t s2_first_press_flag = 0; //S2首次按下标志
uint8_t S1_first_on_state=0; //上电时开关的状态
uint8_t S2_first_on_state=0; //上电时开关的状态
void switch_init(void)
/*
* ============================================================
* S1 状态清理函数
* ============================================================
*/
static void switch_s1_clear_action_state(void)
{
trig1_cnt = 0;
trig1_timeout = 0;
trig1_wait = 0;
GPIO_InitCfg_t GPIO_InitCfg = { 0 }; // 清零初始化配置结构体
GPIO_InitCfg.Mux = GPIO_Mux0; // 选择功能复用器0
GPIO_InitCfg.FunSel = GPIO_Dx; // 选择GPIO功能(非特殊功能)
GPIO_InitCfg.Pull = GPIO_PULLUP; //上拉电阻使能
GPIO_InitCfg.Dir = GPIO_DIR_INPUT; // 输出方向
GPIO_InitCfg.Int = FAIL_EDGE_INT; //使能中断
GPIO_InitCfg.Pin = SWITCH_S1_PIN; // 设置S1引脚
xc_gpio_init(&GPIO_InitCfg); // 初始化GPIO
// GPIO_InitCfg.Dir = GPIO_DIR_INPUT; // 输出方向
// GPIO_InitCfg.Int = FAIL_EDGE_INT; //使能中断
// GPIO_InitCfg.Pin = SWITCH_S2_PIN; // 设置S2引脚
// xc_gpio_init(&GPIO_InitCfg); // 初始化GPIO
xc_gpio_it_config(GPIO_1,FAIL_EDGE_INT);
xc_gpio_it_config(GPIO_19,FAIL_EDGE_INT);
NVIC_EnableIRQ(GPIO_IRQn);
//判断首次上电开关状态
if(xc_gpio_read_pin(SWITCH_S1_PIN)==0)
{
S1_first_on_state=1;
}
else
{
S1_first_on_state=0;
}
if(xc_gpio_read_pin(SWITCH_S2_PIN)==0)
{
S2_first_on_state=1;
}
else
{
S2_first_on_state=0;
}
switch1_RELEASE_flag = 0;
s1_first_press_flag = 0;
s1_return_click_flag = 0;
s1_long_press_done = 0;
s1_press_cnt = 0;
/*
* 新增:
* 清理 5 次对码失效标志。
*/
s1_pair_invalid_flag = 0;
}
/*
* ============================================================
* S1 输出控制:GPIO5
* ============================================================
*/
static void switch_s1_output_on(void)
{
xc_gpio_write_pin(GPIO_5, GPIO_PIN_SET);
flash_ch1_state = xc_gpio_read_pin(GPIO_5);
flash_run();
}
static void switch_s1_output_off(void)
{
xc_gpio_write_pin(GPIO_5, GPIO_PIN_RESET);
flash_ch1_state = xc_gpio_read_pin(GPIO_5);
flash_run();
}
static void switch_s1_output_toggle(void)
{
if(xc_gpio_read_pin(GPIO_5))
{
xc_gpio_write_pin(GPIO_5, GPIO_PIN_RESET);
}
else
{
xc_gpio_write_pin(GPIO_5, GPIO_PIN_SET);
}
flash_ch1_state = xc_gpio_read_pin(GPIO_5);
flash_run();
}
/*
* ============================================================
* 开关 GPIO 初始化
* ============================================================
*/
void switch_init(void)
{
GPIO_InitCfg_t GPIO_InitCfg = { 0 };
GPIO_InitCfg.Mux = GPIO_Mux0;
GPIO_InitCfg.FunSel = GPIO_Dx;
GPIO_InitCfg.Pull = GPIO_PULLUP;
/*
* GPIO1 输入初始化
*/
GPIO_InitCfg.Dir = GPIO_DIR_INPUT;
GPIO_InitCfg.Int = FAIL_EDGE_INT;
GPIO_InitCfg.Pin = SWITCH_S1_PIN;
xc_gpio_init(&GPIO_InitCfg);
/*
* GPIO1 下降沿中断
*/
xc_gpio_it_config(GPIO_1, FAIL_EDGE_INT);
NVIC_EnableIRQ(GPIO_IRQn);
/*
* 上电时检测 GPIO1 初始状态
*/
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 0)
{
S1_first_on_state = 1;
}
else
{
S1_first_on_state = 0;
}
}
/*
* ============================================================
* 开关检测主处理函数
* ============================================================
*
* 需要周期调用。
* 当前按 SWITCH_SCAN_PERIOD_MS = 10ms 计算。
*/
void trigger_check_process(void)
{
if(S1_first_on_state==1)
{
S1_first_on_state=0;
s1_state=DB_PRESS_DEBOUNCE;
}
// if(S2_first_on_state==1)
// {
// S2_first_on_state=0;
//
// s2_state=DB_PRESS_DEBOUNCE;
// }
// if(S1_first_on_state==1)
// {
// S1_first_on_state=0;
// s1_first_press_flag=1;
// s1_state=DB_PRESSED;
// }
// if(S2_first_on_state==1)
// {
// S2_first_on_state=0;
// s2_first_press_flag=1;
// s2_state=DB_PRESSED;
// }
switch(s1_state)
{
case DB_IDLE: //空闲状态
break;
case DB_PRESS_DEBOUNCE: //按下防抖
if(s1_debounce_cnt>0) s1_debounce_cnt--;
if(s1_debounce_cnt==0)
{
//防抖时间到,采样当前电平是否是低电平
if(xc_gpio_read_pin(SWITCH_S1_PIN)==0)
{
s1_state = DB_PRESSED; //进入按下状态,不响应中断
if(trig1_wait == 0)
{
trig1_cnt = 1;
trig1_timeout = TRIGGER_TIMEOUT_MS;
trig1_wait = 1;
}
else
{
if(trig1_timeout>0)
{
trig1_cnt++;
}
trig1_timeout = TRIGGER_TIMEOUT_MS;
//
}
}
else
{
// 杂波导致误触,回到空闲
s1_state = DB_IDLE;
}
}
break;
case DB_PRESSED: //确认按下
// 等待引脚回高电平
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 1)
/*
* ========================================================
* 上电时 GPIO1 已经按下
* ========================================================
*/
if(S1_first_on_state == 1)
{
S1_first_on_state = 0;
s1_state = DB_PRESS_DEBOUNCE;
s1_debounce_cnt = DEBOUNCE_MS;
}
/*
* ========================================================
* S1 状态机
* ========================================================
*/
switch(s1_state)
{
case DB_IDLE:
/*
* 空闲状态低电平补检,防止漏中断。
*/
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 0)
{
s1_state = DB_RELEASE_DEBOUNCE;
s1_debounce_cnt = DEBOUNCE_MS; // 释放30ms防抖
s1_state = DB_PRESS_DEBOUNCE;
s1_debounce_cnt = DEBOUNCE_MS;
}
break;
case DB_RELEASE_DEBOUNCE: //释放防抖
if(s1_debounce_cnt > 0) s1_debounce_cnt--;
case DB_PRESS_DEBOUNCE:
if(s1_debounce_cnt > 0)
{
s1_debounce_cnt--;
}
if(s1_debounce_cnt == 0)
{
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 1) // 确认释放
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 0)
{
s1_state = DB_IDLE; // 回到空闲
trig1_timeout = TRIGGER_TIMEOUT_MS;
switch1_RELEASE_flag=1;
if(s1_first_press_flag==1)
{
s1_first_press_flag=2;
}
s1_state = DB_PRESSED;
s1_press_cnt = 0;
s1_long_press_done = 0;
/*
* 连续触发计数
*/
if(trig1_wait == 0)
{
trig1_cnt = 1;
trig1_timeout = TRIGGER_TIMEOUT_MS;
trig1_wait = 1;
}
else
{
if(trig1_timeout > 0)
{
trig1_cnt++;
}
else
{
/*
* 如果等待标志还在,但超时已经为 0,
* 说明旧状态异常,重新作为第一次点击。
*/
trig1_cnt = 1;
}
trig1_timeout = TRIGGER_TIMEOUT_MS;
}
}
else
{
// 再等20ms
s1_debounce_cnt = DEBOUNCE_MS; // 30ms
s1_state = DB_IDLE;
}
}
break;
}
//
// switch(s2_state)
// {
// case DB_IDLE: //空闲状态
// break;
//
// case DB_PRESS_DEBOUNCE: //按下防抖
// if(s2_debounce_cnt>0) s2_debounce_cnt--;
// if(s2_debounce_cnt==0)
// {
// //防抖时间到,采样当前电平是否是低电平
// if(xc_gpio_read_pin(SWITCH_S2_PIN)==0)
// {
// s2_state = DB_PRESSED; //进入按下状态,不响应中断
// if(trig2_wait == 0)
// {
// trig2_cnt = 1;
// trig2_timeout = TRIGGER_TIMEOUT_MS;
// trig2_wait = 1;
// }
// else
// {
// if(trig2_timeout>0)
// {
// trig2_cnt++;
// }
//
// trig2_timeout = TRIGGER_TIMEOUT_MS;
// }
// }
// else
// {
// // 杂波导致误触,回到空闲
// s2_state = DB_IDLE;
// }
// }
// break;
//
//
// case DB_PRESSED: //确认按下
// // 等待引脚回高电平
// if(xc_gpio_read_pin(SWITCH_S2_PIN) == 1)
// {
// s2_state = DB_RELEASE_DEBOUNCE;
// s2_debounce_cnt = DEBOUNCE_MS; // 释放30ms防抖
// }
// break;
case DB_PRESSED:
/*
* 按下超过 200ms
* 认为是普通不回弹墙壁开关,打开 GPIO5。
*/
if(s1_long_press_done == 0)
{
if(s1_press_cnt < RETURN_SWITCH_CNT)
{
s1_press_cnt++;
}
// case DB_RELEASE_DEBOUNCE: //释放防抖
// if(s2_debounce_cnt > 0) s2_debounce_cnt--;
// if(s2_debounce_cnt == 0)
// {
// if(xc_gpio_read_pin(SWITCH_S2_PIN) == 1) // 确认释放
// {
// s2_state = DB_IDLE; // 回到空闲
// trig2_timeout = TRIGGER_TIMEOUT_MS;
// switch2_RELEASE_flag=1;
// if(s2_first_press_flag==1)
// {
// s2_first_press_flag=2;
//
// }
//
//
// }
// else
// {
// // 再等20ms
// s2_debounce_cnt = DEBOUNCE_MS; // 30ms
// }
// }
// break;
// }
// S1 超时处理
if(s1_press_cnt >= RETURN_SWITCH_CNT)
{
s1_long_press_done = 1;
/*
* 普通不回弹开关只处理第一次有效按下。
*
* 注意:
* 这里仍然要求 trig1_cnt == 1
* 避免快速多次点击被误判成长按开关打开。
*/
if(trig1_cnt == 1 && trig1_wait == 1)
{
trig1_cnt = 0;
trig1_timeout = 0;
trig1_wait = 0;
s1_return_click_flag = 0;
switch1_RELEASE_flag = 0;
s1_first_press_flag = 1;
switch_s1_output_on();
}
else if(trig1_cnt >= TRIGGER_CONTINUE_CNT)
{
/*
* ====================================================
* 关键新增修复
* ====================================================
*
* 如果已经快速拨动到了 5 次或以上,
* 但是最后一次保持在打开状态超过 200ms,
* 那么这一次对码序列作废。
*
* 后面即使再关闭,也不能进入对码。
*/
s1_pair_invalid_flag = 1;
/*
* 防止旧的回弹点击标志残留。
*/
s1_return_click_flag = 0;
switch1_RELEASE_flag = 0;
}
}
}
/*
* 检测释放
*/
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 1)
{
s1_state = DB_RELEASE_DEBOUNCE;
s1_debounce_cnt = DEBOUNCE_MS;
}
break;
case DB_RELEASE_DEBOUNCE:
if(s1_debounce_cnt > 0)
{
s1_debounce_cnt--;
}
if(s1_debounce_cnt == 0)
{
if(xc_gpio_read_pin(SWITCH_S1_PIN) == 1)
{
s1_state = DB_IDLE;
/*
* ====================================================
* 关键新增修复
* ====================================================
*
* 如果前面已经判定:
* 快速拨动 5 次后,最后一次停留打开超过 200ms,
* 那么这次释放只是无效释放。
*
* 直接清理状态,不再进入后面的 5 次对码处理。
*/
if(s1_pair_invalid_flag == 1)
{
switch_s1_clear_action_state();
}
else
{
/*
* 释放后重新给连击窗口计时。
*/
trig1_timeout = TRIGGER_TIMEOUT_MS;
switch1_RELEASE_flag = 1;
if(s1_long_press_done == 0)
{
/*
* 200ms 内释放:
* 回弹点击。
*/
s1_return_click_flag = 1;
}
else
{
/*
* 普通不回弹开关释放。
*/
if(s1_first_press_flag == 1)
{
s1_first_press_flag = 2;
}
}
}
}
else
{
s1_debounce_cnt = DEBOUNCE_MS;
}
}
break;
default:
s1_state = DB_IDLE;
break;
}
/*
* ========================================================
* S1 连击超时处理
* ========================================================
*/
if(trig1_timeout > 0)
{
trig1_timeout--;
}
else if(trig1_timeout==0 && switch1_RELEASE_flag==1 )
{
switch1_RELEASE_flag=2;
}
// 600ms倒计时结束,且有计数
if(trig1_timeout == 0 && trig1_cnt == 1 && trig1_wait == 1 && s1_state == DB_PRESSED) //确定按下1次
{
//printf("按下一次 trig1_cnt %d\r\n",trig1_cnt);
trig1_cnt = 0;
trig1_wait = 0;
s1_first_press_flag=1;
xc_gpio_write_pin(GPIO_5,GPIO_PIN_SET);
flash_ch1_state=xc_gpio_read_pin(GPIO_5);
flash_run();
}
else if(trig1_timeout == 0 && (trig1_cnt > 1 && trig1_cnt < TRIGGER_CONTINUE_CNT))
{
// printf("乱按 trig1_cnt %d\r\n",trig1_cnt);
trig1_cnt = 0;
trig1_wait = 0;
}
else if(trig1_timeout == 0 && trig1_cnt >= TRIGGER_CONTINUE_CNT)
{
//printf("对码 trig1_cnt %d\r\n",trig1_cnt);
if( s1_state == DB_IDLE)
{
rf433_sw_flag = 2; // HPW421: S1/GPIO5 is the single relay L2 pairing key
trig1_cnt = 0;
trig1_wait = 0;
}
else
{
trig1_cnt = 0;
trig1_wait = 0;
}
}
else if(trig1_timeout == 0 && switch1_RELEASE_flag==2 && s1_state == DB_IDLE && s1_first_press_flag==2 )
{
// printf("低电平 trig2_cnt %d\r\n",trig2_cnt);
s1_state = DB_IDLE;
switch1_RELEASE_flag=0;
s1_first_press_flag=0;
xc_gpio_write_pin(GPIO_5,GPIO_PIN_RESET);
flash_ch1_state=xc_gpio_read_pin(GPIO_5);
flash_run();
}
// // S2 超时处理
// if(trig2_timeout > 0)
// {
// trig2_timeout--;
// }
// else if(trig2_timeout==0 && switch2_RELEASE_flag==1 )
// {
// switch2_RELEASE_flag=2;
// }
//
//
// // 600ms倒计时结束,且有计数
// if(trig2_timeout == 0 && trig2_cnt == 1 && trig2_wait == 1 && s2_state == DB_PRESSED) //确定按下1次
// {
//
// trig2_cnt = 0;
// trig2_wait = 0;
// s2_first_press_flag=1;
//
// xc_gpio_write_pin(GPIO_2,GPIO_PIN_SET);
//
// flash_ch2_state=xc_gpio_read_pin(GPIO_2);
// flash_run();
//
//
// }
//
// else if(trig2_timeout == 0 && (trig2_cnt > 1 && trig2_cnt < TRIGGER_CONTINUE_CNT))
// {
//
// trig2_cnt = 0;
// trig2_wait = 0;
//
//
//
// }
// else if(trig2_timeout == 0 && trig2_cnt >= TRIGGER_CONTINUE_CNT)
// {
//
//
// if( s2_state == DB_IDLE)
// {
// rf433_sw_flag = 2;
// trig2_cnt = 0;
// trig2_wait = 0;
// }
// else
// {
// trig2_cnt = 0;
// trig2_wait = 0;
// }
//
//
// }
//
//
//
// else if(trig2_timeout == 0 && switch2_RELEASE_flag==2 && s2_state == DB_IDLE && s2_first_press_flag==2 )
// {
//
//
//
// s2_state = DB_IDLE;
// switch2_RELEASE_flag=0;
// s2_first_press_flag=0;
//
// xc_gpio_write_pin(GPIO_2,GPIO_PIN_RESET);
// flash_ch2_state=xc_gpio_read_pin(GPIO_2);
// flash_run();
// }
}
else if(trig1_timeout == 0 && switch1_RELEASE_flag == 1)
{
switch1_RELEASE_flag = 2;
}
/*
* ========================================================
* S1 回弹开关处理
* ========================================================
*/
if(trig1_timeout == 0 &&
switch1_RELEASE_flag == 2 &&
s1_state == DB_IDLE &&
s1_return_click_flag == 1)
{
if(trig1_cnt == 1 && trig1_wait == 1)
{
/*
* 单击:
* GPIO5 翻转。
*/
switch_s1_clear_action_state();
switch_s1_output_toggle();
}
else if(trig1_cnt > 1 && trig1_cnt < TRIGGER_CONTINUE_CNT)
{
/*
* 2~4 次:
* 不动作,但必须彻底清状态。
*/
switch_s1_clear_action_state();
}
else if(trig1_cnt >= TRIGGER_CONTINUE_CNT)
{
/*
* 5 次及以上:
* 进入对码。
*
* 这里增加 s1_pair_invalid_flag 判断。
* 正常快速拨动 5 次并最终关闭:进入对码。
* 拨动 5 次后停留打开一段时间再关闭:不进入对码。
*/
if(s1_pair_invalid_flag == 0)
{
rf433_sw_flag = 2;
}
switch_s1_clear_action_state();
}
else
{
/*
* 异常兜底清理。
*/
switch_s1_clear_action_state();
}
}
/*
* ========================================================
* 普通不回弹开关释放后关闭 GPIO5
* ========================================================
*/
else if(trig1_timeout == 0 &&
switch1_RELEASE_flag == 2 &&
s1_state == DB_IDLE &&
s1_first_press_flag == 2)
{
/*
* 普通不回弹开关释放后关闭 GPIO5。
*/
switch_s1_clear_action_state();
switch_s1_output_off();
}
/*
* ========================================================
* 兜底:2~4 次超时
* ========================================================
*/
else if(trig1_timeout == 0 &&
trig1_cnt > 1 &&
trig1_cnt < TRIGGER_CONTINUE_CNT)
{
/*
* 2~4 次:
* 不动作,但是必须清理全部状态。
*/
switch_s1_clear_action_state();
}
/*
* ========================================================
* 兜底:5 次及以上超时
* ========================================================
*/
else if(trig1_timeout == 0 &&
trig1_cnt >= TRIGGER_CONTINUE_CNT &&
s1_state == DB_IDLE)
{
/*
* 5 次及以上:
*
* 这里必须保留对码。
* 因为正常快速拨动 5 次后,经常就是走这个兜底分支进入对码。
*
* 但是增加 s1_pair_invalid_flag 判断:
* 如果是“5次后停留打开超过200ms再关闭”,则不允许对码。
*/
if(s1_pair_invalid_flag == 0)
{
rf433_sw_flag = 2;
}
switch_s1_clear_action_state();
}
/*
* ========================================================
* 兜底:异常释放状态
* ========================================================
*/
else if(trig1_timeout == 0 &&
switch1_RELEASE_flag == 2 &&
s1_state == DB_IDLE &&
trig1_cnt == 0 &&
trig1_wait == 0)
{
/*
* 防止残留 switch1_RELEASE_flag == 2。
*/
switch_s1_clear_action_state();
}
}
/*
* ============================================================
* GPIO 中断回调
* ============================================================
*/
void gpio_intr_callback(uint64_t intr_sta)
{
if((intr_sta & ((uint64_t)1 << SWITCH_S1_PIN)) != 0) //如果是GPIO_1的中断
{
if(s1_state == DB_IDLE && S1_first_on_state==0) // 只有空闲才响应
/*
* GPIO1 下降沿中断
*/
if((intr_sta & ((uint64_t)1 << SWITCH_S1_PIN)) != 0)
{
if(s1_state == DB_IDLE && S1_first_on_state == 0)
{
s1_state = DB_PRESS_DEBOUNCE;
s1_debounce_cnt = DEBOUNCE_MS; // 40ms防抖
s1_debounce_cnt = DEBOUNCE_MS;
}
}
// if((intr_sta & ((uint64_t)1 << SWITCH_S2_PIN)) != 0) //如果是GPIO_19的中断
// {
// if(s2_state == DB_IDLE && S2_first_on_state==0)
// {
// s2_state = DB_PRESS_DEBOUNCE;
// s2_debounce_cnt = DEBOUNCE_MS;
// }
// }
}
}
@@ -1,47 +1,75 @@
#ifndef __SWITCH_S_H__
#define __SWITCH_S_H__
#include <stdint.h>
#include "xc_drv_gpio.h"
/*
* ============================================================
* 开关检测说明
* ============================================================
*
* 当前版本只保留 S1
*
* 输入:
* GPIO1
*
* 输出:
* GPIO5
*
* 功能:
*
* 1. 普通不回弹墙壁开关:
* - GPIO1 按下超过 200ms 不松手:
* GPIO5 打开。
* - GPIO1 释放后:
* GPIO5 关闭。
*
* 2. 回弹开关:
* - GPIO1 200ms 内按下松开:
* 认为是一次回弹点击。
* - 单击 1 次:
* GPIO5 翻转,开变关,关变开。
* - 快速点击 2~4 次:
* 不动作。
* - 快速点击 5 次及以上,并且最终释放为关:
* rf433_sw_flag = 2,进入对码。
*
* 3. 修复点:
* - 对码后彻底清理所有开关状态,避免后续只能开不能关。
* - DB_IDLE 状态增加 GPIO1 低电平补检,避免漏中断。
* - 快速拨动 5 次后如果最后停在打开状态,等一段时间再关,
* 不再进入对码。
*/
// 400ms 超时
#define TRIGGER_TIMEOUT_MS 20
// 连续触发次数
#define TRIGGER_CONTINUE_CNT 5
// trigger_check_process() 实际调用周期,单位 ms
#define SWITCH_SCAN_PERIOD_MS 10
#define SWITCH_S1_PIN GPIO_1
#define SWITCH_S2_PIN GPIO_19
// 连击超时时间:20 * 10ms = 200ms
#define TRIGGER_TIMEOUT_MS 20
// 连续触发次数,达到 5 次进入对码
#define TRIGGER_CONTINUE_CNT 5
// 回弹开关判断时间:200ms 内松手,认为是回弹开关
#define RETURN_SWITCH_TIME_MS 200
#define RETURN_SWITCH_CNT (RETURN_SWITCH_TIME_MS / SWITCH_SCAN_PERIOD_MS)
// S1 输入引脚
#define SWITCH_S1_PIN GPIO_1
// 防抖状态机
typedef enum {
DB_IDLE = 0, // 空闲,等待下降沿
DB_PRESS_DEBOUNCE, // 按下防抖中
DB_PRESSED, // 确认按下,等待释放
DB_RELEASE_DEBOUNCE // 释放防抖
DB_IDLE = 0,
DB_PRESS_DEBOUNCE,
DB_PRESSED,
DB_RELEASE_DEBOUNCE
} debounce_state_t;
extern uint8_t rf433_sw_flag;
extern uint8_t S1_first_on_state;
extern uint8_t S2_first_on_state;
void switch_init(void);
void trigger_check_process(void);
#endif