sending data from serial moniter and saving it on the sd card

Hi,
I'm currently sending serial data[uart to serial] from a different micro controller to arduino uno. This is because of limitations of the other microcontroller.

I am able to see the output on the serial monitor on arduino side but the sd card saves it in a random way. Can anyone suggest me what might be wrong with the codes?

I have attached two codes, one with only uart output and the other with sd card code as well.

SerialEventuart.ino (1.26 KB)

SerialEventbasic.ino (1.97 KB)

If your code does not exceed the 9000 character limit, you will get a lot more people looking at your code if you post the code as described in the how to use this forum sticky.

Thank you for your suggestion. Here is the code.

#include <SPI.h>
#include <SD.h>
#define BUFFERSIZE 512
const int chipSelect = 10;
char inputString[101];
String buff= "";
uint8_t inputStringLength = 0;
bool stringComplete = false;  // whether the string is complete
File dataFile;
void setup() {
    pinMode(10,OUTPUT);
  // initialize serial:
  Serial.begin(9600);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
   return;
  }
  Serial.println("card initialized.");
  dataFile = SD.open("ami.txt", FILE_WRITE);
   if( ! dataFile ) {
    int i = millis() + 5000; // 5 seconds
    Serial.println("Card write failed!  Halted...");
      } else {
      Serial.println(F("Writing to: europa.txt")); 
      Serial.println(F("Ready to accept serial data..."));
    }
}
void loop() {
  if (Serial.available()>0) {
    // get the new byte:
   inputString[inputStringLength++] = Serial.read();
  // print the string when a newline arrives:
  if (inputString [inputStringLength] != '\n'||inputStringLength>=BUFFERSIZE-1) {
     inputString[inputStringLength]='\n';
     buff+=inputString;
     //dataFile.write((uint8_t *)inputString,inputStringLength);
     //dataFile.println();
   //Serial.print(inputString);
   //dataFile.flush();
   inputStringLength=0;
   
    if(dataFile){
      dataFile.print(buff);
     // dataFile.flush();
      buff="";
    }
    }
    }
    
   }

Does this code do what you want? It will take a long string and put it into a file on the SD card called "test.txt".

There are problems with doing it this way. It uses the String class which, if misused, can cause memory trouble and the readString() function blocks so the processor is tied up until the String is completely read.

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

const byte csSD = 10;

File myFile;

void setup()
{
   Serial.begin(115200);
   initSD();
}

void loop()
{
   if (Serial.available())
   {
      String incoming = Serial.readString();
      myFile = SD.open("test.txt", FILE_WRITE);
      if (myFile)
      {
         Serial.print("Writing to test.txt...");
         myFile.println(incoming);         
         myFile.close();
         Serial.println("done.");
      }
      else
      {
         // if the file didn't open, print an error:
         Serial.println("error opening test.txt");
      }
   }
}

void initSD()
{
   Serial.print("Initializing SD card...");
   if (!SD.begin(csSD))
   {
      Serial.println("initialization failed!");
      while (1);
   }
   Serial.println("initialization done.");
}

Better would be to read the incoming data into a cstring (small s string) using non blocking techniques like is shown in the serial input basics tutorial. If you have control of the format of the data being sent, you can add start and end markers to make reception more robust. You read in the entire string (make the input buffer big enough) and then send to the SD card.

No, it doesnt print anything onto the sd card.

The code I wrote actually prints out the string based on the end marker only. , yet it prints out random chunks of data.

I know that your posted code does not write to the SD card. I am also aware that your code does not work. I was trying to provide code that does what is in the title of the post. Have you tried the posred code? Is the code that i posted of any use?

If you do try tha posted code, make sure that the line endings in serial monitor is set to CR and LF.

groundFungus:
I know that your posted code does not write to the SD card. I am also aware that your code does not work. I was trying to provide code that does what is in the title of the post. Have you tried the posred code? Is the code that i posted of any use?

If you do try tha posted code, make sure that the line endings in serial monitor is set to CR and LF.

Thank you for helping me out. The code you posted doesn't work ofr me either. It just shows a blank file. No output can be seen in the serial monitor other than Intitialization done.

I'm sending the following from another microcontroller:

