2

Adafriut BMP085に接続されたRaspberry Piを使用して科学プロジェクト用の気球を送信し、C コードを使用して高度の読み取り値を記録および保存します。唯一の問題は、現在一度しか記録されないことです。実行時に必要です。高度を記録し、テキスト ファイルに 30 分ごとに約 24 時間ほど保存します。コードはすぐ下にあります。

コードを自由にコピーして、パラメーターを付けて再アップロードしてください。よろしくお願いします。

#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdlib.h>

#include <unistd.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include "smbus.h" 

#define BMP085_I2C_ADDRESS 0x77

const unsigned char BMP085_OVERSAMPLING_SETTING = 3;

// Calibration values - These are stored in the BMP085
short int ac1;
short int ac2; 
short int ac3; 
unsigned short int ac4;
unsigned short int ac5;
unsigned short int ac6;
short int b1; 
short int b2;
short int mb;
short int mc;
short int md;

int b5; 

unsigned int temperature, pressure, altitude;


// Open a connection to the bmp085
// Returns a file id
int bmp085_i2c_Begin()
{
   int fd;
   char *fileName = "/dev/i2c-0";

   // Open port for reading and writing
   if ((fd = open(fileName, O_RDWR)) < 0)
      exit(1);

   // Set the port options and set the address of the device
   if (ioctl(fd, I2C_SLAVE, BMP085_I2C_ADDRESS) < 0) {               
      close(fd);
      exit(1);
   }

   return fd;
}

// Read two words from the BMP085 and supply it as a 16 bit integer
__s32 bmp085_i2c_Read_Int(int fd, __u8 address)
{
   __s32 res = i2c_smbus_read_word_data(fd, address);
   if (res < 0) {
      close(fd);
      exit(1);
   }

   // Convert result to 16 bits and swap bytes
   res = ((res<<8) & 0xFF00) | ((res>>8) & 0xFF);

   return res;
}

//Write a byte to the BMP085
void bmp085_i2c_Write_Byte(int fd, __u8 address, __u8 value)
{
   if (i2c_smbus_write_byte_data(fd, address, value) < 0) {
      close(fd);
      exit(1);
   }
}

// Read a block of data BMP085
void bmp085_i2c_Read_Block(int fd, __u8 address, __u8 length, __u8 *values)
{
   if(i2c_smbus_read_i2c_block_data(fd, address,length,values)<0) {
      close(fd);
      exit(1);
   }
}


void bmp085_Calibration()
{
   int fd = bmp085_i2c_Begin();
   ac1 = bmp085_i2c_Read_Int(fd,0xAA);
   ac2 = bmp085_i2c_Read_Int(fd,0xAC);
   ac3 = bmp085_i2c_Read_Int(fd,0xAE);
   ac4 = bmp085_i2c_Read_Int(fd,0xB0);
   ac5 = bmp085_i2c_Read_Int(fd,0xB2);
   ac6 = bmp085_i2c_Read_Int(fd,0xB4);
   b1 = bmp085_i2c_Read_Int(fd,0xB6);
   b2 = bmp085_i2c_Read_Int(fd,0xB8);
   mb = bmp085_i2c_Read_Int(fd,0xBA);
   mc = bmp085_i2c_Read_Int(fd,0xBC);
   md = bmp085_i2c_Read_Int(fd,0xBE);
   close(fd);
}

// Read the uncompensated temperature value
unsigned int bmp085_ReadUT()
{
   unsigned int ut = 0;
   int fd = bmp085_i2c_Begin();

   // Write 0x2E into Register 0xF4
   // This requests a temperature reading
   bmp085_i2c_Write_Byte(fd,0xF4,0x2E);

   // Wait at least 4.5ms
   usleep(5000);

   // Read the two byte result from address 0xF6
   ut = bmp085_i2c_Read_Int(fd,0xF6);

   // Close the i2c file
   close (fd);

   return ut;
}

// Read the uncompensated pressure value
unsigned int bmp085_ReadUP()
{
   unsigned int up = 0;
   int fd = bmp085_i2c_Begin();

   // Write 0x34+(BMP085_OVERSAMPLING_SETTING<<6) into register 0xF4
   // Request a pressure reading w/ oversampling setting
   bmp085_i2c_Write_Byte(fd,0xF4,0x34 + (BMP085_OVERSAMPLING_SETTING<<6));

   // Wait for conversion, delay time dependent on oversampling setting
   usleep((2 + (3<<BMP085_OVERSAMPLING_SETTING)) * 1000);

   // Read the three byte result from 0xF6
   // 0xF6 = MSB, 0xF7 = LSB and 0xF8 = XLSB
   __u8 values[3];
   bmp085_i2c_Read_Block(fd, 0xF6, 3, values);

   up = (((unsigned int) values[0] << 16) | ((unsigned int) values[1] << 8) | (unsigned int) values[2]) >> (8-BMP085_OVERSAMPLING_SETTING);

   return up;
}

