Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

I need help with DS1302 and PIC16f877

Status
Not open for further replies.

Blue_Key

New Member
Hello,

i try to interface one DS1302 (real time clock) with one PIC 16F877A.

i have try different way, but each time i got the same bug.


The digits show 0 - 1 - 0 - 3 - 0 - 1 - 0 - 7 - 0 - 1 instead 0-1-2-3-...-8-9.


I try to find a solution by 1 week... i'm going crazy..:(


Here it's my code (with LCD):
Code:
#include <pic.h>
#include <htc.h>
#include <stdlib.h>

//__CONFIG(XT&WDTDIS&LVPDIS);
__CONFIG(0x1832);  

void lcd_line1(void);				//function prototypes
void lcd_line2(void);

void init();                   //I/O init
void lcd_init();               //LCD init
void write(char x);            //display one byte
void lcd_enable();             //LCD display setting.

void delay(void);
void clk_write(unsigned char);
unsigned char clk_read(void);
void clkburst(void);
void datafix(void);


#define RS RA1
#define RW RA2
#define E  RA3

#define	RST			RB5
#define	DATA		RB4
#define	SCLK		RB0
#define DATA_Tris TRISB4

char number[16] = "      :  :      ";
char daydate[16] = "     :  :20     ";
char sec[] = "           ";




void main(void)
{
	char x;
	unsigned char a,b;
	a=0;
	number[2] = number[5] = 0x3a;
	daydate[2] = daydate[5] = 0x3a;
	daydate[6] = 0x32;
	daydate[7] = 0x30;
	TRISB = 0;
	TRISD = 0;
	RST = 0;						//1302 reset low
	SCLK = 0;						//1302 clock low
	RW = 0;							//set lcd R/W low
	E = 0;							//set lcd E low

	delay();



        init();                //I/O init
        lcd_init();            //LCD init

	while(1)
	{
		RST = 1;					//read hours
		clk_write(0xbf);			//burst read
		sec[0] = clk_read();		//sec
		sec[1] = clk_read();		//min		
		sec[2] = clk_read();		//hour
		sec[3] = clk_read();		//date
		sec[4] = clk_read();		//month
		sec[5] = clk_read();		//day
		sec[6] = clk_read();		//year
		sec[7] = clk_read();		//control
		RST = 0;
		datafix();					//convert for display

    PORTD=0x02;                 //clr screen 
    lcd_enable();
        lcd_line1();           //display company's website  
        PORTD=0xC0;            //set the 2nd line display address
        lcd_enable();          //LCD display setting.       
        lcd_line2();           //display company's tel number.  


	}
}

void datafix(void)
{
	char temp,x;
	char *foo = sec;
	char bleh[] = "                ";
	for(x=0;x<14;x+=2)
	{
		temp = *foo;
		temp &+ 0xf0;
		temp >>= 4;
		bleh[x] = temp + 0x30;
		temp = *foo;
		temp &= 0x0f;
		bleh[x+1] = temp + 0x30;
		foo++;
	}
	number[10]=bleh[0];			//sec
	number[11]=bleh[1];
	number[7]=bleh[2];			//min
	number[8]=bleh[3];
	number[4]=bleh[4];			//hour
	number[5]=bleh[5];
	daydate[6]=bleh[6];			//day
	daydate[7]=bleh[7];
	daydate[3]=bleh[8];			//month
	daydate[4]=bleh[9];
	daydate[11]=bleh[12];			//year
	daydate[12]=bleh[13];
}

void clk_write(unsigned char dat)
{
	char x;
	for(x=0;x<8;x++)
	{
		if(dat & 0x01)					//put bit on data pin
		{
			DATA = 1;
		}
		else DATA = 0;
		SCLK = 1;						//toggle clock to latch bit
		SCLK = 0;
		dat >>= 1;						//move next bit into place
	}
}

unsigned char clk_read(void)
{
	char x;
	unsigned char dat,tmpdat;
	dat = 0;
	DATA_Tris = 1;						//make DATA input
	for(x=0;x<8;x++)
	{
		if(DATA)						//read a bit
		{
			tmpdat |= 1;
		} else {
		 	tmpdat |= 0;
		}
		tmpdat <<= 7;
		dat >>= 1;
		dat |= tmpdat;

		SCLK = 1;						//toggle clock to latch bit
		SCLK = 0;
	}
	DATA_Tris = 0;
	return(dat);
}



	
void lcd_16number(int num)
{
	number[0]=(char)(abs(num/10000)+0x30);
	num=num-abs(num/10000)*10000;
	number[1]=(char)(abs(num/1000)+0x30);
	num=num-abs(num/1000)*1000;
	number[2]=(char)(abs(num/100)+0x30);
	num=num-abs(num/100)*100;
	number[3]=(char)(abs(num/10)+0x30);
	num=num-abs(num/10)*10;
	number[4]=(char)(num+0x30);
}




