蓝桥杯模块学习5——按键

news2024/10/7 8:28:08

第一章 硬件部分

1.1 电路的组成部分

1.1.1 按键电路

  1. 原理图:
    在这里插入图片描述

  2. 功能:

     (1) J5:当1和2相接,电路就变成一个4*4的矩阵键盘电路;当2和3相接时,电路变成了一个S4-S7的独立按键
     (2)对于独立按键的分析:https://blog.csdn.net/weixin_63568691/article/details/128374461
     (3)如果学过矩阵的人应该都知道,矩阵中的位置是由行列标号决定,所以我们确定按下按键的行列就能确定按下哪个按键,这时候我们就要用到按键扫描
     (4)按键扫描:我们的思路是,按键是连接行和列的桥梁,如果往某行或者某列输入低电平,其他行或列为高电平,我们只需要检测所有列或者行是否有低电平即可。
    

第二章 具体实验

2.1 实验一:独立按键

  按下S7-S4分别点亮L1-L4,同时要求松手熄灭和消抖

2.2 无操作系统代码

注:一开始接触可以就写这个代码,过省赛应该是没问题的

2.1.1 按照以上思路写的代码

// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "STC15F2K60S2.H" 

#define u8 unsigned char
#define u16 unsigned int
void Close_All(void)
{
	//关闭蜂鸣器和继电器
	P0 = 0x00;
	P2 = (P2 & 0x1f) | 0xA0;
	P2 &= 0x1f;
	//关闭LED灯
	P0 = 0xff;
	P2 = (P2 & 0x1F) | 0x80;
	P2 &= 0x1f;	
}
u8 key_old,key_1ms = 1;
void LED_ON(u8 L_X);
void Key_Proc();
void Timer_0_Init(u16 time);
// 主函数
void main(void)
{
	Close_All();
	Timer_0_Init(1000);//1ms
  while(1)
  { 
		Key_Proc();
  }
}
/*****************LED*******************/
/*
	输入变量:P0口的对应的16进制数
	输出变量:无
	功能:选择相应的锁存器后,通过P0口控制LED灯亮
*/
void LED_ON(u8 L_X)
{
	P0 = L_X;
	P2 = (P2 & 0x1f) | 0x80;
	P2 &= 0x1f;
}

/*****************按键*******************/

/*
	输入变量:无
	输出变量:7-4代表第几个按键被按下;0代表没有按键按下
	功能:检测哪个独立按键被按下
	注意:只有消抖,没有松手检测
*/
u8 Key_read()
{
	u8 i;
	for(i=0;i<4;i++)
	{
			if(!(P3 & (0x01<<i)))
			{
				return 7-i;
			}
	}
	return 0;
}

void Key_Proc()
{
	u8 key_now,key_down,key_up;
	//消抖,同时节省CPU资源
	if(key_1ms < 20) return;
	key_1ms = 1;
   //读取按键按下的编号
	key_now = Key_read();
	//按键按下:通过判断按键状态是否发生变化,并且变化后状态是否为按下
	key_down = key_now & (key_old ^ key_now);
  //按键抬起
	key_up = ~key_now & (key_old ^ key_now);
	//记录当前状态为下一次检测做准备
	key_old = key_now;
	if(key_down)//按键按下
		LED_ON(~(0x01<<(7-key_now)));
	else if(key_up)//按键抬起
		LED_ON(0xff); 
}


/**************定时器**************************/

