51单片机之按键

独立按键

独立按键:通过SW1、SW2、SW3、SW4四个独立按键分别控制LED1、LED2、LED3、LED4的亮灭,具体要求是,按一下(按下并松开)SW,LED点亮,再按一下SW,LED熄灭。

  1. 芯片和按键接法:                                                                          
  2. 原理图:                                                                                                                           
  3. 按键抖动:这个现象是由按键的物理特性导致的,由于按键内部的弹簧和触点具有弹性,当按键被按下或释放时,这些弹性材料会震动,从而导致触点在短时间内反复接触和断开。所以表面上我们虽然只按了一次按键,但实际上是按了多次。如果实际按下的次数是奇数,那么LED就会按照预期点亮或熄灭;而如果是偶数,LED最终还是会回到按下按键之前的状态。
  4. 按键消抖:当我们检测到信号为0时,不能莽撞的认为按键已经被按下了,而是要稍微等一段时间(约10ms),等按键稳定之后,再次检测,如果信号仍然为0,才可以确定按键确实被按下了。
  5. 示意图:                                                                                                                              
  6. 代码实现:
// Int_Key.h
#ifndef __INT_KEY_H__
#define __INT_KEY_H__

#include "Com_Util.h"
#include <STC89C5xRC.H>
#define SW1 P42
#define SW2 P43
#define SW3 P32
#define SW4 P33

bit Int_Key_IsSW1Pressed();
bit Int_Key_IsSW2Pressed();
bit Int_Key_IsSW3Pressed();
bit Int_Key_IsSW4Pressed();

#endif /* __INT_KEY_H__ */

// Int_Key.c
#include "Int_key.h"

bit Int_Key_IsSW1Pressed() {
    if(SW1 == 0) {
        Com_Util_Delay1ms(10);
        if (SW1 == 0) {
            while (SW1 == 0);
            return 1;
        }
        
    }
    
    return 0;
}

bit Int_Key_IsSW2Pressed() {
    if (SW2 == 0) {
        Com_Util_Delay1ms(10);
        if (SW2 == 0) {
            while (SW2 == 0);
            return 1;
        }
    }
    return 0;
}
bit Int_Key_IsSW3Pressed() {
    if (SW3 == 0) {
        Com_Util_Delay1ms(10);
        if (SW3 == 0) {
            while (SW3 == 0);
            return 1;
        }
    }
    return 0;
}
bit Int_Key_IsSW4Pressed()
{
    if (SW4 == 0) {
        Com_Util_Delay1ms(10);
        if (SW4 == 0) {
            while (SW4 == 0);
            return 1;
        }
    }
    return 0;
}

// main.c
#include "Int_Key.h"
#define LED1 P00
#define LED2 P01
#define LED3 P02
#define LED4 P03
void main()
{
    while (1) {
        if (Int_Key_IsSW1Pressed()) {
            LED1 = ~LED1;
        }
        if (Int_Key_IsSW2Pressed()) {
            LED2 = ~LED2;
        }
        if (Int_Key_IsSW3Pressed()) {
            LED3 = ~LED3;
        }
        if (Int_Key_IsSW4Pressed()) {
            LED4 = ~LED4;
        }

    }
}

矩阵按键

按下按键矩阵中的SW5到SW20按键后,数码管显示对应的按键编号。

  1. 实现思路:借用动态扫描的思想,将按钮循环得连接。
  2.                                                                                                                                           
  3. 单片机引脚构造:    弱上拉强下拉;                                                                                                         

原理图:

代码实现:

// Int_DigitalTube.c
#include "Int_DigitalTube.h"
#include <STC89C5xRC.H>
static u8 s_codes[11] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F, // 9
    0x40  // -
};

// 存放显示的数的缓存
static u8 s_buffer[8];

