Wednesday, 13 August 2014

Digital Clock Design using DS1337 RTC

Clock Display / Real Time Clock

Digital clock is increasingly integrated in many modern electronic devices and applications due to the importance of time keeping. In this post, a digital clock was designed such that the time was derived from a Real Time Clock controlled with a microcontroller over I2C interface.




The Design

The digital clock circuit in figure 1.0 is pretty neat.




Figure 1.0: RTC based clock schematic


DS1337 Operation

The DS1337 operates as a slave device on the 12C serial bus. Access is obtained by implementing a START condition and providing a device identification code, followed by Read or Write (R/-W) indication, acknowledgement and then data; subsequent registers can be accessed sequentially until a STOP condition is executed. I2C operation is not guaranteed when VCC is below 1.8V.


Important facts for software development

The time and calendar information is obtained by reading the appropriate register bytes. The registers important to us in this design are seconds (00h), minutes (01h) and hours (02h) registers. The registers values are in the binary-coded decimal (BCD) format!

Bit 6 of the hours register is defined as the 12- or 24-hour mode-select bit. When low, the 24-hour mode is selected. In the 12-hour mode, bit 5 is the AM/PM bit with logic high being PM.

In the 24-hour mode, bit 5 is the second 10-hour bit (20–23 hours).


SPECIAL-PURPOSE REGISTERS

The DS1337 special purpose registers (control (0Eh) and status (0Fh)) are used to configure and monitor the RTC. The Control Register (0Eh) is used to start or stop the RTC oscillator, as well as to control the frequency of the square-wave output.


The system code

The working system code developed using MPLAB IDE  is dumped below.


Code begins:
/****************************************************************************
Digital Clock RTC Design
  AY0438 Display Driver was used to drive Segment LCD VI-402 for DS1338Z RTC clock display!!!!
Version 1.2 13/08/14
***************************************************/

#ifndef _XTAL_FREQ

 // Unless already defined assume 8MHz system frequency
 // This definition is required to calibrate __delay_us() and __delay_ms()
#define _XTAL_FREQ 4000000L // 4MHz
#endif

#include <htc.h>
#include "i2c.h"

#define D_CLK RB0 // set pin for display driver clock

#define D_DIN RB1 // set pin for display driver data input
#define D_LOAD RB2 // set pin for display driver load

// set chip configuration bits

__CONFIG(FOSC_INTOSCIO & WDTE_OFF& PWRTE_OFF & BOREN_OFF & CPD_OFF & CP_OFF);

void Read_RTCTime(void);

void convert_BCDdisplay(void);
unsigned char get_segment_dat(char digit);
void display_update_segments(char *data);
void display_send_byte(unsigned char data); // prototype
//void interrupt isr(void);

// GLOBAL VARIABLE DECLARATIONS


unsigned char mask_R[] = {0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90};

unsigned char mask_L[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};
unsigned char data[] = {0xFF,0xE0,0xFE,0xF6};
unsigned char time[]= {0x12,0x30,0x11};
unsigned char buffer;
char n;

int decToBcd(int dec) //function that converts decimal to BCD

{
return ( (dec/10*16) + (dec%10) );
}

int bcdToDec(int bcd) //function that converts BCD to decimal 

{
  return ( (bcd/16*10) + (bcd%16) );
}

void main(void)

