Sketch Creation - "...Of Memory EEPROM" - Car Engine Controling

Hi everybody !
I'm new here :slight_smile:
I'm using Arduino for 2 years, but now i'm trying to do something more difficult.
I'm having problems with my new Car Controller.

I use :

  • LCD DfRobot Keypad
  • Keypad BV4605 I2C
  • Arduino Uno R2 (Powered by Vin)
  • Max Converter SPI For Temperature
  • A BreadBoard With Alimmentation 5 and 3.3 Each Side

My problems, After 1 minute, Serial print "... Of memory EEPROM"
I Know my Code is not Perfect ... and not finished !
If you have Any tweak, Tell me :slight_smile:

Ps: Sorry for mistake of language, i'm French.

#include <LiquidCrystal.h>
#include <MAX31855.h>
#include <DFR_Key.h>
#include <Wire.h>
#include <bv4506.h>
#include <I2c_bv.h>
#include <EEPROMEx.h>


//Keypad 3X4
BV4506 keypad(0x31);
int keypadDown;
long clavierBkT;
boolean clavierBk = false;

DFR_Key keypadLCD;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 
double voltage,voltageR,voltageC;
int count, clavier = 0, clavierP;

//Action
int waitingA = 0;

//message
String mBuffer1,mBuffer2,mBuffer3,mBuffer4;
int countB;
boolean mBufferM;


//Thermocouple
  // ***** PIN DEFINITIONS ***** Thermocouple
  const  unsigned  char thermocoupleSO = 13;
  const  unsigned  char thermocoupleCS = 12;
  const  unsigned  char thermocoupleCLK = 11;
  // Declaration
  MAX31855  MAX31855(thermocoupleSO, thermocoupleCS, thermocoupleCLK);

//Gestion du loggage
  int logged = 0;
  String passTemp, passCar = String(EEPROM.readInt(10));
    
void setup()
{
  
  //Serial for test
  Serial.begin(115200);
  Serial.println("Demarrage");
  //Keypad
    Wire.begin();
    
  //LCD
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,1);
  
    //pinMode(2, INPUT); // Hall sensor
    //digitalWrite(2, HIGH);
 
  //Demarrage
    lcd.print("Cumpu-Benda");
    delay(1000);
    lcd.clear();

  // Init Boucle
    count = 0;
  

}

void loop()
{
  //Keypad

  //Login
  if (logged == 0) {
    lcd.setCursor(0,0);
    lcd.print("Identification:");
    if (touchePresser()) {
      lcd.setCursor(0,1);
       switch (passAppend(clavierP)) {
        case 1:
          //Bon
          lcd.print("Ok");
          delay(1000);
          lcd.clear();
          logged = 1;
          Serial.println("Logged In");
          break;
        case 2:
          //Faux
          lcd.print("Error Password");
          delay(1000);
          lcd.clear();
          break;
        case 3:
          //Etoile
             for (int i=0; i < passTemp.length(); i++){
              lcd.print("*");
             } 
          break;
      }
    
    }

  }
  
  else {
      
    double Vcc;
    unsigned int ADCValue;
 
    Vcc = readVcc()/1000.0;
    ADCValue = analogRead(1);
    voltage = voltage + ( (ADCValue / 1023.0) * Vcc );
    count++;
    
    keypad.clear();
    clavier = keypadLCD.getKey();
    if (clavier == SAMPLE_WAIT) clavier = 0;  
    
    if (action(-2)) {
      //Faire action plutot que de gerer le reste
    }
    else if (touchePresser()) { //menu keypad Action
      Serial.println("action keypad");
      action(clavierP);
    }//Fin menu keypad
    
    if (messageBuffer()) { // Gestion de l'affichage forcer
    }
    
    else  { // Action au LCD detecter
      if (count >= 200) 
      {
        
          
          if (clavier == 3)
          {
            lcd.clear();  
            voltageC = voltage/count;
            voltageR = (voltageC * 2.7428571) + 2.16;
            lcd.setCursor(0,0);
            lcd.print("Tension Vin");
            lcd.setCursor(0,1);
            lcd.print(voltageR);
            lcd.setCursor(6,1);
            lcd.print(voltageC);
          }
          else if (clavier == 2)
          {
            lcd.clear();     
            voltageC = voltage/count;
            lcd.setCursor(0,0);
            voltageR = (voltageC * 2.7428571) + 2.16;
            float tensionpourcent = fmap(voltageR, 11.80, 13.50, 0.00, 100);
            lcd.print(tensionpourcent);
            lcd.setCursor(7,0);
            lcd.print("%");
            lcd.setCursor(0,1);
            lcd.print(MAX31855.readThermocouple(CELSIUS));
          }
          
          else if (clavier == 4)
          {
            
    
               lcd.clear();
               lcd.setCursor(0,1);
               lcd.print(clavierP);
               lcd.setCursor(0,0);
               lcd.print(keypadDown);
           
          }
      
        
    
    
        voltage = 0;
        voltageR = 0;
        voltageC = 0;
        count = 0;
          
        }
    }//Fin detection clavier LCD
  }//Fin logged =1
} // fin loop

