蓝桥杯(单片机组)学习笔记(六)--------DS1302

家住魔仙堡 提交于 2020-02-15 01:58:44

1.DS1302

DS1302是低功耗实时时钟芯片,它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。主要特点是采用串行数据传输,可为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。
1.引脚分析
在这里插入图片描述
原理图在这里插入图片描述
DS1302是BCD码作为编码方式的,而且是压缩BCD码,8位表示0-99整数(Year = 99),7位表示0-79整数(Sec、Min = 60),6位表示0-49整数(Hour = 24、Date = 31),5位表示0-19整数(Month = 12),4位表示0-9整数(WeekDay = 7)。DS1302是变种SPI,通过SCLK和I/O相互配合,发送和接收信息。SCLK在上升沿前,主机通过I/O口发送数据,DS1302在上升沿是接收;SCLK在下降沿后,DS1302通过I/O口发送数据,主机接收。

使用同步串行通讯简化了DS1302 与微处理器的接口。与时钟/RAM 通讯只需要三根线: CE(也是原理图上的RST,SDA)(读写时必须保持高电平),I/O (数据线), and SCLK (串行时钟)。

2.寄存器结构
在这里插入图片描述如上图,命令字启动每一次数据传输. MSB (位 7)必须是逻辑1. 如果是 0,则禁止对DS1302写入. 位 6 在逻辑0时规定为时钟/日历数据,逻辑1时为RAM数据.位 1 至 位 5 表示了输入输出的指定寄存器.LSB (位 0) 在逻辑0时为写操作(输出),逻辑1时为读操作(输入).命令字以LSB (位 0)开始总是输入.
在这里插入图片描述
由于读出来的是BCD码。BCD 的表示法是用4个二进制位来表示 一个十进制位,(就是2进制转化成10进制)也就是一个字节(16位)能够表示2个十进制数位,这是一种压缩的十进制表示方式,应用很广,最常见的就是CMOS里的时间存放格式就是BCD码格式。低四位的值就是实现十进制数的低四,高4位就是高四位的值,这样我们有很高效的转换方法:低四位+高四位×10 (上面是2位十进制数的)。
举例来说就是:如15用BCD码表示为 0001 0101;
明白了BCD是怎么表示后转换也就容易了,低4位和高4位分别转换然后合并起来就是了!低四位+高四位×10 (上面是2位十进制数的)。当然由于我们数码管上也要一位一位取,就不用高四位×10了,取出来就好了~~

2.时序分析
在这里插入图片描述
二.利用官方给的驱动程序
我们只需要把figure3上面的图搞清楚就好了
在这里插入图片描述
由此可知,写保护 可写是Ds1302_Single_Byte_Write(0XBE,0X00);写保护不可写Ds1302_Single_Byte_Write(0XBE,0X80);
附上全部代码~今天是2月14日耶,祝大家情人节快乐HEIHEI

#include <STC12C5A60S2.H>
#include "ds1302.h"
typedef unsigned char uchar;
typedef unsigned int uint;
uchar code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};
uchar dsbuff[]= {10,10,10,10,10,10,10,10};//存数码管各位的显示符号,10就是关掉,11就是-
uchar discom=0;//位选
uchar S_time[7] = {0x50,0x09,0x19,0x14,0x02,0X00,0x20};//设置时间数(把第五位跳过)
uchar G_time[7] = {0};//保存时间组

void dstime_nyr();
void dstime_sfm();
void get_time();
void set_time();
void smg_Timer0Init();
void All_Init();


void All_Init()
{
	P2 = (P2&0X1F|0X80);
	P0 = 0XFF;
	
	P2 = (P2&0X1F|0XA0);
	P0 = 0X00;
	
	P2 =(P2&0X1F|0XC0);
	P0 = 0X00;
	
	P2 = (P2&0X1F|0XE0);
	P0 = 0XFF;
}

void Delay_ms(uint ms)
{
	uint i,j;
	
	for(i = ms;i >0; i--)
		for(j = 845;j>0;j--);
}


void display()//2ms刷新一次
{
	P2=(P2&0x1f)|0xe0;//顺序不能错
	P0=0xff;//循环进来一次要把段清零
	P2&=0x1f;
	
	P2=(P2&0x1f)|0xc0;//位选
	P0=1<<discom;
	
	P2&=0x1f;//段选
	P2=(P2&0x1f)|0xe0;
	P0=tab[dsbuff[discom]];
	
	P2&=0x1f;
	if(++discom==8)discom=0;
}


void main(void)
{
	All_Init();//初始化
	smg_Timer0Init();//初始化数码管
	set_time();//设置时间
	
	while(1)
	{
		get_time();
	}
}

void smg_Timer0Init(void)		//2毫秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x40;		//设置定时初值
	TH0 = 0xA2;		//设置定时初值
	EA = 1;
	ET0 = 1;
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void smg_time()interrupt 1//每2毫秒进一次中断
{
	static uint n1 = 0;
	
	if(n1 <4000)dstime_sfm();//4000*2ms= 8s 显示8s的时分秒
	else dstime_nyr();//1000*2ms = 2s 显示2s的年月日
	
	if(++n1 == 5000)n1 = 0;
	
	display();//每2ms刷新一次数码管
}

void set_time()//设置时间
{
	char i = 0;
	Ds1302_Single_Byte_Write(0x8E,0X00);//写保护可写
	for(i = 0;i < 7;i++)
	{
		Ds1302_Single_Byte_Write(0x80+i*2,S_time[i]);
	}//依次设置秒、分、时...
	Ds1302_Single_Byte_Write(0X8E,0X80);//写保护不可写
}

void get_time()//获取时间
{
	char i = 0;
	for(i = 0;i<7;i++)
	{
		G_time[i] = Ds1302_Single_Byte_Read(0x81+i*2);
		Delay_ms(5);//延时
	}
}

void dstime_sfm()//显示时间
{
	//BCD转码
	dsbuff[6] = G_time[0]>>4;//秒十位
	dsbuff[7] = G_time[0]&0x0F;//秒个位
	
	dsbuff[5] = 11;//-
	
	dsbuff[3] = G_time[1]>>4;//分十位
	dsbuff[4] = G_time[1]&0x0F;//分个位
	
	dsbuff[2] = 11;//-
	
	dsbuff[0] = G_time[2]>>4;//时十位
	dsbuff[1] = G_time[2]&0x0F;//时个位
}

void dstime_nyr()//显示年月日
{
	dsbuff[6] = G_time[3]>>4;//日十位
	dsbuff[7] = G_time[3]&0x0F;//日个位
	
	dsbuff[5] = 11;//-
	
	dsbuff[3] = G_time[4]>>4;//月十位
	dsbuff[4] = G_time[4]&0x0F;//月个位
	
	dsbuff[2] = 11;//-
	
	dsbuff[0] = G_time[6]>>4;//年十位  注意这里把DAY跳过了
	dsbuff[1] = G_time[6]&0x0F;//年个位
}

特别要注意这个display(),跟我之前的风格有很大的变化,特别是要先对这个段选清零。

超声波

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!