📄 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 + -