sprintf(msg, "\r%d.%d\t%d.%d,\n", finalVal,tempintval, finalVal,tempintval);

which sends constant values of "-256.6 -256.6" to serial monitor

The code you posted doesn't work ofr me either. It just shows a blank file. No output can be seen in the serial monitor other than Intitialization done.

Sorry, I should have made it clear that you should enter a string of data in the serial monitor to be sent to the SD card. So as soon as you see "initialization done.", enter some data in the serial monitor and send the data. The data should be put into the test.txt file on the SD card. I have a SD module connected to my Uno and the sketch works as described.

I'm sending the following from another microcontroller:

How is the other microcontroller connected to the receiving Arduino? Hardware serial? If so, you can't use serial monitor to view the data as only one thing can be connected to a serial port at a time.

Please stop using an unsound method of reading in data and transferring the char array to a String.

You have control over the sent data. Use as '<' start marker and '>' end marker and follow exactly the procedure of receive with start and end markers shown in the previously referenced tutorial Serial Input Basics.

If using those methods leaves you with unwritten data to the SD card, you will receive plenty of additional help, but we won't need to be focused on the data input.

groundFungus:
Sorry, I should have made it clear that you should enter a string of data in the serial monitor to be sent to the SD card. So as soon as you see "initialization done.", enter some data in the serial monitor and send the data. The data should be put into the test.txt file on the SD card. I have a SD module connected to my Uno and the sketch works as described.

Yes, It works now.

groundFungus:
How is the other microcontroller connected to the receiving Arduino? Hardware serial? If so, you can't use serial monitor to view the data as only one thing can be connected to a serial port at a time.

I'm connecting it to Rx on arduino(Hardware serial).

OK the SD card works. Now we can concentrate on reading the data from the other controller properly.

I agree with cattledog (as I said in my reply#3) that it would be best to frame the data with start ("<") and end (">") markers and read it in as a null terminated character array (string, small s) as shown in the serial input basics tutorial.

To be able to use the serial monitor for debug, you will have to connect the other processor to a different serial port, like a software serial port or use a Mega (or other Arduino with multiple hardware serial ports) for the receiving Arduino.

cattledog:
Please stop using an unsound method of reading in data and transferring the char array to a String.

You have control over the sent data. Use as '<' start marker and '>' end marker and follow exactly the procedure of receive with start and end markers shown in the previously referenced tutorial Serial Input Basics.

If using those methods leaves you with unwritten data to the SD card, you will receive plenty of additional help, but we won't need to be focused on the data input.

Hi,

when i try to print single chars, I get a lot of vacant spaces. I dont know why these are occurring.

when i try to print single chars, I get a lot of vacant spaces. I dont know why these are occurring.

If you don't post your code, we don't know why as well.

cattledog:
If you don't post your code, we don't know why as well.

Here is my original code:

#define BUFFERSIZE 512
char inputString[101];
String buff= "";
uint8_t k = 0;
int values;
uint8_t inputStringLength = 0;
bool stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
 // inputString.reserve(200);
}

void loop() {
  if (Serial.available()>0) {
    // get the new byte:
   inputString[inputStringLength++] = Serial.read();
  
  // print the string when a newline arrives:
  if (inputString [inputStringLength] != '\n'||inputStringLength>=BUFFERSIZE-1) {
     inputString[inputStringLength]=0;
     buff=inputString;
  // Serial.flush();
   inputStringLength=0;
    }
    }
    Serial.print(buff);
    buff="";
   }

and here is the code that im using for serial basics:

// Example 1 - Receiving single characters

char receivedChar;
boolean newData = false;

void setup() {
   Serial.begin(9600);
   Serial.println("<Arduino is ready>");
}

void loop() {
   recvOneChar();
   showNewData();
}

void recvOneChar() {
   if (Serial.available() > 0) {
       receivedChar = Serial.read();
       newData = true;
   }
}

void showNewData() {
   if (newData == true) {
       Serial.print("This just in ... ");
       Serial.println(receivedChar);
       newData = false;
   }
}

I even tried to print a single character and the output still is the same. But when i use the char to string conversion, i get the output without any issues. However, the sd card saves randomly organized data.

