Saving data between power cycles

Hello everyone! I just want to say thank you in advance for help on this project since this is one of the last pieces of code I need to learn for my project to finally be finished!

My project is simple: Temperature operated switches for fans.
I am using an Arduino Nano Atmega328 3.0 board
with a 4D systems uLCD32-PTu and simple temp senors and relays.

I use my system in my car for basic functions, which means that the system turns off and on with every time I start and turn off the car so as to not run the car battery dry while it’s parked.

My programs work perfectly for everything I need it to, but the last feature I need to add is effectively some kind of “save” option.

As you will see in my code, when my temp sensors get up to their preset int temps in my code, the fans turn on, and when the temperature goes below that set point, the relays turn off. I have built into the user interface with the uLCD32-PTu an option (Labeled as “slider0_val” and “slider1_val”) to set the switch point temperatures to any number I want from 0 up to 300 degrees if desired.

I have done research on EEPROM memory, but I don’t fully understand it yet, so I can’t get it to work properly yet.

My problem: I want to be able to install this system in any environment I choose and simply set the temperature using the LCD screen, then somehow save those set points so that whatever I set it to is what it stays set to until I otherwise adjust it manually, even through various power cycles.

I apologize for the lengthy explanation, but hopefully it makes sense! What’s the simplest and most efficient way to save my manual changes to this data in between power cycles?

Here is my Arduino code:

#define CHANNEL1 8 //DALLAS RELAY
#define CHANNEL2 9 //DHT RELAY

#include <genieArduino.h>

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2 //DALLAS serial sensors go into input 3
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
DeviceAddress insideCarTemp = { 0x28, 0xDE, 0x57, 0x66, 0x04, 0x00, 0x00, 0x0A };//THIS SENSOR IS THE COOLANT INPUT TEMP SENSOR IN THE BONNEVILLE LEDDIGITS0 and LEDDIGITS7 RED/BLUE/BLACK
DeviceAddress coolantTemp = { 0x28, 0xF5, 0x2F, 0x66, 0x04, 0x00, 0x00, 0x17 };//THIS SENSOR IS THE COOLANT INPUT TEMP SENSOR IN THE BONNEVILLE LEDDIGITS0 and LEDDIGITS7 RED/BLUE/BLACK

int lowSpeedSliderVal = 130; //Thermostat opens at 160* so I want the fans to start somewhere around there
int highSpeedSliderVal = 140;

int slider0_val;//Set point for radiator fan
int slider1_val;//Set point for interior
int humidity, t, temp;

int tempLeeway = 10;

void setup()
{
pinMode(CHANNEL1, OUTPUT); //Low Speed Fan RELAY
pinMode(CHANNEL2, OUTPUT); //High Speed Fan RELAY

sensors.begin(); // DALLAS sensors begin reading
sensors.setResolution(insideCarTemp, 10);
sensors.setResolution(coolantTemp, 10);

genieBegin (GENIE_SERIAL, 56000); //Serial0 for 4D Display

genieAttachEventHandler(myGenieEventHandler);

//Reset the Display (change D4 to D2 if you have original 4D Arduino Adaptor)
pinMode(4, OUTPUT); // Set D4 on Arduino to Output (4D Arduino Adaptor V2 - Display Reset)
digitalWrite(4, 1); // Reset the Display via D4
delay(100);
digitalWrite(4, 0); // unReset the Display via D4

delay (3500); //let the display start up

genieWriteObject(GENIE_OBJ_LED_DIGITS, 3, lowSpeedSliderVal);//preset value fan on/off switch temp
genieWriteObject(GENIE_OBJ_SLIDER, 0, lowSpeedSliderVal);//
genieWriteObject(GENIE_OBJ_LED_DIGITS, 4, highSpeedSliderVal);
genieWriteObject(GENIE_OBJ_SLIDER, 1, highSpeedSliderVal);//
}

