AT89C51芯片,独立按键

设计并制作一个电路,具备密码功能,有三个按键,连续按下K1两次,K2一次,K3一次,数码管显示1,其余无论何种情况均显示0。

可采纳
连接三个按键K1、K2和K3到P1.0、P1.1和P1.2。
编写单片机程序,使单片机循环检测按键输入,如果连续按下K1两次,K2一次,K3一次,就在数码管上显示“1”,否则就显示“0”。

单片机程序如下:

#include <reg52.h>

//数据段定义
unsigned char code Number[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
//定义每个按键的状态
#define K1  P1_0
#define K2  P1_1
#define K3  P1_2

//延时函数
void delay(unsigned int t)
{
    unsigned int i,j;
    for(i=0;i<t;i++)
        for(j=0;j<120;j++);
}

//循环检测按键
char KeyScan(void)
{
    if(K1 == 0) //K1按下
    {
        delay(5); //按键消抖
        if(K1 == 0) //再次确认按键按下
        {
            while(K1 == 0); //等待按键松开
            return 1;
        }
    }
    if(K2 == 0) //K2按下
    {
        delay(5); //按键消抖
        if(K2 == 0) //再次确认按键按下
        {
            while(K2 == 0); //等待按键松开
            return 2;
        }
    }
    if(K3 == 0) //K3按下
    {
        delay(5); //按键消抖
        if(K3 == 0) //再次确认按键按下
        {
            while(K3 == 0); //等待按键松开
            return 3;
        }
    }
    return 0; //无按键按下
}

void main()
{
    unsigned char a,counter = 0;
    unsigned long i = 0;
    
    while(1)
    {
        a = KeyScan(); //检测按键
        if(a == 1) //按下K1
        {
            counter++; //计数器加1
            if(counter == 3) //连续按下K1两次,K2一次,K3一次
            {
                P0 = Number[1]; //在数码管上显示“1”
                delay(200); //延时一段时间
                counter = 0; //计数器清零
            }
        }
        else if(a == 2 || a == 3) //按下K2或K3
        {
            counter = 0; //计数器清零
        }
        else //无按键按下
        {
            P0 = Number[0]; //在数码管上显示“0”
        }
    }
}

该电路可以通过上述程序实现密码功能,当连续按下K1两次,K2一次,K3一次时,数码管上会显示“1”,否则就会显示“0”。

代码如下:

#include <REG52.H>

sbit K1 = P1^0; //K1按键
sbit K2 = P1^1; //K2按键
sbit K3 = P1^2; //K3按键
sbit LED = P2^0; //LED灯
sbit DIO = P2^1; //74HC595数据线
sbit RCLK = P2^2; //74HC595存储锁存线
sbit SCLK = P2^3; //74HC595时钟线

unsigned char code NUM_TAB[10] = { //数码管显示码表
    0xC0,  //0
    0xF9,  //1
    0xA4,  //2
    0xB0,  //3
    0x99,  //4
    0x92,  //5
    0x82,  //6
    0xF8,  //7
    0x80,  //8
    0x98   //9
};

void display(unsigned char number) { //数码管显示函数
    DIO = 0;
    SCLK = 0;
    for (int i = 0; i < 8; i++) { //74HC595中写入一个字节的数据
        DIO = (number & 0x80) >> 7;
        number <<= 1;
        SCLK = 1;
        _nop_();
        _nop_();
        SCLK = 0;
    }
    RCLK = 1; //锁存数据
    _nop_();
    _nop_();
    RCLK = 0;
}

void main() {
    unsigned char cnt = 0; //按下K1的次数
    unsigned char state = 0; //密码输入状态
    P1 = 0xFF; //按键输入口设置为上拉输入
    P2 = 0x00; //数码管输出口初始化
    while (1) {
        if (K1 == 0) { //检测到按下K1
            delay(10); //延时去抖动
            if (K1 == 0) {
                cnt++; //按下K1的次数加一
                if (cnt == 2) { //连续按下K1两次
                    state = 1; //进入下一个状态
                    cnt = 0; //重置K1按下次数
                }
            }
            while (K1 == 0); //等待K1松开
        }
        if (K2 == 0 && state == 1) { //检测到按下K2
            delay(10);
            if (K2 == 0) {
                state = 2; //进入下一个状态
            }
            while (K2 == 0);
        }
        if (K3 == 0 && state == 2) { //检测到按下K3
            delay(10);
            if (K3 == 0) {
                display(NUM_TAB[1]); //数码管显示1
                LED = 1; //点亮LED灯
                delay(500); //延时500ms
                display(0); //数码管清零
                LED = 0; //熄灭LED灯
                state = 0; //回到起始状态
            }
            while (K3 == 0);
        }
    }
}

void delay(unsigned int n) { //延时函数
    while (n--);
}

该代码实现使用 AT89C51 芯片,三个按键通过上拉电阻连接至输入口,数码管使用 74HC595 串行移位寄存器驱动,LED 灯则直接接至输出口。使用状态变量 state 记录当前密码输入状态,计数器 cnt 记录连续按下 K1 次数,在已经连续按下两次 K1 的情况下按下 K2 和 K3 才会触发数码管显示 1 的操作。使用 delay 函数实现延时操作,可能需要根据实际情况适当调整延时时长。

根据上述电路设计,以下是使用C语言编写的代码。假设按键输入值为1,这里采用Arduino框架来实现。

// 定义状态变量和密码序列
#define STATE_IDLE 0
#define STATE_K1_1 1
#define STATE_K1_2 2
#define STATE_K2    3
#define STATE_K3    4

const uint8_t PASSWORD[] = {STATE_K1_1, STATE_K1_1, STATE_K2, STATE_K3};

// 初始化输入引脚和输出引脚
const uint8_t PIN_K1 = 2;
const uint8_t PIN_K2 = 3;
const uint8_t PIN_K3 = 4;
const uint8_t PIN_DS = 5; // 74HC595数据引脚
const uint8_t PIN_SH = 6; // 74HC595时钟引脚
const uint8_t PIN_ST = 7; // 74HC595存储引脚

// 初始化状态机变量
uint8_t state = STATE_IDLE;
uint8_t index = 0;

void setup() {
  pinMode(PIN_K1, INPUT_PULLUP);
  pinMode(PIN_K2, INPUT_PULLUP);
  pinMode(PIN_K3, INPUT_PULLUP);

  pinMode(PIN_DS, OUTPUT);
  pinMode(PIN_SH, OUTPUT);
  pinMode(PIN_ST, OUTPUT);
}

void loop() {
  // 读取按键状态
  uint8_t k1 = digitalRead(PIN_K1);
  uint8_t k2 = digitalRead(PIN_K2);
  uint8_t k3 = digitalRead(PIN_K3);

  // 更新状态机
  switch (state) {
    case STATE_IDLE:
      if (!k1) state = STATE_K1_1;
      break;
    case STATE_K1_1:
      if (!k1) state = STATE_K1_2;
      else if (k2) state = STATE_IDLE;
      break;
    case STATE_K1_2:
      if (!k1) state = STATE_K2;
      else if (k2) state = STATE_IDLE;
      break;
    case STATE_K2:
      if (!k1) state = STATE_IDLE;
      else if (k3) state = STATE_K3;
      break;
    case STATE_K3:
      if (!k1) state = STATE_IDLE;
      else {
        // 匹配密码序列
        if (PASSWORD[index] == state) {
          index++;
          if (index >= sizeof(PASSWORD)) {
            display(1); // 显示数字1
            index = 0; // 密码匹配,重置状态机
          }
        } else {
          // 密码错误,重置状态机
          index = 0;
          state = STATE_IDLE;
        }
      }
      break;
  }

  // 显示数码管状态
  if (state == STATE_IDLE || index > 0) {
    display(0);
  }
}

// 将数字显示在四位数码管上(共阴极)
void display(uint8_t digit) {
  static const uint8_t DIGIT_MAP[] = {
    B11111100, // 数字0
    B01100000, // 数字1
    B11011010, // 数字2
    B11110010, // 数字3
    B01100110, // 数字4
    B10110110, // 数字5
    B10111110, // 数字6
    B11100000, // 数字7
    B11111110, // 数字8
    B11110110  // 数字9
  };
  
  uint8_t data = DIGIT_MAP[digit];
  digitalWrite(PIN_ST, LOW);
  shiftOut(PIN_DS, PIN_SH, LSBFIRST, data);
  digitalWrite(PIN_ST, HIGH);
}

此代码使用Arduino的digitalRead()和digitalWrite()函数来读取和写入GPIO引脚。在处理状态机变量时,使用switch-case语句以识别不同的状态并根据当前输入转换状态。密码匹配检查在STATE_K3中进行,如果密码序列匹配则将数字1显示在数码管上,否则将重置状态机。最后,使用shiftOut()函数向74HC595移位寄存器输出数字的LED段控制数据,以在共阴极

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^