Введите текст заголовка

#include <string.h>
#include <math.h>
#include «BMP180.h»
#include «stm32f4xx_hal.h»


// global struct to store all BMP180 main data.
bmp_t bmp;

extern I2C_HandleTypeDef hi2c1;

 

/*!
* @brief: — Read and check bmp chip ID.This value is fixed to 0x55,
* and can be used to check whether communication is functioning.
* @param[in] — NONE.
* @return — NO_ERR if chip_id is equal to 0x55, otherwise CHIP_ID_INVALID_ERR.
*/
static bmp_err_t read_chip_id (void)
{
uint8_t out_buff = 0;
uint8_t ret_val = NO_ERR;

HAL_I2C_Mem_Read(&hi2c1, BMP_READ_ADDR, BMP_CHIP_ID_REG, 1, &out_buff, 1, BMP_I2C_TIMEOUT);

if (BMP_CHIP_ID_VAL != out_buff)
{
ret_val = CHIP_ID_INVALID_ERR;
}

return ret_val;
}


/*!
* @brief: — Write oversampling settings to the Control register.
* @param[in] — struct of type oss_t
* @param[in] — enum of type oss_ratio_t
* @return — None
*/
static void set_oss (oss_t * oss, oss_ratio_t ratio)
{
uint8_t in_buff[2] = {0};

switch (ratio)
{
case ULTRA_LOW_PWR_MODE:
{
oss->wait_time = BMP_OSS0_CONV_TIME;
break;
}
case STANDARD_MODE:
{
oss->wait_time = BMP_OSS1_CONV_TIME;
break;
}
case HIGH:
{
oss->wait_time = BMP_OSS2_CONV_TIME;
break;
}
case ULTRA_HIGH_RESOLUTION:
{
oss->wait_time = BMP_OSS3_CONV_TIME;
break;
}
default:
{
oss->wait_time = BMP_OSS1_CONV_TIME;
break;
}
}

oss->ratio = ratio;
BMP_SET_I2CRW_REG (in_buff[1], BMP_CTRL_OSS_MASK(ratio));
HAL_I2C_Mem_Write( &hi2c1, BMP_WRITE_ADDR, BMP_CTRL_REG, 1, in_buff, 2, BMP_I2C_TIMEOUT );
}


/*!
* @brief: — Read calibration BMP data. The E2PROM has stored 176 bit of individual calibration data.
* This is used to compensate offset, temperature dependence and other parameters of the sensor.
* @param[in] — struct of type bmp_calib_param_t
* @return — NO_ERR if read calibration data are valid otherwise READ_CALIB_ERR.
*/
static bmp_err_t read_calib_data (short * calib_data)
{
bmp_err_t ret_val = NO_ERR;
uint8_t out_buff[BMP_CALIB_DATA_SIZE] = {0};
uint8_t i = 0;
uint8_t j = 1;

HAL_I2C_Mem_Read(&hi2c1, BMP_READ_ADDR, BMP_CALIB_ADDR, 1, out_buff, BMP_CALIB_DATA_SIZE, BMP_I2C_TIMEOUT);

// Store read calib data to bmp_calib struct.
for (i = 0; i <= BMP_CALIB_DATA_SIZE / 2; i++, j+2)
{
calib_data[i] = (out_buff[i * 2] << 8) | out_buff[j];

// checking that none of the words has the value 0 or 0xFFFF.
if ((0 == calib_data[i]) | (-1 == calib_data[i]))
{
ret_val = GET_CALIB_ERR;
}
}

return ret_val;
}

/*!
* @brief: — Performe initial sequence of BMP sensor
* @param[in] — pointer to struct of type bmp_calib_param_t
* @return — None.
*/
void bmp_init (bmp_t * bmp)
{
memset(bmp, 0x00, sizeof(&bmp)); // clear bmp strut;
bmp->err = read_chip_id (); // check chip validity and I2C communication.
bmp->err = read_calib_data ((short *)&bmp->calib);
set_oss (&bmp->oss, HIGH); // set oversampling settings
}

/*!
* @brief: — Get uncompensated temperature value. UT = temperature data (16 bit)
* @param[in] — None.
* @return — uncompensated temp.
*/
int32_t get_ut (void)
{
uint8_t out_buff[2];

BMP_SET_I2CRW_REG (out_buff[0], BMP_SET_TEMP_CONV);
HAL_I2C_Mem_Write( &hi2c1, BMP_WRITE_ADDR, BMP_CTRL_REG, 1, out_buff, 1, BMP_I2C_TIMEOUT );
HAL_Delay (BMP_TEMP_CONV_TIME);
HAL_I2C_Mem_Read ( &hi2c1, BMP_READ_ADDR, BMP_DATA_MSB_ADDR, 1, out_buff, 2, BMP_I2C_TIMEOUT );

return (out_buff[0] << BYTE_SHIFT) | out_buff[1];
}

