伤城文章网 > 电子/电路 > 大工17春《单片机原理及应用》大作业

大工17春《单片机原理及应用》大作业


网络教育学院 《单片机原理及应用》大作业



目:
学习中心: 层 专 年 学 次:

单片机电子时钟设计 陕西商洛奥鹏 专升本

业: 电气工程及其自动化 级: 2016 号: 年 春 季

161361309019 余 龙

学生姓名:

目录

摘要-------------------------------------------------------------1
1 单片机的相关知识 -------------------------------------------1
1.1 单片机的简介---------------------------------------------------1 1.2 单片机的特点---------------------------------------------------1 1.3 89C52单片机的基本特点-------------------------------------------2

2 电子时钟---------------------------------------------------3
2.1电子时钟的基本特点-----------------------------------------------3 2.2电子时钟的原理--------------------------------------------------4

3 控制系统的硬件设计 ----------------------------------------4
3.1单片机型号的选择------------------------------------------------4 3.2 lcd1602工作的原理----------------------------------------------4 3.3 键盘电路的设计-------------------------------------------------6
3.4 复位电路设计--------------------------------------------------------6

3.5 时钟电路设计--------------------------------------------------7 3.6 整体电路原理图------------------------------------------------7

4 控制系统的软件的设计

-------------------------------------8

4.1程序的设计-----------------------------------------------------8 4.2程序源代码-----------------------------------------------------8

5 仿真结果和实物图----------------------------------------------19
5.1仿真结果-------------------------------------------------------------19 5.2实物图---------------------------------------------------------------19

6 总结-----------------------------------------------------------------------------------------------20
参考文献
-------------------------------------------------------21

摘要:单片计算机即单片微型计算机。由

RAM ,ROM,CPU构成,定时,计数和多种接

口于一体的微控制器。它体积小,成本低,功能强,广泛应用于智能产业和工业自动化上。 而 51系列单片机是各单片机中最为典型和最有代表性的一种。这次课程设计通过对它的学 习,应用,从而达到学习、设计、开发软、硬的能力。 本设计主要设计了一个基于 AT89C52单片机的电子时钟。并在 1602上显示相应的时间。并 通过一个控制键用来实现时间的调节和是否进入省电模式的转换。 具有时钟和日历的功能,年限显示范围是2013-2099(可修改),且具有闰年自动修正 功能

关键字:单片机;子时钟;键盘控制;LCD1602。

1 单片机识的相关知识 1.1 单片机简介
MCS-51是 INTEL公司在成功推广的 MCS-48单片机基础上加以改进而成的 8位单片机。 这种单片机大约是上世纪 70年代末推出的,内部程序可重写的为 8751, 外扩程序的是 8031, 一次性生产, 不可改变程序的是 8051。 外形一般为 DIP40 封装。不久又推出了增强型的 8052,其资源更加丰富。以后又采用 CHMOS技术 推出了 80c51,耗电大大降低。到了 90年代,INTEL公司把精力放到更赚钱的计 算机上,将 51单片机技术转让给了一此其它公司,如 ATMEL Philips等半导体 制造公司,使 51系列单片机的市场份额不断扩大。 尽管十多年前就有人认为 51单片机会很快淘汰, 但事实证明 51单片机经过 不断的改进后,由于技术成熟,使用方便,至今在 8位单片机市场仍然拥有庞大 的用户。 特别是 MCS-51技术的 20年专利期限到期后, 大量的兼容型号不断推出。 从上世纪 90年代后期开始,美国 ATMEL公司在掌握快速擦写的存储器后,推出 了 AT89C系列,此系列在中国获得了广泛的应用。 在此之前,由于可擦写的 8751价格昂贵,国内长时间采用 8031+27C64这 样的外扩存程序储器方式。 51单片机最初只有 DIP40这种很古老的封装,后来推出了 CHMOS工艺的 80C51后开始有了 PLCC44这种相对较小的方形封装。 AT89C系列中开始有 20脚的 DIP20的精简型封装,这极大方便了在一些相对简单的单片机应用,缩小了 PCB 的体积。20脚的有 AT89C1051、AT89C1051、AT89C1051,对应程序存储器分别为 1K、2K、4K。 标准的 51为 4K程序空间,128字节的 RAM,32条端口,5个中断,2个定时 /计数器,12个时钟周期执行一条基本指令,最长的除法为 48个周期。52为 8K 程序空间,256字节的 RAM,32条端口,6个中断,3个定时/计数器。AT89S51 是可在板上直接下载程序的改进型号,并增加了看门狗功能,AT89C51只能在编 程器下写入程序,所以经常会有人在 PCB上安装 IC插座,以便取下来编程更新 程序。 AT的 51系列后来也推出了单周期的 51, 但价格没什么优势, 国内很少使用。 最近几年宏晶在国内大量推广 STC51系列单片机,最近又推出不少所谓 1T的单

