Programming Error and Help

Hello all,

I am looking to do a couple of things with the Arduino and was wondering if my ideas were at all possible? Any help would be greatly appreciated.

First off, I am using the Arduino Uno with the Wireless + SD shield and an XBee Pro hooked onto that shield. I am also using a 4GB microSD card that has been formatted in Windows with the FAT file system. The project that I am creating is a Solar Radiation Monitor that will have a shorted solar cell as an input on Analog Pin A0 which has an input voltage range of 0mV-256.7mV. I have also changed the reference voltage to INTERNAL for a reference of 1.1V to try and get a higher resolution result. End goal would be to have the Arduino take a measurement reading from the attached Solar Cell every minute, convert the reading to a Solar Radiation value (in W/m^2), then save the data to the SD card in the file format of a .csv file and after 3/6/12 months, I could pull the .csv file off of the SD card.

There are a couple of stumbling blocks that I have run into so far that I don't quite know how to solve just yet and was wondering if anyone could supply some guidance.

My first issue is that I wanted to try to take 10 readings inside of that one minute time frame (roughly every 8 secs-ish) and average out the result to get a more precise reading each minute. Below is the code that I have worked out to do this, but for some reason I am getting an error of 'int' is not a template upon compilation at the second for loop. Is it impossible to nest loops (or specifically for loops) in the Arduino architecture?

for (int counter = 0; counter < 100; counter++)
  { 
    //Obtain Solar Sensor Value
    for (int i = 0; int < 10; int++)
    {
      delay (50);
      radiationReading += analogRead(cellPin);
      delay (50);
    }
    radiationReading = radiationReading / 10;
    float trueRadiation = radiationReading * 5.31218;
    wholeNumRad = int (trueRadiation);
    trueRadiation -= wholeNumRad;
    trueRadiation *= 100;
    decimalNumRad = int (trueRadiation);
    String dataString = String(readingNumber) + ", " + String(wholeNumRad) + "." + String(decimalNumRad);
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    //If the file is available, write to it
    if (dataFile) 
    {
      dataFile.println(dataString);
      dataFile.close();
      //Output to the serial port as well
      Serial.println(dataString);
    }  
    //Error for unsuccessful file opening
    else 
    {
      Serial.println("Error Opening datalog.txt");
    }
    readingNumber++; 
    delay (5);
  }

I know the delays are different than my specified times, but I was just testing to see if it worked and I wanted it to go faster.

In the above example, the user would be connected to the Arduino through an XBee on their computer and send a command through Serial to start data acquisition for a pre-described time frame (in this case 100 loops). What I would like to accomplish would be to send the command to start recording data and then being able to leave it infinitely recording for the user's desired time frame and then have the user stop the loop with a Serial command or keyboard keypress (ESC or similar "kill" command or something). Is something like this possible at all?

My last problem is that I would like to retrieve the .csv file from the SD card at anytime through the XBee connection. Is there a way to retrieve a file from the Arduino SD card without pulling out the SD card itself and transferring the data yourself?

Essentially I want the work flow to go like this:
1.) Power up Arduino + XBee outside (on roof or similar).
2.) Have user with computer connect to Arduino + XBee with FTDI connected XBee on their computer.
3.) User sends a "1" to start data acquisition indefinitely.
4.) Wait 3/6/12 months.
5.) User connects to Arduino again and sends an "ESC" keypress to kill data acquisition.
6.) User does X (presses "2" or runs a script or something) and the .csv with all of the data is transferred to the user's computer.
7.) Repeat from 3 or Done.

Below is the total code that I have so far. Thank you so much for your help and effort.

-Billy-

#include <SD.h>    //SD card Library
#include <Wire.h>  //I2C Library

//Solar Sensor Pin Variables
int cellPin = 0;
int radiationReading;
int wholeNumRad = 0;
int decimalNumRad = 0;
long readingNumber = 1;

//SD card Chip Select Constant
const int chipSelect = 4;

//User Input Value
int userInput = 0;