/*!
* @brief: — Calc true temperature.
* @param[in] — pointer to struct of type bmp_t
* @return — true temp.
*/
float get_temp(bmp_t * bmp)
{
int32_t X1 = 0;
int32_t X2 = 0;
float temp = 0;

X1 = (((int32_t)bmp->uncomp.temp — bmp->calib.AC6) * bmp->calib.AC5) >> 15;
X2 = (bmp->calib.MC << 11) / (X1 + bmp->calib.MD);
bmp->data.B5 = X1 + X2;
temp = ((bmp->data.B5 + 8) >> 4) * 0.1f;

if ((temp <= BMP_MIN_TEMP_THRESHOLD) || (temp >= BMP_MAX_TEMP_THRESHOLD))
{
bmp->err = GET_TEMP_ERR;
}

return temp;
}

/*!
* @brief: — Get uncompensated pressure value. UP = pressure data (16 to 19 bit)
* @param[in] — struct of type oss_t
* @return — uncompensated pressure.
*/
int32_t get_up (oss_t oss)
{
uint8_t out_buff[3] = {0};
long up = 0;

BMP_SET_I2CRW_REG (out_buff[0], BMP_SET_PRESS_CONV);
HAL_I2C_Mem_Write ( &hi2c1, BMP_WRITE_ADDR, BMP_CTRL_REG, 1, out_buff, 1, BMP_I2C_TIMEOUT );
HAL_Delay (oss.wait_time);
HAL_I2C_Mem_Read(&hi2c1, BMP_READ_ADDR, BMP_DATA_MSB_ADDR, 1, out_buff, 3, BMP_I2C_TIMEOUT);

up = ((out_buff[0] << SHORT_SHIFT) + (out_buff[1] << BYTE_SHIFT) + out_buff[2]) >> (8 — oss.ratio);
return up;
}

/*!
* @brief: — Calc true pressure.
* @param[in] — struct of type bmp_t
* @return — true pressure in Pa.
*/
int32_t get_pressure(bmp_t bmp)
{
int32_t X1, X2, X3, B3, B6, p = 0;
uint32_t B4, B7 = 0;

B6 = bmp.data.B5 — 4000;
X1 = (bmp.calib.B2 * (B6 * B6 / 0x1000)) / 0x800;
X2 = bmp.calib.AC2 * B6 / 0x800;
X3 = X1 + X2;
B3 = (((bmp.calib.AC1 * 4 + X3) << bmp.oss.ratio) +2) / 4;
X1 = bmp.calib.AC3 * B6 / 0x2000;
X2 = (bmp.calib.B1 * (B6 * B6 / 0x1000)) / 0x10000;
X3 = ((X1 + X2) + 2) / 0x4;
B4 = bmp.calib.AC4 * (unsigned long)(X3 + 32768) / 0x8000;
B7 = ((unsigned long)bmp.uncomp.press — B3) * (50000 >> bmp.oss.ratio);

if (B7 < 0x80000000)
{
p = (B7 * 2) / B4;
}
else
{
p = (B7 / B4) * 2;
}

X1 = (p / 0x100 * (p / 0x100));
X1 = (X1 * 3038) / 0x10000;
X2 = (-7357 * p) / 0x10000;
p = p + (X1 + X2 + 3791) / 0x10;

return p;
}

/*!
* @brief: — Calc true altitude.
* @param[in] — struct of type bmp_t
* @return — true pressure.
*/
float get_altitude (bmp_t * bmp)
{
float altitude = 0;

altitude = BMP_PRESS_CONST_COEFICIENT * (1.0f — pow((bmp->data.press / BMP_PRESS_CONST_SEA_LEVEL), (1/5.255)));

if ((altitude <= BMP_MIN_ALT_THRESHOLD) || (altitude >= BMP_MAX_ALT_THRESHOLD))
{
bmp->err = GET_ALTITUDE_ERR;
}

return altitude;
}

 

#ifndef BMP180_H_
#define BMP180_H_


#include «stdint.h»


// Data type definitions:
#define BYTE_SHIFT (8U)
#define SHORT_SHIFT (16U)

/* Chip-id [R/O] (register D0h): This value is fixed to 0x55,
* and can be used to check whether communication is functioning. */
#define BMP_CHIP_ID_REG (0xD0)
#define BMP_CHIP_ID_VAL (0x55)

/* Measurement control [R/W] (register F4h):
* <4:0> — Controls measurements.
* <5> — SCO : Start of conversion. The value of this bit stays “1” during conversion,
* and is reset to “0” after conversion is complete
* <7:6> — OSS : Controls the oversampling ratio of the pressure measurement
*/
#define BMP_CTRL_REG (0xF4)
#define BMP_CTRL_SCO_BIT(reg) ((reg & 0x20) >> 5)
#define BMP_CTRL_OSS_MASK(oss) (oss = (oss & 0x3) << 6)

#define BMP_OSS0_CONV_TIME (5U)
#define BMP_OSS1_CONV_TIME (8U)
#define BMP_OSS2_CONV_TIME (14U)
#define BMP_OSS3_CONV_TIME (26U)

