找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3986|回复: 2
收起左侧

基于单片机的万年历 机课程设计论文下载 已做出实物

[复制链接]
ID:203329 发表于 2017-5-22 08:03 | 显示全部楼层 |阅读模式
这是一个万年历的小制作,包含有完整的论文,大家可以多多提供意见呀!!
里面有仿真图以及源代码提供下载
还有实物图哟!
洛阳理工学院单片机课程设计


课程名称:基于单片机的万年历
别:计算机与信息工程学院
级:B140509
号:B14050918
名:伍华
人:李威 杨宇      
指导老师:

【目录】
1              诸论
1.1              摘要
1.2              单片机发展概况
1.3              单片机原理及应用简介
2              系统方案
2.1              系统功能
2.2              系统总体方案
2.2              芯片简介
2.2.1              80C52芯片
2.2.2              实时时钟芯片DS1302
2.2.3              DS18B20单总线数字温度计
2.2.4              Lcd1602液晶显示器
3              系统软件设计
4              PROTUES软件仿真
4.1              仿真过程
4.2              仿真结果
5              开发板调试结果
6              心得体会
7              待解决问题
8              附录

1        诸论1.1摘要
本设计是一个基于MCS-51单片机实现的万年历。
单片机中央处理系统的方案设计,选用80C52单片机作为中央处理器,如图所示。该单片机除了拥有MCS-51系列单片机的所有优点外,内部还具有8K的在系统可编程FLASH存储器,低功耗的空闲和掉电模式,极大的降低了电路的功耗,还包含了定时器、程序存储器、数据存储器等硬件,其硬件能符合整个控制系统的要求,不需要外接其他存储器芯片和定时器件,方便地构成一个最小系统。整个系统结构紧凑,抗干扰能力强,性价比高。
1.2单片机发展概况
单片机的发展历史可大致分为4个阶段。
  第一阶段(1974年-1976年):单片机初级阶段。因工艺限制,单片机采用双片的形式而且功能比较简单。1974年12月,仙童公司推出了8位的F8单片机,实际上只包括了8位CPU、64B RAM和2个并行口。
  第二阶段(1976年-1978年):低性能单片机阶段。1976年,Intel公司推出的MCS-48单片机(8位单片机)极大地促进了单片机的变革和发展;1977年,GI公司推出了PIC1650,但这个阶段的单片机仍然处于低性能阶段。
  第三阶段(1978年-1983年):高性能单片机阶段。1978年,Zilog公司推出了28单片机;1980年,Intel公司在MCS-48单片机的基础上推出了MCS-51系列,Mortorola公司推出了6801单片机;这些产品使单片机的性能及应用跃上了一个新的台阶。此后,各公司的8位单片机迅速发展起来。这个阶段推出的单片机普遍带有串行I/O口、多级中断系统、16位定时器/计数器,片内ROM、RAM容量加大,且寻址范围可达64 KB,有的片内还带有A/D转换器。由于这类单片机的性能价格比高,所以被广泛应用,是目前应用数量最多的单片机。
  第四阶段(1983年-现在):8位单片机巩固、发展及16位单片机、32位单片机推出阶段。16位单片机的典型产品为Intel公司生产的MCS-96系列单片机。而32位单片机除了具有更高的集成度外,其数据处理速度比16位单片机提高许多,性能比8位、16位单片机更加优越。20世纪90年代是单片机制造业大发展的时期,这个时期的Mortorola、Intel、ATMEL、德州仪器(TI)、三菱、日立、Philips、LG等公司也开发了一大批性能优越的单片机,极大地推动了单片机的应用。近年来,又有不少新型的高集成度单片机产品涌现出来,出现了单片机产品丰富多彩的局面。目前,除了8位单片机得到广泛应用之外,16位单片机、32位单片机也得到广大用户的青睐。

