382 lines
9.1 KiB
C
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;
|
|
}
|
|
|
|
|