时间控制模块—DS1302芯片的控制编程
- 格式:ppt
- 大小:791.50 KB
- 文档页数:70
dsl302时钟程序详解经典dsl302时钟程序详解DS1302的控制字如图2所示。
控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始2.3数据输入输出(I/O)在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7o2.4 DS1302的寄存器DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表1。
» I日历•別间襦存祁及凡担制孑fir* 野擅"itwtr 収他总cn -T»fsy网移e S』32 1 0林斶son8!ll00-59 f.H IUSVX SIX X2H S3II oum(1Mh、MH K4H851101 \2A12 24« 10 IIH HKMhH M7II01 -2S.2V,W-Jl »o imiAre8SH WII03 - !2(11) 0 IUM MOYI1IAAII8HH ni(i II » 0 0h\V8LH Mill OQ • 9910YLAH此外,DS1302还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。
时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。
DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为COH, FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
/******************* 说明:**************************将实时时钟数据通过LCD1602 显示基于51 单片机**************************************************/#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int uchar dis_time_buf[16]={0};//LCD1602 引脚定义// 采用8 位并行方式,DB0~DB7 连接至LCDDATA0~LCDDATA7sbit RS=P2A0;sbit RW=P2A1;sbit CS=P2A2;#define LCDDATA P0//DS1302 引脚定义sbit RST=P1A3;sbit IO=P1A2;sbit SCK=P1A1;//DS1302 地址定义#define ds1302_sec_add 0x80 // 秒数据地址#define ds1302_min_add 0x82 // 分数据地址#define ds1302_hr_add 0x84 // 时数据地址#define ds1302_date_add 0x86 // 日数据地址#define ds1302_month_add 0x88 // 月数据地址#define ds1302_day_add 0x8a // 星期数据地址#define ds1302_year_add 0x8c // 年数据地址#define ds1302_control_add 0x8e // 控制数据地址#define ds1302_charger_add 0x90#define ds1302_clkburst_add 0xbe// 初始时间定义uchar time_buf[8] = {0x20,0x10,0x06,0x01,0x23,0x59,0x55,0x02};// 初始时间2010年6月1号23 点59 分55 秒星期二// 功能:延时 1 毫秒// 入口参数:x// 出口参数:无//说明:当晶振为12M时,j<112 ;当晶振为11.0592M时,j<122void Delay_xms(uint x){uint i,j;for(i=0;i<x;i++)for(j=0;j<112;j++);// 功能:12us 延时//STC89C52为1T单片机,即1个时钟/机器周期,速度为AT89C52的12倍void Delay_xus(uint t){for(;t>0;t--){_nop_();}}//控制LCD写时序void LCD_en_write(void){CS=1;Delay_xus(20);CS=0;Delay_xus(20);}// 写指令函数void Write_Instruction(uchar command){RS=0;RW=0;CS=1;LCDDATA=command;LCD_en_write();// 写入指令数据}// 写数据函数void Write_Data(uchar Wdata){RS=1;RW=0;CS=1;LCDDATA=Wdata;LCD_en_write();// 写入数据}// 字符显示初始地址设置void LCD_SET_XY(uchar X,uchar Y){uchar address;if(Y==0) address=0x80+X;//Y=0, 表示在第一行显示,地址基数为0x80elseaddress=0xc0+X;//Y 非 0 时,表时在第二行显示,地址基数为 0xC0 Write_Instruction(address);// 写指令,设置显示初始地址}//在第X 行Y 列开始显示 Wdata 所对应的单个字符 void LCD_write_char(uchar X,uchar Y,uchar Wdata){LCD_SET_XY(X,Y)写 地址Write_Data(Wdata);// 写入当前字符并显示}// 清屏函数 void LCD_clear(void){Write_Instruction(0x01); Delay_xms(5);}// 显示屏初始化函数 void LCD_init(void){Write_Instruction(0x38); // 8bit interface,2line,5*7dotsDelay_xms(5);Write_Instruction(0x38); Delay_xms(5);Write_Instruction(0x38);Write_Instruction(0x08); //关显示,不显光标,光标不闪烁 Write_Instruction(0x01); //清屏 Delay_xms(5);//Write_Instruction(0x05); //Write_Instruction(0x06);//Write_Instruction(0x07);Delay_xms(5); // 写一字符,整屏右移 // 写一字符,整屏显示不移动// 写一字符,整屏左移//Write_Instruction(0x0B); Write_Instruction(0x0C);//Write_Instruction(0x0D); //Write_Instruction(0x0E); //Write_Instruction(0x0F); } //DS1302 初始化函数 void ds1302_init(void){Write_Instruction(0x04); // 写一字符,整屏显示不移动 // 关闭显示(不显示字符,只有背光亮) // 开显示,光标、闪烁都关闭// 开显示,不显示光标,但光标闪烁 // 开显示,显示光标,但光标不闪烁}//向DS1302写入一字节数据void ds1302_write_byte(uchar addr, uchar d){uchar i; RST=1;// 启动 DS1302 总线// 写入目标地址: addraddr = addr & 0xFE; // 最低位置零,寄存器 0 位为 0 时写,为 1 时读 for (i = 0; i < 8; i ++) {if (addr & 0x01) {IO=1;}else {IO=0;}SCK=1; //产生时钟 SCK=0;addr = addr >> 1;}// 写入数据: dfor (i = 0; i < 8; i ++) {if (d & 0x01) {IO=1;}else {IO=0;}SCK=1; // 产生时钟 SCK=0; d = d >> 1;}RST=O;〃停止 DS1302 总线}//从DS1302读出一字节数据uchar ds1302_read_byte(uchar addr) {uchar i,temp; RST=1;// 启动 DS1302 总线// 写入目标地址: addr addr = addr | 0x01;// 最低位置高,寄存器 0 位为 0 时写,为 1 时读for (i = 0; i < 8; i ++) {RST=0; SCK=0;//RST 脚置低 //SCK 脚置低if (addr & 0x01) { IO=1;}else { IO=0;}SCK=1;SCK=0;addr = addr >> 1;}// 输出数据:tempfor (i = 0; i < 8; i ++) { temp = temp >> 1; if (IO) {temp |= 0x80;}else {temp &= 0x7F; }SCK=1;SCK=0;}RST=0;//停止DS1302 总线return temp;}//向DS302写入时钟数据void ds1302_write_time(void) {ds1302_write_byte(ds1302_control_add,0x00); // 关闭写保护ds1302_write_byte(ds1302_sec_add,0x80); // 暂停时钟//ds1302_write_byte(ds1302_charger_add,0xa9); // 涓流充电ds1302_write_byte(ds1302_year_add,time_buf[1]); // 年ds1302_write_byte(ds1302_month_add,time_buf[2]); //月ds1302_write_byte(ds1302_date_add,time_buf[3]); // 日ds1302_write_byte(ds1302_hr_add,time_buf[4]); // 时ds1302_write_byte(ds1302_min_add,time_buf[5]); // 分ds1302_write_byte(ds1302_sec_add,time_buf[6]); // 秒ds1302_write_byte(ds1302_day_add,time_buf[7]); // 周ds1302_write_byte(ds1302_control_add,0x80); //打开写保护}//从DS302读出时钟数据void ds1302_read_time(void){time_buf[1]=ds1302_read_byte(ds1302_year_add); // 年time_buf[2]=ds1302_read_byte(ds1302_month_add); // 月time_buf[3]=ds1302_read_byte(ds1302_date_add); // 日time_buf[4]=ds1302_read_byte(ds1302_hr_add); // 时time_buf[5]=ds1302_read_byte(ds1302_min_add); // 分time_buf[6]=(ds1302_read_byte(ds1302_sec_add))&0x7f;// 秒,屏蔽秒的第7 位,避免超出59time_buf[7]=ds1302_read_byte(ds1302_day_add); // 周}void Display(void){LCD_write_char(3,0,dis_time_buf[0]+'0');LCD_write_char(4,0,dis_time_buf[1]+'0');LCD_write_char(5,0,dis_time_buf[2]+'0');LCD_write_char(6,0,dis_time_buf[3]+'0');LCD_write_char(7,0,'/');LCD_write_char(8,0,dis_time_buf[4]+'0');LCD_write_char(9,0,dis_time_buf[5]+'0');LCD_write_char(10,0,'/');LCD_write_char(11,0,dis_time_buf[6]+'0');LCD_write_char(12,0,dis_time_buf[7]+'0');LCD_write_char(15,0,dis_time_buf[14]+'0'); // 第 2 行显示LCD_write_char(3,1,dis_time_buf[8]+'0');LCD_write_char(4,1,dis_time_buf[9]+'0');LCD_write_char(5,1,':');LCD_write_char(6,1,dis_time_buf[10]+'0');LCD_write_char(7,1,dis_time_buf[11]+'0');LCD_write_char(8,1,':');LCD_write_char(9,1,dis_time_buf[12]+'0');LCD_write_char(10,1,dis_time_buf[13]+'0');}// 定时器中断函数void Timer2() interrupt 5// 定时器 2 是 5 号中断{static uchar t;TF2=0;t++;if(t==4) // 间隔200ms(50ms*4) 读取一次时间{t=0;ds1302_read_time(); // 读取时间dis_time_buf[0]=(time_buf[0]>>4); // 年dis_time_buf[1]=(time_buf[0]&0x0f);dis_time_buf[2]=(time_buf[1]>>4);dis_time_buf[3]=(time_buf[1]&0x0f);dis_time_buf[4]=(time_buf[2]>>4); // 月dis_time_buf[5]=(time_buf[2]&0x0f);dis_time_buf[6]=(time_buf[3]>>4); // 日dis_time_buf[7]=(time_buf[3]&0x0f);dis_time_buf[14]=(time_buf[7]&0x07); // 星期// 第 2 行显示dis_time_buf[8]=(time_buf[4]>>4); // 时dis_time_buf[9]=(time_buf[4]&0x0f);dis_time_buf[10]=(time_buf[5]>>4); // 分dis_time_buf[11]=(time_buf[5]&0x0f);dis_time_buf[12]=(time_buf[6]>>4); // 秒dis_time_buf[13]=(time_buf[6]&0x0f);}}// 定时器 2 初始化void Init_timer2(void){RCAP2H=0x3c;〃赋T2初始值0x3cb0,溢出20次为1秒,每次溢出时间为50ms RCAP2L=0xb0;TR2=1; //启动定时器 2ET2=1; // 打开定时器 2 中断EA=1; // 打开总中断}// 主函数void main(void){Delay_xms(50);// 等待系统稳定LCD_init(); //LCD 初始化LCD_clear(); // 清屏ds1302_init(); //DS1302 初始化Delay_xms(10);ds1302_write_time(); // 写入初始值Init_timer2(); // 定时器 2 初始化while(1){Display();}。
DS1302原理及程序说明DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31字节静态RAM ,通过简单的串行接口与单片机进行通信。
实时时钟/日历电路提供秒、分、时、日、日期、月、年的信息,每月的天数和闰年的天数可自动调整,时钟操作可通过AM/PM 指示决定采用24 或12 小时格式。
DS1302 与单片机之间能简单地采用同步串行的方式进行,DS1302的引脚命名如图1-1所示。
通信仅需用到三根信号线:(1)CE 片选,(2)I/O 数据线,(3)SCLK 串行时钟,DS1302与CPU 的连接如图1-2所示。
时钟/RAM 的读/写数据以一个字节或多字节的字符组方式通信,DS1302工作时功耗很低,保持数据和时钟信息时功率小于1mW 。
DS1302具有双电源管脚,用于主电源和备份电源供应Vcc1,为可编程涓流充电电源附加七个字节存储器,它广泛应用于电话传真便携式仪器以及电池供电的仪器仪表等产品领域。
DS1302主要的性能指标如下:实时时钟具有能计算2100 年之前的秒、分、时、日、日期、星期、月、年的能力,还有闰年调整的能力31× 8 位暂存数据存储RAM 串行I/O 口方式,使得管脚数量最少宽范围工作电压2.0~ 5.5V工作电流2.0V 时,小于300nA读/写时钟或RAM 数据时有两种传送方式:单字节传送和多字节传送字符组方式8 脚DIP 封装或可选的8 脚SOIC 封装根据表面装配简单3 线接口与TTL 兼容Vcc=5V 。
DS1302的读写模式工作时序如图1-3和图1-4所示。
图1-3 单字节读模式图1-4 单字节写模式注:在多字节模式下,SCLK 发出同步脉冲,CS 须持续保持高电平直到多字节操作结束,图1-1 DS1302引脚图1-2 DS1302与CPU 接口DS1302内部寄存器的地址定义如表1-1所示。
表1-1 寄存器的地址及定义实验说明1. DS1302与51单片机的连接IO ——P2.7:串行数据输入/输出引脚SCLK ——P2.6:串行时钟引脚CE ——P2.4:片选CE2. LCD 与单片机连接;************************************************************************* ; LCD Module LMB1602 与单片机连接:;************************************************************************* ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ;Vss Vdd V o RS R/W E D0 D1 D2 D3 D4 D5 D6 D7 BLA BLK ; 0V +5V 0V P32 P33 P34 ---------------- P1[0..7] ---------------- +5V 0V;*************************************************************************3. LCD 显示功能说明LCD1602显示格式如图1-5所示。
ds1302时钟芯片工作原理DS1302时钟芯片是一种常用的DIY实用型芯片,主要应用于存储时间和日期信息,它主要包括时间端口、RTC控制程序和RTC配置存储器。
它是一款基于CMOS技术的钟表芯片,它具有极低功耗、更快速的实时时钟,可以支持多种实时时钟功能。
DS1302时钟芯片的工作原理是:第一步,通过时间端口,分别将时间和日期的信息放入RTC的存储器;第二步,RTC控制程序将时钟日期的信息,自动加1累加;第三步,RTC芯片输出实时有效的时间日期信息。
总的来说,DS1302时钟芯片使用简单,操作灵活,它可以设定各种常见的时间格式,数字形式显示24小时制时间、12小时制时间和星期,易于操作和读取,在DIY领域有着广泛的应用。
它有一个特性:它支持Real-time秒读取和转换,RTC为精确的实时计时。
,可以满足大多数系统的需求,更可以连接到外部的按钮或者传感器,实现RTC 功能的灵活扩展。
DS1302时钟芯片从原理上看,可以很好的保持系统的准确时间,同时它可以满足实时计算、定时操作,可以实现自动计算、自动节能和不同时间控制功能,是DIY领域的低成本解决方案,使得DIY领域的应用更加强大。
基于ds1302的数字时钟两个按键控制调整显示年月日时间以及定时,仿真图和程序如下,仅供参考。
K1是方式调整键,不按是0方式调秒,有10种方式,自己试吧,右下角显示的是第几种方式。
K2是调整键,K3没用到。
#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int//uchar data_7seg[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,};uchar hour,min,sec,nian=1,yue=1,zhou=1,ri=1,x,m,n;sbit k1=P3^4;sbit k2=P3^5;//sbit miao=P3^6;sbit rst=P1^2;sbit sck=P1^1;sbit io=P1^0;sbit fm=P1^7;/*函数声明:*/void write_ds1302_byte(uchar dat);void write_ds1302(uchar add,uchar dat);uchar read_ds1302(uchar add);void read_rtc();void set_rtc();void display();void delay(int n);void show();void fmzz();/******************************************************************************************************************************************************/sbit E=P2^2; //1602使能引脚sbit RW=P2^1; //1602读写引脚sbit RS=P2^0; //1602数据/命令选择引脚/********************************************************************* 名称 : Delay_1ms()* 功能 : 延时子程序,延时时间为 1ms * x* 输入 : x (延时一毫秒的个数)* 输出 : 无***********************************************************************/ void Delay_1ms(uint i)//1ms延时{uchar x,j;for(j=0;j<i;j++)for(x=0;x<=148;x++);}/********************************************************************* 名称 : delay()* 功能 : 延时,延时时间大概为5US。
ds1302时钟程序详解,ds1302程序流程图(C程序)ds1302时钟程序详解DS1302 的控制字如图2所示。
控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
数据输入输出(I/O)在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
DS1302的寄存器DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表1。
此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。
时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。
DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
ds1302程序流程图DS1302实时时间流程图4示出DS1302的实时时间流程。
根据此流程框图,不难采集实时时间。
下面结合流程图对DS1302的基本操作进行编程:根据本人在调试中遇到的问题,特作如下说明:DS1302 与微处理器进行数据交换时,首先由微处理器向电路发送命令字节,命令字节最高位MSB(D7)必须为逻辑1,如果D7=0,则禁止写DS1302,即写保护;D6=0,指定时钟数据,D6=1,指定RAM数据;D5~D1指定输入或输出的特定寄存器;最低位L SB(D0)为逻辑0,指定写操作(输入), D0=1,指定读操作(输出)。
#include<reg52.h>#define uchar unsigned charsbit RST=P1^2;sbit SDA=P1^1;sbit SCLK=P1^0;sbit rs=P1^3;sbit lcden=P1^4;sbit key1=P3^7;sbit key2=P3^6;sbit key3=P3^5;uchar t,addr,x,y;void delay(unsigned char t){unsigned char i,j;for(i=t;i>0;i--)for(j=110;j>0;j--);}void delayus(unsigned char t1){for(;t1>0;t1--);}void write_com(unsigned char com)//写lcd1602控制命令{rs=0;P0=com;delay(5);lcden=1;delay(5);lcden=0;}void write_dat(unsigned char dat) //写lcd1602显示数据命令{rs=1;P0=dat;delay(5);lcden=1;delay(5);lcden=0;}void DS1302WriteByte(uchar dat){uchar i;SCLK=0;delayus(2);for(i=0;i<8;i++){SDA=dat&0x01;delayus(2);SCLK=1;delayus(2);SCLK=0;dat>>=1;}}void DS1302Read(uchar cmd) //读ds1302的时间信息并显示出来{uchar dat,a2,i;RST=0;SCLK=0;RST=1;DS1302WriteByte(cmd);delayus(2);for(i=0;i<8;i++){dat>>=1;if(SDA==1)dat|=0x80;SCLK=1;delayus(2);SCLK=0;delayus(2);}SCLK=1;RST=0;if(cmd==0x8b){dat=dat%16;write_dat(0x30+dat);}else{a2=dat%16;dat=dat/16;write_dat(0x30+a2);write_dat(0x30+dat);}}void DS1302Write(uchar cmd, uchar dat) //写时间信息到ds1302 {RST=0;SCLK=0;RST=1;DS1302WriteByte(cmd);DS1302WriteByte(dat);SCLK=1;RST=0;}void init() //初始化部分{P2=0; //关闭锁存器端口write_com(0x01);write_com(0x38);write_com(0x0c);write_com(0x04);DS1302Write(0x8e,0x00);}void key() //按键控制部分{ uchar q;if(key1==0){DS1302Write(0x80,0x80);write_com(0x0f);delay(40);if(key1==0){t++;if(t==9)t=1;switch(t){case 1:write_com(0x85); addr=0x85;break;case 2:write_com(0x88); addr=0x88;break;case 3:write_com(0x8b); addr=0x8b;break;case 4:write_com(0x8e); addr=0x8e;break;case 5:write_com(0xc5); addr=0xc5;break;case 6:write_com(0xc8); addr=0xc8;break;case 7: write_com(0xcb); addr=0xcb;break;case 8: x=x*16+y;DS1302Write(0x80,x);write_com(0x0c);t=0;break;}while(key1==0);x=0;y=0;}}if(key2==0||key3==0){delay(40);if(key2==0){if(t==4)y=0;elsex++;}if(key3==0)y++;switch (t){case 1: if(x==10)x=0;if(y==10)y=0;q=x*16+y;DS1302Write(0x8c,q);break;case 2: if(x==0){if(y==10)y=0;}if(x==1){ if(y==3)y=0;}if(x==2)x=0;q=x*16+y;DS1302Write(0x88,q); break;case 3: if(x==4)x=0;if(y==32)y=0;q=x*16+y;DS1302Write(0x86,q);break;case 4:if(y==8)y=0;q=x*16+y;DS1302Write(0x8a,q); break;case 5: if(x==0||x==1){if(y==10)y=0;}if(x==2){ if(y==4)y=0;}if(x==3)x=0;q=x*16+y;DS1302Write(0x84,q); break;case 6:if(x==6)x=0;if(y==10)y=0;q=x*16+y;DS1302Write(0x82,q);break;case 7: if(x==6)x=0;if(y==10)y=0;q=x*16+y+0x80;DS1302Write(0x80,q);break;}if(addr==0x8e){write_com(addr);write_dat(0x30+y);write_com(addr);}else{write_com(addr);write_dat(0x30+y);write_dat(0x30+x);write_com(addr);}while(key2==0||key3==0);}}void main(){init();while(1){key();if(t==0){write_com(0xcb); // 在第二行显示DS1302Read(0x81); // 读秒write_dat(0x3a);DS1302Read(0x83); // 读分write_dat(0x3a);DS1302Read(0x85); // 读时write_com(0x8e); // 在第一行显示DS1302Read(0x8b); // 读星期write_dat(0x2a);write_dat(' ');DS1302Read(0x87); // 读日write_dat(0x2f);DS1302Read(0x89); // 读月write_dat(0x2f);DS1302Read(0x8d); // 读年write_dat(0x30);write_dat(0x32);} }}。
蓝桥杯单⽚机训练[4]---DS1302时钟芯⽚DS1302是由美国DALLAS公司推出的具有涓细电流充电能⼒的低功耗实时时钟芯⽚。
它可以对年、⽉、⽇、周、时、分、秒进⾏计时,且具有闰年补偿等多种功能。
单⽚机与DS1302通过SPI协议进⾏通信,LSB先⾏,由于举办⽅会提供SPI驱动,⾥⾯读写时序给的很明⽩,关于SPI协议这⾥就不具体讲了,我们下⾯只关注如何使⽤这个芯⽚。
RTC寄存器如下:注意:(1)DS1302采⽤的BCD码,写⼊和读出时需要进⾏转化!(2)CH为时钟暂停标志,置0时钟开始计时(3)WP为写保护位,置0时才可以写⼊数据我们需要实现的功能简单来说就两个1.初始化时间2.读取时间1.我们想要配置初始时间,⾸先要将写保护(WP)关掉,即将8Eh地址最⾼位置零,然后就可以愉快的往时分秒寄存器写相应时间啦,这时要⾮常注意,上⾯RTC寄存器数据是以BCD码进⾏存储的,因此必须将我们的数转为BCD码。
举个栗⼦,我们平常接触到的⼗进制数23,等价于20+3,⽽其BCD码直接就是0x23,就是把⼗位和各位分别放到⾼四位和低四位。
初始化代码如下:void Ds1302_write(u8 h,u8 m,u8 s){Write_Ds1302_Byte(0x8e,0x00); //关闭写保护Write_Ds1302_Byte(0x84,h/10*16+h%10); //时Write_Ds1302_Byte(0x82,m/10*16+m%10); //分Write_Ds1302_Byte(0x80,s/10*16+s%10); //秒Write_Ds1302_Byte(0x8e,0x80); //开启写保护}以BCD码写⼊数据⼤概也就执⾏上⾯⼀次,⽽我们从寄存器把时间读回来却⼀直都是BCD码,⾮常不⽅便,⼀次还得整个函数:u8 bcd_to_dat(u8 n) //传⼊BCD码返回⼗进制数{u8 t1,t2;t1=n/16,t2=n%16;t1=t1*10+t2;return t1;}好了,在上⾯进⾏时间的初始化后,我们就可以愉快的读取时间啦,这⾥时分秒被保存在全局变量中,⽅⾯调⽤。
时钟芯片DS1302汇编程序interval equ 5000;Timer0 定时常数Flag05s bit 00h ;0.5秒标志T_RST Bit P1.2;实时时钟复位线引脚T_CLK Bit P1.1;实时时钟时钟线引脚T_IO Bit P1.0 ;实时时钟数据线引脚;DS1302内部参数,0.5秒读一次SECOND EQU 30HMINUTE EQU 31HHOUR EQU 32HDAY EQU 33HMONTH EQU 34HWEEK EQU 35HYEAR EQU 36HDspBuf EQU 40H ;显示缓冲区SeleDIG equ 44h ;位扫描Ti5ms EQU 45H ;系统时钟每4ms加"1" Ti05S EQU 46HP2BUF EQU 47H ;输出口内部寄存器STATE EQU 48HStTmr equ 49hORG 0000HAJMP STARTORG 0BHAJMP ITimer0ORG 80HSEGCODE:;db 01h,02h,04h,08,10h,20h,40h, 80h DB 3FH,06H,5BH,4FH,66H;段码表 DB 6DH,7DH,07H,7FH,6FH DB 7BH,7CH,39H,5EH,79H,71HDB 00HORG 100HSTART: MOV IE,#00Hclr AMOV R0,#0FFHSTART1: MOV @R0,ADJNZ R0,START1MOV SP,#0C0H ;修改堆栈MOV TMOD,#11HMOV TH0,#HIGH(65536-interval) MOV TL0,#LOW(65536-interval) SETB TR0MOV SECOND,#02H ;初始时间设为12:00:00MOV MINUTE,#01HMOV HOUR,#20HMOV DAY,#30H ;初始日期设为08年1月1日第一周MOV MONTH,#10HMOV WEEK,#01HMOV YEAR,#09HLCALL SETDS1302MOV SELEDIG,#00HMOV IE,#02HSETB EAmov r6,#51hmov r7,#0CDhcall UpdateBufLOOP: nopjnb Flag05s,loop01clr Flag05sinc Ti05sLCALL GET1302call ChgStcall displayloop01: nopnopnopLJMP LOOP;状态转换,;5秒转换一次,state=0,显示“年”;1===“月日”;2===“时分”;3===“分秒”ChgSt: mov a,Ti05sclr csubb a,StTmrcjne a,#10,$+3jc ChgSt00mov StTmr,Ti05sinc StateChgSt00: retDisplay: mov a,Stateanl a,#03hcjne a,#00h,Display01mov r6,#20hmov r7,yearajmp Display00display01:cjne a,#01h,Display02mov r6,monthmov r7,dayajmp Display00display02:cjne a,#02h,Display03mov r6,hourmov r7,minuteajmp Display00display03:cjne a,#03h,Display04mov r6,minutemov r7,secondDisplay00:call UpdateBufretdisplay04:mov state,#0ffhret;更新显示缓冲区;将R6R7的内容显示在LED上,R6为高8位,显示在左边两个LED;R0,ACC,DPTRUpdateBuf:mov dptr,#segcodemov r0,#dspbufmov a,r6anl a,#0f0hswap amovc a,@a+dptrmov @r0,ainc r0mov a,r6anl a,#0fhmovc a,@a+dptrmov @r0,ainc r0mov a,r7anl a,#0f0hswap amovc a,@a+dptrmov @r0,ainc r0mov a,r7anl a,#0fhmovc a,@a+dptrmov @r0,ainc r0ret;定时器0中断服务程序ITimer0:MOV TH0,#HIGH(65536-interval) MOV TL0,#LOW(65536-interval) PUSH ACCmov a,Ti5msinc acjne a,#100,$+3jc ITimer04clr asetb Flag05sITimer04:mov Ti5ms,a;真实的电路必须加以下四行mov a,p2buforl a,#0fhMOV P2,amov p0,#00hINC SELEDIGMOV A,SELEDIGANL A,#03HJNZ ITIM01MOV A,P2BUFANL A,#0F0HORL A,#01HAJMP ITIM00ITIM01:CJNE A,#01H,ITIM02MOV A,P2BUFANL A,#0F0HORL A,#02HAJMP ITIM00ITIM02:CJNE A,#02H,ITIM03MOV A,P2BUFANL A,#0F0HORL A,#04HAJMP ITIM00 ITIM03: MOV A,P2BUFANL A,#0F0HORL A,#08HITIM00: cpl aMOV P2,AMOV A,SELEDIGANL A,#03HADD A,#DSPBUFMOV R0,AMOV A,@R0MOV P0,APOP ACCreti;设置DS1302初始时间,并启动计时SETDS1302:CLR T_RSTnopCLR T_CLKnopSETB T_RSTnopMOV B,#8EH ;写控制命令字LCALL INPUTBYTEMOV B,#00H ;写保护关闭LCALL INPUTBYTESETB T_CLKnopCLR T_RSTMOV R0,#SECOND;内存中的时间首地址MOV R1,#80H;DS1302中的时间首地址MOV R7,#7 ;字节数SETLOOP:CLR T_RSTnopCLR T_CLKnopSETB T_RSTnopMOV B,R1 ;写命令字LCALL INPUTBYTEMOV A,@R0 ;设置时间MOV B,ALCALL INPUTBYTEINC R0INC R1INC R1SETB T_CLKnopCLR T_RSTnopDJNZ R7,SETLOOPCLR T_RSTnopCLR T_CLKnopSETB T_RSTnopMOV B,#8EHLCALL INPUTBYTEMOV B,#80H;开写保护LCALL INPUTBYTESETB T_CLKnopCLR T_RSTnopRET;从DS1302读取时间GET1302:MOV R0,#SECONDMOV R1,#81H;DS1302中读时间的首地址MOV R7,#7GETLOOP:CLR T_RSTnopCLR T_CLKnopSETB T_RSTnopMOV B,R1LCALL INPUTBYTE;写命令字LCALL OUTPUTBYTE;读时间MOV @R0,A ;将从DS1302中读取的时间从内存中保存INC R0 ;修改地址指针 INC R1INC R1SETB T_CLKnopCLR T_RSTnopDJNZ R7,GETLOOPRET;向DS1302写一个字节INPUTBYTE:MOV R4,#8 INPUTLOOP:MOV A,BRRC AMOV B,AMOV T_IO,CSETB T_CLKNOP;NOPCLR T_CLKDJNZ R4,INPUTLOOPRET;从DS1302读一个字节OUTPUTBYTE:clr aclr cMOV R4,#8OUTPUTLOOP:NOP;NOPMOV C,T_IORRC ASETB T_CLKNOP;NOPCLR T_CLKDJNZ R4,OUTPUTLOOPRETEND ;======= ==== 基于DS1302的日历时钟演示实例#include<reg51.h>#include<intrins.h>unsigned char code digit[10]={"0123456789"}; sbit DATA=P3^6;sbit RST=P3^4;sbit SCLK=P3^5;sbit RS=P2^0;sbit RW=P2^1;sbit E=P2^2;sbit BF=P0^7;void delaynus(unsigned char n){ //延时若干微秒unsigned char i;for(i=0;i<n;i++);}void Write1302(unsigned char dat){unsigned char i;SCLK=0;delaynus(2);for(i=0;i<8;i++){DATA=dat&0x01;delaynus(2);SCLK=1;delaynus(2);SCLK=0;dat>>=1;} }函数功能:根据命令字,向1302写一个字节数据入口参数:Cmd,储存命令字;dat,储存待写的数据void WriteSet1302(unsigned char Cmd,unsigned char dat) {RST=0;SCLK=0;RST=1;delaynus(2);Write1302(Cmd);Write1302(dat);SCLK=1;RST=0;}unsigned char Read1302(void){unsigned char i,dat;delaynus(2);for(i=0;i<8;i++){dat>>=1;if(DATA==1)dat|=0x80;SCLK=1;delaynus(2);SCLK=0;delaynus(2);}return dat;}函数功能:根据命令字,从1302读取一个字节数据入口参数:Cmdunsigned char ReadSet1302(unsigned char Cmd){unsigned char dat;RST=0;SCLK=0;RST=1;Write1302(Cmd);dat=Read1302();SCLK=1;RST=0;return dat;}void Init_DS1302(void){WriteSet1302(0x8E,0x00); //写入不保护指令WriteSet1302(0x80,((0/10)<<4|(0%10)));//写入秒的初始值WriteSet1302(0x82,((0/10)<<4|(0%10)));//写入分的初始值WriteSet1302(0x84,((12/10)<<4|(12%10)));//写入小时的初始值WriteSet1302(0x86,((16/10)<<4|(16%10)));//写入日的初始值WriteSet1302(0x88,((11/10)<<4|(11%10)));//写入月的初始值WriteSet1302(0x8c,((8/10)<<4|(8%10)));//写入小时的初始值}函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++) ;}void delaynms(unsigned char n){unsigned char i;for(i=0;i<n;i++) delay1ms();}函数功能:判断液晶模块的忙碌状态返回值:result。
9.1.3 单片机控制DS1302编程/******************************************************功能:通过A VR单片机写时间信息到DS1302,然后读取DS1302的时间信息,并显示到数码管上。
有后备电池的情况下,单片机复位或断电,不影响DS1302的时钟,即DS1302仍能正常计时。
文件名称:main.c修改时间:2012-09-19作者:YLH*****************************************************/unsigned char rec_time[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //定义一个数组存储秒,分,时,日,月,周,年unsigned char seg[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//定义共阳极数码管的0~9的段码unsigned char pos[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //数码管位置信息unsigned char time[13];/*对DS1320三个管脚和单片机的接口进行字符常量定义*/#define SCLK PORTA1_bit#define IO PORTA2_bit#define RST PORTA3_bit/*对74HC595三个管脚和单片机的接口进行字符常量定义*/#define DS PORTB5_bit#define SHCP PORTB7_bit#define STCP PORTB4_bit/*************************************************函数名:ds1302_disp_init()函数功能:初始化连接DS1302、74HC595的端口入口参数:无返回值:无************************************************/void ds1302_disp_init(){DDRA|=0x0e; //设置PA1,2,3端口方向为输出DDRB|=0xb0; //设置PB4,5,7端口方向为输出PORTA&=0xf1; //将PA1,2,3端口初始值初始化为0;PORTB&=0x4f; //将PB4,5,7端口初始值初始化为0;}/*************************************************函数名:write_byte( )函数功能:向DS1302发送一个字节入口参数:dat--要写入的地址或者数据返回值:无************************************************/void write_byte(unsigned char dat){unsigned char i;for(i=0;i<8;i++){SCLK=0; //时钟信号拉低if(dat&0x01)IO=1; //判断地址字节的最低位,1位为1则拉高IO else IO=0; //1位为0,则输入数据为0,拉低IOdelay_us(1);SCLK=1; //时钟信号拉高,产生上升沿delay_us(1);dat>>=1; //字节右移一位}}/*************************************************函数名:read_byte( )函数功能:从DS1302读出一个字节入口参数:无返回值:dat************************************************/ unsigned char read_byte(){unsigned char i, dat=0;DDA2_bit=0; //设置IO的方向为输入IO=0; //设置IO为高阻态,无上拉电阻for(i=0;i<8;i++){dat>>=1; //数据右移一位SCLK=1; //设置SCLK为高电平delay_us(1);SCLK=0; //设置SCLK为低电平,产生下降沿delay_us(1);if(PINA2_bit==1) //如果读出的数据为1dat|=0x80; //数据位1,则写入1}DDA2_bit=1; //将IO口的方向改为输出return dat; //返回读取到的数据}/*************************************************函数名:ds1302_write_byte( )函数功能:向DS1302对应地址发送一个字节入口参数:add--要写入数据的地址;dat--要写入的数据返回值:无************************************************/void ds1302_write_byte(unsigned char add,unsigned char dat){RST=0; //将RST拉低SCLK=0; //将SCLK拉低RST=1; //将RST拉高write_byte(add); //写入地址字节write_byte(dat); //写入数据SCLK=1; //将SCLK拉高RST=0; //将RST拉低}/*************************************************函数名:ds1302_read_byte( )函数功能:从DS1302对应地址读取一个字节入口参数:add--要读出数据所在的地址返回值:shuju************************************************/ unsigned char ds1302_read_byte(unsigned char add){unsigned char shuju; //定义一个变量,存储返回的数据RST=0; //将RST拉低SCLK=0; //将SCLK拉低RST=1; //将RST拉高write_byte(add); //写入地址字节shuju=read_byte(); //读取该地址字节的数据SCLK=1; //将SCLK拉高RST=0; //将RST拉低return shuju; //返回读到的数据}/*************************************************函数名:process_dat( )函数功能:处理单片机读取DS1302得到的时间信息,提取数值入口参数:无返回值:无************************************************/void process_dat()time[0]=rec_time[0]&0x0f; //提取秒的个位time[1]=(rec_time[0]&0x70)>>4; //提取秒的十位time[2]=rec_time[1]&0x0f; //提取分的个位time[3]=(rec_time[1]&0x70)>>4; //提取分的十位time[4]=rec_time[2]&0x0f; //提取小时的个位time[5]=(rec_time[2]&0x30)>>4; //提取小时的十位time[6]=rec_time[3]&0x0f; //提取日的个位time[7]=(rec_time[3]&0x30)>>4; //提取日的十位time[8]=rec_time[4]&0x0f; //提取月的个位time[9]=(rec_time[4]&0x10)>>4; //提取月的十位time[10]=rec_time[5]&0x07; //提取周time[11]=rec_time[6]&0x0f; //提取年的个位time[12]=(rec_time[6]&0xf0)>>4; //提取年的十位}/*************************************************函数名:send_595_byte( )函数功能:单片机向74HC595发送一个字节入口参数:dat返回值:无************************************************/void send_595_byte(unsigned char dat){unsigned char i;for(i=0;i<8;i++){SHCP=0; //移位时钟拉低delay_us(5); //延时if(dat&0x80)DS=1; //如果提取到的最高位为1,则数据线输出1elseDS=0;SHCP=1; //移位时钟拉高,产生上升沿,写入数据delay_us(5);dat<<=1; //数据向左移一位}}/*************************************************函数名:send_595_fram( )函数功能:单片机向74HC595发送一帧数据(一个数据字节,一个位选字节)入口参数:dat--数码管显示的数据;position--数码管位置返回值:无************************************************/void send_595_fram(unsigned char position,unsigned char dat){STCP=0; //锁存时钟拉低send_595_byte(position); //串行写入数码管位置信息send_595_byte(dat); //串行写入数据信息STCP=1; //锁存时钟拉高,产生上升沿,将锁存的数据输出到管脚上}/*************************************************函数名:ds1302_595_display( )函数功能:将处理完的时间信息显示到数码管上入口参数:无返回值:无************************************************/void ds1302_595_display(){unsigned char j;for(j=0;j<8;j++){send_595_fram(pos[j],seg[time[j]]); //显示一帧函数delay_ms(2); //延时2ms}}/*************************************************函数名:main( )函数功能:主程序入口参数:无返回值:无************************************************/void main(){unsigned char i;unsigned char flag; //设置标志位,存放在RAM的0xc0地址内ds1302_disp_init(); //初始化单片机和ds1302及74HC595的接口delay_ms(100); //等待初始化完毕flag=ds1302_read_byte(0xc1); //上电后读取RAM的0xc0地址的字节// if(flag!=0x01) //判断读出的数据是否是上次写入的值,如果是,就说明ds1302没断电。
实验四SPI总线的DS1302实时钟控制一、实验目的1、了解电子电路PROTEUS软件的在单片机方面的仿真使用2、掌握具有SPI总线DS1302、MAX7219芯片的使用及编程二、实验要求在PROTEUS环境下,利用DS1302实时钟芯片实现时间、日期的显示,并且具有调节时间、日期的功能,显示用共阴极LED显示。
用串行芯片MAX7219驱动LED显示.实现此功能的电路原理图如下所示:1、显示“星期”的共阳极二极管接到单片机的P0口,P0口数据线接上拉电阻;2、显示“时间”或“日期”,是采用MAX7219控制共阴极LED来实现3、DS1302的IO脚接单片机的P1.1,时钟信号SCLK接单片机P1.0,复位信号/RST接单片机P1.2。
DS1302的晶振在这里可以不接,电源、地线都省略。
4、MAX7219是用来驱动“时间”或“日期”的LED显示的。
MAX7219的DIN信号脚接单片机的P2.0,/LOAD接单片机的P2.1,CLK接单片机的P2.2;5、时间/日期的调整:按下调整键,再分别按相应的“星期”、“年”、“月”、“日”,“时”、“分”、“秒“键,即可以调整时间/日期;6、在正常显示时,按下“时间/日期“切换键,即可以在显示时间或日期来回切换。
三、PROTEUS环境下的硬件设计1、打开PROTEUS ISIS,在PROTEUS ISIS编辑窗口中单击列表上的“P”按钮,添加下列元器件:元件名称所属类AT89C51 Microprocessor ICSCRYSTAL 晶振MisecllaneousCAP 电容CapacitorRES 电阻ResistorDS1302 Microprocessor ICS7SEG-COM-ANODE共阳极OptoeletronicsBUTTON按键Switches&relaysMAX7129 Microprocessor ICSRESPACK-7排阻Resistor一、软件设计#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit A7=ACC^7;sbit A0=ACC^0;sbit clk=P1^0; //注意P要大写,DS1302的信号脚的连接sbit dat=P1^1;sbit rst=P1^2;sbit DIN=P2^0; //max7219sbit LOAD=P2^1; //max7219sbit CLK=P2^2; //max7219/*--------------------------------------------------------------------------------------------------------------- MAX7219寄存器宏定义---------------------------------------------------------------------------------------------------------------*/#define DECODE_MODE 0x09 //译码控制寄存器#define INTENSITY 0x0A //亮度控制寄存器#define SCAN_LIMIT 0x0B //扫描界限寄存器#define SHUT_DOWN 0x0C //关断模式寄存器#define DISPLAY_TEST 0x0F //测试控制寄存器bit flag=0; //调整控制标记bit flagh=1; //时间日期切换标记uchar temp[7]; //调整前的时间uchar curtime1[8],curtime2[8]; //调整后的时间显示模式uchar tab1[]={58,59,23,31,8,2,10}; //DS1302初始化时间uchar xingqi; //读取的星期uchar code tab2[]={0xff,0xf9,0xA4,0xb0,0x99,0x92,0x82,0xf8}; //显示星期的共阴极LED uchar code tab3[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x60}; //PROTEUS显示时间窗口的代码uchar code tab4[]={0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b,0x01};/*--------------------------------------------------------------------------------------------------------------- 此函数是向MAX7219写数据(操作字或者显示数据)address是内部寄存器的地址;dat是操作字或者显示的数据---------------------------------------------------------------------------------------------------------------*/ void Write_7219(uchar address,uchar dat){ uchar i;ACC=address;LOAD=0; //拉低片选线,选中器件//发送地址for (i=0;i<8;i++) //移位循环8次{CLK=0; //清零时钟总线DIN=A7; //每次取最高位送max7219CLK=1; //时钟上升沿,发送地址address<<=1; //左移一位}ACC=dat; //发送数据for (i=0;i<8;i++){CLK=0;DIN=A7;CLK=1; //时钟上升沿,发送数据dat<<=1;}LOAD=1; //发送结束,上升沿锁存数据}/*--------------------------------------------------------------------------------------------------------------- 这个是MAX7219的初始化程序DECODE_MODE 0x09 //译码控制寄存器INTENSITY 0x0A //亮度控制寄存器SCAN_LIMIT 0x0B //扫描界限寄存器SHUT_DOWN 0x0C //关断模式寄存器DISPLAY_TEST 0x0F //测试控制寄存器---------------------------------------------------------------------------------------------------------------*/ void Init_7219(void){Write_7219(SHUT_DOWN,0x01); //开启正常工作模式(0xX1)Write_7219(DISPLAY_TEST,0x00); //选择工作模式(0xX0)Write_7219(DECODE_MODE,0x00); //选用不译码模式Write_7219(SCAN_LIMIT,0x07); //8只LED全用Write_7219(INTENSITY,0x04); //设置初始亮度}/*--------------------------------------------------------------------------------------------------------------- 这个程序是往DS1302写一个字节的数据dd是要写的数据---------------------------------------------------------------------------------------------------------------*/ void Write_1302_byte(uchar dd) //写一个字节到1302中{uchar i;ACC=dd;for(i=8;i>0;i--){clk=0;dat=A0;clk=1;ACC>>=1;}}/*--------------------------------------------------------------------------------------------------------------- 这个程序是从DS1302中读取一个字节数据将得到的数据存到累加器中最后将数据存到dd 中---------------------------------------------------------------------------------------------------------------*/ uchar Get_1302_byte(void) //从DS1302中读到i个数据{uchar i;dat=1;for(i=8;i>0;i--){clk=0;ACC>>=1; //右移1位A7=dat; //dat=p1.1,先读出的是低位数据clk=1;}return(ACC);}/*--------------------------------------------------------------------------------------------------------------- 单字节写,向DS1302某地址写入命令或者数据,先写地址,后写命令或者数据addr为地址,num为要写入的命令或者数据---------------------------------------------------------------------------------------------------------------*/ void write_1302(uchar addr,uchar num){rst=0;clk=0;rst=1;Write_1302_byte(addr); //写地址Write_1302_byte(num); //写数据clk=1;rst=0;}/*--------------------------------------------------------------------------------------------------------------- 单字节读,从DS1302某地址读出数据,先写地址,后读命令或者数据addr为地址,将数据存到time中---------------------------------------------------------------------------------------------------------------*/ uchar read_1302(uchar addr){uchar time;rst=0;clk=0;rst=1;Write_1302_byte(addr);time=Get_1302_byte();clk=1;rst=0;return(time);}/*--------------------------------------------------------------------------------------------------------------- 设置1302时间即向时间寄存器中多字节一起写入时间{0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; 向时间寄存器中写初始时间的初始地址将数组tab1中的初始值写入DS1302中---------------------------------------------------------------------------------------------------------------*/ void set_rtc(uchar tab[]){ uchar ucaddr=0x80; //向时间寄存器中写初始时间的初始地址uchar a,i;write_1302(0x8e,0x00); //去除写保护for(i=0;i<7;i++){ a=tab[i]/10; //将十进制数转换为BCD码tab[i]=tab[i]%10;tab[i]=tab[i]+a*16;write_1302(ucaddr,tab[i]);//curtime[i]可用指针形式:*curtime,再加一个curtime++,即可ucaddr+=2;}write_1302(0x8e,0x80); //添加写保护}/*--------------------------------------------------------------------------------------------------------------- 这个函数是将1302的时间寄存器中的数据多字节一起读出,放到curtime数组里{0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};从时间寄存器中读数据的初始地址将读出的数据放到数组curtime中---------------------------------------------------------------------------------------------------------------*/ void get_1302() //将1302的时间寄存器中的数据多字节一起读出,放到curtime数组里{ uchar ucaddr=0x81; //从时间寄存器中读数据的初始地址uchar i=0;//for(i=0;i<7;i++)while(i<7){temp[i]=read_1302(ucaddr);ucaddr+=2;i++;}}/*--------------------------------------------------------------------------------------------------------------- 将读出的时间BCD码转换为十进制数显示将星期数单独取出,将年月日数取出放到curtime1中,将时分秒数取出放到curtime2中---------------------------------------------------------------------------------------------------------------*/ void chuli(){uchar a,j=0;uchar i=0;for(i=0;i<7;i++){a=temp[i]/16;temp[i]=temp[i]%16;temp[i]=temp[i]+a*10; //将BCD码转换为十进制数}xingqi=temp[5]; //将星期数单独取出for(i=2;i>0;i--) //将年月日数取出放到curtime1中{curtime1[j]=temp[i]/10;curtime1[++j]=temp[i]%10;curtime1[++j]=10;j++;}curtime1[j]=temp[0]/10;curtime1[++j]=temp[0]%10;j=0;curtime2[j]=temp[6]/10;curtime2[++j]=temp[6]%10;for(i=4;i>2;i--) //将时分秒数取出放到curtime2中{curtime2[++j]=10;curtime2[++j]=temp[i]/10;curtime2[++j]=temp[i]%10;}}void main(void){uchar i;P3=0xff;Init_7219(); //初始化MAX7219set_rtc(tab1); //初始化DS1302for(i=0;i<222;i++);for(i=0;i<222;i++);while(1){ get_1302();chuli();if(flagh) //如果切换键被按下{i=1; //从第一位数码管开始显示while(i<9){Write_7219(i,tab4[curtime1[i-1]]);i++;}}else{i=1; //从第一位数码管开始显示while(i<9){Write_7219(i,tab4[curtime2[i-1]]);i++;}}P0=tab2[xingqi];if(flag){if(p30==0){temp[5]++;if(temp[5]>=8)temp[5]=1;while(p30==0);}if(p31==0){temp[6]++;if(temp[6]>=99)temp[6]=11;while(p31==0);}if(p32==0){temp[4]++;if(temp[4]>=13)temp[4]=1;while(p32==0);}if(p33==0){temp[3]++;if(temp[3]>=32)temp[3]=1;while(p33==0);}if(p34==0){temp[2]++;if(temp[2]>=24)temp[2]=0;while(p34==0);}if(p35==0){temp[1]++;if(temp[1]>=60)temp[1]=0;while(p35==0);}set_rtc(temp); //调整好时间,将调整好的时间送入DS1302}if(p37==0){flag=~flag;if(flag){temp[0]=0;write_1302(0x80,0x80); //将DS1302暂停,开始调整时间}elsewrite_1302(0x80,0x00); //调整结束,时钟开始走while(p37==0);}if(p36==0){flagh=~flagh;while(p36==0);}}}。