Displaying Text from Datalogger shield on OLED SSD1315 (arduino-seeds)?

Hi everyone!

*my english might be lacking so I'm sorry in advance
I'm really new to this and it's my first time posting here but I can't do it alone
please help me find the right way

So I have an Arduino Uno R3 /
Data logger shield from Elegantstunning bought on amazon (the RTC on it, is DS1307)
/ OLED SSD1315 ( from arduino-seeds)

I'm trying to display a text with differents variables ( my BPM, the time and date as shown in the screenshot below) from the Data logger shield SD card on the OLED BUT the issue is that it is showing on the serial monitor (moniteur série) and not on the OLED (all I see is BPM:430)
I suspect it the " int" part in the code, I've tried to change it (SD.open("BPM.txt", FILE_READ or text ...) but I don't know what to put instead

the Arduino Uno is at the bottom then in the middle the Base Shield to connect the OLED * from Arduino Sensor Kit - Bundle* and the datalogger shield on top

  • here is the text in the serial monitor**
Initializing SD card...Writing to test.txt...testing 1, 2, 3.done.
BPM.txt:
Date,Time,BPM
2021/10/17,11:52:48,104,
2021/10/17,11:52:48,109,
2021/10/17,11:52:49,116,
2021/10/17,11:52:49,114,
Date,Time,BPM
2021/10/17,11:52:53,94,
2021/10/17,11:52:54,97,
2021/10/17,11:52:59,47,
Date,Time,BPM
2021/10/17,11:53:23,37,
2021/10/17,11:53:29,49,
2021/10/17,11:53:32,83,
2021/10/17,11:53:33,82,
2021/10/17,11:53:34,82,
2021/10/17,11:53:35,81,
2021/10/17,11:53:36,80,
2021/10/17,11:53:36,80,
2021/10/17,11:53:37,78,
2021/10/17,11:53:38,76,

here is the code (a mix of Arduino_SensorKit, SD library and from this forum [Getting text from an SDcard and printing it on an Oled display])

 #include "Arduino_SensorKit.h"
#include <SPI.h>
#include <Wire.h>
#include <SD.h>

String text;
const int chipSelect = 10;

