Go Down

Topic: real time clock ds 1307 (Read 7296 times) previous topic - next topic

woo_oow

Hi,

im trying to use the ds 1307 realtimeclock
(datasheet:http://www.reichelt.de/?SID=208PfrUqwQARQAAH6JtH4852ebc6602248fba4d6fe06e77038d10;ACTION=7;LA=6;OPEN=1;INDEX=0;FILENAME=A200%252FDS_1307.pdf),
connected via i2c two wire bus
im able to set the the time (it seems like it works) , but if i try to read from the ds 1307 i get always the time and date i set up in 1307 memory. There is no increasement of time.
I use a 32.768 kHz quartz crystal connected to he x1/x2 pins of the RTC, if I remove it there is the same behaviour, nothing changes.

Here is the code I use:


Code: [Select]


#include <Wire.h>

byte _sec =4;
byte _min=8;
byte _hour=3;
byte _day =5;
byte _date=2;
byte _month=6;
byte _year =7;

boolean state;

void setup()
{
 Wire.begin();        // join i2c bus (address optional for master)
 Serial.begin(9600);
 pinMode(13, OUTPUT);
 Wire.beginTransmission(104); // transmit to device #104, the ds 1307

   // **********setting time**************
// Wire.send(sendung, 8); //sec
 Wire.send(_sec); //sec
 Wire.send(_min); //min
 Wire.send(_hour);  //hour
 Wire.send(_day);  //day
 Wire.send(_date); //date
 Wire.send(_month);  //month
// Wire.send(_year);  //year
 

     
                 
 Wire.endTransmission();    // stop transmitting
}

void loop()
{

delay(100);

 Wire.requestFrom(104, 6);    // request 6 bytes from slave ds1307
 while(Wire.available())    // slave may send less than requested
 {
   digitalWrite(13,state); //LED on pin 13 to see if there is activity
   state=!state;
   int c = Wire.receive();
   Serial.println(c);  

 }

delay (100);
}



thanks for help


woo

Daniel

#1
Jun 04, 2007, 12:44 am Last Edit: Jun 04, 2007, 12:50 am by Daniel Reason: 1
hi

check page 7 4 of the datasheet:

"Please note that the initial power on state of all registers is not defined.  Therefore it is important to
enable the oscillator (CH bit=0) during initial configuration. "

You could also check this page on using the Dallas DS1306.
D

woo_oow

Thanks for the fast reply,

I read that, bit 7 of register 00.
But isnt it the same as the "seconds" Register? So it will be set with the _sec value, which is set to 4 (binary 00000010) at the moment?
How to Adress the different registers, just by executing eg 3 times a Wire.send() line to acces the 3rd register?


best
woo

Daniel

hi

not sure.. for inspiration, i would have a look at the  DS1306 tutorial.

D

pha555


Many 32 kHz crystals are not designed to operate at the 6 (or 12) pFd input C of the DS1307.

You might add a 20 pFd cap from each side of the crystal to GRD.

Your CH is being set to 0 which is correct.

pha(at)phanderson.com

woo_oow

I checked the Crystal it has a capacity of 12 pf - should work. But I tried as well with 22pF caps. Still the same.
In some other forums about microkontrollers they write abut that you have to send a 'TWI write' first, then 'repeated (TWI) start' then you can Read the register.  
I guess i need to set the pointer without writing directly to the register.

any ideas?

best
woo

libhart

I just got my 1307 working with the arduino.  I assume you have the resistors tying your SDA and SDL lines to 5V?  This is critical.  Otherwise you won't get reliable reads.

Also, the bigger problem is in your code.  I followed your code at first and got the same result but wondered how the DS1307 knew what address I wanted to read.  That's the problem.  Before you read you want to do at least one write to send in an address which will set the register pointer on the DS1307.  Page 8 of the datasheet glosses over this so quickly that it's easy to miss.  So in your setup function, first do a Wire.send(0x00) to set the register address to 0, then set the time.  At the beginning of your loop function, do a beginTransmission, send another 0x00, then an endTransmission.  Then requestFrom, etc, etc. and the while loop.  You should then be able to see the clock ticking.  Remember though that you're reading out a byte at a time in BCD format, so if you just print the byte the seconds will count to 89 and skip numbers in between.

woo_oow

This sounds great!
Thanks a lot I'll try it soon. I was wondering as well about setting the register pointer, but i didn't get a clue how to do... but this looks good.

thanks again!

woo

libhart

This code is pretty functionally solid so I figured I'd post it.  This will read the date and time and print it out on the serial port.  Even before you set the time you should be able to load this and see it tick.

#include <Wire.h>

int hour;
int minute;
int second;
int month;
int day_of_week;
int day;
int year;

char* dow[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void setup()
{
 Serial.begin(9600);
 Wire.begin();
}

void loop()
{
 // Below required to reset the register address to 0.
 Wire.beginTransmission(104); // transmit to device #104, the ds 1307
 Wire.send(0x00);
 Wire.endTransmission();    // stop transmitting

 Wire.requestFrom(104, 7);    // request 7 bytes from slave ds1307, we'll assume it'll send them all even though it doesn't have to
 second = Wire.receive();
 minute = Wire.receive();
 hour = Wire.receive();
 day_of_week=Wire.receive();
 day = Wire.receive();
 month = Wire.receive();
 year = Wire.receive();

 // Convert all the BCD values that might have "tens" to decimal.  Most arduino folks do this w/shifts but this just looks easier to me.
 hour=hour/16 * 10 + hour % 16;
 minute=minute/16 * 10 + minute % 16;
 second=second/16 * 10 + second % 16;
 day=day/16 * 10 + day % 16;
 month=month/16 * 10 + month % 16;
 year=2000 + year/16 * 10 + year % 16;
 
 Serial.print(hour);
 Serial.print(":");
 if (minute < 10) { Serial.print("0"); }
 Serial.print(minute);
 Serial.print(":");
 if (second < 10) { Serial.print("0"); }
 Serial.print(second);
 Serial.print(" ");
 Serial.print(dow[day_of_week-1]);  // array is 0-6, but the dow register holds 1-7, so subtract 1.
 Serial.print(", ");
 Serial.print(month);
 Serial.print("/");
 Serial.print(day);
 Serial.print("/");
 Serial.print(year);
 Serial.print("\n");
 delay(1000);
}

lucasvickers

So you guys are saying you should have a resistor on your Analog 4 and 5 pins (which connect to the SCL and SDA) ?
I am not using any resistors, but using this same exact code and I get no response from the RTC module.

I bought the module from sparkfun all wired up so I don't think it's because of an incorrect oscillator or anything.

Thanks,
Lucas

lucasvickers

I just caught you guys are probably talking about a pullup resistor!

JB

#11
Dec 08, 2008, 05:51 am Last Edit: Dec 08, 2008, 05:53 am by jbennett Reason: 1
Apologies for reviving an old thread, but it's the closest topic I could find to my problem, and I'm using essentially the code above to talk to my DS1307 mini board.

I have a sketch which (among other things) monitors & calculates the maximum & minimum daily temperatures, then writes the date (dd/mm/yy), MaxTemp & MinTemp to the Arduino's onboard EEPROM memory. This is working fine, but I thought I'd try to add the ability to display the recordings when I connect the USB cable and press 'd' (for 'dump data').

Currently I have to upload a small sketch to display the data, then re-load the original sketch. For simplicity I'd much rather just press 'd' & cut and paste the resulting data, without having to 'stop' the original program. Unfortunately, it seems that trying to monitor the serial port via Serial.read() somehow messes with the SDA/SCL lines. The standard output from my sketch looks like this:
Code: [Select]
15:05:37 on Monday, 8/12/2008 - Current temperature is: 24.7; Max - 23.0, Min - 22.0
15:05:38 on Monday, 8/12/2008 - Current temperature is: 25.7; Max - 24.0, Min - 22.0
15:05:39 on Monday, 8/12/2008 - Current temperature is: 26.4; Max - 25.0, Min - 22.0
15:05:40 on Monday, 8/12/2008 - Current temperature is: 26.9; Max - 26.0, Min - 22.0
15:05:41 on Monday, 8/12/2008 - Current temperature is: 26.8; Max - 26.0, Min - 22.0
15:05:42 on Monday, 8/12/2008 - Current temperature is: 26.6; Max - 26.0, Min - 22.0

When I add in the code to monitor for serial input, the clock output becomes something nonsensical, like this:
Code: [Select]
8:00:00 on I, 8/3/2000 - Current temperature is: 23.5; Max - 0.0, Min - 22.0
8:00:00 on I, 8/3/2000 - Current temperature is: 24.6; Max - 0.0, Min - 22.0
8:00:00 on I, 8/3/2000 - Current temperature is: 25.3; Max - 0.0, Min - 22.0
8:00:00 on I, 8/3/2000 - Current temperature is: 25.9; Max - 0.0, Min - 22.0
8:00:00 on I, 8/3/2000 - Current temperature is: 26.4; Max - 0.0, Min - 22.0
8:00:00 on I, 8/3/2000 - Current temperature is: 26.8; Max - 0.0, Min - 22.0

The data dump does work when I press 'd', but obviously it's pretty much useless if it messes with the clock. As a newbie I'm chuffed to have achieved this functionality, and won't be too fussed if there's no way around this, but you guys seem to be able to solve just about everything else that comes up!! :)

Thanks for reading!

JB

PS - I haven't posted the code because it's pretty long, so let me know if you need it...
JB

mikalhart

#12
Dec 08, 2008, 07:01 am Last Edit: Dec 08, 2008, 07:02 am by mikalhart Reason: 1
It appears not to be just messing with the clock.  Note that the min temperature is also "messed with".  Is it the new sketch still storing the data in the eeprom?  If so, does the original "dump" sketch display the correct values, or is the eeprom corrupted also?

You say the code is pretty big.  Is it too big?  You sometimes see weirdness like this when you unexpectedly run out of memory.  You may have to post the code after all.

Regards,

Mikal

JB

Hi Mikal,

The min temp is actually OK - the grabs I've shown are when the program is displaying output every second, and the Min Temp is calculated over the past 60 seconds.

Well, in the hope that it helps, here's the code...

#include <EEPROM.h>
#include <Wire.h>
#include <math.h>
#include <DateTime.h>

int potPin = 0;                                 // input read pin for LM35 is Analog Pin 0
float temperature = 0;                             // variable which will be calculated in process
long val=0;                                 // variable to store the value coming from the sensor
#define TRIGGER_INACTIVE 0xffffffff              // a special value that indicates that no trigger is active.
unsigned long  endTrigger = TRIGGER_INACTIVE;
#define ThermistorPIN 0                          // Analog Pin 0
double temp;

int MinTemp = 40;       // setting a high initial value makes for easy comparison in the loop,
int MaxTemp = 0;        // and vice versa for a low initial MaxTemp.
int WriteAddress = 0;   // initial address for EEPROM writes.
int ReadAddress = 0;
byte value;             // will be used
int incomingByte = 0;      // for incoming serial data

int hour;
int minute;
int second;
int month;
int day_of_week;
int day;
int year;

char* dow[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

double Thermistor(int RawADC) {
//    Inputs ADC Value from Thermistor and outputs Temperature in Celsius
//    requires: include <math.h>
//    Utilizes the Steinhart-Hart Thermistor Equation:
//    Temperature in Kelvin = 1 / {A + B[ln(R)] + C[ln(R)]^3}
//    where A = 0.001129148, B = 0.000234125 and C = 8.76741E-08
long Resistance;  double Temp;  // Dual-Purpose variable to save space.
Resistance=((10240000/RawADC) - 10000);  // Assuming a 10k Thermistor.  Calculation is actually: Resistance = (1024/ADC)
Temp = log(Resistance); // Saving the Log(resistance) so not to calculate it 4 times later. // "Temp" means "Temporary" on this line.
Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));   // Now it means both "Temporary" and "Temperature"
Temp = Temp - 273.15;  // Convert Kelvin to Celsius                                         // Now it only means "Temperature"
return Temp;  // Return the Temperature
}

