Unable to save input data to SD card in Binary format

I want to take an analog input from one of the pins on the Arduino Uno, save it in an array and then save it on an SD card as a binary file. The user specifies the number of inputs to be stored. Here is the code:

/*

*/

#include <SPI.h>
#include <SD.h>

File myFile;

char size[10];
int sensorPin = A0;
int sensor_value = 0;

void setup() {
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("Initialization failed!");
    return;
  }
  Serial.println("Initialization done.");
  
  //Asking user for input
  Serial.println("Enter comma separated values for Watching Time and Offset Length: (eg 25,20)");
  Serial.println("Total input should be no longer than 10 characters");
}
 
boolean isValidNumber(String str) {
    for(int i = 0; i < str.length(); i++) {
      if(!isDigit(str.charAt(i))) {
        return false;
      }
    }
}

void loop() {

  String watching_time;
  String offset_time;

  while (Serial.available()) {  
    // Accepting string, and splitting it into two inputs
    String user_input = String(Serial.readBytesUntil('\n', size, 10));
    user_input = String(size);
    int comma = user_input.indexOf(',');
    watching_time = (user_input.substring(0, comma));
    offset_time = (user_input.substring(comma+1, user_input.length()));

    // Verifying valid input
    boolean isNumber1 = true;
    boolean isNumber2 = true;
    isNumber1 = isValidNumber(watching_time);
    isNumber2 = isValidNumber(offset_time);

    // Leaving loop if valid input acquired
    if(isNumber1 && isNumber2) {
      Serial.println("Watching time:" + watching_time + '\n' + "Offset time:" + offset_time);
      break;
    }
    else Serial.println("Please enter a valid input in the specified format. The entered input is not a number");
  }
  
  //Converting the strings to integers for the loop
  Serial.print("this shizz is working")
  int watching_time_int = watching_time.toInt();
  int offset_time_int = offset_time.toInt();
  int record_time = watching_time_int - offset_time_int;
  float Voltages[record_time] PROGMEM;

  for (int k = 0; k<watching_time_int; k++) {
    sensor_value = analogRead(sensorPin);
    if (k>= offset_time_int) {
      float voltage = sensor_value * (5.0 / 1023.0);
      Voltages[k - offset_time_int] == voltage;
      myFile = SD.open("example.txt", FILE_WRITE);
      if (myFile) {
        Serial.print("Writing to example.txt...");
        Serial.println(voltage);
        myFile.print(voltage);
        myFile.write(voltage);
        myFile.close();
      }
    }
  }
  
}

Now I enter "55,25" on the Serial Monitor and get this (see file attached).

However, when I remove the SD Card and try reading it on my PC - I get this gibberish (see notepad file attached).

So I thought the encoding must be different and hence I tried reading the file back into the Arduino and printing it onto the Serial Monitor but I got the same thing (file attached).

#include <SPI.h>
#include <SD.h>

File myFile;

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

  Serial.print("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("Initialization failed!");
    return;
  }
  Serial.println("Initialization done.");

  myFile = SD.open("example.txt");
  if (myFile) {
    Serial.println("example.txt:");
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
  }
  else {
    Serial.println("error opening example.txt");
  }
}

void loop() {
  // nothing happens after setup
}

Reading into Arduino.JPG

variable voltage is 4 bytes.
the write_statemaent writes one byte

Thanks for the prompt response - is there another way to do this?

I am taking an analog input from my Arduino Uno and then scaling it as a float from 0 to 5. I am continuously reading data from the Arduino and hence I am storing it in a float array. The number of readings to be stored is specified by the user at the start of the program using the serial monitor. How do I write this data as binary? I can't use the 'write' function because it only sends one byte at a time. Even if I specify the length, using the 'sizeof' function, I get this error:
no matching function for call to 'SDLib::File::write(float [record_time], int)'

If I don't specify the length, it just stores a bunch of gibberish in the txt file.

Is there a better way of dong this? Should I just directly store the analog values and then convert them later when I want to use them?

This doesn't seem to be an encoding problem because if that was the case, then the Arduino should be able to read the data back into itself which it doesn't. I have also tried storing it in a bin file but that didn't help either.

My code is attached below - any help on how to do this would be highly appreciated.

#include <avr/pgmspace.h>/*

*/

#include <SPI.h>
#include <SD.h>
#include <avr/pgmspace.h>

File myFile;

char size[10];
int sensorPin = A0;
int sensor_value = 0;
unsigned int reading_rate = 10000;

void setup() {
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("Initialization failed!");
    return;
  }
  Serial.println("Initialization done.");
  
  //Asking user for input
  Serial.println("Enter comma separated values for Watching Time and Offset Length: (eg 25,20)");
  Serial.println("Total input should be no longer than 10 characters");
}
 
boolean isValidNumber(String str) {
    for(int i = 0; i < str.length(); i++) {
      if(!isDigit(str.charAt(i))) {
        return false;
      }
    }
}

