Go Down

Topic: Program can't open file on SD card (Read 539 times) previous topic - next topic

KarDen

   Hi guys, i've a problem.  I've made a sheme with 3 OneWire devices DS18B20 and a self made microSD shield. An idea is - find all OneWire devices, register them in a table, ask each one 1 time in 5 seconds 12 times and print data to a serial port (port monitor of Arduino IDE) and to a file on microSD card. If i comment a part of program which write data to a file, all the devices are found, table and temperature data from them printed to a serial. When i try to write it parallel to microSD, programm write "error opening test.txt",  BUT! if the file was not on microSD card, it magically appears with 0b size. If i try to write a simple data with a simple programm to a microSD card like "test 1, 2, 3" whithout any changing in wiring it works great. File appears, data writing to it and so on.  Please help me, I'll be glad for any suggestion.
A simple programm, works great:
Code: [Select]

#include <SD.h>

File myFile;

void setup()
{
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
  pinMode(10, OUTPUT);

  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

   myFile = SD.open("test.txt", FILE_WRITE);

  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    Serial.println("error opening test.txt");
  }

  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");

    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
  } else {
    Serial.println("error opening test.txt");
  }
}

void loop()
{

}


And my programm:

Code: [Select]

//use OneWire
#include <OneWire.h>
#include <SD.h>

//OneWire on pin 9

OneWire ds(9);

//variables and massives
int HighByte, LowByte, TReading, Tc_100, Whole, Fract, SignBit;
byte i=0,devicenum=0,k=0,j=0,s=0,tempdata[16],address[8],addressmap[10][8];
String devicetype[10];
File myFile;


//setting up

void setup(void)
{
  Serial.begin(9600);
 
/*while devices appears, i find they addresses and write to a matrix whith 10 strings, so i use up to 10 devises in my programm*/
while (ds.search(address)){
for ( i = 0; i < 8; i++) addressmap[k][i]=address[i];
k=k+1;
}
//remember number of OneWire devices
devicenum = k-1;

/*for each device get a Byte which means type, and write it to another matrix*/
for (k=0; k<=devicenum; k++) {
  switch (addressmap[k][0]) {
  case 16: devicetype[k]="digital thermometer ds1820 (ds1920) series"; break;
  case 32: devicetype[k]="4-channel 16 bit analog->digital converter"; break;
  case 34: devicetype[k]="digital thermometer ds1822"; break;
  case 40: devicetype[k]="digital thermometer ds18b20, up to 12 bit resolution"; break;
  default: devicetype[k]="unknoun 1-Wire device"; break;
                            }
                             }
//print all the addresses and types of devices to a serial
for( k = 0; k <= devicenum; k=k+1) {
Serial.print("Device #"); Serial.print(k); Serial.print(" address is [ ");
  for( i = 0; i < 8; i=i+1) {
    Serial.print(addressmap[k][i], HEX);
    Serial.print(" ");
                            }
    Serial.print(']'); Serial.print(" type of device is "); Serial.println(devicetype[k]);
                                   }
    Serial.println("That's all list of online devices");


   Serial.print("Initializing SD card...");

// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
//   Note that even if it's not used as the CS pin, the hardware SS pin
//   (10 on most Arduino boards, 53 on the Mega) must be left as an output
//   or the SD library functions will not work

pinMode(10, OUTPUT);

  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

// try to open the file
   
  myFile = SD.open("test.txt", FILE_WRITE);
 
  // if ok, then print all the addresses and types of devices to a file:
  if (myFile!=false) {
   
  // print to a serial, that i work whith file 
   Serial.print("Writing device mass to test.txt"); 
   
for( k = 0; k <= devicenum; k=k+1) {
myFile.print("Device #"); myFile.print(k); myFile.print(" address is [ ");
  for( i = 0; i < 8; i=i+1) {
  myFile.print(addressmap[k][i], HEX);
  myFile.print(" ");
                            }
    myFile.print(']'); myFile.print(" type of device is "); myFile.println(devicetype[k]);
                                   }
    myFile.println("That's all list of online devices");
   
// print to a serial, that i work whith file
   Serial.print("Writing devices data to test.txt"); 
// series of 12 measurements
for( s = 0; s < 12; s=s++) {
    for( k = 0; k <= devicenum; k=k+1) {
      for(i=0;i<8;i++) address[i]=addressmap[k][i]; 
  ds.reset();
  ds.select(address);
  ds.write(0x44,1);         // converting
 
  delay(1000);     //maybe 750ms is enough
  ds.reset();
  // we might do a ds.depower() here, but the reset will take care of it.
    ds.select(address);   
  ds.write(0xBE);         // please, write data to a scratchpad
  for ( j = 0; j < 9; j++)   { // getting 9 Byte data from Scratchpad - page 9 from 27 Datasheet DS18B20
    tempdata[j] = ds.read();
  // we need only 0 and 1 Byte from Scratchpad - page 9 from 27 Datasheet DS18B20
  LowByte = tempdata[0];
  HighByte = tempdata[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) TReading = (TReading ^ 0xffff) + 1; // if negative, then 2's comp
 
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;
 
                              }
for (i=0; i<8; i++) Serial.print(address[i],HEX); Serial.print("   "); Serial.print(tempdata[0],HEX); Serial.print("   "); Serial.print(tempdata[1],HEX); Serial.print('\n');
                              // If its negative
  Serial.print(" T = "); if (SignBit) Serial.print("-"); Serial.print(Whole); Serial.print("."); if (Fract < 10) Serial.print("0"); Serial.print(Fract); Serial.println(" C");
                                        }
    Serial.println("I'm waiting about 5 sec before next series of measurement");
    delay (5000);
                            }
    myFile.close();
    Serial.println("Done.");
              }
  // if the file did not open, writing to a serial error
  else Serial.println("error opening test.txt");

}
void loop(void)
{

}

