Datalogging using MCP3208

Hi
I am using MCP3208 as an external adc and writing its data onto sd card. On the first iteration of loop , i get the right voltage values but afterwards i am getting wrong values.

Here is my code and circuit diagram

Any kind of help would be appreciated

mcp3208.ino (3.7 KB)

Use of Strings with Arduino causes memory errors and eventually, program crashes. Get rid of them.

To test whether that String-induced errors are responsible for the current problem, write a simple program that just monitors the ADC and prints the result on the serial monitor, without using String objects.

OP's code, posted properly:

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

RTC_DS1307 RTC;




#define SELPIN 10 //Selection Pin 
#define DATAOUT 11//MOSI 
#define DATAIN  12//MISO 
#define SPICLOCK  13//Clock 
#define aref_voltage 5
#define chipSelect  9//CS for Sd card is PB1 or PIN 9

//const int chipSelect = 9;   //DIGITAL PIN 9(PB1) AS CHIP SELECT OF SD CARD
float readvalue,voltage0,voltage1,voltage2,voltage3,voltage4,voltage5; 

void setup(){ 
 //set pin modes 
 pinMode(SELPIN, OUTPUT); 
pinMode(chipSelect, OUTPUT);
 pinMode(DATAOUT, OUTPUT); 
 pinMode(DATAIN, INPUT); 
 pinMode(SPICLOCK, OUTPUT); 

 //pinMode(8,OUTPUT);
 //disable device to start with 
 
 digitalWrite(SELPIN,HIGH); 
 digitalWrite(DATAOUT,LOW); 
 digitalWrite(SPICLOCK,LOW);
 


 Serial.begin(9600); 
 Wire.begin();
RTC.begin();

// following line sets the RTC to the date & time this sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
/*
  Serial.print("Initializing SD card...");

  // 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:
    while (1);
  }
  Serial.println("card initialized.");
  */
}


float read_adc(int channel){
  int adcvalue = 0;
  byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3)

  //allow channel selection
  commandbits|=((channel-1)<<3);

  digitalWrite(SELPIN,LOW); //Select adc
  // setup bits to be written
  for (int i=7; i>=3; i--){
    digitalWrite(DATAOUT,commandbits&1<<i);
    //cycle clock
    digitalWrite(SPICLOCK,HIGH);
    digitalWrite(SPICLOCK,LOW);    
  }

  digitalWrite(SPICLOCK,HIGH);    //ignores 2 null bits
  digitalWrite(SPICLOCK,LOW);
  digitalWrite(SPICLOCK,HIGH);  
  digitalWrite(SPICLOCK,LOW);

  //read bits from adc
  for (int i=11; i>=0; i--){
    adcvalue+=digitalRead(DATAIN)<<i;
    //cycle clock
    digitalWrite(SPICLOCK,HIGH);
    digitalWrite(SPICLOCK,LOW);
  }
  digitalWrite(SELPIN, HIGH); //turn off device
  return adcvalue;
}

void(*resetFunc)(void)=0;

void loop() { 
 


DateTime now = RTC.now();
int day = now.day();
int month = now.month();
int year = now.year();
int hour = now.hour();
int minute = now.minute();
int second = now.second();
 String slash = "/";
 String colon = ":";
 String date = day + slash + month + slash + year;
 String Time = hour + colon + minute + colon + second;
 Serial.println(date); 
 Serial.println(Time);
  
   readvalue = read_adc(0); 
   voltage0 = (aref_voltage*readvalue)/4096;
// Serial.println(voltage0);
  readvalue = read_adc(1); 
voltage1 = (aref_voltage*readvalue)/4096;
// Serial.println(voltage1);
 readvalue = read_adc(2); 
voltage2 = (aref_voltage*readvalue)/4096;
// Serial.println(voltage2);
 readvalue = read_adc(3); 
voltage3 = (aref_voltage*readvalue)/4096;
// Serial.println(voltage3);
 readvalue = read_adc(4); 
voltage4 = (aref_voltage*readvalue)/4096;
 //Serial.println(voltage4);
 readvalue = read_adc(5); 
voltage5 = (aref_voltage*readvalue)/4096;
//Serial.println(voltage5);
// Serial.println(" "); 

 String dataString ="";
 dataString += String(voltage0);
  dataString += ",";
 dataString += String(voltage1);
  dataString += ",";
 dataString += String(voltage2);
  dataString += ",";
 dataString += String(voltage3); 
 dataString += ",";
 dataString += String(voltage4);
  dataString += ",";
 dataString += String(voltage5);
  dataString += ",";
  Serial.println(dataString);
  

 SD.begin(chipSelect);
   File dataFile = SD.open("FDR.csv", FILE_WRITE);
   
     // if the file is available, write to it:
  if (dataFile)
  {

    dataFile.println(Time);
    
    dataFile.println(date);

    dataFile.println(dataString);
   
   dataFile.close();
    
  
  }
 
 digitalWrite(chipSelect,LOW);
 delay(250); 
 
}

