SD Card File Transfer from Arduino Uno to PC via EZ Link Bluetooth

Hello,

After hours of frustrating research, I am looking for some help. I have an Arduino Uno with a mounted SD card, and I am trying to view the text files on a PC running Windows 7 via a Bluefruit EZ Link Shield (link). I have been successful in pairing the shield/Arduino with my PC as I can wirelessly upload codes. I also have been able to use the following code, which uses an inputted number (1 or 0) in the serial monitor to turn on/off the LED on the Arduino.

// REMIXED BY: TECHBITAR (HAZIM BITAR)
// LICENSE: PUBLIC DOMAIN
// DATE: MAY 2, 2012
// CONTACT: techbitar at gmail dot com

char INBYTE;
int  LED = 13; // LED on pin 13

void setup() {
  Serial.begin(9600); 
  pinMode(LED, OUTPUT);
}

void loop() {
  Serial.println("Press 1 to turn Arduino pin 13 LED ON or 0 to turn it OFF:");
  while (!Serial.available());   // stay here so long as COM port is empty   
  INBYTE = Serial.read();        // read next available byte
  if( INBYTE == '0' ) digitalWrite(LED, LOW);  // if it's a 0 (zero) tun LED off
  if( INBYTE == '1' ) digitalWrite(LED, HIGH); // if it's a 1 (one) turn LED on
  delay(50);
}

I am attempting to work with Gobetwino to transfer these files, but it is not as easy as I thought it would be. I am looking to transfer text files from the SD card to the PC via Bluetooth. I would prefer to open the file with notepad or wordpad, and not in Arduino. I am able to open these files while in the Arduino program.

Thank you for any help you can offer.
Nikki

You should need no more than the FileDump programme included in the IDE to do this. You appear to be au fait with bluetooth data transfer, so now it’s just a matter of sensibly handling the file names, and having Arduino recognise the command.

Below uses the date to name the files. Strip out what you don’t need. The file dumps are simply included in the continuous data stream to a phone. If you are only interested in files, I guess the “continuous data stream” has no content but files, and the terminal log can contain several.

/*
This programme reads temperatures from  three DS18B20 sensors at one 
second intervals.

The temperatures are displayed on Nokia 5110 LCD  

Two of the temperatures, plus the difference between them, is transmitted 
over bluetooth in a format suitable for BlueTooth Terminal/Graphics (CETIN)
in order to display three graphs in real time.

Every tenth reading is recorded on SD card in real numbers to two decimal
places. Each line is timestamped.

A new file is created at midnight using the date as the filename.

Daily files can be read via bluetooth by sending MMDD

Credit to Hacktronics, Mellis & Igoe, Garage Box, Zoomkat, Bildr.org, etc.
Kudos to lar3ry in Saskatchewan, Stanley in KL, Coding Badly in Tx.
*/

#include <OneWire.h>
#include <DallasTemperature.h>
#include <PCD8544.h>             // Nokia 5110
#include "Wire.h"                // MUST HAVE lib for LCD disp, SD card
#include <SD.h>
#include <SPI.h>                 // SD

#define DS1307_ADDRESS 0x68

char filename[] = "00000000.CSV";
File myFile;
char dumpName[] = "00000000.CSV";
File dumpFile;

static PCD8544 lcd;

// Custom symbols
static const byte DEGREES_CHAR = 1;
static const byte degrees_glyph[] = { 0x00, 0x07, 0x05, 0x07, 0x00 };
static const byte SLASH_CHAR = 2;
static const byte slash_glyph[] = {0x00,0x20,0x10,0x08};

// Green group Dee Why SERVICE
byte InThermo[8] =  {0x28, 0x69, 0xC2, 0xB0, 0x03, 0x00, 0x00, 0x9F };
byte OutThermo[8] = {0x28, 0x7A, 0x8B, 0xC0, 0x03, 0x00, 0x00, 0x2F};
byte DrainThermo[8] = {0x28, 0x54, 0xF7, 0x2D, 0x04, 0x00, 0x00, 0x68}; 
byte ShrThermo[8] = {0x28, 0x09, 0xA9, 0xC0, 0x03, 0x00, 0x00, 0x95};  

#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
 
