调试好使的程序。
以下是调试的主要程序:
#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);//写保护
}
}
DS1302跑时误差怎么修正呢?