i have tried that....when i disable sd card operation, adc gives correct output values but i have to perform datalogging essentially

You do not have to use Strings for data logging. You NEVER have to use Strings for anything else, either.

Also removed the strings and only monitored the data serially.......still the same problem

Post your code, with code tags, and describe the problem as clearly as you can.

What device is connected to pin 0 and 1, or is that just a representation of the USB serial monitor.
What is VREF connected to.
What battery voltage, and is it connected to something low impedance.
Leo..

Here is the code

//This code performs datalogging of an external adc on sd card
//MCP3208 is used for reading 6 analog channels
//This data is then appended in string named dataString
//dataString alongwith time and date are logged in a csv file

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

RTC_DS1307 RTC;




#define SELPIN 10 //Selection Pin 
#define DATAOUT 11//MOSI 
#define DATAIN  12//MISO 
#define SPICLOCK  13//Clock 
#define aref_voltage 5
#define chipSelect  9//CS for Sd card is PB1 or PIN 9


float readvalue,voltage0,voltage1,voltage2,voltage3,voltage4,voltage5; 

void setup(){ 
 //set pin modes 
 pinMode(SELPIN, OUTPUT); 
pinMode(chipSelect, OUTPUT);
 pinMode(DATAOUT, OUTPUT); 
 pinMode(DATAIN, INPUT); 
 pinMode(SPICLOCK, OUTPUT); 


 //disable device to start with 
 
 digitalWrite(SELPIN,HIGH); 
 digitalWrite(DATAOUT,LOW); 
 digitalWrite(SPICLOCK,LOW);
 


 Serial.begin(9600); 
 Wire.begin();
RTC.begin();

// following line sets the RTC to the date & time this sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));

}


float read_adc(int channel){
  int adcvalue = 0;
  byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3)

  //allow channel selection
  commandbits|=((channel-1)<<3);
  digitalWrite(chipSelect,LOW);
  digitalWrite(SELPIN,LOW); //Select adc
  // setup bits to be written
  for (int i=7; i>=3; i--){
    digitalWrite(DATAOUT,commandbits&1<<i);
    //cycle clock
    digitalWrite(SPICLOCK,HIGH);
    digitalWrite(SPICLOCK,LOW);    
  }

  digitalWrite(SPICLOCK,HIGH);    //ignores 2 null bits
  digitalWrite(SPICLOCK,LOW);
  digitalWrite(SPICLOCK,HIGH);  
  digitalWrite(SPICLOCK,LOW);

  //read bits from adc
  for (int i=11; i>=0; i--){
    adcvalue+=digitalRead(DATAIN)<<i;
    //cycle clock
    digitalWrite(SPICLOCK,HIGH);
    digitalWrite(SPICLOCK,LOW);
  }
  digitalWrite(SELPIN, HIGH); //turn off device
  return adcvalue;
}



void loop() { 
 


DateTime now = RTC.now();
int day = now.day();
int month = now.month();
int year = now.year();
int hour = now.hour();
int minute = now.minute();
int second = now.second();
 String slash = "/";
 String colon = ":";
 String date = day + slash + month + slash + year;
 String Time = hour + colon + minute + colon + second;
 Serial.println(date); 
 Serial.println(Time);


  //reading adc
   readvalue = read_adc(0); 
   voltage0 = (aref_voltage*readvalue)/4096;
Serial.println(voltage0);
  readvalue = read_adc(1); 
voltage1 = (aref_voltage*readvalue)/4096;
 Serial.println(voltage1);
 readvalue = read_adc(2); 
voltage2 = (aref_voltage*readvalue)/4096;
 Serial.println(voltage2);
 readvalue = read_adc(3); 
voltage3 = (aref_voltage*readvalue)/4096;
 Serial.println(voltage3);
 readvalue = read_adc(4); 
voltage4 = (aref_voltage*readvalue)/4096;
Serial.println(voltage4);
 readvalue = read_adc(5); 
voltage5 = (aref_voltage*readvalue)/4096;
Serial.println(voltage5);
Serial.println(" "); 


//appending adc values to datastring
 String dataString ="";
 dataString += String(voltage0);
  dataString += ",";
 dataString += String(voltage1);
  dataString += ",";
 dataString += String(voltage2);
  dataString += ",";
 dataString += String(voltage3); 
 dataString += ",";
 dataString += String(voltage4);
  dataString += ",";
 dataString += String(voltage5);
  dataString += ",";
  Serial.println(dataString);
  

 SD.begin(chipSelect);      //SD card initialize
 
 File dataFile = SD.open("FDR.csv", FILE_WRITE);    //create file and perform write func
   
     // if the file is available, write to it:
  if (dataFile)
  {

    dataFile.println(Time);
    
    dataFile.println(date);

    dataFile.println(dataString);
   
   dataFile.close();
    
  
  }
 
 digitalWrite(chipSelect,LOW);    //disable SD card
 delay(250); 
 
}

