#include
unsigned char code leddata[]= { 0x3F, 0x06, 0x5B, 0x4F, //0 1 2 3
0x66, 0x6D, 0x7D, 0x07, //4 5 6 7
0x7F, 0x6F, 0x77, 0x7C, //8 9 A b
0x39, 0x5E, 0x79, 0x71, //c d E F
0x76, 0x38, 0x37, 0x3E, //H L n u
0x73, 0x5C, 0x40, 0x00, //P o - 清屏
};
#define digitData P0 //数码管数据
#define startBtn 0 //按键值
#define resetBtn 1
#define counterBtn 2
sbit DX = P2^6;//段选
sbit WX = P2^7;//位选
sbit kaiShi = P3^4;//开始、暂停按键
sbit chongZhi = P3^5;//重置按键
sbit jiCi = P3^6;//计次、记录查看按键
unsigned int recode[8] = {0};//记录数据
unsigned char recodeNum = 0;//记录数据值位置
unsigned char showRe = 0; //查看哪项记录值
unsigned int times = 0; //当前计时时间
unsigned int saveTimes = 0;//暂停查看记录时保存时间数据
unsigned char counter = 0;//定时器次数,构成100ms
unsigned char shuanXi = 0,sXW = 1;//刷新数码管
unsigned char runState = 0;//0表示停止,1表示运行
unsigned char keyTemp[3]= {0}; //按键按下状态持续时间
//六位数码管显示 dat:显示内容下标 wei:哪一个数码管
void display(unsigned char dat,unsigned char wei)//wei 1-6
{
digitData = 0xff; //关掉显示 消除重影
WX = 1;
WX = 0;
//如果不先关闭显示,不论先段选还位选(位选前关闭都不行),而且必须先送段选,再送位选,
//先位选则当前位置会显示上次残留段选数据 导致重影
digitData = leddata[dat];//段选
DX = 1;
DX = 0;
digitData = ~(1<
WX = 1;
WX = 0;
}
//判断当前按键
unsigned char scanKey()
{
P3 = 0x70;//k1 k2 k3给高
if(kaiShi==0)//开始键按下
{
if(keyTemp[0] == 0) keyTemp[0]=1 ;//按键按下 开始记延时
}
else
{
keyTemp[0] = 0; //有抖动重新延时
}
if(chongZhi==0)
{
if(keyTemp[1] == 0) keyTemp[1]=1 ;
}
else
{
keyTemp[1] = 0;
}
if(jiCi==0)
{
if(keyTemp[2] == 0) keyTemp[2]=1 ;
}
else
{
keyTemp[2] = 0;
}
if(keyTemp[0]>5) return startBtn; //5次 5*2ms 超过10ms 消抖
if(keyTemp[1]>5) return resetBtn;
if(keyTemp[2]>5) return counterBtn;
return 0xFF; //没有按键
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
//AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xCF; //设置定时初值
TH0 = 0xF8; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //运行定时器0中断
EA = 1; //开全局中断
}
void main()
{
unsigned char keyValue = 0xFF,keyT = 0xFF;//按键值
unsigned char weiXian[6] = {0,22,0,0,22,0};
Timer0Init();
while(1)
{
if(shuanXi)//刷新sXW位置的数码管中
{
if(times>=6000) //十分钟
{
times = 0;
}
weiXian[0] = times/600;//分钟
weiXian[2] = times/10%60/10;
weiXian[3] = times/10%60%10;
weiXian[5] = times%10;
display(weiXian[sXW-1],sXW);
shuanXi = 0;
}
keyT = scanKey();//当前按键值
if(keyT!=keyValue)//当前按键值与上次按键值不同,则表示按键状态改变。需要做按键处理
{
keyValue = keyT;
//P1 = keyValue;
switch(keyValue)//按键处理
{
case startBtn://开始暂停按下
//if(runState) TR0 = 0; else TR0 = 1;
//runState ? (TR0 = 0) : (TR0 = 1);
runState = !runState;//改变状态
if(runState)//恢复时间
{
times = saveTimes;
}
else//保存时间
{
saveTimes = times;
}
break;
case resetBtn: //重置
if(!runState)
{
times = 0;
saveTimes = 0;
recodeNum = 0;
P1 = 0xFF;
}
break;
case counterBtn: //记录或查看记录
if(runState)//运行时,记录
{
if(recodeNum<8)
{
recode[recodeNum++] = times;
P1 = (0xFF<
}
}
else//暂停查看记录
{
P1 = (0xFF ^(1 << showRe));//点亮showRe位置的灯
times = recode[showRe++];
if(showRe >= recodeNum)
{
showRe = 0;//循环查看记录
}
}
break;
}
}
}
}
void T0_2ms() interrupt 1
{
//定时器重新赋初值 放在终端服务程序最开始有利于降低定时中断误差
TL0 = 0xCF; //设置定时初值
TH0 = 0xF8; //设置定时初值
if(++counter>=50 && runState)//运行状态下100ms 加0.1秒
{
times++;
counter = 0;
}
shuanXi = 1;//数码管周期刷新
if(++sXW>6) //六位循环刷新
{
sXW = 1;
}
if(keyTemp[0]) keyTemp[0]++;//按键持续
if(keyTemp[1]) keyTemp[1]++;//按键持续
if(keyTemp[2]) keyTemp[2]++;//按键持续
}