when i try to print single chars, I get a lot of vacant spaces. I don't know why these are occurring.

What are you entering into the serial monitor? Are you sending any newline or carriage returns?

There is a little pull down box on the lower rught of the monitor window next to the baud rate box. Set this for No line ending.

cattledog:
What are you entering into the serial monitor? Are you sending any newline or carriage returns?

There is a little pull down box on the lower rught of the monitor window next to the baud rate box. Set this for No line ending.

The single character code works when i type anything on serial port.

But, I am sending data from another microcontroller and I would like to see its output on serial port of arduino. When i connect rx of arduino to tx of another microcontroller, I get a lot of vacant spaces.

1 Like

But, I am sending data from another microcontroller and I would like to see its output on serial port of arduino. When i connect rx of arduino to tx of another microcontroller, I get a lot of vacant spaces.

If you don't have an Arduino with multiple hardware serial ports, you will have to use software serial between the sender and the Arduino if you want to use the Serial monitor with the Arduino to debug what is going on.

Here is my best effort to illustrate the advice given to you. Namely, send the data with start and end markers, use a software serial port* on the Uno to receive the data and use the methods from the serial input basics to receive the data to be written to SD card. The code has been tested using 2 Unos connected by software serial.

This sketch is just to send sample data to the Uno with the SD card attached. It shows how the data packet is formed and sent.

// program to transmit sample test data to another Uno to be written to
// an SD card.
// by C. Goulding

#include <SoftwareSerial.h>

SoftwareSerial ssPort(7, 4);

const int BUFFER_SIZE = 32;

int value1 = 26;
int value2 = 15;

void setup()
{
   Serial.begin(115200);
   ssPort.begin(9600);
   Serial.println(F("starting test data transmission"));
   delay(3000);
}

void loop()
{
  static unsigned long timer = 0;
  unsigned long interval = 2000;
  if(millis() - timer >= interval)
  {
    timer = millis();
    char buffer[BUFFER_SIZE];
    sprintf(buffer, "<%d.%d,%d.%d,%lu>", value1, value2, value1, value2, millis());
    Serial.print(F("Transmitting  "));
    Serial.print(buffer);
    ssPort.println(buffer);
    Serial.println(F("   ****** transmission complete"));
  }
}

This sketch receives the data through a software serial port on pins 4 and 7. Each time that it receives a full packet it writes the packet to SD card.

// program to receive test data Iinto a null termnated character
// array (string) and write the string to a SD card
// using methods from Robin2's serial input basics
// by C. Goulding

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

const byte csSD = 10;

File testDataFile;
SoftwareSerial ssPort(4, 7);

const byte numChars = 32; //**** adjust this number for the longest data set
                          // can be up to 255.
char receivedChars[numChars];
boolean newData = false;  // true whenever new data comes in
                          // must be set to false before new data can be read
void setup()
{
   Serial.begin(115200);
   ssPort.begin(9600);
   initSD();
   Serial.println(F("starting test data reception"));
   delay(3000);
}

void loop()
{
   recvWithStartEndMarkers();  // get new data if it is there
   if (newData == true) // got new data, save it to SD
   {
      Serial.print(F("This data just received   "));
      Serial.println(receivedChars);
      testDataFile = SD.open("test.txt", FILE_WRITE);
      if (testDataFile)
      {
         Serial.print(F("Writing to test.txt..."));
         testDataFile.println(receivedChars);
         testDataFile.close();
         Serial.println(F("done."));
      }
      else
      {
         Serial.println(F(" $$$$$ error opening test.txt $$$$"));
      }
      newData = false;  // OK ready for more data
   }
}

void recvWithStartEndMarkers()
{
   static boolean recvInProgress = false;
   static byte ndx = 0;
   char startMarker = '<';
   char endMarker = '>';
   char rc;

   while (ssPort.available() > 0 && newData == false)
   {
      rc = ssPort.read();

      if (recvInProgress == true)
      {
         if (rc != endMarker)
         {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars)
            {
               ndx = numChars - 1;
            }
         }
         else
         {
            receivedChars[ndx] = '\0'; // terminate the string
            recvInProgress = false;
            ndx = 0;
            newData = true;
         }
      }
      else if (rc == startMarker)
      {
         recvInProgress = true;
      }
   }
}

