qq_43420536 2025-01-13 23:42 采纳率: 0%
浏览 161
已结题

STM32单片机传感器读取错误

博世BMP390读数异常:

/*****************************************************************************

 Copyright (C)
 2021 Philipp Garn
 2021-2022 Frank Reifegerste

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.

 *****************************************************************************/

#include "bmp390.h"

#include "stm32_lpm.h"
#include "stm32_timer.h"
#include "stm32_seq.h"
#include "utilities_def.h"

#include "sys_sensors.h"

#include "pins.h"

#define SET_IDLE

extern I2C_HandleTypeDef hi2c1;
extern RTC_HandleTypeDef hrtc;

double bmp390_T, bmp390_P;                                // Results from BMP390

static uint16_t T1, T2;                                        // calibration data
static int8_t T3;
static int64_t Tf;                                     // calibration t_fine data

static int16_t P1, P2, P9;
static int8_t P3, P4;
static uint16_t P5, P6;
static int8_t P7, P8, P10, P11;

static UTIL_TIMER_Object_t MeasurementTimer;        // TimerObject for TIMER_UTIL

static void ( *bmp390_callback )(void) = NULL;        // Callback to be called when measurement is done

#ifdef BME390_FLOATSUPPORT
    static double DT1, DT2, DT3, DTlin;
    static double DP1, DP2, DP3, DP4, DP5, DP6, DP7, DP8, DP9, DP10, DP11;
#endif // FLOATSUPPORT

//static BMP390_ST_AVG AvgFilter[2];

static void CompensateT(uint32_t T);
static void CompensateP(uint32_t P);

static void enterStop(uint32_t delay);

void onTimer_MeasurementReady(void *context);
void task_readMeasurement();
//static void CalAvgValue(uint8_t *Index, int32_t *AvgBuffer, int32_t InputVal, int32_t *OutputVal);

//     uint32_t cy, cy2;                                        // benchmark time points
//    cy = DWT->CYCCNT;                                        // Benchmark
//    cy2 = DWT->CYCCNT;                                        // Benchmark
//    printf("DP %lu\r\n", cy2-cy);

//----------------------------------------------------------------------------
// Sensor initialization
//----------------------------------------------------------------------------
uint8_t bmp390_init() {
    // Activate VDD_P and I2C Pullups
    HAL_GPIO_WritePin(EN_I2C_GPIO_Port, EN_I2C_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(EN_VDD_P_N_GPIO_Port, EN_VDD_P_N_Pin, GPIO_PIN_SET);

    // Register read task so that timer event will be process in main loop
    UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_BMP390_ReadMeasurement),
    UTIL_SEQ_RFU, task_readMeasurement);

    uint8_t value = 0;

    // get sensor status, abort if busy
    uint8_t status = HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR,
    BMP390_REG_STATUS,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);

    uint32_t error = HAL_I2C_GetError(&hi2c1);

    SENSOR_LOG("BMP390 Status: %i, Error %i\r\n", status, error);
    if (!value)
        return false;

    value = BMP390_CMD_SOFTRESET;
    HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_CMD,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
    HAL_Delay(2);                                    // Duration softreset 2 ms

    // test if command execution failed
    HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_ERR,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
    if (value & BMP390_CMD_ERR)
        return false;

    // test chip ID
    HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_CHIP_ID,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
    if (value != BMP390_CHIP_ID)
        return false;

    bmp390_calibrate();

    // set ODR to 25/2Hz -> 80ms sampling period
    //value = BMP390_ODR_12P5;
    //HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_ODR, I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);

    // x32 oversampling for pressure and temperature
//    BMP390_REG_OSR, BMP390_PSMPL_X32 | BMP390_TSMPL_X32 max. Resolution
    value = BMP390_PSMPL_X32 | BMP390_TSMPL_X32;
    HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_OSR,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);

    // switch off IIR filter
//    BMP390_REG_CFG, BMP390_IIR_CF127 127 tap IIR
    value = BMP390_IIR_CF0;
    HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_CFG,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);

    /*
     // enable normal mode
     value = BMP390_P_EN | BMP390_T_EN | BMP390_MODE_NORMAL;
     HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL, I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
     */

    // energy saving: enter sleep mode
    value = BMP390_MODE_SLEEP;
    HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
    return true;
}

