目
录
一
引言...............................................................................................................................5
二
硬件设计.......................................................................................................................5
三
软件设计.......................................................................................................................5
四
调试过程及问题分析.................................................................................................6
五
结论.............................................................................................................................7
六
参考文献.....................................................................................................................7
附件.....................................................................................................................................8
一 引言
单片机应用技术飞速发展,纵观我们现在生活的各个领域,从导弹的导航装置,到飞机上各种仪表的控制,从计算机的网络通讯与数据传输,到工业自动化过程的实时控制和数据处理,以及我们生活中广泛使用的各种智能IC卡、电子宠物等,单片机都起到了举足轻重的作用。
所以单片机技术也日趋成熟。单片机是集CPU,RAM,ROM,定时,计数和多种接口于一体的微控制器。它体积小,成本低,功能强。而52系列单片机是各单片机中最为典型和最有代表性的一种。
此次单片机原理及应用实习通过利用52单片机对电子钟的设计,从而达到学习、了解单片机相关指令在各方面的应用,以及初步了解开发软、硬件的知识。
二 硬件设计
本次单片机原理及应用实习我们组用到的硬件为MCS51开发板和一个LCD12864液晶显示器。
在MCS51开发板中,对于我们组做数字电子钟而言应用到ds1302芯片,蜂鸣器,LED点阵显示屏,STC89S52单片机,锁存器等等硬件设备。
通过对这些硬件的使用实现我们组规定的以及我们拓展的要求。
三 软件设计
此次基于单片机的电子钟的实习基本要求为:
基本要求
(1)能通过键盘设定年月日时分秒;
(2) 在LCD12864上显示年月日时分秒及星期; (3)整点蜂鸣器响6次,每秒响一次,最后一响是整点; (4)按学校的作息时间表定时打铃(可用一个LED灯模拟打铃) 扩展要求
自动计算和显示阴历
基于这些功能,我们用到了如下程序
(1) 时钟程序ds1302 (2) 按键控制程序keyscan
(3) 整点报时程序fengming (4) 作息时间表程序schooltime fengming (5) 显示程序LCD12864 (6) 自动计算阴历程序 Chinesecalender (7) 自动计算星期程序conver_week 我们最初的整体思路是将我们的实习课题分成几个模块,每个人负责一个部分,争取第一周弄完个人部分.第二周主要进行不同模块的整合,以及整个程序的调试和改进.此外准备答辩的PPT,由组长答辩。
程序设计流程图如下:
四 调试过程及问题分析
在这一次单片机原理及应用的实习中,我学到了很多。虽然整个过程并不是一帆风顺的,但是通过
我们的共同努力,最终完成了任务。充分发挥了团队精神,我们互帮互助,共同提高。
我觉得在拿到一个课题的时候,我们首先应该思考的是干什么?然后才是怎么干?最后是如何优化。 于是我开始上网搜有关电子钟设计的相关资料,我了解到:我们本次是利用MCS51开发板和LCD12864液晶显示器制作的,可以完成计时、计分、几秒和校时、校分的功能。微处理器是单片机的核心,完成运算和控制的操作串行口数据存储器与复位电路、时钟电路、校时电路由微处理器控制完成各自的任务。最后通过液晶显示器显示时分秒。
在这次实习中我负责的是显示程序LCD12864,刚开始我对于LCD显示程序并不是太了解。在校园网上找到了些相关的初步显示程序。通过LCD12864中的一些程序的调用,才能进行显示,但那是以图片的形式显示的,与我们所期望的显示还是有一定的差别,所以我又做进一步的修改,通过和组员的讨论,我才知道有一个显示汉字的程序是通过字模软件实现的,之后我们的显示这一块就可以依据我们自己的想法进行设计了。
而在整个的程序综合中,也遇到了一些问题。比如在阴历显示在屏幕上的时候,最初只显示阴历两个字,不显示具体的阴历,后来经过检查发现程序调用出现问题,改正后继续进行优化。
就这样,我们反复的修改调试,最终完成了我们的整个课程设计。
五 结论
在本次的课程设计中,我们虽然走了些小弯路,但是通过我们的共同努力,最终完成了任务。我从中我学到了很多,比如团队协作精神,众人拾材火焰高。任何大问题,在一步一步细化之后,解决起来就轻松得多了!我相信只要付出了就会有收获。无论什么事情,只有当你用心去做了之后你才会发现它的真实意义所在。我觉得这一次实习是非常有意义的,不仅提高了专业素养,还培养了我们的合作精神。我要把握每一次学习的机会,认真对待,为以后的就业及更深层次的发展添砖加瓦。
六 参考文献
一、谭浩强 C语言课程设计(第三版) 清华大学出版社 2005.7
二、杨恢先 黄辉先 单片机原理及应用[M] 北京人民邮电出版社 2006.10
三、C编写组编 常用C语言速查手册 龙门书局 1995
附件
*********************************初始化LCD*******************************/ void Lcminit (void) { cbyte=DISPOFF;
WrL(cbyte);
WrR(cbyte);
cbyte=DISPON;
WrL(cbyte);
WrR(cbyte);
cbyte=DISPFIRST;
WrL(cbyte);
WrR(cbyte);
Lcmcls();
Locatexy(0,0);} /***********************************LCD清屏********************************/ void Lcmcls(void) { uchar i,j;
for(i=0;i
delay(6);
for(j=0;j
delay(6);
Wrdata(0x0,i,j);
}
} }
/************************************写左区*********************************/ void WrL(uchar x) {
P0=0xFF;//P0口送FF,准备读
lck = 0;
P1 = 0x2a;//ELCD=1/W=1(读),CSB=1,CSA=0
lck = 1;
while(P0 & LCDBUZY);//最高位为1,表示忙,则循环
lck = 0;
P1 = 0x00;//ELCD=0,R/W=0(读),CSB=0,CSA=0
lck = 1;
P0 = x;
//数据送到P0口
lck = 0;
P1 = 0x22;//ELCD=1,RW = 0(写),CSB=1,CSA=0
lck = 1;
lck = 0;
P1 = 0x00;//ELCD=0,RW = 0(写),CSB=0,CSA=0
lck = 1; } /***********************************写右区***********************************/
7 void WrR(uchar data x) {
P0=0xFF;//P0口送FF,准备读
lck = 0;
P1 = 0x29;//ELCD=1,R/W=1(读),CSB=0,CSA=1
lck = 1;
while(P0 & LCDBUZY);//最高位为1,表示忙,则循环
lck = 0;
P1 = 0x00;//ELCD=0,R/W=0(读),CSB=0,CSA=1
lck = 1;
P0=x;
//数据送到P0口
lck = 0;
P1 = 0x21;//ELCD=1,RW = 0(写),CSB=0,CSA=1
lck = 1; lck = 0; P1 = 0x00;//ELCD=0,RW = 0(写),CSB=0,CSA=0 lck = 1;
} /**********************************显示定位***********************************/ void Locatexy(uchar row,uchar col) { uchar x, y, right;
switch(col&0xc0)
{ case 0:{
P0=0xFF;//P0口送FF,准备读
lck = 0;
P1 = 0x29;//ELCD=1,R/W=1(读),CSB=0,CSA=1
lck = 1;
while(P0 & LCDBUZY);//最高位为1,表示忙,则循环
lck = 0;
P1 = 0x00;
lck = 1;
right = 1;break;}//置右半屏标志
case 0x40:{
P0=0xFF;//P0口送FF,准备读
lck = 0;
P1 = 0x2a;//ELCD=1,R/W=1(读),CSB=1,CSA=0
lck = 1;
while(P0 & LCDBUZY);//最高位为1,表示忙,则循环
lck = 0;
P1 = 0x00;//ELCD=0,R/W=0(读)CSB=0,CSA=0
lck = 1;
right = 0;break;}//置左半屏标志
}
x=col&0x3f|SETX;//把列数据变成行命令
y=row&0x07|SETY;//把行数据变成行命令
/****************************************************************************/
lck = 0;
if(right)
P1 = 0x29;
else
P1 = 0x2a;
lck = 1;
while(P0 & LCDBUZY);//最高位为1,表示忙,则循环
lck = 0;
P1 = 0x00;
lck = 1; /***********************************以上为判断忙标志**************************/
P0 = y;
lck = 0;
if(right)
P1 = 0x21;
else
P1 = 0x22;
lck = 1;
lck = 0;
P1 = 0x00;
lck = 1; /************************************以上为送行命令*****************************/
P0=0xFF;
lck = 0;
if(right)
P1 = 0x29;
else
P1 = 0x2a;
lck = 1;
while(P0 & LCDBUZY);//最高位为1,表示忙,则循环
lck = 0;
P1 = 0x00;
lck = 1; /*************************************以上为判断忙标志***************************/
P0 = x;
lck = 0;
if(right)
P1 = 0x21;
else
P1 = 0x22;
lck = 1;
lck = 0;
P1 = 0x00;
lck = 1; /*************************************以上为送列命令***************************/
if(right)
statu = 1;
else
statu = 0;//置左又半区标志
} /*************************************数据写输出*******************************/ void Wrdata(uchar x,uchar row,uchar col) {
Locatexy(row,col);//定位显示位置
lck = 0;
if(statu)
P1 = 0x05;//ELCD=0R/W=0(写),D/I= 1 ,CSB=0,CSA=1
else
P1 = 0x06;//ELCD=0,R/W=0(写),D/I= 1 ,CSB=1,CSA=0
lck = 1;
P0 = x;
lck = 0;
if(statu)
P1 = 0x25;//ELCD=1,R/W=0(写),D/I= 1 ,CSB=0,CSA=1
else
P1 = 0x26;//ELCD=1,R/W=0(写),D/I= 1 ,CSB=1,CSA=0
lck = 1;
lck = 0;
P1 = 0x00;
lck = 1; }
/**********************************半角数据点阵输出******************************/ void Puthalf(uchar *strch,uchar row,uchar col) {
uchar i,bakerx;
bakerx = row;
for(i=0;i
{ cbyte=strch[i];
Wrdata(cbyte,bakerx,col);
cbyte=strch[i+1];
Wrdata(cbyte,bakerx+1,col);
col++;
i++; } } void Puthz(uchar *str,uchar row,uchar col) {
uchar i,bakerx;
bakerx=row;
for(i=0;i
{
cbyte=str[i];
Wrdata(cbyte,row,col);
//上半字节输出
i++;
row=bakerx+1;
cbyte=str[i];
Wrdata(cbyte,row,col);
//下半字节输出
row=bakerx;
col=col+1;
} } /****************************字符型点阵行--》列转换************************/ void VtoH8x16change(uchar
*hzbuf) {
uchar i,j,k, cash[16];
uchar
newbyte, savebit[8];
for(k=0;k
newbyte = 0;
for(i=0;i
savebit[i]=hzbuf[i] & 0x80;}
for(j=0;j
savebit[j] = savebit[j] >> (7-j);
newbyte = newbyte | savebit[j]; }
cash[k] = newbyte;
newbyte = 0;
for(i=8;i
savebit[i-8]=hzbuf[i] & 0x80; }
for(j=0;j
savebit[j] = savebit[j] >> (7-j);
newbyte = newbyte |savebit[j]; }
cash[k+1] = newbyte;
for(j=0;j
hzbuf[j] = hzbuf[j]
}
k++; }
for(i=0;i
hzbuf[i] = cash[i]; } /*******************************显示英文和符号字符*******************************/ void vWrite8x16Character(uchar *ch,uchar row,uchar col,bit flag) {uchar
ucXArray[16],i;
if(flag){
// 反白显示英文 for(i = 0; i
ucXArray[i] = ~ch[i];}else{
for(i = 0; i
ucXArray[i] = ch[i]; }
VtoH8x16change(ucXArray); Puthalf(ucXArray,row,col);} /****************************显示中英文字符串************************************/
11 void vWrite8x16String(uchar *str,uchar row, uchar col, bit flag) {
/************************v_RTInputByte*************************/ void v_RTInputByte(uchar ucDa) {
uchar i; ACC = ucDa; for(i=8; i>0; i--) { T_IO = ACC0; /*相当于汇编中的 RRC */ T_CLK = 1; T_CLK = 0; ACC = ACC >> 1; } } /********************** uchar uc_RTOutputByte*************************/
uchar uc_RTOutputByte(void) { uchar i; for(i=8; i>0; i--) { ACC = ACC >>1; /*相当于汇编中的 RRC */ ACC7 = T_IO; T_CLK = 1; T_CLK = 0; }
return(ACC); } /************************v_W1302 *************************************/
void v_W1302(uchar ucAddr, uchar ucDa) { lck = 0; P1 = 0x00; lck = 1;
12 unsigned char i, j,thiscol; j = strlen(str); for(i = 0; i
thiscol = (i % 16) * 8 + col;//计算列地址
if(str[i]
vWrite8x16Character(&char_Table[str[i]-0x20][0],row,thiscol,flag);
}} T_CLK = 0;
lck = 0; P1 = 0x10; lck = 1; v_RTInputByte(ucAddr); /* 地址,命令 */ v_RTInputByte(ucDa); /* 写1Byte数据*/ T_CLK = 1; lck = 0; P1 = 0x00; lck = 1; }
/**************************uc_R1302***********************************/
uchar uc_R1302(uchar ucAddr) { uchar ucDa;
lck = 0; P1 = 0x00; lck = 1;
T_CLK = 0;
lck = 0; P1 = 0x10; lck = 1; v_RTInputByte(ucAddr); /* 地址,命令 */ ucDa = uc_RTOutputByte(); /* 读1Byte数据 */ T_CLK = 1; lck = 0; P1 = 0x00; lck = 1; return(ucDa); }
/************************* v_Set1302 *********************************/
void v_Set1302(uchar *pSecDa) { uchar i; uchar ucAddr = 0x80;
v_W1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/ for(i =7;i>0;i--) {
v_W1302(ucAddr,*pSecDa); /* 秒 分 时 日 月 星期 年 */
13
pSecDa++; ucAddr +=2; } v_W1302(0x8e,0x80); /* 控制命令,WP=1,写保护?*/ } /*******************************v_Get1302**************************************/
void v_Get1302(uchar ucCurtime[]) { uchar i; uchar ucAddr = 0x81; for (i=0;i
uchar temp;
copymt = 0xff;
P0=0xff;
v_Get1302(&buffer); //读取DS1302
Conver_week(0,buffer[6],buffer[4],buffer[3]); Chinesecalender(0,buffer[6],buffer[4],buffer[3]) ; disp = buffer[0] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],2,100,0);//秒个位
temp =buffer[0] & 0x7f; temp = temp/16; disp = temp%10 + \'0\'; vWrite8x16Character(&char_Table[disp-0x20][0],2,92,0);//秒十位
copymt = buffer[1];
disp = buffer[1] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],2,68,0);//分个位
temp =buffer[1] & 0x7f;
temp = temp/16;
disp = temp%10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],2,60,0);//分十位
disp = buffer[2] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],2,30,0);//时个位
temp =buffer[2] & 0x7f;
temp = temp/16;
disp = temp%10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],2,22,0);//时十位
disp = buffer[3] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,100,0);//日个位
temp =buffer[3] & 0x7f;
temp = temp/16;
disp = temp%10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,92,0);//日十位
disp = buffer[4] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,68,0);//月个位
temp =buffer[4] & 0x7f;
temp = temp/16;
disp = temp%10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,60,0);//月十位
disp = buffer[6] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,30,0);//年个位
temp =buffer[6] & 0x7f;
temp = temp/16;
disp = temp%10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,22,0);//年十位
disp = buffer[7] % 0x10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,14,0);//年百位
temp =buffer[7] & 0x7f;
temp = temp/16;
disp = temp%10 + \'0\';
vWrite8x16Character(&char_Table[disp-0x20][0],0,6,0);//年千位
}