Projecting RTC DS3234 data to TFT display

I am using an Arduino Uno R3, DS3234 RTC and TFT display (KMR-1.8 SPI). The schematic looks like this.


I have tested the RTC and TFT using separate sketches and they work fine.

DS3234 code:

#define rtc_cs 10
#include <SPI.h>
#include <RtcDS3234.h>

RtcDS3234<SPIClass> Rtc(SPI, rtc_cs);

void setup () 
{
    Serial.begin(9600);
    SPI.begin();
    Rtc.Begin();
}

void loop () 
{
    RtcDateTime now = Rtc.GetDateTime();
    printDateTime(now);
    Serial.println();
    delay(1000); 
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
    char datestring[20];

    snprintf_P(datestring, 
            countof(datestring),
            PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
            dt.Day() ,
            dt.Month() ,
            dt.Year(),
            dt.Hour(),
            dt.Minute(),
            dt.Second() );
    Serial.print(datestring);
}

I used an elaborate sketch initially to set the RTC date and time and later shortened it to the above format to just initiate the RTC (with battery) and get the time.

TFT Code:

#include <SPI.h>
#include <TFT.h>
#define tft_cs 6
#define rst 8
#define dc 9

TFT myscreen = TFT(tft_cs,dc,rst);

void setup() 
{
myscreen.begin(); 
myscreen.setRotation(1);
myscreen.background(0,0,0);
myscreen.stroke(0,255,0);
myscreen.fill(0,0,225);
myscreen.rect(3,5,150,18);
myscreen.setTextSize(1);
myscreen.text("Sample Text",10,10);
}

void loop() {
myscreen.stroke(255, 255, 255);
myscreen.text("RTC Time:", 10, 30);
delay(1000);
myscreen.stroke(0, 0, 0);
myscreen.text("RTC Time:", 10, 30);
}

I tried combining both the sketches to project the RTC date and time in the TFT display. The RTC values still appear in the serial monitor using the combined sketch but the TFT projects unrecognizable characters in the place of date and time.

RTC+TFT code:

#include <SPI.h>
#include <RtcDS3234.h>
#include <TFT.h>
#define rtc_cs 10
#define tft_cs 6
#define rst 8
#define dc 9

RtcDS3234<SPIClass> Rtc(SPI, rtc_cs);
TFT myscreen = TFT(tft_cs,dc,rst);

void setup() 
{
Serial.begin(9600);
SPI.begin;
Rtc.Begin();
myscreen.begin(); 
      
myscreen.setRotation(1);
myscreen.background(0,0,0);
myscreen.stroke(0,255,0);
myscreen.fill(0,0,225);
myscreen.rect(3,5,150,18);
myscreen.setTextSize(1);
myscreen.text("Sample Text",10,10);

}

void loop() {
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
myscreen.stroke(255, 255, 255);
myscreen.text(now, 10, 30);
delay(1000);
myscreen.stroke(0, 0, 0);
myscreen.text(now, 10, 30);
}
    
#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
    char datestring[20];

    snprintf_P(datestring, 
            countof(datestring),
            PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
            dt.Day(),
            dt.Month(),
            dt.Year(),
            dt.Hour(),
            dt.Minute(),
            dt.Second() );
    Serial.print(datestring);
}

PS: I am new to Arduino and programming. Kindly bear with me if there is a blatant mistake.

Move datestring so it is global. Print that to your screen. Untested:


char datestring[20];  // global now…

void loop() {
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
myscreen.stroke(255, 255, 255);
myscreen.text(datestring, 10, 30);  // print the nice datestring to screen
delay(1000);
myscreen.stroke(0, 0, 0);
myscreen.text(datestring, 10, 30);  // datestring again here
}
    
#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
// moved!    char datestring[20];

If that does not work, see if just screen printing the same thing that worked in your test screen program.

Oh, and welcome to the forum.

a7

Thank you so much for the reply. It worked. Just one more question. The below code under void loop prints the date and time and after 1 second delay erases it and prints the new time.

myscreen.stroke(255, 255, 255);
myscreen.text(datestring, 10, 30);  
delay(1000);
myscreen.stroke(0, 0, 0);
myscreen.text(datestring, 10, 30);

This method gives a flickering effect on the entire date and time when the second changes. Is there a way to avoid this flickering so that the time updates in a smooth way?

