Real Time Clock DS1306 issue

Find out how to setup your programmer's software and how to solve many common problems.

Moderator: phalanx

Post Reply
sambu
Posts: 5
Joined: Wed Oct 24, 2018 1:52 pm

Real Time Clock DS1306 issue

Post by sambu » Wed Oct 24, 2018 2:01 pm

I use two push buttons to make increment and decrement of the year. Using the Button_UP, it is able to make an increment. I am having an issue with Button_DOWN. When the year reach 2000, then I press the Button_DOWN one more time, instead of the year 1999, It jumps to 2055. I don't know what happen. Please help. Thank you.

Code: Select all

	
		lcdcmd(0x84); // set cursor to first row, location 4
		WriteString("Set Year");
		lcdcmd(0xC4);
		WriteString("20");
		BCDtoASCII(year);             // display year
			if(Button_UP)
	     	{	
				MSDelay(20);  // 10 uS
				year = BCD2Binary(year);
				year++;
				year = Binary2BCD(year);
				if(year > 0x99)
				{
					year = 0;
				}
				Write_DS1306(W_Year_address,year);
			
			}
			
			if(Button_DOWN)
	     	{	
				MSDelay(20);  // 10 uS
				year = BCD2Binary(year);
				year--;
				year = Binary2BCD(year);
				if((year & 0x7f) < 0   )
				{
					year = 0x99;
				}
				//	year = Binary2BCD(year);
				Write_DS1306(W_Year_address,year);
			
			}

User avatar
phalanx
Non-SFE Guru
Posts: 1980
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: Real Time Clock DS1306 issue

Post by phalanx » Thu Oct 25, 2018 6:52 am

There isn't enough information in your post to figure out what you're doing wrong specifically.

I do know that the DS1306 uses a BCD value for "year" ranging from 00 to 99 (upper nibble of year can be 0-9 and the lower nibble of year can be 0-9). It's up to your firmware to correctly interpret those values and correlate them to the actual year you want to display. The datasheet does warn that illogical time and date entries result in undefined operation. If you are decrementing year zero (2000) your byte would wrap around to 0xFF which is an illogical date entry and is likely the cause of your problems.

-Bill

sambu
Posts: 5
Joined: Wed Oct 24, 2018 1:52 pm

Re: Real Time Clock DS1306 issue

Post by sambu » Thu Oct 25, 2018 9:52 am

Hi Bill. Thank you for your quick response. I did wrap the data of 0xff
if((year & 0xFF) < 0 )
{
year = 0x99;
}
// year = Binary2BCD(year);
Write_DS1306(W_Year_address,year);
It still jumped to 2055. But if I let if((year & 0xFF) <= 0) // less than and equal zero
then the year count down from 2002, 2001, then jumped to 2099 (skipped 2000). Please help.

User avatar
phalanx
Non-SFE Guru
Posts: 1980
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: Real Time Clock DS1306 issue

Post by phalanx » Fri Oct 26, 2018 4:20 pm

You still haven't shown enough information.
What type is "year?"
How do your BCD and ASCII conversions work?
Have you checked to see the contents of "year" are what you expect after you've applied some logic to it but before you convert it?
Have you considered using multiple variables for "year" so you don't confuse what value you are holding? (year_bin, year_bcd, year_ascii, etc.)
Are you sure your wrapping code is working the way you think it does in your mind?

We need details!

-Bill

sambu
Posts: 5
Joined: Wed Oct 24, 2018 1:52 pm

Re: Real Time Clock DS1306 issue

Post by sambu » Fri Oct 26, 2018 10:53 pm

Hi Bill,
Per your request, I put the following code. Thank you for your time.

Code: Select all

#include<P18F458.h>
#pragma config OSC=HS,WDT=OFF,LVP=OFF,BOR=OFF
#define ldata PORTB		
#define rs PORTDbits.RD5	
#define rw PORTDbits.RD6	
#define en PORTDbits.RD7

#define Button_SET PORTCbits.RC1
#define Button_UP PORTCbits.RC6
#define Button_DOWN PORTCbits.RC0

#define W_Ctrl_address 0x8f   // write control address

#define W_Year_address 0x86   // write year address
#define R_Year_address 0x06   // read year address


//--------- Function Prototye----------------------//
void LCD_init(void);
void lcdcmd(unsigned char);
void lcddata(unsigned char);
void MSDelay(unsigned int);
void BCDtoASCII(unsigned char);
void Write_DS1306(unsigned char, unsigned char);
unsigned char Read_DS1306(unsigned char);
void WriteString(const rom char* );
int Binary2BCD(int);
int BCD2Binary(int);
void set_current_time(void);
void disp_time(void);



//--------- Global variable declaration----------// 
unsigned char day,temp,temp1;
unsigned char hour,minute,second;
unsigned char hour_a,minute_a,second_a;
unsigned char day,date,month,year;
unsigned char ap, ap_a;
unsigned char time, time_a;
	char state = 0;