//  打开数码管的输入使能
void Int_DigitalTube_Init()
{
    SMG_EN = 0;
    LED_EN = 0;
}
static void Int_DigitalTube_DisplaySingle(u8 position, u8 num_code)
{
    // 关闭当前数码管 否则数码管将有重影
    P0 = 0x00;
    // 位选
    // 先将要显示的数左移 3 位
    position <<= 3;
    // 按位与 将P1 的 p13、P14、P15 位置的数变为0
    P1 &= 0xC7;
    // 按位或 |  将 P1 的 p13、P14、P15 位置和 position 相应位置数交换
    P1 |= position;
    // 段选 需要放置的数字
    P0 = num_code;
}

// 将显示的数放在缓存里
void Int_DigitalTube_DisplayNum(s32 num)
{
    u8 i;
    // 将显存清零
    for (i = 0; i < 8; i++) {
        s_buffer[i] = 0x00;
    }

    if (num < 0) { // 这个功能不需要考虑
        num = -num; // 取绝对值
        i   = 7;    // 从最右侧开始显示数字
        // 将每个位上的数放入显存,从右向左填充
        while (num > 0) {
            s_buffer[i] = s_codes[num % 10];
            num /= 10;
            i--;
        }
        // 如果是负数,将负号放在数字之前的一位
        if (i < 7) {
            s_buffer[i] = s_codes[10]; // s_codes[10] 对应负号 '-'
        }
    } else if (num > 0) {
        i = 7; // 正数从最右侧开始显示
        while (num > 0) {
            s_buffer[i] = s_codes[num % 10];
            num /= 10;
            i--;
        }
    } else {
        // 如果 num == 0 ,将0 放在最右边
        s_buffer[7] = s_codes[0];
    }
}

// 循环多次刷新数码管
void Int_DigitalTube_Refresh()
{
    u8 i;
    for (i = 0; i < 8; i++) {
        Int_DigitalTube_DisplaySingle(i, s_buffer[i]);
        Com_Util_Delay1ms(1); // 延时
    }
}
//  Int_DigitalTube.h
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__
#define SMG_EN P36
#define LED_EN P34

#include "Com_Util.h"

void Int_DigitalTube_Init();
void Int_DigitalTube_DisplayNum(s32 num);
void Int_DigitalTube_Refresh();

#endif /* __INT_DIGITALTUBE_H__ */
// Int_keyMatrix.h
#ifndef __INT_KEYMATRIX_H__
#define __INT_KEYMATRIX_H__

#include "Com_Util.h"
#include <STC89C5xRC.H>

u8 Int_KeyMatrix_CheckSW();

#endif /* __INT_KEYMATRIX_H__ */


// Int_KeyMatrix.c
#include "Int_KeyMatrix.h"

u8 Int_KeyMatrix_CheckSW() {
    u8 i, j;
    u8 lines[4] = {0xFE, 0xFD, 0xFB, 0xF7};
    u8 columns[4] = {0x10, 0x20, 0x40, 0x80};
    for (i = 0; i < 4; i++) {
        P2 = lines[i];
        for ( j = 0; j < 4; j++) {
            if ((P2 & columns[j]) == 0x00) {
                Com_Util_Delay1ms(10);
                if ((P2 & columns[j]) == 0x00) {
                    while ((P2 & columns[j]) == 0x00);
                    return 5 + j + 4 * i;
                }
            }
        }
    }
    return 0;
}


// main.c

