dirtwillfly 发表于 2025-9-28 14:04

国产risc-v微控制器读取BMP280

本帖最后由 dirtwillfly 于 2025-9-30 16:48 编辑

第一部分:BMP280介绍

1.1 特性
BMP280是一种数字式气压传感器,在大气压力测量、气象观测、高度测量、室内外温度、湿度、气压等方面有着广泛应用。 BMP280采用了半导体技术,可以测量气体的压力,并将结果转化为数字信号,具有高精度、低功耗、小尺寸等特点。 BMP280常用于智能手机、平板电脑、手表、健康监测器等移动设备中,可以提供气压、海拔、气温、湿度等多项数据,帮助用户获取当前环境的气象信息,提高生活质量。

1.2 关键参数

测量参数:
• 气压:测量范围 300 hPa ~ 1100 hPa(相当于海拔 -500m ~ 9000m)。
• 温度:测量范围 -40°C ~ +85°C。

高精度:
• 气压精度:±0.12 hPa(相当于 ±1m 高度误差)。
• 温度精度:±1.0°C。

低功耗:
• 工作电流:2.7 μA(低功耗模式,1Hz 采样率)。

接口:
• 支持 I²C 和 SPI 通信协议,方便与微控制器连接。

1.3 模块原理图

模块在I2C模式下通过SDO引脚来确定器件地址,SDO接GND模块I2C地址为0x76,接高电平I2C地址为0x77.

原理图:



第二部分:应用开发

2.1 硬件连接
使用的HPM5361开发板P1接口有两组I2C接口,这里使用I2C0接口,即PB03和PB02引脚。
https://bbs.21ic.com/data/attachment/forum/202507/27/204618f5qsg8tj7s7t85mi.png.thumb.jpg


