espressif控制BME280,利用IIC总线实现数据采集

//头文件和库函数:
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/task.h"
#include"stdio.h"

#include "sdkconfig.h" // generated by "make menuconfig"

#include "bme280.h"

//IIC协议端口号设置、SDA_PIN(宏)
#define SDA_PIN GPIO_NUM_21
#define SCL_PIN GPIO_NUM_22

//仅和打印开头相关,可以做为一组数据的数据帧头检测用
#define TAG_BME280 "BME280"

#define I2C_MASTER_ACK 0
#define I2C_MASTER_NACK 1

//确保FAIL状态可用
#ifndef FAIL
#define FAIL -1
#endif


//串口的波特率为115200,但在哪设置的呢?
void i2c_master_init()//初始化
{
	i2c_config_t i2c_config = {
		.mode = I2C_MODE_MASTER,  //设置I2C模式为主机模式(主控模式)
		.sda_io_num = SDA_PIN,    //如上和宏关联
		.scl_io_num = SCL_PIN,    //如上和宏关联
		.sda_pullup_en = GPIO_PULLUP_ENABLE,  //启用SDA线的内部上拉电阻
		.scl_pullup_en = GPIO_PULLUP_ENABLE,  //启用SCL线的内部上拉电阻
		.master.clk_speed = 1000000           //内部时钟为1Mhz,可用看看数据采集速度和上位机画图之间的情况
	};
	i2c_param_config(I2C_NUM_0, &i2c_config);  //IIC端口配置函数(IIC端口和指向 i2c_config_t 类型的常量配置结构的指针)
	/*
	   The I2C port number. I2C 端口号。
       The configuration mode that we set (master/slave)
  	   RX缓冲区禁用。这是适用于从站的接收缓冲区大小。
	   TX 缓冲区禁用。这是发送缓冲区大小,也适用于从站。
       最后一个参数是“intr_alloc_flags”,它是分配中断的标志。在我们的例子中,它是“0”,因为我们在这个例子中没有使用中断。
	 */
	i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
}

s8 BME280_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)//返回的参数分别是板载地址、寄存器地址、要传输的数据和数据长度
{
	s32 iError = BME280_INIT_VALUE;

	esp_err_t espRc;           //数据传输状态参量
	i2c_cmd_handle_t cmd = i2c_cmd_link_create();       //创建链接

	i2c_master_start(cmd);    //主设备调用命令
	i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);   //函数写->指定从地址

	i2c_master_write_byte(cmd, reg_addr, true);
	i2c_master_write(cmd, reg_data, cnt, true);    //将缓冲区数据写入总线
	i2c_master_stop(cmd);

	espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);    // IIC主站发送和排队命令(IIC端口、处理命令和等待时间)
	if (espRc == ESP_OK) {
		iError = SUCCESS;
	} else {
		iError = FAIL;
	}
	i2c_cmd_link_delete(cmd);   //释放命令链接

	return (s8)iError;      //返回值判断传输是否成功或失败
}

s8 BME280_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)  //函数读->返回参数同上
{
	s32 iError = BME280_INIT_VALUE;
	esp_err_t espRc;          //判断数据输入状态

	i2c_cmd_handle_t cmd = i2c_cmd_link_create();   //创建链接

	i2c_master_start(cmd);   //发送I2C开始信号,开始通信
	i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);   //函数写->指定从地址
	i2c_master_write_byte(cmd, reg_addr, true);

	i2c_master_start(cmd);  //发送另一个I2C开始信号,通常在改变通信方向(从写入变为读取)之前使用。
	i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_READ, true);//函数读->读取先前写入的数据
	if (cnt > 1)
	{
		i2c_master_read(cmd, reg_data, cnt-1, I2C_MASTER_ACK);
		//判断要读取的字节数是否大于1,是则从IIC总线上读取cnt-1个字节到reg_data中,并发送ACK表示期望继续接收数据
	}
	i2c_master_read_byte(cmd, reg_data+cnt-1, I2C_MASTER_NACK);//读取最后1个字节,并发送NACK,表示这是接收的最后一个字节。
	//注:reg_data+cnt-1:在C语言中,指针加上一个整数意味着将指针向前移动指定数量的元素。因此,reg_data+cnt-1 指向数组的最后一个元素。
	i2c_master_stop(cmd);  //当前通信结束

	espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);   // IIC主站发送和排队命令(IIC端口、处理命令和等待时间)
	if (espRc == ESP_OK) {
		iError = SUCCESS;
	} else {
		iError = FAIL;
	}

	i2c_cmd_link_delete(cmd);    //释放命令链接

	return (s8)iError;
}

