Go Down

Topic: Adjusting the date on a DS1307 using external buttons? (Read 2556 times) previous topic - next topic

spleen

May 02, 2012, 09:43 am Last Edit: May 02, 2012, 11:06 pm by spleen Reason: 1
Hi all,

Ive undertaken a project to make a clock using the DS1307 RTC chip. I've used these chips before while trying to learn Arduino coding and been generally successful but i'm stumped on part of the code i'm trying to write now. I'd like to use external push buttons to be able to set and adjust the time as a stand alone unit without having to plug into my computer.

I've found some code at this link

http://www.bristolwatch.com/arduino/arduino_ds1307.htm

which is doing pretty much what i want however it only adjusts the hours and minutes. I'd like to be able to adjust the date as well. Ive tried copying the "hours" portion and changing it to month and using a 4th switch (SW03) but although it says that i am adjusting the month in the serial monitor, it doesnt actually change the month on the chip.

I'm also slowly getting my head around binary, dec, bcd and hex etc but cant understand part of the "change time" script at the end. It says

         if ((minutes & 0x0f) > 9) minutes = minutes + 6;

Whats happening here?

Here is the code that i have adjusted. Could someone please take a look and tell me why the month isn't changing even though the serial monitor says it is?

Code: [Select]
#include <Wire.h> // specify use of Wire.h library.

byte blinkPin = 13;
byte SW0 = 4;
byte SW1 = 5;
byte SW2 = 6;
byte SW3 = 7;

void setup()

{
 Wire.begin(); // join i2c bus (address optional for master)
 Serial.begin(9600);
 pinMode(blinkPin, OUTPUT);
 digitalWrite(blinkPin, 0);


 pinMode(SW0, INPUT);  // Set Time (for this use a slide switch)
 pinMode(SW1, INPUT);  // Set Date (for this use a slide switch)
 pinMode(SW2, INPUT);  // N.O. push button switch
 pinMode(SW3, INPUT);  // N.O. push button switch

 digitalWrite(SW0, HIGH); // pull-ups on
 digitalWrite(SW1, HIGH);
 digitalWrite(SW2, HIGH);
 digitalWrite(SW3, HIGH);
}

void loop()
{
 Wire.beginTransmission(0x68);
 Wire.send(0);
 Wire.endTransmission();

 Wire.requestFrom(0x68, 7);
 byte secs = Wire.receive();
 byte mins = Wire.receive();
 byte hrs = Wire.receive();
 byte day = Wire.receive();
 byte date = Wire.receive();
 byte month = Wire.receive();
 byte year = Wire.receive();

 // hours, minutes, seconds

 Serial.print("The time is ");
 if (hrs < 10) Serial.print("0");
 Serial.print(hrs,HEX);    
 Serial.print(":");
 if (mins < 10) Serial.print("0");
 Serial.print(mins, HEX);
 Serial.print(":");
 if (secs < 10) Serial.print("0");
 Serial.println(secs, HEX);

 // use MM-DD-YYYY

 Serial.print("The date is ");
 if (month < 10) Serial.print("0");
 Serial.print(month,HEX);    
 Serial.print("-");
 if (date < 10) Serial.print("0");
 Serial.print(date, HEX);
 Serial.print("-");
 Serial.print("20");
 if (year < 10) Serial.print("0");
 Serial.println(year, HEX);
 Serial.println();


 if (!(digitalRead(SW0))) set_time(); // hold the switch to set time
 delay(1000);    //wait a second before next output
 toggle(blinkPin);
 
 
}


// toggle the state on a pin
void toggle(int pinNum)
{  
 int pinState = digitalRead(pinNum);
 pinState = !pinState;
 digitalWrite(pinNum, pinState);
}




