产品概述

单片机DS 教你玩单片机之DS1302

小编 2024-11-24 产品概述 23 0

教你玩单片机之DS1302

以下所有内容仅适合新手,大神请勿介意哈,如有错误,麻烦大家指正,不喜勿喷。

DS1302简介

DS1302是一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。工作电压宽达2.5~5.5V。采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后备电源进行涓细电流充电的能力。

DS1302的引脚排列,其中Vcc2为主电源,VCC1为后备电源。在主电源关闭的情况下,也能保持时钟的连续运行。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.0V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向),后面有详细说明。SCLK为时钟输入端。 下图为DS1302的引脚功能图:

原理图

DS1302是通过SPI串行总线跟单片机通信的,当进行一次读写操作时最少得读写两个字节,第一个字节是控制字节,就是一个命令,告诉DS1302是读还是写操作,是对RAM还是对CLOK寄存器操作。第二个字节就是要读或写的数据了。

单字节读

只有在SCLK为低电平时,才能将CE置为高电平。所以在进行操作之前先将SCLK置低电平,然后将CE置为高电平,接着开始在IO上面放入要传送的电平信号,然后跳变SCLK。数据在SCLK上升沿时,DS1302读取数据,在SCLK下降沿时,DS1302放置数据到IO上

单字节写

只有在SCLK为低电平时,才能将RST置为高电平。说以在进行操作之前先将SCLK置低电平,然后将RST置为高电平,开始在IO上面放入要传送的电平信号,然后跳变SCLK。数据在SCLK上升沿时,DS1302读取数据,在SCLK下降沿时,DS1302放置数据到IO上

DS1302的时钟寄存器

时钟/日历包含在7个寄存器中,数据在时钟/日历寄存器中是二进制编码的十进制格式存储的,也就是常说的BCD码存储的。

时钟寄存器的第8个字节是写保护寄存器。当WP为“1”的时候是开启写保护,这个时候是禁止对DS1302进行写操作的。当WP为“0”的时候是关闭写保护,这个时候才能对DS1302进行写操作。

因为万年历程序过长,所以,需要看程序的朋友,可以进入我的主页查看文章:《单片机之DS1302万年历实验程序》

单片机之DS1302万年历实验程序

这篇文章是接上一篇《教你玩单片机之DS1302》的内容,有不明白的朋友可以进入我的主页,看我之前发的内容,不喜勿喷。

万年历实验

实验效果 :1602显示时钟,按K3进入时钟设置,按K1选择设置的时分秒日月,按K2选择设置加1。

主程序

#include<reg51.h>

#include"lcd.h"

#include"ds1302.h"

sbit K1=P3^1;

sbit K2=P3^0;

sbit K3=P3^2;

sbit K4=P3^3;

void Int0Configuration();

void LcdDisplay();

unsigned char SetState,SetPlace;

void Delay10ms(void); //误差 0us

void main()

{

unsigned char i;

Int0Configuration();

LcdInit();

Ds1302Init();

while(1)

{

if(SetState==0)

{

Ds1302ReadTime();

}

else

{

if(K1==0)//检测按键K1是否按下

{

Delay10ms();//消除抖动

if(K1==0)

{

SetPlace++;

if(SetPlace>=7)

SetPlace=0;

}

while((i<50)&&(K1==0)) //检测按键是否松开

{

Delay10ms();

i++;

}

i=0;

}

if(K2==0)//检测按键K2是否按下

{

Delay10ms();//消除抖动

if(K2==0)

{

TIME[SetPlace]++;

if((TIME[SetPlace]&0x0f)>9) //换成BCD码。

{

TIME[SetPlace]=TIME[SetPlace]+6;

}

if((TIME[SetPlace]>=0x60)&&(SetPlace<2))//分秒只能到59

{

TIME[SetPlace]=0;

}

if((TIME[SetPlace]>=0x24)&&(SetPlace==2))//小时只能到23

{

TIME[SetPlace]=0;

}

if((TIME[SetPlace]>=0x32)&&(SetPlace==3))//日只能到31

{

TIME[SetPlace]=0;

}

if((TIME[SetPlace]>=0x13)&&(SetPlace==4))//月只能到12

{

TIME[SetPlace]=0;

}

if((TIME[SetPlace]>=0x7)&&(SetPlace==5))//周只能到7

{

TIME[SetPlace]=1;

}

//if(SetPlace==5)//月只能到12

//{

//TIME[SetPlace]=;

//}

}

while((i<50)&&(K2==0)) //检测按键是否松开

{

Delay10ms();

i++;

}

i=0;

}

}

LcdDisplay();

}

}

void LcdDisplay()

