找回密码
 立即注册
查看: 140|回复: 7

行列矩阵扫描多按键识别问题

[复制链接]
  • 打卡等级:常住居民II
  • 打卡总天数:88
  • 最近打卡:2025-05-14 10:37:39

12

主题

55

回帖

627

积分

高级会员

积分
627
发表于 2025-4-27 06:53:22 | 显示全部楼层 |阅读模式
最近做的PC键盘,需要处理多按键识别问题,键盘口使用8x11矩阵方式。

目前的情况是,在同一行上的键,多键按下能识别,不同行上的键多键被按下会出现误判情况。
尝试过扫描本行时,把其它行端口设为高阻输入无上拉模式,也会出现误判情况,俗称的“鬼影”
论坛里有人做过相关的经验可以分享交流下吗?
我的多键识别代码如下:


void         MainKeyPressScan(void)
{
        u32 KeyData;
       
        if( MainKeyPressStructure.KeyScanEnable == DISABLE )
                return;
               
        MainKeyPressStructure.KeyScanEnable  = DISABLE;
        MainKeyPressStructure.KeyScanTime1ms = 0;       
       
        KeyData = GetMainKeyPort();

        if( KeyData != MainKeyPressStructure.KeyPressCode )                                                //按键有变化
                {
                        MainKeyPressStructure.KeyPressCode = KeyData;                                        //取数据
                        MainKeyPressStructure.KeyDebounce = KEY_DEBOUNCE_TIME;                        //开始抖动
                }
        else
                {
                        if( MainKeyPressStructure.KeyDebounce )
                                {
                                        MainKeyPressStructure.KeyDebounce--;
                                        if( MainKeyPressStructure.KeyDebounce == 0)
                                                {
                                                        MainKeyPressStructure.KeyPressCode = KeyData;
                                                        MainKeyPressStructure.KeyPressSuccess  = SUCCESS;
                                                }
                                }
                }

}


//矩阵扫描部分代码,P0口做扫描数据口,P2口和P7.5-7做按键返回数据口。

#define                KEY_SCAN_LINE1_DATA                                ~0x01                        //第1行扫描数据       

#define                KEY_SCAN_LINE2_DATA                                ~0x02                        //第2行扫描数据       



u32         GetMainKeyPort(void)
{
        u8        KeyTempPort2,KeyTempPort7;
        u16 KeyReturnData;
        u32        KeyResult,KeyPressData;

        KeyResult = 0;

        SetPort0Mode(KEY_SCAN_LINE1_DATA, 0, ~KEY_SCAN_LINE1_DATA);                //P00设为准双向口+上拉电阻,其它的设为高祖输入+无上拉电阻
        IO_KeyDelay(IO_KEY_DELAY_TIME);
       
        KeyPressData = MAIN_KEY_WAS_NOT_PRESSED;       
        KEY_IO_SCAN_PORT0 = KEY_SCAN_LINE1_DATA;                                                                //扫描第1行按键
        IO_KeyDelay(IO_KEY_DELAY_TIME);       
        KeyTempPort2 = KEY_IO_RETURN_PORT2;                                                                                //读取按键返回值       
        KeyTempPort7 = KEY_IO_RETURN_PORT7;                                                                                //读取按键返回值
        KeyTempPort7 = ( KeyTempPort7 & KEY_RETURN_PORT7_MARSK ) >> 5;
        KeyTempPort7 |= 0xF8;       
        KeyReturnData = ~((((u16)KeyTempPort7) << 8) | (u16)KeyTempPort2);        
        if( KeyReturnData != MAIN_KEY_WAS_NOT_PRESSED )
                {
                        KeyPressData = ~KEY_SCAN_LINE1_DATA;                                                        //处理第1行按键数据
                        KeyPressData = ( KeyPressData << 16 ) | (u32)KeyReturnData;       
                        KeyResult |= KeyPressData;
                       
                }



        SetPort0Mode(KEY_SCAN_LINE2_DATA, 0, ~KEY_SCAN_LINE2_DATA);
        IO_KeyDelay(IO_KEY_DELAY_TIME);
       
        KeyPressData = MAIN_KEY_WAS_NOT_PRESSED;       
        KEY_IO_SCAN_PORT0 = KEY_SCAN_LINE2_DATA;                                                                //扫描第2行按键
        IO_KeyDelay(IO_KEY_DELAY_TIME);       
        KeyTempPort2 = KEY_IO_RETURN_PORT2;                                                                                //读取按键返回值       
        KeyTempPort7 = KEY_IO_RETURN_PORT7;                                                                                //读取按键返回值
        KeyTempPort7 = ( KeyTempPort7 & KEY_RETURN_PORT7_MARSK ) >> 5;
        KeyTempPort7 |= 0xF8;       
        KeyReturnData = ~((((u16)KeyTempPort7) << 8) | (u16)KeyTempPort2);        
        if( KeyReturnData != MAIN_KEY_WAS_NOT_PRESSED )
                {
                        KeyPressData = ~KEY_SCAN_LINE2_DATA;                                                        //处理第2行按键数据
                        KeyPressData = ( KeyPressData << 16 ) | (u32)KeyReturnData;       
                        KeyResult |= KeyPressData;                       
                }

}

