我正在为一个科学项目发送一个气象气球,Raspberry Pi附加到Adafriut BMP085,并使用一些C代码记录并存储高度读数。唯一的问题是它目前只记录一次,我想要它执行时,它会每半小时记录一次文本文件并将其存储大约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;
}
答案 0 :(得分:2)
如果您在测量间隔内不需要亚秒精度,我会看到两个可能的问题解决方案:
将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;
}
您可能需要重置一些内容,以便在同一程序中进行第二次测量。您可能还想检查sleep()
的返回值以捕获该函数调用的潜在过早结束...
由于您在设备中使用Linux作为操作系统,因此可以在程序周围使用包装脚本:
#!/bin/bash
while true; do
/path/to/your/program >> measurements.log
sleep 1800
done
我将在48小时之后将终止作为练习留给读者......
答案 1 :(得分:2)
您的MAIN()
例程似乎没有任何循环。由于您希望它每30分钟记录一次数据,因此您希望MAIN能够连续循环,imo。
我对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;
}