2012-11-25 88 views
0

我用下面的硬件元素有一些非常奇怪的問題不兼容:SD.h與Arduino的/ C++其他圖書館環境

我想根據需要將傳感器讀數卸載到SD卡上,但在我編寫SD功能之前,只包含SD.h庫會使我的代碼無用。

我的代碼如下:

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

/* This sample code demonstrates the normal use of a TinyGPS object. 
    It requires the use of SoftwareSerial, and assumes that you have a 
    4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx). 
*/ 

//For baraometer 
#include <Wire.h> 

#define BMP085_ADDRESS 0x77 // I2C address of BMP085 

const unsigned char OSS = 2; // Oversampling Setting 

// Calibration values 
int ac1; 
int ac2; 
int ac3; 
unsigned int ac4; 
unsigned int ac5; 
unsigned int ac6; 
int b1; 
int b2; 
int mb; 
int mc; 
int md; 

// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...) 
// So ...Temperature(...) must be called before ...Pressure(...). 
long b5; 
//End of baraometer 

//ACcelerometer 
// These constants describe the pins. They won't change: 
const int xpin = A1;     // x-axis of the accelerometer 
const int ypin = A2;     // y-axis 
const int zpin = A3;     // z-axis (only on 3-axis models) 
//end of accel 

TinyGPS gps; 
SoftwareSerial nss(3, 4); 

static void gpsdump(TinyGPS &gps); 
static bool feedgps(); 
static void print_float(float val, float invalid, int len, int prec); 
static void print_int(unsigned long val, unsigned long invalid, int len); 
static void print_date(TinyGPS &gps); 
static void print_str(const char *str, int len); 

void setup() 
{ 
    //Make sure the analog-to-digital converter takes its reference voltage from 
    // the AREF pin 
    analogReference(EXTERNAL); 

    pinMode(xpin, INPUT); 
    pinMode(ypin, INPUT); 
    pinMode(zpin, INPUT); 

    //Barometer 
    Wire.begin(); 
    bmp085Calibration(); 

    //GPS 
    Serial.begin(115200); 
    nss.begin(57600); 

    Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version()); 
    Serial.println("by Mikal Hart"); 
    Serial.println(); 
    Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS)); 
    Serial.println(); 
    Serial.println("Sats HDOP Latitude Longitude Fix Date  Time  Date Alt  Course Speed Card Distance Course Card Chars Sentences Checksum"); 
    Serial.println("   (deg) (deg)  Age      Age (m)  --- from GPS ---- ---- to London ---- RX RX  Fail"); 
    Serial.println("--------------------------------------------------------------------------------------------------------------------------------------"); 
} 

void loop() 
{ 
    //Accelerometer 
    Serial.print(analogRead(xpin)); 
    Serial.print("\t"); 

    //Add a small delay between pin readings. I read that you should 
    //do this but haven't tested the importance 
    delay(1); 

    Serial.print(analogRead(ypin)); 
    Serial.print("\t"); 
    //add a small delay between pin readings. I read that you should 
    //do this but haven't tested the importance 
    delay(1); 

    Serial.print(analogRead(zpin)); 
    Serial.print("\n"); // delay before next reading: 






    bool newdata = false; 
    unsigned long start = millis(); 

    // Every second we print an update 
    while (millis() - start < 1000) 
    { 
    if (feedgps()) 
     newdata = true; 
    } 


    //barometer 
    float temperature = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first 
    float pressure = bmp085GetPressure(bmp085ReadUP()); 
    float atm = pressure/101325; // "standard atmosphere" 
    float altitude = calcAltitude(pressure); //Uncompensated caculation - in Meters 

    Serial.print("Temperature: "); 
    Serial.print(temperature, 2); //display 2 decimal places 
    Serial.println(" C"); 

    Serial.print("Pressure: "); 
    Serial.print(pressure, 0); //whole number only. 
    Serial.println(" Pa"); 

    Serial.print("Standard Atmosphere: "); 
    Serial.println(atm, 4); //display 4 decimal places 

    Serial.print("Altitude: "); 
    Serial.print(altitude, 2); //display 2 decimal places 
    Serial.println(" M"); 

    Serial.println();//line break 
    //end of barometer 



    gpsdump(gps); 
} 