1.3单片机原理及应用简介
单片机是单片微型计算机的简称,指在一块大规模或超大规模集成电路芯片上制成的微型计算机。单片机具有体积小、功耗低、性价比高、应用灵活等优点,可以作为一个部件嵌入到各种装置和产品中。现代生活中,从通信设备、家用电器、办公应用到工业控制、仪器仪表、汽车电子、航空航天,几乎每件电子和机械产品中都有单片机在工作,单片机的用量早已远远超过包括个人计算机在内的其他计算机的总和。以其嵌入到实际产品中发挥的控制作用或所处的地位,单片机又被称为微控制器或嵌入式微控制器。
  单片机的种类繁多、功能各异。Intel公司的MCS-51系列8位单片机,以其完善的结构、丰富的功能、开放的体系,盛行30多年而不衰。众多半导体厂商(如Atmel、Dallas Semi、Infineon、Philips/Signetics等)获得Intel公司的授权后,在保持代码兼容性的前提下,融合各自先进技术,针对不同市场需求,在时钟、存储器、定时器/计数器、I/O接口、串行总线控制等方面进行了改进、裁剪,使得在任何实际产品的设计中都有最恰当的芯片可供选择,也给这一单片机家族提供了旺盛的生命力。本书选择MCS-51系列单片机作为主讲机型,系统全面地介绍MCS-51单片机内部的功能结构、软硬件资源的原理与应用,以及使用外部电路进行功能扩展的方法。 单片机是单片微型计算机的简称,指在一块大规模或超大规模集成电路芯片上制成的微型计算机。单片机具有体积小、功耗低、性价比高、应用灵活等优点,可以作为一个部件嵌入到各种装置和产品中。现代生活中,从通信设备、家用电器、办公应用到工业控制、仪器仪表、汽车电子、航空航天,几乎每件电子和机械产品中都有单片机在工作,单片机的用量早已远远超过包括个人计算机在内的其他计算机的总和。以其嵌入到实际产品中发挥的控制作用或所处的地位,单片机又被称为微控制器或嵌入式微控制器。
  单片机的种类繁多、功能各异。Intel公司的MCS-51系列8位单片机,以其完善的结构、丰富的功能、开放的体系,盛行30多年而不衰。众多半导体厂商(如Atmel、Dallas Semi、Infineon、Philips/Signetics等)获得Intel公司的授权后,在保持代码兼容性的前提下,融合各自先进技术,针对不同市场需求,在时钟、存储器、定时器/计数器、I/O接口、串行总线控制等方面进行了改进、裁剪,使得在任何实际产品的设计中都有最恰当的芯片可供选择,也给这一单片机家族提供了旺盛的生命力。本书选择MCS-51系列单片机作为主讲机型,系统全面地介绍MCS-51单片机内部的功能结构、软硬件资源的原理与应用,以及使用外部电路进行功能扩展的方法。

2        系统方案2.1系统功能
1:LCD显示年、月、日、时、分、秒、星期、温度信息;
2:用按键可以调整日期和时间、星期;
3:可以设置闹铃时间,到闹铃响起;
2.2系统总体方案
本设计分为编程,仿真,调试开发板等步骤。以单片机为主体,利用单片机的诸多功能来控制外部设备的正常运行。
显示器为LM016L,通过PO口将数据传输到显示器上。时钟信号的发生靠的是DS1302,将时钟信号传到单片机用于显示时间以及定时的功能。利用DS18B20检测外部环境温度,实时检测,将温度数据及时的传输到单片机。
2芯片简介2.2.180C52芯片
80C52芯片结合了HMOS的高速和高密度技术及CHMOS的低功耗特征,它基于标准的MCS-51单片机体系结构和指令系统,属于80C51增强型单片机版本,集成了时钟输出和向上或向下计数器等更多的功能,适合于类似马达控制等应用场合。
80C52内置8位中央处理单元、256字节内部数据存储器RAM、8k片内程序存储器(ROM)32个双向输入/输出(I/O)口、3个16位定时/计数器和5个两级中断结构,一个全双工串行通信口,片内时钟振荡电路。
此外,80C52还可工作于低功耗模式,可通过两种软件选择空闲和掉电模式。在空闲模式下冻结CPU而RAM定时器、串行口和中断系统维持其功能。掉电模式下,保存RAM数据,时钟振荡停止,同时停止芯片内其它功能。80C52有PDIP(40pin)和PLCC(44pin)两种封装形式。
8051片内有 ROM,无须外接外存储器和373,更能体现“单片”的简练。但是你编的程序你无法烧写到其ROM中,只有将程序交芯片厂代你烧写,并是一次性的,今后你和芯片厂都不能改写其内容。
1.001.jpg


