Go Down

Topic: Reading txt file from SD card and sending over I2C (Read 2612 times) previous topic - next topic

WSUBioE13

Hello!

In my project I am using the microSD card on the arduino ethernet shield with a Mega. What I want to do is transfer the data on the SD card via I2C to another mega (the master). I can write to and read from the SD card using the SD library, and I can send small chunks of analog data (as ints) over I2C, but I can't figure out how to send the data on the SD card over I2C. I know that this should be a fairly easy combination of my other two sketches, but I can't get it to work. I have little experience programming (none using C++), and I suspect the problem is coming from using data types improperly or a discrepancy in the speeds at which the arduino can read the SD card and write to the I2C bus. The data on the SD card is stored in the following format:
timestamp: 543;  Voltage read: 2.61
timestamp: 1055;  Voltage read: 1.89
timestamp: 1566;  Voltage read: 0.19
...
The timestamp will actually be coming from a real time clock, but I thought I should solve this problem first before I add anything else. My first attempt was this code:
Slave:
Quote

#include <SD.h>
#include <Wire.h>

File file;

void setup()
{
  Serial.begin(57600);
  pinMode (53,OUTPUT);
  if (!SD.begin(4)){
    Serial.println("SD not initialized");
  }
  else {
    Serial.println("SD initialized");
  } 
  Wire.begin(2);                // join i2c bus with address #2
  Wire.onRequest(requestEvent); // register event
}

void loop()
{
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  file = SD.open("logdata.txt");
  if(file) {
    Serial.println("File opened");
    while (file.available()>0) {
      Wire.write(file.read());
    }
    Serial.println("Data Sent");
  }
}


Master:
Quote

#include <SPI.h>
#include <Wire.h>

void setup ()
{
  //Open Serial communication
  Serial.begin(57600);
  //Open Wire Communication on I2C and assign the slave an address
  Wire.begin(1);
}

void loop ()
{
  //Send a request for info to device 2
  Wire.requestFrom(2,10);
  Serial.println("Data Requested");
  //Receive data while it's available
  while(Wire.available()) {
    //Receive firt byte as c
    char c = Wire.read();
    //Print c
    Serial.print(c);
    //move to next byte
  }
  delay (500); //wait half a second before sending next request
}



I got "Data Requested ÿÿÿÿÿÿÿÿ" on the master Serial port.
I think the error is in the slave in the "Wire.write(file.read());" line. That was just wishful thinking on my part. So next I tried populating a string with characters as the SD card was read and sending that over I2C, but got the same result. (I can print the string to the slave serial port and get the data off of the card).

Sorry for the long post.

Thank you for your help

SurferTim

I always have trouble with the SD card if I do not disable the w5100 SPI. My mega won't even initialize the card. I get a fail.
Code: [Select]
void setup()
{
  Serial.begin(57600);
  // change this to pin 10
  pinMode (10,OUTPUT);
  // add this
  digitalWrite(10,HIGH);

  if (!SD.begin(4)){
    Serial.println("SD not initialized");
  }
  else {
    Serial.println("SD initialized");
  }

  // rest of your setup
}

WSUBioE13