byte  second, minute, hour, weekDay, day, month, year;
int k=0;

const int chipSelect = 4;

float tempC, InTemp, OutTemp, DrainTemp, ShrTemp, Rise, Fall; 

// Define the strings for our datastream IDs
char sensorId0[] = "InThermo";
char sensorId1[] = "OutThermo";
char sensorId2[] = "DrainThermo";
char sensorId3[] = "ShrThermo";
char strIn[8];
char strOut[8];
char strDrain[8];
char strRise[8];
char strFall[8];
char charBuf [15];

String readString;
String stringOne, stringTwo, stringThree, stringFour;
String stringFive, stringSix;

//_________________________________________

void setup() {
  lcd.begin(84, 48);
     // Register the custom symbols...
  lcd.createChar(DEGREES_CHAR, degrees_glyph);
  lcd.createChar(SLASH_CHAR, slash_glyph);
  
  Wire.begin();
  Serial.begin(9600);
  
  delay(300);//Wait for newly restarted system to stabilize

  lcd.setCursor (0,0);
  lcd.println("Init SD CARD");
  // make sure that the default chip select pin 53 is set to
  // output, even if you don't use it:
  pinMode(53, OUTPUT);//MEGA
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) 
  {
    lcd.println("Card failed");
    // don't do anything more:
    return;
  }
  lcd.println("CARD OK");
  delay(2000);
      GetClock();
      getFileName();
  lcd.setCursor(0,2); 
      lcd.println(filename);
        
  lcd.setCursor(5,4);
      lcd.print(hour);
      lcd.print(":");
      lcd.print(minute);
      lcd.print(":");
      lcd.print(second);
      lcd.print("   ");
      lcd.print(day);
        delay(3000);
  
    lcd.clear();
        
  //Sequence for bluetooth
  // "E256,-321,982\n" 
  //so insert three variable between four strings, two are the same twice, 
  //to make a fourth string 
  
  stringOne = "E";
  stringTwo = ",";
  stringThree = "\n";

    running();
  }
//________________________________________________________________

void loop() {
   GetClock();
  if (hour == 0 && minute == 0 && second <2)
  {
    getFileName();
  }
  
    while (Serial.available()) 
  {
    delay(3);  
    char c = Serial.read();
    readString += c; 
  }// end while

  if (readString.length() >0) 
  {  
    getDump();   
   readString="";  
   } // end if
  
  //get the values from the DS8B20's 
  sensors.requestTemperatures();

  InTemp = sensorValue(InThermo);
  OutTemp = sensorValue(OutThermo);  
  DrainTemp = sensorValue(DrainThermo); 
  ShrTemp = sensorValue(ShrThermo);

  Rise = OutTemp - InTemp;
  Fall = ShrTemp - DrainTemp;
  
dtostrf(InTemp,4, 2, strIn);
dtostrf(OutTemp,4, 2, strOut);
dtostrf(Rise,4, 2, strRise);
dtostrf(Fall,4, 2, strFall);

stringFour = stringOne + strIn + stringTwo + strOut;
stringFour = stringFour + stringTwo + strRise + stringThree;

  Serial.println(stringFour);

  lcd.setCursor(42,0);
  lcd.print(InTemp);
  lcd.setCursor(42,1);
  lcd.print (OutTemp);
  lcd.setCursor(42,2);
  lcd.print(DrainTemp);
  lcd.setCursor(42,3);
if (Rise<10.0)
  {
  lcd.print(" ");
  }
  lcd.print(Rise); 
  lcd.setCursor(42,4);\
  lcd.print (ShrTemp);  
  lcd.setCursor(42,5);
if (Fall<10.0)
  {
  lcd.print(" ");
  }
  lcd.print (Fall);

  k=k+1;  

  if (k>9 )
  {  
       myFile = SD.open(filename, FILE_WRITE);//<<<<<<<<<<<<<<<< OPEN
  myFile.print(hour);
  myFile.print(":");
  myFile.print(minute);
  myFile.print(":");
  myFile.print(second);
  myFile.print(",");

  myFile.print(InTemp);
  myFile.print(",");
  myFile.print(OutTemp);
  myFile.print(",");
  myFile.print(DrainTemp);
  myFile.print(",");
  myFile.print(ShrTemp);
  myFile.println();
       myFile.close();//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>CLOSE     
      k=0;
  }
  delay(850);
}  // loop ends here

