Raspberry PiでI2C気温・気圧センサーBMP085を使う時の各言語でのソフトウエア。
C言語
サンプル・ソースコードが『 john.geek.nz : Reading data from a Bosch BMP085 with a Raspberry Pi 』に公開されている。
このソースコードのビルドに必要なsmbus.cは『Hackage :: [Package] hsI2C-0.1.3』 からダウンロードする。
ソースコードを次のように(赤字部分で示すように)少し改変して、コンパイルする。
gcc testBMP085.c smbus.c -lm -o bmp085
testBMP085.c [download site]
/* Raspberry Pi Bosch BMP085 communication code. By: John Burns (www.john.geek.nz) Date: 01 August 2012 License: CC BY-SA v3.0 - http://creativecommons.org/licenses/by-sa/3.0/ */ #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; // Open a connection to the bmp085 // Returns a file id int bmp085_i2c_Begin() { int fd; char *fileName = "/dev/i2c-1"; // 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; } int main(int argc, char **argv) { bmp085_Calibration(); temperature = bmp085_GetTemperature(bmp085_ReadUT()); pressure = bmp085_GetPressure(bmp085_ReadUP()); printf("Temperature\t%0.1f deg-C\n", ((double)temperature)/10); printf("Pressure\t%0.2f hPa\n", ((double)pressure)/100); return 0; }
testBMP085.cで使われているsmbusライブラリのソースコードは次の通り。こちらも、赤字の部分は改変している。
smbus.c [download site]
/*
smbus.c - SMBus level access helper functions
Copyright (C) 1995-1997 Simon G. Vogl
Copyright (C) 1998-1999 Frodo Looijaard <frodol@dds.nl>
Copyright (C) 2012-2013 Jean Delvare <jdelvare@suse.de>
*/
#include <errno.h>
#include <stddef.h>
#include "smbus.h"
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
/* Compatibility defines */
#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN
#define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA
#endif
#ifndef I2C_FUNC_SMBUS_PEC
#define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC
#endif
__s32 i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
__s32 err;
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
err = ioctl(file, I2C_SMBUS, &args);
if (err == -1)
err = -errno;
return err;
}
__s32 i2c_smbus_write_quick(int file, __u8 value)
{
return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL);
}
__s32 i2c_smbus_read_byte(int file)
{
union i2c_smbus_data data;
int err;
err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
if (err < 0)
return err;
return 0x0FF & data.byte;
}
__s32 i2c_smbus_write_byte(int file, __u8 value)
{
return i2c_smbus_access(file, I2C_SMBUS_WRITE, value,
I2C_SMBUS_BYTE, NULL);
}
__s32 i2c_smbus_read_byte_data(int file, __u8 command)
{
union i2c_smbus_data data;
int err;
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
I2C_SMBUS_BYTE_DATA, &data);
if (err < 0)
return err;
return 0x0FF & data.byte;
}
__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value)
{
union i2c_smbus_data data;
data.byte = value;
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
I2C_SMBUS_BYTE_DATA, &data);
}
__s32 i2c_smbus_read_word_data(int file, __u8 command)
{
union i2c_smbus_data data;
int err;
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
I2C_SMBUS_WORD_DATA, &data);
if (err < 0)
return err;
return 0x0FFFF & data.word;
}
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value)
{
union i2c_smbus_data data;
data.word = value;
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
I2C_SMBUS_WORD_DATA, &data);
}
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
{
union i2c_smbus_data data;
data.word = value;
if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
I2C_SMBUS_PROC_CALL, &data))
return -1;
else
return 0x0FFFF & data.word;
}
/* Returns the number of read bytes */
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values)
{
union i2c_smbus_data data;
int i, err;
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
I2C_SMBUS_BLOCK_DATA, &data);
if (err < 0)
return err;
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
const __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > I2C_SMBUS_BLOCK_MAX)
length = I2C_SMBUS_BLOCK_MAX;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
I2C_SMBUS_BLOCK_DATA, &data);
}
/* Returns the number of read bytes */
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
ask for less than 32 bytes, your code will only work with kernels
2.6.23 and later. */
__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length,
__u8 *values)
{
union i2c_smbus_data data;
int i, err;
if (length > I2C_SMBUS_BLOCK_MAX)
length = I2C_SMBUS_BLOCK_MAX;
data.block[0] = length;
err = i2c_smbus_access(file, I2C_SMBUS_READ, command,
length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
I2C_SMBUS_I2C_BLOCK_DATA, &data);
if (err < 0)
return err;
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length,
const __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > I2C_SMBUS_BLOCK_MAX)
length = I2C_SMBUS_BLOCK_MAX;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
}
/* Returns the number of read bytes */
__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
__u8 *values)
{
union i2c_smbus_data data;
int i, err;
if (length > I2C_SMBUS_BLOCK_MAX)
length = I2C_SMBUS_BLOCK_MAX;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
I2C_SMBUS_BLOCK_PROC_CALL, &data);
if (err < 0)
return err;
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
smbus.h
#ifndef LIB_I2C_SMBUS_H #define LIB_I2C_SMBUS_H #include <linux/types.h> #include <linux/i2c.h> extern __s32 i2c_smbus_access(int file, char read_write, __u8 command, int size, union i2c_smbus_data *data); extern __s32 i2c_smbus_write_quick(int file, __u8 value); extern __s32 i2c_smbus_read_byte(int file); extern __s32 i2c_smbus_write_byte(int file, __u8 value); extern __s32 i2c_smbus_read_byte_data(int file, __u8 command); extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value); extern __s32 i2c_smbus_read_word_data(int file, __u8 command); extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value); extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value); /* Returns the number of read bytes */ extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, const __u8 *values); /* Returns the number of read bytes */ /* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you ask for less than 32 bytes, your code will only work with kernels 2.6.23 and later. */ extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values); extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, const __u8 *values); /* Returns the number of read bytes */ extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, __u8 *values); #endif /* LIB_I2C_SMBUS_H */