5

I'm able to set a time and to read it back without any problems but it doesn’t tick up. It stays the same. Even if I restart the serial monitor and thereby resets the buffer(?). So it seems to me that I'm able to set the registers but somehow the oscillator isn't working, do I have to tell it to use the external oscillator? Datasheet. Using Uno Rev3.

I've connected it like this:Schematic

Never mind the BAT54 diode and the "RTC+MCU_VCC" node, its all just backup power from a capacitor. The supply voltage is alright.

The code I've been using is a modified version of this.

// SDA analog pin 4
// SCL analog pin 5

#include <Wire.h>
const int MCP7940 = 0x6F; // Address of MCP7940 see data sheets
const char* days[] =
{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const char* months[] =
{"January", "February", "March", "April", "May", "June", "July", "August","September", "October", "November", "December"};

// Initializes all values: 
byte second = 0;
byte minute = 0;
byte hour = 0;
byte weekday = 0;
byte monthday = 0;
byte month = 0;
byte year = 0;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(2000); // This delay allows the MCU to read the current date and time.

  Serial.print("The current date and time is: ");
  printTime();
  Serial.println("Please change to newline ending the settings on the lower right of the Serial Monitor");
  Serial.println("Would you like to set the date and time now? Y/N");

  while (!Serial.available()) delay(10);
  if (Serial.read() == 'y' || Serial.read() == 'Y')

  // This set of functions allows the user to change the date and time
  {
    Serial.read();
    setTime();
    Serial.print("The current date and time is now: ");
    printTime();
  }


  Serial.println("Thank you.");
}

// Continuous function for converting bytes to decimals and vice versa
void loop() {
}
byte decToBcd(byte val) {
  return ((val/10*16) + (val%10));
}
byte bcdToDec(byte val) {
  return ((val/16*10) + (val%16));
}


// This set of codes is allows input of data
void setTime() {
  Serial.print("Please enter the current year, 00-99. - ");
  year = readByte();
  Serial.println(year);
  Serial.print("Please enter the current month, 1-12. - ");
  month = readByte();
  Serial.println(months[month-1]);
  Serial.print("Please enter the current day of the month, 1-31. - ");
  monthday = readByte();
  Serial.println(monthday);
  Serial.println("Please enter the current day of the week, 1-7.");
  Serial.print("1 Sun | 2 Mon | 3 Tues | 4 Weds | 5 Thu | 6 Fri | 7 Sat - ");
  weekday = readByte();
  Serial.println(days[weekday-1]);
  Serial.print("Please enter the current hour in 24hr format, 0-23. - ");
  hour = readByte();
  Serial.println(hour);
  Serial.print("Please enter the current minute, 0-59. - ");
  minute = readByte();
  Serial.println(minute);
  second = 0;
  Serial.println("The data has been entered.");

  // The following codes transmits the data to the RTC
  Wire.beginTransmission(MCP7940);
  Wire.write(byte(0));
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekday));
  Wire.write(decToBcd(monthday));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.write(byte(0));
  Wire.endTransmission();
  // Ends transmission of data
}


byte readByte() {
  while (!Serial.available()) delay(10);
  byte reading = 0;
  byte incomingByte = Serial.read();
  while (incomingByte != '\n') {
    if (incomingByte >= '0' && incomingByte <= '9')
      reading = reading * 10 + (incomingByte - '0');
    else;
    incomingByte = Serial.read();
  }
  Serial.flush();
  return reading;
}


void printTime() {
  char buffer[3];
  const char* AMPM = 0;
  readTime();
  Serial.print(days[weekday-1]);
  Serial.print(" ");
  Serial.print(months[month-1]);
  Serial.print(" ");
  Serial.print(monthday);
  Serial.print(", 20");
  Serial.print(year);
  Serial.print(" ");

  Serial.print(hour);
  Serial.print(":");

 Serial.print(minute);
 Serial.println();
}


void readTime() {
  Wire.beginTransmission(MCP7940);
  Wire.write(byte(0));
  Wire.endTransmission();
  Wire.requestFrom(MCP7940, 7);
  second = bcdToDec(Wire.read());
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read());
  weekday = bcdToDec(Wire.read());
  monthday = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}
6

Okey, I've been very tired when doing this but I think the problem was with bit 7 at adress 00h. The "seconds byte". That bit is called ST and turns on or off the oscillator. Doing a bitwise OR like this: Wire.write(decToBcd(second) | 128); sets it to "1" (128 = B10000000) and it's running now.

  • Most external RTCs have a bit that must be set in order to activate the oscillator. In the MCP7940M this is ST. – Ignacio Vazquez-Abrams Dec 16 '14 at 2:32
0

you have a small flaw in your readTime function. If you don't want very strange seconds from the device you should combine the two nibbles packed into the seconds byte. Like this:

void readTime() {
  Wire.beginTransmission(MCP7940);
  Wire.write(byte(0));
  Wire.endTransmission();
  Wire.requestFrom(MCP7940, 7);

  int rawsecond = Wire.read();
  second = bcdToDec( rawsecond & 112) + bcdToDec(rawsecond & 15);
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read());
  weekday = bcdToDec(Wire.read());
  monthday = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}

Thanks for the sample - helped me quite a bit.

  • found another one. When accessing the weekday you also need to cut the correct bits out of the byte like this: weekday = bcdToDec(Wire.read() & 7); – Andreas Mar 26 '15 at 21:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.