农妇山泉一亩田 发表于 2024-12-2 15:04:18

51单片机教程(十)- 独立按键输入

1、项目分析



[*]单片机也需要人机交互,掌握常用的输入和输出装备非常须要。
[*]本章选取了最常用的输入模块键盘来演示其典范程序的体例方法。
2、技能准备

1 独立键盘输入



[*] P3口第二功能表https://i-blog.csdnimg.cn/direct/88b1cd6618a94293a22a91fc42471906.png#pic_center
[*] P3.0—P3.7: 双功能口(内置了上拉电阻) 它具有特定的第二功能。
[*] 在不利用它的第二功能时它就是平常的通用准双向I/O口。


[*]读端口和读引脚

[*]读端口:就是读Pn端口寄存器;
[*]读引脚:就是读该引脚在Pn端口寄存器中的对应位,通过引用Pn端口寄存器的值,或者引用Pn端口寄存器中的对应位,就可以实现读端口或者读引脚。

2 认识按键



[*]轻触开关是一种电子开关,利用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。
https://i-blog.csdnimg.cn/direct/9b100b6b1dda460bb35355ce3f1b4f9d.png#pic_center
3 按键分类



[*]键盘输入检测的基本方法:

[*]轮询法。

1. 独立按键



[*]每一个按键对应每一个引脚,相当于一个按键控制一个引脚
https://i-blog.csdnimg.cn/direct/e614b9c5e6274a63ac3e0721426ffb21.png#pic_center
2. 矩阵按键



[*]矩阵按键能控制的东西比较多,利用的引脚也比较多,如果每一个按键控制一个引脚,那么需要16个引脚,若利用矩阵式键盘,则仅需1个引脚组即可,但程序计划相对复杂一些。
https://i-blog.csdnimg.cn/direct/d207e383424e41f0ac862ac9266fb2b8.png#pic_center
[*]矩阵式键盘的识别方法
1. 逐列扫描法
https://i-blog.csdnimg.cn/direct/ba408cbbfd064e9498294dd261d1d9b9.png#pic_center

[*]判断键盘是否按键按下,方法是向全部列线上输入低电平,再读入全部行信号,如果16个按键中恣意一个按键被按下,则读入的行电平则不全为高;反之如无按键按下,则读入的行电平全为高。若S10被按下,则S10按键所在的行线2与列线1导通,则行线的电平被拉低,读入的行信号为低电平,则表示按键已经被按下(现还无法判断是S9、S10、S11、S12被按下)。
[*]逐列扫描判断具体的按键,方法是向列线上逐列送低电平,现送到列线0,列线1、2、3为高电平,读入的行电平的状态就显示了位于列线0的S1、S5、S9、S13四个按键的按键的状态。若键入的行值为全高,则表示无按键按下;在送到列线1,列线0、2、3为高电平,读入的行电平状态则显示S2、S6、S10、S14四个按键的按键的状态,依次类推,直到全部扫描完毕。
2. 行列反转法


[*] 基本原则:通过给行列端口输出两次相反的值,再分别读入的行值和列值进行 求和 或按位 或 运算,得到每个键的扫描码。

[*]向全部的列线上输入低电平,列线输入2次相反的值。
[*]读入行信号,如果16个按键中恣意一个按键被按下,读入的行信号则不全为高,反之,则行信号则全为高,记录现在的值。
[*]向全部的列线上出高电平,行线输入低电平(行列反转),读入全部的列信号,记录现在的值。
[*]将行和列的值合并成扫描码。通过查找扫描码表的方法得出 “哪个按键被按下”。

[*] 具体实现过程:

[*]起首,给P1口输入0xf0,即:11110000,若S10按键被按下,则读入的P1的值为:11010000,在给P1赋相反的值0x0f,即:11110000,此时读入的P1口的值为:00001011,再次把读入的P1的值进行相加或按位 “或” 操作,得到:11011011,即0xdb,这个值是按键S1的扫描码,以此类推,得到别的15个按键的扫描码。
https://i-blog.csdnimg.cn/direct/08dcac757beb43319453fe3d5dd8773a.png#pic_center

