Копнул более основательно часики.
Для начала запустил сканер устройств на шине 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 | --- | 
Первоначально интерес тут представляют строки с 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, но этим займусь завтра.
 
 
Добрый день! Отличная статья, А как установить время?
ОтветитьУдалить