AGS02MA TVOC传感器 I2C 的数据读取与解析

发布时间:2023年12月24日

AGS02MA TVOC传感器 I2C 的数据读取与解析。
AGS02MA内部存在预热,必须供电充足,这也是个具坑。

这里使用了esp32的idf编程,以简明的逻辑,说明传感器的I2C编程步骤。

#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_spi_flash.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "string.h"
#include <stdio.h>

#include "i2c_tvoc.h"

#define TAG "AGS02MA"

// I2C
#define I2C_MASTER_SDA_IO GPIO_NUM_16
#define I2C_MASTER_SCL_IO GPIO_NUM_3
#define I2C_MASTER_NUM I2C_NUM_1
#define I2C_MASTER_FREQ_HZ 25000   //  max 30000
#define WRITE_BIT I2C_MASTER_WRITE //写:0
#define READ_BIT I2C_MASTER_READ   //读:1
#define ACK_CHECK_EN 0x1           //主机检查从机的ACK
#define ACK_CHECK_DIS 0x0          //主机不检查从机的ACK
#define ACK_VAL 0x0                //应答
#define NACK_VAL 0x1               //不应答

// AGS02MA
#define AGS02MA_ADDR 26             //地址
#define AGS02MA_DATA 0x00
#define AGS02MA_CALIBRATION 0x01
#define AGS02MA_VERSION 0x11
#define AGS02MA_SLAVE_ADDRESS 0x21
#define I2C_MASTER_TIMEOUT_MS 1000

#define AGS02MA_OK 0
#define AGS02MA_ERROR -10
#define AGS02MA_ERROR_CRC -11
#define AGS02MA_ERROR_READ -12
#define AGS02MA_ERROR_NOT_READY -13
/*
===========================
全局变量定义
===========================
*/
uint8_t _buffer[5] = {0};

static int64_t last_read_time = -2000000;
static struct tvoc_reading last_read = {
  .status = -1,
  .tvoc = 0
};

uint8_t _CRC8(uint8_t *buf, uint8_t size) {
  uint8_t crc = 0xFF; //  start value
  for (uint8_t b = 0; b < size; b++) {
    crc ^= buf[b];
    for (uint8_t i = 0; i < 8; i++) {
      if (crc & 0x80)
        crc = (crc << 1) ^ 0x31;
      else
        crc = (crc << 1);
    }
  }
  return crc;
}

esp_err_t i2c_init(void) {
  // i2c配置结构体
  i2c_config_t conf = {
      .mode = I2C_MODE_MASTER,
      .sda_io_num = I2C_MASTER_SDA_IO,
      .scl_io_num = I2C_MASTER_SCL_IO,
      .sda_pullup_en = GPIO_PULLUP_ENABLE,
      .scl_pullup_en = GPIO_PULLUP_ENABLE,
      .master.clk_speed = I2C_MASTER_FREQ_HZ,
  };
  esp_err_t error = i2c_param_config(I2C_MASTER_NUM, &conf); //设置I2C
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "i2c_param_config error:%d", error);
    return error;
  }
  //注册I2C服务即使能
  error = i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "i2c_driver_install error:%d", error);
    return error;
  }
  return error;
}

esp_err_t init_AGS02MA(void) {
  // 发送空数据以验证是否响应
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();                                   //新建操作I2C句柄
  i2c_master_start(cmd);                                                          //启动I2C
  i2c_master_write_byte(cmd, AGS02MA_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);    //发地址+写+检查ack
  i2c_master_stop(cmd);                                                           //停止I2C
  esp_err_t error = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);        //I2C发送
  i2c_cmd_link_delete(cmd);      
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "init_AGS02MA i2c_master_cmd_begin error: %d.", error);
    return error;
  }
  return error;
}

esp_err_t get_version(char* ver) {
  uint8_t c[1] = {AGS02MA_VERSION};
  esp_err_t error = i2c_master_write_to_device(I2C_MASTER_NUM, AGS02MA_ADDR, c, sizeof(c), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "get_version i2c_master_cmd_begin error: %d.", error);
    return error;
  }
  vTaskDelay(1000 / portTICK_RATE_MS);
  error = i2c_master_read_from_device(I2C_MASTER_NUM, AGS02MA_ADDR, _buffer, sizeof(_buffer), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "get_version i2c_master_cmd_begin error: %d.", error);
    return error;
  }
  sprintf(ver, "%d-%d-%d-%d", _buffer[0], _buffer[1], _buffer[2], _buffer[3]);
  if (_CRC8(_buffer, 5) != 0) {
    error = AGS02MA_ERROR_CRC;
    ESP_LOGE(TAG, "get_version _CRC8 error: %d.", error);
  }
  return error;
}

esp_err_t setPPBMode() {
  // PPM/PPB
  uint8_t c[5] = {0x00, 0xFF, 0x00, 0xFF, 0x30};
  // UGM3
  // uint8_t c[5] = {0x02, 0xFD, 0x02, 0xFD, 0x00};
  esp_err_t error = i2c_master_write_to_device(I2C_MASTER_NUM, AGS02MA_ADDR, c, sizeof(c), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "get_version i2c_master_cmd_begin error: %d.", error);
    return error;
  }
  return error;
}

esp_err_t readSensor(uint32_t* value) {
  uint8_t c[1] = {AGS02MA_DATA};
  esp_err_t error = i2c_master_write_to_device(I2C_MASTER_NUM, AGS02MA_ADDR, c, sizeof(c), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "readSensor i2c_master_write_to_device error: %d.", error);
    return error;
  }
  vTaskDelay(1000 / portTICK_RATE_MS);
  error = i2c_master_read_from_device(I2C_MASTER_NUM, AGS02MA_ADDR, _buffer, sizeof(_buffer), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  if (error != ESP_OK) {
    ESP_LOGE(TAG, "readSensor i2c_master_read_from_device error: %d.", error);
    return error;
  }
  // check status
  if(_buffer[0] & 0x01) {
    error = AGS02MA_ERROR_NOT_READY;
    ESP_LOGE(TAG, "readSensor status error: %d.", error);
    return error;
  }
  if (_CRC8(_buffer, 5) != 0) {
    error = AGS02MA_ERROR_CRC;
    ESP_LOGE(TAG, "readSensor _CRC8 error: %d.", error);
    return error;
  }
  *value = ((uint32_t)_buffer[1]) << 16;
  *value += ((uint32_t)_buffer[2]) << 8;
  *value += ((uint32_t)_buffer[3]);
  return error;
}

void i2c_tvoc_init() {
  ESP_LOGI(TAG, "app_main_i2c begin");
  bool mr = i2c_init(); // I2C初始化
  ESP_LOGI(TAG, "i2c_init: %d", mr);
  esp_err_t sr = init_AGS02MA();
  ESP_LOGI(TAG, "init_AGS02MA: %d", sr);
  vTaskDelay(1000 / portTICK_RATE_MS); //延时100ms
  char ver[30] = {0};
  esp_err_t vr = get_version(ver);
  ESP_LOGI(TAG, "get_version: %d, ver:%s", vr, ver);
}

struct tvoc_reading read_AGS02MA() {
  if(esp_timer_get_time() - 2000000 < last_read_time) {
    return last_read;
  }
  last_read_time = esp_timer_get_time();

  uint32_t value;
  esp_err_t rsv = readSensor(&value);
  last_read.status = rsv;
  last_read.tvoc = value;
  return last_read;
}

// void app_main() { app_main_i2c(); }
文章来源:https://blog.csdn.net/ReadyShowShow/article/details/135177095
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。