void task_readMeasurement() {
    // VDD_P and I2C Pullups should be active because of CFG_LPM_Flag_BMP390Active flag
    HAL_GPIO_WritePin(EN_I2C_GPIO_Port, EN_I2C_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(EN_VDD_P_N_GPIO_Port, EN_VDD_P_N_Pin, GPIO_PIN_SET);

    uint32_t T, P;

    uint8_t m[6];

    uint8_t value = 0;

    uint32_t tick_start = HAL_GetTick();
    //while (value != (BMP390_CMD_RDY | BMP390_T_RDY | BMP390_P_RDY))    // measurement is running
    while ((value & (BMP390_CMD_RDY | BMP390_T_RDY | BMP390_P_RDY))
           != (BMP390_CMD_RDY | BMP390_T_RDY | BMP390_P_RDY))
    {
        HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_STATUS,
        I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);

        int diff_ticks = HAL_GetTick() - tick_start;
        if (diff_ticks > 1000) {
        break;
        }

    }

    HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PRESS_7_0,
    I2C_MEMADD_SIZE_8BIT, &m[0], 6, 0x10);

#ifdef SET_IDLE
    value = BMP390_MODE_SLEEP;
    HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
#endif
    // energy saving: disable Sensors
    P = (m[2] << 16) | (m[1] << 8) | m[0];
    T = (m[5] << 16) | (m[4] << 8) | m[3];
    CompensateT(T);
    CompensateP(P);                        // Tf is needed here!
    SENSOR_LOG("BMP390 temperature: %.3f\r\n", bmp390_T);
    SENSOR_LOG("BMP390 pressure:    %.3f\r\n", bmp390_P);

    // MeasurementTimer done, can be switched off during STOP
    UTIL_LPM_SetFlag(CFG_LPM_Flag_BMP390Active, UTIL_LPM_DISABLE);

    if (bmp390_callback != NULL) {
        bmp390_callback();
    }
}

void onTimer_MeasurementReady(void *context) {
    UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_BMP390_ReadMeasurement),
                CFG_SEQ_Prio_0);

//    task_readMeasurement();

}

uint8_t bmp390_calibrate() {
    uint8_t m[21];

    // read calibration data
    HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_T1_LSB,
    I2C_MEMADD_SIZE_8BIT, &m[0], 21, 0x10);

    T1 = (m[1] << 8) | m[0];
    T2 = (m[3] << 8) | m[2];
    T3 = m[4];

    P1 = ((m[6] << 8) | m[5]) - 16384;
    P2 = ((m[8] << 8) | m[7]) - 16384;
    P3 = m[9];
    P4 = m[10];
    P5 = (m[12] << 8) | m[11];
    P6 = (m[14] << 8) | m[13];
    P7 = m[15];
    P8 = m[16];
    P9 = (m[18] << 8) | m[17];
    P10 = m[19];
    P11 = m[20];

#ifdef BME390_FLOATSUPPORT
    // 1 / 2^8
//    DT1 = (double)T1 / (double)0.00390625f;                // * 256
    DT1 = (double)T1 * (double)256.0f;                    // * 256
    DT2 = (double)T2 / (double)1073741824.0f;            // / 2^30
    DT3 = (double)T3 / (double)281474976710656.0f;        // / 2^48

    DP1 = (double)P1 / (double)1048576.0f;                // / 2^20
    DP2 = (double)P2 / (double)536870912.0f;            // / 2^29
    DP3 = (double)P3 / (double)4294967296.0f;            // / 2^32
    DP4 = (double)P4 / (double)137438953472.0f;            // / 2^37

    // 1/2^3
//    DP5 = (double)P5 / (double)0.125f;                    // * 8
    DP5 = (double)P5 * (double)8.0f;                    // * 8
    DP6 = (double)P6 / (double)64.0f;                    // / 2^6
    DP7 = (double)P7 / (double)256.0f;                    // / 2^8
    DP8 = (double)P8 / (double)32768.0f;                // / 2^15
    DP9 = (double)P9 / (double)281474976710656.0f;        // / 2^48
    DP10 = (double)P10 / (double)281474976710656.0f;    // / 2^48
    DP11 = (double)P11 / (double)36893488147419103232.0f; // / 2^65
