蓝桥杯省三保底代码——数显+按键功能实现

目录

前言

一、为什么能保底省三

二、数显模块的实现

1.数码管显示​编辑

1)断码表

2)位选

3)段选

4)扫描

2.菜单

三、按键功能的实现

1.按键扫描

2.菜单切换

四、完整代码演示

五、结语


前言

上一期介绍全家桶时,跟大家提到:比赛时可以做出来按键切换菜单的部分,这样子起码省三就有了。这篇文章就去教大家如何实现省三保底。当然,这些代码只靠背可能不太够,比赛的时候需要根据题目小改一下才行。

一、为什么能保底省三

数显+按键切换菜单完成,基本就可以拿到省三,这个比赛是看你完成度给你“打分”的,数显和按键功能其实已经占了题目不少的一部分了,这里的数显是指:读取不到有效数据,仅能显示一个不会更新的数据。

如果你能灵活使用底层驱动的那几个外设,读取到有效数据,顺便完成一点LED灯,那冲击省二都有可能,如果你又能灵活地对数据进行处理,完成题目对数据处理方面的要求,基本完成赛题上的所有功能,那基本省一就稳了。

当然,这也只是我个人说的哈,但也确实听不少人说“完成数显+按键切换菜单可以拿省三”“基本完成题目要求的功能就能稳省一”,我也绝不是空穴来风。

我去年参加蓝桥杯时,NE555读取部分没有实现,其他功能基本实现,也顺利进入了国赛。

二、数显模块的实现

这里以第十三届比赛题目为例,介绍一下数显和按键部分的实现。

1.数码管显示

这部分都是十分基础的代码,不过毕竟这篇文章就是“保底省三”的代码,这部分还是有必要详细介绍一下的。

1)断码表

首先,比赛时会给你一个断码表,所以断码自己会使用计算机算即可,没必要记,真需要显示某个符号了,就使用计算机算一算,下面是23年给的断码表

code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
}

前边那个“code”,抄的时候删不删都可以,没影响。现在不管是个人的电脑,或者赛点的电脑,上边的计算机都有程序员模式,可以切换单位键盘,帮助完成断码

2)位选

在让数码管显示数据之前,我们先需要位选,何为位选呢?其实就是选择你要显示那个数码挂的数据。下图中圈住的,就是用于控制位选的锁存器。我们只需要把需要传输的数据放到P0里,在使能锁存器,并失能锁存器(说人话就是开关一下锁存器,让他更新一下数据就好),就可以把P0的数据存到锁存器里了。P0需要放到数据就是,我们要控制哪一个数码管,高电平有效。一般情况下我们都是一次控制一个数码管,所以P0当中只有一个数据是1,其他都是0.

比如P0=0000 0001就是控制第0个数码管(或者说最左边那个),P0=0000 0010就是控制第一个数码管。P0=0000 1111就是同时控制数码管,给P0赋值之后,开关一次锁存器,就可以选中我们要控制的数码管了,接下来的段选,只影响当前被选中的锁存器。

刚才提到开关锁存器,也就是使能和失能锁存器,锁存器的控制端连在了Y6C,高电平有效,我们只需要给Y6C高电平,在给低电平即可完成开关锁存器。

Y6C连接在一个三线八线译码器上如下图(右边的东西这里不过多介绍)

P27,P26,P25是3线输出,Y0到Y7是7线输出。下边P27,P26,P25简称输入:

如果输入000,则选中Y0;如果输入110,也就是二进制的6,则选择Y6,经过有右边的与非门之后,就可以选中Y6C,打开刚才位选的锁存器。

因此,我们只需要给P2的高三位为110就可以打开位选,给高三位000就可以关闭位选。我们可以定义一个宏定义,来实现位选

#define NIXIE_CHECK()    P2|=0xC0;P2&=0xDF;P2&=0x1F;

3)段选