static void gpsdump(TinyGPS &gps) 
{ 
    float flat, flon; 
    unsigned long age, date, time, chars = 0; 
    unsigned short sentences = 0, failed = 0; 
    static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002; 

    print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5); 
    print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5); 
    gps.f_get_position(&flat, &flon, &age); 
    print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5); 
    print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5); 
    print_int(age, TinyGPS::GPS_INVALID_AGE, 5); 

    print_date(gps); 

    print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2); 
    print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2); 
    print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2); 
    print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6); 
    print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON)/1000, 0xFFFFFFFF, 9); 
    print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2); 
    print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6); 

    gps.stats(&chars, &sentences, &failed); 
    print_int(chars, 0xFFFFFFFF, 6); 
    print_int(sentences, 0xFFFFFFFF, 10); 
    print_int(failed, 0xFFFFFFFF, 9); 
    Serial.println(); 
} 

static void print_int(unsigned long val, unsigned long invalid, int len) 
{ 
    char sz[32]; 
    if (val == invalid) 
    strcpy(sz, "*******"); 
    else 
    sprintf(sz, "%ld", val); 
    sz[len] = 0; 
    for (int i=strlen(sz); i<len; ++i) 
    sz[i] = ' '; 
    if (len > 0) 
    sz[len-1] = ' '; 
    Serial.print(sz); 
    feedgps(); 
} 

static void print_float(float val, float invalid, int len, int prec) 
{ 
    char sz[32]; 
    if (val == invalid) 
    { 
    strcpy(sz, "*******"); 
    sz[len] = 0; 
     if (len > 0) 
      sz[len-1] = ' '; 
    for (int i=7; i<len; ++i) 
     sz[i] = ' '; 
    Serial.print(sz); 
    } 
    else 
    { 
    Serial.print(val, prec); 
    int vi = abs((int)val); 
    int flen = prec + (val < 0.0 ? 2 : 1); 
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1; 
    for (int i=flen; i<len; ++i) 
     Serial.print(" "); 
    } 
    feedgps(); 
} 

static void print_date(TinyGPS &gps) 
{ 
    int year; 
    byte month, day, hour, minute, second, hundredths; 
    unsigned long age; 
    gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age); 
    if (age == TinyGPS::GPS_INVALID_AGE) 
    Serial.print("******* ******* "); 
    else 
    { 
    char sz[32]; 
    sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ", 
     month, day, year, hour, minute, second); 
    Serial.print(sz); 
    } 
    print_int(age, TinyGPS::GPS_INVALID_AGE, 5); 
    feedgps(); 
} 

static void print_str(const char *str, int len) 
{ 
    int slen = strlen(str); 
    for (int i=0; i<len; ++i) 
    Serial.print(i<slen ? str[i] : ' '); 
    feedgps(); 
} 

static bool feedgps() 
{ 
    while (nss.available()) 
    { 
    if (gps.encode(nss.read())) 
     return true; 
    } 
    return false; 
} 

// Stores all of the bmp085's calibration values into global variables 
// Calibration values are required to calculate temp and pressure 
// This function should be called at the beginning of the program 
void bmp085Calibration() 
{ 
    Serial.write("\n\nCalibrating ... "); 
    ac1 = bmp085ReadInt(0xAA); 
    ac2 = bmp085ReadInt(0xAC); 
    ac3 = bmp085ReadInt(0xAE); 
    ac4 = bmp085ReadInt(0xB0); 
    ac5 = bmp085ReadInt(0xB2); 
    ac6 = bmp085ReadInt(0xB4); 
    b1 = bmp085ReadInt(0xB6); 
    b2 = bmp085ReadInt(0xB8); 
    mb = bmp085ReadInt(0xBA); 
    mc = bmp085ReadInt(0xBC); 
    md = bmp085ReadInt(0xBE); 
    Serial.write("Calibrated\n\n"); 
} 

