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.

Clock

Status
Not open for further replies.
Can we use bcd2dec function as below and avoid then having "type" as parameter ?

If so it shoud simplify the rest of code and avoid some shifting and masking commands ?

Code:
unsigned char bcd2dec(unsigned char val)
{
  return ((val/0x10*0xA)+(val%0x10));
}

------

Regarding the reading function byte per byte i found the source here : ( see section 10.7 )

https://books.google.fr/books?id=CB9GaAU1dwsC&pg=PA489&lpg=PA489&dq=ds1306.c&source=bl&ots=Hfj8B1oy5g&sig=cPxc-cI0quvBR27qTD8ke3lLESc&hl=fr&ei=9VkYTY2mHISb8QPm5_iKCg&sa=X&oi=book_result&ct=result&resnum=8&ved=0CFsQ6AEwBzgU#v=onepage&q&f=false
 
Last edited:
maybe... i havent tested it but... i would simply use....

Code:
unsigned char bcd2dec(unsigned char val)
{
  return (((val>>4)*10)+(val & 0x0F));
}

But we still need a type ... mainly because this code works perfect perhaps for SECONDS and MINUTES but for HOURS we only use 6 bits BIT0 to BIT5...

Bits 0 to 3 are Lower part of hour
Bit 4 only is the Upper Hour in 12 Hr mode
or
Bits 4 & 5 are used in 24 hour mode

Bits 6 & 7 are used for other purpose so including them in the math will throw off the value a lot

Code:
unsigned char bcd2dec(unsigned char val, char type)
{
  if(type == 'h')
    return ((((val>>4) & 0x03)*10)+(val & 0x0F));
  else 
    return (((val>>4)*10)+(val & 0x0F));
}
 
Last edited:
Thanks,

How knowing if a 'h' type should or not be used when you call the bcd2dec function ?

I mean, then time goes through the code does not know if time is from 1 to 9 o'clock or from 10 to 12 o'clock ...

Do you always check bit 4 in the main loop ?

I do not see where you do this in your code, can you show me please ?


In fact, i will try to reduce your code because i do not need LCD display and buttons.
i only need date & time setting + date & time readings in 24h format.
Alarms should also be usefull for me.
 
Im fixing my toilet right not but ill write some quick info ...

If you take a look at the datasheet about the registers...

ds-jpg.49381


To get the seconds we need to read register 0x00
To get the minutes we need to read register 0x01
To get the Hours we need to read register 0x02

Lets call these variables bcdSec,bcdMin,bcdHour...

Now to convert them to decimal so we can add or subtract easier we have to do a BCD to DEC conversion.

Using this code:
Code:
unsigned char bcd2dec(unsigned char val)
{
  return (((val>>4)*10)+(val & 0x0F));
}

we can convert seconds and minutes to decimal since these registers use the upper 4 bits for 1 number and the lower 4bits for another number...

For example if the time is 10:20:40 PM

The bcdSec variable will hold the seconds which is 0x40
This is the same for bcdMin... It will have 0x20
If using the 24 hour mode bcdHour will be 0x10
BUT....
if using the 12 hour mode bcdHour will be 0x70

Basically in 12 Hour mode our code has to check the AM PM bit... and also the 12hr mode bit...

so we have to take care of that



LONG STORY SHORT... Since your using 24 hour mode. You can use the bcd2dec without a type:

Code:
unsigned char bcd2dec(unsigned char val)
{
  return (((val>>4)*10)+(val & 0x0F));
}
 
Last edited:
Hello Jason, all

Regarding dec to bcd function, its name is uint2bcd
actually parameter is unsigned char ival.

So if i understand well, there is no need to convert char to int prior using this function ?

if parameter is an unsigned char, shouldn't we name the function uchar2bcd instead ?
Code:
unsigned char uint2bcd(unsigned char ival)
{
	return ((ival / 10) << 4) | (ival % 10);
}

--------------------------

In fact i'm trying to adapt your working to my application ( i do not need buttons for time setting and LCD )

i defined tables that will contents the time to set :
One for DEC values ( this one will be filled-in first by a webserver )
another one for BCD values.
Code:
unsigned char DEC_set_time_rtc[19] = "- --/--/-- --:-- --";
unsigned char BCD_set_time_rtc[];
Let's say DEC_set_time_rtc is already filled-in as follow :
DEC_set_time[2] and DEC_set_time[3] are the DATE values : Decimal and Unit

How should i convert each in BCD and send the result to BCD_set_time_rtc[2] and BCD_set_time_rtc[3] ?

