Help with Strings

Im trying to create a program to list a history of previous faults with the date and time on a TFT Display
I'm having a lot of trouble with this as i am trying to compile a string with the date and time and a brief explanation of the fault.
i want put this information in an array so that i am listing the 10 previous faults that have occurred, with the newest fault simply overwriting the oldest fault and then moving the nine older faults one line down.

I'm sure i would be able to do this with any other type of array, but when i try to just print one element of the string array it prints the same array element 24 some times over and over again, sometimes crashing my program.

if (currentMillis - FaultTimer >= 100) {
  String dataString = rtc.getDateStr();
  dataString += String(",");
  dataString += String(rtc.getTimeStr());
 
 if (FlameLockout == 1) {FaultCode = 1;}
 if (FaultCode != 0){
 if (FaultCode == 1){
 
 FaultCodesDisplay[FaultCodesLine] += dataString;
 FaultCodesDisplay[FaultCodesLine] += String("Flame Out Lockout");
 //FaultCodesDisplay[FaultCodesLine] += '/0';   // i tried adding this, didn't help
 FaultCodesLine ++;
 if (FaultCodesLine >= 9) {FaultCodesLine = 0;}
 

 

 }}}
if (Screen == 2) {
      if(ScreenTwoLoad == 0)
    {
      tft.setTextColor(WHITE);
      tft.setTextSize(1);
      tft.setCursor(0,100);
      tft.println(FaultCodes[FaultCodesLine]);

      
     
      ScreenOneLoad = 0;
      ScreenTwoLoad = 1;
    }}

It is not a good idea to use the String (capital S) class as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

Please post your complete code, not some snippet.

If your program crashes, it gives us a very good reason to say 'stay away from String'.

Also consider using PROGMEM for fixed parts of the error message (e.g. the lockout message itself will never change).

And it's not '/0' but '\0' and it is not needed for Strings.

i would post my code, but I'm trying to rewrite it so it works. so right now my code is a bit of a mess. how do i use cstrings?

do i just replace the word String with the word cstring?

cstring dataString = rtc.getDateStr();

incase i wasn't clear, this is basically what i want to accomplish:

as i would like displayed in serial monitor or tft display

10/10/16 10:28:50 Flame Out Lockout
9/10/16 5:16:10 Low Water Level
ect...
ect...
ect...
8/10/16 20:22:70 Burner Stopped, Oil Level too Low

and then when a new fault appears, if their is not room to display it, it will just delete a older fault and shift all the rest down and place the new fault on top.

11/10/16 15:28:14 BOILER OVER TEMP... RUN!
10/10/16 10:28:50 Flame Out Lockout
9/10/16 5:16:10 Low Water Level
ect...
ect......
ect...
then there is not room on screen for this older fault... so it just gets deleted and overwritten
8/10/16 20:22:70 Burner Stopped, Oil Level too Low

is cstrings the way to do this?

Sparkyman:
how do i use cstrings?

do i just replace the word String with the word cstring?

That's why I gave you the link. And, no, it is not that simple. You need to allocate memory for the string with (for example) char myData[33]; which would create space for a 32 character message and the terminating '\0' (or anything shorter of course).

The code in the demo Serial Input Basics should give you an idea of the concept.

...R

but what I'm trying to setup 10 different spaces for 40 some characters

my brain is going to explode trying to read and understand everything i would need to understand to program something like this, maybe its just best i try to do this another time when i have more experience with Arduino.

You can have a 2 dimensional array of cstrings. I think you create it like this

char myTwoDee[40][10];

or maybe it should be [10][40]

...R

The latter, you want more than 10 characters in one nessage. Glad to see I'm not the only one that has problems with two dimensional arrays:D

@Sparkyman, I will see if I can find some time tomorrow to help you further.

i think i need to read up on what buffers, pointers, invalid operators and invalid conversations are

what i (think) i need to understand at this point is how i can actually save this data to the char

rtc.getDateStr()
rtc.getTimeStr()

and after i save that information i need to save something like

"Flame Out Fault"

the problem is that learned what i needed to know about using strings and was able to save additional information to them using this:

FaultCodes += "Flame Out Lockout";

but i have no understanding of how to do that with a char array and all this documentation is not really helping.

the instructions on this site could just as well be written in a different language for an electrician such as my self to try and understand the point their trying to make.