void loop()
{
static long waitPeriod = millis();

genieDoEvents(); // Do this every loop, checks the input buffer for data from the display and runs myGenieEventHandler()

//Read from sensor every 100ms and write to the display
if (millis() >= waitPeriod)
{
temp = (t * 1.8) + 32; //Convert *C to *F.

float inside = sensors.getTempF(insideCarTemp);
float coolant = sensors.getTempF(coolantTemp);
//float inside = sensors.getTempF(coolant);
//float tempC = sensors.getTempC(insideThermometer);
//insideThermometer = sensors.requestTemperatures(); // Send the command to get DALLAS temperatures
float tempF;

sensors.requestTemperatures();
//tempF = sensors.getTempF(inside);
//Serial.println (inside);////////GOOOD CODE

genieWriteObject(GENIE_OBJ_LED_DIGITS, 0, coolant);//HOME SCREEN RADIATOR TEMP…FORM 0
genieWriteObject(GENIE_OBJ_LED_DIGITS, 1, coolant);//LOW SPEED RADIATOR FAN CONTROL…FORM 1
genieWriteObject(GENIE_OBJ_LED_DIGITS, 7, coolant); //HIGH SPEED RADIATOR FAN CONTROL…FORM 5
genieWriteObject(GENIE_OBJ_LED_DIGITS, 3, inside); // write dallas insideThermometer to LedDigit3
genieWriteObject(GENIE_OBJ_THERMOMETER, 1, coolant); // write dallas insideThermometer to Thermometer0
waitPeriod = millis() + 10; // rerun this code in another 100ms time.

if (slider0_val > coolant)//RADIATOR FAN SLIDER SET POINT WITH DALLAS SENSOR…For some reason it’s responding in polar opposites of the command?
{
digitalWrite(CHANNEL1, HIGH); //RADIATOR FAN
}
else
{
digitalWrite(CHANNEL1, LOW); //RADIATOR FAN
}
/////////////////////////////////////////////////////

if (slider1_val > temp)
{
digitalWrite(CHANNEL2, HIGH);
}
else
{
digitalWrite(CHANNEL2, LOW);
}

}

}

void myGenieEventHandler(void)
{
genieFrame Event;
genieDequeueEvent(&Event);

//If the cmd received is from a Reported Event
if (Event.reportObject.cmd == GENIE_REPORT_EVENT)
{
if (Event.reportObject.object == GENIE_OBJ_SLIDER) // If the Reported Message was from a Slider
{
if (Event.reportObject.index == 0) // If Slider0
{
slider0_val = genieGetEventData(&Event); // Receive the event data from the Slider0
}
}
}

//If the cmd received is from a Reported Event
if (Event.reportObject.cmd == GENIE_REPORT_EVENT)
{
if (Event.reportObject.object == GENIE_OBJ_SLIDER) // If the Reported Message was from a Slider
{
if (Event.reportObject.index == 1) // If Slider1
{
slider1_val = genieGetEventData(&Event); // Receive the event data from the Slider1
}
}
}

//If the cmd received is from a Reported Object, which occurs if a Read Object is requested in the main code, reply processed here.
if (Event.reportObject.cmd == GENIE_REPORT_OBJ)
{
//Put code in here, like the above, if you want to process data when you have used a genieReadObject in your main loop
//Currently there are none, so this section has no code.
//Filter out the Object and the Index like above, and then same the data into a variable as required.
}
}

113 posts and still not using code tags and formatting is not very pretty. Is there a reason for that? I see nothing in your code that uses the EEPROM. Have you tried any of the examples in the EEPROM library?

Please use

 tags when posting code.

[quote]
I have done research on EEPROM memory, but I don't fully understand it yet, so I can't get it to work properly yet. [/quote]
EEPROM memory is memory that stores data when power is removed. (Exactly what you are trying to do.)

The EEPROM functions make it easy to read and write from the EEPROM memory inside of the ATmega chip. Read/write functions read/write bytes. (These have been around for a long time.)

EEPROM.write(0,255);
That writes the value 255 to EEPROM memory location 0.

byte saved_value = EEPROM.read(0);
That reads the value at EEPROM memory location 0 and saves it to the variable saved_value.

Now in your case, if you want to save negative temperatures or temperatures above 255, you'll want to use EEPROM.put() and EEPROM.get() to read/write any variable type. (These are newer functions.)

So basically you figure out a memory map for EEPROM and read/write the values you want to save. 

When I say memory map, keep in mind that an integer is 2 bytes, a float is 4 bytes, etc. So if you're saving integers, you need to account for two bytes.

Address 0: temperature 1
Address 2: temperature 2
Address 4: temperature 3
etc

@James C4S Thanks for that explanation! It really helped me understand things more, but I think I’m still a little lost in understanding exactly how the memory is being stored and then recalled…

I’ve added my first attempt at using EEPROM memory, as posted in my code below, and slider1_val data stores and recalls perfectly according to adjustments, unless I adjust my slider0_val.

Secondly, if I adjust my slider0_val, upon restart, both values return to 0.

Thirdly, in between power cycles, if I adjust both slider1_val to say 100 and slider0_val to 50, both values will be set to 100 upon restart.

To my understanding, I have setup each value to be stored individually and recalled individually in between cycles, but clearly something is out of order. Can someone show me what my problem is and what I need to do to fix this? Thanks in advance!!!

My full code:

#define CHANNEL1 8 //DALLAS RELAY
#define CHANNEL2 9 //DHT RELAY