// Calculate temperature in deg C 
float bmp085GetTemperature(unsigned int ut){ 
    long x1, x2; 

    x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15; 
    x2 = ((long)mc << 11)/(x1 + md); 
    b5 = x1 + x2; 

    float temp = ((b5 + 8)>>4); 
    temp = temp /10; 

    return temp; 
} 

// Calculate pressure given up 
// calibration values must be known 
// b5 is also required so bmp085GetTemperature(...) must be called first. 
// Value returned will be pressure in units of Pa. 
long bmp085GetPressure(unsigned long up){ 
    long x1, x2, x3, b3, b6, p; 
    unsigned long b4, b7; 

    b6 = b5 - 4000; 
    // Calculate B3 
    x1 = (b2 * (b6 * b6)>>12)>>11; 
    x2 = (ac2 * b6)>>11; 
    x3 = x1 + x2; 
    b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2; 

    // Calculate B4 
    x1 = (ac3 * b6)>>13; 
    x2 = (b1 * ((b6 * b6)>>12))>>16; 
    x3 = ((x1 + x2) + 2)>>2; 
    b4 = (ac4 * (unsigned long)(x3 + 32768))>>15; 

    b7 = ((unsigned long)(up - b3) * (50000>>OSS)); 
    if (b7 < 0x80000000) 
    p = (b7<<1)/b4; 
    else 
    p = (b7/b4)<<1; 

    x1 = (p>>8) * (p>>8); 
    x1 = (x1 * 3038)>>16; 
    x2 = (-7357 * p)>>16; 
    p += (x1 + x2 + 3791)>>4; 

    long temp = p; 
    return temp; 
} 

// Read 1 byte from the BMP085 at 'address' 
char bmp085Read(byte address) 
{ 
    Wire.beginTransmission(BMP085_ADDRESS); 
    Wire.write(address); 
    Wire.endTransmission(); 
    Wire.requestFrom(BMP085_ADDRESS, 1); 
    while(!Wire.available()) {}; 
    return Wire.read(); 
} 

// Read 2 bytes from the BMP085 
// First byte will be from 'address' 
// Second byte will be from 'address'+1 
int bmp085ReadInt(byte address) 
{ 
    unsigned char msb, lsb; 

    Wire.beginTransmission(BMP085_ADDRESS); 
    Wire.write(address); 
    Wire.endTransmission(); 

    Wire.requestFrom(BMP085_ADDRESS, 2); 
    while(Wire.available()<2) 
    ; 
    msb = Wire.read(); 
    lsb = Wire.read(); 

    return (int) msb<<8 | lsb; 
} 

// Read the uncompensated temperature value 
unsigned int bmp085ReadUT(){ 
    unsigned int ut; 

    // Write 0x2E into Register 0xF4 
    // This requests a temperature reading 
    Wire.beginTransmission(BMP085_ADDRESS); 
    Wire.write((byte)0xF4); 
    Wire.write((byte)0x2E); 
    Wire.endTransmission(); 

    // Wait at least 4.5 ms 
    delay(5); 

    // Read two bytes from registers 0xF6 and 0xF7 
    ut = bmp085ReadInt(0xF6); 
    return ut; 
} 

// Read the uncompensated pressure value 
unsigned long bmp085ReadUP(){ 
    unsigned char msb, lsb, xlsb; 
    unsigned long up = 0; 

    // Write 0x34+(OSS<<6) into register 0xF4 
    // Request a pressure reading w/ oversampling setting 
    Wire.beginTransmission(BMP085_ADDRESS); 
    Wire.write(0xF4); 
    Wire.write(0x34 + (OSS<<6)); 
    Wire.endTransmission(); 

    // Wait for conversion, delay time dependent on OSS 
    delay(2 + (3<<OSS)); 

    // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB) 
    msb = bmp085Read(0xF6); 
    lsb = bmp085Read(0xF7); 
    xlsb = bmp085Read(0xF8); 

    up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS); 

    return up; 
} 