Wawa:
What device is connected to pin 0 and 1, or is that just a representation of the USB serial monitor.
What is VREF connected to.
What battery voltage, and is it connected to something low impedance.
Leo..

At pin 0 and 1, it is a serial monitor
Vref is connected to 5V
"What battery voltage, and is it connected to something low impedance.?"--i dont undersatand what u are saying

Pin 0 and 1 are internally connected to the USB<>Serial chip of the Uno and shouldn't be used for anything else.
Use SoftwareSerial on two different pins if you are using a second/external serial device.

The (potentially dirty) 5volt supply pin of an Uno is not really suitable as voltage reference for a 12-bit A/D.
What are you trying to measure.

The inputs of an A/D must be connected to something solid (>= 10k impedance).
Floating pins will return random values.
Leo..

Wawa:
Pin 0 and 1 are internally connected to the USB<>Serial chip of the Uno and shouldn't be used for anything else.
Use SoftwareSerial on two different pins if you are using a second/external serial device.

The (potentially dirty) 5volt supply pin of an Uno is not really suitable as voltage reference for a 12-bit A/D.
What are you trying to measure.

The inputs of an A/D must be connected to something solid (>= 10k impedance).
Floating pins will return random values.
Leo..

voltage reference for a 12-bit A/D is not 5 V supply pin of uno. A separate dc voltage source is actually the reference which is named as Vref. The input pins of ADC are connected to a dc voltage source of 3.7V named as U1 (in blue color). It is just for simulation and checking whether i am getting correct values. I still dont inderstand what do you mean by "The inputs of an A/D must be connected to something solid (>= 10k impedance).Floating pins will return random values."

I still dont inderstand what do you mean by

Time to do some reading. Start by googling "floating inputs".

Strings are still in your code, waiting to crash it. What don't you understand about the phrase "get rid of them"?

//appending adc values to datastring
 String dataString ="";
 dataString += String(voltage0);
  dataString += ",";
 dataString += String(voltage1);
  dataString += ",";
 dataString += String(voltage2);
  dataString += ",";
 dataString += String(voltage3);
 dataString += ",";
 dataString += String(voltage4);
  dataString += ",";
 dataString += String(voltage5);
  dataString += ",";
  Serial.println(dataString);

i tested the code without strings but the problem was still the same. I know about the floating inputs but i don't think the input is "floating" because i have connected a dc voltage supply to it. Anyways i have posted the code without strings

//This code performs datalogging of an external adc on sd card
//MCP3208 is used for reading 6 analog channels
//This data is then appended in string named dataString
//dataString alongwith time and date are logged in a csv file

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

RTC_DS1307 RTC;




#define SELPIN 10 //Selection Pin 
#define DATAOUT 11//MOSI 
#define DATAIN  12//MISO 
#define SPICLOCK  13//Clock 
#define aref_voltage 5
#define chipSelect  9//CS for Sd card is PB1 or PIN 9


float readvalue,voltage0,voltage1,voltage2,voltage3,voltage4,voltage5; 

void setup(){ 
 //set pin modes 
 pinMode(SELPIN, OUTPUT); 
 pinMode(chipSelect, OUTPUT);
 pinMode(DATAOUT, OUTPUT); 
 pinMode(DATAIN, INPUT); 
 pinMode(SPICLOCK, OUTPUT); 


 //disable device to start with 
 
 digitalWrite(SELPIN,HIGH); 
 digitalWrite(DATAOUT,LOW); 
 digitalWrite(SPICLOCK,LOW);
 


 Serial.begin(9600); 
 Wire.begin();
 RTC.begin();

// following line sets the RTC to the date & time this sketch was compiled
 RTC.adjust(DateTime(__DATE__, __TIME__));

}


  float read_adc(int channel)
{
  int adcvalue = 0;
  byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3)

  //allow channel selection
  commandbits|=((channel-1)<<3);
  digitalWrite(chipSelect,LOW);
  digitalWrite(SELPIN,LOW); //Select adc
  // setup bits to be written
  for (int i=7; i>=3; i--){
  digitalWrite(DATAOUT,commandbits&1<<i);
  //cycle clock
  digitalWrite(SPICLOCK,HIGH);
  digitalWrite(SPICLOCK,LOW);  
    
}

  digitalWrite(SPICLOCK,HIGH);    //ignores 2 null bits
  digitalWrite(SPICLOCK,LOW);
  digitalWrite(SPICLOCK,HIGH);  
  digitalWrite(SPICLOCK,LOW);

  //read bits from adc
  for (int i=11; i>=0; i--){
  adcvalue+=digitalRead(DATAIN)<<i;
  //cycle clock
  digitalWrite(SPICLOCK,HIGH);
  digitalWrite(SPICLOCK,LOW);
  }
  digitalWrite(SELPIN, HIGH); //turn off device
  return adcvalue;
}