回复

使用道具 举报 送花

3

主题

725

回帖

161

积分

等待验证会员

积分
161
发表于 2025-4-27 06:58:00 | 显示全部楼层
在处理8x11矩阵键盘的多按键识别问题时,您遇到的“鬼影”现象(即不同行上的多键按下时出现误判)是一个常见的技术挑战。这种现象通常是由于矩阵扫描时,电流通过未被激活的行或列,导致误触发。以下是一些可能的解决方案和优化建议:

1. 二极管隔离
在键盘矩阵的每个按键上添加二极管,可以有效地防止电流反向流动,从而避免“鬼影”现象。二极管的方向应确保电流只能从行流向列,或从列流向行,具体取决于您的扫描方式。

2. 改进扫描算法
您的扫描代码可以进一步优化,以确保在扫描某一行时,其他行处于高阻状态,并且没有上拉电阻。以下是一个改进的扫描算法示例:
  1. c
  2. void MainKeyPressScan(void) {
  3.     u32 KeyData;
  4.    
  5.     if (MainKeyPressStructureKeyScanEnable == DISABLE)
  6.         return;
  7.         
  8.     MainKeyPressStructureKeyScanEnable = DISABLE;
  9.     MainKeyPressStructureKeyScanTime1ms = 0;   
  10.    
  11.     for (int row = 0; row < 8; row++) {
  12.         // 激活当前行
  13.         SetRowActive(row);
  14.         
  15.         // 读取列数据
  16.         KeyData = GetColumnData();
  17.         
  18.         // 处理按键数据
  19.         if (KeyData != MainKeyPressStructureKeyPressCode) {
  20.             MainKeyPressStructureKeyPressCode = KeyData;
  21.             MainKeyPressStructureKeyDebounce = KEYDEBOUNCETIME;
  22.         } else {
  23.             if (MainKeyPressStructureKeyDebounce) {
  24.                 MainKeyPressStructureKeyDebounce--;
  25.                 if (MainKeyPressStructureKeyDebounce == 0) {
  26.                     // 处理按键事件
  27.                     ProcessKeyPress(MainKeyPressStructureKeyPressCode);
  28.                 }
  29.             }
  30.         }
  31.         
  32.         // 关闭当前行
  33.         SetRowInactive(row);
  34.     }
  35. }
复制代码

