Ds1307 выдает такие данные на выходе 165/165/165 45:165:85

,

Всем привет, столкнулся вот с такой проблемой таймер реального времени ds1307 выдает данные 165/165/165 45:165:85 на выходе, какое-то время все работало отлияно без проблем. Вот мой скетч

#include <_I2C.h>
#include <Wire.h>
#include <Servo.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo myservo;

const int servoPin = 13; // Пин, к которому подключен сервопривод
const int servoOpenAngle = 180; // Угол, на который открывается сервопривод
const int servoCloseAngle = 10; // Угол, в который закрывается сервопривод
const int buttonPinSetTime = 9; // Пин для кнопки установки времени
const int buttonPinServo = 10; // Пин для кнопки управления сервоприводом
const int buttonPinServoDelay = 8; // Пин для кнопки установки времени до открытия сервопривода
const int ledPin = 12; // Пин для встроенного светодиода (для отладки)
const int mySDA = 4; // Pin for SDA
const int mySCL = 5; // Pin for SCL

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte lastMinute = 0; // Переменная для хранения предыдущей минуты
bool servoActive = false; // Флаг, указывающий, активен ли сервопривод в данный момент
bool setServoDelayMode = false; // Флаг, указывающий, находимся ли в режиме установки задержки перед открытием сервопривода
unsigned long lastServoActionTime = 0; // Переменная для хранения времени последнего действия сервопривода
int servoDelayMinutes = 1; // Переменная для хранения времени задержки перед открытием сервопривода (установим по умолчанию 1 минута)
unsigned long timeToNextServo = 0;

enum SettingState { DAY, MONTH, YEAR, HOUR, MINUTE, SECOND };
SettingState currentState = DAY;

#define SDA_LOW()   (digitalWrite(mySDA, LOW))
#define SDA_HIGH()  (digitalWrite(mySDA, HIGH))
#define SCL_LOW()   (digitalWrite(mySCL, LOW))
#define SCL_HIGH()  (digitalWrite(mySCL, HIGH))
#define SDA_READ()  (digitalRead(mySDA))

void resetRTC() {
  pinMode(mySDA, INPUT_PULLUP);
  pinMode(mySCL, INPUT_PULLUP);
  do {
    SDA_HIGH();
    SCL_HIGH();
    if (SDA_READ()) {
      SDA_LOW();
      delay(1); // Short delay to ensure the signal is set
      SDA_HIGH();
    }
    SCL_LOW();
    delay(1); // Short delay to ensure the signal is set
  } while (SDA_READ() == 0);
}

void setup() {
  myservo.attach(servoPin);
  myservo.write(servoCloseAngle); // Установка сервопривода в начальное положение
  pinMode(buttonPinSetTime, INPUT_PULLUP);
  pinMode(buttonPinServo, INPUT_PULLUP);
  pinMode(buttonPinServoDelay, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);

  lcd.begin(16, 2);
  Wire.begin();
  resetRTC(); // Reset the RTC at the start
}

void loop() {
  unsigned long currentTime = millis(); // Получаем текущее время
  lcd.backlight();
  // Получаем данные от таймера DS1307
  getDS1307Time();
  
  // Отображаем данные на LCD
  displayTime();
  
  // Проверяем, если прошла новая минута, то активируем сервопривод
  if (!servoActive && (currentTime - lastServoActionTime) >= (servoDelayMinutes * 60000)) {
    activateServo();
  }

  // Обновляем время до следующего открытия сервопривода
  if (servoDelayMinutes > 0 && !servoActive) {
    timeToNextServo = (servoDelayMinutes * 60000) - (currentTime - lastServoActionTime);
  }

  // Проверяем нажатие кнопки для установки времени
  if (digitalRead(buttonPinSetTime) == LOW && !servoActive) {
    setCurrentState(HOUR);
    setNewDateTime();
  }
  
  // Проверяем нажатие кнопки для управления сервоприводом
  if (digitalRead(buttonPinServo) == LOW) {
    toggleServo();
  } else {
    // Если кнопка отпущена, закрываем сервопривод
    myservo.write(servoCloseAngle);
    servoActive = false; // Сбрасываем флаг активации сервопривода
  }
  
  // Проверяем нажатие кнопки для установки времени до открытия сервопривода
  if (digitalRead(buttonPinServoDelay) == LOW && !servoActive) {
    setServoDelayMode = true;
    setServoDelayTime();
  }
  
  delay(100); // Небольшая задержка для стабильной работы
}