//sensorValue function
float sensorValue (byte deviceAddress[])
{
  tempC = sensors.getTempC (deviceAddress);
  return tempC;
}

byte bcdToDec(byte val)  {
  // Convert binary coded decimal to normal decimal bers
  return ( (val/16*10) + (val%16) );
}

void running(){
  lcd.setCursor(0,0);
  lcd.print("In");
  lcd.setCursor(73,0);
  lcd.print("\001C");
  lcd.setCursor(0,1);
  lcd.print("Out");
  lcd.setCursor(73,1);
  lcd.print("\001C");
  lcd.setCursor(0,2);
  lcd.print("Drain");
  lcd.setCursor(73,2);
  lcd.print("\001C");
  lcd.setCursor(0,3);
  lcd.print("rise");
  lcd.setCursor(73,3);
  lcd.print("\001C"); 
  lcd.setCursor(0,4);
  lcd.print("Shr");  
  lcd.setCursor(73,4);
  lcd.print("\001C"); 
  lcd.setCursor(0,5);
  lcd.print("fall");  
  lcd.setCursor(73,5);
  lcd.print("\001C"); 
}

void getFileName(){
sprintf(filename, "%02d%02d%02d.csv", year, month, day);
}

void GetClock(){
  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);

  second = bcdToDec(Wire.read());
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  day = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}

void getDump() {
   stringSix = "2015" + readString + ".csv";
   stringSix.toCharArray(charBuf, 15);  
     Serial.println("");
     Serial.println(charBuf);
  File dumpFile = SD.open(charBuf);
  if (dumpFile) 
  {
    lcd.clear();
      lcd.setCursor (0,1);
      lcd.println("DUMP FROM ");
      lcd.setCursor (0,2);
      lcd.println(charBuf);
    while (dumpFile.available())
    {
      Serial.write(dumpFile.read());
    }
    dumpFile.close();
      lcd.clear();
      running();
  }  
  else {
    Serial.println("error opening file");
       }
}

Thank you for your reply! I have the DumpFile working, but I am looking to open/save the transferred files in notepad or wordpad, not through the Arduino serial monitor. I am thinking that this way, I can view multiple files side by side instead of having to re-code to look at a new file each time. I am still looking at the code you provided me, and once I make progress with that, I will come back with updates!

Nikki

I don't think you can transfer the files, only the contents therein. I guess this is a limitation of the SD library, and you may be able to do it with a more sophisticated library, but I'm not sure there is any need for that.

The serial monitor is pretty useless, and not designed for this purpose. Any proper terminal programme can receive the dump to a logfile, and that can be subsequently opened in Notepad. I use RealTerm but they are all much the same.

There should never be a need to "recode". You just need two-way traffic over bluetooth. As you can see, I just send MMDD.

Thank you, Nick. I am just exploring the capabilities of Arduino, and I see how this would not work. I will look into other options, such as the RealTerm that you mentioned. If I figure out a way, I will be sure to post it here.

Thank you for your help,
Nikki

As an update: I am using an example code from GoBetwino for LogFile, which records three random numbers, sends them through the serial port (in my case via Bluetooth) and saves them in a text file on the laptop. Now to figure out if I can merge the DumpFile code with this one to have successful file transfer!

The Arduino code for this feature of GoBetwino is below, where CPTEST and LOGTEST are command names created in GoBetwino. In those commands, I select a text file to write the created data to.

// This sketch demonstrates the use of the Gobetwino commandtypes LGFIL and CPFIL

int serInLen = 25;
char serInString[25];
int logValue1=0;
int logValue2=0;
int logValue3=0;
int result;

void setup() 
{ 
  // Setup serial comm. Initialize random function.
  Serial.begin(9600); 
  randomSeed(analogRead(0));
  delay(5000); 
  // Use the CPTEST copy file command to make a copy of a new empty logfile
  Serial.println("#S|CPTEST|[]#");
  readSerialString(serInString,1000);
  // There ought to be a check here for a non 0 return value indicating an error and some error handling
} 
 
