The RTC module can output the hours as 165, and the minutes as 165. This is some random number that is different every time. Everything works fine, but at random times I get this. Maybe once every half a minute, or more often. It happens randomly. On the next time update after this I get the correct time values.
I am using the RTClib library from Adafruit and a homemade board on ATmega328 programmed into the Arduino IDE. The DS1307 RTC module connection is copied from a purchased module. On the IIC lines there are pull-up resistors with a nominal value of 4.7K near the RTC chip. The pull-up resistors are removed from the OLED screen board, since they are already present near the RTC chip. But if I solder the resistors back to the OLED board, the behavior does not change.
The values of hours and minutes are displayed in the port monitor and on the SSD1306 OLED display. And here's what the problem looks like:
I also add my code:
// Бібліотеки
#include <Wire.h>
#include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_SSD1306.h> // https://github.com/adafruit/Adafruit_SSD1306
#include "RTClib.h" // https://github.com/adafruit/RTClib
#include <Fonts/DSEG7_Classic_Mini_Bold_32.h>
// Ініціалізація
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS1307 rtc;
// Системні змінні
unsigned long timing = 0; // Відлік оновлення циферблату
boolean dd = 1; // Режим показу двокрапки ":"
int dh, dm;
void setup() {
Serial.begin(9600);
rtc.begin();
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.setFont(&DSEG7_Classic_Mini_Bold_32);
}
void loop() {
if (millis() - timing >= 500) {
timing = millis();
display.clearDisplay();
display.setCursor(0,32);
DateTime now = rtc.now();
dh = now.hour(), DEC;
dm = now.minute(), DEC;
Serial.print(dh);
Serial.print(" : ");
Serial.println(dm);
display.setTextColor(SSD1306_WHITE);
if (dh < 10) {
display.print(0);
}
display.print(dh);
if (!dd) {
display.setTextColor(SSD1306_BLACK);
}
display.print(":");
display.setTextColor(SSD1306_WHITE);
if (dm < 10) {
display.print(0);
}
display.print(dm);
display.display();
dd = !dd;
}
}
Maybe someone had such a problem. I already checked my board, everything is fine with it. The code also seems to be fine. I hope you read to the end.
I checked the connection for correctness. I looked visually. Then I checked the connection with a multimeter. Where it is needed, it is there. There are no short circuits on the board. All power supplies are present. The battery has a voltage of 3.1V. The voltage on the RTC and microcontroller is 5V. I took another RTC module and an Arduino Nano. I assembled the circuit on a breadboard and used the same code. After waiting for 10 minutes, I found no bugs. Maybe my RTC chip in DIY pcb is damaged?
Now I have used a crutch in the code. Since most time queries are output correctly, I check if the new response to the query is no more than one unit relative to the old one. Code without oled display. It is not connected.
#include <Wire.h>
#include "RTClib.h" // https://github.com/adafruit/RTClib
RTC_DS1307 rtc;
unsigned long timing = 0;
boolean dd = 1;
int dh, dm, dh_old, dm_old;
void setup() {
Serial.begin(9600);
rtc.begin();
}
void loop() {
if (millis() - timing >= 500) {
timing = millis();
dh_old = dh;
dm_old = dm;
DateTime now = rtc.now();
dh = now.hour();
dm = now.minute();
if (dd) {
if (dh - dh_old <=1 && dm - dm_old <=1) {
if (dh < 10) {
Serial.print(0);
}
Serial.print(dh);
Serial.print(" : ");
if (dm < 10) {
Serial.print(0);
}
Serial.println(dm);
}
else {
Serial.print("[ERROR] ");
Serial.print(dh);
Serial.print(" : ");
Serial.print(dm);
Serial.println(" [ERROR]");
}
}
dd = !dd;
}
}
This is what I got in the serial monitor:
12 : 00
12 : 00
[ERROR] 15 : 0 [ERROR]
[ERROR] 15 : 0 [ERROR]
12 : 00
12 : 00
Half the solution for my problem:
The isValid() check function did not help me. I get the correct data within 0-23 hours, 0-59 minutes and further. But the time is incorrect. For example, the current time is 15:15, and after updating I can get 23:13. isValid() says that the data is correct, although it is not. So I made my own function to check. Since I update the data every half a second, the hours and minutes cannot exceed one minute (hour) or more. Now I just need to make sure that the received time is correct when the device is turned on, and the function checks the correctness relative to the update moment when the device is turned on. My verification function:
bool testRTC(DateTime now, DateTime prev) {
long deltaMinutes = (now.unixtime() - prev.unixtime()) / 60;
return (deltaMinutes >= 0 && deltaMinutes <= 1);
}
Example usage in code. You just need to store the correct time and new time in some variables. I use mynow and prevnow of type DateTime.
#include "RTClib.h" // https://github.com/adafruit/RTClib
RTC_DS1307 rtc;
DateTime mynow, prevnow;
unsigned long timing1 = 0;
int hh, mm;
void setup() {
Serial.begin(9600);
rtc.begin();
// Trying to get the time right
// So far I don't know how to make sure that the first
// time retrieval from the RTC will be successful
// and the time will be correct.
if (rtc.isrunning()) {
do
mynow = rtc.now();
while (!mynow.isValid());
prevnow = rtc.now(); // Updating the last valid time variable
}
}
void loop() {
if (millis() - timing1 > 500 && rtc.isrunning()) { // Update every half a second
mynow = rtc.now(); // Getting a new time
if (testRTC(mynow, prevnow)) { // Calling the validation function
prevnow = mynow; // If the time is correct, write the new time into the last correct time variable.
hh = mynow.hour(); // Just write the value of the hours into a variable
mm = mynow.minute(); // Just write the value of the minutes into a variable
Serial.print("[ OK] ");
Serial.print(prevnow.hour());
Serial.print(":");
Serial.println(prevnow.minute());
}
else { // If the time differs by one minute
Serial.print("[ERR] ");
Serial.print(mynow.hour());
Serial.print(":");
Serial.println(mynow.minute());
}
}
}
// Time validation
bool testRTC(DateTime now, DateTime prev) {
long deltaMinutes = (now.unixtime() - prev.unixtime()) / 60;
return (deltaMinutes >= 0 && deltaMinutes <= 1);
}
The other half of the solution is to make sure that the microprocessor gets the correct time when it is first turned on. I am on the way to doing this and am using the isValid() function, but it has proven unreliable. Thank you all very much!
Everything works fine
... no, it does notI already checked my board, everything is fine with it.
... how did you check it?