声明:本博客内容全部原创,若要转载,请注明出处,谢谢合作!
插图的完整程序在附件中,有兴趣者下载!https://static.assets-stash.eet-china.com/album/old-resources/2009/5/13/a02e6e67-eea8-4397-b11a-0802c4beff7a.rar
目录
1 实验环境 1
1.1采用 Proteus6_9_SP5实现单片机及外围器件的仿真 1
1.2使用Keil uVision3编写本时钟程序(C语言) 1
2 原理图 2
3 程序分析及代码 3
3.1程序分析 3
3.2源代码 4
4 效果图 15
4.1正常显示效果 15
4.2闹钟设置效果 15
4.3功能选择模式效果 16
4.4调时效果 17
1 实验环境
1.1采用 Proteus6_9_SP5实现单片机及外围器件的仿真
如图:
1.2使用Keil uVision3编写本时钟程序(C语言)
如图:
2 原理图
各部分功能实现:
? 通过AT89C52的P2口控制数码管的段选,决定显示的数值;
? 通过AT89C52的P1口及38译码器控制数码管的位选,决定显示哪一位数码管;
? 通过AT89C52的P0口与1*4矩阵键盘连接执行相应功能;
? led发光二极管在闹钟定的时间到达时点亮;
? 因为P0口没有上拉电阻,所以与排阻相连。
3 程序分析及代码
3.1程序分析
3.1.1程序的优点
首次在程序中使用了数组、指针及函数,指针做了函数的参数,大大减少了代码的编写量;
3.1.2程序的缺点
在调试和设置闹钟时可能会出现时钟暂停的情况;设置闹钟函数不够简洁;闪烁不够稳定。
3.1.3总结
此实验是我们学习单片机以来写的第一个较正式的程序,难免存在不足之处。
3.2源代码
E-clock.c程序文件:
#include "E-clock.h"
/*************以下是主函数**************/
void main()
{
iniTimer(); //首先初始化定时计数器
while(1)
{
display(); //调用显示函数
keyScan(); //扫描键盘
bellClock(); //扫描闹钟是否到点
}
}
E-clock.h程序文件:
/*************以下是宏定义**************/
#include <reg52.h>
#define uchar unsigned char //将unsigned char用uchar表示
#define uint unsigned int
/*************以下是功能函数声明**************/
void iniTimer(); // 定时计数器初始化函数
void display(); // 显示模式变换函数
void normalDisplay(uchar *tmp); // 正常显示函数
void oneWeiDisplay(uchar num,uchar wei);// 一位数码管显示函数
void numCount(); // 时间进位函数
void flash(uchar num,uchar wei); // 单位数码管闪动函数
void keyScan(); // 键盘扫描函数
void numadd(uchar *tmp); // 数字加一函数
void bellClock(); // 闹钟定时函数
void delay(); // 延时函数
/*************以下是变量声明**************/
uchar code numTable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,
0x7d, 0x07,0x7f,0x6f,0x40}; //数字字符编码表
uchar code weiTable[]={0x00,0x01,0x02,0x03,0x04,0x05,
0x06,0x07}; // 数码管位编码表
uchar numTmp[6]={0}; // 正常显示的时分秒数据存储数组
uchar bellTmp[6]={0}; // 存储闹钟时间的数据存储数组
sbit Led="P3"^0; // 小灯的位定义
uchar time,flsh,enter,ok,value=1,move; // 各个变量的定义
/*************以下是功能函数定义**************/
void iniTimer()
{
EA=1; //开中断总开关
ET1=1; //允许T1中断
TMOD=0x10; //T1工作于定时方式1
TH1=(65536-50000)/256; //送定时初值高八位
TL1=(65536-50000)%256; //送定时初值低八位
TR1=1; //启动T1工作
}
void display()
{
numCount();
if(enter==1&&ok!=1) //当按下“进入/退出”键后,且没有//按下“确认”键时,进入功能模式,显示1
oneWeiDisplay(value,0);
else if(value==1) //当显示“1”时按下“确认”键,进入//调时模式
normalDisplay(numTmp);
else if(value==2) //当显示“2”时按下“确认”键,
//进入闹钟设置模式
normalDisplay(bellTmp);
}
void normalDisplay(uchar *tmp)
{
if(enter==1&&ok==1&&move==5)//如果进入了模式且按下了//“确认”键且选中最右边数码管
{flash(tmp[0],7);} //那么该位数码管闪动,此时若
//按下“加一”键可以实现加1操作
else oneWeiDisplay(tmp[0],7);//如果没有按键,则正常显示
if(enter==1&&ok==1&&move==4)
{flash(tmp[1],6);}
else oneWeiDisplay(tmp[1],6);
oneWeiDisplay(10,5); //秒与分中间的 “-”
if(enter==1&&ok==1&&move==3)
{flash(tmp[2],4);}
else oneWeiDisplay(tmp[2],4);
if(enter==1&&ok==1&&move==2)
{flash(tmp[3],3);}
else oneWeiDisplay(tmp[3],3);
oneWeiDisplay(10,2); //分与时之间的“-”
if(enter==1&&ok==1&&move==1)
{flash(tmp[4],1);}
else oneWeiDisplay(tmp[4],1);
if(enter==1&&ok==1&&move==0)
{flash(tmp[5],0);}
else oneWeiDisplay(tmp[5],0);
}
void oneWeiDisplay(uchar num,uchar wei)
{
P2=numTable[num];
P1=weiTable[wei];
delay();
P2=0; //让数码管熄灭一下,起到消影的效果
}
void numCount() //实现秒到分,分到时的进位
{
if(time==20)//定时计数器计数20次后 ,达到1秒,time标志//重新置为0
{
time=0;
numTmp[0]++; //秒位加1
}
if(numTmp[0]>9)
{
numTmp[0]=0;
numTmp[1]++;
}
if(numTmp[1]>5)
{
numTmp[1]=0;
numTmp[2]++;
}
if(numTmp[2]>9)
{
numTmp[2]=0;
numTmp[3]++;
}
if(numTmp[3]>5)
{
numTmp[3]=0;
numTmp[4]++;
}
if(numTmp[4]>9)
{
numTmp[4]=0;
numTmp[5]++;
}
if(numTmp[5]==2&&numTmp[4]==4) //到24整点时,从0点//开始重新显示
{
numTmp[4]=0;
numTmp[5]=0;
}
}
void flash(uchar num,uchar wei)
{
flsh++; //让该位数码管灭6次亮一次 ,达到闪烁效果
P2=0;
P1=weiTable[wei];
delay();
if(flsh==6)
{
oneWeiDisplay(num,wei);
flsh=0;
}
}
void keyScan()
{
P0=0x7f;
if(P0!=0x7f)
{
delay(); //键盘延时去抖
if(P0!=0x7f)
{
switch(P0)
{
case 0x7e: // “进入/退出”键
{
enter++; //首次按下该键后,enter标志为1,//进入功能选择模式,数码管显示一
if(enter==2){enter=0;ok=0;value=1; }//进入功
//能模式后,再次按下“进入/退出”键
break; //退出到正常显示状态
}
case 0x7d: // “加一”键
{
if(enter==1&&ok!=1) //当按下“进入/退出”键//后,且没有按下“确认”键时,实现1和2的选择
{
value++;
if(value>2)
value=1;
}
if(enter==1&&ok==1)//当按下“进入/退出”键后,//且按下“确认”键后实现时间的各位加1功能
{
if(value==1) numadd(numTmp);//调时模式时
if(value==2) numadd(bellTmp); //闹钟模式时
}
break;
}
case 0x7b: //“移位”键
{
move++; //实现数码管位的移动
if(move>5) move="0";
break;
}
case 0x77: //“确认”键
{
ok=1; //按下该键,ok标志置1
Led=1; //当小灯亮时,按下该键,小灯熄灭
break;
}
}
while(P0!=0x7f); //如果按键没有松开,则一直等待
}
}
}
void numadd(uchar *tmp)
{
switch(move)//按照时分秒的情况,限制加数的范围
{
case 0: tmp[5]++;if(tmp[5]>2) tmp[5]=0; break;
case 1:tmp[4]++;if(tmp[5]==2&&tmp[4]>3)
tmp[4]=0;if(tmp[4]>9) tmp[4]=0; break;
case 2: tmp[3]++;if(tmp[3]>6) tmp[3]=0; break;
case 3: tmp[2]++;if(tmp[2]>9) tmp[2]=0; break;
case 4: tmp[1]++;if(tmp[1]>6) tmp[1]=0; break;
case 5: tmp[0]++;if(tmp[0]>9) tmp[0]=0; break;
}
}
void bellClock()//将实际时间与设好的闹钟时间比较,如果相等,//则小灯亮
{
if(bellTmp[0]==0&&bellTmp[1]==0&&bellTmp[2]==0&&bellTmp[3]==0&&bellTmp[4]==0&&bellTmp[5]==0)
Led=1; //因闹钟与实际时间初始值均是00-00-00,为了//程序初始时不让小灯亮,将此值屏蔽
else if(numTmp[0]==bellTmp[0]&&numTmp[1]==bellTmp[1]&&numTmp[2]==bellTmp[2]&&numTmp[3]==bellTmp[3]&&numTmp[4]==bellTmp[4]&&numTmp[5]==bellTmp[5]) Led="0";
}
void delay() //实现短暂时间的延时
{
uchar tmp;
for(tmp=0;tmp<200;tmp++);
}
//以下为定时器中断函数,实现50ms的计时
void time1() interrupt 3 using 1
{
TH1=(65536-50000)/256; //重新送初值
TL1=(65536-50000)%256;
time++;
}
4 效果图
4.1正常显示效果
4.2闹钟设置效果
(首次进入闹钟设置时默认为零点)
4.3功能选择模式效果
(注:1为调时)
(注:2为闹钟设置)
4.4调时效果
(注:通过按“加一”键,实现闪烁位的加一由于该位闪烁,所以截图时未显示出数字)
文章评论(0条评论)
登录后参与讨论