3. 去抖动处理
按键抖动是另一个常见问题,可能导致误判。您可以在硬件或软件层面进行去抖动处理。软件去抖动通常通过延时和多次采样来实现。以下是一个简单的去抖动处理示例:
  1. c
  2. define DEBOUNCETIME 20 // 去抖动时间,单位为毫秒
  3. void DebounceKeyPress(u32 KeyData) {
  4.     static u32 LastKeyData = 0;
  5.     static u32 DebounceCounter = 0;
  6.    
  7.     if (KeyData != LastKeyData) {
  8.         DebounceCounter = DEBOUNCETIME;
  9.         LastKeyData = KeyData;
  10.     } else {
  11.         if (DebounceCounter > 0) {
  12.             DebounceCounter--;
  13.             if (DebounceCounter == 0) {
  14.                 // 处理按键事件
  15.                 ProcessKeyPress(KeyData);
  16.             }
  17.         }
  18.     }
  19. }
复制代码

4. 硬件设计优化
在硬件设计上,确保矩阵的行和列之间有足够的隔离,避免信号串扰。使用高质量的PCB材料和合理的布线设计,可以减少信号干扰和误触发。

5. 使用专用芯片
如果上述方法仍无法解决问题,可以考虑使用专用的键盘扫描芯片。这些芯片通常内置了多按键识别和去抖动功能,可以大大简化软件设计和提高系统可靠性。

6. 调试与测试
在实际应用中,调试和测试是确保系统稳定性的关键。使用逻辑分析仪或示波器,可以实时监控矩阵扫描过程中的信号变化,帮助定位和解决问题。

总结
通过上述方法,您可以有效地解决8x11矩阵键盘的多按键识别问题,避免“鬼影”现象。具体实施方案需要根据您的硬件设计和应用需求进行调整。希望这些建议对您有所帮助,祝您的项目顺利成功!

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

3

主题

725

回帖

161

积分

等待验证会员

积分
161
发表于 2025-4-27 06:58:00 | 显示全部楼层
在处理PC键盘的多按键识别问题时,尤其是采用8x11矩阵扫描的方式,确实会遇到“鬼影”(Ghosting)问题。这是由于矩阵扫描的物理特性导致的,特别是在不同行上的按键同时按下时,可能会出现误判。以下是一些专业的建议和解决方案,帮助你优化代码并解决这一问题。

1. 理解“鬼影”问题的根源
“鬼影”问题通常是由于矩阵扫描中的电气特性导致的。当多个按键按下时,电流可能会通过未预期的路径流动,导致误判。具体来说,当不同行和列上的按键同时按下时,可能会形成一个“虚拟”的按键,从而产生误判。

2. 优化扫描算法
为了避免“鬼影”问题,可以采取以下优化措施:

a. 逐行扫描
在扫描某一行时,将该行的输出设置为低电平,同时将所有其他行的输出设置为高阻态或高电平。这样可以确保只有当前行的按键状态被读取,避免其他行的干扰。

b. 使用二极管隔离
在矩阵的每个按键上添加一个二极管,可以防止电流反向流动,从而避免“鬼影”问题。这种方法虽然增加了硬件成本,但能有效解决多按键识别问题。

c. 软件去抖
在读取按键状态后,加入去抖处理,可以有效避免由于按键抖动导致的误判。你已经在代码中实现了去抖处理,这是正确的做法。

3. 代码优化建议
基于上述分析,以下是代码的优化建议:
  1. c
  2. void MainKeyPressScan(void)
  3. {
  4.     u32 KeyData;
  5.    
  6.     if (MainKeyPressStructureKeyScanEnable == DISABLE)
  7.         return;
  8.         
  9.     MainKeyPressStructureKeyScanEnable = DISABLE;
  10.     MainKeyPressStructureKeyScanTime1ms = 0;   
  11.    
  12.     // 逐行扫描
  13.     for (int row = 0; row < 8; row++) {
  14.         // 设置当前行为低电平
  15.         SetRowLow(row);
  16.         
  17.         // 读取列数据
  18.         KeyData = GetMainKeyPort();
  19.         
  20.         // 处理按键状态
  21.         if (KeyData != MainKeyPressStructureKeyPressCode) {
  22.             MainKeyPressStructureKeyPressCode = KeyData;
  23.             MainKeyPressStructureKeyDebounce = KEYDEBOUNCETIME;
  24.         } else {
  25.             if (MainKeyPressStructureKeyDebounce) {
  26.                 MainKeyPressStructureKeyDebounce--;
  27.                 if (MainKeyPressStructureKeyDebounce == 0) {
  28.                     // 处理稳定的按键状态
  29.                     ProcessKeyPress(MainKeyPressStructureKeyPressCode);
  30.                 }
  31.             }
  32.         }
  33.         
  34.         // 恢复当前行为高阻态或高电平
  35.         SetRowHigh(row);
  36.     }
  37.    
  38.     MainKeyPressStructureKeyScanEnable = ENABLE;
  39. }
  40. void SetRowLow(int row) {
  41.     // 设置指定行为低电平,其他行为高阻态或高电平
  42.     // 具体实现取决于硬件设计
  43. }
  44. void SetRowHigh(int row) {
  45.     // 恢复指定行为高阻态或高电平
  46.     // 具体实现取决于硬件设计
  47. }
  48. void ProcessKeyPress(u32 keyCode) {
  49.     // 处理稳定的按键状态
  50.     // 具体实现取决于应用需求
  51. }