Is this correct ? my problem is sending BOTH BCD values Decimal and Unit to the RTC register :

Code:
BCD_set_time[2] = uint2bcd(DEC_set_time_rtc[2]);	
BCD_set_time[3] = uint2bcd(DEC_set_time_rtc[3]);

// Send the result in RTC register ( this is done in 2 steps , maybe not correct ? )
RTC_write(0x84, BCD_set_time_rtc[2]);
RTC_write(0x84, BCD_set_time_rtc[3]);   // < -- Will this command not overwrite the previous one just sent ?
 
Last edited:
Hello

I need your help, please :

I stored all my my DEC value in a table :

Code:
unsigned char DEC_set_time_rtc[19] = "- --/--/-- --:-- --";

DEC_set_time_rtc[0] is DAY
DEC_set_time_rtc[1] is ' ' space character
DEC_set_time_rtc[2] is DATE (x10)
DEC_set_time_rtc[3] is DATE (unit)
DEC_set_time_rtc[4] is '/' character
DEC_set_time_rtc[5] is MONTH (x10)
DEC_set_time_rtc[6] is MONTH (unit)
DEC_set_time_rtc[7] is '/' character
DEC_set_time_rtc[8] is YEAR (x10)
DEC_set_time_rtc[9] is YEAR (unit)
DEC_set_time_rtc[10] is ' ' space character
DEC_set_time_rtc[11] is HOUR (x10)
DEC_set_time_rtc[12] is HOUR (unit)
DEC_set_time_rtc[13] is ':' character
DEC_set_time_rtc[14] is MIN (x10)
DEC_set_time_rtc[15] is MIN (unit)
DEC_set_time_rtc[16] is ' ' space character
DEC_set_time_rtc[17] is SEC (x10)
DEC_set_time_rtc[18] is SEC (unit)
DEC_set_time_rtc[19] is '\0' character

Then i convert each values to BCD and store each in a BCD table :
Code:
unsigned char BCD_set_time_rtc[] = "- --/--/-- --:-- --";

Code:
BCD_set_time_rtc[0] = dec2bcd(DEC_set_time_rtc[0]
BCD_set_time_rtc[2] = dec2bcd(DEC_set_time_rtc[2]);
BCD_set_time_rtc[3] = dec2bcd(DEC_set_time_rtc[3])
... etc ...

Once my BCD table is filled-in and ready, i would like to know how i should send the high and low bytes to registers.

How should i concatenate high and low bytes and send them to register ?

I think about this, but not sure it is the good way to proceed :
Code:
char tmp;
BCD_set_time_rtc[2] = (tmp << 4);
BCD_set_time_rtc[3] = ????? i don't know

RTC_write(0x84, tmp);

I'm not confortable with masking and shifting. :eek:
Many thanks for your help,
 
Last edited:
I'm not confortable with masking and shifting. :eek:
Well, now's the perfect time to get comfortable with it. Dive in and play with it a bit and you'll find it's really not difficult at all. It'll only take you an hour or two tops (more likely a LOT less) to figure it out. Dealing with displays (7-segs and GLCDs) you'll use it constantly. Also useful for doing SPI-type stuff, again for displays and other things.
 
you have to send the decimal values to the RTC not ASCII ok..

Code:
char upper;
char lower;
char bcdOut;

upper = BCD_set_time_rtc[2] - 0x30;
lower = BCD_set_time_rtc[3] - 0x30;
bcdOut = (upper <<4) + lower ;

RTC_write(0x84, bcdOut );

Something like that... Shifting and masking is so easy!

For this example we had to first convert the ASCII back to decimal format which is as simple as deducting 0x30 from it.
Then we have to take the 2 numbers and have them into separate variables for clarity ...
now that we have 2 bytes and they have the decimal version of our time... upper and lower
we have to convert these to 1 bcd byte...

remember a BCD byte for the seconds register is ..
HIGH---LOW
0000 - 0000

so lets say its 21 seconds... our upper and lower should hold the below values after we remove the ascii part
upper = 2
lower = 1

and in binary:
upper = 0000-0010
lower = 0000-0001

Remember how our register works... we have to use
upper - lower
0000 - 0000

so we simply make a new variable call it.. bcdSec
Code:
bcdSec = upper << 4; //This loads the upper byte into bcdSec then shifts bcdSec 4 bits to the left 
//bcdSec should be 0x20 (binary 0010-0000)

bcdSec += lower; //This adds our lower byte in..
bcdSec should now be 21 ( 0010-0001 )
 
Last edited:
Many thanks Jason, the BCD conversion is now working perfectly. :)

