1、前言
更新记录:
2023-10-06:(介绍BME280相关寄存器使用)
2025-04-19:(补充程序)
参考文章:BMP280气压温度传感器详细使用教程
2、背景介绍
我用的BMP280模块为SPI接口。
3、寄存器介绍
最左边一栏 Register Name 就是BMP280的全部寄存器。下面先依次介绍各寄存器,完了再介绍如何使用及使用流程。
1、Register id - 0xD0
#暂无中文解释
The “id” register contains the chip identification number chip_id[7:0], which is 0x58.
This number can be read as soon as the device finished the power-on-reset.
2、Register reset - 0xE0
#往寄存器0xE0写入0xB6即可软重启
The “reset” register contains the soft reset word reset[7:0].
If the value 0xB6 is written to the register, the device is
reset using the complete power-on-reset procedure. Writing
other values than 0xB6 has no effect. The readout value is always 0x00.
3、Register status - 0xF3
#从寄存器0xF3读取一个字节,判断该字节的Bit3和Bit0可以知道当前设备状态。
#下图为两个数据位的解释。
The “status” register contains two bits which indicate the status of the device.
4、Register ctrl_meas - 0xF4
#暂无中文解释
The “ctrl_meas” register sets the data acquisition options of the device.
5、Register config - 0xF5
#暂无中文解释
The “config” register sets the rate, filter and interface options of the device.
Writes to the “config” register in normal mode may be ignored.
In sleep mode writes are not ignored.
6、Register press - 0xF7-0xF9
#这就是大气压数据,但读出来的值不能直接使用,需要进行计算
#暂无其它中文解释
The “press” register contains the raw pressure measurement output data up[19:0].
For details on how to read out the pressure and temperature information from the device.
7、Register temp - 0xFA-0xFC
#这就是温度数据,共占3个寄存器,分别是0xfa(MSB)、0xfb(LSB)、0xfc(XLSB)
#所以要读取三个寄存器的值再拼在一起,MSB为最高位,其是LSB,再是XLSB。
#注意寄存器0xfc(XLSB)的有效位只有高4位(bit7 bit6 bit5 bit4)。低四位为均默认为0,不能包含在内。
#举例:寄存器0xfa的值为0x87,寄存器0xfb的值为0xfa,寄存器0xfc的值为0x80。拼在一起就是0x87fa8,而不是0x87fa80。
#注意:该三个寄存器拼出来的值并不是最后的温度值,而是还需要一些操作的。后面介绍。
The “temp” register contains the raw temperature measurement output data ut[19:0].
For details on how to read out the pressure and temperature information from the device.
以上就是所有寄存器的功能介绍,接下来介绍用法。
4、使用流程介绍
- bmp280上电后,先设置寄存器0xf4(ctrl_meas)和0xf5(config)进行初始化。
往 0xf4 写入 0x55 #选择16倍气压过采样,2倍温度过采样,force mode
往 0xf5 写入 0x10 #由于使用force mode时间不关心,全填0,滤波器使用16倍,SPI模式不关心,写0
- 读取温度数据,就像上面介绍temp寄存器一样的用法。
读 0xfa、0xfb、0xfc,随后将值拼在一起。
上面说了这值不能直接使用。
BMP280还有一些寄存器是用来存放修正参数的,修正参数是固定的、是需要参与计算的,所以得先取出来。
以下是所有修正参数的寄存器
其中dig_T1 ~ dig_T3是温度的修正参数;
其中dig_P1 ~ dig_P9是大气压的修正参数;
一样是MSB为高位,LSB为低位。例如0x89为6e,0x88为0xbc,则dig_T1为0x6ebc;
修正参数知道了,那参与计算的算法是啥?BMP280数据手册有给出。如下:
//BMP280.adc_T就是那三个temp寄存器(0x7a-0x7c)拼出来的值
//BMP280.T1~BMP280.T3就是dig_T1~dig_T3
float BMP280_Compute_T(void) //温度计算
{
int32_t var1, var2,T;
var1 = ((((BMP280.adc_T >> 3) - ((int32_t)BMP280.T1 << 1))) *((int32_t)BMP280.T2)) >>11;
var2 = (((((BMP280.adc_T >> 4) - ((int32_t)BMP280.T1)) *((BMP280.adc_T >> 4) - ((int32_t)BMP280.T1))) >>12) *((int32_t)BMP280.T3)) >>14;
BMP280.t_fine = var1 + var2;
T = (BMP280.t_fine * 5 + 128) >> 8;
return (float)T/100;
}
//暂无中文解释
float BMP280_Compute_P(void) //大气压计算
{
int64_t var1, var2, p;
var1 = ((int64_t)BMP280.t_fine) - 128000;
var2 = var1 * var1 * (int64_t)BMP280.P6;
var2 = var2 + ((var1 * (int64_t)BMP280.P5) << 17);
var2 = var2 + (((int64_t)BMP280.P4) << 35);
var1 = ((var1 * var1 * (int64_t)BMP280.P3) >> 8) +((var1 * (int64_t)BMP280.P2) << 12);
var1 =(((((int64_t)1) << 47) + var1)) * ((int64_t)BMP280.P1) >> 33;
if (var1 == 0)
{
return 0;
}
else
{
p = 1048576 - BMP280.adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)BMP280.P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)BMP280.P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)BMP280.P7) << 4);
return (float)p/256;
}
}
- 每次测量结束后,要重新往寄存器ctrl_meas的低两位mode[1:0]上写0b01或0b10使能传感器又一次测量,否则每次读取的值都是一样的。
往寄存器ctrl_meas 0xF4 写入 0x56或0x55 后再读取新值
5、编写驱动程序
5.1、编写spi bsp程序
下面直接给出程序,涉及两个文件,分别是spi.c和spi.h。
spi.h:
/* spi.h */
#ifndef _SPI_H
#define _SPI_H
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <gpiod.h>
#include <stdint.h>
#include <linux/spi/spidev.h>
#include <pthread.h>
typedef struct spi_handle
{
char *dev_name;
int fd;
pthread_mutex_t mutex;
struct gpiod_chip *cs_gpiochip;
struct gpiod_line *cs_gpioline;
}spi_handle_t;
typedef enum
{
SPIMODE0 = SPI_MODE_0,
SPIMODE1 = SPI_MODE_1,
SPIMODE2 = SPI_MODE_2,
SPIMODE3 = SPI_MODE_3,
}SPI_MODE;
typedef enum
{
S_1M = 1000000,
S_6_75M = 6750000,
S_8M = 8000000,
S_13_5M = 13500000,
S_27M = 27000000,
}SPI_SPEED;
spi_handle_t *spi_handle_alloc(const char *spi_dev, SPI_MODE spi_mode, SPI_SPEED spi_speed, const char *cs_chip, unsigned int cs_num);
void spi_write_and_read(spi_handle_t *spi, unsigned char *send_buf, unsigned int send_buf_len, unsigned char *recv_buf);
void spi_write_then_read(spi_handle_t *spi, unsigned char *send_buf, unsigned int send_buf_len, unsigned char *recv_buf, unsigned int recv_buf_len);
void spi_write_byte_data(spi_handle_t *spi, unsigned char data);
void spi_write_nbyte_data(spi_handle_t *spi, unsigned char *send_buf, unsigned int send_buf_len);
void spi_handle_free(spi_handle_t *spi);
#endif
spi.c:
/* spi.c */
#include "spi.h"
/*******************************
* @brief : SPI同时发送数据和接收数据
* @param : spi - SPI设备句柄
* send_buf - 发送缓冲区
* send_buf_len - 发送缓冲区长度
* recv_buf - 接收缓冲区
* @return: 无
*******************************/
void spi_write_and_read(spi_handle_t *spi, unsigned char *send_buf, unsigned int send_buf_len, unsigned char *recv_buf)
{
struct spi_ioc_transfer xfer[1];
int status;
if (spi == NULL)
return;
if (send_buf == NULL || recv_buf == NULL)
return;
memset(xfer, 0, sizeof(xfer));
xfer[0].tx_buf = (unsigned long)send_buf;
xfer[0].rx_buf = (unsigned long)recv_buf;
xfer[0].len = send_buf_len;
pthread_mutex_lock(&(spi->mutex));
gpiod_line_set_value(spi->cs_gpioline, 0);
status = ioctl(spi->fd, SPI_IOC_MESSAGE(1), xfer);
if (status < 0)
printf("SPI_IOC_MESSAGE failed!\n");
gpiod_line_set_value(spi->cs_gpioline, 1);
pthread_mutex_unlock(&(spi->mutex));
}
/*******************************
* @brief : SPI先发送数据后接收数据
* @param : spi - SPI设备句柄
* send_buf - 发送缓冲区
* send_buf_len - 发送缓冲区长度
* recv_buf - 接收缓冲区
* recv_buf_len - 接收缓冲区长度
* @return: 无
*******************************/
void spi_write_then_read(spi_handle_t *spi, unsigned char *send_buf, unsigned int send_buf_len, unsigned char *recv_buf, unsigned int recv_buf_len)
{
struct spi_ioc_transfer xfer[2];
int status;
if (spi == NULL)
return;
if (send_buf == NULL || recv_buf == NULL)
return;
memset(xfer, 0, sizeof(xfer));
xfer[0].tx_buf = (unsigned long)send_buf;
xfer[0].len = send_buf_len;
xfer[1].rx_buf = (unsigned long)recv_buf;
xfer[1].len = recv_buf_len;
pthread_mutex_lock(&(spi->mutex));
gpiod_line_set_value(spi->cs_gpioline, 0);
status = ioctl(spi->fd, SPI_IOC_MESSAGE(2), xfer);
if (status < 0)
printf("SPI_IOC_MESSAGE failed!\n");
gpiod_line_set_value(spi->cs_gpioline, 1);
pthread_mutex_unlock(&(spi->mutex));
}
/*******************************
* @brief : SPI发送一个字节
* @param : spi - SPI设备句柄
* data - 待发送的字节数据
* @return: 无
*******************************/
void spi_write_byte_data(spi_handle_t *spi, unsigned char data)
{
unsigned char buff[1] = {data};
if (spi == NULL)
return;
pthread_mutex_lock(&(spi->mutex));
gpiod_line_set_value(spi->cs_gpioline, 0);
write(spi->fd, &buff, 1);
gpiod_line_set_value(spi->cs_gpioline, 1);
pthread_mutex_unlock(&(spi->mutex));
}
/*******************************
* @brief : 通过SPI发送多个字节数据
* @param : spi - SPI设备句柄
* send_buf - 发送缓冲区
* send_buf_len - 发送缓冲区长度
* @return: 无
*******************************/
void spi_write_nbyte_data(spi_handle_t *spi, unsigned char *send_buf, unsigned int send_buf_len)
{
struct spi_ioc_transfer xfer[2];
unsigned char recv_buf[send_buf_len];
int status;
if (spi == NULL)
return;
if (send_buf == NULL)
return;
memset(xfer, 0, sizeof(xfer));
memset(recv_buf, 0, sizeof(send_buf_len));
xfer[0].tx_buf = (unsigned long)send_buf;
xfer[0].rx_buf = (unsigned long)recv_buf;
xfer[0].len = send_buf_len;
pthread_mutex_lock(&(spi->mutex));
gpiod_line_set_value(spi->cs_gpioline, 0);
status = ioctl(spi->fd, SPI_IOC_MESSAGE(1), xfer);
if (status < 0)
printf("SPI_IOC_MESSAGE failed!\n");
gpiod_line_set_value(spi->cs_gpioline, 1);
pthread_mutex_unlock(&(spi->mutex));
}
/*******************************
* @brief : 分配并初始化SPI设备句柄
* @param : spi_dev - SPI设备文件路径
* spi_mode - SPI模式
* spi_speed - SPI通信速度
* cs_chip - 片选GPIO芯片
* cs_line - 片选GPIO引脚
* @return: 成功返回SPI设备句柄,失败返回NULL
*******************************/
spi_handle_t *spi_handle_alloc(const char *spi_dev, SPI_MODE spi_mode, SPI_SPEED spi_speed, const char *cs_chip, unsigned int cs_line)
{
int ret;
int fd;
char spi_bits = 8;
SPI_SPEED speed = (uint32_t)spi_speed;
if (!spi_dev)
return NULL;
if (!cs_chip)
return NULL;
fd = open(spi_dev, O_RDWR);
if (fd < 0)
{
printf("open %s failed!\n", spi_dev);
return NULL;
}
/* alloc spi_handle_t */
spi_handle_t *spi = (spi_handle_t *)malloc(sizeof(spi_handle_t));
if (!spi)
{
printf("spi_handle_t allocation failed!\n");
return NULL;
}
spi->fd = fd;
/* spi mode setting */
ret = ioctl(spi->fd, SPI_IOC_WR_MODE, &spi_mode);
if (ret < 0)
{
printf("SPI_IOC_WR_MODE failed!\n");
free(spi);
return NULL;
}
/* bits per word */
ret = ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits);
if (ret < 0)
{
printf("SPI_IOC_WR_BITS_PER_WORD failed!\n");
free(spi);
return NULL;
}
/* spi speed setting */
ret = ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret < 0)
{
printf("SPI_IOC_WR_MAX_SPEED_HZ failed!\n");
free(spi);
return NULL;
}
spi->dev_name = (char *)malloc(strlen(spi_dev) + 1);
if (!(spi->dev_name))
{
printf("dev_name allocation failed!\n");
free(spi);
return NULL;
}
strcpy(spi->dev_name, spi_dev);
ret = pthread_mutex_init(&spi->mutex, NULL);
if (ret != 0)
{
printf("pthread_mutex_init failed!\n");
free(spi->dev_name);
free(spi);
return NULL;
}
/* cs pin init */
spi->cs_gpiochip = gpiod_chip_open(cs_chip);
if (spi->cs_gpiochip == NULL)
{
printf("gpiod_chip_open failed!\n");
free(spi->dev_name);
free(spi);
return NULL;
}
spi->cs_gpioline = gpiod_chip_get_line(spi->cs_gpiochip, cs_line);
if (spi->cs_gpioline == NULL)
{
printf("gpiod_chip_get_line failed!\n");
free(spi->dev_name);
free(spi);
return NULL;
}
ret = gpiod_line_request_output(spi->cs_gpioline, "cs_gpioline", 1);
if (ret < 0)
{
printf("gpiod_line_request_output failed!\n");
free(spi->dev_name);
free(spi);
return NULL;
}
return spi;
}
/*******************************
* @brief : 释放SPI设备句柄
* @param : spi - SPI设备句柄
* @return: 无
*******************************/
void spi_handle_free(spi_handle_t *spi)
{
if (!spi)
return;
if (spi->cs_gpioline)
gpiod_line_release(spi->cs_gpioline);
if (spi->cs_gpiochip)
gpiod_chip_close(spi->cs_gpiochip);
if (spi->dev_name)
{
free(spi->dev_name);
}
pthread_mutex_destroy(&spi->mutex);
free(spi);
}
5.2、编写bme280驱动程序
下面直接给出程序,该程序是按照bme280来写的,bme280比bmp280多了一个湿度数据,向下兼容bmp280。涉及两个文件,分别是bme280.h和bme280.c
bme280.h:
/* bme280.h */
#ifndef _BME280_H
#define _BME280_H
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <gpiod.h>
#include <stdint.h>
#include "spi.h"
/* BME280 REGISTER */
#define BME280_REGISTER_ID (0xD0)
#define BME280_REGISTER_RESET (0xE0)
#define BME280_REGISTER_STATUS (0xF3)
#define BME280_REGISTER_CTRL_MEAS (0xF4)
#define BME280_REGISTER_CONFIG (0xF5)
#define BME280_REGISTER_PRESS_MSB (0xF7)
#define BME280_REGISTER_PRESS_LSB (0xF8)
#define BME280_REGISTER_PRESS_XLSB (0xF9)
#define BME280_REGISTER_TEMP_MSB (0xFA)
#define BME280_REGISTER_TEMP_LSB (0xFB)
#define BME280_REGISTER_TEMP_XLSB (0xFC)
#define BME280_REGISTER_HUMI_MSB (0xFD)
#define BME280_REGISTER_HUMI_LSB (0xFE)
struct bme280_parameter{
unsigned short int T1;
short int T2;
short int T3;
unsigned short int P1;
short int P2;
short int P3;
short int P4;
short int P5;
short int P6;
short int P7;
short int P8;
short int P9;
unsigned char H1;
short int H2;
unsigned char H3;
short int H4;
short int H5;
unsigned char H6;
int adc_T;
int adc_P;
int adc_H;
int t_fine;
};
int bme280_init(const char *spi_dev, const char *cs_chip, unsigned int cs_pin);
void bme280_exit(void);
float bme280_get_temp(void);
float bme280_get_pres(void);
float bme280_get_humi(void);
#endif
bme280.c:
/* bme280.c */
#include "bme280.h"
unsigned char id;
struct bme280_parameter bme280;
static spi_handle_t *bme280_spi;
/*****************************
* @brief : bme280写寄存器
* @param : reg 目标寄存器
* @param : byte 要往目标寄存器写入的值
* @return: none
*****************************/
static void bme280_write_reg(const unsigned char reg, const unsigned char byte)
{
unsigned char send_buf[2];
send_buf[0] = reg;
send_buf[1] = byte;
spi_write_nbyte_data(bme280_spi, send_buf, sizeof(send_buf));
}
/*****************************
* @brief : bme280读寄存器
* @param : reg 目标寄存器
* @return: 返回从目标寄存器读到的值
*****************************/
static unsigned char bme280_read_reg(const unsigned char reg)
{
unsigned char send_buf[1];
unsigned char recv_buf[1];
memset(send_buf, reg, sizeof(send_buf));
memset(recv_buf, 0, sizeof(recv_buf));
spi_write_then_read(bme280_spi, send_buf, sizeof(send_buf), recv_buf, sizeof(recv_buf));
return recv_buf[0];
}
/*****************************
* @brief : bme280读修正参数
* @param : none
* @return: none
*****************************/
static void bme280_read_fix_parameter(void)
{
unsigned char tmp;
//dig_T1
bme280.T1 = bme280_read_reg(0x89);
bme280.T1 <<= 8;
bme280.T1 |= bme280_read_reg(0x88);
//dig_T2
bme280.T2 = bme280_read_reg(0x8B);
bme280.T2 <<= 8;
bme280.T2 |= bme280_read_reg(0x8A);
//dig_T3
bme280.T3 = bme280_read_reg(0x8D);
bme280.T3 <<= 8;
bme280.T3 |= bme280_read_reg(0x8C);
//dig_P1
bme280.P1 = bme280_read_reg(0x8F);
bme280.P1 <<= 8;
bme280.P1 |= bme280_read_reg(0x8E);
//dig_P2
bme280.P2 = bme280_read_reg(0x91);
bme280.P2 <<= 8;
bme280.P2 |= bme280_read_reg(0x90);
//dig_P3
bme280.P3 = bme280_read_reg(0x93);
bme280.P3 <<= 8;
bme280.P3 |= bme280_read_reg(0x92);
//dig_P4
bme280.P4 = bme280_read_reg(0x95);
bme280.P4 <<= 8;
bme280.P4 |= bme280_read_reg(0x94);
//dig_P5
bme280.P5 = bme280_read_reg(0x97);
bme280.P5 <<= 8;
bme280.P5 |= bme280_read_reg(0x96);
//dig_P6
bme280.P6 = bme280_read_reg(0x99);
bme280.P6 <<= 8;
bme280.P6 |= bme280_read_reg(0x98);
//dig_P7
bme280.P7 = bme280_read_reg(0x9B);
bme280.P7 <<= 8;
bme280.P7 |= bme280_read_reg(0x9A);
//dig_P8
bme280.P8 = bme280_read_reg(0x9D);
bme280.P8 <<= 8;
bme280.P8 |= bme280_read_reg(0x9C);
//dig_P9
bme280.P9 = bme280_read_reg(0x9F);
bme280.P9 <<= 8;
bme280.P9 |= bme280_read_reg(0x9E);
//dig_H1
bme280.H1 = bme280_read_reg(0xA1);
//dig_H2
bme280.H2 = bme280_read_reg(0xE2);
bme280.H2 <<= 8;
bme280.H2 |= bme280_read_reg(0xE1);
//dig_H3
bme280.H3 = bme280_read_reg(0xE3);
//dig_H4
bme280.H4 = bme280_read_reg(0xE4);
bme280.H4 <<= 4;
tmp = bme280_read_reg(0xE5);
tmp &= 0x0f;
bme280.H4 |= tmp;
//dig_H
bme280.H5 = bme280_read_reg(0xE6);
bme280.H5 <<= 4;
tmp = bme280_read_reg(0xE5);
tmp &= 0xf0;
tmp >>= 4;
bme280.H5 |= tmp;
//dig_H6
bme280.H6 = bme280_read_reg(0xE7);
}
/*****************************
* @brief : bme280读温度值
* @param : none
* @return: none
*****************************/
static void bme280_read_temp_parameter(void)
{
int ret;
// read temp data
ret = bme280_read_reg(BME280_REGISTER_TEMP_MSB);
bme280.adc_T = ret;
bme280.adc_T <<= 8;
ret = bme280_read_reg(BME280_REGISTER_TEMP_LSB);
bme280.adc_T |= ret;
bme280.adc_T <<= 8;
ret = bme280_read_reg(BME280_REGISTER_TEMP_XLSB);
bme280.adc_T |= ret;
bme280.adc_T >>= 4;
}
/*****************************
* @brief : bme280读压力值
* @param : none
* @return: none
*****************************/
static void bme280_read_pres_parameter(void)
{
int ret;
// read pressure data
ret = bme280_read_reg(BME280_REGISTER_PRESS_MSB);
bme280.adc_P = ret;
bme280.adc_P <<= 8;
ret = bme280_read_reg(BME280_REGISTER_PRESS_LSB);
bme280.adc_P |= ret;
bme280.adc_P <<= 8;
ret = bme280_read_reg(BME280_REGISTER_PRESS_XLSB);
bme280.adc_P |= ret;
bme280.adc_P >>= 4;
}
/*****************************
* @brief : bme280读湿度值
* @param : none
* @return: none
*****************************/
static void bme280_read_humi_parameter(void)
{
int ret;
// read humi data
ret = bme280_read_reg(BME280_REGISTER_HUMI_MSB);
bme280.adc_H = ret;
bme280.adc_H <<= 8;
ret = bme280_read_reg(BME280_REGISTER_HUMI_LSB);
bme280.adc_H |= ret;
}
/*****************************
* @brief : bme280重新测量环境数据
* @param : none
* @return: none
*****************************/
static void bme280_remeasure(void)
{
bme280_write_reg(BME280_REGISTER_CTRL_MEAS, 0x55);
usleep(45000);
}
/*****************************
* @brief : bme280根据修正参数和温度值计算最终的温度数据
* @param : none
* @return: 返回温度数据
*****************************/
static float bme280_compute_temp(void)
{
int var1, var2, T;
var1 = ((((bme280.adc_T>>3) - (bme280.T1<<1))) * bme280.T2) >> 11;
var2 = (((((bme280.adc_T>>4)-bme280.T1) * (bme280.adc_T>>4)-bme280.T1) >> 12) * bme280.T3) >> 14;
bme280.t_fine = var1 + var2;
T = (bme280.t_fine * 5 + 128) >> 8;
return (float)T/100;
}
/*****************************
* @brief : bme280根据修正参数和压力值计算最终的压力数据
* @param : none
* @return: 返回压力数据
*****************************/
static float bme280_compute_pres(void)
{
int64_t var1, var2, p;
var1 = ((int64_t)bme280.t_fine) - 128000;
var2 = var1 * var1 * (int64_t)bme280.P6;
var2 = var2 + ((var1 * (int64_t)bme280.P5) << 17);
var2 = var2 + (((int64_t)bme280.P4) << 35);
var1 = ((var1 * var1 * (int64_t)bme280.P3) >> 8) +((var1 * (int64_t)bme280.P2) << 12);
var1 =(((((int64_t)1) << 47) + var1)) * ((int64_t)bme280.P1) >> 33;
if (var1 == 0)
{
return 0;
}
else
{
p = 1048576 - bme280.adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)bme280.P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)bme280.P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)bme280.P7) << 4);
return (float)p/256;
}
}
/*****************************
* @brief : bme280根据修正参数和湿度值计算最终的湿度数据
* @param : none
* @return: 返回湿度数据
*****************************/
static float bme280_compute_humi(void)
{
double var_H;
var_H = (((double)bme280.t_fine) - 76800.00);
var_H = (bme280.adc_H - (((double)bme280.H4) * 64.0 + ((double)bme280.H5) / 16384.0 * var_H)) * (((double)bme280.H2) / 65536.0 * (1.0 + ((double)bme280.H6) / 67108864.0 * var_H * (1.0 + ((double)bme280.H3) / 67108864.0 * var_H)));
var_H = var_H * (1.0 - ((double)bme280.H1) * var_H / 524288.0);
if(var_H > 100.0)
{
var_H = 100.0;
}
else if(var_H < 0.0)
{
var_H = 0.0;
}
return var_H;
}
/*****************************
* @brief : bme280获取温度数据
* @param : none
* @return: 返回温度数据
*****************************/
float bme280_get_temp(void)
{
bme280_remeasure();
bme280_read_temp_parameter();
return bme280_compute_temp();
}
/*****************************
* @brief : bme280获取压力数据
* @param : none
* @return: 返回压力数据
*****************************/
float bme280_get_pres(void)
{
bme280_remeasure();
// 计算压力值需要用到温度的数据
bme280_read_temp_parameter();
bme280_compute_temp();
bme280_read_pres_parameter();
return bme280_compute_pres();
}
/*****************************
* @brief : bme280获取湿度数据
* @param : none
* @return: 返回湿度数据
*****************************/
float bme280_get_humi(void)
{
bme280_remeasure();
// 计算湿度值需要用到温度的数据
bme280_read_temp_parameter();
bme280_compute_temp();
bme280_read_humi_parameter();
return bme280_compute_humi();
}
/*****************************
* @brief : bme280初始化
* @param : none
* @return: 0初始化成功 -1初始化失败
*****************************/
int bme280_init(const char *spi_dev, const char *cs_chip, unsigned int cs_line)
{
int ret;
if (!spi_dev)
return -1;
if (!cs_chip)
return -1;
/* spi init */
bme280_spi = spi_handle_alloc(spi_dev, SPIMODE0, S_1M, cs_chip, cs_line);
if (!bme280_spi)
return -1;
/* 读取id,检测通信是否正常 */
id = bme280_read_reg(BME280_REGISTER_ID);
if(id == 0x58)
printf("dev is BMP280, id : 0x%x\n", id);
else if(id == 0x60)
printf("dev is BME280, id : 0x%x\n", id);
else
{
printf("can not find BME280/BMP280, read id: 0x%x\n", id);
return -1;
}
/* 读取修正参数 */
bme280_read_fix_parameter();
/* reset */
bme280_write_reg(BME280_REGISTER_RESET, 0xB6);
/* bme280配置 */
/* 16倍气压过采样,2倍温度过采样,force mode */
bme280_write_reg(BME280_REGISTER_CTRL_MEAS, 0x55);
/* 滤波器系数16 */
bme280_write_reg(BME280_REGISTER_CONFIG, 0x10);
bme280_write_reg(0x74, 0xff);
return 0;
}
/*****************************
* @brief : bme280反初始化
* @param : none
* @return: none
*****************************/
void bme280_exit(void)
{
if (bme280_spi)
spi_handle_free(bme280_spi);
}
6、测试
测试还需要编写一个main.c,如下:
/* main.c */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <math.h>
#include "bme280.h"
int main()
{
int ret;
float bmp280_pres = 0;
float bmp280_temp = 0;
ret = bme280_init("/dev/spidev3.0", "/dev/gpiochip6", 11);
if(ret != 0)
{
printf("bmp280 init failed!\n");
return -1;
}
while(1)
{
bmp280_pres = bme280_get_pres();
bmp280_pres = bmp280_pres * 0.001;
bmp280_temp = bme280_get_temp();
printf("pressure = %.2f kPa\n", bmp280_pres);
printf("temp = %.2f\n\n", bmp280_temp);
sleep(1);
}
return 0;
}
执行如下命令编译程序:
# 如果是buildroot系统,需要交叉编译。我这使用的是ubuntu系统,直接gcc编译。
gcc -o build main.c spi.c bme280.c -lgpiod
运行程序:
sudo ./build