#endif // FLOATSUPPORT
}

//----------------------------------------------------------------------------
// get the raw temperature and pressure data from the temperature and pressure register
//----------------------------------------------------------------------------
void bmp390_getsensordata(void) {
    HAL_GPIO_WritePin(EN_I2C_GPIO_Port, EN_I2C_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(EN_VDD_P_N_GPIO_Port, EN_VDD_P_N_Pin, GPIO_PIN_SET);

    // Needs to be active when MeasurementTimer is running
    UTIL_LPM_SetFlag(CFG_LPM_Flag_BMP390Active, UTIL_LPM_ENABLE);

    // start single measurement
    uint8_t value = BMP390_MODE_FORCED2 | BMP390_T_EN | BMP390_P_EN;
    HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL,
    I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);

    UTIL_TIMER_Create(&MeasurementTimer, 0xFFFFFFFFU, UTIL_TIMER_ONESHOT,
                onTimer_MeasurementReady,
                NULL);
    UTIL_TIMER_SetPeriod(&MeasurementTimer, 500); // estimated time for x32 oversampling -> less I2C traffic for polling
    UTIL_TIMER_Start(&MeasurementTimer);

}

#ifdef BME390_FLOATSUPPORT
//----------------------------------------------------------------------------
// Korrekturpolynom Temperatur, Fließkommaversion
// Fließkommavariante: 436 CLKs
//----------------------------------------------------------------------------
void CompensateT(uint32_t T) {

    double v1, v2;

    v1 = (double)T - DT1;
    v2 = v1 * DT2;
    bmp390_T = v2 + v1*v1*DT3;
    DTlin = bmp390_T;
}

//----------------------------------------------------------------------------
// Korrekturpolynom Druck, Fließkommaversion
// Fließkommavariante: 2117 CLKs
//----------------------------------------------------------------------------
void CompensateP(uint32_t Pin) {

    double po1, po2, po3, p;

    p = (double)Pin;
    po1 = DP5 + DP6 * DTlin + DP7 * DTlin*DTlin + DP8 * DTlin*DTlin*DTlin;
    po2 = p * (DP1 + DP2 * DTlin + DP3 * DTlin*DTlin + DP4 * DTlin*DTlin*DTlin);
    po3 = p*p * (DP9 + DP10 * DTlin) + p*p*p * DP11;
    bmp390_P = po1 + po2 + po3;
}
#else
//----------------------------------------------------------------------------
//calculation of the temperature compensate value using of the calibration data (data sheet)
// Multiplikationen: 66 CLKs
// Multiplikationen durch shifts: 31 CLKs
//----------------------------------------------------------------------------
void CompensateT(uint32_t T) {

    /*    int64_t v1, v2, v3, v4, v5, v6, Tc;

     v1 = (int64_t)(T - ((int64_t)256 * T1));
     v2 = (int64_t)(T2 * v1);
     v3 = (int64_t)(v1 * v1);
     v4 = (int64_t)v3 * T3;
     v5 = (int64_t)((int64_t)(v2 * 262144) + v4);
     v6 = (int64_t)(v5 / 4294967296);

     T_fine = v6;
     Tc = (v6 * 25) / 16384; */

    uint64_t v1, v2;
    int64_t v3, Tc;

    v1 = (uint64_t) T - ((uint64_t) T1 << 8);
    v2 = v1 * (uint64_t) T2;
    v3 = v1 * v1 * (int64_t) T3;
    Tf = (((int64_t) v2 << 18) + v3) >> 32;
    Tc = (Tf * 25) >> 14;
    bmp390_T = (double) Tc / 100.0;
}

