FileLogger

AAARRRGGGHHH!!

buffer[i] = i + '0';

Yeah, your suggestion worked PaulS. I had to format the SDcard. To do larger numbers then 9 though I whipped this up:

int number = 1998;
  byte SDArray[4];
  
  int test;
  int test1;
  int test2;
  int test3;
  
  void setup(void) {
  pinMode(MEM_PW, OUTPUT);
  digitalWrite(MEM_PW, HIGH);
  Serial.begin(9600);
  
  
 }
  
  void loop(void){
    
    
  test = number / 1000; //=1
  //Serial.println(test);
  test1 = (number - (1000*test))/100; //(1123 - (1000*1)) / 100 = (1123 - 1000)/10 = 123/100 = 1
  //Serial.println(test1);
  test2 = (number - ((1000*test)+(100*test1)))/10; // = (1123 - (1000+100)) / 10 = 2
  //Serial.println(test2);
  test3 = (number - ((1000*test)+(100*test1)+(10*test2)))/1;// (1123-(1000+100+20))/1 = 3
  //Serial.println(test3);
  
  
   
  SDArray[0] = test  + '0';
  SDArray[1] = test1  + '0';
  SDArray[2] = test2  + '0';
  SDArray[3] = test3  + '0';
  

  
  FileLogger::append("data.log", SDArray, 4);

It breakes down numbers smaller then 10,000 into their individual components e.x. 1998 1,9,9,8 so each can fit into the byte allocated in each array element.

For anyone who wants to write numbers 0-9999 onto their SDcards for sensor logging I wrote this piece of code:

//billtodd
//DEC 27th 09'
#include "FileLogger.h"
#define MEM_PW 8

byte buffer[4];

  int test;
  int test1;
  int test2;
  int test3;
  
  void converter(int number, byte SDArray[6]){
    
  test = number / 1000; //=1  example number is 1123
  //Serial.println(test);
  test1 = (number - (1000*test))/100; //(1123 - (1000*1)) / 100 = (1123 - 1000)/10 = 123/100 = 1
  //Serial.println(test1);
  test2 = (number - ((1000*test)+(100*test1)))/10; // = (1123 - (1000+100)) / 10 = 2
  //Serial.println(test2);
  test3 = (number - ((1000*test)+(100*test1)+(10*test2)))/1;// (1123-(1000+100+20))/1 = 3
  //Serial.println(test3);
  
  SDArray[0] = test  + '0'; //assigns the first digit from the int "number" to array element 0
  SDArray[1] = test1  + '0';//assigns the second digit from the int "number" to array element 1
  SDArray[2] = test2  + '0';
  SDArray[3] = test3  + '0';
  SDArray[4] = 13; //the 13 and 10 are carriage returns so the numbers form a list
  SDArray[5] = 10;
     
  }
  
  void setup(void) {
  pinMode(MEM_PW, OUTPUT);
  digitalWrite(MEM_PW, HIGH);
  Serial.begin(9600);
    
 }
  
  void loop(void){
    
  for(int i=0; i < 60; i++){  //this writes the numbers 0-60 over and over again onto the SDcard
  byte SDArray[6];
  converter(i, SDArray);  //calls the function converter up above
  FileLogger::append("data.log", SDArray, 6);
  }
    
   
}

Look at the sprintf function. It will convert all kinds of numbers, of various sizes, to strings, adding the appropriate null terminator.

I can get filelogger to work, but I had to change:

 result = FileLogger::append("data.log", buffer, length);

to:

 result = FileLogger::append("data.txt", buffer, length);

However, it only works with data.txt
I tried saving a file on the sd card labeled data2.txt, then went into fileloggerdemo changed:

 result = FileLogger::append("data.txt", buffer, length);

to:

 result = FileLogger::append("data2.txt", buffer, length);

Resuts were:"failure to initialize", "failure to append"
I tried several times, then went back to "data.txt" then things worked ok.
(BTW, yes, I added data to the cd file 'data2.txt' before applying it to fileloggerdemo)

Where does one "call the function append()?
When a person opens a file on a cd card, how many 'characters' should be added to the file?

Where does one "call the function append()?

Right here:

result = FileLogger::[glow]append[/glow]("data2.txt", buffer, length);

When a person opens a file on a cd card, how many 'characters' should be added to the file?

When you open the file, no characters should be appended. When you use the append function to append to a file, the 3rd argument is the number of characters in buffer to copy into the file.

I'm getting ascii results on my sd card. I've tried several different things to get actual numbers to appear on the card, but only with partial success. Too many things to remember.
I've temporarily stopped at the following code, which gives me ascii code on my card.

#include "FileLogger.h"
  int x;
  byte seqn;
  int length = 5;
  int tme = 0;

void setup() {
  Serial.begin(9600);
}

void loop() {
 while (tme < 7000){
 seqn = 80; 
 while (seqn <=85){
  byte buffer[5] = {seqn,32,65,13,10};
   byte result;
     x = buffer[0];
     int z = buffer[1];
   result = FileLogger::append("data.txt", buffer, length);
   Serial.print(" A: ");
        if( result == 0) {
          Serial.println("OK");
        } else if( result == 1) {
          Serial.println("Fail initializing");
        } else if( result == 2) {
          Serial.println("Fail appending");
        }
        
            Serial.print(x, DEC);     // 3
            Serial.print("\t");              // prints a tab
            Serial.print(z, DEC);     // 3
            Serial.println();              // prints a tab

    delay(1000);
    seqn = (seqn +1);
    
 }
   tme = millis();
  Serial.println(tme);// 0
 }
}

Looking at this part of the code:
byte buffer[5] = {seqn,32,65,13,10};
seqn is a variable, which are numbers 80-85, I chose those #'s, since they show up as ascii 'P - U'
32 = space, 65 = A, 13= carriage return, 10 = line feed

The extra while loop, controlled by millis(), is just to be sure the thing will stop after approx 7 seconds.

So, on my cd card I get the following result, in a notepad text file:

Q A
R A
S A
T A
U A

Q - U are the result of a changing variable (seqn), A is the constant # 65

What I want to do is feed numerical values into variables, then save those values on my cd card as numbers, rather than ascii code.

    1. time, from 0 seconds to several minutes
  1. electronic pulses from a speed sensor, from 0 to about 3000 pulses/second

I suppose I can copy from the cd's file to excel, then use excel to change to numerical values. My intent is to store data on the card, then enter the data to a spread sheet.

I'm kinda at a quandary at this point.
Can someone help figure out how to get actual numbers on the card?

Paddy

If you store numbers on the card, and those numbers are larger than one byte, as in an int, you will need to use bitshifting to get the most significant byte and least significant byte from the int, and then write the bytes out in the correct order (least, most or most, least).

If the number is larger than 2 bytes, you'll need to split the number into the appropriate number of bytes, and write them in the correct order.

The proper order depends on the software that is going to read the card later.

If that software is excel, you will need to construct a completely properly formatted binary file for excel to read. Good luck with that task.

If the software is excel, and the file is to be a csv (comma separated values file), the file is all text (all ascii values).

I think that what you need to do is to think about whether you really want to write the numbers AS NUMBERS to the file.

Posted by: PaulS
Re: FileLogger
Reply #70 - 28.12.2009 at 00:29:29
Look at the sprintf function. It will convert all kinds of numbers, of various sizes, to strings, adding the appropriate null terminator.

]]
Where can I find information on the use of the sprintf function?

