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

目前没做一下步检查。

相关推荐
SDAU20057 小时前
CH32V103C8T6的时钟操作
单片机·嵌入式硬件
不做无法实现的梦~7 小时前
SBUS 接收机到 STM32:为什么要做硬件反相、如何解析数据、如何接线与实现代码
stm32·单片机·嵌入式硬件
一路往蓝-Anbo7 小时前
第二章:隔离硬件 —— 利用 CMock 伪造 GPIO 与定时器
stm32·单片机·嵌入式硬件·软件工程·信息与通信·tdd
刘延林.9 小时前
esp32 s3+micpython快速验证ML307R 是否能正常连接4G
单片机·嵌入式硬件
不做无法实现的梦~14 小时前
86步进电机和DM860H驱动器的使用方法和记录
单片机·嵌入式硬件
Aaron158814 小时前
RFSOC+VU13P/VU9P+GPU多通道同步一体化解决方案
人工智能·嵌入式硬件·算法·matlab·fpga开发·硬件架构·基带工程
所见即所得1111115 小时前
stm32烧录过程中串口问题(串口被占用无法使用)
stm32·单片机·嵌入式硬件
Freak嵌入式15 小时前
WIZnet-EVB-Pico2开始,用MicroPython玩转以太网开发
arm开发·人工智能·python·嵌入式硬件·机器人·嵌入式·micropython
Ligocious15 小时前
stm32---1.两种开发方式点亮LED
stm32·单片机
黑白园15 小时前
STM32F103C8TC使用ST-Link下载
stm32·单片机·嵌入式硬件