DS1302的程序(适应AVR,含星期自动计算功能)

 最近在做DS1302,上网搜了一堆程序出来,好用得没几个:(
调了半天终于弄出个程序好用的,可以自动计算2000年~2099年中任意一天是星期几。
经过MEGA128上的测试,目前没发现问题,现在发上来,请各位大虾帮忙测试一下。
另外我现在的程序只能做2000年~2099年中的星期计算,现在想做个任意年份的星期计算,一直没找到合适的算法,(有一个叫“蔡勒公式”的,但我按他写的程序就是不好用,可能是我太苯了)还望各位大虾不吝赐教。

虽然是在MEGA64上调的但适用于所有AVR芯片,改下管脚设置就行了。

程序不是我原创,我只是把我找到的DS1302程序和星期计算程序做了下修改使他们能适应我的系统能一起工作而已,在此向写这些程序的原作者表示敬意。

http://blog.csdn.net/zhenhua10 添加日期时间修正程序

#define nop() asm("nop;" ::);

struct timechar
{
uchar nowyear;
uchar nowmonth;
uchar nowday;
uchar nowhour;
uchar nowminute;
uchar nowsecond;
uchar nowweek;
};
struct timechar nowtime;///这里存时间   


#define ds1302_rst   7                     /*!PORTB7 DS1302实时时钟复位线引脚 */
#define ds1302_io   6                      /*!PORTB6 DS1302实时时钟数据线引脚 */   
#define ds1302_sclk  5                      /*!PORTB5 DS1302实时时钟时钟线引脚 */

#define set_ds1302_rst_ddr()  DDRB|=1<<ds1302_rst
#define set_ds1302_rst()        PORTB|=1<<ds1302_rst
#define clr_ds1302_rst()        PORTB&=~(1<<ds1302_rst)

#define set_ds1302_io_ddr()   DDRB|=1<<ds1302_io
#define clr_ds1302_io_ddr()    DDRB&=~(1<<ds1302_io)
#define set_ds1302_io()          PORTB|=1<<ds1302_io
#define clr_ds1302_io()          PORTB&=~(1<<ds1302_io)
#define in_ds1302_io()          PINB&(1<<ds1302_io)

#define set_ds1302_sclk_ddr() DDRB|=1<<ds1302_sclk
#define set_ds1302_sclk()        PORTB|=1<<ds1302_sclk
#define clr_ds1302_sclk()         PORTB&=~(1<<ds1302_sclk)

#define ds1302_sec_reg        0x80
#define ds1302_min_reg        0x82
#define ds1302_hr_reg           0x84
#define ds1302_date_reg         0x86
#define ds1302_month_reg       0x88
#define ds1302_day_reg        0x8a
#define ds1302_year_reg        0x8c
#define ds1302_control_reg      0x8e
#define ds1302_charger_reg    0x90
#define ds1302_clkburst_reg   0xbe

uchar BcdToBin(uchar val)
  {
  val = (val >> 4) *10+(val &0x0f); ///将BCD码转换为10进制数
  return val; ///返回10进制数
  }

uchar BinToBcd(uchar val)
  {
  return ((val / 10) *16+val % 10);
  }

void ds1302_write(uchar reg, uchar data)
  {
  uchar i = 0;
  set_ds1302_io_ddr();
  nop();
  nop();
  clr_ds1302_rst();
  nop();
  nop();
  clr_ds1302_sclk();
  nop();
  nop();
  set_ds1302_rst();
  nop();
  nop();
  for (i = 8; i > 0; i--)
    {
    if (reg &0x01)
    {
      set_ds1302_io();
    }
    else
    {
      clr_ds1302_io();
    }
    nop();
    nop();
    set_ds1302_sclk();
    nop();
    nop();
    clr_ds1302_sclk();
    nop();
    nop();
    reg >>= 1;
    }
  for (i = 8; i > 0; i--)
    {
    if (data &0x01)
    {
      set_ds1302_io();
    }
    else
    {
      clr_ds1302_io();
    }
    nop();
    nop();
    set_ds1302_sclk();
    nop();
    nop();
    clr_ds1302_sclk();
    nop();
    nop();
    data >>= 1;
    }
  clr_ds1302_rst();
  nop();
  nop();
  clr_ds1302_io_ddr();
  nop();
  nop();
  }
uchar ds1302_read(uchar reg)
  {
  uchar data = 0;
  uchar i = 0;
  reg += 1; ///读标志
  set_ds1302_io_ddr();
  nop();
  nop();
  clr_ds1302_rst();
  nop();
  nop();
  clr_ds1302_sclk();
  nop();
  nop();
  set_ds1302_rst();
  nop();
  nop();
  for (i = 8; i > 0; i--)
    {
    if (reg &0x01)
    {
      set_ds1302_io();
    }
    else
    {
      clr_ds1302_io();
    }
    nop();
    nop();
    set_ds1302_sclk();
    nop();
    nop();
    clr_ds1302_sclk();
    nop();
    nop();
    reg >>= 1;
    }
  clr_ds1302_io_ddr();
  nop();
  nop();
  for (i = 8; i > 0; i--)
    {
    data >>= 1;
    if (in_ds1302_io())
    {
      data |= 0x80;
    }
    nop();
    nop();
    set_ds1302_sclk();
    nop();
    nop();
    clr_ds1302_sclk();
    nop();
    nop();
    }
  clr_ds1302_rst();
  nop();
  nop();
  return (data);
  }
uchar check_ds1302(void)
  {
  ds1302_write(ds1302_control_reg, 0x80);
  if (ds1302_read(ds1302_control_reg) == 0x80)
  {
    return 1;
  }
  return 0;
  }
void ds1302_read_time(void)
  {
  uchar tmphour;
  nowtime.nowyear = BcdToBin(ds1302_read(ds1302_year_reg)); ///年
  nowtime.nowmonth = BcdToBin(ds1302_read(ds1302_month_reg)); ///月
  nowtime.nowday = BcdToBin(ds1302_read(ds1302_date_reg)); ///日
  nowtime.nowweek = BcdToBin(ds1302_read(ds1302_day_reg)); ///周
  tmphour = ds1302_read(ds1302_hr_reg); ///时
  nowtime.nowhour = (tmphour &0b00100000) / 32 * 20+(tmphour &0x10) / 16 * 10+(tmphour &0x0F);
  nowtime.nowminute = BcdToBin(ds1302_read(ds1302_min_reg)); ///分
  nowtime.nowsecond = BcdToBin(ds1302_read(ds1302_sec_reg)); ///秒
  }

/*!------------------------------------------------------------------------------
                                2000年~2099年星期算法
-------------------------------------------------------------------------------*/
unsigned char WeekDay20(unsigned char y, unsigned char m, unsigned char d)

  unsigned char A;
  if (m==1||m==2)
  {
  m+=12;
  y--;
  }
  A= (d+2*m+3* (m+1) /5+y+y/4-y/100+y/400+1) %7;
  return A;

}