I also need help with this code:
 byte buffer[5] = {seqn,32,65,13,10};
(32 = space, 65 = A, 13= carriage return, 10 = line feed)
seqn is a variable that could be from 0-2000. It shows up on the SD card in ascii code.
**How can I get the filelogger system to load the values in variable seqn on the sd card as the actual value, whether the data is char or decimal, NOT in ascii. **

For instance: If the data loaded into the variable 'seqn' is a value of 1300, I want to have the value 1300 to show up on the sd card.
At this time, if 'seqn' = 80 thru 85, and when I use this code:

  byte buffer[5] = {seqn,32,65,13,10};
   byte result;
   result = FileLogger::append("data.txt", buffer, length);

the values in 'seqn' show up as P, Q, R, S, T, U

Please help
PO'T

Where can I find information on the use of the sprintf function?

Geez, I don't know. Google, maybe? Or a C programming manual. You're writing C code. You do have a book don't you. No? Well, I'll wait here while you go get one.

You're back with the book? Good.

How can I get the filelogger system to load the values in variable seqn on the sd card as the actual value, whether the data is char or decimal, NOT in ascii.

You are creating a text file. That's what the .txt extension implies, anyway. Everything in the file will be ascii values.

If seqn contains 80, and you write that as a byte to the SD card, you will get a "P". If you want to get "80", instead, you will need to use sprintf (or write the same code that sprintf implements) to convert 80 to "80" before writing the string to the card.

