freeRTOS操作系统机器人实现
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

290 lines
8.4 KiB

/******************************************************************************
版权所有 (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;
/*----------------------------------------------*
* 常量定义 *
*----------------------------------------------*/
/*----------------------------------------------*
* 宏定义 *
*----------------------------------------------*/
rd_btn_t *rd_BtnCreate(int _iActiveLogic)
{
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();
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_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)
{
goto END;
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;
END:
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)
{
goto END;
return RD_INVALUE;
}
rd_slist_remove(&g_sBtnListHead, &(_pBtn->m_tSlist));
_pBtn->m_tSlist.next = NULL;
_pBtn->m_iActive = 0;
END:
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;
}
static void rd_BtnCalHoldTime(rd_btn_t *_pBtn)
{
if(NULL == _pBtn)
{
return;
}
if (Rd_GetTime() < _pBtn->m_iTimeout)
{
_pBtn->m_iHoldTime = UINT32_MAX - _pBtn->m_iTimeout + Rd_GetTime();
}
else
{
_pBtn->m_iHoldTime = Rd_GetTime() - _pBtn->m_iTimeout;
}
}
void rd_BtnProcess(cbk_InPut _pFunc)
{
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);
switch (_pBtn->m_tState)
{
case STATE_NONE_PRESS:
{
if (_pFunc() == _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 (_pFunc() == _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;
} break;
case STATE_PRESS_HOLD:
{
if (_pFunc() == _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;
} break;
default:
break;
}
}
Rd_MutexUnlock(&g_fpBtnCtrl, __func__, NULL);
}