{

TRISB = 0xF0; // Set PORTB pins

//TRISD = 0;
//OSCCON = 0X20; //SET Internal Oscillator to 4 MHz

//initialize LCD driver
D_CLK=0;
D_CLK=1;
D_DIN=0;
D_DIN=1;
D_LOAD=0;
D_LOAD=1;

// set the control register


i2c_WriteTo(0xd0); //slave address 0x0D
i2c_PutByte(0x07); // Control register 
i2c_PutByte(0x10); // enable oscillator 1Hz
i2c_Stop();

// set the time registers register


i2c_WriteTo(0xD0); //slave address 0x0D
i2c_PutByte(0x00); // seconds register 
i2c_PutByte(0x50); // data to seconds registers
i2c_PutByte(0x00); // data to minutes registers
i2c_PutByte(0x00); // data to hours registers - 24hr format
i2c_Stop();

Read_RTCTime(); // read time


convert_BCDdisplay();

display_update_segments(data);

// Loop Forever
while(1) {

if(RB5==0){ // check if mins++ button is pressed  
      
        Read_RTCTime(); // read time

time[1]=bcdToDec(time[1]);
time[1]++; //increment minutes
time[1]=decToBcd(time[1]);

i2c_WriteTo(0xD0); //slave address 0x0D
   i2c_PutByte(0x01); // minutes register 
   i2c_PutByte(time[1]); // data to minutes registers
i2c_Stop();

Read_RTCTime(); // read time

convert_BCDdisplay();
display_update_segments(data);
        }

if(RB4==0){ // check if hours++ button is pressed  

      
        Read_RTCTime(); // read time

time[2]=bcdToDec(time[2]);
time[2]++; //increment hours
time[2]=decToBcd(time[2]);
        
i2c_WriteTo(0xD0); //slave address 0x0D
   i2c_PutByte(0x02); // minutes register 
   i2c_PutByte(time[2]); // data to minutes registers
i2c_Stop();

Read_RTCTime(); // read time

convert_BCDdisplay();
display_update_segments(data);
        }

Read_RTCTime(); // read time

convert_BCDdisplay();
display_update_segments(data);

} // end of while
} // end of main

//FUNCTIONS!!!


void Read_RTCTime(void){

i2c_WriteTo(0xD0); //slave address to write
i2c_PutByte(0x00); // seconds register 

i2c_ReadFrom(0xD0); //
time[0] = i2c_GetByte(I2C_MORE); // read seconds
time[1] = i2c_GetByte(I2C_MORE); // read minutes
time[2] = i2c_GetByte(I2C_LAST); // read hours  
}

void convert_BCDdisplay(void){


for (n=0;n<10;n++){


buffer = time[1];
buffer = buffer << 4;
if((buffer^mask_R[n])==0)
data[3] = get_segment_dat(n);

buffer = time[1];

buffer = buffer >> 4;
if((buffer^mask_L[n])==0)
data[2] = get_segment_dat(n);

buffer = time[2];

buffer = buffer << 4;
if((buffer^mask_R[n])==0)
data[1] = get_segment_dat(n);

buffer = time[2];

buffer = buffer >> 4;
if((buffer^mask_L[n])==0)
data[0] = get_segment_dat(n);
}
}

unsigned char get_segment_dat(char digit){

 switch(digit){
  case 0: digit = 0xfc; break;
  case 1: digit = 0x60; break;
  case 2: digit = 0xda; break;
  case 3: digit = 0xf2; break;
case 4: digit = 0x66; break;
  case 5: digit = 0xb6; break;
  case 6: digit = 0xbe; break;
  case 7: digit = 0xe0; break;
case 8: digit = 0xfe; break;
  case 9: digit = 0xf6; break;
  default: digit = 0;
 }
return digit;
}

void display_update_segments(char *data)
{
display_send_byte(data[0]); // lefthand display
display_send_byte(data[1]);
display_send_byte(data[2]);
display_send_byte(data[3]);
D_LOAD = 1; // move data from shift register to segment latches
D_LOAD = 0;
}

void display_send_byte(unsigned char data) // fuction to write to the display controller

{
unsigned char mask = 0x01;
int n;

for (n=0;n<8;n++)
{
if ((data & mask) == 0)
D_DIN = 0;
else
D_DIN = 1;
D_CLK=1;
D_CLK=0;

mask = mask << 1;

}
}



Results

The real time operation of the digital clock is demonstrated in simulation in Media 1 below.


Media 1: The digital clock in action


Final Words

The digital clock design was achieved and demonstrated successfully, and it is an interesting design to try out.

Related post





No comments:

Post a Comment