单元训练06:独立按键的扩展应用

蓝桥杯

小蜜蜂

cpp 复制代码
#include "stc15f2k60s2.h"

// 定义LED打开
#define LED(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1f | 0x80; \
        P2 = P2 & 0x1f;        \
    }

// 以位数来定义第1、2至6个灯,注意,后面点亮要取反,因为是低电平有效
#define L1 0x01
#define L2 0x02
#define L3 0x04
#define L4 0x08
#define L5 0x10
#define L6 0x20

// 独立按键定义
sbit k7 = P3 ^ 0;
sbit k6 = P3 ^ 1;
sbit k5 = P3 ^ 2;
sbit k4 = P3 ^ 3;

typedef unsigned char uint8_t; // 自定义类型

void Timer0_Init(void) // 1毫秒@12.000MHz
{
    AUXR |= 0x80; // 定时器时钟1T模式
    TMOD &= 0xF0; // 设置定时器模式
    TL0 = 0x20;   // 设置定时初始值
    TH0 = 0xD1;   // 设置定时初始值
    TF0 = 0;      // 清除TF0标志
    TR0 = 1;      // 定时器0开始计时
    ET0 = 1;      // 使能定时器0中断
    EA = 1;
}

uint8_t selectedValue; // S6、S7选择键值
uint8_t controlValue;  // S5、S4控制键值

uint8_t selectEnableS6 = 0; // S6选中
uint8_t selectEnableS7 = 0; // S7选中

uint8_t ledEnableS6 = 0; // 因为S7按一下点亮L1,再按一次熄灭L1,所以用一个变量来操作状态
uint8_t ledEnableS7 = 0; // 因为S6按一下点亮L2,再按一次熄灭L2,所以用一个变量来操作状态

uint8_t ledEnableS4 = 0; // S4控制L4,一般理解为按一下亮,再按下灭
uint8_t ledEnableS5 = 0; // S5控制L3,一般理解为按一下亮,再按下灭

uint8_t timerCounter;
uint8_t timerCounterEnable;

uint8_t keyStatus;      // 获取当前按键状态
uint8_t ledInfo = 0xff; // LED初始状态

uint8_t Falling = 0; // 按键按下的下降沿表示,用于防止长按状态下,前面的变量不停变化。

