You are on page 1of 18

C-code:

/* Test program ATmega8 <----> ds1302 */



#i ncl ude <avr/i o.h>
#i ncl ude <avr/i nterrupt.h>
#i ncl ude <stdi o.h>
#i ncl ude <stri ng.h>
#i ncl ude <stdl i b.h>

#i ncl ude "uart.h"
#i ncl ude "del ay.h"

// General setti ngs

// ds1302 connecti on
#defi ne ds1302_PORT PORTA
#defi ne rst 5
#defi ne cl k 6
#defi ne i o 7

#defi ne rst_1() ds1302_PORT |= (1<<rst);
#defi ne rst_0() ds1302_PORT &= ~ (1<<rst);
#defi ne cl k_1() ds1302_PORT |= (1<<cl k);
#defi ne cl k_0() ds1302_PORT &= ~ (1<<cl k);
#defi ne i o_1() ds1302_PORT |= (1<<i o);
#defi ne i o_0() ds1302_PORT &= ~ (1<<i o);


#defi ne mon 1
#defi ne tue 2
#defi ne wed 3
#defi ne thu 4
#defi ne fri 5
#defi ne sat 6
#defi ne sun 7

#defi ne sec_w 0x80
#defi ne sec_r 0x81
#defi ne mi n_w 0x82
#defi ne mi n_r 0x83
#defi ne hour_w 0x84
#defi ne date_r 0x87
#defi ne month_r 0x89
#defi ne day_r 0x8b
#defi ne year_r 0x8d
#defi ne date_w 0x86
#defi ne month_w 0x88
#defi ne day_w 0x8a
#defi ne year_w 0x8c

#defi ne w_protect 0x8e

// Baud rate setti ng
#defi ne BAUD 9600

voi d ds1302_reset(voi d); //ds1302_reset
voi d ds1302_i ni t (voi d); //ds1302 i ni t
voi d wri te(unsi gned char);
unsi gned char read(voi d);
voi d ds1302_wri te_byte(unsi gned char,unsi gned char);
unsi gned char ds1302_read_byte(unsi gned char);

unsi gned char ds1302_read_byte(unsi gned char w_byte) //read the byte wi th regi ster
w_byte
{
unsi gned char temp;
ds1302_reset();
wri te(w_byte);
temp = read();
rst_0(); // fi ni sh transmi tti on
cl k_0();
return temp;
}

voi d ds1302_i ni t(voi d) // sets al l pi ns as output and l ow
{
DDRA |= (1<<rst) | (1<<cl k) | (1<<i o);
cl k_0(); // scl k -> 0
rst_0(); // rst -> 0
i o_0(); // i o -> 0
}

voi d ds1302_reset(voi d) //sets the pi ns to begi n the ds1302 communi cati on
{
cl k_0(); // scl k -> 0
rst_0(); // rst -> 0
rst_1(); // rst -> 1
}

voi d ds1302_wri te_byte(unsi gned char w_byte, unsi gned char w_2_byte) //wri te the
byte wi th regi ster w_byte
{
ds1302_reset();
wri te(w_byte);
wri te(w_2_byte);
rst_0(); // fi ni sh transmi tti on
cl k_0();
}

voi d wri te(unsi gned char W_Byte) //wri tes the W_Byte to the DS1302
{
unsi gned char i ;

DDRA |= (1<<i o); // i o as output -> 1

for(i = 0; i < 8; ++i )
{
i o_0();

i f(W_Byte & 0x01)
{
i o_1();
}
cl k_0();
del ay_us(2);
cl k_1();
del ay_us(2);
W_Byte >>=1;
}
}

unsi gned char read(voi d) //reads the ds1302 repl y
{
unsi gned char i , R_Byte, TmpByte;

R_Byte = 0x00;

DDRA &= ~(1<<i o); // i o as i nput -> 0

for(i = 0; i < 8; ++i ) //get byte
{
cl k_1();
del ay_us(2);
cl k_0();
del ay_us(2);
TmpByte = 0;
i f(bi t_i s_set(PINA,i o))
TmpByte = 1;
TmpByte <<= 7;
R_Byte >>= 1;
R_Byte |= TmpByte;
}
return R_Byte;
}