//---------------------------------------
//I/O init
void init()
 {
    ADCON1=0x07;               //a port as ordinary i/o.
    TRISA=0x00;                //a port as output.
    TRISD=0x00;                //d port as output.
	return;
 }

//---------------------------------------
//LCD init
void lcd_init()
 {
    PORTD=0x01;                 //clr screen 
    lcd_enable();
    PORTD=0x38;                //8 bits 2 lines 5*7 mode.  
    lcd_enable();
    PORTD=0x0C;                //display on,cursor on,blink on.
    lcd_enable();
    PORTD=0x06;                //character not move,cursor rotate right.
    lcd_enable();
    PORTD=0x80;                //¡
    lcd_enable();
	return;
 }
 


//--------------------------------------
//write a byte to lcd.
void write(char x)
 {
  PORTD=x;                   //data send to PORTD
  RS = 1;                      //is data not command
  RW = 0;                      //is write not read
  E = 0;                       //pull low enable signal
  delay();                   //for a while
  E = 1;                       //pull high to build the rising edge.

	return;    
}

//--------------------------------------
//lcd display setting 
void lcd_enable()
 {
   RS=0;                     //is command not data
   RW=0;                     //is write not read. 
   E=0;                      //pull low enable signal.           
   delay();                  //for a while.                      
   E=1;                      //pull high to build the rising edge
      
	return;
}



 void lcd_line1()
 {
    int i;
    for(i=0;i<16;++i)       //total 16 bytes to display.
       {
         write(number[i]);       //search table to display
       }
	return;
 }

 void lcd_line2()
 {
    int i;
    for(i=0;i<16;++i)       //total 16 bytes to display.
       {
         write(daydate[i]);       //search table to display
       }
	return;
 }


void delay(void)
{
	long int y;
		for(y=0;y<100;y++){}
}





I hope the problem come from the clock read routine..
Code:
unsigned char clk_read(void)
{
	char x;
	unsigned char dat,tmpdat;
	dat = 0;
	DATA_Tris = 1;						//make DATA input
	for(x=0;x<8;x++)
	{
		if(DATA)						//read a bit
		{
			tmpdat |= 1;
		} else {
		 	tmpdat |= 0;
		}
		tmpdat <<= 7;
		dat >>= 1;
		dat |= tmpdat;

		SCLK = 1;						//toggle clock to latch bit
		SCLK = 0;
	}
	DATA_Tris = 0;
	return(dat);
}



Thanks for your help.
 
I can't see anything wrong with your code.

Can you try changing your code so it just reads and displays seconds?
I think this should do it,
Code:
    RST = 1;            //CE I assume?
    clk_write(0x80);    //write seconds
    clk_write(0x00);	//to ensure CH=0
    RST = 0;

    while(1)
    {
        RST = 1;            //CE I assume?
        clk_write(0x81);    //read seconds
	a=clk_read();
        RST = 0;

        PORTD=0x02;         //clr screen 
        lcd_enable();

        x=a>>4;             //display 10s of seconds
        x&=0x07;
        x+=0x30;
        write(x);
        
        x=a;                //display digit seconds
        x&=0x0f;
        x+=0x30;
        write(x);
    }

I added a write to seconds to ensure the clock halt flag is not set.

Mike.
 
Hit that one on the nose I think! Those numbers look like something is going-out of bounds. All wacky stuff happens when overflow occurs! If the clock was still running while you where trying to get the number, that may also do it.. Changing the data while reading will drive you crazy as well....

I just hope we get some sort of conformation.

-BaC
I can't see anything wrong with your code.

Can you try changing your code so it just reads and displays seconds?
I think this should do it,
Code:
    RST = 1;            //CE I assume?
    clk_write(0x80);    //write seconds
    clk_write(0x00);	//to ensure CH=0
    RST = 0;

    while(1)
    {
        RST = 1;            //CE I assume?
        clk_write(0x81);    //read seconds
	a=clk_read();
        RST = 0;

        PORTD=0x02;         //clr screen 
        lcd_enable();

        x=a>>4;             //display 10s of seconds
        x&=0x07;
        x+=0x30;
        write(x);
        
        x=a;                //display digit seconds
        x&=0x0f;
        x+=0x30;
        write(x);
    }

