此次的设计方案选定为: 以单片机STC89C52RC为主控制器,采用单片机内部定时、键盘和动态LED显示数码管设计定时器,选择5位数码管做显示,实现5种倒计时模式,通过控制按键进行选择。
1、99999s-0s
2、9999s-0s
3、999s-0s
4、99s-0s
5、9s-0s
6、开始值由人工输入-0s
#include<reg52.h>
#define uchar unsigned char
sbit ADDR0=P1^0; //亮哪个数码管
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;
uchar cnt=0;//定时器计数 --软件计数器变量,初始化为0
int sec=59; //模式2-模式5 9999,999,99,9
unsigned char sec2[5]={9,9,9,9,9}; //模式1:99999 5个9的情况
int t=0; //一些键值判断需要
unsigned char code KeyCode[]={0xE7,0XD7,0XB7,0X77,0XEB,0XDB,0XBB,0X7B,0XED,0XDD,0XBD,0X7D,0XEE,0XDE,0XBE,0X7E};//矩阵键值
unsigned int key; //按了哪一个键(下标从0开始)
int input[10]; //模式6人工输入
int q=0; //input数组的每一位
int count=0;
unsigned char code led[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff}; //数码管亮几从0-9 我们需要
void delay_ms(unsigned int cnt) //延迟函数,用在按键扫描去抖和数码管延时来取得肉眼看数码管之间一起亮的效果
{
unsigned char i;
while(cnt--)
{
for(i=0;i<=110;i++);
}
}
void scankeyboard() //键盘扫描函数
{
//P2.0-P2.3为Keyout4-Keyout1为输出口连接4条行线 P2.4-p2.7(keyin1-keyin4)为输入口连接4条列线
unsigned char scan1,scan2,keyboard;
unsigned char i;
P2=0xf0;//4条行线输出电平,4条列线作为输出
scan1=P2;//读取列线状态
if(((scan1)&0xf0)!=0xf0) //判断是否有键按下
{
delay_ms(10); //延时去抖
scan1=P2; //再次读取列线状态
if(((scan1)&0xf0)!=0xf0) //再次判断 是否有键按下
{
P2=0x0f; //4条列线线输出电平,4条行线作为输出
scan2=P2; //读取行线状态
keyboard=scan1|scan2; //组合键值
while((P2&0x0f)!=0x0f); //等待按键释放
for(i=0;i<=15;i++)//根据按键编码得出按键编号
{
if(keyboard==KeyCode[i])
key=i; //key为全局变量,就是key为按了哪个键(主函数反复要用到他判断)
}
}
}
}
void main()
{
int temp;
ENLED=0; //这两位是固定好的 数码管要用哪一个
ADDR3=1;
//定时器:
//1.首先要确定TMOD寄存器值(设置定时器T0工作在模式及工作方式1下,起停由TR0控制)
//2.确定计数初值:晶振为11.0592Mhz,是实现一个50ms的定时器,定时时间到将计数器cnt+1,如果当cnt=20时,20*50ms=1s
//初值计算公式:X=M(最大计数值)-C(计数器记满回零所需的计数值) M:方式1的M(16位计数器):2^16
//(2^16-x)*12/(11.05952*10^6)=0.05-->x=19456(十进制)-->十六进制为:4C00;
//所以TH0=0X4C,TL0=0X00
TMOD=0x01; //设置T0为模式1
TH0=0x4C;
TL0=0x00; //50ms定时
IE=0x82; //允许T0中断 或者写成EA=1(中断请求中开关); ET0=1(允许T0中断) 寄存器IE中就变成10000010 所以为0x82
TR0=1; //启动定时器T0 寄存器TCON中的TR0=1启动定时器的工作 可位寻址
while(1)
{ key=-1;
scankeyboard(); //扫描
t=key; //按了几
if(t==0) //k1键 模式1,赋值
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
else if(t==1) //k2键 模式2 赋值
sec=9999;
else if(t==2) //k3键 模式3 赋值
sec=999;
else if(t==3) //k4键 模式4 赋值
sec=99;
else if(t==4) //k5键 模式5 赋值
sec=9;
else
sec=0;
while(key==4)//9 如果按了k5键一直执行模式5(显示9的倒计时)除非key!=4
{
ADDR2=0;
ADDR1=0;
ADDR0=0; //选择数码管6个的右边第一个数码管
temp=sec;
P0=led[temp];//把时间显示在数码管上
delay_ms(2);
scankeyboard();//扫描矩阵键
t=key; //看有没有其他键按下
}
if(t==0)
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
else if(t==1)
sec=9999;
else if(t==2)
sec=999;
else if(t==3)
sec=99;
else if(t==4)
sec=9;
else
sec=0;
while(key==3) //99 如果按了k4键一直执行模式4(显示99的倒计时)除非key!=3
{
ADDR2=0;
ADDR1=0;
ADDR0=0; //选择数码管的左边第一个
temp=sec%10; // 显示99的个位
P0=led[temp];
delay_ms(2); //延时使肉眼看见是同时闪烁
ADDR2=0; //选择数码管的左边第二个
ADDR1=0;
ADDR0=1;
temp=sec/10%10; // 显示99的十位
P0=led[temp];
delay_ms(2);
scankeyboard(); //扫描矩阵键
t=key; //看看有没有其他键按下
}
if(t==0)
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
else if(t==1)
sec=9999;
else if(t==2)
sec=999;
else if(t==3)
sec=99;
else if(t==4)
sec=9;
else
sec=0;
while(key==2) //999 如果按了k3键一直执行模式3(显示999的倒计时)除非key!=2
{
ADDR2=0;
ADDR1=0; //选择最左边的第一位数码管
ADDR0=0;
temp=sec%10; //显示999倒计时的个位
P0=led[temp];
delay_ms(2); //延时
ADDR2=0; //选择最左边的第二位数码管
ADDR1=0;
ADDR0=1;
temp=sec/10%10; //显示999倒计时的十位
P0=led[temp];
delay_ms(2); //延时
ADDR2=0; //选择最左边的第三位数码管
ADDR1=1;
ADDR0=0;
temp=sec/100%10; //显示999倒计时的百位
P0=led[temp];
delay_ms(2); //延时
scankeyboard(); //扫描矩阵键
t=key; //看看有没有其他键按下
}
if(t==0)
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
else if(t==1)
sec=9999;
else if(t==2)
sec=999;
else if(t==3)
sec=99;
else if(t==4)
sec=9;
else
sec=0;
while(key==1) //9999 如果按了k2键一直执行模式2(显示9999的倒计时)除非key!=1就结束循环
{
ADDR2=0;
ADDR1=0;
ADDR0=0; //选择数码管最左边的第一位
temp=sec%10; //显示9999的个位在数码管的最左边的第一位
P0=led[temp];
delay_ms(2);
ADDR2=0; //选择数码管最左边的第二位
ADDR1=0;
ADDR0=1;
temp=sec/10%10; //显示9999的十位在数码管的最左边的第二个数码管
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=0; //选择数码管最左边的第三位
temp=sec/100%10; //显示9999的百位在数码管的最左边的第三个数码管
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=1; //选择数码管最左边的第三位
temp=sec/1000%10; //显示9999的百位在数码管的最左边的第三个数码管
P0=led[temp];
delay_ms(2);
scankeyboard();
t=key;
}
if(t==0)
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
else if(t==1)
sec=9999;
else if(t==2)
sec=999;
else if(t==3)
sec=99;
else if(t==4)
sec=9;
else
sec=0;
while(key==0) //99999 如果按了k1键一直执行模式1(显示99999的倒计时)除非key!=0就结束循环
{
ADDR2=0;
ADDR1=0; //选择数码管最左边的第1个
ADDR0=0;
temp=sec2[4]; //显示在数组sec2的最低位 99999的个位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=0;
ADDR0=1; //选择数码管最左边的第2个
temp=sec2[3]; //显示在数组sec2的倒数第二位 99999的十位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=0; //选择数码管最左边的第3个数码管
temp=sec2[2]; //显示在数组sec2的最低位 99999的百位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=1;
temp=sec2[1]; //选择数码管最左边的第4个数码管
P0=led[temp]; //显示在数组sec2的最低位 99999的千位
delay_ms(2);
ADDR2=1;
ADDR1=0;
ADDR0=0;
temp=sec2[0]; //选择数码管最左边的第5个数码管
P0=led[temp]; //显示在数组sec2的最低位 99999的万位
delay_ms(2);
scankeyboard(); //时时检测有没有其他键按下
t=key;
}
if(t==0)
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
else if(t==1)
sec=9999;
else if(t==2)
sec=999;
else if(t==3)
sec=99;
else if(t==4)
sec=9;
else
sec=0;
if(key==14) //如果按了k15键 开始模式6的人工输入
{ key=-1;
q=0;
t=-1;
while(t!=13) //按了k14键退出输入,输入结束
{
if(q==0)
{
scankeyboard();
t=key;
}
if(t!=-2&&t!=13&&t!=14&t!=-1)//不是结束键不是开始输入键不是检查键
{ input[q++]=t; //把输入的数存进数组的对应一位,存完后加1
ADDR2=0;
ADDR1=0;
ADDR0=0;
temp=input[q-1]; //把输入的数显示在数码管的左边第一位来让使用者知道自己按了多少
P0=led[temp];
delay_ms(2);
}
key=-2; //按完之后马上将键值改变,否则,就算没按也会被扫描成上个键的值key是上个值 检查键
scankeyboard();
t=key;
}
}
if(q>0) //如果人工输入了值
{
while(key==5) //模式6可以用了, 按k6
{
if(q==1) //判断输入的是一位数的话
{ ADDR2=0;
ADDR1=0;
ADDR0=0;
temp=input[0]; //显示在一个数码管一位
P0=led[temp];
delay_ms(2);
}
else if(q==2) // 如果输入的是 二位数
{ ADDR2=0;
ADDR1=0;
ADDR0=0;
temp=input[1]; //显示在二位数码管个位和十位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=0;
ADDR0=1;
temp=input[0];
P0=led[temp];
delay_ms(2);
}
else if(q==3) //3位数
{ ADDR2=0; //个位
ADDR1=0;
ADDR0=0;
temp=input[2];
P0=led[temp];
delay_ms(2);
ADDR2=0; //十位
ADDR1=0;
ADDR0=1;
temp=input[1];
P0=led[temp];
delay_ms(2);
ADDR2=0; //百位
ADDR1=1;
ADDR0=0;
temp=input[0];
P0=led[temp];
delay_ms(2);
}
else if(q==4) //4位数
{ ADDR2=0;
ADDR1=0;
ADDR0=0;
temp=input[3];//个位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=0;
ADDR0=1;
temp=input[2]; //十位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=0;
temp=input[1];//百位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=1;
temp=input[0];//千位
P0=led[temp];
delay_ms(2);
}
else if(q==5) //5位数
{ ADDR2=0;
ADDR1=0;
ADDR0=0;
temp=input[4];//个位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=0;
ADDR0=1;
temp=input[3]; //十位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=0;
temp=input[2];//百位
P0=led[temp];
delay_ms(2);
ADDR2=0;
ADDR1=1;
ADDR0=1;
temp=input[1];//千位
P0=led[temp];
delay_ms(2);
ADDR2=1;
ADDR1=0;
ADDR0=0;
temp=input[0];//万位
P0=led[temp];
delay_ms(2);
}
scankeyboard();
t=key;
}
}
}
}
void clock() interrupt 1 //中断函数 中端号为1:定时器T0溢出中断请求
{
cnt++;//软件计数器变量
TH0=0x4C;
TL0=0x00;
if(cnt==20)//1s
{
cnt=0;
sec--; //模式2-模式5用sec倒计时每过一秒减1
if(sec<0) //模式2-模式5的倒计时归位
{ if(key==1)
sec=9999;
if(key==2)
sec=999;
if(key==3)
sec=99;
if(key==4)
sec=9;
}
if(key==5) //模式6人工输入的倒计时
{
if(q==1) //如果是输入了一位数
{
input[0]--; //每一秒到了个位减一
}
else if(q==2) //如果是输入了二位数
{
input[1]--; //每一秒到了个位数减1
if(input[1]<0) //如果个位数小于0了,从十位借1,十位减1
{
input[1]=9;
input[0]--;
}
}
else if(q==3) //如果输入了三位数
{
input[2]--; //每一秒到了个位数减一
if(input[2]<0) //如果个位数小于0了,从十位借1,十位减1
{
input[2]=9;
input[1]--;
}
if(input[1]<0) //如果十位数小于0了,从百位借1,百位减1
{
input[1]=9;
input[0]--;
}
}
else if(q==4) //四位数
{
input[3]--; //每一秒到了个位数减1
if(input[3]<0) //如果个位数小于0了,从十位借1,十位减1
{
input[3]=9;
input[2]--;
}
if(input[2]<0)//如果十位数小于0了,从百位借1,百位减1
{
input[2]=9;
input[1]--;
}
if(input[1]<0) //如果百位数小于0了,从千位借1,千位减1
{
input[1]=9;
input[0]--;
}
}
else if(q==5) //五位数
{
input[4]--; //每一秒到了个位数减1
if(input[4]<0) //如果个位数小于0了,从十位借1,十位减1
{
input[4]=9;
input[3]--;
}
if(input[3]<0) //如果十位数小于0了,从百位借1,百位减1
{
input[3]=9;
input[2]--;
}
if(input[2]<0) //如果百位数小于0了,从千位借1,千位减1
{
input[2]=9;
input[1]--;
}
if(input[1]<0) //如果千位数小于0了,从万位借1,万位减1
{
input[1]=9;
input[0]--;
}
}
}
if(key==0) //模式1 99999的倒计时
{
sec2[4]--; //每一秒到了个位减一
if(sec2[4]<0) //如果个位数小于0了,从十位借1,十位减1
{
sec2[3]--;
sec2[4]=9;
}
if(sec2[3]<0) //如果十位数小于0了,从百位借1,百位减1
{
sec2[2]--;
sec2[3]=9;
}
if(sec2[2]<0) //如果百位数小于0了,从千位借1,千位减1
{
sec2[1]--;
sec2[2]=9;
}
if(sec2[1]<0) //如果千位数小于0了,从万位借1,万位减1
{
sec2[0]--;
sec2[1]=9;
}
if(sec2[0]==0)//倒计时结束等于0了,则归位重新倒计时
{
sec2[0]=9;
sec2[1]=9;
sec2[2]=9;
sec2[3]=9;
sec2[4]=9;
}
}
}
}