float fmap(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

long readVcc() {
  long result; // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  //result = 1125300L / result; // Back-calculate AVcc in mV 4.48 meurer / 4.07 arduino
  result = (((1.1*6.25)/(5.161))*1023*1000) / result; // Back-calculate AVcc in mV
  return result;
  }
  
//
//Gestion du loggin
//
  
  //Password / Menu / Clavier
  //PassAppend
int passAppend (int toucheC) {
  // On ajoute a la variable
  passTemp = passTemp + String(toucheC);
  // On verifie qu'il fait la longueur du pass
  if (passTemp.length() >= passCar.length()) {
    // Si oui On verifie qu'il est identique au pass
      if (passTemp == passCar) {
      // Si oui on renvoie true
        return 1;
      }
      // Sinon on efface et renvoie false et efface le screen
      else {
        passReset();
        return 2;
      }
   //Sinon On ajoute une étoile au screen
  }
   else return 3;
}

  //PassReset
String passReset() {
 passTemp ="";
 return "Pass Clear"; 
}


  //PassSet
String passSet(int pass) {
    if (EEPROM.updateInt(0, pass)) return "Pass Set";
    else return "Error Set Pass";
}

 //
 //Getion des messages sous forme de buffer
 //
 boolean messageBuffer() {

  if ((mBuffer1 != "") && ( mBuffer1 != "" )) {
      if ((mBuffer3 != "") && ( mBuffer4 != "" )) {
        countB++;
        if(countB == 300) {mBufferM = true; lcd.clear();}
        if (countB > 600) {countB = 0; mBufferM = false; lcd.clear();}
        if (mBufferM) {
          lcd.setCursor(0,0);
          lcd.print(mBuffer3);
          lcd.setCursor(0,1);
          lcd.print(mBuffer4);
        }
        else{
          lcd.setCursor(0,0);
          lcd.print(mBuffer1);
          lcd.setCursor(0,1);
          lcd.print(mBuffer2);
        }
        
      }
      else {
        lcd.setCursor(0,0);
        lcd.print(mBuffer1);
        lcd.setCursor(0,1);
        lcd.print(mBuffer2);
        countB = 0;
      }
    return true;
  }
  else{
  return false;
  countB = 0;
  }

   
 }
 
boolean messageBufferErase() {
   mBuffer1 = "";
   mBuffer2 = "";
   mBuffer3 = "";
   mBuffer4 = "";
 }
 
 
 
 //
 //Gestion des actions
 //
boolean action(int numero) {
       switch (numero) {
        case 1:  //1 Allumage
         if (waitingA == 0) { //Verifie qu'il n'y a pas de demande de confirmation
           mBuffer1 = "Valider :";
           mBuffer2 = "Pre-Allumage";
           mBuffer3 = "* Pour Oui";
           mBuffer4 = "# Pour Non";
           waitingA = 1;
         }
         break;
        case 2:  //2 Allumage Bobine
         
         break;
        case 3:  //3 Demarreur
         
         break;
        case 9:  //9 Set password
         
         break;
        case -2:  //-1 Verifs action
         if (waitingA == 0) return false;
           switch (waitingA) {
             case 1:  //1 Allumage /1 valider /2 Annuler
               if (touchePresser()) {
                 if (clavierP == 10) {}//demarrer
                 else if (clavierP == 11) // Quitter
                   {
                     Serial.println("annulation");
                     messageBufferErase();
                     waitingA = 0;
                   }
               }
             break;
             
           }
           return true;
         break;
       }
 
 
 
 
 
 
 
 }

boolean touchePresser() {
  if (clavierBkT + 100 < millis()) {
    if (clavierBk == false) {
      clavierBkT = millis();
      if (keypad.down() == 1) {clavierBk = true; clavierP = keypad.key(); Serial.println("Clavier P: "+String(clavierP)); return true;}
    }
    else {
     clavierBkT = millis();
     if (keypad.down() == 0) {clavierBk = false;}
    }
  }
return false;
}

Well, immediately I see an issue:

...
String mBuffer1,mBuffer2,mBuffer3,mBuffer4;
...
  String passTemp, passCar = String(EEPROM.readInt(10));
...

You're using Strings. Ditch them and use character arrays and you'll probably see all your problems disappear.

I've try to change that:
GuessTheNumber.ino: In function 'char passReset()':
GuessTheNumber:235: error: invalid conversion from 'const char*' to 'char'
GuessTheNumber.ino: In function 'char passSet(int)':
GuessTheNumber:241: error: invalid conversion from 'const char*' to 'char'

#include <LiquidCrystal.h>
#include <MAX31855.h>
#include <DFR_Key.h>
#include <Wire.h>
#include <bv4506.h>
#include <I2c_bv.h>
#include <EEPROMEx.h>


//Keypad 3X4
BV4506 keypad(0x31);
int keypadDown;
long clavierBkT;
boolean clavierBk = false;

DFR_Key keypadLCD;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 
double voltage,voltageR,voltageC;
int count, clavier = 0, clavierP;

//Action
int waitingA = 0;

//message
char mBuffer1,mBuffer2,mBuffer3,mBuffer4;
int countB;
boolean mBufferM;


//Thermocouple
  // ***** PIN DEFINITIONS ***** Thermocouple
  const  unsigned  char thermocoupleSO = 13;
  const  unsigned  char thermocoupleCS = 12;
  const  unsigned  char thermocoupleCLK = 11;
  // Declaration
  MAX31855  MAX31855(thermocoupleSO, thermocoupleCS, thermocoupleCLK);

//Gestion du loggage
  int logged = 0;
  char passTemp, passCar = EEPROM.readInt(10);
    
void setup()
{
  
  //Serial for test
  Serial.begin(115200);
  Serial.println("Demarrage");
  //Keypad
    Wire.begin();
    
  //LCD
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,1);
  
    //pinMode(2, INPUT); // Hall sensor
    //digitalWrite(2, HIGH);
 
  //Demarrage
    lcd.print("Cumpu-Benda");
    delay(1000);
    lcd.clear();

  // Init Boucle
    count = 0;
  

}