i nt mai n(voi d)
{
unsi gned char sec, temp;
sec = 0;

// Seri al channel (9600, N,8,1)
uart_i ni t((UART_BAUD_SELECT((BAUD),F_OSC)));

sei (); // i nterrupt enabl e

ds1302_i ni t();

ds1302_wri te_byte(w_protect,0x00); //make sure that the WP bi t i s cl eared
ds1302_wri te_byte(sec_w,0x00); //set seconds to 0

whi l e (1)
{
temp = sec;
sec = ds1302_read_byte(sec_r); //read the seconds

uart_putc(sec); // send byte to seri al l i ne
uart_puts_P( "\r"); // LF

del ay_ms(100);
}
}

barnacle - Jan 28, 2007 - 01:17 PM
Post subject:

Here's some code that works fi ne for me; Wi nAVR.

The .h i ncl ude fi l e
Code:
#i fndef _RTC_H_
#defi ne _RTC_H_

#i ncl ude <avr/i o.h>
#i ncl ude <avr/del ay.h>
#i ncl ude <avr/pgmspace.h>
#i ncl ude <stri ng.h>
#i ncl ude <avr/si gnal .h>
#i ncl ude <avr/i nterrupt.h>
#i ncl ude <avr/eeprom.h>
#i ncl ude <stdi o.h>

#defi ne READ 1
#defi ne WRITE 0

struct rtc_ti me{
char second;
char mi nute;
char hour;
char day;
char month;
char year;
};

voi d rtc_i ni t(voi d);
voi d rtc_comms(unsi gned char * data, char address, char rw);
voi d rtc_get_ti me(struct rtc_ti me *);
voi d rtc_set_ti me(struct rtc_ti me *);
#endi f


and the code

Code:
////////////////////////////////////////////////////////////////////////////////////////////
//
// Real ti me cl ock i nterface
//
// CE -> PA7
// IO -> PA6
// SCLK -> PA5
//
// The DS1302 uses three control si gnal s. Al l data transfers occur on the
// edge of the scl k l i ne; ei ther data i s read from or wri tten to the i o l i ne.
// Data transfers onl y occur when the ce l i ne i s hi gh.
//
// The procedure i s:
// rai se the ce l i ne
// send ei ght bi ts whi ch defi ne the address and r ead/wri te pl us enabl e:
//
// [rw][a0][a1][a2][a3][a4][rc][ 1]
//
// then ei ther send or recei ve the data i tsel f
//
// [d0][d1][d2][d3][d4][d5][d6][d7]
//
// when r/w = 1, the devi ce sends data to the control l er whi ch shoul d be
// sampl ed on the *fal l i ng* edge of scl k
//
// when r/w = 0, the devi ce reads data from the control l er whi ch i s sampl ed
// on the *ri si ng* edge of scl k
//
// after the address and data byte have been sent/recei ved, ce i s dropped agai n.
//
// burst mode i s avai l abl e but i s not used i n thi s project.
//
////////////////////////////////////////////////////////////////////////////////////////////

#i fndef _RTC_
#defi ne _RTC_

#i ncl ude "rtc.h"

#defi ne CE PA7
#defi ne IO PA6
#defi ne SCLK PA5


voi d rtc_i ni t(voi d)
{
// i ni ti al i se the rtc i nterface
// set CE and SCLK as output and set them l ow
// set IO i nput hi gh i mpedance no pul l up

DDRA |= _BV(CE);
DDRA |= _BV(SCLK); // make CE and SCLK as outputs
DDRA &= ~(_BV(IO)); // and IO as i nput

PORTA &= ~(_BV(CE));
PORTA &= ~(_BV(SCLK)); // make CE and SCLK l ow to start

}


