使用deepseek写一个单击,双击和长按的检测函数

 DeepSeek好火,注册试用一下,感觉和chatgpt o1差别不大,唯一的问题就是追多几次就崩溃了,再问不下去了。以下是测试结果。   

提问:

     请使用c语言写一个函数,输入参数是是为: A为当前的输入量,取值范围1000-2000, B为当前这个输入量的状态数据结构, 函数检查这个A,判断它的变化,从而判断用户是单击还双击,还是长按。 具体当A变化量大于300时认为是开始了有效的点击,这时认为是按下按钮,记录变化前的值为C ,当A变回和C差值只有50左右时,认为释放按钮。

已深度思考(用时 272 秒)

以下是实现该功能的C语言代码,通过状态机来判断用户的单击、双击和长按动作:

#include <stdlib.h>
#include <stdint.h>

#define PRESS_THRESHOLD     300     // 触发按压的最小变化量
#define RELEASE_THRESHOLD   50      // 释放识别的最大偏差
#define LONG_PRESS_TIME     2000    // 长按时间阈值(毫秒)
#define DOUBLE_CLICK_INTERVAL 300   // 双击间隔(毫秒)
#define IDLE_RESET_TIMEOUT  10000   // 空闲重置时间(毫秒)

typedef enum {
    NO_EVENT,
    SINGLE_CLICK,
    DOUBLE_CLICK,
    LONG_PRESS
} EventType;

typedef enum {
    IDLE,
    PRESSED,
    RELEASED_WAIT
} ButtonState;

typedef struct {
    int idleValue;          // 基准空闲值
    int lastInput;          // 上一次输入值
    uint32_t lastChangeTime;// 最后一次变化时间
    uint32_t pressTime;     // 按压开始时间
    uint32_t releaseTime;   // 释放时间
    ButtonState state;      // 当前状态
    uint8_t clickCount;     // 连击计数器
} BtnState;

// 需要实现的平台时间函数(返回毫秒时间戳)
extern uint32_t get_current_time(void);

EventType check_button_action(int input, BtnState* btn) {
    uint32_t currentTime = get_current_time();
    
    /* 检测输入变化更新计时 */
    if (input != btn->lastInput) {
        btn->lastInput = input;
        btn->lastChangeTime = currentTime;
    }

    /* 10秒无变化重置基准值 */
    if (currentTime - btn->lastChangeTime > IDLE_RESET_TIMEOUT) {
        btn->idleValue = input;
        btn->state = IDLE;
        btn->clickCount = 0;
        return NO_EVENT;
    }

    EventType event = NO_EVENT;
    int delta = input - btn->idleValue;

    switch (btn->state) {
    case IDLE:
        if (abs(delta) > PRESS_THRESHOLD) {
            btn->pressTime = currentTime;
            btn->state = PRESSED;
        }
        break;

    case PRESSED:
        if (abs(delta) <= RELEASE_THRESHOLD) {
            uint32_t holdTime = currentTime - btn->pressTime;
            
            if (holdTime >= LONG_PRESS_TIME) {
                event = LONG_PRESS;
                btn->clickCount = 0;
                btn->state = IDLE;
            } else {
                btn->releaseTime = currentTime;
                btn->clickCount++;
                btn->state = RELEASED_WAIT;
            }
        }
        break;

    case RELEASED_WAIT:
        // 超时处理连击
        if (currentTime - btn->releaseTime > DOUBLE_CLICK_INTERVAL) {
            if (btn->clickCount == 1) {
                event = SINGLE_CLICK;
            } else if (btn->clickCount >= 2) {
                event = DOUBLE_CLICK;
            }
            btn->clickCount = 0;
            btn->state = IDLE;
        } 
        // 检测新的按压
        else if (abs(delta) > PRESS_THRESHOLD) {
            btn->pressTime = currentTime;
            btn->state = PRESSED;
        }
        break;
    }

    return event;
}