void loop()
{
  //Keypad

  //Login
  if (logged == 0) {
    lcd.setCursor(0,0);
    lcd.print("Identification:");
    if (touchePresser()) {
      lcd.setCursor(0,1);
       switch (passAppend(clavierP)) {
        case 1:
          //Bon
          lcd.print("Ok");
          delay(1000);
          lcd.clear();
          logged = 1;
          Serial.println("Logged In");
          break;
        case 2:
          //Faux
          lcd.print("Error Password");
          delay(1000);
          lcd.clear();
          break;
        case 3:
          //Etoile
             for (int i=0; i < sizeof(passTemp); i++){
              lcd.print("*");
             } 
          break;
      }
    
    }

  }
  
  else {
      
    double Vcc;
    unsigned int ADCValue;
 
    Vcc = readVcc()/1000.0;
    ADCValue = analogRead(1);
    voltage = voltage + ( (ADCValue / 1023.0) * Vcc );
    count++;
    
    keypad.clear();
    clavier = keypadLCD.getKey();
    if (clavier == SAMPLE_WAIT) clavier = 0;  
    
    if (action(-2)) {
      //Faire action plutot que de gerer le reste
    }
    else if (touchePresser()) { //menu keypad Action
      Serial.println("action keypad");
      action(clavierP);
    }//Fin menu keypad
    
    if (messageBuffer()) { // Gestion de l'affichage forcer
    }
    
    else  { // Action au LCD detecter
      if (count >= 200) 
      {
        
          
          if (clavier == 3)
          {
            lcd.clear();  
            voltageC = voltage/count;
            voltageR = (voltageC * 2.7428571) + 2.16;
            lcd.setCursor(0,0);
            lcd.print("Tension Vin");
            lcd.setCursor(0,1);
            lcd.print(voltageR);
            lcd.setCursor(6,1);
            lcd.print(voltageC);
          }
          else if (clavier == 2)
          {
            lcd.clear();     
            voltageC = voltage/count;
            lcd.setCursor(0,0);
            voltageR = (voltageC * 2.7428571) + 2.16;
            float tensionpourcent = fmap(voltageR, 11.80, 13.50, 0.00, 100);
            lcd.print(tensionpourcent);
            lcd.setCursor(7,0);
            lcd.print("%");
            lcd.setCursor(0,1);
            lcd.print(MAX31855.readThermocouple(CELSIUS));
          }
          
          else if (clavier == 4)
          {
            
    
               lcd.clear();
               lcd.setCursor(0,1);
               lcd.print(clavierP);
               lcd.setCursor(0,0);
               lcd.print(keypadDown);
           
          }
      
        
    
    
        voltage = 0;
        voltageR = 0;
        voltageC = 0;
        count = 0;
          
        }
    }//Fin detection clavier LCD
  }//Fin logged =1
} // fin loop

