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