I added a write to seconds to ensure the clock halt flag is not set.

Mike.
 
Last edited:
With this code, the problem is the same.

But is not a hardware problem because i have one working .hex file.


Code:
RST = 1;            //CE I assume?
    clk_write(0x80);    //write seconds
    clk_write(0x00);	//to ensure CH=0
    RST = 0;

    while(1)
    {
        RST = 1;            //CE I assume?
        clk_write(0x81);    //read seconds
	a=clk_read();
        RST = 0;



        x=a>>4;             //display 10s of seconds
        x&=0x07;
        x+=0x30;
        number[1] = x;
        
        x=a;                //display digit seconds
        x&=0x0f;
        x+=0x30;
        number[2] = x;

    PORTD=0x02;                 //clr screen 
    lcd_enable();
        lcd_line1();           //display company's website  
        PORTD=0xC0;            //set the 2nd line display address
        lcd_enable();          //LCD display setting.       
        lcd_line2();           //display company's tel number.  


	}


Also i have try two different compiler, CC5X and now HI-Tech... and with this two i got the same bug..
 
Last edited:
It may not be connected to your problem but you have your EN line being switched the wrong way. The way you write to the LCD should be, setup all data,RS,R/W lines, take Enable high, do a short delay and take enable low again. You are doing it the other way round and therefore leaving the LCD enabled until the next data is sent. (edit) You also need a delay after you make Enable high again.

Mike.
 
Last edited:
Thanks Mike for this information. i will change that.