片机,价格较低 STC采用串口直接下载程序,写入程序很方便。

1.2 单片机的特点
1 . 单片机的存储器ROM 和RAM 时严格区分的。ROM 称为程序存储器,只存放 程序,固定常数,及数据表格。RAM 则为数据存储器,用作工作区及存放用户数 据。 2 . 采用面向控制的指令系统。 为满足控制需要, 单片机有更强的逻辑控制能力, 特别是单片机具有很强的位处理能力。 3 . 单片机的I/O 口通常时多功能的。由于单片机芯片上引脚数目有限,为了 解决实际引脚数和需要的信号线的矛盾,采用了引脚功能复用的方法,引脚处于 何种功能, 可由指令来设置或由机器状态来区分。 4 . 单片机的外部扩展能力很强。在内部的各种功能部件不能满足应用的需求 时,均可在外部进行扩展,与许多通用的微机接口芯片兼容,给应用系统设计带 来了很大的方便。

1.3 89C52 单片机介绍
P0 口:P0 口为一个8 位漏级开路双向I/O 口,每脚可吸收8TTL 门电流。当 P1 口的管脚第一次写1 时, 被定义为高阻输入。P0 能够用于外部程序数据存储 器,它可以被定义为数据/地址的第八位。在FIASH 编程时,P0 口作为原码输入 口,当FIASH 进行校验时,P0 输出原码,此时P0 外部必须被拉高。 P1 口:P1 口是一个内部提供上拉电阻的8 位双向I/O 口,P1 口缓冲器能接 收输出4TTL 门电流。P1 口管脚写入1 后,被内部上拉为高,可用作输入,P1 口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH 编程和校验时,P1 口作为第八位地址接收。 P2 口:P2 口为一个内部上拉电阻的8 位双向I/O 口,P2 口缓冲器可接收, 输出4 个TTL 门电流,当P2 口被写“1”时,其管脚被内部上拉电阻拉高,且 作为输入。并因此作为输入时,P2 口的管脚被外部拉低,将输出电流。这是由 于内部上拉的缘故。P2 口当用于外部程序存储器或16 位地址外部数据存储器 进行存取时,P2 口输出地址的高八位。在给出地址“1”时,它利用内部上拉优 势,当对外部八位地址数据存储器进行读写时,P2 口输出其特殊功能寄存器的 内容。P2 口在FLASH 编程和校验时接收高八位地址信号和控制信号。 P3 口:P3 口管脚是8 个带内部上拉电阻的双向I/O 口,可接收输出4 个TTL 门电流。当P3 口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输 入,由于外部下拉为低电平,P3 口将输出电流(ILL)这是由于上拉的缘故。 P3 口也可作为AT89C52 的一些特殊功能口,如下表所示: 口管脚备选功能 P3.0 RXD(串行输入口)P3.1 TXD(串行输出口)P3.2 /INT0(外部中断0) P3.3 /INT1(外部中断1)P3.4 T0(记时器0 外部输入)P3.5 T1(记时器1 外 部输入)P3.6 /WR(外部数据存储器写选通)P3.7 /RD(外部数据存储器读选通) P3 口同时为闪烁编程和编程校验接收一些控制信号。 RST:复位输入。当振荡器复位器件时,要保持RST 脚两个机器周期的高电平时 间。

ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的 地位字节。在FLASH 编程期间,此引脚用于输入编程脉冲。在平时,ALE 端以不 变的频率周期输出正脉冲 信号,此频率为振荡器频 率的1/6。 因此它可用作对 外 部输出的脉冲或用于定时 目的。然而要注意的是: 每当用作外部数据存储器 时, 将跳过一个 ALE 脉冲。如 想 禁 止 ALE 的 输 出 可 在 SFR8EH 地址上置0。 此时, ALE 只 有 在 执 行 MOVX , MOVC 指令 是 ALE 才起 作 用。另外,该引脚被略微 拉高。 如果微处理器在外部执行 状态ALE 禁止, 置位无效。 PSEN:外部程序存储器的 选通信号。在由外部程序 存储器取指期间,每个机 器周期两次/PSEN 有效。 但在访问外部数据存储器 时,这两次有效的 /PSEN 信号 将不出现。 EA/VPP:当 /EA 保持低电 平时,则在此期间外部程 序存储( 0000H-FFFFH ) , 不 管是否有内部程序存储器。 注意加密方式1 时, /EA 将内部锁定为RESET; 当/EA 端保持高电平时,此间内部程序存储器。在FLASH 编程期间,此引脚也用于施加 12V 编程电源(VPP) 。