void KeyScan()
{
    switch (keyStatus)
    {
    case 0: // 初始化,全部按键没按下,为高电平
        k7 = 1;
        k6 = 1;
        k5 = 1;
        k4 = 1;
        keyStatus = 1;
        break;

    case 1:
        if ((k7 == 0) || (k6 == 0)) // 如果S6、S7按下,产生 下降沿,
        {
            keyStatus = 2;
            Falling = 1;
        }
        if (((k5 == 0) || (k4 == 0)) && (selectEnableS6 || selectEnableS7)) // 如果S5、S4按下,同时是在S7或S6已经按下的情况,产生 下降沿,
        {
            keyStatus = 3;
            Falling = 1;
        }
        selectEnableS6 = 1; // 初始化S6启用状态
        selectEnableS7 = 1; // 初始化S7启用状态

        break;

    case 2:
        if ((k7 == 0) && selectEnableS7) // S7按下低电平,同时满足启用状态(用于对应题目中"S6、S7不可响应"操作的要求)
        {
            selectedValue = 7; // 根据按键值对应返回值

            if (Falling) // 第1次按下时,即下降沿时
            {
                ledEnableS7 = ~ledEnableS7; // 用于控制点亮LED的标记,长按不翻转
            }
        }
        else if ((k6 == 0) && selectEnableS6) // 同S7
        {
            selectedValue = 6;
            if (Falling)
            {
                ledEnableS6 = ~ledEnableS6;
            }
        }
        if ((k7 == 0) || (k6 == 0)) // 按键不松开,停在当前状态,长按状态,在测试时,如果不区别长按短按,LED灯会闪烁,因为程序中有翻转情况
        {
            keyStatus = 2; // 停留在当前状态
            Falling = 0;   // 没有下降沿,
        }
        else
        {
            keyStatus = 3;
            Falling = 1;
        }

        break;

    case 3:
        if (k5 == 0) // 同S7、S6
        {
            controlValue = 5;
            if (Falling)
            {
                ledEnableS5 = ~ledEnableS5;
            }
        }
        else if (k4 == 0) // 同S7、S6
        {
            controlValue = 4;
            if (Falling)
            {
                ledEnableS4 = ~ledEnableS4;
            }
        }
        if ((k5 == 0) || (k4 == 0)) // 按键不松开,停在当前状态
        {
            keyStatus = 3;
            Falling = 0;
        }
        else
            keyStatus = 4;
        break;

    case 4:
        if ((k7 == 1) && (k6 == 1) && (k5 == 1) && (k4 == 1))
            keyStatus = 0;

    default:
        keyStatus = 0;
        break;
    }
}
void KeyProc()
{
    if (timerCounterEnable)
    {
        timerCounterEnable = 0;
        KeyScan();

        if ((selectedValue == 7) && selectEnableS7) // S7按下,同时处于"可响应"状态
        {
            if (ledEnableS7) // 对应按下亮,再按下灭的情况中"按下亮"
            {
                ledInfo = ~L1; // 用于点亮L1,要取反
                LED(ledInfo);
                selectEnableS6 = 0; // 关闭S6,使其无法响应按键操作
            }
            else
            {
                ledInfo = 0xff; // 对应按下亮,再按下灭的情况中"再按下灭"
                LED(ledInfo);
                selectEnableS6 = 1; // 启用S6可响应操作
            }
            if (controlValue == 5 && ledEnableS7) // 在S5按下,同时处于S7已经点亮L1的情况下
            {
                if (ledEnableS5)
                {
                    ledInfo = ~(L3 | L1); // 因为题目中说明再次按下S7,L1熄灭,所以无论是按S5还是S4,L1不能熄灭。
                }
                else
                    ledInfo = ~L1; // S5控制的L3灭的情况下,L1 还是亮的。
                LED(ledInfo);
            }
            if (controlValue == 4 && ledEnableS7) // 同上S5分析
            {
                if (ledEnableS4)
                {
                    ledInfo = ~(L4 | L1);
                }
                else
                    ledInfo = ~L1;
                LED(ledInfo);
            }
        }
    }
    else if ((selectedValue == 6) && selectEnableS6) // 同上S7分析
    {
        if (ledEnableS6)
        {
            ledInfo = ~L2;
            LED(ledInfo);
            selectEnableS7 = 0;
        }
        else
        {
            ledInfo = 0xff;
            LED(ledInfo);
            selectEnableS7 = 1;
        }
        if (controlValue == 5 && ledEnableS6)
        {
            if (ledEnableS5)
            {
                ledInfo = ~(L5 | L2);
            }
            else
                ledInfo = ~L2;
            LED(ledInfo);
        }
        if (controlValue == 4 && ledEnableS6)
        {
            if (ledEnableS4)
            {
                ledInfo = ~(L6 | L2);
            }
            else
                ledInfo = ~L2;
            LED(ledInfo);
        }
    }
}
void main()
{
    Timer0_Init();
    timerCounter = 0;
    timerCounterEnable = 0;

    ledInfo = 0xff;
    LED(ledInfo);

    controlValue = 0;
    selectedValue = 0;
    selectEnableS6 = 1;
    selectEnableS7 = 1;

    while (1)
    {
        KeyProc();
    }
}

void Timer0_Isr(void) interrupt 1 // 1ms
{
    if (timerCounter++ == 20)
    {
        timerCounterEnable = 1;
        timerCounter = 0;
    }
}

代码还存在瑕疵,在S5、S4控制切换时,有亮灯延迟的情况,应该是ledinfo赋值的问题。

目前没做一下步检查。

相关推荐
天玑y9 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯
自陈9 小时前
蓝桥杯嵌入式客观题合集
蓝桥杯·蓝桥杯嵌入式客观题
redcocal9 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
辰哥单片机设计12 小时前
门磁模块详解(防盗感应开关 STM32)
stm32·单片机·嵌入式硬件·传感器
夜间去看海12 小时前
基于51单片机的自动清洗系统(自动洗衣机)
嵌入式硬件·51单片机·proteus·洗衣机
yrx02030713 小时前
stm32 IIC总线busy解决方法
stm32·单片机·嵌入式硬件
DANGAOGAO13 小时前
蓝桥杯4. Fizz Buzz 经典问题
算法·蓝桥杯
weixin_4462608514 小时前
24年蓝桥杯及攻防世界赛题-MISC-3
网络安全·蓝桥杯
YHPsophie14 小时前
ATGM331C-5T杭州中科微BDS/GNSS全星座定位授时模块应用领域
经验分享·笔记·单片机·信息与通信·交通物流