But the problem is not that :(

I have also try with 7 segments and problem is the same...

No idea ?
 
Can you try swapping your read/write routines to these,

Code:
void clk_write(unsigned char dat)
{
	char x;
	for(x=0;x<8;x++)
	{
		SCLK=0;				//clock low
		if(dat & 0x01)			//put bit on data pin
			DATA = 1;
		else 
			DATA = 0;
		SCLK = 1;			//toggle clock to latch bit
		dat >>= 1;			//move next bit into place
	}
}

unsigned char clk_read(void)
{
	char x;
	unsigned char dat,tmpdat;
	dat = 0;
	DATA_Tris = 1;				//make DATA input
	for(x=0;x<8;x++)
	{
		SCLK=0;				//make clock low
		dat>>=1;			//shift data
		if(DATA)			//read a bit
		{
			dat |= 0x80;		//set bit high
		} else {
		 	dat &= 0x7f;		//set bit low
		}
		SCLK = 1;			//clock high again
	}
	DATA_Tris = 0;
	return(dat);
}

I have changed them in a bit of a rush and so they probably contain syntax errors.

I'll try and explain the changes later. Gotta go.

Mike.
 
With this routine always the same bug: 0 -1-0-3-0 etc..

Code:
unsigned char clk_read(void)
{
	char x;
	unsigned char dat,tmpdat;
	dat = 0;
	DATA_Tris = 1;						//make DATA input
	tmpdat=0;


	for(x=0;x<8;x++)
	{

		SCLK = 1;						//toggle clock to latch bit

		dat>>=1;			//shift data
		if(DATA)			//read a bit
		{
			dat |= 0x80;		//set bit high
		} else {
		 	dat &= 0x7f;		//set bit low
		}


		SCLK = 0;

	}

	DATA_Tris = 0;
	return(dat);
}




If i change the write routine like that, i have now all digit at 0 but the seconds digits do like that: 1-3-1-3-1-7-1-?-1
Code:
void clk_write(unsigned char dat)
{
	char x;
	for(x=0;x<8;x++)
	{
		SCLK = 0;
		if(dat & 0x01)					//put bit on data pin
		{
			DATA = 1;
		} else {
			 DATA = 0;
		}
		SCLK = 1;						//toggle clock to latch bit

		dat >>= 1;						//move next bit into place
	}
}
 
Last edited:
Did you replace both routines at the same time as they will only work if both are replaced. I made the changes because the first bit of the read data is outputted on the falling edge of the last clock pulse that sends the last written bit.

Can you confirm that RB5 is connected to the /RST pin?

Mike.
 
I have try the to replace both routine and cf post 5, the digits show always 0.

Yes i have verify the connection and the /RST is connected to RB5
 
I'm sorry, I'm at a loss for ideas as to what could be wrong. You state it can't be hardware as you have a working hex file, however, if you have the defines for clock and data the wrong way around this would explain the problem. You should double check that your #defines match the hardware.

Mike.
P.S. can you attach the working hex file. If I get time I'll look at it tomorrow and try and figure out what's wrong.
 
Ok, Thanks..

I will continue to try something...

Here you have the working .hex (renamed to txt) and the asm file. (it's not the asm file from the c compiler).

This example use 7 segments and not LCD display.

I have check configuration word and it's the same.


Thank a lot for your help :)
 

Attachments

  • ds1302.ASM
    9.1 KB · Views: 213
  • ds1302.txt
    1.8 KB · Views: 202
A quick look at that asm file and the only thing they are doing different is clearing the clock line after a transfer. I can't see how it would make any difference whatsoever but just incase, here is the equivalent C routines to the asm routines above,

Code:
void clk_write(unsigned char dat)
{
	char x;
	for(x=0;x<8;x++)
	{
		SCLK=0;				//clock low
		if(dat & 0x01)			//put bit on data pin
			DATA = 1;
		else 
			DATA = 0;
		SCLK = 1;			//toggle clock to latch bit
		dat >>= 1;			//move next bit into place
	}
	SCLK=0;
}

unsigned char clk_read(void)
{
	char x;
	unsigned char dat;
	dat = 0;
	DATA_Tris = 1;				//make DATA input
	for(x=0;x<8;x++)
	{
		SCLK=0;				//make clock low
		dat>>=1;			//shift data
		if(DATA)			//read a bit
		{
			dat |= 0x80;		//set bit high
		} else {
		 	dat &= 0x7f;		//set bit low
		}
		SCLK = 1;			//clock high again
	}
	DATA_Tris = 0;
	SCLK=0;
	return(dat);
}

Mike.
 
With this code, the display show 01 on each numbers (01:01:01 and date aswell) and nothing change..

i have also add
Code:
	RST = 1;
	clk_write(0x8e);			//burst read
	clk_write(0x00);			//burst read
	RST = 0;
like
Code:
DS1302_INI
 BCF SCLK
 BCF RST                            ;first forbid
 MOVLW B'10001110'                  ;write enable 
 MOVWF TIME_TX
 BSF RST                            ;enable 1302
 CALL TIME_WRITE_1                  ;call write a data program
 MOVLW 0H                           ;enable write
 MOVWF TIME_TX
 CALL TIME_WRITE_1                  ;send a byte data
 BCF RST
 RETURN


for initialization but always the same problem..



I try aswell to write the soft followin the asm soft.. but nothing work :(
 
Last edited:
I did some change.. here is the new code..

But i haven't found the problem..


Code:
#include <pic.h>
#include <htc.h>
#include <stdlib.h>

//__CONFIG(XT&WDTDIS&LVPDIS);
__CONFIG(0x1832);  

void lcd_line1(void);				//function prototypes
void lcd_line2(void);

void init();                   //I/O init
void lcd_init();               //LCD init
void ds_init();               //LCD init
void write(char x);            //display one byte
void lcd_enable();             //LCD display setting.

void delay(void);
void clk_write(unsigned char);
unsigned char clk_read(void);
void clkburst(void);
void datafix(void);


#define RS RA1
#define RW RA2
#define E  RA3

#define	RST			RB5
#define	DATA		RB4
#define	SCLK		RB0
//#define DATA_Tris   TRISB.4

char number[16] = {' ',' ',' ',' ',' ',' ',':',' ',' ',':',' ',' ',' ',' ',' ',' '};
char daydate[16] = {' ',' ',' ',' ',' ',':',' ',' ',':','2','0',' ',' ',' ',' ',' '};
unsigned char sec[11] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};


//---------------------------------------
//I/O init
void init()
 {
    TRISA = 0x00;                //a port as output.
	TRISB = 0x00;
    TRISD = 0x00;                //d port as output.

	ADCON1 = 0x06;
   // ADCON1=0x07;               //a port as ordinary i/o.


	return;
 }
void ds_init()
 {

	RST = 0;						//1302 reset low
	SCLK = 0;						//1302 clock low

	RST = 1;
	clk_write(0x8e);		
	clk_write(0x00);			
	RST = 0;

}



void main(void)
{

    init();                //I/O init
	ds_init();
    lcd_init();            //LCD init

	delay();


	while(1)
	{

		RST = 1;					//read hours
		clk_write(0xbf);			//burst read
		sec[0] = clk_read();		//sec
		sec[1] = clk_read();		//min		
		sec[2] = clk_read();		//hour
		sec[3] = clk_read();		//date
		sec[4] = clk_read();		//month
		sec[5] = clk_read();		//day
		sec[6] = clk_read();		//year
		sec[7] = clk_read();		//control
		RST = 0;

		datafix();					//convert for display

    	PORTD=0x02;                 //clr screen 
    	lcd_enable();
        lcd_line1();           //display company's website  
        PORTD=0xC0;            //set the 2nd line display address
        lcd_enable();          //LCD display setting.       
        lcd_line2();           //display company's tel number.  


	}
}

void datafix(void)
{
	char temp,x;
	char *foo = sec;
	char bleh[16] = "                ";
	for(x=0;x<14;x+=2)
	{
		temp = *foo;
		temp &+ 0xf0;
		temp >>= 4;
		bleh[x] = temp + 0x30;
		temp = *foo;
		temp &= 0x0f;
		bleh[x+1] = temp + 0x30;
		foo++;
	}
	number[10]=bleh[0];			//sec
	number[11]=bleh[1];
	number[7]=bleh[2];			//min
	number[8]=bleh[3];
	number[4]=bleh[4];			//hour
	number[5]=bleh[5];
	daydate[6]=bleh[6];			//day
	daydate[7]=bleh[7];
	daydate[3]=bleh[8];			//month
	daydate[4]=bleh[9];
	daydate[11]=bleh[12];			//year
	daydate[12]=bleh[13];
}


void clk_write(unsigned char dat)
{
	char x;

	for(x=0;x<8;x++)
	{
		if(dat & 0x01)					//put bit on data pin
		{
			DATA = 1;
		}
		else {
			 DATA = 0;
		}
		SCLK = 1;						//toggle clock to latch bit
		dat >>= 1;						//move next bit into place
		SCLK = 0;

	}
}

unsigned char clk_read(void)
{
	char x;
	unsigned char dat,tmpdat;
	dat = 0;
	//DATA_Tris = 1;						//make DATA input
	TRISB = 0b00001000;

	tmpdat=0;


	for(x=0;x<8;x++)
	{
		if(DATA)						//read a bit
		{
			tmpdat |= 1;
		} else {
		 	tmpdat |= 0;
		}
		tmpdat <<= 7;
		dat >>= 1;
		dat |= tmpdat;

		SCLK = 1;						//toggle clock to latch bit
		SCLK = 0;
	}


	TRISB = 0b00000000;

	//DATA_Tris = 0;
	return(dat);
}



	
void lcd_16number(int num)
{
	number[0]=(char)(abs(num/10000)+0x30);
	num=num-abs(num/10000)*10000;
	number[1]=(char)(abs(num/1000)+0x30);
	num=num-abs(num/1000)*1000;
	number[2]=(char)(abs(num/100)+0x30);
	num=num-abs(num/100)*100;
	number[3]=(char)(abs(num/10)+0x30);
	num=num-abs(num/10)*10;
	number[4]=(char)(num+0x30);
}





//---------------------------------------
//LCD init
void lcd_init()
 {
    PORTD=0x01;                 //clr screen 
    lcd_enable();
    PORTD=0x38;                //8 bits 2 lines 5*7 mode.  
    lcd_enable();
    PORTD=0x0C;                //display on,cursor on,blink on.
    lcd_enable();
    PORTD=0x06;                //character not move,cursor rotate right.
    lcd_enable();
    PORTD=0x80;                //¡°WWW.PIC16.COM"
    lcd_enable();

	RW = 0;							//set lcd R/W low
	E = 0;							//set lcd E low
	return;
 }
 


//--------------------------------------
//write a byte to lcd.
void write(char x)
 {
  PORTD=x;                   //data send to PORTD
  RS = 1;                      //is data not command
  RW = 0;                      //is write not read

  E = 1;                       //pull low enable signal
  delay();                   //for a while
  E = 0;                       //pull high to build the rising edge.

	return;    
}

//--------------------------------------
//lcd display setting 
void lcd_enable()
 {
   RS=0;                     //is command not data
   RW=0;                     //is write not read. 

   E=1;                      //pull low enable signal.           
   delay();                  //for a while.                      
   E=0;                      //pull high to build the rising edge
      
	return;
}



 void lcd_line1()
 {
    int i;
    for(i=0;i<16;++i)       //total 16 bytes to display.
       {
         write(number[i]);       //search table to display
       }
	return;
 }

 void lcd_line2()
 {
    int i;
    for(i=0;i<16;++i)       //total 16 bytes to display.
       {
         write(daydate[i]);       //search table to display
       }
	return;
 }


void delay(void)
{
	long int y;
		for(y=0;y<100;y++){}
}

I change:
Port setting, like asm code..
The init of the ds1302, like asm code...
LCD driving as you tell me (if i have done correctly)..
And other little things...
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top