{

LcdWriteCom(0x80+0X40);

LcdWriteData('0'+TIME[2]/16);//时

LcdWriteData('0'+(TIME[2]&0x0f));

LcdWriteData('-');

LcdWriteData('0'+TIME[1]/16);//分

LcdWriteData('0'+(TIME[1]&0x0f));

LcdWriteData('-');

LcdWriteData('0'+TIME[0]/16);//秒

LcdWriteData('0'+(TIME[0]&0x0f));

LcdWriteCom(0x80);

LcdWriteData('2');

LcdWriteData('0');

LcdWriteData('0'+TIME[6]/16);//年

LcdWriteData('0'+(TIME[6]&0x0f));

LcdWriteData('-');

LcdWriteData('0'+TIME[4]/16);//月

LcdWriteData('0'+(TIME[4]&0x0f));

LcdWriteData('-');

LcdWriteData('0'+TIME[3]/16);//日

LcdWriteData('0'+(TIME[3]&0x0f));

LcdWriteCom(0x8D);

LcdWriteData('0'+(TIME[5]&0x07));//星期

}

void Int0Configuration()

{

//设置INT0

IT0=1;//跳变沿出发方式(下降沿)

EX0=1;//打开INT0的中断允许。

EA=1;//打开总中断

}

void Int0() interrupt 0

{

Delay10ms();

if(K3==0)

{

SetState=~SetState;

SetPlace=0;

Ds1302Init();

}

}

void Delay10ms(void) //误差 0us

{

unsigned char a,b,c;

for(c=1;c>0;c--)

for(b=38;b>0;b--)

for(a=130;a>0;a--);

}

#include"lcd.h"

#include"lcd.h"

void Lcd1602_Delay1ms(uint c) //误差 0us

{

uchar a,b;

for (; c>0; c--)

{

for (b=199;b>0;b--)

{

for(a=1;a>0;a--);

}

}

}

#ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时

void LcdWriteCom(uchar com) //写入命令

{

LCD1602_E = 0; //使能

LCD1602_RS = 0; //选择发送命令

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = com; //放入命令

Lcd1602_Delay1ms(1);//等待数据稳定

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5); //保持时间

LCD1602_E = 0;

}

#else

void LcdWriteCom(uchar com) //写入命令

{

LCD1602_E = 0; //使能清零

LCD1602_RS = 0; //选择写入命令

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = com;//由于4位的接线是接到P0口的高四位,所以传送高四位不用改

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

//Lcd1602_Delay1ms(1);

LCD1602_DATAPINS = com << 4; //发送低四位

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

}

#endif

#ifndef LCD1602_4PINS

void LcdWriteData(uchar dat)//写入数据

{

LCD1602_E = 0;//使能清零

LCD1602_RS = 1;//选择输入数据

LCD1602_RW = 0;//选择写入

LCD1602_DATAPINS = dat; //写入数据

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5); //保持时间

LCD1602_E = 0;

}

#else

void LcdWriteData(uchar dat)//写入数据

{

LCD1602_E = 0; //使能清零

LCD1602_RS = 1; //选择写入数据

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = dat;//由于4位的接线是接到P0口的高四位,所以传送高四位不用改

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

LCD1602_DATAPINS = dat << 4; //写入低四位

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

}

#endif

#ifndefLCD1602_4PINS

void LcdInit() //LCD初始化子程序

{

LcdWriteCom(0x38); //开显示

LcdWriteCom(0x0c); //开显示不显示光标

LcdWriteCom(0x06); //写一个指针加1

LcdWriteCom(0x01); //清屏

LcdWriteCom(0x80); //设置数据指针起点

}

#else

void LcdInit() //LCD初始化子程序

{

LcdWriteCom(0x32); //将8位总线转为4位总线

LcdWriteCom(0x28); //在四位线下的初始化

LcdWriteCom(0x0c); //开显示不显示光标

LcdWriteCom(0x06); //写一个指针加1

LcdWriteCom(0x01); //清屏

LcdWriteCom(0x80); //设置数据指针起点

}

#endif

#include"ds1302.h"

#include"ds1302.h"

//---DS1302写入和读取时分秒的地址命令---//

//---秒分时日月周年 最低位读写位;-------//

uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};

uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//

//---存储顺序是秒分时日月周年,存储格式是用BCD码---//

uchar TIME[7] = {0, 0, 0x12, 0x01, 0x01, 0x02, 0x13};

void Ds1302Write(uchar addr, uchar dat)