段选与上述位选类似,就是把数码管需要显示的数据放在P0然后再开关一次锁存器即可。也就是下图中左上角的锁存器。P0放的数据,就是我们最开始提到的断码数据。

我们同样使用一个宏定义来完成段选

#define NIXIE_ON()        P2|=0xE0;P2&=0xFF;P2&=0x1F;

4)扫描

为了让数码管显示不同的数据,我们一般是一次性控制一个数码管,如果我们想让八个数码管同时显示不同的数据,就需要扫描。扫描通俗点说就是先控制第一个数码管显示数据,趁着第一个还没熄灭就再去控制第二个数码管显示数据,在控制第三个......完成一轮之后再控制第一个,已知循环下去。

由于它对于时间有要求,所以我们需要把它放在定时器完成扫描。使用location记录当前扫描到第几个数码管了,使用Nixie_num数组记录八个数码管各自需要显示的数据,定时器时间为1ms。

中断服务函如下:

void Timer0_Isr(void) interrupt 1
{
    P0=0x01<<location;NIXIE_CHECK();
    P0=Seg_Table[Nixie_num[location]];NIXIE_ON();
    
    if(++location==8)
        location=0;
}

我们只需在main或者菜单显示函数中给Nixie_num数组对应位置赋值,即可让他显示不同的数据

2.菜单

我们定义一个标志位mod,当mod=0时显示第一个菜单,mod=1时显示第二个菜单以此类推。

这里我们手动添加一个断码表,使之可以显示U和“-”,以及对应的带小数点的数字。

我们注意到题目要求数显部分(第二章开头有介绍),第一位数码管显示的都是U,第二位是当前是第几个菜单,所以我们把这连个单独写出来。注意不需要显示的位需要熄灭,避免切换菜单时不这个菜单不显示的位被异常点亮。

这样我们就可以通过改变mod的值,来显示不同的菜单了

void show_menu(void)
{
    Nixie_num[0]=21;//显示U
    Nixie_num[1]=mod+1;//显示菜单数
    if(mod==0)
    {
        Nixie_num[2]=20;//熄灭
        Nixie_num[3]=20;//熄灭
        Nixie_num[4]=20;//熄灭
        Nixie_num[5]=2;//显示2
        Nixie_num[6]=3+10;//显示3.
        Nixie_num[7]=5;//显示5
    }
    else if(mod==1)
    {
        Nixie_num[2]=20;
        Nixie_num[3]=2;
        Nixie_num[4]=3;
        Nixie_num[5]=22;
        Nixie_num[6]=2;
        Nixie_num[7]=3;
    }
    else if(mod==2)
    {
        Nixie_num[2]=20;
        Nixie_num[3]=20;
        Nixie_num[4]=20;
        Nixie_num[5]=20;
        Nixie_num[6]=2;
        Nixie_num[7]=3;
    }
}

三、按键功能的实现

按键功能要求,以第十三届为例。这里仅完成“切换”按键

1.按键扫描

相信大家单片机入手的第二堂课就是按键(第一堂课应该是点亮LED),这里按键扫描就不过多介绍了,这里放一个我自己用的矩阵按键扫描代码

void get_key(void)
{
    unsigned char key_P3=P3;
    unsigned char key_P4=P4;
    
    P3=0xFF;
    
    P44=0;
    if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=7;}
    else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=6;}
    else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=5;}
    else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=4;}
        
    P42=0;
    if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=11;}
    else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=10;}
    else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=9;}
    else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=8;}
        
    P35=0;
    if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=15;}
    else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=14;}
    else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=13;}
    else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=12;}
        
    P34=0;
    if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=19;}
    else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=18;}
    else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=17;}
    else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=16;}
    
    key_value=0;
    P3=key_P3;
    P4=key_P4;
}

函数末尾把key_value又置为了0,是因为后续所有按键处理都要在按键扫描函数里完成,如果你是刚写完按键扫描,想测试一下的话,可以吧key_value=0给删掉,在main里使用数码管显示key_value的值。