/*************************************************************************/
void dataLogging()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  //Pin 10 must be set to OUTPUT even if it goes unused
  pinMode(10, OUTPUT);

  //Check to see if SD card can be seen
  if (SD.begin(chipSelect)) 
  {
    Serial.println("FAILED!");
    Serial.println("Card failed or not present!");
    return;
  }
  Serial.println("done!");
  Serial.println("SD card has been initialized.");

  //Write Log File Header
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile)
  {
    //Lead with a  blank line since there could be previous data
    dataFile.println(", , , ,");
    String header = "ID, Radiation";
    dataFile.println(header);
    dataFile.close();
    Serial.println(header);
  }
  else
  {
    Serial.println("Couldn't open log file.");
  }

  //Record the Solar Radiation for 10 minutes
  for (int counter = 0; counter < 100; counter++)
  { 
    //Obtain Solar Sensor Value
    for (int i = 0; int < 10; int++)
    {
      delay (50);
      radiationReading += analogRead(cellPin);
      delay (50);
    }
    radiationReading = radiationReading / 10;
    float trueRadiation = radiationReading * 5.31218;
    wholeNumRad = int (trueRadiation);
    trueRadiation -= wholeNumRad;
    trueRadiation *= 100;
    decimalNumRad = int (trueRadiation);
    String dataString = String(readingNumber) + ", " + String(wholeNumRad) + "." + String(decimalNumRad);
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    //If the file is available, write to it
    if (dataFile) 
    {
      dataFile.println(dataString);
      dataFile.close();
      //Output to the serial port as well
      Serial.println(dataString);
    }  
    //Error for unsuccessful file opening
    else 
    {
      Serial.println("Error Opening datalog.txt");
    }
    readingNumber++; 
    delay (5);
  }
}
/*************************************************************************/
void dumpFile()
{
  Serial.print("Initializing SD card...");
  //Pin 10 must be set to OUTPUT even if it goes unused
  pinMode(10, OUTPUT);

  //Check to see if SD card can be seen
  if (SD.begin(chipSelect)) 
  {
    Serial.println("FAILED!");
    Serial.println("Card failed or not present!");
    return;
  }
  Serial.println("done!");
  Serial.println("SD card has been initialized.");

  //Open the file
  File dataFile = SD.open("datalog.txt");

  //Check for the file and, if available, print to serial
  if (dataFile) 
  {
    while (dataFile.available()) 
    {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }  
  //Error for unsuccessful file opening
  else 
  {
    Serial.println("Error opening datalog.txt");
  } 
}
/*************************************************************************/
void closeFile()
{
  pinMode(10, OUTPUT);
  File dataFile = SD.open("datalog.txt");
  dataFile.close();
}
/*************************************************************************/
void deleteFile()
{
  Serial.print("Removing datalog.txt...");
  SD.remove("datalog.txt");

  if (SD.exists("datalog.txt"))
  {
    Serial.println("FAILED!");
    Serial.println("datalog.txt was not deleted.");
  }
  else 
  {
    Serial.println("done!");
    Serial.println("datalog.txt has been deleted.");
    readingNumber = 1;  
  }
}
/*************************************************************************/
int getSerialNumber()   // user input
{
  int result = 0;
  int q = 0;
  while (Serial.available()==0)
  {
    //Wait until something comes into the serial buffer
  } 
  while (Serial.available()>0)
  {
    while (Serial.available()>0)
    {
      //Move the previous digit to the next column on the left, e.g. 1 becomes 10 while there is data in the buffer
      result *= 10;
      //Read the next number in the buffer, subtract 48 to convert to the actual number
      q = Serial.read() - 48;
      result += q;
    }
    delay(5); // the processor needs a moment to process
  }
  return result;
}
/*************************************************************************/
void setup(void)
{
  Serial.begin(9600);
  analogReference(INTERNAL);
  SD.begin(chipSelect);
}

void loop(void)
{
  userInput = getSerialNumber();
  if (userInput == 1)
  {
    dataLogging();
  }
  if (userInput == 2)
  {
    dumpFile();
  }
  if (userInput == 3)
  {
    deleteFile();
  }
}
    for (int i = 0; int < 10; int++)

The variable name is i, not int.

Essentially I want the work flow to go like this

That is all possible.

PaulS:

    for (int i = 0; int < 10; int++)

The variable name is i, not int.

Essentially I want the work flow to go like this

That is all possible.

HAHA. Oh man I'm an idiot. Thank you so much for the help there. Any advice on where to look for the other questions? Specifically the kill command or file transfer?

Thanks again lol.

-Billy-

You'll need to read data from the serial port. If the character is the stop logging command, stop logging. If the character is the file transfer command, read the file off the SD card, and send each character to the serial port.

So after working on the code for a while, I now have almost everything I want to do working. One problem I am having is that I have the data logger portion of my code in the main Arduino loop as shown below:

void loop(void)
{
  if (userInput == 1)
  {
    dataLogging();
  }
  if (userInput == 2)
  {
    dumpFile();
    delay(50);
    setup();
  }
  if (userInput == 3)
  {
    deleteFile();
    delay(50);
    setup();
  }
}

With the code working this way, the data logger can go on infinitely and it works the way I want it to. The infinite loop was stopping when I re-established the Serial connection on my computer and everything was working great until I re-loaded the sketch. After I re-loaded the sketch, the serial connection didn't break the loop and the current reading was just written to the Serial screen and the Arduino would read forever until the reset button was pressed. Now, I believe that the stopping when re-starting Serial is probably a glitch and it isn't supposed to work that way but now I am stuck in an infinite loop until the power cuts out or the reset button is pressed.

So on to the question. Is there a known way to send the equivalent of an Arduino reset button press as a Serial command with the user's keyboard, and if so, how?

Thanks for all of the help! My full code is posted below for your consideration.

-Billy-

/*************************************************************************/
/*************************************************************************/
/************* Radiation Sensing on Pin A0 + SD card logging *************/
/*************************************************************************/
/*************************************************************************/

#include <SD.h>    //SD card Library
#include <Wire.h>  //I2C Library

//Solar Sensor Pin Variables
int cellPin = 0;
float radiationReading;
int wholeNumRad = 0;
int decimalNumRad = 0;
long readingNumber = 1;

//SD card Chip Select Constant
const int chipSelect = 4;

//User Input Value
int userInput = 0;

/*************************************************************************/
void dataLogging()
{
  Wire.begin();
  //Obtain Solar Sensor Value
  radiationReading = 0;
  for (int i = 0; i < 10; i++)
  {
    //delay (5990);
    delay (30);
    radiationReading += analogRead(cellPin);
    delay (5);
  }
  radiationReading = radiationReading / 10;
  float trueRadiation = radiationReading * 4.1841;
  wholeNumRad = int (trueRadiation);
  trueRadiation -= wholeNumRad;
  trueRadiation *= 100;
  decimalNumRad = int (trueRadiation);
  String dataString = String(readingNumber) + ", " + String(wholeNumRad) + "." + String(decimalNumRad);
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  //If the file is available, write to it
  if (dataFile) 
  {
    dataFile.println(dataString);
    dataFile.close();
    //Output to the serial port as well
    Serial.println(dataString);
  }  
  //Error for unsuccessful file opening
  else 
  {
    Serial.println("Error Opening datalog.txt");
  }
  readingNumber++; 
  delay (5);
}
/*************************************************************************/
void dumpFile()
{
  Serial.print("Initializing SD card...");
  //Pin 10 must be set to OUTPUT even if it goes unused
  pinMode(10, OUTPUT);

  //Check to see if SD card can be seen
  if (SD.begin(chipSelect)) 
  {
    Serial.println("FAILED!");
    Serial.println("Card failed or not present!");
    return;
  }
  Serial.println("done!");
  Serial.println("SD card has been initialized.");

  //Open the file
  File dataFile = SD.open("datalog.txt");

  //Check for the file and, if available, print to serial
  if (dataFile) 
  {
    while (dataFile.available()) 
    {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }  
  //Error for unsuccessful file opening
  else 
  {
    Serial.println("Error opening datalog.txt");
  } 
}
/*************************************************************************/
void closeFile()
{
  pinMode(10, OUTPUT);
  File dataFile = SD.open("datalog.txt");
  dataFile.close();
}
/*************************************************************************/
void deleteFile()
{
  Serial.print("Removing datalog.txt...");
  SD.remove("datalog.txt");

  if (SD.exists("datalog.txt"))
  {
    Serial.println("FAILED!");
    Serial.println("datalog.txt was not deleted.");
  }
  else 
  {
    Serial.println("done!");
    Serial.println("datalog.txt has been deleted.");
    readingNumber = 1;  
  }
}
/*************************************************************************/
int getSerialNumber()   // user input
{
  int result = 0;
  int q = 0;
  while (Serial.available()==0)
  {
    //Wait until something comes into the serial buffer
  } 
  while (Serial.available()>0)
  {
    while (Serial.available()>0)
    {
      //Move the previous digit to the next column on the left, e.g. 1 becomes 10 while there is data in the buffer
      result *= 10;
      //Read the next number in the buffer, subtract 48 to convert to the actual number
      q = Serial.read() - 48;
      result += q;
    }
    delay(5); // the processor needs a moment to process
  }
  return result;
}
/*************************************************************************/
void setup(void)
{
  Serial.begin(9600);
  analogReference(INTERNAL);
  userInput = getSerialNumber();
  SD.begin(chipSelect);
  Serial.print("Initializing SD card...");
  //Pin 10 must be set to OUTPUT even if it goes unused
  pinMode(10, OUTPUT);

  //Check to see if SD card can be seen
  if (SD.begin(chipSelect)) 
  {
    Serial.println("FAILED!");
    Serial.println("Card failed or not present!");
    return;
  }
  Serial.println("done!");
  Serial.println("SD card has been initialized.");
  
  //Write Log File Header
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile)
  {
    //Lead with a  blank line since there could be previous data
    dataFile.println(", , , ,");
    String header = "ID, Radiation";
    dataFile.println(header);
    dataFile.close();
    Serial.println(header);
  }
  else
  {
    Serial.println("Couldn't open log file.");
  }
}

void loop(void)
{
  if (userInput == 1)
  {
    dataLogging();
  }
  if (userInput == 2)
  {
    dumpFile();
    delay(50);
    setup();
  }
  if (userInput == 3)
  {
    deleteFile();
    delay(50);
    setup();
  }
}

Bump. Anyone have any advice on this one? Thanks ahead of time!

-Billy-

If the Arduino is connected through the USB / serial interface then you need to toggle DTR. This can be done as described here Google Code Archive - Long-term storage for Google Code Project Hosting.. It is easy in other languages as well.

If the Arduino is connected by ISP you can use AVRDude to trigger the reset. Probably Avrdude can trigger the reset in the USB/serial interface setup as well but I never tried this.

The Arduino is connected via the XBee module on the microcontroller to another XBee on the host computer connected via FTDI and communicating through the Serial port. I would assume that means that your first response is the correct one. If this is the case, what exactly is the URL code doing? By default on the Arduino Uno is the Serial connection supposed to reset the Arduino or not?

Thanks again for the help.

-Billy-

It opens a serial connection, sets DTR to 1, waits 0.25s and then sets DTR to 0.

Thank you for the reply, but how do I implement this into my code? Thank you.

-Billy-

Bump. Sorry for being so needy, lol.

-Billy-

So I've tried a bunch of different ways to get this to work the right way and I am having no luck. I want to be able to open the Serial connection and send the command to log data and then close the Serial connection and still have it data log. Once I reopen the Serial connection, I want it to stop the data logging (either through a reset or something similar) and wait for my next command.

Right now, it is waiting for my command, I send the data logging command, it starts data logging and continues when the Serial connection is closed, but then when the Serial connection is reopened, the Arduino continues to data log without a reset. I haven't modified any hardware and it was my understanding that the Arduino was supposed to reset on Serial connect, but it isn't doing it.

Any help would be greatly appreciated and my code is provided below for consideration.

-Billy-

/* Open Source Solar Monitor */

#include <SD.h>    //SD card Library
#include <Wire.h>  //I2C Library

//Solar Sensor Pin Variables
int cellPin = 0;
int tempPin = 1;
float tempReading;
float radiationReading;
int wholeNumTemp = 0;
int decimalNumTemp = 0;
int wholeNumRad = 0;
int decimalNumRad = 0;
long readingNumber = 1;

//SD card Chip Select Constant
const int chipSelect = 4;

//User Input Value
int userInput = 0;

/*************************************************************************/
void dataLogging()
{
  Wire.begin();
  //Obtain Sensor Values1
  radiationReading = 0;
  tempReading = 0;
  for (int i = 0; i < 10; i++)
  {
    delay (700);
    radiationReading += analogRead(cellPin);
    delay (700);
    tempReading += analogRead(tempPin);
    delay (5);
  }
  radiationReading = radiationReading / 10;
  tempReading = tempReading / 10;
  float trueTempVoltage = tempReading * (1100/1024);
  float celsiusTemp = ((trueTempVoltage) - 500) / 10;
  float fahrenheitTemp = (celsiusTemp * 9.0 / 5.0) + 32.0;
  float trueRadiation = radiationReading * 4.1841;
  wholeNumRad = int (trueRadiation);
  wholeNumTemp = int (fahrenheitTemp);
  fahrenheitTemp -= wholeNumTemp;
  trueRadiation -= wholeNumRad;
  fahrenheitTemp *= 100;
  trueRadiation *= 100;
  decimalNumTemp = int (fahrenheitTemp);
  decimalNumRad = int (trueRadiation);
  String dataString = String(readingNumber) + ", " + String(wholeNumRad) + "." + String(decimalNumRad) + ", " + String(wholeNumTemp) + "." + String(decimalNumTemp);
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  //If the file is available, write to it
  if (dataFile) 
  {
    dataFile.println(dataString);
    dataFile.close();
    //Output to the serial port as well
    Serial.println(dataString);
  }  
  //Error for unsuccessful file opening
  else 
  {
    Serial.println("Error Opening datalog.txt");
  }
  readingNumber++; 
  delay (5);
}
/*************************************************************************/
void dumpFile()
{
  Serial.print("Initializing SD card...");
  //Pin 10 must be set to OUTPUT even if it goes unused
  pinMode(10, OUTPUT);

  //Check to see if SD card can be seen
  if (SD.begin(chipSelect)) 
  {
    Serial.println("FAILED!");
    Serial.println("Card failed or not present!");
    return;
  }
  Serial.println("done!");
  Serial.println("SD card has been initialized.");

  //Open the file
  File dataFile = SD.open("datalog.txt");

  //Check for the file and, if available, print to serial
  if (dataFile) 
  {
    while (dataFile.available()) 
    {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }  
  //Error for unsuccessful file opening
  else 
  {
    Serial.println("Error opening datalog.txt");
  } 
}
/*************************************************************************/
void closeFile()
{
  pinMode(10, OUTPUT);
  File dataFile = SD.open("datalog.txt");
  dataFile.close();
}
/*************************************************************************/
void deleteFile()
{
  Serial.print("Removing datalog.txt...");
  SD.remove("datalog.txt");

  if (SD.exists("datalog.txt"))
  {
    Serial.println("FAILED!");
    Serial.println("datalog.txt was not deleted.");
  }
  else 
  {
    Serial.println("done!");
    Serial.println("datalog.txt has been deleted.");
    readingNumber = 1;  
  }
}
/*************************************************************************/
int getSerialNumber()   // user input
{
  int result = 0;
  int q = 0;
  while (Serial.available()==0)
  {
    //Wait until something comes into the serial buffer
  } 
  while (Serial.available()>0)
  {
    while (Serial.available()>0)
    {
      //Move the previous digit to the next column on the left, e.g. 1 becomes 10 while there is data in the buffer
      result *= 10;
      //Read the next number in the buffer, subtract 48 to convert to the actual number
      q = Serial.read() - 48;
      result += q;
    }
    delay(5); // the processor needs a moment to process
  }
  return result;
}
/*************************************************************************/
void setup(void)
{
  Serial.begin(9600);
  analogReference(INTERNAL);
  userInput = getSerialNumber();
  SD.begin(chipSelect);
  Serial.print("Initializing SD card...");
  //Pin 10 must be set to OUTPUT even if it goes unused
  pinMode(10, OUTPUT);

  //Check to see if SD card can be seen
  if (SD.begin(chipSelect)) 
  {
    Serial.println("FAILED!");
    Serial.println("Card failed or not present!");
    return;
  }
  Serial.println("done!");
  Serial.println("SD card has been initialized.");
  
  //Write Log File Header
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile)
  {
    //Lead with a  blank line since there could be previous data
    dataFile.println(", , , ,");
    String header = "ID, Radiation (in W/m^2), Temperature (in F)";
    dataFile.println(header);
    dataFile.close();
    Serial.println(header);
  }
  else
  {
    Serial.println("Couldn't open log file.");
  }
}

void loop(void)
{
  if (userInput == 1)
  {
    dataLogging();
  }
  if (userInput == 2)
  {
    dumpFile();
    delay(50);
    setup();
  }
  if (userInput == 3)
  {
    deleteFile();
    delay(50);
    setup();
  }
}

Opening the serial connection will reset if the connection is opened "from outside". You are showing the code you will be running "inside" the Arduino. As long as you only look inside it will never work. My code was an example for "outside" code running in Python on a PC.

Thank you for your post. It seems as though the Arduino functions the way I wanted it to, as I stated above, when connected via USB, but when I connect it with the XBee units, it no longer resets when I bring up the Serial connection. Any idea why this would only occur through the wireless XBee?

-Billy-

Maybe you did not connect the relevant pins? What about schematics?