Thanks for the input, but disabling the w5100 didn't solve the problem. I've now replaced the ethernet shield with the sparkfun microSD Transflash breakout board ( http://www.sparkfun.com/products/544 ) and the problem persists. I have the breakout board wired to the SPI pins, 3.3V power, ground, and am using digital pin 22 as my chip select pin. Just like on the ethernet shield, I can read data from the card and print it to a serial port, but I can't write across the I2C bus. I've stuck with the method of populating an array with data from the card, then sending the array across I2C. This time I printed that array to the serial port for debugging and I'm getting a lot nonsense intermixed with the data on the card. Here is my code.

Code: [Select]
#include <SD.h>
#include <Wire.h>

char* c;
int i = 0;
File file;

void setup()
{
  Serial.begin(57600);    //Begin serial communication
  pinMode (53,OUTPUT);    //Set pin 53 as output for SD lib
  if (!SD.begin(22)){     //Check that SD card is initialized
    Serial.println("SD not initialized");
  }
  else {
    Serial.println("SD initialized");
  }
  file = SD.open("logdata.txt");  //Open file
  if(file) {
    Serial.println("File opened"); 
    while (file.available()>0) {
      c[i]=file.read();
      i=i+1;
    }
    Serial.print(c);
  }
  Wire.begin(2);                // join i2c bus with address #2
  Wire.onRequest(requestEvent); // register event
}

void loop()
{
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.beginTransmission (1);
  Wire.write(c);
  Wire.endTransmission(1);
}

SurferTim

You should declare 'c' as a character array:
Code: [Select]
// instead of this
char* c;
// use this
char c[32];

Insure the c array is large enough to hold the entire file.

Also, if you are planning on using that as a zero terminated string, it would be a good idea to insure it is.
Code: [Select]
   while (file.available()>0) {
      c[i]=file.read();
      i=i+1;
      c[i] = 0;
    }


WSUBioE13

Thanks Tim! Now I'm reading from the SD card properly, but I still can't get anything sent across I2C.I have two megas hooked up on the SDA and SCL pins (and of course there's a ground wire between them as well).  Here's the new slave code: 
Code: [Select]
#include <SD.h>
#include <Wire.h>

char c[100];
int i = 0;
File file;

void setup()
{
  Serial.begin(57600);    //Begin serial communication
  pinMode (53,OUTPUT);    //Set pin 53 as output for SD lib
  if (!SD.begin(22)){     //Check that SD card is initialized
    Serial.println("SD not initialized");
  }
  else {
    Serial.println("SD initialized");
  }
  file = SD.open("logdata.txt");  //Open file
 
  if(file) {
    Serial.println("File opened"); 
    while (file.available()>0) {
      c[i]=file.read();
      i=i+1;
      c[i]=0;
    }
    Serial.print(c);
  }
  Wire.begin(2);                // join i2c bus with address #2
  Wire.onRequest(requestEvent); // register event
}

void loop()
{
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Serial.print("Sending data...");
  Wire.beginTransmission(1);
  Wire.write(c);
  Wire.endTransmission(1);
  Serial.println("...data sent");
}


The master is just the Wire Master Reader example, but giving the master address 1 and changing the requested number of bytes to 100.
Code: [Select]
// Wire Master Reader
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Reads data from an I2C/TWI slave device
// Refer to the "Wire Slave Sender" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

void setup()
{
  Wire.begin(1);        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop()
{
  Wire.requestFrom(2, 100);    // request 6 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  {
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
  }

  delay(500);
}

I don't get anything printing out from the master, and the slave never prints out "Sending data..." so I don't think the event is registering at the slave.

Thanks again!

SurferTim

I'm not real strong on the TWI stuff, but isn't the I2C master set up with no slave address?
Code: [Select]
// master
Wire.begin();
// slave 1
Wire.begin(1);

WSUBioE13

From what I've read and tried, it can be set up with no slave address but doesn't have to be. I did try it with no address for the master, same problem.... If I change the slave code from:
Code: [Select]

void requestEvent()
{
  Serial.print("Sending data...");
  Wire.beginTransmission(1);
  Wire.write(c);
  Wire.endTransmission(1);
  Serial.println("...data sent");
}


to just:

Code: [Select]

void requestEvent()
{
  Serial.print("Sending data...");
  Wire.write(c);
  Serial.println("...data sent");
}


I can get some of the file (17 individual characters) but it quickly stops and I get just the ÿÿÿÿÿÿÿÿ stuff again on the Master. Changing the number of bytes I'm trying to receive to anything above 17 doesn't change the serial output of the master. Below 17 and I just get that number of characters.

Thanks again for your help.

Go Up