File myFile;
void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("BPM.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.print("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("BPM.txt", FILE_READ);
  if (myFile) {
    Serial.println("BPM.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      text = myFile.readString();
      delay(100);
      //Serial.println(text);

    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  Serial.println(text);
  // Oled.setFont(u8x8_font_chroma48medium8_r);
  //Oled.setCursor(0, 3);


  Oled.begin();
  Oled.setFlipMode(true);

}

void loop() {
  int  BPM = "BPM.txt", FILE_READ;   // read file

  Oled.setFont(u8x8_font_chroma48medium8_r);
  Oled.setCursor(0, 33);
  Oled.print("BPM: ");
  Oled.print(BPM);
  Oled.refreshDisplay();
  delay(1000);
} 

Thank you!

Why don't you copy exactly what you are doing in setup() when you read the file? It will work just fine in loop() as well.

Hi Seph,

a big plus for posting code as a code-section.
You can do the same with the text in the serial monitor.
Simply click with mouse into the serial monitor
then press

  • Ctrl-A
  • Ctrl-C
    change to a posting
    click on the </>-Button
    then press Ctrl-C

Beeing a beginner and asking here is what this forum is made for.

is a description that is too vague to be understandable.

You made some effort to add a picture. But to be honest this picture does not help
with information.

The most interesting part is the code.
You seem to not yet understand which line does what. But this is crucial!

So please try to describe what do this lines of code do

Serial.print("Writing to test.txt...");
myFile.print("testing 1, 2, 3.");
 Oled.print("BPM: ");

Just try it. Your answer is important to see on what knowledge-level you are.
This is important to be able to adapt the answers to your knowledge-level.

I guess it will not help very much if I write "read in the needed information from the file store it in variables and send it to the OLED"

best regards Stefan

1 Like

Ctrl-V, I guess :wink:

1 Like

Thank you so much ! I changed my original post like you said.

a description that is too vague to be understandable.
Sorry, I meant that I think that the main reason why the code is not doing what I mentioned is because the value I gave to BPM via the Integers is wrong. sorry if it is still vague

Serial.print("Writing to test.txt...");
from my understanding, this line is giving an order to print in the serial moniter "Writing to test.txt..." as an indicator to let me know that the file is about to be written in_

myFile.print("testing 1, 2, 3.");

"testing 1, 2, 3." will be printing, writing in the file in the SD card

Oled.print("BPM: ");

"BPM: " will be shown on the OLED and BPM will be next to a value ( example BPM: 4)

I admit that I am still trying to figure out what I am concretely doing with each line.

I guess it will not help very much if I write "read in the needed information from the file store it in variables and send it to the OLED"

I have to pick some informations, the mains ones from the file, and put them back in the code line by line via the Integers, is that correct? sorry

Thank you!

Thank you for letting me know but I don't quite understand . Will putting it in loop make it automatically be seen on the OLED ? sorry

So I think I did it I

#include "Arduino_SensorKit.h"
#include <SPI.h>
#include <Wire.h>
#include <SD.h>

String text;
const int chipSelect = 10;

File myFile;
void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("BPM.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    Serial.print("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("BPM.txt", FILE_READ);
  if (myFile) {
    Serial.println("BPM.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      text = myFile.readString();
      delay(100);
      //Serial.println(text);

    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  Serial.println(text);
  // Oled.setFont(u8x8_font_chroma48medium8_r);
  //Oled.setCursor(0, 3);


  Oled.begin();
  Oled.setFlipMode(true);

}

void loop(){
  // re-open the file for reading:
  myFile = SD.open("BPM.txt", FILE_READ);
  if (myFile) {
    Oled.println("BPM.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      text = myFile.readString();
      delay(1000);
      Oled.println(text);

    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  Oled.setFont(u8x8_font_chroma48medium8_r);
  Oled.setCursor(0, 3);
  Oled.refreshDisplay();
  delay(1000);
} 

but I am seeing this

I read the code you have posted.

The code inside loop is executed again and again infinitely.
That is what loop is made for:

looping infinitely.
For your testcode it will be better if the code is executed only once.

that is what function setup() is made for
so here is a code-version that has the code that you had inside loop()

inside a new function which I gave the name
myTestSD_OLED_Function()

the lines of code starting with

void myTestSD_OLED_Function() {

are the definition of the function

the line with

myTestSD_OLED_Function(); 

is calling this function

as myTestSD_OLED_Function(); is inside setup()
it gets executed only once

#include "Arduino_SensorKit.h"
#include <SPI.h>
#include <Wire.h>
#include <SD.h>

String text;
const int chipSelect = 10;

File myFile;
void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("BPM.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    Serial.print("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("BPM.txt", FILE_READ);
  if (myFile) {
    Serial.println("BPM.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      text = myFile.readString();
      delay(100);
      //Serial.println(text);

    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  Serial.println(text);
  // Oled.setFont(u8x8_font_chroma48medium8_r);
  //Oled.setCursor(0, 3);

  Oled.begin();
  Oled.setFlipMode(true);

  Oled.setFont(u8x8_font_chroma48medium8_r);

  myTestSD_OLED_Function(); 

}

void myTestSD_OLED_Function() {
  Oled.setCursor(0, 3);
  Oled.refreshDisplay();
  delay(1000);
  
  // re-open the file for reading:
  myFile = SD.open("BPM.txt", FILE_READ);

  if (myFile) {
    Oled.println("BPM.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      text = myFile.readString();
      delay(1000);
      Serial.println(text);
      Oled.println(text);

    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  
}


void loop(){

}

For narrowing down the problem you should print all things that you are "printing to the OLED also print to the serial monitor.
I added this line

      Serial.println(text);
      Oled.println(text);

If this code-version does not work you should go back to the most simple possible code that does test the OLED-Display by printing a constant string

    Serial.println("ABC");
    Oled.println("ABC");

and test if this works

if this works next step is assigning characters to a variable and printing it

    char myTestCharArray [] = "ABC";
    Serial.println(myTestCharArray);
    Oled.println(myTestCharArray);

and test if this works

next with variable-type String

    String myTestStr = "ABC";
    Serial.println(myTestStr);
    Oled.println(myTestStr);

next with variable-type String

If you don't know yet what variables are how setup() and loop() work
I recommend
Take a look into this tutorial:

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

best regards Stefan

1 Like

Thank you a lot! The difference between setup() and loop() was a bit obscure to me but now I understand more how each works, the importance of writing in the right function.

The code still didn 't work _ the Oled now shows "BPM: D"_ D is the beginning of the text (Date,Time,BPM)

I did the tests you put as an alternative and "ABC" can be seen except for variable-type String.

But I looked at the tutorial, the explainations are really clear,so well illustrated; the variable part or String, array for example, I get the essence of it, I just need to read it more than twice to understand but it definitly make the code more accessible.

So maybe I am gonna try to manually type in the variables by using The Arduino String Object shown in the tutorial; putting aside the SD card..

Thank you so much for helping me out with this code and making me understand how the programming works !

this is a hint that the OLED-object can't work with variable-type "String" directly.

But there is a variant to transform variable-type String into a so called c_str-ring.

try

String myTestStr = "ABC";
    Serial.println(myTestStr);
    Oled.println(myTestStr.c_str()  );

The variable type String is not well suited for RAM-limited microcontrollers.
There are some traps with Strings. Globally defined Strings eat up all memory over time and then the program will crash.
The alternatives are arrays of char (c-strings) or a library called SafeString wich you can install with the library-manager in the Arduino-IDE

Here is a demo-code how SafeStrings can be used

This demo-code has two debug-macros. Which reduce the the code you have to write to print to the serial monitor.
If you have questions about anything just ask

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVar,myInterval);
// myVar can be any variable or expression that is defined in scope
// myInterval is the time-interval which must pass by before the next
// print is executed


#include <SafeString.h>
createSafeString(myDemo_SS, 32);
createSafeString(mySecondDemo_SS, 32);

unsigned long myCounter;

// if program starts printout the source-code filename etc. to the serial monitor
void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);  
}

//useful function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 13; // Arduino-Uno Onboard-LED is IO-pin 13

// make onboard-LED blink to show: "program is running"
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);
  
  if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
    digitalWrite(IO_Pin,!digitalRead(IO_Pin) ); 
  }
}



void setup() {
  Serial.begin(115200);
  Serial.println( F("Setup-Start") );
  PrintFileNameDateTime();
  myCounter = 0;
  myDemo_SS = "Hello world!";
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED,500);
  myCounter++;
  
  // loop is running very fast counting up very fast
  // but only once every 1234 milliseconds print 
  if ( TimePeriodIsOver(MyTestTimer,1234) ) {
    mySecondDemo_SS = myDemo_SS;  // assigning a SafeString to another SafeString
    
    mySecondDemo_SS += " ";       // append a SPACE
    mySecondDemo_SS += myCounter; // append integer-number
    Serial.println(mySecondDemo_SS);    
  }  

}

best regards Stefan

This one also doesn't work; SoString and c_str -ring can't be use with OLED because of limited RAM on the Uno _
Which reminds me that I used String at the beginning of the code String text; so that's also why Oled.println(text) didn't work then

Really thank you ! I am using the website you gave me and learning from the beginning Electronics Course for Beginners because there is a lot of basics notions I don't understand yet

About the code, here I am a bit confused about what need to be put there exactly, what is myFixedText referring to please?

Thank you!

first of all: a "macro" is something very different than any C++-language detail

using the #define "statement" to make the compiler "write" code

#define can be used to make the compiler replace text that describes something with (almost) anything else
easy example
let's assume IO-pin number 4 shall be set to work as output
the command for defining an IO-pin to be configured as output is

pinMode(4,OUTPUT);
the number "4" says nothing about he purpose of this IO-pin

let's assume the IO-pin shall switch On/Off a buzzer

you would have to add a comment to explain
pinMode(4,OUTPUT); // IO-pin 4 is buzzer

the compiler needs the number. To make the code easier to read and understand
#define BuzzerPin 4
So the command looks like this
pinMode(BuzzerPin,OUTPUT);

the descriptive word "BuzzerPin" gets replaced through the compiler by a "4"
so what the compiler compiles is still 'pinMode(4,OUTPUT);'

This means - in some way - the define changes your source-code-file right before compiling

 pinMode(BuzzerPin,OUTPUT);

gets replaced by

 pinMode(4,OUTPUT);

the #define can do much more than just replace a word by a single number
it can even take parameters like in this example

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

here myFixedText and variableName are "variables" on the macro-level

if you write this line

dbg("Hello",Counter);

and you start compiling there will happen two steps
inside the define

#define dbg(myFixedText, variableName)
Serial.print( F(#myFixedText " " #variableName"=") );
Serial.println(variableName);

the macro-variable myFixedText is "evaluated to "Hello"
the macro-variable variableName is evaluated to Counter

which means as a first step what happends is

#define dbg("Hello", Counter)

and a second step replace #define dbg("Hello", Counter) by

Serial.print( F("Hello" " " Counter"=") );
Serial.println(Counter);

It will be enough if you understand the pattern

writing

somewhere in your code you defined a variable

int Counter = 123;

somewhere else in your code you write

dbg("Hello",Counter);

results in serial output
"Hello" Counter=123

writing

somewhere in your code you defined a variable

char myArrayOfChar [ ] = "This is my message";

and somewhere else in your code

dbg("Test",myArrayOfChar);

results in serial output
"Test" myArrayOfChar=This is my message

writing

somewhere in your code you defined a variable

byte numberOfButtonPresses = 678;

and somewhere else in your code

dbg("function myTestfunc",numberOfButtonPresses);

results in serial output
"function myTestfunc" numberOfButtonPresses=678

So dbg and dbgi work this way
first parameter a fixed text that is just quoted
second parameter a variable-name or an expression where the macro prints to the serial monitor the variable-name a "=" and then the value of the variable

best regards Stefan

1 Like