void printDouble(double val, byte precision) {
 // prints val with number of decimal places determine by precision
 // precision is a number from 0 to 6 indicating the desired decimal places
 // example: printDouble(3.1415, 2); // prints 3.14 (two decimal places)
 Serial.print (int(val));  //prints the int part
 if( precision > 0) {
   Serial.print("."); // print the decimal point
   unsigned long frac, mult = 1;
   byte padding = precision -1;
   while(precision--) mult *=10;
   if(val >= 0) frac = (val - int(val)) * mult; else frac = (int(val) - val) * mult;
   unsigned long frac1 = frac;
   while(frac1 /= 10) padding--;
   while(padding--) Serial.print("0");
   Serial.print(frac,DEC) ;
 }
}

void TakePhoto() {
 int FanStatus = digitalRead(3);
 digitalWrite(3,LOW); // first, switch off the fans
 Serial.print(" Fans switched off - status stored as ");
 if (FanStatus == 0) Serial.println("OFF");
 else Serial.println("ON");
 digitalWrite(9,HIGH); // then send power to the camera
 Serial.println("  Power to Camera");
//  delay(500); // time for current to get to camera - not sure if this is needed...
 digitalWrite(6,HIGH); // trigger the solenoid for 100 msec
 Serial.println("   Solenoid triggered");
 delay(100);
 digitalWrite(6,LOW);
 delay(15000); // wait 15 seconds for the camera to take a photo then shutdown
 digitalWrite(9,LOW);
 Serial.println("    Camera power switched off");
 digitalWrite(3,FanStatus); // return fans to initial status
 Serial.print(" Fans returned to ");
 if (FanStatus == 0) Serial.print("OFF");
 else Serial.print("ON");
 Serial.println(" status");
}