2 电子时钟
2.1 电子时钟的基本特点
现在高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟、石英 钟、石英表都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要 经常调试,数字式电子钟用集成电路计时时,译码代替机械式传动,用用液晶显 示器代替指针显示进而显示时间,减小了计时误差,这种表具有时、分、秒显示 时间的功能,还可以进行时和分的校对,片选的灵活性好。

2.2 电子时钟的原理
该电子时钟由89C52,1602 液晶等构成,采用晶振电路作为驱动电路,由延 时程序和循环程序达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满 二十四小时为一天。而电路中有四个控制按键,一个是选择,一个进行加数,一 个进行减数,还有一个保存。例如按下选择键,然后1602显示光标,此时可以用 加或减来进行调节,在按下选择键,光标移到不同的单位上,同理进行调节,最 后待日期时间调节好后,按下保存键,时钟开始计时。

3 控制系统的硬件设计 3.1 单片机型号的选择
通过对 51 单片机的学习,认为 STC89C52 是最理想的电子时钟开发芯片。 STC89C52, 最终认为89C52是一种带8K 字节闪烁可编程可擦除只读存储器的低电 压,高性能CMOS8位微处理器,器件采用高密度非易失存储器制造技术制造,与 工业标准的 MCS-52 指令集和输出引脚相兼容。还有一点重要原因,就是采用 AT89C52时不能用开发板进行程序的下载,所以最终选用STC89C52进行设计。

3.2 1602 工作原理及显示电路
字符型LCD 通常有14 条引脚线或16 条引脚线的LCD,多出来的2 条线是背 光电源线VCC(15 脚)和地线GND(16 脚),其控制原理与14 脚的LCD 完全一样 1602液晶的基本的操作分为以下四种: 状态字读操作:输入RS=低、RW=高、EP=高; 输出:DB0~7 读出为状态字; 数据读出操作:输入RS=高、RW=高、EP=高; 输出:DB0~7 读出为数据; 指令写入操作:输入RS=低、RW=低、EP=上升沿; 输出:无; 数据写入操作:输入RS=高、RW=低、EP=上升沿; 输出:无。

如图 1602 模块的引脚

LCD1602 正面

LCD1602 背面

1602 与单片机连接图 3.3 键盘电路设计