voi d rtc_comms(unsi gned char * data, char address, char rw)
{
// read or wri te a si ngl e byte at address
// i f rw = 0, wri te the contents of data
// i f rw = 1, read the contents of address to data
// the ram/~ck control bi t i s passed as the hi gh bi t of the address

unsi gned char control ;
i nt q;

// set up the control byte
control = (address<<1) + 0x80 + rw;

// set CE hi gh to mark start of control
PORTA |= _BV(CE);

// now spi t out the control byte
// ce and scl k are l ow when we get here
// but we need to set the di recti on for i o to output
DDRA |= _BV(IO);

for (q=0; q<8; q++)
{
// set the data bi t
i f (control & 1)
{
PORTA |= _BV(IO);
}
el se
{
PORTA &= ~(_BV(IO));
}

// dri ve the cl ock hi gh to l atch the bi t
PORTA |= _BV(SCLK);

// shi ft the data so the next hi gher bi t i s sent next ti me
control >>= 1;

// hopeful l y C codes thi s sl owl y enough to meet the mi ni mum cl ock peri od
// of a mi crosecond, even though we' re worki ng at 8MHz
// and havi ng l atched, send i t l ow agai n
PORTA &= ~(_BV(SCLK));
}

// now we are di fferent for reads and wri tes
i f (rw == READ)
{
// read a byte

// set the data di recti on to i nput
DDRA &= ~(_BV(IO));

// cl ear the recei vi ng byte
control = 0;

for (q=0; q<8; q++)
{
// as we fi ni sh the control byte cycl e, the cl ock i s l ow
// whi ch means that the data i s avai l abl e to be read
// we get data avai l abl e on the fal l i ng edge of the cl ock

// shi ft the data to make space
control >>= 1;

i f (PINA & _BV(IO))
{
control |= 0x80;
}
el se
{
control &= 0x7f;
}

// dri ve the cl ock hi gh
PORTA |= _BV(SCLK);

// and send i t l ow agai n
PORTA &= ~(_BV(SCLK));
}

// and now we have the data, put i t where we need i t
*data = control ;

}
el se
{
// wri te a byte

// we conti nue to wri te on the ri si ng edge
control = *data;
for (q=0; q<8; q++)
{
// set the data bi t
i f (control & 1)
{
PORTA |= _BV(IO);
}
el se
{
PORTA &= ~(_BV(IO));
}

// dri ve the cl ock hi gh to l atch the bi t
PORTA |= _BV(SCLK);

// shi ft the data so the next hi gher bi t i s sent next ti me
control >>= 1;

// hopeful l y C codes thi s sl owl y enough to meet the mi ni mum cl ock peri od
// of a mi crosecond, even though we're worki ng at 8MHz
// and havi ng l atched, send i t l ow agai n
PORTA &= ~(_BV(SCLK));
}
}

// and one l ast thi ng... bri ng CE l ow agai n to mark compl eti on
// and make the i o l i ne hi gh i mpedance i nput
PORTA &= ~(_BV(CE));
DDRA &= ~(_BV(IO));
PORTA &= ~(_BV(IO));

}

voi d rtc_get_ti me(struct rtc_ti me * ti me)
{
// get the ti me
unsi gned char data;

rtc_comms(&data, 0x00, READ);
ti me->second = (data&0x0f) + ((data&0x70)>>4)*10;

rtc_comms(&data, 0x01, READ);
ti me->mi nute = (data&0x0f) + ((data&0x70)>>4)*10;

rtc_comms(&data, 0x02, READ);
ti me->hour = (data&0x0f) + ((data&0x30)>>4)*10;

rtc_comms(&data, 0x03, READ);
ti me->day = (data&0x0f) + ((data&0x30)>>4)*10;

rtc_comms(&data, 0x04, READ);
ti me->month = (data&0x0f) + ((data&0x10)>>4)*10;

rtc_comms(&data, 0x05, READ);
ti me->year = (data&0x0f) + ((data&0xf0)>>4)*10;
}
#endi f

//--------------------------------------------------------------------
----------
// By Mark Koh
// date : 20-MAR-2008, 02:26AM
//
// Objective : To demostrate DS1302 burst Read and burst write
//
// Code not tested, use at your own risk!! God bless.........
//--------------------------------------------------------------------
----------

#define DS1302_RST_TRIS TRISB.F0 // Modify these code to fix your
IO lines
#define DS1302_IO_TRIS TRISB.F1
#define DS1302_SCLK_TRIS TRISB.F2

#define DS1302_RST_DATA PORTB.F0 // Modify these code to fix your
IO lines
#define DS1302_IO_DATA PORTB.F1
#define DS1302_SCLK_DATA PORTB.F2


void DS1302_INIT();
void DS1302_CLOCK_READ();
void DS1302_CLOCK_WRITE();
void DS1302_RAM_READ();
void DS1302_RAM_WRITE();



unsigned char DS1302_CLOCK_DATA[8];
unsigned char DS1302_RAM_DATA[31];


