mirror of
https://github.com/clockworkpi/WiringPi.git
synced 2025-12-13 00:08:51 +01:00
for kernels 4.8 onwards. Some very old stuff might break. Additional fixes for the ISR code and some tweaks here and there. I've removed the checks for some operations that might fail when using the gpiomem interface - which is now the default way of doing things - if your program segfaults, then you may need to use sudo on it.
238 lines
6.0 KiB
C
238 lines
6.0 KiB
C
/*
|
|
* bmp180.c:
|
|
* Extend wiringPi with the BMP180 I2C Pressure and Temperature
|
|
* sensor. This is used in the Pi Weather Station
|
|
* Copyright (c) 2016 Gordon Henderson
|
|
*
|
|
* Information from the document held at:
|
|
* http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf
|
|
* was very useful when building this code.
|
|
*
|
|
***********************************************************************
|
|
* This file is part of wiringPi:
|
|
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
|
*
|
|
* wiringPi is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* wiringPi is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with wiringPi.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
***********************************************************************
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
#include "wiringPi.h"
|
|
#include "wiringPiI2C.h"
|
|
|
|
#include "bmp180.h"
|
|
|
|
#undef DEBUG
|
|
|
|
#define I2C_ADDRESS 0x77
|
|
#define BMP180_OSS 0
|
|
|
|
|
|
// Static calibration data
|
|
// The down-side of this is that there can only be one BMP180 in
|
|
// a system - which is practice isn't an issue as it's I2C
|
|
// address is fixed.
|
|
|
|
static int16_t AC1, AC2, AC3 ;
|
|
static uint16_t AC4, AC5, AC6 ;
|
|
static int16_t VB1, VB2 ;
|
|
static int16_t MB, MC, MD ;
|
|
|
|
static double c5, c6, mc, md, x0, x1, x2, yy0, yy1, yy2, p0, p1, p2 ;
|
|
|
|
// Pressure & Temp variables
|
|
|
|
uint32_t cPress, cTemp ;
|
|
|
|
static int altitude ;
|
|
|
|
/*
|
|
* read16:
|
|
* Quick hack to read the 16-bit data with the correct endian
|
|
*********************************************************************************
|
|
*/
|
|
|
|
uint16_t read16 (int fd, int reg)
|
|
{
|
|
return (wiringPiI2CReadReg8 (fd, reg) << 8) | wiringPiI2CReadReg8 (fd, reg + 1) ;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* bmp180ReadTempPress:
|
|
* Does the hard work of reading the sensor
|
|
*********************************************************************************
|
|
*/
|
|
|
|
static void bmp180ReadTempPress (int fd)
|
|
{
|
|
double fTemp, fPress ;
|
|
double tu, a ;
|
|
double pu, s, x, y, z ;
|
|
|
|
uint8_t data [4] ;
|
|
|
|
// Start a temperature sensor reading
|
|
|
|
wiringPiI2CWriteReg8 (fd, 0xF4, 0x2E) ;
|
|
delay (5) ;
|
|
|
|
// Read the raw data
|
|
|
|
data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ;
|
|
data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ;
|
|
|
|
// And calculate...
|
|
|
|
tu = (data [0] * 256.0) + data [1] ;
|
|
|
|
a = c5 * (tu - c6) ;
|
|
fTemp = a + (mc / (a + md)) ;
|
|
cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ;
|
|
|
|
#ifdef DEBUG
|
|
printf ("fTemp: %f, cTemp: %6d\n", fTemp, cTemp) ;
|
|
#endif
|
|
|
|
// Start a pressure snsor reading
|
|
|
|
wiringPiI2CWriteReg8 (fd, 0xF4, 0x34 | (BMP180_OSS << 6)) ;
|
|
delay (5) ;
|
|
|
|
// Read the raw data
|
|
|
|
data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ;
|
|
data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ;
|
|
data [2] = wiringPiI2CReadReg8 (fd, 0xF8) ;
|
|
|
|
// And calculate...
|
|
|
|
pu = ((double)data [0] * 256.0) + (double)data [1] + ((double)data [2] / 256.0) ;
|
|
s = fTemp - 25.0 ;
|
|
x = (x2 * pow (s, 2.0)) + (x1 * s) + x0 ;
|
|
y = (yy2 * pow (s, 2.0)) + (yy1 * s) + yy0 ;
|
|
z = (pu - x) / y ;
|
|
fPress = (p2 * pow (z, 2.0)) + (p1 * z) + p0 ;
|
|
cPress = (int)rint (((100.0 * fPress) + 0.5) / 10.0) ;
|
|
|
|
#ifdef DEBUG
|
|
printf ("fPress: %f, cPress: %6d\n", fPress, cPress) ;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* myAnalogWrite:
|
|
* Write to a fake register to represent the height above sea level
|
|
* so that the peudo millibar register can read the pressure in mB
|
|
*********************************************************************************
|
|
*/
|
|
|
|
static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value)
|
|
{
|
|
int chan = pin - node->pinBase ;
|
|
|
|
if (chan == 0)
|
|
altitude = value ;
|
|
}
|
|
|
|
/*
|
|
* myAnalogRead:
|
|
*********************************************************************************
|
|
*/
|
|
|
|
static int myAnalogRead (struct wiringPiNodeStruct *node, int pin)
|
|
{
|
|
int chan = pin - node->pinBase ;
|
|
|
|
bmp180ReadTempPress (node->fd) ;
|
|
|
|
/**/ if (chan == 0) // Read Temperature
|
|
return cTemp ;
|
|
else if (chan == 1) // Pressure
|
|
return cPress ;
|
|
else if (chan == 2) // Pressure in mB
|
|
return cPress / pow (1 - ((double)altitude / 44330.0), 5.255) ;
|
|
else
|
|
return -9999 ;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* bmp180Setup:
|
|
* Create a new instance of a PCF8591 I2C GPIO interface. We know it
|
|
* has 4 pins, (4 analog inputs and 1 analog output which we'll shadow
|
|
* input 0) so all we need to know here is the I2C address and the
|
|
* user-defined pin base.
|
|
*********************************************************************************
|
|
*/
|
|
|
|
int bmp180Setup (const int pinBase)
|
|
{
|
|
double c3, c4, b1 ;
|
|
int fd ;
|
|
struct wiringPiNodeStruct *node ;
|
|
|
|
if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0)
|
|
return FALSE ;
|
|
|
|
node = wiringPiNewNode (pinBase, 4) ;
|
|
|
|
node->fd = fd ;
|
|
node->analogRead = myAnalogRead ;
|
|
node->analogWrite = myAnalogWrite ;
|
|
|
|
// Read calibration data
|
|
|
|
AC1 = read16 (fd, 0xAA) ;
|
|
AC2 = read16 (fd, 0xAC) ;
|
|
AC3 = read16 (fd, 0xAE) ;
|
|
AC4 = read16 (fd, 0xB0) ;
|
|
AC5 = read16 (fd, 0xB2) ;
|
|
AC6 = read16 (fd, 0xB4) ;
|
|
VB1 = read16 (fd, 0xB6) ;
|
|
VB2 = read16 (fd, 0xB8) ;
|
|
MB = read16 (fd, 0xBA) ;
|
|
MC = read16 (fd, 0xBC) ;
|
|
MD = read16 (fd, 0xBE) ;
|
|
|
|
// Calculate coefficients
|
|
|
|
c3 = 160.0 * pow (2.0, -15.0) * AC3 ;
|
|
c4 = pow (10.0, -3.0) * pow(2.0,-15.0) * AC4 ;
|
|
b1 = pow (160.0, 2.0) * pow(2.0,-30.0) * VB1 ;
|
|
c5 = (pow (2.0, -15.0) / 160.0) * AC5 ;
|
|
c6 = AC6 ;
|
|
mc = (pow (2.0, 11.0) / pow(160.0,2.0)) * MC ;
|
|
md = MD / 160.0 ;
|
|
x0 = AC1 ;
|
|
x1 = 160.0 * pow (2.0, -13.0) * AC2 ;
|
|
x2 = pow (160.0, 2.0) * pow(2.0,-25.0) * VB2 ;
|
|
yy0 = c4 * pow (2.0, 15.0) ;
|
|
yy1 = c4 * c3 ;
|
|
yy2 = c4 * b1 ;
|
|
p0 = (3791.0 - 8.0) / 1600.0 ;
|
|
p1 = 1.0 - 7357.0 * pow (2.0, -20.0) ;
|
|
p2 = 3038.0 * 100.0 * pow (2.0, -36.0) ;
|
|
|
|
return TRUE ;
|
|
}
|