void initSD()
{
   Serial.print(F("Initializing SD card..."));
   if (!SD.begin(csSD))
   {
      Serial.println(F("############ initialization failed! ########"));
      while (1);
   }
   Serial.println(F("initialization done."));
}

Maybe you can get some ideas from this that will help with your project.

  • There are "better" software serial libraries, but I use SoftwareSerial, here, because it is simplest and comes with the IDE.

groundFungus:
Here is my best effort to illustrate the advice given to you. Namely, send the data with start and end markers, use a software serial port* on the Uno to receive the data and use the methods from the serial input basics to receive the data to be written to SD card. The code has been tested using 2 Unos connected by software serial.

This sketch is just to send sample data to the Uno with the SD card attached. It shows how the data packet is formed and sent.

// program to transmit sample test data to another Uno to be written to

// an SD card.
// by C. Goulding

#include <SoftwareSerial.h>

SoftwareSerial ssPort(7, 4);

const int BUFFER_SIZE = 32;

int value1 = 26;
int value2 = 15;

void setup()
{
  Serial.begin(115200);
  ssPort.begin(9600);
  Serial.println(F("starting test data transmission"));
  delay(3000);
}

void loop()
{
  static unsigned long timer = 0;
  unsigned long interval = 2000;
  if(millis() - timer >= interval)
  {
    timer = millis();
    char buffer[BUFFER_SIZE];
    sprintf(buffer, "<%d.%d,%d.%d,%lu>", value1, value2, value1, value2, millis());
    Serial.print(F("Transmitting  "));
    Serial.print(buffer);
    ssPort.println(buffer);
    Serial.println(F("  ****** transmission complete"));
  }
}




This sketch receives the data through a software serial port on pins 4 and 7. Each time that it receives a full packet it writes the packet to SD card.


// program to receive test data Iinto a null termnated character
// array (string) and write the string to a SD card
// using methods from Robin2's serial input basics
// by C. Goulding

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

const byte csSD = 10;

File testDataFile;
SoftwareSerial ssPort(4, 7);

const byte numChars = 32; //**** adjust this number for the longest data set
                          // can be up to 255.
char receivedChars[numChars];
boolean newData = false;  // true whenever new data comes in
                          // must be set to false before new data can be read
void setup()
{
  Serial.begin(115200);
  ssPort.begin(9600);
  initSD();
  Serial.println(F("starting test data reception"));
  delay(3000);
}

void loop()
{
  recvWithStartEndMarkers();  // get new data if it is there
  if (newData == true) // got new data, save it to SD
  {
      Serial.print(F("This data just received  "));
      Serial.println(receivedChars);
      testDataFile = SD.open("test.txt", FILE_WRITE);
      if (testDataFile)
      {
        Serial.print(F("Writing to test.txt..."));
        testDataFile.println(receivedChars);
        testDataFile.close();
        Serial.println(F("done."));
      }
      else
      {
        Serial.println(F(" $$$$$ error opening test.txt $$$$"));
      }
      newData = false;  // OK ready for more data
  }
}

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

while (ssPort.available() > 0 && newData == false)
  {
      rc = ssPort.read();

if (recvInProgress == true)
      {
        if (rc != endMarker)
        {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars)
            {
              ndx = numChars - 1;
            }
        }
        else
        {
            receivedChars[ndx] = '\0'; // terminate the string
            recvInProgress = false;
            ndx = 0;
            newData = true;
        }
      }
      else if (rc == startMarker)
      {
        recvInProgress = true;
      }
  }
}

void initSD()
{
  Serial.print(F("Initializing SD card..."));
  if (!SD.begin(csSD))
  {
      Serial.println(F("############ initialization failed! ########"));
      while (1);
  }
  Serial.println(F("initialization done."));
}




Maybe you can get some ideas from this that will help with your project.

* There are "better" software serial libraries, but I use SoftwareSerial, here, because it is simplest and comes with the IDE.

Thank you for the code. I will execute it and inform you about it. However, Can I declare the multiple TX,RX for arduino UNO? So if i declare two digital pins using software serial, will it be used as TX and RX? I wanted to confirm it with you.