// Функция для установки текущего состояния настройки
void setCurrentState(SettingState state) {
  currentState = state;
}

// Функция для настройки новой даты и времени
void setNewDateTime(){
  lcd.clear();
  switch (currentState) {
    case HOUR:
      lcd.print("Set Hour:");
      break;
    case MINUTE:
      lcd.print("Set Minute:");
      break;
    case SECOND:
      lcd.print("Set Second:");
      break;
  }
  lcd.setCursor(0, 1);
  lcd.print("Press to adjust");
  
  while (digitalRead(buttonPinSetTime) == LOW) {
    switch (currentState) {
      case HOUR:
        adjustValue(hour, 0, 23);
        break;
      case MINUTE:
        adjustValue(minute, 0, 59);
        break;
      case SECOND:
        adjustValue(second, 0, 59);
        break;
    }
    lcd.setCursor(0, 1);
    switch (currentState) {
      case HOUR:
        printDigits(hour);
        break;
      case MINUTE:
        printDigits(minute);
        break;
      case SECOND:
        printDigits(second);
        break;
    }
    delay(200);
  }
  
  // Сохранение новой даты и времени в DS1307
  Wire.beginTransmission(0x68);
  switch (currentState) {
    case HOUR:
      Wire.write(2); // Адрес для часов
      Wire.write(decToBcd(hour)); // Часы
      break;
    case MINUTE:
      Wire.write(1); // Адрес для минут
      Wire.write(decToBcd(minute)); // Минуты
      break;
    case SECOND:
      Wire.write(0); // Адрес для секунд
      Wire.write(decToBcd(second)); // Секунды
      break;
  }
  Wire.endTransmission();
  
  lcd.clear();
  lcd.print("Updated!");
  delay(2000);
}

// Функция для установки времени задержки перед открытием сервопривода
void setServoDelayTime() {
  lcd.clear();
  lcd.print("Set Delay (min):");
  lcd.setCursor(0, 1);
  lcd.print(servoDelayMinutes);
  lcd.print(" min");
  
  while (digitalRead(buttonPinServoDelay) == LOW) {
    adjustServoDelay();
    lcd.setCursor(0, 1);
    lcd.print(servoDelayMinutes);
    lcd.print(" min");
    delay(200);
  }
  lcd.clear();
}

// Функция для увеличения значения времени задержки
void adjustServoDelay() {
  servoDelayMinutes++;
  if (servoDelayMinutes > 480) {
    servoDelayMinutes = 0;
  }
}

// Функция для получения данных от таймера DS1307
void getDS1307Time() {
  Wire.beginTransmission(0x68);
  Wire.write(0); // Указываем начальный адрес данных
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7); // Запрашиваем 7 байт данных
  second = bcdToDec(Wire.read() & 0x7F); // Секунды
  minute = bcdToDec(Wire.read()); // Минуты
  hour = bcdToDec(Wire.read() & 0x3F); // Часы (в 24-часовом формате)
  dayOfWeek = bcdToDec(Wire.read()); // День недели
  dayOfMonth = bcdToDec(Wire.read()); // День месяца
  month = bcdToDec(Wire.read()); // Месяц
  year = bcdToDec(Wire.read()); // Год

  // Отладочное сообщение для проверки получения времени
  Serial.print("Time: ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
}

