找回密码
 立即注册
楼主: Cryst***

按键扫描优化方法

[复制链接]
  • TA的每日心情
    奋斗
    6 小时前
  • 签到天数: 142 天

    [LV.7]常住居民III

    15

    主题

    537

    回帖

    1968

    积分

    金牌会员

    打工人

    积分
    1968
    发表于 2023-12-28 16:52:02 | 显示全部楼层
    社区闲人 发表于 2023-12-28 16:00
    【分享】新型的按键扫描程序 + 累计循环次数。不占用定时器
    https://www.stcaimcu.com/forum.php?mod=vie ...

    收到,感谢分享
    打工人
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    6 天前
  • 签到天数: 71 天

    [LV.6]常住居民II

    5

    主题

    71

    回帖

    248

    积分

    中级会员

    积分
    248
    发表于 2024-1-17 11:19:12 | 显示全部楼层
    用定时器来延时和用 软件延时  那个资源用的少些
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    无聊
    5 天前
  • 签到天数: 118 天

    [LV.6]常住居民II

    3

    主题

    204

    回帖

    562

    积分

    高级会员

    积分
    562
    发表于 2024-1-21 15:17:01 | 显示全部楼层
    不用定时器的话可以做成非阻塞形式的,在while(1)里面循环检测,比如加个状态机什么的。
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-4-23 08:28
  • 签到天数: 42 天

    [LV.5]常住居民I

    14

    主题

    54

    回帖

    390

    积分

    中级会员

    积分
    390
    发表于 2024-1-31 16:33:29 | 显示全部楼层
    鸿哥的帖子告诉我,放到定时器里面去,1ms中断一次,判断20次,消抖
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 08:35
  • 签到天数: 124 天

    [LV.7]常住居民III

    12

    主题

    315

    回帖

    882

    积分

    高级会员

    积分
    882
    发表于 2024-1-31 16:59:40 | 显示全部楼层
    QW123 发表于 2024-1-31 16:33
    鸿哥的帖子告诉我,放到定时器里面去,1ms中断一次,判断20次,消抖

    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 21:24
  • 签到天数: 98 天

    [LV.6]常住居民II

    9

    主题

    557

    回帖

    823

    积分

    高级会员

    积分
    823
    发表于 2024-1-31 19:53:32 | 显示全部楼层
    QW123 发表于 2024-1-31 16:33
    鸿哥的帖子告诉我,放到定时器里面去,1ms中断一次,判断20次,消抖

    有必要在1ms这么短的中断中判断按键码?会不会时间片太短了?我觉得10-20ms应该比较合理吧,纯技术探讨
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:54
  • 签到天数: 71 天

    [LV.6]常住居民II

    5

    主题

    39

    回帖

    482

    积分

    中级会员

    积分
    482
    发表于 2024-2-1 22:46:56 | 显示全部楼层
    按键扫描最好方式就是放在10ms计时器中断中,因为检测间隔大于按键抖动时间,不需要做消抖检测,而且这种方式不会和其他程序起冲突。其他放在主循环中执行的方式不靠谱,只要再加上其他程序按键扫描时间间隔就会受影响,难道单片机只检查按键别的什么都不做吗?用计时器中断保证了按键检测时间间隔恒定,学会使用定时器中断是复杂变成的基础。
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 10:35
  • 签到天数: 112 天

    [LV.6]常住居民II

    25

    主题

    304

    回帖

    1037

    积分

    荣誉版主

    Cyber Hamster

    积分
    1037
    发表于 2024-2-2 00:15:47 | 显示全部楼层
    本帖最后由 DebugLab 于 2024-2-2 00:26 编辑

    不使用中断!不使用定时器!不使用延时函数
    怎么消抖?用执行其他程序时间消抖!
    延时函数坚决不用!!!
    放到主循环里一直循环就行,注意一下主循环的频率10~1000Hz都行,中断函数进去必须马上出来,不能进去100ms以上或者死在里面,如果有以固定频率运行的定时器中断,放在里面也行,这个按键扫描程序几乎不耗时。
    基本结构:
    1. void Key_Scan(void)
    2. {
    3.         static bit Key_Flag;
    4.         if(KEY==0)
    5.         {
    6.                 if(Key_Flag==1)
    7.                 {
    8.                         Key_Flag=0;
    9.                         //在这里加按下要执行的
    10.                 }
    11.         }
    12.         else
    13.         {
    14.                 if(Key_Flag==0)
    15.                 {
    16.                         Key_Flag=1;
    17.                         //在这里加松开要执行的
    复制代码

    矩阵键盘因为要切换IO状态读取第二个坐标,需要延时函数消抖,单击双击长按才需要定时器。

    矩阵键盘扫描单击双击长按:

    1. #define Init_Up 25 //默认释放时间
    2. #define Init_Down 25 //默认按下时间
    3. #define Init_Long 100 //默认长按时间
    4. #define Init_Disable 1 //默认死区时间
    5. unsigned char Key_Decode(unsigned char temp)
    6. {
    7.         unsigned char key;
    8.         switch(temp)
    9.         {
    10.                 case 0x01:key=0;break;
    11.                 case 0x02:key=1;break;
    12.                 case 0x04:key=2;break;
    13.                 case 0x08:key=3;break;
    14.                 case 0x10:key=4;break;
    15.                 case 0x20:key=5;break;
    16.                 case 0x40:key=6;break;
    17.                 case 0x80:key=7;break;
    18.                 default:key=0xff;
    19.         }
    20.         return key;
    21. }
    22. void Key_Scan(void)
    23. {
    24.         unsigned char temp_x,temp_y;
    25.         X_BUS=0x00;
    26.         Y_BUS=0xff;
    27.         Delay_x10us(100);
    28.         temp_y=Y_BUS;
    29.         if(temp_y!=0xff)
    30.         {
    31.                 temp_y=Y_BUS;
    32.                 X_BUS=0xff;
    33.                 Y_BUS=temp_y;
    34.                 Delay_x10us(100);
    35.                 temp_x=X_BUS;
    36.                 temp_x=Key_Decode(~temp_x);
    37.                 temp_y=Key_Decode(~temp_y);
    38.                 if(temp_x<8&&temp_y<8)
    39.                 {
    40.                         Key=temp_x*8+temp_y;
    41.                         Key_Flag=1;
    42.                 }
    43.                 else
    44.                 {
    45.                         Key_Flag=0;
    46.                         Key=0xff;
    47.                 }
    48.         }
    49.         else
    50.         {
    51.                 Key_Flag=0;
    52.                 Key=0xff;
    53.         }
    54. }
    55. void Clear_Time(bit flag)
    56. {
    57.         TL1=0x00;
    58.         TH1=0x70;
    59.         TR1=flag;
    60. }
    61. void main(void)
    62. {
    63.         Init();        //初始化设置定时器1为不自动重载模式,以20ms为单位,定20ms
    64.                 Temp=IapReadByte(Sector0);
    65.         if(Temp>=5&&Temp<=50)
    66.                 Time_Up=Temp;
    67.         else
    68.         {
    69.                 IapEraseSector(Sector0);
    70.                 IapProgramByte(Sector0,Init_Up);
    71.                 Time_Up=Init_Up;
    72.         }
    73.         Temp=IapReadByte(Sector1);
    74.         if(Temp>=5&&Temp<=50)
    75.                 Time_Down=Temp;
    76.         else
    77.         {
    78.                 IapEraseSector(Sector1);
    79.                 IapProgramByte(Sector1,Init_Down);
    80.                 Time_Down=Init_Down;
    81.         }
    82.         Temp=IapReadByte(Sector2);
    83.         if(Temp>=50&&Temp<=250)
    84.                 Time_Long=Temp;
    85.         else
    86.         {
    87.                 IapEraseSector(Sector2);
    88.                 IapProgramByte(Sector2,Init_Long);
    89.                 Time_Long=Init_Long;
    90.         }
    91.         Temp=IapReadByte(Sector3);
    92.         if(Temp>=1&&Temp<=10)
    93.                 Time_Disable=Temp;
    94.         else
    95.         {
    96.                 IapEraseSector(Sector3);
    97.                 IapProgramByte(Sector3,Init_Disable);
    98.                 Time_Disable=Init_Disable;
    99.         }
    100.         Key_Temp=255;
    101.         while(1)
    102.         {
    103.                 Key_Scan();
    104.                 if(Key_State!=Key_Flag)        //按键状态改变
    105.                 {
    106.                         Key_State=Key_Flag;
    107.                         Clear_Time(1);
    108.                         if(Key_State)        //按下瞬间
    109.                         {
    110.                                 Count_Down=0;
    111.                                 Key_Single=1;
    112.                                 Key_Long=1;
    113.                                 if(Key_Temp==Key)
    114.                                         Key_Double=1;        //和上次一样
    115.                                 else        //和上次不一样
    116.                                 {
    117.                                         Key_Double=0;
    118.                                         Key_Temp=Key;
    119.                                 }
    120.                         }
    121.                         else        //松开瞬间
    122.                         {
    123.                                 Count_UP=0;
    124.                                 Key_Long=0;
    125.                                 if(Key_Single&&Count_Down>Time_Disable&&Count_Down<Time_Down);
    126.                                 else
    127.                                 {
    128.                                         Clear_Time(0);
    129.                                         Key_Single=0;
    130.                                         Key_Double=0;
    131.                                         Key_Long=0;
    132.                                         Key_Temp=0xff;
    133.                                 }
    134.                         }
    135.                 }
    136.                 if(Key_Flag)        //按下
    137.                 {
    138.                         if(Count_UP>=Time_Long&&Key_Long)        //长按
    139.                         {
    140.                                 Send_Key(Key_Temp+128);
    141.                                 Clear_Time(0);
    142.                                 Key_Single=0;
    143.                                 Key_Double=0;
    144.                                 Key_Long=0;
    145.                                 Key_Temp=0xff;
    146.                         }
    147.                 }
    148.                 else        //松开
    149.                 {
    150.                         if(Count_UP>=Time_Up&&Key_Single)        //单击
    151.                         {
    152.                                 Send_Key(Key_Temp);
    153.                                 Clear_Time(0);
    154.                                 Key_Single=0;
    155.                                 Key_Double=0;
    156.                                 Key_Long=0;
    157.                                 Key_Temp=0xff;
    158.                         }
    159.                         if(Count_UP>=Time_Disable&&Count_UP<=Time_Up&&Count_Down>=Time_Disable&&Count_Down<=Time_Down&&Key_Double&&Key_Single)        //双击
    160.                         {
    161.                                 Send_Key(Key_Temp+64);
    162.                                 Clear_Time(0);
    163.                                 Key_Single=0;
    164.                                 Key_Double=0;
    165.                                 Key_Long=0;
    166.                                 Key_Temp=0xff;
    167.                         }
    168.                 }
    169.         }
    170. }
    171. void Timer1_Isr(void) interrupt 3
    172. {
    173.         Count_UP++;
    174.         Count_Down++;
    175.         if(Count_UP>250||Count_Down>250)
    176.         {
    177.                 Count_UP=0;
    178.                 Count_Down=0;
    179.         }
    180. }
    复制代码

    (=・ω・=)
    回复 支持 1 反对 0 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-4-23 08:28
  • 签到天数: 42 天

    [LV.5]常住居民I

    14

    主题

    54

    回帖

    390

    积分

    中级会员

    积分
    390
    发表于 2024-2-21 16:44:43 | 显示全部楼层
    21cnsound 发表于 2024-1-31 19:53
    有必要在1ms这么短的中断中判断按键码?会不会时间片太短了?我觉得10-20ms应该比较合理吧,纯技术探讨 ...

    1ms 是基础值,意思就是: 定时器1ms 中断一次,然后根据每项任务的需求,累加中断次数,达到一个定时器中断,完成不同的任务要求。比方: 按键是累加10次判断是否按下, LED循环使用累加20次去翻转,移动之类的。  感觉这个用法在要求不高的条件下,还挺省定时器
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-6 08:10 , Processed in 0.067743 second(s), 58 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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