{

uchar n;

RST = 0;

_nop_();

SCLK = 0;//先将SCLK置低电平。

_nop_();

RST = 1; //然后将RST(CE)置高电平。

_nop_();

for (n=0; n<8; n++)//开始传送八位地址命令

{

DSIO = addr & 0x01;//数据从低位开始传送

addr >>= 1;

SCLK = 1;//数据在上升沿时,DS1302读取数据

_nop_();

SCLK = 0;

_nop_();

}

for (n=0; n<8; n++)//写入8位数据

{

DSIO = dat & 0x01;

dat >>= 1;

SCLK = 1;//数据在上升沿时,DS1302读取数据

_nop_();

SCLK = 0;

_nop_();

}

RST = 0;//传送数据结束

_nop_();

}

uchar Ds1302Read(uchar addr)

{

uchar n,dat,dat1;

RST = 0;

_nop_();

SCLK = 0;//先将SCLK置低电平。

_nop_();

RST = 1;//然后将RST(CE)置高电平。

_nop_();

for(n=0; n<8; n++)//开始传送八位地址命令

{

DSIO = addr & 0x01;//数据从低位开始传送

addr >>= 1;

SCLK = 1;//数据在上升沿时,DS1302读取数据

_nop_();

SCLK = 0;//DS1302下降沿时,放置数据

_nop_();

}

_nop_();

for(n=0; n<8; n++)//读取8位数据

{

dat1 = DSIO;//从最低位开始接收

dat = (dat>>1) | (dat1<<7);

SCLK = 1;

_nop_();

SCLK = 0;//DS1302下降沿时,放置数据

_nop_();

}

RST = 0;

_nop_();//以下为DS1302复位的稳定时间,必须的。

SCLK = 1;

_nop_();

DSIO = 0;

_nop_();

DSIO = 1;

_nop_();

return dat;

}

void Ds1302Init()

{

uchar n;

Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能

for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年

{

Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);

}

Ds1302Write(0x8E,0x80); //打开写保护功能

}

void Ds1302ReadTime()

{

uchar n;

for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年

{

TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);

}

}

相关问答

C51 单片机 DS 18B20初始化程序中,初始化函数返回值为1或者0是什么意思,什么用?

里面没有status1这个变量~返回的值的说明,已经说明//返回值ststus是数据线高低电平的意思里面没有status1这个变量~返回的值的说明,已经说明//返回值sts...

【关于51 单片机 ds 18b20led显示问题:18b20采用12位温度转换...

[最佳回答]符号位如果是负数的时候要去补码.百位,个位,十位除以十取余数.小数部分设置一个变量累加起来就行了

ds 18b20占用 单片机 时间怎么解决?

首先你要明白的是,DS18b20用的是单总线通信协议。实现这一协议一般有两种方法,如果单片机带有单总线接口,那么用户无需考虑,用户只需设置相关寄存器,配置通...

如何用51 单片机 读取 ds 18b20的取负温度?求教.18b20的ram中,前...

[最佳回答]判断是否是负,就是取高几位的读取值采用与的方式判断,比如(000)1111100001000,那么高5位可以这样弄,tempH&0x1f,如果这个值=1;说明是负的,否则就...

我需要stc89c52 单片机ds 18b20温度控制的c语言程序,要求可显...

sbitDQ=P1^0;voidusart_init();voidsend_str(char*read_data);voiddelayms(unsignedcharms);voidsend_char(...

多路 DS 18B20与51 单片机 如何连线?依据是什么?求教?

18b20就3根线,1根接地,1根接+5v,1根接单片机io口,很简单,主要是学习读写操作时序18b20就3根线,1根接地,1根接+5v,1根接单片机io口,很简单,主要是学习读写操作...

基于 单片机 msp430和温度传感器 ds 18b20的水温度控制系统的c语...

[最佳回答]我这是用STC做的,应该很容易移植到MPS430上的给你参考一下。#include#include#defineucharunsignedchar#defineuintunsigne...

DS 18B20温度传感器与 单片机 间的通信线(延长线)可以多长 - 15...

加电源或者用寄生模式50-100用5V供电没没问题,只接一支DS18B20最远可以达到500m,18B20单线传输抗干扰能力本来就不高,线最长就几厘米,不管你用什...

用51 单片机 DS 18B20构成的温度检测系统和用热敏电阻加运放...

应该是热敏电阻快,DS18B20硬件比较简单所以需要更多的软件来支持,对时序的要求很重要,每一次采集温度都需要软件来进行启动,所以你的程序越长他的采...

我用c语言写的基于51 单片机 ds 1302芯片1602液晶显示的时钟...

[最佳回答]确定LCD程序没问题的话可以考虑下这个,读不出来,看看初始化对了没,1302到单片机IO口直接加上拉电阻没有,读写时序对了没有,这些搞定了一般就没问题...

猜你喜欢