使用说明

  1. 初始化结构体
     

    BtnState btn = {
        .idleValue = 1500,      // 根据实际初始值设置
        .lastInput = 1500,
        .state = IDLE
    };
  2. 主循环调用

       

int sensor_value = ...; // 获取当前输入量(1000-2000范围)
EventType event = check_button_action(sensor_value, &btn);

switch (event) {
    case SINGLE_CLICK:  // 处理单击
        break;
    case DOUBLE_CLICK:  // 处理双击
        break;
    case LONG_PRESS:    // 处理长按
        break;
}

关键特性说明

  1. 智能基准校准

    • 持续10秒无输入变化时,自动将当前值设为新的基准值(idleValue)

    • 有效避免传感器漂移带来的误触发

  2. 多层状态判断

    • IDLE:监测初始按压动作

    • PRESSED:跟踪按压持续时间

    • RELEASED_WAIT:处理连击判定窗口

  3. 精准时序控制

    • 长按判定(2秒)在释放时触发

    • 双击检测窗口300ms(可调参数)

    • 采用无符号32位时间戳,避免49天溢出问题

  4. 抗干扰设计

    • 通过lastInput记录实现变化检测

    • 使用绝对值比较避免方向依赖

    • 释放阈值宽容度设计(±50)

平台适配提示

需根据具体硬件平台实现时间获取函数:

// 示例:STM32 HAL库实现
uint32_t get_current_time(void) {
    return HAL_GetTick();
}

该实现通过状态机精确区分用户操作意图,适用于需要精细交互控制的嵌入式场景,如智能设备面板、工业控制器等。

检测输入变化更新计时, 使用delta值小50认为没有变化

以下是针对需求优化后的按钮检测实现代码,重点修改输入变化检测逻辑:


#include <stdlib.h>
 #include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>


#define PRESS_THRESHOLD     300     // 按压触发阈值
#define NOISE_THRESHOLD     50      // 无效变化阈值
#define LONG_PRESS_TIME     2000    // 长按判定时间(毫秒)
#define DOUBLE_CLICK_INTERVAL 300   // 双击间隔(毫秒)
#define IDLE_RESET_TIMEOUT  10000   // 空闲重置超时(毫秒)
 
typedef enum {
    NO_EVENT,
    SINGLE_CLICK,
    DOUBLE_CLICK,
    LONG_PRESS
} EventType;
 
typedef enum {
    IDLE,
    PRESSED,
    RELEASED_WAIT
} ButtonState;
 
typedef struct {
    int idleValue;          // 基准空闲值
    int lastInput;          // 有效记录值
    uint32_t lastChangeTime;// 有效变化时间戳
    uint32_t pressTime;     // 按压开始时间
    uint32_t releaseTime;   // 释放时间戳
    ButtonState state;      // 状态机状态
    uint8_t clickCount;     // 连击计数器
} BtnState;
 
// 需实现的平台时间函数(返回毫秒时间戳)
 uint32_t get_current_time(void)
{
    return clock();
}
 
