• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP8266 - Время DS3231 (DS1307?) - чтение, установка

abdurino

New member
Подключение к пинам SCL и SDA я так понял произвольное и его можно менять.
По умолчанию
VCC - 3.3.V
GND - GND
SCL - 4
SDA - 5
На 2м тестовый лед, чтобы понимать что оно вообще работает )

Очень замечательно что после компиляции Arduino IDE сразу запускает программу и не надо дёргать джампер.
И при открытии com порта ESP не ресетится, так что сразу можно давать команды
show time
set time

Удачи.
Код:
#include <Wire.h>

//#define DS1307_CTRL_ID 0x68
int clockAddress = 0x68;  // This is the I2C address
byte second, minute, hour, dayOfWeek, day, dayOfMonth, month, year;


#define LCDPin 2

#define DS1307_SCL 4
#define DS1307_SDA 5



void setup() {
  // put your setup code here, to run once:
  //wire.begin(SCL, SDA)
  Wire.begin(DS1307_SCL, DS1307_SDA);
  //Wire.begin();
  Serial.begin(9600);
  pinMode(LCDPin, OUTPUT);


}

void loop() {
  digitalWrite(LCDPin, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(LCDPin, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second


  if (Serial.available() > 0) {
    String str = Serial.readStringUntil('\n');
    if (str == "show time") {
      getDateDs1307(); // update time variables
      String s = getTimeStr();
      Serial.println(s);
    }
    if (str == "set time") {
      time_set();
    }

  }

}



// Gets the date and time from the ds1307 and prints result
void getDateDs1307() {
  // Reset the register pointer
  Wire.beginTransmission(clockAddress);
  Wire.write(byte(0x00));
  Wire.endTransmission();

  Wire.requestFrom(clockAddress, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(Wire.read() & 0x7f);
  minute     = bcdToDec(Wire.read());

  // Need to change this if 12 hour am/pm
  hour       = bcdToDec(Wire.read() & 0x3f);
  dayOfWeek  = bcdToDec(Wire.read());
  dayOfMonth = bcdToDec(Wire.read());
  day = dayOfMonth;
  month      = bcdToDec(Wire.read());
  year       = bcdToDec(Wire.read());
}
void setDateDs1307()            
{
  // Use of (byte) type casting and ascii math to achieve result.
  /*second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48));
  minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  dayOfWeek = (byte) (Serial.read() - 48);
  dayOfMonth = (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(clockAddress);
  Wire.write(byte(0x00));
  Wire.write(decToBcd(second));  // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));    // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}


String getTimeStr() {
  String str = String(day) + "." + formatDigit(month, 2) + "." + formatDigit(year, 2) + " " + formatDigit(hour, 2) + ":" + formatDigit(minute, 2) + ":" + formatDigit(second, 2);
  return str;
}
String formatDigit(int i, int len) {
  String s = String(i);
  while (s.length() < len) {
    s = "0" + s;
  }
  return (s);
}



void time_set() {
  Serial.println("Enter Year 2 last digits");
  while (Serial.available() <= 0);
  year = Serial.parseInt();
  Serial.println(year);

  Serial.println("Month");
  while (Serial.available() <= 0);
  month = Serial.parseInt();
  Serial.println(month);

  Serial.println("Day");
  while (Serial.available() <= 0);
  day = Serial.parseInt();
  dayOfMonth = day;
  Serial.println(day);

  Serial.println("Day of Week");
  while (Serial.available() <= 0);
  dayOfWeek = Serial.parseInt();
  Serial.println(dayOfWeek);

  Serial.println("Hour");
  while (Serial.available() <= 0);
  hour = Serial.parseInt();
  Serial.println(hour);

  Serial.println("Minute");
  while (Serial.available() <= 0);
  minute = Serial.parseInt();
  Serial.println(minute);

  setDateDs1307();

  Serial.println("Time recvd OK");
}
 
Последнее редактирование:

Mоnk

Member
А что в этом коде надо добавить, чтобы температуру из DS3231 получить и показать?
 

Mоnk

Member
Никому не интересно, похоже...
Отвечу сам себе.
Код:
#include <Wire.h>
#define DS3231_SCL 4
#define DS3231_SDA 5

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year, temperature;

void setup() {
  Wire.begin(DS3231_SCL, DS3231_SDA);
  Serial.begin(115200);
}
void loop() {
 
  if (Serial.available() > 0) {
    String str = Serial.readStringUntil('\n');
    if (str == "get") {
      getDateDS3231(); // update time variables
      String s = getTimeStr();     
      Serial.println("-----------show time-----------");
      Serial.println(s);
    }
    if (str == "set") {
      time_set();
    }
  }
}
void getDateDS3231() {
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7);
  second     = bcdToDec(Wire.read() & 0x7f);
  minute     = bcdToDec(Wire.read());
  hour       = bcdToDec(Wire.read() & 0x3f);
  dayOfWeek  = bcdToDec(Wire.read());
  dayOfMonth = bcdToDec(Wire.read());
  month      = bcdToDec(Wire.read());
  year       = bcdToDec(Wire.read());

//--------------------------------------------
    Wire.beginTransmission(0x68);
    Wire.write(0x11);
    Wire.endTransmission();
    Wire.requestFrom(0x68, 2);
    temperature = (Wire.read() & B01111111) + ( (Wire.read() >> 6) * 0.25 );
}
void setDateDS3231()           
{
  // Use of (byte) type casting and ascii math to achieve result.
  /*second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48));
  minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  dayOfWeek = (byte) (Serial.read() - 48);
  dayOfMonth = (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(0x68);
  Wire.write(byte(0x00));
  Wire.write(decToBcd(second));  // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));    // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}
String getTimeStr() {
  String str = String(dayOfMonth) + "." + formatDigit(month, 2) + "." + formatDigit(year, 2) + " " + dayOfWeek + " " + formatDigit(hour, 2) + ":" + formatDigit(minute, 2) + ":" + formatDigit(second, 2) + " temperature " + temperature;
  return str;
}
String formatDigit(int i, int len) {
  String s = String(i);
  while (s.length() < len) {
    s = "0" + s;
  }
  return (s);
}
void time_set() {
  Serial.println("Enter Year 2 last digits");
  while (Serial.available() <= 0);
  year = Serial.parseInt();
  Serial.println(year);
  Serial.println("Month");
  while (Serial.available() <= 0);
  month = Serial.parseInt();
  Serial.println(month);
  Serial.println("dayOfMonth");
  while (Serial.available() <= 0);
  dayOfMonth = Serial.parseInt();
  Serial.println(dayOfMonth);
  Serial.println("Day of Week");
  while (Serial.available() <= 0);
  dayOfWeek = Serial.parseInt();
  Serial.println(dayOfWeek);
  Serial.println("Hour");
  while (Serial.available() <= 0);
  hour = Serial.parseInt();
  Serial.println(hour);
  Serial.println("Minute");
  while (Serial.available() <= 0);
  minute = Serial.parseInt();
  Serial.println(minute);
  Serial.println("Second");
  while (Serial.available() <= 0);
  second = Serial.parseInt();
  Serial.println(second);
 
  setDateDS3231();
  Serial.println("Time recvd OK");
}
 
Народ, так какой всетаки на ESP8266 SCL, а какой SDA? У вас 4 и 5, а вот тут наоборот. Но я и так и так пробовал. Я конечно упростил. Просто время брал.
Код:
#include <Wire.h>

int clockAddress = 0x68;  // This is the I2C address
byte second, minute, hour, dayOfWeek, day, dayOfMonth, month, year;


#define LCDPin 2

#define DS1307_SCL D1
#define DS1307_SDA D2

void setup() {
  Wire.begin(DS1307_SCL, DS1307_SDA);
  Serial.begin(9600);
  pinMode(LCDPin, OUTPUT);
}

void loop() {
  digitalWrite(LCDPin, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(LCDPin, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second


  //if (Serial.available() > 0) {
    //String str = Serial.readStringUntil('\n');
    //if (str == "show time") {
      getDateDs1307(); // update time variables
      Serial.print(day);
      Serial.print(" ");
      Serial.print(hour);
      Serial.print(":");
      Serial.print(minute);
      Serial.print(":");
      Serial.print(second);
      Serial.print("-----");
      Serial.println(year);
      //String s = getTimeStr();
      //Serial.println(s);
    //}
    //if (str == "set time") {
     // time_set();
    //}

  //}

}
У меня время не меняется и выдает чушь!

165 45:165:85-----165
165 45:165:85-----165
165 45:165:85-----165
165 45:165:85-----165
165 45:165:85-----165
165 45:165:85-----165
 

Mоnk

Member
#define DS1307_SCL D1 #define DS1307_SDA D2
Будем надеяться, что компилятор понимает, что такое Д1 и Д2.
какой всетаки на ESP8266 SCL, а какой SDA
Какой укажите, такой и будет.
C++:
// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>
#define SCL_pin     0   //  D3  ---------- I2C SCL
#define SDA_pin     2   //  D4  ---------- I2C SDA

void setup()
{
  Wire.begin(SDA_pin, SCL_pin);

  Serial.begin(115200);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }   
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}
 

CodeNameHawk

Moderator
Команда форума
Скажите а ведь батарейка не нужна? должны они без батарейки работать?
Нужна. Могут без батарейки, если подать нужное питание вместо батарейки.
В первый раз часы надо запустить, установите произвольное или актуальное время и так каждый раз, если нет батарейки.
 

enjoynering

Well-known member
Если писать просто 4 и 5, то компилятор воспринимает это как GPIO4 и GPIO5. Если глянуть на распиновку той же WEMOS становится очевидно, что GPIO4, GPIO5 и D4, D5 не одно и тоже.
 

Mоnk

Member
Ну у парня все логично. D1 D2. Если мне память не изменяет, в случае вемоса надо было таблицу соответствия в эскиз включать.
 
Нужна. Могут без батарейки, если подать нужное питание вместо батарейки.
В первый раз часы надо запустить, установите произвольное или актуальное время и так каждый раз, если нет батарейки.
Я понимаю, что без батарейки часы не будут помнить время при выключении питания. Это ладно. Сеня смущают такие странные цифры и то что значение секунд не меняется. Я батарейку сейчас для тестирования не подключал. Нужна ли она чтобы часы просто ходили? Не могут ли быть такие странные цифры из-за ее отсутствия? Может у меня микросхема нерабочая? rtc.getMonthStrожет кто знает на каких выводах какие сигналы должны быть, ну кроме +5 и земли?
 

CodeNameHawk

Moderator
Команда форума
Я батарейку сейчас для тестирования не подключал. Нужна ли она чтобы часы просто ходили?
Ответ тот же,
Нужна. Могут без батарейки, если подать нужное питание вместо батарейки.
А еще нужна инициализация часов, чего нету в вашем коде.

Возьмите готовую библиотеку
https://github.com/Makuna/Rtc
, что рекомендуют тут https://arduino-esp8266.readthedocs.io/en/latest/libraries.html#ticker

Если уже какие то установили - сотрите.
 
Последнее редактирование:
Скорость на порту поменял все пошло.
Scanning...
I2C device found at address 0x68 !
done
Т.е. типа он ее видит, но время почему-то то ли не идет, толи считывается неверно.
Батарейку подключил. Вообще с батарейкой подивился. Я думал там как в биосе на матери есть - хорошо, все помнит, нет - значит каждый раз дату и время писать, если нет NTP сервера, ну и все свои настрогйки, но работать будет.
 
Скачал свежую библиотеку DS1307.h и взял пример из нее. СРазу все заработало как надо.
Код:
/*
  DS1307 RTC (Real-Time-Clock) Example

  Uno       A4 (SDA), A5 (SCL)
  Mega      20 (SDA), 21 (SCL)
  Leonardo   2 (SDA),  3 (SCL)
 */

#include <Wire.h>
#include <DS1307.h>


DS1307 rtc;


void setup()
{
  //init Serial port
  Serial.begin(9600);
  while(!Serial); //wait for serial port to connect - needed for Leonardo only

  //init RTC
  Serial.println("Init RTC...");
  rtc.begin();

  //only set the date+time one time
   rtc.set(0, 0, 8, 02, 01, 2021); //08:00:00 24.12.2014 //sec, min, hour, day, month, year

  //stop/pause RTC
  // rtc.stop();

  //start RTC
  rtc.start();
}


void loop()
{
  uint8_t sec, min, hour, day, month;
  uint16_t year;

  //get time from RTC
  rtc.get(&sec, &min, &hour, &day, &month, &year);

  //serial output
  Serial.print("\nTime: ");
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(min, DEC);
  Serial.print(":");
  Serial.print(sec, DEC);

  Serial.print("\nDate: ");
  Serial.print(day, DEC);
  Serial.print(".");
  Serial.print(month, DEC);
  Serial.print(".");
  Serial.print(year, DEC);

  //wait a second
  delay(1000);
}
 
Заработало на макетке. А вот на основно плате так и выдает эти неправильные даты. Но! Там у меня еще датчик bme/bmp280. Он тоже по i2c, но на D5 и D6 и работает с wire.h и показывает верные данные.
Сканер же на этой плате выдает то же
Scanning...
I2C device found at address 0x68 !
done
Вот только какое устройство он видит? Не мешают ли они друг другу?
 

Mоnk

Member
I2C device found at address 0x68 !
Ура! Мелкосхема жива.
Пробуем
C++:
#include <Wire.h>       //---------- I2C

#define SCL_pin     0   //---------- I2C
#define SDA_pin     2   //---------- I2C

void setup()
{
  Serial.begin(115200);
  Wire.begin(SDA_pin, SCL_pin); //---------- I2C
}
 
void loop()
{
  if (Serial.available() > 0)
  {
    String str = Serial.readStringUntil('\n');
    if (str == "get")
    {
      getDateDS3231(); // update time variables
      String s = getTimeStr();     
      Serial.println("-----------show time-----------");
      Serial.println(s);
    }
    if (str == "set")
    {
      time_set();
    }
  }
}
 
void getDateDS3231() {
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7);
  second     = bcdToDec(Wire.read() & 0x7f);
  minute     = bcdToDec(Wire.read());
  hour       = bcdToDec(Wire.read() & 0x3f);
  dayOfWeek  = bcdToDec(Wire.read());
  dayOfMonth = bcdToDec(Wire.read());
  month      = bcdToDec(Wire.read());
  year       = bcdToDec(Wire.read());

//--------------------------------------------
    Wire.beginTransmission(0x68);
    Wire.write(0x11);
    Wire.endTransmission();
    Wire.requestFrom(0x68, 2);
    temperature = (Wire.read() & B01111111) + ( (Wire.read() >> 6) * 0.25 );
}
 
void setDateDS3231()           
{
  // Use of (byte) type casting and ascii math to achieve result.
  /*second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48));
  minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  dayOfWeek = (byte) (Serial.read() - 48);
  dayOfMonth = (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(0x68);
  Wire.write(byte(0x00));
  Wire.write(decToBcd(second));  // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));    // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}
 
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
 
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}
 
 
String getTimeStr() {
  String str = String(dayOfMonth) + "." + formatDigit(month, 2) + "." + formatDigit(year, 2) + " " + dayOfWeek + " " + formatDigit(hour, 2) + ":" + formatDigit(minute, 2) + ":" + formatDigit(second, 2) + " temperature " + temperature;
  return str;
}
String formatDigit(int i, int len) {
  String s = String(i);
  while (s.length() < len) {
    s = "0" + s;
  }
  return (s);
}
 
void time_set() {
  Serial.println("Enter Year 2 last digits");
  while (Serial.available() <= 0);
  year = Serial.parseInt();
  Serial.println(year);
 
  Serial.println("Month");
  while (Serial.available() <= 0);
  month = Serial.parseInt();
  Serial.println(month);
 
  Serial.println("dayOfMonth");
  while (Serial.available() <= 0);
  dayOfMonth = Serial.parseInt();
  Serial.println(dayOfMonth);
 
  Serial.println("Day of Week");
  while (Serial.available() <= 0);
  dayOfWeek = Serial.parseInt();
  Serial.println(dayOfWeek);
 
  Serial.println("Hour");
  while (Serial.available() <= 0);
  hour = Serial.parseInt();
  Serial.println(hour);
 
  Serial.println("Minute");
  while (Serial.available() <= 0);
  minute = Serial.parseInt();
  Serial.println(minute);
 
  Serial.println("Second");
  while (Serial.available() <= 0);
  second = Serial.parseInt();
  Serial.println(second);
 
  setDateDS3231();
 
  Serial.println("Time recvd OK");
}
В терминале вводим get
Показываем, что получилось.
Ну ессно пины в эскизе свои прописать - подключить. И не обязательно для БМП и 3231 делать две квадратные шины.
 
Ибо БМП и 3231 на одной шине прекрасно работают.
А это нормально, что видно только одно устройство. Я начинающий так сказать. bmp я прописывал 0х67 в самой библиотеке, 1307 0х68, а почему видна только 0х68. Хотя bmp точно работает. Температуру, влажность и давление выдает.
В вашем примере получается оба устройства через wire.h работают, но вы указываете только 2 контакта, а у меня bmp на D6 и D5, а часы на D2 и D1. И на макетке я часы тестировал с DS1307.h, с wire.h они не работали.
 
Сверху Снизу