memory for digital programming

I'm fairly new to the wonderful world of arduino, but so far forums and other peoples questions have been a huge help in letting me realize my project. I'm not exactly sure what to read though for this new obstacle in my way. I have a remote sensor which I am receiving data from no problem. I no want to use that data to perform a task. My problem lies in that my task does not have to occur very often. I will try my best to describe what I am looking to do. I would like to receive data 3 times a day. When the sensors recognize a certain specified (low) value consistently for, lets say a week, then I would like the arduino to perform a certain task. I am thinking I need memory to store the received values, and an ability from the arduino to access these values. In the future I would like multiple sensors to communicate with my arduino, each of which will be independent, but perform a task described above. I hope this is isn't confusing, as I am a little confused myself. I would so very much appreciated someone directing me to some appropriate reading materials and advice!

You need to tell us how much data.

It would not be very much data at all, each sensor reads three temperature values, and one soil moisture value. This will happen three time a day.

In that case, you could probably use the on-board EEPROM.

If you are looking at 3 values a day for a week, that's only 21 values. Sensor data is integer, so that's only 42 bytes. You should just be able to define an array. Each day (every third reading), move all the value up 3 positions, discarding the previous "day"'s readings. Loop through the array. If the values are all the same as the specified value (or maybe lower), do whatever it is that needs doing.

You people are amazing, time for me to start reading about arrays and the steps needed to use them with my project!

My advice for using the EEPROM was from a point-of-view of assuming you would only power-up the Arduino each time you wanted to take a reading, and would have some sort of external real-time clock waking it up. If this is not the case, and the Arduino is powered all the time, then the RAM-based array suggested by PaulS should suffice.

The receiving arduino will be powered all the time and be equipped with an RTC. The sensor nodes are wireless and will only wake up three times a day. I am trying to make things as simple as possible for myself as I have very little programming experience, but it is appearing that it may not be so. I have been building so far by just slightly adapting examples found on the net, but for something like this I have yet to find examples which I could use.

Here’s an example of some code that should give you a start (only for one sensor)

#define INVALID_VALUE 0xFFFF
#define N_READINGS 21
#define SOME_VALUE 500
#define SOME_PIN 10

unsigned int sensor_data[N_READINGS];  // ring buffer for one sensor
int data_index = 0;
static unsigned long last_millis = millis();

void setup () {

   Serial.begin (9600);
   pinMode (SOME_PIN, INPUT);
   digitalWrite (SOME_PIN, 1);  // set internal pullup resistor
   
   // fill the ring buffer with a value that won't trigger the task 
   for (int i = 0; i < N_READINGS; i++)
       sensor_data[INVALID_VALUE];
}

boolean time_to_take_reading() {
   static unsigned long this_millis;
   // some code that decides if it's time to take a reading
   // for testing just return true every second
   this_millis = millis();
   if (this_millis - last_millis > 1000) {
      last_millis = this_millis;
      return true;
   }
   return false;
}

int getReading() {
   // some code that gets a reading from the sensor
   // for testing return either 0 or 1000 according to a digital input value
   return digitalRead (SOME_PIN) * 1000;
}

void performTask() {
	// some code that performs the task
	Serial.println ("task");
}

void loop () {
   boolean perform_task;

   if (time_to_take_reading()) {

 	   sensor_data [data_index++] = getReading();  // get a new reading and store at the head of the ring buffer
	   if (data_index >= N_READINGS) data_index = 0; // reset buffer index if necessary
	      
	   perform_task = true;    // assume we will perform the task
	   
	   // scan the ring buffer
	   // if any value in the buffer is greater than SOME_VALUE then reset the the "perform_task" flag
	   for (int i = 0; i < N_READINGS; i++) {
              if (sensor_data[i] > SOME_VALUE)
		      perform_task = false;
	   }
          // if we got through the last loop without resetting the flag then all values 
	   // were < SOME_VALUE so we perform the task
	   if (perform_task)
	       performTask();
    }
}

For multiple sensors you probably should create an array of structures or maybe just more arrays. But we’ll cross that bridge if you get to it.

As written it should print “task” if you hold pin 10 low for 21 seconds.


Rob

In the choice RAM / EEPROM you should choose EEPROM as it allows you to store data persistant (case the Arduino reboots )

What is the expected life of this application? How long should it run? One month? Six? A year? longer?

Hi robtillaart, I would like it to run for as long as possible (excluding the very cold winters here). EEPROM definitely sounds like the way to go.

Do you actually care what the readings are or is it enough to know that a sufficient number were low enough to trigger your task? If you don't, you can just keep a count of how many successive readings were low. If you make it to the triggering count without having a high value to reset the count, it's task time. Simpler, eats less RAM. Twenty one readings per sensor isn't much though, even with the small amount of memory the Arduino has available.

Wildbill has a good point, your really only need counters to record the number of low readings. In this case the code is a lot simpler.


Rob

This sounds like it would work great, I would just have to define a lower threshold limit say, then count the number of successive times the readings fall below until x number are reached, than trigger event. Wow, the simpler the better, I like this method!

Don’t know the system, but probably you want to record the length of low (and high) value sequences too.

Question: Does the execution of the task reset the counters?

Scenario’s:
suppose you have this sequence on a given moment and after 3 Lows you want to exec task

H H H H H L (low = 1) L (low = 2) L (low = 3 => task)

Now there are four possible scenario’s:

  1. H H H H H L (low = 1) L (low = 2) L (low = 3 => task) H (low = 0, no task)

  2. H H H H H L (low = 1) L (low = 2) L (low = 3 => task, low = 0) L (low = 1, no task)

  3. H H H H H L (low = 1) L (low = 2) L (low = 3 => task) L (low = 4 => task)

  4. H H H H H L (low = 1) L (low = 2) L (low = 3 => task) L (low = 4 , no task, allready executed)

Scenario 1 is for completeness.
Scenario 2 resets the counter if task is executed.
Scenario 3 does not reset the counter, and executes every time the counter is above threshold
Scenario 4 does not reset the counter, but executes the task only when counter is exactly threshold

Scenario 4 is in theory the most powerfull as it allows you to define different tasks to be executed at different thresholds! e.g.

H H L (low = 1) L (low = 2) L (low = 3 => task1) L (low = 4) L (low = 5) L (low = 6, task 1) L (low = 7, task2 ) L (low = 8, task3), L (low = 9, task1, task2) etc

What is your scenario? 2,3,4?

I would say the execution would reset the counters for sure. In theory the event execution brings the value from a low to a high, so it would all begin again. By dumping I would continually be freeing up the limited arduino memory also, perhaps especially important if I add more sensors. I don't really need to keep the recorded values, but if I did I could just plug the receiving arduino into a laptop and record the serial data. Scenario 2 it is