单片机实验报告电子时钟_第1页
单片机实验报告电子时钟_第2页
单片机实验报告电子时钟_第3页
单片机实验报告电子时钟_第4页
单片机实验报告电子时钟_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

单片机实验报告(电子时钟)内容最近在回顾复习一下51单片机的一些内容,做一些笔记,记录复习。今天主要是记录51单片机的DS1302时钟实验基础知识,包括DS1302芯片介绍、使用方式、SPI通信协议等内容。注:参考内容(笔记记录内容来自普中单片机学习资料)DS1302时钟芯片是3线SPI接口,所以需要使用51单片机的3个IO口模拟SPI时序与DS1302时钟芯片通信,将时钟日历数据读取出来。开发板上集成了1个DS1302时钟模块,可使用它设计一个多功能电子时钟。1.DS1302芯片介绍DS1302是DALLAS公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过AM/PM指示决定采用24或12小时格式。DS1302与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:①RES复位②I/O数据线③SCLK串行时钟。时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信。DS1302工作时功耗很低保持数据和时钟信息时功率小于1mW。主要的性能指标:(1)实时时钟具有能计算2100年之前的秒、分、时、日、星期、月、年的能力,还有闰年调整的能力;(2)31个8位暂存数据存储RAM;(3)串行I/O口方式使得管脚数量最少;(4)宽范围工作电压2.0~5.5V;(5)工作在2.0V时,电流小于300nA;(6)读/写时钟或RAM数据时有两种传送方式单字节传送和多字节传送字符组方式;(7)8脚DIP封装或可选的8脚SOIC封装根据表面装配;(8)简单3线接口;(9)与TTL兼容Vcc=5V;(10)可选工业级温度范围-40~+85;DS1302的引脚和功能1.VCC2:主电源引脚。2.X1、X2:DS1302外部晶振引脚,通常需外接32.768K晶振。3.GND:电源地。4.CE:使能引脚,也是复位引脚(新版本功能变)。5.I/O:串行数据引脚,数据输出或者输入都从这个引脚。6.SCLK:串行时钟引脚。7.VCC1:备用电源,当主电源引脚断电时,备用电源启动,维持芯片的时钟运行。2.DS1302的使用操作DS1302的大致过程,就是将各种数据写入DS1302的寄存器,以设置它当前的时间的格式。然后使DS1302开始运作,DS1302时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。再用液晶显示,就是我们常说的简易电子钟。所以总的来说DS1302的操作分2步(显示部分属于液晶显示的内容,不属于DS1302本身的内容),