void main(void)
{
	
	SSPSTAT =0;            // read at middle, send on active edge
	SSPCON1 =0x22;         // master SPI enable, Fosc/64
	TRISC = 0;             // make PORTC output
	TRISD = 0;
	TRISCbits.TRISC1 = 1;  // RC1 as input for Button_SET
	TRISCbits.TRISC6 = 1;  // RC6 as input for Button_UP		
	TRISCbits.TRISC0 = 1;  // RC0 as input for Button_DOWN
	TRISCbits.TRISC4 = 1;  // SDI
//	TRISCbits.TRISC5 = 0;  // SDO
	PORTCbits.RC2 = 1;     // enable RTC

	TRISB = 0;             // PortB as output
	en =0;
	LCD_init();

	// ----------------Initialize time and date------------------------//	
	Write_DS1306(W_Year_address,0x18);  // Year of 2018

	while(1)
{
/*-- Get value of time and date by writing each address to DS1306 
			and get data of each from DS1306--    */
	
	year   = Read_DS1306(R_Year_address);  // get year's value
	
		if (Button_SET == 0 && state == 0 )
		{
			disp_time();
		}

	
/* Using Button_SET and Button_UP to test year increment from 2000-2099 
and jump over to 2000 again. While using Button_DOWN to make decrement from 2099-2000
and jump over to 2099 again. 
*/
//-----------------------Set Year --------------------------------//
	if (Button_SET == 1 && state == 0 )
	{
		while(Button_SET ==1); // wait till button is released
		{ 
			state = 1 ;  // start setting alarm value
			lcdcmd(0x01);  // clear LCD
		}
	}	
	if (state == 1)
	{
		lcdcmd(0x84); // set cursor to first row, location 4
		WriteString("Set Year");
		lcdcmd(0xC4);
		BCDtoASCII(year);             // minute
			if(Button_UP)
	     	{	
				MSDelay(20);  // 10 uS
				year = BCD2Binary(year);
				year ++;
				year = Binary2BCD(year);
				if((year & 0xff) >= 0x99)
				{
					year = 0;
				}
			}
	
			
			if(Button_DOWN)
			{
				MSDelay(20);  // 10 uS
				year = BCD2Binary(year);
				year --;
				year = Binary2BCD(year);
		/* issue in the following if condition; year cout down from 2001
			2000, then 1955 */
				if((year & 0xff ) < 0)
				{
					year = 0x99;
	
				}
			}
					
			Write_DS1306(W_Year_address,year); 
	}

//--------------- Return to Initial State------------------------------------//

		if (Button_SET == 1 && state == 1 )
	{
		while(Button_SET ==1); // wait till button is released
		{ 
			state = 0 ;  // start setting alarm value
			lcdcmd(0x01);  // clear LCD
			disp_time();
		}
	}	
}	
}


void disp_time(void)
{
	lcdcmd(0xC0);
	lcddata('2');                 // display number 2
	lcddata('0');	              // display number 0
	BCDtoASCII(year);             // year	
	lcdcmd(0x0C);                 // cursor off

}

void Write_DS1306(unsigned char address, unsigned char write_data)
{
   // Star to write data to DS1306 
	PORTCbits.RC2 = 1;   // begin byte write
	SSPBUF = address;    // send out the write address 
	while(!SSPSTATbits.BF);
	temp = SSPBUF;  
	SSPBUF = write_data;		
	while(!SSPSTATbits.BF);
	temp = SSPBUF;
	PORTCbits.RC2 = 0;   // end byte write
}

unsigned char Read_DS1306(unsigned char w_address)
{
	unsigned char r_data;	
	PORTCbits.RC2 = 1;   // begin byte write
	SSPBUF = w_address;    // send out the write address 
	while(!SSPSTATbits.BF);
	SSPBUF =temp1 ;      // clear BF flag
	while(!SSPSTATbits.BF);
	r_data = SSPBUF;    // get data from DS1306
	PORTCbits.RC2 = 0;   // end byte write
	return r_data;
}

void LCD_init(void)	
{	
	MSDelay(250);
	lcdcmd(0x33);
	MSDelay(250);
	lcdcmd(0x32);
	MSDelay(250);  
	lcdcmd(0x28);  // init LCD 2 lines, 5x7 matrix
	MSDelay(250);
	lcdcmd(0x0E);  // display on, curson on
	MSDelay(15);
	lcdcmd(0x01);  // clear LCD
}

void lcdcmd(unsigned char value)
{
	ldata = (ldata & 0x0f) | (value & 0xf0);
	rs = 0;
	rw = 0;
	en = 1;
	
	MSDelay(3);
	en = 0;
	
	MSDelay(60);
	
	ldata = (ldata & 0x0f) | (value << 4);
	en =1;
	MSDelay(3);
	en = 0;
}

void lcddata(unsigned char value)
{
	ldata = (ldata &0x0f) | (value & 0xf0);
	rs = 1;
	rw = 0;
	en = 1;
	
	MSDelay(3);
	en = 0;	
	
	ldata = (ldata & 0x0f) | (value << 4);
	en =1;
	MSDelay(3);
	en =0;
}