//----------------------------------------------------------------------------
// calculation of the pressure compensate value using of the calibration data (data sheet)
// P = P5 + P6*T + P7*T^2 + P8*T^3   +   P*(P2*T + P3*T^2 + P4*T^3)   +   P^2*(P9 + P10*T)   +   P^3*P11
// Multiplikationen durch shifts: 188 CLKs
//----------------------------------------------------------------------------
void CompensateP(uint32_t P) {

    int64_t v1, v2, v3, v4, v5, v6;
    int64_t offset, sensitivity;
    uint64_t Pc;

    v1 = Tf * Tf;
    v2 = v1 >> 6;
    v3 = (v2 * Tf) >> 8;
    v4 = ((int64_t) P8 * v3) >> 5;
    v5 = ((int64_t) P7 * v1) >> 4;
    v6 = ((int64_t) P6 * Tf) << 22;
    offset = ((int64_t) P5 * ((uint64_t) 1 << 47)) + v4 + v5 + v6; // no bitwise op on signed int

    v2 = ((int64_t) P4 * v3) >> 5;
    v4 = ((int64_t) P3 * v1) << 2;
    v5 = ((int64_t) P2 * Tf) << 21;
    sensitivity = ((int64_t) P1 * ((uint64_t) 1 << 46)) + v2 + v4 + v5;

    v1 = (sensitivity >> 24) * P;
    v2 = (int64_t) P10 * Tf;
    v3 = v2 + ((int64_t) P9 << 16);
    v4 = (v3 * P) >> 13;
    v5 = (v4 * P) >> 9;
    v2 = ((int64_t) P11 * P * P) >> 16;
    v3 = (v2 * P) >> 7;
    v4 = (offset >> 2) + v1 + v5 + v3;
    Pc = ((int64_t) v4 * 25) / ((uint64_t) 1 << 40);
    bmp390_P = (double) Pc / 10000.0;
}
#endif // FLOATSUPPORT

void enterStop(uint32_t delay) {
    HAL_SuspendTick();
    HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, delay,
    RTC_WAKEUPCLOCK_RTCCLK_DIV16);

    //        HAL_PWR_EnterSTANDBYMode();
    HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
    SystemClock_Config();

    HAL_ResumeTick();
}


void bmp390_onReadyCallback(void ( *Callback )()) {
    bmp390_callback = Callback;
}

//----------------------------------------------------------------------------
//calculation of the average value
// filter of the temperature and pressure data and get an output data
// CalAvgValue(&(AvgFilter[0].Index), AvgFilter[0].AvgBuffer, TemperatureIn, TemperatureOut);
// CalAvgValue(&(AvgFilter[1].Index), AvgFilter[1].AvgBuffer, PressureIn, PressureOut);
//----------------------------------------------------------------------------
/*void CalAvgValue(uint8_t *Index, int32_t *AvgBuffer, int32_t InputVal, int32_t *OutputVal) {

 uint8_t i;

 *(AvgBuffer + ((*Index)++)) = InputVal;
 *Index &= 0x07;

 *OutputVal = 0;
 for (i = 0; i < 8; i++) {
 *OutputVal += *(AvgBuffer + i);
 }
 *OutputVal >>= 3;
 }*/


代码为BMP390在以STM32L0单片机为基础的LORAWAN工程的实现。当机器通电第一次读取数据正常,从第二次开始读取数据为0.求解决方案。

  • 写回答

43条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2025-01-13 23:42
    关注
    获得0.50元问题酬金

    以下回复引自免费微信小程序:皆我百晓生。 如问题解决,还请采纳。如仍有疑问,请回复留言或私信博主,以便获得更精准的帮助。

    STM32单片机传感器读取错误:可能是由于接线错误、设备损坏或传感器故障导致的。请检查以下情况:

    1. 确保所有的电源线和地线连接正确。
    2. 检查传感器是否在正常工作状态。
    3. 检查接线端子是否有松动或接触不良。
    4. 检查传感器是否被恶意访问或干扰。
    5. 如果所有这些都正常,可能需要联系制造商或专业人员进行进一步诊断和解决。

    如果你无法解决问题,或者怀疑你的单片机有更严重的故障,建议寻求专业的技术支持。

    评论

报告相同问题?

问题事件

  • 系统已结题 1月21日
  • 创建了问题 1月13日