Overview
The DS1602 consists of two 32 bit counters which provides the capability of some 125 years. The continuous counter increments each second when there is power on either V_bat or on V_cc. The V_cc counter increments only when voltage is present on V_cc. Thus, the DS1602 is useful in determining the amount of time equipment has been in the field and the amount of time it has actually been powered.
When V_bat is present and V_cc is less than V_bat (or at ground), the continuous counter increments, but the interface circuitry is shut down. I have used this in event logging applications where power consumption was critical. V_bat (was present at all times). When a reading was desired, V_cc was momentarily turned on using a PIC output to read the continuous counter.
There is an additional discussion in the context of the Parallax BASIC Stamp 2 elsewhere on this web site.
// DS1602_1.C (CCS - PCM, PIC16F84)
//
// Illustrates how to interface with DS1602 3-Wire Elapsed Time Counter
//
// 16F84 DS1602
//
// RB.2 (term 8) ------10K- ---------- DQ (term 2)
// RB.1 (term 7) -------------------- CLk (term 3)
// RB.0 (term 6) -------------------- RST (term 1)
//
// In this program V_bat was connected to ground.
//
// Clears both continuous and V_cc elapsed time counters. Reads
// and displays content of continuous counter at five second intervals
// ten times.
//
// Sets V_cc counter to 0x12345678. Reads and displays at five second
// intervals ten times.
//
// Note that structures may not be passed to nor returned from a function.
// Rather, they are passed by reference. That is, by using a pointer.
//
// copyright Peter H. Anderson, Baltimore, MD, April, '99
#case
#include <16f84.h>
#include <defs_f84.h>
#define DQ_PIN rb2
#define DQ_DIR trisb2
#define CLK_PIN rb1
#define CLK_DIR trisb1
#define RST_PIN rb0
#define RST_DIR trisb0
#define TxData 0 // RA.0 for serial LCD
#define CONT_CNTR 0
#define V_CC_CNTR 1
#define IN 1
#define OUT 0
struct long32
{
long hi_long;
long lo_long;
};
void ds1602_set_osc_trim(int osc_trim);
void ds1602_clear_counter(int counter);
void ds1602_write_counter(int counter, struct long32 *p_t);
void ds1602_read_counter(int counter, struct long32 *p_t);
void ds1602_out_byte(int v);
int ds1602_in_byte(void);
void ds1602_begin(void);
void ds1602_end(void);
// delay routines
void delay_ms(long t);
void delay_10us(int t);
// LCD routines
void lcd_init(void);
void out_RAM_str(int *s);
void lcd_hex_byte(int val);
void lcd_dec_byte(int val, int digits);
int num_to_char(int val);
void lcd_char(int ch);
void lcd_new_line(void);
void main(void)
{
int n;
struct long32 time32;
lcd_init();
RST_DIR=OUT;
CLK_DIR=OUT;
DQ_DIR=OUT;
ds1602_set_osc_trim(0x03); // in range of 0 - 7
ds1602_clear_counter(CONT_CNTR); // clear both counters
ds1602_clear_counter(V_CC_CNTR);
for(n=0; n<10; n++) // ten readings
{
delay_ms(5000); // wait for 5 seconds
ds1602_read_counter(CONT_CNTR, &time32);
lcd_hex_byte(time32.hi_long>>8);
lcd_hex_byte(time32.hi_long&0xff);
lcd_char(' ');
lcd_hex_byte(time32.lo_long>>8);
lcd_hex_byte(time32.lo_long&0xff);
lcd_new_line();
}
time32.hi_long = 0x0123;
time32.lo_long = 0x4567;
ds1602_write_counter(V_CC_CNTR, &time32); // set counter to 0x01234567
for(n=0; n<10; n++) // 10 readings at nominal 5 second intervals
{
delay_ms(5000); // wait for 5 seconds
ds1602_read_counter(V_CC_CNTR, &time32);
lcd_hex_byte(time32.hi_long>>8);
lcd_hex_byte(time32.hi_long&0xff);
lcd_char(' ');
lcd_hex_byte(time32.lo_long>>8);
lcd_hex_byte(time32.lo_long&0xff);
lcd_new_line();
}
}
void ds1602_set_osc_trim(int osc_trim)
// sets trim of osc to value contained in osc_trim
{
ds1602_begin();
ds1602_out_byte(0xc0 | (osc_trim<<3));
// 11 OSC2 OSC1 OSC0 X X 0
ds1602_end();
}
void ds1602_clear_counter(int counter)
{
ds1602_begin();
if (counter == 0)
{
ds1602_out_byte(0x04); // continuous counter
}
else
{
ds1602_out_byte(0x02); // V_cc counter
}
ds1602_end();
}
void ds1602_write_counter(int counter, struct long32 *p_t)
// writes 32 bits contained in hi_count and lo_count
// to specified counter, beginning with least sig bit
{
ds1602_begin();
if (counter==0)
{
ds1602_out_byte(0x80); // continuous counter
}
else
{
ds1602_out_byte(0x40); // V_cc counter
}
ds1602_out_byte(p_t->lo_long & 0xff); // lo byte of lower long
ds1602_out_byte((p_t->lo_long) >> 8);
ds1602_out_byte(p_t->hi_long & 0xff); // lo byte of high long
ds1602_out_byte((p_t->hi_long) >> 8);
ds1602_end();
}
void ds1602_read_counter(int counter, struct long32 *p_t)
// note that a pointer is used to pass values back to calling routine
{
int lo_byte, hi_byte;
ds1602_begin();
if (counter==0)
{
ds1602_out_byte(0x81); // continuous counter
}
else
{
ds1602_out_byte(0x41); // V_CC counter
}
lo_byte = ds1602_in_byte(); // lo
hi_byte = ds1602_in_byte();
p_t->lo_long = ((long)hi_byte << 8) | lo_byte;
lo_byte = ds1602_in_byte(); // lo
hi_byte = ds1602_in_byte();
p_t->hi_long = ((long)hi_byte << 8) | lo_byte;
}
void ds1602_out_byte(int v)
{
int n;
DQ_DIR=OUT;
for(n=0; n<8; n++)
{
DQ_PIN = v&0x01; // least sig bit first
CLK_PIN=1;
CLK_PIN=0;
v=v>>1;
}
}
int ds1602_in_byte(void)
{
int n, v;
DQ_DIR=IN;
for (n=0; n<8; n++)
{
CLK_PIN=1;
if(DQ_PIN)
{
v=(v>>1) | 0x80; // least significant bit first
}
else
{
v=v>>1;
}
CLK_PIN=0;
}
DQ_DIR=OUT;
return(v);
}
void ds1602_begin(void)
{
RST_PIN=0;
CLK_PIN=0;
RST_PIN=1; // initiate by bringing RST high
}
void ds1602_end(void)
{
CLK_PIN=1;
RST_PIN=0;
}
// delay routines
void delay_10us(int t)
{
#asm
BCF STATUS, RP0
DELAY_10US_1:
CLRWDT
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ t, F
GOTO DELAY_10US_1
#endasm
}
void delay_ms(long t) // delays t millisecs
{
do
{
delay_10us(100);
} while(--t);
}
// LCD routines
int num_to_char(int val) // converts val to hex character
{
int ch;
if (val < 10)
{
ch=val+'0';
}
else
{
val=val-10;
ch=val + 'A';
}
return(ch);
}
void lcd_char(int ch) // serial output to PIC-n-LCD, 9600 baud
{
int n, dly;
// start bit + 8 data bits
#asm
BCF STATUS, RP0
MOVLW 9
MOVWF n
BCF STATUS, C
LCD_CHAR_1:
BTFSS STATUS, C
BSF PORTA, TxData
BTFSC STATUS, C
BCF PORTA, TxData
MOVLW 32
MOVWF dly
LCD_CHAR_2:
DECFSZ dly, F
GOTO LCD_CHAR_2
RRF ch, F
DECFSZ n, F
GOTO LCD_CHAR_1
BCF PORTA, TxData
CLRWDT
MOVLW 96
MOVWF dly
LCD_CHAR_3:
DECFSZ dly, F
GOTO LCD_CHAR_3
CLRWDT
#endasm
}
void lcd_init(void) // sets TxData in idle state and resets PIC-n-LCD
{
#asm
BCF STATUS, RP0
BCF PORTA, TxData
BSF STATUS, RP0
BCF TRISA, TxData
BCF STATUS, RP0
#endasm
lcd_char(0x0c);
delay_ms(250);
}
void lcd_new_line(void) // outputs 0x0d, 0x0a
{
lcd_char(0x0d);
delay_ms(10); // give the PIC-n-LCD time to perform the
lcd_char(0x0a); // new line function
delay_ms(10);
}
void out_RAM_str(int *s)
{
while(*s)
{
lcd_char(*s);
++s;
}
}
void lcd_hex_byte(int val) // displays val in hex format
{
int ch;
ch = num_to_char((val>>4) & 0x0f);
lcd_char(ch);
ch = num_to_char(val&0x0f);
lcd_char(ch);
}
void lcd_dec_byte(int val, int digits)
// displays byte in decimal as either 1, 2 or 3 digits
{
int d;
int ch;
if (digits == 3)
{
d=val/100;
ch=num_to_char(d);
lcd_char(ch);
}
if (digits >1) // take the two lowest digits
{
val=val%100;
d=val/10;
ch=num_to_char(d);
lcd_char(ch);
}
if (digits == 1) // take the least significant digit
{
val = val%100;
}
d=val % 10;
ch=num_to_char(d);
lcd_char(ch);
}