void set_time()   {
 byte minutes = 0;
 byte hours = 0;
 byte month = 0;

 
 {
   while (!digitalRead(SW0))  // set time switch must be released to exit
   {
   while (!digitalRead(SW1)) // set minutes
   {
     minutes++;          
     if ((minutes & 0x0f) > 9) minutes = minutes + 6;
     if (minutes > 0x59) minutes = 0;
     Serial.print("Minutes = ");
     if (minutes <= 9) Serial.print("0");
     Serial.println(minutes, HEX);

     delay(200);
   }

   while (!digitalRead(SW2)) // set hours
   {
     hours++;          
     if ((hours & 0x0f) > 9) hours =  hours + 6;
     if (hours > 0x23) hours = 0;
     Serial.print("Hours = ");
     if (hours <= 9) Serial.print("0");
     Serial.println(hours, HEX);
     delay(200);
   }
   
   while (!digitalRead(SW3)) // set date
   {
     month++;          
     if ((month & 0x0f) > 9) month =  month + 6;
     if (month > 0x12) month = 0;
     Serial.print("month = ");
     if (month <= 9) Serial.print("0");
     Serial.println(month, HEX);
     delay(200);
   }
   }
}

   Wire.beginTransmission(0x68); // activate DS1307
   Wire.send(0); // where to begin
   Wire.send(0x00);          //seconds
   Wire.send(minutes);          //minutes
   Wire.send(0x80 | hours);    //hours (24hr time)
   Wire.send(0x06);  // Day 01-07
   Wire.send(0x01);  // Date 0-31
   Wire.send(0x05);  // month 0-12
   Wire.send(0x09);  // Year 00-99
   Wire.send(0x10); // Control 0x10 produces a 1 HZ square wave on pin 7.
   Wire.endTransmission();
     
}



Also, why is it that the Wire.send code at the end uses (0x09) for the year ( i believe this is somehow the address but looking at the datasheet, can't figure out how) but (minutes) for the minutes?

Thanks so much everyone. Any help is always appreciated!

edit: changed 31 to 12 in the change month part

PaulS

Quote
Could someone please take a look and tell me why the month isn't changing even though the serial monitor says it is?

Without seeing your serial output? No, not really.

Quote
Also, why is it that the Wire.send code at the end uses (0x09) for the year ( i believe this is somehow the address but looking at the datasheet, can't figure out how) but (minutes) for the minutes?

It's your code. You tell us why you do it that way.

P.S. The comments answer your question.

pylon

Trying to interpret your code you're trying to get the day of month with the third button but you call it month (months are cycling at 12 and not 31). Additionally you have the code to enter the day of month but you don't transmit it to the 1307. The date transmitted is always 1st May 09. Also with your code you must have a serial connection to your PC to see what value you got. Why don't you use that connection for setting the date directly?

spleen

PaulS,

Thanks for your reply. Its not actually my code, i'm just trying to apply it to my project. I'm just having some troubles understanding it in the first place which is why im here asking questions.

Pylon,

Thanks for pointing that out. I had initially set it to 12 months but messed the code up so copied that portion back in from elsewhere. Forgot to change it to 12 before posting  :smiley-red:

Also...... THANKYOU! I didn't realise that the wire.send lines at the end were sending the actual figure and not some strange hex address. I thought those bits i.e wire.send(0x09) were sending hex address parts to the ds1307. Ive now changed it to wire.send(month) and it works much gooder!

Lastly, im still not sure what this line in the code is doing??? 

if ((minutes & 0x0f) > 9) minutes = minutes + 6;

Mainly the 0x0f part. The rest of the code im getting my head around ok.

I'll keep plodding away and be back at my next hurdle!

Thanks team

Nick Gammon

#4
May 02, 2012, 11:18 pm Last Edit: May 03, 2012, 01:04 am by Nick Gammon Reason: 1
The chip uses BCD.

http://en.wikipedia.org/wiki/Binary-coded_decimal

So the next number up from 9 is 10 but 10 in hex (ie. go from 0x09 to 0x10). That is a jump of 6 on top of the original add of 1 (ie add 6 to 0x0A to give 0x10).

Quote
Mainly the 0x0f part.


That means in this context "the low order digit". So for example if the minutes were 0x29, and we added 1, we get 0x2A. But we need 0x30, so we test the low order 4 bits (0x0A) and see if they exceed 9, which they do, so we add 6, giving 0x30 as the result.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

spleen

Excellent! Thank you Nick!

That's exactly the kick in the pants I was looking for! Wow, BCD and HEX is easy! Erhum, well maybe not but i certainly see whats happening there now!

Cheers!

Go Up