EventType check_button_action(int input, BtnState* btn) {
    uint32_t currentTime = get_current_time();
    EventType event = NO_EVENT;
    printf("input %d \n",input);

    /* 有效变化检测(Delta>=50才视为变化) */
    int delta_input = input - btn->lastInput;
    if (abs(delta_input) >= NOISE_THRESHOLD) {
    //    printf("delta_input changed %d\n", delta_input);


        btn->lastInput = input;
        btn->lastChangeTime = currentTime;
    }
 
    /* 空闲超时重置基准值(10秒无有效变化) */
    if (btn->idleValue==0 || currentTime - btn->lastChangeTime > IDLE_RESET_TIMEOUT) {
        btn->idleValue = input;
        btn->state = IDLE;
        btn->clickCount = 0;
        
        printf("first call idle %d\n",btn->idleValue );

        return NO_EVENT;
    }
 
    int delta_idle = input - btn->idleValue;
 
    switch (btn->state) {
    case IDLE:
        if (abs(delta_idle) > PRESS_THRESHOLD) {
            printf("pressed \n");
            btn->pressTime = currentTime;
            btn->state = PRESSED;
        }
        break;
 
    case PRESSED:
        if (abs(delta_idle) <= NOISE_THRESHOLD) {
            uint32_t holdDuration = currentTime - btn->pressTime;
            
            if (holdDuration >= LONG_PRESS_TIME) {
                event = LONG_PRESS;
                btn->clickCount = 0;
                btn->state = IDLE;
            } else {
                btn->releaseTime = currentTime;
                btn->clickCount++;
                btn->state = RELEASED_WAIT;
            }
        }
        break;
 
    case RELEASED_WAIT:
        // 双击超时判定
        if (currentTime - btn->releaseTime > DOUBLE_CLICK_INTERVAL) {
            event = (btn->clickCount == 1) ? SINGLE_CLICK : DOUBLE_CLICK;
            btn->clickCount = 0;
            btn->state = IDLE;
        } 
        // 检测新的有效按压
        else if (abs(delta_idle) > PRESS_THRESHOLD) {
            btn->pressTime = currentTime;
            btn->state = PRESSED;
        }
        break;
    }
    
    printf("input %d evt %d \n",input,event);
    return event;
}



int main() {
    BtnState button_state = {0};

    int A;

    // Example usage: simulate input values
    A = 1000; check_button_action(A, &button_state);
    A = 1600; check_button_action(A, &button_state); // Press detected
    usleep(200000); // Sleep for 200 milliseconds
    A = 1200; check_button_action(A, &button_state); // Still pressed
    usleep(1300000); // Sleep for 1300 milliseconds (total 1500ms -> long press)
    A = 1540; check_button_action(A, &button_state); // Force release (long press event)

    // Reset state for next example
    button_state.state = IDLE;
    button_state.clickCount = 0;

    A = 1200; check_button_action(A, &button_state);
    A = 1600; check_button_action(A, &button_state); // Press detected
    usleep(100000); // Sleep for 100ms
    A = 1550; check_button_action(A, &button_state); // Release detected
    usleep(300000); // Sleep for 300ms
    A = 1600; check_button_action(A, &button_state); // Press detected again
    usleep(100000); // Sleep for 100ms
    A = 1550; check_button_action(A, &button_state); // Release detected -> double click

    return 0;
}


主要优化点说明

  1. 智能变化检测

    • 新增delta_input检测输入波动

    • 仅当输入变化量≥50(NOISE_THRESHOLD)时更新有效值和时间戳

    • 示例:输入在1500-1549范围内波动视为无变化

  2. 双重Delta检测机制

    c

    复制

    // 输入波动检测(用于记录有效变化)
    int delta_input = input - btn->lastInput; 
    
    // 操作触发检测(基于基准值)
    int delta_idle = input - btn->idleValue;

    两套检测系统分别用于:

    • delta_input:过滤微小波动,管理空闲计时

    • delta_idle:判断实际按钮操作

  3. 精准空闲管理

    • 10秒计时仅对有效变化(≥50)重置

    • 微小波动不会影响空闲超时判定

    • 超时后自动校准基准值,适应环境变化

  4. 状态机增强

    • PRESSED状态持续监测实际按压持续时间

    • RELEASED_WAIT状态严格限制双击判定窗口

    • 状态转换均通过阈值验证,避免误触发

参数调整建议

参数名称默认值调节方向效果说明
NOISE_THRESHOLD50增大增强抗干扰能力,降低灵敏度
PRESS_THRESHOLD300减小使按压动作更易触发
DOUBLE_CLICK_INTERVAL300ms增大延长双击识别窗口时间
LONG_PRESS_TIME2000ms减小使长按触发更快

该实现通过分层检测机制,在保证操作识别精度的同时有效抑制输入噪声,特别适合存在模拟信号波动的物理按钮或传感器应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值