optical/NxBase/buttons.c
2025-09-04 09:45:08 +08:00

382 lines
9.1 KiB
C

#define __IN_BUTTONS_C
#include "buttons.h"
#include "trigger.h"
//----------------------------------------------------------------------------------------------------------------
#define KEY_SCAN_NUM 2 // 软件去抖, 认为是稳定电平(100ms)
#define KEY_LONG_DOWN_NUM 50 // 连续500ms秒钟按下, 认为是长时间按下
#define KEY_TASK_DISABLE 50 // 500ms内没有响应按键, 那么认为按键无效
//--------------------------------------------------------
//--------------------------------------------------------
#ifndef MAX_BUTTONS_NUM
#define MAX_BUTTONS_NUM 10 // 最大支持按钮个数
#endif
typedef struct
{
ScanFunc scanfunc; // 检测函数
u8 checkState; // 检查状态
TaskFunc ldtaskFunc; // 长按下任务
TaskFunc dtaskFunc; // 按下任务
TaskFunc ctaskFunc; // 点击任务
TaskFunc dQuktaskFunc; // 按下立即响应任务
}ButtonScan;
typedef struct
{
ButtonScan buttonsList[MAX_BUTTONS_NUM];
int buttonsNumber; // 注册的按钮个数
int buttonTask; // 按钮响应程序 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
int scanIndex; // 当前正在扫描/等待执行的按钮
u16 buttonCount; // 按钮扫描计数器
u16 taskCount; // 按钮响应计数器
u8 shakeSta[KEY_SCAN_NUM]; // 软件去抖寄存器
u8 shakeIdx; // 软件去抖寄存器指针
DelayRun delay;
int execing; // 正在执行任务中标志
}ButtonCtrl;
ButtonCtrl g_buttonCtrl;
//----------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------
void InitButtonCtrl(void)
{
int i;
g_buttonCtrl.buttonsNumber = 0; // 注册的按钮个数
g_buttonCtrl.buttonTask = 0; // 按钮响应程序
g_buttonCtrl.scanIndex = -1; // 没有正在扫描的按钮
memset(g_buttonCtrl.buttonsList, 0, sizeof(ButtonScan)*MAX_BUTTONS_NUM);
for (i = 0; i < MAX_BUTTONS_NUM; i++)
{
g_buttonCtrl.buttonsList[i].scanfunc = NULL;
}
g_buttonCtrl.delay = NULL;
AddTriggerToList(10, ScanButtons, NULL); // 10ms
}
//--------------------------------------------------------
// 添加Botton到扫描列表
int AddButtonToList(ScanFunc fp, u8 sta, TaskFunc ldtsk, TaskFunc ctsk, TaskFunc dtsk, TaskFunc dqtsk)
{
if ((fp != NULL) &&
((ldtsk != NULL) || (ctsk != NULL) || (dtsk != NULL) || (dqtsk != NULL)) &&
(g_buttonCtrl.buttonsNumber < MAX_BUTTONS_NUM) &&
1 )
{
memset(&(g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber]), 0, sizeof(ButtonScan));
g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].scanfunc = fp;
g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].checkState = sta;
g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].ldtaskFunc = ldtsk;
g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].ctaskFunc = ctsk;
g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].dtaskFunc = dtsk;
g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].dQuktaskFunc = dqtsk;
g_buttonCtrl.buttonsNumber++;
// printf("add a new button to %d\r\n", g_buttonCtrl.buttonsNumber);
return g_buttonCtrl.buttonsNumber;
}
else
{
printf("add button more than enable\r\n");
return -1;
}
}
//--------------------------------------------------------
// 每10ms扫描一次
void ScanButtons(void)
{
u8 sta,staOk;
int i;
ButtonScan * pScan;
if (g_buttonCtrl.scanIndex == -1)
{// 没有确定目标按钮
for (i = 0; i < g_buttonCtrl.buttonsNumber; i++)
{
pScan = (&(g_buttonCtrl.buttonsList[i]));
if (pScan->scanfunc == NULL)
{
continue;
}
sta = pScan->scanfunc();
if (sta == pScan->checkState) // 有按键处于按下状态
{
g_buttonCtrl.scanIndex = i; // 当前正在扫描/等待执行的按钮
g_buttonCtrl.shakeIdx = 0; // 软件去抖寄存器指针
g_buttonCtrl.taskCount = 0; // 按钮响应计数器
g_buttonCtrl.buttonCount = 0; // 按钮扫描计数器
memset(g_buttonCtrl.shakeSta, (~pScan->checkState), KEY_SCAN_NUM); // 去抖寄存器数组
break;
}
}
}
else if (g_buttonCtrl.scanIndex < g_buttonCtrl.buttonsNumber)
{// 判断按钮状态
pScan = (&(g_buttonCtrl.buttonsList[g_buttonCtrl.scanIndex]));
if (pScan->scanfunc != NULL)
{
sta = pScan->scanfunc(); // 最新值
staOk = 1; // 滤波数组內数据相同时为1,否则为0
// 软件去抖
if (KEY_SCAN_NUM > 1)
{
g_buttonCtrl.shakeSta[g_buttonCtrl.shakeIdx++] = sta;
g_buttonCtrl.shakeIdx %= KEY_SCAN_NUM;
for (i = 0; i < KEY_SCAN_NUM-1; i++)
{
if (g_buttonCtrl.shakeSta[i] != g_buttonCtrl.shakeSta[i+1])
{
staOk = 0;
break;
}
}
}
// 按钮任务生效判断
if (g_buttonCtrl.buttonCount == 0)
{// 初次生效
if ((sta == pScan->checkState) && (staOk == 1))
{// 按下任务生效
g_buttonCtrl.buttonCount = 1;
if (pScan->dQuktaskFunc != NULL)
{// 按下立即响应任务
pScan->dQuktaskFunc();
}
if (pScan->dtaskFunc != NULL)
{// 按下任务
g_buttonCtrl.buttonTask = 1; // 创建按钮任务 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
g_buttonCtrl.taskCount = KEY_TASK_DISABLE; // 按钮响应计数器
}
}
}
else if (g_buttonCtrl.buttonTask != 3)
{// 长按和单击事件检测,单击事件有效后不继续检测
if (sta == pScan->checkState)
{// 按钮按住
if (g_buttonCtrl.buttonCount < KEY_LONG_DOWN_NUM)
{
g_buttonCtrl.buttonCount++;
}
else if (g_buttonCtrl.buttonCount == KEY_LONG_DOWN_NUM)
{// 长按任务
if (pScan->ldtaskFunc != NULL)
{
g_buttonCtrl.taskCount = KEY_TASK_DISABLE; // 按钮响应计数器
g_buttonCtrl.buttonTask = 2; // 创建按钮任务 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
}
g_buttonCtrl.buttonCount++;
}
}
else
{// 按钮抬起
if (staOk == 1) // 按钮抬起滤波
{// 单击任务
if (pScan->ctaskFunc != NULL)
{
g_buttonCtrl.taskCount = KEY_TASK_DISABLE; // 按钮响应计数器
g_buttonCtrl.buttonTask = 3; // 创建按钮任务 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
}
else
{
if (((pScan->dtaskFunc == NULL) && (pScan->ldtaskFunc == NULL) && (pScan->ctaskFunc == NULL)) || // 只注册了快速响应函数
(g_buttonCtrl.buttonTask == -1) || // 按下或长按任务已响应
0 )
{
g_buttonCtrl.buttonTask = 0;
g_buttonCtrl.scanIndex = -1; // 无按钮任务
return;
}
}
}
}
}
// 按钮任务无响应判断
if ((g_buttonCtrl.buttonTask > 0) && // 有任务需要执行
(g_buttonCtrl.taskCount != 0) && // 未超时
1 )
{
if (--g_buttonCtrl.taskCount == 0)
{
if (g_buttonCtrl.buttonTask == 3)
{
g_buttonCtrl.scanIndex = -1; // 无按钮任务
}
g_buttonCtrl.buttonTask = -1;
}
}
}
}
}
//--------------------------------------------------------
int WaitAllButtonUp(void)
{
int i, j;
int rslt;
u32 startTime,loopTime; //运行时间 单位:s
ButtonScan * pScan;
rslt = 0;
startTime = GetMsSoftTimer();
do
{
j = 0;
for (i = 0; i < g_buttonCtrl.buttonsNumber; i++)
{
pScan = (&(g_buttonCtrl.buttonsList[i]));
if (pScan->scanfunc == NULL)
{
continue;
}
if (pScan->scanfunc() != pScan->checkState)
{
j++;
}
}
if (g_buttonCtrl.buttonsNumber == j)
{
break;
}
ScanButtons(); // 扫描按键 // 有按钮未抬起,执行按钮任务
if (g_buttonCtrl.delay != NULL)
{
g_buttonCtrl.delay(1);
}
loopTime = GetMsSoftTimer();
if ((loopTime - startTime) > 5000) // 最多只等待5s时长
{
rslt = -1;
break;
}
}while(1);
g_buttonCtrl.buttonTask = 0;
g_buttonCtrl.scanIndex = -1; // 当前正在扫描/等待执行的按钮
return rslt;
}
void RegDelayFun(DelayRun delay)
{
g_buttonCtrl.delay = delay;
}
void CleanButtonTask(void)
{
g_buttonCtrl.buttonTask = 0; // 按钮响应程序 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
g_buttonCtrl.scanIndex = -1; // 当前正在扫描/等待执行的按钮
}
void ButtonsTask()
{
int i, rslt;
u8 sta;
ButtonScan * pScan;
if (g_buttonCtrl.execing != 0) // 只允许执行一次按键任务, 不能嵌套调用
{
return;
}
g_buttonCtrl.execing++;
if ((g_buttonCtrl.buttonTask > 0) &&
(g_buttonCtrl.scanIndex >= 0) &&
1 )
{
rslt = 0;
for (i = 0; i < g_buttonCtrl.buttonsNumber; i++)
{// 当有两个以上按钮按下时,不响应当前程序
pScan = (&(g_buttonCtrl.buttonsList[i]));
if (pScan->scanfunc == NULL)
{
continue;
}
sta = pScan->scanfunc();
if (sta == pScan->checkState)
{
if (i == g_buttonCtrl.scanIndex)
{// 指定按钮
rslt++;
}
else
{// 异常按钮
rslt--;
printf("button%d state error\r\n", g_buttonCtrl.scanIndex);
}
}
}
if (((g_buttonCtrl.buttonTask != 3) && (rslt == 1)) ||
((g_buttonCtrl.buttonTask == 3) && (rslt == 0)) ||
0 )
{// 只有一个制定按钮按下时,执行事件任务
pScan = (&(g_buttonCtrl.buttonsList[g_buttonCtrl.scanIndex]));
if (pScan != NULL)
{
if (g_buttonCtrl.buttonTask == 1)
{// 1:按下任务
if (pScan->dtaskFunc != NULL)
{
rslt = pScan->dtaskFunc();
}
}
else if (g_buttonCtrl.buttonTask == 2)
{// 2:长按任务
if (pScan->ldtaskFunc != NULL)
{
rslt = pScan->ldtaskFunc();
}
}
else if (g_buttonCtrl.buttonTask == 3)
{// 3:单击任务
if (pScan->ctaskFunc != NULL)
{
rslt = pScan->ctaskFunc();
CleanButtonTask(); // 清除按钮任务
}
}
}
}
g_buttonCtrl.buttonTask = -1; // 执行完成
}
g_buttonCtrl.execing = 0;
}