void main(){
// Place all other init code here
DS1302_INIT();
DS1302_CLOCK_READ();
// Process your clock data here, ensure CH flag is LOW, or else
DS1302 Clock will halt
// Note, I believe at this point, you should able to decode the
clock data yourself
// So, I will not bore you with unnecessarily data conversion
code..
//..
//..
//..
//..
//..
DS1302_CLOCK_WRITE();
// Write data back into DS1302 chip.
//..
//..
//..
//..
//..
DS1302_RAM_READ();
// This will read all RAM data from DS1302, you may delete this
routine if you are not using it.
//..
//..
//..
//..
//..
DS1302_RAM_WRITE();
// This will write back all RAM data from DS1302, you may delete
this routine if you are not using it.
//..
//..
//..
//..
//..

}


void DS1302_INIT(){
DS1302_RST_TRIS = 0; // Define this pin as output
DS1302_IO_TRIS = 1; // Define this pin as input for the start,
need to change when Write
DS1302_SCLK_TRIS = 0; // Define this pin as output

DS1302_RST_DATA = 0; // Hold DS1302 @ reset mode, int clock
still running
DS1302_SCLK_DATA = 0; // Sclk always begins at low
DS1302_IO_DATA = 0; // Hold IO data line low
}
//--------------------------------------------------------------------
----------
// Read all clock data sec, min, hour.......etc into array
//--------------------------------------------------------------------
----------
void DS1302_CLOCK_READ(){
unsigned char cc1,cc2,dat; // cc1 and cc2 are used for
counter

DS1302_IO_TRIS = 0; // Change IO line to output
DS1302_RST_DATA = 1; // Release reset line and prepare for
transfer

dat = 0b10111111; // CLOCK READ BURST COMMAND,
<1><R/#C><1><1><1><1><1><R/#W>
for(cc1=0;cc1<8;cc1++){
if(dat.F0) DS1302_IO_DATA = 1; else DS1302_IO_DATA = 0; //
Output data
dat = dat >> 1; // Shift bit one step to the right.

DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
DS1302_SCLK_DATA = 0;
}
//---------------------------------------------------------------
----------
// After sending command, next is to read all 8 bytes of data
//---------------------------------------------------------------
----------
DS1302_IO_TRIS = 1; // Change IO line to Input, to receive data

for(cc2=0;cc2<8;cc2++){
for(cc1=0;cc1<8;cc1++){
DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
//-----------------------------------
// Read bit when sclk is high
//-----------------------------------
if(DS1302_IO_DATA) dat.F0 = 1; else dat.F0 = 0; // input
data
dat = dat << 1; // shift bit one step to left
}
DS1302_CLOCK_DATA[cc2] = dat; // store result int array
}
//---------------------------------------------------------------
----------
// Whole operation completed, set IO line back to default
//---------------------------------------------------------------
----------
DS1302_SCLK_DATA = 0;
DS1302_IO_TRIS = 1; // Change IO line to input
DS1302_IO_DATA = 0; // Change IO line to input
DS1302_RST_DATA = 0; // Hold reset line, internal clock still
running
}
//--------------------------------------------------------------------
----------
//--------------------------------------------------------------------
----------
void DS1302_CLOCK_WRITE(){
unsigned char cc1,cc2,dat; // cc1 and cc2 are used for
counter

DS1302_IO_TRIS = 0; // Change IO line to output
DS1302_RST_DATA = 1; // Release reset line and prepare for
transfer

dat = 0b10111110; // CLOCK WRITE BURST COMMAND,
<1><R/#C><1><1><1><1><1><R/#W>
for(cc1=0;cc1<8;cc1++){
if(dat.F0) DS1302_IO_DATA = 1; else DS1302_IO_DATA = 0; //
Output data
dat = dat >> 1; // Shift bit one step to the right.

DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
DS1302_SCLK_DATA = 0;
}
//---------------------------------------------------------------
----------
// After sending command, next is to write all 8 bytes of data
//---------------------------------------------------------------
----------
for(cc2=0;cc2<8;cc2++){
dat = DS1302_CLOCK_DATA[cc2];
for(cc1=0;cc1<8;cc1++){
if(dat.F0) DS1302_IO_DATA = 1; else DS1302_IO_DATA = 0;
// Output data
dat = dat >> 1; // Shift bit one step to the right.

DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
DS1302_SCLK_DATA = 0;
}
}
//---------------------------------------------------------------
----------
// Whole operation completed, set IO line back to default
//---------------------------------------------------------------
----------
DS1302_SCLK_DATA = 0;
DS1302_IO_TRIS = 1; // Change IO line to input
DS1302_IO_DATA = 0; // Change IO line to input
DS1302_RST_DATA = 0; // Hold reset line, internal clock still
running
}
//--------------------------------------------------------------------
----------
//--------------------------------------------------------------------
----------