本时钟采用四个按键控制,一个(实物图蓝色线24号引脚)是选择,一个进行 加数(实物图紫色线25号引脚) ,一个进行减数(实物图灰色线26号引脚) ,还有 一个保存(实物图白色线27号引脚) 。例如按下选择键,然后1602显示光标,此 时可以用加或减来进行调节,在按下选择键,光标移到不同的单位上,同理进行 调节,最后待日期时间调节好后,按下保存键,时钟开始计时。

3.4 复位电路设计
单片机复位有上电复位和手动复位两种方式,上电复位是接通电源后利 用 RC 充电来实现复位。手动复位是通过人为干预,强制系统复位。

连接至9号复位引脚

复位电路如图所示,可以实现上电复位和手动复位功能。

3.5 时钟电路设计
系统时钟源由内部时钟方式产生,时钟电路由 12MH 晶振和两个 30PF 瓷片 电容组成,构成自激振荡,形成振荡源提供给单片机。电容可在 5PF 到 30PF 之间选择,电容的大小对振荡频率有微小影响,可起频率微调作用。

3.6 整体电路原理图

4 控制系统的软件设计 4.1 程序设计
由于C 语言程序设计较汇编可读性强,可移植性,且可以大大降低编程的难 度和缩短开发周期,本系统程序采用c 语言设计。

4.2 程序源代码
#include<reg52.h> #include<intrins.h> //包含单片机寄存器的头文件 //包含_nop_()函数定义的头文件

#define uchar unsigned char #define uint unsigned int sbit RS=P2^0; sbit RW=P2^1; sbit E=P2^2; sbit BF=P0^7; //寄存器选择位,将RS位定义为P2.0引脚 //读写选择位,将RW位定义为P2.1引脚 //使能信号位,将E位定义为P2.2引脚 //忙碌标志位,将BF位定义为P0.7引脚 //初始化液晶显示 16 //14

uchar code table[]="2013-12-07 WEEK6"; uchar code table1[]="TIME: 19-27-50";

uchar count,s1num; char second,minute,hour,day,month,year,week; sbit s1=P2^3; //功能键

sbit s2=P2^4; sbit s3=P2^5; sbit s4=P2^6;

//加键 //减键 //保存并退出

/* 延时若干毫秒 */ void delay(uchar n) { uchar i,a,b; for(i=0;i<n;i++) for(b=199;b>0;b--) for(a=1;a>0;a--); } /*********************************************** 函数功能:判断液晶模块的忙碌状态 返回值:result。result=1,忙碌;result=0,不忙 ************************************************/ uchar BusyTest(void) { bit result; RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态 RW=1; E=1; //E=1,才允许读写 _nop_(); //空操作 _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 result=BF; //将忙碌标志电平赋给result E=0; //将E恢复低电平 return result; } /******************************************** 函数功能:写指令 入口参数:dictate *********************************************/ void WriteInstruction(uchar dictate) { while(BusyTest()==1); //如果忙就等待 RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令 RW=0; E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲, //就是让E从0到1发生正跳变,所以应先置"0" _nop_();

_nop_(); //空操作两个机器周期,给硬件反应时间 P0=dictate; //将数据送入P0口,即写入指令或地址 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 } /********************************************* 函数功能:写数据 入口参数:y(为字符常量) **********************************************/ void WriteData(uchar y) { while(BusyTest()==1); RS=1; //RS为高电平,RW为低电平时,可以写入数据 RW=0; E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲, //就是让E从0到1发生正跳变,所以应先置"0" P0=y; //将数据送入P0口,即将数据写入液晶模块 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 } /****************************************** 函数功能:对LCD的显示模式进行初始化设置 *******************************************/ void LcdInitiate(void) { uchar num;

second=50; minute=27; hour=19; week=6; day=7; month=12; year=13; count=0; s1num=0; E=0; delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间 WriteInstruction(0x38); //显示模式设置:16× 2显示, //5× 7点阵,8位数据接口 delay(5); //延时5ms?,给硬件一点反应时间 WriteInstruction(0x38); delay(5); WriteInstruction(0x38); //连续三次,确保初始化成功 delay(5); WriteInstruction(0x0c); //显示模式设置:显示开,无光标, //光标不闪烁 delay(5); WriteInstruction(0x06); //显示模式设置:光标右移,字符不移 delay(5); WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清除 delay(5); WriteInstruction(0x80); for(num=0;num<16;num++) //让液晶显示日期 { WriteData(table[num]); delay(5); } WriteInstruction(0x80+0x40); for(num=0;num<14;num++) //让液晶显示时间 { WriteData(table1[num]); delay(5); } TMOD=0x01; //定时器中断初始化 TH0=(65536-50000)/256; TL0=(65536-50000)%256; EA=1;

ET0=1; TR0=1; } //-------写年月日--------------void write_nyr(uchar add,uchar date) { uchar i,j; i=date/10; j=date%10; WriteInstruction(0x80+add); WriteData(0x30+i); WriteData(0x30+j); } //--------写时分秒--------------void write_sfm(uchar add,uchar date) { uchar i,j; i=date/10; j=date%10; WriteInstruction(0x80+0x40+add); WriteData(0x30+i); WriteData(0x30+j); } //-------------写星期------------void write_week(uchar add,uchar date) { WriteInstruction(0x80+add); WriteData(0x30+date); } //---------该年是否是闰年------------bit leap_year() { int leap; if((year%4==0&&year%100!=0)||year%400==0) leap=1; //是闰年 else leap=0; //非闰年 return leap; }