/* Soft reset [W/O] (register E0h):
* If set to 0xB6, will perform the same sequence as power on reset. */
#define BMP_SOFT_RST_REG (0xE0)
#define BMP_SOFT_RST_VAL (0xB6)

// Calibration data [R/O] (register AAh up to BFh):
#define BMP_CALIB_ADDR (0xAA)
#define BMP_CALIB_DATA_SIZE (22U)

// Device I2C addr register [R/O]: write EEh, read EFh:
#define BMP_READ_ADDR (0xEF)
#define BMP_WRITE_ADDR (0xEE)
#define BMP_I2C_TIMEOUT (50U)
#define BMP_SET_I2CRW_REG(i2c_buff, reg) (i2c_buff = reg)

// BMP measurmenet regs
#define BMP_DATA_MSB_ADDR (0xF6)
#define BMP_DATA_LSB_ADDR (0xF7)
#define BMP_DATA_XLSB_ADDR (0xF8)

// Temp. measurement :
#define BMP_SET_TEMP_CONV (0x2E)

#define BMP_TEMP_CONV_TIME (5U)
#define BMP_MIN_TEMP_THRESHOLD (-40)
#define BMP_MAX_TEMP_THRESHOLD (85U)

// Pressure measurment :
#define BMP_SET_PRESS_CONV (0x34)
#define BMP_PRESS_CONST_SEA_LEVEL (101325.0f) // pressure in Pa
#define BMP_PRESS_CONST_COEFICIENT (44330.0f)

// Altitude measurment :
#define BMP_MIN_ALT_THRESHOLD (-500) // m. relating to sea level)
#define BMP_MAX_ALT_THRESHOLD (9000U) // m. relating to sea level)

 

struct bmp_calib_param_t
{
int16_t AC1;
int16_t AC2;
int16_t AC3;
uint16_t AC4;
uint16_t AC5;
uint16_t AC6;
int16_t B1;
int16_t B2;
int16_t MB;
int16_t MC;
int16_t MD;
};

struct measure_data_t
{
float temp;
int32_t press;
/* for uncompensated values do not use below fields: */
int32_t B5;
float altitude;
};

typedef enum
{
ULTRA_LOW_PWR_MODE = 0,
STANDARD_MODE,
HIGH,
ULTRA_HIGH_RESOLUTION
} oss_ratio_t;

typedef struct
{
oss_ratio_t ratio;
uint8_t wait_time;
}oss_t;

typedef enum
{
NO_ERR = 0,
CHIP_ID_INVALID_ERR,
GET_CALIB_ERR,
GET_TEMP_ERR,
GET_PRESSURE_ERR,
GET_ALTITUDE_ERR
} bmp_err_t;

typedef struct
{
struct bmp_calib_param_t calib;
struct measure_data_t uncomp; // uncompensated values
struct measure_data_t data;
oss_t oss;
bmp_err_t err;
}bmp_t;

 

/*!
* @brief: — Performe initial sequence of BMP180 sensor.
* @param[in] — pointer to struct of type bmp_calib_param_t
* @return — None.
*/
void bmp_init (bmp_t * bmp);

/*!
* @brief: — Read oversampling settings from CTRL reg F4h.
* Oss (register F4h <7:6>): controls the oversampling ratio of the pressure measurement
* (00b: single, 01b: 2 times, 10b: 4 times, 11b: 8 times).
* @param[in] — None.
* @return — None.
*/
static void set_oss (oss_t * oss, oss_ratio_t ratio);

/*!
* @brief: — Get uncompensated temperature value.
* @param[in] — None.
* @return — uncompensated temp.
*/
int32_t get_ut (void);

/*!
* @brief: — Calc true temperature.
* @param[in] — pointer to struct of type bmp_t
* @return — true temp.
*/
float get_temp(bmp_t * bmp);

/*!
* @brief: — Get uncompensated pressure value.
* @param[in] — oss — conversion time.
* @return — uncompensated pressure.
*/
int32_t get_up (oss_t oss);

/*!
* @brief: — Calc true pressure.
* @param[in] — struct of type bmp_t
* @return — true pressure in Pa.
*/
int32_t get_pressure(bmp_t bmp);

/*!
* @brief: — Calc true altitude.
* @param[in] — struct of type bmp_t
* @return — altitude in meters.
*/
float get_altitude (bmp_t * bmp);

#endif /* BMP180_H_ */

 

/* USER CODE BEGIN 2 */
bmp_t bmp;
bmp_init (&bmp);
/* USER CODE END 2 */

 

/* USER CODE BEGIN 3 */
bmp.uncomp.temp = get_ut ();
bmp.data.temp = get_temp (&bmp);
bmp.uncomp.press = get_up (bmp.oss);
bmp.data.press = get_pressure (bmp)*1000/133322;
bmp.data.altitude = get_altitude (&bmp);
printf(«T1= %2.1fC\r\n»,bmp.data.temp);
printf(«P1= %dmm\r\n»,bmp.data.press);
HAL_Delay(1000);
}
/* USER CODE END 3 */