主程序文件rtc.c
/********************************
AVR单片机I/O口操作DS1302接口程序
文件名:rtc.c
编译:WinAVR-20070525
硬件:ATMEGA169PV 时钟:7372800 Hz
SCLK <---- PE5
CE <---- PE3
IO <---> PE4
此程序在硬件上调试通过!
芯艺设计室 2004-2007 版权所有
转载请保留本注释在内的全部内容
WEB: http://www.chipart.cn
Email: changfutong@sina.com
*******************************/
#include
#include
//#define BURST_MODE
#define DS1302_DDR DDRE
#define DS1302_PORT PORTE
#define DS1302_PIN PINE
#define DS1302_CK PE5
#define DS1302_IO PE4
#define DS1302_CE PE3
#define delay_bus(x) _delay_loop_1(x*2)
static inline void ds1302_select(void)
{
DS1302_PORT|=_BV(DS1302_CE);
delay_bus(2);
}
static inline void ds1302_unselect(void)
{
DS1302_PORT&=~_BV(DS1302_CE);
delay_bus(2);
}
//实现读一字节时序
static uint8_t ds1302_read_byte(void)
{
uint8_t i,ret=0;
for(i=0;i<8;i++)
{
ret>>=1;
if(DS1302_PIN & _BV(DS1302_IO))
ret|=0x80;
//给一脉冲
DS1302_PORT|=_BV(DS1302_CK);
delay_bus(1);
DS1302_PORT&=~_BV(DS1302_CK);
delay_bus(1);
}
return ret;
}
//实现写一字节时序
static void ds1302_write_byte(uint8_t dat)
{
uint8_t i;
//IO口设置为输出
DS1302_DDR|=_BV(DS1302_IO);
DS1302_PORT&=~_BV(DS1302_IO);
for(i=0;i<8;i++)
{
//设置好数据口
if(dat& 0x01)
DS1302_PORT|=_BV(DS1302_IO);
else
DS1302_PORT&=~_BV(DS1302_IO);
delay_bus(1);
//给一脉冲
DS1302_PORT|=_BV(DS1302_CK);
delay_bus(1);
DS1302_PORT&=~_BV(DS1302_CK);
dat>>=1;
}
//IO口恢复到输入状态
DS1302_PORT&=~_BV(DS1302_IO);
DS1302_DDR&=~_BV(DS1302_IO);
delay_bus(1);
}
//读寄存器 addr: 0~8
uint8_t rtc_read_reg(uint8_t addr)
{
uint8_t ret;
addr<<=1;
addr|=0x81;
ds1302_select();
ds1302_write_byte(addr);
ret=ds1302_read_byte();
ds1302_unselect();
return ret;
}
//写寄存器
void rtc_write_reg(uint8_t addr,uint8_t dat)
{
addr<<=1;
addr|=0x80;
ds1302_select();
ds1302_write_byte(addr);
ds1302_write_byte(dat);
ds1302_unselect();
}
//读RAM
//在多字节(BURST)模式下读取 x 长度的数据到buf指向的存储区
//在单字节模式下从地址为x(0~31)的RAM中读一字节存储到buf处
void rtc_read_ram(uint8_t x,uint8_t *buf)
{
#ifdef BURST_MODE
uint8_t i;
ds1302_select();
ds1302_write_byte(0xff); //read burts ram
for(i=0;i
buf[i]=ds1302_read_byte();
ds1302_unselect();
#else
x<<=1;
x|=0xc1;
ds1302_select();
ds1302_write_byte(x);
*buf=ds1302_read_byte();
ds1302_unselect();
#endif
}
//写RAM
//在多字节(BURST)模式下写 x 长度的数据到DS1302内部RAM,从0地址开始写
//在单字节模式下在地址为x(0~31)的RAM片写入一字节数据
void rtc_write_ram(uint8_t x,uint8_t *buf)
{
#ifdef BURST_MODE
uint8_t i;
#endif
rtc_write_reg(7,0);//写使能
#ifdef BURST_MODE
ds1302_select();
ds1302_write_byte(0xfe); //write burts ram
for(i=0;i
ds1302_write_byte(buf[i]);
ds1302_unselect();
#else
x<<=1;
x|=0xc0;
ds1302_select();
ds1302_write_byte(x);
ds1302_write_byte(*buf);
ds1302_unselect();
#endif
rtc_write_reg(7,0x80);//写禁止
}
//读取时钟 将读取的时钟以小时,分钟,秒的顺序存入time指向的缓冲区
//读出的数据为二进制格式,而非BCD码
void rtc_get_time(uint8_t *time)
{
uint8_t s,m=0,h;
h=rtc_read_reg(2);
if(h & 0x80)//12小时制
{
if(h& _BV(4))
m=10;
else
m=0;
if(h&_BV(5))
m+=12;
h=m+(h&0x0f);
}
else //24小时制
{
h&=0x3f;
h= (h>>4)*10 + (h & 0x0f);
}
s=rtc_read_reg(0) & 0x7f;
m=rtc_read_reg(1) & 0x7f;
time[2]= (s>>4)*10 + (s & 0x0f);
time[1]= (m>>4)*10 + (m & 0x0f);
time[0]= h;
}
//设置时钟,time中的时钟格式为:时,分,秒二进制式
void rtc_set_time(uint8_t *time)
{
uint8_t h,m,s;
h=time[0]%24;
m=time[1]%60;
s=time[2]%60;
//二进制转BCD
h=((h/10)<<4) + (h%10);
m=((m/10)<<4) + (m%10);
s=((s/10)<<4) + (s%10);
rtc_write_reg(7,0);//write enable
rtc_write_reg(0,s);
rtc_write_reg(1,m);
rtc_write_reg(2,h);
rtc_write_reg(7,0x80);//write disable
}
//读日历 将读取的日历以年,月,日的顺序存入date指向的缓冲区
//读出的数据为二进制格式,而非BCD码
void rtc_get_date(uint8_t *date)
{
uint8_t y,m,d;
y=rtc_read_reg(6);
m=rtc_read_reg(4)& 0x1f;
d=rtc_read_reg(3)& 0x3f;
//BCD转二进制
date[0]=(y>>4)*10 + (y&0x0f);
date[1]=(m>>4)*10 + (m&0x0f);
date[2]=(d>>4)*10 + (d&0x0f);
}
//设置日历
void rtc_set_date(uint8_t *date)
{
uint8_t y,m,d;
//二进制转BCD码
y=((date[0]/10)<<4) + (date[0]%10);
m=((date[1]/10)<<4) + (date[1]%10);
d=((date[2]/10)<<4) + (date[2]%10);
//写入DS1302
rtc_write_reg(7,0);
rtc_write_reg(6,y);
rtc_write_reg(4,m);
rtc_write_reg(3,d);
rtc_write_reg(7,0x80);
}
//读周
void rtc_get_day(uint8_t *day)
{
*day=rtc_read_reg(5) & 0x07;
}
//设置周
void rtc_set_day(uint8_t *day)
{
rtc_write_reg(7,0);
rtc_write_reg(5,(*day)&0x07);
rtc_write_reg(7,0x80);
}
//初始化接口和各寄存器
void rtc_init(void)
{
//CE,CK口设置为输出,IO口设置为输入
DS1302_DDR|=_BV(DS1302_CE)|_BV(DS1302_CK);
DS1302_PORT&=~(_BV(DS1302_CE)|_BV(DS1302_CK)|_BV(DS1302_IO));
DS1302_DDR&=~_BV(DS1302_IO);
if(rtc_read_reg(0) & 0x80)//如果处于暂停状态
{
rtc_write_reg(7,0);//写允许
rtc_write_reg(0,0);//运行
rtc_write_reg(7,0x80);//写保护
}
//... ... 这里你可以检查涓流充电配置并设置寄存器
}
包含头文件 rtc.h
//rtc.h
#ifndef RTC_H
#define RTC_H
uint8_t rtc_read_reg(uint8_t addr);
void rtc_write_reg(uint8_t addr,uint8_t dat);
void rtc_read_ram(uint8_t x,uint8_t *buf);
void rtc_write_ram(uint8_t x,uint8_t *buf);
void rtc_get_time(uint8_t *time);
void rtc_set_time(uint8_t *time);
void rtc_get_date(uint8_t *date);
void rtc_set_date(uint8_t *date);
void rtc_get_day(uint8_t *day);
void rtc_set_day(uint8_t *day);
void rtc_init(void);
//注:此套接口函数中表示寄存器或RAM的地址为偏移地址而不是数据手册中的命令字
//如秒寄存器的地址为0 而不是0x80或0x81
#endif
|
|