#include <genieArduino.h>

#include <EEPROM.h>

//int addressLow = 0;
//int addressHigh = 0;
//byte value0;
//byte value1;

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2 //DALLAS serial sensors go into input 3
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
DeviceAddress insideCarTemp = { 0x28, 0xDE, 0x57, 0x66, 0x04, 0x00, 0x00, 0x0A };//THIS SENSOR IS THE COOLANT INPUT TEMP SENSOR IN THE BONNEVILLE LEDDIGITS0 and LEDDIGITS7 RED/BLUE/BLACK
DeviceAddress coolantTemp = { 0x28, 0xF5, 0x2F, 0x66, 0x04, 0x00, 0x00, 0x17 };//THIS SENSOR IS THE COOLANT INPUT TEMP SENSOR IN THE BONNEVILLE LEDDIGITS0 and LEDDIGITS7 RED/BLUE/BLACK

//int lowSpeedSliderVal = 130; // 130degrees Thermostat opens at 160* so I want the fans to start somewhere around there
//int highSpeedSliderVal = 140; //140degrees
int slider0_val;//EEPROM Set point for low speed fan
int slider1_val;//EEPROM Set point for high speed fan

int memory0 = 0;
int memory3 = 0;
int memory1;
int memory2;

//float memory1;
//float memory2;

//byte memory1 = EEPROM.read(slider0_val);
//byte memory2 = EEPROM.read(slider1_val);

int humidity, t, temp;

int tempLeeway = 10;

void setup()
{
byte memory1 = EEPROM.read(slider0_val);
byte memory2 = EEPROM.read(slider1_val);
//EEPROM.write(slider0_val);
//EEPROM.write(slider1_val);

pinMode(CHANNEL1, OUTPUT); //Low Speed Fan RELAY
pinMode(CHANNEL2, OUTPUT); //High Speed Fan RELAY

sensors.begin(); // DALLAS sensors begin reading
//sensors.setResolution(coolant, 10);
sensors.setResolution(insideCarTemp, 10);
sensors.setResolution(coolantTemp, 10);

genieBegin (GENIE_SERIAL, 56000); //Serial0 for 4D Display

genieAttachEventHandler(myGenieEventHandler);

//Reset the Display (change D4 to D2 if you have original 4D Arduino Adaptor)
pinMode(4, OUTPUT); // Set D4 on Arduino to Output (4D Arduino Adaptor V2 - Display Reset)
digitalWrite(4, 1); // Reset the Display via D4
delay(100);
digitalWrite(4, 0); // unReset the Display via D4

delay (3500); //let the display start up

genieWriteObject(GENIE_OBJ_LED_DIGITS, 3, memory1);//preset value fan on/off switch temp
genieWriteObject(GENIE_OBJ_SLIDER, 0, memory1);//
genieWriteObject(GENIE_OBJ_LED_DIGITS, 4, memory2);
genieWriteObject(GENIE_OBJ_SLIDER, 1, memory2);//

genieWriteObject(GENIE_OBJ_LED_DIGITS, 1, memory1);
genieWriteObject(GENIE_OBJ_LED_DIGITS, 2, memory2);

}

void loop()
{
//memory1 = slider0_val;
//memory2 = slider1_val;

static long waitPeriod = millis();

genieDoEvents(); // Do this every loop, checks the input buffer for data from the display and runs myGenieEventHandler()

//Read from sensor every 100ms and write to the display
if (millis() >= waitPeriod)
{
temp = (t * 1.8) + 32; //Convert *C to *F.

float inside = sensors.getTempF(insideCarTemp);
float coolant = sensors.getTempF(coolantTemp);
//float inside = sensors.getTempF(coolant);
//float tempC = sensors.getTempC(insideThermometer);
//insideThermometer = sensors.requestTemperatures(); // Send the command to get DALLAS temperatures
float tempF;

sensors.requestTemperatures();
//tempF = sensors.getTempF(inside);
Serial.println (inside);

//genieWriteObject(GENIE_OBJ_LED_DIGITS, 0, coolant);//HOME SCREEN RADIATOR TEMP…FORM 0
//genieWriteObject(GENIE_OBJ_LED_DIGITS, 1, coolant);//LOW SPEED RADIATOR FAN CONTROL…FORM 1
//genieWriteObject(GENIE_OBJ_LED_DIGITS, 7, coolant); //HIGH SPEED RADIATOR FAN CONTROL…FORM 5
//genieWriteObject(GENIE_OBJ_LED_DIGITS, 3, coolant); // write dallas insideThermometer to LedDigit3
//genieWriteObject(GENIE_OBJ_THERMOMETER, 1, coolant); // write dallas insideThermometer to Thermometer0
waitPeriod = millis() + 10; // rerun this code in another 100ms time.

if (slider0_val > coolant)//RADIATOR FAN SLIDER SET POINT WITH DALLAS SENSOR…For some reason it’s responding in polar opposites of the command?
{
digitalWrite(CHANNEL1, HIGH); //RADIATOR FAN
}
else
{
digitalWrite(CHANNEL1, LOW); //RADIATOR FAN
}
/////////////////////////////////////////////////////

if (slider1_val > temp)
{
digitalWrite(CHANNEL2, HIGH);
}
else
{
digitalWrite(CHANNEL2, LOW);
}

}

}

