目录一引言 (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<8;i++){delay(6);for(j=0;j<LIMIT;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=0lck = 1;while(P0 & LCDBUZY);//最高位为1,表示忙,则循环lck = 0;P1 = 0x00;//ELCD=0,R/W=0(读),CSB=0,CSA=0lck = 1;P0 = x; //数据送到P0口lck = 0;P1 = 0x22;//ELCD=1,RW = 0(写),CSB=1,CSA=0lck = 1;lck = 0;P1 = 0x00;//ELCD=0,RW = 0(写),CSB=0,CSA=0lck = 1;}void WrR(uchar data x){P0=0xFF;//P0口送FF,准备读lck = 0;P1 = 0x29;//ELCD=1,R/W=1(读),CSB=0,CSA=1lck = 1;while(P0 & LCDBUZY);//最高位为1,表示忙,则循环lck = 0;P1 = 0x00;//ELCD=0,R/W=0(读),CSB=0,CSA=1lck = 1;P0=x; //数据送到P0口lck = 0;P1 = 0x21;//ELCD=1,RW = 0(写),CSB=0,CSA=1lck = 1;lck = 0;P1 = 0x00;//ELCD=0,RW = 0(写),CSB=0,CSA=0lck = 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=1lck = 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=0lck = 1;while(P0 & LCDBUZY);//最高位为1,表示忙,则循环lck = 0;P1 = 0x00;//ELCD=0,R/W=0(读) CSB=0,CSA=0lck = 1;right = 0;break;}//置左半屏标志}x=col&0x3f|SETX;//把列数据变成行命令y=row&0x07|SETY;//把行数据变成行命令if(right)P1 = 0x29;elseP1 = 0x2a;lck = 1;while(P0 & LCDBUZY);//最高位为1,表示忙,则循环lck = 0;P1 = 0x00;lck = 1;/***********************************以上为判断忙标志**************************/ P0 = y;lck = 0;if(right)P1 = 0x21;elseP1 = 0x22;lck = 1;lck = 0;P1 = 0x00;lck = 1;/************************************以上为送行命令*****************************/ P0=0xFF;lck = 0;if(right)P1 = 0x29;elseP1 = 0x2a;lck = 1;while(P0 & LCDBUZY);//最高位为1,表示忙,则循环lck = 0;P1 = 0x00;lck = 1;/*************************************以上为判断忙标志***************************/ P0 = x;lck = 0;if(right)P1 = 0x21;elseP1 = 0x22;lck = 1;lck = 0;P1 = 0x00;lck = 1;/*************************************以上为送列命令***************************/elsestatu = 0;//置左又半区标志}/*************************************数据写输出*******************************/ void Wrdata(uchar x,uchar row,uchar col){Locatexy(row,col);//定位显示位置lck = 0;if(statu)P1 = 0x05;//ELCD=0 R/W=0(写),D/I= 1 ,CSB=0,CSA=1elseP1 = 0x06;//ELCD=0,R/W=0(写),D/I= 1 ,CSB=1,CSA=0lck = 1;P0 = x;lck = 0;if(statu)P1 = 0x25;//ELCD=1,R/W=0(写),D/I= 1 ,CSB=0,CSA=1elseP1 = 0x26;//ELCD=1,R/W=0(写),D/I= 1 ,CSB=1,CSA=0lck = 1;lck = 0;P1 = 0x00;lck = 1;}/**********************************半角数据点阵输出******************************/ void Puthalf(uchar *strch,uchar row,uchar col){uchar i,bakerx;bakerx = row;for(i=0;i<16;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<32;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<16;k++){newbyte = 0;for(i=0;i<8;i++){savebit[i]=hzbuf[i] & 0x80;}for(j=0;j<8;j++){savebit[j] = savebit[j] >> (7-j);newbyte = newbyte | savebit[j]; }cash[k] = newbyte;newbyte = 0;for(i=8;i<16;i++){savebit[i-8]=hzbuf[i] & 0x80; }for(j=0;j<8;j++){savebit[j] = savebit[j] >> (7-j);newbyte = newbyte |savebit[j]; }cash[k+1] = newbyte;for(j=0;j<16;j++){hzbuf[j] = hzbuf[j] <<1; }k++; }for(i=0;i<16;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 < 16; i++)ucXArray[i] = ~ch[i];}else{for(i = 0; i < 16; i++)ucXArray[i] = ch[i]; }VtoH8x16change(ucXArray);Puthalf(ucXArray,row,col);}void vWrite8x16String(uchar *str,uchar row, uchar col, bit flag){unsigned char i, j,thiscol;j = strlen(str);for(i = 0; i < j; i++){ thiscol = (i % 16) * 8 + col;//计算列地址if(str[i] < 0xa1)//当前显示内容为英文字符vWrite8x16Character(&char_Table[str[i]-0x20][0],row,thiscol,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;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_R TOutputByte(); /* 读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); /* 秒分时日月星期年*/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<7;i++){ucCurtime[i] = uc_R1302(ucAddr);/*格式为: 秒分时日月星期年*/ucAddr += 2;delay(100);}}/**********************************屏幕显示*********************************/ void pingmu(){uchar disp,copymt;uchar temp;copymt = 0xff;P0=0xff;v_Get1302(&buffer); //读取DS1302Conver_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);//年千位}。