void setup()
{
pinMode(3,OUTPUT); // FANS control - YELLOW
digitalWrite(3,LOW);
pinMode(6,OUTPUT); // SOLENOID power control - WHITE
digitalWrite(6,LOW);
pinMode(9,OUTPUT); // CAMERA control - BLUE
digitalWrite(9,HIGH);
pinMode(13,OUTPUT);
Serial.begin(115200);
Wire.begin();
}

void loop() {

// Below required to reset the register address to 0.
Wire.beginTransmission(104); // transmit to device #104, the ds 1307
Wire.send(0x00);
Wire.endTransmission();    // stop transmitting

Wire.requestFrom(104, 7);    // request 7 bytes from slave ds1307, we'll assume it'll send them all even though it doesn't have to
second = Wire.receive();
minute = Wire.receive();
hour = Wire.receive();
day_of_week=Wire.receive();
day = Wire.receive();
month = Wire.receive();
year = Wire.receive();

// Convert all the BCD values that might have "tens" to decimal.
hour=hour/16 * 10 + hour % 16;
minute=minute/16 * 10 + minute % 16;
second=second/16 * 10 + second % 16;
day=day/16 * 10 + day % 16;
month=month/16 * 10 + month % 16;

year=2000 + year/16 * 10 + year % 16;

// Change times below to desired photo times. Copy & paste to add more photos per day.
// NOTE: for some reason, 8's & 9's cause an error, so don't use them on their own below;
// 18 & 19 work fine, but 08 & 09 do not.
if (hour == 9) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 10) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 11) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 12) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 13) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 14) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 15) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 16) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 17) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 18) { if (minute == 00) { if (second == 00) { TakePhoto();}}}