2.菜单切换

简单点说,如果按下了S12,就把菜单从1切换到2或者从2切换到3或者从3切换到1。我们只需要把下面的代码放到上述key_value=0之前即可

    if(key_value==12)
    {
        if(mod==0)
            mod=1;
        else if(mod==1)
            mod=2;
        else if(mod==2)
            mod=0;
    }

可能会有人说,我这样写真的好LOW,不过我感觉,我只是为了应对这个比赛才写这样的代码的,这样写纯属是为了少犯错误,容易修改,仅此而已。你当然也可以把代码写的很华丽,包括阿刚才show_menu函数里的代码,只要能达到预期效果就行。

这里仅仅实现了按键切换菜单,有的按键还有切换参数的功能,需要把数码管显示的数据改为对应的参数,在通过按键对参数进行加减,这里不再介绍。

四、完整代码演示

main.c

#include <stc15.h>
#include <intrins.h>
#include "onewire.h"
#include "ds1302.h"code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
//0.到9.
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,
0xFF,//20 熄灭
0xC1,//21 U
0xBF//22 -
};#define NIXIE_CHECK()	P2|=0xC0;P2&=0xDF;P2&=0x1F;
#define NIXIE_ON()		P2|=0xE0;P2&=0xFF;P2&=0x1F;unsigned char Nixie_num[]={20,20,20,20,20,20,20,20};
void Timer0_Init(void);		//1毫秒@12.000MHz
void Delay100ms(void);	//@12.000MHz
void get_key(void);
void show_menu(void);unsigned char location=0;
unsigned char key_value=0;
unsigned char mod=0;void main()
{Timer0_Init();EA=1;while(1){get_key();Delay100ms();}
}
void Timer0_Isr(void) interrupt 1
{P0=0x01<<location;NIXIE_CHECK();P0=Seg_Table[Nixie_num[location]];NIXIE_ON();if(++location==8)location=0;
}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中断
}void Delay100ms(void)	//@12.000MHz
{unsigned char data i, j, k;_nop_();_nop_();i = 5;j = 144;k = 71;do{do{while (--k);} while (--j);} while (--i);
}
void Delay5ms(void)	//@12.000MHz
{unsigned char data i, j;i = 59;j = 90;do{while (--j);} while (--i);
}
void get_key(void)
{unsigned char key_P3=P3;unsigned char key_P4=P4;P3=0xFF;P44=0;if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=7;}else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=6;}else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=5;}else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=4;}P42=0;if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=11;}else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=10;}else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=9;}else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=8;}P35=0;if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=15;}else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=14;}else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=13;}else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=12;}P34=0;if(P30==0){Delay5ms();while(P30==0);Delay5ms();key_value=19;}else if(P31==0){Delay5ms();while(P31==0);Delay5ms();key_value=18;}else if(P32==0){Delay5ms();while(P32==0);Delay5ms();key_value=17;}else if(P33==0){Delay5ms();while(P33==0);Delay5ms();key_value=16;}//S12if(key_value==12){if(mod==0)mod=1;else if(mod==1)mod=2;else if(mod==2)mod=0;}key_value=0;P3=key_P3;P4=key_P4;
}
void show_menu(void)
{Nixie_num[0]=21;//显示UNixie_num[1]=mod+1;//显示菜单数if(mod==0){Nixie_num[2]=20;//熄灭Nixie_num[3]=20;//熄灭Nixie_num[4]=20;//熄灭Nixie_num[5]=2;//显示2Nixie_num[6]=3+10;//显示3.Nixie_num[7]=5;//显示5}else if(mod==1){Nixie_num[2]=20;Nixie_num[3]=2;Nixie_num[4]=3;Nixie_num[5]=22;Nixie_num[6]=2;Nixie_num[7]=3;}else if(mod==2){Nixie_num[2]=20;Nixie_num[3]=20;Nixie_num[4]=20;Nixie_num[5]=20;Nixie_num[6]=2;Nixie_num[7]=3;}
}

