51单片机练习:独立键盘篇

题目:

用数码管的前两位显示一个十进制数,变化范围为00~59,开始时显示00,每按下S2键一次,数值加1;每按下S3键一次,数值减1;每按下S4键一次,数值归零;按下S5键一次,利用定时器功能使数值开始自动每秒加1,再次按下S5键,数值停止自动加1,保持显示原数。(来自郭天祥老师的51单片机练习)

代码:

初始化函数:

void Init()
{
	LE = 0;//锁住led灯,防止实验过程中灯亮
	
	WLE = 1;//打开位选
	P0 = 0xfc;
	WLE = 0;//关闭位选
	P0 = 0xff;//消影
	DLE = 1;//打开段选
	P0 = Table[0];
	DLE = 0;//关闭段选
	delay_1ms(10);
	
	TMOD = 0x01;//定时器工作类型
	TH0 = (65536 - 45872) / 256;//50ms
	TL0 = (65536 - 45872) % 256;
	EA = 1;//总中断
	ET0 = 1;//T0中断
	TR0 = 0;//开启T0
	
	num = 0;
	tt = 0;
}

1ms延时函数:

//延时1ms函数
void delay_1ms(uint z)
{
	uint x,y;
	for(x = z;x > 0;x--)
	{
		for(y =110;y > 0;y--){}
	}
}

四个独立按键函数:

//按键2函数
void Switch2()
{
	while(SW2 == 0)
	{
		delay_1ms(10);//消抖
		if(SW2 == 0)
		{
			num++;//加1
		}
		while(SW2 == 0);//等待按键释放
	}
}

//按键3函数
void Switch3()
{
	while(SW3 == 0)
	{
		delay_1ms(10);//消抖
		if(SW3 == 0)
		{
			if(num == 0)
			{
				num = 59;
			}
			else
			{
				num--;//减1
			}
		}
		while(SW3 == 0);//等待按键释放
	}
}

//按键4函数
void Switch4()
{
	while(SW4 == 0)
	{
		delay_1ms(10);//消抖
		if(SW4 == 0)
		{
			num = 0;//归零
		}
		while(SW4 == 0);//等待按键释放
	}
}

//按键5函数
void Switch5()
{
	while(SW5 == 0)
	{
		delay_1ms(10);//消抖
		if(SW5 == 0)
		{
			if(TR0 == 0)
			{
				TR0 = 1;
			}
			else
			{
				TH0 = (65536 - 45872) / 256;//50ms
				TL0 = (65536 - 45872) % 256;
				TR0 = 0;
			}
		}
		while(SW5 == 0);//等待按键释放
	}
}

数码管显示函数:

//数码管显示函数
void display()
{
	uint ge,shi;
	//定时1s
	if(tt == 20)
	{
		tt = 0;
		num++;
	}
	//计算每秒个位与十位的变化
	if(num == 60)
	{
		num = 0;
		
	}
	shi = num / 10;//十位
	ge = num % 10;//个位
	
	//显示十位
	WLE = 1;
	P0 = 0xfe;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[shi];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
	
	//显示个位
	WLE = 1;
	P0 = 0xfd;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[ge];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
} 

定时器T0中断函数:

void Timer0() interrupt 1
{
	TH0 = (65536 - 45872) / 256;//50ms
	TL0 = (65536 - 45872) % 256;
	tt++;
}

整个项目代码:

#include <reg52.h>

//【例4.1.1】用数码管的前两位显示一个十进制数,变化范围为00~59,开始时显示00,每按下S2键一次,数值加1;
//每按下S3键一次,数值减1;每按下S4键一次,数值归零;按下S5键一次,利用定时器功能使数值开始自动每秒加1,再次按下S5键,数值停止自动加1,保持显示原数。
//晶振为 11.0529MHz

#define uint unsigned int
#define uchar unsigned char
sbit SW2 = P3^4;//S2键
sbit SW3 = P3^5;//S3键
sbit SW4 = P3^6;//S4键
sbit SW5 = P3^7;//S5键
sbit WLE = P2^7;//位选
sbit DLE = P2^6;//段选
sbit LE = P2^5;//led灯的锁存器
//数码管的编码表
uchar code Table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uint num,tt;

void Init();
void delay_1ms(uint z);
void Switch2();//也可以将四个按键都写在一个函数里面
void Switch3();
void Switch4();
void Switch5();
void display();

void main()
{
	Init();
	while(1)
	{
		Switch2();
		Switch3();
		Switch4();
		Switch5();
		display();
	}
}

void Init()
{
	LE = 0;//锁住led灯,防止实验过程中灯亮
	
	WLE = 1;//打开位选
	P0 = 0xfc;
	WLE = 0;//关闭位选
	P0 = 0xff;//消影
	DLE = 1;//打开段选
	P0 = Table[0];
	DLE = 0;//关闭段选
	delay_1ms(10);
	
	TMOD = 0x01;//定时器工作类型
	TH0 = (65536 - 45872) / 256;//50ms
	TL0 = (65536 - 45872) % 256;
	EA = 1;//总中断
	ET0 = 1;//T0中断
	TR0 = 0;//开启T0
	
	num = 0;
	tt = 0;
}

//延时1ms函数
void delay_1ms(uint z)
{
	uint x,y;
	for(x = z;x > 0;x--)
	{
		for(y =110;y > 0;y--){}
	}
}

