单元训练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赋值的问题。

目前没做一下步检查。

相关推荐
蓝斯4979 小时前
从.到实现一个Windows上的虚拟hid键盘设备
windows·单片机·计算机外设
熙芯XiChip10 小时前
硬实时与软实时RTOS核心区别
嵌入式硬件
伟大的前程10 小时前
unsigned int 定义的变量 在 电脑的 64 位系统中 和 32 位 cortex-m0 和 8 位的 51 单片机
单片机·嵌入式硬件
小渔村的拉线工10 小时前
1.HPM6E80 解析芯片整体工作原理和存储架构
单片机·嵌入式硬件·mcu·架构·hpm6e80
熙芯XiChip11 小时前
CAN与CANopen的本质区别
单片机
lilihewo11 小时前
Altium Designer 封装库的创建(分享pcb 3D封装库)
嵌入式硬件·51单片机
神罚天下ET12 小时前
典型arm位单片机启动流程(从上电到main.c)
c语言·arm开发·单片机
碧海银沙音频科技研究院13 小时前
蓝牙耳机使用WSDF5361锂保芯片进入船运模式实现方法
嵌入式硬件·算法
Zevalin爱灰灰14 小时前
模拟信号链电路——基于TL431的电压基准电路
单片机·嵌入式硬件
csdn杰哥14 小时前
瑞萨单片机开发教程[二十七] DTC 外部中断触发传输实验
单片机·嵌入式硬件·mongodb·瑞萨·ra6m5