marco_c

I don't use the SD library because I use SDFat, however, the line
Code: [Select]

if (myFile!=false)

is different from the shorter example and could be the problem.

myFile can be evaluated as a logical expression - as in "(myfile)" - because the C++ compiler will treat any non-zero value as 'true'. So a NULL pointer (typically zero) will evaluate as false, although I would prefer to explicitly use "pointer == NULL". By comparing "myFile != false" the expression is only logically true if myFile is not equal to the value false (and I don't know what it is). Maybe changing this to the same logic as the simpler example could make a difference.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

GoForSmoke

Quote
A simple programm, works great:


If you run it twice, the file has the same data twice? It opens the file every time?

If so then

if (myFile!=false) {

is simply not doing what you think.

I ran your sketch through Autoformat and moved braces just looking for some other answer and got none.

So what happened when you used

if (myFile) {

which still doesn't answer why it would work with no file and not with a file present unless that was read-only.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

el_supremo

I think this:
Code: [Select]
if (myFile!=false) {

should be this:
Code: [Select]
if (myFile != NULL) {

Pete

el_supremo

It is also best to avoid use of the String class. It will eventually cause you grief. Use C null_terminated strings instead.

Pete

KarDen

   To marco_c
   Thank you for your answer. I tried to write this part as in example
Code: [Select]

if (myFile) ...

and some other variants. Nothing of them works.

KarDen

   To GoForSmoke
Thank you for your answer.
The simple programm write "testing 1, 2, 3" many times. +1 each time i turn on Arduino or call a serial port monitor (port monitor of Arduino IDE).
Srting of code
Code: [Select]

if (myFile) {

gives a same result, don't work.
About a simple programm, it works with no file because string of code
Code: [Select]

myFile = SD.open("test.txt", FILE_WRITE);

create a file if it is not present. Whith read only file i did not try.

KarDen

   To el_supremo
Thank you for your answer. Will try.

GoForSmoke


About a simple programm, it works with no file because string of code
Code: [Select]

myFile = SD.open("test.txt", FILE_WRITE);

create a file if it is not present. Whith read only file i did not try.



FILE_WRITE should create the file if none exists and start writing at the end of the new file, which is also the beginning.

However if the file exists then FILE_WRITE should open the file and start writing at the end, the writing there also called append (add to the end) in some languages and documents.

The simple program does those things. The problem in your code may be interrelated or not but it is not that simple at least to me which is a cue for someone else to point out an even simpler answer!

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

KarDen

      To everyone.
Thank you very much for your answers.  Excuse me, I badly know the English language,
and do not understand all of what you write here. I'm from Russia.
With your help and help of my friend I found a solution, a bit strange in my opinion.
   
In the code I posted above it's enough to change one line:

Was:
Code: [Select]

String devicetype[10];


Now:
Code: [Select]

char* devicetype[10];

KarDen

     Here is final version of code
Code: [Select]

//use OneWire
#include <OneWire.h>
#include <SD.h>

//OneWire on pin 9

OneWire ds(9);

//variables and massives
int HighByte, LowByte, TReading, Tc_100, Whole, Fract, SignBit;
byte i=0,devicenum=0,k=0,j=0,s=0,tempdata[16],address[8],addressmap[10][8];
char* devicetype[10];
File myFile;


//setting up

void setup(void)
{
  Serial.begin(9600);
 
/*while devices appears, i find they addresses and write to a matrix whith 10 strings, so i use up to 10 devises in my programm*/
while (ds.search(address)){
for ( i = 0; i < 8; i++) addressmap[k][i]=address[i];
k=k+1;
}
//remember number of OneWire devices
devicenum = k-1;

/*for each device get a Byte which means type, and write it to another matrix*/
for (k=0; k<=devicenum; k++) {
  switch (addressmap[k][0]) {
  case 16: devicetype[k]="digital thermometer ds1820 (ds1920) series"; break;
  case 32: devicetype[k]="4-channel 16 bit analog->digital converter"; break;
  case 34: devicetype[k]="digital thermometer ds1822"; break;
  case 40: devicetype[k]="digital thermometer ds18b20, up to 12 bit resolution"; break;
  default: devicetype[k]="unknoun 1-Wire device"; break;
                            }
                             }
//print all the addresses and types of devices to a serial
for( k = 0; k <= devicenum; k=k+1) {
Serial.print("Device #"); Serial.print(k); Serial.print(" address is [ ");
  for( i = 0; i < 8; i=i+1) {
    Serial.print(addressmap[k][i], HEX);
    Serial.print(" ");
                            }
    Serial.print(']'); Serial.print(" type of device is "); Serial.println(devicetype[k]);
                                   }
    Serial.println("That's all list of online devices");


 
Serial.print("Initializing SD card...");

// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
//   Note that even if it's not used as the CS pin, the hardware SS pin
//   (10 on most Arduino boards, 53 on the Mega) must be left as an output
//   or the SD library functions will not work

pinMode(10, OUTPUT);

  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

// try to open the file
   
  myFile = SD.open("test.txt", FILE_WRITE);
 
  // if ok, then print all the addresses and types of devices to a file:
  if (myFile!=NULL)
  {
    // print to a serial, that i work whith file 
   Serial.println("Writing device mass to test.txt"); 
   
   for( k = 0; k <= devicenum; k=k+1)
  {
    myFile.print("Device #");
    myFile.print(k);
    myFile.print(" address is [ ");
        for( i = 0; i < 8; i=i+1)
        {
         myFile.print(addressmap[k][i], HEX);
         myFile.print(" ");
        }
    myFile.print(']');
    myFile.print(" type of device is ");
    myFile.println(devicetype[k]);
   }
    myFile.println("That's all list of online devices");
            // print to a serial, that i work whith file
   Serial.println("Writing devices data to test.txt"); 
            // series of 12 measurements
   for( s = 0; s < 12; s=s++)
  {
      for( k = 0; k <= devicenum; k=k+1)
    {
      for(i=0;i<8;i++) address[i]=addressmap[k][i]; 
      ds.reset();
      ds.select(address);
      ds.write(0x44,1);         // converting
      delay(1000);              //maybe 750ms is enough
      ds.reset();               // we might do a ds.depower() here, but the reset will take care of it.
      ds.select(address);   
      ds.write(0xBE);         // please, write data to a scratchpad
         for ( j = 0; j < 9; j++) tempdata[j] = ds.read(); // getting 9 Byte data from Scratchpad - page 9 from 27 Datasheet DS18B20
      // we need only 0 and 1 Byte from Scratchpad - page 9 from 27 Datasheet DS18B20
      LowByte = tempdata[0];
      HighByte = tempdata[1];
      TReading = (HighByte << 8) + LowByte;
      SignBit = TReading & 0x8000;  // test most sig bit
    if (SignBit) TReading = (TReading ^ 0xffff) + 1; // if negative, then 2's comp
    Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
    Whole = Tc_100 / 100;  // separate off the whole and fractional portions
    Fract = Tc_100 % 100;
    for (i=0; i<8; i++) myFile.print(address[i],HEX);
      myFile.print("   ");
      myFile.print(tempdata[0],HEX);
      myFile.print("   ");
      myFile.print(tempdata[1],HEX);
      myFile.print('\n');
      myFile.print(" T = ");
     // If its negative
      if (SignBit) myFile.print("-");
      myFile.print(Whole);
      myFile.print(".");
      if (Fract < 10) myFile.print("0");
      myFile.print(Fract);
      myFile.println(" C");
    }
    Serial.println("I'm waiting about 2 sec before next series of measurement");
    delay (2000);
  }
    myFile.close();
    Serial.println("Done.");
  // if the file did not open, writing to a serial error
 
  }
  else Serial.println("error opening test.txt");
}
void loop(void)
{

}

KarDen

     To everyone.
If you guys are interested, in order to thank you, I will describe how I made my cheap micro SD shield with photos and will post it here

GoForSmoke

Yes please!

There are some examples using micro-SD to full size adapter sleeve clear up to old-type floppy drive cable.

Of much interest is going from 5V Arduino to 3.3V SD.
One way is to use 3.3V Arduino!

Best I have seen uses 3.3V supply (different ways of getting that) with pullups and diodes on the signal lines.
When the 5V line is LOW the diode lets current through, the SD pin is LOW.
When the 5V line is HIGH the diode blocks 5V and the 3.3V pullup holds the SD pin 3.3V HIGH.

What I like most with that is the 5V lines are not bleeding current through voltage dividers when they are HIGH.

With SD, I went with 1 voltage divider on the power line, change 5V to 3.3V. That same one also powers the pullups.

Sorry about using English. I am typical only know English American. I did take French class but that ended in 1972.
I hope you have friends to help translate and how good it must be not stuck with just one language!
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

KarDen

      To everyone.
Excuse me for a long time answer, my work takes most of the time.
Here is my DIY micro SD shield:

KarDen

     To everyone.
And the scheme:

Go Up