#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; }