// Функция для отображения данных на LCD
void displayTime() {
  lcd.setCursor(0, 0);
  lcd.print("Time: ");
  printDigits(hour);
  lcd.print(":");
  printDigits(minute);
  lcd.print(":");
  printDigits(second);
  lcd.setCursor(0, 1);
  lcd.print("Delay: ");
  lcd.print(servoDelayMinutes);
  lcd.print("m ");

  if (!servoActive) {
    unsigned long secondsLeft = timeToNextServo / 1000;
    unsigned int minutesLeft = secondsLeft / 60;
    secondsLeft = secondsLeft % 60;

    lcd.print(minutesLeft);
    lcd.print("m ");
    printDigits(secondsLeft); // Используем функцию printDigits для сек

    lcd.print("s");
  } else {
    lcd.print("Active");
  }
}

// Функция для активации сервопривода
void activateServo() {
  if (servoDelayMinutes > 0 && (millis() - lastServoActionTime) >= (servoDelayMinutes * 60000)) {
    servoActive = true;
    myservo.write(servoOpenAngle); // Открываем сервопривод
    delay(10000); // Задержка для стабилизации положения
    myservo.write(servoCloseAngle); // Закрываем сервопривод
    lastServoActionTime = millis(); // Обновляем время последнего действия сервопривода
    timeToNextServo = servoDelayMinutes * 60000; // Сбрасываем время до следующего открытия сервопривода
    
    // Возвращаем сервопривод на исходное положение только если он был открыт
    if (digitalRead(buttonPinServo) == LOW) {
      myservo.write(servoCloseAngle);
      servoActive = false; // Устанавливаем флаг активации сервопривода в false
    }
  }
}

// Функция для управления сервоприводом
void resetServoTimer() {
  lastServoActionTime = millis(); // Сброс времени последнего действия сервопривода
  timeToNextServo = servoDelayMinutes * 60000; // Сбрасываем таймер
}

void toggleServo() {
  // Если кнопка нажата и сервопривод не активен, то запускаем таймер
  if (digitalRead(buttonPinServo) == LOW && !servoActive) {
    myservo.write(servoOpenAngle); // Открываем сервопривод
    servoActive = true; // Устанавливаем флаг активации сервопривода
    resetServoTimer(); // Сбрасываем таймер
    lcd.clear();
  } 

  
    // Если кнопка отпущена, закрываем сервопривод и сбрасываем флаг активации сервопривода
  if (digitalRead(buttonPinServo) == HIGH) {
    myservo.write(servoCloseAngle); // Закрываем сервопривод
    servoActive = false;
    resetServoTimer(); // Сбрасываем таймер
  }
}

// Функция для преобразования двоично-десятичного кода в десятичное число
byte bcdToDec(byte val) {
  return ((val / 16 * 10) + (val % 16));
}

// Функция для преобразования десятичного числа в двоично-десятичный код
byte decToBcd(byte val) {
  return ((val / 10 * 16) + (val % 10));
}

// Функция для вывода числа с ведущими нулями, если оно меньше 10
void printDigits(byte digits) {
  if (digits < 10) {
    lcd.print("0");
  }
  lcd.print(digits);
}

// Функция для увеличения значения с ограничениями
void adjustValue(byte &value, byte minVal, byte maxVal) {
  value++;
  if (value > maxVal) {
    value = minVal;
  }
}

Может знаете в чем проблема

Для начала

Снимок экрана в 2023-03-05 17-05-33

Обратный апостроф - на кнопке ё, апострофы должны располагаться на отдельных строчках. В таком виде скетч обсуждать невозможно

Снимок экрана в 2024-05-18 20-34-09

Да неужели?

я хотел переделать вопрос с ковычками нормальными

Новым постом вставьте в этой же теме

так и хотел сделать

Недавно сталкивался с этой проблемой. Все решилось

  1. проверкой батарейки (должно быть больше 3.4в) Для проверки батарейку можно не вынимать. На плате есть точка минуса.
  2. проверкой контакта минуса батарейки с соответствующем местом на плате.
  3. Отпаивнием диода D1 и еще заменой двух резисторов (поищите в интернете указание на эту операцию). Это нужно, чтобы убрать вредящую батарейке зарядку ее.
    Из двух купленных 1307 одна устойчиво заработала. Одна батарейка была дохлой и один контакт минус батарейки-плата пришлось восстанавливать.

Здесь явно не та проблема

какое-то время все работало но после выключени все сразу становилось таким

А вот это вот как так?