#include "Int_DigitalTube.h"
#include "Int_KeyMatrix.h"
void main()
{
    u8 key;
    Int_DigitalTube_Init();
    while (1) {
        key = Int_KeyMatrix_CheckSW();
        if (key) {
            Int_DigitalTube_DisplayNum(key);
        }
        Int_DigitalTube_Refresh();
    }
}

  • 在Int_DigitalTube_Refresh()函数中,最后加上延迟函数 Com_Util_Delay1ms(1); 不加延时函数,会出现数码管上前一个数字会比后一个数字的亮度暗很多,这是因为主函数执行时,一直做循环,当第一次执行Int_DigitalTube_Refresh函数,先将最后一个数字显示出来,然后执行下次循环,将下一个数字显示出来,在这个过程中,执行Int_DigitalTube_Refresh需要时间,执行一条命令是微妙级的,执行最后一次命令就会和第一次体现出时间相差较大,所以第一次显示的会比最后显示的亮一些,可以加上延迟函数,减小它们之间的时间差,使亮度基本一致。
  • 在数码管上显示时,当按下一个按键不松开,他会显示上一次数字的最后一位数字。当按下不松开时,主函数执行Int_KeyMatrix_CheckSW()函数,在执行里面的for 循环语句时,会执行while ((P2 & columns[j]) == 0x00)这句代码,它会一直等待松开按键,程序就会在次阻塞,主函数中的Int_DigitalTube_Refresh也不会执行,会显示Int_DigitalTube_Refresh函数上一次刷新的数字的最后一位。

按键位移

// Int_DigitalTube.c
// 二进制显示函数
void Int_DigitalTube_DisplayBinary(u8 num)
{
    u8 i;
    for (i = 0; i < 8; i++) {
        s_buffer[i] = s_codes[(num & (0x80 >> i)) == 0x00 ? 0 : 1];  // 判断位置上是0还是1

    }
}


// main.c
#include "Int_DigitalTube.h"
#include "Int_key.h"

void main() {
    u8 init = 0xFF;
    Int_DigitalTube_Init(); // 初始化数码管
    Int_DigitalTube_DisplayBinary(init);
    while (1) {
        // 检测按键状态并更新相应的pair值
        if (Int_Key_IsSW1Pressed()) {
            init <<= 1;
            Int_DigitalTube_DisplayBinary(init);
        }
        // 检测按键状态并更新相应的pair值
        if (Int_Key_IsSW2Pressed()) {
            init >>= 1;
            Int_DigitalTube_DisplayBinary(init);
        }
        // 检测按键状态并更新相应的pair值
        if (Int_Key_IsSW3Pressed()) {
            init += 1;
            Int_DigitalTube_DisplayBinary(init);
        }
        // 检测按键状态并更新相应的pair值
        if (Int_Key_IsSW4Pressed()) {
            init = 0x00;
            Int_DigitalTube_DisplayBinary(init);
        }


        // 更新显示
        Int_DigitalTube_Refresh();
    }
}

按键记数

// main.c
#include "Int_DigitalTube.h"
#include "Int_key.h"

u8 num1 = 0;
u8 num2 = 0;
u8 num3 = 0;
u8 num4 = 0;
u32 getSum() {
    return 1000000 * num1 + 10000L * num2 + 100 * num3 + num4;
}
void main() {

    Int_DigitalTube_Init(); // 初始化数码管
    while (1) {
        // 检测按键状态并更新相应的pair值
        if (Int_Key_IsSW1Pressed()) {
            Int_DigitalTube_Init();
            num1++;
            if (num1 > 99) {
                num1 = 0;
            }
            Int_DigitalTube_DisplayNum(getSum());
        }
        if (Int_Key_IsSW2Pressed()) {
            Int_DigitalTube_Init();
            num2++;
            if (num2 > 99) {
                num2 = 0;
            }
            Int_DigitalTube_DisplayNum(getSum());
        }
        if (Int_Key_IsSW3Pressed()) {
            Int_DigitalTube_Init();
            num3++;
            if (num3 > 99) {
                num3 = 0;
            }
            Int_DigitalTube_DisplayNum(getSum());
        }
        if (Int_Key_IsSW4Pressed()) {
            Int_DigitalTube_Init();
            num4++;
            if (num4 > 99) {
                num4 = 0;
            }
            Int_DigitalTube_DisplayNum(getSum());
        }

        // 更新显示
        Int_DigitalTube_Refresh();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值