//================================================================== // // Filename: key.c // Description: key process. // //------------------------------------------------------------------ // // version: v2.0 // data: 10:08am, 07.Mar.2013, written by Sirius // Description: Change the way to process for CAN & line. // //------------------------------------------------------------------ //================================================================== /*------------------------------------------------------------------------------ * I N C L U D E *------------------------------------------------------------------------------*/ #include "stm32f0xx.h" #include "general.h" #include "main.h" #include "mapp_msg.h" #include "mapp_arm.h" #include "mapp_key.h" #include "mapp_gpio.h" #include "mapp_pwr.h" /*------------------------------------------------------------------------------ * D E F I N E *------------------------------------------------------------------------------*/ /*--- sampling couter ---*/ #define SCAN_ACK_COUNT (2) //2 #define KEY_COUNT (7) /*--- Key status timer ---*/ #define K_TIMER_LONG_PRESS (OS_TIMER_1_2S) /* Continious timer since key pressed */ #define K_TIMER_RPT_INTERVAL (OS_TIMER_200MS) /* Interval timer between twice long press */ /*------------------------------------------------------------------------------ * S T R U C T *------------------------------------------------------------------------------*/ /*---------------------- ** Key struct -----------------------*/ /*------------------------------------------------------------------------------ * S T A T I C - V A R I A B L E S *------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ * G L O B A L *------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ * P R O T O T Y P E *------------------------------------------------------------------------------*/ static void s_KeyDealwithTask(void); static VU16 s_keytime[KEY_COUNT] = {0}; /*---------------------------------------------------------------------- // Function name : ADC_Init // Input parameter : // Output parameter : // Use Function : // Reserve date : 10:25am, 07.Sep.2013, written by zwj ----------------------------------------------------------------------*/ void AdcCfgInit(void) { } /*---------------------------------------------------------------------- // Function name : KeyVarInit // Input parameter : // Output parameter : // Use Function : Init key module variables. // Reserve date : 11:37am, 07.Mar.2013, written by Sirius ----------------------------------------------------------------------*/ void KeyVarInit(void) { } unsigned char key2_5laycnt = 0; /** * @brief 按键扫描与处理任务函数 * * 该函数负责定期扫描所有按键状态,进行防抖处理,并在状态变化时 * 通过消息队列发送按键事件。同时维护gtArm.KeyState变量以记录所有按键的当前状态。 * 优化版:一次性读取所有GPIO状态,避免引脚读取之间的时间差异。 */ void KeyTask(void) { // 静态变量用于记录按键状态的历史信息 static U08 last_KeyVal[KEY_COUNT] = {0}; // 记录每个按键的上一个状态 static U08 trascnt1[KEY_COUNT] = {0}; // 按下状态计数器(用于防抖) static U08 trascnt2[KEY_COUNT] = {0}; // 释放状态计数器(用于防抖) U08 index = 0; // 循环索引 U08 u8KeyVal[KEY_COUNT] = {0}; // 当前按键采样值 // 一次性读取所有GPIO端口状态 uint16_t portA_status = GPIOA->IDR; // 读取GPIOA输入数据寄存器 uint16_t portB_status = GPIOB->IDR; // 读取GPIOB输入数据寄存器 // 从端口状态中提取各按键状态 - 使用位操作代替单独的GPIO_ReadInputDataBit调用 u8KeyVal[0] = !((portB_status & GPIO_Pin_5) != 0); // 呼叫按键 (PB5) u8KeyVal[1] = !gtArm.PA4_Value; // 手柄检测 (PA4) - 特殊处理 u8KeyVal[2] = ((portA_status & GPIO_Pin_7) != 0); // 紧急按钮 (PA7) u8KeyVal[3] = !((portA_status & GPIO_Pin_15) != 0); // 增援按键 (PA15) u8KeyVal[4] = !((portB_status & GPIO_Pin_3) != 0); // 护理按键 (PB3) u8KeyVal[5] = !((portA_status & GPIO_Pin_5) != 0); // 换药按键 (PA5) u8KeyVal[6] = !((portB_status & GPIO_Pin_4) != 0); // 取消按键 (PB4) // 拔针功能特殊处理(手柄和换药按键同时按下) if ((u8KeyVal[1] == 1) && (u8KeyVal[5] == 1)) { // 长按拔针,延时退出 key2_5laycnt = 50; // 设置延时计数 } else { if (key2_5laycnt == 50) { // 拔针按键刚释放 // 发送拔针释放消息 OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(0x0f, KEY_RELEASED)); } if (key2_5laycnt) { key2_5laycnt--; // 递减延时计数 u8KeyVal[1] = 0; // 强制清除手柄按键状态 u8KeyVal[5] = 0; // 强制清除换药按键状态 last_KeyVal[1] = 0; // 更新历史状态 last_KeyVal[5] = 0; // 更新历史状态 return; // 在延时期间跳过正常按键处理 } } // 增加互斥逻辑,防止PB5和PB4同时触发 // 如果两个按键同时被检测为按下,优先处理PB5(呼叫键) if (u8KeyVal[0] == 1 && u8KeyVal[6] == 1) { u8KeyVal[6] = 0; // 忽略PB4按键 } // 遍历所有按键进行状态检测和处理 for (index = 0; index < KEY_COUNT; index++) { if (u8KeyVal[index] == 0) { // 按键未按下 gtArm.KeyState &= ~(1 << index); // 清除对应按键状态位 trascnt1[index] = 0; // 重置按下计数器 trascnt2[index]++; // 增加释放计数器 s_keytime[index] = 0; // 重置长按计时 // 按键释放防抖处理 if (trascnt2[index] > SCAN_ACK_COUNT) { // 防抖时间 trascnt2[index] = 0; // 只有状态确实发生变化时才处理 if (last_KeyVal[index] != u8KeyVal[index]) { // 区分普通释放和长按后释放 if (last_KeyVal[index] == KEY_CONTINUE) { // 长按后释放消息 OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(index+5, KEY_CONTINUE)); } else { // 普通释放消息 OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(index+5, KEY_RELEASED)); } // 更新按键历史状态 last_KeyVal[index] = u8KeyVal[index]; } } } else { // 按键按下 gtArm.KeyState |= (1 << index); // 设置对应按键状态位 trascnt1[index]++; // 增加按下计数器 trascnt2[index] = 0; // 重置释放计数器 s_keytime[index]++; // 增加长按计时 // 按键按下防抖处理 if (trascnt1[index] > SCAN_ACK_COUNT) { // 防抖 trascnt1[index] = 0; // 长按检测(超过1.5秒) if (s_keytime[index] > OS_TIMER_1S5) { // 首次达到长按时间时触发长按 if (last_KeyVal[index] != KEY_CONTINUE) { last_KeyVal[index] = KEY_CONTINUE; // 这里原本有长按消息发送代码(已注释) } } else if (last_KeyVal[index] != u8KeyVal[index]) { // 普通按下消息(状态变化) OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(index+5, KEY_PRESSED)); // 更新按键历史状态 last_KeyVal[index] = u8KeyVal[index]; } } } } } /*=============================== END OF FILE ===============================*/