资源描述
目 录
第一部分 设计任务和要求
1.1 单片机课程设计内容…………………………………………………2
1.2 单片机课程设计要求…………………………………………………2
1.3 系统运行步骤…………………………………………………………2
第二部分 设计方案
2.1 总体设计方案说明……………………………………………………2
2.2 系统方框图……………………………………………………………3
2.3 系统步骤图……………………………………………………………3
第三部分 关键器材及基础介绍
3.1 关键器材………………………………………………………………4
3.2 关键器材介绍…………………………………………………………4
第四部分 系统硬件设计
4.1 最小系统………………………………………………………………6
4.2 LCD显示电路…………………………………………………………6
4.3 键盘输入电路…………………………………………………………7
4.4 蜂鸣器和LED灯电路…………………………………………………7
第五部分 仿真电路图和仿真结果………………………………………………8
第六部分 课程设计总结…………………………………………………………8
第七部分 参考文件………………………………………………………………9
附录A 实物图
附录B 系统源程序
第一部分 设计任务和要求
1.1 单片机课程设计内容
利用STC89C51单片机和LCD1602电子显示器实现电子时钟,可由按键进行调时和12/二十四小时切换。
1.2 单片机课程设计要求
1.能实现年、月、日、星期、时、分、秒显示;
2.能实现调时功效;
3.能实现12/二十四小时制切换;
4.能实现8:00—22:00整点报时功效。
1.3 系统运行步骤
程序首优异行初始化,在主程序循环程序中首先调用数据处理程序,然后调用显示程序,在判定是否有按键按下。若有按键按下则转到对应功效程序实施,没有按键按下则调用时间程序。若没到则循环实施。计时中止服务程序完成秒计时及向分钟、小时进位和星期、年、月、日进位。调时闪烁中止服务程序用于被调单元闪烁显示。调时程序用于调整分钟、小时、星期、日、月、年,关键由主函数组成经过对相关子程序调用,图所表示。实现了对时间设置和修改、LCD显示数值等关键功效。相关调整是靠对功效键判定来实现。
第二部分 设计方案
2.1 总体设计方案说明
1.程序设计及调试
依据单片机课程设计内容和要求,完成Protues仿真电路设计和用Keil软件编写程序,并进行仿真模拟调试。
2.硬件焊接及调试
依据仿真电路图完成电路板焊接,并进行软、硬件调试,只抵达成预期目标。
3.后期处理
对设计过程进行总结,完成设计汇报。
2.2 单片机系统方框图
功效键
增加键
减小键
12/二十四小时制切换键
STC89C51
单片机
LCD显示器
电源
最小系统
2.2 单片机系统步骤图
开始
初始化
时钟子程序
结束
按键扫描子程序
主步骤图 键盘扫描步骤图
时钟步骤图
第三部分 关键器件及介绍
3.1 关键器件
1. STC89C51单片机;
2.LCD1602液晶显示器;
3.2 关键器件介绍
1.STC89C51单片机介绍
STC89C51是采取8051核ISP(In System Programming)在系统可编程芯片,最高工作时钟频率为80MHz,片内含8K Bytes可反复擦写1000次Flash只读程序存放器,器件兼容标准MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISP Flash存放单元,含有在系统可编程(ISP)特征,配合PC端控制程序即可将用户程序代码下载进单片机内部,省去了购置通用编程器,而且速度愈加快。
2.LCD1602液晶显示器介绍
LCD1602能够显示2行16个字符,有8位数据总线D0—D7,和RS、R/W、EN三个控制端口,工作电压为5V,而且带有字符对比度调整和背光。
LCD1602引脚说明以下表所表示:
LCD液晶显示器各引脚功效及结构
编号
符号
引脚说明
编号
符号
引脚说明
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
BLK
背光源地
8
D1
双向数据口
16
BLA
背光源正极
VDD:电源正极,4.5V—5.5V,通常使用5V电压;
VL:LCD对比度调整端,电压调整范围为0—5V。接正极时对比度最弱,接地电源时对比度最高,但对比度过高会产生“鬼影”,所以通常使用一个10K电位器来调整对比度,或直接串接一个电阻到地;
RS:MCU写入数据或指令选择端。MCU要写入指令时,使RS为低电平;MCU要写入数据时,使RS为高电平;
R/W:读写控制端。R/W为高电平时,读取数据;R/W为低电平时,写入数据;
EN:LCD模块使能信号控制端。写数据时,需要下降沿触发模块。
D0—D7:8为数据总线,三态双向。假如MCUI/O口资源担心话,该模块也能够只使用4位数据线D4—D7接口传送数据。
A:LED背光正极。需要背光时, A串接一个限流电阻接VDD, K接地。
K:LED背光地端。
第四部分 系统硬件设计
4.1 最小系统
复位时单片机初始化操作,只要给RST引脚加上两个机器周期以上高电平信号,就能够使STC89C51单片机复位。此次采取是12M晶振,按钮复位电路。
4.2 LCD显示电路
LCD显示器D0到D7和单片机P0口相连,LCD显示器EN口和单片机P3.4口相连,RS和P3.5相连。经过滑动变阻器改变LCD显示器显示对比度。
4.3 键盘输入电路
此次设计采取独立键盘,键盘按下时,对应I/O口电平由高变低,一次检测按键是否被按下。4个独立按键和单片机P3.0—P3.3口相连。
4.3 蜂鸣器和LED灯电路
蜂鸣器作用为准点报时产生报警声,LED在秒钟为偶数时或功效键被按下时亮。蜂鸣器和单片机P2.2口相连,LED灯和单片机P2.3口相连。
第五部分 仿真电路图和仿真结果
用Keil和Protues进行仿真调试,仿真结果完全达成预期目标。
第六部分 课程设计总结
此次单片机课程设计,在我和我搭档陈雅琴默契配合,和邹老师指导和同学帮助下顺利完成了。在设计过程中,从仿真电路设计,源程序书写和修改和实物电路焊接中全部碰到了不少问题,但在我们共同努力下处理了,而且从中学到了不少知识。我们在设计过程中还不停提出自己疑点和新想法,联络实际应用,将书本上学习东西利用到实际中,这些全部令我们受益匪浅。
课程设计需要很大耐心,尤其是碰到困难时候,这也是对我们考验。在设计过程中,我们碰到问题不是感到急躁,而是耐心地寻求处理措施,和老师、同学进行交流讨论,寻求最好处理措施。
总而言之,在此次课程设计中,我们不仅动手、动脑,也学会了不少东西,同时,谢谢对我们设计带来提议、意见和帮助老师和同学们!谢谢!
第七部分 参考文件
《单片机原理及应用(第二版)》 高等教育出版社
《新概念51单片机C语言教程》 电子工业出版社
附录A 实物图
附录B 系统源程序
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcdrs=P3^5; //定义1602液晶RS端
sbit lcden=P3^4;//定义1602液晶LCDEN端
sbit s1=P3^0; //定义按键--功效键
sbit s2=P3^1; //定义按键--增加键
sbit s3=P3^2; //定义按键--减小键
sbit s4=P3^3; //定义按键--闹钟键
sbit beep=P2^2; //定义蜂鸣器端
sbit led=P2^3; //定义LED灯端
uchar count,s1num,s4num;
char year,month,day,week,miao,shi,fen,pshi;
uchar code table[]=" 20 - - ";//定义初始上电时液晶默认显示状态
void delay(uint z) //延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void zhuanhuan()
{
if(shi==0)
pshi=12;
if(shi<=12&&shi>=1)
pshi=shi;
if(shi>12)
pshi=shi-12;
}
void di()//蜂鸣器发声函数
{
beep=0;
delay(300);
beep=1;
delay(300);
}
void write_com(uchar com)//液晶写命令函数
{
lcdrs=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_date(uchar date)//液晶写数据函数
{
lcdrs=1;
lcden=0;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void _shi() //写"AM"、"PM"函数
{
if(shi>=12)
{
write_com(0x80+0x40+1);//写出"PM"
write_date('P');
write_date('M');
}
else
{
write_com(0x80+0x40+1);//写出"AM"
write_date('A');
write_date('M');
}
}
void write_ymd(uchar add1,uchar date1)//写年月日函数
{
uchar shi,ge;
shi=date1/10;//分解一个2位数十位和个位
ge=date1%10;
write_com(0x80+add1);//设置显示位置
write_date(0x30+shi);//送去液晶显示十位
write_date(0x30+ge); //送去液晶显示个位
}
void write_sfm(uchar add,uchar date)//写时分秒函数
{
uchar shi,ge;
shi=date/10;//分解一个2位数十位和个位
ge=date%10;
write_com(0x80+0x40+add);//设置显示位置
write_date(0x30+shi);//送去液晶显示十位
write_date(0x30+ge); //送去液晶显示个位
}
void write_week(char week) //写液晶星期显示函数
{
write_com(0x80+12);
switch(week)
{
case 1: write_date('M');delay(5);
write_date('O');delay(5);
write_date('N');
break;
case 2: write_date('T');delay(5);
write_date('U');delay(5);
write_date('E');
break;
case 3: write_date('W');delay(5);
write_date('E');delay(5);
write_date('D');
break;
case 4: write_date('T');delay(5);
write_date('H');delay(5);
write_date('U');
break;
case 5: write_date('F');delay(5);
write_date('R');delay(5);
write_date('I');
break;
case 6: write_date('S');delay(5);
write_date('A');delay(5);
write_date('T');
break;
case 7: write_date('S');delay(5);
write_date('U');delay(5);
write_date('N');
break;
}
}
void writeym()
{
day=1;
month++;
if(month==13)
{
month=1;
year++;
if(year==100)
year=0;
write_ymd(3,year);//年若改变则重新写入
}
write_ymd(6,month);//月若改变则重新写入
}
void init()//初始化函数
{
uchar num;
lcden=0;
year=13;//初始化种变量值
month=6;
day=21;
week=5;
shi=13;
fen=59;
miao=58;
count=0;
s1num=0;
s4num=0;
write_com(0x38);//初始化1602液晶
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);//设置显示初始坐标
for(num=0;num<15;num++)//显示年月日星期
{
write_date(table[num]);
delay(5);
}
delay(5);
write_com(0x80+0x40+6);//写出时间显示部分两个":"
write_date(':');
delay(5);
write_com(0x80+0x40+9);
write_date(':');
delay(5);
write_week(week);
write_ymd(3,year);//分别送去液晶显示
write_ymd(6,month);
write_ymd(9,day);
write_sfm(10,miao);//分别送去液晶显示
write_sfm(7,fen);
write_sfm(4,shi);
TMOD=0x01;//设置定时器0工作模式1
TH0=(65536-50000)/256;//定时器装初值
TL0=(65536-50000)%256;
EA=1; //开总中止
ET0=1; //开定时器0中止
TR0=1; //开启定时器0
}
void keyscan()//按键扫描函数
{
if(s1==0)
{
delay(5);
if(s1==0)//确定功效键被按下
{
s1num++;//功效键按下次数统计
while(!s1);//释放确定
if(s1num==1)//第一次被按下时
{
TR0=0; //关闭定时器
write_com(0x80+3);//光标定位到年位置
write_com(0x0f); //光标开始闪烁
}
if(s1num==2)//第二次按下光标闪烁定位到月位置
{
write_com(0x80+6);
}
if(s1num==3)//第三次按下光标闪烁定位到日位置
{
write_com(0x80+9);
}
if(s1num==4)//第四次按下光标闪烁定位到星期位置
{
write_com(0x80+12);
}
if(s1num==7)//第七次被按下时光标定位到秒位置
{
write_com(0x80+0x40+10);
}
if(s1num==6)//第六次按下光标闪烁定位到分位置
{
write_com(0x80+0x40+7);
}
if(s1num==5)//第五次按下光标闪烁定位到时位置
{
write_com(0x80+0x40+4);
}
if(s1num==8)//第七次按下
{
s1num=0;//统计按键数清零
write_com(0x0c);//取消光标闪烁
TR0=1; //开启定时器使时钟开始走
}
}
}
if(s1num!=0)//只有功效键被按下后,增加和减小键才有效
{
if(s2==0)
{
delay(5);
if(s2==0)//增加键确定被按下
{
while(!s2);//按键释放
if(s1num==1)//若功效键第一次按下
{
year++; //则调整年加1
if(year==100)//若满100后将清零
year=0;
write_ymd(3,year);//每调整一次送液晶显示一下
write_com(0x80+3);//显示位置重新回到调整处
}
if(s1num==2)//若功效键第二次按下
{
month++;//则调整月加1
if(month==13)//若满12后将置一
month=1;
write_ymd(6,month);//每调整一次送液晶显示一下
write_com(0x80+6);//显示位置重新回到调整处
}
if(s1num==3)//若功效键第三次按下
{
day++;//则调整日加1
if(year%4==0&&month==2)
{
if(day==30)//若满29后将置一
day=1;
}
if(year%4!=0&&month==2)
{
if(day==29)//若满28后将置一
day=1;
}
if(month!=2&&month!=4&&month!=6&&month!=9&&month!=11)
{
if(day==32)//若满31后将置一
day=1;
}
if(month==4||month==6||month==9||month==11)
{
if(day==31)//若满30后将置一
day=1;
}
write_ymd(9,day);;//每调整一次送液晶显示一下
write_com(0x80+9);//显示位置重新回到调整处
}
if(s1num==4)//若功效键第四次按下
{
week++;//则调整星期加1
if(week==8)//若满8后将置一
week=1;
write_week(week);//每调整一次送液晶显示一下
write_com(0x80+12);//显示位置重新回到调整处
}
if(s1num==7)//若功效键第七次按下
{
miao++; //则调整秒加1
if(miao==60)//若满60后将清零
miao=0;
write_sfm(10,miao);//每调整一次送液晶显示一下
write_com(0x80+0x40+10);//显示位置重新回到调整处
}
if(s1num==6)//若功效键第二次按下
{
fen++;//则调整分钟加1
if(fen==60)//若满60后将清零
fen=0;
write_sfm(7,fen);//每调整一次送液晶显示一下
write_com(0x80+0x40+7);//显示位置重新回到调整处
}
if(s1num==5)//若功效键第五次按下
{
shi++;
if(shi==24)//若满24后将清零
{
shi=0;
}
if(s4num==0)
{
write_sfm(4,shi);;//每调整一次送液晶显示一下
write_com(0x80+0x40+4);//显示位置重新回到调整处
}
if(s4num==1)
{
zhuanhuan();
_shi();
write_sfm(4,pshi);;//每调整一次送液晶显示一下
write_com(0x80+0x40+4);//显示位置重新回到调整处
}
}
}
}
}
if(s3==0)
{
delay(5);
if(s3==0)//确定减小键被按下
{
while(!s3);//按键释放
if(s1num==1)//若功效键第一次按下
{
year--;//则调整秒减1
if(year==-1)//若减到负数则将其重新设置为99
year=99;
write_ymd(3,year);//每调整一次送液晶显示一下
write_com(0x80+3);//显示位置重新回到调整处
}
if(s1num==2)//若功效键第二次按下
{
month--;//则调整分钟减1
if(month==0)//若减到负数则将其重新设置为59
month=12;
write_ymd(6,month);//每调整一次送液晶显示一下
write_com(0x80+6);//显示位置重新回到调整处
}
if(s1num==3)//若功效键第二次按下
{
day--;//则调整日加1
if(year%4==0&&month==2)
{
if(day==0)//若满29后将置一
day=29;
}
if(year%4!=0&&month==2)
{
if(day==0)//若满28后将置一
day=28;
}
if(month!=2&&month!=4&&month!=6&&month!=9&&month!=11)
{
if(day==0)//若满31后将置一
day=31;
}
if(month==4||month==6||month==9||month==11)
{
if(day==0)//若满30后将置一
day=30;
}
write_ymd(9,day);;//每调整一次送液晶显示一下
write_com(0x80+9);//显示位置重新回到调整处
}
if(s1num==4)//若功效键第二次按下
{
week--;//则调整小时减1
if(week==0)//若减到负数则将其重新设置为23
week=7;
write_week(week);//每调整一次送液晶显示一下
write_com(0x80+12);//显示位置重新回到调整处
}
if(s1num==7)//若功效键第一次按下
{
miao--;//则调整秒减1
if(miao==-1)//若减到负数则将其重新设置为59
miao=59;
write_sfm(10,miao);//每调整一次送液晶显示一下
write_com(0x80+0x40+10);//显示位置重新回到调整处
}
if(s1num==6)//若功效键第二次按下
{
fen--;//则调整分钟减1
if(fen==-1)//若减到负数则将其重新设置为59
fen=59;
write_sfm(7,fen);//每调整一次送液晶显示一下
write_com(0x80+0x40+7);//显示位置重新回到调整处
}
if(s1num==5)//若功效键第二次按下
{
shi--;
if(shi==-1)//若满24后将清零
shi=23;
if(s4num==0)
{
write_sfm(4,shi);;//每调整一次送液晶显示一下
write_com(0x80+0x40+4);//显示位置重新回到调整处
}
if(s4num==1)
{
zhuanhuan();
_shi();
write_sfm(4,pshi);;//每调整一次送液晶显示一下
write_com(0x80+0x40+4);//显示位置重新回到调整处
}
}
}
}
if(s1num==0)
{
if(s4==0)
{
delay(5);
if(s4==0)//确定功效键被按下
{
s4num++;//功效键按下次数统计
while(!s4);//释放确定
if(s4num==1)//第一次被按下时
{
zhuanhuan();
_shi();
write_sfm(4,pshi);
}
if(s4num==2)//第二次按下
{
s4num=0;//统计按键数清零
write_com(0x80+0x40+1);
write_date(' ');
write_date(' ');
write_sfm(4,shi);
}
}
}
}
}
void main()//主函数
{
init();//首先初始化各数据
while(1)//进入主程序大循环
{
keyscan();//不停检测按键是否被按下
if(s1num!=0)
led=0;
else
led=miao%2;
if((shi>7&&shi<23)&&(fen==0)&&(miao==0))
{
di();
}
}
}
void timer0() interrupt 1//定时器0中止服务程序
{
TH0=(65536-50000)/256;//再次装定时器初值
TL0=(65536-50000)%256;
count++; //中止次数累加
if(count==20) //20次50毫秒为1秒
{
count=0;
miao++;
if(miao==60)//秒加到60则进位分钟
{
miao=0;//同时秒数清零
fen++;
if(fen==60)//分钟加到60则进位小时
{
fen=0;//同时分钟数清零
shi++;
if(shi==24)//小时加到24则小时清零
{
shi=0;
week++;
if(week==8)
{
week=1;
}
write_week(week);//星期若改变则重新写入
day++;
if(year%4==0&&month==2)//判定是否为闰年2月
{
if(day==30)
{
writeym();
}
write_ymd(9,day);//日若改变则重新写入
}
if(year%4!=0&&month==2)//判定是否为平年2月
{
if(day==29)
{
writeym();
}
write_ymd(9,day);//日若改变则重新写入
}
if(month!=2&&month!=4&&month!=6&&month!=9&&month!=11)
{
if(day==32)
{
writeym();
}
write_ymd(9,day);//日若改变则重新写入
}
if(month==4||month==6||month==9||month==11)
{
if(day==31)
{
writeym();
}
write_ymd(9,day);//日若改变则重新写入
}
}
if(s4num==1)
{
zhuanhuan();
_shi();
write_sfm(4,pshi);//12小时制小时若改变则重新写入
}
else write_sfm(4,shi);//二十四小时制小时若改变则重新写入
}
write_sfm(7,fen);//分钟若改变则重新写入
}
write_sfm(10,miao);//秒若改变则重新写入
}
}
展开阅读全文