/*
-----------------------------------------------------------------------------------------
工程:
Test系列工程
环境:
AVR Studio4.17 + WinAVR2010
设备:
Atmega16
作者:
遥远的海
日期:
2015-06-30
说明:
时钟芯片 DS1302
-----------------------------------------------------------------------------------------
*/
//---------------------------
//数据类型
//---------------------------
typedef unsigned char U8; //定义8位无符号数
//---------------------------
//空指令
//---------------------------
#define NOP() __asm("nop") //C 语言中内嵌汇编空指令,起到延时一个指令周期的作用
//PD5 配置为输出,接DS1302时钟信号7脚
#define DS1302_SCLK_L() PORTD&=~0x20 // DS1302时钟信号7脚,M16 PD5低电平
#define DS1302_SCLK_H() PORTD|= 0x20 // DS1302时钟信号7脚,M16 PD5高电平
//PD4 配置为输入、输出,接DS1302数据IO (6)脚
#define DS1302_IO_L() PORTD&=~0x10 //PD4 输出低电平
#define DS1302_IO_H() PORTD|= 0x10 //PD4 输出高电平
#define DS1302_IO_R() (PIND & 0x10) //读取PD4管脚电平状态
#define DS1302_IO_OUT() DDRD |= 0x10 //配置 PD4 口为输出,DS1302 数据线
#define DS1302_IO_IN() DDRD &=~0x10 //配置 PD4 口为输入,DS1302 数据线
//PB7 配置为输出,接DS1302片选5脚
#define DS1302_CE_L() PORTB&=~0x80 //PB7低电平
#define DS1302_CE_H() PORTB|= 0x80 //PB7高电平
//---------------------------
//DS1302控制字
//---------------------------
#define WRITE_SECOND 0x80
#define WRITE_MINUTE 0x82
#define WRITE_HOUR 0x84
#define WRITE_DATE 0x86
#define WRITE_MONTH 0x88
#define WRITE_YEAR 0x8c
#define READ_SECOND 0x81
#define READ_MINUTE 0x83
#define READ_HOUR 0x85
#define READ_DATA 0x87
#define READ_MONTH 0x89
#define READ_YEAR 0x8D
#define WRITE_PROTECT 0x8E
#define WRITE_FLAG 0xD0 //写入RAM区同一个字节的地址
#define READ_FLAG 0xD1 //读取RAM区同一个字节的地址
/*
-----------------------------------------------------------------------------------------
备注:
(1)CE信号只有在时钟线低电平时拉高才有效
(2)由于DS1302输出下拉能力不够,因此AVR读取数据时口线必须配置为输入模式。
(3)DS1302 使用BCD码,读出的数据需要转换成10进制,写入的数据需要转换成BCD码。
-----------------------------------------------------------------------------------------
*/
void DS1302_Write(U8 ucAddr,U8 ucData)
{
U8 m,n,ucTemp;
DS1302_CE_L(); //CE引脚为低,数据传送中止
DS1302_SCLK_L(); //拉低时钟线
NOP();NOP();
DS1302_CE_H(); //CE脚高电平,启动数据传输
NOP();NOP();
DS1302_IO_OUT(); //数据线输出
m=2;
n=8;
ucTemp=ucAddr; //发送数据
while(m--)
{
while(n--) //循环8次移位
{
//向数据线写数据
if(ucTemp & 0x01)
DS1302_IO_H();
else
DS1302_IO_L();
ucTemp>>=1;
NOP();NOP();
//拉高时钟信号产生一个上升沿
DS1302_SCLK_H(); //DS1302在时钟上升沿接收数据
NOP();NOP();
//时钟信号低电平
DS1302_SCLK_L();
NOP();NOP();
}
ucTemp=ucData; //发送数据
n=8;
}
DS1302_CE_L();
}
/*
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
*/
U8 DS1302_Read(U8 ucAddr)
{
U8 n,ucTemp;
DS1302_CE_L(); //CE引脚为低,数据传送中止
DS1302_SCLK_L(); //拉低时钟线
NOP();NOP();
DS1302_CE_H(); //CE脚高电平,启动数据传输
NOP();NOP();
//先发送要读取的地址
DS1302_IO_OUT(); //数据线输出
n=8;
ucTemp=ucAddr; //发送地址
while(n--) //循环8次移位
{
//向数据线写数据
if(ucTemp & 0x01)
DS1302_IO_H();
else
DS1302_IO_L();
ucTemp>>=1;
NOP();NOP();
//拉高时钟信号产生一个上升沿
DS1302_SCLK_H(); //DS1302在时钟上升沿接收数据
NOP();NOP();
//时钟信号低电平
DS1302_SCLK_L();
NOP();NOP();
}
//读取数据
//读取8位数据,在读命令8个SCLK周期之后,
//接下来的8个SCLK周期中的每个脉冲的下降沿DS1302输出数据
DS1302_IO_IN(); //数据线输入
n=8;
ucTemp=0;
while(n--)
{
ucTemp>>=1;
if(DS1302_IO_R()==0x10) //读取数据线电平
ucTemp+=0x80;
NOP();NOP();
//拉高时钟线电平
DS1302_SCLK_H();
NOP();NOP();
//时钟信号低电平,产生一个下降沿,
DS1302_SCLK_L(); //DS1302在时钟下降沿发送数据
NOP();NOP();
}
DS1302_CE_L();
return ucTemp;
}
/*
-----------------------------------------------------------------------------------------
功能:BCD转10进制
输入:
U8* pBCD 待转换的BCD码
输出:
U8* pBCD 待转换的BCD码
返回:
U8
思路:
压缩BCD码一个字符所表示的十进制数据范围为0 ~ 99,进制为100
先求每个字符所表示的十进制值,然后乘以权
备注:
本函数只转换一个字节的BCD码
-----------------------------------------------------------------------------------------
*/
U8 BCDtoDec(U8 BCD)
{
return ((BCD>>4)&0x0F)*10 + (BCD&0x0F);
}
/*
-----------------------------------------------------------------------------------------
功能:十进制转BCD码
输入:
U8 Dec 待转换的十进制数据 Dec<60
输出:
返回:
U8 Bcd 转换后的BCD码
备注:
本函数只转换一个字节的十进制数据
-----------------------------------------------------------------------------------------
*/
//
//////////////////////////////////////////////////////////
U8 DectoBCD(U8 Dec)
{
int temp;
temp = Dec%100;
return ((temp/10)<<4) + ((temp%10) & 0x0F);
}
/*
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
*/
volatile U8 ucSecond;
volatile U8 ucMinute;
volatile U8 ucHour;
void DS1302_ReadTime(void)
{
ucSecond=DS1302_Read(READ_SECOND); //读取秒
ucMinute=DS1302_Read(READ_MINUTE); //读取分钟
ucHour =DS1302_Read(READ_HOUR); //读取小时
ucSecond=BCDtoDec(ucSecond);
ucSecond=DectoBCD(ucSecond);
ucMinute=BCDtoDec(ucMinute);
ucHour=BCDtoDec(ucHour);
}
/*
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
*/
void DS1302_Init(void)
{
U8 ucFlag;
//配置控制管脚
DDRD |= 0x20; //配置 PD5 口为输出,DS1302 时钟信号
DDRD |= 0x10; //配置 PD4 口为输出,DS1302 数据线
DDRB |= 0x80; //配置 PB7 口为输出,DS1302 片选信号
DS1302_CE_H(); //CE 初始高电平
DS1302_IO_L();
DS1302_SCLK_L();
ucFlag=DS1302_Read(READ_FLAG); //读取RAM区标志位数据,如果不是特定的0xaa数据,
//那么就认为电池没电了,时间需要重新更改
if(ucFlag!=0xaa)
{
//注意:写入的数据都是BCD码类型
DS1302_Write(WRITE_PROTECT,0X00); //禁止写保护
DS1302_Write(WRITE_FLAG,0xaa); //RAM区重新写入特定的标志位0xaa
DS1302_Write(WRITE_YEAR,0x15); //年初始化,15年
DS1302_Write(WRITE_MONTH,0x07); //月初始化,7月
DS1302_Write(WRITE_DATE,0x01); //日初始化,1日
DS1302_Write(WRITE_HOUR,0x00); //小时初始化,0点
DS1302_Write(WRITE_MINUTE,0x00); //分钟初始化,0分
DS1302_Write(WRITE_SECOND,0x00); //秒位初始化,0秒
DS1302_Write(WRITE_PROTECT,0x80); //允许写保护
}
}
/*
-----------------------------------------------------------------------------------------
函数:
main
功能:
C 语言主函数
入口:
void
出口:
int
备注:
无
-----------------------------------------------------------------------------------------
*/
int main(void)
{
DS1302_Init();
while(1)
{
DS1302_ReadTime();
}
return 0;
}
/*
-----------------------------------------------------------------------------------------
end of file
-----------------------------------------------------------------------------------------
*/