//按键2函数
void Switch2()
{
	while(SW2 == 0)
	{
		delay_1ms(10);//消抖
		if(SW2 == 0)
		{
			num++;//加1
		}
		while(SW2 == 0);//等待按键释放
	}
}

//按键3函数
void Switch3()
{
	while(SW3 == 0)
	{
		delay_1ms(10);//消抖
		if(SW3 == 0)
		{
			if(num == 0)
			{
				num = 59;
			}
			else
			{
				num--;//减1
			}
		}
		while(SW3 == 0);//等待按键释放
	}
}

//按键4函数
void Switch4()
{
	while(SW4 == 0)
	{
		delay_1ms(10);//消抖
		if(SW4 == 0)
		{
			num = 0;//归零
		}
		while(SW4 == 0);//等待按键释放
	}
}

//按键5函数
void Switch5()
{
	while(SW5 == 0)
	{
		delay_1ms(10);//消抖
		if(SW5 == 0)
		{
			if(TR0 == 0)
			{
				TR0 = 1;
			}
			else
			{
				TH0 = (65536 - 45872) / 256;//50ms
				TL0 = (65536 - 45872) % 256;
				TR0 = 0;
			}
		}
		while(SW5 == 0);//等待按键释放
	}
}

//数码管显示函数
void display()
{
	uint ge,shi;
	//定时1s
	if(tt == 20)
	{
		tt = 0;
		num++;
	}
	//计算每秒个位与十位的变化
	if(num == 60)
	{
		num = 0;
		
	}
	shi = num / 10;//十位
	ge = num % 10;//个位
	
	//显示十位
	WLE = 1;
	P0 = 0xfe;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[shi];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
	
	//显示个位
	WLE = 1;
	P0 = 0xfd;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[ge];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
} 

void Timer0() interrupt 1
{
	TH0 = (65536 - 45872) / 256;//50ms
	TL0 = (65536 - 45872) % 256;
	tt++;
}

心得/经验记录:

1.按键的代码编写过程中,要注意“消抖”(消除人在按动按键的过程中的抖动),这个过程大概延时10ms即可;

2.按键在按下去和释放的瞬间都会有抖动,但是实际过程中,只需要在按下去的时候消抖即可,释放时可以不用消抖;

3.在处理按键按下去的那段代码时,要注意加一个“等待释放”的过程,如果一直按着按键,程序就要等待在那,而不是一直加数;

4.数码管在遇到60的时候要显示0,在0与59之间的加减转换要衔接好;

5.定时器T0的TR0开启或关闭,可以将if else语句简化成TR0 = ~TR0代替;

6.因为P1^7口是第8个发光二极管的口,也是时钟SCLK的口,如果不将发光二极管的使能端LE = 0(锁住),那么在按下按键5的时候,会导致发光二极管亮;

7.可将Switch2()、Switch3()、Switch4()、Switch5()这四个按键写在一个函数里简化,依次判断即可。

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为你提供一个完整的单片机程序实现数码管的上述功能。假设我们还是使用51单片机和共阳数码管,代码如下: ```c #include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit dula = P2^6; sbit wela = P2^7; sbit S2 = P1^0; sbit S3 = P1^1; sbit S4 = P1^2; sbit S5 = P1^3; uchar code table[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f }; void delay(uint t) { while(t--); } void timer_init() { TMOD = 0x01; // 设置定时器0为模式1 TH0 = 0xfc; // 定时器初值为65536-1000=0xfc18 TL0 = 0x18; TR0 = 1; // 启动定时器0 } void timer_stop() { TR0 = 0; // 停止定时器0 } void main() { uchar num = 0; uchar flag = 0; while(1) { // 按下S2键,数码管上的数值1 if(S2 == 0) { delay(1000); if(S2 == 0) { num++; if(num >= 10) { num = 0; } } while(!S2); } // 按下S3键,数码管上的数值减1 if(S3 == 0) { delay(1000); if(S3 == 0) { if(num == 0) { num = 9; } else { num--; } } while(!S3); } // 按下S4键,清零并关闭定时器 if(S4 == 0) { delay(1000); if(S4 == 0) { num = 0; flag = 0; timer_stop(); } while(!S4); } // 按下S5键,启动定时器并自动0到9 if(S5 == 0) { delay(1000); if(S5 == 0) { flag = 1; timer_init(); } while(!S5); } // 定时器中断,自动0到9 if(TF0 == 1) { TF0 = 0; TH0 = 0xfc; TL0 = 0x18; num++; if(num >= 10) { num = 0; } } // 显示数码管上的数值 dula = 1; P0 = table[num]; dula = 0; wela = 1; P0 = ~(1 << (flag ? (num + 1) % 4 : 0)); wela = 0; delay(100); // 数码管扫描延时 } } ``` 这段代码中,我们首先定义了按钮和定时器相关的端口和变量,然后在主函数中通过不断检测按钮状态和定时器中断标志实现了数码管的各种功能。具体来说: - 按下S2键,数码管上的数值1,到9后再按下则显示0; - 按下S3键,数码管上的数值减1,直到0,再按下则显示9; - 按下S4键,清零并关闭定时器; - 按下S5键,启动定时器并自动0到9; - 定时器中断时,自动0到9。 其中,数码管的扫描是通过控制位 `dula` 和 `wela` 实现的,而定时器的使用则需要先进行初始化并设置中断服务程序,这里我们使用的是定时器0和模式1,中断服务程序中每次自动1并更新定时器初值。你可以根据实际情况修改代码中的端口定义和延时时间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值