三行按键扫描详细解析

该文介绍了三行按键扫描的基础算法,利用定时器每10ms执行一次扫描,通过读取端口数据、异或和与运算判断按键状态。同时,文中还讨论了如何通过增加额外的变量和条件判断来处理按键抖动问题,以及如何区分单次触发和长按事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三行按键扫描基础

核心算法:

unsigned char trg;
unsigned char cont;
void KeyRead( void )
{
    unsigned char readDate = P3^0xff; // 第一行
    trg = readDate & (readData ^ cont); // 第二行
    cont = readDate; // 第三行
}

用定时器每隔10ms执行一次按键扫描读取函数

第一行:

P3端口数据并且取反,然后保存到ReadData

第二行:

用来计算触发变量的

第三行:

用来计算连续变量

基础知识

  1. 一位数x异或一用来取反一个数

x ^ 1 = ~x

1 ^ 1 = 0

0 ^ 1 = 1

  1. 一位数x异或零不变

x ^ 0 = x

1 ^ 0 = 1

0 ^ 0 = 0

  1. 一位数x与一用于判断x的值

if((x & 1) == 0) x为0

if((x & 1) == 1) x为1

  1. 一位数x与零用于清零

x & 0 = 0

1 & 0 = 0

0 & 0 = 0

  1. 一位数x或一用于置一

x | 1 = 1

1 | 1 = 1

0 | 1 = 1

  1. 一位数x或零用于判断x的值

if((x | 0) == 1) x为1

if((x | 0) == 0) x为0

模拟状态

初始时候

Cont = 0x00

当没有按键

P30xff

ReadData 读端口并且取反 等于0x00

Trg = ReadData & (ReadData ^ Cont)

Trg = 0x00 & (0x00 ^ 0x00) = 0x00

Cont 等于ReadData,为0x00

结果:

ReadData0x00

Trg0x00

Cont0x00

P30按键按下

P30xfe

ReadData 读端口并且取反 等于0x01

Trg = ReadData & (ReadData ^ Cont)

Trg = 0x01 & (0x01^0x00) = 0x01

Cont 等于ReadData,为0x01

结果:

ReadData0x01

Trg0x01 Trg只会在这个时候对应位的值为1,其它时候都为0

Cont0x01

P30按键按下不松开(长按)

P30xfe

ReadData 读端口并且取反 等于0x01

Trg = ReadData & (ReadData ^ Cont)

Trg= 0x01 & (0x01^0x01) = 0x00

Cont 等于ReadData,为0x01

结果:

ReadData0x01;这个不会变,因为按键没有松开

Trg = 0x00 只要按键没有松开,Trg值永远为 0x00

Cont0x01 只要按键没有松开,Cont值永远为 0x01

P30按键按下松开

P30xff

ReadData 读端口并且取反 等于0x00

Trg = ReadData & (ReadData ^ Cont)

Trg= 0x00 & (0x00^0x01) = 0x00

Cont 等于ReadData,为0x00

结果:回到初始状态

ReadData0x00

Trg0x00

Cont0x00

总结

ReadDataTrgCont
无按下0x000x000x00都为0
第一次扫描P30按下0x010x010x01都为0x01
之后扫描P30按下0x010x000x01
之后扫描P30松开0x000x000x00恢复初始

Trg(triger) 电平从1到0的跳变(下降沿),在对应按键相应位为一

补充一句如果想要判断上升沿 (~ReadData) & (ReadData^ Cont)

Cont(continue)Cont代表的长按键,按着不放Cont的相应位为一

ReadData ^ Cont 解释:

这一次读取结果异或上之前读取结果

如果有变化相应位为一,如果没变化相应位为零

如果没有松手所有位都为零

Trg = ReadData & (0x00)

松手时

Trg = ReadData & (0x01)

这时候就要Trg的值取决于ReadData 设计思路根据基础知识与1判0

只有当读取到按键按下Trg才不等于0

三行按键扫描的改进

产生抖动情况分析

这里我们假设的是抖动时长不超过10ms

在这里插入图片描述

改进程序:

uchar cnt = 0,lastTrg = 0;
void KeyRead( void )
{
    uchar trg = 0,readDate = 0;
    
    //如果我们要读取的只有P30-P33--通过|0xF0消除P34-P37影响
    readDate = (P3|0xF0)^0xff; 
    trg = (readDate^cnt) & readDate;
    cnt = readDate;
    
    //判断上一次是否产生下降沿,并且当前状态是按键按下状态
    //lastTrg^trg & lastTrg这样写也是为了排除其他位影响
    //如果不是当前位,这个结果都为0
    if((lastTrg^trg & lastTrg) && readDate)
    {
        //执行按键按下的程序
    }
    lastTrg = trg;
}

三行按键扫描的具体应用

单次触发

void KeyProc(void)
{
    if ( trg & 相应位置一 ) //  与1判0
    {
        //处理函数
    }
}

长按和连按

#define KEY 0x02 // 按键
void KeyProc(void)
{
	static keyCnt = 0if (cont & KEY) // 如果按键被按着不放
    {
        //短按处理函数
        //连按连加
        keyCnt ++; // 计数加1
        if (keyCnt > 100) // 10ms*100 = 1S 
        {
        	keyCnt = 0;
            //长按处理函数
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值