just wanted to post an update, I'm making some progress. i ended up using char* ... Idk why it just worked

all i can figure out using char* is that i will have to save the date, time , and message in separate arrays, i cannot figure out how to add them together

void loop(){
if (currentMillis - FaultTimer >= 2000) {
 
 if(FlameLockout == 1) {FaultCode = 1;}
 if(FaultCode != XFaultCode){                         // XFaultCode is just a place to save a former value
 
 FaultDates [FaultArray][0] = rtc.getDateStr();
 FaultTimes [FaultArray][0] = rtc.getTimeStr();
 FaultMsg  [FaultArray][0] = "  Flame Out Lockout\0";
 Serial.print(FaultDates[FaultArray][0]);
 Serial.print(FaultTimes[FaultArray][0]);
 Serial.print(FaultMsg[FaultArray][0]);
 FaultArray ++;
 if (FaultArray >9){FaultArray = 0;}

 XFaultCode = FaultCode;
 }
 FaultTimer = currentMillis;

 }
}

i hope, that this is somewhat in the right direction

btw, i would be willing to post my entire code, but it is very long and surpasses the character limit.

You can attach it :wink:

ok, i will post my entire code this time, don't laugh, half of it is intended to be used and the other half is still in debugging mode.

right now i have it set up to record a fault with the time and date overtime i wave my hand over a light sensor.

problem is that every time it records a new time and date stamp it overwrites values saved in different parts of the array, but oddly enough, it doesn't overwrite spots in the array that haven't been written to yet. i don't understand.

Oil_Stove_Program.ino (2.22 KB)

OK so i have made a lot of progresses on this and things are starting to work (a little bit)

the TFT screen will now list faults just like i want it to, but the time that is displayed for them is just the time of the most recent fault. I.E. they all list the same time, and that time is just recorded with the most recent event. i included a picture so you could see some of my setup.

heres the part of the code that I'm fighting with:

#include <DS3231.h>

#include <DallasTemperature.h>

//#include <OneWire.h>

#include <NewPing.h>


//Technical support:goodtft@163.com

// User Defined Timer Values!! These NEED TO BE SET BEFORE OPERATING PROGRAM
unsigned long LockoutAutoResetDelayTime = 10000; // Time in MS to reset burner after when autoreset is possible
unsigned long FlameTimeInVal = 100;              // 1 unit = .5 seconds, the amount of time it takes to cause a flameout lockout
unsigned long FlameTimeOutVal = 100;             // 1 unit = .5 seconds, the amount of time it takes to reset FlameTimeOutVal after flame is recovered
unsigned long RegainLockoutRetryTimer = 500000;  // time in MS, if the burner lights and burns well for this timers duration it will gain more light attempts (up to 2 attempts max)
unsigned long PidUnderTempTimer = 100000;        // the pid needs to meet alarm temp before burner lights, this is the amount of time the pid alarm can be off while burner is burning.
unsigned long BurnerStepInterval = 2000;         // MS wait time between burner steps
unsigned long OilLevelCheck = 0; 
unsigned long  FaultTimer = 0;

// Real Inputs /// 
const int PidRelay = 30; //Input from PID
const int WaterFloat = 31; // Input 31 from water Float
const int FlameSensor = A10; //Analog input 10 from flame sensor
const int WaterTempSens = A11; // Analog Input 11
// Real Ouputs //
const int Pump = 22;  // Output 22 to pump
const int AirCompressor = 23; // Output 23 to air compressor
const int Preheat = 24; //Output 24 to PID
const int Burner = 25; //Output 25 to burner
const int LedPin = 32;

// Input and Output



// other nessicary tags  //
unsigned long OldBurnerStepTime = 0;
unsigned long previousMillis = 0;
unsigned long PreviousMillisFlame = 0;
unsigned long FlameTimeout = 0;
unsigned long XFlameTimeout = 0;
unsigned long FlameTimein = 0;
unsigned long XFlameTimein = 0;
unsigned long LockoutRetryTimer = 0;
unsigned long LockoutRetryCounter = 0;
unsigned long PidAlarmTimeout = 0;
const long FlameOutDelay = 10000;
const int FlameSenseSP = 900; // Setpoint for flame sensor I.E. an acceptable value for flame intensity.
const int TempSPHigh = 180;
const int TempSPLow = 170;
const int off = HIGH;
const int on = LOW;