byte ..., year;

Подожди, подожди, не дави на человека. Он пытается код правильно вставить, а ты его отвлекаешь ))

1 лайк

Молчу-молчу :smiley:

я хотел выводить еще и год месяц и день но потом отказался от этого из-за нехватки места на дисплее

Но вы же с ней работаете потом…

  year = bcdToDec(Wire.read()); // Год

я еще не закончил убирать весь ненужный код

Давай может немного помогу?
По сути избавлялся от варнингов…

Скальпель выскользнул с руки
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Servo.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo myservo;

const int servoPin = 13; // Пин, к которому подключен сервопривод
const int servoOpenAngle = 180; // Угол, на который открывается сервопривод
const int servoCloseAngle = 10; // Угол, в который закрывается сервопривод
const int buttonPinSetTime = 9; // Пин для кнопки установки времени
const int buttonPinServo = 10; // Пин для кнопки управления сервоприводом
const int buttonPinServoDelay = 8; // Пин для кнопки установки времени до открытия сервопривода
const int ledPin = 12; // Пин для встроенного светодиода (для отладки)
const int mySDA = 4; // Pin for SDA
const int mySCL = 5; // Pin for SCL

byte second, minute, hour, dayOfWeek, dayOfMonth, month;
byte lastMinute = 0; // Переменная для хранения предыдущей минуты
bool servoActive = false; // Флаг, указывающий, активен ли сервопривод в данный момент
bool setServoDelayMode = false; // Флаг, указывающий, находимся ли в режиме установки задержки перед открытием сервопривода
unsigned long lastServoActionTime = 0; // Переменная для хранения времени последнего действия сервопривода
int servoDelayMinutes = 1; // Переменная для хранения времени задержки перед открытием сервопривода (установим по умолчанию 1 минута)
unsigned long timeToNextServo = 0;

enum SettingState { HOUR, MINUTE, SECOND, NOTHING };
SettingState currentState = NOTHING;

#define SDA_LOW() (digitalWrite(mySDA, LOW))
#define SDA_HIGH() (digitalWrite(mySDA, HIGH))
#define SCL_LOW() (digitalWrite(mySCL, LOW))
#define SCL_HIGH() (digitalWrite(mySCL, HIGH))
#define SDA_READ() (digitalRead(mySDA))

void resetRTC() {
  pinMode(mySDA, INPUT_PULLUP);
  pinMode(mySCL, INPUT_PULLUP);
  do {
    SDA_HIGH();
    SCL_HIGH();
    if (SDA_READ()) {
      SDA_LOW();
      delay(1); // Short delay to ensure the signal is set
      SDA_HIGH();
    }
    SCL_LOW();
    delay(1); // Short delay to ensure the signal is set
  } while (SDA_READ() == 0);
}

void setup() {
  myservo.attach(servoPin);
  myservo.write(servoCloseAngle); // Установка сервопривода в начальное положение
  pinMode(buttonPinSetTime, INPUT_PULLUP);
  pinMode(buttonPinServo, INPUT_PULLUP);
  pinMode(buttonPinServoDelay, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);

  lcd.begin(16, 2);
  Wire.begin();
  resetRTC(); // Reset the RTC at the start
}

void loop() {
  unsigned long currentTime = millis(); // Получаем текущее время
  lcd.backlight();
  // Получаем данные от таймера DS1307
  getDS1307Time();

  // Отображаем данные на LCD
  displayTime();

  // Проверяем, если прошла новая минута, то активируем сервопривод
  if (!servoActive && (currentTime - lastServoActionTime) >= (servoDelayMinutes * 60000UL)) {
    activateServo();
  }

  // Обновляем время до следующего открытия сервопривода
  if (servoDelayMinutes > 0 && !servoActive) {
    timeToNextServo = (servoDelayMinutes * 60000) - (currentTime - lastServoActionTime);
  }

  // Проверяем нажатие кнопки для установки времени
  if (digitalRead(buttonPinSetTime) == LOW && !servoActive) {
    setCurrentState(HOUR);
    setNewDateTime();
  }

  // Проверяем нажатие кнопки для управления сервоприводом
  if (digitalRead(buttonPinServo) == LOW) {
    toggleServo();
  } else {
    // Если кнопка отпущена, закрываем сервопривод
    myservo.write(servoCloseAngle);
    servoActive = false; // Сбрасываем флаг активации сервопривода
  }

  // Проверяем нажатие кнопки для установки времени до открытия сервопривода
  if (digitalRead(buttonPinServoDelay) == LOW && !servoActive) {
    setServoDelayMode = true;
    setServoDelayTime();
  }

  delay(100); // Небольшая задержка для стабильной работы
}