/*
	输入变量:定时时长___us
	输出变量:无
	功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
	//12T模式
	AUXR &= 0x7f;
	//定时器0 模式0
	TMOD &= 0xf0;
	//设置初值
	TH0 = (65536-time)/256;
	TL0 = (65536-time)%256;
	//打开中断
	ET0 = 1;
	EA = 1;
	//开始计数
	TR0 = 1;
}

void Timer_0_IT(void) interrupt 1
{
	key_1ms++;
}

2.3 RTX51代码

国赛必备,优点是可以在延时的时候畅通无阻的执行其他东西

#include <rtx51tny.h>
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int	

u8 l_data;
void All_Close();
void LED_Show(u8 l_data);
void Key_Proc();
void Startup() _task_ 0
{
	All_Close();
	os_create_task(1);
	os_create_task(2);
	os_delete_task(0);
}

void Key_Task() _task_ 1
{
	while(1)
	{
		os_wait2(K_IVL,19);
		Key_Proc();
	}
}

void LED_Task() _task_ 2
{
	while(1)
	{
		os_wait1(K_SIG);
		LED_Show(l_data);
	}
}
/******************************/

//选择锁存器,输出数据
void Select(u8 cs,u8 s_data)
{
	P0 = s_data;
	P2 = P2 & 0x0f | (cs<<5);
	P2 &= 0x0f;
}

//关闭外设
void All_Close()
{
	//关闭蜂鸣器
	Select(5,0x00);
	//关闭LED
	Select(4,0xff);	
	//关闭数码管
	Select(7,0xff);		
}

//输入8位数据,亮灯,1为亮
void LED_Show(u8 l_data)
{
	Select(4,~l_data);
}

//独立按键按键检测
u8 D_Key()
{
	u8 i=0;
	for(i=0;i<4;i++)
		if((P3 & (0x08>>i)) == 0)
			return i+4;
	return 0;
}

void Key_Proc()
{
	static u8 key_old=0;
	u8 key_now=0,key_down=0,key_up;
	key_now = D_Key();
	key_down = key_now & (key_now ^ key_old);
	key_up = ~key_now & (key_now ^ key_old);
	key_old = key_now;
	
	if(key_down)
	{
		l_data = 0x01<<(key_down-4);
		os_send_signal(2);
	}
	else if(key_up)
	{
		l_data ^= (0x01<<(key_up-4));
		os_send_signal(2);		
	}
}

2.1 实验二:矩阵按键

  用16个按键控制数码管第一个显示0-F

2.2 无操作系统代码

注:一开始接触可以就写这个代码,过省赛应该是没问题的

2.1.1 按照以上思路写的代码

// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "stdio.h"
#include "STC15F2K60S2.H" 
#define u8 unsigned char
#define u16 unsigned int
	
u8 SEG_COT[9];
u8 SEG_Code[8];
u8 temp1;
u8 key_old,SEG_POS,key_delay,seg_delay;

/*
	输入变量:无
	输出变量:无
	功能:关闭蜂鸣器和继电器
*/
void Close_All(void)
{
	//关闭蜂鸣器和继电器
	P0 = 0x00;
	P2 = (P2 & 0x1f) | 0xA0;
	P2 &= 0x1f;
	//关闭LED灯
	P0 = 0xff;
	P2 = (P2 & 0x1F) | 0x80;
	P2 &= 0x1f;	
}


void Key_Proc();
void Timer_0_Init(u16 time);
void SEG_TSL(u8 *input,u8 *output);
void SEG_Proc();
// 主函数
void main(void)
{
	Close_All();	
	Timer_0_Init(1000);//1ms
	
  while(1)
  { 
		Key_Proc();
		SEG_Proc();
  }
}

/********************数码管********************************/