Serial.print(hour);
Serial.print(":");
if (minute < 10) { Serial.print("0"); }
Serial.print(minute);
Serial.print(":");
if (second < 10) { Serial.print("0"); }
Serial.print(second);
Serial.print(" on ");
Serial.print(dow[day_of_week]);
Serial.print(", ");
Serial.print(day);
Serial.print("/");
Serial.print(month);
Serial.print("/");
Serial.print(year);

 int span = 20;  int aRead = 0;
 for (int i = 0; i < span; i++) {        //loop to get average of 20 readings
   aRead = aRead + analogRead(ThermistorPIN);
}
 aRead = aRead / span;
 temperature = Thermistor(aRead);
Serial.print(" - Current temperature is: "); printDouble(temperature,1);     // display Celsius

Serial.print("; Max - "); printDouble(MaxTemp,1);     // display current MaxTemp
Serial.print(", Min - "); printDouble(MinTemp,1);     // display current MinTemp
Serial.println("");

 if( temperature > 35 ){  // is the Temp above 35 degrees Celcius?
     if( endTrigger == TRIGGER_INACTIVE){  // only proceed if no trigger is active.  
       // trigger the fans and store the time to turn off the LED
        digitalWrite(3, HIGH);
   Serial.println("              Threshold Temperature EXCEEDED, switching fans on.");
        endTrigger = DateTime.now() + (1 * 60); // set trigger for 1 minute(s) from now
             // note that DateTime.now() returns seconds since Arduino started
   }
 }
   if( DateTime.now() >= endTrigger ){ // only process this if endTrigger has been set
     if( temperature > 33 ){  // if temp has dropped below 33 degrees Celcius, turn fans off
       Serial.println("   Temperature still above threshold, fans remaining on.");
     endTrigger = DateTime.now() + (1 * 60);
     }      // or, if temp is still above threshold, leave fans on for another minute
     else if( temperature <= 33 ) {Serial.println("   Temperature has dropped below threshold, fans switched OFF.");
     digitalWrite(3,LOW);
     endTrigger = TRIGGER_INACTIVE;
     }
   }

