设计题目:基于单片机的可调电子时钟
院 系: 电气工程系
专 业:
年 级:
姓 名:
指导教师:
西南交通大学峨眉校区
20## 年 5月 15 日
一 原理:
1.1单片机最小系统接线图原理:
图1
单片机最小系统是在以MCS-51单片机为基础上扩展,使其能更方便地运用于测试系统中不仅具有控制方便、组态简单和灵活性大等优点,而且可以大幅度提高被测试的技术指标,从而能够大大提高产品的质量和数量。单片机以其功能强、体积小、可靠性高、造价低和开发周期短等优点,称为在实时检测和自动控制领域中广泛应用的器件,在工业生产中称为必不可少的器件,尤其是在日常生活中发挥的作用也越来越大。本课题设计主要利用MCS-51单片机I/O口,蜂鸣器,键盘。适合于我们学生用于单片机的学习掌握和一些各种科研立项等的需求。因此,研究单片机最小系统有很大的实用意义
。1.2 LCD1602接线图:
图2
1.2.1 LCD1602的工作原理:
1602LCD分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别。
1.2.2 1602LCD主要技术参数:
显示容量:16×2个字符
芯片工作电压:4.5—5.5V
工作电流:2.0mA(5.0V)
模块最佳工作电压:5.0V
字符尺寸:2.95×4.35(W×H)mm
1.2.3 引脚功能说明:
第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脚:背光源负极。
1.2.4 控制命令表:
指令1:清显示,指令码01H,光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标
1.3独立键盘接线图:
图3
P1口作为一般的输入输出口使用,如图所示:只要有按键按下,那么相应管脚的数值就会发生改变,这就是我们判断按键是否按下的原理,其中需要注意的就是由于单片机芯片运算速度快,在按键按下的时候由于按键具有抖动现象,所以我们必须要注意消抖,这是程序能够正确运行的关键,不能大意。
二 系统接线图原理:
图4
单片机应用系统是指微处理器用于工业测量控制功能所必备的硬件结构系统。在这幅图中,有复位电路,石英晶体振荡电路即时钟电路,两个独立键盘电路,IO接口电路,LCD1602接线电路。过程输入/输出通道包括模拟量输入/输出通道和开关量输入/输出通道两大部分。对模拟量信号的采集,需要经过模拟量输入通道的A/D转换器转换成数字信号,再通过接口送入微处理器进行加工处理、分析运算等。各部分的组合,就构成了硬件接线原理图,到达这一步,硬件设计就完成了,接下来的工作就是编程。
三 程序流程图:
图5
程序流程图用于程序的编写,是设计的核心。其中,开始阶段包含了各变量的赋值,各IO口的赋值,以及数组等的初始化。检测有无按键按下这个板块是核心也是难点,我们必须要注意消斗和松手检测。计算键值这个板块主要在于数值的计算,这需要自己完成,而计算机不能帮你完成,因此需要对二进制数与十六进制之间进行转化,所以要细心。送值显示是利用LCD1602来完成的,所以重点在编程。
四 程序:
#include<reg51.h>
#include<stdio.h>
sbit k1 = P1^1; //位申明,根据硬件接线电路对必要的位进行定义,下同
sbit k2 = P1^5;
sbit k3 = P1^7;
sbit rs = P3^1;
sbit en = P3^5;
unsigned int num, m, n, i, j, h, d; //定义几个必要的变量
unsigned char tab[] = " 15:15:15"; //定义一个数组
unsigned char tab1[]=" It not easy"; //定义一个数组,简要说明此次编程的感受
void delay( int x) //粗略延时函数,延时时间约为x毫秒
{
int y;
while(--x)
{
for( y=0;y<115;++y);
}
}
void wtc( unsigned char ord) //LCD写命令函数
{
rs = 0;
en = 1;
P2 = ord;
delay(1);
en = 1;
delay(2);
en = 0;
}
void wtd( unsigned char dta) //LCD写数据函数
{
rs = 1;
en = 0;
P2 = dta;
delay(1);
en = 1;
delay(5);
en = 0;
}
void ini() //初始化函数,对相关数据以及变量等初始化
{
wtc(0x38); //显示设置
wtc(0x0c); //光标设置
wtc(0x06); //显示方式设置
wtc(0x01); //清屏
wtc(0x80); //初始化地址
TH0 = (65536-50000)/256; //定时50ms时,对定时器装初值
TL0 = (65536-50000)%256; //同上
m = 5;
j = 0;
d = 0;
TMOD = 0x01; //定时器方式等设置
EA = 1;
ET0 = 1;
TR0 = 1;
tab[3] = 1;
tab[4] = 5;
tab[6] = 1;
tab[7] = 5;
tab[9] = 1;
tab[10] = 5;
n = tab[3]*10+tab[4];
}
void displ( unsigned int addr,unsigned char dt) // LCD命令和数据显示函数,负责在指定位置显示指定数据
{
wtc(0x80+addr); //指定地址
wtd(0x30+dt); //显示数据
}
void shix() //时间显示函数,在指定位置显示 时,分,秒
{
displ(4, tab[4]);
displ(3, tab[3]);
displ(7, tab[7]);
displ(6, tab[6]);
displ(10, tab[10]);
displ(9, tab[9]);
}
void jishi() // 计时函数,清0定时器的计量值同时改变对应 时,分,秒的值
{
if(num==20)
{
num = 0;
++tab[10];
if(tab[10]>9)
{
tab[10] = 0;
++tab[9];
if(tab[9]>5)
{
tab[9] = 0;
++tab[7];
if(tab[7]>9)
{
tab[7] = 0;
++tab[6];
if(tab[6]>5)
{
tab[6] = 0;
++tab[4];
++n;
if(n>23)
{
n = 0;
tab[4] = 0;
tab[3] = 0;
}
if(tab[4]>9)
{
tab[4] = tab[4]-10;
}
}
}
}
}
}
}
void keyj() // 数值加键判别函数,实现相应数值的加
{
if(k2==0)
{
delay(5);
if(k2==0)
{
while(!k2); //消抖
if(d==1)
{
++tab[4];
++n;
if(n>23)
{
tab[4] = 0;
tab[3] = 0;
n = 0;
}
if(tab[4]>9)
{
++tab[3];
}
if(tab[4]>9)
tab[4] = tab[4]-10;
}
if(d==2)
{
++tab[7];
if(tab[7]>9)
{
tab[7] = 0;
++tab[6];
if(tab[6]>5)
tab[6] = 0;
}
}
if(d==3)
{
++tab[10];
if(tab[10]>9)
{
tab[10] = 0;
++tab[9];
if(tab[9]>5)
tab[9] = 0;
}
}
wtc(0x0c); //关光标
shix();
}
}
}
void keyg() //功能键判别函数,实现按键的判定以及完成相应需要完成的工作
{
if(k1==0)
{
delay(5);
if(k1==0)
{
while(!k1); //消抖
++j;
++d;
m = 1;
TR0 = 0; //关闭定时器
if(j>3)
{
wtc(0x0c);
j = 0;
d = 0;
m = 5;
TR0 = 1;
}
if(j==1)
{
wtc(0x84);
wtc(0x0f);
}
if(j==2)
{
wtc(0x80+7);
wtc(0x0f);
}
if(j==3)
{
wtc(0x80+10);
wtc(0x0f); //光标闪烁
}
}
}
keyj();
}
void main() //主函数,负责各个子函数的调用
{
unsigned int i;
ini();
wtc(0x01);
for(i=0;i<15;++i)
wtd(tab[i]);
wtc(0x80+0x40);
for(i=0;i<15;++i)
wtd(tab1[i]);
while(1)
{
keyg();
if(m==5)
{
shix();
jishi();
}
}
}
void tim0() interrupt 1 //中断函数
{
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
++num; //计数
}
五 仿真结果运行图
5.1:
图6
图6为没有按键按下时,时钟正常运行时的结果图,该图正确反映了时间的走动,完成了准确计时并且显示相应时间的任务,达到了此次课程设计的基本内容和基本要求之一,同时也是此次课程设计的第一个成功点。
5.2:
图7
图7为功能键在一轮循环中,第一次按下后的结果显示,此时定时器停止计时,并且光标在小时的个位开始闪烁,很明显,这是提醒我们调节时间,同时也是为调整时间按键做准备,以及为下一个需要调整的值做准备。
5.3:
图8
图8为功能键在一轮循环中第二次按下后的结果显示,其目的和用意同图7,当然,当我们再次按下功能键后,光标会在秒的个位显示,这里就不再重复显示了,当我们在一轮循环中第四次按下功能键后,光标会停止闪烁,并接着计时。
5.4:
图9
图9为数值加键按下后调整时间时的图,此时,每按一下数值加键,光标显示位置的数会加1,这一步就实现了时钟可调这一要求,当在一轮循环中,我们第四次按下功能键后,定时器恢复并继续计时,到此,可调电子时钟的设计完成。
六 课程设计心得体会:
通过此次课程设计,使我更加扎实的掌握了有关单片机方面的知识,在设计过程中虽然遇到了一些问题,但经过一次又一次的思考,一遍又一遍的检查终于找出了原因所在,也暴露出了前期我在这方面的知识欠缺和经验不足。实践出真知,通过亲自动手制作,使我们掌握的知识不再是纸上谈兵。
过而能改,善莫大焉。在课程设计过程中,我不断发现错误,不断改正,不断领悟,不断获取。最终的检测调试环节,本身就是在践行“过而能改,善莫大焉”的知行观。这次课程设计终于顺利完成了,在设计中遇到了很多问题,最后在老师的指导下,终于游逆而解。在今后社会的发展和学习实践过程中,一定要不懈努力,不能遇到问题就想到要退缩,一定要不厌其烦的发现问题所在,然后一一进行解决,只有这样,才能成功的做成想做的事,才能在今后的道路上劈荆斩棘,而不是知难而退,那样永远不可能收获成功,收获喜悦,也永远不可能得到社会及他人对你的认可!
课程设计诚然是一门专业课,给我很多专业知识以及专业技能上的提升,同时又是一门讲道课,一门辩思课,给了我许多道,给了我很多思,给了我莫大的空间。同时,设计让我感触很深。使我对抽象的理论有了具体的认识。通过这次课程设计,我掌握了有关单片机I/O口的使用以及矩阵式键盘的接法和扫描计算等等,加深了单片机编程软件以及仿真软件的应用,让我对单片机的认识以及操作更上一层楼。
我认为,在这次的实践中,不仅培养了独立思考、动手操作的能力,在各种其它能力上也都有了提高。更重要的是,我学会了很多学习的方法。而这是日后最实用的,真的是受益匪浅。要面对社会的挑战,只有不断的学习、实践,再学习、再实践。这对于我们的将来也有很大的帮助。以后,不管有多苦,我想我们都能变苦为乐,找寻有趣的事情,发现其中珍贵的事情。就像中国提倡的艰苦奋斗一样,我们都可以在实践结束之后变的更加成熟,会面对需要面对的事情。
回顾起此课程设计,至今我仍感慨颇多,从理论到实践,在这段日子里,可以说得是苦多于甜,但是可以学到很多很多的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到问题,可以说得是困难重重,但可喜的是最终都得到了解决。
此次设计也让我明白了思路即出路,有什么不懂不明白的地方要及时请教或上网查询,只要认真钻研,动脑思考,动手实践,就没有弄不懂的知识,收获颇丰。
七 参考文献:
《单片机原理及C51开发技术》西南交通大学出版社。
第二篇:液晶显示的电子钟c程序
可遥控校对时间(先按STOP,调时,START),用1206液晶显示(r/w接地),能自动进行闰年补偿,程序如下(红外接收输出管脚接单片机外部中断0),用时可能由于遥控码不一样而需要稍加修改,有需要遥控解码的请留言
如发现错误,请指正
还可以加入闹钟的程序
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit rs=P3^5;
sbit en=P3^4;
sbit dula=P2^6;
sbit wela=P2^7;
uchar code tablelcd[]={
0x30,0x31,0x32,0x33,
0x34,0x35,0x36,0x37,
0x38,0x39,0x41,0x42,
0x43,0x44,0x45,0x46,0x20,0x2d,0x3a,0x27};
uchar table[15]={0x00,0x01,0x02,0x03,0x05,0x06,0x08,0x09,0x0c, 0x43,0x44,0x46,0x47,0x49,0x4a};
uchar num,temp0,n,flag;
uint shi,fen,miao,ye,ri,zhou,time,nian;
uchar irdate[33];
uchar ircode[4];
uchar disp[8];
uchar xian[8];
uchar xian1[8];
uchar irreceok,irtime,irflag,bitnum;
void delay(uchar z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=0;y<110;y++);
}
void timer0init()
{
EA=1;
TMOD=0x12;
TH0=0x00;
TL0=0x00;
TH1=(65536-46080)/256;
TL1=(65536-46080)%256;
ET0=1;
TR0=1;
ET1=1;
TR1=1;
}
void intinit()
{
EA=1;
IT0=1;
EX0=1;
}
void irdell()
{
uchar temp,k,j,i;
k=1;
for(i=0;i<4;i++)
{
for(j=0;j<8;j++) {
temp=temp>>1; if(irdate[k]>6) {
temp=temp|0x80; }
k++;
}
ircode[i]=temp; }
}
void irwork()
{
disp[0]=ircode[0]/16; disp[1]=ircode[0]%16; disp[2]=ircode[1]/16; disp[3]=ircode[1]%16; disp[4]=ircode[2]/16; disp[5]=ircode[2]%16; disp[6]=ircode[3]/16; disp[7]=ircode[3]%16; }
void write_com(uchar com) {
rs=0;
P0=com;
delay(5);
en=1;
delay(5);
en=0;
}
void write_date(uchar date) {
rs=1;
P0=date;
delay(5);
en=1;
delay(5);
en=0;
}
void init()
{
shi=0;
fen=0;
miao=0;
nian=2012;
ye=1;
ri=1;
zhou=7;
n=0;
temp0=100;
timer0init();
intinit();
dula=0;
wela=0;
en=0;
write_com(0x38);
write_com(0x0f);
write_com(0x06);
delay(15);
write_com(0x38);
delay(5);
write_com(0x38);
delay(5);
write_com(0x38);
write_com(0x38);
write_com(0x08);
write_com(0x01);
write_com(0x06);
write_com(0x0f);
}
void readrece()
{
if(ircode[1]==0xbf) /*用户码校,可不要,是为了防止错码而产生误操作而设*/ {
switch(ircode[3])
{
case 0xf3: temp0=0;/*数字0~9的红外码*/
break;
case 0xef: temp0=1;
break;
case 0xee: temp0=2;
break;
case 0xed: temp0=3;
break;
case 0xeb: temp0=4;
break;
case 0xea: temp0=5;
break;
case 0xe9: temp0=6;
break;
case 0xe7: temp0=7;
break;
case 0xe6: temp0=8;
break;
case 0xe5: temp0=9;
break;
case 0xf7: temp0=11; /*左键红外码*/ break;
case 0xf5: temp0=12; /*右*/
break;
case 0xfa: temp0=13; /*上*/
break;
case 0xf2: temp0=14; /*下*/
break;
case 0xf6: flag=0;TR1=1; /*STOP*/ break;
case 0xf9: flag=1;TR1=0; /*START*/ break;
// case 0xfb: 4;
// break;
// case 0xff: 1;
// break;
// case 0xfe: 2;
// break;
// case 0xfd: 3;
// break;
}
}
}
void set()
{
if(ircode[1]==0xbf)
{
if(temp0<10)
{
switch(n)
{
case 0: nian=nian%1000+(1000*temp0); break;
case 1: nian=nian/1000*1000+nian%100+(100*temp0); break;
case 2: nian=nian/100*100+nian%10+(10*temp0); break;
case 3: nian=nian/10*10+temp0;
break;
case 4: ye=ye%10+(10*temp0);
break;
case 5: ye=ye/10*10+temp0;
break;
case 6: ri=ri%10+(10*temp0);
break;
case 7: ri=ri/10*10+temp0;
break;
case 8: zhou=temp0;
break;
case 9: shi=shi%10+(10*temp0);
break;
case 10: shi=shi/10*10+temp0;
break;
case 11: fen=fen%10+(10*temp0);
break;
case 12: fen=fen/10*10+temp0;
break;
case 13: miao=miao%10+(10*temp0);
break;
case 14: miao=miao/10*10+temp0;
break;
}
write_date(tablelcd[temp0]);
n++;
if(n>=15)
n=0;
}
if(temp0==11)
{
n--;
if(n>=15)
n=14;
}
if(temp0==12)
{
n++;
if(n>=15)
n=0;
}
if((temp0==13)&&(n>8)) n=0;
if((temp0==14)&&(n<=8)) n=9;
if(n>=15)
n=0;
write_com(0x80+table[n]); }
}
void fenli()
{
xian[0]=nian/1000; xian[1]=nian/100%10; xian[2]=nian/10%10; xian[3]=nian%10; xian[4]=17;
xian[5]=ye/10;
xian[6]=ye%10;
xian[7]=17;
xian[8]=ri/10;
xian[9]=ri%10;
xian[10]=16;
xian[11]=16;
xian[12]=zhou;
xian1[0]=shi/10;
xian1[1]=shi%10; xian1[2]=18;
xian1[3]=fen/10;
xian1[4]=fen%10; xian1[5]=18;
xian1[6]=miao/10; xian1[7]=miao%10; }
void main()
{
init();
while(1)
{
if(flag==0)
{
fenli();
write_com(0x80);
for(num=0;num<13;num++) {
write_date(tablelcd[xian[num]]); }
write_com(0x80+0x43);
for(num=0;num<8;num++) {
write_date(tablelcd[xian1[num]]); }
write_com(0x80);
}
if(irreceok)
{
P1=0xfe;
irdell();
irreceok=0;
irwork();
readrece();
if(flag==1)
set();
temp0=100;
P1=0xff;
}
}
}
void timer0() interrupt 1
{
irtime++;
}
void inter() interrupt 0
{
if(irflag)
{
if(irtime>30)
{
bitnum=0;
}
irdate[bitnum]=irtime;
irtime=0;
bitnum++;
if(bitnum==33)
{
bitnum=0;
irreceok=1;
}
}
else
{
irflag=1;
irtime=0;
}
}
void timer() interrupt 3
{
TH1=(65536-46080)/256;
TL1=(65536-46080)%256;
time++;
if(time>=20)
{
time=0;
miao++;
if(miao>=60)
{
miao=0;
fen++;
if(fen>=60)
{
fen=0;
shi++;
if(shi>=24)
{
shi=0;
zhou++;
if(zhou>7)
{
zhou=1;
}
ri++;
if((ye==4)||(ye==6)||(ye==9)||(ye==11)) {
if(ri>30)
{
ri=1;
ye++;
}
}
else
{
if(ye==2)
{
if(((nian%100!=0)&&(nian%4==0))||(nian%400==0)) {
if(ri>29)
{
ri=1;
ye++;
}
}
else
{
if(ri>28)
{
ri=1;
ye++;
}
}
}
else
{
if(ri>31)
{
ri=1;
ye++;
}
}
}
}
}
if(ye>12)
{
ye=1;
nian++;
}
}
if(fen>59)
fen=0;
if(shi>23)
shi=0;
if((zhou>7)||(zhou==0))
zhou=1;
if((ri>31)||(ri==0))
ri=1;
if((ye>12)||(ye==0)) ye=1;
}
}