/*
  输入变量:input,输入字符数组;output:输出16进制数数组
	输出变量:无
	功能:将字符串转化为对应数码管显示的16进制数
*/
void SEG_TSL(u8 *input,u8 *output)
{
	//j一定要赋值
	u8 i=0,temp=0,j=0;
	for(i=0;i<8;i++,j++)
	{
		switch(input[j])
		{
			case '0': temp = 0xc0; break;
      case '1': temp = 0xf9; break;
      case '2': temp = 0xa4; break;
      case '3': temp = 0xb0; break;
      case '4': temp = 0x99; break;
      case '5': temp = 0x92; break;
      case '6': temp = 0x82; break;
      case '7': temp = 0xf8; break;
      case '8': temp = 0x80; break;
      case '9': temp = 0x90; break;
      case 'A': temp = 0x88; break;
      case 'B': temp = 0x83; break;
      case 'C': temp = 0xc6; break;
      case 'D': temp = 0xA1; break;
      case 'E': temp = 0x86; break;
      case 'F': temp = 0x8E; break;
      case 'H': temp = 0x89; break;
      case 'L': temp = 0xC7; break;
      case 'N': temp = 0xC8; break;
      case 'P': temp = 0x8c; break;
      case 'U': temp = 0xC1; break;
      case '-': temp = 0xbf; break;
      case ' ': temp = 0xff; break;
      default: temp = 0xff;
		}
		if(input[j+1] == ".")
		{
			temp &= 0x7f;
			j++;
		}
		output[i] = temp;
	}
}

/*
	输入变量:num,要显示数据;PIS,显示位置,从左到右分别为0-7
	输出变量:无
	功能:操作138译码器,4-7分别对应Y4-Y7,其余都会使译码器不起作用
	注意:需要把存放从1-f对应的16进制数数组也移植
*/
void SEG_Show(u16 num,u16 PIS)
{
		//消影
  	P0 = 0xff;
		P2 = (P2 & 0x1f) | 0xE0;
    P2 &= 0x1f;
		//改变显示位置
  	P0 = 0x01<<PIS;
		P2 = (P2 & 0x1f) | 0xC0;
	  P2 &= 0x1f;
		//改变数据
  	P0 = num;
		P2 = (P2 & 0x1f) | 0xE0;
    P2 &= 0x1f;
}

void SEG_Proc()
{
	if(seg_delay) return;
	seg_delay = 1;
	sprintf(SEG_COT, "%02u",(u16)temp1);
	SEG_TSL(SEG_COT,SEG_Code);
}
/*****************按键*******************/
/*
	输入变量:无
	输出变量:检测到的按键,如果返回0代表没有检测到任何按键按下
	功能:矩阵键盘按键检测
*/
u8 M_Buttun()
{
	u16 temp = 0;
	u8 i = 0;
	u16 sign = 0x8000;
	//往每行中输入低电平
	//L1:P44 L2:P42 L1:P44 L3:P35  L4:P34
	P44=0;P42=1;P35=1;P34=1;//第一列
	temp = temp | (P3&0x0f);//只保存低四位数据
	P44=1;P42=0;P35=1;P34=1;//第二列
	temp = temp<<4 | (P3&0x0f);//只保存低四位数据
	P44=1;P42=1;P35=0;P34=1;//第三列
	temp = temp<<4 | (P3&0x0f);//只保存低四位数据
	P44=1;P42=1;P35=1;P34=0;//第四列
	temp = temp<<4 | (P3&0x0f);//只保存低四位数据
	for(i=0;i<16;i++)
	{
		if((~temp) & (sign>>i))//从最高位检测到最低位
			return i+4;
	}
	return 0;
}
void Key_Proc()
{
	u8 key_now,key_down,key_up;
	//延时一段时间消抖,同时节省CPU资源
	if(key_delay) return;
	key_delay = 1;
   //读取按键按下的编号
	key_now = M_Buttun();
	//按键按下:通过判断按键状态是否发生变化,并且变化后状态是否为按下
	key_down = key_now & (key_old ^ key_now);
  //按键抬起
	key_up = ~key_now & (key_old ^ key_now);
	//记录当前状态为下一次检测做准备
	key_old = key_now;
	if(key_down)//按键按下
	{                         
		temp1 = key_now;
	}
}


/**************定时器**************************/

