C51之秒表按键计时版

使用两个按键,一个复位一个停止,代码将每个部分都拆解开,很详细,而且对定时器进行了补偿,进一步减小了误差,而且数值是在小数点后两位,具

#include <reg52.h>
#include<intrins.h>

sbit DU = P2^6;
sbit WE = P2^7;
sbit keys1=P3^4;//声明矩阵按键最后一行的列
sbit keys2=P3^5;
sbit keys3=P3^6;
sbit keys4=P3^7;

unsigned char code LedChar[]= {
//0     1     2     3     4    5     6      7     8    9
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
//a    b    c   d    e   f     
0x77,0x7c,0x39,0x5e,0x79,0x71};	//共阴极数码管0~9

unsigned char LedBuff[6] = 
{0x00,0x00,0x00,0x00,0x00,0x00//数码管显示缓冲区
};

unsigned char KeySta[4] = {1,1,1,1};//按键当前状态
bit StopwatchRunning = 0;//秒表运行标志
bit StopwatchRefresh = 1;//秒表刷新标志
unsigned char DecimalPart = 0;//小数部分
unsigned int  IntegerPart = 0;//整数部分
unsigned char T0RH = 0;//T0重载值的高字节
unsigned char T0RL = 0;//T0重载值的低字节

void ConfigTimer0(unsigned int ms);//配置定时器0
void StopwatchDisplay();
void KeyDriver();

void main()
{
    EA = 1;//总使能
	P3 = 0xfe;//打开矩阵第四行
	ConfigTimer0(2);//配置T0定时2ms
	while(1)
	{
	   if(StopwatchRefresh)
	   {
	   	  StopwatchRefresh = 0;
		  StopwatchDisplay();//秒表显示
	   }
	   KeyDriver();
	}
}

void ConfigTimer0(unsigned int ms)//配置定时器0
{
 unsigned long tmp;//临时变量
 tmp = 11059200/12;//定时器计数频率
 tmp = (tmp * ms)/1000;//计算所需的计数值
 tmp = 65536 - tmp;//计算所需的重载值
 tmp = tmp + 18;// 补偿中断响应延时造成的误差
 T0RH = (unsigned char)(tmp>>8);//把高八位存起来
 T0RL = (unsigned char)tmp;//把低八位存起来
 TMOD &= 0xf0;//高4位保持不变
 TMOD |= 0x01;//低4位最低位变1
 TH0 = T0RH;//加载T0的重载值
 TL0 = T0RL;
 ET0 = 1;//定时器0的中断使能
 TR0 = 1;//启动T0
}

void StopwatchDisplay()//存储数值到缓存区的函数,并点亮小数点,虽然叫秒表显示函数,但实际在这个函数里并没有显示到数码管的指令
{
 signed char i;
 unsigned char buf[4];//数据转换缓存区
 LedBuff[0] =  LedChar[DecimalPart%10];//小数部分存到数码管缓存区
 LedBuff[1]	=  LedChar[DecimalPart/10];

 buf[0] = IntegerPart%10;//将整数部分转化成4位十进制值
 buf[1] = (IntegerPart/10)%10;
 buf[2] = (IntegerPart/100)%10;
 buf[3] = (IntegerPart/1000)%10;

   for (i=3;i>=1;i--)//从最高位起,为0不显示,直到非零
    {
       if(buf[i]==0)
	     LedBuff[i+2]=0x00;
	   else
	     break;   
    }
	for(;i>=0;i--) //剩余的转化成数码管显示的值
   {
   	 LedBuff[i+2]=LedChar[buf[i]];
   }
   LedBuff[2]|=0x80;//点亮小数点
}

void StopwatchAction()//秒表器启动停止函数
{
   if(StopwatchRunning)
     StopwatchRunning = 0;//已启动则停止
   else
     StopwatchRunning = 1;//已停止则启动
}

void StopwatchReset()//秒表复位函数
{
  StopwatchRunning = 0;//停止秒表
  DecimalPart = 0;//清0计数值	   
  IntegerPart = 0;
  StopwatchRefresh = 1;//重置刷新标志
}

void KeyDriver()//检测按键状态并执行操作,主函数调用
{
  unsigned char i;
  static unsigned char backup[4] = {1,1,1,1};//按键值备份
    for (i=0;i<4;i++)//循环检测4*4矩阵按键
   	 {
		  if(backup[i]!=KeySta[i])//判断按键是否按下
		    {
			  if(backup[i]!=0)//按键按下就执行
			   {
			   	 if(i == 1)
				   StopwatchReset();
				 else if(i == 2)
				   StopwatchAction();
			   }
			   backup[i] = KeySta[i];//刷新前一次的备份值
			}
	 }
}

void KeyScan()	//按键扫描函数,在中断中调用
{
  unsigned char i;
  static unsigned char keybuf[4]={0xff,0xff,0xff,0xff};//按键扫描缓冲区
  keybuf[0] = (keybuf[0]<<1) | keys1; //将按键状态移入缓冲区
  keybuf[1] = (keybuf[1]<<1) | keys2;
  keybuf[2] = (keybuf[2]<<1) | keys3;
  keybuf[3] = (keybuf[3]<<1) | keys4;
 
    for(i=0;i<4;i++)//消抖更新按键状态
  {
  	if(keybuf[i]==0x00)	//连续扫描4次值为0,则认为按键已经按下
	KeySta[i]=0;
	else if(keybuf[i]==0xff)
	KeySta[i]=1;
  }
}

void LedScan()//数码管动态刷新
{
    static unsigned char i = 0;
    DU=1;
	P0 = 0x00;
    DU=0;
    switch(i)
        {
           case 0:WE= 1;P0=0x7f;i++;WE=0; DU=1;P0=LedBuff[0]; DU=0;break;     
           case 1:WE= 1;P0=0xbf;i++;WE=0; DU=1;P0=LedBuff[1]; DU=0;break;     
           case 2:WE= 1;P0=0xdf;i++;WE=0; DU=1;P0=LedBuff[2]; DU=0;break;     
           case 3:WE= 1;P0=0xef;i++;WE=0; DU=1;P0=LedBuff[3]; DU=0;break;     
           case 4:WE= 1;P0=0xf7;i++;WE=0; DU=1;P0=LedBuff[4]; DU=0;break;
           case 5:WE= 1;P0=0xfb;i=0;WE=0; DU=1;P0=LedBuff[5]; DU=0;break;                               		                                  
           default: break;
        }            
 
}

void StopwatchCount()
{
   if(StopwatchRunning)//处于运行状态
   {
   	 DecimalPart++;	//小数部分加1
	   if(DecimalPart>=100)
	   {
	   	 DecimalPart = 0;
		 IntegerPart++;
		  if(IntegerPart>=10000)
		    IntegerPart = 0;
	   }
	   StopwatchRefresh = 1;
   }
}
		    	
void time_0() interrupt 1
{
static unsigned char flag10ms = 0;
  TH0 = T0RH;//加载T0的重载值
  TL0 = T0RL;
  LedScan();
  KeyScan();
  flag10ms++;
  if(flag10ms>=5)
  {
   flag10ms = 0;
   StopwatchCount();
  }

}

体原理每个部分都有注释

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值