Problems with the DS3231 together with the sd card

I'm having problems when using the DS3231 simultaneously with the micro sd card module, when I don't initialize the sd card, the information regarding temperature, time and date appear on the serial monitor perfectly, but when I initialize the sd card , to later save the information there, the sensor information goes crazy, just because I initialized the SD card. PS: I tested the SD card separately, and it works perfectly in isolation.

Code:

//HOME AUTOMATION ARDUINO CODE

// Including of libraries
#include <SD.h>             //SD card library
#include <SPI.h>            //SD card library
#include "Wire.h"           // RTC library
#include "RTClib.h"         // RTC library
#include "ds3231.h"
#define DS3231_I2C_ADDRESS 0x68  // defining real time clock module

#define BUFF_MAX 128

// Arduino component pins

const int sdCardCS = 4;  // SD card module Pins
//SD MOSI = 11
//SD MISO = 12
//SD SCK = 13
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = { "Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sabado" }; // week days

void setup() {

#ifndef ESP8266
  while (!Serial)
    ;  // for Leonardo/Micro/Zero
#endif

  Serial.begin(9600);

  Wire.begin();

  delay(1000);  // wait for console opening
  Serial.print("SD CARD STARTUP.....");

  pinMode(10, OUTPUT);
  delay(2000);
  // if (SD.begin(sdCardCS)) {
  //   Serial.println("SD CARD FAILED!");
  //   return;
  // }
  // Serial.println("SD CARD INITIALIZED!");

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1)
      ;
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2016, 7, 17, 12, 19, 0));



    delay(1000);
  }
}


void loop() {

  char in;
  char buff[BUFF_MAX];
  char tempF[6];
  float temperature;
  struct ts t;

  parse_cmd("C", 1);

  temperature = DS3231_get_treg();  //Get temperature
  dtostrf(temperature, 5, 1, tempF);

  DateTime now = rtc.now();

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" (");
  Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
  Serial.print(") ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();


  Serial.println();
  //  delay(1000);

  // print temperature reading to seriel
  //Serial.println(tempC);
  Serial.println("");
  Serial.print("Temperature C - ");
  Serial.print(tempF);
  Serial.println("C ");

  // File dFile = SD.open("datalog.txt", FILE_WRITE);

  // // if available, write the file:
  // if (dFile) {
  //   dFile.println("");
  //   dFile.print(now.year(), DEC);
  //   dFile.print('/');
  //   dFile.print(now.month(), DEC);
  //   dFile.print('/');
  //   dFile.print(now.day(), DEC);
  //   dFile.print(" (");
  //   dFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
  //   dFile.print(") ");
  //   dFile.print(now.hour(), DEC);
  //   dFile.print(':');
  //   dFile.print(now.minute(), DEC);
  //   dFile.print(':');
  //   dFile.print(now.second(), DEC);
  //   dFile.println("Temperature is - ");
  //   dFile.print(tempF);
  //   dFile.print(",");
  //   dFile.print("The Light Reading is -");
  //   dFile.println("");
  //   dFile.close();
  //   // print to the serial port too:
  //   Serial.print(tempF);
  //   Serial.println("C ");


  //   delay(1000);
  // }
  // // if the file isn't open, show error:
  // else {
  //   Serial.println("error opening datalog.txt");
  // }

  delay(5000); //Interval
}

// microseconds to centimeters conversion
long MsToCm(long microseconds) {
  return microseconds / 29 / 2;
}

void parse_cmd(char* cmd, int cmdsize) {
  uint8_t i;
  uint8_t reg_val;
  char buff[BUFF_MAX];
  struct ts t;

  if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register
    Serial.print("temperature reg is ");
    Serial.println(DS3231_get_treg(), DEC);
  }  
}

Serial monitor with the card initialized:
SD CARD STARTUP.....SD CARD INITIALIZED!
Couldn't find RTC

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Soft WDT reset

Exception (4):
epc1=0x402010f4 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