3 按键抖动



[*]按键中有一个金属弹片,当按下按键时会挤压金属弹片来导通电流,而松手时金属弹片会弹归去,在其闭合、断开瞬间均有抖动过程,抖动时间一样寻常在5—10ms。
[*]按下和松手都会让金属弹片有抖动,这个抖动的电流是不稳固的,会影响程序对按键的判断。
https://i-blog.csdnimg.cn/direct/7367f7266a4f4a7a9dec8d076d08a5e7.png#pic_center


[*]解决方法
[*]硬件处理方法:利用另一种没用抖动或者抖动频率小的硬件。
[*]软件处理方法:利用程序来超过这个抖动,也就是用一个延迟函数来将这个按下的抖动时间消除(消抖)。

4 按键原理图

https://i-blog.csdnimg.cn/direct/b3b4657530554c4caa210bc89830a929.png#pic_center




[*] 判断按键按下的实现方法
https://i-blog.csdnimg.cn/direct/2c5df527bde8409e99669cb4fc5a22f2.png#pic_center

[*]先判断键是否按下,若按下了延时10 ms,跳过按下抖动期。
[*]再判断按键是否按下,若是说明按键真的按下了,否则说明是干扰信号,如果键真的按下了,则等候键开释,如果键开释了,延时10 ms,
[*]再判断键是否开释,若开释了,说明按键真的开释了,否则说明是干扰信号,如果按键真的开释了,说明一次完整的按键过程完成了。
3、项目实现

1 1个按键控制1个LED灯亮灭



[*]实行要求

[*]按下K2 则LED1亮,再次按下LED1灭,如此循环。

[*]实行分析

[*]判断按键是否按下,按下则对LED灯的状态取反。

[*]实行代码#include <reg52.h>

// 2、定义端口:按键/LED
sbit key = P3^4;
sbit led = P1^0;

void delay(unsigned int v);

void main()
{
   while(1)
   {
           // 3、判断按键是否按下:按下key对应的电平值为0
           if(key == 0)
           {
                   // 消抖 - 10ms
                   delay(1000);
                  
                   // 再次判断按键是否按下
                   if(key == 0)
                   {
                           // 按键是按下:电平值为0趋于稳定
                          
                           // 方法1:判断led的状态,如果是电平值为0,则设置为1,否则设置为0
//                                if(led == 1){
//                                        led = 0;
//                                }else{
//                                        led = 1;
//                                }
                          
                           // 方法2:对LED状态值取反
                           led = !led;
                   }
           }
   }
}

// 延迟函数
void delay(unsigned int v)
{
   while(v--);
}


2 4个按键控制4个LED灯



[*]实行要求

[*]按下第1个独立按键K2 2个赤色的led灯亮
[*]按下第2个独立按键K3 2个绿色的led灯亮
[*]按下第3个独立按键K4 2个黄色的led灯亮
[*]按下第4个独立按键K5 2个蓝色的led灯亮

[*]实行分析

[*]若分别独立判断K2-K5是否按下,则代码冗余,可以编写函数用于扫描哪个按键按下并返回,通过返回值判断,实现LED的亮灭控制。




[*] 实行代码
#include <reg52.h>
       
#define uint unsigned int
       
// 定义端口:4个按键/LED
sbit key2 = P3^4;
sbit key3 = P3^5;
sbit key4 = P3^6;
sbit key5 = P3^7;

sbit led1 = P1^0;
sbit led2 = P1^2;
sbit led3 = P1^4;
sbit led4 = P1^6;

// 定义按键的取值
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY5_PRESS 5
#define KEY_UNPRESS 0

uint key_scan(uint mode);
void delay(unsigned int v);

void main()
{
        while(1)
        {
                // 表示获取哪个按键被按下
                uint key_value = key_scan(1);   // 返回值:0 2 3 4 5
               
                // 判断对应的按键来实现LED灯控制
                switch(key_value){
                        case KEY2_PRESS: led1 = !led1; break;
                        case KEY3_PRESS: led2 = !led2; break;
                        case KEY4_PRESS: led3 = !led3; break;
                        case KEY5_PRESS: led4 = !led4; break;
                }
        }
}


