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;
}
使用说明
-
初始化结构体:
BtnState btn = { .idleValue = 1500, // 根据实际初始值设置 .lastInput = 1500, .state = IDLE };
-
主循环调用:
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;
}
关键特性说明
-
智能基准校准:
-
持续10秒无输入变化时,自动将当前值设为新的基准值(idleValue)
-
有效避免传感器漂移带来的误触发
-
-
多层状态判断:
-
IDLE:监测初始按压动作
-
PRESSED:跟踪按压持续时间
-
RELEASED_WAIT:处理连击判定窗口
-
-
精准时序控制:
-
长按判定(2秒)在释放时触发
-
双击检测窗口300ms(可调参数)
-
采用无符号32位时间戳,避免49天溢出问题
-
-
抗干扰设计:
-
通过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;
}
主要优化点说明
-
智能变化检测:
-
新增
delta_input
检测输入波动 -
仅当输入变化量≥50(
NOISE_THRESHOLD
)时更新有效值和时间戳 -
示例:输入在1500-1549范围内波动视为无变化
-
-
双重Delta检测机制:
c
复制
// 输入波动检测(用于记录有效变化) int delta_input = input - btn->lastInput; // 操作触发检测(基于基准值) int delta_idle = input - btn->idleValue;
两套检测系统分别用于:
-
delta_input
:过滤微小波动,管理空闲计时 -
delta_idle
:判断实际按钮操作
-
-
精准空闲管理:
-
10秒计时仅对有效变化(≥50)重置
-
微小波动不会影响空闲超时判定
-
超时后自动校准基准值,适应环境变化
-
-
状态机增强:
-
PRESSED状态持续监测实际按压持续时间
-
RELEASED_WAIT状态严格限制双击判定窗口
-
状态转换均通过阈值验证,避免误触发
-
参数调整建议
参数名称 | 默认值 | 调节方向 | 效果说明 |
---|---|---|---|
NOISE_THRESHOLD | 50 | 增大 | 增强抗干扰能力,降低灵敏度 |
PRESS_THRESHOLD | 300 | 减小 | 使按压动作更易触发 |
DOUBLE_CLICK_INTERVAL | 300ms | 增大 | 延长双击识别窗口时间 |
LONG_PRESS_TIME | 2000ms | 减小 | 使长按触发更快 |
该实现通过分层检测机制,在保证操作识别精度的同时有效抑制输入噪声,特别适合存在模拟信号波动的物理按钮或传感器应用场景。