标题: 关于矩阵键盘代码优化问题 [打印本页]

作者: yuyash    时间: 2024-11-29 13:36
标题: 关于矩阵键盘代码优化问题
我是 51 单片机新手,在学习 [bilibili 51教程[6-1] 矩阵键盘] (https://www.bilibili.com/video/B ... eopod.episodes&p=15) 时发现这段代码有点冗余,可以优化一下吗?

原视频代码类似以下:

```c
# ifndef MATRIX_H
# define MATRIX_H

# include "8051.h"
# include "delay.h"

unsigned char matrix_keydown()
{
  /*
  unsigned char i;
  for (i = 3; i > 0; --i)
  {
    P1 = 0xff;
    // 我好烦啊,这个P1到底怎么回事
    P1 = P1 ^ (0x01 << i + 4);

    if (P1_7 == 0) {delay(3); while (P1_7 == 0); delay(3); return 1 + (3 - i);}
    if (P1_6 == 0) {delay(3); while (P1_6 == 0); delay(3); return 5 + (3 - i);}
    if (P1_5 == 0) {delay(3); while (P1_5 == 0); delay(3); return 9 + (3 - i);}
    if (P1_4 == 0) {delay(3); while (P1_4 == 0); delay(3); return 13 + (3 - i);}
  }
  */
  P1 = 0xff;
  P1_3 = 0;
  if (P1_7 == 0) {delay(3); while (P1_7 == 0); delay(3); return 1;}
  if (P1_6 == 0) {delay(3); while (P1_6 == 0); delay(3); return 5;}
  if (P1_5 == 0) {delay(3); while (P1_5 == 0); delay(3); return 9;}
  if (P1_4 == 0) {delay(3); while (P1_4 == 0); delay(3); return 13;}

  P1 = 0xff;
  P1_2 = 0;
  if (P1_7 == 0) {delay(3); while (P1_7 == 0); delay(3); return 2;}
  if (P1_6 == 0) {delay(3); while (P1_6 == 0); delay(3); return 6;}
  if (P1_5 == 0) {delay(3); while (P1_5 == 0); delay(3); return 10;}
  if (P1_4 == 0) {delay(3); while (P1_4 == 0); delay(3); return 14;}

  P1 = 0xff;
  P1_1 = 0;
  if (P1_7 == 0) {delay(3); while (P1_7 == 0); delay(3); return 3;}
  if (P1_6 == 0) {delay(3); while (P1_6 == 0); delay(3); return 7;}
  if (P1_5 == 0) {delay(3); while (P1_5 == 0); delay(3); return 11;}
  if (P1_4 == 0) {delay(3); while (P1_4 == 0); delay(3); return 15;}

  P1 = 0xff;
  P1_0 = 0;
  if (P1_7 == 0) {delay(3); while (P1_7 == 0); delay(3); return 4;}
  if (P1_6 == 0) {delay(3); while (P1_6 == 0); delay(3); return 8;}
  if (P1_5 == 0) {delay(3); while (P1_5 == 0); delay(3); return 12;}
  if (P1_4 == 0) {delay(3); while (P1_4 == 0); delay(3); return 16;}

  return 0;
}

# endif

```
可以看出代码量太长了。

我想进行优化类似以下:
```C
# ifndef MATRIX_H
# define MATRIX_H

# include "delay.h"

unsigned char math_key()
{
  // 简单的算法在哪里?
  // 不能将 P1 预设为 0x0f
  // 先暴力过了
  unsigned char S2, S1;
  S2 = P1 & 0x0f;
  S2 = P1 - 1 << 2 | 1;
  S1 = P1 & 0xf0 >> 4;
  return S2 + S1;
  // return ((P1 & 0x0f) - 1 << 2 | 1) + (P1 & 0xf0 >> 4);
}

unsigned char matrix_keydown()
{
  unsigned char key_number = 0;
  // 当 P1 被按下时用 math_key() 算出按键位置分别对应 1-16
  if (P1 != 0xff)
  {
    delay(3);
    key_number = math_key();
  }
  return key_number;
}

# endif
```
可惜失败了。。。
自己试错了许久,有点似懂非懂原因,觉得这个失败有点知识的缺陷,可以有版友帮助解答一下吗?
可以指点一下优化的方向吗?



作者: xiaobendan001    时间: 2024-11-29 16:14
不是有个反转法吗?
作者: lkc8210    时间: 2024-11-29 16:35
  1.                         switch(Keypad)
  2.                         {
  3.                                 case 0x0E:KeyVal=1;break;
  4.                                 case 0x0D:KeyVal=2;break;
  5.                                 case 0x0B:KeyVal=3;break;
  6.                                 case 0x07:KeyVal=4;break;
  7.                         }
  8.                         Keypad = 0xF0;
  9.                         _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
  10.                         switch(Keypad)
  11.                         {
  12.                                 case 0xE0:KeyVal+=0;break;
  13.                                 case 0xD0:KeyVal+=4;break;
  14.                                 case 0xB0:KeyVal+=8;break;
  15.                                 case 0x70:KeyVal+=12;break;
  16.                         }
复制代码

作者: WL0123    时间: 2024-11-29 21:41
给你一个简单的4*4矩阵按键示例参考


  1. #include <reg51.h>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. uchar  code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
  5. uchar KeyValue=0;//键值变量


  6. void delayms(uint k)
  7. {
  8.         uint i,j;
  9.         for(i=k;i>0;i--)
  10.                 for(j=115;j>0;j--);
  11. }

  12. void key_scan()                                        //按键扫描程序
  13. {
  14.         static bit sign=0;                        //位变量
  15.         static unsigned int count=0;//计数变量
  16.         P3=0xf0;                                        //赋值P3 1111 0000
  17.         if(P3!=0xf0)                                //检测有按键按下
  18.         {
  19.                 if(++count>=20 && sign==0)//计数消抖
  20.                 {                       
  21.                         sign=1;                        //按键自锁标志置1
  22.                         switch(P3)
  23.                         {
  24.                                 case(0Xe0):KeyValue = 1;break;
  25.                                 case(0Xd0):KeyValue = 2;break;
  26.                                 case(0Xb0):KeyValue = 3;break;
  27.                                 case(0X70):KeyValue = 4;break;
  28.                         }
  29.                         P3=0x0f;                        //赋值P3 0000 1111
  30.                         switch(P3)
  31.                         {
  32.                                 case(0X0e):KeyValue+= 0;break;
  33.                                 case(0X0d):KeyValue+= 4;break;
  34.                                 case(0X0b):KeyValue+= 8;break;
  35.                                 case(0X07):KeyValue+=12;break;
  36.                         }
  37.                 }
  38.         }
  39.         else                                                //键抬起
  40.         {
  41.                 sign=0;                                //按键自锁标志清0
  42.                 count=0;                                //消抖计数清0
  43.         }
  44. }

  45. void display()                                        //数码管显示程序
  46. {
  47.         static uchar i=0;
  48.         P0=0x00;
  49.         P2=~(0x01<<i);
  50.         if(i)P0=table[KeyValue%10];
  51.         else P0=table[KeyValue/10];
  52.         i=++i%2;
  53. }

  54. void main()                                                //主函数
  55. {
  56.         while(1)
  57.         {
  58.                 key_scan();                                //按键扫描程序
  59.                 display();                                //数码管显示键值1~16
  60.                 delayms(1);                                //延时控制主循环周期约1ms
  61.         }
  62. }
复制代码




作者: zpwgf    时间: 2024-12-2 09:15
#include <stdint.h>

// 假设你有一个适当的 delay 函数
void delay(uint16_t ms);

// 假设 P1 和 P1_x (x = 0, 1, 2, 3, 4, 5, 6, 7) 已经被定义并连接到相应的硬件
#define ROW_COUNT 4
#define COL_COUNT 4

// 矩阵键盘扫描函数
unsigned char matrix_keydown()
{
    uint8_t row, col;
    static const uint8_t rowPins[] = {P1_0, P1_1, P1_2, P1_3};
    static const uint8_t colPins[] = {P1_4, P1_5, P1_6, P1_7};
    static const uint8_t keyMap[ROW_COUNT][COL_COUNT] = {
        {1, 5, 9, 13},
        {2, 6, 10, 14},
        {3, 7, 11, 15},
        {4, 8, 12, 16}
    };

    for (row = 0; row < ROW_COUNT; ++row)
    {
        P1 = 0xFF; // 设置所有列为高电平
        rowPins[row] = 0; // 将当前行设为低电平

        for (col = 0; col < COL_COUNT; ++col)
        {
            if (colPins[col] == 0) // 检查是否有列被拉低
            {
                delay(3); // 消抖
                while (colPins[col] == 0); // 等待按键释放
                delay(3); // 消抖
                return keyMap[row][col]; // 返回按键值
            }
        }

        rowPins[row] = 1; // 恢复当前行为高电平,为下一行做准备
    }

    return 0; // 没有按键被按下
}
可以尝试一下这个方法,没验证过,
作者: qinlu123    时间: 2024-12-5 13:47
代码量长不是问题,问题是代码里while阻塞,这样你的单片机再跑其他任务就非常受影响
作者: zh080223    时间: 2024-12-5 18:30
#ifndef MATRIX_H
#define MATRIX_H

#include "8051.h"
#include "delay.h"

unsigned char matrix_keydown() {
    unsigned char row, col;
    unsigned char key_code = 0;

    for (row = 0; row < 4; ++row) {
        P1 = 0xff; // Set all rows high
        P1_3 = (row & 0x01) ? 1 : 0; // Select row
        P1_2 = (row & 0x02) ? 1 : 0;
        P1_1 = (row & 0x04) ? 1 : 0;
        P1_0 = (row & 0x08) ? 1 : 0;

        for (col = 0; col < 4; ++col) {
            if ((P1 >> (col + 4)) & 0x01) { // Check column
                delay(3); // Debounce
                if ((P1 >> (col + 4)) & 0x01) { // Double check
                    key_code = 1 + row * 4 + col; // Calculate key code
                    while ((P1 >> (col + 4)) & 0x01); // Wait for key release
                    delay(3); // Debounce
                    return key_code;
                }
            }
        }
    }

    return 0; // No key pressed
}

#endif
这样会好一点,你参考一下
作者: 空白名    时间: 2024-12-6 10:05
为什么不放在定时器里去做按键扫描,阻塞的程序浪费资源啊,既然是优化那么实时行也是程序要考虑的点啊,不太赞同阻塞的做法

作者: qinlu123    时间: 2024-12-7 09:44
空白名 发表于 2024-12-6 10:05
为什么不放在定时器里去做按键扫描,阻塞的程序浪费资源啊,既然是优化那么实时行也是程序要考虑的点啊,不 ...

小伙子我看好你




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1