/*
        功能:按键扫描函数
        参数:
                mode: 表示按键扫描方式
                        0:单次扫描
                        1:连续扫描
        返回值:
                2 表示K2按下
                3 表示K3按下
                4 表示K4按下
                5 表示K5按下
                0 表示无按键按下
*/
uint key_scan(uint mode)
{
        // 定义按键的初始状态值
        static uint key = 1;
       
        // 对模式的判断
        if(mode) key=1;
       
        // 判断4个按键中是否按下
        if(key==1 && (key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0))
        {
                // 消抖
                delay(1000);
                key = 0;
               
                // 判断具体是哪个按键按下
                if(key2 == 0) return KEY2_PRESS;// return 2
                if(key3 == 0) return KEY3_PRESS;// return 3
                if(key4 == 0) return KEY4_PRESS;// return 4
                if(key5 == 0) return KEY5_PRESS;// return 5
        }else if(key2 == 1 && key3 == 1 && key4 == 1 && key5 == 1){
                key = 1;
        }
        return KEY_UNPRESS;
}



// 延迟函数
void delay(unsigned int v)
{
        while(v--);
}

3 按键控制数码管显示



[*]实行要求

[*]按下按键1实现数码管+1;
[*]按下按键2实现数码管-1;
[*]按下按键3清零;

[*]实行分析

[*]先利用2位数码显示00-99,判断按键是否按下,则修改记录数据变量值加1,减1或者为0的设置,同时需当数值减为0则设置为0,当加到99则设置为99。




[*]实行代码
#include <reg52.h>
#include "delay.h"

#define uint unsigned int

// 定义位选与段选
#define pos P2
#define par P0

// 定义端口:4个按键/LED
sbit key2 = P3^4;
sbit key3 = P3^5;
sbit key4 = P3^6;
sbit key5 = P3^7;

// 定义按键的取值
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY5_PRESS 5
#define KEY_UNPRESS 0

// 分别对应:0/1/2/3/4/5/6/7/8/9
uint par_value[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};


// 记录数码管显示值
uint number = 3;
uint ge, shi;

uint keyScan(uint mode);
void delay(uint v);

void main()
{
        while(1)
        {       
                uint key_value = keyScan(0);
               
                // 判断对应的按键来控制数值是否越界控制
                if(key_value == KEY2_PRESS)
                {
                        if(number == 99)
                        {
                                number = 99;
                        }else{
                                number++;
                        }
                }
                else if(key_value == KEY3_PRESS)
                {
                        if(number == 0)
                        {
                                number = 0;
                        }else{
                                number--;
                        }
                }
                else if(key_value == KEY4_PRESS)
                {
                        number = 0;
                }
               
                shi = number / 10;
                ge = number % 10;
                       
                // 显示十位
                pos = 0x18;
                par = par_value;
                delay(100);
               
                // 显示个位
                pos = 0x28;
                par = par_value;
                delay(100);
        }
}


uint keyScan(uint mode)
{
        // 定义按键的初始状态值
        static uint key = 1;
       
        // 对模式的判断
        if(mode) key=1;
       
        // 判断4个按键中是否按下
        if(key==1 && (key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0))
        {
                // 消抖
                delay(5000);
                key = 0;
               
                // 判断具体是哪个按键按下
                if(key2 == 0) return KEY2_PRESS;// return 2
                if(key3 == 0) return KEY3_PRESS;// return 3
                if(key4 == 0) return KEY4_PRESS;// return 4
                if(key5 == 0) return KEY5_PRESS;// return 5
        }else if(key2 == 1 && key3 == 1 && key4 == 1 && key5 == 1){
                key = 1;
        }
        return KEY_UNPRESS;
}


// 延迟函数
void delay(unsigned int v)
{
        while(v--);
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 51单片机教程(十)- 独立按键输入