当前位置: 首页 > article >正文

51单片机——按键实验

由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms,为了确保 CPU 对按键的一次闭合仅作一次处理,必须进行消抖

普中开发板是采用软件消抖,一般来说一个简单的按键消抖就是先读取按键的状态,如果得到按键按下之后,延时 10ms,再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。其中延时10ms 就是软件消抖处理 

1、独立按键实验

P3.1控制K1, P3.0控制K2, P3.2控制K3, P3.3控制K4

软件去抖动方法:

(1)先设置 IO 口为高电平(由于开发板 IO 都有上拉电阻,所以默认 IO 为高电平)

(2)读取 IO 口电平确认是否有按键按下

(3)如有 IO 电平为低电平后,延时几个毫秒

(4)再读取该 IO 电平,如果仍然为低电平,说明按键按下

(5)执行按键控制程序

要实现的功能是:通过开发板上的独立按键K1控制D1指示灯亮灭 

#include "reg51.h"
typedef unsigned int u16;
typedef unsigned char u8;
void delay(u16 time){
    while(time--);
}
//控制D1-D4指示灯
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
sbit LED4=P2^3;
//使用宏定义的方法定义独立按键的键值
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0
//定义按键对应的管脚口
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
//封装一个函数,按键返回一个键值
u8 key_scan(u16 mode){  //mode:模式,有0和1操作,如果操作0,单次扫描;如果操作1,连续扫描
    //打一个标志
    static u16 key=1;
    if(mode==1){
        key=1;
    }
    if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0)){
        //消抖处理,需要延时5ms-10ms
        delay(1000);
        key=0;
        //如果仍是按下,信号稳定
        if(KEY1==0){
            return KEY1_PRESS;
        }else if(KEY2==0){
            return KEY2_PRESS;
        }else if(KEY3==0){
            return KEY3_PRESS;
        }else if(KEY4==0){
            return KEY4_PRESS;
        }
    }else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1){
        key=1;
        return KEY_UNPRESS;
    }
}
void main(){
    u8 key=0;
    while(1){
        key=key_scan(0);
        if(key==KEY1_PRESS){
            LED1=!LED1; 

            delay(1000);  //加一下延时可以验证单次扫描和连续扫描的情况
        }else if(key==KEY2_PRESS){
            LED2=!LED2;
        }else if(key==KEY3_PRESS){
            LED3=!LED3;
        }else if(key==KEY4_PRESS){
            LED4=!LED4;
        }
    }
}

2、矩阵按键实验

 

P1端控制矩阵键盘 

P1.7连接矩阵键盘的第1行,P1.6连接矩阵键盘的第2行,P1.5连接矩阵键盘的第3行,P1.4连接矩阵键盘的第4行

P1.3连接矩阵键盘的第1列,P1.2连接矩阵键盘的第2列,P1.1连接矩阵键盘的第3列,P1.0连接矩阵键盘的第4列

  0          0         0          0          0         0         0         0

--------------------------------------------------------------------------

P1.7    P1.6    P1.5    P1.4    P1.3    P1.2    P1.1    P1.0  

        独立键盘有一端固定为低电平,此种方式编程比较简单。 而矩阵键盘两端都与单片机 I/O 口相连,因此在检测时需编程通过单片机 I/O 口送出低电平

单片机 I/O 口送出低电平检测方法有多种,最常用的是行列扫描和线翻转法:

        (1)行列扫描法:先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的

        (2)线翻转法:就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键

 2.1 行列扫描法

行列扫描法:先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的

#include "reg51.h"
typedef unsigned int u16;
typedef unsigned char u8;
void delay(u16 time){
    while(time--);
}
//使用宏定义定义矩阵按键的管脚
#define KEY_MATRIX_PORT P1
//数码管:静态数码管操作
#define SMG_A_DP_PORT P0
//0-F
u16 gmsg_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