PaulS

God Member

Online

Arduino rocks

Posts: 1282
Seattle, WA USA
Gender:
Re: FileLogger
Reply #76 - Yesterday at 13:28:15 Quote:

Where can I find information on the use of the sprintf function?

Geez, I don't know. Google, maybe? Or a C programming manual. You're writing C code. You do have a book don't you. No? Well, I'll wait here while you go get one.

You're back with the book? Good.

Well, gees, give an old man a break for getting this far.If you find my questions annoying, feel free to ignore them. :-?

Due to the impenetrable thickness of my skull, :o and my lack of programming skills, :-[ I shall give up on the FileLogger and use another system that works for me, like sirmorris' ufat, (MMC/uFat2 and Deviceprint)

Gee, I wonder how I was able to get that one into operation.

The first thing shown in any programming class is some sort of hello world program. For the Arduino, that's blinking an LED. For a C programming class it's printing "Hello World", using the printf function. The sprintf function is a derivative of that function that places the output into a string buffer, instead of on an output stream.

If someone suggests that you use a function you are not familiar with, it takes 10 seconds to google the function. If you can't be bothered with doing that, why should I do it for you?

If someone suggests that you use a function you are not familiar with, it takes 10 seconds to google the function. If you can't be bothered with doing that, why should I do it for you?

A simple answer would have been: "You can find it by googleing such and such"
I suppose having five stars over your name gives you the privilege of being impolite, but I didn't ask you in particular, and I didn't ask you to do anything in particular for me.

You need not have replied in the first place. If dumb questioners annoy you, just ignore and move on.

In case anyone else is interested, some information on an emulation of 'printf' can be found at the Arduino Playground: Arduino Playground - Printf

As stated in the playgroud
"This function emulates the stdio.h printf() functionality in C and will send the output to the Serial connection using Serial.print()."

Appending data to files with FileLogger,sprintf works quite well for converting to string data. :wink:

Info on sprintf:
http://www.cppreference.com/wiki/c/io/sprintf

http://docs.roxen.com/pike/7.0/tutorial/strings/sprintf.xml

I am having a lot of trouble getting FileLogger to work on my arduino Mega. I changed the SPI settings to the ones mentioned in an earlier post. I have reformatted my card in more ways than I knew existed to get fat16. I have a file "data.log" and a file "data.txt", both with a single '1' in the file. It is giving me serial output on my computer, but all it will do is fail to initialize. I am not sure what I am missing. Can anyone help me?

EDIT: I also forgot to mention, I get the same results when using the FileLoggerDemo as my own code. And I am using this microsd card slot:

Hi all,

I am new to Arduino and also new to this forum. Currently I got an Arduino Duemilanove (ATmega168) and got the Seeeduino sd shield. I downloaded the FileLogger library and I have sucessfully run the example code (that I have to create a file data.log and put a character there). For my project, I am planning to log data (say, temperature) every second, for about 6 months. I want to make a number of ".txt" files which contains the logged data for each day: eg. if in a txt file, each line contains a record for 1 sec. there will be 86400 lines in the txt file, for one day data. And there will be about 180 txt files stored in the SD card.

I wonder, if anyone has idea if that is possible? I read that I have to create a file beforehand b4 I append data to that specific file, can anyone tell me that if I can "create a file" within the "loop()", I just found that creating files beforehand is a hard code way and I want to avoid that. Also, if I stored all data in a single txt file for half year, the data will be huge and it seems to be dangerous for my project if something screwed up in between. Moreover, I would also like to learn about alternative solution.

Anyways, thanks for your help.

-klo

Hi to ALL!!!
There is a way to read de SDCard with the filelogger library?
If not, how can be done?
Thank's!!

Hi, i tried this with the microSD shield from sparkfun and an arduino duemilanove. I can't get it work. Do i have to do something special if i use the sparkfun shield? How do i have to wire it? Do i need to use a special digital pin to power up? I always get the error "Fail initializing" and sometimes "fail appending".

Need Help.

I have been working on a sketch to record my electrical power usage to a SD card and transmit the data via xBee using the Serial.print command. I have been using Seeeduino Stalker 168 and 328. The 328 works fine but the 168 will not work using both the Serial.print and the Filelogger statements. If I comment out the Serial.print statements, the filelogger works and if I comment out the filelogger statements, the Serial.print works.

The problem is that the 168 does not have enough RAM to run the sketch. I adjusted the RX_BUFFER_SIZE to 8 to maximize RAM. Does anybody have any ideals about modifying the sketch to get it to run on the 168? The filelogger library seems to use a good size piece of RAM so I would like to know if there is a way to reduce its usage.

Here is the sketch:

/*
 * Meter reading program using Itron smart meter
 *
 * StalkerMeterLogger.pde
 * Sketch writes incoming data from IR detector
 * 
 * CRS8291 - Arduino forum username
 *
 * Data output in following format with example
 * siteID, unixTime, watts, totalWatts, 15MinuteDemand, max15MinuteDemand, temperature degrees K
 * 14,1288310640,200,79859,12000,12236,29315
 *
 */

#include "FileLogger.h" // http://code.google.com/p/arduino-filelogger/
#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h> // a basic DS1307 library - http://www.arduino.cc/playground/Code/Time

const int ledPin = 8;   // LED watt indicator initialization.
int ledState = LOW;  // watt LED indicator lamp
unsigned long ledOnTime = 0;     // start time of LED pulse count on time

byte siteID[2]= {'1','4'};
byte delimiter[1]= {','};
byte crlf[2]= {0x0D,0x0A};

volatile unsigned int wattSensor = 0;  // Counts power pulses in interrupt, 1 pulse = 1 watt
unsigned int wattSensorCount; //number of watts during logging interval 
unsigned long totalWatts = 0;  // Total power used since the sketch started ???

unsigned long oldtime=0; //last time loop has ran

unsigned int demandMinutes[15];  //Array that holds each powerusage reading done during the last 15 minutes
unsigned int demandMinutesKwh=0; //Average of last 15 minutes in Kwh
unsigned int maxDemandKwh=0; //Maximum 15 minute demand in Kwh

const int resetDay = 1; //day of month to reset counters, 1-31
const int resetHour = 0; //hour of day to reset counters, 0-23
const int resetMinute = 0; //minute of hour to reset counters, 0-59

const int tempPin = 1; //the analog pin the TMP36's Vout (sense) pin is connected to
unsigned int temperatureK; //temperatue in degrees kelvin, used to eliminate negative temperatures

void setup(void)
{
  pinMode(ledPin, OUTPUT);  // LED watt indicator initialization

  attachInterrupt(1, wattSensorInterrupt, FALLING);

  for (int i=0; i<15 ;i++) //Initialize last fifteen minute Kwh to 0
    demandMinutes[i]=0;

  setSyncProvider(RTC.get);   // the function to get the time from the RTC

  //  Serial.begin(9600);
  //  int calcRam = freeRam();
  //  Serial.print("Free RAM: ");
  //  Serial.println(calcRam);  
}

void loop(void)
{
  time_t t = now();
  // turn watt led off if 50 ms has passed since watt counted
  if (digitalRead(ledPin) == HIGH && millis() - ledOnTime >= 50) {
    digitalWrite(ledPin, LOW);
  }
  if( minute(t) != oldtime) //1 minute interval for data reporting
  {
    wattSensorCount = wattSensor; //get the count from the interrupt handler 
    wattSensor = 0;    //reset the watts count
    wattSensor = 300; //=18kwh, used for testing, comment out or delete for normal operation
    totalWatts = totalWatts + wattSensorCount; //total watts counter
    oldtime = minute(t); //use this for one minute interval
    calculateDemand(); // Calculate 15 minute demand
    measureTemperature(); //measure temperature in degrees Kelvin
    /*
    Serial.print("14,"); // print site id
     Serial.print(t); //print unix time
     Serial.print(',');
     Serial.print(wattSensorCount); //print watts per minute
     Serial.print(',');
     Serial.print(totalWatts); //print accumulated watts
     Serial.print(',');
     Serial.print(demandMinutesKwh); //print 15 minute demand
     Serial.print(',');
     Serial.print(maxDemandKwh); //print max 15 minute demand
     Serial.print(',');
     Serial.print(temperatureK); //print temperature in degrees Kelvin
     Serial.println();
     */
    FileLogger::append("data.txt", siteID, 3);     //print site id
    write_long(t);                                 //print unix time
    FileLogger::append("data.txt", delimiter, 1);
    write_long(wattSensorCount);                   //print watts per minute
    FileLogger::append("data.txt", delimiter, 1);
    write_long(totalWatts);                        //print accumulated watts
    FileLogger::append("data.txt", delimiter, 1);
    write_long(demandMinutesKwh);                  //print 15 minute demand
    FileLogger::append("data.txt", delimiter, 1);
    write_long(maxDemandKwh);                      //print max 15 minute demand
    FileLogger::append("data.txt", delimiter, 1);
    write_long(temperatureK);                      //print temperature in degrees Kelvin
    FileLogger::append("data.txt", crlf, 2);

    //reset totalWatts and maxDemandKwh to zero once a month
    if ((day(t) == resetDay) && (hour(t) == resetHour)) {
      if ((minute(t) == resetMinute)) {
        totalWatts = 0;
        maxDemandKwh = 0;
      }
    }
  }
}

void calculateDemand() //calculates rolling 15 minute average of one minute Kw usage
{
  for (int i=0; i<15 ;i++) //Block move previous 14 minutes by one step
    demandMinutes[i]=demandMinutes[i+1];
  demandMinutes[14]=wattSensorCount; //Assign latest one minute average to 15 minute average array
  demandMinutesKwh=0; //Reset demandMinutesKwh to 0
  for (int i=0; i<15 ;i++)  //Calculate new 15 minute demand
    demandMinutesKwh=demandMinutesKwh+demandMinutes[i];
  demandMinutesKwh=demandMinutesKwh*4;

  if (demandMinutesKwh > maxDemandKwh) //Assign maxDemandKwh to demandMinutesKwh if new high demand
    maxDemandKwh=demandMinutesKwh;
}

void measureTemperature (void) {
  unsigned int tempReading = 0;        // the analog reading from the sensor
  analogRead(tempPin); //discard first reading
  for (int i = 0; i < 50; i++) {
    tempReading = tempReading + analogRead(tempPin);
  }
  unsigned int voltage = tempReading * 329 / 1024 /50; 
  temperatureK = (((voltage - 50) * 100) + 27315);  // degrees K * 100 to save as integer
}

void write_long(uint32_t number) //break data into byte array for writing to FileLogger
{
  uint8_t buf[10];
  uint8_t i=0;
  do {
    i++;
    buf[sizeof(buf) - i] = number%10 + '0';
    number /= 10;
  } 
  while (number);

  FileLogger::append("data.txt", &buf[sizeof(buf) - i], i);
}

void wattSensorInterrupt() // routine called when external interrupt is triggered
{
  wattSensor = wattSensor + 1;  //Update number of pulses, 1 pulse = 1 watt
  ledOnTime = millis();
  digitalWrite(ledPin, HIGH);
}
/*
// this function will return the number of bytes currently free in RAM      
 int freeRam(void)
 {
 extern int  __bss_end; 
 extern int  *__brkval; 
 int free_memory; 
 if((int)__brkval == 0) {
 free_memory = ((int)&free_memory) - ((int)&__bss_end); 
 }
 else {
 free_memory = ((int)&free_memory) - ((int)__brkval); 
 }
 return free_memory; 
 }
 */

edit: Currently the Serial.print is commented out for the filelogger to work.