Go Down

Topic: DS1307 adrress register help ! (Read 4986 times) previous topic - next topic

halejandro

Aug 08, 2011, 05:00 am Last Edit: Aug 08, 2011, 05:51 am by halejandro Reason: 1
Hi,
I don't see "0x7F" or "0x3F" in the timekeeper register . What do they mean?
Thx!
I am Learning, please be Patient !

CrossRoads

#1
Aug 08, 2011, 06:01 am Last Edit: Aug 08, 2011, 06:03 am by CrossRoads Reason: 1
0x7F indicate HEX format for 7F, (0111 1111), or decimal 127
0x3F indicate HEX format for 3F, (0011 1111), or decimal 63

Often times it helps to see the numbers that way, especially when the upper 4 bits are indicating something different than the lower 4 bits.
Say perhaps the lower 4 only represented 0-9, and the upper 4 represented 0-5  (000-101) and the 4th bit was some else altogether.

Here is a simple sketch I wrote to set the registers in a DS1307.

To send commands, open the Serial Monitor.
The sketch requests an update every 5 seconds.
Use the following commands:
F0xx [enter] where xx is the high nibble (4 bits) and low nibble per the data sheet.
Seconds starts from power- off as 80, the high bit indicates time is not running.

Code: [Select]

/*
Test of RTC DS1307 via I2C.
Counts
Seconds,
Minutes,
Hours,
Date of the Month,
Month,
Day of the week, and
Year with Leap-Year

56 bytes battery backed RAM
Square Wave Output: Off, 1Hz, and 3 higher frequencies
*/

#include <Wire.h>

//variables
byte seconds_address = 0x00;
byte seconds; // bit 7 = Clock Halt, Enabled = 0, Halt = 1
// bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9
byte minutes_address = 0x01;
byte minutes;  // bits 6-5-4 = tens of minutes, bits 3-2-1-0 = units of minutes
byte hours_address = 0x02;
byte hours;  // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
// bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
// bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)
byte day_week_address = 0x03;
byte day_week = 0; // range 01-07
byte date_month_address = 0x04;
byte date_month = 0; // range 01-31
byte month_address = 0x05;
byte month = 0; // range 01-12
byte year_address = 0x06;
int year = 0; // upper byte 0-9, lower byte 0-9
byte square_address = 0x07;
byte sqwe = 0;  // square wave enable
// Out-0-0-Sqwe-0-0-RS1-RS0
// Out, Sqwe = 0/0 - Square wave output = 0
// Out, Sqwe = 1/0 - Square wave output = 1
// Out, Sqwe = 0/1 or 1/1 - Square wave output per RS1/RS0
// RS1/RS0 = 00 = 1 Hz
// RS1/RSo = 01 = 4 KHz
// RS1/RS0 = 10 = 8 KHz
// RS1/RS0 = 11 = 32 KHz
byte RTC_ram_address = 0x08; //range = 08-63, 0x08-0x3F

int RTC_address = 0x68; // 1101 000

byte incomingCommand = 0;
byte RTC_write_command = 0;
byte RTC_read_command = 0;
byte RTC_ram_command = 0;
// use F0xx, F1xx,F2xx, F3xx, F4xx, F5xx, F6xx, F7xx
// to send one register write commands
// use E0xx to read registers back   << not coded yet, reads them all back every time
// use C0xx to read RAM back           << not coded yet
byte incomingRegister = 0;
byte RTC_register = 0;
byte incomingData = 0;
byte new_data = 0;
byte outgoingData = 0;
int delay_time = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long duration = 5000;

void setup() {
 Wire.begin(); // no address, we are master
 Serial1.begin (57600);  
 Serial1.flush();
 currentMillis = millis();  
}

