本文在蓝牙从机例程上添加tmos任务来实现一些按键操作,如短按,长按和双击。
源文件:
/* * button_tmos.c * * Created on: 2025年9月30日 * Author: 14646 */ #include "button_tmos.h" // 全局变量 uint8_t tmos_TaskID = INVALID_TASK_ID; // TMOS任务ID uint16_t press_duration = 0; // 按键按下持续时间(ms) uint8_t click_count = 0; // 短按计数(0:无点击,1:单击待确认,2:双击) uint8_t is_pressed = 0; // 按键当前状态(0:未按下,1:按下) // TMOS事件处理函数 uint16_t tmos_ProcessEvent(uint8_t task_id, uint16_t events) { // 系统消息事件处理(必须保留,TMOS框架要求) if(events & SYS_EVENT_MSG) { uint8_t *pMsg; if((pMsg = tmos_msg_receive(tmos_TaskID)) != NULL) { tmos_msg_deallocate(pMsg); // 释放消息内存 } return (events ^ SYS_EVENT_MSG); // 清除已处理事件 } // 按键扫描事件:周期性检测按键状态变化(按下/松开) if(events & BUTTON_SCAN_EVT) { uint32_t current_state = GPIOB_ReadPortPin(BUTTON_KEY); // 32位状态变量 // 检测到按键按下(从"未按下"变为"按下") if(current_state == 0 && !is_pressed) { is_pressed = 1; // 标记为按下状态 press_duration = 0; // 重置按下时长计数 // 启动计时事件,持续累加按下时间 tmos_start_task(tmos_TaskID, BUTTON_HOLD_EVT, SCAN_INTERVAL); } // 重新启动扫描事件,保证周期性检测 tmos_start_task(tmos_TaskID, BUTTON_SCAN_EVT, SCAN_INTERVAL); return (events ^ BUTTON_SCAN_EVT); // 清除已处理事件 } // 按键按住计时事件:累加按下时长,直到按键松开 if(events & BUTTON_HOLD_EVT) { uint32_t current_state = GPIOB_ReadPortPin(BUTTON_KEY); // 32位状态变量 // 按键仍处于按下状态:继续累加时长 if(current_state == 0 && is_pressed) { press_duration += SCAN_INTERVAL; // 累加按下时间(每次间隔SCAN_INTERVAL) // 继续启动计时事件,保持计数 tmos_start_task(tmos_TaskID, BUTTON_HOLD_EVT, SCAN_INTERVAL); } // 按键已松开(从"按下"变为"松开"):此时判定长按/短按 else if(current_state != 0 && is_pressed) { is_pressed = 0; // 标记为松开状态 // 判定为长按:松开时按下时长≥长按阈值 if(press_duration >= LONG_PRESS_MIN) { PRINT("long press (released)\n"); // 长按松开后触发 click_count = 0; // 长按后重置点击计数,避免干扰双击逻辑 } // 判定为短按:松开时按下时长<短按阈值(参与双击计数) else if(press_duration < SHORT_PRESS_MAX) { click_count++; // 短按计数+1 if(click_count == 1) { // 第一次短按:启动双击超时检测,等待第二次短按 tmos_start_task(tmos_TaskID, DOUBLE_CLICK_EVT, DOUBLE_CLICK_MAX); } else if(click_count == 2) { // 第二次短按(在超时前):判定为双击 PRINT("double click\n"); click_count = 0; // 重置计数 tmos_stop_task(tmos_TaskID, DOUBLE_CLICK_EVT); // 停止超时检测 } } // 中间状态(按下时长在SHORT_PRESS_MAX~LONG_PRESS_MIN之间):视为无效操作 else { click_count = 0; // 重置计数,避免干扰后续判断 } } return (events ^ BUTTON_HOLD_EVT); // 清除已处理事件 } // 双击超时事件:超过最大间隔未检测到第二次短按,判定为单击 if(events & DOUBLE_CLICK_EVT) { if(click_count == 1) { PRINT("single click\n"); // 输出单击 } click_count = 0; // 重置计数 return (events ^ DOUBLE_CLICK_EVT); // 清除已处理事件 } // 未处理的事件(返回0表示全部处理完毕) return 0; } // 按键GPIO初始化 void button_gpio_init() { // 配置按键引脚为上拉输入(根据硬件实际情况调整,此处为示例) GPIOB_ModeCfg(BUTTON_KEY, GPIO_ModeIN_PU); } // 按键TMOS任务初始化 void button_tmos_init() { // 注册事件处理函数,获取任务ID tmos_TaskID = TMOS_ProcessEventRegister(tmos_ProcessEvent); // 启动按键扫描事件(立即开始,间隔SCAN_INTERVAL) tmos_start_task(tmos_TaskID, BUTTON_SCAN_EVT, SCAN_INTERVAL); PRINT("button_tmos_init complete\n"); }
头文件:
/* * button_tmos.h * * Created on: 2025年9月30日 * Author: 14646 */ #include "CONFIG.h" #ifndef BUTTON_TMOS_H_ #define BUTTON_TMOS_H_ // 按键引脚定义 #define BUTTON_KEY GPIO_Pin_22 // 事件定义 #define BUTTON_SCAN_EVT 0x0001 // 按键扫描事件(周期性检测按键状态) #define BUTTON_HOLD_EVT 0x0002 // 按键按住计时事件(累加按下时长) #define DOUBLE_CLICK_EVT 0x0004 // 双击超时检测事件(判断是否为双击) // 时间参数配置(单位:ms,可根据实际需求调整) #define SCAN_INTERVAL MS1_TO_SYSTEM_TIME(20) // 按键扫描间隔(20ms一次,平衡响应速度和资源占用) #define SHORT_PRESS_MAX MS1_TO_SYSTEM_TIME(500) // 短按最大时长(超过此值不算短按,不参与双击) #define LONG_PRESS_MIN MS1_TO_SYSTEM_TIME(1000) // 长按最小时长(松开后判定为长按的阈值) #define DOUBLE_CLICK_MAX MS1_TO_SYSTEM_TIME(300) // 双击最大间隔(两次短按松开的间隔超过此值则判定为单击) extern void button_gpio_init(); extern void button_tmos_init(); #endif /* BUTTON_TMOS_H_ */
在主函数中只要调用button_gpio_init();和button_tmos_init();即可,button_tmos_init();需在蓝牙协议栈初始化后调用。
int main(void) { #if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE) PWR_DCDCCfg(ENABLE); #endif SetSysClock(CLK_SOURCE_PLL_60MHz); #if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE) GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU); GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU); #endif #ifdef DEBUG GPIOA_SetBits(bTXD1); GPIOA_ModeCfg(bTXD1, GPIO_ModeOut_PP_5mA); UART1_DefInit(); #endif button_gpio_init(); PRINT("%s\n", VER_LIB); CH59x_BLEInit(); HAL_Init(); GAPRole_PeripheralInit(); Peripheral_Init(); button_tmos_init(); Main_Circulation(); }
打印输出结果:

浙公网安备 33010602011771号