背景
由于智能睡眠环境监测,最主要的数据是温度、湿度、空气质量、气压,那么最好是采用四合一的传感器,那么博世正好有这一款传感器BME680,因此本篇文章主要是记录一下驱动BME680。
一、BME680传感器介绍
BME680是一款气压、气体、温湿度的四合一传感器,主要特性有低功耗,能够计算出空气质量。
并且1s内能够显示计算出气体电阻。数据手册的特性如下图:
二、编写代码
主要参照网络大神使用wiringPi库进行I2C驱动,大神,直接造了轮子,就拿来用了。个人主要是把微雪的代码拿来用就可以了。
参考链接:BME680 Environmental Sensor - Waveshare Wiki
主要代码如下:
#include "main.h"
#define BME68X_VALID_DATA UINT8_C(0xB0)
//Raspberry 5 platform's default I2C device file
#define IIC_Dev "/dev/i2c-1"
struct bme68x_dev dev;
int fd;
void user_delay_us(uint32_t period, void *intf_ptr)
{
usleep(period);
}
int8_t user_i2c_read(uint8_t reg_addr, uint8_t *data, uint32_t len,void *intf_ptr)
{
write(fd, ®_addr,1);
read(fd, data, len);
return 0;
}
int8_t user_i2c_write(uint8_t reg_addr, const uint8_t *data, uint32_t len,void *intf_ptr)
{
int8_t *buf;
buf = malloc(len +1);
buf[0] = reg_addr;
memcpy(buf +1, data, len);
write(fd, buf, len +1);
free(buf);
return 0;
}
void print_sensor_data(struct bme68x_data *comp_data)
{
#ifdef BME68X_USE_FPU
printf("temperature:%0.2f*C pressure:%0.2fhPa humidity:%0.2f%% Gas resistance:%0.2f ohm\r\n",\
comp_data->temperature, comp_data->pressure/100, comp_data->humidity, comp_data->gas_resistance );
sysData.envTemp = comp_data->temperature;
sysData.envHumidity = comp_data->humidity;
sysData.airPressure = comp_data->pressure / 100;
//sysData.airQuality = comp_data->gas_resistance / 100;
printf("\r\b\r");
#else
printf("temperature:%ld*C pressure:%ldhPa humidity:%ld%% Gas resistance:%lu ohm\r\n",comp_data->temperature, comp_data->pressure/100, comp_data->humidity, comp_data->gas_resistance );
printf("\r\b\r");
#endif
}
int8_t stream_sensor_data_forced_mode(struct bme68x_dev *dev)
{
int8_t rslt;
uint8_t n_fields;
uint32_t del_period;
struct bme68x_conf conf;
struct bme68x_heatr_conf heatr_conf;
struct bme68x_data comp_data;
/* Recommended mode of operation: Indoor navigation */
conf.os_hum = BME68X_OS_1X;
conf.os_pres = BME68X_OS_16X;
conf.os_temp = BME68X_OS_2X;
conf.filter = BME68X_FILTER_SIZE_15;
rslt = bme68x_set_conf(&conf, dev);
dev->delay_us(40*1000,dev->intf_ptr);
heatr_conf.enable = BME68X_ENABLE;
heatr_conf.heatr_temp = 300;
heatr_conf.heatr_dur = 100;
rslt = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &heatr_conf, dev);
dev->delay_us(40*1000,dev->intf_ptr);
printf("Temperature Pressure Humidity Gas resistance\r\n");
/* Continuously stream sensor data */
rslt = bme68x_set_op_mode(BME68X_FORCED_MODE, dev);
/* Wait for the measurement to complete and print data [url=home.php?mod=space&uid=1140227]@25Hz[/url] */
del_period = bme68x_get_meas_dur(BME68X_FORCED_MODE, &conf, dev) + (heatr_conf.heatr_dur * 1000);
dev->delay_us(del_period*5, dev->intf_ptr);
rslt = bme68x_get_data(BME68X_FORCED_MODE, &comp_data, &n_fields, dev);
if(n_fields)
{
print_sensor_data(&comp_data);
}
return rslt;
}
int8_t stream_sensor_data_parallel_mode(struct bme68x_dev *dev)
{
int8_t rslt;
uint8_t n_fields;
struct bme68x_conf conf;
struct bme68x_heatr_conf heatr_conf;
struct bme68x_data comp_data[3];
uint16_t temp_prof[10] = { 320, 100, 100, 100, 200, 200, 200, 320, 320, 320 };
uint16_t mul_prof[10] = { 5, 2, 10, 30, 5, 5, 5, 5, 5, 5 };
/* Recommended mode of operation: Indoor navigation */
conf.os_hum = BME68X_OS_1X;
conf.os_pres = BME68X_OS_16X;
conf.os_temp = BME68X_OS_2X;
conf.filter = BME68X_FILTER_SIZE_15;
conf.odr = BME68X_ODR_62_5_MS;
rslt = bme68x_set_conf(&conf, dev);
dev->delay_us(40*1000,dev->intf_ptr);
heatr_conf.enable = BME68X_ENABLE;
heatr_conf.heatr_temp_prof = temp_prof;
heatr_conf.heatr_dur_prof = mul_prof;
heatr_conf.shared_heatr_dur = 140 - (bme68x_get_meas_dur(BME68X_PARALLEL_MODE, &conf, dev) / 1000);
heatr_conf.profile_len = 10;
rslt = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &heatr_conf, dev);
dev->delay_us(40*1000,dev->intf_ptr);
rslt = bme68x_set_op_mode(BME68X_PARALLEL_MODE, dev);
dev->delay_us(40*1000,dev->intf_ptr);
printf("Temperature Pressure Humidity Gas resistance\r\n");
while (1) {
/* Delay while the sensor completes a measurement */
dev->delay_us(70*1000,dev->intf_ptr);
rslt = bme68x_get_data(BME68X_FORCED_MODE, comp_data, &n_fields, dev);
for (uint8_t i = 0; i < n_fields; i++)
{
if (comp_data[i].status == BME68X_VALID_DATA)
{
print_sensor_data(&comp_data[i]);
}
}
}
return rslt;
}
void bme680Init(void) {
static uint8_t dev_addr=BME68X_I2C_ADDR_HIGH;
int8_t rslt = BME68X_OK;
int8_t bsec_ret = BSEC_OK;
uint8_t bsec_state[BSEC_MAX_STATE_BLOB_SIZE] = {0};
uint8_t bsec_config[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE] = {0};
int bsec_state_len, bsec_config_len;
if ((fd = open(IIC_Dev, O_RDWR)) < 0) {
printf("Failed to open the i2c bus");
exit(1);
}
if (ioctl(fd, I2C_SLAVE, 0x77) < 0) {
printf("Failed to acquire bus access and/or talk to slave.\n");
exit(1);
}
//dev.dev_id = BME68X_I2C_ADDR_PRIM;//0x76
dev.intf_ptr = &dev_addr; //0x77
dev.intf = BME68X_I2C_INTF;
dev.read = user_i2c_read;
dev.write = user_i2c_write;
dev.delay_us = user_delay_us;
rslt = bme68x_init(&dev);
printf("\r\n BME68X Init Result is:%d \r\n",rslt);
/* Initialize BSEC library */
bsec_ret = bsec_init();
if (bsec_ret != BSEC_OK)
{
printf("\r\n bsec_init Result is:%d \r\n",rslt);
}
/* Load library config, if available */
bsec_config_len = config_load(bsec_config, sizeof(bsec_config));
if (bsec_config_len != 0)
{
bsec_ret = bsec_set_configuration(bsec_config, bsec_config_len, work_buffer, sizeof(work_buffer));
if (bsec_ret != BSEC_OK)
{
return ret;
}
}
/* Load previous library state, if available */
bsec_state_len = state_load(bsec_state, sizeof(bsec_state));
if (bsec_state_len != 0)
{
bsec_ret = bsec_set_state(bsec_state, bsec_state_len, work_buffer, sizeof(work_buffer));
if (bsec_ret != BSEC_OK)
{
return ret;
}
}
/* Set temperature offset */
//bme680_temperature_offset_g = temperature_offset;
/* Call to the function which sets the library with subscription information */
bsec_ret = bme680_bsec_update_subscription(BSEC_SAMPLE_RATE_LP);
if (bsec_ret != BSEC_OK)
{
return ret;
}
}
void bme680_test(void)
{
stream_sensor_data_forced_mode(&dev);
//stream_sensor_data_parallel_mode(&dev);
}
三、硬件连接
使用树莓派的I2C1,将如图的I2C1的引脚与BME680的I2C1的SDA&SCL连接即可。
四、验证
1、使能I2C
1) 运行sudo raspi-config
选择Interface Option
2)选择I2C接口
3)进行使能即可
2、检测I2C器件
1)查看i2c设备
ls /dev/ | grep i2c*
2)安装i2c-tools
sudo apt-get install -y i2c-tools
3)检测IC设备器件
一开始全是0,找不到数据,进行如下操作就可以了。记得重启
sudo modprobe -r i2c_bcm2708 #卸载设备 -r代表remove sudo modprobe i2c_bcm2708 #重新载入设备
检测到BME680的器件地址为0x77,与实际器件地址一致
3、编译代码
gcc -Wall *.c -o bme68x -lwiringPi
4、运行
运行之后可以看到打印气体电阻、气压、温湿度的值
5、与OLED联合显示