int Screen = 1;
int ScreenOneLoad = 0;
int ScreenTwoLoad = 0;
int FlameLockout = 1;
int XFlameLockout = 0;
int FlameDetected = 0;
int XFlameDetected = 1;
int BurnerStep = 0;
int XBurnerStep = 1;
int BurnerStepDelay = 0;
int XBurnerStepDelay = 1;
int XXBurnerStepDelay = 1;
int LockoutRetry = 0;
int LockoutTimer = 0;
int OilLevelHR = 0;
int OilLevel = 0;
int TemperatureF;
int FaultCode[9];
int XFaultCode[9];
int FaultCodeIndex = 0;
char* FaultCodes[40];
char* FaultTimes[10][8];
char* FaultDates[10][10];
char* FaultMsg[10][40];
int FaultArray;
int NewFaultLocation;
int Line = 0;
int TxtLine;
int NewFault = 0;

#define trigPin 52
#define echoPin 53
#define TRIGGER_PIN  52
#define ECHO_PIN     53
#define MAX_DISTANCE 200
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);


//Temp Sensor Stuff
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 35
 
// Setup a oneWire instance to communicate with any OneWire devices 
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
 
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>
#include <EEPROM.h>

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

#define  BLACK   0x0000
#define  BLUE   0x0000
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

#define BOXSIZE 40
#define BOXSIZET 50
#define BOXSIZEW 120
#define PENRADIUS 3
int oldcolor, currentcolor;
int FirstTextLine = BOXSIZET + 10;
int SecondTextLine = FirstTextLine + 20;
int ThirdTextLine = SecondTextLine + 20;
int FourthTextLine = ThirdTextLine + 20;

DS3231  rtc(SDA, SCL); // Clock Stuff

void setup(void) {
  

}

#define MINPRESSURE 10  // define some shit
#define MAXPRESSURE 1000 // define more shit


void loop()
{
  unsigned long currentMillis = millis();
 
  int FlameSens = analogRead(FlameSensor);
  int TimerBlackout;
  int WaterFloatState = digitalRead(WaterFloat);
  int PreheatDone = digitalRead(PidRelay); 

  

if (currentMillis - FaultTimer >= 500) {

 
 if(FlameSens < FlameSenseSP) {FaultCode[1] = 1;} else{ FaultCode[1] = 0;}
 if(FlameLockout == 1){ FaultCode[2] = 1;} else { FaultCode[2] = 0;}
 
 for (FaultCodeIndex = 0; FaultCodeIndex < 9; FaultCodeIndex ++){
 if(FaultCode[FaultCodeIndex] == 0){ XFaultCode[FaultCodeIndex] = 0;}
 if(FaultCode[FaultCodeIndex] != XFaultCode[FaultCodeIndex] && FaultCode[FaultCodeIndex] != 0){
 
 FaultArray++;
 if (FaultArray > 9){FaultArray = 0;}
 FaultDates [FaultArray][0] = rtc.getDateStr();
 FaultTimes [FaultArray][0] = rtc.getTimeStr();
 if (FaultCodeIndex == 1){FaultMsg[FaultArray][0] = "  Flame Sensor Dark";}
 if (FaultCodeIndex == 2){FaultMsg[FaultArray][0] = "  Flame Out Lockout";}
 if (FaultCodeIndex == 3){FaultMsg[FaultArray][0] = "  Low Water LVL";}
 
 Serial.print(FaultDates[FaultArray][0]);
 Serial.print(FaultTimes[FaultArray][0]);
 Serial.println(FaultMsg[FaultArray][0]);
 Serial.println("FaultArray");Serial.println(FaultArray);
 XFaultCode[FaultCodeIndex] = FaultCode[FaultCodeIndex];
 ScreenTwoLoad = 0;
 //NewFault = 1;
 }}
 FaultTimer = currentMillis;

 }



    // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////Controlls for Screen 2          
    if (Screen == 2) {
      if(ScreenTwoLoad == 0)
    {tft.drawRect(BOXSIZEW, 0, BOXSIZEW, BOXSIZET, WHITE);   // Bug Fix for page buttons
     tft.drawRect(0, 0, BOXSIZEW, BOXSIZET, BLUE);  //          Same Bug Fix

     tft.fillRect(0, BOXSIZE +1, tft.width(), tft.height() - BOXSIZE -1, BLACK); 
     tft.drawRect(BOXSIZEW, 0, BOXSIZEW, BOXSIZET, WHITE);   // Bug Fix for page buttons
     tft.drawRect(0, 0, BOXSIZEW, BOXSIZET, BLUE);  //          Same Bug Fix
     tft.setTextColor(WHITE);
     tft.setTextSize(1);
     for (Line = 0; Line < 9; Line++){
      TxtLine = 100 + (Line *10);
     NewFaultLocation = FaultArray - Line;
     
     if (NewFaultLocation < 0) {NewFaultLocation = NewFaultLocation + 10;}
     tft.setCursor(0,TxtLine);
     tft.println(FaultDates[NewFaultLocation][0]);
     tft.setCursor(70,TxtLine);
     tft.println(FaultTimes[NewFaultLocation][0]);
     tft.setCursor(110,TxtLine);
     tft.println(FaultMsg[NewFaultLocation][0]);
    
     
    
     }
    


      
     
      ScreenOneLoad = 0;
      ScreenTwoLoad = 1;
    }}

 
}

