⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ds1302.h

📁 使用ATmega32驱动DS1302
💻 H
字号:
/******************************************************************** 
 功            能:DS1302 IO口模拟串行时钟 读写程序
 说            明:MCU:atmage32  8M
 设            计:   
 修            改:蔡春晓
 日            期:2009.05.09
********************************************************************/

#ifndef _DS1302_H
#define _DS1302_H

#include <iom32v.h>
#include <macros.h>

#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif

//ds1302显示变量,可以在主程序上调用
unsigned char year;//年
unsigned char month;//月
unsigned char week;
unsigned char date;//日
unsigned char hour;//时
unsigned char minute;//分
unsigned char second;//秒

//ds1302端口定义
#define DS1302_PORT PORTD
#define DS1302_INPORT PIND
#define	DS1302_DDR	DDRD
#define DS1302_RST  PD7
#define DS1302_IO   PD6
#define DS1302_SCLK PD5

//ds1302操作定义
#define Set_ds1302_rst_ddr()  DS1302_DDR |=BIT(DS1302_RST)
#define Set_ds1302_rst()      DS1302_PORT|=BIT(DS1302_RST) 
#define Clr_ds1302_rst()      DS1302_PORT &=~ BIT(DS1302_RST)
	
#define Set_ds1302_io_ddr()   DS1302_DDR|=BIT(DS1302_IO) 
#define Clr_ds1302_io_ddr()   DS1302_DDR&=~ BIT(DS1302_IO) 
#define Set_ds1302_io()       DS1302_PORT|=BIT(DS1302_IO) 
#define Clr_ds1302_io()       DS1302_PORT&=~ BIT(DS1302_IO) 
#define In_ds1302_io()        DS1302_INPORT&=~ BIT(DS1302_IO) 
	
#define Set_ds1302_sclk_ddr() DS1302_DDR |=BIT(DS1302_SCLK)
#define Set_ds1302_sclk()     DS1302_PORT|=BIT(DS1302_SCLK) 
#define Clr_ds1302_sclk()     DS1302_PORT&=~ BIT(DS1302_SCLK) 

//ds1302相关寄存器定义	
#define 	ds1302_second_reg 0x80 
#define 	ds1302_minute_reg 0x82 
#define 	ds1302_hour_reg 0x84
#define 	ds1302_date_reg 0x86 
#define 	ds1302_month_reg 0x88 
#define 	ds1302_week_reg 0x8a 
#define 	ds1302_year_reg 0x8c 
#define 	ds1302_control_reg 0x8e 
#define 	ds1302_charger_reg 0x90 
#define 	ds1302_clkburst_reg 0xbe 


//函数原型的声明
void Ds1302_PORT_init(void);
void Ds1302_initral(void);
void Ds1302_writebyte(uchar data);
unsigned char Ds1302_readbyte(void);
void Ds1302_write(unsigned char ucAddr, unsigned char ucDa);
unsigned char Ds1302_read(unsigned char ucAddr);
void Ds1302_read_time(unsigned char *ptr);
void Ds1302_Set(uchar y,uchar m,uchar d,uchar h,uchar f,uchar s, uchar w);
unsigned char Check_ds1302(void);
void Delay1302(void);
unsigned char Bcd2Hex(unsigned char data);
unsigned char Hex2Bcd(unsigned char data);



//函数的定义

/***************************************************
//DS1302端口初始化程序
***************************************************/
void Ds1302_PORT_init(void)
{
	Clr_ds1302_rst(); //把RST的PORT变为低,如果为输入,即有上拉;如果为输出,即拉低RST(停止传输)
	Set_ds1302_rst_ddr(); //RST设置为默认的输出

	Clr_ds1302_sclk(); //把时钟的PORT变为低,如果为输入,即有上拉;如果为输出,即拉低时钟(当前空闲)
	Set_ds1302_sclk_ddr(); //时钟设置为默认的输出

	Set_ds1302_io_ddr(); //把IO设置为默认的输出

}

