Arduino盾牌,SD卡数据记录器,为什么我的SD卡会死?

时间:2014-02-25 10:23:19

标签: arduino sd-card

我有一个真正烦人的问题,我似乎找不到解决方案。

我创建了一个简单的arduino代码,用于在2个模拟引脚上扫描曲线,由DAC单元控制。扫描是实时完成的,每秒扫描一次,并存储在SD卡中,文件分为几小时。

我的问题是SD卡上的SPI接口在继续使用期间停止响应。 我使用以下arduino mega shield http://pcb.daince.net/doku.php?id=data_logger 和“金士顿MicroSDHC 4GB安全数字卡,66X”存储

我运行了以下代码3天,当我回来时,SPI没有响应(我之前做过1小时测试没有问题,我检查过系统正确更改了文件)

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

//Static definitions 
#define ADG509_A0_pin          39
#define ADG509_A1_pin          38
#define SS_DAC_pin             53
#define voltage_analog_pin     11
#define current_analog_pin     12
#define led                    13
#define DS1307_ADDRESS         0x68
#define chip_select            53

//Adjustable definitions 
#define ADC_to_voltage         1/213 // the value for converting the arduino ADC to voltage
#define number_of_samples      100   //number of measurements, should be able to be divided by 4 without giving decimals
#define time_per_data_set      500   //the delay between datasets in milisecondss, note the the "delay = system_computation_time + time_per_data_set"   
#define current_gain_ratio     2     //the realtion between the voltage level on the pin and current on from the solar pannel
#define voltage_gain_ratio     10  //the realtion between the voltage level on the pin and the voltage level from the solar panel
#define number_samples_per_measurement    5   //the number of ADC readings used to make an average of each measuring point, note this number greatly effects sweeping time
#define delay_per_measurement    1



void set_DAC(float value);           // gets an input between 0.0 and 5.0 and sets the voltage to the value
void write_measurement_to_SD(float current, float voltage, int number);  //writes the numbers to the SD card if initialized
void write_to_file();                //check is a new SD card file should be created and makes it ef nessesary. Also handles the data writing to the file
void get_time();                     //Get the current time of the system, and store them in global variables
int bcdToDec(byte val);              //Converts bytes to decimals numbers 
char intToChar(int val, int number); //Converts integers to chars, only exept up to 2 dicimals

word output_word_for_DAC = 0;        //used to type cast input of set_DAC to word before usage
byte data = 0;                       //temp variable need for DAC, it is the byte send over the communication
float volt;                          //stores a temporary voltage measurement
float current;                       //stores a temporary current measurement
float current_level;                 //stores the short curciut current level, it is used to find the optimal placement for measuring points
char filename[13] = "F0000000.txt";  //stores the current active filename for writing on the SD card
File dataFile;                       //the current version of the datafile on the SD card
int years, months, monthsDay, weekDay, hours, minute, seconds; //global varibles used to store the last time reading
float current_array[number_of_samples]; //used to store all current measurements points during sweep
float voltage_array[number_of_samples]; //used to store all voltage measurements points during sweep
int typecast_int;                    // used for typecasting float to int 
int last_measurement_time;
int is_SDcard_there;

void setup() {   
  pinMode(ADG509_A0_pin, OUTPUT); 
  pinMode(ADG509_A1_pin, OUTPUT);  
  pinMode(SS_DAC_pin, OUTPUT);
  pinMode(led, OUTPUT); 

  digitalWrite(led, LOW);  
  digitalWrite(ADG509_A1_pin, LOW);
  digitalWrite(ADG509_A0_pin, LOW);

  SPI.begin(); // start up the SPI bus
  SPI.setBitOrder(MSBFIRST);

  Wire.begin();
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {;}
  Serial.print("Initializing SD card...");
  if (!SD.begin(chip_select)) {
    Serial.println("Card failed, or not present");
    is_SDcard_there = 0;
    return;+
  }
  Serial.println("card initialized.");
  is_SDcard_there = 1;
}