/*
	输入变量:定时时长___us
	输出变量:无
	功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
	//12T模式
	AUXR &= 0x7f;
	//定时器0 模式0
	TMOD &= 0xf0;
	//设置初值
	TH0 = (65536-time)/256;
	TL0 = (65536-time)%256;
	//打开中断
	ET0 = 1;
	EA = 1;
	//开始计数
	TR0 = 1;
}

void Timer_0_IT(void) interrupt 1
{
	//按键10ms检测一次
	if(++key_delay == 10) key_delay = 0;
	//数码管500ms检测一次
	if(++seg_delay == 500) seg_delay = 0;
	
	SEG_Show(SEG_Code[SEG_POS],SEG_POS);
	if(++SEG_POS == 8)SEG_POS = 0;
}

2.3 RTX51代码

国赛必备,优点是可以在延时的时候畅通无阻的执行其他东西

#include <rtx51tny.h>
#include <STC15F2K60S2.H>
#include <stdio.H>
#define u8 unsigned char
#define u16 unsigned int	

u8 COD[8],COT[9],PSI;
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
};

void All_Close();
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 COD,u8 PSI);
void Startup() _task_ 0
{
	All_Close();
	os_create_task(1);
	os_create_task(2);
	os_delete_task(0);
}

void Key_Proc();
void Key_Task() _task_ 1
{
	while(1)
	{
		os_wait2(K_IVL,19);
		Key_Proc();
	}
}

void SEG_Task() _task_ 2
{
	while(1)
	{
		SEG_Show(COD[PSI],PSI);
		if(++PSI == 8)PSI = 0;
		os_wait2(K_IVL,2);
	}
}
/******************************/

//选择锁存器,输出数据
void Select(u8 cs,u8 s_data)
{
	P0 = s_data;
	P2 = P2 & 0x0f | (cs<<5);
	P2 &= 0x0f;
}

//关闭外设
void All_Close()
{
	//关闭蜂鸣器
	Select(5,0x00);
	//关闭LED
	Select(4,0xff);	
	//关闭数码管
	Select(7,0xff);		
}

//矩阵按键按键检测
u8 M_Key()
{
	u8 i=0;
	u16 key_temp=0;

	//置零检测
	P44=0;P42=1;P35=1;P34=1;
	key_temp = P3 & 0x0f;	
	P44=1;P42=0;P35=1;P34=1;
	key_temp = (key_temp<<4) | (P3 & 0x0f);		
	P44=1;P42=1;P35=0;P34=1;
	key_temp = (key_temp<<4) | (P3 & 0x0f);		
	P44=1;P42=1;P35=1;P34=0;
	key_temp = (key_temp<<4) | (P3 & 0x0f);			
	
	for(i=0;i<16;i++)
		if((key_temp & (0x8000>>i)) == 0)
			return i+4;
	return 0;	
}
void Key_Proc()
{
	u8 key_now,key_down;
	static u8 key_old;
	
	key_now  = M_Key();
	key_down = key_now & (key_now ^ key_old);
	key_old = key_now;
	
	if(key_down)
	{
		sprintf(COT,"%02u",(u16)key_down);
		SEG_TSL(COT,COD);		
	}
		
}

//输入字符串,输出数码管段码
void SEG_TSL(u8 *input,u8 *output)
{
	u8 i=0;
	for(i=0;i<8;i++)
	{
		switch(input[i])
		{
			case '0':output[i] = Seg_Table[0];break;
			case '1':output[i] = Seg_Table[1];break;
			case '2':output[i] = Seg_Table[2];break;
			case '3':output[i] = Seg_Table[3];break;
			case '4':output[i] = Seg_Table[4];break;
			case '5':output[i] = Seg_Table[5];break;
			case '6':output[i] = Seg_Table[6];break;
			case '7':output[i] = Seg_Table[7];break;
			case '8':output[i] = Seg_Table[8];break;
			case '9':output[i] = Seg_Table[9];break;
			case '-':output[i] = ~0x40;break;
			default:output[i] = 0xff;
		}
	}
}
void SEG_Show(u8 COD,u8 PSI)
{
	//消隐
	Select(7,0xff);	
	//位选
	Select(6,0x01<<PSI);	
	//段选
	Select(7,COD);		
}

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

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

相关文章

