资源描述
. . .
单片微机原理与应用课 程 设 计
题 目 数 字 电 子 钟
系 (部) 机 电 工 程 系
班 级
姓 名
学 号
指导教师
2014 年 2 月 24 日至 3 月 7 日 共 2 周
2014 年 3 月 7 日
24 / 26
目 录
1 摘要1
2 硬件选择与电路设计2
2.1系统构成原理图2
2.2单片机的选择2
2.2.1单片机复位电路与晶振电路3
2.3时钟芯片DS13024
2.3.1 DS1302引脚说明4
2.3.2 DS1302电路设计与分析5
2.4显示电路与驱动6
3 软件设计与仿真调试8
3.1程序编写与调试8
3.2 仿真电路调试9
4总结与体会11
参考文献12
附录一 源程序13
附录二 仿真结果图22
1 摘要
时钟是现代社会应用广泛的计时工具,在航天、电子等科研单位,工厂、医院、学校等企事业单位,各种体育赛事与至我们每个人的日常生活中都发挥着重要的作用。
现今,高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟,石英表,石英钟都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要经常调校,数字式电子钟用集成电路计时时,译码代替机械式传动,用LED显示器代替指针显示,减小了计时误差。
电子时钟主要是利用电子技术将时钟电子化、数字化,拥有时间精确、体积小、界面友好、可扩展性能强等特点,被广泛应用于生活和工作当中。当今市场上的电子时钟品类繁多,外形小巧别致。也有体型较大的,诸如公共场所的大型电子报时器等。电子时钟首先是数字化了的时间显示或报时器,在此基础上,人们可以根据不同场合的要求,在时钟上加置其他功能,比如定时闹铃,万年历,环境温度、湿度检测,环境空气质量检测,USB扩展口功能等。
2 硬件选择与电路设计
2.1系统构成与原理图
整体电路由单片机、时钟芯片DS1302、复位电路、晶振电路、数码管驱动电路(74LS373)、显示电路(6位共阳数码管)构成。该硬件电路设计简单,抗干扰能力强。数字电子钟系统原理图如图2.1。
图2.1数字电子钟原理图
2.2 单片机的选择
目前在单片机系统中,应用比较广泛的微处理器芯片主要为8XC5X系列单片机。该系列单片机均采用标准MCS-52核,硬件资源相互兼容,品类齐全,功能完善,性能稳定,体积小,价格低廉,货源充足,调试和编程方便,所以应用极为广泛。
例如比较常用的AT89C2052单片机,带有2KB Flash可编程、可擦除只读存储器(E2PROM)的低压、高性能8位CMOS微型计算机。拥有15条可编程I/O引脚,2个16位定时器/计数器,6个中断源,可编程串行UART通道,并能直接驱动LED输出。
仅仅是为了完成时钟设计或者是环境温度采集设计,应用AT89C2052单片机完全可以实现。但是将两种功能结合在一片单片机上,就需要更多的I/O引脚,故本设计采用具有32根I/O引脚的AT89C52单片机。
AT89C52单片机是一款低功耗,低电压,高性能CMOS 8位单片机,片含4KB(可经受1000次擦写周期)的FLASH可编程可反复擦写的只读程序存储器(EPROM),器件采用CMOS工艺和ATMEI公司的高密度、非易失性存储器(NURAM)技术制造,其输出引脚和指令系统都与MCS-52兼容。片的FLASH存储器允许在系统可改编程序或用常规的非易失性存储器编程器来编程。因此,AT89C52是一种功能强,灵活性高且价格合理的单片机,可方便的应用在各个控制领域。
AT89C52具有以下主要性能:
1. 4KB可改编程序Flash存储器;
2. 全静态工作:0——24Hz;
3. 128×8字节部RAM;
4. 32个外部双向输入/输出(I/O)口;
5. 6个中断优先级; 2个16位可编程定时计数器;
6. 可编程串行通道;
7. 片时钟振荡器。
此外,AT89C52是用静态逻辑来设计的,其工作频率可下降到0Hz,并提供两种可用软件来选择的省电方式——空闲方式(Idle Mode)和掉电方式(Power Down Mode)。在空闲方式中,CPU停止工作,而RAM、定时器/计数器、串行口和中断系统都继续工作。在掉电方式中,片振荡器停止工作,由于时钟被“冻结”,使一切功能都暂停,只保存片RAM中的容,直到下一次硬件复位为止。AT89C51引脚图如图2.2。
图2.2 AT89C52芯片
2.2.1单片机复位电路与晶振电路
时钟电路采用部振荡方式,在引脚XTAL1和XYAL2外接晶体振荡器,频率12MHZ。电容C1、C2起稳定振荡频率,快速起振的作用,值为30PF。部振荡方式所得的时钟信号比较稳定,实用电路中使用较多。复位电路与晶振电路如图2.3。
图2.3单片机复位电路与振荡电路
2.3时钟芯片DS1302
DDS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟日历芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小于31天时可以自动调整,且具有闰年补偿功能。工作电压宽达2.5~5.5V。采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后备电源进行涓细电流充电的能力。有主电源和备份电源双引脚,而且备份电源可由大容量电容(>1F)来替代。需要强调的是,DS1302需要使用32.768KHz的晶振。
2.3.1 DS1302引脚说明
DS1302引脚图如图2.4。
图2.4 DS1302芯片引脚图
DS1302的引脚功能参照表2-1。
表2-1 DS1302引脚功能说明
引脚号
名称
功能
1
VCC1
备份电源输入
2
X1
32.768KHz晶振输入
3
X2
32.768KHz晶振输出
4
GND
地
5
RST
控制移位寄存器/复位
6
I/O
数据输入/输出
7
SCLK
串行时钟
8
VCC2
主电源输入
2.3.2 DS1302电路设计与分析
时钟芯片电路连接图如图2.5。
图2.5 DS1302连接电路
该系统使用AT89C52单片机作为核心,通过读取时钟日历芯片DS1302数据,完成此电子时钟的主要功能——时钟。
AT89C52单片机P1.1直接接DS1302的RST端,上电后,AT89C52的P1.1脚自动输出高电平。P1.2作为串行时钟接口,P1.3作为时钟数据的I/O。DS1302采用双电源供电,平时由+5V电源供电,当+5V掉电之后,由图中+3V备用电池供电,可以保持DS1302继续工作。当+5V电源恢复供电时,LED依旧显示当前时间,而不会因为断电使系统复位到初始化时间,避免了重新校时的麻烦。
特别需要注意X1和X2两端连接的晶振,该晶振频率为32.768KHz。
同时有五个按键来完成时钟/秒表的切换、时间校对以与省电模式的开启/关闭。按钮连接图如图2.6。
图2.6按键连接与功能说明
2.4 显示电路与驱动
采用六位共阳数码管作为显示器,分别显示时、分、秒。
数码管的接口有静态接口和动态接口两种。
静态接口为固定显示方式,无闪烁,其电路可采用一个并行口接一个数码管,数码管的公共端按共阳或共阴分别接地或VCC。但这种接法占用接口多。
动态接口采用各数码管循环轮流显示的方法,当循环显示的频率较高时利用人眼的暂留特性,好像数码管在同时显示而看不出轮流显示的现象,用两个两个接口分别完成字选和位选。
这里采用了动态显示的方法来实现LED显示器P0口接七段数码管的段选,由于此处数码管为共阳数码管,因此要发光的选段对应的端口清零,其他端口置1;P2口接七段数码管的位选,由于此处数码管为共阳数码管,因此位选到的数码管公共端置1,其他数码管公共端清零。用74LS373接成直通的方式作为驱动电路。连接如图2.7。
图2.7 数码管与驱动连接图
3软件设计与仿真调试
3.1 程序编写与调试
开始
单片机的主程序流程如图3.1。
调用上电子程序
初始化
调用显示子程序
功能程序
有按键按下?
Y
N
读取DS1302数据
图3.1 主函数流程图
单片机AT89C52对时钟芯片DS1302的控制需要通过程序驱动来实现,程序主要完成两个方面的任务:①利用单片机实现对DS1302寄存器的地址定义和控制字的写入,②实现对DS1302的数据读取。
初始化DS1302要求为低电平,SCLK为低电平。 被设置为高电平就启动了一个数据传送的过程。SCLK的16个方波完成一次数据传送,前8个方波用于输入命令字节,后8个方波用于数据的输出(读DS1302)或数据的输入(写DS1302)。在SCLK的上升沿,I/O线上的数据被送入DS1302;在SCLK的下降沿,DS1302输出数据在I/O线上。写和读各需要一个程序,写DS1302程序流程图如图3.2所示,读DS1302程序流程图如图3.3所示。
启动
写数据字节一位
复位端变高启动一次数据传送工作
结束
SCLK发脉冲
复位端变低
SCLK发脉冲
写命令字节一位
够8次吗?
够8次吗?
N
Y
Y
N
启动
读数据字节一位
复位端变高启动一次数据传送工作
结束
SCLK发脉冲
复位端变低
SCLK发脉冲
写命令字节一位
够8次吗?
够8次吗?
N
Y
Y
N
图3.2写DS1302流程图 图3.3读DS1302流程图
利用keil软件编写源程序见附录一。
3.2 仿真电路调试
在Proteus仿真软件中按照原理图选择器件并连接好。将调试好的程序录入到单片机中。按下仿真按钮有错误将会有提醒和引导,按照指示进行调试即可。
若没有错误则开始功能调试。开机将显示00.00.00,进入时钟界面。按下切换键则进入秒表初始界面如图3.4。
图3.4秒表初始界面
陆续检验下边的按键是否有其本身功能,包括时间调整、上调、下调、省电。省电模式现象如图3.5。
图3.5省电模式
整体仿真结果图见附录二。
4总结与体会
从开始接到论文要求到时钟/秒表计时器的实现,再到论文文章的完成,每走一步对我来说都是新的尝试与挑战,这也是我在大学期间独立完成的最大的项目。在这段时间里,我学到了很多知识也有很多感受,我开始了独立的学习和试验,查看相关的资料和书籍,让自己头脑中模糊的概念逐渐清晰,使自己非常稚嫩作品一步步完善起来,每一次改进都是我学习的收获。
要做好一个课程设计,就必须做到:在设计程序之前,对所用单片机的部结构有一个系统的了解,知道该单片机有哪些资源;要有一个清晰的思路和一个完整的软件流程图;在设计程序时,不能妄想一次就将整个程序设计好,反复修改、不断改进是程序设计的必经之路;要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便;在设计课程过程中遇到问题是很正,但我们应该将每次遇到的问题记录下来,并分析清楚,以免下次再碰到同样的问题。
这次课程设计让我们学到了很多东西,查资料、选方案、设计电路、撰写设计报告等等,使我们得到了一次较全面的工程实践训练,而且进一步巩固了课程的基本知识。
参考文献
[1].群芳,肖看.《单片机原理、接口与应用》.清华大学,2005.3
[2].丁元杰.《单片微机原理与应用》(第二版).机械工业,2005.2
[3].有德,志英.《单片微型机原理、应用于实验》.复旦大学,2000.4
附录一 源程序
#include<reg52.h>
#include<intrins.h>
unsigned char a,miao,shi,shi1,shi2,fen,fen1,fen2,x,key1n,temp,j=0,mmiao=0,mfen=0;
unsigned char ri,yue,nian,week;
#include<DS1302.h>
unsigned char code dispcode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
unsigned char code point[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //带小数点数的代码
sbit qiehuan=P3^0;
sbit key1=P3^1;
sbit key2=P3^2;
sbit key3=P3^3;
sbit SD=P3^4;
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
sbit LED4=P2^3;
sbit LED5=P2^4;
sbit LED6=P2^5;
sbit POT =P0^7;
void display(uchar x);
void miaobiaoxianshi();
void shengdian();
uchar m=0,m1=0,m2=0,m3=0,m4=0;
void delayms(uint x)
{
uchar j;
while(x--)
{
for(j=0;j<114;j++)
{;}
}
}
void ReadTime()
{
miao = BCD_Decimal(read_1302(0x81));
fen = BCD_Decimal(read_1302(0x83));
shi = BCD_Decimal(read_1302(0x85));
ri = BCD_Decimal(read_1302(0x87));
yue = BCD_Decimal(read_1302(0x89));
nian=BCD_Decimal(read_1302(0x8d));
week=BCD_Decimal(read_1302(0x8b))-1;
}
uchar key1scan()
{
if(key1==0)// key1为功能键
{
delayms(10);//延时,用于消抖动
if(key1==0)//延时后再次确认按键按下
{
m++;
if(m==5)m=0;
while(1)
{display(m);if(key1==1)break;}
}
}
return m
}
void key2scan(uchar n)
{
if(n!=0)//当key1按下以下。再按以下键才有效(按键次数不等于零)
{
if(key2==0) //上调键
{
delayms(10);
if(key2==0)
{
while(1){display(m);if(key2==1)break;}
switch(n)
{
case 1:shi1=shi/10;
shi1++;
if(shi1==3)shi1=0;
temp=shi1*16+(shi)%10;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x84,temp);//向DS1302写小时寄存器84H写入调整后的小时数据BCD码
write_1302(0x8e,0x80);//打开写保护
break;
case 2:shi2=shi%10;
shi2++;
if(shi/10==2)
{
if(shi2==5)shi2=0;
}
else if(shi2==10)shi2=0;
temp=shi/10*16+shi2;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00) ; //允许写,禁止写保护
write_1302(0x84,temp);//向DS1302写小时寄存器84H写入调整后的小时数据BCD码
write_1302(0x8e,0x80);//打开写保护
break;
case 3:fen1=fen/10;
fen1++;if(fen1==6)fen1=0;
temp=fen1*16+(fen)%10;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x82,temp);//向DS1302写分寄存器82H写入调整后的分数据BCD码
write_1302(0x8e,0x80);//打开写保护
break;
case 4:fen2=fen%10;
fen2++; if(fen2==10) fen2=0;
temp=fen/10*16+fen2;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x82,temp);//向DS1302写分寄存器82H写入调整后的分数据BCD码
write_1302(0x8e,0x80);//打开写保护
break ;
}
}
}
}
}
void key3scan(uchar n)
{
if(n!=0)//当key1按下以下。再按以下键才有效(按键次数不等于零)
{
if(key3==0) //上调键
{
delayms(10);
if(key3==0)
{
while(1){display(m);if(key3==1)break;}
switch(n)
{
case 1:shi1=shi/10;
shi1--;
if(shi1==(0-1))shi1=2;
temp=shi1*16+(shi)%10;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x84,temp);//向DS1302写小时寄存器84H写入调整后的小时数据BCD码
write_1302(0x8e,0x80);//打开写保护
break;
case 2:shi2=shi%10;
shi2--;
if(shi/10==2)
{
if(shi2==(0-1))shi2=4;
}
else
if(shi2==(0-1))shi2=9;
temp=shi/10*16+shi2;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x84,temp);//向DS1302写小时寄存器84H写入调整后的小时数据BCD码
write_1302(0x8e,0x80);//打开写保护
break;
case 3:fen1=fen/10;
fen1--;if(fen1==(0-1))fen1=5;
temp=fen1*16+(fen)%10;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x82,temp);//向DS1302写分寄存器82H写入调整后的分数据BCD码
write_1302(0x8e,0x80);
break;
case 4:fen2=fen%10;
fen2--; if(fen2==(0-1)) fen2=9;
temp=fen/10*16+fen2;//十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x82,temp);//向DS1302写分寄存器82H写入调整后的分数据BCD码
write_1302(0x8e,0x80);//打开写保护
break;
}
}
}
}
}
void display(uchar x)
{
ReadTime();
P0=0xff; P0=dispcode[shi/10]; if(x==1){m1++;if(m1==200)m1=0;}if(x!=1)m1=0;LED1=1;LED2=0;LED3=0;LED4=0;LED5=0;LED6=0;if(m1%40==0)delayms(1);
P0=0xff; P0=dispcode[shi%10]; if(x==2){m2++;if(m2==200)m2=0;}if(x!=2)m2=0;LED1=0;LED2=1;LED3=0;LED4=0;LED5=0;LED6=0;POT=0;if(m2%40==0)delayms(1);
P0=0xff; P0=dispcode[fen/10]; if(x==3){m3++;if(m3==200)m3=0;}if(x!=3)m3=0;LED1=0;LED2=0;LED3=1;LED4=0;LED5=0;LED6=0;if(m3%40==0)delayms(1);
P0=0xff; P0=dispcode[fen%10]; if(x==4){m4++;if(m4==200)m4=0;}if(x!=4)m4=0;LED1=0;LED2=0;LED3=0;LED4=1;LED5=0;LED6=0;POT=0;if(m4%40==0)delayms(1);
P0=0xff; P0=dispcode[miao/10]; LED1=0;LED2=0;LED3=0;LED4=0;LED5=1;LED6=0;delayms(1);
P0=0xff; P0=dispcode[miao%10]; LED1=0;LED2=0;LED3=0;LED4=0;LED5=0;LED6=1;delayms(1);
}
void miaobiao()
{
if(qiehuan==0)
{
delayms(10);
if(qiehuan==0)
{
while(!qiehuan);
L02: while(1)
{
P0=0xff; P0=dispcode[0]; LED1=1;LED2=0;LED3=0;LED4=0;LED5=0;LED6=0;delayms(1);
P0=0xff; P0=dispcode[0]; LED1=0;LED2=1;LED3=0;LED4=0;LED5=0;LED6=0;POT=0;delayms(10);
P0=0xff; P0=dispcode[0]; LED1=0;LED2=0;LED3=1;LED4=0;LED5=0;LED6=0;delayms(1);
P0=0xff; P0=dispcode[0]; LED1=0;LED2=0;LED3=0;LED4=1;LED5=0;LED6=0;POT=0;delayms(10);
P0=0xff; P0=dispcode[0]; LED1=0;LED2=0;LED3=0;LED4=0;LED5=1;LED6=0;delayms(1);
P0=0xff; P0=dispcode[0]; LED1=0;LED2=0;LED3=0;LED4=0;LED5=0;LED6=1;delayms(1);
shengdian();
if(qiehuan==0)
{
delayms(10);
if(qiehuan==0)
{
while(!qiehuan);
goto L01;
}
}
if(key2==0)
{
delayms(10);
if(key2==0) break;
}
}
L00: while(1)
{
delayms(10);
j++;
if(j==100)
{j=0;mmiao++;}
if(mmiao==60){mmiao=0;mfen++;}
miaobiaoxianshi();
if(key3==0)
{
delayms(10);
if(key3==0)
{
while(1)
{
miaobiaoxianshi();
if(key2==0)
{
delayms(10);
if(key2==0)goto L00;
}
if(qiehuan==0)
{
delayms(10);
if(qiehuan==0)
{
while(!qiehuan);
goto L1;
}
}
if(key1==0)
{
delayms(10);
if(key1==0)
{
j=0;mfen=0;mmiao=0;
goto L02;
}
}
}
}
}
if(qiehuan==0)
{
delayms(10);
if(qiehuan==0)
{
while(!qiehuan);
goto L01;
}
}
}
}
}
L01: _nop_();
}
void miaobiaoxianshi()
{
P0=0xff; P0=dispcode[mfen/10];
if(x==1)
{m1++;if(m1==200)m1=0;}
if(x!=1)
m1=0;LED1=1;LED2=0;LED3=0;LED4=0;LED5=0;LED6=0;
if(m1%40==0)
delayms(1);
P0=0xff;
P0=dispcode[mfen%10];
if(x==2)
{m2++;if(m2==200)m2=0;}
if(x!=2)
m2=0;LED1=0;LED2=1;LED3=0;LED4=0;LED5=0;LED6=0;POT=0;
if(m2%40==0)
delayms(1);
P0=0xff;
P0=dispcode[mmiao/10];
if(x==3)
{m3++;
if(m3==200)
m3=0;}
if(x!=3)
m3=0;
LED1=0;LED2=0;LED3=1;LED4=0;LED5=0;LED6=0;
if(m3%40==0)
delayms(1);
P0=0xff;
P0=dispcode[mmiao%10];
if(x==4)
{m4++;
if(m4==200)
m4=0;}
if(x!=4)
m4=0;LED1=0;LED2=0;LED3=0;LED4=1;LED5=0;LED6=0;POT=0;
if(m4%40==0)
delayms(1);
P0=0xff;
P0=dispcode[j/10];
LED1=0;LED2=0;LED3=0;LED4=0;LED5=1;LED6=0;
delayms(1);
P0=0xff;
P0=dispcode[j%10];
LED1=0;LED2=0;LED3=0;LED4=0;LED5=0;LED6=1;
delayms(1);
}
void shengdian()
{
if(SD==0)
{
delayms(10);
if(SD==0)
{
while(!SD);
while(1)
{
P0=0x00;
P2=0x00;
if(SD==0)
{
delayms(10);
if(SD==0)
{
while(!SD);
break;
}
}
}
}
}
void main()
{
key1n=0;
ds1302_init(); //调用DS1302时钟的初始化子函数
while(1)
{
key1n=key1scan();
display(key1n);
key2scan(key1n);
key3scan(key1n);
miaobiao();
shengdian();
}
}
DS1302.H头文件
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uintunsigned int
//DS1302时钟芯片与C51之间的引脚连接定义
sbit IO=P1^3;
sbit SCLK=P1^2;
sbit RST=P1^1;
sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
void write_byte(uchar dat)
{
ACC=dat;
RST=1;
for(a=8;a>0;a--)
{
IO=ACC0;
SCLK=0;
SCLK=1;
ACC=ACC>>1;
}
}
uchar read_byte() //读一个字节
展开阅读全文