KT24-1110_65E-HA-651B/apps/common/device/bmp280/bmp280.c
2024-11-10 18:44:17 +08:00

405 lines
16 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "app_config.h"
#include "asm/clock.h"
#include "system/timer.h"
#include "bmp280.h"
#include "asm/cpu.h"
#include "generic/typedef.h"
#include "generic/gpio.h"
#if defined(TCFG_BMP280_DEV_ENABLE) && TCFG_BMP280_DEV_ENABLE
#undef LOG_TAG_CONST
#define LOG_TAG "[bmp280]"
#define LOG_ERROR_ENABLE
#define LOG_INFO_ENABLE
#include "debug.h"
struct _bmp280_dev_platform_data *bmp280_iic_info;
#if TCFG_BMP280_USER_IIC_TYPE
#define iic_init(iic) hw_iic_init(iic)
#define iic_uninit(iic) hw_iic_uninit(iic)
#define iic_start(iic) hw_iic_start(iic)
#define iic_stop(iic) hw_iic_stop(iic)
#define iic_tx_byte(iic, byte) hw_iic_tx_byte(iic, byte)
#define iic_rx_byte(iic, ack) hw_iic_rx_byte(iic, ack)
#define iic_read_buf(iic, buf, len) hw_iic_read_buf(iic, buf, len)
#define iic_write_buf(iic, buf, len) hw_iic_write_buf(iic, buf, len)
#define iic_suspend(iic) hw_iic_suspend(iic)
#define iic_resume(iic) hw_iic_resume(iic)
#else
#define iic_init(iic) soft_iic_init(iic)
#define iic_uninit(iic) soft_iic_uninit(iic)
#define iic_start(iic) soft_iic_start(iic)
#define iic_stop(iic) soft_iic_stop(iic)
#define iic_tx_byte(iic, byte) soft_iic_tx_byte(iic, byte)
#define iic_rx_byte(iic, ack) soft_iic_rx_byte(iic, ack)
#define iic_read_buf(iic, buf, len) soft_iic_read_buf(iic, buf, len)
#define iic_write_buf(iic, buf, len) soft_iic_write_buf(iic, buf, len)
#define iic_suspend(iic) soft_iic_suspend(iic)
#define iic_resume(iic) soft_iic_resume(iic)
#endif
/* extern void delay(unsigned int cnt);//eeprom */
extern void delay_2ms(int cnt);//fm
static bool bmp280_read_buf(u8 reg, u8 *buf, u8 len)
{
iic_start(bmp280_iic_info->iic_hdl);
if (0 == iic_tx_byte(bmp280_iic_info->iic_hdl, BMP280_I2C_ADDR << 1 | 0)) {
iic_stop(bmp280_iic_info->iic_hdl);
log_error("bmp280 read fail1!\n");
return false;
}
delay_2ms(bmp280_iic_info->iic_delay);
if (0 == iic_tx_byte(bmp280_iic_info->iic_hdl, reg)) {
iic_stop(bmp280_iic_info->iic_hdl);
log_error("bmp280 read fail2!\n");
return false;
}
delay_2ms(bmp280_iic_info->iic_delay);
iic_start(bmp280_iic_info->iic_hdl);
if (0 == iic_tx_byte(bmp280_iic_info->iic_hdl, BMP280_I2C_ADDR << 1 | 1)) {
iic_stop(bmp280_iic_info->iic_hdl);
log_error("bmp280 read fail3!\n");
return false;
}
for (u8 i = 0; i < len - 1; i++) {
buf[i] = iic_rx_byte(bmp280_iic_info->iic_hdl, 1);
delay_2ms(bmp280_iic_info->iic_delay);
}
buf[len - 1] = iic_rx_byte(bmp280_iic_info->iic_hdl, 0);
iic_stop(bmp280_iic_info->iic_hdl);
delay_2ms(bmp280_iic_info->iic_delay);
return true;
}
static bool bmp280_write_byte(u8 reg, u8 data)
{
iic_start(bmp280_iic_info->iic_hdl);
if (0 == iic_tx_byte(bmp280_iic_info->iic_hdl, BMP280_I2C_ADDR << 1)) {
iic_stop(bmp280_iic_info->iic_hdl);
log_error("bmp280 write fail1!\n");
return false;
}
delay_2ms(bmp280_iic_info->iic_delay);
if (0 == iic_tx_byte(bmp280_iic_info->iic_hdl, reg)) {
iic_stop(bmp280_iic_info->iic_hdl);
log_error("bmp280 write fail2!\n");
return false;
}
delay_2ms(bmp280_iic_info->iic_delay);
if (0 == iic_tx_byte(bmp280_iic_info->iic_hdl, data)) {
iic_stop(bmp280_iic_info->iic_hdl);
log_error("bmp280 write fail3!\n");
return false;
}
iic_stop(bmp280_iic_info->iic_hdl);
delay_2ms(bmp280_iic_info->iic_delay);
return true;
}
//设置BMP过采样因子 MODE
//BMP280_SLEEP_MODE||BMP280_FORCED_MODE||BMP280_NORMAL_MODE
bool bmp280_set_temoversamp(bmp_oversample_mode *oversample_mode)
{
u8 regtmp;
regtmp = ((oversample_mode->t_osample) << 5) |
((oversample_mode->p_osample) << 2) |
((oversample_mode)->workmode);
/* log_info("init reg:%x",regtmp); */
return bmp280_write_byte(BMP280_CTRLMEAS_REG, regtmp);
}
//设置保持时间和滤波器分频因子
bool bmp280_set_standby_filter(bmp_config *bmp_config)
{
u8 regtmp;
regtmp = ((bmp_config->t_sb) << 5) |
((bmp_config->filter_coefficient) << 2) |
((bmp_config->spi_en));
/* log_info("init config reg:%x",regtmp); */
return bmp280_write_byte(BMP280_CONFIG_REG, regtmp);
}
//设置bmp280工作模式
void bmp280_set_work_mode(BMP280_WORK_MODE workmode)
{
u8 ctrl_maes_data = 0;
bmp280_read_buf(BMP280_CTRLMEAS_REG, &ctrl_maes_data, 1);
/* log_info("old ctrl_maes_data:%x ",ctrl_maes_data); */
ctrl_maes_data &= ~(BIT(1) | BIT(0));
ctrl_maes_data += (workmode << 0);
/* log_info("nem ctrl_maes_data:%x ",ctrl_maes_data); */
bmp280_write_byte(BMP280_CTRLMEAS_REG, ctrl_maes_data);
}
//bmp280 复位
bool bmp280_reset() //return 1:ok; 0:fail
{
return bmp280_write_byte(BMP280_RESET_REG, BMP280_RESET_VALUE);
}
bmp280_params bmp280_par;
bool bmp280_init(void *priv)
{
u8 bmp280_id;
if (priv == NULL) {
log_info("bmp280 init fail(no priv)\n");
return false;
}
bmp280_iic_info = (struct _bmp280_dev_platform_data *)priv;
if (bmp280_read_buf(BMP280_CHIPID_REG, &bmp280_id, 1)) {
log_info("bmp280 id:%x", bmp280_id);
} else {
log_error("read bmp280 id fail!");
return false;
}
/********************读矫正参数*********************/
u8 temp[24] = {0};
bmp280_read_buf(BMP280_DIG_T1_LSB_REG, temp, 24);
//温度传感器的矫正值
bmp280_par.t1 = (((u16)temp[1]) << 8) + temp[0];
bmp280_par.t2 = (temp[3] << 8) + temp[2];
bmp280_par.t3 = (temp[5] << 8) + temp[4];
//大气压传感器的矫正值
bmp280_par.p1 = (((u16)temp[7]) << 8) + temp[6];
bmp280_par.p2 = (temp[9] << 8) + temp[8];
bmp280_par.p3 = (temp[11] << 8) + temp[10];
bmp280_par.p4 = (temp[13] << 8) + temp[12];
bmp280_par.p5 = (temp[15] << 8) + temp[14];
bmp280_par.p6 = (temp[17] << 8) + temp[16];
bmp280_par.p7 = (temp[19] << 8) + temp[18];
bmp280_par.p8 = (temp[21] << 8) + temp[20];
bmp280_par.p9 = (temp[23] << 8) + temp[22];
/* log_info("%d,%d,%d;%d,%d,%d,%d,%d,%d,%d,%d,%d",bmp280_par.t1,bmp280_par.t2,bmp280_par.t3,bmp280_par.p1,bmp280_par.p2,bmp280_par.p3,bmp280_par.p4,bmp280_par.p5,bmp280_par.p6,bmp280_par.p7,bmp280_par.p8,bmp280_par.p9); */
/******************************************************/
if (!(bmp280_write_byte(BMP280_RESET_REG, BMP280_RESET_VALUE))) { //往复位寄存器写入给定值
log_error("bmp280 reset error!\n");
return false;
}
bmp_config bmp_configstr;
bmp_configstr.t_sb = BMP280_T_SB1;
bmp_configstr.filter_coefficient = BMP280_FILTER_MODE_4;
bmp_configstr.spi_en = DISABLE;
if (!(bmp280_set_standby_filter(&bmp_configstr))) {
log_error("bmp280 init mode error!\n");
return false;
}
bmp_oversample_mode bmp_oversample_modestr;
bmp_oversample_modestr.t_osample = BMP280_T_MODE_1;
bmp_oversample_modestr.p_osample = BMP280_P_MODE_3;
bmp_oversample_modestr.workmode = BMP280_NORMAL_MODE;
if (!(bmp280_set_temoversamp(&bmp_oversample_modestr))) {
log_error("bmp280 init mode error!\n");
return false;
}
return true;
}
/*****************算法*******************/
/************计算补偿值***************/
s32 t_fine; //用于计算补偿
#if USE_FIXED_POINT_COMPENSATE //使用定点补偿
// Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
// t_fine carries fine temperature as global value
static s32 bmp280_compensate_t_int32(s32 adc_T)
{
s32 var1, var2, T;
var1 = (((adc_T >> 3) - ((s32)bmp280_par.t1 << 1)) * ((s32)bmp280_par.t2)) >> 11;
var2 = (((((adc_T >> 4) - ((s32)bmp280_par.t1)) * ((adc_T >> 4) - ((s32)bmp280_par.t1))) >> 12) * ((s32)bmp280_par.t3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}
// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
// Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
static u32 bmp280_compensate_p_int64(s32 adc_P)
{
s64 var1, var2, p;
var1 = ((s64)t_fine) - 128000;
var2 = var1 * var1 * (s64)bmp280_par.p6;
var2 = var2 + ((var1 * (s64)bmp280_par.p5) << 17);
var2 = var2 + (((s64)bmp280_par.p4) << 35);
var1 = ((var1 * var1 * (s64)bmp280_par.p3) >> 8) + ((var1 * (s64)bmp280_par.p2) << 12);
var1 = (((((s64)1) << 47) + var1)) * ((s64)bmp280_par.p1) >> 33;
if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((s64)bmp280_par.p9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((s64)bmp280_par.p8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((s64)bmp280_par.p7) << 4);
return (u32)p;
}
#else //使用浮点补偿
// Returns temperature in DegC, double precision. Output value of “51.23” equals 51.23 DegC.
// t_fine carries fine temperature as global value
static double bmp280_compensate_t_double(s32 adc_T)
{
double var1, var2, T;
var1 = (((double)adc_T) / 16384.0 - ((double)bmp280_par.t1) / 1024.0) * ((double)bmp280_par.t2);
var2 = ((((double)adc_T) / 131072.0 - ((double)bmp280_par.t1) / 8192.0) * (((double)adc_T) / 131072.0 - ((double) bmp280_par.t1) / 8192.0)) * ((double)bmp280_par.t3);
t_fine = (s32)(var1 + var2);
T = (var1 + var2) / 5120.0;
return T;
}
// Returns pressure in Pa as double. Output value of “96386.2” equals 96386.2 Pa = 963.862 hPa
static double bmp280_compensate_p_double(s32 adc_P)
{
double var1, var2, p;
var1 = ((double)t_fine / 2.0) - 64000.0;
var2 = var1 * var1 * ((double)bmp280_par.p6) / 32768.0;
var2 = var2 + var1 * ((double)bmp280_par.p5) * 2.0;
var2 = (var2 / 4.0) + (((double)bmp280_par.p4) * 65536.0);
var1 = (((double)bmp280_par.p3) * var1 * var1 / 524288.0 + ((double)bmp280_par.p2) * var1) / 524288.0;
var1 = (1.0 + var1 / 32768.0) * ((double)bmp280_par.p1);
if (var1 == 0.0) {
return 0; // avoid exception caused by division by zero
}
p = 1048576.0 - (double)adc_P;
p = (p - (var2 / 4096.0)) * 6250.0 / var1;
var1 = ((double)bmp280_par.p9) * p * p / 2147483648.0;
var2 = p * ((double)bmp280_par.p8) / 32768.0;
p = p + (var1 + var2 + ((double)bmp280_par.p7)) / 16.0;
return p;
}
#endif
//获取BMP当前状态
//status_flag = BMP280_MEASURING
// BMP280_IM_UPDATE
static u8 bmp280_getstatus(u8 status_flag)
{
u8 flag;
bmp280_read_buf(BMP280_STATUS_REG, &flag, 1);
if (flag & status_flag) {
return 1;
} else {
return 0;
}
}
//温度值-℃(实际值的100倍(定点法)或实际值(浮点法))
static bmp_temperature_data bmp280_get_temperature(void)
{
u8 tem_data[3] = {0};
long signed bit32;
bmp280_read_buf(BMP280_TEMPERATURE_MSB_REG, tem_data, 3);
bit32 = ((long)(tem_data[0] << 12)) | ((long)(tem_data[1] << 4)) | (tem_data[2] >> 4);
/* log_info("tembit32:%ld",bit32); */
#if USE_FIXED_POINT_COMPENSATE //使用定点补偿
return bmp280_compensate_t_int32(bit32);
#else //使用浮点补偿
return bmp280_compensate_t_double(bit32);
#endif
}
//获取大气压值-Pa(实际值的100倍(定点法)或实际值(浮点法))
static bmp_pressure_data bmp280_get_pressure(void)
{
u8 tem_data[3] = {0};
long signed bit32;
bmp280_read_buf(BMP280_PRESSURE_MSB_REG, tem_data, 3);
bit32 = ((long)(tem_data[0] << 12)) | ((long)(tem_data[1] << 4)) | (tem_data[2] >> 4);
/* log_info("prebit32:%ld,t_fine:%d",bit32,t_fine); */
#if USE_FIXED_POINT_COMPENSATE //使用定点补偿
u32 pressure = bmp280_compensate_p_int64(bit32);
pressure = pressure * 100 / 256;
#else //使用浮点补偿
double pressure = bmp280_compensate_p_double(bit32);
#endif
return pressure;
}
/*
* 仅在BMP280被设置为normal mode时
* 可使用该接口直接读取温度和气压。
* (实际值的100倍(定点法)或实际值(浮点法))
*/
void bmp280_get_temperature_and_pressure(bmp_temperature_data *temperature, bmp_pressure_data *pressure)
{
while (bmp280_getstatus(BMP280_MEASURING));
while (bmp280_getstatus(BMP280_IM_UPDATE));
*temperature = bmp280_get_temperature(); //必须先读温度再度气压
*pressure = bmp280_get_pressure();
}
/**
* 当BMP280被设置为forced mode时
* 可使用该接口直接读取温度和气压。
* (实际值的100倍(定点法)或实际值(浮点法))
*/
void bmp280_forced_mode_get_temperature_and_pressure(bmp_temperature_data *temperature, bmp_pressure_data *pressure)
{
bmp280_set_work_mode(BMP280_FORCED_MODE);
bmp280_get_temperature_and_pressure(temperature, pressure);
}
//计算高度, 返回海拔高度: (m)
#include "math.h"
#define SEA_LEVEL_PRESSURE 1013.23f
float bmp280_get_altitude(bmp_temperature_data temperature, bmp_pressure_data pressure)
{
/* log_info("temperature:%d,pressure:%d",(s32)temperature,(u32)pressure); */
#if USE_FIXED_POINT_COMPENSATE //使用定点补偿
/* return 44330 * (1.0 - pow(pressure/10000 / SEA_LEVEL_PRESSURE, 0.1903)); */
//计算公式温度用实际值,压强用实际值的百分之一
return ((float)powf(SEA_LEVEL_PRESSURE / ((float)pressure / 10000.0), 0.190223f) - 1.0f) * ((float)temperature / 100.0 + 273.15f) / 0.0065f; // Calculate the altitude in metres
#else //使用浮点补偿
/* return 44330 * (1.0 - pow(pressure/100 / SEA_LEVEL_PRESSURE, 0.1903)); */
//计算公式温度用实际值,压强用实际值的百分之一
return ((float)powf(SEA_LEVEL_PRESSURE / ((float)pressure / 100.0), 0.190223f) - 1.0f) * ((float)temperature + 273.15f) / 0.0065f; // Calculate the altitude in metres
#endif
}
/*************************test*************************/
#if 0
static struct _bmp280_dev_platform_data bmp280_iic_info_test = {
.iic_hdl = 0,
.iic_delay = 0
};
#define _portio 0
void bmp280_init_read_test()
{
u16 i = 0, iii = 40;
bmp_pressure_data bmp_pressure;
bmp_temperature_data bmp_temperature;
float bmp280_altitude = 0;
/* JL_PORTA->DIR &= ~(BIT(0)|BIT(9)|BIT(10)); */
/* JL_PORTA->OUT &= ~(BIT(0)|BIT(9)|BIT(10)); */
iic_init(0);
log_info("bmp280 init***************************\n");
if (bmp280_init(&bmp280_iic_info_test)) {
log_info("bmp280 init ok!***************************\n");
while (iii--) {
bmp280_get_temperature_and_pressure(&bmp_temperature, &bmp_pressure);
/* bmp280_forced_mode_get_temperature_and_pressure(&bmp_temperature , &bmp_pressure); */
bmp280_altitude = bmp280_get_altitude(bmp_temperature, bmp_pressure);
#if USE_FIXED_POINT_COMPENSATE //使用定点补偿
log_info("bmp280 fixed Pressure %ld.%02dpa,temperature:%d.%02dc,alti:%d.%02dm\n", bmp_pressure / 100, bmp_pressure % 100, bmp_temperature / 100, bmp_temperature % 100, (s32)bmp280_altitude, (u32)((s32)(bmp280_altitude * 100) % 100));
#else //使用浮点补偿
log_info("bmp280 float Pressure %d.%02dpa,temperature:%d.%02dc,alti:%d.%02dm\n", (s32)bmp_pressure, (s32)(bmp_pressure * 100) % 100, (s32)bmp_temperature, (s32)(bmp_temperature * 100) % 100, (s32)bmp280_altitude, (u32)((s32)(bmp280_altitude * 100) % 100));
#endif
os_time_dly(50);
}
} else {
log_error("bmp280 init fail!***************************\n");
}
while (1);
}
#endif
#endif