基于C51单片机的简单万年历设计.docx
- 文档编号:7357541
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:30
- 大小:298.61KB
基于C51单片机的简单万年历设计.docx
《基于C51单片机的简单万年历设计.docx》由会员分享,可在线阅读,更多相关《基于C51单片机的简单万年历设计.docx(30页珍藏版)》请在冰豆网上搜索。
基于C51单片机的简单万年历设计
第X届学生科技节
-----单片机设计
作品名称:
基于C51单片机的万年历设计
专业:
xxxxx
班级:
xx
指导老师:
xxxxx
组长:
xxxxxx学号:
xxxxxxxxxx
组员:
xxxxxx学号:
xxxxxxxxxx
一、绪论
众所周知单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。
本设计要制作的就是单片机于生活中最为常见的几种应用——万年历。
本设计以AT89S52单片机作为核心,可以显示当前的日历和时间,时间也可以人为设定,显示格式为年(四位),月(两位),日(两位),时(两位),分(两位),秒(两位)。
设置时间的位切换、设定数值、启动定时器、切换日历通过外部中断来实现。
万年历显示电路由LCD1602组成,制作该装置的材料需要有软硬件的支持,硬件方面AT89C51单片机,晶振,电源,液晶屏LCD1602。
二、系统功能
本次设计的是万年历,采用LCD1602显示,实现的功能如下:
1.显示当前时间,显示格式为年(四位),月(两位),日(两位),时(两位),分(两位),秒(两位);
2.时钟计时,自动进行时间的位切换;
3.键盘设置,能通过键盘设定当前时间和计时,并通过键盘人为设定时间。
三、
硬件电路
1.
2.
3.
3.1.电路设计框图
3.2.系统硬件概述
本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作,本系统选用12MHZ的晶振,使得单片机有合理的运行速度;利用液晶屏LCD1602显示时间信息,通过对AT89S52单片机的编程控制液晶屏LCD1602的显示。
显示时间在LCD1602,通过按键切换选择。
外部按键可及时设定或调整时间信息。
四、各模块功能及工作原理
4.
4.1.单片机主控制模块的设计
AT89S52是一种低功耗、高性能CMOS8位微控制器,具有8K在系统可编程Flash存储器。
AT89S52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3,MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。
18引脚和19引脚接时钟电路,XTAL1接外部晶振和微调电容的一端,在片内它是振荡器倒相放大器的输入,XTAL2接外部晶振和微调电容的另一端,在片内它是振荡器倒相放大器的输出。
第9引脚为复位输入端,接上电容,电阻及开关后够上电复位电路,20引脚为接地端,40引脚为电源端。
引脚图如图图4.1:
图4.1AT89S52引脚结构图4.2.1LCD1602引脚结构
4.2.LCD1602显示模块
4.2.1LCD1602引脚介绍
LCD1602采用标准的14脚(无背光)或16脚(带背光)接口,引脚图如图图4.2.1:
各引脚接口说明如表4.2.2所示:
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极
表4.2.2LCD1602引脚说明
第1脚:
VSS为地电源。
第2脚:
VDD接5V正电源。
第3脚:
VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:
RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:
R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:
E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:
D0~D7为8位双向数据线。
第15脚:
背光源正极。
第16脚:
背光源负极。
4.2.2LCD1602指令
1602液晶模块内部的控制器共有11条控制指令,如表4.2.3
编号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容
表4.2.3LCD1602的指令说明
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:
1为高电平、0为低电平)
指令1:
清显示,指令码01H,光标复位到地址00H位置。
指令2:
光标复位,光标返回到地址00H。
指令3:
光标和显示模式设置I/D:
光标移动方向,高电平右移,低电平左移S:
屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效。
指令4:
显示开关控制。
D:
控制整体显示的开与关,高电平表示开显示,低电平表示关显示C:
控制光标的开与关,高电平表示有光标,低电平表示无光标B:
控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:
光标或显示移位S/C:
高电平时移动显示的文字,低电平时移动光标。
指令6:
功能设置命令DL:
高电平时为4位总线,低电平时为8位总线N:
低电平时为单行显示,高电平时双行显示F:
低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:
字符发生器RAM地址设置。
指令8:
DDRAM地址设置。
指令9:
读忙信号和光标地址BF:
为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:
写数据。
指令11:
读数据。
4.2.3LCD1602读/写操作
LCD1602基本操作时序说明,如表4.2.4
读状态
输入
RS=L,R/W=H,E=H
输出
D0—D7=状态字
写指令
输入
RS=L,R/W=L,D0—D7=指令码,E=高脉冲
输出
无
读数据
输入
RS=H,R/W=H,E=H
输出
D0—D7=数据
写数据
输入
RS=H,R/W=L,D0—D7=数据,E=高脉冲
输出
无
表4.2.4LCD1602基本操作时序说明
4.2.4LCD1602显示模块流程图
Y
4.3.键盘模块
本设计采用4乘4键盘的反转法控制万年历的计时和时间设定,4乘4键盘电路图如图图4.3.1
图4.3.2
4.3.1键盘功能图
4.3.2流程图
Y
N
Y
YN
YN
Y
N
Y
N
N
Y
N
N
Y
4.4计时模块
4.4.1计数器工作原理
计数器:
是单片机应用中的重要部件,工作方式灵活,可以对外部事件计数和检测等;实现计数功能。
其核心是特殊功能寄存器中能进行加1计数的寄存器。
实现原理:
对T0或T1引脚输入的外部脉冲计数,如下图:
4.4.2流程图
NY
YN
NY
YN
NY
YN
NY
N
Y
五、实现结果
六、系统的实用性及创新性
基本功能:
能显示当前时间和计时,实现基本时钟功能。
创新性:
界面友好,能实现计时和键盘数字的时间设定和自增、自减的时间设定。
七、调节中遇到的问题及心得体会
问题一
LCD1602的初始化不规范,导致无法正确在LCD1602上显示相应的字符,时间等。
解决
在网上及课本上查找有关LCD1602初始化的程序,找出错误的地方并及时改正,最终解决了LCD1602的初始化问题。
问题二
在对秒、分、时、日、月、年等的大小判断时,采用逐位判断,导致程序冗长,不利于程序的优化。
解决
通过老师的指导及其他相关程序的借鉴,对时间大小的判断进行优化,将秒的十位和各位合为一个整体进行判断,分、时、日、月、年类似。
问题三
在计时模块中,因为细节问题,找不到导致不能正常计时的原因。
解决
通过老师的精心指导,找到不能正常计时的原因,将中断次数的判断if(count>100)改为if(count>=100)即可。
问题四
在键盘设计模块中,对空数组的定义无效。
解决
通过查找相关资料,了解到空数组的定义要放在data中,不能放在code中。
将空数组定义为uchara[14]使其默认放在data中就解决了该问题。
八、程序设计
5.
6.
7.
8.
8.1.流程图
N
Y
Y
Y
8.2.源代码
#include
#defineucharunsignedchar
#defineuintunsignedint
ucharcodeBuffer[4]={0xfe,0xfd,0xfb,0xf7};
ucharcodetable[]={'0','1','2','3','4','5','6','7','8','9','<','>','+','-','!
','@'};
ucharcodew[14]={0x83,0x84,0x85,0x86,0x88,0x89,0x8b,0x8c,0xc4,0xc5,0xc7,0xc8,0xca,0xcb};
uchara[14];
sbitE=P2^7;//1602使能引脚
sbitRW=P2^6;//1602读写引脚
sbitRS=P2^5;//1602数据/命令选择引脚
voidDelay(uintxms);//延时
voidTime0_Init();//中断请求
voidtimer1_int(void);//中断
voidcharge();//判断秒分时日月等是否大于额外值,若大于向上一位加一
voidftime();//初始时间
voidtimeon();//计时
voidadd();//自加
voidsub();//自减
voidwcmd(uchardel);//1602写指令
voidwrite(uchardel);//1602写数据
voidL1602_init(void);//1602初始化
voidsecond();//秒显示
voidminute();//分显示
voidhours();//时显示
voiddays();//日显示
voidmonth();//月显示
voidyears();//年显示
voidother();//符号显示
voidnumber();//键盘输入数字
uintcount,t;//中断执行次数,光标位置参数
ucharsec=0;//初始秒
ucharmin=0;//初始分
ucharhour=0;//初始时
ucharday=0;//初始日
ucharmon=0;//初始月
ucharyearh=0;//初始年前两位
ucharyearl=0;//初始年后两位
//1602命令函数
voidwcmd(uchardel)
{
P0=del;
RS=0;
RW=0;
E=1;
Delay
(1);
E=0;
Delay
(1);
}
//1602写数据函数
voidwrite(uchardel)
{
P0=del;
RS=1;
RW=0;
E=1;
Delay
(1);
E=0;
Delay
(1);
}
//1602初始化
voidL1602_init(void)
{
wcmd(0x38);
wcmd(0x38);
wcmd(0x38);
wcmd(0x0e);
wcmd(0x06);
wcmd(0x01);
}
//显示秒
voidsecond()
{
uchari,j;
i=sec/10;
j=sec%10;
wcmd(0xca);
write(table[i]);
write(table[j]);
}
//显示分
voidminute()
{
uchari,j;
i=min/10;
j=min%10;
wcmd(0xc7);
write(table[i]);
write(table[j]);
}
//显示时
voidhours()
{
uchari,j;
i=hour/10;
j=hour%10;
wcmd(0xc4);
write(table[i]);
write(table[j]);
}
//显示日
voiddays()
{
uchari,j;
i=day/10;
j=day%10;
wcmd(0x8b);
write(table[i]);
write(table[j]);
}
//显示月
voidmonth()
{
uchari,j;
i=mon/10;
j=mon%10;
wcmd(0x88);
write(table[i]);
write(table[j]);
}
//显示年
voidyears()
{
uchari,j,m,n;
i=yearh/10;
j=yearh%10;
m=yearl/10;
n=yearl%10;
wcmd(0x83);
write(table[i]);
write(table[j]);
write(table[m]);
write(table[n]);
}
//符号显示
voidother()
{
wcmd(0xc9);
write(':
');
wcmd(0xc6);
write(':
');
wcmd(0x87);
write('-');
wcmd(0x8a);
write('-');
}
//延时
voidDelay(uintxms)
{
uinti,j;
for(i=0;i for(j=0;j<110;j++); } //计时 voidtimeon() { if(count>=100) {count=0; charge(); } ftime();//显示初始时间 } //时间初值 voidftime() { second();Delay(5); minute();Delay(5); hours();Delay(5); days();Delay(5); month();Delay(5); years();Delay(5); other();Delay(5); } //各个按键返回值 uintKeyvalue() {uinti,j; uchartemp; uintKey_value; while (1) { P1=0xf0; if(P1! =0xf0) {Delay(100); if(P1! =0xf0) for(j=0;j<4;j++) {P1=Buffer[j]; temp=0x10; for(i=0;i<4;i++) { if(! (P1&temp)) { Key_value=i+j*4; } temp<<=1; } } returnKey_value; } } } //字符串显示 voidL1602_string(ucharhang,ucharlie,uchar*p) { uchara,b=0; if(hang==1)a=0x80; if(hang==2)a=0xc0; a=a+lie-1; while (1) { wcmd(a++); b++; if((*p=='\0')||(b==16))break; write(*p); Delay(500); p++; } } //自增 voidadd() { wcmd(w[t]);//光标置位 if(t==1)//光标在第二个位置时 { if(yearh<99)//判断年前两位是否小于99,是,年前两位加1,并显示 { yearh++; years(); } } elseif(t==3)//光标在第四个位置时 { if(yearl<99)//判断年后两位是否小于99,是,年后两位加1,并显示 { yearl++; years(); } } elseif(t==5)//光标在第六个位置时 { if(mon<12)//判断月是否小于12,是,月加1,并显示 { mon++; month(); } } elseif(t==7)//光标在第八个位置时 { if(day<30)//判断日是否小于30,是,日加1,并显示 { day++; days(); } } elseif(t==9)//当光标在第十个位置时 { if(hour<12)//判断时是否小于12,是,时加1,并显示 { hour++; hours(); } } elseif(t==11)//光标在第十二个位置时 { if(min<59)//判断分是否小于59,是,分加1,并显示 { min++; minute(); } } elseif(t==13)//光标在第十四个位置时 { if(sec<59)//判断秒是否小于59,是,秒加1,并显示 { sec++; second(); } } } //自减 voidsub() { wcmd(w[t]);//光标置位 if(t==1)//光标在第二个位置时,判断年前两位是否大于0,是,年前两位减1,并显示 { if(yearh>0) { yearh--; years(); } } elseif(t==3)//光标在第四个位置时,判断年后两位是否大于0,是,年后两位减1,并显示 { if(yearl>1) { yearl--; years(); } } elseif(t==5)//光标在第六个位置时,判断月是否大于1,是,月减1,并显示 { if(mon>1) { mon--; month(); } } elseif(t==7)//光标在第八个位置时,判断日是否大于1,是,日减1,并显示 { if(day>1) { day--; days(); } } elseif(t==9)//光标在第十个位置时,判断时是否大于0,是,时减1,并显示 { if(hour>0) { hour--; hours(); } } elseif(t==11)//光标在第十二个位置时,判断分是否大于0,是,分减1,并显示 { if(min>0) { min--; minute(); } } elseif(t==13)//光标在第十四个位置时,判断秒是否大于0,是,秒减1,并显示 { if(sec>0) { sec--; second(); } } } //主函数 voidmain() {ucharkeys; uinti,key;//数组a的参数 i=0; t=0;//位置参数 L1602_init();//1602初始化 L1602_string(1,5,"Showtime");//初始界面显示 L1602_string(2,5,"Welcome! ");//初始界面显示 while (1) { key=Keyvalue();//将键值赋值给key keys=table[key]; if(keys=='@')//判断键值是否为@,是,执行计时 { Time0_Init(); while (1) timeon(); } elseif(keys=='! ')//判断键值是否为! ,是,显示初始时间,光标在第一个位置 { ftime(); wcmd(0x83);} elseif(keys=='-'||keys=='+')//判断键值是否为+或- { if(keys=='+')//键值为+,执行自加函数 { add(); } else//键值为-,执行自减函数 { sub(); } }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 C51 单片机 简单 万年历 设计