51单片机入门实验代码——独立按键实验

实验之前要了解两个知识点:按键是否被按下的判断  和  消抖 

如图所示K1健右边接地,左边与P31引脚相连并且有个上拉电阻。

如何判断按键是否被按下: 笔者的理解如下,如果有误请评论区告知我,谢谢!

当K1键未被按下,右边是断开状态,P31因为上拉电阻的存在显示为高电平。

当K1键被按下时,右边是联通状态,P31因为右边接地有通路,电压明显减少,显示为低电平。

消抖:因为按键的时候会形成一会高电平一会低电平,不好判断按键是否被按下,如下图所示:

实验一:用KEY1键翻转LED1的状态(资料代码):

#include "reg51.h" 
#include "intrins.h" 

typedef unsigned int u16;
typedef unsigned char u8;

sbit KEY1 = P3^1;                 // 定义键位
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

sbit LED1 = P2^0;                 // 定义LED灯

#define KEY1_PRESS  1             // 宏定义一个标志 KEY1_PRESS 为KEY1的返回值 
#define KEY2_PRESS  2
#define KEY3_PRESS  3
#define KEY4_PRESS  4
#define KEY_UNPRESS 0

void delay10us(u16 ten_us)        // 延时程序
{
	while(ten_us--);
}

u8 key_scan(u8 mode)              // 扫描按键是否被按下,在主程序while中就是一直在扫描
{
	static u8 key = 1;            // 设置静态变量key来决定是否要扫描 静态变量的意义在于key的值是保留每一次的赋值操作 key = 1这里只是赋了个初值,只运行一次
	
	if(mode) key = 1;             // mode为1,表示为持续扫描。mode为0,表示为一次扫描。
	
	if(key = 1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))   // 当key为1 并且按键有被按下,执行下面的操作 返回对应的值 函数结束 
	{
			delay10us(1000);
			key = 0;
		
			if(KEY1==0)
				return KEY1_PRESS;
			else if(KEY2==0)
				return KEY2_PRESS;
			else if(KEY3==0)
				return KEY3_PRESS;
			else if(KEY4==0)
				return KEY4_PRESS;
	}
	else if(KEY1==1 && KEY2==1 && KEY3==1 && KEY4==1)  // 无按键按下或者按键已经结束,此时所有的按键处于打开状态 将key复位便于下次扫描
	{
		key = 1;
	}
	return KEY_UNPRESS;
}

void main()
{
	u8 key=0;
	while(1)
	{
		key=key_scan(0);        
		if(key==KEY1_PRESS)    // 检测KEY1是否按下
			LED1=!LED1;        // LED1状态翻转
	}
}

实验一:用KEY1键翻转LED1的状态(简单版):

#include "reg51.h" 

typedef unsigned int u16;
typedef unsigned char u8;

sbit KEY1 = P3^1;
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

sbit LED1 = P2^0;

void delay10us(u16 ten_us)
{
	while(ten_us--);
}

void main()
{
	while(1)
	{
			if(KEY1==0)                // 判断KEY1是否被按下
			{
				delay10us(1000);       // 消抖
				while(KEY1==0);        // 循环判断
				LED1=!LED1;            // 翻转LED灯状态
			}
	}
}

实验二:用KEY1、KEY2 控制 数码管时间钟 秒(sec)的加减:

学习视频:11.按键应用调整时间之初体验_哔哩哔哩_bilibili

如何用数码管显示可以走动的时间,可参考《51单片机入门实验代码——独立按键实验》实验四

51单片机入门实验代码——动态数码管显示-CSDN博客

#include "reg51.h" 
#include "intrins.h" 
 
typedef unsigned int u16;
typedef unsigned char u8;

sbit KEY1 = P3^1;                                 // 定义KEY1键
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

#define SMG_A_DP_PORT P0                          // 宏定义数码管
 
u8 gsmg_code[18] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
									0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40};  // 多添加了横杠-:0x40
 
u8 date_code[8] = {16,16,17,16,16,17,16,16};	  // 初始化晶体管
 
u16 hour=12, min=59, sec=22;                      // 设置时间变量初值                   
 
u8 count = 0;
 
void delay10us(u16 ten_us)                        // 延时程序
{
	while(ten_us--);
}
 
jisuan()                                          // 将时间变量计算到date_code数组中,最后输入到P0
{
	date_code[0] = sec%10;                        // 最低两位显示 秒
	date_code[1] = sec/10;
 
	date_code[3] = min%10;                        // 中间两位显示 分
	date_code[4] = min/10;
 
	date_code[6] = hour%10;                       // 最高两位显示 时
	date_code[7] = hour/10;	
	
}
 
