本帖最后由 dffzh 于 2026-4-16 19:48 编辑
最近在做基于MCU+矩阵按键的USB键盘,程序上不知道用什么样的框架会比较稳妥,以及扩展性好;然后参考了AI代码,加上自己添加的,实现了下面这么一段矩阵按键扫描功能,当然支持多个按键的组合按键功能:
- uint8_t key_buff[KEY_BUFF_MAX]; // 1个shift键+1个ctrl键+1个alt键+普通按键7个
- uint8_t last_key_buff[KEY_BUFF_MAX];
- /*延时函数(消抖用)*/
- static void matrix_key_delay_ms(uint16_t ms)
- {
- // 根据你的单片机主频修改
- // HAL_Delay(ms); // STM32示例
- uint16_t i, j;
- for(i = 0; i < ms; i++)
- {
- for(j = 0; j < 120; j++);
- }
- }
- void matrix_key_init(void)
- {
- ROW_HIGH(ROW0_PIN);
- ROW_HIGH(ROW1_PIN);
- ROW_HIGH(ROW2_PIN);
- ROW_HIGH(ROW3_PIN);
- ROW_HIGH(ROW4_PIN);
- ROW_HIGH(ROW5_PIN);
- ROW_HIGH(ROW6_PIN);
- ROW_HIGH(ROW7_PIN);
- }
- /*读取9列状态*/
- static uint16_t Key_ReadCol(void)
- {
- uint16_t col = 0;
- if(COL_READ(COL0_PIN) == 0) col |= (1<<0);
- if(COL_READ(COL1_PIN) == 0) col |= (1<<1);
- if(COL_READ(COL2_PIN) == 0) col |= (1<<2);
- if(COL_READ(COL3_PIN) == 0) col |= (1<<3);
- if(COL_READ(COL4_PIN) == 0) col |= (1<<4);
- if(COL_READ(COL5_PIN) == 0) col |= (1<<5);
- if(COL_READ(COL6_PIN) == 0) col |= (1<<6);
- if(COL_READ(COL7_PIN) == 0) col |= (1<<7);
- if(COL_READ(COL8_PIN) == 0) col |= (1<<8);
- return col;
- }
- /*8×9矩阵按键扫描核心函数*/
- // 返回值:0xFF = 无按键
- // 0~71 = 对应按键编号(8行×9列)
- static uint16_t MatrixKey_Scan(void)
- {
- //uint16_t col_val;
- uint8_t row_index = 0;
- uint8_t col_index = 0;
- uint8_t key_val = 0xFF; // 默认无按键, 键值 = 行号 × 9 + 列号
- uint8_t current_key = 0;
- uint8_t tmp_key_buff[KEY_BUFF_MAX] = {0x00,};
- uint8_t key_num = 3; //front 3 is ModifierKey
- //第一步:所有行输出高电平
- ROW_HIGH(ROW0_PIN);
- ROW_HIGH(ROW1_PIN);
- ROW_HIGH(ROW2_PIN);
- ROW_HIGH(ROW3_PIN);
- ROW_HIGH(ROW4_PIN);
- ROW_HIGH(ROW5_PIN);
- ROW_HIGH(ROW6_PIN);
- ROW_HIGH(ROW7_PIN);
- //第二步逐行拉高扫描
- for(row_index = 0; row_index < MATRIX_KEY_ROW_NUM; row_index++)
- {
- // 所有行先拉高
- ROW_HIGH(ROW0_PIN);
- ROW_HIGH(ROW1_PIN);
- ROW_HIGH(ROW2_PIN);
- ROW_HIGH(ROW3_PIN);
- ROW_HIGH(ROW4_PIN);
- ROW_HIGH(ROW5_PIN);
- ROW_HIGH(ROW6_PIN);
- ROW_HIGH(ROW7_PIN);
- // 当前行拉低
- switch(row_index)
- {
- case 0: ROW_LOW(ROW0_PIN); break;
- case 1: ROW_LOW(ROW1_PIN); break;
- case 2: ROW_LOW(ROW2_PIN); break;
- case 3: ROW_LOW(ROW3_PIN); break;
- case 4: ROW_LOW(ROW4_PIN); break;
- case 5: ROW_LOW(ROW5_PIN); break;
- case 6: ROW_LOW(ROW6_PIN); break;
- case 7: ROW_LOW(ROW7_PIN); break;
- }
- matrix_key_delay_ms(10); // 消抖
- col_val[row_index] = Key_ReadCol(); // 读取9列
- if(col_val[row_index] != 0) // 有按键按下
- {
- // 判断是哪一列
- for(col_index = 0; col_index < MATRIX_KEY_COL_NUM; col_index++)
- {
- if((col_val[row_index] & (1 << col_index)))
- {
- key_val = row_index * 9 + col_index; // 计算键值 0~71
-
- current_key = matrix_key_map[row_index][col_index];
- switch(current_key)
- {
- case SW14_KEY_SHIFT_VALUE:
- tmp_key_buff[0] = current_key;
- break;
- case SW22_KEY_CTRL_VALUE:
- tmp_key_buff[1] = current_key;
- break;
- case SW30_KEY_ALT_VALUE:
- tmp_key_buff[2] = current_key;
- break;
- default: //else normal key
- tmp_key_buff[key_num++] = current_key;
- break;
- }
- }
- }
- }
- }
- //update current key value
- memcpy(key_buff, tmp_key_buff, KEY_BUFF_MAX);
- //update last key value when key state has changed
- if(memcmp(last_key_buff, key_buff, KEY_BUFF_MAX))
- {
- memcpy(last_key_buff, tmp_key_buff, KEY_BUFF_MAX);
- #ifdef PRINT_ENABLE
- printf("key buff: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\r\n", \
- tmp_key_buff[0], \
- tmp_key_buff[1], \
- tmp_key_buff[2], \
- tmp_key_buff[3], \
- tmp_key_buff[4], \
- tmp_key_buff[5], \
- tmp_key_buff[6], \
- tmp_key_buff[7]);
- #endif
- }
- return 0;
- }
主函数接口是MatrixKey_Scan,key_buff数组存储按键值,前面三个元素存储修饰按键值(Shift,Ctrl,Alt),后面几个元素存储普通按键值,支持多个组合按键。
二维数组matrix_key_map存储与硬件对应的按键码值,8行9列的按键矩阵。
当按键状态,也就是key_buff数组的值发生任何改变后,更新上一次值,并且通过串口打印出来。
做了简单测试,倒是能实现矩阵按键扫描功能,串口打印也比较正常:
但不确定是否存在某些特殊情况下的异常?没做过USB键盘,是否有做过的,欢迎提建议。
|