void MSDelay(unsigned int itime)
	{	
		unsigned int i, j;
		for(i=0;i<itime;i++)
			for(j=0;j<135;j++);
	}
 
void BCDtoASCII(unsigned char myValue)
{
	unsigned char tmp = myValue;
	tmp = tmp & 0xF0;            // mask lower nibble
	tmp = tmp >> 4;              // swap it
	tmp = tmp | 0x30;            // convert it to ASCII
	lcddata(tmp);                // display to LCD
	tmp = myValue;               // for other digit
	tmp = tmp & 0x0F;            // mask upper nibble
	tmp = tmp | 0x30;            // convert it to ASCII
	lcddata(tmp);                // display to LCD
}

void WriteString(const rom char *buffer)
 {
	while(*buffer)     // Write data to LCD up to null
	{
//		MSDelay(1);
		MSDelay(3);
		lcddata(*buffer);  // Write character to LCD
		buffer++; 
	}
	return;
 } 

int Binary2BCD(int a)
{
	int t1,t2;
	t1 = a%10;
	t1 = t1 & 0x0f;
	a = a/10;
	t2 = a%10;
	t2 = 0x0f & t2;
	t2 = t2 << 4;
	t2 = 0xf0 & t2;
	t1 = t1 | t2;
	return t1;
}

int BCD2Binary ( int a )
{
	int BCD1;  // upper nibble
	int BCD2;  // lower nibble
	int b; 	   // variable of a binary number after converting BCD to Binary

	BCD1 = a & 0xf0; // Mask off 4 lower bit
	BCD2 = a & 0x0f; // Mask off 4 upper bit

	BCD1 = BCD1 >> 4; // shift 4 upper bit of BCD1 to the right 4 times
	BCD1 = BCD1 * 10; // Multiply BCD1 by 10
	b = BCD1 + BCD2; // sum of BCD1 and BCD2
	
	return b;
}


User avatar
phalanx
Non-SFE Guru
Posts: 1980
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: Real Time Clock DS1306 issue

Post by phalanx » Tue Oct 30, 2018 9:08 am

I found your problem and it has to do with the Binary2BCD() function in this section of code:

Code: Select all

			if(Button_DOWN)
			{
				MSDelay(20);  // 10 uS
				year = BCD2Binary(year);
				year --;
				year = Binary2BCD(year);
				if((year & 0xff ) < 0)
				{
					year = 0x99;
	
				}
			}
When you decrement "year" which is an unsigned char, it wraps around to 0xFF which is then being passed to Binary2BCD().

Code: Select all

int Binary2BCD(int a)
{
	int t1,t2;
	t1 = a%10;
	t1 = t1 & 0x0f;
	a = a/10;
	t2 = a%10;
	t2 = 0x0f & t2;
	t2 = t2 << 4;
	t2 = 0xf0 & t2;
	t1 = t1 | t2;
	return t1;
}
Binary2BCD() takes 0xFF and MODs it with 10 (decimal) which gives you a value of 5 which is stored in t1.
0xFF is then divided by 10 (decimal) which gives you 0x19 in "a"
"a" mod 10 (decimal) also equals 5 and is stored in t2.
You then rotate and combine them which becomes 0x55 and it's stored in t1
t1 is returned to your "button down" logic

This brings us to this statement in your "button down" logic:

Code: Select all

				if((year & 0xff ) < 0)
				{
					year = 0x99;
	
				}
At this point, "year" contains the value 0x55. ANDing year with 0xFF doesn't do anything since that just returns the value of year. If(year<0) is the same statement. This statement will never be true because year is an unsigned char so it will never be negative. Since this is skipped, year remains 0x55 which is then stored in the DS1306 and is why you get the year 2055. A better comparison would be to check if year > 0x99, then set it to 0x99.

Go back and think about the algorithm being used in your BinarytoBCD() function and make sure to pay attention to the number bases being used at each step.

It's inefficient to keep changing "year" between binary, BCD, and ASCII. Once you have the BCD year from the RTC, you should convert it into whatever forms you need and store them in unique variables.

You have to be more careful in the data types you are passing to functions. In many cases, you are passing unsigned chars to functions that expect signed ints. In 8-bit PICs, ints and chars are the same size but this could bite you in the future if you're not careful.

-Bill

sambu
Posts: 5
Joined: Wed Oct 24, 2018 1:52 pm

Re: Real Time Clock DS1306 issue

Post by sambu » Sun Nov 04, 2018 4:13 pm

Hi Bill,
Thank you for indicating the error of Binary2BCD function. I am working on it now. Hopefully, I will make it work. Thanks Bill.

sambu
Posts: 5
Joined: Wed Oct 24, 2018 1:52 pm

Re: Real Time Clock DS1306 issue

Post by sambu » Tue Nov 06, 2018 6:59 pm

Hi Bill.
I have fixed the Binary2BCD function, and now it is working. Thank you for your help Bill. I appreciate it. Please see video demo on Youtube :D

https://www.youtube.com/watch?v=yZwWnlI ... e=youtu.be

Post Reply