《课程设计(完整).doc》由会员分享,可在线阅读,更多相关《课程设计(完整).doc(39页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、成绩 课程设计报告 题 目 基于单片机的电子时钟设计 课 程 名 称 单片机原理及应用 院 部 名 称 机电工程学院 专 业 电气工程及其自动化 班 级 12电气工程及其自动化(单) 学 生 姓 名 钱 凯 学 号 课程设计地点 工科楼 C304 课程设计学时 20 指 导 教 师 李国利 金陵科技学院教务处制目录一、概述41.1 设计任务与要求:41.2 设计目的:4二、总体设计方案及说明4三、系统硬件电路设计53.1 AT89C51单片机最小系统53.2DS1302实时时钟芯片模块63.3 DS18B20温度传感器模块73.4 LCD1602液晶显示模块83.5 4*4矩阵按键9四、系统软
2、件部分设计104.1 软件流程图104.2 系统源程序13五、系统仿真过程与结果295.1 proteus仿真软件简介295.2 Keil软件简介295.3 结合proteus仿真软件与Keil软件编译过程29六、制作过程与功能实现336.1实物制336.2 功能实现34七、总结35八、参考文献36附录一:36附录二:38摘 要基于AT89C51单片机设计了电子,系统主要包括单片机最小系统、温度采集电路、显示电路、时钟电路等等。系统采用DS18B20温度传感器对室内进行温度测量,加上DS1302实时时钟芯片内置时间,同时将当前温度信息和时间发送到LCD进行显示。画出了系统原理图,进行了软件设计
3、,给出了系统流程图,并编写了系统程序。最后进行了系统仿真,仿真结果表明,所设计的系统能够满足要求。本系统具有成本低,可靠性高和安全实用等特点,广泛应用于社会生活的各个领域。 关键词:AT89C51单片机;DS18B20;DS1302手动时间调整; 一、概述1.1 设计任务与要求:设计一个基于单片机并采用LCD显示的日历电子钟,要求:1)系统功能:可进行秒分时、天月年计时、温度;可进行手动时间调整。2)给出系统设计方案,画出硬件连线图,并说明工作原理;3)画出程序框图并编写程序。1.2 设计目的:通过本课程设计,使学生掌握控制系统设计的一般步骤,掌握系统总体控制方案的设计方法。使学生进一步掌握微
4、型计算机应用系统的硬、软件开发方法,输入/输出(I/O)接口技术,应用程序设计技术,并能结合专业设计简单实用的单片机应用系统。针对课堂重点讲授内容使学生加深对单片机硬件原理的理解及提高C51语言程序设计的能力,为以后的毕业设计搭建了单片机系统应用平台,提高学生的开发创新能力。二、总体设计方案及说明本方案以AT89C51单片机为控制核心,由DS18B20温度传感器模块,DS1302实时时钟芯片模块,LCD1602液晶显示模块, 4*4矩阵按键以及上拉电阻和下拉电阻构成。通过LCD1602液晶显示模块显示时间及温度,通过按键可以设置年月日、分时秒。本设计采用5V电源,程序主要是通过单片机下载的软件
5、来完成。图2-1 系统框图三、系统硬件电路设计3.1 AT89C51单片机最小系统(1)时钟电路单片机工作时,从取指令到译码再进行微操作,必须在时钟信号控制下才能有序地进行,时钟电路就是为单片机工作提供基本时钟的。单片机的时钟信号通常有两种产生方式:内部时钟方式和外部时钟方式。内部时钟方式的原理电路如图所示。在单片机XTAL1和XTAL2引脚上跨接上一个晶振和两个稳频电容,可以与单片机片内的电路构成一个稳定的自激振荡器。晶振的取值范围一般为024MHz,常用的晶振频率有6MHz、12 MHz、11.0592 MHz、24 MHz等。本次设计采用11.0592MHZ。一些新型的单片机还可以选择更
6、高的频率。外接电容的作用是对振荡器进行频率微调,使振荡信号频率与晶振频率一致,同时起到稳定频率的作用,一般选用2030pF的瓷片电容。外部时钟方式则是在单片机XTAL1引脚上外接一个稳定的时钟信号源,它一般适用于多片单片机同时工作的情况,使用同一时钟信号可以保证单片机的工作同步。时序是单片机在执行指令时CPU发出的控制信号在时间上的先后顺序。AT89C51单片机的时序概念有4个,可用定时单位来说明,包括振荡周期、时钟周期、机器周期和指令周期。振荡周期:是片内振荡电路或片外为单片机提供的脉冲信号的周期。时序中1个振荡周期定义为1个节拍,用P表示。时钟周期:振荡脉冲送入内部时钟电路,由时钟电路对其
7、二分频后输出的时钟脉冲周期称为时钟周期。时钟周期为振荡周期的2倍。时序中1个时钟周期定义为1个状态,用S表示。每个状态包括2个节拍,用P1、P2表示。机器周期:机器周期是单片机完成一个基本操作所需要的时间。一条指令的执行需要一个或几个机器周期。一个机器周期固定的由6个状态S1S6组成。指令周期:执行一条指令所需要的时间称为指令周期。一般用指令执行所需机器周期数表示。AT89C51单片机多数指令的执行需要1个或2个机器周期,只有乘除两条指令的执行需要4个机器周期。(2)复位电路无论是在单片机刚开始接上电源时,还是运行过程中发生故障都需要复位。复位电路用于将单片机内部各电路的状态恢复到一个确定的初
8、始值,并从这个状态开始工作。单片机的复位条件:必须使其RST引脚上持续出现两个(或以上)机器周期的高电平。单片机的复位形式:上电复位、按键复位。上电复位电路中,利用电容充电来实现复位。在电源接通瞬间,RST引脚上的电位是高电平(Vcc),电源接通后对电容进行快速充电,随着充电的进行,RST引脚上的电位也会逐渐下降为低电平。只要保证RST引脚上高电平出现的时间大于两个机器周期,便可以实现正常复位。按键复位电路中,当按键没有按下时,电路同上电复位电路。如在单片机运行过程中,按下RESET键,已经充好电的电容会快速通过4.7K电阻的回路放电,从而使得RST引脚上的电位快速变为高电平,此高电平会维持到
9、按键释放,从而满足单片机复位的条件实现按键复位。图3-1 单片机复位电路3.2 DS1302实时时钟芯片模块DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。工作电压宽达2.55.5V。采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后背电源进行涓细电流充电的能力。DS1302的外部引脚分配如图,DS1302用于数据记录,特别是对某些具有
10、特殊意义的数据点的记录上,能实现数据与出现该数据的时间同时记录,因此广泛应用于测量系统中。 1.各引脚的功能为: 图3-4 时钟芯片外部引脚Vcc1:主电源;Vcc2:备份电源。当Vcc2Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2 Vcc1时,由Vcc1向DS1302供电。 SCLK:串行时钟,输入,控制数据的输入与输出; I/O:三线接口时的双向数据线; CE:输入信号,在读、写数据期间,必须为高。该引脚有两个功能:第一,CE开始控制字访问移位寄存器的控制逻辑;其次,CE提供结束单字节或多字节数据传输的方法。图3-5 时钟芯片3.3 DS18B20温度传感器模块DS18B
11、20工作原理:DS18B20的温度检测与数字数据输出全集成于一个芯片之上,从而抗干扰力更强。其一个工作周期可分为两个部分,即温度检测和数据处理。在讲解其工作流程之前我们有必要了解18B20的内部存储器资源。18B20共有三种形态的存储器资源,它们分别是: ROM 只读存储器,用于存放DS18B20ID编码,其前8位是单线系列编码(DS18B20的编码是19H),后面48位是芯片唯一的序列号,最后8位是以上56的位的CRC码(冗余校验)。数据在出产时设置不由用户更改。DS18B20共64位ROM。RAM 数据暂存器,用于内部计算和数据存取,数据在掉电后丢失,DS18B20共9个字节RAM,每个字
12、节为8位。第1、2个字节是温度转换后的数据值信息,第3、4个字节是用户EEPROM(常用于温度报警值储存)的镜像。在上电复位时其值将被刷新。第5个字节则是用户第3个EEPROM的镜像。第6、7、8个字节为计数寄存器,是为了让用户得到更高的温度分辨率而设计的,同样也是内部温度转换、计算的暂存单元。第9个字节为前8个字节的CRC码。EEPROM 非易失性记忆体,用于存放长期需要保存的数据,上下限温度报警值和校验数据,DS18B20共3位EEPROM,并在RAM都存在镜像,以方便用户操作。图3-3 温度传感器模块3.4 LCD1602液晶显示模块LCD1602可以显示16*2=32个字符,也可以用来
13、显示一些汉字图片(利用取模软件提取),原理图中的可调电阻是用来调节字符显示的亮度的,调节是要有耐心,应为用到的是精密可调电阻,这个需要转很多圈,不容易显示出来,注意不能跳到太亮,要不很容易烧掉液晶,下面为接口说明,一般不显示很可能是程序的问题和可调电阻没有调节好。 图3-6 LCD1602液晶的原理图3.5 4*4矩阵按键矩阵键盘又称为行列式键盘,它是用4条I/O线作为行线,4条I/O线作为列线组成的键盘。在行线和列线的每一个交叉点上,设置一个按键。这样键盘中按键的个数是4*4个。这种行列式键盘结构能够有效地提高单片机系统中I/O的利用率。图3-7 矩阵按键电路四、系统软件部分设计4.1 软件
14、流程图图4-1 主函数系统流程图程序开始,首先先进行系统初始化。然后先进行温度的采集,时间的采集,最后将温度和时间送至LCD显示数据。图4-2 DS18B20温度传感器的读取流程图单片机向DS18B20温度传感器发送数据采集温度,温度传感器首先进行系统的初始化DS18B20温度传感器每1秒钟进行一次温度采集,如果温度有变化则读取温度,若温度没有变化将继续返回上一步循环。图 4-3 DS1302读取系统流程图单片机向DS1302时钟芯片发送数据采集时间,DS1302时钟芯片首先进行系统初始化。DS1302时钟芯片是200ms进行一次时间的数据采集。如果时间变化,则读取时间,如果没有变化,则返回上
15、一步继续循环。 图4-4 LCD显示器系统流程图单片机向LCD显示器发送数据要求显示温度和时间,LCD显示器首先进行初始化。然后读取温度和时间。下一步判断按键是否按下,如果按下就将设置时间送至LCD显示器进行显示。如果没有设置则返回上一步,然后送至LCD显示器进行显示。4.2 系统源程序#include struct sTime /日期时间结构体定义 unsigned int year; unsigned char mon; unsigned char day; unsigned char hour; unsigned char min; unsigned char sec; unsigned
16、 char week;bit flag1s = 0; /1s定时标志bit flag200ms = 1; /200ms定时标志struct sTime bufTime; /日期时间缓冲区unsigned char setIndex = 0; /时间设置索引unsigned char T0RH = 0; /T0重载值的高字节unsigned char T0RL = 0; /T0重载值的低字节void ConfigTimer0(unsigned int ms);void RefreshTimeShow();void GetShowTemp();extern void InitDS1302();ex
17、tern void GetRealTime(struct sTime *time);extern void SetRealTime(struct sTime *time);extern void KeyScan();extern void KeyDriver();extern void InitLcd1602();extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);extern void LcdSetCursor(unsigned char x, unsigned char y);extern
18、 void LcdOpenCursor();extern void LcdCloseCursor();extern bit Start18B20();extern bit Get18B20Temp(int *temp);void main() unsigned char psec=0xAA; /秒备份,初值AA确保首次读取时间后会刷新显示 EA = 1; /开总中断 ConfigTimer0(1); /T0定时1ms Start18B20(); /启动DS18B20 InitDS1302(); /初始化实时时钟 InitLcd1602(); /初始化液晶 /初始化屏幕上固定不变的内容 LcdS
19、howStr(3, 0, 20 - -); LcdShowStr(1, 1, : : -C); while (1) KeyDriver(); /调用按键驱动 if (flag200ms & (setIndex = 0) /每隔200ms且未处于设置状态时, flag200ms = 0; GetRealTime(&bufTime); /获取当前时间 if (psec != bufTime.sec) /检测到时间有变化时刷新显示 RefreshTimeShow(); psec = bufTime.sec; /用当前值更新上次秒数 if (flag1s & (setIndex = 0) /每隔1s读
20、取并显示温度 flag1s = 0; GetShowTemp(); /* 将一个BCD码字节显示到屏幕上,(x,y)-屏幕起始坐标,bcd-待显示BCD码 */void ShowBcdByte(unsigned char x, unsigned char y, unsigned char bcd) unsigned char str4; str0 = (bcd 4) + 0; str1 = (bcd&0x0F) + 0; str2 = 0; LcdShowStr(x, y, str);/* 获取并显示温度 */void GetShowTemp() int temp; unsigned char
21、 str4; if (Get18B20Temp(&temp) /读取当前温度并判断是否成功 /读取成功时,刷新当前温度显示 temp = 4; /右移4位以舍弃小数位 str0 = temp/10 + 0; /显示为两位十进制数字 str1 = temp%10 + 0; str2 = 0; LcdShowStr(11, 1, str); else /读取失败时,提示错误信息 LcdShowStr(11, 1, -); Start18B20(); /重新启动下一次转换/* 刷新日期时间的显示 */void RefreshTimeShow() ShowBcdByte(5, 0, bufTime.y
22、ear); ShowBcdByte(8, 0, bufTime.mon); ShowBcdByte(11, 0, bufTime.day); ShowBcdByte(1, 1, bufTime.hour); ShowBcdByte(4, 1, bufTime.min); ShowBcdByte(7, 1, bufTime.sec);/* 刷新当前设置位的光标指示 */void RefreshSetShow() switch (setIndex) case 1: LcdSetCursor(5, 0); break; case 2: LcdSetCursor(6, 0); break; case
23、3: LcdSetCursor(8, 0); break; case 4: LcdSetCursor(9, 0); break; case 5: LcdSetCursor(11, 0); break; case 6: LcdSetCursor(12, 0); break; case 7: LcdSetCursor(1, 1); break; case 8: LcdSetCursor(2, 1); break; case 9: LcdSetCursor(4, 1); break; case 10: LcdSetCursor(5, 1); break; case 11: LcdSetCursor(
24、7, 1); break; case 12: LcdSetCursor(8, 1); break; default: break; /* 递增一个BCD码的高位 */unsigned char IncBcdHigh(unsigned char bcd) if (bcd&0xF0) 0x90) bcd += 0x10; else bcd &= 0x0F; return bcd;/* 递增一个BCD码的低位 */unsigned char IncBcdLow(unsigned char bcd) if (bcd&0x0F) 0x00) bcd -= 0x10; else bcd |= 0x90;
25、return bcd;/* 递减一个BCD码的低位 */unsigned char DecBcdLow(unsigned char bcd) if (bcd&0x0F) 0x00) bcd -= 0x01; else bcd |= 0x09; return bcd;/* 递增时间当前设置位的值 */void IncSetTime() switch (setIndex) case 1: bufTime.year = IncBcdHigh(bufTime.year); break; case 2: bufTime.year = IncBcdLow(bufTime.year); break; cas
26、e 3: bufTime.mon = IncBcdHigh(bufTime.mon); break; case 4: bufTime.mon = IncBcdLow(bufTime.mon); break; case 5: bufTime.day = IncBcdHigh(bufTime.day); break; case 6: bufTime.day = IncBcdLow(bufTime.day); break; case 7: bufTime.hour = IncBcdHigh(bufTime.hour); break; case 8: bufTime.hour = IncBcdLow(
27、bufTime.hour); break; case 9: bufTime.min = IncBcdHigh(bufTime.min); break; case 10: bufTime.min = IncBcdLow(bufTime.min); break; case 11: bufTime.sec = IncBcdHigh(bufTime.sec); break; case 12: bufTime.sec = IncBcdLow(bufTime.sec); break; default: break; RefreshTimeShow(); RefreshSetShow();/* 递减时间当前
28、设置位的值 */void DecSetTime() switch (setIndex) case 1: bufTime.year = DecBcdHigh(bufTime.year); break; case 2: bufTime.year = DecBcdLow(bufTime.year); break; case 3: bufTime.mon = DecBcdHigh(bufTime.mon); break; case 4: bufTime.mon = DecBcdLow(bufTime.mon); break; case 5: bufTime.day = DecBcdHigh(bufTi
29、me.day); break; case 6: bufTime.day = DecBcdLow(bufTime.day); break; case 7: bufTime.hour = DecBcdHigh(bufTime.hour); break; case 8: bufTime.hour = DecBcdLow(bufTime.hour); break; case 9: bufTime.min = DecBcdHigh(bufTime.min); break; case 10: bufTime.min = DecBcdLow(bufTime.min); break; case 11: buf
30、Time.sec = DecBcdHigh(bufTime.sec); break; case 12: bufTime.sec = DecBcdLow(bufTime.sec); break; default: break; RefreshTimeShow(); RefreshSetShow();/* 右移时间设置位 */void RightShiftTimeSet() if (setIndex != 0) if (setIndex 1) setIndex-; else setIndex = 12; RefreshSetShow(); /* 进入时间设置状态 */void EnterTimeS
31、et() setIndex = 2; /把设置索引设置为2,即可进入设置状态 LeftShiftTimeSet(); /再利用现成的左移操作移到位置1并完成显示刷新 LcdOpenCursor(); /打开光标闪烁效果/* 退出时间设置状态,save-是否保存当前设置的时间值 */void ExitTimeSet(bit save) setIndex = 0; /把设置索引设置为0,即可退出设置状态 if (save) /需保存时即把当前设置时间写入DS1302 SetRealTime(&bufTime); LcdCloseCursor(); /关闭光标显示/* 按键动作函数,根据键码执行相应
32、的操作,keycode-按键键码 */void KeyAction(unsigned char keycode) if (keycode=0) & (keycode8); /定时器重载值拆分为高低字节 T0RL = (unsigned char)tmp; TMOD &= 0xF0; /清零T0的控制位 TMOD |= 0x01; /配置T0为模式1 TH0 = T0RH; /加载T0重载值 TL0 = T0RL; ET0 = 1; /使能T0中断 TR0 = 1; /启动T0/* T0中断服务函数,执行按键扫描和200ms定时 */void InterruptTimer0() interrup
33、t 1 static unsigned char tmr200ms = 0; static unsigned int tmr1000ms = 0; TH0 = T0RH; /重新加载重载值 TL0 = T0RL; KeyScan(); /按键扫描 tmr200ms+; if (tmr200ms = 200) /定时200ms tmr200ms = 0; flag200ms = 1; tmr1000ms+; if (tmr1000ms = 1000) /定时1000ms tmr1000ms = 0; flag1s = 1; /* 文件名:Lcd1602.c* 描 述:1602字符液晶驱动模块*
34、版本号:v1.0.0* 备 注:*/#include #define LCD1602_DB P0sbit LCD1602_RS = P10;sbit LCD1602_RW = P11;sbit LCD1602_E = P15;/* 等待液晶准备好 */void LcdWaitReady() unsigned char sta; LCD1602_DB = 0xFF; LCD1602_RS = 0; LCD1602_RW = 1; do LCD1602_E = 1; sta = LCD1602_DB; /读取状态字 LCD1602_E = 0; while (sta & 0x80); /bit7等
35、于1表示液晶正忙,重复检测直到其等于0为止/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */void LcdWriteCmd(unsigned char cmd) LcdWaitReady(); LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_DB = cmd; LCD1602_E = 1; LCD1602_E = 0;/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */void LcdWriteDat(unsigned char dat) LcdWaitReady(); LCD1602_RS = 1; LCD1602_RW = 0; LCD1602_DB = dat; LCD1602_E = 1; LCD1602_E = 0;/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */void LcdSetCursor(unsigned char x, unsigned char y) unsigned char addr;
限制150内