复制代码

4. 硬件设计建议
除了软件优化,硬件设计也是解决“鬼影”问题的关键。以下是一些硬件设计建议:

a. 使用二极管隔离
如前所述,在矩阵的每个按键上添加二极管,可以有效防止电流反向流动,避免“鬼影”问题。

b. 增加上拉电阻
在列线上增加上拉电阻,可以确保在未按下按键时,列线处于高电平状态,从而避免误判。

c. 优化PCB布局
合理的PCB布局可以减少电气干扰,降低“鬼影”问题的发生概率。确保行线和列线之间的间距足够大,避免交叉干扰。

5. 测试与验证
在优化代码和硬件设计后,建议进行充分的测试,确保多按键识别功能正常工作。测试时,可以模拟各种按键组合,特别是不同行上的按键同时按下的情况,验证是否会出现“鬼影”问题。

总结
通过逐行扫描、使用二极管隔离、软件去抖以及优化硬件设计,可以有效解决8x11矩阵键盘的多按键识别问题,避免“鬼影”现象。希望以上建议能帮助你优化键盘设计,提升用户体验。如有进一步问题,欢迎继续交流。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:208
  • 最近打卡:2025-06-16 08:41:37
已绑定手机

67

主题

1912

回帖

4295

积分

荣誉版主

无情的代码机器

积分
4295
发表于 2025-4-27 09:21:09 | 显示全部楼层
原理图建议也上传下,有没有楼上说的二极管
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:88
  • 最近打卡:2025-05-14 10:37:39

12

主题

55

回帖

627

积分

高级会员

积分
627
发表于 2025-4-27 09:32:57 | 显示全部楼层
没有二极管隔离,最初设计时没考虑要多个按键情况。
矩阵8x11,8各行扫描使用P0口,11个列扫描使用P2口和P7口的4、5、6位,没有二极管隔离。
单个键没问题。同一个行扫描信号所在的键也可以识别多个按键,不同行扫描信号所在的键识别有误。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:88
  • 最近打卡:2025-05-14 10:37:39

12

主题

55

回帖

627

积分

高级会员

积分
627
发表于 2025-4-27 09:35:49 | 显示全部楼层
改硬件的话,在每行扫描信号加入MOS管(总共8个),扫描该行时,MOS管打开,其它的行MOS管关闭,这个应该可以解决“鬼影”问题。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:468
  • 最近打卡:2025-06-16 07:06:57
已绑定手机

79

主题

5131

回帖

9138

积分

超级版主

DebugLab

积分
9138
发表于 2025-4-27 10:54:18 | 显示全部楼层
没有二极管,如矩阵中某个矩形三个顶点同时导通,就无法判断矩形中第四个顶点的状态
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:389
  • 最近打卡:2025-06-16 06:53:55

6

主题

10

回帖

172

积分

注册会员

积分
172
发表于 2025-4-30 07:44:08 | 显示全部楼层
学习了。
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-16 12:03 , Processed in 0.182718 second(s), 88 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表