题目:

数码管后三位显示计数值count,范围是0~999
若S4按下,计数值加一,长按1s后,计数值一直加;
若S5按下,计数值减一,长按1s后,计数值一直减;
若S6按下,计数值清零。

代码如下:

#include "STC15F2K60S2.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
uchar segCode[25]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,       //0~9的段码(不带小数点)
									 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff}; //0.~9.的段码(带小数点) 以及0xff全灭
uchar segVal[]={20,20,20,20,20,20,20,20};  //数码管初始化显示1 2 3 4 1. 2. 3. 4.
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
bit s4Flag=0;
bit s5Flag=0;
uint count=0;//计数值初始值0
uchar keySta[]  = {1,1,1}; //当前按键状态
uchar keyBack[] = {1,1,1};//按键值备份,保存前一次的值(上一次的按键状态)
uchar keyBuf[]  = {0xff,0xff,0xff};
void SelectHC573(uchar val) 
{
	switch(val)
	{
		case 4 : P2 = (P2 & 0x1f) | 0x80; break;
		case 5 : P2 = (P2 & 0x1f) | 0xa0; break;
		case 6 : P2 = (P2 & 0x1f) | 0xc0; break;
		case 7 : P2 = (P2 & 0x1f) | 0xe0; break;
		default: P2 = (P2 & 0x1f); break;		
	}
}
void InitSystem()//系统初始化关闭蜂鸣器、继电器、LED
{
	SelectHC573(5);
	P0 = 0xbf;      //由于不同板子的引脚接法不同,此时的初始值也不同
	SelectHC573(4);	
	P0 = 0xff;     //LED全灭
}
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}
uchar segFlag = 0;
uint count1s=0;
void ServiceTimer0() interrupt 1
{
	uchar pushp0,pushp2,k;
	pushp0 = P0;//保护P0、P2值不被中断所影响
	pushp2 = P2;
//数码管
	SelectHC573(6);
	P0 = (0x01<<segFlag);
	SelectHC573(7);	
	P0 = segCode[segVal[segFlag]];
	segFlag++;
	if(segFlag == 8) segFlag = 0;
//按键检测	
	keyBuf[0] = (keyBuf[0]<<1) | S4;
	keyBuf[1] = (keyBuf[1]<<1) | S5;
	keyBuf[2] = (keyBuf[2]<<1) | S6;
	for(k=0; k<3; k++)
	{
		if(keyBuf[k] == 0x00)
			keySta[k] = 0;
		else if(keyBuf[k] == 0xff)
			keySta[k] = 1;			
	}
//1s
	if(s4Flag == 1 || s5Flag==1)//如果s4或s5按下,启动1s定时
	{
		count1s++;
		if(count1s>2000) 					//为了防止按下时间太长,导致count1s溢出
			count1s=2000;
	}
	else
		count1s=0;
	P2 = pushp2;
	P0 = pushp0;
}
void Delay100ms()		//@12.000MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 5;
	j = 144;
	k = 71;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void main()
{
	InitSystem();
	Timer0Init();
	while(1)
	{	
		segVal[5] = count/100;
		segVal[6] = count%100/10;
		segVal[7] = count%10;	
//如果S4按下,计数值count加一,长按(大于一秒)计数值count持续加
		if(keySta[0] != keyBack[0])  //当前值与前次值不相等说明此时按键有动作(按下或弹起)
		{
			if(keySta[0] == 0)					//如果这一次值为 0,则说明当前是按下动作
			{
				s4Flag=1;									//启动1s定时		
				while(keySta[0] == 0)    	//如果按键没有松开,即一直在按下
				{
					if(count1s>1000)				//如果按键按下时间大于1s
					{
						if(count==999)				//计数值最大999,当加到999的时候,不再增加
							count=999;
						else
							count++;						//计数值持续加
						segVal[5] = count/100;
						segVal[6] = count%100/10;
						segVal[7] = count%10;	
						Delay100ms();					//这个一定要加上,具体时间可按要求调节,否则会影响数码管显示,计数值很快就会达到阈值	
					}
				}		
				if(count1s<=1000)					//按键时间小于1s,为短按,计数值加1
				{
					if(count==999)					//计数值最大999,当加到999的时候,不再增加
						count=999;
					else
						count++;								//计数值加一		
					segVal[5] = count/100;
					segVal[6] = count%100/10;
					segVal[7] = count%10;	
				}
				s4Flag=0;									//按键松开,关闭1s定时
			}
			keyBack[0] = keySta[0];
		}
//如果S5按下,计数值count减一,长按(大于一秒)计数值count持续减(原理和按键S4一样)
		if(keySta[1] != keyBack[1])
		{
			if(keySta[1] == 0)
			{
				s5Flag=1;
				while(keySta[1]==0)
				{
					if(count1s>1000)
					{
						if(count==0)	
							count=0;
						else
							count--;
						segVal[5] = count/100;
						segVal[6] = count%100/10;
						segVal[7] = count%10;		
						Delay100ms();	
					}
				}
				if(count1s<=1000)		
				{
					if(count==0)	
						count=0;
					else
						count--;
					segVal[5] = count/100;
					segVal[6] = count%100/10;
					segVal[7] = count%10;						
				}
				s5Flag=0;
			}
			keyBack[1] = keySta[1];
		}
//如果S6按下,计数值count清零
		if(keySta[2] != keyBack[2])
		{
			if(keySta[2] == 0)
			{
				count=0;
			}
			keyBack[2] = keySta[2];
		}
	}
}