void myGenieEventHandler(void)
{
genieFrame Event;
genieDequeueEvent(&Event);

//If the cmd received is from a Reported Event
if (Event.reportObject.cmd == GENIE_REPORT_EVENT)
{
if (Event.reportObject.object == GENIE_OBJ_SLIDER) // If the Reported Message was from a Slider
{
if (Event.reportObject.index == 0) // If Slider0
{
slider0_val = genieGetEventData(&Event); // Receive the event data from the Slider0
}
}
}

//If the cmd received is from a Reported Event
if (Event.reportObject.cmd == GENIE_REPORT_EVENT)
{
if (Event.reportObject.object == GENIE_OBJ_SLIDER) // If the Reported Message was from a Slider
{
if (Event.reportObject.index == 1) // If Slider1
{
slider1_val = genieGetEventData(&Event); // Receive the event data from the Slider1
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////

/* //If the cmd received is from a Reported Event
if (Event.reportObject.cmd == GENIE_REPORT_EVENT)
{
if (Event.reportObject.object == GENIE_OBJ_WINBUTTON) // If the Reported Message was from a Slider
{
if (Event.reportObject.index == 11) // If button 11
{
genie.WriteContrast(0); // Receive the event data from the button11
}
else
{
genie.WriteContrast(1);
}
}
}

*//////////////////////////////////////////////////////////////////////////////////////////////////////

//If the cmd received is from a Reported Object, which occurs if a Read Object is requested in the main code, reply processed here.
if (Event.reportObject.cmd == GENIE_REPORT_OBJ)
{
//Put code in here, like the above, if you want to process data when you have used a genieReadObject in your main loop
//Currently there are none, so this section has no code.
//Filter out the Object and the Index like above, and then same the data into a variable as required.
}

//EEPROM MEMORY
EEPROM.write(memory1, slider0_val);
EEPROM.write(memory2, slider1_val);

}

 byte memory1 = EEPROM.read(slider0_val);
 byte memory2 = EEPROM.read(slider1_val);

Why are the addresses to read from/write to stored in variables with _val in the name?

 EEPROM.write(memory1, slider0_val);
 EEPROM.write(memory2, slider1_val);

The address to write to is not the second argument.

Back to RTFM for you.

Why are the addresses to read from/write to stored in variables with _val in the name?

Because I have setup my interface to be able to control the set values upon request of the user. slider0_val is the name of the widget I need to preset the value to upon startup from the previous use of the device. The rest of my logic commands are dependent upon it. Are you saying "_val" causing all my problems?

The address to write to is not the second argument.

It was my understanding from example codes, that the first address in this write command is the location that I am writing/updating to upon each loop cycle. The second is where I am getting the value from.

I am completely self-taught in arduino coding and I have only just begun to start learning more complicated procedures. I am clearly not an expert in C++, so please give me grace as I learn.. :confused:

Are you saying "_val" causing all my problems?

No, I am saying that it is causing me problems in understanding your code. I prefer to see Pin in the name of variables that hold pin numbers, State in the name of variables that hold pin state, Addr in the name of variables that hold EEPROM addresses, etc.

It was my understanding from example codes, that the first address in this write command is the location that I am writing/updating to upon each loop cycle. The second is where I am getting the value from.

The first argument is the address in EEPROM to write to. The second argument is the value to write at that address. That is what makes _val in the name so confusing. It does NOT contain a value to be saved. It contains an address.

@PaulS I left the titles as they are for my own personal preference. I fail to see how the titles of each address could cause the program to behave the way it does, so long as everything is still in order...

[quote author=James C4S date=1489183027 link=msg=3169875]

Address 0: temperature 1 Address 2: temperature 2 Address 4: temperature 3 etc

[/quote]

or, save yourself the trouble of all that mapping and put it all into a struct

excuse the pun...

@pYro_65 does a fine job on that Lib... I believe put() works byte-by-byte across the object.

Gustermaximus:
so long as everything is still in order…

But, clearly, (to me, at least, despite the dumb names), things are NOT still in order.