void writeRegister(int deviceAddress, byte address, byte val) { 
    Wire.beginTransmission(deviceAddress); // Start transmission to device 
    Wire.write(address);  // Send register address 
    Wire.write(val);   // Send value to write 
    Wire.endTransmission(); // End transmission 
} 

int readRegister(int deviceAddress, byte address){ 
    int v; 
    Wire.beginTransmission(deviceAddress); 
    Wire.write(address); // Register to read 
    Wire.endTransmission(); 

    Wire.requestFrom(deviceAddress, 1); // Read a byte 

    while(!Wire.available()) { 
    // waiting 
    } 

    v = Wire.read(); 
    return v; 
} 

float calcAltitude(float pressure){ 

    float A = pressure/101325; 
    float B = 1/5.25588; 
    float C = pow(A,B); 
    C = 1 - C; 
    C = C /0.0000225577; 

    return C; 
} 

誠然,現在,它只是多個例子草圖的聚集,但他們的工作。我從加速度計,GPS單元和氣壓計獲取採樣讀數,每秒一次。但是,一旦我簡單地將#include <SD.h>行添加到草圖中,它將無法正確運行。串行監視器不顯示任何內容。我有上述草圖的類似版本(省略,因爲它們更長),但我得到了相同的結果:無論是混亂的文本或串口監視器上沒有。如果我註釋掉包含SD.h庫的行,一切正常。......

存在已知的SD.h庫問題或衝突嗎?是的,我不使用的SD訪問所需的引腳(數字引腳#4)我的傳感器連接....

UPDATE:

我至少想通了,它有什麼做的SoftSerial(SoftSerial.h)庫以及使用SoftSerial對象(我稱之爲nss)。如果我不打電話給nss.begin,我可以加載所有庫,並讓所有工作都可以工作。這有什麼矛盾的原因嗎?

回答

2

原來我內存不足。讓串行無響應是一種常見症狀。這最終是我用來追蹤和結束我的記憶問題。

0

第一件事是檢查Arduino網站,在SD文檔(here)有該microcontrollerSD card之間的通信使用SPI(文檔here)一提起這發生在digital pins111213。如果這是您的Serial顯示器問題的根源,我不會感到驚訝。

閱讀在Sd2Card.h一些意見,可能會非常棘手,讓您的設置才能正常工作:

/** 
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos. 
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13. 
* 
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used 
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1 
* but many SD cards will fail with GPS Shield V1.0. 
*/ 

即使你把MEGA_SOFT_SPI一個非0值,你可能還是不及格(defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))檢查。

我建議嘗試使用沒有TinyGPS的相同草圖來查明問題。

另外,檢查出this sketch它似乎在做類似於你正在做的事情,也許你可以根據這裏做的事情來修復你的問題。

+0

「兆豐Arduinos」在註釋中是指在特定的Arduino基於ATmega1280或ATmega2560 CPU的套件。所以沒有 - 當然這是行不通的。 – duskwuff

+0

引腳11,12和13未使用,所以不能這樣做。雖然我注意到我使用WiFi Shield,它也使用11,12和13針作爲自己的用途,但我使用的SD卡內置在WiFi Shield中。然而,請注意,我甚至沒有使用SD卡本身(還沒有得到那麼多),但只是加載庫... – WildBill

+0

@WildBill我懷疑是'sd.h'或它包含的文件'sdfat .h'或'sdfatutil.h''#define'一個與你的其他庫混淆的值。您是否嘗試更改'#include'命令? – emartel

0

爲CS使用PIN 4,改變在Sd2card.h圖書館SD的MOSI,MISO和SCK,希望你能擺脫問題