void BME280_delay_msek(u32 msek)
{
	vTaskDelay(msek/portTICK_PERIOD_MS);
}
//宏定义IIC地址位(由板子的端口决定->查手册,一般为0x76)
//#define BME280_I2C_ADDRESS1                  (0x76)
//#define BME280_I2C_ADDRESS2                  (0x77)

void bme280_reader_task(void *ignore)  //采集传感器数据并连续打印在串行终端上
{
	struct bme280_t bme280 = {
		.bus_write = BME280_I2C_bus_write,
		.bus_read = BME280_I2C_bus_read,
		.dev_addr = BME280_I2C_ADDRESS1,
		.delay_msec = BME280_delay_msek
	};             //结构体->传感器初始化
	               //定义结构体bme280_t的参数,分别包括IIC的写、读、地址和延迟
    //声明以下变量存储数据
	s32 com_rslt;    //温湿度和气压共同打印在串行终端上
	s32 v_uncomp_pressure_s32;
	s32 v_uncomp_temperature_s32;
	s32 v_uncomp_humidity_s32;

	com_rslt = bme280_init(&bme280);          //指针指向结构体bme280_t,用以初始化传感器

	//**温湿度和压力值采样(参数的状态不懂)应该是已经定义好
	com_rslt += bme280_set_oversamp_pressure(BME280_OVERSAMP_16X);
	com_rslt += bme280_set_oversamp_temperature(BME280_OVERSAMP_2X);
	com_rslt += bme280_set_oversamp_humidity(BME280_OVERSAMP_1X);

	com_rslt += bme280_set_standby_durn(BME280_STANDBY_TIME_1_MS);    //将传感器的待机持续时间写入寄存器
	com_rslt += bme280_set_filter(BME280_FILTER_COEFF_16);            //设置IIR滤波器参数

	com_rslt += bme280_set_power_mode(BME280_NORMAL_MODE);            //设置传感器的电源模式(睡眠模式、强制模式、正常模式)
	                                                                  //BME280_NORMAL_MODE、BME280_SLEEP_MODE、BME280_NORMAL_MODE
	if (com_rslt == SUCCESS)
	{
		while(true)
		{
			vTaskDelay(40/portTICK_PERIOD_MS);  //延时0.25s
            //读取未补偿的温湿度和压力参数
			com_rslt = bme280_read_uncomp_pressure_temperature_humidity(
				&v_uncomp_pressure_s32, &v_uncomp_temperature_s32, &v_uncomp_humidity_s32);
			//判断正确则从串行终端上打印实际的温湿度和气压值(未补偿和实际值之间的关系?)
			//串行输入和上位机显示的类型:start T= 26.66 H= 36.34 P= 1000.78 end->数据采样速率?1s传数25次。
			if (com_rslt == SUCCESS)
			{
				printf("BME280 %.2f degC / %.3f hPa / %.3f %% \n",
					bme280_compensate_temperature_double(v_uncomp_temperature_s32),
					bme280_compensate_pressure_double(v_uncomp_pressure_s32)/100, // Pa -> hPa
					bme280_compensate_humidity_double(v_uncomp_humidity_s32));
			}
			else
			{
				ESP_LOGE(TAG_BME280, "measure error. code: %d", com_rslt);
			}
		}
	} else
	{
		ESP_LOGE(TAG_BME280, "init or setting error. code: %d", com_rslt);  //判断初始化或设置错误
	}

	vTaskDelete(NULL);   //删除调用任务
}

void app_main(void)
{
	i2c_master_init();     //初始化主节点
	xTaskCreate(&bme280_reader_task, "bme280_reader_task",  2048, NULL, 6, NULL);//创建读取任务并在控制台连续打印传感器采集的数据
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值