//----------键盘扫描-------------------void keyscan() { if(s1==0) //第一个键是否按下 { delay(5); if(s1==0) { while(!s1); s1num++; if(s1num>7) s1num=1; if(s1num==1) //第一个键被按一次 { TR0=0; WriteInstruction(0x80+0x40+13); WriteInstruction(0x0f); } if(s1num==2) { WriteInstruction(0x80+0x40+10); } if(s1num==3) { WriteInstruction(0x80+0x40+7); } if(s1num==4) { WriteInstruction(0x80+9); } if(s1num==5) { WriteInstruction(0x80+6); } if(s1num==6) { WriteInstruction(0x80+3); } if(s1num==7) { WriteInstruction(0x80+15); } } }

if(s1num!=0) //如果功能键被按下 { if(s2==0) //第二个按下 { delay(5); if(s2==0) { while(!s2); if(s1num==1) //第一个键被按一次,秒钟加一 { second++; if(second==60) second=0; write_sfm(12,second); WriteInstruction(0x80+0x40+13); } if(s1num==2) //第一个键被按二次,分钟加一 { minute++; if(minute==60) minute=0; write_sfm(9,minute); WriteInstruction(0x80+0x40+10); } if(s1num==3) //第一个键被按三次,时钟加一 { hour++; if(hour==24) hour=0; write_sfm(6,hour); WriteInstruction(0x80+0x40+7); } if(s1num==4) //日期加一 { day++; if(day==32) day=1; write_nyr(8,day); WriteInstruction(0x80+9); } if(s1num==5) //月加一 { month++; if(month==13)

month=1; write_nyr(5,month); WriteInstruction(0x80+6); } if(s1num==6) //年加一 { year++; if(year==99) year=0; write_nyr(2,year); WriteInstruction(0x80+3); } if(s1num==7) //星期加一 { week++; if(week==8) week=1; write_week(15,week); WriteInstruction(0x80+15); } } } if(s3==0) //第三个键被按下 { delay(5); if(s3==0) { while(!s3); if(s1num==1) //秒减一 { second--; if(second==-1) second=59; write_sfm(12,second); WriteInstruction(0x80+0x40+13); } if(s1num==2) //分减一 { minute--; if(minute==-1) minute=59; write_sfm(9,minute); WriteInstruction(0x80+0x40+10); }

