基于51单片机的按键计数仿真设计

一、项目描述

基于89C52单片机,在protues环境中开发了一个含有按键计数功能的小项目,计数最大值是999。输入是接在P32口和P3^3口的两个按键,输出是在1602显示屏上显示结果。程序在keil C51软件中编写调试。

二、硬件设计

主体是单片机一个,外围电路有晶振电路、复位电路、1602液晶显示屏、两个按钮开关按键。1602的VSS接地,VDD接电源,VEE接滑动变阻器来调节电位,以此调节屏幕对比度。RS接P30,来选择数据或者命令;E接P31,控制1602使能;根据工作手册,RW可以一直为低电平,因此RW始终接地。D0~D7接到P2口作为传输总线。两个按键接在P32口和P3^3口,分别对应外部中断0和外部中断1,且低电平触发中断。晶振电路可以提供11.0592MHZ的工作频率,复位电路可以通过按钮开关按键复位。
图 1 硬件线路连接

三、软件代码

/********************************************************
* 文    件: 1602显示屏按键计数
* 作    者: 
* 外部晶振: 11.0592MHZ	
* 编译环境: Keil μVisio4	
* 功    能: 数码管静态显示			   			            			   
* 注意事项: 
********************************************************/

#include<reg52.h>
unsigned char code table1[]="COUNT:"; 			//命名数组用来显示字符“COUNT:”
int count = 0;   								//全局变量初始化

sbit RS = P3^0;									//数据/命令选择接口
sbit EN = P3^1;									//使能接口
sbit button1 = P3^2;							//按键1接在P3^2接口,对应外部中断0
sbit button2 = P3^3;							//按键2接在P3^3接口,对应外部中断1

/********************************************************
函数名:毫秒级CPU延时函数
调  用:delay_ms(?);
参  数:1~65535(参数不可为0)
返回值:无
结  果:占用CPU方式延时与参数数值相同的毫秒时间
备  注:应用于1T单片机时i<600,应用于12T单片机时i<125
/********************************************************/

void delay(unsigned int a)
{
    unsigned int i;
    while( --a != 0){
        for(i = 0; i < 125; i++);
    }
}

/********************************************************
函数名:写指令函数
调  用:writeinstruction(x);
参  数:无符号十六进制数0x??
返回值:无
结  果:将指令发送给1602控制器
/********************************************************/

void  writeinstruction(unsigned char x)
{   
    RS = 0;
	EN = 0;
    P2 = x;
    delay(5);
    EN = 1;
    delay(5);
    EN = 0;
}

/*********************************************************
函数名:写数据函数
调  用:writedata(y);
参  数:无符号十六进制数0x??
返回值:无
结  果:将数据发送至1602内部的显示内存中
/*********************************************************/

void  writedata(unsigned char y)
{   
    RS = 1;
	EN = 0;
    P2 = y;
    delay(5);
    EN = 1;
    delay(5);
    EN = 0;
}

/*********************************************************
函数名:写变量函数
调  用:writechar(z);
参  数:无符号十六进制数0x??
返回值:无
结  果:将数据发送至1602内部的显示内存中
备  注:不能将整数型变量count直接作为writedata的参数,需要将个、十、百位分别+48(0x30)转化成ascii码。
/*********************************************************/

void  writechar(unsigned char z)						 
{
	unsigned char A;
	unsigned char B;
	unsigned char C;
	RS = 1;
	EN = 0;
    A = z/1%10;									//取个位
    B = z/10%10;								//取十位
    C = z/100%10;								//取百位
	writedata(C+48);			
    delay(5);	
	writedata(B+48);							//分离出变量的每一位数,再将每一位加上0x30,
    delay(5);	
	writedata(A+48);							//这样就变成了ASCII码了,再送给LCD才能显示出来变量的每一位的值。
    delay(5);
}