void DS1302_RAM_READ(){
unsigned char cc1,cc2,dat; // cc1 and cc2 are used for
counter

DS1302_IO_TRIS = 0; // Change IO line to output
DS1302_RST_DATA = 1; // Release reset line and prepare for
transfer

dat = 0b11111111; // CLOCK READ BURST COMMAND,
<1><R/#C><1><1><1><1><1><R/#W>
for(cc1=0;cc1<8;cc1++){
if(dat.F0) DS1302_IO_DATA = 1; else DS1302_IO_DATA = 0; //
Output data
dat = dat >> 1; // Shift bit one step to the right.

DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
DS1302_SCLK_DATA = 0;
}
//---------------------------------------------------------------
----------
// After sending command, next is to read all 31 bytes of data
//---------------------------------------------------------------
----------
DS1302_IO_TRIS = 1; // Change IO line to Input, to receive data

for(cc2=0;cc2<31;cc2++){
for(cc1=0;cc1<8;cc1++){
DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
//-----------------------------------
// Read bit when sclk is high
//-----------------------------------
if(DS1302_IO_DATA) dat.F0 = 1; else dat.F0 = 0; // input
data
dat = dat << 1; // shift bit one step to left
}
DS1302_RAM_DATA[cc2] = dat; // store result int array
}
//---------------------------------------------------------------
----------
// Whole operation completed, set IO line back to default
//---------------------------------------------------------------
----------
DS1302_SCLK_DATA = 0;
DS1302_IO_TRIS = 1; // Change IO line to input
DS1302_IO_DATA = 0; // Change IO line to input
DS1302_RST_DATA = 0; // Hold reset line, internal clock still
running
}

//--------------------------------------------------------------------
----------
//--------------------------------------------------------------------
----------

void DS1302_RAM_WRITE(){
unsigned char cc1,cc2,dat; // cc1 and cc2 are used for
counter

DS1302_IO_TRIS = 0; // Change IO line to output
DS1302_RST_DATA = 1; // Release reset line and prepare for
transfer

dat = 0b11111110; // CLOCK WRITE BURST COMMAND,
<1><R/#C><1><1><1><1><1><R/#W>
for(cc1=0;cc1<8;cc1++){
if(dat.F0) DS1302_IO_DATA = 1; else DS1302_IO_DATA = 0; //
Output data
dat = dat >> 1; // Shift bit one step to the right.

DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
DS1302_SCLK_DATA = 0;
}
//---------------------------------------------------------------
----------
// After sending command, next is to write all 31 bytes of data
//---------------------------------------------------------------
----------
for(cc2=0;cc2<31;cc2++){
dat = DS1302_RAM_DATA[cc2];
for(cc1=0;cc1<8;cc1++){
if(dat.F0) DS1302_IO_DATA = 1; else DS1302_IO_DATA = 0;
// Output data
dat = dat >> 1; // Shift bit one step to the right.

DS1302_SCLK_DATA = 0; // Create a clock pulse, about 2us
(freq 500Khz)
delay_us(1);
DS1302_SCLK_DATA = 1;
delay_us(1);
DS1302_SCLK_DATA = 0;
}
}
//---------------------------------------------------------------
----------
// Whole operation completed, set IO line back to default
//---------------------------------------------------------------
----------
DS1302_SCLK_DATA = 0;
DS1302_IO_TRIS = 1; // Change IO line to input
DS1302_IO_DATA = 0; // Change IO line to input
DS1302_RST_DATA = 0; // Hold reset line, internal clock still
running
}
//--------------------------------------------------------------------
----------
//--------------------------------------------------------------------
----------



Top





markkoh
Post subject:
Posted: 19 Mar 2008 20:21


Joined: 13 Jan 2006 18:06
Posts: 14
Location: Singapore
Need some correction to my code..

For routine DS1302_CLOCK_READ and DS1302_RAM_READ, pls change

Line---> if(DS1302_IO_DATA) dat.F0 = 1; else dat.F0 = 0; // input data
dat = dat << 1; // shift bit one step to left

To ---> if(DS1302_IO_DATA) dat.F7 = 1; else dat.F7 = 0; // input data
dat = dat >> 1; // shift bit one step to left

Sorry for the error, data are shifted in LSB first.

You might also like