Problem with i2c communication and ds1307 RTC

I am not an expert in programming.... also not good at English. So don't Laugh at me.
I have a ds1307 RTC. I want to send hour, minute, second, day, month, year of this RTC from one Arduino to another Arduino. To do this I use i2c communication between two Arduino. I successfully send the hour, minute, second, day, month. But the year is not received by the slave receiver. It gives wrong value 229 Instead of 2021.
Here is the sender code:

#include<Wire.h>
#include <RTClib.h>
int hour, minute, second, day, month, year;
RTC_DS1307 rtc;
void setup() {
  Wire.begin();
  Serial.begin(9600);
  rtc.begin();
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    rtc.adjust(DateTime(__DATE__, __TIME__));
  } else {
    Serial.println("OK! RTC is running");
  }
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  } else {
    Serial.println("OK! RTC found");
  }
}

void loop() {
  DateTime now = rtc.now();
  hour = now.hour();
  minute = now.minute();
  second = now.second();
  day = now.day();
  month = now.month();
  year = now.year();
  Wire.beginTransmission(9);//9 here is the address of the slave board
  Wire.write(hour);//Transfers the value of potentiometer to the slave board
  Wire.write(minute);
  Wire.write(second);
  Wire.write(day);
  Wire.write(month);
  Wire.write(year);
  Wire.endTransmission();
  Serial.print("Time-");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.print(second);
  Serial.println();
  Serial.print("Date-");
  Serial.print(day);
  Serial.print(":");
  Serial.print(month);
  Serial.print(":");
  Serial.print(year);
  Serial.println();
  delay(1000);
}

Here is the receiver code:

#include<Wire.h>
int hour, minute, second, day, month, year;
void setup() {
  // Begin the Serial at 9600 Baud
  Wire.begin(9);
  Serial.begin(9600);
  Wire.onReceive(receiveEvent);
}

void receiveEvent(int bytes) {
  while (1 < Wire.available()) {
    hour = Wire.read();
    minute = Wire.read();
    second = Wire.read();
    day = Wire.read();
    month = Wire.read();
    delay(1000);
    year = Wire.read();
  }
}

void loop() {
  Serial.print("Time-");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.print(second);
  Serial.println();
  Serial.print("Date-");
  Serial.print(day);
  Serial.print(":");
  Serial.print(month);
  Serial.print(":");
  Serial.print(year);
  Serial.println();
  delay(1000);
}

And Serial for both sender and receiver:

Now what can i do?

Advance thanks.

I give a clue why you are getting 229 instead of 2021.

2021 decimal = 07E5 in hex ===> E5 = 229 decimal (Slave receives only the lower byte)

I2C Bus is a byte-oriented system which means that the bus handles data as an 8-bit (1-byte) block. You have 2021 (0x07E5) which is, in fact, 2-byte data. Remember that data are always saved in memory locations in bit form.

So, the solution is: (left for you).......

2 Likes

I got the point. Thanks for your advise.
As a new comer, i understand that i need to received both LSB and MSB, isn't it?
But i only receive LSB. InshaAllah i will try to solve the problem as like you guide me.

1 Like

I think I solved the riddle....

I also try without this delay . But its not happening for delay. its for Slave receives only the lower byte.

My dear friend, the delay is not the only difference between your code and mine....

Yes, and you also need to break the integer into two bytes when you send as well.

@johi has also pointed out another issue which prevents you from reading all the bytes you send.

while (1 < Wire.available()) {

I see you change the while (1 < Wire.available()) To the while (0 < Wire.available())
But nothing is changed! See the below:

You could send the year as offset from 2000 (or whatever can fit in a single byte), or you could send the whole time as a 4 bytes unix timestamp

You could make the sender send 2 bytes (an int data type) for the year and decode the 2 bytes to an int at the receiver or, since for the forseeable future, the first 2 digits of the year are going to be 20 you could send just the tens and ones (21) as 1 byte. Then just add 2000 to the byte received.

1 Like

You could make the sender send 2 bytes (an int data type) for the year and decode the 2 bytes to an int at the receiver or, since for the forseeable future, the first 2 digits of the year are going to be 20 you could send just the tens and ones (21). Then just add 2000 to the byte received.

Thanks........

How many write() methods the Master must execute to transfer an int type year variable?

2 Likes

I think this is better, first solution was too optimistic, but do not know if write send msb or lsb first?

You should fix your own sketch by sending the 16-bit value of your year variable of Post-1 from the Master. At Slave side, collect the arraived data bytes noting down that the argument (int bytes) of the receiveEvent() routine is always equal to number of data bytes received from the Master.

Read the material of this link.

1 Like

It will send whatever byte you tell it to send.

wire.write() was used incorrectly on a two byte integer value.
It was already pointed out which byte he received-- the lsb

2021 decimal = 07E5 in hex ===> E5 = 229 decimal (Slave receives only the lower byte)

It gets confusing when you change the code after others have already responded.

The sender code also needs to be modified:

  Wire.beginTransmission(9);//9 here is the address of the slave board
  Wire.write(hour);//Transfers the value of potentiometer to the slave board
  Wire.write(minute);
  Wire.write(second);
  Wire.write(day);
  Wire.write(month);
  Wire.write(lowByte(year));
  Wire.write(highByte(year));
  Wire.endTransmission();

You could alternatively use the following, assuming the int is stored with the least significant byte first, which is true for all the arduino boards I am familiar with.

  Wire.write((byte*)&year, 2);
2 Likes

This is the perfect solution for me. Thanks a lot.

It is possible to reduce the number of code lines using for() loop.

byte timeArray[10];
void receiveEvent(int howMany) //howMany is always equal to data bytes received from Master
{
     for(int i =; i<howMany; i++)
     {  
           timeArray[i] = Wire.read();   //timeArray[[0] = hour, timeArray[1] = second, ..., 
     }
     int year = Wire.read[i] <<8 | Wire.read[i-1];
}
1 Like

You have a point, will take this into acount in the future.

that's good idea........
Are you from bangladesh?
Can I have your email address please?