/*********************************************************
函数名:1602设置初始化函数
调  用:init1602();
参  数:无
返回值:无
结  果:初始化。具体指令在手册中查询。
/*********************************************************/

void  init1602()
{ 
                                                       
	writeinstruction(0x38);        				//设置显示模式 指令码 00111000 => 0x38      
	delay(5);
	writeinstruction(0x0C);        				//[00001DCB]:D为显示开关,B为光标开关,C为光标闪烁开关。0x0C:开显示 不显示光标 不闪烁
	delay(5);	
	writeinstruction(0x06);        				//写一个字符后地址指针加一
	delay(5);	
	writeinstruction(0x01);       	    		//清屏       
	delay(5);	

}

/**********************************************************
函数名:主函数main
/**********************************************************/

void  main()
{  
	char i;

	init1602();
	writeinstruction(0x80);      				//设置数据地址指针从第一个开始
	delay(5);
	
	/* 初始化中断 */
    EA = 1;
    EX0 = 1;
    EX1 = 1;
	
	/* 写初始字符:COUNT:0 */
    for (i = 0; i < 6; ++i) 					//逐个写入第一行数据
    {
        writedata(table1[i]);
        delay(20);
    }

	writeinstruction(0x02); 					//第一行光标返回
    writeinstruction(0x80 + 0x40); 				//数据地址指针指向第二行第一个	
	writechar(count);
	
	/*砸瓦鲁多 */
	while(1);									//程序停在这里,等待中断到来
}

/*********************************************************
函数名:中断显示计数值函数
调  用:按下button1
参  数:无
返回值:无
结  果:显示当前计数值。具体指令在手册中查询。
/*********************************************************/

void Display()interrupt 0 using 1
{
	int i;
	if(button1==0)
	{
    	delay(10);
    	if(button1==0)
    	{
        	count++; 			 				//按键松开后,程序会运行到这里,计数值加1
			while(!button1);				 	//如果按键没有松开,程序会停在这里
    	}
		writeinstruction(0x01);	 				//清屏   
		for (i = 0; i < 6; ++i)  				//逐个写入第一行数据
    	{
       		writedata(table1[i]);
        	delay(20);
    	}	
		writeinstruction(0x02); 				//回车
    	writeinstruction(0x80 + 0x40);  		//换行					
		writechar(count);
	}

/*********************************************************
函数名:中断清零函数
调  用:按下button2;
参  数:无
返回值:无
结  果:计数值清零。具体指令在手册中查询。
/*********************************************************/
}

void Clear() interrupt 2 using 1
{
	int i;
    writeinstruction(0x01);
	count=0; 									//count计数清零
	for (i = 0; i < 6; ++i) 					//逐个写入第一行数据
    {
       	writedata(table1[i]);
        delay(20);
    }
	writeinstruction(0x02); 					//回车
    writeinstruction(0x80 + 0x40); 				//换行
	writechar(count);
}

四、结果展示

图 2每按button1一次液晶计数+1

图 3每按button2一次液晶计数清零

五、经验总结

在硬件连接方面,最初是用P0口作为数据传输总线,但1602每次都出现乱码,经排查后发现原因是未接上拉电阻。在接了上拉电阻之后依然不能正常显示,于是转为P2口作为数据传输总线,同时发现了RW口可以一直接地,省去了一个接口。

在软件调试方面,在向1602发送数据时不能用写数据函数writedata()直接将变量写入,因此我又编写了一个writechar()函数,通过将变量的个、十、百位分别转为char型,再加上+48(+0x30)转成ascii码,便可以用writedata()函数将十六进制数写入。1602可以将ascii码直接转为对应的字符再屏幕上显示。

4.4 更新:按键后的刷新很慢是因为延迟函数时间过长了,之前调试的时候没注意到这里用的是毫秒级延时,所以延时设置短一点就可以变得丝滑顺畅了。RST复位也有问题,把复位电阻改成1k就可以复位了,10k太大了。

  • 20
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值