void loop() { 
 


DateTime now = RTC.now();
int day = now.day();
int month = now.month();
int year = now.year();
int hour = now.hour();
int minute = now.minute();
int second = now.second();
 //String slash = "/";
 //String colon = ":";
 //String date = day + slash + month + slash + year;
 //String Time = hour + colon + minute + colon + second;
 Serial.println(day); 
 Serial.println(month);
 Serial.println(year);

  //reading adc
   readvalue = read_adc(0); 
   voltage0 = (aref_voltage*readvalue)/4096;
Serial.println(voltage0);
  readvalue = read_adc(1); 
voltage1 = (aref_voltage*readvalue)/4096;
 Serial.println(voltage1);
 readvalue = read_adc(2); 
voltage2 = (aref_voltage*readvalue)/4096;
 Serial.println(voltage2);
 readvalue = read_adc(3); 
voltage3 = (aref_voltage*readvalue)/4096;
 Serial.println(voltage3);
 readvalue = read_adc(4); 
voltage4 = (aref_voltage*readvalue)/4096;
Serial.println(voltage4);
 readvalue = read_adc(5); 
voltage5 = (aref_voltage*readvalue)/4096;
Serial.println(voltage5);
Serial.println(" "); 

/*
//appending adc values to datastring
 String dataString ="";
 dataString += String(voltage0);
  dataString += ",";
 dataString += String(voltage1);
  dataString += ",";
 dataString += String(voltage2);
  dataString += ",";
 dataString += String(voltage3); 
 dataString += ",";
 dataString += String(voltage4);
  dataString += ",";
 dataString += String(voltage5);
  dataString += ",";
  Serial.println(dataString);
 */ 

 SD.begin(chipSelect);      //SD card initialize
 
 File dataFile = SD.open("FDR.csv", FILE_WRITE);    //create file and perform write func
   
     // if the file is available, write to it:
  if (dataFile)
  {

    //dataFile.println(Time);
    
    //dataFile.println(date);

    dataFile.println("This is a test");
   
   dataFile.close();
    
  
  }
 
 digitalWrite(chipSelect,LOW);    //disable SD card
 delay(250); 
 
}

Take out the SD card stuff and try again.

It is a very bad idea to open the SD file every time through the loop() function. Open it once in setup() and close it when you are done logging.

jremington:
Take out the SD card stuff and try again.

It is a very bad idea to open the SD file every time through the loop() function. Open it once in setup() and close it when you are done logging.

I took out the sd.begin and sd.open from loop and put it in the setup but it had the same results. As far as i can understand, the problem is that sd card and mcp3208 share the same spi lines. Therefore, in the code, when only mcp3208 is working, correct output is shown but when sdcard initialises, may be it creates problem for the mcp3208???

That is a good point. Some SD cards are known to not properly share the bus.

And you are not using the SPI hardware for the MPC3208 anyway! You can't mix hardware and software SPI on the same pins.

Just use any other available pins for the MCP3208.

Or, you can do data logging to a microSD card very easily with just a serial connection, using the Sparkfun Openlog. I've been using the OpenLog for years and strongly recommend them.

jremington:
That is a good point. Some SD cards are known to not properly share the bus.

And you are not using the SPI hardware for the MPC3208 anyway! You can't mix hardware and software SPI on the same pins.

Just use any other available pins for the MCP3208.

Or, you can do data logging to a microSD card very easily with just a serial connection, using the Sparkfun Openlog. I've been using the OpenLog for years and strongly recommend them.

But i am using different chipselect for sd card and mcp3208. Thats what differentiate them. When one device is on the other is disable. There must be something wrong in the code

You cannot use the SPI pins for normal I/O when they are being used by the SPI hardware.

How can i disable my sd card ? I mean what is the command? I tried by pulling the chipSelect pin high and low but it doesn't affect sd card operation.

How can i disable my sd card ?

By disconnecting it from the SPI pins, and removing the SD library and calls.

The solution to your problem was posted in reply #15. Use other pins for the ADC.