📄 ds1302.c
字号:
/****************************************************************************************
DS1302的mega8控制程序
程序功能:该程序是用AVR来控制对ds1302
读写信号等的操作.
硬件连接:分配PC1=SCLK,PC2=I/O,PC3=RST
三个I/O口分别作为时钟、数据、复位
的控制。
显示部分用12864液晶来显示时时时间
作者:张国旗
2008年12月31号
****************************************************************************************/
#define uchar unsigned char
#define uint unsigned int
#define TRUE 1
#define FALSE 0
//=========RTC常量=================
#define RTC_DDR DDRC
#define RTC_PORT PORTC
#define RTC_CLK PC1 //时钟
#define RTC_DATA PC2 //数据
#define RTC_CS PC3 //复位
//============命令=================
#define RD 0x01
#define WR 0x00
#define C_SEC 0x80 //秒
#define C_MIN 0x82 //分
#define C_HR 0x84 //时
#define C_DAY 0x86 //日
#define C_MTH 0x88 //月
#define C_WK 0x8A //星期 DATE
#define C_YR 0x8C //年
#define C_WP 0x8E //控制(写保护)
#define C_CHARGE 0x90 //涓流充电
#define C_BURST 0xBE //时钟多字节
//===========配置================
#define CLK_HALT 0x80 //停止时钟控制位 SECOND bit7
#define CLK_START 0x00 //启动时钟
#define M12_24 0x80 //12/24小时值选择位 HOUR bit7
#define PROTECT 0x80 //写保护控制位 CONTROL bit7
#define UPROTECT 0x00 //写保护控制位 CONTROL bit7
//=========涓流充电控制常量======
#define TC_D1R2 0xA5 //high 1 Diode +2K Resistors
#define TC_D2R8 0xAB //low 2 Diodes+8K Resistors
#define TC_DISABLED 0x00 //Disabled(TCS<>1010 or DS=00 or RS=00)
//=========RAM 命令=============
#define C_RAMBASE 0xC0 //RAM0~RAM30<<1 地址需左移一位
//===================延时函数========================
//5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
//1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
//==================================================
void Delayus(uint US)
{
uint i;
US=US*5/4; //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<US;i++);
}
void Delayms(uint MS)
{
uint i,j;
for( i=0;i<MS;i++)
for(j=0;j<1141;j++); //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
/*******************************************
函数名称: DS1302_init
功 能: 初始化DS1302的数据接口
参 数: 无
返回值 : 无
/********************************************/
void DS1302_portinit(void)
{
RTC_DDR|=BIT(RTC_CLK)|BIT(RTC_DATA)|BIT(RTC_CS);
//将时钟端(RTC_CLK)数据端(RTC_DATA)片选端(RTC_CS)设置为输出
}
/*******************************************
函数名称: DS1302_writeB
功 能: 向DS1302写入一个字节数据(没有RST操作)
参 数: byte--要写入的数据
返回值 : 无
********************************************/
void DS1302_writeB(uchar byte)
{
uchar i;
for(i=0;i<8;i++) //8位数据计数
{
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端
if(byte&0x01) //当前位是否是1
{
RTC_PORT|=BIT(RTC_DATA); //当前位是1,拉高数据端
}
else
{
RTC_PORT&=~BIT(RTC_DATA); //当前位是0,拉低数据端
}
Delayus(10); //调整时钟和脉冲宽度
RTC_PORT|=BIT(RTC_CLK); //时钟上升沿(DS1302采样数据)
byte>>=1; //数据右移1位,为送出新数据位做准备
}
}
/*******************************************
函数名称: DS1302_readB
功 能: 从DS1302读出一个字节数据(没有RST操作)
参 数: 无
返回值 : byte--读出的数据
********************************************/
uchar DS1302_readB(void)
{
uchar i,byte=0;
RTC_DDR&=~BIT(RTC_DATA); //将数据端口设置为输入
RTC_PORT&=~BIT(RTC_DATA); //无上拉电阻
for(i=0;i<8;i++) //8位数据计数
{
byte>>=1; //保存读入的数据位
RTC_PORT|=BIT(RTC_CLK); //时钟上升沿
Delayus(10); //延时,调整时钟脉冲宽度
RTC_PORT&=~BIT(RTC_CLK); //时钟下降沿,DS1302输出数据位
Delayus(10); //等待数据变化(MEGA16太快,必须等待DS1302的数据位输出,否则不能正确读出)
if(PINC&BIT(RTC_DATA)) //当前位是否是高电平
{
byte|=BIT(PB7); //是高电平就将返回数据的当前位置1
}
else
{
byte&=~BIT(PB7); //是低电平就将返回数据的当前位置0
}
}
RTC_DDR|=BIT(RTC_DATA); //最后将数据端口设置为输出
return byte; //返回读出的数据
}
/*******************************************
函数名称: DS1302_writeD
功 能: 向DS1302的某个地址写入一个字节数据
参 数: addr--地址值(寄存器或RAM)
data--要写入的地址
返回值 : 无
/********************************************/
void DS1302_writeD(uchar addr,uchar data)
{
{
RTC_PORT&=~BIT(RTC_CS); //拉低片选端
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端
Delayus(10);
RTC_PORT|=BIT(RTC_CS); //拉高片选端
Delayus(10); //调整片选脉冲
DS1302_writeB(addr); //写入操作命令(地址)
Delayus(10);
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端
Delayus(10);
DS1302_writeB(data); //写入数据
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端
Delayus(10); //调整片选脉冲
RTC_PORT&=~BIT(RTC_CS); //拉低片选端
}
}
/*******************************************
函数名称: DS1302_readD
功 能: 从DS1302的某个地址读出一个字节数据
参 数: addr--地址值(寄存器或RAM)
返回值 : data--读出的数据
********************************************/
uchar DS1302_readD(uchar addr)
{
uchar data;
RTC_PORT&=~BIT(RTC_CS); //拉低片选端
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端
Delayus(10);
RTC_PORT|=BIT(RTC_CS); //拉高片选端
Delayus(10); //调整片选脉冲
DS1302_writeB(addr); //写入操作命令(地址)
Delayus(10);
data=DS1302_readB(); //读出数据
Delayus(10);
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端
RTC_PORT&=~BIT(RTC_CS); //拉低片选端
return data; //返回读出的数据
}
/*******************************************
函数名称: DS1302_setT
功 能: 设置DS1302的时间
参 数: ptTimeD--设置时间数组指针
返回值 : 无
********************************************/
void DS1302_setT(uchar ptTimeD[])
{
uchar i;
uchar addr = 0x80; //写入地址从秒寄存器开始
DS1302_writeD(C_WP|WR,UPROTECT); //控制命令,WP位为0,允许写操作
Delayms(5);
for(i=0;i<7;i++)
{
DS1302_writeD(addr|WR,ptTimeD[i]); // 秒 分 时 日 月 星期 年
addr+=2;
Delayms(1);
}
DS1302_writeD(C_WP|WR,PROTECT); //控制命令,WP位为1,不允许写操作
}
/*******************************************
函数名称: DS1302_getT
功 能: 读取DS1302的当前时间
参 数: time[]--读取的时间数组
返回值 : 无
********************************************/
void DS1302_getT(uchar time[])
{
uchar i;
/*=======下面的是单次读写===================
uchar addr = 0x80; //读取地址从秒寄存器开始
for(i=0;i<7;i++)
{
time[i]=DS1302_readD(addr|RD); // 秒 分 时 日 月 星期 年
addr+=2;
}
===========================================*/
//=========下面是多字节读取================
RTC_PORT&=~BIT(RTC_CS); //拉低片选端
Delayus(10);
RTC_PORT|=BIT(RTC_CS); //拉高片选端
Delayus(10); //调整片选脉冲
DS1302_writeB(0xbf); // 0xbf:时钟多字节读取命令
for (i=0;i<8;i++) //时间数据的存放格式是:
{ //秒,分,时,日,月,星期,年,控制
time[i]=DS1302_readB(); //【7个数据(BCD格式)+1个控制】
}
RTC_PORT&=~BIT(RTC_CS); //拉低片选端
//======================================
RTC_PORT&=~BIT(RTC_CLK); //拉低时钟端(时钟端在不操作时为低)
}
/*******************************************
函数名称: DS1302_check
功 能: 检测DS1302是否正常工作
参 数: 无
返回值 : exist--为TRUE为检测到DS1302,为FALSE为没检测到
/********************************************/
uchar DS1302_check(void)
{
uchar exist;
DS1302_writeD(C_WP|WR,UPROTECT); //写入写允许命令
DS1302_writeD(C_RAMBASE|WR,0xA5); //RAM0写入0xA5
exist=DS1302_readD(C_RAMBASE|RD); //读取RAM0
if(exist==0xA5)
{
exist=TRUE; //如果读取值与写入值相等,返回TRUE
}
else
{
exist=FALSE; //如果读取值与写入值不相等,返回FALSE
}
return exist;
}
/*******************************************
函数名称: DS1302_init
功 能: 初始化DS1302
参 数: 无
返回值 : 无
********************************************/
void DS1302_init(void)
{
DS1302_writeD(C_WP|WR,UPROTECT); //写入写允许命令
DS1302_writeD(C_SEC|WR,CLK_START); //启动振荡器,DS1302开始工作
DS1302_writeD(C_WP|WR,PROTECT); //控制命令,WP位为1,不允许写操作
}
/*******************************************
函数名称: BCD_ASCII
功 能: 将压缩BCD码转换成ascii码
参 数: BCD--将要转换的压缩BCD码
ptasc--转换后的ASCII码数组指针
返回值 : 无
/********************************************/
void BCD_ASCII(uchar BCD,uchar ptasc[])
{
ptasc[0]=BCD/16|0x30; //0X58 35 38 //转换十位
ptasc[1]=BCD&0x0F|0x30; //转换个位
}
/*******************************************
函数名称: Disp_time
功 能: 在1602液晶上显示当前时间(第1行格式:年-月-日 星期;第2行格式:时-分-秒)
参 数: time[]--时间数组
返回值 : 无
/********************************************/
void Disp_time(uchar time[])
{
unsigned int vstrtemp,i;
unsigned int vstr[8];
vstr[0] = time[3]/16+0x30;
vstr[1] = time[3]%16+0x30;
vstr[2] = '/';
vstr[3] = time[4]/16+0x30;
vstr[4] = time[4]%16+0x30;
vstr[5] = '/';
vstr[6] = time[6]/16+0x30;
vstr[7] = time[6]%16+0x30;
WriteCommand(0x30); //时间显示起始坐标
WriteCommand(0x92);
for(i=0;i<8;i++)
{
vstrtemp=vstr[i];
WriteData(vstrtemp);
}
vstr[0] = time[2]/16+0x30;
vstr[1] = time[2]%16+0x30;
vstr[2] = ':';
vstr[3] = time[1]/16+0x30;
vstr[4] = time[1]%16+0x30;
vstr[5] = ':';
vstr[6] = time[0]/16+0x30;
vstr[7] = time[0]%16+0x30;
WriteCommand(0x30); //时间显示起始坐标
WriteCommand(0x8a);
for(i=0;i<8;i++)
{
vstrtemp=vstr[i];
WriteData(vstrtemp);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -