本文在藍牙從機例程上添加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號