166 lines
5.2 KiB
C++
166 lines
5.2 KiB
C++
#include "Wire.h"
|
||
#include "time.h"
|
||
|
||
// 7-bit RTC address on the I2C bus, specified in the datasheet
|
||
#define RTC_ADDR 0x68
|
||
#define RTC_DATA_SIZE 7
|
||
|
||
// Specify 1 to set a new time at initialization
|
||
#define RTC_SET_NEW_TIME 0
|
||
|
||
uint8_t rxBytes[15];
|
||
struct tm newTime;
|
||
char str[32];
|
||
|
||
void setup()
|
||
{
|
||
Serial.begin(115200);
|
||
Serial.println("Start I2C rtc");
|
||
|
||
// Initializing the device as a master on the I2C bus
|
||
Wire.begin();
|
||
|
||
// Set new time if necessary
|
||
if (RTC_SET_NEW_TIME) {
|
||
initDS1307(); // Initialization of ds1307
|
||
writeTimeToRtc(); // setting time is written inside the function
|
||
}
|
||
}
|
||
|
||
void loop()
|
||
{
|
||
// Read and display the current time
|
||
readTimeFromRtc();
|
||
delay(2000);
|
||
}
|
||
|
||
// ------------------- rtc ------------------- //
|
||
// Function for initializing the DS1307 chip
|
||
void initDS1307(void)
|
||
{
|
||
/* According to the datasheet, the bits in three registers
|
||
are checked: 0x00, 0x02 and 0x07
|
||
*/
|
||
uint8_t oneByte;
|
||
Wire.requestFrom(RTC_ADDR, 1, 0x00, 1, 1);
|
||
// Get data
|
||
if(Wire.available())
|
||
oneByte = Wire.read();
|
||
if (oneByte & 0x80) {
|
||
Wire.beginTransmission(RTC_ADDR); // Start of transaction
|
||
Wire.write(0x00); // Writing command for a transaction
|
||
Wire.write(oneByte & ~0x80); // Writing data for a transaction
|
||
Wire.endTransmission(); // Completing a transaction
|
||
}
|
||
|
||
Wire.requestFrom(RTC_ADDR, 1, 0x02, 1, 1);
|
||
// Get data
|
||
if(Wire.available())
|
||
oneByte = Wire.read();
|
||
if (oneByte & 0x40) {
|
||
Wire.beginTransmission(RTC_ADDR); // Start of transaction
|
||
Wire.write(0x02); // Writing command for a transaction
|
||
Wire.write(oneByte & ~0x40); // Writing data for a transaction
|
||
Wire.endTransmission(); // Completing a transaction
|
||
}
|
||
|
||
Wire.requestFrom(RTC_ADDR, 1, 0x07, 1, 1);
|
||
// Get data
|
||
if(Wire.available())
|
||
oneByte = Wire.read();
|
||
if ((oneByte & 0x03) || !(oneByte & 0x10)) {
|
||
Wire.beginTransmission(RTC_ADDR); // Start of transaction
|
||
Wire.write(0x07); // Writing command for a transaction
|
||
Wire.write(oneByte & ~0x03 | 0x10); // Writing data for a transaction
|
||
Wire.endTransmission(); // Completing a transaction
|
||
}
|
||
}
|
||
|
||
// Function to write new time to rtc
|
||
void writeTimeToRtc(void)
|
||
{
|
||
/* The data to be written is located in the common buffer.
|
||
First, the register address is specified - writing starts from register 0x00.
|
||
Next, the values of seconds, minutes, etc. are listed in accordance with the
|
||
order of the corresponding registers, specified in the datasheet for ds1307.
|
||
The values are pre-translated into binary-decimal format
|
||
*/
|
||
// sec min hour wday mday month year
|
||
uint8_t buf[] = {0x00, dec2bcd(00), dec2bcd(01), dec2bcd(12), dec2bcd(2), dec2bcd(1), dec2bcd(1), dec2bcd(24)};
|
||
|
||
Wire.beginTransmission(RTC_ADDR); // Start of transaction
|
||
Wire.write(buf, sizeof(buf)); // Writing data for a transaction
|
||
uint8_t result = Wire.endTransmission(); // Completing a transaction
|
||
|
||
// Show results
|
||
if (result == 0)
|
||
Serial.println("New time successfully set");
|
||
else
|
||
Serial.println("New time set failed");
|
||
}
|
||
|
||
// Function to read time from rtc
|
||
void readTimeFromRtc(void)
|
||
{
|
||
/* Send a request to receive data from rtc. When reading from rtc, you must
|
||
first specify from which register to start reading. To do this, use the extended
|
||
version of the requestFrom() function. In the arguments specify:
|
||
- device address,
|
||
- the number of bytes we want to read,
|
||
- the address of the starting register,
|
||
- the size of the address of the starting register in bytes,
|
||
- 1 - generate a stop condition after the request, 0 - do not generate
|
||
*/
|
||
Wire.requestFrom(RTC_ADDR, RTC_DATA_SIZE, 0x00, 1, 1);
|
||
// Get data
|
||
uint8_t i = 0;
|
||
while(Wire.available())
|
||
rxBytes[i++] = Wire.read();
|
||
|
||
// Show new time in the port upon successful reading
|
||
if (i == RTC_DATA_SIZE)
|
||
parseAndShowTime();
|
||
else
|
||
Serial.println("New time read failed");
|
||
}
|
||
|
||
// Functions for converting binary-decimal code to decimal and back
|
||
uint8_t bcd2dec(uint8_t val)
|
||
{
|
||
return (val >> 4) * 10 + (val & 0x0f);
|
||
}
|
||
|
||
uint8_t dec2bcd(uint8_t val)
|
||
{
|
||
return ((val / 10) << 4) + (val % 10);
|
||
}
|
||
|
||
// Function for format and output the current time to the port
|
||
void parseAndShowTime(void)
|
||
{
|
||
/* take the values for time output from the received data buffer.
|
||
Convert the values into decimal format and adjust them in accordance with
|
||
the datasheet for ds1307
|
||
*/
|
||
newTime.tm_sec = bcd2dec(rxBytes[0] & 0x7f);
|
||
newTime.tm_min = bcd2dec(rxBytes[1]);
|
||
if (rxBytes[2] & (1 << 6))
|
||
{
|
||
// RTC in 12 hour mode
|
||
newTime.tm_hour = bcd2dec(rxBytes[2] & 0x1f) - 1;
|
||
if (rxBytes[2] & (1 << 5))
|
||
newTime.tm_hour += 12;
|
||
}
|
||
else
|
||
newTime.tm_hour = bcd2dec(rxBytes[2] & 0x3f);
|
||
newTime.tm_wday = bcd2dec(rxBytes[3])-1;
|
||
newTime.tm_mday = bcd2dec(rxBytes[4]);
|
||
newTime.tm_mon = bcd2dec(rxBytes[5])-1;
|
||
// Subtract 1900 so that the year is correctly displayed in the struct tm type structure
|
||
newTime.tm_year = bcd2dec(rxBytes[6])+2000-1900;
|
||
|
||
// The received time is output to the port in the format Sun Aug 19 02:56:02 2012
|
||
strftime(str, sizeof(str), "%c", &newTime);
|
||
Serial.println(str);
|
||
}
|