Hi,

char* s[10][10];

creates a matrix of 100 char pointers.

What you probably want is:

char* s[10];

then store in the n-th element the address of a string literal, like this:

s[0] = (char*)" Flame Sensor Dark";

See this example:

const int MAX_MSG_CNT = 10;


// array of char pointers
char* FaultMsgs[MAX_MSG_CNT];


// initialise the pointers to zero
void initFaultMsgs() {
  for (int i = 0; i< MAX_MSG_CNT; i++) {
    FaultMsgs[i] = (char*)0;
  }
}


// print all entries that point to something
void printMessages() {
  for (int i = 0; i < MAX_MSG_CNT; i++) {
    if (FaultMsgs[i] != (char*)0) {
      Serial.print("fault ");
      Serial.print(i);
      Serial.print(": ");
      Serial.println(FaultMsgs[i]);
    }
  }
}


void setup() {
  Serial.begin(115200);

  initFaultMsgs();

  // make first entry point to a string literal
  // it will store the address of the static string
  FaultMsgs[0] = (char*)"Flame Sensor Dark";
  
  printMessages();
}


void loop() {
}

Also, it seems to me these lines:

        if (FaultCodeIndex == 1) {
          FaultMsg[FaultArray][0] = "  Flame Sensor Dark";
        }
        if (FaultCodeIndex == 2) {
          FaultMsg[FaultArray][0] = "  Flame Out Lockout";
        }
        if (FaultCodeIndex == 3) {
          FaultMsg[FaultArray][0] = "  Low Water LVL";
        }

should probably read:

        if (FaultCode[FaultCodeIndex] == 1) {
          FaultMsg[FaultArray][0] = "  Flame Sensor Dark";
        }
        if (FaultCode[FaultCodeIndex] == 2) {
          FaultMsg[FaultArray][0] = "  Flame Out Lockout";
        }
        if (FaultCode[FaultCodeIndex] == 3) {
          FaultMsg[FaultArray][0] = "  Low Water LVL";
        }

Thanks for everybody who helped me out on this, i was finally able to get it working the way i wanted it to

Sparkyman:
i want put this information in an array so that i am listing the 10 previous faults that have occurred, with the newest fault simply overwriting the oldest fault and then moving the nine older faults one line down.

I'm sure i would be able to do this with any other type of array, but when i try to just print one element of the string array it prints the same array element 24 some times over and over again, sometimes crashing my program.

Without reading your code, straight away I suspect that your algorithm to move all the lines down by one is actually copying line 1 to line 2, line 2 to line 3, and so on and thus filling all of your array with the same stuff. I'd also suspect that the reason for the crash is that you are also copying the last element of the array into the space one element after the array, and so writing over something else. You need to stop one element before the end, and move the second last into the last element. Recall, also, that i a 10-element array, the last element is element 9.

PaulMurrayCbr:
Without reading your code, straight away I suspect that your algorithm to move all the lines down by one is actually copying line 1 to line 2, line 2 to line 3, and so on

I have not read the code either. But if it involves physically moving data from one line to another it is silly. All you need to do is keep a separate array with the line indices in the appropriate order.

...R