平板触控笔要原装的吗?苹果平替笔性价比高的推荐

与苹果的电容笔不同&#xff0c;市场上的电容笔只会给人一种倾斜的压感&#xff0c;并不会像苹果的电容笔那样&#xff0c;可以给人一种重力的压感。不过&#xff0c;如果你不一定要画画&#xff0c;那你就不用花很多钱去买一支苹果的原装电容笔了&#xff0c;只需一支平替电容…

ss命令使用详解

ss是Socket Statistics的缩写。顾名思义&#xff0c;ss命令可以用来获取socket统计信息&#xff0c;它可以显示和netstat类似的内容。ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息&#xff0c;而且比netstat更快速更高效。 当服务器的socket连接数量变得非常大…

从小白到专家:如何在营销中利用 AI 的力量

欢迎来到营销的未来&#xff0c;时至今日人工智能和人类专业知识以前所未有的方式结合在一起。 认识ChatGPT&#xff0c;这是改变游戏规则的革命性工具。 借助ChatGPT&#xff0c;你最终将能够利用AI的力量做出明智的、数据驱动的决策来满足你的受众需求。 但ChatGPT不仅仅是…

[高光谱]高光谱数据的获取与展示

一、环境准备 需要安装spectral包&#xff0c;这个包专门用于高光谱数据展示。 pip install spectral 二、数据加载 要预先准备原始高光谱的.mat数据和分类数据gt.mat(ground-turth)&#xff1b;然后使用scipy.io中的loadmat(.)将其读入程序。 from scipy.io import loadmat…

JCJC句子改写在线工具上线-202305

JCJC句子改写在线工具上线-202305 字根科技发布了新版JCJC在线句子改写功能。 使用网址&#xff1a; JCJC在线句子改写 新版的在线中文句子改写一共分为三种模式&#xff1a; 严谨模式普通模式休闲模式 上述三种改写模式适用于不同的改写需求&#xff0c;界面展示如下&…

springboot读取和写入csv文件数据

前言 csv格式的表格&#xff0c;和xls以及xlsx格式的表格有一些不同&#xff0c;不能够直接用处理xls的方式处理csv&#xff1b; 以下我将介绍如何读取并写入csv数据 准备工作 要处理csv格式的表格数据&#xff0c;我们首先需要引入pom.xml的依赖 <dependency><art…

Linux如何实现动态IP

Linux系统可以通过DHCP&#xff08;动态主机配置协议&#xff09;来实现动态IP。DHCP是一种自动分配IP地址的协议&#xff0c;它可以自动为网络中的设备分配IP地址、子网掩码、网关等网络参数&#xff0c;从而实现动态IP。 在Linux系统中&#xff0c;可以使用DHCP客户端工具来…

分享个常用的跨境电商数据分析平台

在跨境电商人眼中&#xff0c;适合用在跨境电商数据分析上的大数据分析平台该是怎样的&#xff1f;是效率高、财务指标计算快、业务能随时自助分析&#xff0c;最好是能将平台自身的分析经验分享给跨境电商企业&#xff0c;为企业提供更专业的服务。这样的大数据分析平台虽然少…

【Prometheus】实战Prometheus部署

目录 架构安装部署Exporters 架构 Prometheus的基本原理是通过HTTP周期性抓取被监控组件的状态&#xff0c;任意组件只要提供对应的HTTP接口并符合Prometheus定义的数据格式&#xff0c;就可以介入Prometheus监控 Prometheus Server负载定时在目标上抓取metrics(指标)数据&…

chatgpt-最常报错Access denied

一、问题 Access denied 的原因基本都是由于 IP 地址&#xff0c;例如我们用国内网络直接访问 ChatGPT 官网就会报错 Access denied&#xff08;访问被拒绝&#xff09;&#xff0c;Error reference number 1020&#xff08;错误参考编号&#xff1a;1020&#xff09; 二、原因…

Nginx(一)---Nginx下载及安装

