目录
一、设计内容
内容:用单片机控制实现基本数字电子钟的设计,扩展了4X4键盘和4位LED数码显示器,可用于显示和按键控制。
功能:能够显示时和分;可通过按键设置闹钟功能;可进行整点报时;可通过按键设置分校时。
二、总体方案设计
2.1 功能分析
数字电子钟系统可以分为主控制单元、复位电路、键盘电路、显示电路等。
2.2 各模块功能说明
晶振电路的功能:每个单片机系统里都有晶振,全程是叫晶体震荡器,在单片机系统里晶振的作用非常大,他结合单片机内部的电路,产生单片机所必须的时钟频率,单片机的一切指令的执行都是建立在这个基础上的,晶振的提供的时钟频率越高,那单片机的运行速度也就越快。晶振用一种能把电能和机械能相互转化的晶体在共振的状态下工作,以提供稳定,精确的单频振荡。
复位电路的功能:把电路初始化到一个确定的状态,一般来说,单片机复位电路作用是把一个例如状态机初始化到空状态,而在单片机内部,复位的时候单片机是把一些寄存器以及存储设备装入厂商预设的一个值。
键盘电路:根据4×4矩阵键盘,它是用四条I/O线作为行线,四条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4×4个。这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。实现按键控制闹钟,设置时间的功能。
显示电路的功能:采用4位共阴极数码管驱动方式P2口相应的位置0 即选择要显示的数码管位,P0口相应的位置1即可显示相应的数码管段。负责显示时钟的时和分。
三、硬件系统设计
使用了Produce软件进行硬件原理图的仿真设计。
部分电路如图所示:
a. 主控电路: 80C51单片机
b. 晶振电路:89C51单片机内部的振荡电路是一个高增益反相放大器,引线XTAL1和XTAL2分别 为反相振荡放大器的输入及内部时钟工作电路的输入和来自反相振荡器的输出,该反相放大 器可以配置为片内振荡器。
c. 复位电路:采用上电复位,上电后,由于电容充电,使RST持续一段时间的高电平,从而实 现上电复位操作。这不仅能使单片机复位,还能是单片机的外围设备同时复位,当程序出 现错误时,可以随时使电路复位。
d. 键盘电路:当按键被按下时,相应的引脚被拉低,经扫描后,获得键值,并执行键功能程 序,因此通过按下同一个键,将执行不同的功能程序。
e. 显示电路:主要是数码管显示数字电子钟的时和分。
四、软件系统设计
4.1 程序总体流程图
主函数的流程框图:先进行初始化设定初值,然后相关子程序的调用
4.2 主要模块程序流程
1.调用中断服务子程序,循环次数++,因为定时时长为50ms,所以循环次数为20时,循环次数清0,秒++;秒为60时分加++,秒清0;分为60时,时++,分清0;时为24时,时清0,中断返回。
2.先确认弹簧消抖是否有键按下,之后判断扫描按键,不同的按键触发不同功能。
五、源代码
部分代码展示:
#include<reg51.h>
#define tl 0xba; //宏定义 tl赋初值
#define th 0x3c; //宏定义 th赋初值
sbit speaker=P3^5; //闹钟输出 蜂鸣器
unsigned char code led[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //数码管显示的数字0-9的编码
unsigned char count0,second,minit,hour; //时间时分秒
unsigned int second1,minit1,hour1;//闹钟时分秒
//timenum1是调节时间的按键按下的次数
//timenum2是调节闹钟的按键按下的次数
//f1是否在设置闹钟
//f2是否在设置时间
unsigned char timenum1,timenum2,f1,f2;
unsigned int dsflg;
unsigned char temp;
//延时子程序 代码烧路软件自动生成的
void delay(void)
{
unsigned int i;
for(i=0;i<100;i++);
}
//50ms
//数码管显示
void display(void)
{
P0=led[hour/10]; //p0口送数据 拆数显示,时的十位
P2=0xFE; //片选 P2.0
delay(); //延时
P2=0xFF; //片选关
P0=led[hour%10]; //p0口送数据 拆数显示,时的个位
P2=0xFD; //P2.1
delay();
P2=0xFF;
P0=led[minit/10]; //p0口送数据 拆数显示,分的十位
P2=0xFB; //P2.2
delay();
P2=0xFF;
P0=led[minit%10]; //p0口送数据 拆数显示,分的个位
P2=0xF7; //P2.3
delay();
P2=0xFF;
}
//扫描按键
void keyscan()
{
unsigned char temp;
P1=0xfe; // 给P1.0赋低电平
temp=P1;
temp=temp&0xf0; //判断P1.0那一列是否有键按下
if(temp!=0xf0)// 确定有键按下的时候
{
delay1(10); //延时子程序进行消抖
temp=P1;
temp=temp&0xf0; //再次判断p1.0那一列是否有键按下
if(temp!=0xf0) //确定有键按下
{
temp=P1; //将P1的值给temp
switch(temp)
{
case 0xee: //p1.4口
timenum1++; //标记++
TR1=0; //不启动T1 ,关闭蜂鸣器
f2=0; //进入调时间的状态
if(timenum1==1||timenum2==1) //如果timenum1==1 调时
{
dsflg=0; //正在调时间
}
if(timenum1==3) 如果timenum1==4 退出
{
TR1=1; //启动T1
timenum1=0; //将按键次数归零
dsflg=1; //退出调时间
f2=1; //退出调节时间
}
break;
case 0xde: //p1.5口
//调时间
if(timenum1==1) //如果timenum1==1 调时
{
hour++; //小时++
}
if(timenum1==2) //如果timenum1==2 调分
{
minit++;
}
//调闹钟
if(timenum2==1) //如果timenum2==1 调时 闹钟
{
hour1++; //小时++
}
if(timenum2==2) //如果timenum2==2 调分 闹钟
{
minit1++;
}
break;
case 0xbe: //p1.6口
speaker=1; //蜂鸣器处于不响状态在设置时间的时候
if(timenum1==1) //如果timenum1==1 调时
{
hour--; //小时--
}
if(timenum1==2) //如果timenum1==2 调分
{
minit--; //分钟--
}
//调闹钟
if(timenum2==1) //如果timenum2==1 调时 闹钟
{
hour1--; //小时--
}
if(timenum2==2) //如果timenum2==2 调分 闹钟
{
minit1--;
}
break;
case 0x7e://p1.7
timenum2++; //标记++
f1=0; //进入设置闹钟
if(timenum2==1||timenum2==2) //如果timenum2=1设定脑钟的小时
{
dsflg=0; //正在调时间
}
if(timenum2==3) //如果timenum2=3退出
{
timenum2=0; //将按键次数归零
dsflg=1; //退出调时间
f1=1; // 退出设置闹钟
}
break;
}
while(temp!=0xf0) //判断按键是否弹起
{
temp=P1;
temp=temp&0xf0;
}
}
}
}
//按键控制 时间设置
void Keykonzhi()
{
if(timenum1==1) //如果timenum1==1 调时
{
if(hour>23) //限位
{
hour=0;
}
P0=led[hour/10]; //显示小时
P2=0xFE; //小时十位 p2.0
delay();
P2=0xFF;
P0=led[hour%10]; //显示小时
P2=0xFD; //小时个位 p2.1
delay();
P2=0xFF;
}
if(timenum1==2) 如果timenum1==2 调分 //以下也是和调时一样的方法
{
if(minit>59)
{
minit=0;
}
P0=led[minit/10];
P2=0xFB; //分钟十位 p2.2
delay();
P2=0xFF;
P0=led[minit%10];
P2=0xF7; //分钟个位 p2.3
delay();
P2=0xFF;
}
}
//设置闹钟
void almset()
{
timenum1=0;
if(timenum2==1) //如果timenum2==1设定闹钟的小时
{
if(hour1>23) //限位
{
hour1=0;
}
P0=led[hour1/10];//小时显示 十位
P2=0xFE;//p2.0
delay();
P2=0xFF;
P0=led[hour1%10];
P2=0xFD;//p2.1 小时个位 显示
delay();
P2=0xFF;
}
if(timenum2==2) //如果timenum2==2设定闹钟的分钟 和上面小时一样
{
if(minit1>59)
{
minit1=0;
}
P0=led[minit1/10];//显示分钟十位
P2=0xFB; // p2.2
delay();
P2=0xFF;
P0=led[minit1%10];//显示分钟个位
P2=0xF7;// p2.3
delay();
P2=0xFF;
}
}
//控制闹钟 (闹钟到了设定时间就会响)
void almkozi()
{
if((hour1==hour)&&(minit1==minit)&&(second<4))
{
speaker=0; //闹钟时间到,蜂鸣器响
}
if(minit==0&&second<4)
{
//整点报时,蜂鸣器响
speaker=0;
}
if(second>4) //控制蜂鸣器响的时长
{
speaker=1; //关闭蜂鸣器
}
}
六、测试结果展示
1. 时钟显示:最开始设置时间为12:59。
2 . 闹钟调时:手动按键调整时钟的时。
3. 闹钟调分:手动按键调整时钟的分。
4. 整点报时:时钟到整点蜂鸣器就会响,达到报时的效果。
七、设计总结
在做课程设计的过程中,我进一步认识到全面专业知识以及逻辑思考方式对研究问题的重要性,同时我也更加具体的掌握了课程设计的基本方法。经过不断的努力,我终于完成了这次课程设计,总的来说,我学到了不少的东西,知道了理论联系实际的重要性。在设计过程中我遇到了很多的困难,但没放弃,查阅了许多相关的书籍,自己独立思考和借鉴了前人的许多优秀成果,并与所学的知识紧密的结合了起来。我相信这过程对我今后的学习和工作有着积极的影响,并搭好了平台。通过这次设计,我对这门课有了更好的理解,尤其结合了这几年学的相关的专业知识,对各门课都有了一个较全面的理解。这必将对我以后的学习和工作有很大的帮助。本次课程设计的定时闹钟电路,可以满足人们的基本要求,但因为知识水平有限,此电路中存在一定的问题,虽可以通过增加电路解决,但过于复杂和现有水平有限,本次设计就未深入涉及,想要更好的改进电路,需要进一步的努力,如果有好的意见,希望老师给予支持指导。
篇幅有限,只写了一部分内容,若想获取源代码和课程设计报告的请戳