Копнул более основательно часики.
Для начала запустил сканер устройств на шине i2C. Рекомендую сохранить этот скетч в свою библиотеку, чтобы он был под руками - очень полезная штука!
Сканер обнаруживает два устройства на шине i2C по следующим адресам:
1. 0x57 - это адрес микросхемы памяти AT24C32
2. 0x68 - адрес микросхемы DS3231SN
Cтоит учитывать - сканер возвращает адреса в формате шестнадцатеричной системы.
Т.е в привычном нам десятичном формате получим адреса 87 и 104.
Нас интересует адрес 0x68 (104).
Сделал себе первую пометочку.
Следующий шаг - скачать даташит к микросхеме. Найти его можно, например, по этой ссылке
Читаю, радуюсь большому количеству английских букв и разнообразных таблиц. :)
Самое интересное началось на странице 11, где присутствует следующая таблица:
Figure 1. Timekeeing Registers
Address | bit 7 MSB | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 LSB | Function | Range |
00H | 0 | 10 seconds | seconds | Seconds | 00-59 |
01H | 0 | 10 minutes | minutes | Minutes | 00-59 |
02H | 0 | 12/24 | AM/PM 10 hour | 10 hour | hour | Hours | 1-12+AM/PM 00-23 |
03H | 0 | 0 | 0 | 0 | 0 | day | Day | 1-7 |
04H | 0 | 0 | 10 date | date | Date | 00-31 |
05H | Century | 0 | 0 | 10 month | month | Month/Century | 01-12+Century |
06H | 10 year | year | Year | 00-99 |
07H | A1M1 | 10 seconds | seconds | Alarm 1 seconds | 00-59 |
08H | A1M2 | 10 minutes | minutes | Alarm 1 minutes | 00-59 |
09H | A1M3 | 12/24 | AM/PM 10 hour | 10 hour | hour | Alarm 1 hours | 1-12+AM/PM 00-23 |
0AH | A1M4 | DY/DT | 10 date | day | Alarm 1 day | 1-7 |
date | Alarm 1 date | 1-31 |
0BH | A2M2 | 10 minutes | minutes | Alarm 2 minutes | 00-59 |
0CH | A2M3 | 12/24 | AM/PM 10 hour | 10 hour | hour | Alarm 2 hours | 1-12+AM/PM 00-23 |
0DH | A2M4 | DY/DT | 10 date | day | Alarm 2 day | 1-7 |
date | Alarm 2 date | 1-31 |
0EH | EOSC | BBSQW | CONV | RS2 | RS1 | INTCN | A2IE | A1IE | Control | --- |
0FH | OSF | 0 | 0 | 0 | EN32kHz | BSY | A2F | A1F | Control/status | --- |
10H | SIGN | DATA | DATA | DATA | DATA | DATA | DATA | DATA | Agign Offset | --- |
11H | SIGN | DATA | DATA | DATA | DATA | DATA | DATA | DATA | MSB of Temp | --- |
12H | DATA | DATA | 0 | 0 | 0 | 0 | 0 | 0 | LSB of Temp | --- |
Рекомендую все-таки скачать даташит - там есть такие замечательные отметочки в оригинальной таблице - крышечки. Как я понял, обозначают, какое состояние бита отвечает за состояние AM/PM или DY/DT, например. В моей таблице этого нет.
Первоначально интерес тут представляют строки с 00H до 06H и c 0EH до 12H. Блок с алармами (07H-0DH) пока пропущу - им займусь позже.
Далее приведен скетч, работающий напрямую с данными на DS3231.
#include <Wire.h>
#define DS3231_I2C_ADDRESS 0x68
byte seconds, minutes, hours, day, date, month, year;
char weekDay[4];
byte tMSB, tLSB;
float temp3231;
void setup()
{
Wire.begin();
Serial.begin(9600);
//set control register to output square wave on pin 3 at 1Hz
Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
Wire.write(0x0E); //выставляемся в 14й байт
Wire.write(B00000000); //сбрасываем контрольные регистры
Wire.write(B10001000); //выставляем 1 на статус OSF и En32kHz
Wire.endTransmission();
}
void loop() {
watchConsole(); //читаем консоль. Если нажата "T" читаем из консоли следующий 7 байт и устанавливаем время.
get3231Date(); //получаем данные
//и потом их выводим через Serial.print()
Serial.print(weekDay); Serial.print(", "); Serial.print(month, DEC); Serial.print("/"); Serial.print(date, DEC); Serial.print("/"); Serial.print(year, DEC); Serial.print(" - ");
Serial.print(hours, DEC); Serial.print(":"); Serial.print(minutes, DEC); Serial.print(":"); Serial.print(seconds, DEC);
Serial.print(" Temperature: "); Serial.print(get3231Temp());Serial.print("; ");
Serial.println(get3231Register(0x0F)); //получаем и выводим статусовый регистр
delay(1000);
}
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
void watchConsole()
{
if (Serial.available()) { // Look for char in serial queue and process if found
if (Serial.read() == 84) { //If command = "T" Set Date
set3231Date();
get3231Date();
Serial.println(" ");
}
}
}
void set3231Date()
{
//T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year)
//T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99)
//Example: 02-Feb-09 @ 19:57:11 for the 3rd day of the week -> T1157193020209
seconds = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.
minutes = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
hours = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
day = (byte) (Serial.read() - 48);
date = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
month = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
year = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
Wire.beginTransmission(DS3231_I2C_ADDRESS); //начали сессию
Wire.write(0x00); //поставляемся в нулевой байт для чтения данных
Wire.write(decToBcd(seconds));
Wire.write(decToBcd(minutes));
Wire.write(decToBcd(hours));
Wire.write(decToBcd(day));
Wire.write(decToBcd(date));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.endTransmission();//закрыли сессию
}
byte get3231Register(byte regNo) {
// send request to receive data starting at register regNo
Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
Wire.write(regNo); // start at register regNo
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 1); // request one byte
if(Wire.available()) return Wire.read();
}
void set3231Register(byte regNo, byte value) {
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(regNo);
Wire.write(value);
Wire.endTransmission();
}
void get3231Date()
{
// send request to receive data starting at register 0
Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
Wire.write(0x00); // start at register 0
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes
if(Wire.available()) {
seconds = Wire.read(); // get seconds
minutes = Wire.read(); // get minutes
hours = Wire.read(); // get hours
day = Wire.read();
date = Wire.read();
month = Wire.read(); //temp month
year = Wire.read();
//Конвертация происходит очень просто - битовым оператором & мы очищаем МЛАДШИЕ (0,1,2,3) четыре бита , сдвигаем все вправо на 4 позиции (очищенные биты
//вылезут при этом с левой стороны и результат умножаем на 10, т.к. в старших битах хранится информация о десятках секунд.
//После этого битовым оператором & очищаем СТАРШИЕ (4,5,6,7)четыре бита и получаем секунды. Затем суммируем десятки секунд и единиц.
seconds = (((seconds & B11110000)>>4)*10 + (seconds & B00001111));
minutes = (((minutes & B11110000)>>4)*10 + (minutes & B00001111));
hours = (((hours & B00110000)>>4)*10 + (hours & B00001111));
day = (day & B00000111); // 1-7
date = (((date & B00110000)>>4)*10 + (date & B00001111)); // 1-31
month = (((month & B00010000)>>4)*10 + (month & B00001111)); //msb7 is century overflow
year = (((year & B11110000)>>4)*10 + (year & B00001111));
}
else {
//oh noes, no data!
}
switch (day) {
case 1:
strcpy(weekDay, "Mon");
break;
case 2:
strcpy(weekDay, "Tue");
break;
case 3:
strcpy(weekDay, "Wed");
break;
case 4:
strcpy(weekDay, "Thu");
break;
case 5:
strcpy(weekDay, "Fri");
break;
case 6:
strcpy(weekDay, "Sat");
break;
case 7:
strcpy(weekDay, "Sun");
break;
}
}
float get3231Temp()
{
//temp registers (11h-12h) get updated automatically every 64s
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x11);
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
if(Wire.available()) {
tMSB = Wire.read(); //2's complement int portion
tLSB = Wire.read(); //fraction portion
temp3231 = (tMSB & B01111111); //do 2's math on Tmsb
temp3231 += ( (tLSB >> 6) * 0.25 ); //only care about bits 7 & 8
}
else {
//oh noes, no data!
}
return temp3231;
}
Вот как-то так. Непонятно пока, что произойдет при совпадении текущего времени с установленным в байтах 07h-0Ah и в 0Bh-0Dh, но этим займусь завтра.