void loop() {
  //finding the shortcurcuit current of the solar panel
  get_time();
  last_measurement_time = seconds;
  set_DAC(5); //open fet
  delayMicroseconds(1000);
  current_level = analogRead(current_analog_pin);
  for(float counter2 = 0; counter2 < 10; counter2++){
    current_level += analogRead(current_analog_pin);
  }
  current_level = (current_level/10)* 1.1 * ADC_to_voltage;
  //fully opening the fet to insure that the solar pannel is stable at max voltage before beginning the sweep
  set_DAC(0); //ground fet
  delayMicroseconds(10000);  

  if(is_SDcard_there == 1){
    digitalWrite(led, HIGH); 
  } 

  //sweeping the first 80% current on the curve with 25% of the measuring points 
  //note no calculations should be put in here, since it slow the sweep down  
  for(float counter = 0; counter < number_of_samples * 0.25; counter++){ 
    set_DAC((counter*current_level * 0.80) / (number_of_samples * 0.25));
    delayMicroseconds(200);  
    current = analogRead(current_analog_pin);
    volt = analogRead(voltage_analog_pin);
    for(float counter2 = 0; counter2 < number_samples_per_measurement - 1; counter2++){
      current += analogRead(current_analog_pin);
      volt += analogRead(voltage_analog_pin);
    }
    current = current / number_samples_per_measurement;
    volt = volt / number_samples_per_measurement;
    typecast_int = counter;
    current_array[typecast_int] = current;
    voltage_array[typecast_int] = volt;
  }

  //sweeping the last 20% current on the curve with 75% of the measuring points 
  //note no calculations should be put in here, since it slow the sweep down  
  for(float counter = 0; counter < number_of_samples * 0.75; counter++){ 
    set_DAC(current_level * 0.80 + (counter*current_level * 0.20) / (number_of_samples * 0.75));
    delayMicroseconds(200);  
    current = analogRead(current_analog_pin);
    volt = analogRead(voltage_analog_pin);
    for(float counter2 = 0; counter2 < number_samples_per_measurement - 1; counter2++){
      current += analogRead(current_analog_pin);
      volt += analogRead(voltage_analog_pin);
    }
    current = current / number_samples_per_measurement;
    volt = volt / number_samples_per_measurement;
    typecast_int = counter + number_of_samples * 0.25;
    current_array[typecast_int] = current;
    voltage_array[typecast_int] = volt;
  }

  set_DAC(5); //sets DAC high to prepare for next short curcuit measurement 
  digitalWrite(led, LOW); 

  //converting data to desired values and writing them to the file
  String to_write = "";
  int check;
  char buffer[20];
  to_write = "0,0,-2";
  to_write += '\r';
  to_write += '\n';
  to_write += "0,";
  to_write += intToChar(minute,0);
  to_write += intToChar(minute,1);
  to_write += intToChar(seconds,0);
  to_write += intToChar(seconds,1);
  to_write += ",-1";
  to_write += '\r';
  to_write += '\n';

  for(int counter = 0; counter < number_of_samples-1; counter++){
    to_write += dtostrf(current_array[counter] = current_array[counter] * ADC_to_voltage * current_gain_ratio, 0, 2, buffer);
    to_write += ",";
    to_write += dtostrf(voltage_array[counter] = voltage_array[counter] * ADC_to_voltage * voltage_gain_ratio, 0, 2, buffer);
    to_write += ",";
    to_write += counter;
    to_write += '\r';
    to_write += '\n';
  }
  to_write += dtostrf(current_array[99] = current_array[99] * ADC_to_voltage * current_gain_ratio, 0, 2, buffer);
  to_write += ",";
  to_write += dtostrf(voltage_array[99] = voltage_array[99] * ADC_to_voltage * voltage_gain_ratio, 0, 2, buffer);
  to_write += ",99";
  Serial.println(to_write);  //should only be used for debugging since it slow down the system to much

  compute_filename(); //initialize a new filename if needed

  check = 0;
  while(check == 0 && is_SDcard_there == 1){
    dataFile = SD.open(filename,FILE_WRITE);
    check = dataFile.println(to_write);
    if (dataFile){
      dataFile.close();
    }
  } 

  //wait for next seconds      
while(last_measurement_time + delay_per_measurement > seconds){
    get_time(); 
    if(seconds < last_measurement_time){seconds = seconds + 60;}
  }
}