How do you display current time once time is set ?
I mean, did you create an infinite loop that will always request values from each registers and do a BCD to DEC -> ASCII conversion ?
doing this from an infinite loop with check RTC registers many time per second, maybe it is not a good way to proceed ?

Maybe best is to go with an interrupt sent from RTC to the Pic ?
Actually, I would like to display time in "real time" .
 
what i do is store the Seconds value and everytime i check the clock i determine if the second has changed and if so update the time. this way even if i check the clock 20 times in 1 second i draw it to lcd 1 time
 
Hello,

I've finish to write my DS1305/DS1306 but i'm not able to communicate with the RTC, Maybe SPI is not well initiated or maybe SPI W/R functions have problem ?

My Pic is 18F97J60 ( 40 Mhz clock )

When i write a value to RTC register and then try to read it back i always get 0x00 . :(
I should find there seconds getting incremented there instead ...

I first initiated SPI in mode 1 and wrote RTC control register to clear WP flag with SPI_RTC_Init();

SPI test from main loop :
Code:
        RTC_write(0x80, 0b00000010);               // set second register = 3
       
        Nop();Nop();Nop();

        second_from_rtc = RTC_read(0x00);
Any help will be much appreciated.
Many thanks,


Here are my SPI functions :

DS1306.c

Code:
#define __DS1306_C

#include "DS1306.h"
#include <stdio.h>


// *******************************/
//             VARIABLES
// *******************************/
unsigned char BCD_read_time_rtc[];
unsigned char rtc_ctrl_register;
// *******************************/
//      Init SPI configuration
// *******************************/
void SPI_RTC_Init(void)
{
 	BYTE SPICON1Save;

	RTC_CS_IO = 0;
	RTC_CS_TRIS = 0; 						// Pic CS pin is output

#if defined(__18CXX)						
	RTC_SCK_TRIS = 0;
	RTC_SDO_TRIS = 0;
	RTC_SDI_TRIS = 1;
#endif

// Save current SPI config	
	SPICON1Save = SSP1CON1;					// Save current SPI setting
// End Save SPI config

// Configure SPI
	RTC_SPI_ON_BIT = 0;						// Stop SPI
    RTC_SPICON1 = RTC_SPICON1_CFG;			// Apply new SPI settings for RTC
	RTC_SPI_ON_BIT = 1;						// Start SPI
    RTC_SPI_IF = 0;							// Clear SPI Flag

#if defined(__18CXX)
	RTC_SPISTAT = RTC_SPISTAT_CFG;			// Apply new SPISTAT register config
#endif


// Send control command : disable WP, enable 1 Hz output.	
	RTC_write(WR_CTRL_REGISTER, 0b00000000);
	RTC_write(WR_CTRL_REGISTER, 0b00000100);
	rtc_ctrl_register = RTC_read(RD_CTRL_REGISTER);

 		 		 
// Restore SPI config
	SSP1CON1 = SPICON1Save;					// Restore old SPI setting
// End Restore SPI config
}



/************************************
    Read a Register off the DS1306
************************************/
unsigned char RTC_read(unsigned int address)
{
	unsigned char p;
	BYTE SPICON1Save;

// Save SPI config	
   SPICON1Save = SSP1CON1;					// Save current SPI setting
// End Save SPI config

// Configure SPI
	RTC_SPI_ON_BIT = 0;						// Stop SPI
    RTC_SPICON1 = RTC_SPICON1_CFG;			// Apply new SPI settings for RTC
	RTC_SPI_ON_BIT = 1;						// Start SPI
	
    	RTC_CS_IO = 1;						// Enable CS
		RTC_SPI_IF = 0;						// Clear SPI Flag

		RTC_SSPBUF = address;				// Send SPI command
		while (!RTC_SPI_IF);				// Wait until address is shifted out
		RTC_SPI_IF = 0;
		p = RTC_SSPBUF;                    	// Get register value

		return(p);							// Return read value
		RTC_CS_IO = 0;						// Disable CS

// Restore SPI config
	SSP1CON1 = SPICON1Save;					// Restore old SPI setting
// End Restore SPI config
}


/************************************
      Write to DS1306 Register 
************************************/
void RTC_write(unsigned int address, unsigned char value)
{
  BYTE SPICON1Save;
  volatile BYTE Dummy;

// Save SPI config	
   SPICON1Save = SSP1CON1;					// Save current SPI setting
// End Save SPI config

// Configure SPI
	RTC_SPI_ON_BIT = 0;						// Stop SPI
    RTC_SPICON1 = RTC_SPICON1_CFG;			// Apply new SPI settings for RTC
	RTC_SPI_ON_BIT = 1;						// Start SPI

    RTC_CS_IO = 1;							// Enable CS
    RTC_SPI_IF = 0;							// Clear SPI Flag

    RTC_SSPBUF = address;                	// Transmit address	
    while(!RTC_SPI_IF);						// Wait until data is shifted out
    RTC_SPI_IF = 0;
	Dummy = RTC_SSPBUF;						// Clear SPI Buffer
 
    RTC_SSPBUF = value;						// Transmit value
    while(!RTC_SPI_IF);						// Wait until data is shifted out
	RTC_SPI_IF = 0;
    Dummy = RTC_SSPBUF;						// Clear SPI Buffer
  
    RTC_CS_IO = 0;							// Disable CS

// Restore SPI config
	SSP1CON1 = SPICON1Save;					// Restore old SPI setting
// End Restore SPI config
}

DS1306.h
Code:
#ifndef _RTC_H
#define _RTC_H


// RTC pins
#define RTC_CS_IO                   (LATGbits.LATG3)
#define RTC_CS_TRIS		(TRISGbits.TRISG3)
#define RTC_SCK_TRIS		(TRISCbits.TRISC3)
#define RTC_SDI_TRIS		(TRISCbits.TRISC4)
#define RTC_SDO_TRIS		(TRISCbits.TRISC5)

#define RTC_SPI_IF            (PIR1bits.SSPIF)
#define RTC_SSPBUF          (SSP1BUF)
#define RTC_SPISTAT         (SSP1STAT)
#define RTC_SPICON1         (SSP1CON1)
#define RTC_SPI_ON_BIT     (SSP1CON1bits.SSPEN)


//////////////////////////
//     SPI settings     //
//////////////////////////
    #define RTC_SPISTAT_CFG  		(0x40)  	// Sample at middle of data output time (SMP, bit7 = 0) - Tx on transition from active to idle clock (CKE, bit 6 = 1)
    #define RTC_SPICON1_CFG  		(0x21)      // SSPEN bit is set, SPI in master mode, FOSC/16, IDLE state is low level


// RTC SPI opcodes:
#define WR_CTRL_REGISTER	0x8F 					// Write CTRL register address
#define RD_CTRL_REGISTER	0x0F 					// Read CTRL register address

#define RD_SEC			0x00
#define WR_SEC			0x80
#define RD_MIN			0x01
#define WR_MIN			0x81
#define RD_HOUR  		0x02
#define WR_HOUR		0x82
#define RD_DAY  		        0x03
#define WR_DAY			0x83
#define RD_DATE			0x04
#define WR_DATE			0x84
#define RD_MONTH		0x05
#define WR_MONTH		0x85
#define RD_YEAR			0x06
#define WR_YEAR			0x86

#define RD_ALR_SEC		0x07
#define WR_ALR_SEC		0x87
#define RD_ALR_MIN		0x08
#define WR_ALR_MIN		0x88
#define RD_ALR_HOUR  	        0x09
#define WR_ALR_HOUR		0x89
#define RD_ALR_DAY  	        0x0A
#define WR_ALR_DAY		0x8A
#define RD_ALR_DATE		0x0B
#define WR_ALR_DATE		0x8B
#define RD_ALR_MONTH	0x0C
#define WR_ALR_MONTH	0x8C
#define RD_ALR_YEAR		0x0D
#define WR_ALR_YEAR		0x8D


//////////////////////////
//       Variables      //
//////////////////////////

extern unsigned char BCD_set_time_rtc;

extern unsigned char read_ascii_Day;
extern unsigned char read_ascii_Date;
extern unsigned char read_ascii_Month;
extern unsigned char read_ascii_Year;
extern unsigned char read_ascii_Hour;
extern unsigned char read_ascii_Min;
extern unsigned char read_ascii_Sec;

extern unsigned char BCD_Day;
extern unsigned char BCD_Date;
extern unsigned char BCD_Month;
extern unsigned char BCD_Year;
extern unsigned char BCD_Hour;
extern unsigned char BCD_Min;
extern unsigned char BCD_Sec;

//////////////////////////
//       Prototypes     //
//////////////////////////

void SPI_RTC_Init(void);

unsigned char RTC_read(unsigned int address);

void RTC_write(unsigned int address, unsigned char value);

#endif // _RTC_H
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top