2.2.2实时时钟芯片DS1302
美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟电路DS1302的结构、工作原理及其在实时显示时间中的应用。它可以对年、月、日、周日、时、分、秒进行计时,且具有闰年补偿等多种功能。
DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768kHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc≥2.5V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。
I/O为串行数据输入输出端(双向),后面有详细说明。
SCLK为时钟输入端。
1.002.jpg
2.2.3DS18B20单总线数字温度计
DS18B20是常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。[
DS18B20的读写时序和测温原理与DS1820相同,只是得到的温度值的位数因分辨率不同而不同,且温度转换时的延时时间由2s减为750ms。 DS18B20测温原理如图3所示。图中低温度系数晶振的振荡频率受温度影响很小,用于产生固定频率的脉冲信号送给计数器1。高温度系数晶振随温度变化其振荡率明显改变,所产生的信号作为计数器2的脉冲输入。计数器1和温度寄存器被预置在-55℃所对应的一个基数值。计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当计数器1的预置值减到0时,温度寄存器的值将加1,计数器1的预置将重新被装入,计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温度。斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正计数器1的预置值。[
1.003.jpg

2.2.4Lcd1602液晶显示器
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
1602采用标准的16脚接口,其中:
第1脚:GND为电源地
第2脚:VCC接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会 产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,
低电平(0)时进行写操作。
第6脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳
变时执行指令。
第7~14脚:D0~D7为8位双向数据端。第15~16脚:空脚或背灯电
源。15脚背光正极,16脚背光负极。+
1.004.jpg


3        系统软件设计

1.005.jpg

在多功能模块化程序设计中,主程序的作用时设置系统运行的一些初始状态及系统运行的环境,并将各种功能子程序按要求连接起来组成一个功能强大的系统。本系统主程序的流程图如图。在本程序中,LCD1602初始化:8位数据接口,两行显示,5*7点阵字符,显示开,关光标,光标移动为增量式。
LCD1602的初始化已被写成一个函数LCD——INITIAL(),直接调用就可完成LCD1602的初始化。


4        PROTUES软件仿真4.1    仿真过程
  •          仿真:打开keil uVision2,建立工程,输入所编写的源程序并对程序进行编译,在软件的帮助下检查其中的错误并进行反复修改,知道编译正确侯运行,生成相应的HEX文件,并进行保存,保存时给其命名,以便将来载入程序时容易找到。
  •          打开PROTUES软件,并出画单片机电子万年历具体运行电路图。
  •          检查所画电路运行图,确保没有错误以后,在PROTUES下对原理图进行加载keil uVision下的源程序。


1.006.jpg
4.2    仿真结果
1.007.jpg
1.008.jpg
5        开发板调试结果
1.009.jpg

1.010.jpg
6        程序流程图
1.011.jpg
7        心得体会
课程设计是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节,回顾此次单片机课程设计,我感觉受益良多,其中编程,仿真,调试开发板等步骤。这次课程设计是我懂得理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学知识和实践相结合起来,从理论中得出结论,才能真正让所学的知识服务于我们的生活,服务于我们的社会,从而提高我们的实际动手能力和独立思考的能力,同时加强了与同学的合作和与老师的沟通,收获很多大!这次课程设计也让我发现了自己的不足之处,对以前学过的理论知识理解得不够深刻,掌握得不够牢固,对单片机汇编语言掌握得不好,一定要把以前的知识温故而知新。


8        待解决问题
1:仿真部件所属的库
2:程序中一则警告无法消除
9        附录
  
单片机源程序如下:

  1. #include              //52单片机的头文件,规定了52单片机的寄存器和IO口
  2. #include              //_nop_空指令及左右循环移位子函数库
  3. #define uchar unsigned char              //宏定义
  4. #define uint unsigned int
  5. sbit lcden=P2^6;                 //定义下面通过lcden来操作P2^6口,1602液晶使能控制端
  6. sbit lcdwr=P2^5;                //定义下面通过lcdwr来操作P2^5口,1602读写选择端
  7. sbit lcdrs=P2^4;                //定义下面选数据寄存器还是选指令寄存器控制端
  8. sbit sda=P3^6;                 //定义DS1302数据总线,DS1302设置时间
  9. sbit rst=P3^4;                            //定义DS1302复位
  10. sbit sck=P3^5;                            //定义时钟总线
  11. sbit s1=P3^0;                            //定义设置按钮
  12. sbit s2=P3^1;                            //定义调试按钮
  13. sbit s3=P3^2;                            //定义确定按钮
  14. sbit s4=P3^3;                                                                                                                                
  15. sbit DQ=P3^7;                            //定义DS18B20通信端口
  16. sbit ACC0=ACC^0;
  17. sbit ACC7=ACC^7;
  18. sbit BELL=P1^5;
  19. char fen,shi,miao,ri,yue,nian,zhou,s1num,s2num,s4num,flag1,flag2,lshi,lfen;
  20. uchar code table[]={" 2016-  -       "};                                                        //要写入1602液晶的数据
  21. uchar code alarm[]={" CLOCK SETTINGS"};                                                                      //要写入1602液晶的数据
  22. uchar code alarm1[]={"            :   "};                                                        //要写入1602液晶的数据
  23. uchar code table1[]={"   :  :      .  "};                                                        //字库中的字可直接以外加""号的形式直接写入
  24. uchar code table2[]={"   Wan Nian Li !"};                                                        //欢迎界面
  25. uchar code table3[]={"Wo Men Jie Zuo!!"};                                                        //欢迎界面


  26. //*****************星期编码表**********************************
  27. uchar code Weeks[][3]={{"SUN"},{"MON"},{"TUE"},{"WED"},{"THU"},{"FRI"},{"SAT"},{"SUN"}};
  28. uchar i,j;               
  29. //*********************短暂延时********************************
  30. void delay0(uint z)
  31. {                     
  32.               while(z--);
  33. }
  34. //*********************毫秒延时********************************
  35. void delay(uint z)
  36. {
  37.               uint x,y;
  38.               for(x=z;x>0;x--)
  39.                             for(y=110;y>0;y--);
  40. }
  41. //DS18B20初始化函数
  42. void Init_DS18B20(void)
  43. {
  44.               unsigned char x=0;
  45.               DQ=1;                                                        //DQ复位,DQ一般是表示单总线的数据接口端                               //
  46.               delay0(8);                                           //稍做延时
  47.               DQ=0;                                                        //单片机将DQ拉低
  48.               delay0(80);                                          //精确延时
  49.               DQ=1;                                                        //拉高总线
  50.               delay0(14);
  51.               x=DQ;                                                        //稍做延时后?如果x=0则初始化成功?x=1则初始化失败
  52.               delay0(20);
  53. }

  54. //DS18B20读一个字节
  55. uchar ReadOneChar(void)
  56. {
  57.               unsigned char i=0;
  58.               unsigned char dat=0;
  59.               for(i=8;i>0;i--)
  60.               {
  61.                             DQ=0;                                            //给脉冲信号
  62.                             dat>>=1;                            //让从总线上读到的位数据,依次从高位移动到低位                                                                                                                                                          //
  63.                             DQ=1;                                          //给脉冲信号
  64.                             if(DQ)
  65.                                           dat|=0x80;
  66.                             delay0(4);
  67.               }
  68.               return(dat);
  69. }

  70. //DS18B20写一个字节?
  71. void WriteOneChar(unsigned char dat)
  72. {
  73.               unsigned char i=0;
  74.               for(i=8;i>0;i--)
  75.               {
  76.                             DQ=0;
  77.                             DQ=dat&0x01;
  78.                             delay0(5);
  79.                             DQ=1;
  80.                             dat>>=1;
  81.               }
  82. }

  83. //DS18B20读取温度
  84. uint ReadTemperature(void)
  85. {
  86.               unsigned char a=0;
  87.               unsigned char b=0;
  88.               unsigned int t=0;
  89.               float tt=0;
  90.               Init_DS18B20();
  91.               WriteOneChar(0xCC);                                          //跳过读序号列号的操作
  92.               WriteOneChar(0x44);                             //启动温度转换
  93.               Init_DS18B20();
  94.               WriteOneChar(0xCC);                                          //跳过读序号列号的操作
  95.               WriteOneChar(0xBE);                                          //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
  96.               a=ReadOneChar();
  97.               b=ReadOneChar();
  98.               t=b;
  99.               t<<=8;
  100.               t=t|a;
  101.               tt=t*0.0625;                                                        //将温度的高位与低位合并
  102.               t=tt*10+0.5;                                                        //对结果进行4舍5入
  103.               return(t);
  104. }
  105. /*********************蜂鸣器函数************************************************/
  106. void didi()
  107. {
  108.               uchar i;
  109.               for(i=0;i<60;i++)
  110.               {
  111.                             BELL=0;
  112.                             delay(1);
  113.                             BELL=1;
  114.                             delay(1);
  115.               }
  116. }

  117. /*******************向1602液晶中写一个指令**************************************/
  118. void write_com(uchar com)
  119. {
  120.               lcdwr=0;                            //lcdwr为读写控制端,
  121.               //lcdwr=0,
  122.               lcdrs=0;                            //液晶rs接口为0时,写指令,rs为1时写数据
  123.               P0=com;                                          //将要写的指令赋给P0口,
  124.               delay(5);                            //由1602读写操作时序图,先将指令赋给P0口,延时后将使能
  125.               lcden=1;                            //端lcden置高,再延时一段时间,然后将lcden置低,这样指令
  126.               delay(5);                            //就写入到LCD了
  127.               lcden=0;
  128. }
  129. /****************************






  130. ***************************************/
  131. void write_data(uchar date)
  132. {
  133.               lcdrs=1;                             //与写指令类似,这里lcdrs设为1
  134.               P0=date;
  135.               delay(5);
  136.               lcden=1;
  137.               delay(5);
  138.               lcden=0;
  139. }

  140. /*****************************初使化1602液晶************************************/
  141. void init_1602()
  142. {
  143.               lcdwr=0;
  144.               lcden=0;
  145.               write_com(0x38);                            //设置LCD为16*2显示、5*7点阵、8位数据接口模式
  146.               write_com(0x0c);                            //开显示、不显示光标
  147.               write_com(0x06);                            //写一个字符后,地址指针加1
  148.               write_com(0x01);                            //显示清0
  149.               P0=0xff;
  150. }


  151. /*******************************************************************************/
  152. void gudingtime_1602()
  153. {
  154.               uchar num;
  155.               write_com(0x80);                                          //将指针指向初始位置
  156.               for(num=0;num<16;num++)                            //循环函数,用于将"2012-  -     "写入液晶
  157.                             write_data(table[num]);
  158.               write_com(0x80+0x40);                            //将指针指向1602液晶的第二行?
  159.               for(num=0;num<16;num++)                            //功能与上同,用于将"   :  :         "写入
  160.                             write_data(table1[num]);
  161. }
  162. void gudingtime_1602_1()
  163. {
  164.               uchar num1;
  165.               write_com(0x80);                                          //将指针指向初始位置
  166.               for(num1=0;num1<16;num1++)              //循环函数,用于将"?2012-  -      "写入液晶
  167.                             write_data(alarm[num1]);
  168.               write_com(0x80+0x40);                            //将指针指向1602液晶的第二行
  169.               for(num1=0;num1<16;num1++)//功能与上同,用于将"   :  :      .  "写入
  170.                             write_data(alarm1[num1]);
  171. }


  172. /**************************显示初始化界面函数*************************************/
  173. void displaystar(void)
  174. {
  175.               uchar i;
  176.               write_com(0x80);
  177.               for(i=0;i<16;i++)
  178.               write_data(table2[i]);
  179.               write_com(0x80+0x40);
  180.               for(i=0;i<16;i++)
  181.               write_data(table3[i]);
  182. }

  183. /***************************显示时间、日期子函数*********************************/
  184. void write_sfm(uchar add,uchar time)                            //用于在1602上显示年、月、日、时、分、秒。Add为显示位置,time为要显示的内容
  185. {
  186.               uchar shiwei,gewei;
  187.               shiwei=time/16;                                                                                                  //将从DS1302中读取的BCD码数据转化成十六
  188.               gewei=time%16;                                                                                                  //十六进制个位
  189.               write_com(add+0x80);                                                                      //定义显示在液晶的什么位置
  190.               write_data(0x30+shiwei);                                                        //由1602液晶字库可知,0~9的数据码分别对应0x30~0x39
  191.               write_data(0x30+gewei);                                                                      //初使化中设定了写一个字符后,地址指针加1
  192. }                                                                                                                                                          //?不用重新光标写位?
  193. void write_temp(uchar add,uint temp)                            //用于在1602上显示年、月、日、时、分、秒。Add为显示位置,time为要显示的内容
  194. {
  195.               uchar shi,ge,xshu;
  196.               shi=temp/100;                                                                                                  //将从DS1302中读取的BCD码数据转化成10进制个位和10??
  197.               ge=temp%100/10;                                                                                                  //进制十位?
  198.               xshu=temp%10;
  199.               write_com(add+0x80);                                                                      //定义显示在液晶的什么位置??
  200.               write_data(0x30+shi);                                                                      //由1602液晶字库可知,0~9的数据码分别对应0x30~0x39
  201.               write_data(0x30+ge);                                                                       //初使化中设定了写一个字符后,地址指针加1,因此这里
  202.               write_com(0x80+0x40+14);
  203.               write_data(0x30+xshu);                                                                      //?不用重新光标写位?
  204. }

  205. /**************************显示周子函数*****************************************/
  206. void write_zhou(uchar time1)                            //用于在1602上显示周信息,与显示
  207. {                                                                                                                //时间日期子函数类似?
  208.               uchar gewei;
  209.               gewei=time1%16;                                                        //一周七天,因此只需个位?
  210.               write_com(0x80+14);
  211.               write_data(0x30+gewei);
  212. }
  213. /***************************写数据字节子函数************************************/
  214. void Input_1byte(uchar TD)                                          //写一字节数据
  215. {
  216.               uchar i;
  217.               ACC=TD;
  218.               for(i=8;i>0;i--)
  219.               {
  220.                             sda=ACC0;
  221.                             sck=1;
  222.                             sck=0;
  223.                             ACC=ACC>>1;
  224.               }
  225. }

  226. /*************************
  227. 读数据字节子函数**************************************/
  228. uchar Output_1byte(void)                            //读一字节数据
  229. {
  230.               uchar i;
  231.               for(i=8;i>0;i--)
  232.               {
  233.                             ACC=ACC>>1;
  234.                             ACC7=sda;
  235.                             sck=1;
  236.                             sck=0;
  237.               }
  238.               return(ACC);
  239. }
  240. /***************************写DS1302数据函数***********************************/
  241. void write_1302(uchar DS_ADD,uchar DS_DAT)                                          //写操作
  242. {
  243.               rst=0;
  244.               sck=0;
  245.               rst=1;
  246.               Input_1byte(DS_ADD);
  247.               Input_1byte(DS_DAT);
  248.               sck=1;
  249.               rst=0;
  250. }
  251. /***************************读DS1302数据函数***********************************/
  252. uchar read_1302(uchar DS_ADD)                                          //读操作
  253. {
  254.               uchar DS_INF;
  255.               rst=0;
  256.               sck=0;
  257.               rst=1;
  258.               Input_1byte(DS_ADD);
  259.               DS_INF=Output_1byte();
  260.               sck=1;
  261.               rst=0;
  262.               return(DS_INF);
  263. }

  264. /*************************初始化DS1302子函数***********************************/
  265. void inital_1302()
  266. {
  267.               write_1302(0x8e,0x00);                                          //禁止写保护
  268.               write_1302(0x90,0xaa);                                          //定义充电
  269.               write_1302(0x80,0x53);                                          //秒
  270.               write_1302(0x84,0x09);                                          //时
  271.               write_1302(0x82,0x56);                                          //分
  272.               write_1302(0x8c,0x13);                                          //年
  273.               write_1302(0x88,0x04);                                          //月
  274.               write_1302(0x86,0x14);                                          //日
  275.               write_1302(0x8a,0x07);                                          //星期?
  276.               write_1302(0xc0,0x08);                                          //闹钟小时初始化
  277.               write_1302(0xfc,0x00);                                          //闹钟分钟初始化
  278.               write_1302(0x8e,0x80);                                          //开保护?
  279. }

  280. /********************************************************************************扫描函数********************************************************************************/
  281. void keyscan()
  282. {
  283.               if(s1==0&&s4num==0)                                          //按键1按下且s4在此之前未曾按过?
  284.               {
  285.                             delay(5);
  286.                             if(s1==0&&s4num==0)
  287.                             {
  288.                                           flag1=1;
  289.                                           s1num++;
  290.                                           while(!s1);
  291.                                           didi();
  292.                                           if(s1num==1)
  293.                                           {
  294.                                                         write_com(0x80+0x40+8);                            //光标移动到**位置
  295.                                                         write_com(0x0f);                                          //显示光标?
  296.                                           }
  297.                                           if(s1num==2)
  298.                                           {
  299.                                                         write_1302(0x8e,0x00);                            //禁止写保护
  300.                                                         write_1302(0x80,miao);                            //写入秒信息
  301.                                                         write_1302(0x8e,0x80);                            //开写保护
  302.                                                         write_com(0x80+0x40+5);
  303.                                           }
  304.                                           if(s1num==3)
  305.                                           {
  306.                                                         write_1302(0x8e,0x00);
  307.                                                         write_1302(0x82,fen);
  308.                                                         write_1302(0x8e,0x80);
  309.                                                         write_com(0x80+0x40+2);
  310.                                           }
  311.                                           if(s1num==4)
  312.                                           {
  313.                                                         write_1302(0x8e,0x00);
  314.                                                         write_1302(0x88,yue);
  315.                                                         write_1302(0x8e,0x80);
  316.                                                         write_com(0x80+14);
  317.                                           }
  318.                                           if(s1num==5)
  319.                                           {
  320.                                                         write_1302(0x8e,0x00);
  321.                                                         write_1302(0x84,shi);
  322.                                                         write_1302(0x8e,0x80);
  323.                                                         write_com(0x80+10);
  324.                                           }
  325.                                           if(s1num==6)
  326.                                           {
  327.                                                         write_1302(0x8e,0x00);
  328.                                                         write_1302(0x86,ri);
  329.                                                         write_1302(0x8e,0x80);
  330.                                                         write_com(0x80+7);
  331.                                           }
  332.                                           if(s1num==7)
  333.                                           {
  334.                                                         write_1302(0x8e,0x00);
  335.                                                         write_1302(0x8c,nian);
  336.                                                         write_1302(0x8e,0x80);
  337.                                                         write_com(0x80+4);
  338.                                           }
  339.                                           if(s1num==8)
  340.                                           {
  341.                                           flag1=0;
  342.                                           s1num=0;
  343.                                           write_1302(0x8e,0x00);
  344.                                           write_1302(0x8a,zhou);
  345.                                           write_1302(0x8e,0x80);
  346.                                           write_com(0x0c);                            //不显示光标?
  347.                                           }
  348. }

  349. }



  350. /*******************************************************************************/

  351.   if(s1num!=0&&s4num==0)                            //按键1按下*次且s4再此之前未曾按过
  352. {
  353.   if(s2==0)
  354.     {
  355.                 delay(5);
  356.                 if(s2==0)
  357.                 {
  358.                   while(!s2);
  359.                             didi();
  360.                             if(s1num==1)
  361.                             {
  362.                      int x1,x2;
  363.                                x1=miao%16;
  364.                                x2=miao/16;
  365.                                x1++;
  366.            if(x1==10)
  367.                                {
  368.                                  x1=0;
  369.                                           x2++;
  370.                                           if(x2>=6)
  371.                  x2=0;
  372.            }
  373.             miao=x1+x2*16;
  374.             write_sfm(7+0x40,miao);//将修改的数送到1602显示
  375.                                           write_com(0x80+0x40+8);//挪回光标
  376.         }
  377.          if(s1num==2)
  378.                             {
  379.                                int x3,x4;
  380.                                x3=fen%16;
  381.                                x4=fen/16;
  382.                                x3++;
  383.                                if(x3==10)
  384.                                {
  385.                                   x3=0;
  386.                                             x4++;
  387.                                             if(x4>=6)
  388.                                             x4=0;
  389.                                }
  390.            fen=x3+x4*16;
  391.            write_sfm(4+0x40,fen);
  392.            write_com(0x80+0x40+5);
  393.          }
  394.          if(s1num==3)
  395.                             {
  396.                                int x5,x6;
  397.                                x5=shi%16;
  398.                                x6=shi/16;
  399.            x5++;
  400.                                 if(x6>=2&&x5>=4)
  401.                                           {
  402.                                             x5=0;
  403.                                             x6=0;
  404.             }
  405.             if(x5==10)
  406.                                           {
  407.                                             x5=0;
  408.                                             x6++;
  409.                                           }
  410.             shi=x5+x6*16;
  411.             write_sfm(1+0x40,shi);
  412.                                           write_com(0x80+0x40+2);
  413.          }
  414.          if(s1num==4)
  415.                             {
  416.                                 zhou++;
  417.                                           if(zhou==8)
  418.                                           zhou=1;
  419.             write_zhou(zhou);
  420.             write_com(0x80+14);
  421.          }
  422.                             if(s1num==5)
  423.                             {
  424.                                 int x5,x6;
  425.                                           x5=ri%16;
  426.             x6=ri/16;
  427.                                           x5++;
  428.             if(x6>=3&&x5>=1)
  429.                                           {
  430.                                              x5=1;
  431.                                              x6=0;
  432.             }
  433.             if(x5==10)
  434.                                           {
  435.                                              x5=0;
  436.                                              x6++;
  437.                                           }
  438.             ri=x5+x6*16;
  439.                                           write_sfm(9,ri);
  440.                                           write_com(0x80+10);
  441.          }
  442.          if(s1num==6)
  443.                             {
  444.                                 int x5,x6;
  445.                                           x5=yue%16;
  446.                                           x6=yue/16;
  447.                                           x5++;
  448.             if(x6>=1&&x5>=3)
  449.                                           {
  450.                                              x5=1;
  451.                                              x6=0;
  452.             }
  453.             if(x5==10)
  454.                                           {
  455.                                              x5=0;
  456.                x6++;
  457.             }
  458.             yue=x5+x6*16;
  459.                                           write_sfm(6,yue);
  460.             write_com(0x80+7);
  461.          }
  462.                             if(s1num==7)
  463.                             {
  464.                                 int x5,x6;
  465.                                           x5=nian%16;
  466.                                           x6=nian/16;
  467.                                           x5++;
  468.             if(x6>=2&&x5>=1)
  469.                                           {
  470.                                              x5=1;
  471.                                              x6=0;
  472.             }
  473.             if(x5==10)
  474.                                           {
  475.                                              x5=0;
  476.                                              x6++;
  477.                                           }
  478.             nian=x5+x6*16;
  479.                                           write_sfm(3,nian);
  480.             write_com(0x80+4);
  481.          }
  482.     }
  483.   }
  484. }







  485. if(s1num!=0||s4num!=0) // 在调整模式下
  486.     {   
  487.               if(s3==0)  //如果确定键按下  
  488.                 {   
  489.                  delay(5);   
  490.                   if(s3==0)  //延时并重新检测S3是否按下,用于差小误差
  491.                                {
  492.                                  if(s1num!=0)     
  493.                                  {            
  494.                                             while(!s3);
  495.                                             didi();//在松手时将调整后的时间、日期及周信息写 入DS1302,退出调整模式并隐藏光标,按键次数清0
  496.                                             write_1302(0x8e,0x00);      
  497.                                             write_1302(0x80,miao);      
  498.                                             write_1302(0x84,shi);   
  499.                                             write_1302(0x82,fen);  
  500.                                             write_1302(0x8a,zhou);  
  501.                                             write_1302(0x8c,nian);   
  502.                                             write_1302(0x88,yue);   
  503.                                             write_1302(0x86,ri);   
  504.                                             write_1302(0x8e,0x80);
  505.                                             flag1=0;   
  506.                                             write_com(0x0c);
  507.                                             s1num=0;     
  508.                                             gudingtime_1602();
  509.                                           }
  510.                                                                       if(s4num!=0)
  511.                                                                       {
  512.                                                                       while(!s3);didi();//再松手是将调整后的时间、日期及周信息写入DS1302,退出调整模式并隐藏光标,按键次数清0
  513.                                                  write_1302(0x8e,0x00);            
  514.                                                            write_1302(0xc0,lshi);                 
  515.                                                            write_1302(0xfc,lfen);   
  516.                                                            write_1302(0x8e,0x80);   
  517.                                                                       flag2=0;     
  518.                                                                       write_com(0x0c);   
  519.                                                                       s4num=0;         
  520.                                                                       gudingtime_1602();               
  521.                    }                                                                                                     
  522.                                 }      
  523.                                                         }         
  524.                                                                       }   
  525. if(s4==0&&s1num==0)          //按键4按下*次且s1再次之前未曾按 过        
  526. {                     
  527. delay(5);      
  528.               if(s4==0&&s1num==0)   
  529.   {                  
  530. s4num++;         
  531.               flag2=1;               
  532.                 while(!s4);didi();      
  533.               if(s4num==1)  
  534.   {      
  535.               gudingtime_1602_1();                  
  536.               lshi=read_1302(0xc1);//从ds1302里面的RAM读取闹钟时, 此处不放在while(1)大循环里面是因为ds1302里面的RAM里的数据是不变的只需读取一次      
  537.               lfen=read_1302(0xfd);//从ds1302里面的RAM读取闹钟分      
  538.                 write_sfm(0x40+10,lshi);//将闹钟时送到1602显示         
  539.                 write_com(0x80+0x40+12);//将闹钟:送到1602显示
  540.               write_data(table1[3]);      
  541.               write_sfm(0x40+13,lfen);//将闹钟分送到1602?   
  542.                 write_com(0x80+0x40+14);     
  543. write_com(0x0f);      
  544. }                    
  545.                 if(s4num==2)   
  546. {         
  547.                 write_1302(0x8e,0x00);  //禁止写保护   
  548.                 write_1302(0xfc,lfen); //闹钟初始化   
  549.                             write_1302(0x8e,0x80); //开写保护      
  550.                 lshi=read_1302(0xc1);  //从ds1302里面的RAM读取闹钟 时,此处不放在while(1)大循环里面是因为ds1302里面的RAM里的数据是不变的只需读取一次     
  551.                             lfen=read_1302(0xfd); //从ds1302里面的RAM读取闹钟分     
  552.               write_sfm(0x40+10,lshi);//将闹钟时送到1602显示      
  553.                 write_sfm(0x40+13,lfen);//将闹钟分送到1602显示      
  554.                 write_com(0x80+0x40+11);      
  555.                 write_com(0x0f);  
  556. }   
  557.               if(s4num==3)  
  558.   {         
  559. s4num=0;     
  560. flag2=0;      
  561. write_1302(0x8e,0x00);//禁止写保护   
  562. write_1302(0xc0,lshi);//闹钟初始化   
  563.    write_1302(0x8e,0x80);//开写保护     
  564.    write_com(0x0c);   //不显示光标      
  565.    write_com(0x01);   //显示清0   
  566.    gudingtime_1602();
  567.   }
  568.     }   
  569. ……………………

  570. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
单片机课程设计伍锡华 - r9wm4.doc (1.43 MB, 下载次数: 45)

评分

参与人数 1黑币 +5 收起 理由
syl829416534 + 5

查看全部评分

回复

使用道具 举报

ID:1 发表于 2017-5-22 17:51 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:464863 发表于 2019-1-8 20:31 | 显示全部楼层
写得非常好啊
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表