float fmap(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

long readVcc() {
  long result; // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  //result = 1125300L / result; // Back-calculate AVcc in mV 4.48 meurer / 4.07 arduino
  result = (((1.1*6.25)/(5.161))*1023*1000) / result; // Back-calculate AVcc in mV
  return result;
  }
  
//
//Gestion du loggin
//
  
  //Password / Menu / Clavier
  //PassAppend
int passAppend (int toucheC) {
  // On ajoute a la variable
  passTemp = passTemp + char(toucheC);
  // On verifie qu'il fait la longueur du pass
  if (sizeof(passTemp) >= sizeof(passCar)) {
    // Si oui On verifie qu'il est identique au pass
      if (passTemp == passCar) {
      // Si oui on renvoie true
        return 1;
      }
      // Sinon on efface et renvoie false et efface le screen
      else {
        passReset();
        return 2;
      }
   //Sinon On ajoute une étoile au screen
  }
   else return 3;
}

  //PassReset
char passReset() {
 passTemp = "";
 return "Pass Clear"; 
}


  //PassSet
char passSet(int pass) {
    if (EEPROM.updateInt(0, pass)) return "Pass Set";
    else return "Error Set Pass";
}

 //
 //Getion des messages sous forme de buffer
 //
 boolean messageBuffer() {

  if ((mBuffer1 != "") && ( mBuffer1 != "" )) {
      if ((mBuffer3 != "") && ( mBuffer4 != "" )) {
        countB++;
        if(countB == 300) {mBufferM = true; lcd.clear();}
        if (countB > 600) {countB = 0; mBufferM = false; lcd.clear();}
        if (mBufferM) {
          lcd.setCursor(0,0);
          lcd.print(mBuffer3);
          lcd.setCursor(0,1);
          lcd.print(mBuffer4);
        }
        else{
          lcd.setCursor(0,0);
          lcd.print(mBuffer1);
          lcd.setCursor(0,1);
          lcd.print(mBuffer2);
        }
        
      }
      else {
        lcd.setCursor(0,0);
        lcd.print(mBuffer1);
        lcd.setCursor(0,1);
        lcd.print(mBuffer2);
        countB = 0;
      }
    return true;
  }
  else{
  return false;
  countB = 0;
  }

   
 }
 
boolean messageBufferErase() {
   mBuffer1 = "";
   mBuffer2 = "";
   mBuffer3 = "";
   mBuffer4 = "";
 }
 
 
 
 //
 //Gestion des actions
 //
boolean action(int numero) {
       switch (numero) {
        case 1:  //1 Allumage
         if (waitingA == 0) { //Verifie qu'il n'y a pas de demande de confirmation
           mBuffer1 = "Valider :";
           mBuffer2 = "Pre-Allumage";
           mBuffer3 = "* Pour Oui";
           mBuffer4 = "# Pour Non";
           waitingA = 1;
         }
         break;
        case 2:  //2 Allumage Bobine
         
         break;
        case 3:  //3 Demarreur
         
         break;
        case 9:  //9 Set password
         
         break;
        case -2:  //-1 Verifs action
         if (waitingA == 0) return false;
           switch (waitingA) {
             case 1:  //1 Allumage /1 valider /2 Annuler
               if (touchePresser()) {
                 if (clavierP == 10) {}//demarrer
                 else if (clavierP == 11) // Quitter
                   {
                     Serial.println("annulation");
                     messageBufferErase();
                     waitingA = 0;
                   }
               }
             break;
             
           }
           return true;
         break;
       }
 
 
 
 
 
 
 
 }

boolean touchePresser() {
  if (clavierBkT + 100 < millis()) {
    if (clavierBk == false) {
      clavierBkT = millis();
      if (keypad.down() == 1) {clavierBk = true; clavierP = keypad.key(); Serial.println("Clavier P: "+char(clavierP)); return true;}
    }
    else {
     clavierBkT = millis();
     if (keypad.down() == 0) {clavierBk = false;}
    }
  }
return false;
}

"char variable" stores one character.

"char *variable" points to a block of memory that can contain characters

"char variable[20]" reserves a block of 20 bytes in memory and points to it.

Now you tell me what's wrong.

I suggest you read: http://en.wikibooks.org/wiki/C_Programming/Arrays#Strings

"char *variable" points to a block of memory that can contain characters

A slight correction. variable can be pointed to a block of memory. By itself, it simply defines a variable that is a pointer. That pointer then must be explicitly pointed to a block of memory. Many of the problems with pointers are caused by assuming that a pointer points to a block of memory when it does not, or when the block it points to is read-only or too small.

But, for a password, it need to be empty at start ?!

benda95280:
But, for a password, it need to be empty at start ?!

What is empty?

Memory can never be empty. For it to be empty it would have to vanish.

A block of memory, pointed to by a char * variable, will always contain something. Even if that is just all character 0, it's still full of it.

If you'd read that page I posted you'd know that a char array "string" contains a series of characters terminated by the character 0 (that's not the ASCII character 0, but the actual numeric value 0, 8 bits all set to 0), so an "empty" string would be no characters terminated by the character 0.

And for you to put something in there it doesn't have to be "empty" in the first place - you will just overwrite what is in there already, even if it's just garbage.

char password[30];

getMyPassword(password);  // fictitious function that gets a password from the user.

if (strcmp(password, "letmein") == 0) {
  Serial.println("You entered the right password.");
} else {
  Serial.print("Sorry, ");
  Serial.print(password);
  Serial.println(" isn't the right password.  Try again.");
}

Thanks for you answer,
I've try to use Char.

When writing

char passCar;
passCar = EEPROM.readInt(10);

Passcar return "9"
And Serial print : "outside of EEPROM memory"

With

char* passCar;
passCar = EEPROM.readInt(10);

Return GuessTheNumber:53: error: invalid conversion from 'uint16_t' to 'char*'

Sketch Size: 11042 on 32256

:frowning:

Spot the disparity:

char passCar;

passCar = EEPROM.readInt(10);

http://playground.arduino.cc/Code/EEPROMex
Only Int or Byte. How can i do ?

benda95280:
Arduino Playground - HomePage
Only Int or Byte. How can i do ?

A byte is an unsigned char. They are both 8 bits in size.

I can't see it causing your problem though. Have you determined at which point in your program this message is being generated?

The message about Eeprom is shown when i press a key on the Keypad.
Example :
When key pressed it have to show : Serial.println("Clavier P: "+char(clavierP));
1 times show :
2: avier P:
3: lavier P:
4: om memory
5: Out of Eeprom mem
6: 255
7: Clavier P:
8: Strange Characters
...

And SPI bus do something Crazy like return ~10 times the goog key and after return 255

With :
EEPROM.writeByte(10, '12345');
u =>[/u] carPass = EEPROM.readByte(10);
Return 5

EEPROM.writeByte(10, 12345);
u =>[/u] carPass = EEPROM.readByte(10);
Return 9

Serial.println("Clavier P: "+char(clavierP));

By doing that you are inadvertantly using the String class still. You'd be much better doing:

Serial.print("Clavier P: ")
Serial.println((char)clavierP);

With :
EEPROM.writeByte(10, '12345');
(char) => carPass = EEPROM.readByte(10);
Return 5

EEPROM.writeByte(10, 12345);
(char) => carPass = EEPROM.readByte(10);
Return 9

Neither of those values are a byte, so who knows what you're actually writing to the EEPROM at that time? Well, for the second one the answer is 12345 & 0xFF = 57. And anything inside '' is a single character value, so what '12345' would equate to is a mystery to me.

majenko:

Serial.println("Clavier P: "+char(clavierP));

By doing that you are inadvertantly using the String class still. You'd be much better doing:

Serial.print("Clavier P: ")

Serial.println((char)clavierP);

For that, ok i've understand.

But, how can i store the password in EEprom, and Read/use It After ?
EEPROM.writeInt Was good for me, because i can store "12345" Or " 987654321".
But i need to concate Integer when keyPress, and 5+1 = 6 | Not 51 ...
With string type, "5"+1 = 51.

A project so simple, but not so...

But i need to concate Integer when keyPress, and 5+1 = 6 | Not 51 ...
With string type, "5"+1 = 51.

What is the type/value of the key? If you have something like char key = ???; in your code, and key is '5', for instance, then byte keyVal = key - '0'; will result in keyVal being 5. Surely you can figure out that 5 and 1 as separate keys should not produce 6. And, it should be pretty obvious that adding a string ("5") and a value will not result in a value.

Multiplying the existing value by 10 and adding the next value is a useful technique to master.

Everithing look like works like a charm.
Why ?
Let me explain to you:

majenko:
Spot the disparity:

char passCar;

passCar = EEPROM.readInt(10);

Yes it Was a big ... mistake

majenko:

Serial.println("Clavier P: "+char(clavierP));

By doing that you are inadvertantly using the String class still. You'd be much better doing:

Serial.print("Clavier P: ")

Serial.println((char)clavierP);

... It solve a lot of problems ... Incredible !

PaulS:

But i need to concate Integer when keyPress, and 5+1 = 6 | Not 51 ...
With string type, "5"+1 = 51.

What is the type/value of the key? If you have something like char key = ???; in your code, and key is '5', for instance, then byte keyVal = key - '0'; will result in keyVal being 5. Surely you can figure out that 5 and 1 as separate keys should not produce 6. And, it should be pretty obvious that adding a string ("5") and a value will not result in a value.

Multiplying the existing value by 10 and adding the next value is a useful technique to master.

I shall also bow to that experience ...

For the SPI Bus witch was being crazing:
The Keypad Had buffer witch need to be sometimes cleared ...

keyPad.clear();

To conclude, With some optimisation on Type, using more Byte and Boolean ...
Everithing Works

For people who was interested, the story continue here :