/****************************************************************************** 版权所有 (C), 2018-2099, Radkil ****************************************************************************** 文 件 名 : button.c 版 本 号 : 初稿 作 者 : Radkil 生成日期 : 2026年3月25日星期三 最近修改 : 功能描述 : 按键时间驱动处理(含优先级机制) 修改历史 : 1.日 期 : 2026年3月25日星期三 作 者 : Radkil 修改内容 : 创建文件 ******************************************************************************/ #include "button.h" #include "rd_thread.h" #include "rd_time.h" /*----------------------------------------------* * 外部变量说明 * *----------------------------------------------*/ /*----------------------------------------------* * 外部函数原型说明 * *----------------------------------------------*/ /*----------------------------------------------* * 内部函数原型说明 * *----------------------------------------------*/ /*----------------------------------------------* * 全局变量 * *----------------------------------------------*/ /*----------------------------------------------* * 模块级变量 * *----------------------------------------------*/ #define RD_BUTTON_ELIMINATION_TIME_DEFAULT 15 /**< 按键消抖默认时间 15ms */ #define RD_BUTTON_TWO_INTERVAL_TIME_DEFAULT 500 /**< 两次按键按下间隔超过500ms清零重复计数 */ #define RD_BUTTON_HOLD_CYCLE_TIME_DEFAULT 500 /**< 按键按下后持续调用回调函数的周期 */ static rd_slist_t g_sBtnListHead = RD_SLIST_OBJECT_INIT(g_sBtnListHead); static rd_mutex_t g_fpBtnCtrl = RD_MUTEX_INITIALIZER; /*----------------------------------------------* * 模块级变量 - 优先级控制 * *----------------------------------------------*/ static int g_iPriorityLock = 0; /**< 优先级锁:>0 时屏蔽低于该值的按键 */ /*----------------------------------------------* * 常量定义 * *----------------------------------------------*/ /*----------------------------------------------* * 宏定义 * *----------------------------------------------*/ /** * @brief 判断按键是否被优先级锁屏蔽 * @return 1=被屏蔽,0=允许处理 */ static int rd_BtnIsPriorityLocked(rd_btn_t *_pBtn) { if (g_iPriorityLock <= 0) return 0; /* 优先级数值越小越高,被锁的按键优先级低于锁值则屏蔽 */ if (_pBtn->m_iPriority >= g_iPriorityLock) return 1; return 0; } /** * @brief 更新当前最高活跃优先级(用于自动加锁/解锁) */ static void rd_BtnUpdatePriorityLock(void) { rd_slist_t *pNode; rd_slist_t *pN; int highest = -1; /* -1 表示没有按键处于按下状态 */ rd_slist_for_each(pNode, pN, &g_sBtnListHead) { rd_btn_t *_pBtn = rd_slist_entry(pNode, rd_btn_t, m_tSlist); if (_pBtn->m_iActive && (_pBtn->m_tState == STATE_PRESS_DOWN || _pBtn->m_tState == STATE_PRESS_HOLD)) { if (highest < 0 || _pBtn->m_iPriority < highest) highest = _pBtn->m_iPriority; } } if (highest < 0) { /* 没有按键按下,自动解锁 */ g_iPriorityLock = 0; } else { /* 有按键按下,锁定比它优先级低的按键 */ g_iPriorityLock = highest + 1; } } rd_btn_t *rd_BtnCreate(int _iActiveLogic, rd_btn_read_func pReadFunc, int _iPriority) { rd_btn_t *pBtn = (rd_btn_t *)RD_MALLOC(sizeof(rd_btn_t)); if (pBtn == NULL) return NULL; RD_MEMSET(pBtn, 0, sizeof(rd_btn_t)); pBtn->m_iActive = 0; pBtn->m_iRepeatCnt = 0; pBtn->m_iEliminationTime = RD_BUTTON_ELIMINATION_TIME_DEFAULT; pBtn->m_tEvent = EVENT_NUM; pBtn->m_tState = STATE_NONE_PRESS; pBtn->m_iHoldTime = 0; pBtn->m_iPrevHoldTime = 0; pBtn->m_iHoldCycleTime = RD_BUTTON_HOLD_CYCLE_TIME_DEFAULT; pBtn->m_iActiveLogic = _iActiveLogic; pBtn->m_iTimeout = Rd_GetTime(); pBtn->m_pReadFunc = pReadFunc; pBtn->m_iPriority = _iPriority; /* 新增:初始化优先级 */ rd_slist_init(&(pBtn->m_tSlist)); return pBtn; } int rd_BtnDelete(rd_btn_t *_pBtn) { if(NULL == _pBtn) { return RD_INVALUE; } Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); rd_slist_remove(&g_sBtnListHead, &(_pBtn->m_tSlist)); _pBtn->m_iActive = 0; _pBtn->m_tSlist.next = NULL; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); RD_FREE(_pBtn); return RD_SUCCESS; } int rd_BtnStart(rd_btn_t *_pBtn) { if(NULL == _pBtn) { return RD_INVALUE; } Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); if (_pBtn->m_iActive) { Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_INVALUE; } _pBtn->m_iRepeatCnt = 0; _pBtn->m_tEvent = EVENT_NUM; _pBtn->m_tState = STATE_NONE_PRESS; _pBtn->m_iHoldTime = 0; _pBtn->m_iPrevHoldTime = 0; _pBtn->m_iTimeout = Rd_GetTime(); rd_slist_append(&g_sBtnListHead, &(_pBtn->m_tSlist)); _pBtn->m_iActive = 1; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_SUCCESS; } int rd_BtnStop(rd_btn_t *_pBtn) { if(NULL == _pBtn) { return RD_INVALUE; } Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); if (!_pBtn->m_iActive) { Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_INVALUE; } rd_slist_remove(&g_sBtnListHead, &(_pBtn->m_tSlist)); _pBtn->m_tSlist.next = NULL; _pBtn->m_iActive = 0; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_SUCCESS; } int rd_BtnSetEliminationTime(rd_btn_t *_pBtn, uint8_t _iEliminationTime) { if(NULL == _pBtn) { return RD_INVALUE; } Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); _pBtn->m_iEliminationTime = _iEliminationTime; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_SUCCESS; } int rd_BtnSetHoldCycleTime(rd_btn_t *_pBtn, uint32_t _iHoldCycleTime) { if(NULL == _pBtn) { return RD_INVALUE; } Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); _pBtn->m_iHoldCycleTime = _iHoldCycleTime; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_SUCCESS; } int rd_BtnSetEventCbk(rd_btn_t *_pBtn, rd_BtnEvent _eEvent, void (*_pEventCbk)(rd_btn_t *pBtn)) { if(NULL == _pBtn) { return RD_INVALUE; } if (_eEvent >= EVENT_NUM) return RD_INVALUE; Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); _pBtn->m_pEventCbk[_eEvent] = _pEventCbk; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_SUCCESS; } /** * @brief 手动设置按键优先级 */ int rd_BtnSetPriority(rd_btn_t *_pBtn, int _iPriority) { if (NULL == _pBtn) return RD_INVALUE; Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); _pBtn->m_iPriority = _iPriority; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); return RD_SUCCESS; } /** * @brief 手动加优先级锁(屏蔽优先级 >= _iLockValue 的按键) * @param _iLockValue 锁值,优先级 >= 此值的按键被屏蔽,0=解锁 */ void rd_BtnPriorityLock(int _iLockValue) { Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); g_iPriorityLock = _iLockValue; Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); } /** * @brief 手动解锁优先级锁 */ void rd_BtnPriorityUnlock(void) { rd_BtnPriorityLock(0); } static void rd_BtnCalHoldTime(rd_btn_t *_pBtn) { if(NULL == _pBtn) { return; } _pBtn->m_iHoldTime = Rd_GetTime() - _pBtn->m_iTimeout; } void rd_BtnProcess() { rd_slist_t *pNode; rd_slist_t *pN; Rd_MutexLock(&g_fpBtnCtrl, __func__, NULL); rd_slist_for_each(pNode, pN, &g_sBtnListHead) { rd_btn_t *_pBtn = rd_slist_entry(pNode, rd_btn_t, m_tSlist); /* ===== 新增:优先级屏蔽判断 ===== */ if (rd_BtnIsPriorityLocked(_pBtn)) continue; /* 被屏蔽的按键直接跳过,不更新状态 */ int level = _pBtn->m_pReadFunc(); switch (_pBtn->m_tState) { case STATE_NONE_PRESS: { if (level == _pBtn->m_iActiveLogic) { _pBtn->m_iTimeout = Rd_GetTime() + _pBtn->m_iEliminationTime; _pBtn->m_tState = STATE_CHECK_PRESS; } else { /* 间隔过大,清零 */ if (_pBtn->m_iRepeatCnt) { if ((Rd_GetTime() - _pBtn->m_iTimeout) > (UINT32_MAX / 2)) { _pBtn->m_iRepeatCnt = 0; } } } } break; case STATE_CHECK_PRESS: { if (level == _pBtn->m_iActiveLogic) { if ((Rd_GetTime() - _pBtn->m_iTimeout) < (UINT32_MAX / 2)) { _pBtn->m_tState = STATE_PRESS_DOWN; } } else { _pBtn->m_tState = STATE_NONE_PRESS; } } break; case STATE_PRESS_DOWN: { _pBtn->m_iHoldTime = 0; _pBtn->m_iPrevHoldTime = 0; _pBtn->m_iRepeatCnt++; _pBtn->m_tEvent = EVENT_PRESS_DOWN; RD_BUTTON_EVENT_CBK(_pBtn, _pBtn->m_tEvent); _pBtn->m_iTimeout = Rd_GetTime(); _pBtn->m_tState = STATE_PRESS_HOLD; /* ===== 新增:按下后更新优先级锁 ===== */ rd_BtnUpdatePriorityLock(); } break; case STATE_PRESS_HOLD: { if (level == _pBtn->m_iActiveLogic) { rd_BtnCalHoldTime(_pBtn); if (_pBtn->m_iHoldTime - _pBtn->m_iPrevHoldTime >= _pBtn->m_iHoldCycleTime) { _pBtn->m_tEvent = EVENT_HOLD; RD_BUTTON_EVENT_CBK(_pBtn, _pBtn->m_tEvent); _pBtn->m_iPrevHoldTime = _pBtn->m_iHoldTime; } } else { _pBtn->m_tState = STATE_PRESS_UP; } } break; case STATE_PRESS_UP: { _pBtn->m_tEvent = EVENT_PRESS_UP; RD_BUTTON_EVENT_CBK(_pBtn, _pBtn->m_tEvent); _pBtn->m_tEvent = EVENT_CLICK; RD_BUTTON_EVENT_CBK(_pBtn, _pBtn->m_tEvent); _pBtn->m_iTimeout = Rd_GetTime() + RD_BUTTON_TWO_INTERVAL_TIME_DEFAULT; _pBtn->m_tState = STATE_NONE_PRESS; /* ===== 新增:释放后更新优先级锁 ===== */ rd_BtnUpdatePriorityLock(); } break; default: break; } } Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL); }