五、结语

不同人写代码的风格不一样,我只是分享了我写的一套省三代码。如果你自己之前有跟其他人学过,现在不妨把代码整理整理,至少做到连续两次,可以写出一模一样的代码,这样可以减少比赛时犯错误。

最后,希望没有准备充分的同学不要放弃,现在冲一冲那个省二省三也不是问题,提前预祝冲击省一的同学,国赛再见!

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

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

相关文章

【书生·浦语大模型实战营第二期】学习笔记1

1. Introduction 开源llm举例&#xff1a;LLaMA 、Qwen 、Mistral 和Deepseek 大型语言模型的发展包括预训练、监督微调&#xff08;SFT&#xff09;和基于人类反馈的强化学习&#xff08;RLHF&#xff09;等主要阶段 InternLM2的显著特点 采用分组查询注意力&#xff08;GQA…

IP组播基础

原理概述 IANA ( Internet Assigned Numbers Authority &#xff09;将 IP 地址分成了 A 、 B 、 C 、 D 、 E5类&#xff0c;其中的 D 类为组播 IP 地址&#xff0c;范围是224.0.0.0~239.255.255.255。 一个 IP 报文&#xff0c;其目的地址如果是单播 IP 地址&#xff…

螺旋矩阵的算法刷题

螺旋矩阵的算法刷题 本文主要涉及螺旋矩阵的算法 包括三个题目分别是 59. 螺旋矩阵 II54. 螺旋矩阵 中等LCR 146. 螺旋遍历二维数组 文章目录 螺旋矩阵的算法刷题一 、螺旋矩阵简单1.1 实现一&#xff08;我认为这个方法更巧妙&#xff01;&#xff01;&#xff09;1.2 实现二&…

短视频矩阵系统--技术3年源头迭代

短视频矩阵系统核心技术算法主要包括以下几个方面&#xff1a; 1. 视频剪辑&#xff1a;通过剪辑工具或API从各大短视频平台抓取符合要求的视频。这些视频通常符合某些特定条件&#xff0c;如特定关键词、特定时间段发布的视频、视频点赞评论转发等数据表现良好的视频。 2. 视…

2024年【熔化焊接与热切割】报名考试及熔化焊接与热切割模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 熔化焊接与热切割报名考试考前必练&#xff01;安全生产模拟考试一点通每个月更新熔化焊接与热切割模拟试题题目及答案&#xff01;多做几遍&#xff0c;其实通过熔化焊接与热切割作业考试题库很简单。 1、【单选题】…

基于随机森林与LSTM神经网络的住宅用电比较分析及预测 代码+论文 完整毕设

摘要 本文旨在探讨基于随机森林&#xff08;Random Forest&#xff09;与长短期记忆神经网络&#xff08;Long Short-Term Memory, LSTM&#xff09;的住宅用电比较分析及预测方法。随机森林是一种集成学习方法&#xff0c;通过构建多个决策树进行预测&#xff0c;具有较强的鲁…

[疑难杂症2024-002]一个“显而易见“的问题,是如何进入生产环境的?

本文由Markdown语法编辑器编辑完成。 1. 前言 最近在处理一个在医院上线的系统的问题。这个问题&#xff0c;由于关联的模块比较多&#xff0c;至少涉及到3个模块之间的功能调用。因此&#xff0c;协调大家都有时间来排查问题不是很方便。这个问题就拖了有一周左右。医院那边…

钡铼技术R40路由器助力智能船舶航行数据实时传输与分析

钡铼技术R40路由器在智能船舶领域的应用&#xff0c;对于航行数据的实时传输与分析具有重要意义。随着航运业的不断发展和智能化水平的提升&#xff0c;船舶航行数据的及时传输和有效分析对船舶的安全、运营效率等方面至关重要。而引入钡铼技术R40路由器&#xff0c;则可以实现…

libVLC 捕获鼠标、键盘事件

在实现播放器的时候&#xff0c;我们需要捕获键盘、鼠标事件进行视频快进、快退&#xff0c;或者双击全屏/退出全屏窗口、鼠标右键弹出菜单栏。默认情况下&#xff0c;在使用libVLC库的时候&#xff0c;我们无法捕获这些事件&#xff0c;因为我们将Qt的视频窗口传递给了libVLC。…

工厂数据分析系统用这个开源库准没错

ScottPlot是一款简单易用、高度定制、性能卓越的.NET绘图库&#xff0c;支持跨平台操作。除提供标准图表类型外&#xff0c;还支持交互式操作&#xff0c;呈现生动的数据展示。在工厂数字化系统中&#xff0c;可用于生产数据可视化、设备监测和质量控制。无论用于科学研究、数据…

Springboot基础之——自定义starter

引言 在实际开发中&#xff0c;经常会定义一些公共的组件&#xff0c;提供给各个项目团队使用。而在SpringBoot项目中&#xff0c;一般会将这些公共组件封装成SpringBoot的starter。 如果想要自定义starter的话&#xff0c;就要先了解自动配置原理。 1 自动配置原理 1.1 什…

地物波谱库共享网站汇总

ENVI自5.2版本重新梳理了原有的标准波谱库&#xff0c;新增一些物质波谱&#xff0c;在ENVI5.6中存放在…\Harris\ENVI56\ resource\speclib&#xff0c;分别存放在四个文件夹中&#xff0c;储存为ENVI波谱库格式&#xff0c;有两个文件组成&#xff1a;.sli和.hdr。 ENVI保留…

代码随想录——搜索插入位置(Leetcode35)

题目链接 class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;int left 0;int right len - 1;int index -1;while(left < len / 2){if(nums[left] target || target < nums[left]){index left;break;}else{left;}if(nums[ri…

通过Caliper进行压力测试程序,且汇总压力测试问题解决

环境要求 第一步. 配置基本环境 部署Caliper的计算机需要有外网权限;操作系统版本需要满足以下要求:Ubuntu >= 16.04、CentOS >= 7或MacOS >= 10.14;部署Caliper的计算机需要安装有以下软件:python 2.7、make、g++(gcc-c++)、gcc及git。第二步. 安装NodeJS # …

高效 CUDA 调试:将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具

高效 CUDA 调试&#xff1a;将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具 NVIDIA Compute Sanitizer 是一款功能强大的工具&#xff0c;可以节省您的时间和精力&#xff0c;同时提高 CUDA 应用程序的可靠性和性能。 在 CUDA 环境中调试代码既具有挑…

超详细的fiddler教程

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Fiddler&#xff08;中文名称&#xff1a;小提琴&#xff09;是…

【算法题】三道题理解算法思想--滑动窗口篇

滑动窗口 本篇文章中会带大家从零基础到学会利用滑动窗口的思想解决算法题&#xff0c;我从力扣上筛选了三道题&#xff0c;难度由浅到深&#xff0c;会附上题目链接以及算法原理和解题代码&#xff0c;希望大家能坚持看完&#xff0c;绝对能有收获&#xff0c;大家有更好的思…

win11 安装SIBR 3dgs

1.安装显卡驱动 下载地址&#xff1a; 官方驱动 | NVIDIA下载适用于 GeForce、TITAN、NVIDIA RTX、数据中心、GRID 等 NVIDIA 产品的新驱动。https://www.nvidia.cn/Download/index.aspx?langcn 2.安装cuda 下载地址&#xff1a;如果无法打开&#xff0c;切换.com为.cn&am…

JavaScript基础练习题之计算数组元素的和与平均值

一、如何使用JavaScript计算数组元素的和与平均值&#xff1f; 二、正确的源程序 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>计算数组元素的和与平均值</title></head><body><h1>计算数组元…