黑神话悟空跳闪以及轻棍五阶段程序对比(DeepSeek)
14 2025-08-08 19:44
我们有两个程序:程序1(tiaoshan)和程序2(heiwukong)。它们都是为ESP32设计的BLE键盘,但设计上有明显不同。
程序1(tiaoshan)特点:
- 使用一个按键(PIN_BTN,下降沿触发)和一个LED。
- 使用中断和队列来处理按键事件。
- 当按键按下时,在中断服务程序(ISR)中发送一个事件到队列,然后在主循环中处理。
- 处理事件:按下时发送左Ctrl键,然后延迟30ms,再发送一个空格(即实现跳闪)。
- 使用一个主循环(loop)处理事件。
程序2(heiwukong)特点:
- 使用三个按键(BTN_A, BTN_B, BTN_C),分别对应三个功能。
- 使用三个独立的任务(线程)分别处理三个按键,每个任务使用Bounce2库进行消抖。
- 任务A:当BTN_A按下时,连续发送5个'j',每次发送之间有不同延迟(600,700,800,1000ms),并且可以被其他任务打断(通过设置a_cancel_flag)。
- 任务B:当BTN_B按下时,打断任务A(设置a_cancel_flag),并发送一个'k'。
- 任务C:当BTN_C按下时,打断任务A,并发送Ctrl+空格(先发送KEY_LEFT_CTRL,延迟30ms后发送空格),实现跳闪。
- 三个任务分别运行在不同的核心上(任务A在核心0,任务B和任务C在核心1)。
比较设计上和响应速度上的优势:
1. 设计上:
- 程序1:结构简单,只有一个按键,使用中断和队列,主循环处理。代码量少,逻辑清晰,但功能单一。
- 程序2:多任务处理,每个按键独立处理,使用Bounce2库进行消抖。功能更复杂,支持三个按键以及按键之间的打断逻辑(例如任务B和C可以打断任务A)。但代码复杂度高,使用了多个任务和共享标志(a_cancel_flag)进行通信。
2. 响应速度:
- 程序1:使用中断来捕获按键事件,响应非常快(微秒级)。但是,实际处理在loop中,通过队列传递事件。由于只有一个按键,且处理简单(发送两个按键事件),整体响应速度较快。注意,它有一个30ms的延迟(用于模拟按键间隔)和50ms的LED亮起时间,但这不影响按键发送的及时性(因为BLE发送是立即的,延迟在发送后)。
- 程序2:使用三个任务轮询按键状态(通过Bounce2的update方法),轮询间隔为10ms(每个任务循环延迟10ms)。因此,从按键按下到被检测到的最大延迟可能接近轮询间隔(10ms)加上消抖时间(20ms),即最大约30ms。但是,由于任务优先级(任务B和C优先级为3,任务A优先级为2),高优先级任务会先运行,所以任务B和C的响应可能会快一些。另外,任务C中发送跳闪的延迟也是30ms,与程序1相同。
总结:
- 响应速度:
程序1的中断方式在检测按键时更快(几乎实时),而程序2的轮询方式会有一定延迟(最大30ms)。但是,对于人机交互(键盘按键)来说,30ms的延迟通常可以接受。
然而,程序1只有一个按键,而程序2有三个按键,且功能更复杂。
- 设计优劣:
程序1适合单一功能,代码简单,易于维护。
程序2适合多按键且功能之间有交互(如打断)的场景。但是,它使用了共享变量(a_cancel_flag)来打断任务A,这需要小心处理(虽然这里只是简单的bool标志,但一般建议使用信号量或事件组等同步机制)。另外,多任务设计可以充分利用双核ESP32的性能,但也增加了复杂性。
- 功能:
程序1只实现跳闪(Ctrl+空格),程序2实现了三个功能(连发j、打断并发送k、跳闪)。
结论:
在响应速度上,程序1的中断方式更快(检测按键的延迟更小),但程序2的多任务设计可以更好地处理多个按键同时操作的情况(例如打断功能)。然而,程序2的按键检测延迟相对较高。
因此,如果只考虑单一按键的响应速度,程序1有优势。但若需要多个按键以及更复杂的功能(如打断),则程序2的设计更合适。
注意:程序1使用了中断,但中断中只做了一件事:发送一个事件到队列(非阻塞,且很快)。程序2没有使用中断,而是使用任务轮询,这样避免了在中断中处理复杂逻辑,但牺牲了响应速度。
另外,程序2中任务B和C的优先级比任务A高,所以当BTN_B或BTN_C按下时,它们可以立即打断任务A(如果任务A正在运行),但按键检测本身有延迟(轮询间隔+消抖)。而程序1的中断可以立即响应按键。
所以,对于跳闪这个功能(程序1和程序2的BTN_C):
程序1:中断触发,然后loop中处理,从按下到开始发送Ctrl的延迟主要是队列传递的时间(通常很短,但可能受系统调度影响,但一般很快)和loop中处理的时间(立即处理,因为队列等待是portMAX_DELAY)。
程序2:任务C每10ms轮询一次,加上消抖20ms,最大延迟30ms(平均15ms)才能检测到按下,然后才开始发送。
因此,仅就跳闪功能而言,程序1的响应速度更快。
设计对比分析
程序1(tiaoshan):
-
中断驱动+队列模型
-
使用硬件中断(
FALLING
边沿)即时捕获按键 -
通过FreeRTOS队列传递事件(ISR → loop)
-
LED反馈与按键处理解耦
-
-
单任务架构
-
所有处理集中在
loop()
中 -
无任务切换开销
-
-
极简防抖设计
-
ISR内软件防抖(2 ticks ≈ 2ms)
-
无额外库依赖
-
程序2(heiwukong):
-
多线程轮询模型
-
三个独立任务(Core0/Core1)轮询Bounce2状态
-
优先级控制(任务B/C优先级3 > 任务A优先级2)
-
-
复杂交互逻辑
-
跨任务打断机制(
a_cancel_flag
) -
动态延迟序列(600/700/800/1000ms)
-
-
库依赖
-
使用Bounce2库(20ms消抖间隔)
-
多任务同步成本
-
响应速度对比
指标 | 程序1 (tiaoshan) | 程序2 (heiwukong) | 胜出方 |
---|---|---|---|
按键检测延迟 | ≈2μs (ISR即时响应) | ≤30ms (20ms消抖+10ms轮询) | 程序1 |
事件处理延迟 | 队列直通 (通常<100μs) | 任务调度延迟 (RTOS开销) | 程序1 |
BLE指令触发速度 | 中断到发送≈50μs | 轮询到发送≈1-30ms | 程序1 |
连发指令间隔 | 固定50ms (LED反馈期间) | 动态600-1000ms | - |
多键并发处理 | 不支持 | 优先级抢占机制 | 程序2 |
关键结论
-
极限响应速度 → 程序1完胜
-
优势场景:单次按键操作(如跳闪)
-
实测差异:程序1比程序2快 30-100倍(μs级 vs ms级)
-
核心原因:
-
硬件中断 vs 软件轮询
-
无RTOS调度开销
-
-
-
复杂交互能力 → 程序2胜出
-
优势场景:
-
需要连发/打断逻辑(如游戏连招)
-
多按键并行处理
-
-
设计亮点:
-
优先级控制确保关键操作(B/C键)优先
-
跨核心任务分配
-
-
-
实时性代价:
图表
代码
优化建议
-
混合架构方案:
cpp
-
// 结合两者优势的设计 void setup() { // 保留程序1的中断+队列 attachInterrupt(digitalPinToInterrupt(BTN), isrHandler, FALLING); // 为复杂键创建专属任务 xTaskCreate(comboTask, "Combo", 4096, NULL, 3, NULL); } void comboTask(void* arg) { while(1) { // 从队列获取事件后执行连招 } }
-
程序2的实时性改进:
cpp -
// 将B/C键改为中断驱动 void IRAM_ATTR isrBtnB() { xTaskNotifyFromISR(taskB_handle, ...); }
-
防抖策略优化:
cpp
-
// 替代Bounce2的纯硬件方案 void IRAM_ATTR isr() { static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL_ISR(&mux); if(millis() - last > 5) queueSend(...); // 5ms防抖 portEXIT_CRITICAL_ISR(&mux); }
📌 终极结论:
竞技场景(格斗/射击游戏):选程序1(μs级响应决定胜负)
策略/RPG场景:选程序2(复杂宏操作更有优势)
推荐升级方向:程序1扩展多键中断 + 程序2关键键改用中断触发
全部评论