// Функция для установки текущего состояния настройки
void setCurrentState(SettingState state) {
  currentState = state;
}

// Функция для настройки новой даты и времени
void setNewDateTime() {
  lcd.clear();
  switch (currentState) {
    case HOUR:
      lcd.print("Set Hour: ");
      break;
    case MINUTE:
      lcd.print("Set Minute: ");
      break;
    case SECOND:
      lcd.print("Set Second: ");
      break;
    default:
      break;
  }
  lcd.setCursor(0, 1);
  lcd.print("Press to adjust");

  while (digitalRead(buttonPinSetTime) == LOW) {
    switch (currentState) {
      case HOUR:
        adjustValue(hour, 0, 23);
        break;
      case MINUTE:
        adjustValue(minute, 0, 59);
        break;
      case SECOND:
        adjustValue(second, 0, 59);
        break;
      default:
        break;
    }
    lcd.setCursor(0, 1);
    switch (currentState) {
      case HOUR:
        printDigits(hour);
        break;
      case MINUTE:
        printDigits(minute);
        break;
      case SECOND:
        printDigits(second);
        break;
      default:
        break;
    }
    delay(200);
  }

  // Сохранение новой даты и времени в DS1307
  Wire.beginTransmission(0x68);
  switch (currentState) {
    case HOUR:
      Wire.write(2); // Адрес для часов
      Wire.write(decToBcd(hour)); // Часы
      break;
    case MINUTE:
      Wire.write(1); // Адрес для минут
      Wire.write(decToBcd(minute)); // Минуты
      break;
    case SECOND:
      Wire.write(0); // Адрес для секунд
      Wire.write(decToBcd(second)); // Секунды
      break;
    default:
      break;
  }
  Wire.endTransmission();

  lcd.clear();
  lcd.print("Updated!");
  delay(2000);
}

// Функция для установки времени задержки перед открытием сервопривода
void setServoDelayTime() {
  lcd.clear();
  lcd.print("Set Delay (min): ");
  lcd.setCursor(0, 1);
  lcd.print(servoDelayMinutes);
  lcd.print(" min");

  while (digitalRead(buttonPinServoDelay) == LOW) {
    adjustServoDelay();
    lcd.setCursor(0, 1);
    lcd.print(servoDelayMinutes);
    lcd.print(" min");
    delay(200);
  }
  lcd.clear();
}

// Функция для увеличения значения времени задержки
void adjustServoDelay() {
  servoDelayMinutes++;
  if (servoDelayMinutes > 480) {
    servoDelayMinutes = 0;
  }
}

// Функция для получения данных от таймера DS1307
void getDS1307Time() {
  Wire.beginTransmission(0x68);
  Wire.write(0); // Указываем начальный адрес данных
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7); // Запрашиваем 7 байт данных
  second = bcdToDec(Wire.read() & 0x7F); // Секунды
  minute = bcdToDec(Wire.read()); // Минуты
  hour = bcdToDec(Wire.read() & 0x3F); // Часы (в 24-часовом формате)
  dayOfWeek = bcdToDec(Wire.read()); // День недели
  dayOfMonth = bcdToDec(Wire.read()); // День месяца
  month = bcdToDec(Wire.read()); // Месяц

  // Отладочное сообщение для проверки получения времени
  Serial.print("Time: ");
  Serial.print(hour);
  Serial.print(": ");
  Serial.print(minute);
  Serial.print(": ");
  Serial.println(second);
}