void loop() {

 if (Serial1.available() >1){
   incomingCommand = Serial1.read();
   //incomingRegister = Serial.read();
   incomingData = Serial1.read();
   Serial1.print ("command ");
   Serial1.println (incomingCommand & 0xF0, HEX);
   Serial1.print ("register ");
   Serial1.println(incomingCommand & 0x0F, HEX);
   Serial1.print ("data ");
   Serial1.println (incomingData, HEX);
 }
 // *******************************************
 RTC_write_command = incomingCommand & 0xF0;  // mask off high byte
 if (RTC_write_command == 0xF0){  // check for Write command
   RTC_register = incomingCommand & 0x0F;  // mask off low btye
   incomingCommand = 0;
   new_data = incomingData;
   Serial1.print (" Sending a command ");
   switch (RTC_register){
   case 0: // write seconds
       Serial1.println ("Seconds ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(seconds_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
     delay (delay_time);
     break;
   case 1: // write minutes
   Serial1.print ("Minutes ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(minutes_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
     delay (delay_time);
     break;
   case 2: // write hours
       Serial1.print ("Hours ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(hours_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
   case 3: // write day
       Serial1.print ("Day ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(day_week_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
   case 4: // write date of month
       Serial1.print ("Day of Month ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(date_month_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
   case 5: // write month
       Serial1.print ("Month ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(month_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
   case 6: // write year
       Serial1.print ("Year ");
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(year_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
   case 7: // write square wave
       Serial1.print ("Square Wave ");
   Serial1.println (RTC_register, HEX);
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(square_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
   case 8: // write RAM
       Serial1.print ("RAM ");
   Serial1.println (RTC_register, HEX);
     Wire.beginTransmission(RTC_address); // select device
     Wire.send(RTC_ram_address);          // queue the register
     Wire.send(new_data);                  // queue data
     Wire.endTransmission();            // send it
    delay (delay_time);
     break;
     // all others,do nothing
     Serial.println ("Invalid command ");
   }  // end Switch
 } // end if command == F
 // ************************************

 currentMillis = millis();
 if ( (currentMillis - previousMillis) >= duration){
   previousMillis = currentMillis;  
   // Reset the register pointer  
   Wire.beginTransmission(RTC_address);  
   Wire.send(0x00);  
   Wire.endTransmission();  

   Wire.requestFrom(RTC_address,8 );  
   seconds = Wire.receive();  
   minutes = Wire.receive();  
   hours = Wire.receive();  
   day_week = Wire.receive();  
   date_month = Wire.receive();  
   month = Wire.receive();  
   year = Wire.receive();  
   sqwe = Wire.receive();

   // Seconds
   // bit 7 = Clock Halt, Enabled = 0, Halt = 1
   // bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9

   // Hours
   // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
   // bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
   // bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

   Serial1.print ("Hrs " );
   Serial1.print (hours, HEX);
   Serial1.print (" Mins ");
   Serial1.print (minutes, HEX);
   Serial1.print (" Secs ");
   Serial1.print (seconds, HEX);
   Serial1.print (" Day ");
   Serial1.print (day_week, HEX);
   Serial1.print (" Date ");
   Serial1.print (date_month, HEX);
   Serial1.print (" Month ");
   Serial1.print (month, HEX);
   Serial1.print (" Year 20");
   Serial1.print (year, HEX);
   Serial1.print (" Square Wave ");
   Serial1.println (sqwe, HEX);

 }
}
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

Code: [Select]
   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); //
   Wire.endTransmission();
}


Oh, you set every address with the datasheet info, that´s good, now I can understand that part, but why does in this sketch, the address of every bit is not the same?
must it be 0x7F and 0x3F or can they be other numbers?    


I am Learning, please be Patient !

CrossRoads

It does not need to be in HEX format, it just makes it easier to see.
For example, to set the seconds, you might think just send over a decimal 57 for example. However, those decimal numbers get converted to binary by the compiler when the code is created;  decimal 57 is 11 1001 in binary, which is HEX 39 (0x39) (use your windows calculator in Scientific view mode to see this - enter a number in one format, and click the circle of other formats).
But if you were to send over 0x39 to the DS1307, your seconds would be set to 39, because the DS1307 uses the upper 4 bits (3) and the lower 4 bits (9) independently.
So instead what you have to send over is 0x57 (0101, decimal 5, and 0111, decimal 7). 0x57 is decimal 87.
So the hex representation (0x##) is convenient to use in certain cases.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

#4
Aug 08, 2011, 07:36 am Last Edit: Aug 08, 2011, 08:01 am by halejandro Reason: 1
Serial1 was not declare in this escope?

In your sketch you´r doing a bitwise AND: IncomingCommand & 0x0F, why?
I am Learning, please be Patient !

CrossRoads

Change Serial1 to just Serial, I was testing my board that has 2 serial port, regular USB and added RS232

Here's my double serial ported board
http://www.crossroadsfencing.com/BobuinoRev17/

    RTC_register = incomingCommand & 0x0F;  // mask off low btye
    incomingCommand = 0;
    new_data = incomingData;
    Serial1.print (" Sending a command ");
    switch (RTC_register){                              << bitwise And force the command to be 00, 01, 02...08  for the command selection here.
    case 0: // write seconds                           << I suppose these could easily have been  case (0xF0):       as well.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

It´s prety cool you´r board!
bitwise AND makes any value 00, 01, 02......08, it is the address that I can send from the serial monitor !
I am Learning, please be Patient !

CrossRoads

Thanks!

And yes.
Iwasn't sending from the IDE serial monitor, I don't know if that sends out straight hex like that. You may have to tweak the command break apart code some.

Try it and see.

Good night!
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

what are you using to send the commands?

I made this sketch but it didn't work, I'm just a beginner! :~

Code: [Select]

#include <Wire.h>
#include <LiquidCrystal.h>

byte hrs, mins, secs;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}

void setup(){
  Wire.begin();
  lcd.begin(16,2); 
       
}

void setDS1307(){
  Wire.beginTransmission(0x68);
  Wire.send(0);
  Wire.send(decToBcd(hrs));
  Wire.send(decToBcd(mins));
  Wire.send(decToBcd(secs));
  Wire.endTransmission();
}

void requestDS1307(byte hours,
byte minutes,
byte seconds){ 
  Wire.beginTransmission(0x68);
  Wire.send(0);
  Wire.endTransmission(); 
 
  Wire.requestFrom(0x68,3);
  hours=bcdToDec(Wire.receive());
  minutes=bcdToDec(Wire.receive());
  seconds=bcdToDec(Wire.receive());
}
 
void loop(){
 
  lcd.setCursor(0,0);
  lcd.print(" ");
  lcd.print(hrs, DEC);
  lcd.print(":");
  lcd.print(" ");
  lcd.print(mins, DEC);
  lcd.print(":");
  lcd.print(" ");
  lcd.print(secs, DEC);
}
I am Learning, please be Patient !

CrossRoads

I had a serial monitor program called RS232
http://www.evmsoft.com/
Your sketch is more complex than mine.

What didn't work?
I would skip the dectobcd stuff, just do everything in hex so you can that the upper nibble and lower nibble have the right data.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

What is the purpose of the square wave?
I am Learning, please be Patient !

CrossRoads

Whatever you'd like. Some folks use the 1Hz as a steady interrupt to do something every second.
Your imagination is the limit for the  higher speeds - maybe to have interrupts at faster rates for more precise timing control.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

#12
Aug 09, 2011, 01:37 am Last Edit: Aug 09, 2011, 01:42 am by halejandro Reason: 1
I´m trying to do a watering controller, I wanna set time/date via switch and that shows the info in a LCD, I read that the square wave output drain the battery faster, what do if I don´t defined it in the code?
Is it possible to use a specific time to activate and deactivate a relay like a time alarm using I2C?
I am Learning, please be Patient !

CrossRoads

Write 0 to the Square waver register, that will turn it off.
On the other hand, the RTV only draws 1.5mA.
You can use the 1/Sec pulse to wake up the uc once a second to check the time, if not the time you want, go back into power down sleep mode until the next 2nd.  Keep going until you reach the turn on/turn off time.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

halejandro

This is what it shows the serial monitor, is it right? I´m sending data in hex but nothing changes !
I am Learning, please be Patient !

Go Up