/***************************************************
//初始化DS1302内部程序
***************************************************/
void Ds1302_initral(void)
{
	unsigned char sec;
	Ds1302_write(ds1302_control_reg,0x00);   //关闭写保护
	sec = Ds1302_read(ds1302_second_reg); //先读出second 处理完之后在回送回去
											 //这样保证秒不丢失
	Ds1302_write(ds1302_second_reg,0x80);    //暂停     
	Ds1302_write(ds1302_charger_reg,0xa9);   //涓流充电 2个2极管2k电阻

	Ds1302_write(ds1302_second_reg,sec&0x7f); //启动振荡
	Ds1302_write(ds1302_control_reg,0x80);    //打开写保护		
}


/**************************************************
//往DS1302写一个字节
**************************************************/
void Ds1302_writebyte(uchar data)//往DS1302写一个字节
{  
	unsigned char  i;

	for(i=0; i<8;i++) 
	{ 
		Clr_ds1302_sclk(); //先拉低,代表空闲(其实进入时应该是低的)
		Delay1302();

		if(data&BIT(i))
			Set_ds1302_io();
		else
			Clr_ds1302_io();

		Set_ds1302_sclk(); //写字节时,最后的高电平应该保持
		Delay1302();		
	}	  
} 

/**************************************************
//从DS1302中读出一个字节
**************************************************/	    
unsigned char Ds1302_readbyte(void) //时序上,这个函数是紧跟着 Ds1302_writebyte() 的
{
	unsigned char i,k,AA=0;    

	Clr_ds1302_io_ddr(); //IO口变成输入,其他的仍保持
                         //Ds1302_writebyte() 退出时:RST 为高,时钟为高
	for(i=0; i<8; i++) 
	{
		Clr_ds1302_sclk(); //拉低时钟,造成下降沿
		Delay1302();

		k = (DS1302_INPORT & BIT(DS1302_IO));    //读数据,从低位开始  
		if(k)  
			AA |= BIT(i);  
		else  
			AA &= ~ BIT(i); 

		Set_ds1302_sclk(); //拉高时钟,待会拉低,造成下降沿,最后退出for时是拉高
		Delay1302();		
	}  
	return(AA);  
} 

/**************************************************
//往DS1302的某地址写一个字节的内容
**************************************************/
void Ds1302_write(unsigned char ucAddr, unsigned char ucDa) 
{ 
	Ds1302_PORT_init(); //先通过拉低RST,设置为默认的输出,表示停止输出
	Delay1302();        //再拉低时钟,表示空闲,时钟设置为默认的输出
	                    //把IO设置为默认的输出
	Set_ds1302_rst();  //拉高RST,准备传输
	Delay1302();       //我觉得可以把这个语句放到 Ds1302_writebyte() 函数中,放在外面更具可观性
                       //毕竟写中包含:1、写地址;2、写内容,是一个整体,RST为高贯穿于整个过程
	Ds1302_writebyte(ucAddr);       // 地址,命令

	Delay1302();

	Ds1302_writebyte(ucDa);         // 写1字节数据 

	Ds1302_PORT_init(); //端口回到默认状态

} 	

/**************************************************
//从DS1302的某地址读出一个字节
**************************************************/	
unsigned char Ds1302_read(unsigned char ucAddr) 
{ 
	unsigned char ucData,AA;

	ucAddr |= BIT(0); //读出时,校正地址的最低位为1,因为define时只定义了写的地址,最低位置1变成读地址

	Ds1302_PORT_init(); //端口进入到默认状态
	Delay1302();        //RST 拉低,设为输出,表示停止输出;时钟拉低,设为输出,表示当前空闲;IO设为输出

	Set_ds1302_rst();  // 拉高RST,准备传输
	Delay1302();

	Ds1302_writebyte(ucAddr);             // 地址,命令 
	Delay1302();

	//由写字节出来时,时钟仍是高的,即是处于第8个时钟周期的高电平阶段
	//注意,不能丢失第8个时钟周期的下降沿,否则读取出错
	//即必须要进入 Ds1302_readbyte() 后,才能把时钟拉低,并且读出此下降沿时的DS1302输出字节的低位

	ucData = Ds1302_readbyte();         // 读1字节数据  
	Delay1302();

	Ds1302_PORT_init(); //端口进入到默认状态

	return(ucData); 
} 