// gets an input between 0.0 and 5.0 and sets the voltage to the value
void set_DAC(float value){
  if(value <= 5){
    value = value*819;    
    int conveter = value;
    output_word_for_DAC = conveter;
    digitalWrite(SS_DAC_pin, LOW);
    data = highByte(output_word_for_DAC);
    data = 0b00001111 & data;
    data = 0b00110000 | data;
    SPI.transfer(data);
    data = lowByte(output_word_for_DAC);
    SPI.transfer(data);
    digitalWrite(SS_DAC_pin, HIGH);
  }
}

//writes the numbers to the SD card if initialized
void write_measurement_to_SD(float current, float voltage, int number){
  dataFile = SD.open(filename,FILE_WRITE);
  dataFile.print(current);
  dataFile.print(',');
  dataFile.print(voltage);
  dataFile.print(',');
  dataFile.print(number);   
  dataFile.println(';');  
  if (dataFile){
    dataFile.close();
  }
}

//Converts bytes to decimals numbers 
int bcdToDec(byte val){
   return ( (val/16*10) + (val%16) );
} 

//Converts integers to chars, only exept up to 2 dicimals
char intToChar(int val, int number){  // note it only take ints with 2 digits
  String tempString = "";
  char returnValue[3];
  if(val < 10){
    tempString += 0;
  }
  tempString += val;
  tempString.toCharArray(returnValue,3);
  return returnValue[number];
}

//Get the current time of the system, and store them in global variables
void get_time(){
   Wire.beginTransmission(DS1307_ADDRESS);
   byte zero = 0x00;
   Wire.write(zero);
   Wire.endTransmission();
   Wire.requestFrom(DS1307_ADDRESS, 7);
   seconds = bcdToDec(Wire.read());
   minute = bcdToDec(Wire.read());
   hours = bcdToDec(Wire.read() & 0b111111); //24 hours time
   weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
   monthsDay = bcdToDec(Wire.read());
   months = bcdToDec(Wire.read());
   years = bcdToDec(Wire.read());
}

//check if the system need a new filename
void compute_filename(){
  get_time();
  filename[1] = intToChar(years,1);
  filename[2] = intToChar(months,0);
  filename[3] = intToChar(months,1);
  filename[4] = intToChar(monthsDay,0);
  filename[5] = intToChar(monthsDay,1);
  filename[6] = intToChar(hours,0);
  filename[7] = intToChar(hours,1);
  if (dataFile){
    dataFile.close();
  }  
}

我知道这是一个很大的代码转储,我很抱歉,但是当我不知道是什么杀死了我的SD卡时,我真的很想减去它。

对此事的任何帮助表示赞赏 我也欢迎任何关于我可以测试以隔离或定位错误的想法

2 个答案:

答案 0 :(得分:1)

可能有两种错误:

1资源泄漏

2 RAM溢出

为1你可以把一些代码写在串行RAM使用evry loop()上,如果那个数字增长,一些库(因为你没有用alloc()分配内存)就会被破坏。对于2,不要构建to_write,而是直接使用Serial.println(),alyas尝试使用数组/字符串wicth使用少于100字节或者你可能有问题(String dinamically分配空间,并且该分配可能会失败..默默地。然后坏事appen)

答案 1 :(得分:1)

在过去的10年里,我已经完成了很多SD卡的工作,我注意到如果在CMD线路中收到垃圾,SD卡很容易变成非响应模式 / em>的。似乎至少某种垃圾被解释为设置卡密码的命令,从而锁定卡。在我使用SD库代码或新硬件设计的那些年里,它已经发生在我身上至少10次了,所以在我看来,它必须是一些容易以某种方式生成的位模式。

我已经能够将(micro)SD卡放入我的旧Symbian手机中,该手机会立即识别该卡被锁定并提供重新格式化卡并重置密码。您可以尝试使用SD卡,以查看您的问题是否与我所遇到的相同。我隐约记得一些便宜的佳能相机也能以类似的方式拯救一些卡。