// Now need a loop to read the temperature in the box, work out a daily MinTemp & MaxTemp, and record to EEPROM memory.
// This needs to repeat every day.

 if( temperature > MaxTemp) {MaxTemp = temperature;}
 if( temperature < MinTemp) {MinTemp = temperature;}

// if (second == 0){
// if (hour == 23) { if (minute == 59) { if (second == 50) {}} // just before midnight to avoid possible date confusion
if (minute == 0){ if (second == 0){

   EEPROM.write(WriteAddress,(day));
   ++WriteAddress;
   EEPROM.write(WriteAddress,month);
   ++WriteAddress;
   EEPROM.write(WriteAddress,(year-2000));
   ++WriteAddress;    
   EEPROM.write(WriteAddress,MaxTemp);
   ++WriteAddress;
   Serial.println("                              MaxTemp recorded");
   MaxTemp = 0;
 }
}


... code continued next post ...
JB

JB

#14
Dec 08, 2008, 12:30 pm Last Edit: Dec 08, 2008, 12:33 pm by jbennett Reason: 1
... The section after "MinTemp = 40" below seems to be causing the problems. If I comment this lot out down to the delay my program behaves just fine.

// if (second == 30){
// if (hour == 12) { if (minute == 00) { if (second == 00) {}}
if (minute == 30){ if (second == 0){
   EEPROM.write(WriteAddress,MinTemp);
   ++WriteAddress;
   Serial.println("                              MinTemp recorded");
   MinTemp = 40;
   }
 }
 // DATA-DUMP: check for any incoming serial input, then proceed only if 'd' is pressed
     if (Serial.available() > 0) {
     incomingByte = Serial.read();      
         if (incomingByte == 100) {
         Serial.println("          Data dump initiated:");
           Serial.print("\t");
           Serial.print("   Date");
           Serial.print("\t");
           Serial.print("MaxTemp");
           Serial.print("\t");
           Serial.println("MinTemp");

           value = EEPROM.read(ReadAddress);
           while (ReadAddress < 511) {
//              Serial.print(ReadAddress);
//              Serial.print("\t");
             Serial.print(value, DEC);
             ReadAddress = ReadAddress + 1;
             value = EEPROM.read(ReadAddress);
             Serial.print("/"); Serial.print(value, DEC);
             ReadAddress = ReadAddress + 1;
             value = EEPROM.read(ReadAddress);
             if(value < 10) {
               Serial.print("/200");}
               else {Serial.print("/20");}
             Serial.print(value, DEC);
             ReadAddress = ReadAddress + 1;
             value = EEPROM.read(ReadAddress);
             Serial.print("\t"); Serial.print("   "); Serial.print(value, DEC);
             ReadAddress = ReadAddress + 1;
             value = EEPROM.read(ReadAddress);
             Serial.print("\t"); Serial.print("   "); Serial.print(value, DEC);
             ReadAddress = ReadAddress + 1;
             Serial.println();
             }
         ReadAddress = 0;
     }
     }
delay(1000);
}


Just for a quick run-down, the program is designed to take a photo at the pre-programmed times each day. The camera system will be remotely deployed & run off a solar panel & 12V battery. The program monitors temperatures & will switch on fans to cool down the box if the temp goes over 35 degrees Celcius. We're recording the temperatures to see what extremes the camera is being exposed to, as it's just a consumer-grade Canon PowerShot A720IS.

As I mentioned, the program WITHOUT the data dump feature works fine so there's no problems there. Just not sure why the data dump section is corrupting the clock's data!! :(

Sorry for the lengthy posts and thanks for any ideas!!

JB

PS - by the way, thanks to those of you who recognise the bits of code above that they've contributed to this project!  ;D
JB

Go Up