// Функция для отображения данных на LCD
void displayTime() {
  lcd.setCursor(0, 0);
  lcd.print("Time: ");
  printDigits(hour);
  lcd.print(": ");
  printDigits(minute);
  lcd.print(": ");
  printDigits(second);
  lcd.setCursor(0, 1);
  lcd.print("Delay: ");
  lcd.print(servoDelayMinutes);
  lcd.print("m ");

  if (!servoActive) {
    unsigned long secondsLeft = timeToNextServo / 1000;
    unsigned int minutesLeft = secondsLeft / 60;
    secondsLeft = secondsLeft % 60;

    lcd.print(minutesLeft);
    lcd.print("m ");
    printDigits(secondsLeft); // Используем функцию printDigits для сек

    lcd.print("s");

  } else {
    lcd.print("Active");
  }
}

// Функция для активации сервопривода
void activateServo() {
  if (servoDelayMinutes > 0 && (millis() - lastServoActionTime) >= (servoDelayMinutes * 60000UL)) {
    servoActive = true;
    myservo.write(servoOpenAngle); // Открываем сервопривод
    delay(10000); // Задержка для стабилизации положения
    myservo.write(servoCloseAngle); // Закрываем сервопривод
    lastServoActionTime = millis(); // Обновляем время последнего действия сервопривода
    timeToNextServo = servoDelayMinutes * 60000UL; // Сбрасываем время до следующего открытия сервопривода

    // Возвращаем сервопривод на исходное положение только если он был открыт
    if (digitalRead(buttonPinServo) == LOW) {
      myservo.write(servoCloseAngle);
      servoActive = false; // Устанавливаем флаг активации сервопривода в false
    }

  }
}

// Функция для управления сервоприводом
void resetServoTimer() {
  lastServoActionTime = millis(); // Сброс времени последнего действия сервопривода
  timeToNextServo = servoDelayMinutes * 60000; // Сбрасываем таймер
}

void toggleServo() {
  // Если кнопка нажата и сервопривод не активен, то запускаем таймер
  if (digitalRead(buttonPinServo) == LOW && !servoActive) {
    myservo.write(servoOpenAngle); // Открываем сервопривод
    servoActive = true; // Устанавливаем флаг активации сервопривода
    resetServoTimer(); // Сбрасываем таймер
    lcd.clear();
  }

  // Если кнопка отпущена, закрываем сервопривод и сбрасываем флаг активации сервопривода

  if (digitalRead(buttonPinServo) == HIGH) {
    myservo.write(servoCloseAngle); // Закрываем сервопривод
    servoActive = false;
    resetServoTimer(); // Сбрасываем таймер
  }
}

// Функция для преобразования двоично-десятичного кода в десятичное число
byte bcdToDec(byte val) {
  return ((val / 16 * 10) + (val % 16));
}

// Функция для преобразования десятичного числа в двоично-десятичный код
byte decToBcd(byte val) {
  return ((val / 10 * 16) + (val % 10));
}

// Функция для вывода числа с ведущими нулями, если оно меньше 10
void printDigits(byte digits) {
  if (digits < 10) {
    lcd.print("0");
  }
  lcd.print(digits);
}

// Функция для увеличения значения с ограничениями
void adjustValue(byte &value, byte minVal, byte maxVal) {
  value++;
  if (value > maxVal) {
    value = minVal;
  }
}

> Скетч использует 7884 байт (25%) памяти устройства. Всего доступно 30720 байт.
> Глобальные переменные используют 581 байт (28%) динамической памяти, оставляя 1467 байт для локальных переменных. Максимум: 2048 байт

Не видя кода, таки интересуюсь - а зачем вы работаете с RTC напрямую, без библиотек? Если у вас недостаточно опыта, то это прямой путь к таким ошибкам

1 лайк

проблему это не решило

библиотека wire.h уже используется для работы с RTC

Это я знаю. Вопрос был - зачем вы напрямую пытаетесь работать с регистрами модуля RTC? Не проще ли было бы использовать специализированную библиотеку? Например RTCLib.h

Пусть библиотека разбирается с регистрами, а вам отдает готовые данные

1 лайк