//头文件和库函数:
#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);//创建读取任务并在控制台连续打印传感器采集的数据
}
espressif控制BME280,利用IIC总线实现数据采集
最新推荐文章于 2024-07-12 17:26:52 发布