蓝桥杯模块学习5——独立按键(深夜学习——单片机)

目录

一、硬件部分:

1、原理图:

 二、独立按键:

1、功能一参考代码:

(1)宏定义:

(2)主函数:(感觉现在迷上位操作了,不会的可以自已定义IO口)

1、功能一参考代码(模块化):

2、功能二参考代码: 

(1)宏定义:(同上)

(2)主函数:(如果跟着我之前几篇文章一起优化过自己代码的人,应该看得懂我这次写的代码,如果看不懂建议回去巩固一下)

(3)主函数:(优化版但可能比较难懂)

3、功能一参考代码: (直观化)

4、优化代码:(最好学过定时器后再来学习以下代码)

(1)宏定义:

(2)主函数:


一、硬件部分:

1、原理图:

 (1)J5:当1和2相接,电路就变成一个4*4的矩阵键盘电路;当2和3相接时,电路变成

了一个S4-S7的独立按键

(2)对于独立按键的分析:

独立按键,按键检测_佛科院深夜学习的博客-CSDN博客https://blog.csdn.net/weixin_63568691/article/details/128374461

蓝桥杯模块学习5——独立按键(深夜学习——单片机)_第1张图片

 二、独立按键:

实现功能:

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

(2)S7、S6为选择键,S5和S4为开关键:

        (A)当按下S7,指示灯L1亮(无松手检测),同时表明当前选择L3、L4,分别由S5和S4控制(有松手检测)

        (B)当按下S6,指示灯L2亮(无松手检测),同时表明当前选择L5、L6,分别由S5和S4控制(有松手检测)

        (C)同时要求未进行选择之前,开关键不起作用

1、功能一参考代码:

(1)宏定义:

#ifndef _PUBLIC_H
#define _PUBLIC_H

#include 

#define u8 unsigned char
#define u16 unsigned int

void Delay_1ms(u16 num);
void Close_All(void);
void Delay_10us(u16 num);
#endif
#include "Public.h"
// 延时函数(最小约1ms@12MHz)
void Delay_1ms(u16 num)
{
  unsigned int i;
  while(num--)
    for(i=0; i<628; i++);
}


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

void Delay_10us(u16 num)
{
  u16 i;
  while(num--)
    for(i=0; i<3; i++);
}

(2)主函数:(感觉现在迷上位操作了,不会的可以自已定义IO口)

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

void LED_ON(u8 L_X);

