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

news2024/12/23 16:04:47

蓝桥杯

小蜜蜂

#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赋值的问题。

目前没做一下步检查。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039970.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

发两张Pop!_OS 24.04-alpha版本截图

发两张Pop!_OS 24.04-alpha版本截图

《Linux运维总结:基于x86_64架构CPU使用docker-compose一键离线部署etcd 3.5.15容器版分布式集群》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:《Linux运维篇:Linux系统运维指南》 一、部署背景 由于业务系统的特殊性,我们需要面对不同的客户部署业务系统&#xff0…

flink文档刨析

flink任务运行方式 flink任务提交方式有3种 session、per-job、application三种 flink任务运行底座也有三种,Standalone、yarn、k8s 原则上一个flink任务运行的方式由3*39种,但是有些是没法搭配的 yarn:包括yarn-session 、yarn-per-job 、…

vue2+OpenLayers 天地图上凸显出当前地理位置区域(4)

凸显出当前区域 需要当前地方的json数据 这个可以在阿里的这个阿里 看下效果图 遮盖层的逃命都是可以调的 引入 下面一段代码 import sx from "/views/json/sx1.json"; // 下载的json import GeoJSON from "ol/format/GeoJSON"; // ol的一些方法 imp…

C++ | Leetcode C++题解之第335题路径交叉

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isSelfCrossing(vector<int>& distance) {int n distance.size();// 处理第 1 种情况int i 0;while (i < n && (i < 2 || distance[i] > distance[i - 2])) {i;}if (i n) {ret…

郊游、旅游管理系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设残哥 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目、 源…

汽车4S店管理系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设残哥 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目、 源…

微信小程序--26(全局配置-1)

一、全局配置文件 1.标志 app.json 2.配置项 pages 记录当前小程序所有页面的存放路径 window 全局配置小程序窗口配置 tabBar 设置小程序底部的tabBar效果 style 是否启用新版本的组将样式 3.window 导航栏区域 navigationBar …

计算机学生高效记录并整理编程学习笔记的方法

哪些知识点需要做笔记&#xff1f; 以下是我认为计算机学生大学四年可以积累的笔记。 ① 编程语言类&#xff08;C语言CJava&#xff09;&#xff1a;保留课堂笔记中可运行的代码部分&#xff0c;课后debug跑一跑。学习语言初期应该多写代码&#xff08;从仿写到自己写&#…

LeetCode - 88 合并两个有序数组(Java JS Python C C++)

题目来源 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使…

解决Tomcat 10启动日志乱码及在IntelliJ IDEA中控制台输出乱码的问题

目录 一.背景: 二.出现乱码的原因: 三.Tomcat解决乱码过程: 四.IDEA解决乱码效果: 五.Tomcat的优点和缺点: 一.背景: 在Tomcat启动起来的时候&#xff0c;界面就会出现很多的繁体字根本不知道是什么意思&#xff0c;相信大家看了也很是头痛。 还有一个是在IDEA控制台出现的…

触摸感应芯片原厂/抗干扰2路2通道触摸/双通道触摸方案VK3602XS SOP8

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VK3602XS 封装形式&#xff1a;SOP8 概述 VK3602XS具有2个触摸按键&#xff0c;可用来检测外部触摸按键上人手的触摸动作。该芯片具有 较高的集成度&#xff0c;仅需极少的外部组件便可实现触摸按键的检测。 提供了2…

进程空间回收和线程

一.进程空间的回收 1.wait pid_t wait(int *status); 功能&#xff1a;该函数可用于阻塞等待任意子进程退出并回收进程的状态 参数&#xff1a;status进程退出时候的状态 如果不关心其退出状态一般用NULL表示 如果要回收进程退出状态&#xff0c;WEXITATUS回收 返回值&…

虚幻5|入门AI行为树,建立敌人

本章分成两块部分一块是第一点的制作一个简单的AI&#xff0c;后面第二点之后是第二部分建立ai行为树。这两个部分是一个衔接&#xff0c;最好不要跳看 一&#xff0c;制作一个简单的AI 1.首先&#xff0c;我们创建一个敌人的角色蓝图&#xff0c;添加一个场景组件widget用于…

django快速实现个人博客(附源码)

文章目录 一、工程目录组织结构二、模型及管理实现1、模型2、admin管理 三、博客展现实现1、视图实现2、模板实现 四、部署及效果五、源代码 Django作为一款成熟的Python Web开发框架提供了丰富的内置功能&#xff0c;如ORM&#xff08;对象关系映射&#xff09;、Admin管理界面…

鸿蒙(API 12 Beta3版)【使用投播组件】案例应用

华为视频接入播控中心和投播能力概述** 华为视频在进入影片详情页播放时&#xff0c;支持在控制中心查看当前播放的视频信息&#xff0c;并进行快进、快退、拖动进度、播放暂停、下一集、调节音量等操作&#xff0c;方便用户通过控制中心来操作当前播放的视频。 当用户希望通…

Immutable-持久化数据结构:助力 React 性能提升

React 更新 state 时为什么要使用 Immutable 语法&#xff1f;Immutable 可持久化数据结构 是什么&#xff1f;如何在 React 项目中使用相关 Immutable 类库&#xff1f; 从 useState 说起 状态更新流程 &#x1f4e2; setState(value) React 内部流程&#xff1a; #mermaid-…

ubuntu下使用docker和socket进行数据交互记录

ubuntu下使用docker和socket进行数据交互记录 概述&#xff1a;主要实现了在宿主机上通过8000端口传递一张图像给docker镜像&#xff0c;然后镜像中处理后&#xff0c;通过8001端口回传处理后的图像给宿主机。 第一章、构建镜像 一、dockerfile文件 1.拉取ubuntu20.04镜像 …

【前端面试】挖掘做过的nextJS项目(下)

https://blog.csdn.net/weixin_43342290/article/details/141170360?spm1001.2014.3001.5501文章浏览阅读105次。需求:快速搭建宣传官网1.适应pc、移动端2.基本的路由跳转3.页面渲染优化4.宣传的图片、视频资源的加载优化5.seo优化全栈react web应用、tailwind css原子工具的支…

Python中的多行字符串和文档字符串

Python中的多行字符串和文档字符串 Python中&#xff0c;多行字符串和文档字符串都使用三引号&#xff08;""" 或 &#xff09;来定义。都可以跨越多行而不需要使用行连接符&#xff08;\&#xff09;。 多行字符串和文档字符串都可以利用转义符来调整格式——…