void loop() {

  String watching_time;
  String offset_time;

  while (Serial.available()) {  
    // Accepting string, and splitting it into two inputs
    String user_input = String(Serial.readBytesUntil('\n', size, 10));
    user_input = String(size);
    int comma = user_input.indexOf(',');
    watching_time = (user_input.substring(0, comma));
    offset_time = (user_input.substring(comma+1, user_input.length()));

    // Verifying valid input
    boolean isNumber1 = true;
    boolean isNumber2 = true;
    isNumber1 = isValidNumber(watching_time);
    isNumber2 = isValidNumber(offset_time);

    // Leaving loop if valid input acquired
    if(isNumber1 && isNumber2) {
      Serial.println("Watching time:" + watching_time + '\n' + "Offset time:" + offset_time);
      break;
    }
    else Serial.println("Please enter a valid input in the specified format. The entered input is not a number");
  }
  
  //Converting the strings to integers for the loop
  int watching_time_int = watching_time.toInt();
  int offset_time_int = offset_time.toInt();
  int record_time = watching_time_int - offset_time_int;
  float Voltages[record_time] PROGMEM;

  for (int k = 0; k<watching_time_int; k++) {
    sensor_value = analogRead(sensorPin);
    if (k>= offset_time_int) {
      float voltage = sensor_value * (5.0 / 1023.0);
      Voltages[k - offset_time_int] == voltage*1000;
    }
    if (k = watching_time_int-1){
    myFile = SD.open("example.txt", FILE_WRITE);
      if (myFile) {
       Serial.print("Writing to example.txt...");
        myFile.write(Voltages);
        myFile.close();
        Serial.print("Done");  
      }
    }
  }
  
  
}
  float Voltages[record_time] PROGMEM;

What's that supposed to do?

Once you get your array into RAM, I can see no reason not to use the write method

if (k = watching_time_int-1)Oops

AWOL:
Once you get your array into RAM, I can see no reason not to use the write method.

I'm not sure I understand - I did use the 'write' function and it just wrote gibberish to the file. Do you mean I should not use PROGMEM? Because I will have about a few thousand elements in the array.

You have to ask yourself how the readings get into PROGMEM.

  Voltages[k - offset_time_int] == voltage*1000;Certainly not like that.

Certainly not at all.

In that case I'm not sure how to do this. I'm a beginner and have been on this for a while now. I've read the Arduino reference pages over and over to no avail.

What I'm doing here is converting the float to integers (not the variable but the actual value) so that it can be written easily in binary but obviously it's not working. And even if I try and write a single float value on the serial monitor as binary, it doesn't work.

Can you list some good links to get well versed with this or could you please tell me how it's done :-).

Thanks

Let's turn it around - where did you find the reference that said to store dynamic data in flash memory?

And even if I try and write a single float value on the serial monitor as binary, it doesn't work.

I see no evidence for that assertion.

If speed is an issue, then there's little point in converting and storing floating point values to SD. Store raw values, and do the conversion on a platform that is better suited to the task.
If speed ain't an issue, store floating point values in whatever format is best suited to the task at hand (hint)

I figured that since I would be storing a very large volume of data, I might rather use this kind of memory. But even if I remove PROGMEM, I still have the same problem.

As far as the 'write' function goes, it only writes once byte at a time and hence it doesn't work. I have to convert the variable to long to even see that gibberish. If I try and write the float directly, it says:
call of overloaded 'write(float&)' is ambiguous.

If I just try to 'write' an integer like 985, then nothing prints to the serial monitor.

I will worry about speed after I get my code to work.

I figured that since I would be storing a very large volume of data, I might rather use this kind of memory

You figured wrong. Very wrong.

But even if I remove PROGMEM, I still have the same problem.

You may have a problem, but it is not the same problem.

Vague hand-waving helps no-one. If you want help, post the code you're having difficulty with.

From your very first post (on another thread, on another forum section)  Voltages[k - offset_time_int] == voltage;

You've got a problem understanding assignment vs. comparison.

This has been pointed out before.

By now, you should have figured-out that storing to flash memory is not sensible or feasible, so it's time to start specifying what it is you want to achieve, to start defining how to solve that problem.

Cast the float pointer to a byte or char so that write() can handle it.

const int NumFloats = 100;
float MyFloats[NumFloats];


void loop() {
  int StartFloat = 2;
  int NumToWrite = 3;
  Serial.write((byte*)&(MyFloats[StartFloat]), NumToWrite * sizeof(float));
}

This will write the bytes for 3 of the array elements starting at the one numbered 2.

AWOL:
If you want help, post the code you're having difficulty with.

I literally just remove PROGMEM from the code. That's the only modification I make to to the code.

AWOL:
From your very first post (on another thread, on another forum section)

  Voltages[k - offset_time_int] == voltage;

You've got a problem understanding assignment vs. comparison.

This has been pointed out before.

By now, you should have figured-out that storing to flash memory is not sensible or feasible, so it's time to start specifying what it is you want to achieve, to start defining how to solve that problem.

In that case, what are my other options? What are some other methods I can use?

MorganS:
Cast the float pointer to a byte or char so that write() can handle it.

const int NumFloats = 100;

float MyFloats[NumFloats];

void loop() {
 int StartFloat = 2;
 int NumToWrite = 3;
 Serial.write((byte)&(MyFloats[StartFloat]), NumToWrite * sizeof(float));
}




This will write the bytes for 3 of the array elements starting at the one numbered 2.

That gives me the error : "call of overloaded 'write(byte, unsigned int)' is ambiguous"

In that case, what are my other options?

I don't know because I DON'T KNOW WHAT YOU WANT TO DO.

I want to take the voltages and write them in binary on the SD card.

So do it.
Don't make such a big song-and-dance about it.

But I'm getting errors so I need help with that. If you can help me please do! If you don't have the patience to help, please stop posting here as I don't think any of your 7 messages have helped me one bit. They only make me feel stupid(which I may well be but it's not your job to tell me that!). Your over-condescending language does not not help people - it only makes them more confused and nervous.

Thanks! :slight_smile:

There are plenty of examples of how to read an analogue input.
Work through a few.

There are plenty of examples of how to write data to an SD card.
Work through a few.

Hopefully, along the way, you'll learn the difference between an assignment in C and a comparison.
You'll also learn how to cast a pointer to one type to a pointer to another type.

Then, review the code you've got, and compare its performance against your spec, which despite repeated hints, you've failed to post.

Good luck.

I genuinely don't know what you're saying. My code is right on this page in the original post and in Reply #3.