/************************************************************
//读出当前时间程序
//分别读出当前的年月日、时分秒、星期(BCD码)
//把他们转换成二进制代码,例如 59秒 读出时为 0x59 转换成0x3b(等于十进制的59)
//并且赋值给相应的数组(长度为7字节)
*************************************************************/
void Ds1302_read_time(unsigned char *ptr) //ptr为指向数组首地址的指针
{
	year = Bcd2Hex(Ds1302_read(ds1302_year_reg)); //BCD变成二进制
	month = Bcd2Hex(Ds1302_read(ds1302_month_reg));
	date = Bcd2Hex(Ds1302_read(ds1302_date_reg));

	week = Bcd2Hex(Ds1302_read(ds1302_week_reg));

	hour = Bcd2Hex(Ds1302_read(ds1302_hour_reg));
	minute = Bcd2Hex(Ds1302_read(ds1302_minute_reg));
	second = Bcd2Hex(Ds1302_read(ds1302_second_reg));

	*ptr++=year; *ptr++=month; *ptr++=date; 
	*ptr++=hour; *ptr++=minute; *ptr++=second;
	*ptr++=week;
}


/********************************************************************************
//DS1302设置程序 
// y,m,d,h,f,s,w分别为压缩bcd码
//                 年      月      日      时      分     秒      星期
********************************************************************************/
void Ds1302_Set(uchar y,uchar m,uchar d,uchar h,uchar f,uchar s, uchar w)                 
{	
	Ds1302_write(ds1302_control_reg,0x00);   //关闭写保护
	//s = Ds1302_read(ds1302_second_reg); //先读出second 处理完之后再回送回去
											 //这样保证秒不丢失,没用(在初始化时要用)
	Ds1302_write(ds1302_second_reg,0x80);    //暂停     
	Ds1302_write(ds1302_charger_reg,0xa9);   //涓流充电 2个2极管2k电阻
			
	Ds1302_write(ds1302_year_reg,y);   //年
	Ds1302_write(ds1302_month_reg,m);  //月
	Ds1302_write(ds1302_date_reg,d);   //日
	Ds1302_write(ds1302_hour_reg,h);   //时
	Ds1302_write(ds1302_minute_reg,f); //分
	Ds1302_write(ds1302_second_reg,s); //秒

	Ds1302_write(ds1302_week_reg,w);  //星期中的第几天,如0x01代表星期一
	
	Ds1302_write(ds1302_second_reg,s&0x7f); //启动振荡,同时也是秒的设置 与0x7f是去掉最高的无用位
	Ds1302_write(ds1302_control_reg,0x80);    //打开写保护		
}

/**************************************************
//DS1302设备的检查
**************************************************/
unsigned char Check_ds1302(void) 
{ 
	Ds1302_write(ds1302_control_reg,0x80); 
	if(Ds1302_read(ds1302_control_reg)==0x80)
		return 1; 
	else
		return 0; 
} 

/**************************************************
//scLk延时
**************************************************/				
void Delay1302(void)
{
	//16条NOP() 指令,即使外部晶振为16MHz,传输频率也变成了1MHz
	 //而且还有其他的开销
	NOP();	NOP();	NOP();	NOP(); //4*4
	NOP();	NOP();	NOP();	NOP();
	NOP();	NOP();	NOP();	NOP();
	NOP();	NOP();  NOP();  NOP();
}

/**************************************************
//由BCD变成二进制
**************************************************/
unsigned char Bcd2Hex(unsigned char data) 
{
	uchar y;
	y = ((data&0xf0)>>4)*10+(data&0x0f);
	return(y);
}

/**************************************************
//data<99,由二进制变成BCD
//好像这里也没有用到
**************************************************/
unsigned char Hex2Bcd(unsigned char data);
unsigned char Hex2Bcd(unsigned char data)
{                                        
	uchar y;
	y = (data/10<<4) | data%10;
	return(y);	
}

#endif







⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -