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(); }