// 主函数
void main(void)
{
	u8 i;
	Close_All();
  while(1)
  { 
		for(i=0;i<4;i++)
		{
			if(!(P3 & (0x01<

1、功能一参考代码(模块化):

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

void LED_ON(u8 L_X);
u8 Key_check();

// 主函数
void main(void)
{
	u8 temp;
	Close_All();
  while(1)
  { 
		if(temp=Key_check())
		{
			LED_ON(~(0x01<<(7-temp)));
			while(!(P3 & 0x01<<(7-temp)));
			LED_ON(0xff);
		}
  }
}

/*
	输入变量:P0口的对应的16进制数
	输出变量:无
	功能:选择相应的锁存器后,通过P0口控制LED灯亮
*/
void LED_ON(u8 L_X)
{
	P0 = L_X;
	P2 = (P2 & 0x1f) | 0x80;
	P2 &= 0x1f;
}

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

2、功能二参考代码: 

(1)宏定义:(同上)

(2)主函数:(如果跟着我之前几篇文章一起优化过自己代码的人,应该看得懂我这次写的代码,如果看不懂建议回去巩固一下)

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

void LED_ON(u8 L_X);
u8 Key_check();

// 主函数
void main(void)
{
	u8 temp,last_led;
	Close_All();
  while(1)
  { 
		if(temp=Key_check())
		{
			//按下S7
			if(temp==7)
			{
				//L1亮,并且保存好L1亮的信息
				LED_ON(~(last_led=0x01<<(7-temp)));
				//松手后再进行其他操作,但不关灯
				while(!(P3 & 0x01<<(7-temp)));
				while(1)
				{
					//再对S5、S4进行判断
					temp=Key_check();
					if(temp==5||temp==4)
					{
						//L1和其中之一的灯一起亮
						LED_ON(~((0x01<<(7-temp))|last_led));
						while(!(P3 & 0x01<<(7-temp)));
						//保持为L1亮的状态
						LED_ON(~last_led);
					}
					if(temp==7)
					{
						//关闭所有灯
						LED_ON(0xff);
						while(!(P3 & 0x01<<(7-temp)));
						break;
					}
			  }
			}
			//按下S6
			if(temp==6)
			{
				//L2亮
				LED_ON(~(last_led=0x01<<(7-temp)));
				//松手后再进行其他操作,但不关灯
				while(!(P3 & 0x01<<(7-temp)));
				while(1)
				{
					//再对S5、S4进行判断
					temp=Key_check();
					if(temp==5||temp==4)
					{
						//如果是按下S6,表明选择L5、L6
						LED_ON(~((0x01<<(7-temp+2))|last_led));
						while(!(P3 & 0x01<<(7-temp)));
						LED_ON(~last_led);
					}
					if(temp==6)
					{
						LED_ON(0xff);
						while(!(P3 & 0x01<<(7-temp)));
						break;
					}
			  }
			}
		}
  }
}

/*
	输入变量:P0口的对应的16进制数
	输出变量:无
	功能:选择相应的锁存器后,通过P0口控制LED灯亮
*/
void LED_ON(u8 L_X)
{
	P0 = L_X;
	P2 = (P2 & 0x1f) | 0x80;
	P2 &= 0x1f;
}

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

(3)主函数:(优化版但可能比较难懂)

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

void LED_ON(u8 L_X);
u8 Key_check();

// 主函数
void main(void)
{
	u8 temp,last_led,c_sign;
	Close_All();
  while(1)
  { 
		if(temp=Key_check())
		{
			if(temp==7||temp==6)
			{
				//按下S7,控制L3、L4
				if(temp==7)
					c_sign=0;
				//按下S6,控制L5、L6
				if(temp==6)
					c_sign=2;
				//L1/L2亮,并且保存好L1/L2亮的信息
				LED_ON(~(last_led=0x01<<(7-temp)));
				//松手后再进行其他操作,但不关灯
				while(!(P3 & 0x01<<(7-temp)));
				while(1)
				{
					//再对S5、S4进行判断
					temp=Key_check();
					if(temp==5||temp==4)
					{
						//L1和其中之一的灯一起亮
						LED_ON(~((0x01<<(7-temp+c_sign))|last_led));
						while(!(P3 & 0x01<<(7-temp)));
						//保持为L1亮的状态
						LED_ON(~last_led);
					}
					//检测到控制键按下且标志位对应
					if((temp==7&&c_sign==0)||(temp==6&&c_sign==2))
					{
						//关闭所有灯
						LED_ON(0xff);
						while(!(P3 & 0x01<<(7-temp)));
						break;
					}
			   }
			  }
			}
		}
}

/*
	输入变量:P0口的对应的16进制数
	输出变量:无
	功能:选择相应的锁存器后,通过P0口控制LED灯亮
*/
void LED_ON(u8 L_X)
{
	P0 = L_X;
	P2 = (P2 & 0x1f) | 0x80;
	P2 &= 0x1f;
}

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

由于不太清楚是模块化思想编程好,还是减少模块和位运算尽量直观化的方法好,我决定都尝试一下

3、功能一参考代码: (直观化)

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

void LED_ON(u8 L_X);

sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
// 主函数
void main(void)
{
	u8 i;
	Close_All();
  while(1)
  { 
		if(!S7)
		{
			Delay_1ms(20);
			if(!S7)
			{
				LED_ON(~(0x01<

4、功能二参考代码: (直观化)

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

void LED_ON(u8 L_X);
u8 Key_check();

sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;

// 主函数
void main(void)
{
	Close_All();
  while(1)
  { 
		if(!S7)
		{
			Delay_1ms(20);
			if(!S7)
			{
				LED_ON(~(0x01<<0));
				while(!S7);
				while(1)
				{
					if(!S5)
					{
						Delay_1ms(20);
						if(!S5)
						{
							LED_ON(~((0x01<<2)|(0x01<<0)));
							while(!S5);
							LED_ON(~(0x01<<0));
						}
					}
					if(!S4)
					{
						Delay_1ms(20);
						if(!S4)
						{
							LED_ON(~((0x01<<3)|(0x01<<0)));
							while(!S4);
							LED_ON(~(0x01<<0));
						}
					}
					if(!S7)
					{
						Delay_1ms(20);
						if(!S7)
						{
							while(!S7);
							LED_ON(0xff);
							break;
						}
					}
			  }
			}
		}
		if(!S6)
		{
			Delay_1ms(20);
			if(!S6)
			{
				LED_ON(~(0x01<<1));
				while(!S6);
					while(1)
					{
						if(!S5)
						{
							Delay_1ms(20);
							if(!S5)
							{
								LED_ON(~((0x01<<4)|(0x01<<1)));
								while(!S5);
								LED_ON(~(0x01<<1));
							}
						}
						if(!S4)
						{
							Delay_1ms(20);
							if(!S4)
							{
								LED_ON(~((0x01<<5)|(0x01<<1)));
								while(!S4);
								LED_ON(~(0x01<<1));
							}
						}
						if(!S6)
						{
							Delay_1ms(20);
							if(!S6)
							{
								while(!S6);
								LED_ON(0xff);
								break;
							}
						}
					 }
		      }
				}
	}
		
}

/*
	输入变量:P0口的对应的16进制数
	输出变量:无
	功能:选择相应的锁存器后,通过P0口控制LED灯亮
*/
void LED_ON(u8 L_X)
{
	P0 = L_X;
	P2 = (P2 & 0x1f) | 0x80;
	P2 &= 0x1f;
}

写完的个人感受:

(1)优点:直观化的可读性强,在局部阅读属于一看就明白,如果是一小部分写错,几乎是一下子就能看出错误;缺点:代码整体冗杂,如果是整体有错误,全局阅读性很差,特别是存在过多大括号的情况下‘;重复性强,如果存在一处错误,基本上需要改多处;可移植性差,基本不存在一码多用的情况

(2)优点:模块化的可移植性强,有时候写着写着发现都是用已经写好的函数;整体可读性强,基本上都是不同的模块组成,可以分开一部分一部分看;修改简单,由于程序大量使用同一函数,基本上只需要改某个的函数就行;缺点:局部可读性极差,极其考虑逻辑思维能力;函数与主函数联系起来较为麻烦;

(3)总结:建议还是以模块化思维编程会更有逻辑性,但是不要过度追求模块化,实在想不明白的地方直接用最笨的方法也行,在平时可以进行优化训练,但在比赛场上就不要硬求优化,能写出来就行

更新:学习其他代码后而且经过一个实际工程代码的编写,深感之前代码的鲁棒性太差了,也通过定时器和位操作优化了消抖和松手检测

4、优化代码:(最好学过定时器后再来学习以下代码)

蓝桥杯模块学习8——定时器中断(深夜学习——单片机)_佛科院深夜学习的博客-CSDN博客icon-default.png?t=MBR7https://blog.csdn.net/weixin_63568691/article/details/128508355

(1)宏定义:

#ifndef _PUBLIC_H
#define _PUBLIC_H

#include "STC15F2K60S2.H" 

#define u8 unsigned char
#define u16 unsigned int

void Delay_1ms(u16 num);
void Close_All(void);
void Delay_10us(u16 num);
#endif
#include "Public.h"
// 延时函数(最小约1ms@12MHz)
void Delay_1ms(u16 num)
{
  unsigned int i;
  while(num--)
    for(i=0; i<628; i++);
}


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

void Delay_10us(u16 num)
{
  u16 i;
  while(num--)
    for(i=0; i<3; i++);
}

(2)主函数:

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

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<

你可能感兴趣的:(蓝桥杯单片机,单片机,学习,蓝桥杯)