void loop() 
{ 
   //Create some random values to log to a file on the PC.  This could be sensor readings or whatever
   //but for this example it's just 3 random values
   logValue1= random(0,1000);
   logValue2= random(0,1000);
   logValue3= random(0,1000);
   logData(logValue1,logValue2,logValue3);
   delay(500); 
}

// Send the LOGTEST command to Gobetwino the 3 random values are separated by semicolons
 
void logData( int value1, int value2, int value3) 
{
   char buffer[5];
  
   Serial.print("#S|LOGTEST|[");
   Serial.print(itoa((value1), buffer, 10));
   Serial.print(";");
   Serial.print(itoa((value2), buffer, 10));
   Serial.print(";");
   Serial.print(itoa((value3), buffer, 10));
   Serial.println("]#");
   readSerialString(serInString,1000);
   // There ought to be a check here for a non 0 return value indicating an error and some error handeling
} 

//read a string from the serial and store it in an array
//you must supply the array variable - return if timeOut ms passes before the sting is read
void readSerialString (char *strArray,long timeOut) 
{
   long startTime=millis();
   int i;

   while (!Serial.available()) {
      if (millis()-startTime >= timeOut) {
         return;
      }
   }
   while (Serial.available() && i < serInLen) {
      strArray[i] = Serial.read();
      i++;
   }
}

I am attempting to merge this code with the DumpFile code so I can select a preexisting file from my SD card. Any suggestions as I go along with this?

Thanks!
Nikki

I'm afraid not. At the risk of sounding like a spoiler, I found Gobetweeno simply more trouble than it's worth, and the lack of traffic concerning it on this forum may also reflect that.

The code posted above does more or less what you describe - except that it does it with (gasp!) real numbers from real sensors.

  1. It sends data out via bluetooth each second for view as a live graph on the phone
    2, Every tenth read goes to SD, with timestamp
  2. A new file is made every day and dated
  3. Files on SD can be downloaded over bluetooth. I use a phone, but RealTerm could do the same thing. The data eventually lands up in Excel.

It is probably easier to add dumpfile to the main programme. It is essentially a self-contained module but you do need to inquire for an incoming signal in the loop, as shown above.

That is unfortunate…Well thank you anyway!

Nikki

I got it! I was just revisiting this idea the other day, and below is my code. All I have to do now is convert the ASCII characters into regular numbers, but that should be easy compared to the rest! What I did was merged a portion of the DumpFile and changed the Serial.write to a Serial.print. From there, I named an int, data1, to be dataFile.read(); so that GoBetwino could handle the multiple lines. Next, to convert out of ASCII!

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

const uint8_t chipSelect = 10;

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

  if (!SD.begin(chipSelect)) {
    return;
  }
  File dataFile = SD.open("data.txt");

  Serial.print("#S|TEST|[");
  if (dataFile) {
    while (dataFile.available()) {
      int data1 = dataFile.read();
      Serial.print(data1);
    }
    dataFile.close();
    Serial.println("]#");
    delay(2000);
  }
}

void loop()
{
}

OK, as I said, you seem to be fine with data transfer, so I guess the ASCII was the problem all along. I don’t know why you are in ASCII in the first place. Maybe that has something to do with the type of data recorded.

NikkiS:
I got it! I was just revisiting this idea the other day, and below is my code. All I have to do now is convert the ASCII characters into regular numbers, but that should be easy compared to the rest! What I did was merged a portion of the DumpFile and changed the Serial.write to a Serial.print. From there, I named an int, data1, to be dataFile.read(); so that GoBetwino could handle the multiple lines. Next, to convert out of ASCII!

#include <SPI.h>

#include <SD.h>

const uint8_t chipSelect = 10;

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

if (!SD.begin(chipSelect)) {
    return;
  }
  File dataFile = SD.open(“data.txt”);

Serial.print("#S|TEST|[");
  if (dataFile) {
    while (dataFile.available()) {
      int data1 = dataFile.read();
      Serial.print(data1);
    }
    dataFile.close();
    Serial.println("]#");
    delay(2000);
  }
}

void loop()
{
}

This will give to a new file in SD card what about your original question of viewing data in pc?