这两个引脚,在开发板上已经有了10K的上拉电阻,使用的BMP280上也有上拉电阻,这里可以共存,不需要特殊处理。
https://bbs.21ic.com/data/attachment/forum/202507/27/204903dwvkdk9wzklt1wxv.png.thumb.jpg
2.2 驱动代码
读寄存器:
int8_t bmp280_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bmp280_dev *dev)
{
    int8_t rslt;

    rslt = null_ptr_check(dev);
    if ((rslt == BMP280_OK) && (reg_data != NULL))
    {
      /* Mask the register address' MSB if interface selected is SPI */
      if (dev->intf == BMP280_SPI_INTF)
      {
            reg_addr = reg_addr | 0x80;
      }
      rslt = dev->read(dev->dev_id, reg_addr, reg_data, len);

      /* Check for communication error and mask with an internal error code */
      if (rslt != BMP280_OK)
      {
            rslt = BMP280_E_COMM_FAIL;
      }
    }
    else
    {
      rslt = BMP280_E_NULL_PTR;
    }

    return rslt;
}
设置寄存器:
int8_t bmp280_set_regs(uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, const struct bmp280_dev *dev)
{
    int8_t rslt;
    uint8_t temp_buff; /* Typically not to write more than 4 registers */
    uint16_t temp_len;
    uint8_t reg_addr_cnt;

    if (len > 4)
    {
      len = 4;
    }
    rslt = null_ptr_check(dev);
    if ((rslt == BMP280_OK) && (reg_addr != NULL) && (reg_data != NULL))
    {
      if (len != 0)
      {
            temp_buff = reg_data;

            /* Mask the register address' MSB if interface selected is SPI */
            if (dev->intf == BMP280_SPI_INTF)
            {
                /* Converting all the reg address into proper SPI write address
               * i.e making MSB(R/`W) bit 0
               */
                for (reg_addr_cnt = 0; reg_addr_cnt < len; reg_addr_cnt++)
                {
                  reg_addr = reg_addr & 0x7F;
                }
            }

            /* Burst write mode */
            if (len > 1)
            {
                /* Interleave register address w.r.t data for burst write*/
                interleave_data(reg_addr, temp_buff, reg_data, len);
                temp_len = ((len * 2) - 1);
            }
            else
            {
                temp_len = len;
            }
            rslt = dev->write(dev->dev_id, reg_addr, temp_buff, temp_len);

            /* Check for communication error and mask with an internal error code */
            if (rslt != BMP280_OK)
            {
                rslt = BMP280_E_COMM_FAIL;
            }
      }
      else
      {
            rslt = BMP280_E_INVALID_LEN;
      }
    }
    else
    {
      rslt = BMP280_E_NULL_PTR;
    }

    return rslt;
}
软复位:
int8_t bmp280_soft_reset(const struct bmp280_dev *dev)
{
    int8_t rslt;
    uint8_t reg_addr = BMP280_SOFT_RESET_ADDR;
    uint8_t soft_rst_cmd = BMP280_SOFT_RESET_CMD;

    rslt = null_ptr_check(dev);
    if (rslt == BMP280_OK)
    {
      rslt = bmp280_set_regs(&reg_addr, &soft_rst_cmd, 1, dev);

      /* As per the datasheet, startup time is 2 ms. */
      dev->delay_ms(2);
    }

    return rslt;
}
硬件初始化:
int8_t bmp280_init(struct bmp280_dev *dev)
{
    int8_t rslt;

    /* Maximum number of tries before timeout */
    uint8_t try_count = 5;

    rslt = null_ptr_check(dev);
    if (rslt == BMP280_OK)
    {
      while (try_count)
      {
            rslt = bmp280_get_regs(BMP280_CHIP_ID_ADDR, &dev->chip_id, 1, dev);

            /* Check for chip id validity */
            if ((rslt == BMP280_OK) &&
                (dev->chip_id == BMP280_CHIP_ID1 || dev->chip_id == BMP280_CHIP_ID2 || dev->chip_id == BMP280_CHIP_ID3))
            {
                rslt = bmp280_soft_reset(dev);
                if (rslt == BMP280_OK)
                {
                  rslt = get_calib_param(dev);
                }
                break;
            }

            /* Wait for 10 ms */
            dev->delay_ms(10);
            --try_count;
      }

      /* Chip id check failed, and timed out */
      if (!try_count)
      {
            rslt = BMP280_E_DEV_NOT_FOUND;
      }
      if (rslt == BMP280_OK)
      {
            /* Set values to default */
            dev->conf.filter = BMP280_FILTER_OFF;
            dev->conf.os_pres = BMP280_OS_NONE;
            dev->conf.os_temp = BMP280_OS_NONE;
            dev->conf.odr = BMP280_ODR_0_5_MS;
            dev->conf.spi3w_en = BMP280_SPI3_WIRE_DISABLE;
      }
    }

    return rslt;
}获取配置:
int8_t bmp280_get_config(struct bmp280_config *conf, struct bmp280_dev *dev)
{
    int8_t rslt;
    uint8_t temp = { 0, 0 };

    rslt = null_ptr_check(dev);
    if ((rslt == BMP280_OK) && (conf != NULL))
    {
      rslt = bmp280_get_regs(BMP280_CTRL_MEAS_ADDR, temp, 2, dev);
      if (rslt == BMP280_OK)
      {
            conf->os_temp = BMP280_GET_BITS(BMP280_OS_TEMP, temp);
            conf->os_pres = BMP280_GET_BITS(BMP280_OS_PRES, temp);
            conf->odr = BMP280_GET_BITS(BMP280_STANDBY_DURN, temp);
            conf->filter = BMP280_GET_BITS(BMP280_FILTER, temp);
            conf->spi3w_en = BMP280_GET_BITS_POS_0(BMP280_SPI3_ENABLE, temp);
            dev->conf = *conf;
      }
    }
    else
    {
      rslt = BMP280_E_NULL_PTR;
    }

    return rslt;
}获取状态:
int8_t bmp280_get_status(struct bmp280_status *status, const struct bmp280_dev *dev)
{
    int8_t rslt;
    uint8_t temp;

    rslt = null_ptr_check(dev);
    if ((rslt == BMP280_OK) && (status != NULL))
    {
      rslt = bmp280_get_regs(BMP280_STATUS_ADDR, &temp, 1, dev);
      status->measuring = BMP280_GET_BITS(BMP280_STATUS_MEAS, temp);
      status->im_update = BMP280_GET_BITS_POS_0(BMP280_STATUS_IM_UPDATE, temp);
    }
    else
    {
      rslt = BMP280_E_NULL_PTR;
    }

    return rslt;
}获取电源模式
int8_t bmp280_get_power_mode(uint8_t *mode, const struct bmp280_dev *dev)
{
    int8_t rslt;
    uint8_t temp;

    rslt = null_ptr_check(dev);
    if ((rslt == BMP280_OK) && (mode != NULL))
    {
      rslt = bmp280_get_regs(BMP280_CTRL_MEAS_ADDR, &temp, 1, dev);
      *mode = BMP280_GET_BITS_POS_0(BMP280_POWER_MODE, temp);
    }
    else
    {
      rslt = BMP280_E_NULL_PTR;
    }

    return rslt;
}设置电源模式:
int8_t bmp280_set_power_mode(uint8_t mode, struct bmp280_dev *dev)
{
    int8_t rslt;

    rslt = null_ptr_check(dev);
    if (rslt == BMP280_OK)
    {
      rslt = conf_sensor(mode, &dev->conf, dev);
    }

    return rslt;
}获取原始数据:
int8_t bmp280_get_uncomp_data(struct bmp280_uncomp_data *uncomp_data, const struct bmp280_dev *dev)
{
    int8_t rslt;
    uint8_t temp = { 0 };

    rslt = null_ptr_check(dev);
    if ((rslt == BMP280_OK) && (uncomp_data != NULL))
    {
      rslt = bmp280_get_regs(BMP280_PRES_MSB_ADDR, temp, 6, dev);
      if (rslt == BMP280_OK)
      {
            uncomp_data->uncomp_press =
                (int32_t) ((((uint32_t) (temp)) << 12) | (((uint32_t) (temp)) << 4) | ((uint32_t) temp >> 4));
            uncomp_data->uncomp_temp =
                (int32_t) ((((int32_t) (temp)) << 12) | (((int32_t) (temp)) << 4) | (((int32_t) (temp)) >> 4));
            rslt = st_check_boundaries((int32_t)uncomp_data->uncomp_temp, (int32_t)uncomp_data->uncomp_press);
      }
      else
      {
            rslt = BMP280_E_UNCOMP_DATA_CALC;
      }
    }
    else
    {
      rslt = BMP280_E_NULL_PTR;
    }

    return rslt;
}





桃乐丝 发表于 2025-10-4 12:00

很不错,在这个基础上修改下,就可以拿到项目上用的。比AI写的要靠谱多了
页: [1]
查看完整版本: 国产risc-v微控制器读取BMP280