目录
摘 要 3
一 、实训目的 4
二 、具体内容 4
三 、方案讨论 5
四 仿真电路 5
4.1、仿真流程 5
4.2、仿真电路图 6
五 、程序设计 6
六、 程序流程图 12
七 、程序分析 13
八、 绘制PCB图 14
九、腐蚀/打孔/焊接 15
摘 要
数字时钟具有性能稳定、精确度高、成本低、易十产品化,以及万便、实用等特点。适用于家庭、公司、机关等众多场所。为人们的日常生活、出行安排提供了方便成为人们日常生活中不可缺少的一部分。
近些年,随着科技的发展和社会的进步,人们对数字钟的要求也越来越高,传统的时钟已不能满足人们的需求。多功能数字钟不管在性能还是在样式上都发生了质的变化,有电子时钟、数字闹钟等等。单片机在多功能高精度时钟中的应用已是非常普遍的,人们对高精度钟的功能及工作顺序都非常熟悉,但是却很少知道它的内部结构以及工作原理。由单片机作为数字钟的核心控制器,可以通过它的时钟信号进行计时实现计时功能,将其时间数据经单片机输出,利用液晶显示屏显示出来。通过键盘可以进行定时、校时功能。输出设备显示器可以用液晶显示技术和数码管显示技术。
一 、实训目的
- 在学习了《单片机原理及接口技术》课程后,为了加深对理论知识的理解,学习理论知识在实际中的运用,培养动手能力和解决实际问题的能力。
- 熟悉Ptoteus及Keil软件的调试和仿真。
- 通过实验提高对单片机的认识。
- 通过实验提高焊接、布局、电路检查能力。
- 通过实验提高软件调试能力。
- 进一步熟悉和掌握单片机的结构及工作原理。
- 通过课程设计,掌握以单片机为核心的电路设计的基本方法和技术。
- 通过实际程序设计和调试,逐步掌握模块化程序设计方法和调试技术。
二 、具体内容 - 具体要求
1 实时显示秒、分、时、星期(可自动或手动设置显示)
2 利用三个按键实现时间的调节(加/减/切换)
3 处于调节模式下,lcd屏幕要有相应的提示
2. 方案设计
采用1602lcd屏幕用于时间显示,采用at89c52单片机用作主控芯片,使用轻触开关调整时间
三 、方案讨论
- 89c52单片机有四个I/O口,液晶屏数据传输需要独占一个I/O口,由于P0口用作I/O口时,需要加上拉电阻,从而增加制作成本,增加电路复杂度,故数据传输接口不宜采用P0口
- 1602液晶屏还需要连接RS,RW,E三个接口从而控制数据读写,同时应当考虑到系统稳定性,所以不能将其同按键连接到同一接口
- 需要三个按键控制时间的加减和调整,而89c52单片机只有两个外部中断接口,所以不考虑将按键接入到外部中断接口上.
- 综上所述,最终将液晶屏的数据传输接口接入到P1口,RS,RW,E分别接入P37,P36,P35口,将按键key0,key1,key3接入到P27,P26,P25口,此外,该单片机还需要晶振电路才能运行
- 所需物料:
a) stc89c521
b) lcd16021
c) 按键开关3
d) 晶振1
e) 独石电容2
f) 排针4
四 仿真电路
4.1、仿真流程
1.在计算机上打开“PROTEUS8”仿真软件。
2.建立新的项目,选择start模块中的new project。选择项目文件保存的路径,点击下一步,选择项目所需电路板的大小接着点击下一步,选择不创建pcb点击下一步,创建Firmware Project Family选择8051,Controller选择AT89C51创建完成。
3.在keil4编写仿真所用的程序,首先新建一个工程,选择project-new project,弹出一个对话框,填写工程名,确定。然后选择你所使用的AT89C51芯片确定。然后点击文件File—New,新建一个文件,确定。然后将新建的文件添加进工程中,开始编写代码运行无误后创建hex文件再进行编译。
4.将电路图完成载入用keil4创建的hex文件最终实现仿真。
4.2、仿真电路图
五 、程序设计
- 程序论证:
a) 定时可采用两种方式来实现:
i. 方式1:自定义延时函数,缺点:精度不高
ii. 方式2:使用89c52单片机中自带的定时器实现,优点:精度高,容易实现
iii. 综合两种方式,故采用方式2,使用单片机中自带的定时器计时,最终采用定时器0方式1,设置初值为50000微妙,循环20次为1秒
b) 由于按键只有三个,但需要实现对星期,小时,分钟,秒钟的加减,所以需要一个按键对需要更改的参数进行切换,另外两个按键实现加和减
i. 切换可以定义一个flag,按下切换按键就对flag的值加一,通过flag来判断是对具体哪个参数进行修改,所要修改的参数有:星期,小时,分钟,秒钟,故要求flag有四个及以上的值,另外,还需要让时钟不处于设置模式,所以最终确定的flag的值为0,1,2,3,4;同时还需要使flag的值不能大于4,所以需要增加一个判定条件,即flag>4,则flag=0;
ii. 时间的加和减有两个按键,所以需要定义两个函数实现对时间的增加和减少,在调用时间加/减函数的时候把flag传递到该函数中去,该函数通过判定flag的值就能精准定位需要加或减的参数
c) 程序中有了flag这个参数,所以程序能清楚的知道它要调整的参数,而用户不知道,需要将正在调整什么项目显示到液晶屏幕上,所以需要另外定义个dispset函数来显示用户正在调整的参数,同时这个函数需要将flag的值传递过去
d) 同时需要考虑,时间调整到一个极值就不能继续增加或减小,如一天中只有0点到23点,如果超过23点,则会变成0点,同理,星期只有1-7,分钟只有0-59,如果超过这个极值,程序会自动将其赋值为初始值
2. 最终程序:
#include <reg51.h>
#define DATAPORT P1//定义数据端口
#define uchar unsigned char
sbit RS=P3^7; //定义RS 数据/命令选择接口
sbit RW=P3^6; //定义RW 读/写选择接口
sbit E=P3^5; //定义使能接口
sbit key0=P2^7;//加
sbit key1=P2^6;//减
sbit key2=P2^5;//切换
int timeflag=0;//调整时间flag
uchar tablew1[]=“MTWTFSS”;
uchar tablew2[]=“ouehrau”;
uchar tablew3[]=“neduitn”;
uchar tablew4[]="…"; //周的数组( Mon. Tue. Wed. Thu. Fri. Sat. Sun.)
uchar tablesetweek[]=“set week”;//显示设置周
uchar tablesethour[]=“set hour”; //显示设置小时
uchar tablesetminute[]=“set minute”; //显示设置分钟
uchar tablesetsecond[]=“set second”; //显示设置秒
uchar tablesetnull[]=“LkwCxwPhl”;
char d[]={‘0’,‘0’,’:’,‘0’,‘0’,’:’,‘0’,‘0’};//定义初始化值
uchar week=0,hour=0,minute=0,second=0,count=20; //定义秒分时周
void transfer();
void init(); //初始化函数声明
void writeCOM(uchar i); //写命令函数声明
void writeData(uchar j); //写数据函数声明
void fbusy(); //检查忙函数声明
void timechange(int t); //时间调整函数
void disp(); //声明显示函数
void dispset(int timeflag);//显示设置
void timeadd(int timeflag);
void timecut(int timeflag);
int i; //全局变量i
void delay(int num){
int j,k;
for(j=0;j<=num;j++){
for(k=0;k<=120;k++);
}
}
int main(void){
EA=1; //使能=1
ET0=1;
TMOD=0x01;//定时器0方式1
TH0=(65535-50000)/256;
TL0=(65535-50000)%256; //初值为50000微秒
TR0=1;
init();
while(1){
transfer(); //秒分时周转换
disp(); //显示时间
dispset(timeflag); //显示设置
if(key2==0){
init();
delay(200);
timeflag++;
if(timeflag>4){ //让flag小于等于4
timeflag=0;
init();
}
}
if(key0==0){ //按下后减小数值
delay(200);
timeadd(timeflag);
}
if(key1==0){ //按下后增加数值
delay(200);
timecut(timeflag);
}
}
}
void disp(){ //显示时间函数
writeCOM(0x80); //写入显示缓冲区起始地址为第1行第2列
writeData(tablew1[week]);
writeCOM(0x81);
writeData(tablew2[week]);
writeCOM(0x82);
writeData(tablew3[week]);
writeCOM(0x83);
writeData(tablew4[week]);
writeCOM(0xc0);
for(i=0;i<8;i++){
writeData(d[i]);
}
}
void dispset(int timeflag){ //显示设置状况函数
switch(timeflag){
case(0):
writeCOM(0x87);
for(i=0;i<10;i++){
writeData(tablesetnull[i]);
}
break;
case(1):
writeCOM(0x87);
for(i=0;i<8;i++){
writeData(tablesetweek[i]);
}
break;
case(2):
writeCOM(0x87);
for(i=0;i<8;i++){
writeData(tablesethour[i]);
}
break;
case(3):
writeCOM(0x87);
for(i=0;i<10;i++){
writeData(tablesetminute[i]);
}
break;
case(4):
writeCOM(0x87);
for(i=0;i<10;i++){
writeData(tablesetsecond[i]);
}
break;
}
}
void init(){
writeCOM(0x01); //清屏
writeCOM(0x38); //开显示,读8位数据,显示两行,使用5*7的字型
writeCOM(0x0c); //显示器开,光标关,字符不闪烁
writeCOM(0x06); //字符不动,光标自动右移一位
}
void writeCOM(uchar i){ //写命令
fbusy();
RS=0;
RW=0;
E=1;
DATAPORT=i;
E=0; //负脉冲写
}
void writeData(uchar j){ //写数据
fbusy();
RS=1;
RW=0;
E=1;
DATAPORT=j;
E=0; //负脉冲写
}
void fbusy(){//检查忙函数
DATAPORT=0xff; //读之前向端口写1,确保读数正确
RS=0;RW=1;
E=0;
E=1; //正脉冲读
while(DATAPORT&0x80){ //忙,等待
E=0;
E=1;
}
}
void transfer(){ //用于秒分时周的显示
d[0]=hour/10+0x30;
d[1]=hour%10+0x30;
d[3]=minute/10+0x30;
d[4]=minute%10+0x30;
d[6]=second/10+0x30;
d[7]=second%10+0x30;
}
void clock() interrupt 1{ //计时
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
while(–count==0){
count=20; //50毫秒*20等于1秒
second++;
if(second>=60){
second=0; //秒到分钟
minute++;
if(minute>=60){ //分钟到小时
minute=0;
hour++;
if(hour>=24){ //小时到天
hour=0;
week++;
if(week>=7){ //星期天到星期一
week=0;
}
}
}
}
}
}
void timeadd(int flag){//时间加
switch(flag){
case(1):
if(week6){
week=0;
break;
}
week++; //增加星期的值
break;
case(2):
if(hour23){
hour=0;
break;
}
hour++; //增加小时的值
break;
case(3):
if(minute59){
minute=0;
break;
}
minute++; //增加分钟的值
break;
case(4):
if(second59){
second=0;
break;
}
second++; //增加秒的值
break;
default:
break;
}
}
void timecut(int flag){ //时间减
switch(flag){
case(1):
if(week0){
week=6;
break;
}
week–; //减少星期的值
break;
case(2):
if(hour0){
hour=23;
break;
}
hour–; //减少小时的值
break;
case(3):
if(minute0){
minute=59;
break;
}
minute–; //减小分钟的值
break;
case(4):
if(second0){
second=59;
break;
}
second–; //减少秒的值
break;
default:
break;
}
}
六、 程序流程图
该流程图先对电路进行初始化,然后程序main函数开始顺序执行,进入主程序,在主程序中调用各个子程序,在运行时可对时钟进行调整,key2键是选择调整对象,key0键是进行增加,key1键是进行减少。
七 、程序分析
-
使用单片机P1口输出数据
-
使用单片机P2口的567引脚进行按键检测
-
使用P3口对lcd屏RS/RW的控制
-
使用flag标识实现对分/时/星期 的修改定位
-
定时器采用定时器0方式1,设置初值为50000
-
timeflag的值为1就改变星期的值,为2就改变小时的值,为3就改变分钟的值,为4就改变秒钟的值,为其他就不做任何操作.
-
通过key1/key0的按下去调用时间加/减的函数,并将timeflag的值传递到时间加/减的函数中.
八、 绘制PCB图 -
绘制原理图库
a) 测量各个元器件引脚的数量,准确的将原理图库绘制出来
a) 测量元器件具体大小,绘制各元器件的封装 -
绘制原理图
a) 参考方正电路绘制出原理图,并加上晶振电路,电源电路,和排针
b) 最终原理图效果: -
原理图导入pcb完成布线工作
九、腐蚀/打孔/焊接
- 焊接好之后需要用万用表检测是否通路,有引脚短路
- 最终实物图
- 将预先编译好的hex程序文件烧录至单片机
- 测试各项功能是否正常