u16 key_matrix_scan(){
    //定义一个变量返回
    u16 key_value=0;
    //给第一列赋值0,其余全为1
    KEY_MATRIX_PORT=0xf7;
    if(KEY_MATRIX_PORT!=0xf7){
        //消抖
        delay(1000);
        //检测行
        switch(KEY_MATRIX_PORT){
            case 0x77:
                key_value=1;
                break;
            case 0xb7:
                key_value=5;
                break;
            case 0xd7:
                key_value=9;
                break;
            case 0xe7:
                key_value=13;
                break;
        }
    }
    //等待按键松开
    while(KEY_MATRIX_PORT!=0xf7);
    
    
    //给第二列赋值0,其余全为1
    KEY_MATRIX_PORT=0xfb;
    if(KEY_MATRIX_PORT!=0xfb){
        //消抖
        delay(1000);
        //检测行
        switch(KEY_MATRIX_PORT){
            case 0x7b:
                key_value=2;
                break;
            case 0xbb:
                key_value=6;
                break;
            case 0xdb:
                key_value=10;
                break;
            case 0xeb:
                key_value=14;
                break;
        }
    }
    //等待按键松开
    while(KEY_MATRIX_PORT!=0xfb);
    
    
    //给第三列赋值0,其余全为1
    KEY_MATRIX_PORT=0xfd;
    if(KEY_MATRIX_PORT!=0xfd){
        //消抖
        delay(1000);
        //检测行
        switch(KEY_MATRIX_PORT){
            case 0x7d:
                key_value=3;
                break;
            case 0xbd:
                key_value=7;
                break;
            case 0xdd:
                key_value=11;
                break;
            case 0xed:
                key_value=15;
                break;
        }
    }
    //等待按键松开
    while(KEY_MATRIX_PORT!=0xfd);
    
    
    //给第四列赋值0,其余全为1
    KEY_MATRIX_PORT=0xfe;
    if(KEY_MATRIX_PORT!=0xfe){
        //消抖
        delay(1000);
        //检测行
        switch(KEY_MATRIX_PORT){
            case 0x7e:
                key_value=4;
                break;
            case 0xbe:
                key_value=8;
                break;
            case 0xde:
                key_value=12;
                break;
            case 0xee:
                key_value=16;
                break;
        }
    }
    //等待按键松开
    while(KEY_MATRIX_PORT!=0xfe);
    
    //返回值
    return key_value;
}

void main(){
    u16 key=0;
    while(1){
        key=key_matrix_scan();
        if(key!=0){
            SMG_A_DP_PORT=gmsg_code[key-1];
        }
    }
}

2.2 线翻转法

线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键 

 #include "reg51.h"
typedef unsigned int u16;
typedef unsigned char u8;
void delay(u16 time){
    while(time--);
}
//使用宏定义定义矩阵按键的管脚
#define KEY_MATRIX_PORT P1
//数码管:静态数码管操作
#define SMG_A_DP_PORT P0
//0-F
u16 gmsg_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

u16 key_matrix_flip_scan(){
    u16 key_value=0;
    //使所有行线为低电平,列线为高电平
    KEY_MATRIX_PORT=0x0f;
    if(KEY_MATRIX_PORT!=0x0f){
        //消抖
        delay(1000);
        if(KEY_MATRIX_PORT!=0x0f){
            //测试列,使所有行线为低电平,列线为高电平
            KEY_MATRIX_PORT=0x0f;
            switch(KEY_MATRIX_PORT){
                case 0x07:
                    key_value=1;  //暂时赋一个值
                    break;
                case 0x0b:
                    key_value=2;
                    break;
                case 0x0d:
                    key_value=3;
                    break;
                case 0x0e:
                    key_value=4;
                    break;
            }
            //测试行,使所有列线为低电平,行线为高电平
            KEY_MATRIX_PORT=0xf0;
            switch(KEY_MATRIX_PORT){
                case 0x70:
                    key_value=key_value;
                    break;
                case 0xb0:
                    key_value=key_value+4;
                    break;
                case 0xd0:
                    key_value=key_value+8;
                    break;
                case 0xe0:
                    key_value=key_value+12;
                    break;
            }
            while(KEY_MATRIX_PORT!=0xf0);
        }else{
            key_value=0;
        }
        return key_value;
    }
}

void main(){
    u16 key=0;
    while(1){
        key=key_matrix_flip_scan();
        if(key!=0){
            SMG_A_DP_PORT=gmsg_code[key-1];
        }
    }
}


http://www.kler.cn/a/467069.html

相关文章:

  • 轻量级通信协议 JSON-RPC 2.0 详解
  • LLM - 使用 LLaMA-Factory 部署大模型 HTTP 多模态服务 教程 (4)
  • QT----------QT Data Visualzation
  • CANFD芯片在商业航天的应用
  • 25年对AI产业的25点预测以及展望思考
  • LLM大模型RAG内容安全合规检查
  • YOLOv10-1.1部分代码阅读笔记-autobackend.py
  • python3GUI--智慧交通监控与管理系统 By:PyQt5
  • Chromebook 的 4 个最佳变声器
  • Dart语言的软件工程
  • 回调机制实现观察者模式
  • 什么是索引
  • PyTorch FlexAttention技术实践:基于BlockMask实现因果注意力与变长序列处理
  • SMMU软件指南之系统架构考虑
  • 【玩转全栈】----Django连接MySQL
  • Verilog语法之generate与genvar用法
  • maven 打包时优先选择本地仓库
  • 小程序学习06——uniapp组件常规引入和easycom引入语法
  • VSCode设置ctrl或alt+mouse(left)跳转
  • 计算机毕业设计Python+Spark中药推荐系统 中药识别系统 中药数据分析 中药大数据 中药可视化 中药爬虫 中药大数据 大数据毕业设计 大
  • 网络攻击原理与常用方法
  • 启航数据结构算法之雅舟,悠游C++智慧之旅——线性艺术:顺序表之细腻探索
  • 仿生的群体智能算法总结之三(十种)
  • 【数据结构-单调队列】力扣1438. 绝对差不超过限制的最长连续子数组
  • 链表算法练习
  • Arduino Uno简介与使用方法