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); }