Not really, but you can do the erase thing very immediately before the new time thing, so a few things that are now between, and take some time, aren't and therefor won't, viz:

    Serial.println();
    myscreen.stroke(0, 0, 0);
    myscreen.text("                           ", 10, 30);  // erase old datestring 

    myscreen.stroke(255, 255, 255);
    myscreen.text(datestring, 10, 30);  // print the nice datestring to screen. 
    delay(1000);

I had to print blanks, because the trick of writing the Sam string again in black ink fails when the new time is different… you could store the old currently visible time and use it to write over with black ink, but that seems like too much trouble.

It may be faster to figure out a rectangle that covers the same area of the screen and draw that in black.

a7

The code you suggested removed the flickering but the seconds keep printing on the previous values that within few seconds it turns into a block of pixels. I also tried the black rectangle idea but it brings back the flickering. Anyways, I don't want to spend more time over such subtle cosmetic issue. My major issue was solved by your initial comment. Thank you so much for your time and suggestion.

I'm wired a bit differetn. I obsess over subtle cosmetic issues. I find faults with the UI of many (most?) digital device I have.

It annoys me, that annoys the GF. :expressionless:

To me, esp in a commercial product, it is just lazy.

But I get it, you do you.

I (almost) never just write code for ppl here, but... if your original technique for erasing the old time functions to do that, never mind the flickering, post your best code here on this thread at an appropriate time and

I will write something for you to try.

a7

Extremely sorry for the delayed response. I was caught up with some work deadlines. So couldn't look into this for a month or so.

Anyways, I am posting my final code here. I have added an AHT25 to the setup to get the temperature and humidity info as well. Feel free to tinker with it when you have time and see if you can make it better.

#include <Wire.h>
#include <SPI.h>
#include <RtcDS3234.h>
#include <TFT.h>
#include <AHTxx.h>

#define rtc_cs 3
#define tft_cs 7
#define rst 8
#define dc 9


RtcDS3234<SPIClass> Rtc(SPI, rtc_cs);
TFT lcd = TFT(tft_cs, dc, rst);

float T;
float RH;
AHTxx aht20(AHTXX_ADDRESS_X38, AHT2x_SENSOR);


void setup()
{
  Serial.begin(9600);
  SPI.begin;
  Rtc.Begin();
  lcd.begin();

  Serial.println();

  while (aht20.begin() != true)
  {
    Serial.println(F("AHT2x not connected or fail to load calibration coefficient")); //(F()) save string to flash & keeps dynamic memory free

    delay(5000);
  }

  Serial.println(F("AHT20 OK"));


  lcd.setRotation(1);
  lcd.background(0, 0, 0);
  lcd.setTextSize(0.5);
  lcd.fill(0, 0, 225);
  lcd.stroke(255, 255, 255);
  lcd.text("Time: ", 6, 25);
  lcd.text("Temperature:      \367C", 6, 35);
  lcd.text("Relative Humidity:      %", 6, 45);
}

char datestring[20];


void loop() 
{
  RtcDateTime now = Rtc.GetDateTime();
  printDateTime(now);
  Serial.println();

  T = aht20.readTemperature();
  Serial.print("Temperature: ");
  Serial.println(T);

  RH = aht20.readHumidity();
  Serial.print("Relative Humidity: ");
  Serial.println(RH);

  char tem [6];
  String(T).toCharArray(tem, 6);

  char rhum [6];
  String(RH).toCharArray(rhum, 6);

  lcd.stroke(255, 255, 255);
  lcd.text(datestring, 40, 25);
  lcd.text(tem, 78, 35);
  lcd.text(rhum, 115, 45);

  delay(800);

  lcd.stroke(0, 0, 0);
  lcd.text(datestring, 40, 25);
  lcd.text(tem, 78, 35);
  lcd.text(rhum, 115, 45);
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime & dt)
{ snprintf_P(
    datestring,
    countof(datestring),
    PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
    dt.Day(),
    dt.Month(),
    dt.Year(),
    dt.Hour(),
    dt.Minute(),
    dt.Second()
  );
  Serial.print(datestring);
}

Thank you.

Thank you. If you happy, I'm happy. There are a number of changes that might improve the appearance of the operations of your device.

I am currently unable to run your code either in real life or in simulation. But if I read it correctly, you:

write the current date, time, temperature and humidity to the LCD

delay for 800 ms then

write (erase!) the very same date, time, temperature and humidity

rinse and repeat

