[资料分享] 最近闲来无事,调试了一下时钟芯片DS1302程序,挺好使

zhtong19860109   2010-10-19 16:19 楼主

调试好使的程序。

以下是调试的主要程序:

#include<avr/io.h>
#include<util/delay.h>
#include "HW.h"

//#define BURST_MODE

#define DS1302_DDR   DDRB
#define DS1302_PORT  PORTB
#define DS1302_PIN   PINB
#define DS1302_DDRCS   DDRD
#define DS1302_PORTCS  PORTD
#define DS1302_CK    PB7
#define DS1302_IO   PB6
#define DS1302_CE   PD2

#define delay_bus(x) _delay_loop_1(x*2)

static inline void ds1302_select(void)
{
  DS1302_PORTCS|=BIT(DS1302_CE);
  delay_bus(2);
}

static inline void ds1302_unselect(void)
{
  DS1302_PORTCS&=~BIT(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 & BIT(DS1302_IO))
      ret|=0x80;
   
    //给一脉冲
    DS1302_PORT|=BIT(DS1302_CK); 
    delay_bus(1); 
    DS1302_PORT&=~BIT(DS1302_CK);
   
    delay_bus(1);
  }
  return ret;
}

//实现写一字节时序
static void ds1302_write_byte(uint8_t dat)
{
  uint8_t i;
 
  //IO口设置为输出
  DS1302_DDR|=BIT(DS1302_IO);
  DS1302_PORT&=~BIT(DS1302_IO);

  for(i=0;i<8;i++)
  {
    //设置好数据口
    if(dat& 0x01)
      DS1302_PORT|=BIT(DS1302_IO);
    else
      DS1302_PORT&=~BIT(DS1302_IO);
     
    delay_bus(1);
   
    //给一脉冲
    DS1302_PORT|=BIT(DS1302_CK);
    delay_bus(1); 
    DS1302_PORT&=~BIT(DS1302_CK);
   
    dat>>=1; 
  } 
  //IO口恢复到输入状态
  DS1302_PORT&=~BIT(DS1302_IO); 
  DS1302_DDR&=~BIT(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=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);
  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& BIT(4))
      m=10;
    else
      m=0;
   
    if(h&BIT(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_DDRCS |= BIT(DS1302_CE);
  DS1302_DDR|=BIT(DS1302_CK);
  DS1302_PORTCS &=~(BIT(DS1302_CE));
  DS1302_PORT&=(BIT(DS1302_CK)|BIT(DS1302_IO));
  DS1302_DDR&=~BIT(DS1302_IO); 

  if(rtc_read_reg(0) & 0x80)//如果处于暂停状态
  {
    rtc_write_reg(7,0);//写允许
    rtc_write_reg(0,0);//运行
    rtc_write_reg(7,0x80);//写保护
  } 
}

回复评论 (9)

你这程序好使吗?
点赞  2010-10-19 16:23
大哥,这个程序我下来运行一下,有点出入啊,能不能把最完整的程序给我啊,谢谢了~
我爱电子!
点赞  2010-10-19 16:23

回复 沙发 月黑杀人夜 的帖子

那必须得,朋友你有兴趣调吗?
点赞  2010-10-19 16:25
这是最终版?怎么感觉少了些什么啊!
点赞  2010-10-19 16:25

回复 板凳 jjkwz 的帖子

行,你的邮箱号
点赞  2010-10-19 16:26

回复 5楼 wangpengdy 的帖子

恩,只是上传了部分程序,把你的邮箱号发给我吧。
点赞  2010-10-19 16:28

回复 6楼 zhtong19860109 的帖子

kdfjk@163.com
太谢谢大哥了!
我爱电子!
点赞  2010-10-19 16:29

回复 8楼 jjkwz 的帖子

给你发过去了
点赞  2010-10-19 16:30

DS1302跑时误差怎么修正呢?

点赞  2020-1-28 20:05
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复