//===============================================
//名称:Date_Correct()
//描述: 日期时间修正子程序
//参数:
//作者:zhenhua   http://blog.csdn.net/zhenhua10
//===============================================
void Date_Correct(struct timechar * bTime)
 { 
  if(bTime->nowyear>99)
    bTime->nowyear=99;
  if(bTime->nowmonth>12)
    bTime->nowmonth =12;
  if(bTime->nowmonth==2)
  {
    if(bTime->nowyear%4==0&&bTime->nowday>29)
       bTime->nowday = 29;//闰年
    else if(bTime->nowday>28)
    bTime->nowday = 28;
  }
  if(bTime->nowday>31&&(bTime->nowmonth==1||bTime->nowmonth==3||bTime->nowmonth==5||bTime->nowmonth==7||
     bTime->nowmonth==8||bTime->nowmonth==10||bTime->nowmonth==12))
 bTime->nowday = 31;
  if(bTime->nowday>30&&(bTime->nowmonth==4||bTime->nowmonth==5||bTime->nowmonth==6||bTime->nowmonth==9||
     bTime->nowmonth==11))
 bTime->nowday = 30;

  if(bTime->nowmonth==0)
    bTime->nowmonth=1;
  if(bTime->nowday==0)
    bTime->nowday=1;

  if(bTime->nowhour>=24)
    bTime->nowhour=0;
  if(bTime->nowminute>=60)
    bTime->nowminute=0;
  if(bTime->nowsecond>=60)
    bTime->nowsecond=0;   
 }

 

void ds1302_write_time(void)
  {
  uchar bcdyear;
  uchar bcdmonth;
  uchar bcdday;
  uchar bcdhour;
  uchar bcdminute;
  uchar bcdsecond;
  uchar bcdweek;

  Date_Correct(&nowtime);//日期时间修正

  bcdyear = BinToBcd(nowtime.nowyear);
  bcdmonth = BinToBcd(nowtime.nowmonth);
  bcdday = BinToBcd(nowtime.nowday);
  bcdhour = BinToBcd(nowtime.nowhour);
  bcdminute = BinToBcd(nowtime.nowminute);
  bcdsecond = BinToBcd(nowtime.nowsecond);
   
  nowtime.nowweek=WeekDay20(nowtime.nowyear,nowtime.nowmonth,nowtime.nowday);
  bcdweek = BinToBcd(nowtime.nowweek);
   
  ds1302_write(ds1302_control_reg, 0x00); ///关闭写保护
  ds1302_write(ds1302_sec_reg, 0x80); ///暂停
  ds1302_write(ds1302_day_reg, bcdweek); ///周   
  ds1302_write(ds1302_charger_reg, 0xa9); ///涓流充电
  ds1302_write(ds1302_year_reg, bcdyear); ///年
  ds1302_write(ds1302_month_reg, bcdmonth); ///月
  ds1302_write(ds1302_date_reg, bcdday); ///日
  ds1302_write(ds1302_hr_reg, bcdhour); ///时
  ds1302_write(ds1302_min_reg, bcdminute); ///分
  ds1302_write(ds1302_sec_reg, bcdsecond); ///秒
  ds1302_write(ds1302_control_reg, 0x80); ///打开写保护
  }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以下代码为转载:

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

主程序文件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<avr/io.h>
#include<util/delay.h>

//#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<x;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<x;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

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值