单片机课程设计-简易电子时钟.doc
单片机课程设计报告题目:简易电子时钟 专业: 自动化 班级: 12级自动化1班 日期: 2014 年 3月 一、 设计目的 随着科技的快速发展,时间的流逝,至从观太阳、摆钟到现在电子钟,人类不断研究,不断创新纪录。美国DALLAS公司推出的具有涓细电流充电能的低功耗实时时钟电路DS1302。它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小。对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。该电路采用STC89C51单片机作为核心,功耗小,能在5V的低压工作,电压可选用35V电压供电。 综上所述此万年历具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。 本电路为实现电子万年历的功能,采用单片机STC89C51,辅助以必要的外围电路,用C语言编写程序,并进行模块化设计而成的电子万年历系统.它通过LCD能正确显示阳历星期和时分秒,温度等,可以进行整点提醒,具有功能稳定,精确度高和可调的特点。1、通过单片机原理及应用教程了解单片微型计算机的发展;2、根据课程设计的要求,学会设计程序的过程,学会应用程序设计调试软件、学会根据要求运用PCB设计电路板硬件部分;3、通过调试程序设计模块,掌握单片微型计算机的结构原理,了解程序设计的编程思想;4、通过软件调试熟悉使用单片机指令系统,掌握C语言程序设计方法及编程技巧,掌握子程序的设计与使用,熟悉定时器中断服务程序的设计及调用过程。5、综合课程设计更全方面了解单片机的硬件和软件知识。 二、 设计要求和方案选择 设计要求:1、 显示出基本时间:时、分、秒;(基础部分)2、 显示年、月、日、周具体时间(拓展部分)3、 断电保护时间功能(拓展部分)4、 环境温度感应功能显示(拓展部分)5、 整点报时功能(拓展部分)方案选择:根据题目基本要求以及外拓展功能,本次单片机课程设计打算以AT89S52单片机系统为基础实现以上的设计要求,并在此分为软硬件模块结合实现所要求的功能,各重要模块如下:1、 AT89S52单片机最小系统 最小系统包括晶体振荡电路、复位开关和电源部分。图2为STC89C52RC单片机的最小系统。2、 DS1302时钟芯片模块 时钟模块采用DS1302芯片,DS1302是DALLAS公司推出的涓流充电时钟芯片内含有一个实时时钟/日历和31字节静态RAM通过简单的串行接口与单片机进行通信实时时钟/日历电路提供秒分时日日期月年的信息每月的天数和闰年的天数可自动调整时钟操作可通过AM/PM指示决定采用24或12小时格式DS1302与单片机之间能简单地采用同步串行的方式进行通信仅需用到三个口线:RST复位、I/O数据线、SCLK串行时钟。时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信。3、 18B20温度感应芯片模块温度测量传感器采用DALLAS公司DS18B20的单总线数字化温度传感器,测温范围为-55125,可编程为9位12位A/D转换精度,测温分辨率达到0.0625,采用寄生电源工作方式,CPU只需一根口线便能与DS18B20通信,占用CPU口线少,可节省大量引线和逻辑电路。4、 LCD1602液晶显示器模块LCD液晶显示模块采用LCD1602型号,具有很低的功耗,正常工作时电流仅2.0mA/5.0V。通过编程实现自动关闭屏幕能够更有效的降低功耗。LCD1602分两行显示,每行可显示多达16个字符。LCD1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,通过内部指令可实现对其显示多样的控制,并且还能利用空余的空间自定义字符。5、 蜂鸣器模块 三、 软件设计当硬件做出来的时候下一步就是在软件上实现所要求的功能,各个芯片最好都应该有各自的基本C文件程序,然后再在主函数上用函数的调用的方法最后实现功能。以下是本次课程设计的全部代码:#include<reg51.h>#include"DS18B20_3.H"#define uint unsigned int#define uchar unsigned charuchar a,miao,shi,fen,ri,yue,nian,week,flag,key1n,temp;/flag用于读取头文件中的温度值,和显示温度值#define yh 0x80 /LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)#define er 0x80+0x40 /LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)/液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口)sbit rs=P20;sbit en=P22;sbit rw=P21; /如果硬件上rw接地,就不用写这句和后面的rw=0了sbit led=P26; /LCD背光开关/DS1302时钟芯片与C51之间的引脚连接定义sbit IO=P11;sbit SCLK=P10;sbit RST=P12;sbit ACC0=ACC0;sbit ACC7=ACC7;/*ACC累加器=AACC.0=E0H ACC.0就是ACC的第0位。Acc可以位寻址。累加器ACC是一个8位的存储单元,是用来放数据的。但是,这个存储单元有其特殊的地位,是单片机中一个非常关键的单元,很多运算都要通过ACC来进行。以后在学习指令时,常用A来表示累加器。但有一些地方例外,比如在PUSH指令中,就必须用ACC这样的名字。一般的说法,A代表了累加器中的内容、而ACC代表的是累加器的地址。 */校时按键与C51的引脚连接定义sbit key1=P15; /设置键sbit key2=P16; /加键sbit key3=P17; /减键sbit buzzer=P13;/蜂鸣器,通过三极管9012驱动,端口低电平响/*/uchar code tab1="20 - - " /年显示的固定字符uchar code tab2=" : : "/时间显示的固定字符/延时函数,后面经常调用void delay(uint xms)/延时函数,有参函数uint x,y;for(x=xms;x>0;x-) for(y=110;y>0;y-);/*液晶写入指令函数与写入数据函数,以后可调用*/*在这个程序中,液晶写入有关函数会在DS1302的函数中调用,所以液晶程序要放在前面*/write_1602com(uchar com)/*液晶写入指令函数*rs=0;/数据/指令选择置为指令rw=0; /读写选择置为写P0=com;/送入数据delay(1);en=1;/拉高使能端,为制造有效的下降沿做准备delay(1);en=0;/en由高变低,产生下降沿,液晶执行命令write_1602dat(uchar dat)/*液晶写入数据函数*rs=1;/数据/指令选择置为数据rw=0; /读写选择置为写P0=dat;/送入数据delay(1);en=1; /en置高电平,为制造下降沿做准备delay(1);en=0; /en由高变低,产生下降沿,液晶执行命令lcd_init()/*液晶初始化函数*write_1602com(0x38);/设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据write_1602com(0x0c);/开显示不显示光标write_1602com(0x06);/整屏不移动,光标自动右移write_1602com(0x01);/清显示write_1602com(yh+1);/日历显示固定符号从第一行第1个位置之后开始显示for(a=0;a<14;a+)write_1602dat(tab1a);/向液晶屏写日历显示的固定符号部分/delay(3);write_1602com(er+2);/时间显示固定符号写入位置,从第2个位置后开始显示for(a=0;a<8;a+)write_1602dat(tab2a);/写显示时间固定符号,两个冒号/delay(3);/*over*/*DS1302有关子函数*/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()/读一个字节RST=1;for(a=8;a>0;a-)ACC7=IO;SCLK=1;SCLK=0;ACC=ACC>>1;return (ACC);/-void write_1302(uchar add,uchar dat)/向1302芯片写函数,指定写入地址,数据RST=0;SCLK=0;RST=1;write_byte(add);write_byte(dat);SCLK=1;RST=0;uchar read_1302(uchar add)/从1302读数据函数,指定读取数据来源地址uchar temp;RST=0;SCLK=0;RST=1;write_byte(add);temp=read_byte();SCLK=1;RST=0;return(temp);uchar BCD_Decimal(uchar bcd)/BCD码转十进制函数,输入BCD,返回十进制 uchar Decimal; Decimal=bcd>>4; return(Decimal=Decimal*10+(bcd&=0x0F);/-void ds1302_init() /1302芯片初始化子函数(2010-01-07,12:00:00,week4)RST=0;SCLK=0;write_1302(0x8e,0x00); /允许写,禁止写保护 /write_1302(0x80,0x00); /向DS1302内写秒寄存器80H写入初始秒数据00/write_1302(0x82,0x00);/向DS1302内写分寄存器82H写入初始分数据00/write_1302(0x84,0x12);/向DS1302内写小时寄存器84H写入初始小时数据12/write_1302(0x8a,0x04);/向DS1302内写周寄存器8aH写入初始周数据4/write_1302(0x86,0x07);/向DS1302内写日期寄存器86H写入初始日期数据07/write_1302(0x88,0x01);/向DS1302内写月份寄存器88H写入初始月份数据01/write_1302(0x8c,0x10);/向DS1302内写年份寄存器8cH写入初始年份数据10write_1302(0x8e,0x80); /打开写保护/-/温度显示子函数void write_temp(uchar add,uchar dat)/向LCD写温度数据,并指定显示位置uchar gw,sw;gw=dat%10;/取得个位数字sw=dat/10;/取得十位数字write_1602com(er+add);/er是头文件规定的值0x80+0x40write_1602dat(0x30+sw);/数字+30得到该数字的LCD1602显示码write_1602dat(0x30+gw);/数字+30得到该数字的LCD1602显示码 write_1602dat(0xdf);/显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码 write_1602dat(0x43);/显示"C"符号,0x43是液晶屏字符库里大写C的地址码/-/时分秒显示子函数void write_sfm(uchar add,uchar dat)/向LCD写时分秒,有显示位置加、现示数据,两个参数uchar gw,sw;gw=dat%10;/取得个位数字sw=dat/10;/取得十位数字write_1602com(er+add);/er是头文件规定的值0x80+0x40write_1602dat(0x30+sw);/数字+30得到该数字的LCD1602显示码write_1602dat(0x30+gw);/数字+30得到该数字的LCD1602显示码/-/年月日显示子函数void write_nyr(uchar add,uchar dat)/向LCD写年月日,有显示位置加数、显示数据,两个参数uchar gw,sw;gw=dat%10;/取得个位数字sw=dat/10;/取得十位数字write_1602com(yh+add);/设定显示位置为第一个位置+addwrite_1602dat(0x30+sw);/数字+30得到该数字的LCD1602显示码write_1602dat(0x30+gw);/数字+30得到该数字的LCD1602显示码/-void write_week(uchar week)/写星期函数write_1602com(yh+0x0c);/星期字符的显示位置switch(week)case 1:write_1602dat('M');/星期数为1时,显示 write_1602dat('O'); write_1602dat('N'); break; case 2:write_1602dat('T');/星期数据为2时显示 write_1602dat('U'); write_1602dat('E'); break;case 3:write_1602dat('W');/星期数据为3时显示 write_1602dat('E'); write_1602dat('D'); break;case 4:write_1602dat('T');/星期数据为4是显示 write_1602dat('H'); write_1602dat('U'); break;case 5:write_1602dat('F');/星期数据为5时显示 write_1602dat('R'); write_1602dat('I'); break;case 6:write_1602dat('S');/星期数据为6时显示 write_1602dat('T'); write_1602dat('A'); break;case 7:write_1602dat('S');/星期数据为7时显示 write_1602dat('U'); write_1602dat('N'); break;/*主函数*/*void main()lcd_init(); /调用液晶屏初始化子函数ds1302_init(); /调用DS1302时钟的初始化子函数init(); /调用定时计数器的设置子函数led=0; /打开LCD的背光电源 buzzer=0;/蜂鸣器长响一次 delay(80); buzzer=1;while(1) /无限循环下面的语句: keyscan(); /调用键盘扫描子函数 void timer0() interrupt 1 /取得并显示日历和时间 /Init_DS18B20();/温度传感器DS18b2初始化子函数,在头文件中 flag=ReadTemperature();/将18b2头文件运行返回的函数结果送到变量FLAG中,用于显示 /读取秒时分周日月年七个数据(DS1302的读寄存器与写寄存器不一样): 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);/显示温度、秒、时、分数据: write_temp(12,flag);/显示温度,从第二行第12个字符后开始显示 write_sfm(8,miao);/秒,从第二行第8个字后开始显示(调用时分秒显示子函数)write_sfm(5,fen);/分,从第二行第5个字符后开始显示write_sfm(2,shi);/小时,从第二行第2个字符后开始显示/显示日、月、年数据:write_nyr(9,ri);/日期,从第二行第9个字符后开始显示 write_nyr(6,yue);/月份,从第二行第6个字符后开始显示write_nyr(3,nian);/年,从第二行第3个字符后开始显示write_week(week);四、 硬件部分要做出来一个实物出来必须事先构造好各个模块,设计所需要的芯片以及了解各个芯片的工作原理和实现功能的构造部分、芯片之间该如何连接起来、准备好各元器件以便焊接等,首先在Altium Designer软件的原理图中画出各个模块,本次课程设计的原理图和PCB图如下:五、 调试及运行结果根据书本的内容和上课时老师所讲授的知识,同时翻阅相关的芯片资料等,然后一步一步的写程序,写出了程序之后发现不能按要求实现功能,其中有1602显示出乱码、时钟不会变化、温度值异常等问题,最后一个问题一个问题地去解决,完成一个功能解决下一个问题,经过两天的软件调试,最后简易时钟能够实现所需要的效果,最后本次课程设计圆满完成。以下是本次课程设计的实物效果:六、 总结(感想和心得等) 经过大家多天的努力,终于完成了第一次任务,设计出了汇集外观精美、方便实用、功能强大于一体的数字电子钟。该数字钟采用桌面式摆放设计,附带双电源装备,可供不时之需,而且具有温度,整点提醒等一些列常用的附加功能,更加方便实用,符合现实要求;多功能时钟还具有掉电也不会丢失时间的优点,可避免不必要的烦恼,设计更加的人性化和智能化。同时还能够自定义调整显示灰度和屏幕背光亮度,带背光功能,夜里更实用!当然,单片机就是软件和硬件的典型结合体,同时要做出自己的一个实物出来也相对会难一点。但在这个过程中给了我很大的体会,在学习的过程中遇到问题是一件幸运的事,因为此时你会去想办法去解决它,到了以后遇到同样的问题你也会用相似的方法去解决,同时也能提高自己的自学能力。这次的实践,也可以说是经过了多天的学习,尽管期间苦难重重,但我们还是从中学习了不少新的知识和解决困难的方法,也体验到了自主创作的快乐。14