一.初识Nginx Nginx 是一个功能强大的 Web 服务器和反向代理服务器。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力确实在同类型的网页服务器中表现较好&#xff0c;中国大陆使用nginx网站用户有&#xff1a;百度、京东、新浪、网易、腾讯、淘宝…

在Windows中如何使用工具恢复已删除的文件?

​当你的电脑遇到任何类型的数据丢失问题时&#xff0c;傲梅恢复之星都会帮助你。你可以在Windows 11/10/8/7中快速轻松的从HDD/SSD恢复丢失或删除的数据。 傲梅恢复之星功能 易于使用&#xff1a;你可以通过3个简单易行的步骤轻松恢复丢失的数据。 适合多种数据丢失情况&a…

787. K 站中转内最便宜的航班

有 n 个城市通过一些航班连接。给你一个数组 flights &#xff0c;其中 flights[i] [fromi, toi, pricei] &#xff0c;表示该航班都从城市 fromi 开始&#xff0c;以价格 pricei 抵达 toi。 现在给定所有的城市和航班&#xff0c;以及出发城市 src 和目的地 dst&#xff0c;…

LPP 和 Kernel LPP

无监督度量学习的降维讲义:LPP Lecture notes in dimensionality reduction for unsupervised metric learning: LPPLECTURE 6: LOCALITY PRESERVING PROJECTIONS AND KERNEL LPP A. Kernel LPP Lecture notes in dimensionality reduction for unsupervised metric learning: …

DHCP数据包分析

目录 1、DHCP 2、DHCP报文种类 3、DHCP工作原理 4、DHCP报文格式 1、DHCP DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;&#xff0c;前身是BOOTP协议&#xff0c;是一个局域网的网络协议&#xff0c;使用UDP协议工作&am…

国产手机无奈放弃芯片研发,关键还是芯片制造,前路在何方?

OPPO放弃芯片研发&#xff0c;影响仍然在继续&#xff0c;这引发了各方对国产芯片发展方向的思考&#xff0c;那么如果不是OPPO&#xff0c;其他国产芯片企业又能突破困境么&#xff1f;其实关键还是在芯片制造。 国内最强大的芯片企业&#xff0c;由于众所周知的原因&#xff…

ChatGPT联网后几大功能

这周ChatGPT plus 已经可以联网了&#xff0c;联网后对我们的用处更大了&#xff0c;这里总结了几点ChatGPT联网 后的几个功能&#xff1a; 1.对给定的网页进行读取&#xff0c;并根据解读后来回答问题 给ChatGPT一个网址&#xff0c;让他总结一下这个网址&#xff0c;不到一…

Java 中 CAS 是什么,有哪些实际应用场景

CAS 是什么 CAS&#xff08;Compare And Swap&#xff09;是一种并发编程中的原子操作&#xff0c;用于实现多线程之间的同步。在 Java 中&#xff0c;CAS 操作通过 sun.misc.Unsafe 类实现。 CAS 操作是一种乐观锁机制&#xff0c;它假设对于共享变量的修改操作不会引起冲突…

一个高级测试工程师从23岁到33岁,经历过时间才会懂的这个行业

本文将概述测试工程师的现状及发展方向&#xff0c;并着重介绍测试开发工程师的发展及所需具备的技能&#xff0c;以及本部门搭建的测试平台的概况和意义。 一、测试工程师的现状 很多测试小伙伴在工作中有时会比较迷茫&#xff0c;不知该怎样突破瓶颈&#xff0c;更好的发展。…

加密解密软件VMProtect教程(六):主窗口之控制面板“项目”部分(2)

VMProtect 是新一代软件保护实用程序。VMProtect支持德尔菲、Borland C Builder、Visual C/C、Visual Basic&#xff08;本机&#xff09;、Virtual Pascal和XCode编译器。 同时&#xff0c;VMProtect有一个内置的反汇编程序&#xff0c;可以与Windows和Mac OS X可执行文件一起…