void main()
{
    u8 i=0;
    jisuan();                                           // 初始化时间初值
	while(1)
	{
		for(i=0;i<8;i++)                                // 循环 位控制LED的显示位
		{
			P2 = i<<2;                                  // i为几,LED第几位显示
			SMG_A_DP_PORT = gsmg_code[date_code[i]];    // LED显示数值
			delay10us(125);                             
			SMG_A_DP_PORT = 0x00;                       // LED消除上次显示的光影
		}
		//count++;        // 这里与实验四不同的是count++被注释掉了 所以永远不会执行后面的if(count==100) 
		if(count==100)                                  // for每循环执行一次 要8*1.25ms=10ms 当count为100时,用时100*10ms=1s (我猜的理论上是这样)
		{
			count=0;                        
			sec++;
			if(sec==60)                                 // 用时1s后sec+1,加到60 min+1,以此类推
			{
				sec=0;
				min++;
				if(min==60)
				{
					min=0;
					hour++;
					if(hour==24)
					{
						hour=0;
					}
				}
			}
			jisuan();                                    // sec、min、hour计算完成后保存到date_code数组,最后在while下次循环中写到数码管中
		}

		if(KEY1 == 0)                                    // 通过KEY1来将秒(sec)加一 但是可以加到61 后续会优化
		{
			delay10us(1000);                             // 消抖
			while(KEY1 == 0);
			sec++;
			jisuan();
		}
		if(KEY2 == 0)                                    // 通过KEY2来将秒(sec)减一
		{
			delay10us(1000); 	
			while(KEY2 == 0);
			sec--;
			jisuan();
		}
	}
}

实验三:用KEY1来移动设置位,并用KEY2 设置数码管时间钟:

学习视频:12.按键应用调整时间之完结版(时钟调整时间)_哔哩哔哩_bilibili

#include "reg51.h" 
#include "intrins.h" 
 
typedef unsigned int u16;
typedef unsigned char u8;

sbit KEY1 = P3^1;                                 // 定义KEY1键
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

#define SMG_A_DP_PORT P0                          // 宏定义数码管
 
u8 gsmg_code[18] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
									0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40};  // 多添加了横杠-:0x40
 
u8 date_code[8] = {16,16,17,16,16,17,16,16};	  // 初始化晶体管
 
u16 hour=12, min=59, sec=22;                      // 设置时间变量初值                   
 
u8 count = 0;

u8 shezhiwei = 0;                                 // 设置设置位来控制修改数码管的哪一位

void delay10us(u16 ten_us)                        // 延时程序
{
	while(ten_us--);
}
 
jisuan()                                          // 将时间变量计算到date_code数组中,最后输入到P0
{
	date_code[0] = sec%10;                        // 最低两位显示 秒
	date_code[1] = sec/10;
 
	date_code[3] = min%10;                        // 中间两位显示 分
	date_code[4] = min/10;
 
	date_code[6] = hour%10;                       // 最高两位显示 时
	date_code[7] = hour/10;	
	
}
 
void main()
{
    u8 i=0;
    jisuan();                                           // 初始化时间初值
	while(1)
	{
		for(i=0;i<8;i++)                                // 循环 位控制LED的显示位
		{
			P2 = i<<2;                                  // i为几,LED第几位显示
            if(count < 50 && i == shezhiwei)
               SMG_A_DP_PORT = 0;                       // 使设置位闪烁
            else
			    SMG_A_DP_PORT = gsmg_code[date_code[i]];    // LED显示数值
			delay10us(125);                             
			SMG_A_DP_PORT = 0x00;                       // LED消除上次显示的光影
		}
		count++;                                        // count记录执行了多少次for循环
		if(count==100)                                  // for每循环执行一次 要8*1.25ms=10ms 当count为100时,用时100*10ms=1s (我猜的理论上是这样)
		{
			count=0;     
           if(shezhiwei==-1)                            // 这个if是设置完成后继续时间进行                            
            {              
        	sec++;
			if(sec==60)                                 // 用时1s后sec+1,加到60 min+1,以此类推
			{
				sec=0;
				min++;
				if(min==60)
				{
					min=0;
					hour++;
					if(hour==24)
					{
						hour=0;
					}
				}
			}
			jisuan();                                    // sec、min、hour计算完成后保存到date_code数组,最后在while下次循环中写到数码管中
            }
		}

		if(KEY1 == 0)                                    // 通过KEY1来移动设置位
		{
			delay10us(1000);                             // 消抖
            while(KEY1 == 0);
			shezhiwei++;
            if(shezhiwei==8)                             // 当设置位到最高位还按了一次 设置结束 ,shezhiwei=-1 ,离开设置模式,正常进行时钟
                shezhiwei=-1;
            else if(shezhiwei==2)
                shezhiwei++;
            else if(shezhiwei==5)
                shezhiwei++;
		}
		if(KEY2 == 0)                                    // 通过KEY2修改设置位的数值
		{
			delay10us(1000); 	
			while(KEY2 == 0);
            if(shezhiwei==0)
			{
                sec++; sec%=60;
                jisuan();
            }
		    else if(shezhiwei==1)
			{
                sec+=10; sec%=60;
                jisuan();
            }
		    else if(shezhiwei==3)
			{
                min++; min%=60;
                jisuan();
            }
		    else if(shezhiwei==4)
			{
                min+=10; min%=60;
                jisuan();
            }
		    else if(shezhiwei==6)
			{
                hour++; hour%=24;
                jisuan();
            }
		    else if(shezhiwei==7)
			{
                hour+=10; hour%=24;
                jisuan();
            }

		}
	}
}

以上内容,学习所用。如有侵权,Call我必删。

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值