stack>>>
ctx: count
sp: 3ffffe40 end: 3fffffd0 offset: 0160
3fffffa0: 53444653 00000400 003d0900 feefeffe
3fffffb0: 3fffdad0 00000000 3ffeeb2c 40206e5c
3fffffc0: feefeffe feefeffe 3fffdab0 40101045
<<<stack<<<
`

Serial monitor with the card no initialized:

Temperature C - 31.8C
temperature reg is 31.7500000000
2024/3/15 (Sexta) 16:47:32

HEALP ME PLEASE

Please edit your post to add code tags.

Instructions are in the "How to get the best out of this forum" post, linked at the head of every forum category.

Please include links to the DS3231 module and SD card module you are using. And a schematic could also be helpful in diagnosing your problem.

As you are probably aware, rtc is an I2C device and SD card is an SPI device. The only thing they have in common is the Arduino and the power supply. You might look to the latter, particularly as card slots are not famous for their frugality.

1 Like

For what its worth, this code runs an SD card, OLED, Thermocouple and RTC on a SAMD21 M0 mini. I don't think the SAMD21 is needed but I was learning it so I used it here.

Perhaps you can dissect it and get yours working.

John

/*
    Furnace Monitor App (author jrf aka JohnRob)

    Writes furnace data to SD Card with every furnace data input change.
    Samples at 100ms rate with a DEBOUNCE samples.

	see: FurnaceLogNotes.docx/pdf
   see Lucidchart for flowcharts.

    !!!! Cannot set RTC date or time.   Must use "SetDateTime" and the included library !!!!

  Revisions:
	v0.1  2023-05-21 based on FurnaceApp v14, changed pinout
   v0.2  2023-06-11 added run/pause switch.
   v0.3  2023-06-24 changes in display formatting, added pause switch, sorted out error signals
   v0.5  2023-      made array buffer for data to SD.
   
TODO:
   buffer the data going to the SD card to reduce the Number of writes.

   EIC Interrupt Control:
  	   EIC->CTRL.bit.ENABLE = 1;   and   	EIC->CTRL.bit.ENABLE = 0;

  Target Processor / Board:
      SAMD21 M0 mini - a Variant of the Arduino M0 (RobotDyn version)

   Hardware:
	 1) MAX31855k,4 SPI, performs conversion when CS goes high, No library req'd
    2) DataLoggerV11 board:
	   - SD Card, SPI,  caution some boards don't tri-state MISO,   SDFat library
	   - DS3132 RTC,        No library required.
	   - OLED 128 x 32      ASCII1306 Library
    3) Hand made Isolator board for 24Vac Inputs 
*/

#define VERSION "Ver: 0.5"
#define DEBUG

#define bufferSize 128

#include <Wire.h>
#include <SPI.h>  // SD Card & TypeK

#include "SdFat.h"
SdFat SD;  // keep existing code that used SD but still use the SdFat library

// OLED
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

#include "BoilerApp.h"
#include "oledMap.h"  // no code, just display information

// *** declare Functions Prototypes ********************************************
// ***************************************************************************


void init_pins_int(void);
bool initSD_Card(void);
bool init_RTC(void);
bool init_TypeK(void);
void init_OLED(void);
void ConvertSectoHour(int32_t n);
void WriteDataSD(void);
bool WriteFileHeader(void);
uint16_t ReadRawTemperature(void);

// *** declare Objects *******************************************************
// ***************************************************************************
File myFile;  // create instance of a "File" class for SD Card

SSD1306AsciiWire oled;  // create an "oled" object

// *** declare gVariables ****************************************************
// ***************************************************************************
uint16_t hour;
uint8_t minute;
uint8_t second;

byte ourInputs[] = { BurnerPin, Level1Pin, Level2Pin, Level3Pin, Level4Pin };
#define NUMINPUTS sizeof(ourInputs)
uint8_t Data[NUMINPUTS + 2], prevData1[NUMINPUTS + 2], prevData2[NUMINPUTS + 2];
uint8_t tempData;
bool _BufferData = false;  // goes true on input change resulting in the data written to SD
// Δ seconds, Temp °C, Burner, Level 1, Level 2, Level 3, Level 4
uint32_t _ΔSecBuffer[bufferSize];
float _tempBuffer[bufferSize];
bool _BurnerBuffer[bufferSize];
bool _Level1_Buffer[bufferSize];
bool _Level2_Buffer[bufferSize];
bool _Level3_Buffer[bufferSize];
bool _Level4_Buffer[bufferSize];

bool gSys_error = false;
bool gSD_error  = false;
bool gRTC_error = false;
bool gTC_error  = false;


// *** Setup  ****************************************************************
// ***************************************************************************

void setup() {

  SerialUSB.begin(115200);
  while (!SerialUSB) {}
  delay(2000);
  SerialUSB.println(".....starting    ");
  SerialUSB.print(" number of inputs defined = ");
  SerialUSB.println(NUMINPUTS);

  // start I2C...
  Wire.begin();
  Wire.setClock(100000UL);

  SPI.begin();  // not sure if this is needed for SD card?

  // *** init Devices <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  init_pins_int();
  init_OLED();
  gTC_error = init_TypeK();
  gSD_error = initSD_Card();
  SerialUSB.println(gDataFile);
  gRTC_error = init_RTC();
  WriteFileHeader();
  oled.print(VERSION);
  oled.setCursor(0 * 8, 4);
  if (gRTC_error) {
    oled.print("RTC Error");
    delay(20000);
  } else {
    oled.print(" setup complete");
    delay(5000);
  }
}  //--- setup ---

uint32_t oldMillis = millis();  // aka "unsigned long"

// ***************************************************************************
// *** MAIN loop *************************************************************
// ***************************************************************************

void loop() {

  while (digitalRead(Run_Pause)) {
    oled.println(" paused ");
    delay(2000);
  }

  if (millis() >= oldMillis + 100) {
    for (uint8_t i = 0; i <= NUMINPUTS - 1; i = i + 1) {
      // -----------------------------------------see end of h file
      Data[i] = digitalRead(ourInputs[i]);
      tempData = prevData2[i] << 2 | prevData1[i] << 1 | Data[i];
      prevData2[i] = prevData1[i];
      prevData1[i] = Data[i];

      if ((tempData == 3) | (tempData == 4)) { _BufferData = true; }
    }  // --- for ---


// =======================================================================
// =====  log data here
// =======================================================================
    if (_BufferData) {
      WriteDataSD();
      _BufferData = false;
      ++logCount;
      oled.SSD1306Ascii::setCursor(10 * 8, 2);
      oled.clearToEOL();
      oled.print(logCount);
    }


bool _BufferData = false;  // goes true on input change resulting in the data written to SD
// Δ seconds, Temp °C, Burner, Level 1, Level 2, Level 3, Level 4
uint32_t _ΔSecBuffer[bufferSize];
float _tempBuffer[bufferSize];
bool _BurnerBuffer[bufferSize];
bool _Level1_Buffer[bufferSize];
bool _Level2_Buffer[bufferSize];
bool _Level3_Buffer[bufferSize];
bool _Level4_Buffer[bufferSize];





// "Δ seconds, Temp °C, Burner, Level 1, Level 2, Level 3, Level 4"
//   uint32_t , float, bool, bool, bool,bool, bool

// =======================================================================
// ===== 
// =======================================================================

    oldMillis = millis();
  }  // -- 100 millis --

  if (gDisplaySeconds >= displayUpdate) {
    if (gSD_error | gRTC_error | gTC_error) {
      gSys_error = true;
    }
    else{
      gSys_error = false; 
    }

    UpdateDisplay();
    gDisplaySeconds = 0;
  }

}  // --- loop

// ************************************************************
// *** interrupt routine(s) *************************************
// ************************************************************

void ispSeconds() {
  ++SQWseconds;
  ++gDisplaySeconds;
}

// **********************************************************************
// *** functions ********************************************************
// **********************************************************************

// RTC communication  ------------------------------------------------------------------
uint8_t I2C_readByte(const uint8_t addr) {
  uint8_t data;
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(addr);
  Wire.requestFrom(RTC_ADDRESS, (uint8_t)1);
  data = Wire.read();
  RTC_Error = Wire.endTransmission();  //returned status; 0 = success
  return data;
}  // readByte()

//--------------------------------------------------------------------------------------
void I2C_writeByte(const uint8_t addr, const uint8_t data) {
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(addr);
  Wire.write(data);
  RTC_Error = Wire.endTransmission();
}  // writeByte()

//--------------------------------------------------------------------------------------
void UpdateDisplay(void) {
  // Display1 line
  oled.home();
  oled.print("run h:m ");
  oled.clearToEOL();
  ConvertSectoHour(SQWseconds);
  oled.print(hour);
  oled.print(":");
  if (minute < 10) oled.print("0");
  oled.print(minute);
  //oled.print(":");
  //if (second < 10)  oled.print("0");
  //oled.print(second);

  // Display1 line 2
  oled.setCursor(0 * 8, 2);
  oled.print("# rdgs ");
  

  // Display1 line 3
  oled.setCursor(0 * 8, 4);
  oled.print("Temp     ");
  oled.clearToEOL();
  uint16_t RTemp;
  RTemp = (ReadTemperature() >> 2) * 0.25;
  oled.print(RTemp);
  oled.print(" $C");

  // Display1 line 4
  oled.setCursor(0 * 8, 6);
  oled.print("Status:");
  if (gSD_error | gRTC_error | gTC_error) {
    oled.print(" Error");
  } else {
    oled.print("No Error");
  }
}  // --- end of Display1 ---

// void  clearField (uint8_t col, uint8_t row, uint8_t n)
// void  clearToEOL ()




//--------------------------------------------------------------------------------------
uint16_t ReadTemperature(void) {
  uint16_t gRawData = 0;

  digitalWrite(TC_CSn, LOW);  //stop  measurement/conversion
  delayMicroseconds(10);
  digitalWrite(TC_CSn, HIGH);  //start measurement/conversion
  delay(200);
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));  // ??  see .h line 35
  digitalWrite(TC_CSn, LOW);                                        // because the SD and T/C SPI's operate at different speeds, we must not assert
                                                                    // CS\ until after the SPI.beginTransaction.  This allows time to change the SPI
                                                                    // clock before attempting to read data.

  // read MSB only:
  gRawData = SPI.transfer16(0x0000);  // TypeK is read only, doesn't matter what is sent in SPI.transfer16(0x000)
  digitalWrite(TC_CSn, HIGH);         // de-select and start a new conversion to be read the next time through
  SPI.endTransaction();
  SerialUSB.print("gRawData=  ");
  SerialUSB.println(gRawData);  //  for debug only
  gTC_error = false;
  if (gRawData & 0b01) {
    gTC_error = true;
  }
  return gRawData;
}

//--------------------------------------------------------------------------------------
void WriteDataSD(void) {

#ifdef DEBUG
  SerialUSB.print(Data[0]);
  SerialUSB.print(",   ");
  SerialUSB.print(Data[1]);
  SerialUSB.print(",   ");
  SerialUSB.print(Data[2]);
  SerialUSB.print(",   ");
  SerialUSB.print(Data[3]);
  SerialUSB.print(",   ");
  SerialUSB.print(Data[4]);
  SerialUSB.print(",   ");
  SerialUSB.println();
#endif

  myFile = SD.open(gDataFile, FILE_WRITE);
  SerialUSB.print(" myfile results= ");
  SerialUSB.println(myFile);
  if (myFile) {
    myFile.print(SQWseconds);
    myFile.print(", ");
    myFile.print((ReadTemperature() >> 2) * 0.25);
    myFile.print(", ");
    //SerialUSB.println("writing to SD");
    myFile.print(Data[0]);
    myFile.print(", ");  // Burner
    myFile.print(Data[1]);
    myFile.print(", ");  // Level 1
    myFile.print(Data[2]);
    myFile.print(", ");  // Lavel 2
    myFile.print(Data[3]);
    myFile.print(", ");  // Level 3
    myFile.print(Data[4]);
    myFile.print(", ");  // Level 4
    myFile.println("end of data");
    myFile.close();
  }  // if (myFile),  Loop time was: 18 ~ 19 ms with a few at 25 ms
  else {
    SD_Error = true;  // --- if (myFile) else
  }
}  // WriteDataSD

//--------------------------------------------------------------------------------------
// function convert second into hour minutes seconds
//--------------------------------------------------------------------------------------
void ConvertSectoHour(uint32_t n) {
  hour = n / 3600;
  n = n % 3600;
  minute = n / 60;
  n %= 60;
  second = n;
}

// --- Toggle LED --------------------------------------------
//digitalWrite(ledPin,!digitalRead(ledPin));


// ************************************************************
// *** initialization functions *******************************
// ************************************************************

void init_pins_int(void) {

  // Setup CS pins first....
  pinMode(TC_CSn, HIGH);  // enables pull-up immediately keeping pin high
  digitalWrite(TC_CSn, HIGH);

  pinMode(SD_CSn, HIGH);
  digitalWrite(SD_CSn, HIGH);

  pinMode(SS, OUTPUT);  // not sure this is required.
  // Note even if you use a different chip select pin, the hardware SS pin must be kept as an output
  // or the SD library functions will not work.

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, 0);

  pinMode(Level4Pin, INPUT_PULLUP);
  pinMode(Level3Pin, INPUT_PULLUP);
  pinMode(Level2Pin, INPUT_PULLUP);
  pinMode(Level1Pin, INPUT_PULLUP);
  pinMode(BurnerPin, INPUT_PULLUP);
  pinMode(intSQWPin, INPUT);

  attachInterrupt(digitalPinToInterrupt(intSQWPin), ispSeconds, RISING);

  pinMode(Run_Pause, INPUT_PULLUP);
  return;
}

//--- OLED Initialization ------------------------------------------------------------------------
void init_OLED() {
  oled.begin(&SH1106_128x64, OLEDADDRESS);
  oled.setFont(ZevvPeep8x16);  // Screen = 4 (0,2,4,6) lines X 16 characters (0 to 15)
  oled.clear();
}


// --- SD Card initialization function ---
bool initSD_Card(void) {
  bool error = false;
  if (!SD.begin(SD_CSn)) {
    error = true;  //returns 1 on success, 0 on failure.
  }

  if (digitalRead(SD_Detectn)) {
    oled.setCursor(0 * 8, 4);
    oled.print(" no SC Card installed");
  }

  // loop until we find a file that doesn't already exist.......
  do {
    itoa(gFileNumb, gDataFile, 10);  // (value, Array, base)
    const char *extension = ".csv";
    strcat(gDataFile, extension);  // syntax:  strcat(dest, source)
    ++gFileNumb;
  } while (SD.exists(gDataFile));  // assume will Rtn false if  no communication.

  myFile = SD.open(gDataFile, FILE_WRITE);
  if (myFile) {  // if the file opened okay, write to it:
    myFile.print(" init...");
    //myFile.println(gDataFile);
    myFile.close();
  } else {
    error = true;  // if the file didn't open, print an error:
  }
  return error;
}  // --- initSD_Card ---


//--------------------------------------------------------------------------------------
bool init_RTC(void) {
  bool error;
  gReg0x0F = I2C_readByte(RTC_0F);  // (address, data)
  if (gReg0x0F & 0b10000000) {      // test OSF bit
    error = true;
  } else {
    I2C_writeByte(RTC_0E, 0x0);
    I2C_writeByte(RTC_0F, 0x0);
    error = false;
  }
  return error;
}  // --- init_RTC ---

//--------------------------------------------------------------------------------------



//--------------------------------------------------------------------------------------
bool init_TypeK(void) {
  // doesn't really initialize, simply reads the error bit

  int16_t gRawData = 0;
  bool error = false;
  //digitalWrite(TC_CSn, LOW);
  //delayMicroseconds(10);           // spec is 1µs
  digitalWrite(TC_CSn, HIGH);
  //delay(1);

  // read the MSB only (i.e. D31 - D16)
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));  //  ??? see .h line35
  digitalWrite(TC_CSn, LOW);                                        // because the SD and T/C SPI's operate at different speeds, we must not assert
                                                                    // CS\ until after the SPI.beginTransaction.  This allows time to change the SPI
                                                                    // clock before attempting to read data.


  gRawData = SPI.transfer16(0x0000);  // TypeK is read only, doesn't matter what is sent in SPI.transfer16(0x000)
  digitalWrite(TC_CSn, HIGH);         // deselect
  SPI.endTransaction();

  if (gRawData & 0b0001) {
    error = true;
  }  // in the MSB, the fault bit (D16) is availiable
  return error;
}

//--------------------------------------------------------------------------------------
bool WriteFileHeader() {
  bool error = false;
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00);  // This is the first register address (Seconds)
  // ... read from here 7 uint8_t's
  Wire.endTransmission(false);
  Wire.requestFrom(RTC_ADDRESS, 7);
  uint8_t ss = bcd2bin(Wire.read() & 0x7F);  // why mask 8th bit here?
  uint8_t mm = bcd2bin(Wire.read());
  uint8_t hh = bcd2bin(Wire.read());
  Wire.read();  // day of week, not used
  uint8_t d = bcd2bin(Wire.read());
  uint8_t m = bcd2bin(Wire.read());
  uint16_t y = bcd2bin(Wire.read()) + 2000;

  myFile = SD.open(gDataFile, FILE_WRITE);
  if (myFile) {
    myFile.print("DataFile Name: ");
    myFile.println(gDataFile);
    myFile.println();
    myFile.print("Firmware Version:  ");
    myFile.println(VERSION);
    myFile.println();
    myFile.print("Creation Date - Time: ");
    myFile.print(y);
    myFile.print("-");
    myFile.print(m);
    myFile.print("-");
    myFile.print(d);
    myFile.print("  ");
    myFile.print(hh);
    myFile.print(":");
    myFile.print(mm);
    myFile.print(":");
    myFile.println(ss);
    myFile.println();
    myFile.println("Δ seconds, Temp °C, Burner, Level 1, Level 2, Level 3, Level 4");
    myFile.close();
    //  0394  hex for delta symbol in excel
  } else {
    error = true;
  }
  return error;
}

// --- end of code ---

/*
Abbreviated function explanation:
   Goal is to log every furnace change with time, temperature and input states.

   Time is in elapsed seconds since startup.  On startup, the full time an date is written to
   SD file becoming the zero seconds reference.  All data is then recorded as seconds from this
   time - date.

   Furnace inputs are read every 100 ms (time could may changed).  On reading, a count is initialized
   for any changed input.  If an input is still shown as changed after a 2 count of samples, the program
   accepts this change as valid and logs the data to the SD card.  Now that we are reading the thermostat
   output, we might change this to a 20ms delay and reread.
  

   Note 1: Since we only want Temperature from the MAX31855k we only need to Read
		the MSB which contains the temperature and a failure indication.

   Note 2: TypeK is read every <displayUpdate> seconds.  The conversion is actually immediately
        after the temperature is read.  So <gTK_RawTemperature> is <displayUpdate> seconds old.

   Note 3: OLED Display:
		Health status of:
			TypeK -  Status from "beginTransmission" ~line 62, 182
			RTC and RTC current time (i.e. ofs):  ~lines 149, 159, 295
			SD Card   @lines  109, 128
		Temperature
		# of changes written to SD
		HHH:MM:SS

      OLED Line 1:
      1234567890123456
      ttt°C,Rdg ######

      OLED Line 2:
      1234567890123456
      SRT000 HHH:MM:SS
*/

// --- eof ---

1 Like

I will try, thank you!

Thank you bro, I switched to SPI and it worked

I've fixed your attempt at code tags :wink: Thanks for trying :+1:

Code tags are three backticks ( ``` ) on their own line.

1 Like

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