Since time goes forward in 1000 ms increments, sometimes you will be writing the same information as last loop, sometimes you will be writing a new time.

So there will be an odd rhythmic hiccup which may be observable to a perfectionist.

Also, delay(800) absolutely kills your loop(), meaning that if a day comes when you want to squeeze more functionality into this simple sketch, you would have to rethink that.

So, better: in the loop(), watch to see if the seconds have advnaced. When you see the seconds have advanced, then and only then erase the old written text, and replace it with newly calculated text.

This will make the writing to the LCD regular, in synch with the movement of time.

This will also free your loop() to run wild as it is meant to.

Even better, although it would mean lotsa code and reworking your nicely divided functions, would be to erase/replace only characters that have actually changed since the previous second. This would make for the minimum of observable defects.

In all cases, the less time you spend between "erase" and "replace", the less time there will be a blank spot where a character is sposed to be, and would be the very barest minimum of visible defects.

I repeat, if you happy, I'm happy. But I also repeat, I obsess over subtle cosmetic issues. I enjoy discovering the cause of any I observe and the challenge of eliminating, to the extent possible, any I can. And as I said, if I see them in a commercial product it makes me wish I could fire the engineer(s) who didn't care. Enough.

HTH

a7

Thanks for the reply.

Yes. That's what I thought so initially, but by keeping a time delay of anything between 800 and 1000 ms, the TFT randomly skips a second and displays the next second. It happens like 7-8 times with a minute duration. It displays every second correctly when the delay is between 600-800 ms.

Agreed. But it is best I can do to get a decent projection in the TFT. Check the attached clip, It's not the best, but at least it is readable.

delay.zip (3.7 MB)

On the other hand, anything < 600 ms or removing the delay altogether makes the replacement on the TFT faster, making it unreadable. Check the below clip.

wo_delay.zip (3.4 MB)

I tried that with only the seconds and it was the best result I have ever got. But as you told, I realized that it involves a lot of code if have to do the same for minutes and hours too. Honestly, I don't know how to do that. I can try it if you can give a head start.

Another question. Is it possible to freeze the TFT with the last projected values for close to a min, say 800-900 ms and then use the erase and replace code without using the delay function? Sorry if it sounds dumb.

Never apologize for questions or lack of experience. We all started nowhere.

Here's your code (minus the humidity and temperature) adjusted to free the loop() and eliminate delay(x).

Sry I am still without the ability to compile let alone test this code, but you should see the general idea if you put your finger on it and trace through the logic.

You must have had at least half the idea…

#include <Wire.h>
#include <SPI.h>
#include <RtcDS3234.h>
#include <TFT.h>
#include <AHTxx.h>

#define rtc_cs 3
#define tft_cs 7
#define rst 8
#define dc 9


RtcDS3234<SPIClass> Rtc(SPI, rtc_cs);
TFT lcd = TFT(tft_cs, dc, rst);

float T;
float RH;
AHTxx aht20(AHTXX_ADDRESS_X38, AHT2x_SENSOR);

char datestring[20];
char previousDateString[20];
char previousSecond = -1;

void setup()
{
  Serial.begin(9600);
  SPI.begin;
  Rtc.Begin();
  lcd.begin();

  datestring[0] = '\0';
  previousDateString[0] = '\0';

  Serial.println();



  lcd.setRotation(1);
  lcd.background(0, 0, 0);
  lcd.setTextSize(0.5);
  lcd.fill(0, 0, 225);
  lcd.stroke(255, 255, 255);
  lcd.text("Time: ", 6, 25);

}

void loop() 
{
  RtcDateTime now = Rtc.GetDateTime();

  if (now.second() != previousSecond) {
    return;   // not time to do anything. do other "well-behaved" stuff if you want
  }

// the rest of this loop() runs every time the seconds advacne:

  previousSecond = now.second();

  printDateTime(now);
  Serial.println();

// erase the old datestring
  lcd.stroke(0, 0, 0);
  lcd.text(previousDateString, 40, 25);

// immediately write the new datestring
  lcd.stroke(255, 255, 255);
  lcd.text(datestring, 40, 25);

  strcpy(previousDateString, datestring);   // for next erase
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime & dt)
{ snprintf_P(
    datestring,
    countof(datestring),
    PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
    dt.Day(),
    dt.Month(),
    dt.Year(),
    dt.Hour(),
    dt.Minute(),
    dt.Second()
  );
  Serial.print(datestring);
}

HTH

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.