// Calculate pressure given uncalibrated pressure
// Value returned will be in units of XXXXX
unsigned int bmp085_GetPressure(unsigned int up)
{
   int x1, x2, x3, b3, b6, p;
   unsigned int b4, b7;

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

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

   b7 = ((unsigned int)(up - b3) * (50000>>BMP085_OVERSAMPLING_SETTING));
   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;

   return p;
}

// Calculate temperature given uncalibrated temperature
// Value returned will be in units of 0.1 deg C
unsigned int bmp085_GetTemperature(unsigned int ut)
{
   int x1, x2;

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

   unsigned int result = ((b5 + 8)>>4);  

   return result;
}

// This Altitude part is stolen from some some unknown
// Arduino library.  The number divided into pressure for
// float A is derived from the local pressure as explained
// at http://learn.adafruit.com/bmp085/using-the-bmp085.
unsigned int bmp085_Altitude(float pressure)
{
   float A = pressure/101794.58;
   float B = 1/5.25588;
   float C = pow(A,B);
   C = 1 - C;
   C = C / 0.0000225577;

   return C;
}



int main(int argc, char **argv)

{

   bmp085_Calibration();

   temperature = bmp085_GetTemperature(bmp085_ReadUT());
   pressure = bmp085_GetPressure(bmp085_ReadUP());
        altitude = bmp085_Altitude(pressure);

   printf("Temperature\t%0.1f *F\n", ((double)temperature)/10 * 1.8 + 32);
   printf("Pressure\t%0.2f hPa\n", ((double)pressure)/100);
        printf("Altitude\t%0.1f Feet\n", ((double)altitude)*3.280839895);

   return 0;
}
4

2 に答える 2

2

MAIN()ルーチンにループがないようです。30分ごとにデータを記録したいので、MAINを連続してループさせたいと思います。

私は Raspberry PI についてはあまり知りませんが、Arduino については知っていますが、メイン エントリ ポイント ルーチンは自動的に呼び出されMAIN()ます。

の内臓をループで包み、MAIN()30 分間スリープを使用することができます。代わりに、MAIN をループしながら他のアクティビティを実行したいが、それでも 30 分ごとに記録したい場合は、変数を保存して、lastTimeDataStoredループのたびにそれを比較できます。30分以上になると、データを保存し、変数を現在の時刻にリセットします。

int main(int argc, char **argv)

{

   bmp085_Calibration();

   while (true) //loop indefinitely
   {
     temperature = bmp085_GetTemperature(bmp085_ReadUT());
     pressure = bmp085_GetPressure(bmp085_ReadUP());
     altitude = bmp085_Altitude(pressure);

     printf("Temperature\t%0.1f *F\n", ((double)temperature)/10 * 1.8 + 32);
     printf("Pressure\t%0.2f hPa\n", ((double)pressure)/100);
     printf("Altitude\t%0.1f Feet\n", ((double)altitude)*3.280839895);

     //either sleep for 30 minutes or check variable to see if 30 minutes has passed
     usleep((1000*60)*30); //sleep 30 minutes
   }

   return 0;
}
于 2012-12-28T18:31:29.587 に答える
2

測定間隔で1秒未満の精度が必要ない場合、問題に対する2つの潜在的な解決策があります。

  1. main()キャリブレーション以外の内容をループでラップし、sleep()1800 秒の引数を指定して呼び出しを含めます。

    int main(int argc, char **argv) {
        bmp085_Calibration();
    
       int count;
    
       for (count = 0; count < 49; ++count) {
           temperature = bmp085_GetTemperature(bmp085_ReadUT());
           pressure = bmp085_GetPressure(bmp085_ReadUP());
           altitude = bmp085_Altitude(pressure);
    
           printf("Temperature\t%0.1f *F\n", ((double)temperature)/10 * 1.8 + 32);
           printf("Pressure\t%0.2f hPa\n", ((double)pressure)/100);
           printf("Altitude\t%0.1f Feet\n", ((double)altitude)*3.280839895);
    
           sleep(1800);
       }
    
       return 0;
    }
    

    同じプログラム内で 2 回目の測定を行うには、いくつかの設定をリセットする必要がある場合があります。の戻り値をチェックして、sleep()その関数呼び出しが途中で終了する可能性をキャッチすることもできます...

  2. デバイスの OS として Linux を使用しているため、プログラムの周りにラッパー スクリプトを使用できます。

    #!/bin/bash
    
    while true; do
        /path/to/your/program >> measurements.log
    
        sleep 1800 
    done
    

    読者への演習として、48 時間後に終了します...

于 2012-12-28T18:27:26.957 に答える