if(s1num==3) //时减一 { hour--; if(hour==-1) hour=23; write_sfm(6,hour); WriteInstruction(0x80+0x40+7); } if(s1num==4) //日减一 { day--; if(day==0) day=31; write_nyr(8,day); WriteInstruction(0x80+9); } if(s1num==5) //月减一 { month--; if(month==0) month=12; write_nyr(5,month); WriteInstruction(0x80+6); } if(s1num==6) //年减一 { year--; if(year==-1) year=99; write_nyr(2,year); WriteInstruction(0x80+3); } if(s1num==7) //日期减一 { week--; if(week==0) week=7; write_week(15,week); WriteInstruction(0x80+15); } } } if(s4==0) { //保存并退出

s1num=0; WriteInstruction(0x0c); TR0=1; } } } /****************************************** main function *******************************************/ void main(void) { uchar k=0; LcdInitiate(); //调用LCD初始化函数 while(1) { keyscan(); k=1; } } /***************************************** 函数功能:定时器T0的中断服务函数 ******************************************/ void timer0() interrupt 1 { count++; if(count==13) { count=0; second++; if(second==60) //秒计满60,秒归0,分+1 { second=0; minute++; if(minute==60) //分计满60,分归0,时+1 { minute=0; hour++; if(hour==24) //时计满24,时归0,星期+1,日+1 { hour=0; week++; day++;

if(week==8) week=1; //星期计满7,星期归1 if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) // 大 月 三十一天 { if(day==32) //大月天数计满31,日归1,月+1 { day=1; month++; } } if(month==4||month==6||month==9||month==11) //小月三十天 { if(day==31) { //小月天数计满30,日归1,月+1 day=1; month++;

} } if(month==2) { if(leap_year()) { if(day==30) //闰年二月29天??计满,日归1,月+1 { day=1; month++; } } else { if(day==29) //非闰年二月28天 计满,日归1,月+1 { day=1; month++; } } } if(month==13) //月计满12,月归1,年+1 { month=1; year++;

if(year==99) //年计满99,年归0 { year=0; } write_nyr(2,year); } write_nyr(5,month); } write_nyr(8,day); write_week(15,week); } write_sfm(6,hour); } write_sfm(9,minute); } write_sfm(12,second); }

5 仿真结果和实物图 5.1 仿真结果

5.2 实物图

6 总结:
说句实话, 这个时钟在硬件上没有什么太多的技术含量,只有一个单片机的 最小系统和一个显示电路,其实它们可以结合在一起,但是为了以后的方便,我 还是将它们设计了两个部分, 方便以后最小系统的其他方面的应用。还有就是程 序, 这个时钟程序如果让我自己写的话那我肯定不能再规定时间内完成,所以还 是靠外界力量的帮忙。也正是如此,我找到我学习单片机的弱点,那就是程序的 编写,记得室友百度开玩笑说: “程序是单片机的灵魂” ,想想当时很搞笑,但仔

细一想,那还真是个恰当的比喻,如果说单片机没有程序的输入,那么它不能完 成任何事情。 虽然本学期的单片机课程即将结束,但是我学习单片机的过程还没 有结束,以后还是要在程序的编写上多多下工夫。 此次的电子时钟设计给我奠定了一个实践基础,我会在以后的学习、生活中 磨练自己,使自己适应于以后的竞争。当遇到不会或是设计不出来的地方,我们 就会在QQ 群里讨论或者是同学之间相互帮助。团结就是力量,无论在现在的学 习中还是在以后的工作中,团结都是至关重要的,有了团结会有更多的理念、更 多的思维、更多的情感。

参考文献
[1]郭天祥.新概念51单片机C语言教程—— 入门,提高,开发,拓展 全攻略[M].北京:电子工业出版社,2009.


搜索更多“大工17春《单片机原理及应用》大作业”

网站地图

All rights reserved Powered by 伤城文章网 5xts.com

copyright ©right 2010-2021。
伤城文章网内容来自网络,如有侵犯请联系客服。zhit325@126.com