DS1302有一个控制寄存器、12个日历、时钟寄存器和31个RAM。(1)控制寄存器控制寄存器用于存放DS1302的控制命令字,DS1302的RST(CE使能引脚)引脚回到高电平后写入的第一个字节就为控制命令。它用于对DS1302读写过程进行控制,格式如下:上图是DS1302的寄存器样式:1、第7位永远都是1;2、第6位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器;3、第5到第1位,为RAM或者寄存器的地址;4、最低位,高电平表示RD,即下一步操作将要“读”;低电平表示W,即下一步操作将要“写”。比如要读秒寄存器则命令为10000001,反之写为10000000,要注意其含义。(2)日历/时钟寄存器DS1302共有12个寄存器,其中有7个与日历、时钟相关,存放的数据为BCD码形式。格式如下:对几个寄存器做下说明:秒寄存器:低四位为秒的个位,高的次三位为秒的十位。最高位CH为DS1302的运行标志,当CH=0时,DS1302内部时钟运行,反之CH=1时停止;小时寄存器:时寄存器。最高位为12/24小时的格式选择位,该位为1时表示12小时格式。当设置为12小时显示格式时,第5位的高电平表示下午(PM);而当设置为24小时格式时,第5位为具体的时间数据。写保护寄存器:当该寄存器最高位WP为1时,DS1302只读不写,所以要在往DS1302写数据之前确保WP为0。慢充电寄存器(涓细电流充电)寄存器:当DS1302掉电时,可以马上调用外部电源保护时间数据。该寄存器就是配置备用电源的充电选项的。其中高四位(4个TCS)只有在1010的情况下才能使用充电选项;低四位的情况与DS1302内部电路有关,具体可以查看DS1302手册。在日历/时钟寄存器中都是以BCD码存放数据,BCD码是通过4位二进制码来表示1位十进制中的0~9这10个数码。如下所示:(3)DS1302的读写时序在控制指令字节输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位(位0)开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7(数据传输由低位到高位)。其时序图如下所示:上图就是DS1302的三个时序:复位时序,单字节写时序,单字节读时序;CE(RST):复位时序,即在RST引脚产生一个正脉冲,在整个读写器件,RST要保持高电平,一次字节读写完毕之后,要注意把RST返回低电平准备下次读写周期;单字节读时序:注意读之前还是要先对寄存器写命令,从最低位开始写;可以看到,写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现。所以,在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!这个就是DS1302操作中最特别的地方。当然读出来的数据也是最低位开始。单字节写时序:两个字节的数据配合16个上升沿将数据写入即可。程序注意事项:(1)要记得在操作DS1302之前关闭写保护;(2)注意用延时来降低单片机的速度以配合器件时序;(3)DS1302读出来的数据是BCD码形式,要转换成我们习惯的10进制,转换方法在源程序里;(4)读取字节之前,将IO设置为输入口,读取完之后,要将其改回输出口;(5)在写程序的时候,建议实现开辟数组(内存空间)来集中放置DS1302的一系列数据,方便以后扩展键盘输入。硬件设计:从上图中可知,DS1302芯片的控制管脚接至单片机P3.4-P3.6上,在芯片的X1、X2管脚处外接了一个32.768KHZ晶振,为时钟运行提供一个稳定的时钟频率,C2和C3为旁路电容,目的是消除晶振起振时产生的电感干扰。开发板无外接备用电池,如果需要可自行将外部备用电源接入第8脚VCC1。3.实验内容和结果实现的功能是:数码管上显示电子时钟时分秒,格式为“XX-XX-XX”程序main.c程序#include"public.h"#include"smg.h"#include"ds1302.h"voidmain(){u8time_buf[8];//将读取的时间格式数据转化为数码管的段选数据数码管显示的内容ds1302_init();//初始化时间while(1){ds1302_read_time();//读取时间函数//gds1302_time[7]={0x47,0x19,0x16,0x21,0x08,0x07,0x22}//秒、分、时、日、月、周、年//数码管显示的是小时-分钟-秒16:19:47初始化的起始时间//秒gds1302_time[0]分gds1302_time[1]小时数据gds1302_time[2]//对数据进行提取小时的十位个位分钟的十位个位秒的十位个位time_buf[0]=gsmg[gds1302_time[2]/16];//十六进制表示的BCD值转化成十进制并提取十位数字,并转化为数码管的段选显示数据time_buf[1]=gsmg[gds1302_time[2]%16];//十六进制表示的BCD值转化成十进制并提取个位数字//小时数16是存储的BCD码0x16数值上是以十六进制存储00010110对应的数值是16+4+2=22//0x16/16=22/16=10x16%16=22%16=6即将十六进制表示的BCD值转化成十进制,并提取出来time_buf[2]=0x40;//横杆段选01000000共阴的数码管段选显示-号类似time_buf[3]=gsmg[gds1302_time[1]/16];//分钟的十位time_buf[4]=gsmg[gds1302_time[1]%16];//分钟的个位time_buf[5]=0x40;//横杆段选time_buf[6]=gsmg[gds1302_time[0]/16];//秒的十位段码数据time_buf[7]=gsmg[gds1302_time[0]%16];//秒的个位smg_display(time_buf,1);}}public.c程序#include"public.h"voiddelay_10us(u16time)//延时大概10us函数{while(time--);}voiddelay_ms(u16time)//延时大概1ms函数{u16i,j;for(i=time;i>0;i--)for(j=110;j>0;j--);}public.h头文件#ifndef_public_H#define_public_H#include"reg52.h"//定义别名typedefunsignedintu16;typedefunsignedcharu8;//自定义延时函数声明voiddelay_10us(u16time);//延时大概10us函数voiddelay_ms(u16time);//延时大概1ms函数#endifds1302.c程序//DS1302的驱动程序#include"ds1302.h"#include"intrins.h"//加载intrins.h头文件包括1us延时函数u8gwrite_rtc_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//写秒、分、时、日、月、周、年寄存器的地址u8gread_rtc_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};//读秒、分、时、日、月、周、年寄存器的地址//BCD码的形式存储也就是4位二进制表示一位十进制0-9可以用十六进制赋值u8gds1302_time[7]={0x47,0x43,0x18,0x21,0x08,0x07,0x22};//秒、分、时、日、月、周、年//默认是24小时格式,初始时间数据//0x47表示十进制47秒2100年2021年前面的20是固定的0x21//DS1302的读写函数根据时序//DS1302写字节函数无返回值写会传递16位//前8位是控制字节后8位是数据传输数据从低到高voidds1302_write_byte(u8addr,u8dat){u8i=0;DS1302_RST=0;//使能端低位_nop_();//12M晶振延时1微秒_nop_()1us函数在intrins.h头文件里面DS1302_CLK=0;//串行时钟低位_nop_();//延时1微秒DS1302_RST=1;//使能端高位_nop_();//延时1微秒//数据开始写入控制指令字节由低位到高位/*控制指令字节1、第7位永远都是1;2、第6位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器;3、第5到第1位,为RAM或者寄存器的地址;4、最低位,高电平表示RD,即下一步操作将要"读";低电平表示W,即下一步操作将要"写"。低位->高位传输R/WA0A1A2A3A4R/C1001写入数据要是在RST(CE)使能端为高电平,SCLK时钟信号的上升沿写入数据,下降沿读取数据,调用写函数的时候,要关闭写保护,并且数据传输是由低位传输到高位*/for(i=0;i<8;i++){//把地址写入I/ODS1302_IO=addr&0x01;//获取addr的低位//假设addr11111011&00000001=00000001addr>>=1;//对addr地址数据使用右移赋值语句addr>>=1等价与addr=addr>>1让次低位变成最低位DS1302_CLK=1;//写入数据要上升沿写入前面设置SCLK=0了_nop_();//数据写入了DS1302_CLK=0;//为下一次的上升沿做准备_nop_();//延时1us}for(i=0;i<8;i++){//把8位数据写入I/O此时的I/O是输出数据,将数据传输DS1302_IO=dat&0x01;//获取dat的低位dat>>=1;//对addr地址数据使用右移赋值语句dat>>=1等价与dat=dat>>1让次低位变成最低位DS1302_CLK=1;//写入数据要上升沿写入前面设置SCLK=0了_nop_();//数据写入了DS1302_CLK=0;//为下一次的上升沿做准备_nop_();//延时1us}//单字节写完之后,将RST设置为低电平为下一次写作准备DS1302_RST=0;_nop_();//延时1us}//DS1302读字节函数有数据返回值读会传递16位//前8位是写入控制字节后8位是数据读取传输数据从低到高u8ds1302_read_byte(u8addr)//需要传入参数控制字节{u8i=0;u8receive_dat=0;//I/O输出数据的中间存储位变量,存储的是一位数据u8value=0;//存储I/O输出的数据的值8位保存字节的数据DS1302_RST=0;//使能端低位_nop_();//12M晶振延时1微秒_nop_()1us函数在intrins.h头文件里面DS1302_CLK=0;//串行时钟低位_nop_();//延时1微秒DS1302_RST=1;//使能端高位_nop_();//延时1微秒//数据开始写入控制指令字节由低位到高位for(i=0;i<8;i++){//把地址写入I/ODS1302_IO=addr&0x01;//获取addr的低位//假设addr11111011&00000001=00000001addr>>=1;//对addr地址数据使用右移赋值语句addr>>=1等价与addr=addr>>1让次低位变成最低位DS1302_CLK=1;//写入数据要上升沿写入前面设置SCLK=0了_nop_();//数据写入了DS1302_CLK=0;//为下一次的上升沿做准备_nop_();//延时1us}//在一个时钟信号的下降沿开始读取数据数据是在I/O上,此时的I/O是输出数据for(i=0;i<8;i++){receive_dat=DS1302_IO;//I/O输入的是一位先输入低位/*value>>=1表示使用右移赋值运算符等价于value=value>>1receive_dat表示一位的值receive_dat<<7左移7位变成最高位value表示8位字节的值传输的是从最低位到最高位获取数据,可以先将位移动7位到最高位,然后在慢慢移动到最低位例如按照或运算的规则先运行右边value>>1,再运行(receive_dat<<7)再把两者或运算结果赋值给valuei=0,假设receive_dat=1,此时value=0(初值),value是8位右移1位之后value>>100000000receive_dat左移7位10000000或运算类似于求和有1则为1或运算后value=10000000i=1,假设receive_dat=0value是8位右移1位之后01000000receive_dat左移7位00000000或运算后value=01000000依次类推1会移动到最低位*/value=(receive_dat<<7)|(value>>1);//等效与两个语句合在一起value>>=1;value|=temp<<7;DS1302_CLK=1;//上次结束写入控制字节后DS1302_CLK=0SCLK下降沿读取数据_nop_();//延时1微秒在头文件intrins.h里面DS1302_CLK=0;//读取数据_nop_();}//整个读完给RST拉低为低电平DS1302_RST=0;_nop_();//延时1us//当前是I/O口处于读的状态也就是数据输入的状态,要将I/O口恢复为输出状态///对于实物中,P3.4口没有外接上拉电阻的,此处代码需要添加,使数据口有一个上升沿脉冲。DS1302_CLK=1;_nop_();//延时1usDS1302_IO=0;_nop_();//延时1usDS1302_IO=1;_nop_();//延时1usreturnvalue;}voidds1302_init(void)//DS1302的初始化函数对DS1302设置一个初始的时间{u8i=0;//定义循环变量ds1302_write_byte(0x8e,0x00);//关闭写保护WP=0/*写保护寄存器地址100011110x8f读操作写保护寄存器地址10001110写操作0x8e写保护寄存器内容WP0000000WP为1时写保护只读不能写0x80WP为0时关闭写保护000000000x00*/for(i=0;i<7;i++)//写入初始化时间{ds1302_write_byte(gwrite_rtc_addr[i],gds1302_time[i]);}ds1302_write_byte(0x8e,0x80);//打开写保护WP=1}voidds1302_read_time(void)//ds1302读取时间函数{u8i=0;for(i=0;i<7;i++){gds1302_time[i]=ds1302_read_byte(gread_rtc_addr[i]);//将读取到的时间存储到存储时间的数组上,更新时间}}ds1302.h头文件#ifndef_ds1302_H#define_ds1302_H#include"public.h"//定义DS1302的控制管脚sbitDS1302_RST=P3^5;//使能引脚复位引脚sbitDS1302_CLK=P3^6;//串行时钟引脚sbitDS1302_IO=P3^4;//输入/输出数据引脚//自定义函数声明//DS1302写字节函数前8位是addr控制字节后8位dat是数据传输数据从低到高voidds1302_write_byte(u8addr,u8dat);u8ds1302_read_byte(u8addr);voidds1302_init(void);//DS1302的初始化函数对DS1302设置一个初始的时间voidds1302_read_time(void);//ds1302读取时间函数externu8gds1302_time[7];//声明变量,可供其他.c文件使用#endifsmg.c程序#include"smg.h"u8gsmg[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,\0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};//共阴极数码管显示数据1-F,最后一个是数码管全灭\表示c语言中的续行符voidsmg_display(u8dat[],u8pos)//dat[]是数码管段选数据显示0123...//pos位选12345678第几个数据管//pos:从左开始第几个位置开始显示,范围1-8//更改数码管的显示提供数据和数码管使用的位置{u8i=0;//定义变量的时候赋初值,防止一些编译器识别未用的变量产生报错u8pos_temp=pos-1;//for(i=pos_temp;i<8;i++){switch(i)//用switch-case语句进行位选{case7:W_C=0;W_B=0;W_A=0;break;//对应选择了Y0-LED1最后一个数码管case6:W_C=0;W_B=0;W_A=1;break;//对应选择了Y0-LED2case5:W_C=0;W_B=1;W_A=0;break;//对应选择了Y0-LED3case4:W_C=0;W_B=1;W_A=1;break;//对应选择了Y0-LED4case3:W_C=1;W_B=0;W_A=0;break;//对应选择了Y0-LED5case2:W_C=1;W_B=0;W_A=1;break;//对应选择了Y0-LED6case1:W_C=1;W_B=1;W_A=0;break;//对应选择了Y0-LED7case0:W_C=1;W_B=1;W_A=1;break;//对应选择了Y0-LED8第一个数码管}SMG_Port=dat[i-pos_temp];//段选信号//传送段选数据delay_10us(100);//大概1ms延时SMG_Port=0x00;//消隐}}smg.h头文件#ifndef_smg_H#define_smg_H#include"public.h"#defineSMG_PortP0//宏定义将P0口定义SMG_Port//开发板的数码管段选信号由P0口(P0.0-P0.7)控制//定义数码管显示内容的数组//定义的是全局变量gsmg开头externu8gsmg[17];//对数组声明sbitW_C=P2^4;//sbit定义位变量位控制选择数码管sbitW_B=P2^3;//sbit定义位变量sbitW_A=P2^2;//sbit定义位变量voidsmg_display(u8dat[],u8pos);//声明数码管动态扫描显示函数#endif实验结果4.补充知识4.1涓流充电涓流充电是用来弥补电池在充满电后由于自放电而造成的容量损失。一般采用脉冲电流充电来实现上述目的。涓流充电:微小的脉冲电流充电,确保电池真正饱和,延长电池使用时间。涓流充电(tricklecharge,maintenancecharge)是为补偿自放电,使蓄电池保持在近似完全充电状态的连续小电流充电。又称维护充电(浮充)。电信装置、信号系统等的直流电源系统的蓄电池,在完全充电后多处于涓流充电状态,以备放电时使用。涓流充电:微小的脉冲电流充电,确保电池真正饱和,延长电池使用时间。镍氢电池充电全过程包括快速充电、连续式充电、涓流充电三个阶段。经过前两个阶段之后,虽然系统电量显示100%,但实际上电池并未真正达到饱和状态。此时剩余的容量只能靠微小的脉冲电流补充,这个阶段通常需要30-40分钟。三个阶段全部完成,电池才能真正达到电量饱和的良好状态。快速充电:能够迅速地将电池充到80%,但仍需进行连续式充电和涓流充电才能完全充满。连续式充电:充电电流逐渐减小,确保电池进入充满临界状态,要获得最佳续航能力,还需要进行涓流充电。涓流充电:微小的脉冲电流充电,确保电池真正饱和,延长电池使用时间。4.2SPI基础知识(来自知乎作者李清龙的《SPI接口协议介绍与应

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论